Commit Graph
1179 Commits
Author SHA1 Message Date
Nick Vigilante c13dd06d2f ci(.github/workflows): disable audit-docs-paths pending cross-repo auth (#26571)
The `audit-docs-paths` job in `weekly-docs.yaml` fetches a config file
from a private upstream source. An anonymous read returns 404 and the
job fails on every weekly run, firing a misleading "Stale docs paths
found in site/src/" Slack notification (a pre-existing bug in the
notification copy, tracked separately).

We originally tried to authenticate the fetch with the existing CI token
used for cross-repo work (the same one used by `contrib.yaml`), but that
token does not have read access to the upstream source. The proper fix
is a GitHub App scoped to cross-repo `Contents: Read`; the docs team is
tracking the App provisioning internally.

Until the App is provisioned, this PR disables the job behind a
`vars.AUDIT_DOCS_PATHS_ENABLED` repository variable. The variable is
unset, so the job skips on the weekly cron and on `workflow_dispatch`.
The other two jobs in this workflow (`prepare-linkspector-browser`,
`check-docs`) keep running normally, so docs PRs still get link-checked.

Re-enabling once the App is provisioned is a one-line change: set
`AUDIT_DOCS_PATHS_ENABLED` to `'true'` on this repo, no workflow edit
required.

<details>
<summary>Investigation log (why the App is needed)</summary>

