Skip to content

🤖 feat: add the dormant CoderTemplateTest reconciler skeleton - #197

Merged
ThomasK33 merged 2 commits into
mainfrom
feat/template-test-4-reconciler-skeleton
Oct 3, 2026
Merged

ThomasK33 merged 2 commits into
mainfrom
feat/template-test-4-reconciler-skeleton

Conversation

@ThomasK33

@ThomasK33 ThomasK33 commented Oct 3, 2026 •

Copy link
Copy Markdown
Member

Summary

Fourth layer of the CoderTemplateTest stack (Refs #152), the first half of the plan's PR 3. It adds CoderTemplateTestReconciler without registering it, so the kind stays dormant and nothing changes for users. The reconciler never creates a workspace.

I split the plan's PR 3 in two because the full version came to about 790 hand-written lines. This PR is the skeleton and control-plane access. The next layer adds owner eligibility, the organization, template, and version lookups, version pinning, and the workspace name check.

What

internal/controller/codertemplatetest_controller.go runs the first step that applies, then returns:

  1. Assertions (assertion failed: ...): client, scheme, and clock are set. The fetched object matches the request. The UID gives a ktt- name of 28 hex characters, and a recorded status.workspaceName matches it. A create marker or workspace ID fails fast, because this controller never creates workspaces.
  2. Deletion: releases the finalizer at once. No test can own a workspace yet.
  3. Finalizer coder.com/template-test-cleanup (new constant in api/v1alpha1), stored with Update before any Coder call. A finished test whose workspace is gone is not given the finalizer again.
  4. Initialization: phase=Pending, startTime, observedGeneration, Reconciling=True, Ready=False, Stalled=False.
  5. A final test sets WorkspaceDeleted=True (NotCreated) if needed, then releases the finalizer. It is never evaluated again.
  6. Deadline: startTime + timeoutSeconds passed gives Failed DeadlineExceeded, with the last wait reason in message.
  7. Lookups: the referenced CoderControlPlane (missing, being deleted, or without status.url: ControlPlaneNotReady), operator access and the token Secret (OperatorAccessNotReady), spec.templateTests.ownerUserID (OwnerNotConfigured), and the owner's existence in Coder (OwnerNotEligible). Other Coder failures wait with CoderUnavailable and only the status code and Coder's short message.
  8. When everything resolves, the test waits with ReadyToCreate. The plan's PR 4 replaces this with the create step.

Every status write uses Status().Update with the read resourceVersion and is skipped when nothing changed. Waits requeue after 15 s, never past the deadline. The reconciler reads the clock again after its Coder lookups, so a deadline that passes during a slow lookup still fails the test. Coder calls use a 30 s client timeout. Messages are capped at 256 bytes.

Coder URL: an HTTP status.url is used as is. With TLS, status.url is HTTPS on the service name, which certificates rarely cover, so the controller uses controlPlaneSDKURL (internal HTTP) like the control-plane controller. #198 tracks the same change for the provisioner and the aggregated API server.

k8s.io/utils/clock/testing is now vendored (from the module already in go.mod) for the fake clock.

Follow-ups from the #196 assessment

  1. Reserved names: Coder v2.37.2 rejects only the lowercase words (codersdk.NameValid compares str == "new" || str == "create", and httpapi calls it on the raw value). The CEL rule already matches, so it stays case-sensitive. A new API test row pins that New.CREATE is accepted.
  2. Fake orgByIdent: this layer looks up no organization, so it does not depend on it. The next layer, which adds the lookups, makes it case-insensitive like v2.37.2 GetOrganizationByName (LOWER(name)) and tests a mixed-case template reference.
  3. Dormant-CRD guard: unchanged. The activation PR (plan PR 7) removes or adjusts it.

Not in this layer, by plan: the control-plane-gone release (amendment A1) and deletion-policy: retain (A2) come with cleanup in PR 5. The 429 backoff comes with the create path in PR 4.

Tests

internal/controller/codertemplatetest_controller_test.go (envtest with the fake Coder, a new reconciler per call to model restarts, and a fake clock):

  • Each wait reason, then recovery: operator access not ready, missing status.url, control plane deleted, no owner configured, unknown owner, a Coder 503 (CoderUnavailable), and finally ReadyToCreate. The first reconcile only adds the finalizer and makes no Coder call. No create request is sent. Deleting the waiting test releases it at once.
  • Deadline while Pending: at 899 s the requeue is 1 s, at 900 s the test is Failed DeadlineExceeded with Stalled=True, Ready=False, WorkspaceDeleted=True (NotCreated), and no finalizer. Later reconciles do not change it.
  • Deadline after a slow lookup: the clock passes the deadline during the lookups, and the test fails with DeadlineExceeded and the last wait ReadyToCreate.
  • codertemplatetest_internal_test.go: an HTTP status.url stays unchanged, and an HTTPS one with TLS becomes http://coder.ns.svc.cluster.local:80.
  • codertemplatetest_api_test.go: New.CREATE is accepted.

The fake's token now equals the token that createTestControlPlane stores, so tests reuse that helper.

Mutation check (scratch worktree, each mutation fails at least one test): no finalizer before Coder calls, no deadline, no deadline recheck after lookups, status.url for HTTPS, and no finalizer release for a finished test.

Validation

All on the pushed tree, with exit 0 each:

  • make verify-vendor, make test, make test-integration, make build, make lint
  • make codegen, make manifests, make docs-reference (no diff afterwards)
  • go test -race ./internal/controller/...

Line count

586 hand-written added lines and 3 removed. Vendored k8s.io/utils/clock/testing adds 419 lines.


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

Add CoderTemplateTestReconciler without registering it: assertions,
cleanup finalizer before any Coder call, status initialization, the
deadline while Pending, control-plane and operator-token access, and the
owner setting with an existence check. Finished tests and deleted tests
that never created a workspace release the finalizer at once.

Refs #152

Signed-off-by: Thomas Kosiewski <tk@coder.com>

---
_Generated with [`xum`](https://github.com/coder/xum) • Model: `anthropic:claude-opus-5-5` • Thinking: `high`_

Change-Id: I92e96b44f6940e8031f1c3bf1aa59f9205c180aa
@ThomasK33

Copy link
Copy Markdown
Member Author

@codex security review

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 3, 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-03T06:45:21.885109Z 878b6e6 Manual request
🔒 Security Review ✅ Completed 2026-10-03T06:44:49.922287Z 878b6e6 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.

@chatgpt-codex-connector

Copy link
Copy Markdown

🛡️ Codex Security Review

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

Reviewed commit: 93e81bf644

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: 93e81bf644

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

Address the #197 review: with TLS, call Coder through the internal HTTP
URL like the control-plane controller, and fail a test whose deadline
passed while its Coder lookups ran.

Refs #152

Signed-off-by: Thomas Kosiewski <tk@coder.com>

---
_Generated with [`xum`](https://github.com/coder/xum) • Model: `anthropic:claude-opus-5-5` • Thinking: `high`_

Change-Id: I6405b4c0ba48b42032689b9532dc6a63e3e3b636
@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: 878b6e6623

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

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Already looking forward to the next diff.

Reviewed commit: 878b6e6623

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

@ThomasK33
ThomasK33 added this pull request to the merge queue Oct 3, 2026
Merged via the queue into main with commit 9f00126 Oct 3, 2026
10 checks passed
@ThomasK33
ThomasK33 deleted the feat/template-test-4-reconciler-skeleton branch October 3, 2026 06:55
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