feat(agentapi): serve /agent/v1 on a unix socket; labctl learns unix:// LAB_URL #208
No reviewers
Labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
Cloonar/coding-lab!208
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "afk/201"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Closes #201
What
/agent/v1is now additionally served on a unix domain socket at<state-dir>/agent.sock— the SAMEagentapi.Handler()instance the TCP listener mounts, so run-token auth applies identically per transport. Newagentapi.SocketPath/agentapi.ListenSocket(stale socket removed before Listen, chmod 0700 — the 0700 state dir covers the pre-chmod window; clean shutdown unlinks vianet.UnixListenerclose). Both servers share the errCh/graceful-shutdown wiring; the startup log line now carriesagent_sock. The web/human TCP surface is untouched.LAB_URL=unix:///abs/pathaccepted everywhere. One seam inClient(requestBase()+ a socket-dialing transport inhttpClient()), through which bothdo()and the hand-built streamingSecretScanrequest pass — sowithClientverbs,secret exec,secret scan, and the pre-push guard hook all inherit it with zero command-layer changes. Relative socket paths (unix://foo.sock) fail fast with a clear error before any dial. http(s) behavior byte-identical.labURLprecedence is now--agent-url(verbatim) →unix://<state-dir>/agent.sock. The--base-url/loopback fallbacks are gone — routing agent traffic through the external origin was exactly issue #30's SSO-hairpin failure mode, and the socket always exists.--agent-urlalso admitsunix:///abs/path(config validation;--base-urlstays http(s)-only). Small deliberate scope addition: the default LAB_URL is itself a unix URL now, so the explicit override must be able to name a socket too (custom path today, the #205 container mount point tomorrow).services.lab.agentUrldefault flips"http://127.0.0.1:<port>"→null, so module deployments actually pick up the socket default instead of silently pinning loopback TCP.Proof
internal/agentapi/socket_test.go: stale-file/orphaned-socket/fresh recreation with 0700+ModeSocket asserts; realHandler()round-trip over the socket (401 without token, 200 with a seeded run token).internal/labctl/uds_test.go: relative-path rejection, unreachable-socket dial error,issue view/issue commentround trip against the real agentapi handler over UDS (view output byte-identical to the TCP fixture), andsecret scan(the hand-built streaming request) blocking a seeded leak / passing a clean range over the socket.--agent-url unix:///…accepted, relative rejected,--base-url unix://…still rejected;TestLabURLpins the new precedence.bin/lab+bin/labctl, temp state dir): boot →agent.sockappearssrwx------;labctl issue listover the socket reaches AuthMiddleware ("invalid run token", identical to TCP); SIGKILL → stale socket left → restart recreates and serves; SIGTERM → graceful shutdown, socket unlinked.go build ./..., fullgo test ./...,go vet ./...,gofmt -lclean, and golangci-lint 2.12.2 (CI's exact pin) → 0 issues.Notes for the maintainer
pr createuses (do(), tested over the socket viaissue comment), and the binary smoke covers the transport with production binaries.services.lab.agentUrlexplicitly (e.g. in Cloonar/nixos host config) will override the socket default until that setting is dropped — worth checking when the rev pin is bumped.🤖 Generated with Claude Code
[autoland] verdict: reject
FAIL — CI aggregate is failure:
ci-nix / flake-checkred after 18m34s (runs/225).ci / nativeis green (runs/226, 8m33s), so the Go build/test/vet/lint path is fine; the break is nix-specific and PR-introduced.Root cause (blocker)
This PR flips the NixOS module default
services.lab.agentUrltonull(nix/module.nix:256), and the ExecStart only emits the flaglib.optionals (cfg.agentUrl != null)(nix/module.nix:78-80). Correct. But the flake'snixos-moduleregression check still asserts the old loopback default and was not updated — andflake.nixis not in this PR's diff at all:flake.nix:232—grep '^ExecStart=' "$unitPath" | grep -qF -- '"--agent-url" "http://127.0.0.1:8080"'The dummy system (
flake.nix:104-121) setsbaseUrlbut noagentUrl, so with the new null default the unit emits no--agent-urlat all. Verified locally by evaluating the dummylab.serviceExecStart:So the line-232 grep cannot match → the
nixos-modulecheck fails →nix flake checkfails. That is the flake-check red.Required fix (author)
Update the
flake.nix:227-232regression block to assert the new #201 socket-default behavior instead of the removed loopback flag — e.g. assert the default unit carries no--agent-url(the socket is lab's internal default, not a CLI flag), and refresh the issue-#30 rationale comment (lines 227-231) to the socket model. Optionally add a dummy that setsagentUrl = "unix:///…"/http to prove the flag still serializes when explicitly set. Re-runnix flake check -Llocally (the**/*.nixpath filter means any module change re-triggers this gate) before handing back.Signal relied on:
labctl pr checks 208aggregate = failure; root cause confirmed by localnix evalof the dummy ExecStart.[autoland] verdict: fix-done
[autoland] verdict: pass