Skip to content

🤖 fix: finish the CoderAIProvider activation follow-ups - #408

Merged
ThomasK33 merged 6 commits into
mainfrom
coderaiprovider-followups
Oct 30, 2026
Merged

ThomasK33 merged 6 commits into
mainfrom
coderaiprovider-followups

Conversation

@ThomasK33

@ThomasK33 ThomasK33 commented Oct 30, 2026 •

Copy link
Copy Markdown
Member

Summary

This PR resolves the five follow-ups of the CoderAIProvider activation in #321.

  1. GitOps health rules. config/gitops/ now holds an Argo CD Lua rule and a Flux healthCheckExprs entry for CoderAIProvider. docs/how-to/gitops.md has a new section, "Health rules for CoderAIProvider", that copies both. health_test.go runs them over 14 fixture objects and keeps the doc copies equal to the files. A key update that Coder never committed no longer reads as healthy (see Implementation).
  2. Reason after an operator disable. After the credential kill switch disables a provider and someone repairs the Secret, the object still reports DisabledExternally. The message no longer claims that someone disabled the provider in Coder. It now reads "Provider X is disabled in Coder, by a Coder admin or by the controller's credential kill switch. The controller does not enable it again until the spec changes."
  3. ENABLED column. kubectl get coderaiproviders now prints the new status.enabled field: the enabled flag that Coder reported at the controller's last read or update. A refused object that Coder does not have shows an empty cell, not true. A provider that someone deleted in Coder shows an empty cell too.
  4. Plan test S9. No code change. 🤖 fix: finish the CoderMCPServer delete and RBAC test follow-ups #399 already covers it on main (details below).
  5. YAML seeding facts on a Coder bump. A new test fails when the vendored github.com/coder/coder/v2 version is not in the list of versions that the seeding facts were checked against. The failure message lists the four Coder files to re-check. I checked v2.37.8 now: the facts still hold.

Background

#315 activated CoderAIProvider, and #321 tracks what it left open. None of these items blocks activation.

Implementation

Item 1. The AI provider controller writes Ready, Reconciling and Stalled together on every status write, with one reason, one message and observedGeneration. CoderMCPServer does the same. So the rules match the CoderMCPServer rules, apart from the kind and the deletion message (Deleting the Coder AI provider). The test helper mcpServerStatus is renamed to readyReconcilingStalled, because both kinds use it now. The new cases include a failed kill-switch disable (Reconciling with a credential reason, so Progressing) and a kill switch (Stalled, so Degraded). The gitops.md section sits between "Check after promotion" and "What CI covers". The only other gitops.md change is one added sentence at the end of the intro.

Item 1, interrupted update. An independent verifier found that both rules reported Healthy/Current for a spec that Coder never received. The trigger is a spec edit plus a Secret rotation whose PATCH hangs until the reconcile context expires. syncAIProvider writes the resend marker before the PATCH, and writeStatus advanced status.observedGeneration on that write. The stored object then had observedGeneration=2 next to Ready=True from generation 1. Two changes fix it:

  • Root cause. status.observedGeneration now moves only in applyAIProviderStep, which also writes the conditions for that generation. The intermediate writes (the resend marker and the provider ID after a create) leave it at the old generation. The new envtest TestCoderAIProviderInterruptedUpdateKeepsObservedGeneration reproduces the hang and then checks that the next reconcile applies the edit.
  • Defense. The Lua rule ignores conditions whose observedGeneration is not metadata.generation. The Flux inProgress expression is true until the Ready condition carries the current generation. This covers statuses that an older controller wrote. The health case "stale conditions" holds the verifier's stored state and expects Progressing/InProgress.

Item 2. I kept the reason DisabledExternally and changed only the message. The controller cannot tell who disabled the provider last: an admin can enable it and disable it again between two reconciles. The user's next step is the same in both cases (edit the spec). CoderMCPServer already documents the same behavior under the same reason. A status marker could name the cause exactly, but it adds API state for no new user action, so I left it out. docs/how-to/manage-ai-providers.md now says that DisabledExternally also follows a repaired Secret.

Item 3. status.enabled (*bool) gets the value of answer.Enabled after each Coder answer that checkAIProviderAnswer accepts, in the sync and in the kill-switch disable. A Coder 404 (providerGone, and the disable path) sets it to nil. The printer column reads .status.enabled. Regenerated: deepcopy, CRD, dist/install.yaml, docs/reference/api/coderaiprovider.md.

