Skip to content

🤖 test: add the CoderMCPServer Kind E2E phases - #389

Merged
ThomasK33 merged 5 commits into
mainfrom
mcp-e2e-phases
Oct 15, 2026
Merged

ThomasK33 merged 5 commits into
mainfrom
mcp-e2e-phases

Conversation

@ThomasK33

@ThomasK33 ThomasK33 commented Oct 15, 2026 •

Copy link
Copy Markdown
Member

Summary

The Kind E2E driver now exercises the active CoderMCPServer controller against a real Coder (v2.37.2, no license). It uses the stub from #371 as both the MCP server and the OpenAI-compatible LLM, so a real Coder chat proves credential delivery and tool names. This is plan step M10 of #155 (plan 7.3, phases P0 to P7 and P9). P8, the tool lists, comes with M11.

Phases (hack/e2e-workspace-lifecycle.sh)

The new steps run after the AI Gateway key phases and before the namespace deletion.

Phase What the driver does What it checks
P0 setup Deploys the stub (imagePullPolicy: Never, Services mcp-stub and mcp-stub-2). Creates an openai-compat provider and a model that point at the stub, through the Coder API. has_license: false, the stub is Ready. P4 (e) runs here (see below). Then the CCP opt-in lists the organization.
P1 apply An opted-in Opaque Secret for http://mcp-stub.<ns>.svc:8080 and an api_key CR with access.groups: [Everyone] Ready=True Applied. Coder's GET by status.configID: slug, URL, enabled, has_api_key. The ACL is exactly Everyone read. The CR and the operator log hold no key.
P2 chat The tester user (an organization member with a password login) creates a chat that selects the server Every new tools/list request at the stub has the right Host and the SHA-256 of the local key. The LLM got exactly e2e-mcp__alpha, e2e-mcp__beta, e2e-mcp__Gamma.
P3 rotation A new Secret value, then an annotation-only change The next chat turn carries the new key hash. After the annotation, Coder's updated_at is unchanged.
P4 refusals (a) an unlabeled Secret, (b) the operator token Secret, (c) a foreign origin, (d) a slug created first through the Coder API, (e) an organization the CCP does not list, (f) force_on without allowForceOn CredentialNotOptedIn, CredentialRefused, CredentialDestinationNotAllowed, SlugConflict, MCPServersNotAllowed, ForceOnNotAllowed, and no configID. Coder's config list (IDs, slugs, URLs, enabled, updated_at) is the same before, after, and after deleting the CRs.
P5 URL change spec.url to mcp-stub-2, then the new origin in the Secret Before the origin: CredentialDestinationNotAllowed, and Coder keeps the old URL, enabled. After: Ready, the new URL, and the next turn reaches mcp-stub-2 with the matching key hash.
P6 access access.groups: [], then [Everyone], with the tester user's session 400 "One or more MCP server IDs are invalid or disabled." and an empty ACL, then 201 and a full turn check.
P7 kill switch A disable through the Coder API, an annotation, then a displayName edit DisabledExternally and Coder stays disabled. After the edit: Ready and enabled.
P9 delete Delete the CR; keep a second Ready CR into the namespace deletion Coder's own 404 for the config ID. The second CR goes with the namespace, and the operator log has its ControlPlaneGone release.

P4 (e) runs in P0, before the P1 server exists. Unlicensed Coder has one organization, and a CR that names a missing organization gets OrganizationNotFound, not MCPServersNotAllowed. So the driver sets the CCP list to [e2e-no-such-org], checks the refusal and that Coder is unchanged, and then sets the real list. Changing the list after P1 would disable the P1 server.

Keys are 48 random hex characters in 0600 files, masked in GitHub Actions logs, and reach jq --rawfile, kubectl create/replace -f, grep -f and sha256sum only through files. The driver prints only "key hash match" or fails with "no match". It reads the stub's /report through the API server's service proxy, so no extra port-forward runs. The chats run as the tester: a chat created with the operator token never ran a turn on Kind. The driver logs in as the tester in P0, and on a local rerun that reuses the tester (409) it first sets this run's password. The tester's session token stays in the 0600 file member.hdr, which cleanup removes. While a turn runs, the driver logs the stub's request methods and tool counts (no header values).

Red evidence (hack/e2e-workspace-lifecycle_test.sh)

The offline stubs gain a fake CoderMCPServer controller, the fake Coder MCP routes, a fake stub report and a fake chat. Each phase has at least one failure row that breaks the checked behavior. Each row asserts that the driver exits non-zero with the FAIL message below and stops before the next mutation:

