Run the controller on a laptop with just controller-local - #139
Merged
Merged
Conversation
An open guard (no API token, no issuer) resolved every request to anonymous, a viewer, so a controller without auth could be looked at but not driven. CONTROLLER_DEV_IDENTITY names the open-guard caller instead, drops whatever X-Auth-Request-* headers the client wrote, and refuses to boot on a guarded deployment where it would name every caller. Running a draft through the local executor turned up four more breaks: - A draft stores files with no mode, so its scripts unpacked 0644 and failed with EACCES. The pod mounts the pack with default_mode 0755; the local run now does the same. - FORGE_STORAGE_ROOT was never set, so a report task read the pod path /var/lib/forge. The local run gets a per-run forge dir. - run_env stripped HOME and USER, which the host claude CLI needs to find its login (the macOS keychain lookup keys on USER). The subprocess is the same OS user, so withholding them isolated nothing. It also stripped OPENSHELL_PODMAN_SOCKET, the only way the engine finds podman on macOS. - Local mode refused backend = "openshell" as cluster-only. The engine boots the sandbox on the podman compute driver by default, and examples/revise-loop runs that way through the local controller. An openshell pack still needs sandbox_image, now in both modes. With no inferable kube config the overrides ConfigMap watch is skipped instead of warning every 30s. The recipe pins KUBECONFIG=/dev/null so a laptop controller never writes into whatever cluster the shell points at. Assisted-by: Claude
|
Docs preview for this PR is built and attached as the Download Rebuilt for 9cb00df. |
Assisted-by: Claude
wseaton
enabled auto-merge
September 22, 2026 20:27
Local mode now dispatches openshell packs, so the refusal this test asserts comes from a pod deployment with no deploy profile. Assisted-by: Claude
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
just controller-localbrings up Postgres in podman and runs the controller on loopback with no identity provider, no Vault and no cluster. Every request lands as$USER, an admin, and launches run as localcrucible plan runsubprocesses.docs/controller-local.mdcovers it.The new piece is
CONTROLLER_DEV_IDENTITY: an open guard used to resolve every caller to an anonymous viewer, so a controller without auth was read-only. The dev identity only builds on an open guard (which already forces a loopback bind) and boot fails if it is set alongside a token or an issuer.Driving drafts through the local executor also turned up four breaks, fixed here:
./role.shhit EACCESFORGE_STORAGE_ROOTwas unset, so report tasks read/var/lib/forgeHOME/USER/OPENSHELL_PODMAN_SOCKETwere stripped from the run env, so the hostclaudecould not find its login and the engine could not find podman on macOSbackend = "openshell"was refused as cluster-only, though the engine runs it on the podman compute driverAlso skips the overrides ConfigMap watch when there is no kube config to infer.
Checked against a live local controller:
examples/playbookas a draft (completes, verdict valid), a one-taskclaudeagent draft ($0.17, done), andexamples/revise-loopon an OpenShell sandbox in podman (two rounds, done). Controller tests for auth, dispatch, drafts, local_run and dispatch_target pass, plus clippy and both modgraph checks.