mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
1ab4ed8db510d026d6b5fbcc84dbe2d80f5881f9
15471
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
1ab4ed8db5 |
feat: exclude AI Bridge usage from AI Governance seat counting (#27280)
Under the new `ai-gateway-seat-exclusion` experiment, AI Bridge usage stops counting toward AI Governance seats. ## Seat recording Under the experiment, `RecordInterception` no longer records `ai_seat_state` usage for the initiator: AI Gateway access is licensed by the AI Governance add-on rather than per seat. This experiment is independent of `workspace-capable-licensing` (#27279) so the two licensing behaviors can be enabled separately. Task workspace builds still claim AI Governance seats. ## Manual verification Verified live on a dev deployment (provider chained to dev.coder.com's gateway, model `gpt-5.6-luna`): with the experiment off, the first bridge request from each identity type (admin, plain member, service account) wrote an `ai_seat_state` row (`aibridge` reason); with it on, requests recorded interceptions but left seat state untouched — no new rows, and existing rows' `last_used_at` did not advance. Part of the gateway-accounts feature. ## Stack Part 2 of the gateway-accounts stack: 1. **#27279**: permission-based license seat counting. Behind the `workspace-capable-licensing` experiment and gated on the AI Governance add-on, `user_limit` counts only users the RBAC engine authorizes to create workspaces. 2. **This PR**: stops AI Bridge usage from claiming AI Governance seats under the new `ai-gateway-seat-exclusion` experiment. 3. ~~**#27281**: adds a `use_shared` capability precondition for workspace ACL grants, so workspace sharing is ineffective for (and rejected toward) users without workspace capabilities, evaluated live on every authorization.~~ This will be done in follow-up work when we have time to look into the performance impact. Related but independent: **#27278** hides the Workspaces page create CTAs for users without workspace-create permission. |
||
|
|
6c102cc3f3 |
feat: count only workspace-capable users toward license seats (#27279)
Adds permission-based license seat counting behind the
`workspace-capable-licensing` experiment. When the experiment is enabled
and a valid license carries the AI Governance add-on, the `user_limit`
feature counts only active users the RBAC engine authorizes to create a
workspace, instead of every active user. Users without workspace-create
capability ("gateway accounts", e.g. AI-Gateway-only users) no longer
consume seats.
## How it works
- A new `GetActiveUsersAuthorizationRoles` bulk query returns effective
roles (implied member roles, org default member roles) and group
memberships for every seat-eligible user (active, not deleted, not
system, not a service account), matching `GetActiveUserCount` semantics.
- `license.CountWorkspaceCapableUsers` evaluates `workspace.create`
against the any-organization object form, which covers site-wide grants,
membership grants, and org-scoped bans in one check. Evaluation is
deduplicated on a sha256 of each user's canonical subject JSON (a fixed
sentinel user ID, sorted deduplicated roles and groups), so cost scales
with unique subjects rather than user count, and every subject field
participates in both the evaluation and the key.
- The AI Governance add-on is only known after license claims are
parsed, so `Entitlements()` passes a lazy `WorkspaceCapableUserCountFn`
(following the `ManagedAgentCountFn` precedent) and
`LicensesEntitlements` resolves it when a validated add-on is present.
Each license's `user_limit` claim becomes a candidate pair of limit and
counting mode, the most favorable pair is selected (see Behavior notes),
and the selected pair's limit, entitlement, and count become the
`user_limit` feature's terms; the warnings read the same values.
`license.Entitlements` gains `logger`, `authorizer`, and `experiments`
parameters.
- All custom roles are prefetched in a single query before evaluation
(new exported `rolestore.PrefetchCustomRoles`), and each count emits one
Info log line (capable count, eligible active users, unique subjects,
elapsed) whose presence identifies the counting mode. The count is
bounded by a 60s timeout.
## Behavior notes
- Without the experiment or without the add-on, the legacy
`GetActiveUserCount` path is unchanged.
- When the mode is active, the over-limit and expired-limit warnings say
"workspace-capable users" instead of "active users", since that is what
was counted.
- With multiple licenses, each license's `user_limit` claim forms a
candidate pair of limit and counting mode (workspace-capable for add-on
licenses, all active users otherwise), and the most favorable pair is
enforced: a pair satisfied by its own count wins over any unsatisfied
one, then higher entitlement, then higher limit. One license's limit is
never combined with another license's counting mode, so a small add-on
license can neither borrow a bigger non-add-on limit nor suppress it.
- Licenses in their grace period still gate the count; it reverts to the
legacy count only on hard expiry. While the add-on exists only on
grace-period licenses, a warning tells admins the counting mode will
revert and states the legacy active-user count they will then be
measured by.
- Count errors (database failures, timeout) abort the entitlements
computation, matching the legacy count's error semantics: the refresh
fails and the caller keeps the previous entitlements rather than a
silently different count. One exception: a stored role string that fails
to parse is logged and treated as not workspace-capable instead of
failing the refresh, since authorization fails closed on such roles
anyway.
- The experiment is deliberately not in `ExperimentsSafe`.
Part of the gateway-accounts feature; no behavior changes for
deployments without the experiment.
## Stack
Part 1 of the gateway-accounts stack. Each PR builds on the previous:
1. **#27279 (this PR)**: permission-based license seat counting. Behind
the `workspace-capable-licensing` experiment and gated on the AI
Governance add-on, `user_limit` counts only users the RBAC engine
authorizes to create workspaces.
2. **#27280**: adds the `organization-ai-gateway-access` org role
carrying the AI Bridge interception permissions (extracted from the
member floors, backfilled into org default roles by migration) and
enforces it at AI Gateway authentication; bridge usage stops claiming AI
Governance seats under the experiment.
3. ~~**#27281**: gates workspace ACL grants on matching member-level
capability (each granted action only takes effect while the recipient
holds that action in the org), so workspace sharing is ineffective for
(and rejected toward) users without workspace capabilities, evaluated
live on every authorization.~~ Tabled — excluded from the
gateway-accounts MVP.
Related but independent: **#27278** hides the Workspaces page create
CTAs for users without workspace-create permission.
## Benchmarks
`BenchmarkCountWorkspaceCapableUsers` (in `usercount_bench_test.go`, run
manually with `go test ./enterprise/coderd/license/ -bench
BenchmarkCountWorkspaceCapableUsers -benchtime 5x -run '^$'` — never
executed by CI) measures the count across user-scale and role-diversity
shapes:
| Scenario | Users | ~Unique subjects | per count |
|---|---|---|---|
| Uniform | 1k | 4 | 8.5ms |
| Uniform | 10k | 4 | 71ms |
| Uniform | 50k | 4 | 344ms |
| ManyOrgs (100 orgs) | 10k | ~200 | 112ms |
| CustomRoles (1000 org-scoped roles) | 10k | ~1000 | 168ms |
| UniquePairs (every user a distinct subject) | 10k | ~10,000 | 2.66s |
Summary:
- **Row-side cost is ~7µs per user, linear** (role parsing, subject
canonicalization, and sha256 per row). The bulk query + subject dedupe
handles 50k users in ~350ms; extrapolated 100k ≈ 0.7s. A non-issue at
the 10-minute refresh cadence.
- **Unique subjects are the dominant axis at ~0.26ms each** (role
expansion + one any-organization rego evaluation per subject). The
worst-case scenario — every user a distinct subject — costs ~2.7s at 10k
users, extrapolating to ~13s at 50k.
- **Realistic deployments sit near the cheap rows.** Subject diversity
tracks orgs × role/group combinations, not user count; only per-user
custom roles or per-user org-membership patterns approach the worst
case.
- Caveat encountered while building the harness: the roles query's plan
depends on accurate table statistics. With stale stats (e.g. right after
a bulk user import, before autovacuum ANALYZEs), the planner picks a
nested-loop plan that re-runs the aggregation per user row — a ~300×
regression (1.08s for 1k users). Fresh statistics restore the hash-join
plan; the harness ANALYZEs after seeding, so the numbers above reflect
the healthy plan.
|
||
|
|
00d134ebfd | chore: remove classic parameter UI (#25014) | ||
|
|
d57965ee7f |
chore: regenerate prices.json from models.dev (#27549)
Implements: https://linear.app/codercom/issue/AIGOV-493/update-pricesjson-with-current-model-rates-before-cost-control-release Run `make gen/aibridge-prices` to regenerate `prices.json` from `models.dev`. This update: - adds support for the upstream `claude-opus-5` model; - removes older `openai` models that have been removed upstream, keeping us in sync with `models.dev`. |
||
|
|
2574e6b785 |
feat: notify admins when a user crosses an AI budget threshold (#27415)
Implements: https://linear.app/codercom/issue/AIGOV-289/notify-users-and-admins-on-budget-warning-and-limit-reached Notify admins when a user crosses an AI budget threshold, complementing the user-facing notifications from https://github.com/coder/coder/pull/27346 When a priced interception pushes a user's period spend across the warning (85%) or limit (100%) threshold, the Owners and User Admins now receive an admin notification naming the affected user, alongside the user's own notification. The affected user is excluded from the admin recipients since they already get the user-facing copy. Delivery is best-effort: a failure to enqueue is logged and never blocks recording the interception. The admin templates always show the effective group the spend is attributed to, and note when the limit comes from a per-user override rather than the group budget. Depends on https://github.com/coder/coder/pull/27346 ## Screenshots: <img width="1101" height="440" alt="image" src="https://github.com/user-attachments/assets/eb731088-05c8-47bd-9d06-fc9d07f63a08" /> <img width="468" height="391" alt="image" src="https://github.com/user-attachments/assets/b89b76a6-3fa8-4735-99a2-43e119a7a7e3" /> |
||
|
|
51ac968d5a |
feat: wire up Template Builder session telemetry endpoint (#27124)
`TemplateBuilderSession` telemetry types and telemetry-server ingestion were added in earlier PRs (#25082, coder/coder-telemetry-server#41), but no code ever produced session events. This adds the missing producer. **Backend**: `POST /api/v2/templatebuilder/sessions` reports wizard entry and compose completion events directly via `api.Telemetry.Report()`, using the same inline pattern as `NetworkEvents` and `UserTailnetConnections`. No database migration or `createSnapshot()` changes needed. RBAC requires `policy.ActionCreate` on `ResourceTemplate.AnyOrganization()`, matching the compose endpoint. **Frontend**: The template builder wizard fires `wizard_entry` on page mount and `compose_completion` on create success or failure. A client-generated session ID (UUID) correlates the two events for the same wizard visit, enabling precise funnel analysis and abandonment detection in BigQuery. Duration is tracked via `Date.now()` in the wizard state. Closes https://linear.app/codercom/issue/DEVEX-599 <details> <summary>Implementation plan</summary> ## Root Cause Analysis The DEVEX-599 ticket diagnosis suggested missing DB tables, queries, and `eg.Go` blocks. That diagnosis assumes the DB-backed periodic snapshot path is required. It is not. Investigation shows two telemetry reporting patterns in the codebase: 1. **DB-backed periodic snapshots** (`createSnapshot()` with `eg.Go` blocks): Used for durable entities like workspaces, templates, users. 2. **Direct inline reporting** (`api.Telemetry.Report(&telemetry.Snapshot{...})`): Used for ephemeral events like `NetworkEvents`, `UserTailnetConnections`, `CLIInvocations`. Template builder sessions are ephemeral events, so the direct inline reporting pattern is the correct fit. ## Backend Changes - `codersdk/templatebuilder.go`: `TemplateBuilderSessionRequest` type with `SessionID`, `EventType` enum, `TemplateBuilderSession()` client method - `coderd/coderd.go`: Route registration in `/templatebuilder` group - `coderd/templatebuilder_handler.go`: Handler with RBAC check, request validation, session ID fallback, and inline telemetry report - `coderd/templatebuilder_handler_test.go`: Tests for wizard entry, compose completion, invalid event type, disabled feature, and member RBAC rejection ## Frontend Changes - `site/src/api/api.ts`: `recordTemplateBuilderSession` API method - `site/src/api/queries/templateBuilder.ts`: React Query mutation - `site/src/pages/TemplateBuilder/wizardState.ts`: `sessionId` and `enteredAt` fields, `createWizardState()` factory for per-mount initialization - `site/src/pages/TemplateBuilder/TemplateBuilderPageView.tsx`: `sessionId` prop, `useReducer` initializer form - `site/src/pages/TemplateBuilder/TemplateBuilderPage.tsx`: Telemetry calls for wizard entry (on mount) and compose completion (on create success/failure) </details> > 🤖 Generated by Coder Agents --------- Co-authored-by: Coder Agent <agent@coder.com> |
||
|
|
daf655dff8 |
fix(coderd/x/chatd/chaterror): classify aibridge 403 as ChatErrorKindUsageLimit (#27538)
Adds the string `ai budget` to the classifier for `ChatErrorKindUsageLimit`. <img width="809" height="267" alt="Screenshot 2026-07-27 at 18 27 13" src="https://github.com/user-attachments/assets/7e2ba9ae-8168-4fd4-87f6-c4e7dfdc9526" /> Testing notes: - I set the group limit by running `insert into group_ai_budgets values ('<everyone group UUID>', 1, NOW(), NOW());` > Created by a human, trimmed down by a Coder agent. --------- Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> |
||
|
|
95be28850d | refactor(site/src/pages): delete unreachable tool render paths (#27527) | ||
|
|
5af3d95b06 |
test(coderd/rbac): verify workspace creation ban denies any_org create (#27533)
<!-- Created by Coder Agents on behalf of @Emyrk. --> Adds RBAC tests for a user holding both `organization-workspace-access` and `organization-workspace-creation-ban`. - Single org with both roles: the `any_org` workspace create check returns **false**, since the ban's negative permission is the only organization vote. - Member of two orgs, banned in one, workspace-access in the other: `any_org` create returns **true**, since the max vote across organizations wins. - Per-org checks confirm the ban denies create/delete only in the banned org, and non-banned actions (read, update) remain allowed. --- <sub>Coder Agents on behalf of @Emyrk.</sub> |
||
|
|
5699f1cdfb |
fix: retry and cache e2e Coder release downloads to reduce test-e2e ssh flake (#27470)
closes DEVEX-651 ## Summary Fixes coder/internal#218 (`flake: e2e-test / test ssh`). Despite the title, the `ssh with client v2.8.0` / `ssh with agent v2.12.1` cases (`site/e2e/tests/outdatedCLI.spec.ts`, `outdatedAgent.spec.ts`) are not failing because of a bug in SSH. They fail during **setup**, in `downloadCoderVersion()`, which runs `install.sh` to fetch an old Coder release from GitHub. Transient GitHub errors (HTTP 403/503, surfacing as nonzero `curl` exit codes such as 22 or 1) make `install.sh` fail and take the whole ssh test down with it. This is an external-download flake, confirmed by the recurring `install.sh failed with code {22,1}` evidence in the issue thread and Ethan's note ("Networking issues again"). ## Changes 1. **Retry-with-backoff** (`site/e2e/helpers.ts`): `downloadCoderVersion()` now retries `install.sh` up to 5 times with exponential backoff and jitter (~1s, 2s, 4s, 8s). A single transient download failure no longer fails the test. `install.sh` already reuses completed binaries and resumes partial downloads (`curl -C -`), so retries are cheap. 2. **Cross-run cache** (`.github/workflows/ci.yaml`): the `test-e2e` job now persists `/tmp/coder-e2e-cache` with `actions/cache`, so most runs skip the GitHub download entirely. The key is derived from the spec files that pin the downloaded versions, so it invalidates when those versions change. Saves are restricted to `main` (`restore` runs everywhere), matching the existing cache-poisoning convention used for the Vale and golangci-lint caches. Before this change, neither retry, mirror, nor cross-run caching protected this path; the only caching was within a single run. ## Testing - `biome check e2e/helpers.ts` passes. - `tsc --noEmit` introduces no new errors. - CI `test-e2e` exercises the changed path. <details> <summary>Investigation notes</summary> - The failure always originates in `downloadCoderVersion` -> `install.sh` -> `fetch()` (`curl -#fL ... https://github.com/coder/coder/releases/download/vX.Y.Z/...`). - `curl` exit 22 = server returned an HTTP error (403 seen in logs); exit 1 = other transient failure. GitHub also returned 503s across the workflow in some occurrences. - `/tmp/coder-e2e-cache` was not persisted by any `actions/cache` step in `ci.yaml`, so every fresh job re-downloaded from GitHub and was exposed to the flake. - Retry addresses transient failures; the cache removes the dependency on GitHub for most runs. Combined, they target the root cause at two layers. </details> --- This PR was generated by Coder Agents on behalf of @aqandrew. |
||
|
|
ce4ee923c2 |
feat: notify users when AI spend crosses the budget threshold (#27346)
Implements: https://linear.app/codercom/issue/AIGOV-289/notify-users-and-admins-on-budget-warning-and-limit-reached Notify users when their AI spend crosses a budget threshold for their effective group. Two thresholds are covered: a warning at 85%, and a limit-reached notification at 100%. Detection runs on the post-response path, right after the interception's cost is added to the user's daily spend. It reads the user's AI spend on the same transaction where token usage is recorded and AI daily spend is incremented, and derives the pre-interception total by subtracting this interception's cost. In case of `oldSpend < threshold && newSpend >= threshold` - notification is sent. A single interception that crosses both thresholds enqueues both notifications. Detection and delivery are best-effort: a failure is logged and never fails usage recording. The payload uses only stable values (the threshold percentage and the spend limit, not the exact spend), so duplicate enqueues are deduplicated by the notification system. The two templates are added via migration and appear in each user's notification settings under the "AI Budget" group. Admin notifications (owners and user admins) are a follow-up: #27415. ## Screenshots: <img width="1102" height="252" alt="image" src="https://github.com/user-attachments/assets/62291510-09ca-4cdf-a1f5-4bdc11a1db4b" /> <img width="466" height="384" alt="image" src="https://github.com/user-attachments/assets/030460ff-6fe2-4d59-b247-3550c543ef30" /> --------- Co-authored-by: Cian Johnston <cian@coder.com> |
||
|
|
c9e68987c1 |
fix(coderd/aibridged): retain dialer notification (#27529)
Fixes flake caused by race in `TestReady/FalseBeforeConnection` test. |
||
|
|
60c20be46f | chore(site): remove beta labels from user secrets dashboard (#27512) | ||
|
|
025ded0536 | docs: remove beta labels from user secrets (#27510) | ||
|
|
92d45a0411 |
docs: document SCIM 2.0 handler opt-in and legacy flag (#27469)
Documents the SCIM 2.0 handler introduced in #25572 and how to opt in. Adds a "SCIM 2.0 handler" subsection to the SCIM section of `docs/admin/users/oidc-auth/index.md`: - The handler follows RFC 7644 and supports user provisioning/deprovisioning and user listing. - Opt in with `CODER_SCIM_USE_LEGACY=false` (also `--scim-use-legacy` / `scimUseLegacy`); requires a server restart. - Behavior notes: delete/deactivate suspends (never hard-deletes), reactivation goes through dormant, usernames are immutable. - Notes it will eventually become the default behavior. Behavior details were verified against `enterprise/coderd/scimroutes.go`, `enterprise/coderd/scim/`, and the `SCIM Use Legacy` option in `codersdk/deployment.go`. `make lint/markdown` and `make lint/emdash` pass. --- Generated by Coder Agents on behalf of @Emyrk. --------- Co-authored-by: Nick Vigilante <nickvigilante@users.noreply.github.com> |
||
|
|
fd2faaa2f8 | refactor(site/src/pages/AgentsPage): drop defensive code for impossible chat states (#27513) | ||
|
|
5770085435 |
fix: add prefix to standalone metrics (#27526)
Adds `coder_ai_gateway_` to standalone Gateway metics to match embedded case. |
||
|
|
b67e1b24f9 |
fix(coderd/x/chatd): avoid request recorder race (#27525)
`TestActiveServer_BasicAssistantGenerationAndPromptPreparation` could race by reassigning a request recorder captured by concurrent callbacks. Keep the recorder immutable across both scenarios. Closes https://github.com/coder/internal/issues/1626 |
||
|
|
dba45cede7 |
fix: remove 403 from key failover and cooldown on 401 (#27419)
## Problem When a key returned 401 or 403, the pool marked it permanently unavailable for the lifetime of that in-memory pool. This is bad UX: a transient auth failure or a briefly-misconfigured key could take a key out of rotation until the operator either restarted Coder or reconfigured the key (even re-saving the same working value). ## Changes - **403 removed from key failover**: it's a per-request authorization failure, not a key-level problem, so it's surfaced to the caller as-is without marking the key or failing over. - **401 now applies a temporary cooldown** (like 429) so the key recovers on its own instead of staying blocked. - When every key is in an auth-failure cooldown, the pool reports a `502` with no `Retry-After`, but the keys still recover automatically once the cooldown elapses. Closes https://linear.app/codercom/issue/AIGOV-421/ai-gateway-a-quarantined-centralized-key-never-recovers-without-a Closes https://linear.app/codercom/issue/AIGOV-533/403s-misclassifying-keys-as-permanently-down-in-ai-gateway > [!NOTE] > Initially generated by Claude Opus 4.7, modified and reviewed by @ssncferreira |
||
|
|
6f2011af88 |
feat: add chat summary tab in the right sidebar and per-chat cost endpoint (#26649)
Stacked on #26657 (the persisted whole-chat summary backend). Base branch is `chat-summary-62j9`; review/merge that first. Adds a reusable `ChatSummary` component. The summary text is the persisted whole-chat summary (`chat.summary`) introduced by #26657. It is generated asynchronously and may be `null` until the first summary is produced, in which case the popover renders a muted empty state. Live updates arrive via that PR's `chat_summary_change` watch event, which is already merged into the chat caches. Cost is served by a new per-chat endpoint, `GET /api/experimental/chats/{chat}/cost`, which rolls up assistant-message cost across a chat's root and child (subagent) chats and is authorized like the other `{chat}` routes (read on the chat, 404 otherwise). Visual and interaction coverage lives in `ChatSummary.stories.tsx` and `ChatSummaryPopover.stories.tsx` (including populated-summary, empty-state, and cost-loading cases). --------- Co-authored-by: Cursor <cursoragent@cursor.com> |
||
|
|
88c7304e0b |
feat: add AppearanceProvider to decouple externalImages from theme (#27197)
> 🤖 This PR was modified by Coder Agents on behalf of Jake Howell.
## What
Introduces an `AppearanceProvider` / `useAppearance` context that
publishes **user** appearance values derived from the active site theme,
and migrates the current consumers of `theme.externalImages` (`Avatar`,
`ExternalImage`, `IconsPage`) to read from it.
## Why
Today, per-user appearance concerns like `externalImages` are smuggled
onto the Emotion theme object, which forces components to pull in
`useTheme` purely to reach a single appearance value. That couples "how
something looks for this user" to "how the styling engine happens to be
wired", and means every new user-appearance value has to be bolted onto
the theme.
This context gives user appearance a home of its own, decoupled from
Emotion. Components ask for what they actually need (`const {
externalImages } = useAppearance()`) instead of reaching through the
theme.
## Scope: user appearance, not admin appearance
To be explicit, this provider is about **user-level** appearance — the
per-user, theme-derived rendering concerns. It is deliberately *not* the
deployment-level `AppearanceConfig` (application name/logo, service
banners, support/docs links) that admins configure; that is a separate
concern with its own data source and shouldn't be folded in here.
## Future scope
`externalImages` is the **first** value to move here, not the only one.
`Appearance` is deliberately modelled as an open interface so future
*user* appearance state can live in one place without touching every
consumer or overloading the theme again. Likely candidates are other
per-user, theme-derived values, e.g.:
- Terminal font / other typography preferences currently surfaced via
user appearance settings.
- Theme mode and other theme-derived rendering styles that follow the
same "read one value off the theme" pattern as `externalImages`.
- Accessibility-oriented rendering preferences (e.g. reduced motion) as
they're added.
Centralising these behind a single provider keeps consumers stable as
the surface grows and avoids re-litigating the `useTheme` coupling each
time (laziness now, less maintenance later).
## Changes
- Add `site/src/theme/appearance.tsx` (`AppearanceProvider`,
`useAppearance`), defaulting `externalImages` to `forDarkThemes` to
match `DEFAULT_THEME`.
- Wrap children with `AppearanceProvider` in `ThemeOverride` and in the
Storybook preview decorator.
- Migrate `Avatar`, `ExternalImage`, and `IconsPage` off
`theme.externalImages` and onto `useAppearance`.
## Notes
- Kept as a **draft** pending the go-ahead to open for review.
- No behavioural change intended; this is a plumbing/refactor step.
|
||
|
|
54bdb48cac |
fix(site): revert vite bump to 8.0.10 (#27504)
Vite 8.0.14–8.0.16 pulls in a Rolldown regression that emits calls to `init_emotion_react_browser_development_esm` without importing it, which crashes the site in `vite`/dev (`Uncaught ReferenceError`). Revert [#27485](https://github.com/coder/coder/pull/27485) (`8.0.10 → 8.0.16`) back to Vite 8.0.10 until we can bump to Vite >= 8.1.0, which includes the Rolldown fix. |
||
|
|
9e2fa105de |
fix: wrong border with in <WorkspaceBuildLogsSection /> (#27507)
I caught this earlier today, annoyed me. `border-width` was coming through wrong due to the use of just a `border-solid`. | Old | New | | --- | --- | | <img width="1220" height="480" alt="PREVIEW_BUILD_LOGS_OLD" src="https://github.com/user-attachments/assets/1a2bbf48-3b65-49b6-9a29-8dc1ac587d0d" /> | <img width="1028" height="475" alt="PREVIEW_BUILD_LOGS_NEW" src="https://github.com/user-attachments/assets/3dcf00b2-4bcb-4588-adbd-ac219e981813" /> | | <img width="220" height="220" alt="build-logs-corner-old" src="https://github.com/user-attachments/assets/97e03646-2625-4a2b-abfc-0f325fe197d1" /> | <img width="220" height="220" alt="build-logs-corner-new" src="https://github.com/user-attachments/assets/4fd90c9a-0487-49b8-a0b3-4c2f05aa8c92" /> | |
||
|
|
6120fb5988 | refactor(site): clean up workspace and template settings layouts (#25209) | ||
|
|
6159eb4fc5 | feat(coderd/x/chatd): add structured error fields to wait_agent error payload (#27478) | ||
|
|
ff10beb042 | fix(coderd/x/chatd): surface child error detail in wait_agent last_error (#27477) | ||
|
|
e9951b07d4 |
fix(coderd/x/chatd/chatloop): surface reasoning-only content-filter refusals as terminal errors (#27476)
## Problem Anthropic can end a stream with `stop_reason: "refusal"` after reasoning content has already streamed. The content-filter guard in `chatloop.GenerateAssistant` only fired when the step content was completely empty, so a reasoning-only refusal bypassed it: the turn finished as `status=waiting` with `last_error=null`, and the user saw the chat silently stop mid-turn with no explanation. This looked like a Coder fault when the provider had rejected the response. Observed twice in dogfood on 2026-07-23 (chat `c72f99fc`, debug steps show `finish_reason=content-filter` with reasoning-only content). ## Change Treat a content-filter finish as terminal whenever the step produced no user-visible output. A new `hasUserVisibleContent` helper counts any non-reasoning part (text, tool call, tool result) as user-visible; reasoning-only or empty steps now return the existing `contentFilterError`, which flows through the established pipeline: classified `ChatErrorKindContentFilter` (non-retryable, refusal category/detail when provided), persisted `chats.last_error`, streamed error event, and the "Response blocked" callout in the chat UI. Behavior for steps with visible text or tool calls is unchanged, and the frontend needs no changes. ## Testing - New regression subtest `ReasoningOnlyContentSurfacesTerminalError` (reasoning stream then content-filter finish) beside the existing empty-content and partial-content subtests, which are unchanged. - `go test ./coderd/x/chatd/...` and lint pass. - Dogfood UAT against a local dev instance with a mock Anthropic upstream passed all three scenarios: reasoning-only refusal shows the "Response blocked" callout with `last_error.kind=content_filter` and no retry affordance; text-then-refusal still completes normally; empty refusal still errors. > This PR was created by Mux acting on Mike's behalf. |
||
|
|
591f357574 |
chore: remove releaser v2 flow and drop v1 naming (#27421)
## Summary Removes the GitHub Actions-driven releaser **v2** pipeline so the interactive release wizard is the only release path, and drops the `v1` naming now that it is the sole implementation. ## Changes - Delete `.github/workflows/tag-and-release.yaml` (the v2 workflow). - Delete `scripts/releaser/v2/`. - Move `scripts/releaser/v1/` into `scripts/releaser/` as `package main`. - Rewrite `scripts/releaser/main.go` to a single wizard command: drop the `--legacy` flag and the v2 `rc`/`branch`/`release` subcommands and hidden CI compat commands. `--dry-run` is preserved. - Update `scripts/release.sh` to run `go run ./scripts/releaser "$@"` (no `--legacy`). The legacy `release.yaml` workflow (triggered by `scripts/release.sh`) is unchanged and remains the release pipeline. ## Validation - `go build ./scripts/releaser/...` - `go test ./scripts/releaser/...` - `go vet` + `golangci-lint run ./scripts/releaser/...` - `gofmt -l` clean > [!NOTE] > The GPG signing key check removal is handled in a stacked follow-up PR based on this branch. <details> <summary>Implementation plan</summary> - v2 flow = `scripts/releaser/v2/` + `.github/workflows/tag-and-release.yaml` (uses `go run ./scripts/releaser prepare-release|generate-notes`). `v2` was imported only by `main.go`; the workflow was referenced nowhere else. - v1 flow = interactive wizard in `scripts/releaser/v1/`, reached via `--legacy`, driving `release.yaml` (triggered by `scripts/release.sh`). - No `docs/` referenced the releaser tool or these workflows. - Steps: delete the v2 workflow and package; move `v1/*` up to `scripts/releaser/` (`package main`, including test files); rewrite `main.go` to a single wizard command; update `release.sh`. </details> --- Generated by Coder Agents on behalf of @f0ssel. |
||
|
|
320817fa30 |
chore: bump postcss from 8.5.15 to 8.5.18 in /site (#27486)
Bumps [postcss](https://github.com/postcss/postcss) from 8.5.15 to 8.5.18. <details> <summary>Release notes</summary> <p><em>Sourced from <a href="https://github.com/postcss/postcss/releases">postcss's releases</a>.</em></p> <blockquote> <h2>8.5.18</h2> <ul> <li>Restricted loading previous source maps file to the <code>opts.from</code> folder for security reasons (use <code>unsafeMap: true</code> to disable the check).</li> </ul> <h2>8.5.17</h2> <ul> <li>Fixed <code>Maximum call stack size exceeded</code> error.</li> <li>Fixed Prototype hijacking for <code>postcss.fromJSON()</code>.</li> <li>Fixed <code>Input#origin()</code> for unmapped end position (by <a href="https://github.com/chatman-media"><code>@chatman-media</code></a>).</li> </ul> <h2>8.5.16</h2> <ul> <li>Fixed <code>Input#origin()</code> position (by <a href="https://github.com/mizdra"><code>@mizdra</code></a>).</li> <li>Fixed <code>raws</code> after rehydrating a JSON AST (by <a href="https://github.com/sarathfrancis90"><code>@sarathfrancis90</code></a>).</li> <li>Fixed putting parent-less node in <code>nodes</code> of new node (by <a href="https://github.com/MahinAnowar"><code>@MahinAnowar</code></a>).</li> <li>Fixed computing <code>offset</code> in <code>positionBy()</code> (by <a href="https://github.com/greymoth-jp"><code>@greymoth-jp</code></a>).</li> <li>Fixed <code>rangeBy()</code> on <code>index: 0</code> (by <a href="https://github.com/sarathfrancis90"><code>@sarathfrancis90</code></a>).</li> </ul> </blockquote> </details> <details> <summary>Changelog</summary> <p><em>Sourced from <a href="https://github.com/postcss/postcss/blob/main/CHANGELOG.md">postcss's changelog</a>.</em></p> <blockquote> <h2>8.5.18</h2> <ul> <li>Restricted loading previous source maps file to the <code>opts.from</code> folder for security reasons (use <code>unsafeMap: true</code> to disable the check).</li> </ul> <h2>8.5.17</h2> <ul> <li>Fixed <code>Maximum call stack size exceeded</code> error.</li> <li>Fixed Prototype hijacking for <code>postcss.fromJSON()</code>.</li> <li>Fixed <code>Input#origin()</code> for unmapped end position (by <a href="https://github.com/chatman-media"><code>@chatman-media</code></a>).</li> </ul> <h2>8.5.16</h2> <ul> <li>Fixed <code>Input#origin()</code> position (by <a href="https://github.com/mizdra"><code>@mizdra</code></a>).</li> <li>Fixed <code>raws</code> after rehydrating a JSON AST (by <a href="https://github.com/sarathfrancis90"><code>@sarathfrancis90</code></a>).</li> <li>Fixed putting parent-less node in <code>nodes</code> of new node (by <a href="https://github.com/MahinAnowar"><code>@MahinAnowar</code></a>).</li> <li>Fixed computing <code>offset</code> in <code>positionBy()</code> (by <a href="https://github.com/greymoth-jp"><code>@greymoth-jp</code></a>).</li> <li>Fixed <code>rangeBy()</code> on <code>index: 0</code> (by <a href="https://github.com/sarathfrancis90"><code>@sarathfrancis90</code></a>).</li> </ul> </blockquote> </details> <details> <summary>Commits</summary> <ul> <li><a href="https://github.com/postcss/postcss/commit/4c0d194c136fd374495d0993c890d794cab65b81"><code>4c0d194</code></a> Release 8.5.18 version</li> <li><a href="https://github.com/postcss/postcss/commit/92b4e7891ec7b811821d01acc8aa0f010caf41e2"><code>92b4e78</code></a> Update dependencies</li> <li><a href="https://github.com/postcss/postcss/commit/95663d3eb7ba26f4854dd19d3b4f4425760cf56c"><code>95663d3</code></a> Limit where source map can be loaded for security reasons</li> <li><a href="https://github.com/postcss/postcss/commit/74e25ae9f4efaa56a41a449064a655d7da78072c"><code>74e25ae</code></a> Release 8.5.17 version</li> <li><a href="https://github.com/postcss/postcss/commit/d1518afd5a88f42728b30b87f8917210f363f9f1"><code>d1518af</code></a> Fix Maximum call stack size exceeded error</li> <li><a href="https://github.com/postcss/postcss/commit/2421312ffea96ba77b35ce24a1b2d9c2e22b5e83"><code>2421312</code></a> Fix linter</li> <li><a href="https://github.com/postcss/postcss/commit/a50352c583df991710f92ccac25b36304695161a"><code>a50352c</code></a> Fix CI</li> <li><a href="https://github.com/postcss/postcss/commit/33948f0969bb858acdd52c9692e3a785a3ed0a73"><code>33948f0</code></a> Prevent prototype hijacking in fromJSON</li> <li><a href="https://github.com/postcss/postcss/commit/2131909351161cd2c5fc2be58b14919a873ea824"><code>2131909</code></a> Update dependencies</li> <li><a href="https://github.com/postcss/postcss/commit/93440abcca92793b31c5d1fdf5f2da7b58b27599"><code>93440ab</code></a> Fix non-closed <code>\<div align="center"></code> in README (<a href="https://redirect.github.com/postcss/postcss/issues/2110">#2110</a>)</li> <li>Additional commits viewable in <a href="https://github.com/postcss/postcss/compare/8.5.15...8.5.18">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 postcss since your current version.</p> </details> <br /> Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> |
||
|
|
dd794101cb |
chore: bump vite from 8.0.10 to 8.0.16 in /site (#27485)
Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) from 8.0.10 to 8.0.16. <details> <summary>Release notes</summary> <p><em>Sourced from <a href="https://github.com/vitejs/vite/releases">vite's releases</a>.</em></p> <blockquote> <h2>v8.0.16</h2> <p>Please refer to <a href="https://github.com/vitejs/vite/blob/v8.0.16/packages/vite/CHANGELOG.md">CHANGELOG.md</a> for details.</p> <h2>v8.0.15</h2> <p>Please refer to <a href="https://github.com/vitejs/vite/blob/v8.0.15/packages/vite/CHANGELOG.md">CHANGELOG.md</a> for details.</p> <h2>v8.0.14</h2> <p>Please refer to <a href="https://github.com/vitejs/vite/blob/v8.0.14/packages/vite/CHANGELOG.md">CHANGELOG.md</a> for details.</p> <h2>v8.0.13</h2> <p>Please refer to <a href="https://github.com/vitejs/vite/blob/v8.0.13/packages/vite/CHANGELOG.md">CHANGELOG.md</a> for details.</p> <h2>v8.0.12</h2> <p>Please refer to <a href="https://github.com/vitejs/vite/blob/v8.0.12/packages/vite/CHANGELOG.md">CHANGELOG.md</a> for details.</p> <h2>v8.0.11</h2> <p>Please refer to <a href="https://github.com/vitejs/vite/blob/v8.0.11/packages/vite/CHANGELOG.md">CHANGELOG.md</a> for details.</p> </blockquote> </details> <details> <summary>Changelog</summary> <p><em>Sourced from <a href="https://github.com/vitejs/vite/blob/main/packages/vite/CHANGELOG.md">vite's changelog</a>.</em></p> <blockquote> <h2><!-- raw HTML omitted --><a href="https://github.com/vitejs/vite/compare/v8.0.15...v8.0.16">8.0.16</a> (2026-06-01)<!-- raw HTML omitted --></h2> <h3>Bug Fixes</h3> <ul> <li><strong>deps:</strong> reject UNC paths for launch-editor-middleware (<a href="https://redirect.github.com/vitejs/vite/issues/22571">#22571</a>) (<a href="https://github.com/vitejs/vite/commit/50b951225bbf6151eb84a3ad5a454908ab4a76c9">50b9512</a>)</li> <li>reject windows alternate paths (<a href="https://redirect.github.com/vitejs/vite/issues/22572">#22572</a>) (<a href="https://github.com/vitejs/vite/commit/dc245c71e5007ea4d891a025e2d69ac96c736546">dc245c7</a>)</li> </ul> <h2><!-- raw HTML omitted --><a href="https://github.com/vitejs/vite/compare/v8.0.14...v8.0.15">8.0.15</a> (2026-06-01)<!-- raw HTML omitted --></h2> <h3>Features</h3> <ul> <li>send 408 on request timeout (<a href="https://redirect.github.com/vitejs/vite/issues/22476">#22476</a>) (<a href="https://github.com/vitejs/vite/commit/c85c9eeb9aaf41f477b48b057146887bd5620797">c85c9ee</a>)</li> <li>update rolldown to 1.0.3 (<a href="https://redirect.github.com/vitejs/vite/issues/22538">#22538</a>) (<a href="https://github.com/vitejs/vite/commit/646dbedd2870f8ec48df0321177d8aa64bbd1575">646dbed</a>)</li> </ul> <h3>Bug Fixes</h3> <ul> <li>capitalize error messages and remove spurious space in parse error (<a href="https://redirect.github.com/vitejs/vite/issues/22488">#22488</a>) (<a href="https://github.com/vitejs/vite/commit/85a0eff1c82bbb7c99a0fe8e63704316578a40d3">85a0eff</a>)</li> <li><strong>deps:</strong> update all non-major dependencies (<a href="https://redirect.github.com/vitejs/vite/issues/22511">#22511</a>) (<a href="https://github.com/vitejs/vite/commit/2686d7d0b722402204d3bcc687a87adea1bcf9fa">2686d7d</a>)</li> <li><strong>dev:</strong> fix html-proxy cache key mismatch for /@fs/ HTML paths (<a href="https://redirect.github.com/vitejs/vite/issues/21762">#21762</a>) (<a href="https://github.com/vitejs/vite/commit/47c4213f134f562c41ed7c031e4788510cf7e31e">47c4213</a>)</li> <li><strong>glob:</strong> error on relative glob in virtual module when no files match (<a href="https://redirect.github.com/vitejs/vite/issues/22497">#22497</a>) (<a href="https://github.com/vitejs/vite/commit/5c8e98f8b584ac5d42f0f9b8580c49792213b13c">5c8e98f</a>)</li> <li><strong>optimizer:</strong> close the rolldown bundle when write() rejects (<a href="https://redirect.github.com/vitejs/vite/issues/22528">#22528</a>) (<a href="https://github.com/vitejs/vite/commit/e3cfb9deecff563550fa1b8abd27656b8b292815">e3cfb9d</a>)</li> <li><strong>resolve:</strong> provide onWarn for viteResolvePlugin in JS plugin containers (<a href="https://redirect.github.com/vitejs/vite/issues/22509">#22509</a>) (<a href="https://github.com/vitejs/vite/commit/40985f1c09b7696e594e6c5695fbc315d2da2c83">40985f1</a>)</li> </ul> <h3>Miscellaneous Chores</h3> <ul> <li><strong>deps:</strong> update rolldown-related dependencies (<a href="https://redirect.github.com/vitejs/vite/issues/22566">#22566</a>) (<a href="https://github.com/vitejs/vite/commit/3052a67d9350f4c5076ab1c222c4a21a589cbcdd">3052a67</a>)</li> </ul> <h3>Code Refactoring</h3> <ul> <li>correct logic in <code>collectAllModules</code> function (<a href="https://redirect.github.com/vitejs/vite/issues/22562">#22562</a>) (<a href="https://github.com/vitejs/vite/commit/6978a9ceb942c4f5e211d52b8a1e569f8a65c80c">6978a9c</a>)</li> </ul> <h2><!-- raw HTML omitted --><a href="https://github.com/vitejs/vite/compare/v8.0.13...v8.0.14">8.0.14</a> (2026-05-21)<!-- raw HTML omitted --></h2> <h3>Features</h3> <ul> <li>update rolldown to 1.0.2 (<a href="https://redirect.github.com/vitejs/vite/issues/22484">#22484</a>) (<a href="https://github.com/vitejs/vite/commit/96efc88570b6a6ddf1a910f106920cbac07b3cf0">96efc88</a>)</li> </ul> <h3>Bug Fixes</h3> <ul> <li><strong>deps:</strong> update all non-major dependencies (<a href="https://redirect.github.com/vitejs/vite/issues/22471">#22471</a>) (<a href="https://github.com/vitejs/vite/commit/98b81632139d51820f82036e58d6fbbf122b77b3">98b8163</a>)</li> <li><strong>dev:</strong> handle errors when sending messages to vite server (<a href="https://redirect.github.com/vitejs/vite/issues/22450">#22450</a>) (<a href="https://github.com/vitejs/vite/commit/e8e9a34dcf2540139de558a10187630884d10217">e8e9a34</a>)</li> <li><strong>html:</strong> handle trailing slash paths in transformIndexHtml (<a href="https://redirect.github.com/vitejs/vite/issues/22480">#22480</a>) (<a href="https://github.com/vitejs/vite/commit/5d94d1bffdb2a15de9341194d89baec86ce1f693">5d94d1b</a>)</li> <li><strong>optimizer:</strong> pass oxc jsx options to transformSync in dependency scan (<a href="https://redirect.github.com/vitejs/vite/issues/22342">#22342</a>) (<a href="https://github.com/vitejs/vite/commit/b3132dacea9c6e0cf526cd9f0f09d850f577c262">b3132da</a>)</li> </ul> <h3>Miscellaneous Chores</h3> <ul> <li><strong>deps:</strong> update rolldown-related dependencies (<a href="https://redirect.github.com/vitejs/vite/issues/22470">#22470</a>) (<a href="https://github.com/vitejs/vite/commit/7cb728eb629cc677661f1bc52a044ffc0b87fc7f">7cb728e</a>)</li> <li>remove irrelevant commits from changelog (<a href="https://github.com/vitejs/vite/commit/2c69495f250edf01132d4a20128de19dbe836086">2c69495</a>)</li> </ul> <h3>Code Refactoring</h3> <ul> <li><strong>glob:</strong> do not rewrite import path for absolute base (<a href="https://redirect.github.com/vitejs/vite/issues/22310">#22310</a>) (<a href="https://github.com/vitejs/vite/commit/0ae2844ab6d6d1ccf78a2975b8132769fc35b302">0ae2844</a>)</li> </ul> <!-- raw HTML omitted --> </blockquote> <p>... (truncated)</p> </details> <details> <summary>Commits</summary> <ul> <li><a href="https://github.com/vitejs/vite/commit/f94df87ff03b40b65e29bacdc04cc18c7bccaa4a"><code>f94df87</code></a> release: v8.0.16</li> <li><a href="https://github.com/vitejs/vite/commit/dc245c71e5007ea4d891a025e2d69ac96c736546"><code>dc245c7</code></a> fix: reject windows alternate paths (<a href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/22572">#22572</a>)</li> <li><a href="https://github.com/vitejs/vite/commit/50b951225bbf6151eb84a3ad5a454908ab4a76c9"><code>50b9512</code></a> fix(deps): reject UNC paths for launch-editor-middleware (<a href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/22571">#22571</a>)</li> <li><a href="https://github.com/vitejs/vite/commit/8d1b0195fd186d0b3297d7cd17acff6c96797420"><code>8d1b019</code></a> release: v8.0.15</li> <li><a href="https://github.com/vitejs/vite/commit/2686d7d0b722402204d3bcc687a87adea1bcf9fa"><code>2686d7d</code></a> fix(deps): update all non-major dependencies (<a href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/22511">#22511</a>)</li> <li><a href="https://github.com/vitejs/vite/commit/3052a67d9350f4c5076ab1c222c4a21a589cbcdd"><code>3052a67</code></a> chore(deps): update rolldown-related dependencies (<a href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/22566">#22566</a>)</li> <li><a href="https://github.com/vitejs/vite/commit/e3cfb9deecff563550fa1b8abd27656b8b292815"><code>e3cfb9d</code></a> fix(optimizer): close the rolldown bundle when write() rejects (<a href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/22528">#22528</a>)</li> <li><a href="https://github.com/vitejs/vite/commit/6978a9ceb942c4f5e211d52b8a1e569f8a65c80c"><code>6978a9c</code></a> refactor: correct logic in <code>collectAllModules</code> function (<a href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/22562">#22562</a>)</li> <li><a href="https://github.com/vitejs/vite/commit/646dbedd2870f8ec48df0321177d8aa64bbd1575"><code>646dbed</code></a> feat: update rolldown to 1.0.3 (<a href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/22538">#22538</a>)</li> <li><a href="https://github.com/vitejs/vite/commit/85a0eff1c82bbb7c99a0fe8e63704316578a40d3"><code>85a0eff</code></a> fix: capitalize error messages and remove spurious space in parse error (<a href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/22488">#22488</a>)</li> <li>Additional commits viewable in <a href="https://github.com/vitejs/vite/commits/v8.0.16/packages/vite">compare view</a></li> </ul> </details> <br /> [](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> |
||
|
|
5fbb9c978d |
chore: bump react-router from 7.15.1 to 7.18.0 in /site (#27484)
Bumps [react-router](https://github.com/remix-run/react-router/tree/HEAD/packages/react-router) from 7.15.1 to 7.18.0. <details> <summary>Release notes</summary> <p><em>Sourced from <a href="https://github.com/remix-run/react-router/releases">react-router's releases</a>.</em></p> <blockquote> <h2>v7.18.0</h2> <p>See the changelog for release notes: <a href="https://github.com/remix-run/react-router/blob/main/CHANGELOG.md#v7180">https://github.com/remix-run/react-router/blob/main/CHANGELOG.md#v7180</a></p> <h2>v7.17.0</h2> <p>See the changelog for release notes: <a href="https://github.com/remix-run/react-router/blob/main/CHANGELOG.md#v7170">https://github.com/remix-run/react-router/blob/main/CHANGELOG.md#v7170</a></p> <h2>v7.16.0</h2> <p>See the changelog for release notes: <a href="https://github.com/remix-run/react-router/blob/main/CHANGELOG.md#v7160">https://github.com/remix-run/react-router/blob/main/CHANGELOG.md#v7160</a></p> </blockquote> </details> <details> <summary>Changelog</summary> <p><em>Sourced from <a href="https://github.com/remix-run/react-router/blob/main/packages/react-router/CHANGELOG.md">react-router's changelog</a>.</em></p> <blockquote> <h2>v7.18.0</h2> <h3>Patch Changes</h3> <ul> <li>Fix server handler prerender responses when using <code>ssr: false</code> and <code>future.v8_trailingSlashAwareDataRequests: true</code>. Avoids false positive "SPA Mode" detection when serving prerendered paths (<a href="https://redirect.github.com/remix-run/react-router/pull/15173">#15173</a>)</li> <li>Use the <code>ServerRouter</code> nonce for nonce-aware SSR components when they don't provide their own value so strict CSP pages can load them. (<a href="https://redirect.github.com/remix-run/react-router/pull/15170">#15170</a>)</li> <li>Use <code>turbo-stream</code> to serialize and deserialize Framework Mode hydration errors (<a href="https://redirect.github.com/remix-run/react-router/pull/15175">#15175</a>)</li> <li>Precompute route branch matchers to avoid recompiling route path regexes during matching (<a href="https://redirect.github.com/remix-run/react-router/pull/15186">#15186</a>)</li> <li>Use the constructed request URL host when validating action request origins. (<a href="https://redirect.github.com/remix-run/react-router/pull/15185">#15185</a>)</li> <li>Remove the un-documented custom error serialization logic from Data Mode SSR built-in hydration flows (<a href="https://redirect.github.com/remix-run/react-router/pull/15175">#15175</a>)</li> <li>Validate protocols in RSC render redirects (<a href="https://redirect.github.com/remix-run/react-router/pull/15177">#15177</a>)</li> <li>Consolidate url normalization logic and better handle mixed slashes (<a href="https://redirect.github.com/remix-run/react-router/pull/15176">#15176</a>)</li> </ul> <h2>v7.17.0</h2> <h3>Minor Changes</h3> <ul> <li>Ship a subset of the official documentation inside the <code>react-router</code> package (<a href="https://redirect.github.com/remix-run/react-router/pull/15121">#15121</a>) <ul> <li>Markdown docs are now available in <code>node_modules/react-router/docs</code>, letting AI coding agents and the React Router agent skills read official docs locally</li> <li>Excludes auto-generated API docs (<code>api/</code>), <code>community/</code> content, and tutorials (<code>tutorials/</code>)</li> </ul> </li> </ul> <h2>v7.16.0</h2> <h3>Minor Changes</h3> <ul> <li>Stabilize <code>future.unstable_trailingSlashAwareDataRequests</code> as <code>future.v8_trailingSlashAwareDataRequests</code> (<a href="https://redirect.github.com/remix-run/react-router/pull/15098">#15098</a>)</li> </ul> <h3>Patch Changes</h3> <ul> <li> <p>Disable manifest path when lazy route dicovery is disabled (<a href="https://redirect.github.com/remix-run/react-router/pull/15068">#15068</a>)</p> </li> <li> <p>Fix browser URL creation to use the configured history window instead of the global window. (<a href="https://redirect.github.com/remix-run/react-router/pull/15066">#15066</a>)</p> <ul> <li>Pass the history/router window through to <code>createBrowserURLImpl</code> so custom window contexts keep the correct URL origin.</li> </ul> </li> <li> <p>Fix <code>useNavigation()</code> return type to preserve discriminated union across navigation states (<a href="https://redirect.github.com/remix-run/react-router/pull/15095">#15095</a>)</p> </li> <li> <p>Widen <code>MetaDescriptor</code> <code>script:ld+json</code> type from <code>LdJsonObject</code> to <code>LdJsonObject | LdJsonObject[]</code> to permit multiple JSON-LD schemas in a single <code><script type="application/ld+json"></code> tag emitted by <code><Meta /></code> (<a href="https://redirect.github.com/remix-run/react-router/pull/15082">#15082</a>)</p> </li> </ul> </blockquote> </details> <details> <summary>Commits</summary> <ul> <li><a href="https://github.com/remix-run/react-router/commit/6fb1e79f8304eddd8b78759edea83cb32389ebf5"><code>6fb1e79</code></a> Release v7.18.0 (<a href="https://github.com/remix-run/react-router/tree/HEAD/packages/react-router/issues/15187">#15187</a>)</li> <li><a href="https://github.com/remix-run/react-router/commit/09e6020d1950e54f361f7ad00938ecd4dde60929"><code>09e6020</code></a> Optimize route matching internals (<a href="https://github.com/remix-run/react-router/tree/HEAD/packages/react-router/issues/15186">#15186</a>)</li> <li><a href="https://github.com/remix-run/react-router/commit/5b57f5f371595ad97ac91cca389c5adc08ddcc3a"><code>5b57f5f</code></a> Request Host derivation + CSRF check simplifications (<a href="https://github.com/remix-run/react-router/tree/HEAD/packages/react-router/issues/15185">#15185</a>)</li> <li><a href="https://github.com/remix-run/react-router/commit/ce596e823f0d7b883a433af1d5a839a8b9fe0242"><code>ce596e8</code></a> Validate RSC redirect protocols (<a href="https://github.com/remix-run/react-router/tree/HEAD/packages/react-router/issues/15177">#15177</a>)</li> <li><a href="https://github.com/remix-run/react-router/commit/1cebd2a823bb232ad74dcb2d970f750070b2bebe"><code>1cebd2a</code></a> chore: format</li> <li><a href="https://github.com/remix-run/react-router/commit/9d22943fd46c8ae4b08236425fa3549e10e9ad1a"><code>9d22943</code></a> Use turbo stream for framework hydration errors (<a href="https://github.com/remix-run/react-router/tree/HEAD/packages/react-router/issues/15175">#15175</a>)</li> <li><a href="https://github.com/remix-run/react-router/commit/bf63729561365b50705a24fd576e293424df23ef"><code>bf63729</code></a> Consolidate url normalization logic (<a href="https://github.com/remix-run/react-router/tree/HEAD/packages/react-router/issues/15176">#15176</a>)</li> <li><a href="https://github.com/remix-run/react-router/commit/4ce8ff72737bcf43afc7e9f5705c9214a19ec9f6"><code>4ce8ff7</code></a> Fix prerendering pathname issue with trailingSlashAwareDataRequests e… (<a href="https://github.com/remix-run/react-router/tree/HEAD/packages/react-router/issues/15173">#15173</a>)</li> <li><a href="https://github.com/remix-run/react-router/commit/4f060dd11cd8bedcba9e3ee96fce832bd987fe25"><code>4f060dd</code></a> Use ServerRouter nonce when nonce prop is not specified (<a href="https://github.com/remix-run/react-router/tree/HEAD/packages/react-router/issues/15170">#15170</a>)</li> <li><a href="https://github.com/remix-run/react-router/commit/3fce6d67f805a76b9c3e5a2f0352847ffb3355d2"><code>3fce6d6</code></a> Update docs on data router singleton</li> <li>Additional commits viewable in <a href="https://github.com/remix-run/react-router/commits/react-router@7.18.0/packages/react-router">compare view</a></li> </ul> </details> <br /> [](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> |
||
|
|
76b35edaff |
ci: backport to ESR and ESR-1 release branches (#27460)
## What Extend the backport workflow so the `backport` label fans out to **every actively supported release channel**, not just the latest three minors. Target branches are now the union of: - the latest 3 `release/2.X` branches (mainline `n`, stable `n-1`, security `n-2`), and - the active **ESR** and **maintenance ESR (ESR-1)** branches. The set is de-duplicated, so a branch that is both stable and ESR (today `release/2.34`) is backported once. Dry-run against the current branch list yields `release/2.29`, `release/2.33`, `release/2.34`, `release/2.35`. ## Why ESR / ESR-1 are designated biannually and can sit well below the top-3 window, so the previous `head -3` heuristic silently skipped them (e.g. the maintenance ESR `release/2.29`). The current ESR was only covered by coincidence when it happened to equal stable. ## Changes - Add `scripts/release_channels/esr_versions.txt` as the single source of truth for active ESR minors. - `scripts/update-release-calendar.sh` now reads that file instead of a hardcoded `ESR_VERSIONS` array (calendar output verified unchanged). - `backport.yaml` `detect` job unions the latest 3 branches with the ESR branches (existence-checked, warns and skips missing ones) and de-duplicates. - Backport PRs now get a `backport/v<version>` label, mirroring `cherry-pick.yaml`, with `issues: write` added to create the label. ### Resilience to partial failures Even with the independent matrix (`fail-fast: false`), a single branch's job could previously abort without leaving anything behind, forcing the remaining branches to be backported entirely by hand. Fixed so each branch always ends with a PR (real or placeholder): - Label, assignee, and reviewer are attached **after** the PR is created, as best-effort steps. Requesting review from / assigning the PR author is rejected by GitHub, which previously aborted `gh pr create` under `set -e` and left no PR. - Idempotency now keys off an existing backport **PR** rather than the branch, and an existing backport branch is reused instead of bailing, so a re-run recovers a branch that was pushed before its PR was opened. - The workflow now comments on the original PR with each created backport link, flagging conflicts that still need manual resolution. - Conflicting cherry-picks continue to open a placeholder PR with copy-paste resolution steps. ## Validation - `actionlint`, `shellcheck -x`, and `zizmor` all pass. - Re-ran `update-release-calendar.sh`; ESR statuses (`2.29 Extended Support Release`, `2.34 Stable (ESR)`) are identical after the refactor. - Dry-ran the detection logic against the live branch list (see set above). <details> <summary>Implementation plan</summary> # Plan: Backport to all supported release channels (mainline, stable, security, ESR, ESR-1) ## Goal The backport GitHub Action should open cherry-pick PRs against every actively supported release branch: | Channel | Meaning | Example today | |-------------------------|-----------------------------|----------------| | Mainline | last release (n) | `release/2.35` | | Stable | n-1 | `release/2.34` | | Security Support | n-2 | `release/2.33` | | ESR | current Extended Support | `release/2.34` | | Maintenance ESR (ESR-1) | previous ESR still patched | `release/2.29` | All channels map to `release/2.X` branches. ## What we targeted before `.github/workflows/backport.yaml` took the exact `release/2.X` branches, sorted by minor descending, and kept the top 3 (mainline/stable/security). ESR and ESR-1 are not derivable from version ordering, so the maintenance ESR was silently skipped. ## Source of truth for ESR branches `scripts/update-release-calendar.sh` already encoded the active ESR minors (`ESR_VERSIONS=(29 34)`), driving the release calendar. Rather than maintaining a second list, this list was extracted into a shared data file consumed by both the calendar script and the workflow. ## Changes 1. Extract the ESR minors into `scripts/release_channels/esr_versions.txt`; update `update-release-calendar.sh` to read it. 2. Extend the `detect` job to emit the union of the top-3 branches and one `release/2.<minor>` per ESR entry, existence-checked and de-duplicated. 3. Add per-release `backport/v<version>` labels (with `issues: write`), mirroring the cherry-pick workflow. ## Assumptions - Major version is always `2` (matches existing code). - The ESR list is maintained manually when ESR versions change. - `cherry-pick.yaml` stays single-branch and is out of scope. - Missing ESR branches are skipped with a warning, not a failure. </details> --- *Opened by Coder Agents on behalf of @f0ssel.* |
||
|
|
0f1eafa17e |
docs(docs/admin): document wildcard hostname suffixes (#27482)
Documents wildcard hostname suffixes such as `*-apps.example.com`, which the existing application hostname parser and Helm chart already support. Explains the generated application hostname and the DNS and TLS wildcard required for each supported form. Also adds the suffix form to the installation summary. Validated with the repository's documentation linters and pre-commit hook, the hostname-pattern unit test, and an end-to-end workspace application on Coder v2.35.2. |
||
|
|
f96338110b | fix(codersdk): reject trailing data after closing single quote in env import (#27474) | ||
|
|
b8727d9c23 | fix: don't show admin settings dropdown to everyone (#27481) | ||
|
|
4f50b77ac5 |
fix: tweak Pill styles (#27475)
|
||
|
|
3cf97ff8e7 | fix: show selected owner's external auth when creating a workspace (#26653) | ||
|
|
d5a3963167 |
feat: add bulk user secret import endpoint and SDK client (PLAT-240) (#26724)
Adds `POST /api/v2/users/{user}/secrets/batch` and
`codersdk.Client.ImportUserSecrets` to import env, JSON, or YAML secrets
atomically. The endpoint validates each entry, rolls back the full batch
on conflicts or limits, omits secret values from responses and audit
logs, and imports keys that cannot be injected as environment variables
with an empty `env_name`.
Part of the [PLAT-240 bulk secret import
stack](https://linear.app/codercom/issue/PLAT-240). Reviewed and updated
by Coder Agents on behalf of @dylanhuff-at-coder.
|
||
|
|
73af2ca632 |
docs: audit and fix manifest.json page descriptions for SEO (#27267)
## What Audit and fix the page `description` fields in `docs/manifest.json` so each one is accurate, unique, and follows meta-description SEO best practices, targeting 70-155 characters. Tracking: DOCS-576 ## Why Many manifest descriptions were terse (243 of 272 hand-maintained descriptions were under 70 characters), a few reused another page's description (copy/paste errors), and one just repeated its own title. These feed the per-page `<meta name="description">` on coder.com/docs, so they matter for search snippets and click-through. ## What changed The manifest diff is +244 / -244 lines, touching only `description` string values (0 structural lines changed). A second commit regenerates one downstream file (see Generated file below). - **Fixed 5 copy/paste errors** where a page reused another page's description: - `admin/monitoring/index.md` (had Security's text) - `admin/monitoring/metrics.md` (had Logs' text) - `admin/templates/template-permissions.md` (had "Creating Templates" text) - `admin/networking/stun.md` (had Port Forwarding's text) - `admin/provisioners/manage-provisioner-jobs.md` (had the provisioners index text) - **Fixed `reference/index.md`**, whose description merely repeated the title "Reference". - **Corrected wording**: "Coderd API" to Coder REST API; "VSCode" to VS Code; dropped the `&` shorthand on the AI Gateway index per the docs style guide. - **Corrected accuracy**: the AI landing page listed outdated example agents (GPT-Code, OpenDevin, SWE-Agent); it now references agents used elsewhere in the docs (Claude Code, Aider). - **Expanded terse descriptions** into the 70-155 range with active-voice, front-loaded phrasing. ## Generated file `docs/install/releases/feature-stages.md` is generated by `scripts/release/docs_update_feature_stages.sh`, which copies the beta pages' manifest descriptions verbatim into the beta-features table. Three rows (MCP Server, JetBrains Toolbox, Coder Agents) update to match the new descriptions; User secrets is unchanged. Regenerated with `make gen` so the generated-files check stays clean. ## Scope / exclusions Auto-generated reference subtrees are intentionally left untouched, since `make gen` rebuilds them from source and would revert hand edits (and fail the generated-files check): - `Reference > Command Line` children, from `scripts/clidocgen` (each command's `Short` help) - `Reference > REST API` children, from `scripts/apidocgen` - `Reference > Agent API` children The section index nodes themselves (Reference, REST API, Command Line, Agent API) are hand-maintained and are in scope. ## Validation - `docs/manifest.json` is valid JSON; diff touches only `description` values. - All 272 in-scope descriptions are now 70-155 characters, with 0 duplicates across distinct pages. - No double quotes, backslashes, em/en dashes, or `&` / `<` / `>` in descriptions. - Biome 2.4.10 (`scripts/biome_format.sh`) is a no-op on the result. - `scripts/check_emdash.sh` passes. > This PR was created with AI assistance (Coder Agents). |
||
|
|
5bafbace8e |
docs: add What's next? carve-out to the Learn more style rule (#27163)
## What Adds a **What's next?** carve-out to the **Learn more, not Next steps** rule in the docs style guide (`docs/.style/style-guide/word-choice.md`). The existing `## Learn more, not Next steps` heading, its two rationales, and the ban on **Next steps** are unchanged, so the `#learn-more-not-next-steps` anchor is preserved. A new `### Sequenced tutorials: What's next?` subsection lets a tutorial in an ordered series point to the single next tutorial, and the enforcement note now clarifies that the planned `Coder.LearnMore` rule flags **Next steps**, not **What's next?**. ## Why **What's next?** and **Learn more** do different jobs: - **What's next?** carries the reader along a defined sequence: the single next tutorial. - **Learn more** stays optional related reading, such as feature or reference pages. The **What's next?** phrasing also avoids the "steps" mobility metaphor, so the inclusive-language reason for banning **Next steps** still holds. The merged Quickstart "Customize your template" series (#26712) already uses **What's next?** sections, so this codifies the pattern those pages adopted. ## Implementation plan and decision log - Keep `## Learn more, not Next steps` (preserves the anchor and the core ban). - Add `### Sequenced tutorials: What's next?` after the Learn more Do/Don't examples: a tutorial in an ordered series may add a **What's next?** section pointing to the single next tutorial, placed above **Learn more**, written as a short sentence with the link. - Add a **Do** example showing **What's next?** above **Learn more**. - Update the closing note to: *Enforced by `Coder.LearnMore` (planned). The planned rule flags Next steps, not What's next?.* Decisions: - Subsection, not a new top-level rule, keeps the shared rationale and the `#learn-more-not-next-steps` anchor intact. - The planned Vale rule must flag **Next steps** but allow **What's next?**, so the note calls that out explicitly to prevent a future false positive. - Diff scope: only the Learn more section changes (21 insertions, 1 deletion); no other rules are touched. --- Generated by Coder Agents on behalf of @nickvigilante. |
||
|
|
66a55e1ebd |
feat(docs/.style): enable Coder.GerundHeading (#25502)
## Summary Adds `Coder.GerundHeading`, a `warning`-level Vale rule that flags headings and titles whose first word ends in `-ing` (a gerund or present participle used as a verb form, like `Installing` or `Configuring`). Task headings read better in the imperative (`Install Coder`); concept headings read better as nouns (`Installation`). The choice is context-dependent, so the rule is a `warning`: it annotates without blocking CI. The style-guide section this rule enforces already lives on `main` at [`capitalization-and-punctuation.md#no-gerund-leading-headings`](https://github.com/coder/coder/blob/main/docs/.style/style-guide/capitalization-and-punctuation.md#no-gerund-leading-headings). This PR adds the matching rule and nothing else: the net diff is a single file. ## What's in this PR - `docs/.style/styles/Coder/GerundHeading.yml` (new). Heading-scoped `existence` rule, anchored regex `^[A-Z][a-z]+ing\b`, `level: warning`. - `exceptions:` mirror the style guide's **Exceptions** section: `-ing` words that name a feature, category, or attribute (`Logging`, `Monitoring`, `Networking`, `Tracing`, `Troubleshooting`, `Pricing`, `Billing`, ...) plus words that only look like gerunds (`Bring`, `String`, ...). This branch was rebuilt onto `main`'s restructured `docs/.style/` (the single `style-guide.md` became a `style-guide/` directory and Vale moved into `ci.yaml`), which is why the diff is now just the rule. ## Scope: rule only The rule ships as a `warning`, so it surfaces the existing `-ing` task headings (~200) as advisory annotations rather than failing CI. De-gerunding those headings (imperative rewrites plus internal anchor fixes) is a corpus-wide content change and lands in a dedicated follow-up PR, tracked separately. Splitting keeps this PR to the rule and keeps the content churn reviewable on its own. <details> <summary>Decision log</summary> **`existence` + `scope: heading`, not `sequence` + `tag: VBG`.** Vale's POS-tagging sequence rules are hardcoded to sentence scope and never reach heading text, so a `VBG` sequence rule fires on paragraphs and stays silent on H1-H6. Google's and Microsoft's heading rules all use the existence+regex pattern; this rule follows it. **Exceptions align to the committed style guide, not the original branch design.** The first draft of this rule intentionally left concept-noun gerunds (`Logging`, `Monitoring`, ...) in the flagged set. Since then, `main`'s style guide declared exactly those as non-violations. The rule now excepts them so the rule and the guide agree. An excepted first word is allowed everywhere, which is a deliberate precision trade-off for a first-word regex: `Monitoring Coder` (a task) is not flagged, but the standalone concept heading `Monitoring` stays clean. **Severity = warning.** The imperative-vs-noun choice is judgment-bound, which is the case the `warning` tier exists for: strong guidance, legitimate human-judgment exceptions, no CI block. **Verification.** `make lint/prose` loads the rule cleanly; the excepted words (`Troubleshooting`, `Monitoring`, `Networking`, `Logging`, `Contributing`, `Styling`, `Scaling`, `Routing`, `Pricing`, `Billing`, `Tracing`) each produce zero findings. </details> --- *Opened via Coder Agents on @nickvigilante's behalf.* |
||
|
|
8654b1cec3 |
docs: add clarification of install methods in Get Started guide (#27466)
I was confused by the difference between the Quickstart page and the Install page. Fixes DOCS 602 <!-- 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. --> |
||
|
|
9e09fa86d8 |
chore: add @coder/docs as a CODEOWNER for docs content and tooling (#27240)
Linked Linear issue: [DOCS-571](https://linear.app/codercom/issue/DOCS-571/add-coderdocs-as-a-codeowner-for-docs-content-and-tooling-in) ## What Adds `@coder/docs` as a CODEOWNER for documentation content and docs-specific tooling, so the docs team is automatically requested for review (and notified) whenever these paths change. ## Paths added - `/docs/` — documentation content - `/offlinedocs/` — offline docs app - `/.vale.ini`, `/.markdownlint.jsonc`, `/.markdownlint-cli2.jsonc` — prose/Markdown lint config - `scripts/clidocgen/`, `scripts/apidocgen/`, `scripts/auditdocgen/`, `scripts/metricsdocgen/`, `scripts/docgenenv/` — reference-docs generators + shared helper - Docs CI workflows, **co-owned with `@jdomeracki-coder`**: `.github/workflows/doc-check.yaml`, `docs-preview.yaml`, `deploy-docs.yaml`, `weekly-docs.yaml` Patterns are root-anchored and appended after the existing entries. The workflow lines co-own with `@jdomeracki-coder` (who owns `.github/`), so no existing ownership is removed. ## Out of scope - `.swaggo` (API swagger-gen config) — intentionally left with its current default ownership. ## Notes - Intended as **notify-only**: auto-requests `@coder/docs` for review on these paths. `main` does not enforce required code-owner review, so this does not gate merges. - Takes effect once merged to `main`, and only if `@coder/docs` has write access to this repo. _Opened as a draft._ |
||
|
|
2f879910af |
fix(coderd): harden oauth2 redirect validation (#27274)
Closes DEVEX-604 Hardens `redirect` URL handling in the OAuth2/OIDC/external-auth callback flows so redirects are always reduced to a safe, relative path local to the application. Previously a redirect value with an opaque scheme (e.g. `javascript:...`) or a path with multiple leading slashes (e.g. `///evil.com`) could survive sanitization mostly intact. Also de-duplicates the previously copy-pasted `uriFromURL` helper (now exported `httpmw.URIFromURL`) so there's a single implementation shared by `coderd/userauth.go`, `coderd/externalauth.go`, and `coderd/httpmw/oauth2.go`. <details> <summary>Context</summary> Addresses a low-severity finding reported via a pentest disclosure: the redirect sanitizer used `url.Parse(...).RequestURI()`, which doesn't reject non-hierarchical (opaque) URLs and doesn't collapse extra leading slashes, so crafted `redirect` values could partially survive sanitization. </details> This PR was authored by a Coder Agent on behalf of @aslilac. |
||
|
|
10624122c5 |
feat(site/src): show spend for unlimited and zero AI budgets (#27458)
The group members table hid a member's spend behind a bare "Unlimited"
label when their budget resolves to a group with no limit, and rendered
a $0 budget as a special "None" label. Spend now always shows: as
"$X / Unlimited USD" for unlimited budgets, and as a normal limit row
("Group limit $0", exceeded color once spend is above zero) for $0
budgets.
The Everyone badge drops "(not allocated)" when the Everyone group's
own budget or a user override applies, showing "Everyone" or
"Everyone (individual)" instead. The not-attributed tooltip now states
that the amount is the user's spend in the viewed group and that their
AI budget is managed by another group, replacing the misleading
"Not attributed to this group" wording.
|
||
|
|
3c7a1d33e3 |
feat: add persisted whole-chat summary with background generation (#26657)
Adds a persisted whole-chat summary that backs the chat summary popover. A new nullable `chats.summary` column is populated in the background after a successful root-chat turn and pushed to clients via a new `chat_summary_change` watch event (distinct from `summary_change`, which is bound to `last_turn_summary`), so the popover reads `chat.summary` straight off the loaded `Chat` with no extra query. This is the data source for the popover and per-chat cost UI built in #26649; the popover can consume `chat.summary` once this lands (the field is nullable, so merge order does not matter). ## How it works - **Generation** runs in the existing successful-turn finalize hook, detached from the request so the user's turn is never blocked. A cadence gate generates the first summary after one completed turn, then regenerates every three turns, using the `chats.summary_generated_at` freshness marker. Generation reads compaction-aware history, renders it to a bounded plain-text transcript (short transcripts are skipped), and asks for a 1-3 sentence summary via structured output. Failures never clear an existing summary. - **Staleness** is guarded by `history_version` (mirroring `last_turn_summary`), so a background write racing a newer turn loses while worker lifecycle transitions cannot reject a fresh write. - **Model selection** uses the chat's configured model. ## Deferred to follow-ups - **Cost accounting**: the `chat_messages.cost_source` discriminator and summary/title usage recording were removed from this PR so summary persistence is not blocked by hidden accounting rows advancing `history_version`. Title usage recording stays on main's `InsertChatMessages` path. - **Model override**: deployment-wide summary generation model selection is split into #26803; the base feature always uses the chat model. ## Notes - Migration `000540` adds `chats.summary` and `chats.summary_generated_at`, and recreates `chats_expanded` to expose the new columns. - Root chats only; shared viewers pick up the summary on their next refetch (live watch events are owner-only). Refs #26649 --------- Co-authored-by: Cursor <cursoragent@cursor.com> |
||
|
|
9ce366414e | fix(site): remember reasoning effort per model on new chat (#27457) | ||
|
|
591edcb050 | chore: add DanielleMaywood as CODEOWNER of AgentsPage (#27456) | ||
|
|
468b1a27a3 |
fix: remove standalone AI Gateway http listener dependency on loading providers (#27303)
Fixes an issue where the standalone AI Gateway waited for the initial provider load before starting its HTTP server. HTTP serving now starts independently of provider synchronization. `/healthz` becomes available when the HTTP server starts, while `/readyz` requires an active DRPC connection and completed initial provider load. Enables the Helm chart's startup and liveness probes by default because liveness no longer depends on provider loading. |
||
|
|
b9fad66214 |
refactor: authorize AI budget reads against the user resource directly (#27443)
Replaces the `GetUserByID` read used as an authz check in the AI budget-resolution queries with a targeted `authorizeContext` against the user resource. Same RBAC decision, one fewer db query per resolution step. Follow-up to https://github.com/coder/coder/pull/27364#discussion_r3632577802. > [!NOTE] > Initially generated by Claude Opus 4.7, modified and reviewed by @ssncferreira |