Phase Row The break The driver fails with
P0 mcp-licensed Coder reports a license Coder has a license: the MCP phases test unlicensed Coder
P1 mcp-never-ready The controller never gets Ready timed out ... waiting for: MCP server e2e-mcp Ready
P1 mcp-cr-leak The key appears in the CR status CoderMCPServer e2e-mcp or the operator log holds the MCP server key
P2 mcp-hash-mismatch A wrong key reaches the stub ... with the key in ai-key-mcp-1: key hash no match
P2 mcp-tools-missing The LLM does not get Gamma the LLM did not get exactly the tools ...
P3 mcp-no-rotation The new Secret version is recorded but the old key is sent ... with the key in ai-key-mcp-2: key hash no match
P3 mcp-meta-resend An annotation-only change writes to Coder a metadata-only Secret change wrote to Coder
P4 mcp-wrong-reason CredentialMalformed instead of CredentialDestinationNotAllowed MCP server e2e-mcp-origin stalled with ... want Ready=False CredentialDestinationNotAllowed
P5 mcp-url-early Coder's URL changes before consent Coder config ... changed before the Secret allowed the new origin
P6 mcp-acl-open The ACL keeps Everyone a tester chat that selects e2e-mcp with access.groups [] answered HTTP 201, want 400
P7 mcp-kill-undone The controller enables the server again the controller undid the disable of MCP server e2e-mcp
P9 mcp-delete-kept The config stays in Coder MCP server config e2e-mcp ... still exists in Coder after its object was deleted
P9 mcp-ns-stuck The CR keeps its finalizer in the namespace deletion timed out ... waiting for: test, provider, control plane, and namespace coder deleted

The existing rows now include the MCP mutations in their expected mutation order, the receipt counts 48 passed cases, and the argv and output checks also cover the tester's session token.

Validation

  • bash ./hack/e2e-workspace-lifecycle_test.sh: ALL OFFLINE TESTS PASSED, also with jq 1.7.1, the jq of the CI runner (jq 1.8 accepted a manifest expression that 1.7 refuses, review round 1). Each scenario is now capped at 180 s instead of 60 s, because the longer lifecycle passed the old cap on a loaded host.
  • The tester-exists scenario checks that a reused tester gets the run's password before the login. Without the reset it fails (mutation checked).
  • shellcheck on both scripts: clean.
  • Local gates on this head: make verify-vendor, make build, make lint, GOFLAGS=-mod=vendor go tool govulncheck ./..., make test, make test-integration, go test -race ./internal/controller/, and make docs-check pass. make codegen, make manifests, make build-installer and make docs-reference leave no diff.
  • The full Kind E2E runs in CI on this head, because the PR changes hack/e2e-workspace-lifecycle*.sh.

Size

396 changed lines, all hand-written: 238 in the driver and 158 in the offline tests.

Refs #155


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

Refs #155

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

Copy link
Copy Markdown
Member Author

@codex security review

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 15, 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-15T02:16:28.716221Z 4a668ed Manual request
🔒 Security Review ✅ Completed 2026-10-15T02:12:17.799863Z 4a668ed 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: 7c5864d3fb

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: 7c5864d3fb

ℹ️ 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 hack/e2e-workspace-lifecycle.sh Outdated
Comment thread hack/e2e-workspace-lifecycle_test.sh Outdated
Change-Id: I207bcc7046ff83339244700771d7e8d01703f9bb
Signed-off-by: Thomas Kosiewski <tk@coder.com>
Change-Id: If189ddd1f40425390164d2e20dc9eecdd8de9c99
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: 3651b36582

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. Bravo.

Reviewed commit: 3651b36582

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

…report while a turn runs

Change-Id: I77f799fa8c9d58f1e880f14f1f11f43edf5cf88f
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: 32036c4de7

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: 32036c4de7

ℹ️ 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 hack/e2e-workspace-lifecycle.sh
… log in

Change-Id: Ic2b43f6e0689ff70cb37f90d2973b469d0f1c80c
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: 4a668edb1a

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. Nice work!

Reviewed commit: 4a668edb1a

ℹ️ 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 15, 2026
Merged via the queue into main with commit c9dab9e Oct 15, 2026
10 checks passed
@ThomasK33
ThomasK33 deleted the mcp-e2e-phases branch October 15, 2026 02:40
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