fed-sx-m2: Step 5b — pipeline:validate_inbound/3 + 14 tests
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 23s

New federation inbound pipeline that runs envelope-shape -> peer
signature -> replay against the receiving actor's inbox log.

pipeline.erl additions:
  validate_inbound/3(Activity, PeerActorState, InboxLog)
      runs inbound_stages(PeerAS, InboxLog) and halts on first
      failure (existing run_stages/2 driver). Returns ok |
      {error, Reason}.
  inbound_stages/2(PeerAS, InboxLog)
      [stage_envelope, stage_signature(PeerAS), stage_replay(InboxLog)]

M1's validate_inbound/1 and the static inbound_stages/0 (envelope-
only) are preserved — outbox-side callers don't have to re-key on
a peer-AS they don't have.

Signature verification routes through the peer's actor-state
:public_keys (NOT the local kernel's actor-state). Peer-AS
resolution is the caller's responsibility for 5b; Step 5c wires
the peer-actors cache lookup.

14 cases in next/tests/inbox_pipeline.sh:
  - happy path: valid signed activity + correct peer AS + empty
    inbox -> ok
  - bad envelope shape -> {error, _} (stage_envelope rejects)
  - unsigned activity -> stage_envelope rejects on
    {missing_field, signature} before sig runs
  - wrong peer AS (peer's claimed key bytes differ from real) ->
    {error, bad_signature}
  - replay: inbox already contains the same activity -> {error, replay}
  - inbox with a different activity doesn't trigger replay
  - inbound_stages/2 returns exactly 3 stages
  - inbound_stages/0 still returns 1 stage
  - validate_inbound/1 still works
  - shape failure short-circuits before sig
  - sig failure short-circuits before replay
  - two distinct activities both verify against empty inbox
  - inbox-of-one doesn't replay the other

Conformance 761/761. 130/130 across 10 Step-5-adjacent suites
(pipeline_envelope, pipeline_signature, pipeline_replay,
pipeline_driver, inbox_pipeline, inbox_bucket, nx_kernel_multi,
bootstrap_start, http_publish, outbox_publish, smoke_app_pure).
This commit is contained in:
2026-06-06 16:22:47 +00:00
parent bc4b23cc62
commit d103ecb863
3 changed files with 212 additions and 8 deletions

View File

@@ -344,12 +344,22 @@ actor *received*), and broadcasts to projections.
fully independent (appending to one doesn't touch the other).
`next/tests/inbox_bucket.sh` 14/14. Signature verification +
pipeline gating live in 5b.
- [ ] **5b** — Inbound validation pipeline:
`pipeline:validate_inbound/2(Activity, PeerActorState)` runs
`stage_envelope` → `stage_signature(PeerAS)` → `stage_replay(InboxLog)`.
Sig verification uses the peer's actor-state `:public_keys`, NOT
the local kernel's. Peer-AS resolution is the caller's
responsibility for 5b (5c wires the cache lookup).
- [x] **5b** — Inbound validation pipeline. New
`pipeline:validate_inbound/3(Activity, PeerActorState, InboxLog)`
runs the federation inbound stage list — `stage_envelope` →
`stage_signature(PeerAS)` → `stage_replay(InboxLog)` — halting
on the first failure. New helper `inbound_stages/2(PeerAS, InboxLog)`
exposes the stage list for callers that want to splice extra
stages. Existing `validate_inbound/1` and the static
`inbound_stages/0` (envelope-only) stay untouched so outbox-side
callers don't have to re-key on a peer-AS they don't have. Sig
verification uses the peer's actor-state `:public_keys`, NOT the
local kernel's; peer-AS resolution is the caller's responsibility
(Step 5c wires the cache lookup). 14 cases in
`inbox_pipeline.sh`: happy path, bad shape, missing :signature
(rejected by stage_envelope before sig runs), wrong peer AS
(bad_signature), replay against inbox, distinct activities both
verify, stage short-circuit ordering verified.
- [ ] **5c** — Peer-actors cache projection (`peer_actors.erl`):
on first inbound from a new peer, fetches the peer's actor doc
and caches the public-keys. v2: synchronous fetch via the
@@ -770,6 +780,22 @@ proceed.
Newest first.
- **2026-06-06** — Step 5b: federation inbound pipeline.
`pipeline:validate_inbound/3(Activity, PeerAS, InboxLog)` runs
`stage_envelope` → `stage_signature(PeerAS)` → `stage_replay(InboxLog)`
in order, halting on first failure. New `inbound_stages/2`
helper returns the 3-stage list. M1's `validate_inbound/1` +
static `inbound_stages/0` (envelope-only) preserved for outbox-
side callers. 14/14 in `inbox_pipeline.sh` covering happy path,
bad shape, missing :signature, wrong peer AS, replay against
inbox, distinct activities both verify, stage short-circuit
ordering. Sig verification routes through the peer's AS (not the
local kernel's) — Step 5c will wire the cache lookup. Conformance
761/761. 130/130 across 10 Step-5-adjacent suites
(pipeline_envelope, pipeline_signature, pipeline_replay,
pipeline_driver, inbox_pipeline, inbox_bucket, nx_kernel_multi,
bootstrap_start, http_publish, outbox_publish, smoke_app_pure).
- **2026-06-06** — Step 5a: per-actor :actor_inbox log bucket.
`nx_kernel.erl` `add_actor/4` now opens a fresh log via
`log:open/2` with a distinct `inbox_base_stub()` for each new