Commit Graph
16 Commits
Author SHA1 Message Date
kyleandClaude Opus 5.5 ba369f82ba brokerd: refuse / and a symbolic link as a socket's directory
brokerd makes a socket's directory 0700. With a socket directly in / it would
chmod /, and through a symbolic link it would change the link's target. Both
are now refused at start with #brokerd-start-failed. Without the fix the link
case started and served, with the shared directory made private.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-22 21:44:29 -07:00
kyleandClaude Opus 5.5 6af89f7c60 brokerd: runbook pointers for startup failures, no thread panics, args_os
M3a review findings 3, 5 (the cast), 6, 7 (brokerd), 11. A config, directory
or socket failure at start now ends with docs/runbook.md#brokerd-start-failed,
and losing a listener with #brokerd-listener-lost; both entries are new.
Threads start through thread::Builder, so a refused thread is reported
instead of silently killing a listener; an aborted connection no longer stops
the daemon. brokerd reads args_os and keeps the config path as a path. The
"requester went away" result is recorded at the time it happens.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-22 21:07:59 -07:00
kyleandClaude Opus 5.5 eed0a221ca Audit writer: open a record-less log, share the log-name rule, keep the lock file
M3a review findings 1, 2, 4 and part of 5. One empty log file made brokerd
panic at startup (files[len - 2]); it now opens as an empty log. brokerd's
name check tested one month digit, so a file bxctl ignored could become
brokerd's latest file; both now use proto::is_audit_log_name. Writer no
longer unlinks audit/.lock, which opened a two-writer window. No unwrap in
short_check.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-22 21:05:13 -07:00
kyleandClaude Opus 5.5 d7009dc488 brokerd tests: read the final frame after the handler closes, on macOS
The test client set its read timeout before every frame. On macOS that
fails with EINVAL once the handler has sent its final frame and closed,
so every admin test that reads a second frame failed there (40 runs of
40 at 2408e2c). The frame is already buffered, so the client now takes
that one refusal as the peer having closed and reads it. The plan's copy
changes with it.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-22 18:28:18 -07:00
kyle 3ecaef3c8b Add brokerd serve: startup, both sockets, and the expiry thread
Implemented-By: OpenCode session (model recorded in docs/implementer-log.md)
2026-09-20 17:24:57 -07:00
kyle d250678355 Handle approvals, refusals and grant checks on admin.sock
Implemented-By: OpenCode session (model recorded in docs/implementer-log.md)
2026-09-20 13:54:01 -07:00
kyle e68e626cd7 Handle a tool request from decision to answer
Implemented-By: OpenCode session (model recorded in docs/implementer-log.md)
2026-09-20 12:59:42 -07:00
kyle cff22ce579 Add the ledger: the audit writer and session state behind one lock
Implemented-By: OpenCode session (model recorded in docs/implementer-log.md)
2026-09-20 03:30:37 -07:00
kyle caf8fd6eca Add the table of pending approvals
Implemented-By: OpenCode session (model recorded in docs/implementer-log.md)
2026-09-19 16:48:09 -07:00
kyle 57734ebb9a Replace the runner stub with the Runtime seam and RunSpec
Implemented-By: OpenCode session (model recorded in docs/implementer-log.md)
2026-09-19 16:43:56 -07:00
kyle ded7eb8c50 Add the audit writer with its startup check
Implemented-By: OpenCode session (model recorded in docs/implementer-log.md)
2026-09-19 16:32:37 -07:00
kyle 726ce1f766 Keep each session's taint and untrusted flag in a file
Implemented-By: OpenCode session (model recorded in docs/implementer-log.md)
2026-09-19 03:08:46 -07:00
kyle e1e6c7a338 Decide tool calls against grants, taint and time
Implemented decide and redecide in crates/brokerd/src/policy.rs:
SessionState, Label, Denial, private Matched, and Decision/Ask (private
fields, Debug only, nine getters each) with the Outcome enum. decide
rejects an unknown tool (args not parsed) and malformed arguments before
matching, then runs the M1-M5 matching pass in id order and returns
Allowed/Ask/Denied by the winner's mode; redecide re-runs matching now
and rebuilds the Decision from the Ask. Seven doctests (six compile_fail,
one compiling) guard the two facts. policy 7, policy_matching 10,
policy_redecide 7, policy_property 4, doc 7 all pass; make gate ok.

Implemented-By: OpenCode session (model recorded in docs/implementer-log.md)
2026-09-19 03:05:01 -07:00
kyle e2ab29aa15 Load grant files, failing closed on any invalid file
crates/brokerd/src/grants.rs reads grants/*.toml into a GrantSet: load reports every problem in every file and returns either a complete valid set or the full problem list, never a partial one; from_grants sorts by id and collects every rule-2..9 problem; render prints each problem then the runbook pointer. All 17 grants tests pass; make gate prints gate: ok.

Implemented-By: OpenCode session (model recorded in docs/implementer-log.md)
2026-09-19 02:50:26 -07:00
kyle 9150effc8e Add typed tool arguments and the form checks for paths, hosts and URLs
Implemented brokerd::args: a pure module (no I/O, no clock) that parses tool
arguments into a typed ToolArgs and checks the form of paths, hosts and URLs.
Four private deny_unknown_fields structs drive parse and canonical_json; path,
cwd and url are validated as written and never normalised. All 13 args tests
pass and make gate prints gate: ok.

Implemented-By: OpenCode session (model recorded in docs/implementer-log.md)
2026-09-19 02:37:31 -07:00
kyle 5502de1c90 Add brokerd's configuration
Implemented crates/brokerd/src/config.rs: typed Paths, Sockets, Approvals and
Config with serde(deny_unknown_fields, default) on every struct, hand-written
ConfigError (Read/Parse) with Display and std::error::Error, and the parse/load/
broker_socket/admin_socket/audit_dir/state_dir methods. Added serde, serde_json
and toml to crates/brokerd/Cargo.toml, registered pub mod config; in lib.rs,
added brokerd to the serde and serde_json Used-by cells in docs/dependencies.md,
and copied the given test and six fixtures byte-identical. 7 config tests pass;
make gate prints gate: ok.

Implemented-By: OpenCode session (model recorded in docs/implementer-log.md)
2026-09-19 02:24:15 -07:00