Skip to content

feat(mecak8s-kind): add one-shot kind-up and kind-down tasks - #2054

Draft
tgrunnagle wants to merge 2 commits into
mainfrom
shorthaired-mailman
Draft

tgrunnagle wants to merge 2 commits into
mainfrom
shorthaired-mailman

Conversation

@tgrunnagle

Copy link
Copy Markdown
Contributor

Summary

Adds one-shot bring-up and teardown targets to the operator-run mecak8s Kind fixture (deploy/mecak8s-kind/Taskfile.yml), built entirely from existing targets:

  • task mecak8s:kind-up runs kind-keycloak-setup → :build → kind-hosts-add → kind-keycloak-demo in order. It deletes and recreates mecatl-dev, so it has a Task prompt: guard. Without a terminal, Task cancels it (exit 205) unless --yes is passed.
  • task mecak8s:kind-down runs mecatui logout against the fixture target (best effort), then kind-hosts-remove and kind-destroy. It is safe to run again.

Both use cmds:, not deps:, because Task runs deps in parallel.

The hosts tasks also no longer call sudo when nothing needs to change. /etc/hosts is world-readable, so kind-hosts-add and kind-hosts-remove check it without privileges first and call sudo only to add a missing alias or remove one that is present. The privileged re-check inside the append stays, so adding is still safe to repeat. As a result:

  • once the aliases exist (they are the same for every cluster), task --yes mecak8s:kind-up runs with no prompt, for example from a script;
  • kind-hosts-remove no longer overwrites /etc/hosts.bak when there is nothing to remove.

This PR also adds /deploy/mecak8s-kind/kconfig.yaml to .gitignore. That generated kubeconfig holds admin credentials for the disposable cluster and, unlike the mecak8s-vmcp fixture's kubeconfig, was not ignored.

Development stage

  • Plan / Interface — Bounded/Architectural behavioral and exact-interface contract; no implementation
  • Implementation — based on an approved, merged Plan / Interface PR
  • Combined — compact one-task Bounded/Architectural exception; no separate plan PR
  • Spike / Routine / Cleanup — acceptance-plan spine exempt; Spike evidence does not ship as-is

Contract linkage

  • Work classification: Routine
  • Classification rationale: the change only adds compositions of existing targets to the local, operator-run fixture Taskfile, and narrows when that fixture's hosts tasks call sudo. It changes no runtime, public API, protobuf, persistence, chart or trust-boundary interface, and the base kind-setup dependency boundary pinned by the fixture tests is unchanged.
  • Decision record: None — no design decision beyond the existing fixture.
  • Human waiver of spine: No
  • Acceptance plan: N/A (Routine)
  • Human decisions resolved and recorded: N/A — the directing human chose the prompt guard on kind-up and the check-before-sudo change to the hosts tasks.
  • Plan / Interface PR: N/A
  • Approved commit baseline: N/A
  • Combined/exemption rationale: Routine fixture tooling, as above.

Interface conformance

  • N/A (Routine). New operator commands: task mecak8s:kind-up and task mecak8s:kind-down.

Issue relationship

No tracking issue.

Type of change

  • Behavioral/interface plan
  • Bug fix
  • New feature
  • Refactoring (no behavior change)
  • Dependency update
  • Documentation/process
  • Other (describe):

Test plan

Baseline checks

  • Acceptance-plan checker — N/A (Routine; no plan)
  • Linting (task lint) — passes when run as Linux (GOOS=linux task lint, what CI targets). See the reviewer notes about macOS.
  • Fast offline test suite (task test) — covered by the race run
  • Pre-review race suite (task test:race) — passes except one macOS-only failure this change didn't cause (see reviewer notes). Two other timing-sensitive packages failed under load and passed on an isolated -race rerun.
  • Offline demo (go run ./cmd/mecademo) — shows the tool call, permission ask and approval, and result
  • Markdown changed: docs generation/link checks (task docs)
  • User docs/user-facing behavior changed: site build — N/A (fixture README only; nothing under user-docs/)
  • Guarded engine API affected — N/A
  • Intentional engine API change — N/A
  • Landed plan: strict acceptance trace — N/A
  • Final implementation review: /panel-review — not run

Fixture tests

TestMecak8sKindFixture_OneShotLifecycle checks:

  • kind-up has a prompt: and no deps:;
  • the step order of both tasks;
  • both hosts tasks check /etc/hosts before reaching sudo.

Removing the prompt or swapping kind-hosts-add and kind-keycloak-demo makes it fail. The existing closure tests confirm every referenced task exists and that the base kind-setup chain still pulls in no identity layer.

Live Kind run (Docker, mock provider, macOS arm64)

Prompt guard

  • Run without a terminal: cancelled before deleting anything.
  • Run in a terminal: completed after confirmation.

