Skip to content

feat(broker): privileged broker over an authenticated local IPC boundary - #12

Open
undeemed wants to merge 12 commits into
mainfrom
fm/fpsm-broker-0e
Open

feat(broker): privileged broker over an authenticated local IPC boundary#12
undeemed wants to merge 12 commits into
mainfrom
fm/fpsm-broker-0e

Conversation

@undeemed

@undeemed undeemed commented Jul 27, 2026

Copy link
Copy Markdown
Owner

Intent

Implement the privileged broker skeleton and authenticated local IPC boundary for fpsmaxxing: a long-running broker process that owns the ControlPlane (provider + journal) and exposes capability discovery and bounded provider lifecycle over a Linux Unix-domain-socket IPC boundary behind a Windows-named-pipe-ready trait, with fail-closed peer authentication (SO_PEERCRED same-uid), single-owner-per-knob enforcement, policy-boundary hardening, and Linux-safe integration tests.

What Changed

  • Added the fpsmaxxing-broker binary (apps/broker) and a new crates/ipc crate: the broker owns the ControlPlane on a dedicated worker thread and serves exactly two operations - capability discovery and a bounded provider lifecycle - to local peers over length-prefixed JSON frames on a Unix domain socket, behind LocalTransport/PeerAuthorizer traits shaped for a later Windows named pipe. Three fail-closed checks guard the boundary (SO_PEERCRED same-uid ACL before any request is read, a capability-catalog check, and a single-owner-per-knob ledger), alongside a 1 MiB frame cap, a 32-connection limit with a 30s idle timeout, a short rejection-write deadline for unauthenticated peers, truncated echoes of client text, and a non-zero exit if the control-plane worker is lost.
  • Hardened broker startup paths and instance management: the broker establishes an owner-only (0700) private directory under $XDG_RUNTIME_DIR, or always /run/fpsmaxxing when running as root, vets every resolved socket/journal path as absolute with an ancestor chain unwritable by other users, creates the audit journal 0600, reads only broker-specific FPSMAXXING_BROKER_SOCKET/FPSMAXXING_BROKER_JOURNAL_PATH overrides (never the gateway's FPSMAXXING_JOURNAL_PATH), parses argv as OsString with a typed error, and takes an exclusive advisory lock on broker.lock before opening the journal or binding the socket so a second broker per uid refuses to start.
  • Added typed BrokerRequest/BrokerResponse wire messages in crates/contracts/src/ipc.rs with matching schemas/broker-request.schema.json and schemas/broker-response.schema.json, tightened ChangeRequest::parameters to reject non-object JSON so the Rust type matches the schemas, and covered the path with tokio integration tests (journaled lifecycle, foreign-peer refusal, owner conflict, malformed frames, connection cap, dead worker). README, docs/ARCHITECTURE.md, the threat model, and AGENTS.md now describe the boundary as built, including the interim nature of the same-uid ACL and the fact that the gateway still runs its own in-process control plane rather than calling the broker.

Testing

  • ⏭️ Test - skipped

Pipeline

Updates from git push no-mistakes

✅ **intent** - passed

✅ No issues found.

✅ **Rebase** - passed

✅ No issues found.

⏭️ **Review** - skipped

Step was skipped.

⏭️ **Test** - skipped

Step was skipped.

⏭️ **Document** - skipped

Step was skipped.

✅ **Lint** - passed

✅ No issues found.

✅ **Push** - passed

✅ No issues found.

Follow-up work (deferred, tracked)

Reviewed during this PR and deliberately deferred with maintainer sign-off; also recorded in docs/ARCHITECTURE.md "Deferred broker work":

  • Client reconnect-on-Closed - the broker closes idle connections after 30s but BrokerClient has no reconnect/keepalive; deferred because no consumer routes through the broker yet.
  • Bounded dispatch / BrokerClient::request timeout (broker-dispatch-unbounded) - a wedged-but-alive worker can stall connections (the fail-fast path only covers worker death); rides with the graceful-shutdown follow-up. A fixed deadline risks false timeouts on slow real hardware, and stuck-applied-state safety belongs to the watchdog TTL story.
  • Graceful shutdown / SIGTERM handling - deferred to a separate task.
  • Split-privilege ACL (fpsm-broker-splitacl) - the same-uid SO_PEERCRED ACL is interim; verified peer-identity journaling and owner-label authentication arrive with the Windows-SID / uid-mapped split-privilege ACL. Non-root single-instance is best-effort (root is airtight).

Testing note

The full workspace suite (94 tests) plus cargo fmt --check, check, clippy -D warnings, and deny check passed on this exact commit (f43e5df8) in the preceding pipeline run. The Review / Test / Document "skipped" markers above come from the final run, which used --skip review,test,document solely to retry the lint step after a transient API-capacity (529) failure - those steps had already passed on this same commit and were not bypassed on their merits.

undeemed added 12 commits July 27, 2026 06:31
…boundary

Implement the privileged side of the architecture: a long-running broker
that owns the ControlPlane (provider + journal) and exposes capability
discovery and a bounded provider lifecycle to authenticated local peers.

- crates/ipc: platform-abstracted local IPC behind traits - a LocalTransport
  seam (Unix domain socket now, Windows named pipe later), length-delimited
  framing bounded against hostile input, a fail-closed PeerAuthorizer with a
  Linux SO_PEERCRED same-uid ACL (SameUidAuthorizer), and a gateway-side
  BrokerClient. Unix specifics are cfg-gated so the crate still builds on
  Windows.
- crates/contracts: typed BrokerRequest/BrokerResponse wire messages plus
  broker-request/broker-response JSON schemas kept in sync by contract tests.
- apps/broker: BrokerService enforcing three fail-closed checks - peer auth,
  a capability-catalog check that rejects raw shell / arbitrary Registry
  paths / out-of-catalog ids, and single-owner-per-knob (OwnershipLedger).
  The non-Send control plane is confined to one worker thread reached through
  a Send BrokerHandle; malformed frames are rejected without crashing it.
- Integration tests (Linux-safe): full journaled lifecycle over the socket,
  foreign peer rejected, second owner rejected, malformed frames survived.

Control-plane and provider-sdk are untouched. Docs and AGENTS.md updated.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant