Skip to content

🤖 feat: activate the CoderAIProvider controller - #315

Merged
ThomasK33 merged 11 commits into
mainfrom
ai-provider-activate
Oct 14, 2026
Merged

ThomasK33 merged 11 commits into
mainfrom
ai-provider-activate

Conversation

@ThomasK33

@ThomasK33 ThomasK33 commented Oct 14, 2026 •

Copy link
Copy Markdown
Member

Summary

Plan row A7 of #154: the operator now runs the CoderAIProvider controller and installs its CRD. A new how-to documents the key Secret, the credential kill switch, the seeding limits and deletion.

This PR targets main. It builds on #312 (plan row A6, the delete path) and #325 (the provider ID check and the Coder-only delete 404, #323), which have landed. I brought it onto main with a merge commit; the diff against main is only the A7 change.

Refs #154

A7 gates (plan section 7.1, G3)

All hard gates are on main: #227 (#238), #236 (#293), #249 (#258), the #253 round-3 follow-ups (#265), #267 (#276), #268 (#283), #290 (#298), #277 and #289 (#303), #287 and #296 (#302), and the config-file check (#310). Plan row A6 (the delete path, #312) lands first, because without it a deleted object and its namespace would never finish deleting.

What

  • internal/app/controllerapp: registers CoderAIProviderReconciler.
  • RBAC markers: get, list, watch, patch on coderaiproviders, get, update on coderaiproviders/status, and update on coderaiproviders/finalizers. list is needed by the informer (the plan listed get, watch and patch). The secrets rule does not change (gate G2, test S9).
  • Dormancy: coder.com_coderaiproviders.yaml leaves DORMANT_CRDS. The CI guard step for it is removed. The other dormant kinds keep the mechanism.
  • CI: the e2e path filter adds internal/controller/coderaiprovider*.
  • config/samples/coder_v1alpha1_coderaiprovider.yaml.
  • docs/how-to/manage-ai-providers.md (AI providers, chat models and AI policies as controller CRDs #154 A7 checklist item 1, comment 6159404078): the key Secret and its value rules, the status reasons, the credential kill switch (any credential error disables the provider, and re-enabling needs a spec edit), dashboard kill switches, the seeding limits (envFrom, config files through CODER_CONFIG_PATH, --config or -c reserve anthropic, and a seeding setting added after the provider exists), deletion, and RBAC guidance.
  • internal/controller/coderaiprovider_env.go: the comment now says that only bedrock_base_url and bedrock_region seed anthropic from YAML. IsConfigured ignores bedrock_model and bedrock_small_fast_model (codersdk/aiproviders_bedrock.go:82-96 at v2.37.3). The check is unchanged.
  • Generated: the CRD in config/crd/bases, config/rbac/role.yaml, config/default/kustomization.yaml, dist/install.yaml, docs/reference/api/coderaiprovider.md, and the API nav in mkdocs.yml.

Review round 1

  • r4266594232 (P2: the getting-started cleanup deletes the control plane first, so a provider would stay in Coder): fixed. docs/tutorials/getting-started.md now deletes every CoderAIProvider before the control plane.
  • r4266594239 (P2: delete is owner power too): fixed. The warning and the RBAC table in the how-to name delete.
  • From the dogfood run: the how-to now says that the operator notices a dashboard change at its next read (resync about every 10 minutes, or at once on a change of the object, its Secret or its control plane).

Review round 2

  • r4266732699 (P2: the metadata-only no-write note was too broad): fixed. It now names the kill-switch exception and the resend after an operator restart.
  • r4266732709 (P2: the bounded delete needs working operator access): fixed in the deletion section.
  • r4266732716 (P2: operator inventories): CoderAIProvider is listed in docs/how-to/deploy-controller.md, docs/index.md and docs/explanation/architecture.md.

Review rounds 3 and 4

Stuck finalizer docs (#325 final assessment)

docs/how-to/manage-ai-providers.md has a "Stuck finalizer" section: an endless CoderUnavailable wait on delete (Coder unreachable, or a 404 that Coder did not send), and the assertion failed: error for a status.providerID that is not a UUID. It gives a JSON patch that first tests the finalizer at its index, then removes it, and a step to check Coder for a leftover provider and delete it in the dashboard.

Not in this PR

Validation

Local gates on the pushed tree, exit 0 each: make verify-vendor, make test, make test-integration, make build, make lint, go tool govulncheck ./..., go test -race ./internal/controller/, make codegen manifests build-installer docs-reference with no diff, make docs-check (strict MkDocs build), actionlint v1.7.10, and CI's markdownlint-cli2 0.18.1 and cspell 8.19.4 on docs/**/*.md.

Kind E2E (full CI job replica, 21 of 21 steps) and the plan section 9 dogfood passed on 96fbd65 and again on the final head 7b55c27, including the bounded delete while the control plane is Terminating: see the PR comments 6160744797 and 6161226918. CI's own E2E (Kind + CNPG + Templates) job also passed on this head.

Line count

Hand-written: 9 files changed, 212 insertions(+), 28 deletions(-). Generated: 5 files changed, 389 insertions(+), 14 deletions(-) (CRD move, RBAC role, kustomization, install bundle, API reference).


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

The finalizer now deletes the Coder provider that the object proved it
created: by the recorded ID, or after a read that finds this object's nonce
when only a create marker exists. 204 or 404 releases the finalizer, and a
failed delete retries every 60 seconds. When the control plane is gone, the
finalizer goes at once. While the control plane is being deleted, one
bounded delete attempt runs first (plan D12).

Refs #154

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

chatgpt-codex-connector Bot commented Oct 14, 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-14T05:57:11.570107Z 4e7685f Manual request
🔒 Security Review ✅ Completed 2026-10-14T05:56:39.621004Z 4e7685f 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: 96fbd65cf5

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.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 96fbd65cf5

ℹ️ 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".

Comment thread docs/how-to/manage-ai-providers.md
Comment thread docs/how-to/manage-ai-providers.md
…lookup answer

Change-Id: Ia687ee9bc423b12876f8827a959c735b556f1c56
Signed-off-by: Thomas Kosiewski <tk@coder.com>
@ThomasK33
ThomasK33 force-pushed the ai-provider-activate branch from 96fbd65 to cee53e3 Compare October 14, 2026 04:13
@ThomasK33

Copy link
Copy Markdown
Member Author

@codex review

@ThomasK33

Copy link
Copy Markdown
Member Author

@codex security review

@ThomasK33

Copy link
Copy Markdown
Member Author

Kind E2E and dogfood (plan G3, section 9), run on 96fbd65

The head has since moved to cee53e3: the #312 review fixes (delete-path edge cases, covered in envtest) and docs. I will rerun this on the final head after the reviews.

Image identity: the operator image built from the head (sha256:1ece3688bd95…) equals the node image ID and the running container's image on both clusters.

Part A: full CI E2E (Kind + CNPG + Templates) job, local replica with E2E_FULL=true. All 21 steps passed in 638 s, including the offline driver tests and 28 of 28 workspace lifecycle cases. The coderaiprovider controller started with no errors, and its reconcile metric exists.

Part B: plan section 9 steps 1 to 8 for CoderAIProvider, plus a namespace deletion. Coder v2.37.2, kind v0.26.0, kindest/node v1.32.0.

Step Result
1-2. Key Secret, apply the provider Ready / Applied in under 1 s: 1 POST (created disabled with the nonce), then 1 PATCH.
3. Coder API name, type, base_url, display name and enabled match. The masked key (first 4 + ... + last 4) equals the locally computed mask.
4. Dashboard /ai/settings/providers at 1440 px and 390 px (below).
5. Rotation The key ID and mask changed with exactly 1 PATCH. An annotation-only change sent 0 writes. Neither key value is in the operator log.
6. Refusals CredentialNotOptedIn, CredentialRefused (operator token Secret), CredentialDestinationNotAllowed, NameConflict (the API-made provider stayed unchanged). 0 Coder writes each.
7a. Dashboard disable DisabledExternally, 0 writes for 60 s. A displayName edit enabled it again (1 PATCH, same key ID).
7b. Credential kill switch Removing the Secret label disabled the provider in Coder (1 PATCH within 6 s), CredentialNotOptedIn. Restoring the label sent 0 writes. A spec edit enabled it again.
8. Delete 1 DELETE (204), then Coder answers 404 and the object is gone. Deleting the NameConflict object left the other provider unchanged.
9. Namespace deletion 4 provider objects; all gone in 6 s, the namespace in 17 s. The control plane went first, so the operator released with ControlPlaneGone (the bounded-delete path did not run here; envtest covers it).

Notes from the run, none of them blocking:

  • A dashboard change shows only at the next read (resync about every 10 minutes). The how-to now says so (cee53e3).
  • After the credential kill switch and a Secret repair, the reason reads DisabledExternally although the operator disabled the provider itself. Behavior matches the docs; the wording is a follow-up.
  • kubectl get coderaiproviders shows ENABLED true for refused objects that do not exist in Coder (the column shows the spec).

Providers list, desktop
Providers list, 390 px
Provider disabled in the dashboard
Provider enabled again after the credential repair and a spec edit, 390 px


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

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: cee53e37bc

ℹ️ 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".

Comment thread docs/how-to/manage-ai-providers.md Outdated
Comment thread docs/how-to/manage-ai-providers.md Outdated
Comment thread internal/app/controllerapp/controllerapp.go
@chatgpt-codex-connector

Copy link
Copy Markdown

🛡️ Codex Security Review

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

Reviewed commit: cee53e37bc

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.

… control plane is being deleted

Change-Id: I99f643fee0650ef981484202e3d35d8d67f10a7d
Signed-off-by: Thomas Kosiewski <tk@coder.com>
@ThomasK33
ThomasK33 force-pushed the ai-provider-activate branch from cee53e3 to 4263ed8 Compare October 14, 2026 04:31
@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. Keep it up!

Reviewed commit: 4263ed8bda

ℹ️ 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: 4263ed8bda

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.

…s a 404

Change-Id: Id18d664b10707befd7e2c4bc2af78012f3ef8fb4
Signed-off-by: Thomas Kosiewski <tk@coder.com>
The operator now runs the CoderAIProvider controller and installs its CRD.
The controller gets RBAC on coderaiproviders and its status and finalizers
subresources. The Secret rule does not change. A new how-to covers the key
Secret, the credential kill switch, the seeding limits and deletion.

Refs #154

Change-Id: If0f7968062016829043a2559342ea3150a674f11
Signed-off-by: Thomas Kosiewski <tk@coder.com>
… delete as owner power

Change-Id: Idfa61c5e1d811b02075dca247895563b9fb1242d
Signed-off-by: Thomas Kosiewski <tk@coder.com>
Change-Id: I7ba108fd9674446d12ecb8f4f0aee6e3e5f5624b
Signed-off-by: Thomas Kosiewski <tk@coder.com>
…CoderAIProvider in the inventories

Change-Id: I941c32cbe8915d7cd6bfeeca63908111226e6ad5
Signed-off-by: Thomas Kosiewski <tk@coder.com>
Change-Id: I197dbdca709523bdd0a4f7bffe3e5690408be8b1
Signed-off-by: Thomas Kosiewski <tk@coder.com>
@ThomasK33
ThomasK33 force-pushed the ai-provider-activate branch from 4263ed8 to 7b55c27 Compare October 14, 2026 04:45
@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 Security Review

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

Reviewed commit: 7b55c2765f

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.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 7b55c2765f

ℹ️ 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".

Comment thread internal/controller/coderaiprovider_env.go
@ThomasK33

Copy link
Copy Markdown
Member Author

Kind E2E and dogfood rerun on the final head 7b55c27

Image identity: the image built from this head (sha256:ffc2d7dbe05f…) equals the node image ID and the running container's image on both clusters.

Part A, full CI E2E (Kind + CNPG + Templates) replica (E2E_FULL=true): 21 of 21 steps passed in 616 s, including 28 of 28 workspace lifecycle cases. The coderaiprovider controller started with no errors.

Part B (Coder v2.37.2):

Step Result
Apply Ready / Applied: 1 POST, 1 PATCH. Fields and the masked key match.
Rotation 1 PATCH, new key ID. An annotation-only change sent 0 writes. No key value in the operator log.
Refusals CredentialNotOptedIn, CredentialRefused, CredentialDestinationNotAllowed, NameConflict: 0 writes each.
Credential kill switch Label removed: 1 PATCH, enabled=false. Label restored: 0 writes, still disabled. Spec edit: enabled again, same key ID.
Delete 1 DELETE (204), then 404 in Coder, object gone.
Bounded delete (plan D12) Control plane held Terminating with working operator access: deleting a Ready provider sent exactly 1 DELETE (204), Coder then answered 404, and the object was gone in 0.17 s. After the hold went, the namespace finished in 17 s.

Not exercised live (envtest covers them): the 2-minute create settle window and the release on an access error while the control plane is being deleted.

Providers list after the rerun, desktop


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

Change-Id: I90d1eedc61dc0fb679a738da32a7b1db88e1ac8b
Signed-off-by: Thomas Kosiewski <tk@coder.com>
Change-Id: Id811345fe37e29ff88dfa3be63709a6932023ad4
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 Security Review

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

Reviewed commit: 4e7685f36f

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.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 4e7685f36f

ℹ️ 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".

Comment thread docs/how-to/manage-ai-providers.md
Comment thread internal/app/controllerapp/controllerapp.go
@ThomasK33

Copy link
Copy Markdown
Member Author

G3 on the final head 4e7685f

This head merges main (with #312 and #325) into the branch. The diff against main is only the A7 change.

CI full E2E: run 38518624650, job 115703697201 passed with the full Kind steps; the "Skip full E2E on pull requests" step was skipped.

Image identity (local runs): the image built from this head (sha256:13110678006d…) equals the node image ID and the running container's image on both clusters.

Local full CI E2E replica (E2E_FULL=true): 21 of 21 steps passed in 635 s, including 28 of 28 workspace lifecycle cases.

Section 9 dogfood (Coder v2.37.2). Writes are POST, PATCH and DELETE on /api/v2/ai/providers, from Coder's own request metrics.

Step Result Writes
Apply Ready / Applied. Fields and the masked key match. 1 POST + 1 PATCH
Rotation New key ID, mask matches. An annotation-only change sends nothing. No key value in the operator log. 1 PATCH, then 0
Refusals CredentialNotOptedIn, CredentialRefused, CredentialDestinationNotAllowed, NameConflict (the API-made provider is unchanged). 0
Dashboard disable DisabledExternally, no re-enable for 60 s. A displayName edit enables it again. 0, then 1 PATCH
Credential kill switch Label removed: enabled=false, CredentialNotOptedIn. Label restored: still disabled. Spec edit: enabled again. 1, 0, 1 PATCH
Delete Coder answers 404, the object is gone. 1 DELETE (204)
Bounded delete Control plane held Terminating with working access: the only change across all Coder counters was 1 DELETE (204), then 404, object gone in 0.17 s. The namespace then finished in 17 s. 1 DELETE

"Stuck finalizer" docs, followed as written:

Check Result
Forged status.providerID: ../../users/me, then delete The object stays Terminating with the finalizer. Its status does not change.
The doc's log grep Finds assertion failed: AI provider coder/openai has status.providerID "../../users/me", which is not a canonical UUID.
Coder requests 0 on /api/v2/ai/providers* and /api/v2/users/me.
JSON patch with a wrong index, or a wrong value Fails, no change.
The doc's jsonpath, then its test + remove patch Index 0; patched, the object is gone.
Step 4 The provider was still in Coder. Deleting it in the dashboard sent 1 DELETE; Coder then answers 404.

Providers list, desktop
Providers list, 390 px
Leftover provider after the stuck finalizer was removed
Delete dialog in the dashboard

Notes, none blocking: a stuck object with a forged ID keeps showing Ready=True (the doc says the status does not change, and the log is the signal), and a failed test op prints only "The request is invalid".


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

@ThomasK33
ThomasK33 added this pull request to the merge queue Oct 14, 2026
Merged via the queue into main with commit 7b1a636 Oct 14, 2026
13 checks passed
@ThomasK33
ThomasK33 deleted the ai-provider-activate branch October 14, 2026 06:21
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