feat(auth): operator auth via Authelia (M18-8) #190
No reviewers
Labels
No labels
area:agents
area:dashboard
area:database
area:design
area:design-review
area:flows
area:infra
area:meta
area:security
area:sessions
area:webhook
area:workdir
security
type:bug
type:chore
type:meta
type:user-story
No milestone
No project
No assignees
2 participants
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
charles/claude-hooks!190
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "dev/169"
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?
Summary
apps/server/src/auth.tsmodule: IPv4 CIDR matching,extractUser(trusted-proxy check),checkOperatorAuth(operator gate)Bun.serve.requestIP→ auth middleware; strips any user-suppliedx-claude-client-ipto prevent spoofingPOST /task,/cancel,/breakdown,/reset,/agentsPATCH/POST/DELETE, all/architect/*) gated behindguardMutating; read-only monitor routes remain open on the LANGET /whoami(always open) echoesreq.user,auth_enabled, andlogout_urlfor the SPA headerconfig/agents.json::authblock parsed at startup; boot fails iftrust_proxyis empty when the block is presentuseWhoamihooktrust_proxyconfig, end-to-endcurlverificationTest plan
auth.test.ts(CIDR helpers,extractUser,checkOperatorAuth, route-level 403/200, anti-spoofing)Closes #169
Rebase blocked — agent environment issue
Every shell command fails with:
The Claude Code harness needs to write a session-env directory under
CLAUDE_CONFIG_DIR(/home/claude/.config/claude-code/) before it will execute any command, but that path is mounted read-only in theclaude-hooks-devcontainer (the credentials bind-mount covers the whole directory).This is a container configuration issue, not a code conflict. The rebase cannot proceed until the environment is fixed.
To fix: the session-env path needs to be writable. Options:
/home/claude/.config/claude-code/session-env/inside the dev container.CLAUDE_CONFIG_DIRto a different writable path that doesn't overlap the read-only credentials mount, and point the credentials bind at a sub-path.Once fixed, re-assign the issue and I'll complete the rebase.
Review — M18-8 operator auth via Authelia ✅
CI green (run #1791, 3m12s). All acceptance criteria from issue #169 are met. No blocking issues found.
Acceptance criteria
Remote-Userfrom trusted proxy only, attaches asreq.user/architect/*+ mutating routes (/task,/cancel,/reset,/breakdown,/sweep,/agentsPOST/PATCH/DELETE) gated/health,/events,/queue,/history,/stats,/usage,/storage,/agentsGET open on LAN/webhook/forgejoleft open (HMAC-guarded, not Authelia)trust_proxyis empty butauthblock is present/whoamiopen, echoesuser/auth_enabled/logout_urlSecurity design
handleRequeststripsx-claude-client-ipfrom the raw incoming request, then re-injects it from the verifiedBun.serve.requestIP()socket address. The global middleware reads only the injected value — an external caller setting that header gets it wiped before routing. Test for this path exists ("x-claude-client-ip header cannot be spoofed by the client")./0(match all),/32(host-exact), invalid octets pass throughipv4ToInt→NaN→ipInCidrreturnsfalse.normaliseIpcorrectly maps::1→127.0.0.1and unwraps::ffff:x.x.x.x; even a malformed variant like::ffff:999.999.999.999would be extracted butipv4ToIntwould reject it as out-of-range.checkOperatorAuth(user, null)when noauthblock is present → returnsnull(open). Pre-M18-8 deployments see no behaviour change./whoamiexposure: intentionally open so the SPA can discover whether auth is configured. It revealsauth_enabledandlogout_urlbut no secrets. Matches the acceptance criterion.Minor observation (non-blocking)
useWhoamiinapp-shell.tsxfetches on mount only — if the Authelia session expires and the user re-authenticates while the SPA is open, the displayed username won't update until a page reload. Acceptable for an operator-only tool; no change needed.LGTM — ready to merge.