Repository navigation
fix(access): central project access gate, fail-closed lookups, file policy and origin check (lr-783ba1) - #430
Merged
Conversation
…d (lr-783ba1) One access gate at the entry of project message handling authorizes the current project and any targetSlug before a handler runs. Access lookups fail closed everywhere (upgrade, HTTP route, lists, palette, schedules), a record with no visibility is private, worktrees take their parent's access, and project lists and schedules reach each client filtered. File access shares one policy across the WS handlers, the HTTP route and the watchers: fileBrowser permission on every fs_ message but fs_unwatch, no daemon-user fallback in os-users mode, hex-only git revisions, project-relative git paths run as the caller's OS identity, per-connection watches. Global CLAUDE.md and shared env are administrator-only; env messages act on the authorized slug. Session rename, delete and search check access to the session. The WebSocket origin check compares host and port against the request host, with an operator allow-list. Client-supplied vendor, tab and call ids no longer index plain objects, and extension and MCP results are accepted only from the socket the call went to. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…r-783ba1) Session prompt stores, the request index, allowedTools, the MCP, worker and app-server correlation tables and the client tables keyed by server ids (file tree, cursors, notes, team panel, message handlers) are prototype-less maps, so a name such as constructor or __proto__ finds no entry. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…ck and hostile keys (lr-783ba1) Real server, real login cookies and real WebSocket clients for the gate, fail-closed lookups, lists, schedules, session actions and origin; real git and files for the file policy; real fs.watch for per-connection watches. One test per gap and per caller shape. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…te null-prototype comparisons (lr-783ba1) A test that clears the require cache no longer swallows a failed require.resolve; a guard test finds the pattern in any test file. Grant and prompt-store comparisons read the prototype-less maps through a plain copy. The extension-result test names the socket its commands went to. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…key handling (lr-783ba1) Also checks the owner and allow-list before reading the user store in the project access predicate, since it now runs for every message. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
… browser tools (lr-783ba1) The extension-command bookkeeping moves to lib/extension-commands.js so the socket binding is tested directly; the browser tools it was first tested through exist only where an agent CLI is installed, which CI does not have. The harness retries its cleanup while an adapter is still writing under HOME. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
|
BOBBIE — blocking (3 finding(s), 1 dropped)
Dropped candidates (1):
|
|
PEACHES — blocking (16 finding(s), 2 dropped)
Dropped candidates (2):
|
…d run read-only git as the repository owner (lr-783ba1) A connection with no user record is the implicit owner in single-user mode and a stranger in multi-user mode; every gate, filter, route and the WebSocket upgrade asks lib/project-access.js instead of dereferencing the user, and an upgrade always answers or destroys the socket. Read-only git no longer overrides safe.directory. In os-users mode it runs as the uid that owns the repository, with fsmonitor, hooks, external diff and textconv switched off on every call. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…ns flagged in review (lr-783ba1) Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…ner git rule (lr-783ba1) Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
|
PEACHES — clean (3 finding(s))
|
|
BOBBIE — clean (1 finding(s), 1 dropped)
Dropped candidates (1):
|
…tion so an unauthenticated palette request is refused (lr-783ba1)
principalFor(user, { authenticated }) yields the implicit single-user owner for a missing user only when the caller proved the login: isRequestAuthed(req) for HTTP, the WebSocket upgrade check (recorded on the connection and read with authOf) or the local MCP bridge. GET /api/palette/search had no login check ahead of it and returned every session title to an unauthenticated caller in single-user mode. Every call site of the resolver now passes the proof it has.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…bdirectory projects keep history (lr-783ba1) Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…es as empty in the require-cache guard (lr-783ba1) Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
|
PEACHES — clean (2 finding(s), 1 dropped)
Dropped candidates (1):
|
|
BOBBIE — clean (0 finding(s), 1 dropped) Dropped candidates (1):
|
Contributor
|
Merged via clagentic-loadout v0.2.0
|
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.
TASK: lr-783ba1 (lead). Also delivers lr-877be7, lr-bd22ea, lr-85c259 and lr-543036 items 1, 2 and 4 (item 3 goes to PR-3). Close all of them on merge; close lr-543036 only when both PRs have landed.
What changed (final state of the PR)
Authorization was opt-in per handler and a failed lookup counted as allowed. Now:
Docs: docs/guides/architecture.md (Access Control and Input Trust), MODULE_MAP.md.
Tests
Round 3 additions: test/authentication-precedes-principal.test.js (real server, the login gate stood in with a switch; in single-user and multi-user mode an unauthenticated palette search and recent list, /p//api/file, /p//, the root, /info and the WebSocket upgrade are all refused; the local MCP bridge works unauthenticated; an authenticated single-user owner is served the palette, file, root, info and socket; a login naming no user in multi-user mode is nobody). test/project-access-units.test.js (proof matrix: only the boolean true counts; authOf; gate refuses an unproven single-user connection). test/project-filesystem-policy.test.js (unproven single-user socket refused on every settings, fs and git message; repository subdirectory, nested .git file, no repository, and a root-only real setuid run in a subdirectory). test/require-cache-reset-guard.test.js (regex literals with quotes and braces, empty-statement and void 0 catch bodies, division kept as division).
Fixture edits to existing tests (the contract they encode changed): fakeSocket in project-filesystem-policy now marks the socket authenticated like the upgrade does; the single-user gate test and the project-access-units single-user cases pass the proof; the hub-recent-sessions wiring regex expects authOf(ws).
Demonstrated failure on 9e63a94 lib with the new tests present: single-user palette returned 200 instead of 401 (unauthenticated), the proof matrix, authOf, unproven gate, unproven socket and findRepositoryRoot tests failed; with the fix they pass.
Failing-test-ID set
CREW_SOP section 6 compliance record (access gate, upgrade check, message gate, git runner)
Pending post-merge real run: os-users with real Linux accounts, the live Caddy front end with trustedProxy, and the Chrome extension origin once the operator lists it.
Notes
Not folded (followups)
🤖 Generated with Claude Code