Skip to content

🤖 feat: CoderProvisioner drift detection, status conditions, and test coverage#46

Closed
ThomasK33 wants to merge 38 commits into
mainfrom
provisioners-drift-conditions
Closed

🤖 feat: CoderProvisioner drift detection, status conditions, and test coverage#46
ThomasK33 wants to merge 38 commits into
mainfrom
provisioners-drift-conditions

Conversation

@ThomasK33

Copy link
Copy Markdown
Member

Summary

Implements the three main follow-ups from the CoderProvisioner deep review: spec drift detection with automatic key rotation, meaningful status conditions, and expanded test coverage.

Background

The CoderProvisioner controller successfully deploys external provisioner daemon Pods and manages a provisioner key in coderd. A deep review identified three functional gaps:

  1. Spec drift was ignored — when the key Secret already existed, changes to tags, key name, or organization name never took effect.
  2. Status conditions were defined but never populated, making failures hard to diagnose via kubectl describe.
  3. Key rotation/recovery paths were untested, especially the flow where coderd returns empty key material for existing keys.

Implementation

Drift Detection + Rotation

  • Added OrganizationName and TagsHash fields to CoderProvisionerStatus to record what was last applied to coderd.
  • Added deterministic hashProvisionerTags() helper using sorted keys + FNV-1a.
  • Controller now compares desired state against persisted status on every reconcile. When org name, key name, or tags hash drift, it deletes the old key (using previous status values) and creates a new one.

Status Conditions

  • Added 5 condition type constants: ControlPlaneReady, BootstrapSecretReady, ProvisionerKeyReady, ProvisionerKeySecretReady, DeploymentReady.
  • Controller now sets conditions on both success and failure paths (e.g., ControlPlaneReady=False when the control plane is unreachable).
  • Fixed reconcileStatus to update fields individually instead of wholesale replacement, preserving conditions set earlier in the reconcile loop.

Test Coverage

  • Upgraded the fake bootstrap client to support response queues and request recording, enabling multi-call flow testing.
  • Added 6 new envtest test cases: secret-loss rotation, tags drift, key name drift, ready phase + conditions, failure conditions, and long-name truncation.

Other Improvements

  • Added kubebuilder validation markers (MaxLength) on user-provided identifier fields.
  • Added kubectl get print columns (Phase, Replicas, Age).
  • Improved sample manifest with prerequisites documentation and secret creation guidance.
  • Added /coder-k8s to .gitignore.

Validation

  • make verify-vendor
  • make lint
  • make build
  • make test
  • make test-integration
  • make docs-reference-check

Risks

  • Drift rotation deletes the old key before creating a new one. If the create fails after delete, the provisioner will be temporarily keyless until the next reconcile succeeds. This is acceptable because the old key's tags/name were already wrong and unusable for job routing.
  • Best-effort old key deletion during drift — if the old key can't be deleted (e.g., it was already manually removed), the controller logs a warning and proceeds with creating the new key. This avoids getting stuck.

📋 Implementation Plan

Plan: CoderProvisioner deep-review follow-ups (drift, conditions, tests)

Context / Why

The current CoderProvisioner CRD + controller successfully deploys external provisioner daemon Pods and manages a provisioner key in coderd. A deep review found three functional gaps we want to close:

  1. Spec drift is ignored when the key Secret already exists (tags/key name changes never take effect).
  2. Status conditions exist but are never populated, making failures hard to diagnose via kubectl describe.
  3. Key rotation/recovery paths are untested, especially when coderd won’t return plaintext key material.

This plan implements drift detection (option a), adds meaningful conditions, expands test coverage, and ensures docs/samples do not leak secrets.


Evidence (review surface)

  • internal/controller/coderprovisioner_controller.go
    • Only calls EnsureProvisionerKey when the Secret is missing/empty (if !secretUsable { ... }).
    • reconcileStatus replaces status wholesale, wiping Conditions.
  • internal/controller/coderprovisioner_controller_test.go
    • Covers basic create, skip on existing secret, deletion, and control-plane-gone deletion.
    • Does not cover: rotation on empty key response, tags drift rotation, key name drift, long-name truncation, ready-phase transition, or condition setting on failure.
  • internal/coderbootstrap/provisionerkeys.go
    • EnsureProvisionerKey returns plaintext key only on create; existing keys return metadata with Key == "".
  • api/v1alpha1/coderprovisioner_types.go
    • Defines Status.Conditions but nothing sets them today.

