Commit Graph
15622 Commits
Author SHA1 Message Date
dependabot[bot] f5e0519180 chore: bump github.com/aws/aws-sdk-go-v2/service/sts from 1.44.0 to 1.45.3 (#27831)
Bumps
[github.com/aws/aws-sdk-go-v2/service/sts](https://github.com/aws/aws-sdk-go-v2)
from 1.44.0 to 1.45.3.
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/aws/aws-sdk-go-v2/commit/4aeeb0d7a4293f0b31c2e0be83e65da6f7fd4ae2"><code>4aeeb0d</code></a>
Release 2023-11-28.2</li>
<li><a
href="https://github.com/aws/aws-sdk-go-v2/commit/e09e153704d4da6ae2bb0ae3875058950d31206b"><code>e09e153</code></a>
Regenerated Clients</li>
<li><a
href="https://github.com/aws/aws-sdk-go-v2/commit/8293e2ca285a7333a9931a0a3b37b2bcf7cdc05d"><code>8293e2c</code></a>
Update endpoints model</li>
<li><a
href="https://github.com/aws/aws-sdk-go-v2/commit/713fb0f31a188015915d785556ebf16ddb08085a"><code>713fb0f</code></a>
Update API model</li>
<li><a
href="https://github.com/aws/aws-sdk-go-v2/commit/830202d722c904c7e3da40e8dde7b9338d08752c"><code>830202d</code></a>
Merge customizations for service s3</li>
<li><a
href="https://github.com/aws/aws-sdk-go-v2/commit/2de0027dc478a6ae80e9f2d24d904a425169a23b"><code>2de0027</code></a>
Release 2023-11-28</li>
<li><a
href="https://github.com/aws/aws-sdk-go-v2/commit/f0c890c5eaf354ff23feb727ded9f50aaee9f1c4"><code>f0c890c</code></a>
Regenerated Clients</li>
<li><a
href="https://github.com/aws/aws-sdk-go-v2/commit/e032d9ea8d98d366f2467a72834d2cc0ee865edd"><code>e032d9e</code></a>
Update endpoints model</li>
<li><a
href="https://github.com/aws/aws-sdk-go-v2/commit/507661ff1edbc896fbdfe3ea2e4c2e74be3b4e3c"><code>507661f</code></a>
Update API model</li>
<li><a
href="https://github.com/aws/aws-sdk-go-v2/commit/4128360684a451476e33c0f979921bc46ff63656"><code>4128360</code></a>
fix: respect functional option modifications to RetryMaxAttempts (<a
href="https://redirect.github.com/aws/aws-sdk-go-v2/issues/2390">#2390</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/aws/aws-sdk-go-v2/compare/service/s3/v1.44.0...service/iot/v1.45.3">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=github.com/aws/aws-sdk-go-v2/service/sts&package-manager=go_modules&previous-version=1.44.0&new-version=1.45.3)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-08-04 11:18:08 +00:00
Marcin Tojek 11b38272f6 chore(docs): update release docs for v2.36.0 (#27828)
Automated docs update for v2.36.0 release.

Created by `releasetui`.
2026-08-04 12:54:59 +02:00
Michael Suchacz 6b8f820493 feat: remove native chat cost tracking in favor of AI Gateway cost data (#27330)
## Stack Context

This stack makes AI Gateway data and budgets the source of truth for AI
spend controls.

1. Re-back the per-chat cost endpoint with AI Gateway data (#27328,
merged).
2. Remove native chat usage limits (#27329, merged).
3. **This PR, now based on `main`:** remove native chat cost tracking
and its dedicated admin UI.

## Summary

Removes native per-message price calculation, model pricing fields, cost
persistence, aggregate cost queries, and admin cost API types. It also
deletes the Analytics and Spend pages plus their legacy redirects. The
AI Gateway-backed per-chat cost row and compact budget indicators
remain.

The spend documentation is renamed to `spend-management.md` and updated
for the remaining surfaces, group budget APIs, CSV export, upgrade
handling for native pricing and cost history, and the absence of a
deployment-wide spend dashboard. The per-chat cost API documents that
data follows AI Gateway retention and reports zero after all matching
requests are purged.

No schema is dropped in this release. `chat_messages.total_cost_micros`
remains nullable and unwritten so replicas from the previous release can
continue inserting messages during rolling upgrades. #27600 tracks
removal after the compatibility window.

> Mux prepared this PR on Mike's behalf.
2026-08-04 12:27:38 +02:00
Paweł BanaszewskiandCian Johnston 0b8b48913f fix: fix port assignment race from aigatewaystart_internal_test (#27801)
The AI Gateway tests reserved a port with `testutil.RandomPort`, which
binds and closes `127.0.0.1:0`, then bound it later in `serve`.
If something took the port in between, `serve` failed at `net.Listen`
and the error went unread, leaving only a 10s `Eventually` timeout.

The gateway now exposes its bound address via `httpAddr` and a
`listenerReady` latch, so tests listen on port 0 and read the address
afterwards. `requireListening` reports `serve`'s error where an address
must still be fixed upfront.

---
Investigated and authored with Coder Agents.

---------

Co-authored-by: Cian Johnston <cian@coder.com>
2026-08-04 09:51:14 +00:00
Michael Suchacz f0e6ac64b3 feat: remove native chat usage limits in favor of AI Gateway budgets (#27329)
## Stack Context

This stack makes AI Gateway data and budgets the source of truth for AI
spend controls.

1. Re-back the per-chat cost endpoint with AI Gateway data (#27328,
merged).
2. **This PR:** remove native chat usage limits.
3. Remove native chat cost tracking and its dedicated admin UI (#27330).

## Summary

Removes the native usage-limit API, SDK types, SQL, and chat enforcement
for deployment, user, and group chat limits. Compact AI Gateway budget
indicators remain in the Agents sidebar, user menu, and group settings.
Gateway budget rejections and provider quota failures continue to
classify as usage-limit errors, including a 409 response for synchronous
title generation.

Budget-period labels now use the API's UTC boundaries, so users see the
same dates in every browser timezone. The documentation explains the AI
Gateway replacement, its licensing requirements, and the differences
from native limits.

No schema is dropped in this release. The usage-limit table, index, user
and group columns, constraints, audit mappings, and generated scan
fields remain for mixed-version rolling upgrades. #27600 tracks their
removal after the compatibility window.

## Breaking change

Native day, week, and month chat spend limits are removed and are not
migrated. AI Gateway budgets are month-based, group-scoped with per-user
overrides, and require the AI Gateway entitlement. Deployments without
that entitlement no longer have chat spend enforcement.

> Mux prepared this PR on Mike's behalf.
2026-08-04 11:36:49 +02:00
Paweł Banaszewski a2287d6739 chore: fix port availability check flake from aigatewaystart_internal… (#27784)
Extends state tracking in `standaloneGateway` which is used in tests to
simplify checks.
Flaky `requireListenerAvailable` was removed.
2026-08-04 11:33:34 +02:00
Michael Suchacz 404bb2f663 refactor(coderd/x/chatd): own provider option construction in one function (#27705)
Stacked on #27704.

Provider option conversion and reasoning effort injection both create
OpenAI option structs, so each of the four call sites had to pair them
in the right order and pick the same transport for each.

`chatprovider.ProviderOptionsForCall` now owns both steps, and the two
helpers it wraps are unexported. The advisor, main generation,
compaction override, and quickgen paths each collapse to one call.

The ARCHITECTURE section on transport selection is updated to match:
`ProviderOptionsForCall` is described as the only entry point in
`chatprovider` that builds provider options for a call, delegating
OpenAI conversion to `chatopenai.ProviderOptionsFromChatConfig`, and it
now records that the quickgen turn status label and chat summary paths
deliberately send no provider options.

> Mux prepared this PR on Mike's behalf.
2026-08-04 08:13:00 +00:00
Michael Suchacz 0e16e356b0 refactor(coderd/x/chatd): read the OpenAI transport from the model (#27704)
Stacked on #27703.

Provider option conversion, reasoning effort injection, and file part
acceptance each recomputed the OpenAI wire format from `(provider,
modelID, override)`. They now read it from `chatprovider.Model`, so a
decision cannot drift from the client it was built for.

`ProviderOptionsFromChatConfig` takes a `Transport`,
`ApplyReasoningEffort` takes a `Model`, and `AcceptsFilePartMediaType`
becomes a `Model` method. `UsesResponsesAPI` and `UsesResponsesOptions`
are deleted. The override extraction is unexported and reachable only
from `ModelFromConfig`, which now takes the model's
`ChatModelOpenAIConfig` directly, removing the six scattered extractions
at call sites.

That also resolves the computer-use mismatch. The computer-use model is
a hardcoded default with no config row of its own: its client was built
without an override while request preparation applied the chat model's.
Preparation now reads the computer-use model's own transport, so the two
agree without one model's client settings following a different model.
Passing the chat model's `openai_config` into the computer-use client
would have made them agree on the wrong value.

`TestModelTransportConsumersAgree` pins the invariant in one test: the
HTTP path the client actually hits, the concrete provider option struct
type, the type created by reasoning effort, and text/image file
acceptance.

> Mux prepared this PR on Mike's behalf.
2026-08-04 08:00:19 +00:00
Michael Suchacz b5c9e8e471 refactor(coderd/x/chatd): carry the resolved OpenAI transport on a model wrapper (#27703)
Stacked on #27683.

The OpenAI wire format is decided when the client is built, then thrown
away, so downstream sites recompute it from `(provider, modelID,
override)`. Any disagreement fails silently: the SDK type-asserts the
concrete provider options struct and discards every OpenAI option, and
text attachments are dropped because Responses natively accepts only
images and PDFs.

This adds `chatprovider.Model`, which pairs a fantasy client with the
transport resolved from that client's own identity. Its fields are
unexported and only the constructor sets the transport, deriving it from
the client, so no caller can pick a transport that disagrees with the
client it wraps. `chatopenai.Transport`'s zero value is invalid and
panics when read rather than defaulting to a wire format, following the
existing precedent for construction invariants.

`Model` is threaded through construction, the resolve paths, and the
four struct fields that store a model for later request preparation.
Terminal call sites keep taking `fantasy.LanguageModel` and receive
`LanguageModel()`, which avoids a new package edge from `chatloop` and
`chatadvisor` into `chatprovider`.

No decisions move yet. The consumers still recompute the transport, and
`UsesResponsesAPI` now delegates to `TransportFor` so the two agree by
construction. #27704 makes the consumers read it from the model.

> Mux prepared this PR on Mike's behalf.
2026-08-04 07:46:32 +00:00
Michael Suchacz c6cee10e8b feat: add per-model OpenAI Responses API toggle (#27683)
chatd hardcoded `WithUseResponsesAPI()`, so the provider SDK's static
known-model list decided whether an OpenAI model spoke the Responses API
or Chat Completions. A model absent from that list silently fell back to
Chat Completions until the fantasy fork was patched.

This exposes the SDK's `WithResponsesAPIFunc` hook as a per-model
setting, `openai_config.use_responses_api`, stored in the existing
`chat_model_configs.options` JSONB. Unset keeps the known-model list,
`true` forces Responses, `false` forces Chat Completions. There is no
migration.

It sits in a new construction-time `openai_config` section rather than
in `provider_options.openai` because it selects the API when the client
is built, while `provider_options` holds per-request parameters. That
placement is also load-bearing: a config setting only this field would
otherwise materialize an OpenAI request-options struct and turn on
provider-side response storage, since `Store` defaults to true there.

Three places independently decided the transport and would silently
disagree with the client actually built:

| Site | Effect when it disagrees |
| --- | --- |
| `ModelFromConfig` | the transport being overridden |
| `AcceptsFilePartMediaType` | text attachments dropped, since Responses
natively accepts only images and PDFs |
| `UsesResponsesOptions` | the SDK type-asserts the concrete options
struct, so every OpenAI option is discarded |

They share one predicate here, `chatopenai.UsesResponsesAPI`, with the
override threaded to each. The rest of the stack removes that threading
by resolving the transport once and carrying it. Compaction overrides
and the quickgen debug model built clients without `ConfigOptions`, so
they now pass it and pick up both this setting and the existing
Anthropic beta headers.

The toggle also makes transport-conditional option handling
admin-switchable, so two hardening changes ride along.
`ServiceTierFromChat` now maps every tier the codersdk enum advertises
(`auto`, `default`, `flex`, `scale`, `priority`); it previously returned
nil for `default` and `scale`, so flipping a model to Responses silently
dropped a configured `service_tier` that the API accepts (fantasy
forwards the value unchanged). And a new
`TestProviderOptionsTransportParity` pins, per `provider_options.openai`
field, which transport honors it, against a table in ARCHITECTURE.md, so
a field honored on one transport and silently ignored on the other fails
the test unless recorded as intentional.

Review rounds also caught two lifecycle gaps around the new field.
`isZeroChatModelCallConfig` now inspects `OpenAIConfig`, so a stored
options blob whose only setting is this toggle survives into GET/list
responses instead of reading as `model_config: null`;
`TestIsZeroChatModelCallConfigCoversEveryField` sets each config field
in isolation and fails if any field is invisible to the zero check. And
the model editor's update path sends an explicit empty `model_config`
when an edit clears the last field, since an omitted property preserves
the stored options server-side; covered by the
`EditClearingLastOptionSendsEmptyConfig` story.

Azure keeps following the known-model list, because the Azure provider
exposes no equivalent hook. The model editor renders Azure with the
OpenAI option schema, so instead of shipping a visible but inert
control, the option schema generator gains a `providers` struct tag that
it emits as `visible_for_providers`. Gating uses the raw provider type
rather than the alias table, so the control appears only for
openai-typed providers. No hand-written frontend field: the editor
renders it from the generated schema.

Closes
https://linear.app/codercom/issue/CODAGT-874/add-completionsresponses-api-toggle-in-model-editor

> Mux prepared this PR on Mike's behalf.
2026-08-04 09:30:27 +02:00
blinkagent[bot]andblink-so[bot] 84cdc17602 docs: bump AI Gateway client modules to latest and remove Coder Tasks refs (#27810)
Updates the AI Gateway client docs under
`docs/ai-coder/ai-gateway/clients/` to reference the latest module
versions on registry.coder.com and removes mentions of Coder Tasks from
those pages.

Uses pessimistic (`~>`) version constraints so users automatically pick
up compatible non-breaking updates within the same major.

### Version bumps

| Module | Old | New |
|---|---|---|
|
[`coder/claude-code`](https://registry.coder.com/modules/coder/claude-code)
| `4.7.3` | `~> 5.2` (latest `5.2.0`) |
|
[`coder-labs/codex`](https://registry.coder.com/modules/coder-labs/codex)
| `~> 5.0` | `~> 5.3` (latest `5.3.0`) |
| [`coder/mux`](https://registry.coder.com/modules/coder/mux) | `~> 1.0`
| `~> 1.5` (latest `1.5.0`) |

### Coder Tasks removal

- `claude-code.md`: removed the *Coder Tasks* example block (v5 of the
module is a major refactor that dropped the `ai_prompt` input and
`task_app_id` output).
- Remaining inputs in the example (`agent_id`, `workdir`,
`enable_ai_gateway`) still match the latest module.
- `codex.md` and `mux.md` did not reference Tasks, so only version bumps
were needed there.

cc @matifali

---------

Co-authored-by: blink-so[bot] <211532188+blink-so[bot]@users.noreply.github.com>
2026-08-04 12:09:23 +05:00
Michael Suchacz 9bab7a8e06 fix(coderd): preseed AI providers for title tests (#27564) 2026-08-04 08:55:03 +02:00
Sas SwartandClaude Opus 4.8 a60f393773 feat(site): show network calls list on AI session detail (#27426)
Renders the per-call network calls as a collapsible panel above the
session threads, using the `network_call_logs` field added to the
threads API.

Each row shows the request method, allowed/blocked status, URL, and
timestamp, and expands to show the protocol, matched rule, and full
detail. The header shows the total count and a blocked-count badge from
the session summary; when the server caps the list, the panel notes how
many calls are shown. The panel is omitted when the session did not pass
through Agent Firewall.

### PR map (merge strictly bottom-up)

This change is a 4-PR stack. Each PR depends on all the ones below it,
so merge in this exact order:

1. #27417 — backend network summary (base `main`)
2. #27418 — frontend summary rows (base #27417)
3. #27425 — backend per-call list `network_call_logs` (base #27418)
4. #27426 — frontend network-calls panel (base #27425)

Refs AIGOV-464

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

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-08-04 08:30:09 +02:00
Ethan a779320d87 feat(scaletest): llm-mock tool calls and paced streaming (#26850)
`coder exp scaletest llm-mock` used to return only canned text, so Coder
Agents scaletests pointed at it never exercised the path that matters
most: the agentic tool-call loop where the model asks for a tool, the
workspace runs it, the result is fed back, and the model is re-prompted
before it finally answers. This teaches the mock to reproduce that loop
deterministically so scaletests actually drive real tool execution and
hold streams open the way a live model would.

It adds `--tool-calls-per-turn` and `--tool-call-command` so the OpenAI
Chat Completions endpoint emits a controllable number of `execute` tool
calls per turn (only when the request advertises an `execute` tool,
otherwise it falls back to text, so it stays a safe drop-in). It also
adds paced streaming with
`--min-stream-duration`/`--max-stream-duration` (randomized per
response) and `--response-payload-size`, so runs can simulate slow or
long-lived responses instead of flushing everything at once.

Closes CODAGT-307

Closes GRU-48
2026-08-04 16:24:14 +10:00
Ethan 1f946bb50b ci(.github): retry Go module downloads (#27816)
Closes CODAGT-878
Closes https://github.com/coder/internal/issues/1621

The Go module proxy failure in the linked issue is outside our control,
but `lint` and `test-e2e` currently download modules during their `make`
targets without any retry. Other CI jobs already wrap `go mod download`
with `./.github/scripts/retry.sh`, so this just copies that precedent to
both affected jobs.
2026-08-04 14:23:48 +10:00
Jake Howell cce5a21933 chore(site): remove unused SelectMenu component (#27800)
`SelectMenu` was only referenced by its Storybook story. Nothing in the
app consumed it.

Delete the component and story so we drop the unused MUI `MenuItem` /
`MenuList` wrapper and avoid treating dead demui code as a shared
primitive.
2026-08-04 13:22:52 +10:00
dependabot[bot] d899f02e42 chore: bump terraform-google-modules/container-vm/google from 3.2.0 to 3.3.0 in /examples/templates/gcp-vm-container (#27813)
Bumps
[terraform-google-modules/container-vm/google](https://github.com/terraform-google-modules/terraform-google-container-vm)
from 3.2.0 to 3.3.0.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/terraform-google-modules/terraform-google-container-vm/releases">terraform-google-modules/container-vm/google's
releases</a>.</em></p>
<blockquote>
<h2>v3.3.0</h2>
<h2><a
href="https://github.com/terraform-google-modules/terraform-google-container-vm/compare/v3.2.0...v3.3.0">3.3.0</a>
(2026-03-06)</h2>
<h3>Features</h3>
<ul>
<li><strong>deps:</strong> Update Terraform Google Provider to v7
(major) (<a
href="https://redirect.github.com/terraform-google-modules/terraform-google-container-vm/issues/151">#151</a>)
(<a
href="https://github.com/terraform-google-modules/terraform-google-container-vm/commit/25aeb5e8eb9525fdac47cfeb79eb7b20295d9a10">25aeb5e</a>)</li>
</ul>
<h3>Bug Fixes</h3>
<ul>
<li><strong>TF&gt;=1.3:</strong> Update cft/developer-tools Docker tag
to v1.25 (<a
href="https://redirect.github.com/terraform-google-modules/terraform-google-container-vm/issues/145">#145</a>)
(<a
href="https://github.com/terraform-google-modules/terraform-google-container-vm/commit/49bb1a86c908b8a626b78977d83b1c01f3b5e39b">49bb1a8</a>)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/terraform-google-modules/terraform-google-container-vm/blob/main/CHANGELOG.md">terraform-google-modules/container-vm/google's
changelog</a>.</em></p>
<blockquote>
<h2><a
href="https://github.com/terraform-google-modules/terraform-google-container-vm/compare/v3.2.0...v3.3.0">3.3.0</a>
(2026-03-06)</h2>
<h3>Features</h3>
<ul>
<li><strong>deps:</strong> Update Terraform Google Provider to v7
(major) (<a
href="https://redirect.github.com/terraform-google-modules/terraform-google-container-vm/issues/151">#151</a>)
(<a
href="https://github.com/terraform-google-modules/terraform-google-container-vm/commit/25aeb5e8eb9525fdac47cfeb79eb7b20295d9a10">25aeb5e</a>)</li>
</ul>
<h3>Bug Fixes</h3>
<ul>
<li><strong>TF&gt;=1.3:</strong> Update cft/developer-tools Docker tag
to v1.25 (<a
href="https://redirect.github.com/terraform-google-modules/terraform-google-container-vm/issues/145">#145</a>)
(<a
href="https://github.com/terraform-google-modules/terraform-google-container-vm/commit/49bb1a86c908b8a626b78977d83b1c01f3b5e39b">49bb1a8</a>)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/terraform-google-modules/terraform-google-container-vm/commit/ab943364f6add0de89de1d3c79ca23e6852e5a12"><code>ab94336</code></a>
chore(main): release 3.3.0 (<a
href="https://redirect.github.com/terraform-google-modules/terraform-google-container-vm/issues/152">#152</a>)</li>
<li><a
href="https://github.com/terraform-google-modules/terraform-google-container-vm/commit/10d2424042cc02a4d3efff00db9b33d7e48f4452"><code>10d2424</code></a>
chore: Migrate gsutil usage to gcloud storage (<a
href="https://redirect.github.com/terraform-google-modules/terraform-google-container-vm/issues/159">#159</a>)</li>
<li><a
href="https://github.com/terraform-google-modules/terraform-google-container-vm/commit/f15666132398848678ba5fd299d7ff36cb46be67"><code>f156661</code></a>
chore: update .github/workflows/lint.yaml</li>
<li><a
href="https://github.com/terraform-google-modules/terraform-google-container-vm/commit/1a9a202d61c2663333d943bc08badaef427aa2c4"><code>1a9a202</code></a>
chore: update .github/workflows/lint.yaml</li>
<li><a
href="https://github.com/terraform-google-modules/terraform-google-container-vm/commit/9c708636cc9655b257b374773ea0068813fb736c"><code>9c70863</code></a>
chore: update .github/workflows/stale.yml</li>
<li><a
href="https://github.com/terraform-google-modules/terraform-google-container-vm/commit/df594b380ee57cb246d02c188d0189ecdda04c0f"><code>df594b3</code></a>
chore: update .github/workflows/stale.yml</li>
<li><a
href="https://github.com/terraform-google-modules/terraform-google-container-vm/commit/83a8daf400c4980e28e800b2b28f0c9690ce962c"><code>83a8daf</code></a>
chore: update .github/workflows/lint.yaml</li>
<li><a
href="https://github.com/terraform-google-modules/terraform-google-container-vm/commit/ab4a4eb85321af9db8b0ebfd64d80925441c0931"><code>ab4a4eb</code></a>
chore: update .github/workflows/lint.yaml</li>
<li><a
href="https://github.com/terraform-google-modules/terraform-google-container-vm/commit/604cf93040d5cc3b5e671c6eff9b7e1db4c0d60b"><code>604cf93</code></a>
chore: update .github/workflows/lint.yaml</li>
<li><a
href="https://github.com/terraform-google-modules/terraform-google-container-vm/commit/4016c71b40be077379b38cf549c04382ceee3d82"><code>4016c71</code></a>
chore: update .github/workflows/lint.yaml</li>
<li>Additional commits viewable in <a
href="https://github.com/terraform-google-modules/terraform-google-container-vm/compare/v3.2.0...v3.3.0">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=terraform-google-modules/container-vm/google&package-manager=terraform&previous-version=3.2.0&new-version=3.3.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-08-04 00:34:28 +00:00
Steven Masley 52423eb87b feat: promote MinimumImplicitMember experiment to GA (#27472)
Promotes the `minimum-implicit-member` experiment to GA and removes it.

## What changes

- The `minimum-implicit-member` experiment constant, its
`RoleOptions.MinimumImplicitMember` toggle, and the global
`rbac.MinimumImplicitMember()` accessor are deleted. The minimal-member
behavior is now the only behavior: `organization-member` and
`organization-service-account` carry only the floor (read-self records,
notifications, and similar) and grant **no workspace permissions**.
Workspace access lives exclusively on the
`organization-workspace-access` role.
- The experiment gate on customizing `default_org_member_roles` (`PATCH
/organizations/{org}`) is removed; the built-in-roles-only validation
remains.
- The dashboard's Default Roles section and the implied-roles display on
the members page are no longer experiment-gated.
- Admin docs: new "Default member roles" section in
`docs/admin/users/organizations.md`, cross-linked from
`groups-roles.md`.

## Why this is safe for existing deployments

Migration `000516` (shipped earlier) backfilled
`default_org_member_roles` with `['organization-workspace-access']` on
every organization. Members therefore keep exactly the effective
permissions they had with the experiment off; the workspace elevation
flows through the default role instead of being baked into
`organization-member`.

**Rollback caveat:** rolling back past this release restores the bundled
elevation, silently re-granting workspace access to members of
organizations that cleared their default roles.

## Review

Deep-review R1 findings are addressed in `chore: address deep-review
findings` (copy fixes, read-only Default Roles for viewers, removable
overlapping explicit grants, RBAC prose restoration, test
de-tautologizing, docs). Point-by-point disposition is in the PR
comments.

---

Generated by Coder Agents on behalf of @Emyrk.
2026-08-03 15:56:56 -05:00
dylanhuff-at-coderandNick Vigilante fe4a73f8ab docs: note user secret target uniqueness and delivery boundary (#27532)
Two gaps in the user secrets guide, both independent of any pending
secrets work.

## Changes

**Target uniqueness (`Update a secret`, `File secrets`).** The guide
teaches `coder secret update api-key --file ""` but never states that
env names and file paths are unique per user, so the conflict you get
when setting a target back has no explanation in the docs. The `File
secrets` paragraph also read as though duplicate file paths are
tolerated with a warning; an identical path is rejected outright, while
two *different* paths resolving to the same location are both accepted
and produce the agent warning. Both indexes are partial (`WHERE env_name
!= ''` / `WHERE file_path != ''`), so a cleared target really is
released for another secret to claim — now stated.

**Delivery boundary (`How your secrets reach a workspace`).** Coder
controls where a secret is delivered, not whether it is still valid.
Nothing done in Coder revokes a credential a workspace already received,
so an exposed credential is rotated at its source. This applies to
deletion as much as to clearing a target.

No new headings, no changes to the existing tables or callouts.

> This PR was generated by Coder Agents on behalf of
@dylanhuff-at-coder.

---------

Co-authored-by: Nick Vigilante <nickvigilante@users.noreply.github.com>
2026-08-03 13:06:30 -07:00
Rowan SmithandAtif Ali f44e8c12d6 fix: support adding multiline secrets via the UI (#27253)
**Summary**

Root cause (confirmed by reading SecretDialog.tsx): the Value field on
the User Secrets "Add secret"/"Edit secret" dialog was rendered as
<Input type="text">, a single-line HTML control, so pasting a multiline
kubeconfig/PEM/YAML got visually collapsed and the newlines were lost
before the value ever reached the form state or the API request.

Fix applied in
site/src/pages/UserSettingsPage/SecretsPage/SecretDialog.tsx:

* Swapped the Value field's <Input> for the same <Textarea> component
already used for the Description field (which correctly preserves
multiline text).
* Added rows={4} so the box is usable for multiline content, and
font-mono for readability of config-like values.
* Kept the "mask typed value" obscuring behavior but switched
-webkit-text-security:circle to :disc (Chromium's supported keyword for
<textarea>; circle is input-specific and silently no-ops on textareas).
* Removed the now-unused Input import.
* All existing onFocus/onChange/onBlur masking/saved-value logic was
preserved as-is; FormHelpers types already supported
HTMLTextAreaElement, so no type changes were needed.

Test fix in
site/src/pages/UserSettingsPage/SecretsPage/SecretsPageView.stories.tsx:
the EditSecretClearValue story's toBeVisible() assertion on the helper
text was racing the render/layout commit (this test already used a
waitFor for an analogous transient-visibility check on the neighboring
Clear button). The taller textarea shifted that timing enough to expose
the race consistently when run as part of the full suite. Wrapped the
assertion in waitFor(...) to match the existing pattern.

*Created with the help of Mux and Sonnet, tested by a human*

Working with a secret file like this:
```
➜  Downloads cat ~/.kube/config
apiVersion: v1
clusters:
  - cluster:
        certificate-authority-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJkakNDQVIyZ0F3SUJBZ0lCQURBS0JnZ3Foa2pPUFFRREFqQWpNU0V3SHdZRFZRUUREQmhyTTNNdGMyVnkKZG1WeUxXTmhRREUzTWpBNU16VTFOelV3SGhjTk1qUXdOekUwTURVek9UTTFXaGNOTXpRd056RXlNRFV6T1RNMQpXakFqTVNFd0h3WURWUVFEREJock0zTXRjMlZ5ZG1WeUxXTmhRREUzTWpBNU16VTFOelV3V1RBVEJnY3Foa2pPClBRSUJCZ2dxaGtqT1BRTUJCd05DQUFTK1JRaUlLa0RVV0tKR0Y0ZFdnbWZSVTA1Wjg1ellQSWt6aWlHUXdBZ1gKMXdyQThhNVRRbzVuYlJmeWxRQXZtZDB1SE04a05GTmZIYXJwc3lxZkZyS0dvMEl3UURBT0JnTlZIUThCQWY4RQpCQU1DQXFRd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBZEJnTlZIUTRFRmdRVTBmUHdjMWpnd1BraFN2Q0cwbjQ1CnZTV09ES1V3Q2dZSUtvWkl6ajBFQXdJRFJ3QXdSQUlnQ3RCRm5KR0VJVVRSZ1RRaXZFSWJIODVwQnlMdmx1RjMKQ2ZTRFhDc3hlaWtDSUF4a0JKWnJ2eUUzQzNWRWdVT0t2d2VzVUN4cFBOendpbkg5Qkd4TXJuTk4KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo=
        server: https://192.168.50.23:6443
    name: k3s-3-pi
```

Created via the UI in 2.35.1:
```
coder_dev=> select * from user_secrets;
-[ RECORD 1 ]+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
id           | 12853b89-a56b-408a-a9b0-11591ed04898
user_id      | 2702b6f3-b094-47ee-975e-47dc7887dbed
name         | kubeconfig
description  |
value        | apiVersion: v1 clusters:   - cluster:         certificate-authority-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJkakNDQVIyZ0F3SUJBZ0lCQURBS0JnZ3Foa2pPUFFRREFqQWpNU0V3SHdZRFZRUUREQmhyTTNNdGMyVnkKZG1WeUxXTmhRREUzTWpBNU16VTFOelV3SGhjTk1qUXdOekUwTURVek9UTTFXaGNOTXpRd056RXlNRFV6T1RNMQpXakFqTVNFd0h3WURWUVFEREJock0zTXRjMlZ5ZG1WeUxXTmhRREUzTWpBNU16VTFOelV3V1RBVEJnY3Foa2pPClBRSUJCZ2dxaGtqT1BRTUJCd05DQUFTK1JRaUlLa0RVV0tKR0Y0ZFdnbWZSVTA1Wjg1ellQSWt6aWlHUXdBZ1gKMXdyQThhNVRRbzVuYlJmeWxRQXZtZDB1SE04a05GTmZIYXJwc3lxZkZyS0dvMEl3UURBT0JnTlZIUThCQWY4RQpCQU1DQXFRd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBZEJnTlZIUTRFRmdRVTBmUHdjMWpnd1BraFN2Q0cwbjQ1CnZTV09ES1V3Q2dZSUtvWkl6ajBFQXdJRFJ3QXdSQUlnQ3RCRm5KR0VJVVRSZ1RRaXZFSWJIODVwQnlMdmx1RjMKQ2ZTRFhDc3hlaWtDSUF4a0JKWnJ2eUUzQzNWRWdVT0t2d2VzVUN4cFBOendpbkg5Qkd4TXJuTk4KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo=         server: https://192.168.50.23:6443     name: k3s-3-pi
env_name     |
file_path    | ~/.kube/config
created_at   | 2026-07-15 15:55:07.438234+10
updated_at   | 2026-07-15 15:55:07.438234+10
value_key_id |
```

Post change:
```
coder=# select * from user_secrets ;
-[ RECORD 1 ]+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
id           | 7c4858bc-ee87-45f0-b85d-0e9b1474d69c
user_id      | 0f0a590b-0358-4a24-bb25-ccc936bcc8d6
name         | kubeconfig
description  |
value        | apiVersion: v1                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          +
             | clusters:                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               +
             |   - cluster:                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            +
             |         certificate-authority-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJkakNDQVIyZ0F3SUJBZ0lCQURBS0JnZ3Foa2pPUFFRREFqQWpNU0V3SHdZRFZRUUREQmhyTTNNdGMyVnkKZG1WeUxXTmhRREUzTWpBNU16VTFOelV3SGhjTk1qUXdOekUwTURVek9UTTFXaGNOTXpRd056RXlNRFV6T1RNMQpXakFqTVNFd0h3WURWUVFEREJock0zTXRjMlZ5ZG1WeUxXTmhRREUzTWpBNU16VTFOelV3V1RBVEJnY3Foa2pPClBRSUJCZ2dxaGtqT1BRTUJCd05DQUFTK1JRaUlLa0RVV0tKR0Y0ZFdnbWZSVTA1Wjg1ellQSWt6aWlHUXdBZ1gKMXdyQThhNVRRbzVuYlJmeWxRQXZtZDB1SE04a05GTmZIYXJwc3lxZkZyS0dvMEl3UURBT0JnTlZIUThCQWY4RQpCQU1DQXFRd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBZEJnTlZIUTRFRmdRVTBmUHdjMWpnd1BraFN2Q0cwbjQ1CnZTV09ES1V3Q2dZSUtvWkl6ajBFQXdJRFJ3QXdSQUlnQ3RCRm5KR0VJVVRSZ1RRaXZFSWJIODVwQnlMdmx1RjMKQ2ZTRFhDc3hlaWtDSUF4a0JKWnJ2eUUzQzNWRWdVT0t2d2VzVUN4cFBOendpbkg5Qkd4TXJuTk4KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo=+
             |         server: https://192.168.50.23:6443                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              +
             |     name: k3s-3-pi
env_name     |
file_path    | ~/.kube/config
created_at   | 2026-07-15 15:49:08.772126+10
updated_at   | 2026-07-15 15:53:39.375332+10
value_key_id |
```

And displayed correct in the Coder workspace:
<img width="508" height="238" alt="image"
src="https://github.com/user-attachments/assets/a0e9208e-cb73-4636-94e4-a67dcb510da4"
/>


Add secret UI is now a multiline input box:
<img width="534" height="839" alt="image"
src="https://github.com/user-attachments/assets/6e2a89a3-bef2-40c0-852e-0c9ac8e2f0cd"
/>

Co-authored-by: Atif Ali <atif@coder.com>
2026-08-03 11:52:07 -07:00
Ben Potter 8a4adeec32 fix(agent): detect IPv6-bound listening ports (#27765)
Closes https://github.com/coder/coder/issues/15675

Dev servers that bind to the IPv6 wildcard address (Next.js, Node's
default `http.Server`, Go's `net.Listen` on wildcard addresses, and
others) never showed up in the dashboard Ports panel, even though they
were listening and reachable. The agent's port scanner only called
`netstat.TCPSocks`, which reads `/proc/net/tcp` (IPv4 only); an `[::]`
dual-stack socket lives exclusively in `/proc/net/tcp6`, so the panel
reported "No open ports were detected."

Also scan `netstat.TCP6Socks` and merge the results into the existing
dedupe loop. The IPv6 scan failure is non-fatal so hosts with IPv6
disabled (missing `/proc/net/tcp6`, Windows with the v6 stack off) keep
their IPv4 results instead of the Ports panel 500ing.

Both captures below: `python3 -m http.server 5123 --bind ::` running in
the same workspace, built from main vs this branch ([full
recordings](https://github.com/coder/coder/tree/recordings/recordings/ipv6-listening-ports)).

## Before


![before](https://raw.githubusercontent.com/coder/coder/recordings/recordings/ipv6-listening-ports/before.jpg)

## After


![after](https://raw.githubusercontent.com/coder/coder/recordings/recordings/ipv6-listening-ports/after.jpg)

<details>
<summary>Debugging and decision log</summary>

- Reproduced on a dogfood workspace: `next-server` listening on `*:3000`
per `ss -tlnp`, `curl` returning 200, but `GET
/api/v2/workspaceagents/{agent}/listening-ports` returning `{"ports":
[]}`. Port 3000 (hex `0BB8`) present in `/proc/net/tcp6`, absent from
`/proc/net/tcp`.
- Confirmed `agent/ports_supported.go` only calls `netstat.TCPSocks`;
the library's `TCP6Socks` (parses `/proc/net/tcp6` on Linux,
`GetTcp6Table2` on Windows) was never referenced.
- Control test: an IPv4-bound (`0.0.0.0`) listener was detected
correctly, isolating the bug to the missing IPv6 scan.
- Made the IPv6 scan failure non-fatal after review: returning an error
would break the entire ports endpoint (HTTP 500 on every poll) on
IPv6-disabled hosts, a regression from the current behavior of "IPv4
ports only." Silent fallback matches the spirit of
`ports_unsupported.go`, which returns an empty list rather than
erroring.
- The fix lives in the OS-backed `osListeningPortsGetter` behind the
`ListeningPortsGetter` interface from #20842, so the fake used by coderd
tests is unaffected.
- Dedupe by port in the existing `seen` map covers dual-stack sockets
that appear in both tables on Windows.
- `TestOSListeningPortsGetter_IPv6` listens on `[::]:0` and asserts
detection; it skips when the host can't bind IPv6. Verified it fails
against the pre-fix code.

</details>

> 🤖 This PR was opened by [Coder
Agents](https://coder.com/docs/ai-coder/agents) on behalf of @bpmct.
2026-08-03 11:50:36 -07:00
Nick Vigilante 71c7e92084 ci: broaden linkspector Stack Overflow ignore for weekly docs check (#27799)
## Problem

The weekly docs link check
([`weekly-docs`](https://github.com/coder/coder/blob/main/.github/workflows/weekly-docs.yaml)
-> [linkspector](https://github.com/UmbrellaDocs/linkspector)) is
failing.

- **Failing run:**
https://github.com/coder/coder/actions/runs/30805217850/job/91691078170
- **Broken link:** `https://stackoverflow.com/a/55570286` in
`docs/admin/users/idp-sync.md` (line 576), reported `Status: 403`.

Stack Overflow returns `403` to the GitHub runner IPs (bot detection),
so a valid link is flagged as broken. This is the same false-positive
mode already handled for `npmjs.com`, `merriam-webster.com`,
`splunk.com`, etc. in `.github/.linkspector.yml`.

## Fix / why a bare `stackoverflow.com` pattern

linkspector matches `ignorePatterns` as regex substrings against each
URL. The config already ignored `stackoverflow.com/questions`, but the
failing URL is an **answer** link (`/a/...`) that the `/questions`
pattern does not cover, and it has no `www.` prefix, so a
`www.stackoverflow.com` entry would not match it either.

Broadening to a bare `stackoverflow.com`:

- fixes the failing `/a/55570286` link;
- keeps the existing `/questions/...` link in
`docs/about/contributing/frontend.md` covered (so the now-redundant
`stackoverflow.com/questions` line is removed);
- also covers any `www.` variant.

## Validation

- Confirmed the `stackoverflow.com` regex matches `/a/`, `/questions/`,
and `www.` variants; config parses; `typos` clean.
- The `weekly-docs` `pull_request` trigger is path-filtered to
`docs/**`, so this `.github/`-only change does not auto-run linkspector
here. Validated end-to-end via a manual `workflow_dispatch` on this
branch, which passed:
https://github.com/coder/coder/actions/runs/30829301773

<details>
<summary>Unrelated failing check: <code>Pixel / Review</code> (visual
regression)</summary>

`Pixel / Review` reports failed visual tests ([build
6916](https://pixel.coder.com/@coder/coder/builds/6916)). This PR only
edits `.github/.linkspector.yml` (link-checker config) and changes no
UI, components, or rendered output, so these are pre-existing
visual-baseline diffs / flakes unrelated to this change. All
path-relevant required checks (`fmt`, `gen`, `lint`, `changes`, `title`,
`Storybook`, `Flake Check`) pass.

</details>

Linear:
[DOCS-606](https://linear.app/codercom/issue/DOCS-606/fix-weekly-docs-link-check-allowlist-stack-overflow-in-linkspector)

> This PR was created with AI assistance (Coder Agents).
2026-08-03 18:40:54 +00:00
ba4779fc87 docs: lead with env vars in admin docs and add configuration reference (#26824)
## What & why

Admin/setup docs lead with `coder server --flag` examples, but most
operators configure Coder through `CODER_*` environment variables
(system service, container, or Helm chart). There is no single page
mapping a setting to its env var, CLI flag, YAML key, and default, so
searching the docs for an env var name such as `CODER_PG_CONNECTION_URL`
returns nothing.

This adds a generated configuration reference and begins shifting admin
docs to lead with the environment-variable form.

## Changes

- **Generated configuration reference**
(`docs/admin/setup/configuration-reference.md`): a searchable,
per-setting list of every visible deployment option. Each option is a
heading (grouped and nested by serpent group) followed by its
description and the environment variable, CLI flag, YAML key, and
default that apply to it. Generated from `codersdk.DeploymentValues` so
it stays in sync.
- **Generator + `make gen` wiring** (`scripts/configdocgen/`): new
binary plus a Makefile target and `GEN_FILES` entry, mirroring the
existing `clidocgen` / `auditdocgen` pattern. Output is host-independent
(same env normalization as `clidocgen`).
- **Demo conversion** (`docs/admin/users/github-auth.md`): inverted to
lead with the `/etc/coder.d/coder.env` env-var form; the CLI-flag form
becomes a closing note that links to the reference. H2 slugs preserved.
- **Style guide** (`.claude/docs/DOCS_STYLE_GUIDE.md`): documents the
env-var-first convention for admin/setup docs.
- **Navigation**: manifest entry under Administration → Setup, plus a
TIP callout on the setup index.

## Risk

Docs + gen pipeline only; no runtime change. The page is regenerated by
`make gen`; the `gen` and `check-docs` CI checks pass.

## Follow-up

Several other admin pages still lead with flag walls. Recommend sweeping
them incrementally in separate PRs rather than expanding scope here.

<details>
<summary>Implementation notes (provenance, conflict resolution,
verification)</summary>

- Continues prior work by @aslilac and @bpmct from the
`kayla/docs-env-vars-first` branch. Both original commits are
cherry-picked here with authorship preserved.
- Rebased onto current `main`. Resolved two `Makefile` conflicts where
`main` had since added the `feature-stages.md` gen target at the same
locations; kept both targets (union) in `GEN_FILES`, `gen/mark-fresh`,
and the recipe block.
- The original branch's checked-in page predated recent
`codersdk.DeploymentValues` changes, so it was **regenerated** against
current `main` (adds `CODER_SCIM_USE_LEGACY`, the `Networking / Cluster`
section with `CODER_CLUSTER_HOST`, `CODER_BOUNDARY_LOG_RETENTION`, and
the AI Gateway description rename). The `gen` CI check enforces this
stays current.
- Fixed flag-link anchors for short-form flags (`--config`,
`--log-filter`): the generator derives the anchor from `FlagShorthand`
to match `clidocgen`'s heading (e.g. `#-l---log-filter`).
- `linkspector` ignores the AWS Bedrock base URL that appears as an
illustrative `<region>` placeholder in an option description, consistent
with the existing `openai.com` ignore patterns.

</details>

<details>
<summary>Configuration reference layout (2026-07-08 update)</summary>

Reworked the reference from a wide table into a nested, per-setting list
so it fits without horizontal scrolling and stops repeating the group
name in every heading:

- **List, not table.** Each option renders as a heading, its
description, and a bullet list of only the configuration methods that
apply to it (non-applicable methods are omitted instead of shown as
`-`).
- **Nested sections.** Sections nest by the serpent group hierarchy, so
`Email / Email Authentication` becomes `Email` (h2) with an `Email
authentication` (h3) subsection instead of a redundant flat title.
- **Shorter, sentence-case headings.** The redundant group prefix is
stripped from each option name and the remainder is lowercased to
sentence case, preserving acronyms and mixed-case tokens (`URL`, `TLS`,
`OAuth2`, `GitHub`) plus a small proper-noun allowlist (`Coder`,
`Terraform`, `Honeycomb`, `Anthropic`, `Bedrock`, ...). Example: `AI
Gateway Send Actor Headers` becomes `Send actor headers`.
- **Deprecated options** sort to the end of each section and lead with
an emphasized **Deprecated** marker. Headings stay clean (no
`(deprecated)` suffix) so their anchors remain stable.
- **Section intros** render from a group's `Description` when the source
defines one (e.g. DERP); no hand-maintained prose or links are
introduced.

All transformations run in pure Go at `make gen` time (no AI at
generation time). Generation is idempotent, and `markdownlint` and
`golangci-lint` both pass.

</details>

---

🤖 Opened by Coder Agents on behalf of @nickvigilante. Continues work by
@aslilac and @bpmct.

---------

Co-authored-by: Kayla (via Coder Agents) <kayla@coder.com>
Co-authored-by: Coder Agents <noreply@coder.com>
Co-authored-by: Ben Potter <me@bpmct.net>
2026-08-03 14:33:01 -04:00
Nick Vigilante ee7e7ecb74 docs: add a glossary to the reference section (#27165)
Adds a reference glossary at `docs/reference/glossary.md` that defines
the Coder-specific terms and product names readers encounter across the
docs, and registers it in `docs/manifest.json` under **Reference**.

The page prioritizes the term collisions around "agent": it
disambiguates Coder Agents (the AI product), the workspace agent (the
in-workspace daemon), and the `coder_agent` Terraform resource with an
`[!IMPORTANT]` callout and cross-referenced entries. Every definition
was checked against the current docs, and every internal link is a
relative path that resolves in-repo.

Decision log and verification notes

**Scope of this PR**

- Creates the glossary page (`docs/reference/glossary.md`) and its
manifest entry.
- Adds glossary drift-prevention guidance in response to review feedback
(see **Follow-up from review** below).
- Out of scope (tracked separately): `Glossary: ` cross-link callouts
across the docs IA, the search-ranking boost, the workspace-daemon
rename decision, and the automated glossary lint guard
([DOCS-604](https://linear.app/codercom/issue/DOCS-604)).

**Follow-up from review (@bpmct)**

Ben flagged the risk that terms get introduced, renamed, or deprecated
without the glossary keeping up. Addressed in commit c12dea4 by pointing
both humans and tooling at the glossary:

- `docs/.style/content-guidelines.md`: a canonical Structural rule to
update the glossary in the same change that introduces, renames, or
deprecates a product or feature name.
- `.claude/skills/doc-check/SKILL.md`: doc-check flags terminology
changes that need a glossary update.
- `.claude/skills/write-docs/SKILL.md`: authoring updates the glossary
in the same change, plus a pre-handoff checklist item.
- `docs/.style/style-guide/word-choice.md`: cross-links the glossary as
the fuller product-name registry.

The single source of truth is the content-guidelines rule; the skills
reference it rather than restate it. The automated lint guard is
deliberately split into
[DOCS-604](https://linear.app/codercom/issue/DOCS-604): it touches
CI/build config and depends on the planned `Coder.ProductTerms` Vale
rule, so keeping it out holds this PR to a doc-only footprint. The four
files above are Markdown-only additions, validated in CI (markdownlint,
emdash, Vale advisory) rather than re-run locally.

**Source**

- Migrated and expanded from a generated glossary draft, then reconciled
against the live docs.

**Corrections made vs. the draft**

- AI Gateway and Agent Firewall are gated by the **AI Governance
Add-On** (Coder v2.32+), not plain Premium. Confirmed in
`docs/ai-coder/ai-governance.md`.
- Coder Tasks is framed as deprecated (12-month ESR, removed from new
releases starting v2.37; Coder Agents is the long-term replacement), per
`docs/ai-coder/tasks.md`.
- "Formerly AI Bridge" and "formerly Agent Boundaries" confirmed via the
rebranding-migration and agent-firewall pages; Agent Firewall backends
are `nsjail` (default) and `landjail`.
- OpenTofu is described as a custom Terraform binary that works but is
not officially supported, per `docs/admin/integrations/opentofu.md`.
- Premium markers were taken from `docs/manifest.json` (`"state":
["premium"]`).

**Local validation** (glossary page)

- `markdownlint-cli2`: 0 errors.
- `scripts/check_emdash.sh`: clean.
- Vale (`Coder` package): 0 errors, 0 warnings, 0 suggestions.
- All 120 links checked; every relative link resolves in-repo.
- 103 terms; no duplicate sibling headings (MD024 `siblings_only`).

**Reviewer note**

- This is a first-pass migration. Per the docs authoring skill, each
entry deserves a final accuracy pass before the page leaves draft. Flag
any term you want reworded, split, merged, or dropped.

> This PR was created with AI assistance (Coder Agents).
2026-08-03 14:32:13 -04:00
Steven Masley 76eb43a78e test(coderd): drain dormancy audit log before reset in StartWakesUpDormantWorkspace (#27541)
Closes PLAT-219 /
[coder/internal#1532](https://github.com/coder/internal/issues/1532).

The reported failure (`should have 2 item(s), but has 3`) was the stop
build's outcome audit landing after `auditor.ResetLogs()`; that path was
already deflaked by #26232 and the pre-reset drain added in #25037.

This closes the remaining hole in the same class: the dormancy update's
audit log is exported in a middleware `defer` after the API response, so
it can also land after `ResetLogs` and break the exact `len == 2`
assertion. Extend the pre-reset poll to drain the dormancy write entry
alongside the stop build entry.

Verified with `go test ./coderd -run TestWorkspaceDormant -count=5` and
`-race`.

> Generated by Coder Agents on behalf of @Emyrk.
2026-08-03 13:29:42 -05:00
Michael Suchacz 6e5f02bfbe fix: bound golangci-lint memory to stop lint OOM kills (#27637)
## Summary

Reduce peak memory during linting so cold-cache runs do not exhaust
memory on high-core development hosts or leave CI runners with little
headroom.

## Problem

`golangci-lint` v1 sizes its default concurrency from available CPUs,
not the cgroup memory limit. On a 96-CPU development host capped at 32
GiB, a cold-cache full lint run peaked at about 33.9 GB and reached the
cgroup limit. The CI workflow also used bare `make -j`, which allows
every lint target to run concurrently.

## Fix

Make the supported `make lint/go` path cap `golangci-lint` at the lower
of detected CPUs and eight workers, preserving lower concurrency on
smaller hosts. Preserve an inherited `GOMEMLIMIT`, use a configurable 8
GiB fallback when it is unset, and bound CI's parallel lint targets to
the runner CPU count.

In the same high-core cold-cache reproduction, peak memory for the full
lint target fell to about 10.1 GB. Raw `golangci-lint run` invocations
remain unchanged.

A `golangci-lint` v2 migration remains separate because it does not size
concurrency from the memory limit and requires broader configuration
migration work.

> Mux prepared and updated this PR on Mike's behalf.
2026-08-03 19:49:22 +02:00
Nick Vigilante 4e54f311bd Revert "chore: add @coder/docs as a CODEOWNER for docs content and tooling" (#27802)
Reverts coder/coder#27240

The emails got too spammy, and so we need to find another mechanism to
track PRs and how well each PR is documented.
2026-08-03 17:35:26 +00:00
Stefan Richter 24ff135801 feat(helm/coder): make HTTPS redirect status code configurable (#27360)
Add coder.httproute.httpsRedirect.statusCode to configure the HTTPRoute
redirect response code, defaulting to 308. Validate that the value is
one of 301, 302, 303, 307, or 308.

<!--

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.

-->
2026-08-03 17:11:36 +00:00
Michael Suchacz fc24c27dfd fix: reserve chat hook dispatch capacity for running turns (#27656)
## Context

Follow-up fix from live UAT of the merged chat lifecycle hooks stack
(#27430). Its companion UAT fix (#27655) has merged, so this targets
`main` directly.

## Why?

UAT measured a burst of 1,500 concurrent chat creations against a
consumer with 1.2s latency. 255 were admitted and 1,245 got `502
hook_dispatch_failed (over_capacity)`, which is correct fail-closed
behavior. The collateral wasn't: the same burst failed 24 `stop`
dispatches, parking chats that had already been admitted and had already
executed tools. One 256-slot semaphore served every event, so new-work
admission could take every slot and kill turns in flight.

Callers now classify each dispatch as admission or generation, and
admission draws from a 192-slot gate held *before* the shared pool. At
least 64 shared slots stay reachable only by dispatches for work a chat
already admitted. The dispatcher is per `coderd` replica, so these
limits are per replica, not deployment-wide, and the docs say so.

**The caller classifies, not the event type.** Event type isn't a
reliable proxy in either direction: a subagent spawn dispatches
`user_prompt_submit` from inside a running turn, and the edit path
dispatches `session_start` at admission time. `CapacityClassUnset` is
rejected in `Dispatch`, so a new call site fails closed rather than
silently inheriting a share.

**Acquisition order is load-bearing.** Admission takes its own gate
first. Taking a shared slot first would let admissions queued on the
gate occupy the very capacity the reserve protects. `acquireCapacity` is
the only path that takes either pool, so the order can't be bypassed.

## What this does not guarantee

Nothing bounds how many turns generate concurrently, so the 192/64 split
is a judgement call, not a derived ceiling. This stops an *admission*
burst from consuming every slot; it does not make the remainder
sufficient. A large enough generation load can still exhaust the reserve
and error a running chat. The docs say so explicitly rather than
promising a guarantee the code doesn't deliver.

Generation can now take all 256 slots, so generation traffic starves
admission harder than before. That's the intended priority: rejecting a
new prompt is recoverable, ending a turn that already ran tools is not.

## Testing

Red-green proved both new tests. Removing the release-on-failure path
fails `RefusedSharedAcquireReleasesAdmission` deterministically;
removing the expired-deadline check fails
`ExpiredDeadlineRefusesFreeSlot` in 18/30 runs.

That deadline check fixes a real race found in review. `acquire`
previously shared one `time.Timer` across both acquires. Because
`select` picks a ready case at random, an admission dispatch could take
a slot after its capacity deadline had passed. Measured over 300 trials:
135 late acquisitions, worst overshoot 2.1ms. `acquire` now takes an
absolute deadline and refuses an expired one before selecting, which
measures 0/300.

Go: `coderd/x/agenthooks/...` and `coderd/x/chatd/...`, plus `-race
-count=3` on the dispatcher.

> Mux opened this PR on Mike's behalf.
2026-08-03 19:04:54 +02:00
Fabien Penso 7bd9f5ec93 fix: correct authorization header spelling in api docs (#27721)
Corrects the misspelled `Authorizaiton` Swagger header name to
`Authorization` in the source annotation and checked-in generated API
documentation.

This prevents generated API specs and SCIM examples from documenting the
wrong HTTP header name.
2026-08-03 16:31:26 +00:00
Michael Suchacz df1c0f9710 feat: show what a chat lifecycle hook changed (#27655)
## Stack Context

Follow-up fixes from live UAT of the merged chat lifecycle hooks stack
(#27430). Two PRs:

1. **This PR**: make hook effects visible and correctly attributed in
the transcript.
2. [`mike/chat-hooks-uat/dispatch-capacity`]: reserve dispatch capacity
so an admission burst can't fail running turns.

## Why?

UAT found three ways the transcript misrepresented what a lifecycle hook
did. All three are user-visible and share the same surface
(`chathooks/effects.go`, `codersdk.ChatMessagePart`, the conversation
timeline), so they're reviewed together.

**A prompt `input_override` silently discarded attachments.**
`ComposeUserPromptContent` replaced the entire submitted part list with
one text part, dropping `file` and `file-reference` parts along with
their `chat_file_links`. The user saw their attachments vanish with no
explanation. The override now replaces submitted *text* parts only and
preserves non-text parts in order. A consumer that wants to block
attachments uses `deny`, which is the documented mechanism for refusing
a submission.

**Every user-visible `system` row was labelled "Lifecycle hook".** The
timeline keyed the notice off `role === "system"`. That was correct only
by accident, because the hook `user_message` was the sole client-visible
system row. The backend now emits the notice as a typed `hook-notice`
part and the timeline renders on that, so a future system row can't be
mislabelled as a policy notice.

**Nothing marked a tool call the hook had rewritten.** A consumer could
replace tool input via `input_override` and the transcript showed the
rewritten input as if the model had produced it. `ChatMessagePart` gains
`hook_rewritten`, set from `preflight.Overrides` on the same path that
already carries `ToolCallCreatedAt`, and the tool row renders a
"Modified by policy" badge.

`ToolCall.PolicyProvider` renders the badge itself, at four wrap sites:
the `Tool` dispatch wrapper, the `ReadFilesTool` aggregate and its
per-file rows, and `ReadFileTimelineBlock` (grouped and single
`read_file` rows bypass `Tool`). Renderer props do not include the flag;
descendants consume it through the provider context.

The badge is emitted by the provider rather than by the shared header
because several renderer branches return early without one, including
the auth-required `execute` card, a completed `ask_user_question`, and
an empty question payload. Those branches would drop the attribution
with no type or runtime error, and the gap is not greppable: every
renderer file contains a header somewhere, only individual branches do
not. Emitting at the provider removes the possibility instead of
enumerating the cases.

A rewritten call is wrapped in a group labelled by its badge, so one
rewritten file inside a merged read is attributed on its own rather than
inheriting the group's badge. `HeaderButton` still appends the policy
wording to an explicit `ariaLabel`, since an explicit `aria-label`
replaces the name computed from descendants.

Provider-executed calls are excluded from attribution. Hooks never see
them, and duplicate tool-call ID rejection deliberately skips them, so a
reused ID would otherwise mark a provider-executed call as
policy-rewritten.

## Testing

Go: `coderd/x/chatd/...`, `coderd/x/agenthooks/...`, `codersdk/...`, and
`coderd -run 'Hook|Chat'`. Frontend: `tsc` plus every `AgentsPage`
story; the only failures are `MCP Tool Completed` and `Scroll To Bottom
Button Works With Inverse Scroll`, both of which fail on trunk.

A registry-wide story asserts every registered renderer shows the badge,
verified against three inverted toggles: removing the badge, hiding it
with `display:none`, and skipping the provider for one renderer (which
names that renderer). Storybook also covers the rewritten subagent
spawn, a completed empty question payload, a non-hook system message,
and a failed `read_file` guarding the accessible name.

> Mux opened this PR on Mike's behalf.
2026-08-03 18:27:39 +02:00
Bobby HoandTracy Johnson 4245e4e378 feat: expose dynamic client registration in deployment settings (#27480)
Adds the admin-controlled OAuth2 Dynamic Client Registration setting
landed by #27316 (`GET`/`PUT /api/v2/oauth2-provider/settings`) to the
OAuth2 Applications deployment settings page, since it was previously
only reachable via the API or `coder oauth2-provider dcr
enable|disable`.

The page is now tabbed, **Applications** and **Settings**, so DCR has a
home that further OAuth2 settings can share (an Initial Access Token
setting is a likely next one). The active tab is backed by a `tab`
search param, so `?tab=settings` links straight to it, and an
unpermitted deep link falls back to **Applications** rather than
selecting nothing. On the Settings tab, DCR renders as a titled section
with a description, an `Enabled` badge when active, and an
Enable/Disable button.

Enabling opens a confirmation dialog, since it lets any OAuth2 client
self-register against the deployment without prior admin approval (RFC
7591). Disabling is immediate, no confirmation.

The control is a button rather than a switch on design feedback: a
switch reads as an immediate on/off flip, which conflicts with a
confirmation dialog standing in front of it, and it left the only
explanation of the risk inside a dialog that disappears. A button
carries the confirmation step without misrepresenting what a click
costs, the always-visible description explains the setting on the page,
and the `Enabled` badge gives the active state a persistent indicator.
The layout follows Tracy's mockup on `tj/oauth2-apps-pagination`; the
apps-table pagination work that shares that branch is deliberately not
included here.

Visibility and editability are gated on the same
`ResourceDeploymentConfig` RBAC checks the endpoint itself enforces
(`viewDeploymentConfig` / `editDeploymentConfig`), not a separate
hardcoded check. The view takes the settings values as one optional
`settings` prop, absent when the viewer lacks `viewDeploymentConfig`, so
"cannot view" is the shape of the prop rather than a flag the caller
keeps consistent with the values beside it, and the tab is not rendered
at all.

Closes https://github.com/coder/coder/issues/27432

## Where this sits in the request path

```mermaid
sequenceDiagram
    autonumber
    actor Admin
    participant View as OAuth2AppsSettingsPageView<br/>(Tabs + Enable/Disable + Dialog)
    participant Page as OAuth2AppsSettingsPage<br/>(React Query)
    participant S as coderd

    Note over Page: On mount
    Page->>S: GET /api/v2/oauth2-provider/settings
    S-->>Page: { dynamic_client_registration_enabled }
    Page-->>View: settings: { dynamicClientRegistrationEnabled, canEdit, ... }

    Note over Admin,View: Admin opens the Settings tab and enables DCR
    Admin->>View: click "Enable"
    View->>View: open confirmation dialog<br/>(no request sent yet)
    Admin->>View: click Confirm
    View->>Page: settings.onDynamicClientRegistrationChange(true)
    Page->>S: PUT /api/v2/oauth2-provider/settings<br/>{dynamic_client_registration_enabled: true}
    S-->>Page: 200 OK (audited)
    Page->>S: GET /api/v2/oauth2-provider/settings (refetch)
    S-->>Page: { dynamic_client_registration_enabled: true }
    Page-->>View: section shows the "Enabled" badge and a Disable button

    Note over Admin,View: Admin disables DCR
    Admin->>View: click "Disable"
    View->>Page: onDynamicClientRegistrationChange(false)<br/>(no dialog, disable is immediate)
    Page->>S: PUT ... {dynamic_client_registration_enabled: false}
    S-->>Page: 200 OK (audited)
```

## Files changed

All 10 files are hand-written; nothing in this PR is `make gen` output.

| File | What changed |
|---|---|
| `site/src/api/api.ts` | New
`getOAuth2ProviderSettings`/`putOAuth2ProviderSettings` methods, thin
typed wrappers around the two endpoints #27316 added to `main`. |
| `site/src/api/api.test.ts` | Covers both methods against the request
they issue and the error they propagate. |
| `site/src/api/queries/oauth2.ts` | A `getSettings` query and a
`putSettings` mutation that invalidates the settings key on success.
Both the app and settings keys now derive from a shared
`oauth2ProviderKey` constant. |
| `site/src/api/queries/oauth2.test.ts` | 4 tests: the key nesting, both
delegations, and that a successful update invalidates the settings key
without touching app queries. |
| `.../OAuth2AppsSettingsPage.tsx` | Wires query and mutation into the
page and passes the settings values down as one object, or omits it
entirely without `viewDeploymentConfig`. The apps error stays its own
prop, since the view gates the applications empty state on it. |
| `.../OAuth2AppsSettingsPageView.tsx` | `Tabs` splitting Applications
from Settings. The settings tab distinguishes loading, failed, and a
value the server omitted rather than rendering nothing, and the header's
"Add application" action is scoped to the applications tab. |
| `.../OAuth2AppsSettingsPageView.stories.tsx` | 14 stories, covering
the tab wiring, both permission boundaries, the header action's scope,
and the settings tab's loading, fetch-error, update-error, and
value-omitted states. |
| `.../DynamicClientRegistrationSetting.tsx` | The section itself:
heading, description including what disabling does not undo, `Enabled`
badge, a permission explanation when the viewer cannot edit, and one
button that confirms only in the enable direction. |
| `.../DynamicClientRegistrationSetting.stories.tsx` | 11 stories,
including focus surviving an in-flight request and the dialog ignoring a
value that changes underneath it. |
| `docs/admin/integrations/oauth2-provider.md` | Adds the web UI route
to the DCR section, which previously enumerated only the CLI and the
management API. |

## Suggested review order

Follows the direction data actually flows, from the raw HTTP call up to
the rendered section.

1. **`site/src/api/api.ts`**: the two new methods. Confirms they match
the `codersdk.OAuth2ProviderSettings` shape #27316 landed and sit next
to the existing OAuth2 app methods they mirror.
2. **`site/src/api/queries/oauth2.ts`**: the query/mutation pair. The
mutation's `onSuccess` → `invalidateQueries` is the one detail worth
double-checking: it's what makes the on-screen state catch up with what
was just saved, rather than trusting the PUT payload.
3. **`OAuth2AppsSettingsPage.tsx`**: the container. Check the two
separate permission gates (`viewDeploymentConfig` on the query's
`enabled` option, `editDeploymentConfig` on the button's editability)
match the RBAC the backend enforces.
4. **`OAuth2AppsSettingsPageView.tsx`**: the tabs and the settings tab's
four states. The `settings` prop being optional is what hides the tab;
the error inside the tab is deliberately separate from the page-level
`error`, which gates the applications empty state.
5. **`DynamicClientRegistrationSetting.tsx`**: the section. Two things
worth reading closely: the enable path opens the dialog while the
disable path calls straight through, and lacking permission uses the
native `disabled` attribute while an in-flight request uses
`aria-disabled`, so a keyboard user is not blurred mid-flip.
6. **The two story files**: read last, as they exercise everything above
without a real server. The dialog stories query
`canvasElement.ownerDocument.body` rather than `canvasElement`, since
the dialog renders into a portal attached to `<body>`.

## Deliberately not in this PR

- **ENG-3116**: the applications list cannot distinguish self-registered
clients from admin-created ones. Surfacing that needs a new field on
`codersdk.OAuth2ProviderApp`, which is an API addition this PR does not
need.
- **ENG-3118**: reusing the shared `EnabledBadge` and `SettingsHeader`
primitives for this section. Both hinge on what the mockup intends, and
the badge in particular is a visible change either here or on the four
other pages that share it.

## Screenshots

Default (disabled):
<img width="1676" height="497" alt="image"
src="https://github.com/user-attachments/assets/cfa60266-8678-410e-9577-16ef474491e3"
/>



Enabling (confirmation dialog):

<img width="1661" height="558" alt="image"
src="https://github.com/user-attachments/assets/a7d54fdd-f65d-4fec-9ed9-3bfdcfdae5be"
/>



Enabled:

<img width="1666" height="559" alt="image"
src="https://github.com/user-attachments/assets/d39251c2-771c-4608-81c2-dda151b35c3d"
/>

---------

Co-authored-by: Tracy Johnson <tracy@coder.com>
2026-08-03 08:29:35 -07:00
Jake Howell 497ab9e1a6 refactor(site): demui PortForwardButton and popover view (#27786)
Migrate the port-forward popover off MUI and Emotion onto shadcn
Select/FormField and Tailwind.

Replaces FormControl, Select, MenuItem, TextField, Stack, and Link usage
in `PortForwardButton` / `PortForwardPopoverView`, and updates the
popover stories to match.
2026-08-04 01:13:52 +10:00
Jake Howell 0a30dc8184 refactor(site): demui template editor dialogs and create-template inputs (#27791)
Migrate remaining MUI usage in template create/editor flows to shared
shadcn components (`FormField`, `Input`, `Textarea`, `Checkbox`,
`RadioGroup`, `Link`).

Also drops `disablePortal` on the publish-version help popover so it is
no longer clipped by the dialog overflow.
2026-08-04 01:13:34 +10:00
Jake Howell 20ff957c74 refactor(site): demui workspace topbar, schedule controls, and timings (#27790) 2026-08-03 15:04:23 +00:00
Ethan 4dbb3a236c test: fix tailnet connection teardown flake (#27768)
Closes https://github.com/coder/internal/issues/1620
Closes ENG-3043

The callback cleanup added in #20687 stops new node callbacks, but it
can still race with one that's already in flight. That callback may call
`UpdatePeers` after the destination `tailnet.Conn` closes, so the test
fails with `connection closed` even though the redirect behaviour is
correct.

To fix, we'll just ignore `tailnet.ErrConnClosed` in the asynchronous
`stitch` helpers, whilst continuing to assert on every other error.
2026-08-04 01:03:30 +10:00
Marcin TojekandNick Vigilante 07073024ee docs: update 2.35 latest release to v2.35.3 (#27511)
Updates the release calendar in `docs/install/releases/index.md` so the
2.35 mainline row points at the latest patch release `v2.35.3` instead
of `v2.35.2`.

> [!NOTE]
> This PR was generated by Coder Agents on behalf of @mtojek.

---------

Co-authored-by: Nick Vigilante <nickvigilante@users.noreply.github.com>
2026-08-03 14:32:12 +00:00
Jake Howell fc27714fcd refactor(site): demui workspace build data and outdated tooltip (#27787)
Replace Emotion `css` / `useTheme` and MUI `Link` in
`WorkspaceBuildData` and `WorkspaceOutdatedTooltip` with Tailwind
semantic classes and the shared `Link` component.
2026-08-04 00:31:14 +10:00
Nick Vigilante 0e1a9a9f05 ci: run test-go-pg mise tool install under bash on Windows (#27483)
## What

Add `shell: bash` to the `Install Go mise tools` step in the
`test-go-pg` job so it runs under Git bash on the `windows-2022` matrix
leg.

## Why

`test-go-pg (windows-2022)` has been failing in the **Normalize File and
Directory Timestamps** step with:

```
mtimehash: command not found
##[error]Process completed with exit code 127.
```

before any tests run, which trips the aggregate `required` gate.

Root cause: the `Install Go mise tools` step had no `shell:`, so on
Windows it ran under **PowerShell**, while `./.github/scripts/retry.sh`
is a bash script (`#!/usr/bin/env bash`). The step silently no-oped on
Windows (zero output), so `mtimehash` was only present when the mise
tool cache was warm. On a cache miss it was never installed, and the
normalize step failed with exit 127. `main` stays green only because the
cache is usually warm — both green and failing runs use the same
`depot-windows-2022-16` runner, so this is **not** a fork/runner-routing
issue.

Pre-existing CI-tooling issue, unrelated to the change that surfaced it
(a Helm-only community PR, #27360).

## Fix

One line: pin the step to `shell: bash` so the install actually runs on
Windows and repairs a cache miss instead of being silently skipped.

## Verification

<details>
<summary>Local proof that the step's install target builds and
<code>mtimehash</code> runs under bash</summary>

```
$ bash ./.github/scripts/retry.sh --max-attempts 1 -- echo "retry.sh OK under bash"
retry.sh OK under bash

$ GOBIN=/tmp/demobin go install github.com/slsyy/mtimehash/cmd/mtimehash@v1.0.0
$ ls -l /tmp/demobin/mtimehash
-rwxr-xr-x 1 coder coder 6692858 /tmp/demobin/mtimehash

# the tool that was "command not found" now runs and rewrites the mtime:
$ printf 'hello' > /tmp/mt.txt                 # mtime 2026-07-24 15:32
$ find /tmp/mt.txt | /tmp/demobin/mtimehash    # exit 0
$ # mtime now 1997-11-30 (content-hash derived)
```
</details>

Final confirmation is this PR's own `test-go-pg (windows-2022)` run.
Note: if the mise cache is warm on this run the job passes regardless;
the fix specifically hardens the cache-miss path this step exercises on
Windows.

## Follow-up (not in this PR)

- Make the normalize step resilient (skip when `mtimehash` is absent /
invoke via `mise exec`) so a missing cache optimizer can't hard-fail the
job.
- Audit other Windows `run:` steps that invoke `retry.sh`/bash scripts
without `shell: bash`.

Linear: DOCS-605

> This PR was created with AI assistance (Coder Agents).
2026-08-03 10:25:22 -04:00
Susana Ferreira ec9b0f04d1 feat(site): label AI spend as estimated (#27584)
AI spend is estimated by multiplying token usage by a snapshot of
published model prices that ships with each Coder release, so it can
differ from provider invoices.

Label spend figures as estimated and link to the [How spend is
estimated](https://coder.com/docs/@main/ai-coder/ai-gateway/cost-controls#how-spend-is-estimated)
docs section. "Estimated spend" matches the terminology already defined
in the cost controls doc.

## Changes

- Group members tooltip: "Monthly AI spend for this user." becomes
"Estimated monthly AI spend for this user.", followed by an inline docs
link.
- Groups table tooltip: "Current AI spend compared to the group's AI
budget..." becomes "Estimated AI spend compared to...", with the same
link.
- User dropdown: "(AI spend/month)" becomes "(Estimated AI
spend/month)".
- `StatusIconTooltip` now exports `SpendEstimateDocsLink`, shared by
both tooltips.

> [!NOTE]
> Initially generated by Claude Opus 5, modified and reviewed by
@ssncferreira
2026-08-03 14:56:36 +01:00
Susana Ferreira f4110122ec fix(site): link spend page alert to cost control migration section (#27782)
The "Read more here" link in the spend page alert pointed at the top of
the cost controls doc, which doesn't explain the v2.36 move to AI
Governance.
Point it at the `#migrate-from-coder-agents-cost-control` section
instead:
https://coder.com/docs/@main/ai-coder/ai-gateway/cost-controls#migrate-from-coder-agents-cost-control

Related to internal slack thread:
https://codercom.slack.com/archives/C0AEHQGLW22/p1785747924721539
2026-08-03 11:48:22 +01:00
Sas SwartandClaude Opus 4.8 8886a5749a feat: add network calls list to AI session threads API (#27425)
The AI session threads API returned only a network call *summary*
(total/blocked counts + top domains). This adds the per-call list so the
session detail can render individual Agent Firewall network calls.

`ListAIBridgeSessionNetworkCalls` reuses the same sequence-number
windowing as the existing summary and includes all protocols. The list
is exposed as `network_call_logs` on the threads response and is capped
server-side at 100 rows. The summary (`network_calls.total`/`blocked`)
remains authoritative for whole-session totals: the list length and its
blocked count equal the summary only when a session has at most 100
calls, and are truncated beyond that.

### PR map (merge strictly bottom-up)

This change is a 4-PR stack. Each PR depends on all the ones below it,
so merge in this exact order:

1. #27417 — backend network summary
2. #27418 — frontend summary rows
3. #27425 — backend per-call list `network_call_logs`
4. #27426 — frontend network-calls panel

Refs AIGOV-464

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

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-08-03 11:34:27 +02:00
Jake Howell fba9f0d485 refactor(site): migrate <Markdown /> and <InlineMarkdown /> off MUI (#27724)
Replace Emotion `css` / MUI theme tokens in `Markdown` with Tailwind
semantic classes, and swap `InlineMarkdown`'s MUI `Link` for the shared
`Link` component.

Code block colors now use theme tokens (`surface-secondary`,
`syntax-key`, `content-destructive`) instead of hardcoded zinc/teal and
`theme.palette`. Also adds a `WithLink` story for the full Markdown
component.
2026-08-03 19:26:58 +10:00
Jake Howell 31ac9a4782 fix(site): use "Create token" wording in token settings (#27634)
> 🤖 This PR was written by Coder Agents on behalf of Jake Howell.

The token settings page button read **"Add token"**, while everything
else uses **"Create"**:

- The page the button navigates to is titled "Create Token" with a
"Create token" submit button (`CreateTokenPage` / `CreateTokenForm`).
- CLI: `coder tokens create`
- SDK: `CreateToken`
- API: `create-token-api-key` / `CreateTokenRequest`

This aligns the button with the dominant nomenclature by changing "Add
token" → "Create token".
2026-08-03 19:23:50 +10:00
Jake Howell c350710aeb refactor(site): remove mui components from <LicenseSettingsPage /> descendants (#27764)
Migrate license settings views off MUI by replacing `TextField` with
`Textarea` on the add-license form and `MuiLink` with our `Link`
component in the empty licenses state.
2026-08-03 19:19:07 +10:00
Jake Howell a76c51dfc4 fix(site): correct autostop restart prompt on the workspace schedule page (#27632)
> 🤖 This PR was written by Coder Agents on behalf of Jake Howell.

## Problem

Enabling autostop on a running workspace never showed the "restart now
to apply?" dialog. The new TTL was saved, but a running build's deadline
is only calculated when the build starts, so autostop silently did not
take effect until a manual restart. Changing an already-enabled value
did prompt, so the behavior was inconsistent.

Separately, dismissing that dialog with **Apply later** navigated the
user away to the workspace, exactly like confirming did.

## Root cause

The dialog was gated on `getAutostop(workspace).autostopEnabled`, which
derives from `workspace.ttl_ms` — the **pre-submit** state (the
workspace is not refetched until after the mutation). That expression
means "was autostop enabled *before* this change", which maps to:

| Transition | Pre-submit enabled | Dialog | Correct? |
|---|---|---|---|
| Disabled → enabled (add) | `false` | not shown | ❌ the reported bug |
| Enabled → new value (modify) | `true` | shown | ✅ |
| Enabled → disabled (remove) | `true` | shown | ❌ (nothing to apply) |

This guard came from #16085, which intended to *skip* the prompt when
**removing** autostop (safe, because that PR also made the backend clear
a running build's deadline server-side when TTL is set to null). By
keying off the old state it actually skipped the prompt on **add** and
still showed it on **remove** — the opposite of its intent.

## Fix

- Key the prompt off the submitted form value
(`values.autostopEnabled`), with an inline comment documenting the
trigger conditions. This fixes the reported bug and restores #16085's
intent:
  - add → prompt ✅
  - modify → prompt ✅
  - remove → no prompt ✅ (deadline cleared server-side)
  - stopped / unchanged → no prompt ✅
- **Apply later** now just closes the dialog and keeps the user on the
schedule page; the saved value still applies on the next start.
**Restart** is unchanged (restarts and navigates to the workspace).

## Testing

Storybook `play`-function coverage on `WorkspaceSchedulePage` for all
cases: enable, change value, disable, enable-while-stopped,
autostart-only, and Apply-later-stays-on-page (the last also asserts
`restartWorkspace` is not called). A prior story that asserted the
pre-fix behavior (prompting on disable) was reworked. `tsc` and `biome`
clean.

<details>
<summary>Investigation notes</summary>

History of the gating condition:

- Originally `if (data.autostopChanged) { ... }` — prompted on every
autostop change (enable included).
- #16085 ("allow removing deadline for running workspace", fixes #9775)
added `&& getAutostop(workspace).autostopEnabled`. Its description
states the goal was to "not show a confirmation dialog when the change
is to remove autostop", and the same PR added backend logic in
`putWorkspaceTTL` to clear a running build's deadline when TTL is null.
- A later refactor added `&& workspace.latest_build.status ===
"running"`.

Because the backend already clears the deadline live on removal, no
restart is needed there; the frontend only needs to prompt when autostop
ends up enabled on a running workspace. The fix keys off the submitted
state so all three transitions behave correctly.

</details>
2026-08-03 19:11:11 +10:00
Jake Howell 0028fea0e5 refactor(site): migrate VS Code button menus off MUI (#27730)
Replace MUI `Menu`/`MenuItem` (and the Emotion `css` prop) in
`VSCodeDesktopButton` and `VSCodeDevContainerButton` with the shared
shadcn `DropdownMenu`.

The variant selector keeps the split-button layout, sizes the menu to
the button group via an `inline-flex` anchor (so width is not the full
parent), and uses `collisionPadding` so the menu stays inset from the
viewport edge.
2026-08-03 19:09:59 +10:00
Jake Howell 5e29a878f2 refactor(site): demui <ProvisionerTagsField /> (#27763)
Replace MUI `TextField` in `ProvisionerTagsField` with the shared
`Input` component.
2026-08-03 19:09:13 +10:00
Jake Howell ce20ad8b2f refactor(site): demui <NotificationEvents /> into dropdown (#27732)
> [!NOTE]
> We don't have a planned migration path for the MUI `<ToggleGroup />`.
Therefore, I've swapped these to dropdowns as an inbetween.

Migrate deployment notification event settings off MUI
`Card`/`List`/`ToggleButtonGroup` and Emotion styles.

Template groups now use the same Tailwind card layout as user
notification settings, and the delivery method control is a shared
`Select` dropdown with icon + label.

| Old | New |
| --- | --- |
| <img width="1041" height="189" alt="NOTIFICATION_EVENTS_OLD"
src="https://github.com/user-attachments/assets/2fe37dab-1ba2-43c2-9d01-3edf9883054a"
/> | <img width="1041" height="203" alt="NOTIFICATION_EVENTS_NEW"
src="https://github.com/user-attachments/assets/40afc42f-93f6-4972-8e02-dceaf95fb034"
/> |
2026-08-03 19:09:01 +10:00
Jake Howell 26bae42c98 refactor(site): rename <404Page /> to <NotFoundPage /> (#27731)
The component was already named `NotFoundPage`, but it lived under
`pages/404Page/404Page.tsx`. Rename the directory and file to match the
component name, and update the lazy import and organization settings
import paths.
2026-08-03 19:08:44 +10:00