Commit Graph

14287 Commits

Author SHA1 Message Date
Cian Johnston 581f3bdd14 fix(coderd/httpapi): stop writing websocket frames to ResponseRecorder in test (#25284)
The `mockEventSenderWrite` function in `newOneWayWriter()` wrote
WebSocket frame data to both the `net.Pipe` and the
`httptest.ResponseRecorder`. After `websocket.Accept()` calls
`WriteHeader(101)`, the recorder rejects body writes with `"response
status code does not allow body"`. When `HeartbeatClose` sends a ping,
the control frame flush routes through the recorder, producing an
ERROR-level log that `slogtest` catches as a test failure.

Removed the `recorder.Write(b)` call from the write function. The
recorder is only needed for header/status inspection; WebSocket frame
data should only go through the `net.Pipe`.

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

> 🤖 Generated by Coder Agents
2026-05-14 09:15:14 +01:00
Jaayden Halko 024132e8a4 feat: add theme_mode, theme_light, theme_dark to UserAppearanceSettings (#25076)
Part 1: Backend portion of a change broken into 2 PRs.
Part 2: #25077 

Adds three new UserAppearanceSettings fields (theme_mode, theme_light,
theme_dark) on top of the existing theme_preference and terminal_font.
Replaces GetUserThemePreference and GetUserTerminalFont with a single
GetUserAppearanceSettings aggregate query. The PUT handler is wrapped in
db.InTx so sync-mode's mode + slot writes can never half-apply.
2026-05-14 05:44:05 +01:00
Ethan d147dd3bdd feat(site/src/pages/AgentsPage/components): show workspace quota in usage indicator (#25168)
This updates the Agents sidebar usage indicator to surface workspace
quota alongside AI spend limits. When both signals are active, the
compact trigger renders stacked bars in the same order as the dropdown
instead of collapsing them into a single percent.

The dropdown still shows the full labels, percentages, and details for
each usage section, and Storybook coverage now exercises the combined
sidebar state.


<img width="315" height="261" alt="image"
src="https://github.com/user-attachments/assets/e5cfc276-2cc0-4dc9-9400-6d1b829e75e2"
/>

<img width="320" height="243" alt="image"
src="https://github.com/user-attachments/assets/506ae8ad-3d93-4857-9cdb-b3cf4142772d"
/>

<img width="314" height="353" alt="image"
src="https://github.com/user-attachments/assets/5af3644f-f155-43a4-bae9-91b33a0a4333"
/>

<img width="322" height="349" alt="image"
src="https://github.com/user-attachments/assets/9ae4ae55-55aa-4a2f-856e-f462793f389e"
/>




Relates to CODAGT-197
2026-05-14 11:59:00 +10:00
Ethan a35f71cd8a fix(coderd/x/chatd): retry HTTP/2 stream resets (#25170)
Mid-stream HTTP/2 peer resets from LLM providers can arrive after a 200
streaming response has already emitted provisional parts. Previously
those resets fell through as generic non-retryable errors because
`stream ID` messages did not match retryable transport signals, and
stream IDs could be misread as HTTP statuses.

Classify retryable HTTP/2 RST_STREAM codes as transient timeout
failures, ignore stream IDs during status extraction, and keep the
existing `retry` event as the rollback boundary for provisional message
parts so replacement attempts do not replay failed-attempt output.

Closes CODAGT-382
2026-05-14 11:40:43 +10:00
Kayla はな 2943bf5f21 fix(site): use ExternalImage for icon URLs (#25315) 2026-05-13 17:52:05 -06:00
Danielle Maywood ef1093d0dd fix(site): hide sticky metadata user messages (#25316) 2026-05-13 22:27:38 +01:00
Nick Vigilante 7aaa8485db docs: update screenshot to point to generic URL (#25314)
At present, the docs point to an internal URL, so I'm updating the
screenshot to point to a ficticious address.

Fixes DOCS-59
2026-05-13 17:20:09 -04:00
Michael Suchacz d1a471e29e fix(coderd/x/chatd): retune subagent selection guidance (#25311)
> Mux working on behalf of Mike.

## Summary

- retune chatd subagent guidance to prefer `general` for substantial
delegated work, including read-only synthesis and planning support
- narrow `explore` guidance to repository-local code lookup and bounded
tracing
- add regression tests for planning, spawn tool, and Plan Mode guidance
text

## Tests

- `go test ./coderd/x/chatd -run
'Test(DefaultSystemPromptPlanningGuidance_SteersSubagentSelection|SpawnAgent_DescriptionSteersGeneralForSubstantialResearch|SpawnAgent_PlanModeDescriptionOmitsComputerUse|PlanningOverlaySubagentGuidance_UsesPlanModeSafeDescriptions|ExploreSubagentIsReadOnly)$'`
- `make lint`
- `make test TEST_PACKAGES=./coderd/x/chatd RUN=Guidance && make test
TEST_PACKAGES=./coderd/x/chatd RUN=Description`
- pre-commit hook during `git commit`
2026-05-13 23:10:21 +02:00
Kayla はな 341051ceee fix: exclude service accounts from license seat count (#24401) 2026-05-13 13:55:53 -07:00
Zach e0be9bf213 feat: surface missing coder_secret requirements on resolve-autostart (#25081)
Adds `dynamicparameters.EvaluateSecretMismatch` as a shared helper on
top of the existing renderer, then wires it into the resolve-autostart
handler so the UI can surface unsatisfied `coder_secret` requirements in
a template alongside parameter mismatch for autostart.

The lifecycle executor changes will land in a follow-up that depend
on this helper. The UI changes that consume the new `secret_mismatch`
field is also a follow-up.

Generated with assistance from Coder Agents.
2026-05-13 14:20:02 -06:00
Steven Masley 0f505aa4da chore: unhide flag to force unix filepaths in config-ssh (#25142)
Docs now include this flag. This flag is now also viewable in linux/mac
despite it effectively being a `no-op`.

Closes https://github.com/coder/coder/issues/24205
2026-05-13 14:59:33 -05:00
Michael Suchacz 38f586107d refactor: remove agents TUI (#25190) 2026-05-13 21:30:11 +02:00
Kayla はな 660fa9478f style(site): use shorthand for boolean JSX props (#25096) 2026-05-13 10:56:50 -06:00
George K 49c6191bbe fix(coderd/azureidentity): add Azure IMDS G2 chain certificates (#25243)
Azure IMDS attested data signatures can now chain through
Microsoft TLS G2 RSA CA OCSP intermediates, then through the
cross-signed Microsoft TLS RSA Root G2 certificate, before reaching
DigiCert Global Root G2.

coderd did not bundle the new G2 OCSP intermediates or the
cross-signed Microsoft TLS RSA Root G2 bridge certificate, so it could
fail to build a trusted chain for affected IMDS signatures.

Related to:
https://linear.app/codercom/issue/PLAT-205/bug-azure-instance-identity-verification-is-broken
2026-05-13 09:07:44 -07:00
Danielle Maywood 7fe4d97fd0 fix(site): align streaming thinking spacing (#25291) 2026-05-13 17:05:34 +01:00
Thomas Kosiewski b9b8d763e3 refactor(site/src/pages/AgentsPage): break AgentChatPage circular dep (#25287)
`AgentChatPageView.tsx` imported `getPersistedSidebarTabId` /
`savePersistedSidebarTabId` from `AgentChatPage.tsx`, which already
imports `AgentChatPageView`, closing a cycle that `pnpm run
lint:circular-deps`
reports but doesn't fail on (dpdm defaults to exit code 0; the script
is missing `--exit-code circular:1`).

Move the three sidebar-tab localStorage helpers and the key prefix into
`utils/sidebarTabStorage.ts` alongside `draftStorage.ts` and the other
per-chat storage modules. Pure code move, no behavior change.

After this change, `pnpm run lint:circular-deps` reports zero cycles.

---------

Signed-off-by: Thomas Kosiewski <tk@coder.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 17:13:32 +02:00
Jaayden Halko 36200b625e fix: fix flaky storybook test (#25272) 2026-05-13 16:08:18 +01:00
Kyle Carberry 5040ab6fca feat: filter chats by diff URL via the q search parameter (#24970)
Adds a `diff_url:` term to the `q` search parameter on `GET
/api/experimental/chats` so callers can look up the chat associated with
a particular pull request, merge request, or any other URL persisted on
the chat's diff status.

```
q=diff_url:"https://github.com/coder/coder/pull/123"
```

Match is case-insensitive. When the URL lives on a delegated sub-agent's
diff status, the parent chat is returned so the relationship surfaces
from a single lookup.

<details>
<summary>Design notes</summary>

- **Forge-agnostic.** Reuses the existing `chat_diff_statuses.url`
column rather than introducing a `pr:` vocabulary, since the SDK already
documents the URL as "may point to a pull request or a branch page
depending on whether a PR has been opened." Works for GitHub PRs, GitLab
MRs, branch pages, etc.
- **Composes with `archived:`.** The two terms can be combined:
`q=archived:true diff_url:"..."`.
- **Case handling.** The parser used to lowercase the entire `q` string
up front, which would mangle URL path segments. Switched to lowercasing
only the field key inside `searchTerms` (already happens there) and
keeping the value as the caller typed it. The SQL comparison lowercases
on both sides.
- **Validation.** `diff_url` must be a syntactically valid HTTP(S) URL
with a non-empty host. No forge-specific validation.
- **Index.** Adds `idx_chat_diff_statuses_url_lower` on `LOWER(url)` so
the lookup is cheap even on large datasets.
- **Sub-agent fan-in.** `EXISTS` clause matches when the URL lives on
the chat itself or any chat with `root_chat_id` equal to the chat's id,
so a delegated sub-agent's PR pulls in its parent.
- **Deferred.** Sentinels like `pr:any` / `pr:none` and a forge-agnostic
state filter (`diff_state:open|merged|closed`) were intentionally left
out of this change. They couple cleanly to a second forge or a clearer
product call, and shipping them now would lock in vocabulary we may want
to revisit.

</details>

## Tests

- `coderd/searchquery`: parser tests for valid URLs, case handling (key
insensitive, value preserved), composition with `archived:`, and
validation errors (non-HTTP scheme, missing host, malformed URL).
- `coderd/exp_chats_test.go`: end-to-end coverage hitting `ListChats`.
Verifies a root chat matches its own URL, a parent chat surfaces when
only a sub-agent has the URL, lookups are case-insensitive, non-matching
URLs return empty, and invalid URLs return `400`.

---

_This PR was authored by a Coder Agent on behalf of @kylecarbs._
2026-05-13 11:06:42 -04:00
Seth Shelnutt 8eb7051987 fix(scripts/ironbank): update base image to UBI9 and remove urllib3 (CVE-2026-44431) (#25217)
The IronBank Dockerfile used UBI8-minimal:8.7 as its base image.
IronBank has migrated images to UBI9 base, and the bundled urllib3
1.26.5 in the image triggers CVE-2026-44431 (sensitive headers leaked on
cross-origin redirects via the low-level API).

This updates the base image from UBI8-minimal to UBI9-minimal and
explicitly removes python3-urllib3 after package installation. Coder is
a Go binary and does not invoke Python at runtime, so urllib3 is unused.

Refs
[ENT-4](https://linear.app/codercom/issue/ENT-4/ironbank-v23111-update-urllib3-from-1265-to-fix-cve-2026-44431),
[ENT-51](https://linear.app/codercom/issue/ENT-51/ironbank-main-update-base-image-urllib3-cve-2026-44431),
[CVE-2026-44431](https://nvd.nist.gov/vuln/detail/CVE-2026-44431)

> Generated by Coder Agents

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

- **Base image**: Moved from `ubi8-minimal:8.7` to `ubi9-minimal:9.6` to
align with IronBank's UBI9 migration and reduce overall vulnerability
surface.
- **urllib3 removal**: Added explicit `microdnf remove python3-urllib3`
with error suppression (`|| true`) so the build succeeds whether or not
the package is present in the base image. This handles both the minimal
and full UBI9 base image variants that IronBank may use.
- **Crypto policies**: RHEL 9 uses the same
`/etc/crypto-policies/back-ends/*.config` paths as RHEL 8; no changes
needed.
- **Build script**: Updated the `registry.access.redhat.com` override
from `ubi8/ubi-minimal:8.7` to `ubi9/ubi-minimal:9.6` for local builds.

</details>
2026-05-13 10:41:56 -04:00
Jakub Domeracki 1a1f06aa79 fix: verify PKCS7 signature on Azure instance identity tokens (#25286)
Migrates Azure instance identity verification from
`go.mozilla.org/pkcs7` and `github.com/fullsailor/pkcs7` to
`github.com/smallstep/pkcs7`, using `VerifyWithChainAtTime` to validate
both the PKCS7 signature and the certificate chain in one call. The
previous code only verified the signer certificate against a set of
intermediates/roots but did not verify that the PKCS7 signature itself
covered the content, meaning tampered payloads could be accepted.

The `Options` struct is restructured to accept `Roots`, `Intermediates`,
and `CurrentTime` as explicit fields instead of embedding
`x509.VerifyOptions`. The test helper `NewAzureInstanceIdentity` now
builds a realistic 3-level certificate chain (Root CA -> Intermediate CA
-> Signing Cert) matching real Azure trust hierarchy. New tests
(`TestValidate_TamperedContent`,
`TestValidate_UntrustedCertWithValidSignature`) confirm tampered and
untrusted envelopes are rejected.

Addresses GHSA-6x44-w3xg-hqqf.

> [!NOTE]
> This PR was authored by Coder Agents.

<details>
<summary>Implementation Plan</summary>

### Files Changed

| File | Summary |
|------|---------|
| `coderd/azureidentity/azureidentity.go` | Replace `signer.Verify()`
with `VerifyWithChainAtTime`; restructure `Options` struct; add
`ParseCertificates()` helper |
| `coderd/azureidentity/azureidentity_test.go` | Add `testCertChain`
builder, tampered-content and untrusted-cert tests; update existing
tests for new `Options` API |
| `coderd/coderd.go` | Change `AzureCertificates` field from
`x509.VerifyOptions` to `azureidentity.Options` |
| `coderd/workspaceresourceauth.go` | Pass `api.AzureCertificates`
directly instead of wrapping |
| `coderd/coderdtest/coderdtest.go` | Migrate to `smallstep/pkcs7`;
build 3-level cert chain in test helper |
| `go.mod` / `go.sum` | Add `github.com/smallstep/pkcs7`; remove
`fullsailor/pkcs7` and `go.mozilla.org/pkcs7` |

</details>
2026-05-13 14:14:07 +00:00
Danielle Maywood b52c0bdb56 fix(site/src/pages/AgentsPage/components): unify live thinking spacing and sizing (#25192) 2026-05-13 12:51:49 +01:00
Jakub Domeracki 57b11d405f fix(coderd): harden Azure identity certificate fetch (#25274)
Security improvements:
- Restrict cert fetches to a host+port allowlist (Microsoft and DigiCert
on 80/443).
- Route requests through a dedicated `http.Client` that resolves the
host once and dials the validated IP directly, preventing DNS rebinding.
- Reject loopback, private (RFC 1918 / IPv6 ULA), link-local, multicast,
unspecified, CGNAT, benchmarking, and IPv4-mapped IPv6 addresses.
- Cap the certificate response body at 1 MiB.
- Log the underlying error via slog and return a generic detail to the
caller to prevent information disclosure.
2026-05-13 12:51:44 +02:00
Jakub Domeracki 9400eaa957 revert(coderd): "Merge commit from fork" (#25273)
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 12:10:27 +02:00
Mathias Fredriksson 5b87d7b74f feat(agent/agentcontextconfig): discover skills from ~/.coder/skills (#25271)
The default skills lookup only scanned the project-relative
.agents/skills directory, so personal skills had to be repeated
per project or wired in via CODER_AGENT_EXP_SKILLS_DIRS. Now the
default is the comma-separated list ~/.coder/skills,.agents/skills,
which lets discoverSkills's existing first-occurrence-wins policy
prefer home-scoped skills over project ones with the same name.

The change is additive when ~/.coder/skills is absent
(missing directories are silently skipped in discoverSkills) and
unaffects users who set the env var explicitly.

Closes CODAGT-403
2026-05-13 12:56:24 +03:00
Jakub Domeracki fb3aef1883 Merge commit from fork
* fix(coderd): Harden Azure identity certificate fetch

- Restrict cert fetches to a host+port allowlist (Microsoft and
  DigiCert on 80/443).
- Route requests through a dedicated `http.Client` that resolves
  the host once and dials the validated IP directly.
- Reject loopback, private (RFC 1918 / IPv6 ULA), link-local,
  multicast, unspecified, CGNAT, benchmarking, and IPv4-mapped
  IPv6 addresses.
- Cap the certificate response body at 1 MiB.
- Log the underlying error via slog and return a generic detail
  to the caller.
- Add unit tests for the URL allowlist, IP classification, and
  dialer.

* fix(coderd/azureidentity): add IPv6 special-use ranges to SSRF blocklist

The extraBlockedNetworks list only contained IPv4 CIDRs. Add IPv6
equivalents that Go's stdlib classification methods do not cover:

  - 64:ff9b:1::/48  RFC 8215 NAT64 translation
  - 100::/64         RFC 6666 discard-only
  - 2001:2::/48      RFC 5180 benchmarking
  - 2001:db8::/32    RFC 3849 documentation

IPv6 ranges already handled by stdlib (unchanged):

  - ::1/128   (IsLoopback)
  - fc00::/7  (IsPrivate, ULA)
  - fe80::/10 (IsLinkLocalUnicast)
  - ff00::/8  (IsMulticast)
  - ::/128    (IsUnspecified)
2026-05-13 11:55:41 +02:00
Danielle Maywood 5be959e111 fix(agent): retry devcontainer sub-agent rejection test (#25187) 2026-05-13 10:22:51 +01: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
dependabot[bot] eedde58b55 chore: bump protobufjs from 7.5.5 to 7.5.6 in /site (#25222)
Bumps [protobufjs](https://github.com/protobufjs/protobuf.js) from 7.5.5
to 7.5.6.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/protobufjs/protobuf.js/releases">protobufjs's
releases</a>.</em></p>
<blockquote>
<h2>protobufjs: v7.5.6</h2>
<h2><a
href="https://github.com/protobufjs/protobuf.js/compare/protobufjs-v7.5.5...protobufjs-v7.5.6">7.5.6</a>
(2026-04-27)</h2>
<h3>Bug Fixes</h3>
<ul>
<li>Backport input hardening and CLI fixes to 7.x (<a
href="https://redirect.github.com/protobufjs/protobuf.js/issues/2173">#2173</a>)
(<a
href="https://github.com/protobufjs/protobuf.js/commit/75392ea1b78bdc4faba027b5db44ad7c50e9c454">75392ea</a>)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/protobufjs/protobuf.js/blob/protobufjs-v7.5.6/CHANGELOG.md">protobufjs's
changelog</a>.</em></p>
<blockquote>
<h2><a
href="https://github.com/protobufjs/protobuf.js/compare/protobufjs-v7.5.5...protobufjs-v7.5.6">7.5.6</a>
(2026-04-27)</h2>
<h3>Bug Fixes</h3>
<ul>
<li>Backport input hardening and CLI fixes to 7.x (<a
href="https://redirect.github.com/protobufjs/protobuf.js/issues/2173">#2173</a>)
(<a
href="https://github.com/protobufjs/protobuf.js/commit/75392ea1b78bdc4faba027b5db44ad7c50e9c454">75392ea</a>)</li>
</ul>
<h2><a
href="https://github.com/protobufjs/protobuf.js/compare/protobufjs-v7.5.3...protobufjs-v7.5.4">7.5.4</a>
(2025-08-15)</h2>
<h3>Bug Fixes</h3>
<ul>
<li>invalid syntax in descriptor.proto (<a
href="https://redirect.github.com/protobufjs/protobuf.js/issues/2092">#2092</a>)
(<a
href="https://github.com/protobufjs/protobuf.js/commit/5a3769a465fead089a533ad55c21d069299df760">5a3769a</a>)</li>
</ul>
<h2><a
href="https://github.com/protobufjs/protobuf.js/compare/protobufjs-v7.5.2...protobufjs-v7.5.3">7.5.3</a>
(2025-05-28)</h2>
<h3>Bug Fixes</h3>
<ul>
<li>descriptor extensions handling post-editions (<a
href="https://redirect.github.com/protobufjs/protobuf.js/issues/2075">#2075</a>)
(<a
href="https://github.com/protobufjs/protobuf.js/commit/6e255d4ad6982cc857f26e1731c2cedcf5796f68">6e255d4</a>)</li>
</ul>
<h2><a
href="https://github.com/protobufjs/protobuf.js/compare/protobufjs-v7.5.1...protobufjs-v7.5.2">7.5.2</a>
(2025-05-14)</h2>
<h3>Bug Fixes</h3>
<ul>
<li>ensure that types are always resolved (<a
href="https://redirect.github.com/protobufjs/protobuf.js/issues/2068">#2068</a>)
(<a
href="https://github.com/protobufjs/protobuf.js/commit/4b51cb2b8450b77f9f5de1c562e7fae93b19d040">4b51cb2</a>)</li>
</ul>
<h2><a
href="https://github.com/protobufjs/protobuf.js/compare/protobufjs-v7.5.0...protobufjs-v7.5.1">7.5.1</a>
(2025-05-08)</h2>
<h3>Bug Fixes</h3>
<ul>
<li>optimize regressions from editions implementations (<a
href="https://redirect.github.com/protobufjs/protobuf.js/issues/2066">#2066</a>)
(<a
href="https://github.com/protobufjs/protobuf.js/commit/6406d4c18afae309fc7b5f4a24d9674d85da180b">6406d4c</a>)</li>
<li>reserved field inside group blocks fail parsing (<a
href="https://redirect.github.com/protobufjs/protobuf.js/issues/2058">#2058</a>)
(<a
href="https://github.com/protobufjs/protobuf.js/commit/56782bff0c4b5132806eb1a6bc4d08f930c4aaad">56782bf</a>)</li>
</ul>
<h2><a
href="https://github.com/protobufjs/protobuf.js/compare/protobufjs-v7.4.0...protobufjs-v7.5.0">7.5.0</a>
(2025-04-15)</h2>
<h3>Features</h3>
<ul>
<li>add Edition 2023 Support (<a
href="https://github.com/protobufjs/protobuf.js/commit/f04ded3a03a3ddd383f0228e2fe2627a51f31aa3">f04ded3</a>)</li>
<li>add Edition 2023 Support (<a
href="https://github.com/protobufjs/protobuf.js/commit/ac9a3b9fe3134d48187e41b08d54ffaceddc6c1b">ac9a3b9</a>)</li>
<li>add Edition 2023 Support (<a
href="https://github.com/protobufjs/protobuf.js/commit/e5ca5c84e326699e10258367883a54934e0bfe14">e5ca5c8</a>)</li>
<li>add Edition 2023 Support (<a
href="https://github.com/protobufjs/protobuf.js/commit/a84409b47f9ba0dba56da1af8054fb54f85d85a1">a84409b</a>)</li>
<li>add Edition 2023 Support (<a
href="https://github.com/protobufjs/protobuf.js/commit/9c5a178c4b59e0aa65ecac0bd7420171213b2ff9">9c5a178</a>)</li>
<li>add Edition 2023 Support (<a
href="https://github.com/protobufjs/protobuf.js/commit/b2c686721e3b63d092419fa1cbe58e1deb89534e">b2c6867</a>)</li>
<li>add Edition 2023 Support (<a
href="https://github.com/protobufjs/protobuf.js/commit/60f3e51087ca2c247473410f39331e1c766aefef">60f3e51</a>)</li>
<li>add Edition 2023 Support (<a
href="https://github.com/protobufjs/protobuf.js/commit/a6563617de04d510d6e8865eb6c5067f10247f64">a656361</a>)</li>
<li>add Edition 2023 Support (<a
href="https://github.com/protobufjs/protobuf.js/commit/869a95b1e5f553c76243aac45619061407a41084">869a95b</a>)</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/protobufjs/protobuf.js/commit/2189e5beeca6a70e4c104dfdb9fb8200bc5f81fe"><code>2189e5b</code></a>
chore: release protobufjs-v7.x (<a
href="https://redirect.github.com/protobufjs/protobuf.js/issues/2174">#2174</a>)</li>
<li><a
href="https://github.com/protobufjs/protobuf.js/commit/75392ea1b78bdc4faba027b5db44ad7c50e9c454"><code>75392ea</code></a>
fix: Backport input hardening and CLI fixes to 7.x (<a
href="https://redirect.github.com/protobufjs/protobuf.js/issues/2173">#2173</a>)</li>
<li><a
href="https://github.com/protobufjs/protobuf.js/commit/8af8d7c0e9800879625f7d0d4a7fb51beb4410cd"><code>8af8d7c</code></a>
chore(ci): Fix 7.x release please configuration (<a
href="https://redirect.github.com/protobufjs/protobuf.js/issues/2169">#2169</a>)</li>
<li><a
href="https://github.com/protobufjs/protobuf.js/commit/e92ca42244ad67203b48d836290062dae037ead6"><code>e92ca42</code></a>
chore(ci): Enable release-please for 7.x (<a
href="https://redirect.github.com/protobufjs/protobuf.js/issues/2166">#2166</a>)</li>
<li>See full diff in <a
href="https://github.com/protobufjs/protobuf.js/compare/protobufjs-v7.5.5...protobufjs-v7.5.6">compare
view</a></li>
</ul>
</details>
<details>
<summary>Maintainer changes</summary>
<p>This version was pushed to npm by <a
href="https://www.npmjs.com/~GitHub%20Actions">GitHub Actions</a>, a new
releaser for protobufjs since your current version.</p>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=protobufjs&package-manager=npm_and_yarn&previous-version=7.5.5&new-version=7.5.6)](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)
You can disable automated security fix PRs for this repo from the
[Security Alerts page](https://github.com/coder/coder/network/alerts).

</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-12 20:29:06 +00:00
Seth Shelnutt f355e010e8 fix(coderd/database): clean up org memberships when user is soft-deleted (#25149)
The soft-delete cleanup trigger (`delete_deleted_user_resources`)
removed `api_keys`, `user_links`, and `user_secrets` but left
`organization_members` rows intact. When a new user was created with a
previously-deleted user's email, both user IDs had org membership rows
in the same organization, producing duplicate-email members.

Extend the trigger to also delete `organization_members` for the
soft-deleted user. This cascades through the existing
`trigger_delete_group_members_on_org_member_delete`, which cleans up
group memberships automatically. The migration backfills by removing
zombie rows for already-deleted users.

Fixes ENG-831

> [!NOTE]
> 🤖 Generated by Coder Agents

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

**Root cause**: `GetOrganizationIDsByMemberIDs` does not join on
`users.deleted = false`, so stale org membership rows for soft-deleted
users were visible to internal queries. Even the filtered queries
(`OrganizationMembers`, `PaginatedOrganizationMembers`) could surface
duplicate emails when a new active user reused a deleted user's email.

**What changed**:
- Migration 000491 extends `delete_deleted_user_resources()` to `DELETE
FROM organization_members WHERE user_id = OLD.id`
- Backfill removes existing zombie org memberships for soft-deleted
users
- `TestOrgMembersSoftDeleteTrigger` covers org membership removal, raw
row cleanup, and cascading group membership cleanup
</details>
2026-05-12 16:20:25 -04:00
Kayla はな 9810d299d2 chore: make dynamic parameters TemplateEmbedPage the default (#25069) 2026-05-12 18:28:36 +00: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
Ben Potter 5e44c71305 docs: call out coder/skills setup skill on install and quickstart pages (#25194)
<!--

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-05-12 12:36:00 -05:00
dependabot[bot] 4b54925abc chore: bump the x group across 1 directory with 7 updates (#25198)
Bumps the x group with 4 updates in the / directory:
[golang.org/x/crypto](https://github.com/golang/crypto),
[golang.org/x/mod](https://github.com/golang/mod),
[golang.org/x/net](https://github.com/golang/net) and
[golang.org/x/tools](https://github.com/golang/tools).

Updates `golang.org/x/crypto` from 0.50.0 to 0.51.0
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/golang/crypto/commit/b8a14a8d65f88c0c79c139171f1354c69a6cdb8a"><code>b8a14a8</code></a>
go.mod: update golang.org/x dependencies</li>
<li><a
href="https://github.com/golang/crypto/commit/9d9d5078968ddb8a279092c665a24e7de4178778"><code>9d9d507</code></a>
x509roots/fallback/bundle: fix bundle test with Go 1.27+</li>
<li><a
href="https://github.com/golang/crypto/commit/fd0b90d21f9ab4b5dd398e9526b570bfea86e370"><code>fd0b90d</code></a>
acme: include Problem in OrderError.Error</li>
<li><a
href="https://github.com/golang/crypto/commit/b9e53593a6073e6a786c49e9ad27956a9b77e54e"><code>b9e5359</code></a>
pbkdf2: turn into a wrapper for crypto/pbkdf2</li>
<li><a
href="https://github.com/golang/crypto/commit/cc0e4fc1d49127130b0d00612a2eeed2ab745d40"><code>cc0e4fc</code></a>
hkdf: forward Extract to the standard library</li>
<li><a
href="https://github.com/golang/crypto/commit/a8e9237a216b050e1b11e041863825104a6811db"><code>a8e9237</code></a>
x509roots/fallback: update bundle</li>
<li>See full diff in <a
href="https://github.com/golang/crypto/compare/v0.50.0...v0.51.0">compare
view</a></li>
</ul>
</details>
<br />

Updates `golang.org/x/mod` from 0.35.0 to 0.36.0
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/golang/mod/commit/643da9ba74f1165d8cae1505d453b3de3cf21b7b"><code>643da9b</code></a>
go.mod: update golang.org/x dependencies</li>
<li><a
href="https://github.com/golang/mod/commit/ccc3cdf529d1eee2a832437eb1b85240044d21cb"><code>ccc3cdf</code></a>
zip: include 'but content has correct sum' note in TestVCS</li>
<li><a
href="https://github.com/golang/mod/commit/ab3031803214705d2c9f1102318b083e7086a155"><code>ab30318</code></a>
zip: update zip hashes for new flate compression</li>
<li>See full diff in <a
href="https://github.com/golang/mod/compare/v0.35.0...v0.36.0">compare
view</a></li>
</ul>
</details>
<br />

Updates `golang.org/x/net` from 0.53.0 to 0.54.0
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/golang/net/commit/b138e06246cb323f2f380c2b7f7dd91f581dd56b"><code>b138e06</code></a>
go.mod: update golang.org/x dependencies</li>
<li><a
href="https://github.com/golang/net/commit/689f70a42abd350f3a1aaa70b0d13eb9543d927a"><code>689f70a</code></a>
quic: fix wrong final size being used for RESET_STREAM frame</li>
<li><a
href="https://github.com/golang/net/commit/208f306b2f0fd008b388bee2c2644be279778e94"><code>208f306</code></a>
http3: increase handshake timeout</li>
<li><a
href="https://github.com/golang/net/commit/49810da71b9026da9e0d028a6ad8c7730c52d9c4"><code>49810da</code></a>
http2: enable net/http wrapping when go &gt;= 1.27</li>
<li><a
href="https://github.com/golang/net/commit/5e11a5ab891c117eda83b4304d60dd13286c1c76"><code>5e11a5a</code></a>
quic: fix data race in streamForFrame</li>
<li><a
href="https://github.com/golang/net/commit/8c63081cd380ea768db5651941614b73472160ff"><code>8c63081</code></a>
http2: use empty Transport rather than DefaultTransport in
http2wrap</li>
<li><a
href="https://github.com/golang/net/commit/fc7b466ca49cb204039630533ece4fc557eb35cd"><code>fc7b466</code></a>
http2: add http2wrap test</li>
<li><a
href="https://github.com/golang/net/commit/15c2cb1875fd727313dc4de909b3ee149422fbe2"><code>15c2cb1</code></a>
http2: avoid overflowing 32-bit int when http2wrap enabled</li>
<li><a
href="https://github.com/golang/net/commit/64651885c2f2d745d77af2d7af2edbf568c179af"><code>6465188</code></a>
http2: add wrapped Server</li>
<li><a
href="https://github.com/golang/net/commit/72f419a894cb0597dd5b6bcf119086bf2af41231"><code>72f419a</code></a>
http2: add wrapped ClientConn</li>
<li>Additional commits viewable in <a
href="https://github.com/golang/net/compare/v0.53.0...v0.54.0">compare
view</a></li>
</ul>
</details>
<br />

Updates `golang.org/x/sys` from 0.43.0 to 0.44.0
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/golang/sys/commit/fb1facd76f95fa87c151018200ea5e4892ff115d"><code>fb1facd</code></a>
windows: avoid uint16 overflow in NewNTUnicodeString</li>
<li><a
href="https://github.com/golang/sys/commit/94ad893e1e59c1d079221324d38945d2aad8703f"><code>94ad893</code></a>
windows: add GetIfTable2Ex, GetIpInterface{Entry,Table},
GetUnicastIpAddressT...</li>
<li><a
href="https://github.com/golang/sys/commit/54fe89f8411576c06b345b341ca79a77d878a4ad"><code>54fe89f</code></a>
cpu: use IsProcessorFeaturePresent to calculate ARM64 on windows</li>
<li><a
href="https://github.com/golang/sys/commit/df7d5d7b60641d17d87e2b50911124cb65f954fd"><code>df7d5d7</code></a>
unix: automatically remove container created by mkall.sh</li>
<li><a
href="https://github.com/golang/sys/commit/68a4a8e945b22751c1a619261b1d755372a1d5f7"><code>68a4a8e</code></a>
unix: avoid nil pointer dereference in Utime</li>
<li><a
href="https://github.com/golang/sys/commit/690c91f6ecf3b3ef141ad2aedb1306a868b3a176"><code>690c91f</code></a>
unix: add CPUSetDynamic for systems with more than 1024 CPUs</li>
<li>See full diff in <a
href="https://github.com/golang/sys/compare/v0.43.0...v0.44.0">compare
view</a></li>
</ul>
</details>
<br />

Updates `golang.org/x/term` from 0.42.0 to 0.43.0
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/golang/term/commit/3c3e4855f7d2eb06c3e48933554add9ec6b599b5"><code>3c3e485</code></a>
go.mod: update golang.org/x dependencies</li>
<li>See full diff in <a
href="https://github.com/golang/term/compare/v0.42.0...v0.43.0">compare
view</a></li>
</ul>
</details>
<br />

Updates `golang.org/x/text` from 0.36.0 to 0.37.0
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/golang/text/commit/3ef517e623a4bfc08d6457f87d73afda7af7d8e1"><code>3ef517e</code></a>
go.mod: update golang.org/x dependencies</li>
<li>See full diff in <a
href="https://github.com/golang/text/compare/v0.36.0...v0.37.0">compare
view</a></li>
</ul>
</details>
<br />

Updates `golang.org/x/tools` from 0.44.0 to 0.45.0
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/golang/tools/commit/2aabba0e4be44cc8f254ced118a7156d04bbc9f3"><code>2aabba0</code></a>
go.mod: update golang.org/x dependencies</li>
<li><a
href="https://github.com/golang/tools/commit/ef989b3f45baff2849e87f4a70d9a189be5a6959"><code>ef989b3</code></a>
go/types/internal/play: show Info.Instances[Ident]</li>
<li><a
href="https://github.com/golang/tools/commit/21d44f2f2bb3f3a8e06e35523d14bb70cb275c89"><code>21d44f2</code></a>
go/analysis/passes/inline: document skipping of TestF-&gt;F calls</li>
<li><a
href="https://github.com/golang/tools/commit/ec83c2190d81a18bbd472cc1498575b168017e5d"><code>ec83c21</code></a>
go/analysis/passes/modernize: minmax: only remove exact userdefined</li>
<li><a
href="https://github.com/golang/tools/commit/5625353d39195f1deb9261c5ee983abbdc4a15ca"><code>5625353</code></a>
go/analysis/passes/modernize: improve value variable name
generation</li>
<li><a
href="https://github.com/golang/tools/commit/15a3bd5d4ce0651f5cf43ea125db2110c67b257b"><code>15a3bd5</code></a>
gopls/internal/analysis/errorsastype: imporove example clarity</li>
<li><a
href="https://github.com/golang/tools/commit/cd57ef8f8dd7a30ef500bfe1eef0779223cbdfc3"><code>cd57ef8</code></a>
go/packages: include dependency errors when CompiledGoFiles is
missing</li>
<li><a
href="https://github.com/golang/tools/commit/053fdbcef55e8f977d8decc0fde2920c61eb5374"><code>053fdbc</code></a>
go/analysis/passes/modernize: minmax: fix pure operands only</li>
<li><a
href="https://github.com/golang/tools/commit/bf84681c4a0185014c089cffd533e22bbeffcb49"><code>bf84681</code></a>
go/analysis/passes/errorsas: add example of invalid errors.As use</li>
<li><a
href="https://github.com/golang/tools/commit/23921d1decfe5da40309ac183353c8cb38b03dfa"><code>23921d1</code></a>
gopls: add errorsastype analyzer</li>
<li>Additional commits viewable in <a
href="https://github.com/golang/tools/compare/v0.44.0...v0.45.0">compare
view</a></li>
</ul>
</details>
<br />

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-12 17:33:46 +00:00
dependabot[bot] 0234422a55 chore: bump google.golang.org/api from 0.277.0 to 0.278.0 (#25201)
Bumps
[google.golang.org/api](https://github.com/googleapis/google-api-go-client)
from 0.277.0 to 0.278.0.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/googleapis/google-api-go-client/releases">google.golang.org/api's
releases</a>.</em></p>
<blockquote>
<h2>v0.278.0</h2>
<h2><a
href="https://github.com/googleapis/google-api-go-client/compare/v0.277.0...v0.278.0">0.278.0</a>
(2026-05-05)</h2>
<h3>Features</h3>
<ul>
<li><strong>all:</strong> Auto-regenerate discovery clients (<a
href="https://redirect.github.com/googleapis/google-api-go-client/issues/3582">#3582</a>)
(<a
href="https://github.com/googleapis/google-api-go-client/commit/76b1187e506ac0f48caac67907dd0805b253f74c">76b1187</a>)</li>
<li><strong>all:</strong> Auto-regenerate discovery clients (<a
href="https://redirect.github.com/googleapis/google-api-go-client/issues/3584">#3584</a>)
(<a
href="https://github.com/googleapis/google-api-go-client/commit/e36c88361d11545583325c3ac6bdbd9cf1f1a7d0">e36c883</a>)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/googleapis/google-api-go-client/blob/main/CHANGES.md">google.golang.org/api's
changelog</a>.</em></p>
<blockquote>
<h2><a
href="https://github.com/googleapis/google-api-go-client/compare/v0.277.0...v0.278.0">0.278.0</a>
(2026-05-05)</h2>
<h3>Features</h3>
<ul>
<li><strong>all:</strong> Auto-regenerate discovery clients (<a
href="https://redirect.github.com/googleapis/google-api-go-client/issues/3582">#3582</a>)
(<a
href="https://github.com/googleapis/google-api-go-client/commit/76b1187e506ac0f48caac67907dd0805b253f74c">76b1187</a>)</li>
<li><strong>all:</strong> Auto-regenerate discovery clients (<a
href="https://redirect.github.com/googleapis/google-api-go-client/issues/3584">#3584</a>)
(<a
href="https://github.com/googleapis/google-api-go-client/commit/e36c88361d11545583325c3ac6bdbd9cf1f1a7d0">e36c883</a>)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/googleapis/google-api-go-client/commit/07c758daacbc24e32753c3f1b537c7f6cce626f0"><code>07c758d</code></a>
chore(main): release 0.278.0 (<a
href="https://redirect.github.com/googleapis/google-api-go-client/issues/3583">#3583</a>)</li>
<li><a
href="https://github.com/googleapis/google-api-go-client/commit/e36c88361d11545583325c3ac6bdbd9cf1f1a7d0"><code>e36c883</code></a>
feat(all): auto-regenerate discovery clients (<a
href="https://redirect.github.com/googleapis/google-api-go-client/issues/3584">#3584</a>)</li>
<li><a
href="https://github.com/googleapis/google-api-go-client/commit/76b1187e506ac0f48caac67907dd0805b253f74c"><code>76b1187</code></a>
feat(all): auto-regenerate discovery clients (<a
href="https://redirect.github.com/googleapis/google-api-go-client/issues/3582">#3582</a>)</li>
<li>See full diff in <a
href="https://github.com/googleapis/google-api-go-client/compare/v0.277.0...v0.278.0">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=google.golang.org/api&package-manager=go_modules&previous-version=0.277.0&new-version=0.278.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-05-12 17:19:34 +00:00
Thomas Kosiewski 969da320ec feat: export Coder Agents debug logs (#25039)
Adds JSON export actions to the Coder Agents Debug panel so users can download either the current chat's recent debug runs or one expanded run for support sharing.

The export reuses the existing chat debug endpoints and react-query cache, adds Storybook and unit coverage for the JSON envelope, and updates the chat debug logging docs with UI and cURL instructions.

Refs CODAGT-280.

Generated by Coder Agents.

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

- Chat-level export fetches full detail for each listed debug run with `queryClient.fetchQuery(chatDebugRun(chatId, run.id))` and writes a single JSON file.
- Run-level export uses the already-loaded detail query data from an expanded run card.
- The JSON envelope includes `version`, `scope`, `exported_at`, `chat_id`, and either `runs` or `run`.
- The chat-level export reflects the current backend list endpoint behavior, up to the 100 newest debug runs.
- Agent-browser dogfooding verified files were downloaded and that `jq` validated the chat-level and run-level JSON contents.

</details>
2026-05-12 17:39:57 +02:00
Kyle Carberry 147f50c5e8 fix(agent/x/agentmcp): watch MCP config files for late-appearing or rewritten config (#25172)
## Bug

`agent/x/agentmcp/Manager` resolves its config paths once at boot, calls
`Reload`, and then only re-stats them lazily when a `GET
/api/v0/mcp/tools` request arrives (PR #24700). If any of the manager's
MCP config files (`~/.mcp.json` by default, or whatever paths
`agentcontextconfig.MCPConfigFiles()` resolves from
`CODER_AGENT_EXP_MCP_CONFIG_FILES`) is created, atomically rewritten, or
removed _after_ that initial `Reload` and _before_ the next tools HTTP
request, the manager keeps serving the stale (often empty) snapshot.
`parseAndDedup` silently swallows `fs.ErrNotExist`, so a late-appearing
file looks indistinguishable from "no config" until something pokes the
manager again.

This affects any workspace where the file lands after
`MarkStartupSettled` fires, including:

- a startup script that writes `~/.mcp.json` after MCP init
- a user creating or editing the file mid-session
- an installer, dotfiles step, or sync tool writing the file later in
startup
- another agent process (Claude Code, etc.) producing the file
out-of-band
- editor rewrites that land as `Write + Chmod + Rename` bursts

### Concrete repro (dual-agent workspace)

The race is easiest to reproduce on dual-agent workspaces (inner sandbox
+ outer host), where the inner agent's `scriptRunner` has
`script_count=0` and `mcpManager.Reload` fires at ~t+0.3 s while the
host agent writes `~/.mcp.json` ~21 s later. Timeline from
`workspace-otto-aa16`:

- agent up `20:23:38.918`
- lifecycle Ready `20:23:39.200`
- MCP config file Birth `20:24:00.460` (~21 s gap)
- no MCP log lines for 8 minutes
- first `GET /api/v0/mcp/tools` at `20:32:11.812` logs `[warn] mcp: mcp
reload canceled by caller`, takes 4946 ms; subsequent turns are cached
at 2 ms.

The single-agent case has the same race; it's just usually narrow enough
that the next HTTP request masks it, at the cost of a multi-second stall
on the first call that has to do the lazy reload itself. PR #25034's
`MarkStartupSettled` does not help: "settled" fires before the file is
necessarily on disk.

## Fix

Add an fsnotify-backed `configWatcher` to `agent/x/agentmcp/Manager`.
The watcher consumes whatever paths the manager is told to reload, which
is the same `[]string` returned by
`agentcontextconfig.MCPConfigFiles()`.

For each path the watcher:

- Watches the **parent directory** of the path, not the file itself.
This handles late creation, atomic rewrite (rename + create), and
deletion uniformly because inotify watches on individual non-existent
files return `ENOENT` and are lost across renames. The pattern matches
`agent/agentcontainers/watcher`.
- Walks up to the first existing **ancestor directory** when the parent
does not yet exist, and re-arms deeper on `Create` events that promote
an unrealized path.
- Refcounts directory watches so multiple configured paths sharing a
parent dir only register one inotify watch.
- Resolves symlinks **once at arming time** via `filepath.EvalSymlinks`;
never chases arbitrary symlink targets on events.
- Debounces multi-event editor writes through a single
`quartz.AfterFunc` timer so a `Write + Chmod + Rename` burst produces
one reload.
- Fires a debounced callback that calls `Manager.Reload`, which routes
through the existing singleflight so concurrent triggers coalesce.
- Re-syncs on every `Reload` call so a future path-list change is picked
up.

Lifecycle: the watcher is armed lazily on the first `Reload` (no
goroutine cost for unit tests that never reload). `Manager.Close` marks
the manager closed and closes its `closedCh` before tearing down the
watcher, so any in-flight watcher-driven reload observes the close via
`waitReload` and returns `ErrManagerClosed` instead of blocking
`firesWG.Wait()` on a stuck connect. The watcher then waits for its
goroutine and any in-flight debounced `fire` callback before returning.

`parseAndDedup` behavior is unchanged: `fs.ErrNotExist` still records an
empty snapshot. With the watcher armed before that snapshot is
committed, any `Create` event that races `parseAndDedup` is still
delivered.

This is the agent-side complement to PR #25169, which fixes chatd's
mid-turn workspace MCP discovery. `MarkStartupSettled` semantics are not
changed.

## Tests (`agent/x/agentmcp/configwatcher_internal_test.go`)

All new tests pass with the fix and fail without it. No `time.Sleep`;
synchronization uses `testutil.Eventually` for fsnotify-driven
assertions and the quartz mock clock for debounce assertions.

- `TestWatcher_LateFileTriggersReload` - the late-file regression: empty
dir, settle startup, `Reload` sees no file, write the file later,
watcher reloads, tools appear.
- `TestWatcher_RewriteTriggersReload` - existing file overwritten with a
new server list, watcher reloads, cache reflects new server.
- `TestWatcher_RemovalTransitionsToEmpty` - delete the file, watcher
reloads, manager transitions to empty cleanly.
- `TestWatcher_DebouncesBurst` - quartz mock clock; three back-to-back
`scheduleFire` calls produce exactly one `onChange` after `AdvanceNext`.
- `TestWatcher_CloseStopsGoroutine` - construct/Reload/Close five times
to surface goroutine or fd leaks under `-race`.
- `TestWatcher_DualAgentHTTPNoStall` - integration: write file after
`Reload`, wait for watcher reload, then `GET /tools` returns the MCP
tools in less than `testutil.WaitShort` instead of the multi-second
"reload canceled" stall.
- `TestWatcher_LateParentDirTriggersReload` - parent dir doesn't exist
at `Reload` time; create the dir then the file; watcher re-arms deeper
and reloads.
- `TestWatcher_SharedParentRefcount` - two configured paths share a
parent dir; only one inotify watch is registered and both reload on
changes.
- `TestWatcher_CloseDoesNotStallOnInFlightReload` - installs a
`connectStartedHook` to block a watcher-driven reload mid-`connectAll`,
then asserts `Close()` returns within `WaitMedium`. Regression-verified:
reverting the close-ordering causes the test to time out.

## Acceptance checklist

- [x] `go test ./agent/x/agentmcp/... -race -count=1` passes (also
`-count=5`).
- [x] All `./agent/...` tests pass under `-race -short`.
- [x] No emdash, endash, or ` -- `; `scripts/check_emdash.sh` clean.
- [x] No `time.Sleep` in tests.
- [x] New tests fail without the fix and pass with it (verified by
temporarily disabling `m.armWatcher(paths)` and by reverting `Close()`
ordering).

## Out of scope

No changes to chatd's mid-turn workspace MCP discovery (PR #25169) or
`MarkStartupSettled` semantics.

---

<sub>This pull request was prepared by a [Coder
Agents](https://coder.com/docs/admin/ai-coder) run.</sub>
2026-05-12 11:32:39 -04:00
Atif Ali e6e2d9789e docs: mention making the GitHub App public and APP_INSTALL_URL (#25188)
## Summary

The GitHub App walkthrough in `docs/admin/external-auth/index.md` stops
after \"install the app for your organization,\" which is enough for the
admin who created the app but not for anyone else. Every other Coder
user hitting **Link GitHub** lands on a GitHub 404 (`This is not the web
page you are looking for`) because:

1. New GitHub Apps default to **\"Only on this account\"** / not public.
GitHub returns 404 from the OAuth-authorize URL for any user other than
the owner.
2. `CODER_EXTERNAL_AUTH_0_APP_INSTALL_URL` — the env var that makes
Coder render an \"Install GitHub App\" link in the UI — is undocumented
today.

This PR adds one extra step at the end of the GitHub App configuration
walkthrough covering both.

## Test plan

- [x] \`make fmt/markdown\` clean
- [x] Doc reviewer eyes
2026-05-12 15:02:00 +00:00
Yevhenii Shcherbina b5e1ea33d8 feat: add AI budget policy and period deployment config (#25122)
Closes
https://linear.app/codercom/issue/AIGOV-283/add-deployment-config-for-ai-budget-policy-and-period

Adds `CODER_AI_BUDGET_POLICY` and `CODER_AI_BUDGET_PERIOD` deployment
options for AI Governance cost controls.
2026-05-12 10:48:36 -04:00
Ethan fabf7d31fc test: use default provider in TestPatchChatMessage/ChangesModel (#25189)
`TestPatchChatMessage/ChangesModel` hardcoded `"openai"` as the provider
for the override model config. After #25171, the shared chat test
harness registers a single `"openai-compat"` provider by default, so
calling `createAdditionalChatModelConfig(..., "openai", ...)` fails with
HTTP 400 `Chat provider is not configured` before the test can exercise
the model-change path. The subtest was added in #25084 after #25171 was
reviewed, so the harness change and the new hardcoded provider only met
on `main`.

Use `defaultModel.Provider` so the override always matches whatever
provider the harness registered. This mirrors every other call site of
`createAdditionalChatModelConfig` in the file.

Closes https://github.com/coder/internal/issues/1530
2026-05-12 14:05:08 +00:00
Thomas Kosiewski 38091f1d82 fix(site/src/pages/AgentsPage/components/ChatConversation): remove attachment copy actions (#25119)
Messages with chat file attachments showed a `Copy message` action even
though the action only copied `parsed.markdown` and omitted the
attachment content.

Hide the message copy action whenever a parsed message contains file
attachments, and add regression coverage for both user and assistant
attachment messages.

Refs
https://linear.app/codercom/issue/CODAGT-344/remove-or-fix-copy-buttons-on-file-attachments

Generated by Coder Agents.
2026-05-12 15:46:39 +02:00
Atif Ali 97ee54a8c1 fix(site): clarify deleted workspace actions (#25186)
## Summary
Updates the deleted workspace banner so its CTA recreates from the
original template instead of sending users to the generic templates
list.

## Changes
- Change the CTA to `Create another from <template>`.
- Link the CTA to the original template workspace create flow.
- Shorten the banner copy to `This workspace has been deleted.`

## Validation
- `pnpm exec biome check --error-on-warnings
src/pages/WorkspacePage/Workspace.tsx
src/pages/WorkspacePage/WorkspaceDeletedBanner.tsx
src/pages/WorkspacePage/WorkspaceDeletedBanner.stories.tsx`
- `pnpm run lint:types`
- `git diff --check`
- `git commit` pre-commit hooks

> 🤖 This PR was created with the help of Coder Agents, and needs a human
review. 🧑💻
2026-05-12 18:45:20 +05:00
Ben Potter cc001ccaf0 docs(docs/ai-coder/ai-gateway/clients): fix enable_aibridge -> enable_ai_gateway (#25098)
The Claude Code and Codex CLI registry modules expose the variable as
`enable_ai_gateway`, not `enable_aibridge`. Templates using the docs as
written fail Terraform init with `An argument named "enable_aibridge" is
not expected here.`

Verified in
[`registry/coder/modules/claude-code/main.tf`](https://github.com/coder/registry/blob/main/registry/coder/modules/claude-code/main.tf)
and
[`registry/coder-labs/modules/codex/main.tf`](https://github.com/coder/registry/blob/main/registry/coder-labs/modules/codex/main.tf),
where the variable is declared as `enable_ai_gateway` and gates the
`ANTHROPIC_BASE_URL` / `ANTHROPIC_AUTH_TOKEN` injection.

_Generated with the help of Coder Agents._
2026-05-12 08:18:41 -05:00
Michael Suchacz 96333acda3 fix(coderd): filter build instance agents in SQL (#25031)
Replaces the per-agent Go-side template-version filter in
`handleAuthInstanceID` with a purpose-built SQL query.

`GetWorkspaceBuildAgentsByInstanceID` joins `workspace_agents ->
workspace_resources -> workspace_builds -> provisioner_jobs ->
workspaces` and excludes:

- non-`workspace_build` provisioner jobs (template-version-import,
dry-run)
- deleted agents and sub-agents
- deleted workspaces

The handler:

- drops the per-candidate `GetWorkspaceResourceByID` /
`GetProvisionerJobByID` lookups
- drops the `provisioner_jobs.input` JSON parsing and the follow-up
`GetWorkspaceBuildByID` call
- compares `latestHistory.ID` against `selected.WorkspaceBuildID`
returned directly from the query
- preserves the existing recycled-instance safety check and matching
response codes

One intentional behavior tightening: agents whose workspace is deleted
now return 404 (previously they could reach the recycled-instance check
and return 400, or 200 if the stale build was still latest). This
matches the existing token-auth path, which already refuses to
authenticate against deleted workspaces.

The original `GetWorkspaceAgentsByInstanceID` query is intentionally
untouched. It remains the generic raw lookup used elsewhere in tests and
helpers.

The dbauthz wrapper for the new query uses the system-read fast path
with `fetchWithPostFilter` for non-system reads, with `RBACObject()`
delegating to the embedded `WorkspaceTable`.

Tests:

- new `TestGetWorkspaceBuildAgentsByInstanceID` covering newest-first
ordering, exclusion of deleted/sub agents, exclusion of template-import
and dry-run jobs, and exclusion of deleted workspaces
- new dbauthz mock test for `GetWorkspaceBuildAgentsByInstanceID`
- new `TestPostWorkspaceAuthAWSInstanceIdentity/RecycledInstanceID`
exercising the recycled-instance rejection branch (HTTP 400 when the
agent's build is no longer latest)
- existing `TestPostWorkspaceAuth{AWS,Azure,Google}InstanceIdentity`
continue to cover the handler end to end (including the template-version
+ workspace-build same-instance-ID scenario via
`setupInstanceIDWorkspace`)

> Mux is acting on Mike's behalf.
2026-05-12 14:55:56 +02:00
Kyle Carberry b0b07536fc feat: add opt-in Coder identity headers for MCP servers (#25153) 2026-05-12 08:54:53 -04:00
Michael Suchacz f1d160c7f4 fix: allow changing model when editing earlier chat message (#25084)
Editing a previous user message and selecting a different model in the
picker silently kept using the original model: the selection was dropped
on the frontend, in the SDK, and in the backend, so both the replacement
user message and the assistant turn that followed ran against the old
model.

Plumb the selected model through all three layers (`AgentChatPage`,
`codersdk.EditChatMessageRequest`, `chatd.EditMessageOptions` /
`Server.EditMessage`), defaulting to the original message's model when
the client does not specify one. The existing `InsertChatMessages` CTE
already advances `chats.last_model_config_id` when the inserted
message's model differs, so the assistant turn picks up the new
selection without further changes. The new model is validated inside the
transaction, so an unknown ID rolls the edit back and returns a 400
`Invalid model config ID.`, mirroring the `SendMessage` path.

Refs: CODAGT-345

This change was generated by a Coder agent.

<details>
<summary>Implementation plan</summary>

# CODAGT-345: Editing an earlier message cannot change model

## Problem

When editing a previous user message in a chat, the user can change the
model in the model picker, but the backend keeps using the original
message's model. The model selection is dropped at three layers:

1. **Frontend:** `AgentChatPage.tsx`'s edit branch builds an
`EditChatMessageRequest` that omits `model_config_id`. The new-message
branch (a few lines below) does include it.
2. **SDK:** `codersdk.EditChatMessageRequest` has no `ModelConfigID`
field at all.
3. **Backend:** `chatd.EditMessageOptions` has no model field, and
`Server.EditMessage` always copies the original message's
`ModelConfigID` into the replacement message.

Once the replacement user message is inserted with the original model,
the `InsertChatMessages` CTE leaves `chats.last_model_config_id`
unchanged, so the assistant turn that follows runs against the old
model.

## Fix

Plumb the selected model through all three layers, defaulting to the
original message's model when the client doesn't override it. This
mirrors the `SendMessage` path, which already accepts a
`model_config_id` and validates it via
`resolveSendMessageModelConfigID`.

### Backend

- `codersdk/chats.go`: add `ModelConfigID *uuid.UUID` to
`EditChatMessageRequest`.
- `coderd/x/chatd/chatd.go`:
  - Add `ModelConfigID uuid.UUID` to `EditMessageOptions`.
- In `EditMessage`, after fetching the edited message, resolve the
model: if `opts.ModelConfigID != uuid.Nil`, validate it exists with
`tx.GetChatModelConfigByID` (using `chatdModelConfigLookupContext`),
otherwise keep `editedMsg.ModelConfigID.UUID`. Pass the resolved ID into
`newChatMessage(...)`.
  - Reuse the existing `ErrInvalidModelConfigID` sentinel.
- `coderd/exp_chats.go` (`patchChatMessage`):
- Read `req.ModelConfigID` (nil-safe), pass into
`chatd.EditMessageOptions`.
- Add a `case xerrors.Is(editErr, chatd.ErrInvalidModelConfigID)` arm
returning 400 `Invalid model config ID.`, matching the
`postChatMessages` handler.

### Frontend

- `site/src/pages/AgentsPage/AgentChatPage.tsx`:
- In the edit branch, set `model_config_id: effectiveSelectedModel ||
undefined` on the `EditChatMessageRequest`.
- On success, persist the chosen model to `lastModelConfigIDStorageKey`
so the next chat from this browser keeps the same default. Mirrors the
new-message branch.

### Generated

- `make site/src/api/typesGenerated.ts` and `make
coderd/apidoc/swagger.json` produce the updated `EditChatMessageRequest`
schema in `typesGenerated.ts`, `coderd/apidoc/{docs.go,swagger.json}`,
and `docs/reference/api/{chats.md,schemas.md}`.

## Tests

- `coderd/x/chatd/chatd_test.go`:
- `TestEditMessageWithModelConfigOverride`: edit with a different model
-> replacement message and `chats.LastModelConfigID` use the new model.
- `TestEditMessagePreservesModelConfigByDefault`: edit without
`ModelConfigID` -> original model preserved.
- `TestEditMessageRejectsUnknownModelConfig`: passes a random UUID ->
`ErrInvalidModelConfigID`, original message still present,
`LastModelConfigID` unchanged (rollback).
- `coderd/exp_chats_test.go` (under `TestPatchChatMessage`):
- `ChangesModel`: end-to-end via SDK; `edited.Message.ModelConfigID` and
`chat.LastModelConfigID` both match the new model.
- `InvalidModelConfigID`: random UUID -> 400 `Invalid model config ID.`.

</details>
2026-05-12 14:51:55 +02:00
Michael Suchacz f847ff3731 test(coderd/x/chatd): skip stale notification flakes (#25177)
Skip the chatd tests that currently flake because the control
notification flow cannot distinguish stale wake/status NOTIFY payloads
from real interrupt requests. Each skipped test includes a TODO to
re-enable it after the chatd notification flow refactor handles stale
notifications correctly.

Supersedes #25133, #25134, #25135, and #25139.

Refs [CODAGT-353](https://linear.app/coder/issue/CODAGT-353),
[CODAGT-356](https://linear.app/coder/issue/CODAGT-356),
[CODAGT-360](https://linear.app/coder/issue/CODAGT-360), and
[CODAGT-361](https://linear.app/coder/issue/CODAGT-361).

> Mux working on behalf of Mike.
2026-05-12 14:50:30 +02:00
Ethan 4e08543ace test(coderd): centralize chat test harness and stabilize flakes (#25171)
Chat tests previously constructed a real `openai` provider with a fake
API key and no `BaseURL`, so background title generation hit
`api.openai.com` and timed out under `-race`. The same root cause
produced several distinct flakes: title regeneration races with
synchronous `UpdateChat`/`ProposeChatTitle`, and pagination races
against `updated_at` bumps from real-network processing.

This moves the fake OpenAI-compatible provider and the chat-settle wait
into first-class `coderdtest` capabilities.
`coderd.Options.ChatProviderAPIKeys` is the new seam tests use to
redirect chat traffic to a local `httptest.Server`.
`coderdtest.WaitForChatSettled` replaces per-test waiters and drains
tracked chat-daemon work after the chat row leaves `pending`/`running`.
The `newChatClient*` constructors funnel through one options builder
that installs the fake provider before the coderd test server so cleanup
ordering is deterministic.

Closes https://github.com/coder/internal/issues/1528 & Closes ENG-2659
Closes https://github.com/coder/internal/issues/1480 & Closes CODAGT-359
Closes https://github.com/coder/internal/issues/1507 & Closes CODAGT-368
Relates to https://github.com/coder/internal/issues/1397 & Relates to
CODAGT-374
2026-05-12 22:13:55 +10:00
Jaayden Halko 8ba24e0e54 feat(site): add collapsible agent sections (#25173)
closes CODAGT-395

<img width="426" height="480" alt="Screenshot 2026-05-12 at 19 04 03"
src="https://github.com/user-attachments/assets/ba336ecf-3e90-48b0-b5d3-b10499909953"
/>

Adds collapsible section headers to the Agents sidebar, including
visible counts and chevrons for pinned and time-grouped chats.

The section header toggle keeps nested chat expansion state independent,
preserves the existing filter dropdown behavior, and adds Storybook
coverage for counts, collapse or expand interactions, and filter menu
behavior.
2026-05-12 13:07:57 +01:00
Danielle Maywood a55430b8fd fix(site/src/pages/AgentsPage): suppress last-message spacer during active stream (#25120) 2026-05-12 12:31:40 +01:00
Cian Johnston caabb3c4ab fix(site): show Organizations in admin dropdown for single-org OSS deployments (#25175)
Fixes https://linear.app/codercom/issue/CODAGT-350

On OSS or no-license single-org deployments, the Organizations admin
link was hidden because `canViewOrganizationSettings` was gated on
`showOrganizations`, which requires either a multi-org entitlement or >1
org. The page was still reachable via direct URL, but the members view
displayed a raw "Template RBAC is a Premium feature. Contact sales!"
error from the groups API.

Two fixes:

1. Always render the Organizations link inside the `DeploymentDropdown`.
The dropdown itself is only shown to users with admin-level permissions,
so Organizations is effectively gated on having admin access.

2. Remove `groupsByUserIdQuery.error` from the error chain on the
members page. The groups endpoint is gated behind
`templateRBACEnabledMW` on enterprise, returning a 403 on OSS. The
groups data is already optional, so the page renders fine without it.

> Generated by Coder Agents
2026-05-12 12:28:43 +01:00