Initial attempt (commits `5cca548`, `fc0ff59`, now discarded)
authenticated the fetch via the GitHub Contents API with `Accept:
application/vnd.github.raw` and an existing CI token already used for
cross-repo writes. `coder-agents-review` approved that approach in Round
2 ([review
4546533491](https://github.com/coder/coder/pull/26571#pullrequestreview-4546533491)),
and all 29 CI checks passed.

Validation via `workflow_dispatch` (run
[27973114839](https://github.com/coder/coder/actions/runs/27973114839))
failed at the fetch step with `curl: (22) The requested URL returned
error: 404`. The bare `curl` against the same URL with a personal access
token returned HTTP 200 and valid JSON, so the call shape was correct;
the CI token just lacks the necessary scope on the upstream source. The
Contents API returns 404 (not 403) when a token cannot see a private
repository, which is why the original failure mode was hard to
attribute.

Options considered:

1. **Extend the existing CI token** to include the missing read access.
Cheapest in lines of code, but the token is org-CI-owned and changing
its scope has blast radius beyond this job.
2. **New fine-grained PAT.** Tightest scope, but PATs are user-owned. If
the issuing user leaves the org, the token auto-revokes and the audit
silently breaks again, which is exactly the failure mode this PR is
trying to make less likely.
3. **GitHub App owned by the org.** Tied to the org, not a user;
survives staff turnover; least-privileged per repo. Heaviest setup
because creation, installation, and secret provisioning all need org
admin.

Option 3 is the right long-term answer but is not same-day. Disabling
the job is the smallest change that stops the noise immediately, and the
feature-flag variable keeps the re-enable path to one step.

</details>

<details>
<summary>Validation</summary>

* `actionlint` clean on `.github/workflows/weekly-docs.yaml`.
* Branch passed all 29 CI checks under the previous authentication
approach; this revision is strictly smaller (one job-level `if` guard +
comments), no new failure surface introduced.
* The disable cannot be tested end-to-end without merging, since the
affected job runs on `schedule` / `workflow_dispatch` against `main`.
Once merged: confirm the next weekly run (or a manual
`workflow_dispatch`) shows `audit-docs-paths` as skipped, with no Slack
notification.

</details>

---

> Generated by [Coder Agents](https://coder.com) on behalf of
@nickvigilante.
2026-06-22 15:45:41 -04:00
Nick Vigilante ee3572ab9a feat: wire Vale prose linter into docs CI (#25467)
Wires Vale into docs CI as an advisory (non-blocking) prose-lint step.
Closes [DOCS-40](https://linear.app/codercom/issue/DOCS-40).

> **Integration update (rebased onto `main`).** Since this branch was
opened, `main` consolidated docs linting into the **required**
`lint-docs` job in `ci.yaml` and removed the standalone `docs-ci.yaml`
([#25608](https://github.com/coder/coder/pull/25608)). This PR adds Vale
to that `lint-docs` job instead of resurrecting `docs-ci.yaml`, and the
`docs/.style/` scaffold defers to the merged
[#25466](https://github.com/coder/coder/pull/25466) (DOCS-180). Vale
stays advisory.

> **Post-review refactor.** Following the Coder Agents review, Vale is
now invoked through `mise exec "aqua:errata-ai/vale"` (the same pattern
as `actionlint`/`zizmor`) instead of a bespoke `curl`/`tar` download.
This removed the GNU-only `grep -oP` version extraction and `uname`/arch
mapping that broke on macOS BSD grep, and the prose step now skips paths
a PR deletes. See the resolved review threads for CRF-17/19/20/21/22.

A sample of what this check does is as follows:

<img width="1443" height="1293" alt="image"
src="https://github.com/user-attachments/assets/cf68dbf9-d9df-49ba-8dbf-200875bc289e"
/>

## What changes

- `.vale.ini` at the repo root: Google base + Coder (custom, empty in
v1) + curated write-good. `alex` rules are pulled in a la carte. Inline
comments justify every enable/disable.
- `mise.toml`: pin Vale `3.7.1` via aqua. `mise.lock`: lock that pin
across all platforms so `mise install --locked` (used by `build_image`)
resolves it.
- `Makefile`: a `docs/.style/.vale-synced` sentinel that gates `vale
sync`, and a `lint/prose` target that runs `vale --no-exit`. Both invoke
Vale via `mise exec "aqua:errata-ai/vale" -- vale ...`, so mise owns the
version and the OS/arch download (no hand-rolled install path).
- `.github/workflows/ci.yaml`: append Vale steps to the existing
required `lint-docs` job: `Detect changed Markdown`, `Restore Vale
styles`, `Prepare Vale styles` (`make docs/.style/.vale-synced`), `Vale
prose lint`, and a default-branch-only `Save Vale styles`. They lint
only changed Markdown under `docs/` that still exists on disk, with a
problem matcher for inline PR annotations.
- `.github/vale-problem-matcher.json`: parses `vale --output=line` so
alerts surface as annotations on the Files Changed tab.
- `.gitignore` and the workflow cache `path:`: use
`docs/.style/styles/*` plus a `!docs/.style/styles/Coder` negation so
adding a package does not require parallel edits.
- `.markdownlint-cli2.jsonc`: ignore the synced styles so `make
lint/markdown` does not lint upstream READMEs.

Scaffold prose under `docs/.style/` and
`.claude/docs/DOCS_STYLE_GUIDE.md` / `AGENTS.md` come from the merged
DOCS-180; this PR no longer touches them. Net diff against `main` is the
8 Vale-wiring files only.

## Severity policy (v1)

Rule severity reflects two things together: the rule's false-positive
rate against real Coder docs and the gravity of the rule. Low FPs plus
high gravity argues for `error`; lower gravity or more judgment calls
argue for `warning` or `suggestion`. v1 lands most rules at `warning`
and the wordiness rules at `suggestion`.

A rule promotes to `error` only when (a) its false-positive rate against
real content is effectively zero and (b) the existing-content violation
count for that rule is also zero. Vale exits non-zero only on
error-level alerts regardless of `MinAlertLevel`; the Makefile and CI
invoke Vale with `--no-exit` so the baseline error count from
un-overridden Google rules does not fail the build while real failures
(bad config, missing files) still propagate.

## CI integration

Vale runs as steps appended to the required `lint-docs` job in
`ci.yaml`, gated on changed Markdown:

1. **`Detect changed Markdown`** (`tj-actions/changed-files`) scopes to
changed `**.md`; the prose step re-filters to `docs/` (the `docs/**.md`
glob silently skips dot-prefixed dirs and would miss
`docs/.style/style-guide.md`).
2. **`Restore Vale styles`** (`actions/cache/restore`), keyed off
`hashFiles('.vale.ini', 'mise.toml', 'docs/.style/styles/Coder/**')`.
mise manages the Vale binary, so only the synced styles are cached.
3. **`Prepare Vale styles`** runs `make docs/.style/.vale-synced` (`mise
exec ... vale sync`).
4. **`Vale prose lint`** filters the changed set to `docs/` paths still
present on disk, then runs `mise exec ... vale --no-exit --output=line`,
emitting inline annotations via the problem matcher.
5. **`Save Vale styles`** writes the cache, gated to `refs/heads/main`
only so PR runs cannot poison the cache other branches restore from (the
zizmor `cache-poisoning` concern).

**Every Vale step is `continue-on-error: true`.** This is a deliberate
change from the original standalone-workflow design: now that Vale lives
inside the *required* `lint-docs` job, a transient `vale sync` network
failure (or first-use `mise` install blip) would otherwise block merges.
`continue-on-error` keeps Vale advisory, so only the markdownlint /
table-formatter checks above (`pnpm check-docs`) remain merge-blocking.
`vale --no-exit` additionally keeps the baseline error count from
un-overridden Google rules from failing the step.

## Verification

- `actionlint` clean on `ci.yaml` (local + `make
lint/actions/actionlint`); `zizmor --persona regular` reports no
findings.
- `make lint/prose` on the full `docs/` corpus: ~406 errors, ~5,346
warnings, ~7,928 suggestions across 461 files, exit 0 (`--no-exit`),
Vale `3.7.1` installed by mise.
- Net diff vs `main` is the 8 Vale-wiring files only; the `docs/.style/`
scaffold already matches `main`.

<details>
<summary>Implementation plan and decision log</summary>

### Why this rule set

The Vale evaluation against the full docs corpus (measured 2026-05-18)
produced ~43,940 raw violations across six candidate base styles. The
selection here drops Microsoft and RedHat (overlap with Google, and
RedHat's Spacing rule hammers technical IDs), and proselint (Annotations
rule treats `> [!NOTE]` admonitions as TODO markers).

Within the kept styles:

- **Google** is the base. Disables: `EmDash` (conflicts with `make
lint/emdash`), `Latin` (i.e./e.g. are fine for our audience), `Spacing`
(4,500 errors on `codersdk.SomeType` patterns in the auto-generated API
reference). Softened: `Parens` to `suggestion`, `WordList` to `warning`.
- **write-good** is the base, with `Passive` and `E-Prime` off.
`TooWordy` and `ThereIs` are suggestions; `Weasel` is a warning.
- **alex** is cherry-picked (not in `BasedOnStyles`): `Ablist`,
`Condescending`, `LGBTQ`, `ProfanityLikely`, `Race`, `Suicide` at
warning. The `ProfanityMaybe`/`ProfanityUnlikely` rules trip on
`execute`, `kill`, `failed`, and `attack`, which read as technical
vocabulary in our context.
- **Coder** is in `BasedOnStyles` but the directory is empty in v1.
Rules land through the per-rule tickets in the [Docs style
guide](https://linear.app/codercom/project/docs-style-guide-7828445b9afc)
project.

### Why `mise exec` instead of a download block

Vale is pinned in `mise.toml` like `actionlint` and `zizmor`, so
invoking it via `mise exec "aqua:errata-ai/vale" -- vale ...` makes the
pin the single source of truth and lets mise handle the OS/arch-specific
download. This replaced an earlier ~30-line `curl`/`tar` block whose
GNU-only `grep -oP ...\K` version extraction returned empty on macOS BSD
grep. Note: the bare `vale` short name in `mise exec` ignores the pin
and resolves to the latest release, so the full aqua key is required.

### Why `vale sync` instead of vendoring

The three style packages weigh ~272 KB combined, so vendoring is cheap.
But Vale's ecosystem treats `Packages = ` + `vale sync` as canonical,
the upstream LICENSE files are not in the package tarballs (would need
to be added manually), and the CI cache makes the sync nearly free after
the first run. Sticking with the canonical pattern keeps the repo lean
and the upgrade path obvious.

### Why `lint/prose` is not in `lint:` or `lint-light:`

Vale on the full docs corpus takes ~20s on cold caches. Forcing every
pre-commit through that would be aggressive for a feature that ships as
warnings. `make lint/typos` follows the same pattern (it is in
`lint-light` but not `lint`; CI invokes it directly). v1 keeps Vale
opt-in locally and CI-only by default; promote to `lint:` once the rule
set stabilizes.

### Exit-code handling

Two mechanisms combine, and the choice changed when the step moved into
the required `lint-docs` job:

- `vale --no-exit` suppresses Vale's non-zero exit on alerts, so the
baseline error-level violations from un-overridden Google rules do not
fail the step while the cleanup PRs land. Real failures (config invalid,
file missing) still exit non-zero.
- `continue-on-error: true` on every Vale step. Because the steps now
run inside the *required* `lint-docs` job, a `vale sync`
download/network blip must not block merges. The original (standalone,
non-required) design rejected `continue-on-error` for showing a
misleading yellow badge; in a required job that tradeoff flips, and
advisory-yellow is strictly preferable to merge-blocking-red on an
infrastructure flake. `|| true` in the Makefile was also rejected: it
swallows missing-config failures indiscriminately.

### Pre-mortem

- **Generated docs noise**: `docs/reference/` is dominated by
auto-generated content (clidocgen, apidocgen, auditdocgen,
metricsdocgen). The architectural decision is to fix the generators, not
exclude paths in Vale. Google.Spacing is the only rule silenced
specifically to defer the generator fix; everything else surfaces as
warnings.
- **First-run cost**: `mise` installs the pinned Vale (a single small
binary) and `vale sync` pulls the style packages on a cold run. The
Actions cache keyed off `hashFiles('.vale.ini', 'mise.toml',
'docs/.style/styles/Coder/**')` makes subsequent runs near-instant; the
`Coder/**` hash is defense-in-depth against
[actions/toolkit#713](https://github.com/actions/toolkit/issues/713) so
a future cache release that regresses path-negation cannot serve a stale
`Coder/` from cache.
- **Required-job blast radius**: moving Vale into the required
`lint-docs` job means any Vale step failure would gate merges. Mitigated
by `continue-on-error` on all Vale steps plus a clean skip when no
changed `docs/` Markdown remains on disk, so only `pnpm check-docs`
stays blocking.
- **Cross-platform install**: handled by mise (aqua backend) rather than
a hand-rolled `uname`/arch map, which removes the macOS BSD-grep break
the review flagged.
- **Deleted files**: `all_changed_files` is ACMRD and lists paths a PR
removes; the prose step filters to files still present on disk so Vale
does not error on a missing file.
- **Local-vs-CI parity**: CI lints changed files only; local `make
lint/prose` lints the full tree. This mirrors `make lint/markdown` (full
tree) vs the changed-files CI step. Acceptable for v1.

</details>

---

*Filed via [Coder Agents](https://coder.com/docs/ai-coder/agents) on
Nick's behalf.*
2026-06-22 14:14:31 -04:00
Cian Johnston fc83d77189 ci: correct location of redirects.json in weekly-docs workflow (#26542) 2026-06-19 12:03:55 +01:00
Ben Potter 787392ef16 ci: add docs-path redirect audit to weekly-docs workflow (#26472)
Closes
[DOCS-257](https://linear.app/codercom/issue/DOCS-257/b-vitest-validate-docs-literals-against-docsmanifestjson)

Extends `weekly-docs` with a new `audit-docs-paths` job that
cross-references TS/TSX `docs()` calls against
`coder.com/redirects.json` and fails when any path resolves via a
redirect (i.e. is stale). Also fixes two bugs in the existing
`check-docs` job:

- **Scheduled runs were a no-op** — `github-pr-review` reporter silently
exits 0 without a PR context. Now uses `local` reporter on schedule so
broken links actually fail the job.
- **Slack notification was broken** — payload used `"msg"` (invalid)
instead of `"text"` (the standard Slack webhook field).

Sample Slack output:

![slack-notification-sample](https://i.imgur.com/N6E7d9s.png)

Safe to merge in any order relative to #25740 — the audit job checks for
the script and skips gracefully if not yet available.

---

> Generated by [Coder Agents](https://coder.com) on behalf of @bpmct.
2026-06-17 11:59:35 -05:00
Nick Vigilante 182bdc871a docs: scaffold docs/.style for the prose style guide (#25466)
Adds a private contributor-tooling directory at `docs/.style/` that will
host the canonical prose style guide and the custom Vale rules used to
enforce it. The directory's contents do not deploy to `coder.com/docs`.

This PR is the scaffold only. The Vale configuration, the rule set, and
the per-rule style-guide sections all land in follow-up PRs.

## What changes

- New `docs/.style/` directory with:
  - `README.md` explaining the convention
  - `style-guide.md` as a table-of-contents scaffold
- `styles/Coder/README.md` placeholder so Git tracks the empty Vale
rules dir
- `.github/workflows/deploy-docs.yaml`: skip the workflow on
`.style`-only pushes, and exclude `.style` paths from the
surgical-reindex git diff on mixed commits. Defense-in-depth on top of
the manifest-driven coder.com routing.
- `.github/.linkspector.yml`: add `docs/.style` to `excludedDirs`
- `AGENTS.md` and `.claude/docs/DOCS_STYLE_GUIDE.md`: cross-link to the
new style guide for agents

## Verification

- `make pre-commit-light` clean (`fmt/markdown`, `lint/markdown`,
`lint/typos`, `lint/emdash`, `lint/actions/actionlint`,
`lint/shellcheck`).
- `markdown-table-formatter --check` and `markdownlint-cli2` both
process the new files (existing globs are `find docs -name '*.md'`).
- `actionlint` clean on the modified workflow.
- coder.com exclusion works because route discovery and Algolia indexing
are manifest-driven; this directory is not in `docs/manifest.json`. The
workflow changes are defense in depth.

<details>
<summary>Implementation plan and decision log</summary>

### Decisions

- **Location**: `docs/.style/` (leading dot, mirrors `.github/`,
`.vscode/`, `.claude/`). Vale's `StylesPath` will be
`docs/.style/styles/`; `.vale.ini` lands at repo root in a follow-up.
- **Existing public page `docs/about/contributing/documentation.md`**:
untouched in this PR. Nick's separate information-architecture rework
will redirect it to GitHub at the right time.
- **Placeholder for empty `styles/Coder/`**: real `README.md`, not
`.gitkeep`. Discoverable on GitHub, lints with the existing tooling,
lists the planned starter rules.
- **CONTRIBUTING.md**: not touched. It's a 2-line redirect to
`coder.com/docs/CONTRIBUTING`; bloating it would defeat the redirect.
- **`.claude/docs/DOCS_STYLE_GUIDE.md`**: kept as the structure/research
companion. A blockquote at the top points at the new canonical prose
guide.

### coder.com exclusion mechanism (verified by inspection)

Direct inspection of `coder/coder.com`:

- Route discovery in
[`src/utils/docs/docs.ts`](https://github.com/coder/coder.com/blob/master/src/utils/docs/docs.ts)
iterates `routes` from `docs/manifest.json`. Files not in the manifest
never become routes.
- The Algolia surgical indexer at
[`src/utils/algoliaDocs/surgical.ts`](https://github.com/coder/coder.com/blob/master/src/utils/algoliaDocs/surgical.ts)
explicitly skips paths not in the manifest, incrementing `pathsSkipped`.

Net result: not adding anything from `docs/.style/` to `manifest.json`
is the only thing that has to be true for the exclusion to work. The
`deploy-docs.yaml` tweaks are defense in depth.

### deploy-docs.yaml changes (pre-mortem)

1. Trigger path negation `!docs/.style/**` skips the workflow on
`.style`-only pushes. GitHub Actions only suppresses when every changed
file matches a negation, so mixed commits still trigger.
2. The git-diff pathspec `:(exclude)docs/.style/**` drops `.style` paths
from the surgical-reindex payload on mixed commits.

Risks considered:

- **Test contract**: `.github/workflows/test-deploy-docs-diff.sh` only
exercises the downstream awk parser, not the git-diff invocation. The
exclusion happens at git-diff time; the parser sees the same
`<status>\0<path>\0` format. No test change needed.
- **First push to a brand-new branch**: the workflow falls back to
whole-branch reindex when `BEFORE_SHA` is all zeros. Whole-branch
reindex re-extracts records from the manifest, which still excludes
`.style` files because they are not in the manifest.
- **Workflow-dispatch**: takes the whole-branch path; same reasoning.
Safe.

### Why a real README in `styles/Coder/` instead of `.gitkeep`

It explains intent, lists the upcoming rules, and lints with the
existing tooling. The cost is one extra Markdown file; the upside is
that a contributor browsing GitHub sees the plan without clicking
around.

</details>

---

*Filed via [Coder Agents](https://coder.com/docs/ai-coder/agents) on
Nick's behalf.*


Linear: DOCS-180
2026-06-17 13:19:37 +00:00
McKayla はな 3e68dd304a ci: set up pixel (#26324)
IT'S FINALLY HERE
2026-06-16 14:43:54 -06:00
Spike Curtis 792afc0842 ci: capture PostgreSQL logs in the gen job (#26340)
Adds a `test-postgres-docker-logs` Make target that dumps the test
PostgreSQL container's logs via `docker logs`. The container already
logs every statement to stderr (`log_statement=all`, no
`logging_collector`), so Docker captures them and no volume mounting or
reconfiguration is needed.

The CI `gen` job now starts the container with `make
test-postgres-docker` before `make gen`, collects the logs at the end
(always, even on failure), and uploads them as the `gen-postgres-logs`
artifact to help debug generation issues that depend on the database.

Refs: https://github.com/coder/internal/issues/1568

<sub>Opened by Coder Agents on behalf of @spikecurtis.</sub>
2026-06-15 16:23:36 -04:00
Nick Vigilante fb24110933 feat(.github/workflows): trigger docs reindex on release.published (DOCS-327) (#26070)
Closes
[DOCS-327](https://linear.app/codercom/issue/DOCS-327/trigger-docs-reindex-on-codercoder-releasepublished).

## What

Add `release: { types: [published] }` to
`.github/workflows/deploy-docs.yaml` so that publishing a stable
`vX.Y.Z` GitHub Release on this repo auto-dispatches the docs-sync
handler against the corresponding `release/X.Y` branch. The existing
`push` and `workflow_dispatch` triggers are unchanged.

The `Compute action and ref` step gains a release-event branch that:

- Skips prereleases (`github.event.release.prerelease == true`) with a
workflow notice.
- Matches the tag against `^v([0-9]+)\.([0-9]+)\.[0-9]+$` and translates
`v2.35.0` to `release/2.35`.
- Falls through with a notice and `exit 0` for any tag that doesn't
match the plain semver shape (`v2.35`, `v2.35.0-rc.1`, etc.).

Downstream validation, HMAC body construction, and the POST step are
unchanged. The POST step gains an `if: steps.input.outputs.action != ''`
guard so the two `exit 0` paths skip the POST instead of sending empty
`action`/`ref` to the production handler.

A new `.github/workflows/test-deploy-docs-release.sh` exercises the
release-event bash against the 11 event scenarios in the table below
plus 3 regex boundary cases, mirroring the existing
`test-deploy-docs-diff.sh` pattern.

## Why

Today, every mainline rollover requires a human to dispatch this
workflow manually with `action=index, ref=release/X.Y`. We just hit this
rotation friction on
[DOCS-324](https://linear.app/codercom/issue/DOCS-324/rotate-algolia-indexer-allowlist-for-v234-launch-add-release234-drop)
(v2.34 launch) and the resulting empty-search-results incident on
`/docs/@v2.34.x/...`. `release.published` is the right cue: it fires
exactly when a version becomes user-visible, not when its release branch
is cut weeks earlier with possibly-incomplete docs.

## Coupling (important)

This change is **intentionally inert until coder.com's
`INDEXED_REFS_BY_CORPUS` allowlist becomes self-rotating** (filed under
[DOCS-210](https://linear.app/codercom/issue/DOCS-210/automated-docs-index-lifecycle-management)).
Until that lands, the handler still rejects new minors with `{action:
"skipped", reason: "...not in INDEXED_REFS_BY_CORPUS"}` and this
workflow logs the skip. Pre-wiring lets both halves land roughly in
parallel so the next release cut after both ship is automatic.

Reviewers: feel free to merge this independently. There is no downside
to the wiring being live before the allowlist half ships; worst case,
every release-publish event creates a no-op workflow run.

## Behavior trace (the cases the bash handles)

<details>
<summary>11 event scenarios I walked through by hand</summary>

| Event | Tag | prerelease | Result |
|---|---|---|---|
| push to main | n/a | n/a | `index`, `ref=main` (existing) |
| push to release/2.34 | n/a | n/a | `index`, `ref=release/2.34`
(existing) |
| workflow_dispatch index release/2.34 | n/a | n/a | `index`,
`ref=release/2.34` (existing) |
| workflow_dispatch delete release/2.31 | n/a | n/a | `delete`,
`ref=release/2.31` (existing) |
| release.published | `v2.35.0` | `false` | `index`, `ref=release/2.35`
(new) |
| release.published | `v2.35.0-rc.1` | `true` | notice + `exit 0` (new)
|
| release.published | `v2.35.0-rc.1` | `false` | notice + `exit 0`,
regex miss (new) |
| release.published | `v2.35` | `false` | notice + `exit 0`, regex miss
(new) |
| release.published | `release-2.35` | `false` | notice + `exit 0`,
regex miss (new) |
| release.published | `v0.0.0` | `false` | `index`, `ref=release/0.0`
then handler rejects via allowlist (defense in depth) |
| release.published | `` (empty) | unset | notice with `<unknown>` +
`exit 0` |

</details>

## Safety

- The handler's allowlist gate still applies; this PR can only cause
`{action: "skipped"}` responses until DOCS-210's allowlist-derivation
lands. No risk of indexing an unintended ref.
- The workflow's existing input validation (`case "$REF" in
main|release/*)`) rejects any translation output that isn't
`release/<int>.<int>`. Defense in depth in case the regex ever loosens
by accident.
-
[DOCS-121](https://linear.app/codercom/issue/DOCS-121/post-mortem-docs-search-outage-2026-05-12-pr-25049-merge-wiped-docs)
self-trigger risk is not present here: the new trigger is
`release.published`, not push-on-paths. Workflow file edits cannot
induce a release event.
- `concurrency: { group: deploy-docs-${{ github.ref }} }` already
exists. Release events have `github.ref=refs/tags/vX.Y.Z`, distinct from
push events on the same release branch. A theoretical race resolves
through the handler's atomic deleteBy+saveObjects.
- The POST step now has an `if:` guard that skips downstream calls when
the Compute step exits early without writing outputs. Closes the
empty-env-var failure mode that coder-agents-review CRF-1 flagged.

## Verification

- `actionlint .github/workflows/deploy-docs.yaml` clean.
- `make pre-commit-light` clean: `fmt/shfmt`, `fmt/markdown`,
`lint/actions/actionlint`, `lint/shellcheck`, `lint/markdown`,
`lint/emdash`, `lint/typos`, etc.
- `.github/workflows/test-deploy-docs-release.sh`: 14 cases pass (11
scenario table + 3 regex boundary cases).
- Bash logic hand-traced through 11 event scenarios (table above).

## Out of scope

- Build-time allowlist derivation in coder.com (DOCS-210a, will be
filed/PR'd as a sibling change).
- Webhook-driven cleanup of aged-out refs
([DOCS-210](https://linear.app/codercom/issue/DOCS-210) parent).
- code-server release lifecycle (different repo, code-server's docs
corpus stays at `main`).

---

_Coder Agents on behalf of @nickvigilante._
2026-06-12 17:54:32 -04:00
Danny Kopping fda6fc9345 ci(.github/workflows): label cherry-pick PRs with the target release (#25887)
## Summary

Adds a `cherry-pick/v<version>` label to the cherry-pick PRs that the
`Cherry-pick to release` workflow creates automatically, so cherry-picks
for a specific release can be filtered and identified easily (for
example
`cherry-pick/v2.31`).

## Changes

- Compute `CHERRY_PICK_LABEL="cherry-pick/v${VERSION}"` from the
resolved
  release branch.
- Create the label on demand with `gh label create --force` so the
workflow stays idempotent across re-runs and concurrent runs, and works
  even when the label does not exist yet.
- Apply the label at PR creation via `gh pr create --label`.
- Grant `issues: write` permission, required to create the label.
- Document the new label convention in the workflow header.

## Notes

The version is derived from the existing release-branch resolution
(`release/2.X` -> `2.X`), so no new configuration is required. The label
name uses a `v` prefix to match the requested `cherry-pick/vX.YZ`
format.

<details>
<summary>Implementation context</summary>

The label is created before the existing-PR idempotency check and
applied
in the same `gh pr create` call already used for assignees/reviewers, so
it
fits the workflow's existing conventions (branch, title, body) without
changing control flow.

</details>

---

*This PR was created by Coder Agents on behalf of @dannykopping.*
2026-06-11 20:13:03 +02:00
Garrett Delfosse b95697a370 ci: rewrite release workflow to be fully GitHub Actions-driven (#25162)
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.
2026-06-04 14:38:48 -04:00
Atif Ali 6ef687cdfb chore: remove Nix dev image from dogfood template and pipeline (#26022) 2026-06-03 16:49:27 +05:00
Dean Sheather 6c230d6e0f chore(.github): remove fly.io workspace-proxy deployment (#25126)
Removes the fly.io-based workspace-proxy deployment from CI. The dogfood
workspace proxies in Paris (`cdg`), Sydney (`syd`), and Johannesburg
(`jnb`) are no longer deployed via fly.io, and the São Paulo proxy
session-token secret was already unreferenced in `deploy.yaml`.

## Changes

- Deleted `.github/fly-wsproxies/{paris,sydney,jnb}-coder.toml`.
- Removed the `deploy-wsproxies` job from
`.github/workflows/deploy.yaml`,
along with its `workflow_call.secrets` block declaring the five `FLY_*`
  inputs.
- Removed the matching `secrets:` pass-through from the `deploy` job in
  `.github/workflows/ci.yaml`.

The Kubernetes/EKS dogfood deploy job and `should_deploy.sh` logic are
unchanged.

## Repository secrets that can now be deleted

Once this lands, the following GitHub Actions repository secrets are no
longer referenced anywhere in this repo and are safe to remove:

- `FLY_API_TOKEN`
- `FLY_PARIS_CODER_PROXY_SESSION_TOKEN`
- `FLY_SYDNEY_CODER_PROXY_SESSION_TOKEN`
- `FLY_JNB_CODER_PROXY_SESSION_TOKEN`
- `FLY_SAO_PAULO_CODER_PROXY_SESSION_TOKEN` (was already passed through
  but unused inside `deploy.yaml`)

Worth double-checking they aren't referenced by any other repos / org
workflows before deleting from the org/repo settings.

## Out of scope (intentionally left alone)

- `site/static/icon/fly.io.svg` — region icon, used at runtime for any
  user-deployed workspace proxy that picks the fly.io icon.
- `docs/install/other/index.md` — unofficial "Run Coder on Fly.io"
  community install entry, unrelated to our CI.
- `site/src/testHelpers/entities.ts` `*.fly.dev.coder.com` strings — UI
  test fixtures.

## Validation

- `python3 -c "yaml.safe_load(...)"` on both edited workflows.
- `make pre-commit` ran via the git hook on commit (actionlint,
shellcheck,
  typos, helm, markdown, etc. all green).
- Repo-wide grep confirms no remaining `FLY_`, `flyctl`, `fly.toml`, or
  `fly-wsproxies` references in `.github/` or `scripts/`.
2026-06-03 21:22:41 +10:00
Ethan 5088b5fa5f ci: extend flake-go bump test-count to 35 (#25981)
Two changes to make the `flake-go` workflow produce better signal when
something hangs or flakes at low rates.

**Job timeout (20m → 25m).** The Go-level `-timeout 20m` baked into
`make test` (`Makefile:1428`) currently raced the runner's 20m
hard-kill, so a hanging test got SIGTERM'd by Actions instead of
SIGQUIT'd by Go, and we never got the goroutine dump. Bumping the
workflow job to 25m mirrors the layering already used by `test-go-pg` in
`ci.yaml:409` and gives Go's timeout the 5m head start it expects.

**Test count (25 → 35).** Catches lower-frequency flakes that 25
attempts miss too often. For a 5% per-run flake, detection probability
goes from ~72% at n=25 to ~83% at n=35; for 1–2% flakes the lift is
larger. The longest successful flake-go run to date was 11m49s at n=25,
so n=35 should peak around ~16–17m and stay well inside the new 25m
budget.
2026-06-03 00:20:42 +10:00
Thomas KosiewskiandClaude Opus 4.8 f6a4ed309f ci: fix Windows runner PATH casing for mise, not in cli (#25972)
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-02 10:46:40 +00:00
Thomas KosiewskiandClaude Opus 4.8 550aa6d6a2 ci: install gotestsum in flake check workflow (#25934)
The Flake Check workflow runs `make test` through the `test-go-pg`
action, which invokes `gotestsum`, but the workflow never installs it.
The mise refactor (#25727) deleted the `setup-go` action that previously
installed `gotestsum` implicitly, and added explicit `mise install ...
go:gotest.tools/gotestsum` steps to every other Go test job. The flake
check's `Install Go mise tools` step only listed `whichtests`, so the
check fails with `gotestsum: command not found` whenever it selects
changed tests to run.

Add `go:gotest.tools/gotestsum` to the flake check's install step,
matching the other `test-go-pg` jobs in `ci.yaml` and
`nightly-gauntlet.yaml`.

Refs #25727

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-02 12:11:00 +10:00
Mathias Fredriksson ed4311b2cb ci: add Git usr/bin to PATH on Windows (#25939)
## Summary

Fixes all 9 Windows CI test failures caused by the mise CI refactor
(`fe257666d7`, PR #25727).

### Root cause

`jdx/mise-action` exports `Path` (Windows convention) via `GITHUB_ENV`.
Bash on Windows maintains its own `PATH`. When Go's `os.Environ()`
returns both, `cmd.exe` subprocesses non-deterministically pick the
MSYS-translated `PATH` (forward slashes), causing Windows executables
(`printf`, `powershell.exe`, `cmd.exe`) to be unresolvable.

These failures only appeared on `main` (where `-count=1` forces real
test execution) and were masked on PRs by Go test cache.

### Fixes applied

**CI (`setup-mise` action)**:
- Write both `Path` and `PATH` to `GITHUB_ENV` with Git usr/bin
prepended

**Code (`cli/root.go`)**:
- Add `appendAndDedupEnv` helper that deduplicates case-insensitive env
vars on Windows, preferring native Windows paths (backslashes) over MSYS
paths

**Code (`cli/configssh_windows.go`)**:
- Use absolute paths for `powershell.exe` and `cmd.exe` in the SSH
config `Match exec` escape function, avoiding PATH resolution entirely

**Tests**:
- Switch `--header-command` tests from `printf` to `echo` (cmd.exe
builtin) for reliable cross-platform execution
- Add env dedup in `Test_sshConfigMatchExecEscape` for subprocess PATH
consistency

Fixes coder/internal#1556, coder/internal#1558, coder/internal#1559

> 🤖 Generated by Coder agent, will be reviewed by @mafredri. 🏂🏻
2026-06-02 11:51:16 +10:00
Thomas Kosiewski fe257666d7 ci: refactor CI to use mise for shared tool setup (#25727) 2026-06-01 15:55:19 +02:00
Ethan 76d3181aba ci(.github/workflows): bump action-linkspector to v1.5.2 (#25882)
The `check-docs` job has been failing on every PR touching `docs/**`
since 2026-05-29. `umbrelladocs/action-linkspector` runs linkspector
under puppeteer, which expects an exact Chrome build (e.g.
`148.0.7778.97`) in `/home/runner/.cache/puppeteer`. When that build
isn't present on the hosted runner, linkspector crashes with `Could not
find Chrome` and reviewdog then fails parsing the empty rdjson output
with `proto: syntax error`.

The pinned `v1.4.1` of the action was installing linkspector `0.4.7`,
whose puppeteer requires `148.0.7778.97`; that build is no longer in the
runner cache. Upstream `v1.5.2` upgrades linkspector to `0.5.3` and adds
Chromium fallback logic, but on `ubuntu-22.04` x86_64 none of its new
code paths fire (the AppArmor branch is gated on `lsb_release -rs ==
"24.04"`, the system-Chromium branch on aarch64 or missing 24.04
sysctl), so the bump alone leaves the same Chrome error in place.

This PR:

- Bumps the action to `v1.5.2` (linkspector `0.5.3`).
- Sets `PUPPETEER_EXECUTABLE_PATH=/usr/bin/google-chrome` on the action
step. The hosted `ubuntu-22.04` image ships Google Chrome at that path.
`v1.5.2`'s `script.sh` short-circuits Chromium setup when this env is
set, so puppeteer skips the cache lookup and uses the runner binary
directly.

End-to-end verified by temporarily perturbing `docs/**` on this branch
so the workflow's `pull_request` trigger would fire:
https://github.com/coder/coder/actions/runs/26732938434. `check-docs`
ran linkspector against `docs/**` for ~2m30s and exited 0, with no
`Could not find Chrome` or reviewdog parse errors in the log. That
perturbation has been removed from the branch.

Refs UmbrellaDocs/action-linkspector#62,
UmbrellaDocs/action-linkspector#61
2026-06-01 13:42:37 +10:00
Nick Vigilante e32fdc813b ci: rerun docs preview job on subsequent pushes (#25456)
Fixes DOCS-174: the docs-preview workflow only fired on `pull_request:
opened`. Subsequent pushes left the preview comment stale.

## Changes

- Add `synchronize` and `reopened` to trigger types so subsequent pushes
retrigger the workflow.
- Add a workflow-level `concurrency` group keyed by PR number with
`cancel-in-progress: true` so rapid successive pushes don't race the
comment-upsert lookup.
- Replace always-create comment logic with an upsert: find the existing
comment containing `<!-- docs-preview -->` and PATCH it; fall through to
create only when none exists or the PATCH itself fails (comment was
deleted between find and update).
- Filter the upsert lookup to comments authored by `github-actions[bot]`
so a human comment containing the marker is never silently overwritten.
- Decouple the `gh api` lookup from the `head -n 1` pipe so API failures
(network, auth, rate-limit) propagate immediately instead of being
swallowed by `|| true`.
- Delete the stale preview comment when a `synchronize` push drops all
Markdown changes (e.g. a follow-up push that removes the file an earlier
push had previewed but still touches `docs/`). The previous preview
comment would otherwise point at a deleted page.
- Extract the marker and the comment-selector jq into a single
`DOCS_PREVIEW_MARKER` variable and a `list_docs_preview_comments` shell
function so the stale-cleanup and upsert branches share one source of
truth.

## Out of scope

Vercel ISR cache invalidation for feature branch previews requires a
coder.com change (the `algolia-docs-sync` endpoint only accepts `main`
and `release/*` refs). Tracked separately in DOCS-174 out-of-scope
notes.

Pulls that fully revert their `docs/` changes in a follow-up push won't
fire this workflow at all (GitHub's `paths` filter requires a path match
in the diff), so a stale preview comment can survive on that specific
edge. Removing the `paths` filter to handle it would run the workflow on
every PR push, which is disproportionate. Acknowledged in
[CRF-12](https://github.com/coder/coder/pull/25456#discussion_r3313738550).

<details>
<summary>Implementation notes</summary>

**Marker and selector deduplication**: The marker string and jq selector
previously appeared at three sites (comment body, stale-cleanup API
call, upsert API call). They're now consolidated into
`DOCS_PREVIEW_MARKER` plus a `list_docs_preview_comments` shell function
so a future marker change updates one place.

**Comment body construction**: The double-quoted multi-line string form
with escaped backticks (`` \` ``) for the inline-code spans is
shellcheck-clean. An earlier draft used `printf -v comment_body` with a
single-quoted format string containing backticks, which triggered
SC2016; the printf-three-pieces workaround that replaced it has since
been simplified to the direct double-quoted form.

**Upsert logic**: `gh api --paginate` fetches all PR comments, jq
filters to `github-actions[bot]`-authored comments containing the
marker, and the workflow PATCHes the first match. If the PATCH fails
(404 because the comment was deleted between find and update), the
script falls through to `gh pr comment` to create a new one. Self-heals
on the next push if both paths somehow fail.

**Stale-cleanup logic**: Same selector as upsert, but in the early-exit
branch when no Markdown files exist in this push. `DELETE` failures are
logged and execution continues (the next push will re-attempt or post a
fresh comment), so a transient API failure won't fail the CI job.

</details>

> Generated by Coder Agents on behalf of @nickvigilante
2026-05-28 10:03:21 -04:00
Danny KoppingandClaude Opus 4.7 f91390b2c8 ci: don't fail job if commenting on locked PR (#25765)
The final step of `.github/workflows/cherry-pick.yaml` comments on the
original PR with a link to the cherry-pick PR. If the original PR is
locked, `gh pr comment` fails and the whole job exits with status 1,
even though the backport branch and PR were created successfully.

See
https://github.com/coder/coder/actions/runs/26559681779/job/78239379200
for an example.

Make the comment non-fatal: log a warning and continue.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-28 13:26:04 +02:00
Mathias Fredriksson 673709bd34 ci(.github/workflows/doc-check): update agents-chat-action to v0.3.0 (#25784) 2026-05-28 11:16:34 +00:00
Ethan ca7f07142e ci: add Go test flake detector workflow (#25667)
Adds a `flake-go` workflow that hunts for ordering-dependent and racy Go
tests on pull requests. The workflow runs only on PRs (cancelling
earlier runs on new commits) and skips test execution when no Go test
files changed.

A single `flake_go` job uses
[coder/whichtests](https://github.com/coder/whichtests) with
`--coalesce` to compute the directly-modified `Test*` functions from the
PR diff and emit them as one target row. The same job then runs those
selected tests on a deliberately resource-constrained 4-vCPU runner with
4x parallelism oversubscription, `-count=25`, and `-shuffle=on` to
amplify contention and surface flakes.

Pinned at
[coder/whichtests@ec33bab](https://github.com/coder/whichtests/commit/ec33bab1ec04cd86beb7a61a069db4463dba63f5).

Reuses the `test-go-pg` composite (with its new `run-regex`,
`test-shuffle`, and `gotestsum-json-file` inputs) and the
`go-test-failure-report` composite, both introduced on the base branch
(#25670), so this workflow shares one implementation of the gotestsum +
failure-report path with the existing CI jobs.

`Makefile` adds `TEST_SHUFFLE` support and single-quotes `RUN` so
whichtests' regex survives shell parsing.

Stacked on top of #25670.

Demo @
https://github.com/coder/coder/actions/runs/26494322649/job/78018779381?pr=25667

Closes CODAGT-381
2026-05-28 12:35:37 +10:00
blinkagent[bot]andblink-so[bot] 1bfc1ce2c4 chore: update terraform to v1.15.5 (#25746)
Bumps bundled Terraform from `1.15.2` to `1.15.5` across all pinned
locations:

- `.github/actions/setup-tf/action.yaml`
- `scripts/Dockerfile.base`
- `install.sh`
- `flake.nix` (+ updated SRI hash for the linux_amd64 zip)
- `mise.toml`
- `mise.lock` (+ updated per-platform SHA256 checksums)
- `provisioner/terraform/testdata/version.txt`
-
`provisioner/terraform/testdata/resources/ai-tasks-disabled/ai-tasks-disabled.tfplan.json`

## Why

Terraform 1.15.5 is built with Go 1.25.10, while the 1.15.2 we currently
ship was built with Go 1.25.8. The newer Go runtime addresses recent
stdlib CVEs flagged by security scanners.

Releases included: 1.15.3 (provider install crash fix, nested-module
stack migration fix), 1.15.4 (Linux s390x builds, symlinked provider dir
fix), 1.15.5.

Release notes:
https://github.com/hashicorp/terraform/releases/tag/v1.15.5

## Cherry-pick

#25747 mirrors this PR against `release/2.34`.

Created on behalf of @Shelnutt2

Co-authored-by: blink-so[bot] <211532188+blink-so[bot]@users.noreply.github.com>
2026-05-27 16:46:25 -04:00
Garrett Delfosse 5991a2c8b0 ci: trigger CI on release branch creation (#25744)
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
2026-05-27 14:46:18 -04:00
Mathias Fredriksson 2730a87975 ci(.github/workflows/doc-check): update agents-chat-action to v0.2.0 (#25731) 2026-05-27 17:51:18 +03:00
Ethan f422ac89cc ci: extract go-test-failure-report composite action (#25670)
The Go test jobs in `ci.yaml` each had ~30 lines of inline shell that
wrapped `gotestsum` with a PATH shim to capture JSON, then ran
`gotestsummary` and `upload-artifact` to publish a failure report. Three
jobs carried three near-identical copies.

This change replaces the three inline blocks with a single composite
action at `.github/actions/go-test-failure-report/` that runs the same
`gotestsummary` invocation, writes the same markdown to
`GITHUB_STEP_SUMMARY`, and uploads the same NDJSON artifact. The PATH
shim is gone; gotestsum's native `GOTESTSUM_JSONFILE` env variable is
used instead, plumbed through the `test-go-pg` composite.

`test-go-pg` gains three optional inputs:

- `gotestsum-json-file` — explicit JSON file path (or `default` for
`${RUNNER_TEMP}/go-test.json`)
- `run-regex` — passed to `go test -run`
- `test-shuffle` — passed to `go test -shuffle`

All three have safe defaults so existing callers are unaffected.

No observable change in CI behavior: the three existing test-go-pg jobs
continue to emit the same JSON, render the same failure summary, and
upload the same artifact.

Stacked under #25667, which uses the new composite and inputs to power a
new flake-detector workflow.
2026-05-28 00:16:46 +10:00
Ethan e99f7171e4 ci: require docs lint when docs change (#25608)
Move docs linting into the required CI umbrella and reuse the existing
`changes` job so docs lint runs when docs or CI files change, plus on
`main` as a backstop.

This is motivated by the docs lint failures on #25601. That PR touched
`.claude/docs/TESTING.md`; the standalone `Docs CI` workflow picked it
up because `docs-ci.yaml` used broad `**.md` matching, but local `pnpm
lint-docs` and `make lint` did not catch the same file because they only
scanned `docs/**` plus root `*.md`. The first failed Docs CI run
reported markdownlint errors in `.claude/docs/TESTING.md` (`MD040` and
`MD031`), and the next run reported a markdown table formatter failure
in the same file.

That mismatch is why this PR exists: prevent unrelated PRs from being
surprised by stale `.claude/docs/**` lint drift only after they happen
to touch one of those files. The local docs scripts now include
`.claude/docs/**`, and the old standalone `Docs CI` workflow is removed
so we do not maintain separate path-filter logic outside the required CI
workflow.

> Generated by mux, but reviewed by a human
2026-05-27 12:30:05 +10:00
Thomas KosiewskiandClaude Opus 4.7 51836e681e refactor: build dogfood image as base + mise oci layers (#25448)
Splits the dogfood image into two artifacts:

- `ghcr.io/coder/oss-dogfood-base:<distro>-<base-sha>`: Ubuntu base with
apt packages, chrome, rustup, brew, gh, and the mise binary. The
base-sha is a cache key over `Dockerfile.base` and `files/`, so commits
that don't touch those inputs reuse the previous build.
- `codercom/oss-dogfood:<final-sha>-<distro>` and rolling tags
(`:22.04`, `:26.04`, `:latest`, `:<branch>`): produced by `mise oci
build` on top of the base, with one content-addressed OCI layer per mise
tool. The rolling tag scheme is unchanged, so the workspace template
doesn't need updating.

Single-tool version bumps now invalidate only that tool's OCI layer, so
workspaces re-pull just what changed instead of the entire 5-6 GB image
on every recreate.

Also:

- Drops the build-time `pnpm dlx playwright@1.47.0 install --with-deps
chromium` step (~400 MB) and the equivalent `playwright-driver.browsers`
install from `flake.nix`. `@playwright/mcp` (used by the claude-code and
codex MCP servers in `dogfood/coder/main.tf`) does NOT auto-install
browsers, so the existing `install-deps` `coder_script` now runs two
installs on workspace start: `pnpm exec playwright install chromium` for
the site's pinned `@playwright/test`, and `npx
--package=@playwright/mcp@latest playwright-core install --no-shell
chromium` so the MCP servers find their matching browser revision.
Browser revisions coexist under
`~/.cache/ms-playwright/chromium-<rev>/`, which lives on the home volume
so both downloads happen once per workspace recreate and persist across
restarts. Net effect: same MCP behavior as before, +~1-2 min on first
workspace start. Nix devshell users running site e2e tests locally now
need `pnpm exec playwright install` once (instead of getting browsers
via nixpkgs).
- Bumps the pinned mise binary to v2026.5.12 (matching main after
#25521) and adds top-level `min_version = "2026.5.12"` to `mise.toml` so
every consumer (devs, CI, the embedded mise inside the dogfood image,
mise oci builds) fails fast on an older mise.
- Adds bison, flex, libicu-dev, libreadline-dev, uuid-dev, and
zlib1g-dev to both Ubuntu base images for source-build use cases (e.g.,
building Postgres from source).
- Replaces skopeo with crane as the registry client `mise oci push`
shells out to: crane is added to `mise.toml`, the workflow drops its
`apt-get install skopeo` and forces `--tool crane`, and the local
wrapper image stops bundling skopeo. One source of truth for tool
versions, no apt drift, smaller wrapper image, and workspace users get a
registry client on PATH for free via mise oci's tool layers.
- Removes `nix.hash`/`mise.hash` and their Makefile rules. The registry
digest already captures every effective change since CI rebuilds when
any baked-in input moves; the per-file `filesha1()` entries in
`pull_triggers` are redundant.

Supersedes #25400 (the `mise.hash` pull trigger landed there in
`2b612abe7b`; this PR removes it as part of the broader simplification).

> [!NOTE]
> `mise oci build` is experimental and requires `MISE_EXPERIMENTAL=1`
(set at job level in the workflow). The local-only
`scripts/dogfood/mise-oci-wrapper.sh` builds a tiny
`coderdev/mise-oci-wrapper:<version>` Debian image with curl-installed
mise on first invocation (cached by version tag thereafter); we don't
reuse `jdxcode/mise:latest` because that tag lags upstream GitHub
releases by days and would defeat the `min_version` enforcement above.

> [!NOTE]
> `compute-base-sha.sh` and `compute-final-sha.sh` are cache keys, not
strict content addresses: the base Dockerfile still pulls dynamic
resources at build time (gh/buildx `releases/latest`, chrome
`stable_current_amd64.deb`, apt mirror state). Two runs with identical
checked-in files can produce slightly different bytes, which is
acceptable here because the cache-hit savings on irrelevant commits
outweigh that drift.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Signed-off-by: Thomas Kosiewski <tk@coder.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-26 14:52:21 +02:00
Cian Johnston 579daaff70 feat: add GitLab support to coderd/externalauth/gitprovider
Fixes CODAGT-146

Add GitLab support to the gitprovider package for gitsync/chatd PR
diff flows. This is a squashed stack of 3 PRs:

#25651 - refactor(coderd/externalauth): prepare gitprovider for multi-provider support
- Change gitprovider.New to return (Provider, error)
- Extract shared helpers (parseRetryAfter, checkRateLimitError,
  countDiffLines, escapePathPreserveSlashes) from github.go
- Update all callers (db2sdk, exp_chats, gitsync) for new signature
- Add error logging for provider construction failures
- Thread context through provider resolution

#25652 - feat(coderd/externalauth/gitprovider): add GitLab provider
- Implement full Provider interface: FetchPullRequestStatus,
  FetchPullRequestDiff, FetchBranchDiff, ResolveBranchPullRequest
- Handle nested groups, forks, and self-hosted instances
- Rate limit detection on both library and raw HTTP paths
- URL parsing/building with NormalizePullRequestURL support
- Unit tests covering error paths, URL parsing, state mapping
- Document GitLab configuration and known limitations

#25653 - test(coderd/externalauth/gitprovider): add GitLab VCR integration tests
- FetchPullRequestStatus: 4 fixtures (open, conflicts, merged, closed)
- FetchPullRequestDiff: 4 fixtures
- FetchBranchDiff: 3 fixtures (open, deleted, fork)
- ResolveBranchPullRequest: 3 fixtures
- go-vcr cassettes with sanitized GitLab API responses
2026-05-25 17:41:02 +01:00
Cian Johnston 0a45f96d30 ci: validate dogfood image tooling by running gen, fmt, lint, build (#25475)
Adds a `test_image` job that runs `make gen`, `make fmt`, `make lint`, and `make build` inside the
newly built image via `docker run`. This helps detect breaking changes before merge. 

> [!NOTE]
> Generated with [Coder Agents](https://coder.com/agents)
2026-05-25 17:02:13 +01:00
Mathias Fredriksson 471249f3e2 ci: migrate doc-check workflow to coder/agents-chat-action (#25178)
Replace the inline `curl` + `jq` block in
`.github/workflows/doc-check.yaml` with a single `uses:
coder/agents-chat-action` step.

Closes CODAGT-375
2026-05-22 19:09:36 +03:00
Nick Vigilante 5840ac5f6e ci(.github/workflows/docs-ci.yaml): scope changed-files per tool (#25317)
## Problem

`Docs CI` fails on PRs that only touch binary assets under `docs/`.
Example: [#25314](https://github.com/coder/coder/pull/25314), which
swaps a single PNG and produces thousands of `MD010/no-hard-tabs`,
`MD049/emphasis-style`, and `MD018/no-missing-space-atx` errors at
columns like 16,285 of the image.

## Root cause

The single `tj-actions/changed-files` step was doing two jobs at once:
detecting which Markdown files changed (for `lint` and `fmt`), and
gating whether the workflow had anything to do at all. Its `files`
filter matched `docs/**` in addition to `**.md`, so any non-Markdown
file under `docs/` (PNG, GIF, JPG, MP4, SVG) ended up in
`all_changed_files` and was passed straight to `markdownlint-cli2`,
which opened the file and parsed the binary bytes as Markdown.

`markdownlint-cli2`'s own `ignores` setting is a discovery-time filter
and does not gate files passed explicitly on the command line, so the
filtering has to happen in the caller.

## Fix

Adopt a per-tool convention: each downstream tool gets its own
`changed-files` step scoped to the files that tool can process. For now
that is a single `changed-md` step matching `**.md`, consumed by `lint`
and `fmt`. A future tool (e.g. an image linter, video size check, or
link checker) can be added purely additively, by appending another
`changed-*` step and a step that consumes its output, without changing
the existing filters.

The workflow-level `on.push.paths` / `on.pull_request.paths` triggers
stay broad (`docs/**`, `**.md`) so the workflow still runs on
screenshot-only PRs; the per-tool filters decide which individual steps
execute. On a screenshot-only PR the existing `if:
steps.changed-md.outputs.any_changed == 'true'` guard skips `lint` and
`fmt` cleanly.

## Verification

- `actionlint .github/workflows/docs-ci.yaml` passes.
- Reproduced the original failure locally: `pnpm exec markdownlint-cli2
docs/images/install/install_from_deployment.png` produces the same flood
of violations seen in the failing CI run on #25314.
- First revision of this PR (workflow with `**.md`-only filter, single
`changed-files` step) was green on `Docs CI`; the current revision is
structurally equivalent for the existing tools and just renames the step
id and adds the per-tool comment.

<details>
<summary>Decision log</summary>

- Considered adding `ignores` to `.markdownlint-cli2.jsonc` to skip
non-Markdown files. Rejected: `markdownlint-cli2` treats `ignores` as a
discovery-time glob filter and still lints files passed explicitly on
the command line, so it would not have fixed the failure.
- Considered narrowing the existing single `changed-files` step's
`files` filter to `**.md` only. Rejected as the final shape: it solves
the immediate bug but conflates "which Markdown files changed" with
"should the workflow run at all", so adding a second tool with a
different file set later (e.g. an image linter) would require contorting
or duplicating that step.
- Chose the per-tool-filter shape so adding a future tool is additive:
one new `changed-*` step plus one new step that consumes its output,
with no edits to existing steps.

</details>

## Disclosure

Opened on behalf of @nickvigilante by Coder Agents.
2026-05-15 10:15:25 -04:00
Nick Vigilante aa87d55a6d ci(.github/workflows): audit workflow self-references in paths (#25288)
Three workflows besides `deploy-docs.yaml`
([DOCS-124](https://linear.app/codercom/issue/DOCS-124),
[#25285](https://github.com/coder/coder/pull/25285)) self-reference in
their `paths:` triggers: `docker-base.yaml`, `docs-ci.yaml`,
`dogfood.yaml`. This was flagged during review of #25285
([DEREM-1](https://github.com/coder/coder/pull/25285#discussion_r3234975475))
as a bug class worth treating uniformly. This PR is the audit.

Each self-reference is either justified inline or removed:

* **`docker-base.yaml`** keeps the self-reference. It's PR-only and
gated by `push: ${{ github.event_name != 'pull_request' }}` on the
`depot/build-push-action`, so PRs build the base image without
publishing.
* **`docs-ci.yaml`** drops the self-reference. The `lint` and `fmt`
steps gate on `tj-actions/changed-files` matching `docs/**` or `**.md`,
so a workflow-only run no-ops. `actionlint` and `make lint/actions`
catch YAML problems before merge regardless.
* **`dogfood.yaml`** keeps the self-reference. PR runs build images
without pushing and run `terraform init` + `validate` only; pushes to
main retag rolling tags on `codercom/oss-dogfood`,
`oss-dogfood-vscode-coder`, and `oss-dogfood-nix`, plus `terraform
apply` against dev.coder.com which produces new `coderd_template`
versions with unchanged content. Idempotent and bounded.

Refs DOCS-121, DOCS-129.

<details>
<summary>Decision table</summary>

| Workflow | Self-ref location | Effect on workflow-only edit | Decision
|
|---|---|---|---|
| `deploy-docs.yaml` | push + workflow_dispatch | Destructive (DOCS-121)
| Removed in [#25285](https://github.com/coder/coder/pull/25285) |
| `docker-base.yaml` | PR-only | Build base image, never push | Keep
with inline comment |
| `docs-ci.yaml` | push + PR | Empty run; lint/fmt skipped by `if:` |
Remove (wasted runner minutes) |
| `dogfood.yaml` | push + PR | PR: build without push, terraform
validate. Main: retag rolling tags, terraform apply, new cosmetic
template versions | Keep with inline comment |

</details>

---
_Coder Agents on behalf of @nickvigilante._
2026-05-15 08:49:17 -04:00
Nick Vigilante 81b6132e02 fix(.github/workflows/deploy-docs.yaml): drop self-trigger from paths (#25285)
Edits to `.github/workflows/deploy-docs.yaml` previously self-triggered
the workflow on push to `main` and `release/*` because the file was
listed in its own `paths:`. On 2026-05-12, this caused merge of #25049
to fire a production reindex with no `docs/**` changes, which entered
the empty-`paths_json` whole-branch path in the Algolia handler and
wiped the `docs` index (see DOCS-121).

This change removes `.github/workflows/deploy-docs.yaml` from `paths:`
so the workflow only runs against real docs content. Reindexes from a
workflow edit alone now require `workflow_dispatch`, which already
accepts a `ref` input and an `action` choice of `index` or `delete`. The
other safety net (a workflow-level `paths_json=[]` guard in
`algolia-and-isr`) is tracked separately in DOCS-122.

Refs DOCS-121, DOCS-122, DOCS-124.

---
_Coder Agents on behalf of @nickvigilante._
2026-05-15 08:48:48 -04:00
Thomas KosiewskiandClaude Opus 4.7 5f9b3220b5 chore: install dogfood image tooling via mise.toml (#25282)
This PR replaces the hand-rolled `curl | tar | go install | cargo
install` chains in the dogfood Ubuntu 22.04 and 26.04 Dockerfiles with a
single `mise install` driven by a new repo-root `mise.toml`.

The previous Dockerfiles installed ~25 CLIs across three multi-stage
builds with versions hardcoded inline. Version bumps were scattered
across the Dockerfiles, the root `mise.toml` (added in #24618 but
otherwise unused at runtime), and CI's setup actions; build-time network
failures came from a dozen distinct endpoints; and `mise` itself sat in
the image with no manifest to install from.

The new flow:

- The repo's `mise.toml` is the single source of truth for image tool
versions. The Dockerfiles `COPY` it to `/etc/mise/config.toml` and run a
single `mise install` as the `coder` user.
- Tools are installed into `/opt/mise/data` rather than the default
`/home/coder/.local/share/mise`, so they live in the image (not on the
persistent home volume) and reach every workspace on recreate.
- Build context moves to the repo root so the Dockerfile can `COPY
mise.toml`; an allowlist `.dockerignore` keeps the transferred context
to ~24 kB.
- Optional `--secret id=github_token` plumbing through the Makefile and
`.github/workflows/dogfood.yaml` lifts aqua's GitHub API quota from
60/hr unauthenticated to 1000/hr with `secrets.GITHUB_TOKEN`.
- `MISE_TRUSTED_CONFIG_PATHS=/home/coder:/etc/mise` is set as an ENV so
users who clone the coder repo into their workspace home aren't prompted
to `mise trust`.

Net diff for the two Ubuntu Dockerfiles: -399 / +244 lines (~200 lines
shorter each). The `FROM rust-utils`, `FROM go`, and `FROM proto`
multi-stage builds are gone; so are the NVM/Node block, the bulk
binary-install block (golangci-lint, helm, kubectx, syft, cosign, bun),
the gh `.deb`/lazygit/doctl tarball installs, the gofmt
`update-alternatives` line, and the `yq`→`yq4` rename
(`scripts/lib.sh:267-275` already auto-detects either name).

Both images were built and smoke-tested with Apple's `container` CLI on
macOS — every migrated tool resolves to the expected pinned version
including outside the cloned coder repo (e.g. `gh` from `/home/coder`,
matching the workspace startup script in `dogfood/coder/main.tf`),
`sqlc` runs (proving `CGO_ENABLED=1` was honoured at install), `yq
--version` reports v4 for `scripts/lib.sh`'s detection, and `gofmt`
resolves via the mise shim.

Follow-ups (out of scope here):

- Commit a multi-platform `mise.lock` so `gh = "latest"` and the other
floating versions resolve deterministically across rebuilds and dev
machines.
- Migrate CI's `setup-go` / `setup-node` actions to consume `mise.toml`
so image and CI versions stop being able to drift.

---------

Signed-off-by: Thomas Kosiewski <tk@coder.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 11:36:22 +02:00
Spike Curtis 132fa87bf3 fix: only embed Azure roots on darwin (#25312)
Partially reverts #25136 for non-darwin platforms.

In general we want to avoid pinning trust roots to embedded Certs, since that limits operational flexibility. If Azure changes CAs, operators should, at most, be able to update the OS trust store to keep Coder working correctly. Embedding roots means we need to upgrade the Coder binary.

Since Coder Server on macOS is not really supported for production use, embedding only in that case to ease development and testing is OK.
2026-05-14 11:45:21 -04:00
Thomas Kosiewski f71bccf53f ci(.github/actions/setup-node): verify active Node version (#25143)
Updates the shared setup-node composite action to current Node 24 based
releases of `pnpm/action-setup` and `actions/setup-node`. This avoids
the deprecated Node 20 action runtime seen in CODAGT-178 while keeping
the third-party actions pinned by SHA.

Adds an explicit post-setup check that fails inside Setup Node when
`node --version` is not `v22.19.0`, so self-hosted runner/toolcache
mismatches are surfaced before `pnpm install` reports a dependency
engine error.

Closes https://github.com/coder/internal/issues/1457

Generated by Coder Agents.
2026-05-14 12:07:09 +02:00
Ethan 8955599bd0 fix: bump sqlc fork to v1.31.1 merge, strip pg_dump meta-commands (#25105)
Closes https://github.com/coder/internal/issues/965

Recent `pg_dump` patch releases (13.22+ / 14.19+ / 15.14+ / 16.10+ /
17.6+) emit `\restrict` / `\unrestrict` psql meta-commands at the head
and tail of schema dumps. These broke both `sqlc` and our
`scripts/migrate-test` schema-equality check. PR #19696 worked around it
by pinning `pg_dump` to a Docker image.

This change unpins the workaround now that `sqlc` handles the
meta-commands:

* Bumps the coder/sqlc fork pin to [`337309b` on
coder/sqlc:main](https://github.com/coder/sqlc/commit/337309bfb9524f38466a5090e310040fc7af0203),
the merge of upstream v1.31.1 (coder/sqlc#6). v1.31.1 includes
[sqlc-dev/sqlc#4390](https://github.com/sqlc-dev/sqlc/pull/4390), the
upstream `\restrict` / `\unrestrict` parser fix. Updated in three places
that pin the fork SHA: `flake.nix` (`sqlc-custom`),
`.github/actions/setup-sqlc/action.yaml`, and the
`dogfood/coder/ubuntu-{22,26}.04` Dockerfiles. The flake's `sha256` /
`vendorHash` are reset to `pkgs.lib.fakeSha256`; Nix will surface the
real hashes on first build, per the existing comment block.
* Reverts #19696's Docker pin in `coderd/database/dbtestutil/db.go`.
Local `pg_dump` (13+) and the `postgres:13` Docker fallback both work
again.
* Strips `\restrict` / `\unrestrict` lines in `normalizeDump` so
`scripts/migrate-test`'s schema comparison is stable across `pg_dump`
versions (the token in those lines is randomized per run).
`TestNormalizeDumpStripsRestrict` locks the behavior in.
* Regenerates with v1.31.1, picking up the version stamp and one
upstream correctness fix in `DeleteLicense`
([sqlc-dev/sqlc#4383](https://github.com/sqlc-dev/sqlc/pull/4383): don't
shadow the input parameter when scanning a single-column return).
2026-05-13 18:55:24 +10:00
Nick Vigilante 36d52ba504 feat(.github/workflows): trigger Algolia, ISR, and Vercel deploy on docs/** changes (#25049)
Folds the Algolia/ISR sync trigger and surgical-reindex path computation
into the existing `deploy-docs.yaml` workflow so a single `docs/**` push
fires every update path the docs site needs.

One preflight job feeds two parallel sibling jobs:

- **`changes`** (preflight): diffs `github.event.before` against
`github.sha` to compute `manifest_changed` and `paths_json` (a JSON
array of `{path, status}` objects derived from `git diff --name-status
-z`, capped at 50 entries). The mapping is `A → added`, `M/T →
modified`, `D → deleted`, `R<n> → renamed` (indexed by the new path).
Falls back to whole-branch (emits `paths_json: "[]"`) on
`workflow_dispatch`, the first push to a new branch, fetch failure,
manifest changes (route restructuring would orphan records), or >50
markdown files.
- **`algolia-and-isr`** (always, parallel with `vercel-rebuild`):
HMAC-signed POST to `coder.com/api/algolia-docs-sync` with the
`paths_json` array as part of the body. Refreshes the Algolia `docs`
slice for the `(corpus, ref)` pair and ISR-revalidates every navigable
route the handler touched. Markdown-only edits surface in seconds with
no full rebuild. The step summary line `Mode: \`surgical\` (N path(s))`
lets operators verify which path ran without scrolling through the curl
output.
- **`vercel-rebuild`** (parallel with `algolia-and-isr`, only when
`docs/manifest.json` changed): fires the existing Vercel deploy hook for
a full build. Manifest changes can register or remove routes that
Next.js's `getStaticPaths` only re-evaluates on a full build, so
ISR-per-existing-path is not enough.

Trigger expanded from "main + manifest.json" to "main and `release/*` +
any `docs/**`" so release-branch docs edits also flow through the same
pipeline. The Vercel rebuild path stays gated on manifest changes
regardless of branch.

The pure shell + curl + openssl + jq + awk pipeline is preserved
verbatim. Zero Algolia or Node dependencies in CI.

## Why one workflow instead of two

The original split (a standalone Algolia workflow + the existing
`deploy-docs.yaml`) would have run twice per manifest push, with two
parallel concurrency groups, two GitHub Actions step summaries, and two
ways to forget to add a secret. Folding into one file makes the trigger
story symmetrical: "docs change → all docs surfaces refresh," with the
rebuild path being a strict superset of the ISR path, and the surgical
path strictly cheaper than whole-branch when computable.

## Pre-merge testing

The companion handler PR (coder/coder.com#741) supports an
`ALGOLIA_DOCS_INDEX` env-var override, scoped to `docs_smoke` on the
Vercel preview deploy, so this workflow can be exercised end-to-end
against a disposable index without touching production records. The
smoke harness at `~/audit/smoke/run.sh` (workspace-only) signs and posts
the same body shape this workflow does, so it covers the same crypto
path. To exercise the workflow itself, push a docs-only commit to a
throwaway branch and watch the step summary; the `algolia-and-isr` job
will print the resolved mode.

## Prerequisites before this can do anything useful

1. `secrets.ALGOLIA_DOCS_SYNC_SECRET` must be added as an Actions secret
on this repo. The same value goes on `coder.com`'s Vercel env. The
workflow logs a clear error and aborts with no network call if the
secret is missing.
2. The handler at coder/coder.com#741 must be merged and deployed.
Without it, the POST will 404.
3. `secrets.DEPLOY_DOCS_VERCEL_WEBHOOK` is already in place from the
existing `deploy-docs.yaml`; this PR does not change its usage.

## Demo, validation, and design

- Front-end-only fixes (modal layout, scroll-shadow, rank-order
preservation): coder/coder.com#749 ships these against production today,
independent of this PR.
- Companion handler PR on `coder.com`: coder/coder.com#741. Includes the
surgical-mode plumbing this workflow's `paths_json` output drives.
- Full design lives in the workspace at
`~/plans/algolia-search-revamp.md`. Key sections:
  - §6.0–6.2: why the indexer lives in `coder.com`, not here.
  - §6.7: per-version add/remove mechanics.
  - §6.8: ISR revalidate rationale and same-time refresh.
- §6.9: surgical per-page reindex (workflow + handler + planning rules).

---

This PR was generated by Coder Agents.
2026-05-12 14:18:31 -04:00
Michael Suchacz bb8c40e764 feat: stream go test failure summary and drop raw json artifact (#25146)
This follows up on
https://github.com/coder/coder/actions/runs/25684936801/job/75406131184?pr=25139
by replacing the large raw Go test JSON artifact with inline structured
summaries and a compact failures-only artifact.

## What changed

- Added `scripts/gotestsummary`, a streaming Go tool that reads
gotestsum JSON and renders failed tests as Markdown.
- Updated the three Go test jobs to publish per-test `<details>`
sections in the job summary.
- Removed upload of the raw `go-test.json` artifact.
- Added upload of `go-test-failures-*.ndjson` with compact failure
records for deeper inspection.
- Deleted the old bash and `jq` summary script.

## Why

- The previous raw artifact was about 35 MB compressed and 445 MB raw in
the linked run.
- Passing-test output made the artifact noisy and slow to inspect.
- The old summary truncated output to 600 characters.
- The new path keeps streaming, bounded output and writes structured
diagnostics for only final failed tests.

## Validation

- `gofmt -w scripts/gotestsummary`
- `gofmt -l scripts/gotestsummary`
- `go test ./scripts/gotestsummary/...`
- `go vet ./scripts/gotestsummary/...`
- `grep -rn 'go-test-failure-summary.sh' . || true`
- `grep -rn 'go-test-failure-summary.sh\|go-test.json\|go-test-json-'
.claude .agents docs AGENTS.md || true`
- `make lint/agents`
- `make lint/emdash`
- `make lint/markdown`
- `make lint/shellcheck`
- `git diff --check origin/main..HEAD`

> This PR was prepared by Mux working on Mike's behalf.
2026-05-12 00:08:37 +02:00
Michael Suchacz 85792d08bc feat: add harness engineering layer for agent workflows (#24791)
This PR adds an opinionated harness-engineering layer for agent-driven
workflows: a small set of agent-readable docs, mechanical structure
checks, structured CI failure summaries, an architecture-lint umbrella,
and per-worktree dev-server isolation. The goal is to make local dev,
tests, and CI mechanically inspectable by agents without changing app
runtime behavior.

## What landed

**Agent docs and navigation**
- `.claude/docs/OBSERVABILITY.md`, `.claude/docs/DEV_ISOLATION.md`,
`.claude/docs/AGENT_FAILURES.md`: task-oriented guides for logs,
tracing, Prometheus, dev-server isolation, and a seeded failure catalog.
- `AGENTS.md`: added an `Agent navigation` block, then trimmed the file
from 375 to 229 lines by migrating duplicated detail into
`WORKFLOWS.md`, `GO.md`, `TESTING.md`, and `DATABASE.md`. The
user-managed custom-instructions block is preserved.
- `.agents/docs`: symlink mirror of `.claude/docs` for agent runtimes
that look under `.agents`.

**Mechanical checks**
- `scripts/check_agents_structure.sh`: validates `@...` references in
tracked `AGENTS.md` files and warns when root grows past 600 lines.
Wired as `make lint/agents` and into `make lint`.
- `scripts/audit-agent-readiness.sh`: report-first audit of harness
readiness. Currently `10 ok, 0 warn, 0 fail`.
- `scripts/check_architecture.sh` / `make lint/architecture`: umbrella
architecture-lint target. Consolidates the existing
`check_enterprise_imports.sh` and `check_codersdk_imports.sh` so they
run exactly once via the umbrella. Slot is open for new high-confidence
rules.

**Structured CI failure summaries**
- `scripts/playwright-failure-summary.sh`: parses
`site/test-results/results.json` and writes Markdown to
`$GITHUB_STEP_SUMMARY` on failure. Wired into the `test-e2e` matrix job.
- `scripts/go-test-failure-summary.sh`: parses `go test -json`
line-delimited output the same way. Wired into `test-go-pg`,
`test-go-pg-17`, and `test-go-race-pg` by injecting `gotestsum
--jsonfile` in the workflow without touching `Makefile`. JSON also
uploaded as a CI artifact on failure.
- `site/e2e/playwright.config.ts`: enables `screenshot:
only-on-failure`, `trace: retain-on-failure`, JSON reporter, and HTML
reporter alongside existing reporters.
- `.github/workflows/ci.yaml`: failure artifact uploads for Playwright
now use `if: failure()` and predictable names
(`playwright-artifacts-<variant>-<sha>`).

**Per-worktree dev-server isolation** (`scripts/develop/main.go`)
- Deterministic FNV-64a hash of the worktree path produces a port offset
in `[0, 1000)` (50 buckets, step 20 to avoid API/proxy overlap across
adjacent buckets).
- Offset is applied only to defaults; both env vars (`CODER_DEV_PORT`,
`CODER_DEV_WEB_PORT`, `CODER_DEV_PROXY_PORT`,
`CODER_DEV_PROMETHEUS_PORT`) and CLI flags retain priority.
- Hardcoded ports `9090` (embedded Prometheus UI) and `12345` (Delve)
are unchanged by design.
- Startup banner shows each port's source: `default`, `offset`, or
`explicit`.
- Unit tests in `scripts/develop/main_test.go` cover determinism,
bounds, no-overlap across the four ports, and explicit-skip behavior.
- State (`.coderv2/`) was already worktree-isolated via `os.Getwd()`, so
no state-dir changes were needed.

## Validation

`make lint/agents`, `make lint/architecture`, `make lint/emdash`, `bash
scripts/audit-agent-readiness.sh` (10 ok, 0 warn, 0 fail), `shellcheck`
on all 5 new scripts, `go test ./scripts/develop/...`, and `js-yaml`
parse of `ci.yaml` all pass. Synthetic fixtures verify both
failure-summary scripts handle empty/missing input (silent exit 0),
ANSI-stripped output, and parent/subtest formatting.

## Known follow-ups (deferred)

- Frontend Storybook/Vitest failure summary: lowest-leverage slice of
the failure-summary work. Skipping until observed pain.
- Architecture lint currently only delegates to existing import checks;
new rules (`InTx` outer-store detection, swagger-annotation lint) plug
in as needed.
- 50 port-offset buckets means two worktree paths can occasionally
collide. The DEV_ISOLATION doc tells users to set the relevant env var
when this happens.

> Mux opened this PR on Mike's behalf.
2026-05-11 17:27:29 +02:00
Jiachen Jiang e9f0385198 docs: update AI Governance label and add v2.32 requirement (#24708)
## Summary

Replace the "Premium" label with "AI Governance Add-On" and add a
disclaimer that the AI Governance Add-On is required for AI Gateway and
Agent Firewall as of Coder v2.32, across all AI Governance doc pages and
their children.

## Changes

**Label and requirement updates (7 files):**
- `docs/ai-coder/ai-governance.md`: Removed "(Premium)" from title;
updated GA section to state add-on required as of v2.32.
- `docs/ai-coder/ai-gateway/setup.md`: "Premium license" → "AI
Governance Add-On license".
- `docs/ai-coder/ai-gateway/ai-gateway-proxy/setup.md`: "Premium
license" → "AI Governance Add-On".
- `docs/ai-coder/ai-gateway/clients/claude-code.md`: "(Premium feature)"
→ "(AI Governance Add-On)".
- `docs/manifest.json`: `"state": ["premium"]` → `"state": ["ai
governance add-on"]` for 4 nav entries.

**Disclaimer added to all child pages (26 files):**

AI Gateway pages (18):
`index.md`, `setup.md`, `audit.md`, `monitoring.md`, `mcp.md`,
`reference.md`, `ai-gateway-proxy/index.md`,
`ai-gateway-proxy/setup.md`, `clients/index.md`,
`clients/claude-code.md`, `clients/codex.md`, `clients/mux.md`,
`clients/opencode.md`, `clients/factory.md`, `clients/cline.md`,
`clients/kilo-code.md`, `clients/roo-code.md`, `clients/vscode.md`,
`clients/jetbrains.md`, `clients/zed.md`, `clients/copilot.md`

Agent Firewall pages (8):
`index.md`, `version.md`, `landjail.md`, `rules-engine.md`,
`nsjail/index.md`, `nsjail/docker.md`, `nsjail/k8s.md`, `nsjail/ecs.md`

Other: `security.md`

> [!NOTE]
> The `"ai governance add-on"` state value in `manifest.json` is new.
The docs site renderer may need to be updated to support this state
value.

> Generated by Coder Agents
2026-05-07 17:09:54 -05:00
Jon Ayers ffe2595f63 fix: scan coder-preview:main instead of coder:latest (#25056) 2026-05-07 18:15:26 +00:00
Jon Ayers eef09f3d98 chore: update terraform to v1.15.2 (#25045) 2026-05-07 11:07:19 -05:00
Atif Ali 3d03c393d2 chore: bump Go toolchain version to 1.26.2 (#24975)
## Summary
Bumps the repository Go toolchain from 1.25.9 to 1.26.2 across local
development, CI, dogfood Docker images, and Nix builds.

## Changes
- Update `go.mod` and the shared setup-go action to Go 1.26.2.
- Update dogfood Ubuntu image Go versions and the official linux-amd64
tarball checksum.
- Move Nix Go module builds from `buildGo125Module` to
`buildGo126Module`.
- Regenerate API docs affected by Go 1.26 stdlib URL documentation
changes.

## Validation
- `./scripts/check_go_versions.sh`
- `make fmt`
- `make lint`
- `make build-slim`
- `make test TEST_SHORT=1`
- `make pre-commit`

> 🤖 This PR was created with the help of Coder Agents, and needs a human
review. 🧑💻
2026-05-06 17:06:07 +05:00
Atif Ali 4385cabf6d chore: bump to refactored Claude and Codex modules (#24981)
Bumps the dogfood template to the refactored Claude Code and Codex
modules and removes the Coder Tasks integration.

Claude and Codex now use slim-window app buttons that launch each tool
in its own tmux session. This replaces the task-specific `develop.sh`
and `preview` apps that were only created for Coder Tasks workspaces.

The PR also wires the OpenAI dogfood secret through the deployment
template so Codex can fall back to template configured BYOK when AI
Gateway is disabled.

Tested with this template version:
[https://dev.coder.com/templates/coder/coder/versions/outstanding_hermann97](<https://dev.coder.com/templates/coder/coder/versions/outstanding_hermann97>)
2026-05-06 17:05:34 +05:00
david-fraley 27b527dc7f ci(.github/workflows/docs-preview.yaml): deep-link preview to first changed page (#24832) 2026-04-30 20:11:48 +00:00
Muhammad Danish f9068c2afa ci: use env var instead of passing winget token inline (#24387) 2026-04-29 06:50:14 +00:00
Lukasz 2446be44b8 fix: restore osv scanner workflow (#24702) 2026-04-27 09:06:07 +00:00
Atif Ali 1e21b288b9 ci: add permissions section to backport.yaml (#24654) 2026-04-23 18:41:03 +05:00