Implementation details

1) Drift detection + rotation (option a)

Files:

  • api/v1alpha1/coderprovisioner_types.go
  • internal/controller/coderprovisioner_controller.go

1.1 Add status fields to record what we last applied to coderd

Add to CoderProvisionerStatus:

  • OrganizationName string — the organization name used (defaulted to default).
  • TagsHash string — deterministic hash of spec.tags last applied to the provisioner key.

Rationale: we need a persisted “previous desired state” to detect drift across reconciles.

1.2 Add deterministic tag hashing

In the controller, add a helper:

func hashProvisionerTags(tags map[string]string) string {
	keys := maps.Keys(tags)
	slices.Sort(keys)

	h := fnv.New32a()
	for _, k := range keys {
		_, _ = h.Write([]byte(k))
		_, _ = h.Write([]byte{0})
		_, _ = h.Write([]byte(tags[k]))
		_, _ = h.Write([]byte{0})
	}
	return fmt.Sprintf("%08x", h.Sum32())
}

1.3 Rework the key/secret decision tree

In Reconcile, compute “desired” values and compare to the “applied” status:

  • desiredOrgName := provisionerOrganizationName(spec.organizationName)
  • desiredKeyName, desiredSecretName, desiredSecretKey := provisionerKeyConfig(...)
  • desiredTagsHash := hashProvisionerTags(spec.tags)

Compute drift:

  • orgDrift := status.OrganizationName != "" && status.OrganizationName != desiredOrgName
  • keyNameDrift := status.ProvisionerKeyName != "" && status.ProvisionerKeyName != desiredKeyName
  • tagsDrift := status.TagsHash != "" && status.TagsHash != desiredTagsHash

Compute other needs:

  • secretUsable := Secret exists AND has non-empty data at desiredSecretKey (current logic)
  • metadataMissing := status.OrganizationID == "" || status.ProvisionerKeyID == "" || status.ProvisionerKeyName == ""

Then:

  • If orgDrift || keyNameDrift || tagsDrift: rotate (delete old key, create new key with desired tags), then update Secret.
  • Else if !secretUsable: ensure key; if response has empty Key, rotate to recover plaintext.
  • Else if metadataMissing: call EnsureProvisionerKey to populate IDs/name (Key may be empty, that’s OK).

Rotation rules:

  • Delete the previous key using status.OrganizationName + status.ProvisionerKeyName (best-effort delete, but treat failure as fatal if it prevents create).
  • Create the desired key using EnsureProvisionerKey(desired...) and require non-empty plaintext key to update the Secret.

1.4 Avoid unnecessary rotation on SecretRef changes

If status.SecretRef exists and spec.key.secretName or spec.key.secretKey changes:

  • Try to copy key material from the old secretRef → desired secretRef.
  • Only rotate remote key if key material can’t be recovered locally.

This prevents needless disruption when users only rename the Secret or change the data key.


2) Populate and preserve Status.Conditions

Files:

  • api/v1alpha1/coderprovisioner_types.go
  • internal/controller/coderprovisioner_controller.go

2.1 Add condition type constants

Add condition constants (API package) such as:

  • CoderProvisionerConditionControlPlaneReady
  • CoderProvisionerConditionBootstrapSecretReady
  • CoderProvisionerConditionProvisionerKeyReady
  • CoderProvisionerConditionProvisionerKeySecretReady
  • CoderProvisionerConditionDeploymentReady

2.2 Update controller to set conditions (and not wipe them)

  • Import k8s.io/apimachinery/pkg/api/meta and use meta.SetStatusCondition(&provisioner.Status.Conditions, cond).
  • Refactor reconcileStatus to start from existing status, update fields, and preserve conditions.

2.3 Best-effort condition updates on failure paths

For common failures (missing control plane URL, missing bootstrap secret/token, coderd API errors):

  • Set an appropriate condition to False with a safe message.
  • Call Status().Update best-effort (do not override the returned reconcile error).

