Skip to content

PRD-01: capability-gated Resolve (resolver authentication) - #55

Merged
hellno merged 2 commits into
mainfrom
claude/issue-45-readiness-brief-3dazc3
Jun 14, 2026
Merged

PRD-01: capability-gated Resolve (resolver authentication)#55
hellno merged 2 commits into
mainfrom
claude/issue-45-readiness-brief-3dazc3

Conversation

@hellno

@hellno hellno commented Jun 14, 2026

Copy link
Copy Markdown
Owner

Replace the same-uid-only Resolve gate with an unforgeable capability so the
public proposer socket can no longer self-approve — closing THREAT-MODEL
residual-risk #1 and unblocking any external proposer (#48/#50).

Mechanism (resolves ADR 0001 PRD-01 open question → socketpair inheritance,
app is the parent): the app mints an AF_UNIX socketpair before spawning the
daemon, hands the child one end by fd inheritance (DECKARD_RESOLVE_FD), and
keeps the other as a ControlChannel. The daemon honours Resolve only on that
inherited end (Channel::Control); a Resolve on the public socket is refused
with a typed resolve_not_authorized denial. STOP stays reachable on every
channel. Each respawn re-mints the pair; the channel fails closed while the
daemon is restarting.

  • deckard-contract: add resolve_not_authorized to the frozen deny vocabulary
    (no wire/frame change — the channel carries authority, so Wire-contract evolution: Hello capability discovery + the five evolution rules #31 doesn't apply).
  • deckard-signerd: Channel enum + gate in Daemon::handle; serve_control +
    adopt_control_fd (the one daemon-side unsafe, scoped + validated: rejects a
    non-stream fd, sets close-on-exec); ControlChannel + control_pair in
    supervise.rs with respawn re-handshake; blocking frame helpers.
  • deckard-app: route Resolve over the control channel, Execute over the public
    socket (execute only signs an already-Allowed record).
  • Tests: new resolver_auth.rs (public-socket Resolve rejected, control-channel
    accepted, STOP-on-public, red-team second-proposer-cannot-self-approve);
    migrate existing resolve sites to the control channel.
  • THREAT-MODEL residual build(gpui): default to the git GPUI pair (Zed + gpui-component) over crates.io #1 → Mitigated; ADR records the decision.

CONTROL_TIMEOUT exceeds the daemon's broadcast lock-hold so normal
back-pressure isn't mistaken for a dead channel.

claude added 2 commits June 14, 2026 13:08
Replace the same-uid-only Resolve gate with an unforgeable capability so the
public proposer socket can no longer self-approve — closing THREAT-MODEL
residual-risk #1 and unblocking any external proposer (#48/#50).

Mechanism (resolves ADR 0001 PRD-01 open question → socketpair inheritance,
app is the parent): the app mints an AF_UNIX socketpair before spawning the
daemon, hands the child one end by fd inheritance (DECKARD_RESOLVE_FD), and
keeps the other as a ControlChannel. The daemon honours Resolve only on that
inherited end (Channel::Control); a Resolve on the public socket is refused
with a typed resolve_not_authorized denial. STOP stays reachable on every
channel. Each respawn re-mints the pair; the channel fails closed while the
daemon is restarting.

- deckard-contract: add resolve_not_authorized to the frozen deny vocabulary
  (no wire/frame change — the channel carries authority, so #31 doesn't apply).
- deckard-signerd: Channel enum + gate in Daemon::handle; serve_control +
  adopt_control_fd (the one daemon-side unsafe, scoped + validated: rejects a
  non-stream fd, sets close-on-exec); ControlChannel + control_pair in
  supervise.rs with respawn re-handshake; blocking frame helpers.
- deckard-app: route Resolve over the control channel, Execute over the public
  socket (execute only signs an already-Allowed record).
- Tests: new resolver_auth.rs (public-socket Resolve rejected, control-channel
  accepted, STOP-on-public, red-team second-proposer-cannot-self-approve);
  migrate existing resolve sites to the control channel.
- THREAT-MODEL residual #1 → Mitigated; ADR records the decision.

CONTROL_TIMEOUT exceeds the daemon's broadcast lock-hold so normal
back-pressure isn't mistaken for a dead channel.
…ness-brief-3dazc3

# Conflicts:
#	crates/deckard-app/src/signer.rs
@hellno
hellno merged commit f53271f into main Jun 14, 2026
5 checks passed
@hellno
hellno deleted the claude/issue-45-readiness-brief-3dazc3 branch June 14, 2026 13:22
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.

2 participants