## What happened
The [Tag and Release
run](https://github.com/coder/coder/actions/runs/28549109434/job/84641825784)
failed in the `prepare-release` job at the step "Prepare release
(calculate version, create tag and branch)" with:
```
error: create tag v2.35.0-rc.0: exit status 128
```
## Root cause
`prepare-release` creates an **annotated** tag via `git tag -a`
(`scripts/release-action/prepare.go`), which records a tagger and
therefore requires a git identity. The job never ran `git config
user.name/user.email`, and runners have none configured, so git aborts
with exit status 128. The real `fatal:` message was hidden because
`realExecutor.RunMutation` discarded the command's stderr.
## Changes
- **`.github/workflows/tag-and-release.yaml`**: add a "Configure git
identity" step (`ci@coder.com` / `Coder CI`) to the `prepare-release`
job, before the release tool runs. This matches the identity pattern
already used later in the same workflow.
- **`scripts/release-action/cmdexec.go`**: capture stderr in
`RunMutation` and include it in the returned error, so a failing
mutation surfaces the underlying command output (e.g. git's `fatal:`
line) instead of only `exit status N`.
- **`scripts/release-action/cmdexec_test.go`**: add a test asserting
stderr is surfaced on failure.
## Testing
- `go test ./scripts/release-action/...` passes.
- `go vet ./scripts/release-action/...` and `gofmt` clean.
- `actionlint .github/workflows/tag-and-release.yaml` clean.
- Reproduced the failure locally: `git tag -a` with no usable identity
exits 128 (`fatal: no email was given and auto-detection is disabled`);
with an identity configured it succeeds.
<details>
<summary>Root-cause analysis / decision log</summary>
**Failing step** runs `go run ./scripts/release-action prepare-release
--type create-release-branch --ref main --commit cb1a87b…`.
1. The tool computes the next version `v2.35.0-rc.0` and calls
`createAndPushTag`, which runs `git tag -a v2.35.0-rc.0 -m "Release
v2.35.0-rc.0" <targetRef>` (`prepare.go:56`).
2. That git command exits **128**, wrapped as `error: create tag
v2.35.0-rc.0: exit status 128`.
**Why it's the identity, and not something else:**
- No `git config user.name/user.email` step exists in the
`prepare-release` job; the `setup-mise` action does not set it; and the
tool itself never sets an identity. Annotated tags require a tagger, so
`git tag -a` fails on runners whose auto-detected identity is bogus
(`…@runner.(none)`), which is rejected under git's strict identity
check.
- Not a pre-existing tag collision: no `v2.35.0*` tag exists on the
remote, and the code pre-checks for an existing tag (and would emit a
different "already exists" error).
- Not an unresolved ref: `targetRef` resolves to the provided commit
SHA, checked out at `fetch-depth: 0`.
- The log was unhelpful because `RunMutation` used `cmd.Run()` without
wiring git's stderr (`cmdexec.go`), discarding the `fatal:` line and
leaving only `exit status 128`. This PR fixes that too.
- The sibling `release.yaml` explicitly sets `git config
user.email/user.name` before its git mutations; that step was simply
missing from the newer `tag-and-release.yaml` `prepare-release` job.
</details>
---
> Generated by Coder Agents on behalf of @f0ssel.
The `tag-and-release` workflow fails at startup with `Can't find
'action.yml', 'action.yaml' or 'Dockerfile' under
.../.github/actions/setup-go`. #26422 reintroduced stale references to
the `./.github/actions/setup-go` and `./.github/actions/setup-node`
composite actions, both of which were removed in #25727 when CI migrated
shared tool setup to `mise`.
This replaces both with the `setup-mise` pattern already used elsewhere
in the same workflow. The `prepare-release` job now installs `go` via
`setup-mise` (dropping the old `use-cache: false`, since Go caching is
now opt-in through the `go-cache` action). The `update-docs` job
installs `node pnpm` via `setup-mise` and adds `pnpm-install` so
`scripts/update-release-calendar.sh` still has the dependencies it needs
for `make fmt/markdown`.
`actionlint` and the `pre-commit` hook pass locally.
<details>
<summary>Root cause and decision log</summary>
**Symptom:** `tag-and-release.yaml` references
`./.github/actions/setup-go`, but that directory has no
`action.yml`/`action.yaml`/`Dockerfile`.
**How it broke:**
- #25727 (`ci: refactor CI to use mise for shared tool setup`) deleted
`.github/actions/setup-go/action.yaml` and
`.github/actions/setup-node/action.yaml`, migrating every workflow to
`./.github/actions/setup-mise`.
- #26422 (`feat: add dry-run flag via CommandExecutor interface`)
rewrote `tag-and-release.yaml`. It adopted `setup-mise` in one job but
left two stale references: `setup-go` (prepare-release) and `setup-node`
(update-docs), likely a rebase/merge artifact.
**Scope check:** Swept every workflow for local-action references
pointing at missing directories. The only genuine misses were `setup-go`
and `setup-node`. `create-task-action` is an external action checked out
at runtime via `actions/checkout` (not a repo-local action), and
`embedded-pg-cache`/`test-cache` resolve to existing `download`/`upload`
subdirectories.
**Mapping decisions:**
- `setup-go` (`use-cache: false`) to `setup-mise` with `install-args:
"go"`. The old action also installed `gotestsum`/`mtimehash` and
pre-warmed modules, but `prepare-release` only runs `go run
./scripts/release-action`, so `go` alone is sufficient. Caching stays
off, matching the original `use-cache: false`.
- `setup-node` to `setup-mise` with `install-args: "node pnpm"` plus
`pnpm-install`. The old action provided node + pnpm and installed
`node_modules`; `make fmt/markdown` (invoked at the end of the calendar
script) needs `node_modules/.installed` and `pnpm exec
markdown-table-formatter`.
</details>
---
Generated by Coder Agents on behalf of @f0ssel.
## Summary
Adds a `--dry-run` capability to the `release-action` Go tool and
exposes it through a **new** manual workflow, `tag-and-release.yaml`,
without disturbing the existing `release.yaml` pipeline.
PR #25162 had rewritten `release.yaml` in place to be driven by
`scripts/release-action`, which changed its `workflow_dispatch` inputs
from `release_channel`/`release_notes`/`dry_run` to
`release_type`/`commit_sha`. That broke `scripts/releaser`, which
dispatches `release.yaml` with the original inputs. This PR restores
`release.yaml` and moves the Go-driven pipeline to its own workflow.
## Workflow layout after this PR
| Workflow | Trigger | Driven by | Purpose |
|---|---|---|---|
| `release.yaml` | `scripts/releaser` (`gh workflow run`) | legacy
inline shell | Existing pipeline, restored to pre-#25162 state |
| `tag-and-release.yaml` | Manual (Actions UI) |
`scripts/release-action` Go tool | New pipeline with `prepare-release` +
`dry_run` |
`release.yaml` is restored byte-for-byte to its pre-#25162 version, so
its inputs match what `scripts/releaser` sends again.
## `release-action` design
### CommandExecutor interface
Abstracts CLI command execution behind read-only and mutating methods:
| Method | Purpose | Dry-run behavior |
|---|---|---|
| `RunOutput` | Read-only, capture stdout | Executes normally |
| `Run` | Read-only, exit code only | Executes normally |
| `RunMutation` | Changes remote state, no output | **Prints command,
skips execution** |
| `RunMutationStdout` | Changes remote state, streaming I/O | **Prints
command, skips execution** |
Two implementations: `realExecutor` (executes via `os/exec`) and
`dryRunExecutor` (delegates read-only calls, prints mutating calls).
### `prepare-release` subcommand
Composes `calculateNextVersion` with idempotent tag and branch
creation+push, emitting the same JSON as `calculate-version`. Matching
existing refs are skipped; mismatched refs error.
### `tag-and-release.yaml` `dry_run` input
When enabled: `prepare-release` runs with `--dry-run` (version
calculated, plan printed, nothing pushed), notes are generated for
inspection, and the build+publish job is skipped via an `if` guard
(cascading to homebrew/winget/docs).
## Mutating commands covered by `--dry-run`
| Command | Call site |
|---|---|
| `git tag -a <version> ...` | `createAndPushTag` |
| `git push origin refs/tags/...` | `createAndPushTag` |
| `git push origin <sha>:refs/heads/...` | `createAndPushBranch` |
| `gh release create ...` | `publishRelease` |
`git fetch --tags --force origin` is intentionally not a mutation; it
only updates local remote-tracking refs and must run for accurate
version calculation.
## Changes
- **New**: `scripts/release-action/cmdexec.go`, `prepare.go` (+ tests)
- **Refactored**: `git.go`, `github.go`, `calculate.go`, `notes.go`,
`commit.go`, `publish.go` to thread `CommandExecutor`; added `gitMutate`
- **Updated**: `main.go` adds `--dry-run` flag and `prepare-release`
subcommand
- **New**: `.github/workflows/tag-and-release.yaml` (manual, Go-driven,
with `dry_run`)
- **Reverted**: `.github/workflows/release.yaml` to its pre-#25162 state
> [!NOTE]
> Generated by Coder Agents on behalf of @f0ssel
## Problem
`scripts/check_emdash.sh` is a diff gate for pull requests: it resolves
the merge-base against the target branch and only inspects added lines.
When it cannot resolve a base ref, it fell back to scanning **every
tracked file**.
Push builds on release branches hit exactly this case: the `lint` job
checks out with `fetch-depth: 1`, so `origin/main` is absent, and
`GITHUB_BASE_REF` is only set for `pull_request` events. With no base
ref, the whole-tree scan flags the many pre-existing emdash/endash
characters already in the repo and fails `make lint` (`lint/emdash`),
even though the build introduced none of them. Observed on
`release/2.34` CI (run
[27704528068](https://github.com/coder/coder/actions/runs/27704528068/job/81949529546)).
## Fix
When no base ref can be determined (i.e. outside a pull request), skip
the check instead of scanning the entire tree. A full scan remains
available on demand via `scripts/check_emdash.sh --all`.
## Testing
- **No base ref** (release-push simulation, no `GITHUB_BASE_REF`, no
`origin/main`): old script scans all files and fails on a pre-existing
emdash; new script skips and exits 0.
- **PR path** (diff vs merge-base): `OK: no emdash or endash characters
found.`
- **`--all`**: still scans the full tree (flags pre-existing characters
as before).
- `shellcheck` and `shfmt` clean.
## Backports
Backport PRs target `release/2.33` and `release/2.34` (same bug, older
script variant). `release/2.29` and `release/2.32` do **not** contain
`scripts/check_emdash.sh`, so there is nothing to backport there.
<details>
<summary>Decision log</summary>
Considered alternatives to the skip:
1. **Compare against `github.event.before`** on push events. Rejected:
the before-SHA is frequently unreachable in a `fetch-depth: 1` clone,
and wiring it in requires per-workflow env changes that complicate
backports.
2. **Fetch `origin/main` / deepen history** in the release lint job.
Rejected for the same backport-surface reason and because it only masks
the design intent.
The check exists to stop *new* emdashes from landing via PRs; that gate
already ran on the originating PRs. On non-PR builds there is no
meaningful diff base, so skipping is correct and self-contained in the
script (clean to backport). The explicit `--all` mode is preserved for
intentional full-tree audits.
</details>
---
Generated by Coder Agents on behalf of @f0ssel.
`AgentCoordinateeAuth.Authorize` validated every prefix in
`upd.Node.Addresses` (each must be a `/128` derived from the
authenticating agent's own UUID) but applied no equivalent check to
`upd.Node.AllowedIps`. Because `AllowedIPs` are installed verbatim into
the WireGuard peer config (`tailnet/configmaps.go`) and WireGuard
routing is driven by `AllowedIPs`, a malicious agent could advertise a
victim agent's `/128` and become an eligible route for that IP. With
`ServerTailnet` tunneling to many agents and routing by destination IP,
this could let an attacker intercept sessions intended for the victim
workspace.
This applies the same UUID-derivation validation to `AllowedIps` that
already guards `Addresses`, extracted into a shared
`authorizeNodePrefixes` helper. The check is the single chokepoint used
by both the in-memory coordinator (`tailnet/coordinator.go`) and the
Postgres coordinator (`enterprise/tailnet/connio.go`), so one fix covers
both. Legitimate agents are unaffected: an agent's `AllowedIPs` is a
clone of its `Addresses` (`tailnet/node.go`), which are already
UUID-derived `/128`s.
Fixes PLAT-264 (SEC-89): https://linear.app/codercom/issue/PLAT-264
<details>
<summary>Implementation notes and decision log</summary>
### Root cause
Asymmetric validation in `tailnet/tunnel.go`: `Addresses` were bound to
the agent's UUID, but `AllowedIps` were trusted as-is and propagated
into the WireGuard peer config, which drives routing.
### Why the fix is safe for legitimate agents
- `tailnet/node.go` builds the node with `AllowedIPs:
slices.Clone(u.addresses)`, identical to `Addresses`.
- `agent/agent.go` sets those addresses to
`TailscaleServicePrefix.PrefixFromUUID(agentID)` and
`CoderServicePrefix.PrefixFromUUID(agentID)` (both `/128`,
UUID-derived).
- The existing `Addresses` check already accepts exactly those prefixes
plus the legacy workspace agent IP, so identical validation of
`AllowedIPs` passes for real traffic and only rejects forged prefixes.
### Coverage: one method, both coordinators
`AgentCoordinateeAuth.Authorize` is the shared auth path. A failed
`Authorize` is wrapped as `AuthorizationError{Wrapped: err}` and closes
the agent's response stream.
### Tests
- `tailnet/tunnel_internal_test.go`: fast unit tests on `Authorize`
(valid AllowedIPs accepted; foreign `/128` rejected with
`InvalidNodeAddressError`; wrong-bits rejected with
`InvalidAddressBitsError`).
- `tailnet/coordinator_test.go`: in-memory coordinator closes the agent
stream on a forged `AllowedIp`.
- `enterprise/tailnet/pgcoord_test.go`: same regression for the Postgres
coordinator.
Verified the regression tests fail when the new `AllowedIps` check is
disabled, then pass with it enabled. Local validation: targeted tests
(in-memory, internal, and Postgres-backed enterprise), plus `make
pre-commit` (gen/fmt/lint/build) passing.
</details>
> Generated by Coder Agents on behalf of @f0ssel.
Replace the local interactive release CLI and legacy shell scripts with
a non-interactive Go tool (`scripts/release-action/`) and a rewritten
`release.yaml` workflow. Release managers trigger releases from the
GitHub Actions UI by selecting a branch, picking a release type (`rc`,
`release`, or `create-release-branch`), and optionally providing a
commit SHA.
The Go tool has four subcommands: `calculate-version` (computes next
version from git state), `generate-notes` (release notes from commit log
and PR metadata), `publish` (creates GitHub release with checksums), and
the workflow handles tag creation, branch creation, building, and
downstream publishing.
`scripts/version.sh` fallback now uses `git describe` (nearest ancestor
tag) instead of global latest so dev builds on release branches show the
correct version series.
## Problem
The OIDC callback checks `email_verified` via a Go type assertion
(`verifiedRaw.(bool)`). When an IdP returns the claim as a string
(`"false"`), a number, or omits it entirely, the assertion fails
silently and the email is implicitly treated as verified. Several real
IdPs (SAML-to-OIDC bridges, certain Azure AD B2C configurations) emit
string-typed booleans, making this reachable in practice.
## Fix
Add `coerceEmailVerified()` to handle `bool`, `string`
(`"true"`/`"false"`/`"1"`/`"0"` via `strconv.ParseBool`), `float64`,
`json.Number`, and `int`/`int64` variants. Rewrite the check to be
fail-closed: an absent claim, an unrecognized type, or any non-truthy
value is treated as unverified and rejected. The existing
`IgnoreEmailVerified` config option remains as an escape hatch.
Fixes https://linear.app/codercom/issue/PLAT-228
> Generated with [Coder Agents](https://coder.com) by @f0ssel
<details><summary>Implementation plan</summary>
### Production code (`coderd/userauth.go`)
- Added `encoding/json` import
- Added `coerceEmailVerified(v interface{}) (verified bool, ok bool)`
helper near EOF
- Replaced the type-assertion block (lines ~1342-1363) with fail-closed
logic that uses `coerceEmailVerified`
### Unit tests (`coderd/userauth_internal_test.go`, new file)
- Table-driven test covering: `bool`, `string` (`"true"`, `"false"`,
`"1"`, `"0"`, `"TRUE"`, `"t"`, `"f"`, `"invalid"`, `""`), `json.Number`,
`float64`, `int`, `int64`, `nil`, `[]string{}`, `map[string]string{}`
### Integration tests (`coderd/userauth_test.go`,
`coderd/users_test.go`)
- Added 3 new test cases: `EmailVerifiedMissingIgnored` (200),
`EmailVerifiedAsStringTrue` (200), `EmailVerifiedAsStringFalse` (403)
- Updated existing test cases that omitted `email_verified` and expected
success to include `"email_verified": true`
### FakeIDP (`coderd/coderdtest/oidctest/idp.go`)
- `encodeClaims` now defaults `email_verified` to `true` (like `exp`,
`aud`, `iss`) so tests that don't care about the verification flow are
unaffected
</details>
## Problem
`findLinkedUser` in `coderd/userauth.go` falls back to email-based user
lookup when no `linked_id` match is found. This fallback was used for
**all logins**, not just first-time linking. An attacker who registers
the victim's email at the IdP (with a different OIDC subject) bypasses
the `linked_id` check and gets matched to the victim's Coder account.
Combined with the `email_verified` type assertion bypass (PLAT-228),
this creates a chained account-takeover vector.
## Fix
Restrict the email fallback in `findLinkedUser` so that when a user
found by email already has a `user_link` with a non-empty `linked_id`
that **differs** from the current login's `linked_id`, the function
returns no user. This blocks account takeover while preserving:
- **First-time linking**: No existing `user_link` exists, email fallback
works as before.
- **Legacy links**: Empty `linked_id` (pre-migration), email fallback
still works.
- **Normal logins**: Matching `linked_id` resolves via the primary path,
no fallback needed.
Also adds a `UpdateUserLinkedID` query to backfill `linked_id` on legacy
links (only when currently empty) during login, gradually migrating them
to the secure path.
The `findLinkedUser` signature now accepts `loginType` explicitly
instead of relying on `user.LoginType`, ensuring the correct link is
checked in the legacy lookup.
## Breaking change
Marked `release/breaking`. An account whose `user_link` already has a
populated `linked_id` that does not match the subject the IdP presents
will now be denied login (403) instead of silently resolving via the
email fallback. The most likely trigger is changing
`CODER_OIDC_ISSUER_URL` (the `linked_id` is `issuer||subject`), or two
identities sharing one email. Accounts with an empty (legacy)
`linked_id` are unaffected and are backfilled on their next login.
Fixes: https://linear.app/codercom/issue/PLAT-229
<details><summary>Implementation details</summary>
### Files changed
- `coderd/userauth.go`: Core fix in `findLinkedUser` + backfill logic in
`oauthLogin`
- `coderd/database/queries/user_links.sql`: New `UpdateUserLinkedID`
query
- `coderd/database/dbauthz/dbauthz.go`: Authorization for new query
(`ActionUpdate` on the user object, matching `InsertUserLink`)
- `coderd/userauth_test.go`: New OIDC and GitHub tests
- Generated files: `queries.sql.go`, `querier.go`, `dbmock.go`,
`querymetrics.go`
### New tests
- `TestUserOIDC/OIDCEmailFallbackBlockedByExistingLink`: Attacker with a
different `sub` but the same email is rejected (403) when the victim has
an existing link (covers signups enabled and disabled).
- `TestUserOIDC/OIDCFirstTimeLinkByEmailAllowed`: User created via
SCIM/API (no `user_link`) can still link via email on first OIDC login,
and the `linked_id` is populated.
- `TestUserOIDC/OIDCLegacyLinkBackfill`: User with empty `linked_id` can
login and their `linked_id` is backfilled with the correct value.
- `TestUserOIDC/OIDCEmailFallbackBlockedByIssuerChange`: Existing link
recorded under a previous issuer is rejected (403) after the issuer
changes (documents the breaking behavior).
- `TestUserOAuth2Github/EmailFallbackBlockedByExistingLink`: GitHub
attacker with a different user ID but the victim's email is rejected
(403).
</details>
> [!NOTE]
> This PR was authored by Coder Agents on behalf of @f0ssel.
---------
Co-authored-by: Coder Agents <agents@coder.com>
`PUT /api/v2/users/{user}/password` was protected only by
`ActionUpdatePersonal`, which the built-in `user-admin` role holds
site-wide. No guard prevented targeting an owner. The old-password check
is skipped for non-self resets, so a user-admin could reset any owner's
password and authenticate as them, gaining full deployment control.
Add an owner-role guard to `putUserPassword` that refuses password-reset
requests when the target holds the owner role unless the caller is also
an owner. This is modeled on the guard in `putUserStatus`, but differs
in that it conditionally allows owner-to-owner resets (whereas
`putUserStatus` blocks all suspension of owners regardless of caller).
Fixes https://linear.app/codercom/issue/PLAT-227
<details><summary>Implementation details</summary>
- Guard inserted after the `Authorize` check, before `httpapi.Read`
- `apiKey.UserID != user.ID` gates the check so self-password-change is
unaffected
- Acting user's roles fetched from DB to verify owner status (same
pattern as `putUserStatus`)
- Returns HTTP 400 consistent with sibling handler error style
- Two new test cases: `UserAdminCannotResetOwnerPassword`,
`OwnerCanResetOwnerPassword`
</details>
> Generated with [Coder Agents](https://coder.com) by @f0ssel
Updates the install docs for the v2.34.0 release, branched off the
latest `main`.
Supersedes #25995: same release-docs update, but cut from current `main`
and with every "Latest Release" link refreshed. The automated PR carried
stale patch links and a `vv2.34.0` typo.
## Changes
- `docs/install/releases/index.md`: regenerate the release calendar.
2.34 → Mainline, 2.33 → Stable, and every "Latest Release" link points
to the current patch per minor (`2.24.6, 2.29.16, 2.30.9, 2.31.14,
2.32.5, 2.33.6, 2.34.0`).
- `docs/install/rancher.md`: version selector → Mainline `2.34.0`,
Stable `2.33.6`.
- `docs/install/kubernetes.md`: Helm `--version` → Mainline `2.34.0`,
Stable `2.33.6` (chart + OCI), matching the Rancher guide.
Addresses the review feedback on #25995: the `vv2.34.0` typo, bumping
Stable to `2.33.6`, and keeping the Kubernetes guide in sync with
Rancher.
<details>
<summary>Notes for reviewers</summary>
- Verified with `markdownlint-cli2` (0 errors) and
`markdown-table-formatter --check` (no reformatting needed).
- The calendar was regenerated via `scripts/update-release-calendar.sh`.
That script's `get_latest_patch` does not exclude prerelease tags, so it
selected `v2.34.0-rc.0` over `v2.34.0`; that row was corrected by hand.
A follow-up fix to the script would prevent this recurring.
- The linkspector 404 on `coder.com/changelog/coder-2-34` is expected
for a fresh release; that page publishes alongside the release.
</details>
---
*Generated by Coder Agents on behalf of @f0ssel.*
GitHub Actions does not reliably trigger the push-based CI workflow when
a new branch is created at a commit that already has a workflow run from
another branch (e.g. `main`). This meant cutting a release branch
produced no CI run on it, so `should_deploy.sh` never got to approve the
deploy from the release branch.
Adds the `create` event trigger to `ci.yaml` with a condition on the
`changes` job to only proceed for release branch creations. All other
jobs depend on `changes`, so non-release branch creations are a no-op.
> Generated with [Coder Agents](https://coder.com/agents) by @f0ssel
`NewDataBuilder` allocated `make([]byte, 0, req.FileSize)` using the
client-supplied `int64` with no upper-bound check. The DRPC 4 MiB wire
cap limits message size but not the integer value, so a crafted message
with `FileSize = 1<<40` forces a 1 TiB allocation, triggering an
unrecoverable `runtime.throw` that kills the entire `coderd` process.
Add a `MaxFileSize` constant (100 MiB, matching `HTTPFileMaxBytes` in
`coderd/files.go`) and reject negative or oversized `FileSize`, plus
negative or excessive `Chunks`, before the allocation.
`BytesToDataUpload` also returns an error for oversized data to preserve
the encode/decode round-trip contract. Fix a pre-existing reversed
subtraction in the `Add()` overflow error message.
Closes https://linear.app/codercom/issue/PLAT-231
<details>
<summary>Implementation details</summary>
- `provisionersdk/proto/dataupload.go`: New exported `MaxFileSize`
constant; validation in `NewDataBuilder` and `BytesToDataUpload`. Fixed
reversed subtraction in `Add()` error.
- `provisionersdk/proto/dataupload_test.go`: New
`TestNewDataBuilderValidation` with 7 subtests.
- Updated all 5 callers of `BytesToDataUpload` for new error return.
- Audited all `make([]byte, ...)` in provisioner paths; no other
client-supplied sizes.
</details>
> Generated by Coder Agents on behalf of @f0ssel
The `update-release-calendar.sh` script did not account for Extended
Support Release (ESR) versions. Running it would drop ESR entries (e.g.
2.24) from the calendar entirely or mark them as "Not Supported" instead
of "Extended Support Release".
## Changes
- Add `ESR_VERSIONS` array for tracking active ESR minor versions
- Add `is_esr_version()` helper to check ESR membership
- Extract `generate_release_row()` to reduce duplication
- Prepend ESR versions older than the standard window
- Override "Not Supported" status for ESR versions within the window
> [!NOTE]
> When new ESR versions are designated or old ones reach end of life,
update the `ESR_VERSIONS` array at the top of the script.
<!-- This PR was authored by Coder Agents -->
When releasing a `.0` version (e.g. `v2.33.0`) from a release branch,
the release notes diff was comparing against the most recent RC (e.g.
`v2.33.0-rc.3`) instead of the last stable release from the previous
minor series (e.g. `v2.32.X`).
## The bug
`prevVersion` is set to the latest tag matching the branch's
`major.minor` from merged tags. For a `.0` release, this is the latest
RC (e.g. `v2.33.0-rc.3`). The commit range for release notes then
becomes `v2.33.0-rc.3..HEAD` instead of `v2.32.X..HEAD`, so the notes
only show the delta from the last RC rather than all changes since the
previous real release. The compare link also points to
`v2.33.0-rc.3...v2.33.0`.
## The fix
After all semver sanity checks have run (so version suggestion and
validation are unaffected), when the new version is a `.0` release and
`prevVersion` is an RC, override `prevVersion` with the last stable
release from the previous minor series. This makes both the commit range
and compare link use the correct base (e.g. `v2.32.X..HEAD` and
`v2.32.X...v2.33.0`).
> Generated with [Coder Agents](https://coder.com/agents)
---------
Co-authored-by: Zach <3724288+zedkipp@users.noreply.github.com>
Fixes two bugs in the release tool.
## 1. RC tags chosen over release tags on release branches
`allSemverTags()` and `mergedSemverTags()` rely on `git tag
--sort=-v:refname` for ordering. Git's version sort treats pre-release
suffixes (e.g. `-rc.0`) as *greater* than the base release version,
which is the opposite of semver where `v2.32.0 > v2.32.0-rc.0`.
When the release branch code iterates the tag list looking for the first
matching `major.minor`, it finds the RC tag first, leading to incorrect
version suggestions (e.g. suggesting `v2.32.0` again instead of
`v2.32.1`).
**Fix:** Re-sort parsed tags using the existing `GreaterThan` method via
a new `sortVersionsDesc` helper.
## 2. Misleading mainline changelog blurb on ESR/older branch patches
When releasing a patch on an older branch (e.g. `release/2.29` for ESR),
the version is neither mainline nor stable. Declining the stable prompt
would always produce the mainline changelog note ("This is a mainline
Coder release..."), which is incorrect.
**Fix:** Only emit the mainline note when the version's minor matches
the current mainline series. For older branches the changelog omits the
note entirely.
> Generated by Coder Agents
When the control plane connection drops and reconnects, a new
`tunnelUpdater` is created with empty workspace state. This causes the
in-memory DNS resolver to lose all host records, breaking `.coder` name
resolution until the server sends a fresh workspace snapshot.
If the API is unreachable (e.g., the route goes through a VPN that is
also reconnecting), the snapshot never arrives and DNS stays broken
indefinitely — requiring a full Coder Desktop restart.
Fix: carry workspace state from the previous `tunnelUpdater` to the new
one on reconnect, and immediately re-apply DNS hosts so the resolver
stays populated during the reconnection window.
Fixes https://linear.app/codercom/issue/PLAT-110
<details><summary>Investigation & decision log</summary>
### Root cause analysis
Customer diagnostic data from Roblox (March 31) showed:
- NRPT rule present (`.coder` → `fd60:627a:a42b::53`) — routing is
correct
- DNS resolver returns NXDOMAIN for everything including the sentinel
`is.coder--connect--enabled--right--now.coder` — resolver is running but
has zero host records
- Coder Connect UI shows "connected" — the WireGuard data plane is up
The resolver is empty because
`TunnelAllWorkspaceUpdatesController.New()` creates a fresh
`tunnelUpdater` with `workspaces: make(map[uuid.UUID]*Workspace)`
(empty). The previous updater's workspace data is discarded. If the
server's workspace snapshot is delayed or the API is unreachable, the
resolver has no records to serve.
This is compounded by GlobalProtect VPN reconnects: the Coder API is
behind the VPN, so when GP reconnects, the API route is temporarily lost
and the snapshot can't arrive.
### What this PR changes
- `TunnelAllWorkspaceUpdatesController.New()` now clones workspace state
from the previous updater before creating the new one
- Immediately re-applies DNS hosts with the inherited state (log:
`re-applying DNS hosts from previous session`)
- When the server's snapshot arrives, it replaces the inherited data
normally
- If `SetDNSHosts` fails during re-apply, it's logged as a warning and
not fatal — the recvLoop will program DNS when the snapshot arrives
### What this PR does NOT fix (future work)
- **Tunnel binary restart**: when the tunnel process itself is killed
and relaunched, all in-memory state is lost. A DNS host cache on disk
would be needed for this case.
- **NRPT rule cleanup on startup**: the Tailscale fork's
`nrptRuleDatabase` constructor unconditionally deletes all NRPT rules on
engine creation. Deferring cleanup to the first successful `SetDNS` call
would reduce the DNS gap.
- **Hosts file retry**: the `setHosts()` retry in the Tailscale fork
(5×10ms) is too short for environments where endpoint security locks the
file.
These are tracked as follow-up items in the `coder/tailscale` fork.
</details>
> 🤖 Generated by Coder Agents
Supersedes #23343.
## Problem
`author_association` on `pull_request_target` events is unreliable:
- Returns `CONTRIBUTOR` instead of `MEMBER` when both apply
([actions/github-script#643](https://github.com/actions/github-script/issues/643)).
- Returns `NONE` for members with private org visibility
([community#18690](https://github.com/orgs/community/discussions/18690)).
This causes org members to incorrectly receive the `community` label.
## Approach
Replace the `author_association` check with an explicit
`orgs.checkMembershipForUser()` API call, which reliably detects both
public and private org members.
Uses a dedicated **GitHub App** via `actions/create-github-app-token`
instead of a PAT. The App only needs **Organization > Members: Read**
permission. Installation tokens are short-lived (1 hour) and
auto-rotated — no long-lived secrets to worry about.
### Setup required
A repo/org admin needs to:
1. Create a GitHub App with only **Organization > Members: Read**
permission.
2. Install it on the `coder` org.
3. Store the App ID as a repository variable: `ORG_MEMBERSHIP_APP_ID`.
4. Store the App's private key as a repository secret:
`ORG_MEMBERSHIP_APP_PRIVATE_KEY`.
> [!NOTE]
> Generated by Coder Agents
---------
Co-authored-by: Jakub Domeracki <jakub@coder.com>
After the cherry-pick workflow creates a backport PR, it now comments on
the original PR to notify the author with a link to the new PR.
If the cherry-pick had conflicts, the comment includes a warning.
## Changes
- Capture the URL output of `gh pr create` into `NEW_PR_URL`
- Add `gh pr comment` on the original PR with the link
- Append a conflict warning to the comment when applicable
> Generated by Coder Agents
When a devcontainer subagent is terraform-managed, the provisioner sets
its directory to the host-side `workspace_folder` path at build time. At
runtime, the agent injection code determines the correct
container-internal
path from `devcontainer read-configuration` and sends it via
`CreateSubAgent`.
However, the `CreateSubAgent` handler only updated `display_apps` for
pre-existing agents, ignoring the `Directory` field. This caused
SSH/terminal
sessions to land in `~` instead of the workspace folder (e.g.
`/workspaces/foo`).
Add `UpdateWorkspaceAgentDirectoryByID` query and call it in the
terraform-managed subagent update path to also persist the directory.
Fixes PLAT-118
<details><summary>Root cause analysis</summary>
Two code paths set the subagent `Directory` field:
1. **Provisioner (build time):** `insertDevcontainerSubagent` in
`provisionerdserver.go`
stores `dc.GetWorkspaceFolder()` — the **host-side** path from the
`coder_devcontainer` Terraform resource (e.g. `/home/coder/project`).
2. **Agent injection (runtime):**
`maybeInjectSubAgentIntoContainerLocked` in
`api.go` reads the devcontainer config and gets the correct
**container-internal**
path (e.g. `/workspaces/project`), then calls `client.Create(ctx,
subAgentConfig)`.
For terraform-managed subagents (those with `req.Id != nil`),
`CreateSubAgent`
in `coderd/agentapi/subagent.go` recognized the pre-existing agent and
entered
the update path — but only called `UpdateWorkspaceAgentDisplayAppsByID`,
discarding the `Directory` field from the request. The agent kept the
stale
host-side path, which doesn't exist inside the container, causing
`expandPathToAbs` to fall back to `~`.
</details>
> [!NOTE]
> Generated by Coder Agents
Adds a GitHub Actions workflow that runs on PRs targeting `release/*`
branches to flag non-bug-fix cherry-picks.
## What it does
- Triggers on `pull_request_target` (opened, reopened, edited) for
`release/*` branches
- Checks if the PR title starts with `fix:` or `fix(scope):`
(conventional commit format)
- If not a bug fix, comments on the PR informing the author and emits a
warning (via `core.warning`), but does **not** fail the check
- Deduplicates comments on title edits by updating an existing comment
(identified by a hidden HTML marker) instead of creating a new one
> [!NOTE]
> Generated by Coder Agents
The cherry-pick and backport workflows create PRs under
`github-actions[bot]`. Since GitHub doesn't support creating PRs on
behalf of another user, this adds attribution to the user who added the
label (`github.event.sender.login`):
- **Assignee**: the labeler is assigned to the backport PR
- **Reviewer**: the labeler is added as a reviewer
- **PR body**: includes "Requested by: @user"
Applied to both `cherry-pick.yaml` and `backport.yaml`.
---
> Generated by Coder Agents
The agent SSH server unconditionally allows all four SSH forwarding
paths (TCP local, TCP reverse, Unix local, Unix reverse). This is a
sandbox escape vector when workspaces are used for AI agent containment
— a reverse tunnel lets anything inside the workspace reach the user's
local machine, bypassing network isolation.
This adds two new agent CLI flags / environment variables:
- `--block-reverse-port-forwarding` /
`CODER_AGENT_BLOCK_REVERSE_PORT_FORWARDING` — blocks both TCP (`ssh -R`)
and Unix socket reverse forwarding
- `--block-local-port-forwarding` /
`CODER_AGENT_BLOCK_LOCAL_PORT_FORWARDING` — blocks both TCP (`ssh -L`)
and Unix socket local forwarding
Template admins can set these via the `env` block on the container/VM
resource that runs the agent (e.g. `docker_container`,
`kubernetes_pod`), or via `coder_env` resources tied to the agent.
Fixes https://github.com/coder/coder/issues/22275
<details>
<summary>Implementation notes</summary>
Follows the existing `BlockFileTransfer` pattern:
1. `agent/agentssh/agentssh.go` — New `BlockReversePortForwarding` and
`BlockLocalPortForwarding` fields on `Config`. TCP callbacks check these
before allowing forwarding. The `direct-streamlocal@openssh.com` channel
handler is wrapped to reject Unix local forwards.
2. `agent/agentssh/forward.go` — `forwardedUnixHandler` gains a
`blockReversePortForwarding` field to reject
`streamlocal-forward@openssh.com` requests.
3. `agent/agent.go` — New fields on `Options` and `agent` struct,
plumbed to SSH config.
4. `cli/agent.go` — New serpent flags with env vars.
5. Tests cover all four blocked paths: TCP local, TCP reverse, Unix
local, Unix reverse.
</details>
> 🤖 Generated by Coder Agents
Adds a GitHub Actions workflow that automatically cherry-picks merged
PRs to the last 3 release branches when the `backport` label is applied.
## How it works
1. Add the `backport` label to any PR targeting `main` (before or after
merge).
2. On merge (or on label if already merged), the workflow discovers the
latest 3 `release/*` branches by semver.
3. For each branch, it cherry-picks the merge commit (`-x -m1`) and
opens a PR.
Created backport PRs follow existing repo conventions:
- **Branch:** `backport/<pr>-to-<version>`
- **Title:** `<original PR title> (#<pr>)` — e.g. `fix(site): correct
button alignment (#12345)`
- **Body:** links back to the original PR and merge commit
If cherry-pick has conflicts, the PR is still opened with instructions
for manual resolution — no conflict markers are committed.
Also:
- Removes `scripts/backport-pr.sh` (replaced by this workflow)
- Removes `.github/cherry-pick-bot.yml` (old bot config)
- Adds a section to the contributing docs explaining how to use the
backport label
> [!NOTE]
> Generated with [Coder Agents](https://coder.com/agents)
Adds a GitHub Actions workflow that cherry-picks merged PRs to the
latest release branch when the `cherry-pick` label is applied.
## How it works
1. Add the `cherry-pick` label to any PR targeting `main` (before or
after merge).
2. On merge (or on label if already merged), the workflow detects the
latest `release/*` branch.
3. It cherry-picks the merge commit (`-x -m1`) and opens a PR.
This complements the `backport` label (see #24025) which targets the
latest **3** release branches. `cherry-pick` targets only the **latest**
one — useful for getting fixes into the current release.
Created PRs follow existing repo conventions:
- **Branch:** `backport/<pr>-to-<version>`
- **Title:** `<original PR title> (#<pr>)` — e.g. `fix(site): correct
button alignment (#12345)`
- **Body:** links back to the original PR and merge commit
If the cherry-pick encounters conflicts, the workflow aborts the
cherry-pick, creates an empty commit with resolution instructions, and
opens the PR with a `[CONFLICT]` prefix so the author can resolve
manually.
Also:
- Removes `scripts/backport-pr.sh` (replaced by this workflow)
- Removes `.github/cherry-pick-bot.yml` (old bot config)
- Adds a section to the contributing docs explaining the `cherry-pick`
label
> [!NOTE]
> Generated with [Coder Agents](https://coder.com/agents)
RC tags are now created directly on `main`. The `release/X.Y` branch is
only cut when the actual release is ready. This eliminates the need to
cherry-pick hundreds of commits from main onto the release branch
between the first RC and the release.
## Workflow
```
main: ──●──●──●──●──●──●──●──●──●──
↑ ↑ ↑
rc.0 rc.1 cut release/2.34, tag v2.34.0
\
release/2.34: ──●── v2.34.1 (patch)
```
1. **RC:** On `main`, run `./scripts/release.sh`. The tool detects main
(or a detached HEAD reachable from main), prompts for the commit SHA to
tag, suggests the next RC version, and tags it.
2. **Release:** When the RC is blessed, create `release/X.Y` from `main`
(or the specific RC commit). Switch to that branch and run
`./scripts/release.sh`, which suggests `vX.Y.0`.
3. **Patch:** Cherry-pick fixes onto `release/X.Y` and run
`./scripts/release.sh` from that branch.
## Changes
### `scripts/releaser/release.go`
- Two modes based on branch:
- **`main` (or detached HEAD from main)** — RC tagging. Prompts for the
commit SHA to tag (defaults to HEAD). Always checks out the target
commit so the flow operates in detached HEAD. Suggests the next RC based
on existing RC tags.
- **`release/X.Y`** — Release/patch mode. Suggests `vX.Y.0` if the
latest tag is an RC, or the next patch otherwise.
- Detached HEAD support: if `git branch --show-current` is empty, checks
whether HEAD is an ancestor of `origin/main` and enters RC mode
automatically.
- Commit selection prompt in RC mode: shows current commit, lets the
user confirm or provide a different SHA.
- Warns if you try to tag a non-RC on main, or an RC on a release
branch.
- Skips open-PR check and branch sync check in RC mode (not useful on
main).
### `scripts/releaser/main.go`
- Updated help text.
### `.github/workflows/release.yaml`
- RC tags (`*-rc.*`): skip the release-branch validation (they live on
main).
- Non-RC tags: still require the corresponding `release/X.Y` branch.
### `docs/about/contributing/CONTRIBUTING.md`
- Rewrote the Releases section with the new workflow, release types
table, and ASCII diagram.
- Replaced the old "Creating a release" / "Creating a release (via
workflow dispatch)" subsections.
<details><summary>Decision log</summary>
### Why this approach?
Previously, cutting a release branch early for an RC meant
cherry-picking all of main's progress onto that branch before the actual
release — often hundreds of commits. This approach avoids that entirely:
RCs are just tagged snapshots of main, and the release branch only
exists once you need it for stabilization and backports.
### Files NOT changed
- **`scripts/release/publish.sh`** — `--rc` flag controls GitHub
prerelease marking (tag-level, not branch-level). `target_commitish`
already defaults to `main` when the tag isn't on a release branch.
- **`scripts/release/tag_version.sh`** — No RC-specific branch logic.
- **`scripts/releaser/version.go`** — Version parsing/comparison
unchanged.
- **`docs/install/releases/index.md`** — Public-facing docs describe RC
as a release channel with no branch-level detail.
</details>
> Generated by Coder Agents
Two fixes for the release script:
**1. Branch regex cleanup** — Simplified to only match `release/X.Y`.
Removed
support for `release/X.Y.Z` and `release/X.Y-rc.N` branch formats. RCs
are
now tagged from main (not from release branches), and the three-segment
`release/X.Y.Z` format will not be used going forward.
**2. Changelog range for first release on a new minor** — When no tags
match
the branch's major.minor, the commit range fell back to `HEAD` (entire
git
history, ~13k lines of changelog). Now computes `git merge-base` with
the
previous minor's release branch (e.g. `origin/release/2.32`) as the
changelog
starting point. This works even when that branch has no tags pushed yet.
Falls
back to the latest reachable tag from a previous minor if the branch
doesn't
exist.
This adds full RC release support to the release scripts and GitHub
Actions workflow. Previously, the tooling only supported stable and
mainline releases with strict vMAJOR.MINOR.PATCH semver tags.
Changes:
- scripts/releaser/version.go: Add Pre field to version struct for
prerelease suffixes (e.g. "rc.0"), update regex, parsing, String(),
comparison methods, and add IsRC()/rcNumber() helpers.
- scripts/releaser/release.go: Detect RC branches (release/X.Y-rc.N),
suggest RC version numbers, auto-set "rc" channel (skipping
stable/mainline prompt), add RC advisory to release notes, skip docs
update for RC releases.
- .github/workflows/release.yaml: Add "rc" channel option, fix branch
derivation for RC tags (v2.32.0-rc.0 -> release/2.32-rc.0 instead of
broken release/2.32.0-rc), skip homebrew/winget/package publishing for
RC releases.
- scripts/release/publish.sh: Add --rc flag, pass --prerelease to gh
release create for RC releases.
- scripts/releaser/version_test.go: Add comprehensive unit tests for
version parsing, string formatting, IsRC, rcNumber, GreaterThan, and
Equal with RC versions.
<!--
If you have used AI to produce some or all of this PR, please ensure you
have read our [AI Contribution
guidelines](https://coder.com/docs/about/contributing/AI_CONTRIBUTING)
before submitting.
-->
The `echo_latest_mainline_version()` function fetches all GitHub
releases and sorts by version number to find the latest mainline
release. It did not filter out pre-release tags (e.g. `v2.32.0-rc.0`),
so publishing an RC release caused `coder.com/install.sh` to resolve the
RC as the latest mainline version instead of the actual mainline
release.
Adds a `grep` filter for strict semver (`MAJOR.MINOR.PATCH`) before
sorting, so tags with pre-release suffixes like `-rc.0` are excluded
from version resolution.
## Summary
The `build` CI job on `main` is failing with:
```
ERROR: Computed invalid windows version format: 2.32.0-rc.0.1
```
This started when the `v2.32.0-rc.0` tag was created, making `git
describe` produce versions like `2.32.0-rc.0-devel+4f571f8ff`.
## Root cause
`scripts/build_go.sh` converts the version to a Windows-compatible
`X.Y.Z.{0,1}` format by stripping pre-release segments. It uses
`${var%-*}` (shortest suffix match), which only removes the last
`-segment`. For RC versions this leaves `-rc.0` intact:
```
2.32.0-rc.0-devel → strip %-* → 2.32.0-rc.0 → + .1 → 2.32.0-rc.0.1 ✗
```
## Fix
Switch to `${var%%-*}` (longest suffix match) so all pre-release
segments are stripped from the first hyphen onward:
```
2.32.0-rc.0-devel → strip %%-* → 2.32.0 → + .1 → 2.32.0.1 ✓
```
Verified all version patterns produce valid output:
| Input | Output |
|---|---|
| `2.32.0` | `2.32.0.0` |
| `2.32.0-devel` | `2.32.0.1` |
| `2.32.0-rc.0-devel` | `2.32.0.1` |
| `2.32.0-rc.0` | `2.32.0.1` |
Fixes
https://github.com/coder/coder/actions/runs/23511163474/job/68434008241
## Description
When multiple organizations have templates with the same name, the
Prometheus `/metrics` endpoint returns HTTP 500 because Prometheus
rejects duplicate label combinations. The three `coderd_insights_*`
metrics (`coderd_insights_templates_active_users`,
`coderd_insights_applications_usage_seconds`,
`coderd_insights_parameters`) used only `template_name` as a
distinguishing label, so two templates named e.g. `"openstack-v1"` in
different orgs would produce duplicate metric series.
This adds `organization_name` as a label to all three insight metric
descriptors to disambiguate templates across organizations.
## Changes
**`coderd/prometheusmetrics/insights/metricscollector.go`**:
- Added `organization_name` label to all three metric descriptors
- Added `organizationNames` field (template ID → org name) to the
`insightsData` struct
- In `doTick`: after fetching templates, collect unique org IDs, fetch
organizations via `GetOrganizations`, and build a
template-ID-to-org-name mapping
- In `Collect()`: pass the organization name as an additional label
value in every `MustNewConstMetric` call
**`coderd/prometheusmetrics/insights/testdata/insights-metrics.json`**:
Updated golden file to include `organization_name=coder` in all metric
label keys.
Fixes#21748
Fixes#22030
## Problem
When a template has `require_active_version = true` and a workspace is
outdated, the web UI always shows "Update and start" as the **only**
button (for all users including admins), but `coder start` starts with
the old version. For admins, this silently succeeds on the stale
version. For non-admins, it goes through a clunky 403→retry path. This
also affects the VS Code extension, which calls `coder start --yes`
under the hood.
## Root Cause
`buildWorkspaceStartRequest()` in `cli/start.go` checks
`workspace.AutomaticUpdates == "always"` but ignores
`workspace.TemplateRequireActiveVersion`. The server-side autostart
already ORs both settings together:
```go
// coderd/autobuild/lifecycle_executor.go
func useActiveVersion(opts, ws) bool {
return opts.RequireActiveVersion || ws.AutomaticUpdates == "always"
}
```
The CLI was missing the `RequireActiveVersion` check.
## Fix
Add `workspace.TemplateRequireActiveVersion` to the existing OR
condition:
```go
// Before:
if workspace.AutomaticUpdates == codersdk.AutomaticUpdatesAlways || action == WorkspaceUpdate {
// After:
if workspace.AutomaticUpdates == codersdk.AutomaticUpdatesAlways || workspace.TemplateRequireActiveVersion || action == WorkspaceUpdate {
```
Now `coder start` and `coder restart` proactively use the active
template version when `require_active_version` is set, matching the web
UI and server autostart behavior. The 403→retry fallback remains as a
safety net but is no longer the primary path for any user.
## Testing
Updated `enterprise/cli/start_test.go` — all user types (owner, template
admin, ACL admin, group ACL admin, member) now expect the active version
when `require_active_version` is set, and verify the 403→retry message
does NOT appear.
## Summary
Custom roles that can create workspaces on behalf of other users need to
be able to list users to populate the owner dropdown in the workspace
creation UI. Previously, this required a separate `user:read`
permission, causing the dropdown to fail for custom roles.
## Changes
- Modified `GetUsers` in `dbauthz` to check if the user can create
workspaces for any owner (`workspace:create` with `owner_id: *`)
- If the user has this permission, they can list all users without
needing explicit `user:read` permission
- Added tests to verify the new behavior
## Testing
- Updated mock tests to assert the new authorization check
- Added integration tests for both positive and negative cases
Fixes#18203
## Summary
Fixes flaky `TestServer/BuiltinPostgres` test caused by port conflicts
in CI.
## Fix
Increase retry attempts from 3 to 10 for better odds when port conflicts
occur.
Fixes https://github.com/coder/internal/issues/1017
Fixes https://github.com/coder/coder/issues/18350
I attempted the route of relying on just the session env vars, in hopes
that this issue was fixed in Toolbox and the process name matching was
no longer need, but it was not a fruitful endeavor and it seems to be
using the same connection logic as it did in gateway, just with new
binary and flag names.
## Summary
- Updated documentation references to use the correct registry path
structure
- Changed URLs from incorrect paths to the correct format:
- Modules main page: registry.coder.com/modules
- Specific modules: registry.coder.com/modules/coder/{module-name}
## Test plan
- Verify that all documentation links to modules point to the correct
URL structure
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Edward Angert <EdwardAngert@users.noreply.github.com>
Fixes an issue where old ssh configs that use the
`owner--workspace--agent` format will fail to properly use the `coder
ssh` command since we migrated off the `coder vscodessh` command.
Part of https://github.com/coder/internal/issues/150
- Stop creating the VPC since we rely on an existing VPC in the
scaletest GCP project now
- Add prometheus remote writer to the new prometheus deployment
Closes https://github.com/coder/internal/issues/148
This has been validated to have working proxies with the `small`
scenario.
- [x] multi-region gcp infrastructure
- [x] use cloudflare provider to automate dns entries
- [x] automate proxy registration
- [x] multi-regional proxies
- [x] move scenarios into locals
This excludes the infrastructure for `cert-manager` and `otel-collector`
and those will be included in followup PRs.
Part of https://github.com/coder/coder/issues/15176
I originally kept this the same because I wanted to be conservative
about when we start dropping activity, but this is proving to be a
problem when using `coder ssh` with `--usage-app=disabled`. Because the
workspace agent still counts this as a connection (I think it still
should so it's counted somewhere) but not as a SSH / IDE session. This
leads to background ssh tasks that want to be untracked still continuing
to bump activity when it shouldn't. This makes it so we have to have an
explicit session to bump activity.
What this changes:
- Unhides the `--key` flag on provisioner start
- Deprecates and hides `provisionerd` command group in favor of
`provisioner(s)`
- Removes org id from `coder provisioner keys list`