Security constraint: condition messages must never include session token or provisioner key material; only refer to secret names/keys and high-level errors.


3) Tests: drift/rotation/conditions + truncation

Files:

  • internal/controller/coderprovisioner_controller_test.go
  • internal/controller/workspaceproxy_controller_test.go (fake bootstrap client)

3.1 Upgrade the fake bootstrap client to support sequences

Replace static provisionerKeyResponse with either:

  • A queue ([]EnsureProvisionerKeyResponse) consumed per call, or
  • A callback (EnsureProvisionerKeyFn(callN, req)) for complex scenarios.

This is required to test “empty key → delete → recreate” flows.

3.2 Add envtest cases

Add tests to cover:

  • Rotation on secret loss: first EnsureProvisionerKey returns Key:"", verify DeleteProvisionerKey then second ensure returns plaintext.
  • Rotation on tags drift: change spec.tags, reconcile, verify delete+ensure and Secret updated.
  • Rotation on key name drift: change spec.key.name, reconcile, verify old key deleted and new key created.
  • Secret exists but configured data key missing/empty: ensure controller recovers (copy or rotate).
  • Long-name truncation: CR name >63; verify SA/Role/Deployment names are <=63 (and update expectedProvisionerServiceAccountName helper to match real truncation logic).
  • Ready transition + conditions: set deployment.Status.ReadyReplicas=1 and verify Phase=Ready and DeploymentReady=True.
  • Failure conditions: missing bootstrap secret should set BootstrapSecretReady=False.

4) Docs & samples: ensure no secret leakage

Files:

  • config/samples/coder_v1alpha1_coderprovisioner.yaml

  • (optional) a short how-to doc under docs/how-to/

  • Keep samples using credentialsSecretRef only (no literal tokens/keys).

  • Add commented, placeholder-only instructions for creating the bootstrap secret (e.g., kubectl create secret ... --from-literal=token=<...>).

  • Re-run make docs-reference after API/status changes and confirm generated docs contain no secret values.


5) Other deep-review items (judgment)

Implement now (low effort, improves robustness):

  • Add missing field comments to CoderProvisionerStatus (parity with other types).
  • Add kubebuilder validation markers (MaxLength, Pattern) for user-provided identifier fields that become K8s names / Coder key identifiers.
  • Ensure reconcileStatus does not accidentally erase conditions (covered above).

Defer (nice-to-have):

  • Refactor DeleteProvisionerKey to take a request struct for consistency with other bootstrap methods.
  • Decide whether to change default key naming to avoid multi-namespace collisions (or document the limitation).

Validation

Run after implementation:

  • make codegen
  • make manifests
  • make docs-reference-check
  • make lint
  • make test
  • make test-integration
  • make build

Generated with mux • Model: anthropic:claude-opus-4-6 • Thinking: xhigh • Cost: $19.36

…ecret loss

Addresses Codex review feedback:
- Deletion finalizer now gracefully handles missing CoderControlPlane or
  bootstrap credentials (common during namespace teardown). Logs a warning
  and proceeds to finalizer removal instead of blocking.
- When the provisioner key secret is deleted but the key already exists
  in coderd, the controller now rotates the key (delete + recreate) to
  obtain fresh plaintext material for secret recovery.
- Added test for best-effort deletion when control plane is deleted first.
…ble control plane

Addresses additional Codex review feedback:
- Finalizer cleanup now uses the key name from status (reflecting what
  was actually created in coderd) rather than the current spec value,
  preventing orphaned keys when spec.key.name is edited after creation.
- All fetchControlPlane errors during deletion are treated as
  non-blocking (not just NotFound), handling the case where the control
  plane exists but has an empty status.url.
Addresses Codex round 3 feedback:
- All token-read errors during deletion are now best-effort (not just
  NotFound). Handles wrong key names, empty values, etc.
- Organization identity for finalizer cleanup uses status.OrganizationID
  (which may contain the resolved UUID) before falling back to spec.
Codex round 4:
- DeleteProvisionerKey errors during deletion are now logged and
  skipped (best-effort), preventing transient API failures from blocking
  finalizer removal.