Item 4. config/rbac/rbac_test.go (TestSecretAccessMatchesGolden) scans every config/rbac/*.yaml and compares each Secret rule and each binding with config/rbac/testdata/secret-access.yaml. That golden file holds the secrets rule of role.yaml (ClusterRole manager-role). I checked that the test catches a change: I added deletecollection to the rule locally, and the test failed with "the Secret rules of role.yaml ClusterRole manager-role changed".

Item 5. Go test binaries carry no dependency build info (go version -m on the test binary lists no deps), so the test reads vendor/modules.txt. aiProviderSeedingFactsChecked lists v2.37.3 and v2.37.8. To check v2.37.8, I compared the GitHub blob SHAs of codersdk/deployment.go, cli/server.go, coderd/ai_providers_migrate.go and codersdk/aiproviders_bedrock.go at both tags. All four are byte-identical. compare v2.37.3...v2.37.8 (21 commits) touches none of them. So bedrock_base_url and bedrock_region are still the only YAML keys that seed anthropic, and keys and indexed providers still have no YAML keys. When Dependabot bumps Coder to v2.37.8, the test passes. A later bump fails until someone re-checks the facts.

Validation

  • make verify-vendor, make build, make lint, make test: pass.
  • make test-integration (envtest): pass.
  • make codegen manifests docs-reference build-installer: no diff after the commit.
  • make docs-check (mkdocs strict), markdownlint-cli2 "docs/**/*.md", cspell: pass.
  • Red checks. On the old code, the new column test fails (Expected nil, but got: true for a refused object, and true instead of false after the kill switch). The kill-switch test fails on the old message. The seeding test fails when I remove v2.37.3 from the list.
  • Branch merged with origin/main (🤖 fix: resend the AI provider key after a read confirms a create #397, 🤖 docs: add a runnable GitOps promotion example for CoderTemplateTest #405) without conflicts.
  • Red then green for the interrupted update: commit 3191e80 adds the tests. On it, the envtest fails with expected: 1, actual: 2 for observedGeneration, Argo returns Healthy, and Flux returns Current. Commit 8360722 makes them pass. The verifier's own probes also pass on the new head: the old stored object now reads Progressing/InProgress, and the fixed controller stores observedGeneration=1.

Risks

  • status.enabled is the value at the last read. While Coder is unreachable, it can be stale. Right after a create, it stays empty until the first successful read.
  • CoderMCPServer keeps its spec.enabled column. This PR does not change it.
  • CoderMCPServer also advances observedGeneration in writeStatus, and it has one intermediate write (the config ID after a create or record). I did not check whether that write can leave stale conditions. It is outside CoderAIProvider activation follow-ups (#154) #321, so this PR does not change it.

Fixes #321
Refs #154


Generated with mux • Model: anthropic:claude-opus-5-5 • Thinking: high

Change-Id: I453fc37a3fd4f09a28da18f4dbaf8107279e069b
Signed-off-by: Thomas Kosiewski <tk@coder.com>
…-checked (#321)

Change-Id: Ie1f26ea7cabac34dd359578376bc9c5d03e85cb5
Signed-off-by: Thomas Kosiewski <tk@coder.com>
…and name the kill switch in DisabledExternally (#321)

Change-Id: I89cd4e9232b2137ed31723bf53eb5617d99963ad
Signed-off-by: Thomas Kosiewski <tk@coder.com>
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 30, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-30T16:32:26.797485Z 8360722 Manual request
🔒 Security Review ✅ Completed 2026-10-30T16:33:43.086940Z 8360722 Manual request
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@ThomasK33

Copy link
Copy Markdown
Member Author

@codex security review

@chatgpt-codex-connector

Copy link
Copy Markdown

🛡️ Codex Security Review

Security review completed. No security issues were found in this pull request.

Reviewed commit: ff28bd827d

View security finding report

Only the user who started this review can view the report in Codex.

ℹ️ About Codex security reviews in GitHub

This is an experimental Codex feature. Security reviews are triggered when:

  • You comment "@codex security review"
  • A regular code review gets triggered (for example, "@codex review" or when a PR is opened), and you’re opted in so security review runs alongside code review

Once complete, Codex will leave suggestions, or a comment if no findings are found.

…wups

Change-Id: I9c3fa381d5700bd36e627dfbe8817fdda4fa8a9c
Signed-off-by: Thomas Kosiewski <tk@coder.com>
…#321)

Change-Id: I62d50f4f4f6ae0a361573150674430adb1b0c03c
Signed-off-by: Thomas Kosiewski <tk@coder.com>
A key update writes the resend marker before the PATCH. That write
advanced status.observedGeneration while the conditions still described
the previous generation, so an interrupted update left a status that the
GitOps health rules read as Ready for the unapplied spec.

Only applyAIProviderStep moves status.observedGeneration now. The Argo
CD and Flux rules also ignore conditions from an older generation.

Change-Id: Id66dfc77bf93844320499ec2b37836d3ec3bf266
Signed-off-by: Thomas Kosiewski <tk@coder.com>
@ThomasK33

Copy link
Copy Markdown
Member Author

@codex review

@ThomasK33

Copy link
Copy Markdown
Member Author

@codex security review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Delightful!

Reviewed commit: 836072265d

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@chatgpt-codex-connector

Copy link
Copy Markdown

🛡️ Codex Security Review

Security review completed. No security issues were found in this pull request.

Reviewed commit: 836072265d

View security finding report

Only the user who started this review can view the report in Codex.

ℹ️ About Codex security reviews in GitHub

This is an experimental Codex feature. Security reviews are triggered when:

  • You comment "@codex security review"
  • A regular code review gets triggered (for example, "@codex review" or when a PR is opened), and you’re opted in so security review runs alongside code review

Once complete, Codex will leave suggestions, or a comment if no findings are found.

@ThomasK33
ThomasK33 added this pull request to the merge queue Oct 30, 2026
Merged via the queue into main with commit 60b71fd Oct 30, 2026
12 of 13 checks passed
@ThomasK33
ThomasK33 deleted the coderaiprovider-followups branch October 30, 2026 17:12
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.

CoderAIProvider activation follow-ups (#154)

1 participant