Repository navigation
🤖 fix: finish the CoderAIProvider activation follow-ups - #408
Conversation
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>
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
|
@codex security review |
🛡️ Codex Security ReviewSecurity review completed. No security issues were found in this pull request. Reviewed commit: Only the user who started this review can view the report in Codex. ℹ️ About Codex security reviews in GitHubThis is an experimental Codex feature. Security reviews are triggered when:
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>
|
@codex review |
|
@codex security review |
|
Codex Review: Didn't find any major issues. Delightful! Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
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". |
🛡️ Codex Security ReviewSecurity review completed. No security issues were found in this pull request. Reviewed commit: Only the user who started this review can view the report in Codex. ℹ️ About Codex security reviews in GitHubThis is an experimental Codex feature. Security reviews are triggered when:
Once complete, Codex will leave suggestions, or a comment if no findings are found. |
Summary
This PR resolves the five follow-ups of the
CoderAIProvideractivation in #321.config/gitops/now holds an Argo CD Lua rule and a FluxhealthCheckExprsentry forCoderAIProvider.docs/how-to/gitops.mdhas a new section, "Health rules for CoderAIProvider", that copies both.health_test.goruns 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).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."ENABLEDcolumn.kubectl get coderaiprovidersnow prints the newstatus.enabledfield: 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, nottrue. A provider that someone deleted in Coder shows an empty cell too.main(details below).github.com/coder/coder/v2version 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,ReconcilingandStalledtogether on every status write, with one reason, one message andobservedGeneration.CoderMCPServerdoes the same. So the rules match theCoderMCPServerrules, apart from the kind and the deletion message (Deleting the Coder AI provider). The test helpermcpServerStatusis renamed toreadyReconcilingStalled, because both kinds use it now. The new cases include a failed kill-switch disable (Reconciling with a credential reason, soProgressing) and a kill switch (Stalled, soDegraded). 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/Currentfor a spec that Coder never received. The trigger is a spec edit plus a Secret rotation whose PATCH hangs until the reconcile context expires.syncAIProviderwrites the resend marker before the PATCH, andwriteStatusadvancedstatus.observedGenerationon that write. The stored object then hadobservedGeneration=2next toReady=Truefrom generation 1. Two changes fix it:status.observedGenerationnow moves only inapplyAIProviderStep, 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 envtestTestCoderAIProviderInterruptedUpdateKeepsObservedGenerationreproduces the hang and then checks that the next reconcile applies the edit.observedGenerationis notmetadata.generation. The FluxinProgressexpression is true until theReadycondition carries the current generation. This covers statuses that an older controller wrote. The health case "stale conditions" holds the verifier's stored state and expectsProgressing/InProgress.Item 2. I kept the reason
DisabledExternallyand 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).CoderMCPServeralready 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.mdnow says thatDisabledExternallyalso follows a repaired Secret.Item 3.
status.enabled(*bool) gets the value ofanswer.Enabledafter each Coder answer thatcheckAIProviderAnsweraccepts, 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 everyconfig/rbac/*.yamland compares each Secret rule and each binding withconfig/rbac/testdata/secret-access.yaml. That golden file holds thesecretsrule ofrole.yaml(ClusterRolemanager-role). I checked that the test catches a change: I addeddeletecollectionto 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 -mon the test binary lists no deps), so the test readsvendor/modules.txt.aiProviderSeedingFactsCheckedlistsv2.37.3andv2.37.8. To check v2.37.8, I compared the GitHub blob SHAs ofcodersdk/deployment.go,cli/server.go,coderd/ai_providers_migrate.goandcodersdk/aiproviders_bedrock.goat both tags. All four are byte-identical.compare v2.37.3...v2.37.8(21 commits) touches none of them. Sobedrock_base_urlandbedrock_regionare still the only YAML keys that seedanthropic, 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.Expected nil, but got: truefor a refused object, andtrueinstead offalseafter the kill switch). The kill-switch test fails on the old message. The seeding test fails when I removev2.37.3from the list.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.expected: 1, actual: 2forobservedGeneration, Argo returnsHealthy, and Flux returnsCurrent. Commit 8360722 makes them pass. The verifier's own probes also pass on the new head: the old stored object now readsProgressing/InProgress, and the fixed controller storesobservedGeneration=1.Risks
status.enabledis 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.CoderMCPServerkeeps itsspec.enabledcolumn. This PR does not change it.CoderMCPServeralso advancesobservedGenerationinwriteStatus, 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