- Secret existence check now also validates the configured data key is
  present and non-empty. A secret with a missing or empty key triggers
  key rotation/recovery instead of silently proceeding.
@ThomasK33

Copy link
Copy Markdown
Member Author

@codex review

@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: 3849035117

ℹ️ 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/coderprovisioner_controller.go
Comment thread internal/controller/coderprovisioner_controller.go Outdated
@ThomasK33

Copy link
Copy Markdown
Member Author

@codex review

Addressed both review findings:

  1. P1 (status stamping): reconcileStatus now receives appliedOrgName/appliedTagsHash which are only updated from desired values when the key was actually reconciled (drift-detected or !secretUsable paths). When the secret is usable and no drift detected, existing status values are preserved.

  2. P2 (secret name truncation): provisionerKeyConfig() now bounds the default secret name to 253 characters using the same FNV hash truncation pattern as other naming helpers.

@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: 9d3c6c313c

ℹ️ 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/coderprovisioner_controller.go Outdated
@ThomasK33

Copy link
Copy Markdown
Member Author

@codex review

Addressed the ProvisionerKeyReady condition feedback: the condition is now only set to True inside the drift-detected and !secretUsable branches, where EnsureProvisionerKey is actually called. When the secret is already usable and no drift detected, the condition is left unchanged (preserving whatever was previously set, or absent if never verified).

@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: 310f277580

ℹ️ 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/coderprovisioner_controller.go Outdated
Comment thread internal/controller/coderprovisioner_controller.go
@ThomasK33

Copy link
Copy Markdown
Member Author

@codex review

Addressed both findings:

  1. P1 (deletion org): reconcileDeletion now uses status.OrganizationName first, falling back to the spec-derived name only when status is empty. This ensures the delete targets the correct org even if spec changed but rotation never completed.

  2. P1 (ProvisionerKeyReady on failure): All error return paths in both the drift-rotation and !secretUsable branches now set ProvisionerKeyReady=False with reason ProvisionerKeyFailed and a descriptive message before returning. This covers: ensure failure, delete-for-rotation failure, recreate failure, and empty key material after rotation.

@ThomasK33

Copy link
Copy Markdown
Member Author

@codex review

Addressed both findings:

  1. Status write guard (P1): Added equality.Semantic.DeepEqual check with a pre-mutation snapshot in reconcileStatus. Status is only written when fields actually changed, preventing infinite reconcile loops.

  2. Secret-ref migration (P1): Resolved as deferred — recovering key material from a previously-referenced secret during spec.key.secretName changes is a valid optimization (section 1.4 of the implementation plan) but adds complexity around secret ownership and cross-reference tracking. This is tracked as a follow-up and does not affect correctness (rotation still produces a working key).

@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: f6cb4149e9

ℹ️ 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/coderprovisioner_controller.go Outdated
Comment thread internal/controller/coderprovisioner_controller.go Outdated
@ThomasK33

Copy link
Copy Markdown
Member Author

@codex review

Both findings addressed:

  1. Empty key validation (P1): After backfill rotation, rotated.Key is now checked — empty material returns an assertion error with ProvisionerKeyReady=False.

  2. Requeue on ensure failure (P2): Initial EnsureProvisionerKey failure in backfill now returns an error + RequeueAfter: 10s instead of silently continuing.

@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: 2132a72f17

ℹ️ 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/coderprovisioner_controller.go Outdated
@ThomasK33

Copy link
Copy Markdown
Member Author

@codex review

Fixed: delete failure in metadata-backfill now returns an error + RequeueAfter: 10s instead of silently continuing. All failure paths in the backfill branch now properly retry.

@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: 6c747d9077

ℹ️ 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/coderprovisioner_controller.go Outdated
@ThomasK33

Copy link
Copy Markdown
Member Author

@codex review

Fixed: removed RequeueAfter from error returns in backfill — controller-runtime's error-based exponential backoff handles retries. Also removed the now-unused time import.

@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: 24a291cfff

ℹ️ 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/coderprovisioner_controller.go
Comment thread internal/controller/coderprovisioner_controller.go
@ThomasK33

