feat(broker-nats): ingress auth enforcement (PR-D2 — final auth #47) - #74
Merged
Conversation
Wires authorization into the broker's per-message path. broker-nats stays free of a
@murmurv2/federation dependency via injection: subscribeWithAck accepts an optional
InboundAuthorizer hook; the daemon wires federation authorizeInbound into it when
MURMUR_ENFORCE_AUTH is on (default OFF -> no hook -> no enforcement, fully back-compat).
In processEnvelopeFrame, after dedup and before onMessage: if an authorizer is wired
and rejects, the envelope is terminal — NACK auth-rejected:<reason>, onMessage is NEVER
called, and it is acked (not retried, since auth failure is not transient). The hook
returns only {accepted, reason} and must not log the token body.
Tests (tests/broker-auth-enforce.test.mjs, fake-nc harness, no live NATS): reject ->
NACK auth-rejected:<reason> + not delivered; accept -> delivered + ack; no authorizer ->
pass-through; reason defaults to 'denied'.
Completes auth/authz #47 (PR-A centralize payload, PR-B subject, PR-C envelope authToken,
PR-D1 authorizeInbound, PR-D2 broker enforce). Verified: build PASS; test:unit 68/68
(+4); full npm test 0 fail incl interop (a2a 6/6, federation 30/30); diff --check clean.
|
To use Codex here, create a Codex account and connect to github. |
Merged
alexfrmn
added a commit
that referenced
this pull request
Jun 22, 2026
…nism) (#75) Repo-level release for the work since 2.2.0 (#66-#74 + cross-host A2A validation): - root version 2.2.0 -> 2.3.0 - CHANGELOG [2.3.0]: discovery complete, streaming complete, auth/authz enforcement mechanism, conformance extended to all wire types, versioned protocol spec; Changed: centralized stableEnvelopePayload; Fixed: de-flaked C2; Validated: real cross-host A2A. [Unreleased]/Pending: daemon auth end-to-end wiring + npm republish @ 0.2.0. - README: What's New in v2.3 + Roadmap (streaming + discovery -> delivered; auth = mechanism shipped, daemon wiring remaining; A2A cross-host note). - Package versions: core/federation/broker-nats -> 0.2.0 (new public API); cascaded all workspace dep ranges to ^0.2.0 so workspace resolution + CI npm ci stay consistent. npm REPUBLISH is intentionally NOT done here (OTP-gated to Alex); it fixes the consumer caveat that published core@0.1.0 predates stableEnvelopePayload / authToken / authorizeInbound. Verified: npm install re-links @murmurv2/core@0.2.0 -> ./packages/core locally; build PASS; full npm test 0 fail (unit 68, core 49, federation 30, a2a 6, broker-ws 4, federation-nats 10); git diff --check clean. Co-authored-by: alexfrmn <freedmancolin@gmail.com>
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.
What (PR-D2 — the final piece of auth/authz #47)
Wires authorization into the broker's per-message delivery path.
Design: dependency-free injection
broker-nats does not import @murmurv2/federation.
subscribeWithAckaccepts an optionalInboundAuthorizerhook; the daemon wiresauthorizeInbound(PR-D1) into it whenMURMUR_ENFORCE_AUTHis on. Default OFF → no hook → no enforcement → fully back-compat.Enforcement (processEnvelopeFrame)
After dedup, before
onMessage: if an authorizer is wired and rejects, the envelope is terminal —NACK auth-rejected:<reason>,onMessageis never called, and it is acked (not retried — auth failure isn't transient). Hook returns only{accepted, reason}; never logs the token body.Tests (
tests/broker-auth-enforce.test.mjs, fake-nc, no live NATS)reject → NACK
auth-rejected:<reason>+ not delivered · accept → delivered + ack · no authorizer → pass-through · reason defaults todenied.Completes auth #47
PR-A (centralize payload) → PR-B (subject) → PR-C (envelope authToken) → PR-D1 (authorizeInbound) → PR-D2 (broker enforce).
Verification
build PASS; test:unit 68/68 (+4); full
npm test0 fail incl interop (a2a 6/6, federation 30/30);git diff --checkclean.Review by diff + CI. @codex final auth PR. Daemon wiring (read MURMUR_ENFORCE_AUTH + construct authorizeInbound with the agent's roster/identity/audience) can be a tiny follow-up or part of your daemon-deploy lane.