kind-up cluster state (all verified):

  • Cluster: node Ready. 16/16 pods Running with 0 restarts. All rollouts complete.

  • Helm: cert-manager v1.17.2 and mecak8s revision 2 (base install, then the Keycloak overlay).

  • Image: both replicas run the image ID built locally from this tree.

  • Provider: --mock set and no provider Secret.

  • Pod security: the namespace enforces the restricted policy.

  • Certificates: all three Ready. The exported fixture-ca.crt matches the cluster Secret byte for byte.

  • Local files: kubeconfig and CA file 0600, state directory 0700.

  • Host access: host ports bound to 127.0.0.1 only.

  • TLS: verifies through the alias, localhost and 127.0.0.1. Fails without the fixture CA and with a wrong hostname.

  • OIDC: login through a scripted Authorization Code + PKCE flow (the fixture user's password and the tokens were never printed). The discovery issuer matches, and tokens carry aud=mecak8s and mecak8s:access. A spent authorization code can't be reused.

  • API authentication:

    Request HTTP gRPC
    No token, garbage token or forged signature 401 status 16
    Valid token 200 status 0
  • Sessions: create returns 201. The session is stored in Redis, and each replica serves it when port-forwarded individually.

  • User isolation: a second user gets 404 on another user's session (read, transcript, rename).

  • Prompt: a mock prompt runs end to end over SSE.

  • Logs: no errors; only the warnings expected for this fixture.

  • No-sudo path: with the aliases present, kind-hosts-add exited 0 without a terminal and never called sudo.

kind-down

  • The cluster and node container, state directory, kubeconfig, lock file and both aliases are removed, and the three loopback ports are closed.
  • The /etc/hosts.bak diff shows only the two alias lines changed.
  • No fixture credential remains.
  • A second run without a terminal exits 0, prints "nothing to remove", calls no sudo, and leaves /etc/hosts.bak unchanged.

Changes

File Change
deploy/mecak8s-kind/Taskfile.yml Add kind-up (prompt-guarded) and kind-down; hosts tasks call sudo only when an entry must change
deploy/mecak8s-kind/fixture_test.go TestMecak8sKindFixture_OneShotLifecycle plus the fixtureTaskBlock and assertOrdered helpers
deploy/mecak8s-kind/README.md One-shot bring-up and teardown section; when sudo is needed
.claude/skills/mecak8s-kind-manual-verify/SKILL.md Point setup at kind-up and cleanup at kind-down
.gitignore Ignore deploy/mecak8s-kind/kconfig.yaml

User-facing change

Operators of the local Kind fixture get two new commands, task mecak8s:kind-up and task mecak8s:kind-down. kind-hosts-add and kind-hosts-remove now ask for a sudo password only when /etc/hosts actually needs to change. No product runtime behavior changes.

Special notes for reviewers

  • macOS-only gate failures this change didn't cause:
    • task lint on darwin reports 3 staticcheck SA4023 findings in internal/executionexecutor and cmd/mecatl-executor. The !linux stub always returns an error, so err != nil looks always true. The same packages show 0 issues when linted as Linux.
    • TestMecatedCLICompositionValidatesMicroVMDefaultAfterReadiness (cmd/mecated/microvm_command_test.go) fails every time on darwin. It binds a socket under /dev/fd/<n>/, which works through /proc/self/fd on Linux but not on macOS.
  • Side finding, not addressed here: the canned --mock provider (internal/app/registry.go) is one process-wide mockllm with a single scripted text turn. After the first prompt on a replica, later prompts get empty replies and end with no_progress, so a second manual mock session on the fixture looks broken.
  • kind-up still deletes the existing cluster after confirmation, the same way kind-keycloak-setup does. To keep a healthy cluster, use kind-keycloak-apply as the README describes.

🤖 Generated with Claude Code

tgrunnagle and others added 2 commits October 1, 2026 15:30
Compose the existing fixture targets into a single bring-up and teardown:

- kind-up: kind-keycloak-setup, build, kind-hosts-add, kind-keycloak-demo,
  run sequentially. It recreates mecatl-dev, so it carries a Task prompt
  guard; without a terminal Task cancels it unless --yes is passed.
- kind-down: mecatui logout (best effort), kind-hosts-remove, kind-destroy.

kind-hosts-add and kind-hosts-remove now read the world-readable
/etc/hosts unprivileged first and reach sudo only when an entry must
change, so a converged run never prompts and removal no longer
overwrites /etc/hosts.bak when there is nothing to remove.

TestMecak8sKindFixture_OneShotLifecycle pins the prompt guard, the step
order of both tasks, and the check-before-sudo order of the hosts tasks.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
kind-setup writes deploy/mecak8s-kind/kconfig.yaml (cluster-admin client
credentials for the disposable mecatl-dev cluster). Unlike the sibling
mecak8s-vmcp fixture kubeconfig it was not ignored, so a stray `git add`
could commit it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

This branch has not been deployed

No deployments
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