Copy link
Copy Markdown
Member Author

Both findings are pre-existing design limitations, not issues introduced by this PR:

  1. Reconcile missing coderd keys (P1): The controller has never re-validated keys in coderd during steady state. Adding periodic health checks against coderd is a separate feature that requires careful rate-limiting and would affect all provisioner reconciles. Tracked as a follow-up.

  2. Watch for control plane changes (P2): This is the same pre-existing limitation already discussed and resolved in a prior review round. SetupWithManager was not changed in this PR. Tracked as a follow-up.

Both items are worth implementing but are scope expansions beyond this PR's goal of drift detection, conditions, and test coverage. The changes in this PR are all net-improvements to the controller's robustness.

Pausing the review loop for human direction — Codex keeps surfacing valid pre-existing gaps rather than issues with the implemented changes.

@ThomasK33

Copy link
Copy Markdown
Member Author

@codex review

@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: 24a291cfff

ℹ️ 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/coderprovisioner_controller.go Outdated
Comment thread internal/controller/coderprovisioner_controller.go Outdated
@ThomasK33

Copy link
Copy Markdown
Member Author

@codex review

Addressed both:

  1. ControlPlaneRef drift (P1): Added status.controlPlaneRefName to track which control plane the key was minted for. Changing spec.controlPlaneRef.name now triggers key rotation. Backfill path stamps it for existing resources.

  2. Cached read-after-write (P2): Removed all redundant r.Get() calls after CreateOrUpdate in ensureProvisionerKeySecret, reconcileServiceAccount, reconcileRole, reconcileRoleBinding, and reconcileDeployment. Objects are already populated by CreateOrUpdate.

@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: 3591763491

ℹ️ 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/coderprovisioner_controller.go Outdated
Comment thread internal/controller/coderprovisioner_controller.go Outdated
@ThomasK33

Copy link
Copy Markdown
Member Author

@codex review

Both addressed:

  1. Control plane URL tracking (P1): Added status.controlPlaneURL to persist the URL the key was minted on. Drift-rotation delete now uses the previous URL from status, falling back to current URL when status is empty.

  2. Status snapshot timing (P2): Snapshot taken at start of Reconcile (before any setCondition calls) and passed to reconcileStatus as a parameter. Condition mutations are now visible to the equality check.

@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: 7517bc0c43

ℹ️ 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/coderprovisioner_controller.go Outdated
Comment thread internal/controller/coderprovisioner_controller.go Outdated
@ThomasK33

Copy link
Copy Markdown
Member Author

@codex review

Both addressed:

  1. URL drift (P1): Added controlPlaneURLDrift to drift detection so URL changes trigger key rotation.
  2. URL stamping (P2): Added appliedControlPlaneURL tracking — URL is only persisted when key is actually minted/rotated, preserving the previous minting URL for correct drift cleanup.

@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: dc0144f219

ℹ️ 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/coderprovisioner_controller.go Outdated
@ThomasK33

Copy link
Copy Markdown
Member Author

@codex review

Fixed: reconcileDeletion now prefers status.ControlPlaneURL for key cleanup, falling back to fetching the current control plane object only when status is empty. Updated test expectations to match.

@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: c6151aaab5

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

"ProvisionerKeyReady",
"Provisioner key is available in coderd",
)
} else if status.OrganizationName == "" || status.TagsHash == "" || status.ControlPlaneRefName == "" {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Backfill missing control-plane URL metadata

status.ControlPlaneURL is consumed later for URL drift detection and deletion cleanup, but this metadata-backfill branch only runs when org/tags/control-plane-ref fields are empty. If a provisioner has those fields populated while status.controlPlaneURL is empty (e.g., after upgrading from an intermediate revision or a status patch), this branch is skipped, so the URL never gets restored; that disables controlPlaneURLDrift and forces deletion cleanup to depend on fetching a live CoderControlPlane, which can skip key deletion when the control plane object is already gone.

Useful? React with 👍 / 👎.

@ThomasK33 ThomasK33 closed this Feb 11, 2026
@ThomasK33 ThomasK33 deleted the provisioners-drift-conditions branch February 14, 2026 00:31
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