Skip to content

feat: surface missing coder_secret requirements with a dialog on workspace update#25375

Draft
zedkipp wants to merge 1 commit into
mainfrom
zedkipp/plat-81-missing-secrets-dialog
Draft

feat: surface missing coder_secret requirements with a dialog on workspace update#25375
zedkipp wants to merge 1 commit into
mainfrom
zedkipp/plat-81-missing-secrets-dialog

Conversation

@zedkipp
Copy link
Copy Markdown
Contributor

@zedkipp zedkipp commented May 14, 2026

When coder_secret requirements are introduced in a new template version, an in-flight update build fails on start with a 400 carrying the missing secret descriptors. Without dedicated handling, the user lands on the generic build-failed dialog with no actionable guidance.

This mirrors the existing dynamic-parameter recovery flow: classify the failure on the client, surface a dedicated dialog with the count of missing secrets, and present a placeholder action button to navigate to the user-secrets page.

Introduces a workspace-build-scoped error envelope, codersdk.WorkspaceBuildErrorResponse, rather than widening the shared codersdk.Response. It is structurally a superset of Response with a kinded validations slice whose Kind discriminator (missing_secret_env or missing_secret_file) lets the frontend route entries between parameter validation failures and missing coder_secret requirements within a single response.

GIF of this in action (note that the two required secrets are for the env and file added in a single coder secret create command):
secrets-required

Implementation notes

codersdk (new types, build-scoped)

  • codersdk.WorkspaceBuildErrorResponse: superset of codersdk.Response. Returned by workspace build endpoints (postWorkspaceBuilds).
  • codersdk.WorkspaceBuildValidationError: mirrors ValidationError plus an optional Kind discriminator.
  • codersdk.WorkspaceBuildValidationErrorKind and the two WorkspaceBuildValidationErrorKindMissingSecret{Env,File} constants.

codersdk.Response and codersdk.ValidationError are unchanged from main.

Backend wiring

  • coderd/dynamicparameters/error.go: DiagnosticError keeps its existing Response() method (returns generic codersdk.Response, used by tag validation, preset validation, and chatd introspection). Adds BuildResponse() returning codersdk.WorkspaceBuildErrorResponse with per-entry Kind populated from each keyed diagnostic's Extra.Code.
  • coderd/dynamicparameters/resolver.go: iterates SecretRequirements and appends one keyed hcl.Diagnostic per unsatisfied requirement. The diagnostic key is the env or file name; Extra carries a previewtypes.DiagnosticExtra whose Code records whether the requirement is env- or file-shaped.
  • coderd/wsbuilder/wsbuilder.go: BuildError gains BuildResponse() mirroring its existing Response(). Delegates through errors.As on e.Wrapped to avoid recursion.
  • coderd/httpapi/httperror: new WorkspaceBuildResponder interface and IsWorkspaceBuildResponder helper. WriteWorkspaceBuildError checks for it first, then promotes any generic Responder result into the build envelope so the build endpoint consistently emits WorkspaceBuildErrorResponse.
  • coderd/workspacebuilds.go: the non-validation 409 (deleted-workspace guard) is rewritten to emit WorkspaceBuildErrorResponse directly. Swagger annotations on postWorkspaceBuilds add explicit @Failure 400 and @Failure 409 for the new envelope.

Frontend

  • site/src/api/errors.ts: FieldError keeps the optional kind field; doc comment updated to point at WorkspaceBuildValidationErrorKind.
  • site/src/api/api.ts: new MissingSecretsError. updateWorkspace's catch block filters validations into parameter entries first (existing ParameterValidationError), and falls back to entries whose kind is in the generated WorkspaceBuildValidationErrorKinds set (MissingSecretsError).
  • site/src/modules/workspaces/WorkspaceMoreActions/MissingSecretsDialog.tsx: dialog mirroring UpdateBuildParametersDialogExperimental. Body is count-only; no env-name list.
  • site/src/modules/workspaces/WorkspaceUpdateDialogs.tsx: adds a missingSecrets dialog wired off error instanceof MissingSecretsError.

Scope

Only the updateWorkspace flow is updated. changeWorkspaceVersion, startWorkspace, and the experimental workspace-parameters page surface through WorkspaceErrorDialog as before; widening scope is out of band with the original PLAT-81 brief.

Counting caveat

Secret requirements are keyed by their env or file name, so the unlikely case of two SecretRequirementStatus entries colliding on the same name would collapse into a single WorkspaceBuildValidationError. Preview already deduplicates upstream, so this is a documented edge rather than an observed regression.


This PR was generated by Coder Agents on behalf of @zedkipp.

@github-actions
Copy link
Copy Markdown

Docs preview

📖 View docs preview for docs/reference/api/agents.md

@zedkipp zedkipp force-pushed the zedkipp/plat-81-missing-secrets-dialog branch 2 times, most recently from cc68933 to efebab2 Compare May 15, 2026 17:59
</DialogDescription>
<DialogDescription>
Would you like to go to the user secrets page to review and update
secrets before continuing?
Copy link
Copy Markdown
Contributor Author

@zedkipp zedkipp May 15, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not the wording I would have chosen, but this mirrors the text from when there are unmet workspace parameter requirements:

Image

@zedkipp zedkipp force-pushed the zedkipp/plat-81-missing-secrets-dialog branch 2 times, most recently from 16108b2 to cb806c6 Compare May 15, 2026 21:58
…space update

When an update build fails because the active template version declares
coder_secret requirements the workspace owner has not satisfied, surface
a dedicated dialog with a count and a placeholder action to navigate to
the user-secrets page. Mirrors the existing dynamic-parameter dialog
behavior so the two failure modes route through structurally identical
UX.

Introduce a workspace-build-scoped error envelope rather than widening
codersdk.Response. codersdk.WorkspaceBuildErrorResponse is structurally a
superset of codersdk.Response, with a kinded validations slice
(WorkspaceBuildValidationError) whose Kind discriminator lets the
frontend route entries between parameter validation failures and missing
coder_secret requirements within a single response. The two new
constants are WorkspaceBuildValidationErrorKindMissingSecretEnv and
WorkspaceBuildValidationErrorKindMissingSecretFile. Other endpoints'
codersdk.Response / codersdk.ValidationError schemas are unchanged.

Internally, missing secrets flow as keyed hcl.Diagnostics whose Extra
carries a previewtypes.DiagnosticExtra with the matching code.
DiagnosticError.BuildResponse() reads the code via
ExtractDiagnosticExtra and translates it to a
WorkspaceBuildValidationErrorKind. DiagnosticError.Response() (used by
non-build consumers like tag validation and chatd introspection) still
emits the generic codersdk.Response shape with no kind information.

WriteWorkspaceBuildError checks for WorkspaceBuildResponder first, then
promotes any generic Responder result into the build envelope, so the
build endpoint consistently emits WorkspaceBuildErrorResponse.

The Go to user secrets button is rendered for layout parity but
disabled; PLAT-102 builds the user-secrets page and once it lands we
will wire the destination here.
@zedkipp zedkipp force-pushed the zedkipp/plat-81-missing-secrets-dialog branch from cb806c6 to 1b8d45c Compare May 15, 2026 22:16
Comment thread site/src/api/api.ts
// appropriate dialog. Parameter validations take priority: they
// surface during stop+start, while secret requirements only fire
// on start, so a workspace that has both will typically discover
// parameters first.
Copy link
Copy Markdown
Contributor Author

@zedkipp zedkipp May 15, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment isn't totally accurate. I think it should read When the response carries both parameter and missing-secret entries, surface the parameter dialog first. Missing secrets re-surface on the next build attempt.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant