Skip to content

🤖 feat: sweep the cleanup records of CoderAIGatewayKey objects that went without a delete (#353 part 2d) - #386

Merged
ThomasK33 merged 4 commits into
mainfrom
feat/ai-gateway-key-cleanup-sweep
Oct 14, 2026
Merged

ThomasK33 merged 4 commits into
mainfrom
feat/ai-gateway-key-cleanup-sweep

Conversation

@ThomasK33

@ThomasK33 ThomasK33 commented Oct 14, 2026 •

Copy link
Copy Markdown
Member

Refs #353 (part 2d: the CoderAIGatewayKey half of option B′, sweep). Refs #156. Stacked on #385 (records). Review only the top commit. I retarget this PR to main after #385 lands.

Summary

The cleanup record sweep from #375 now also handles CoderAIGatewayKey records. After a namespace deletion with an external database, the leftover keys are deleted in Coder once the namespace comes back with a control plane on the same Coder deployment. A different deployment at the same URL is never swept. Provider sweeping is unchanged.

Design note (option B′, #353 (comment))

The sweep keeps every rule of #375. The only new part is how one record's resources are deleted. That part now goes through a per-kind table (cleanupRecordKinds): the object type to look up, the words for the Event, and the sweep function.

Invariant Providers (#375, unchanged) Keys (this PR)
4. Who sweeps A ready control plane in the record's namespace whose live /buildinfo deployment ID equals the record's Same
5. What is deleted The recorded provider ID, or the provider whose display name is the nonce Every listed key whose name is the record's prefix ck8s-<UID without dashes>- plus a serial. The prefix is checked against the record's UID first (assertion). No other key is touched.
6. When Object with that UID gone (live read), 5 minutes after the last create Same. The object is gone, so no serial bound applies: after the settle window no create of the object can still commit.
7. Record removed Delete answered with success or Coder's own 404 A site owner's LIST shows no key with the prefix. The pass deletes and lists again, at most twice. A failed LIST or DELETE, or a 404 that is not Coder's own, keeps the record (retry in 1 minute).
8. No match Metric and NoMatchingDeployment Event Same, with the kind label CoderAIGatewayKey. The Event says "the AI Gateway keys".

The sweeper also wakes a key record when its CoderAIGatewayKey is deleted, as it does for providers.

Validation

  • New tests in cleanup_sweep_key_test.go:
    • TestCleanupSweepAIGatewayKeys: the settle window, no match, a different deployment at the same URL, and then the sweep. The sweep deletes the current, the retiring and an orphan key. It leaves a person's key and another object's ck8s- key, and the metrics change.
    • TestCleanupSweepAIGatewayKeyCases: a living object, the same name with a new UID, a proxy 404, a LIST that still shows a key, an operator user that is not a site owner, and a control plane in another namespace.
  • Red then green: 6 mutations, each caught by a test: keys not swept, "gone" without a confirming LIST, no prefix filter, no site-owner check, any 404 confirming a delete, and an object lookup by name only.
  • Local gates: build-installer, codegen, docs-reference, drift, verify-vendor, build, lint, govulncheck, test, test-integration, race, docs-check, actionlint. All passed.
  • Kind dogfood with a licensed Coder on 5bb2486 (same Go code as the head; the round-2 commit changes only docs): 🤖 feat: sweep the cleanup records of CoderAIGatewayKey objects that went without a delete (#353 part 2d) #386 (comment). A namespace deletion left 2 keys. A different deployment at the same URL and a control plane in another namespace swept nothing. The namespace came back on the same database, and then 0 keys and 0 records were left.

Risks

  • The provider path changes only in its log wording (Swept the Coder resources of a deleted object). Its Event text is the same as before.
  • A sweep of keys lists every key in the deployment (Coder has no filter). That is one LIST per record per sweep, the same LIST the key controller already sends.

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

… part 2c)

Change-Id: I6c7f7e46475e8077e1e05bace6651255696f5782
Signed-off-by: Thomas Kosiewski <tk@coder.com>
…t without a delete (#353 part 2d)

Change-Id: Ibf00c765664b1fa913d842a5c3e42509ea71312f
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-14T22:12:57.392489Z 56e0768 Manual request
🔒 Security Review ✅ Completed 2026-10-14T22:15:51.707048Z 56e0768 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: 5bb2486924

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 commented Oct 14, 2026 •

Copy link
Copy Markdown
Member Author

Dogfood: key sweep after a namespace deletion (head 5bb2486)

Operator image sha256:c1d7f3119391264dc5e7af9f23a7be018dbe341caee6b2cfa1b8924ae569464e, built from this head (it includes #385). Kind v1.32, licensed Coder v2.37.2 with CODER_AI_GATEWAY_ENABLED=true, and an external Postgres in namespace db with two databases (A = coder, B = coderb). Recording: one run, 21:51:51Z to 22:00:42Z.

Step What happened Result
1 ns1: control plane on database A, CoderAIGatewayKey gateway, one rotation Coder holds keys …-0 (retiring) and …-1 (current). Record ck8s-cleanup-4633560d-… has deployment ID 234459b7-… (A), prefix ck8s-4633560d570b40d185d7fe77f9fb19d3-, coderID = current key ID. 0 matches of the Secret's key in the record.
2 kubectl delete namespace ns1 (10 s) 1 release without a delete. Database A still holds both keys. The record stays.
3 Negative control: a new ns1 whose control plane has the same URL but uses database B (deployment 66d7113d-…) After the settle window: NoMatchingDeployment Warning Event on the record, coder_k8s_cleanup_records_unmatched{kind="CoderAIGatewayKey"} 1. Database A still holds 2 keys. Not swept.
4 Spoof control: ns2 with a control plane on database A (it answers the recorded deployment ID) After 90 s, database A still holds 2 keys. A control plane in another namespace never sweeps.
5 ns1 comes back with a control plane on database A Operator log: "object": "CoderAIGatewayKey ns1/gateway" "result": "deleted 2 keys, and a list shows none left".
6 Result Database A: 0 ck8s- keys. 0 records. coder_k8s_cleanup_records_swept_total{kind="CoderAIGatewayKey"} 1, unmatched 0.

The key counts come straight from the ai_gateway_keys table (names only). Leak scan: 0 key-shaped (43-character) values in the recording and in the full operator log.

End of the run

key-sweep-dogfood.mp4

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

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

Copy link
Copy Markdown
Member Author

@codex review

Round 2: one docs-only commit. The advisor found that the how-to said the sweep deletes "every key whose name starts with the prefix". The code (ownAIGatewayKeys) deletes only the prefix followed by a serial. The docs now say that. No code change.

@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. Breezy!

Reviewed commit: 56e07688a0

ℹ️ 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: 56e07688a0

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.

Base automatically changed from feat/ai-gateway-key-cleanup-records to main October 14, 2026 22:41
…leanup-sweep

Change-Id: I4ab65c5fe1c0be7661b20c783c3df60d89b2077b
Signed-off-by: Thomas Kosiewski <tk@coder.com>
@ThomasK33
ThomasK33 added this pull request to the merge queue Oct 14, 2026
Merged via the queue into main with commit 57ee69a Oct 14, 2026
13 checks passed
@ThomasK33
ThomasK33 deleted the feat/ai-gateway-key-cleanup-sweep branch October 14, 2026 23:13
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