Skip to content

Enforce NIP-OA authorization time bounds - #7004

Merged
jmecom merged 2 commits into
mainfrom
jm/enforce-nip-oa-time-bounds
Aug 31, 2026
Merged

jmecom merged 2 commits into
mainfrom
jm/enforce-nip-oa-time-bounds

Conversation

@jmecom

@jmecom jmecom commented Aug 28, 2026

Copy link
Copy Markdown
Collaborator

NIP-OA relay admission now evaluates signed created_at< and created_at> conditions against the already verified authentication event timestamp. An owner-signed credential such as created_at<1 no longer upgrades its holder to relay membership.

The verified timestamp now flows from NIP-42, NIP-98, and Blossom authentication through the shared membership gate used by WebSocket, HTTP, Git, media, huddles, GIF, and workflow requests. Owner-attested access fails closed when no signed authentication timestamp is available. Direct relay members keep their existing admission behavior, and kind= remains connection-level metadata as specified by NIP-AA.

Tests cover strict time-bound evaluation, missing timestamp rejection, and HTTP authentication timestamp propagation.

Testing:

  • cargo test -p buzz-sdk nip_oa::tests -- --nocapture
  • cargo test -p buzz-relay api::relay_members::tests -- --nocapture
  • cargo test -p buzz-relay api::bridge::tests -- --nocapture
  • just ci

Signed-off-by: Jordan Mecom <jm@squareup.com>
@github-actions

github-actions Bot commented Aug 28, 2026

Copy link
Copy Markdown

🔐 Codex Security Review

Status: review required for the current range.

The current range is a3730784fc851bb1125b40cca9b0a30788a293c1...2e6edd6a559f6cf7f7cc8f3c62ec642ad4986328.
A new review must complete for this exact range. When manual authorization
is required, a Block organization member must comment exactly
@buzz-security-review 2e6edd6a559f6cf7f7cc8f3c62ec642ad4986328 to authorize a new review.
Any previous review applies only to its recorded range.

@jmecom

jmecom commented Aug 28, 2026

Copy link
Copy Markdown
Collaborator Author

@buzz-security-review 51ad528

@jmecom
jmecom marked this pull request as ready for review August 28, 2026 20:25
@jmecom
jmecom requested a review from a team as a code owner August 28, 2026 20:25
Signed-off-by: Jordan Mecom <jm@squareup.com>

@wpfleger96 wpfleger96 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 Reviewed at head 2e6edd6 alongside an independent second source review and live E2E verification — all three came back clean.

Both source reviews traced the verified timestamp from NIP-42, NIP-98, Git, and Blossom auth through every enforce_relay_membership() / extract_nip_oa_owner() consumer, and confirmed strict bound semantics, canonical hex enforcement, duplicate x-auth-tag rejection, and the X-Pubkey fail-closed path. Live testing ran this head as a closed relay (BUZZ_REQUIRE_RELAY_MEMBERSHIP=true, BUZZ_ALLOW_NIP_OA_AUTH=true) with 15/15 targeted scenarios passing over real NIP-42 WebSocket and NIP-98 HTTP, including equality-boundary denials, expired credentials, dual auth tags, duplicate headers, and the direct-member regression path.

No findings.

@jmecom
jmecom merged commit e47690c into main Aug 31, 2026
39 checks passed
@jmecom
jmecom deleted the jm/enforce-nip-oa-time-bounds branch August 31, 2026 17:18
wpfleger96 pushed a commit that referenced this pull request Aug 31, 2026
…h-coordinator

* origin/main:
  fix: retrieving cold memories; add regression task (#6950)
  Enforce NIP-OA authorization time bounds (#7004)
  feat(db): configurable writer session timeouts (lock, idle-txn, statement) (#6229)
  feat(desktop): use segmented controls for channel creation (#6845)
  feat(buzz-agent): surface stop reason and silent-turn WARN in telemetry (#7038)

Signed-off-by: Duncan <dcfd242e557282d7a1e2cf2e6877522682f1e5c6156dc92ca7d90eaedd3b0f95@buzz.block.builderlab.xyz>
wpfleger96 added a commit that referenced this pull request Aug 31, 2026
…h-coordinator

* origin/main:
  fix: retrieving cold memories; add regression task (#6950)
  Enforce NIP-OA authorization time bounds (#7004)
  feat(db): configurable writer session timeouts (lock, idle-txn, statement) (#6229)
  feat(desktop): use segmented controls for channel creation (#6845)
  feat(buzz-agent): surface stop reason and silent-turn WARN in telemetry (#7038)

Signed-off-by: Duncan <dcfd242e557282d7a1e2cf2e6877522682f1e5c6156dc92ca7d90eaedd3b0f95@buzz.block.builderlab.xyz>
Co-authored-by: Will Pfleger <pfleger.will@gmail.com>
Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
wpfleger96 added a commit that referenced this pull request Aug 31, 2026
…h-coordinator

* origin/main:
  fix: retrieving cold memories; add regression task (#6950)
  Enforce NIP-OA authorization time bounds (#7004)
  feat(db): configurable writer session timeouts (lock, idle-txn, statement) (#6229)
  feat(desktop): use segmented controls for channel creation (#6845)
  feat(buzz-agent): surface stop reason and silent-turn WARN in telemetry (#7038)

Signed-off-by: Duncan <dcfd242e557282d7a1e2cf2e6877522682f1e5c6156dc92ca7d90eaedd3b0f95@buzz.block.builderlab.xyz>
Co-authored-by: Will Pfleger <pfleger.will@gmail.com>
Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
wpfleger96 pushed a commit that referenced this pull request Aug 31, 2026
…on-runtime

* origin/main:
  fix: retrieving cold memories; add regression task (#6950)
  Enforce NIP-OA authorization time bounds (#7004)
  feat(db): configurable writer session timeouts (lock, idle-txn, statement) (#6229)
  feat(desktop): use segmented controls for channel creation (#6845)
  feat(buzz-agent): surface stop reason and silent-turn WARN in telemetry (#7038)
  fix(desktop): surface channel history load failures (#7013)
  fix(composer): polish automatic mentions (#6956)

Signed-off-by: Duncan <dcfd242e557282d7a1e2cf2e6877522682f1e5c6156dc92ca7d90eaedd3b0f95@buzz.block.builderlab.xyz>
wpfleger96 pushed a commit that referenced this pull request Aug 31, 2026
* origin/main:
  feat: render agent avatars as squircles (#7106)
  fix(ci): salvage Codex review output on PTY-shutdown hang (#7042)
  fix: retrieving cold memories; add regression task (#6950)
  Enforce NIP-OA authorization time bounds (#7004)
  feat(db): configurable writer session timeouts (lock, idle-txn, statement) (#6229)
  feat(desktop): use segmented controls for channel creation (#6845)
  feat(buzz-agent): surface stop reason and silent-turn WARN in telemetry (#7038)
  fix(desktop): surface channel history load failures (#7013)
  fix(composer): polish automatic mentions (#6956)

Signed-off-by: Hayt <9e1c23a3fd83f61da34420e4e88ff1b16e45cafcc0cd9019eb07d4ecfa8ca9b0@buzz.block.builderlab.xyz>
jrobotham-square added a commit that referenced this pull request Aug 31, 2026
…age-rw

* origin/main:
  feat: render agent avatars as squircles (#7106)
  fix(ci): salvage Codex review output on PTY-shutdown hang (#7042)
  fix: retrieving cold memories; add regression task (#6950)
  Enforce NIP-OA authorization time bounds (#7004)
  feat(db): configurable writer session timeouts (lock, idle-txn, statement) (#6229)
  feat(desktop): use segmented controls for channel creation (#6845)
  feat(buzz-agent): surface stop reason and silent-turn WARN in telemetry (#7038)
  fix(desktop): surface channel history load failures (#7013)
  fix(composer): polish automatic mentions (#6956)

Signed-off-by: Joel Robotham <jrobotham@squareup.com>
wpfleger96 pushed a commit that referenced this pull request Aug 31, 2026
…-history

* origin/main:
  feat: render agent avatars as squircles (#7106)
  fix(ci): salvage Codex review output on PTY-shutdown hang (#7042)
  fix: retrieving cold memories; add regression task (#6950)
  Enforce NIP-OA authorization time bounds (#7004)
  feat(db): configurable writer session timeouts (lock, idle-txn, statement) (#6229)
  feat(desktop): use segmented controls for channel creation (#6845)
  feat(buzz-agent): surface stop reason and silent-turn WARN in telemetry (#7038)

Signed-off-by: Duncan <dcfd242e557282d7a1e2cf2e6877522682f1e5c6156dc92ca7d90eaedd3b0f95@buzz.block.builderlab.xyz>
rileycrane pushed a commit that referenced this pull request Aug 31, 2026
* origin/main: (32 commits)
  fix(acp): wake agents from workflow messages (#6953)
  feat: render agent avatars as squircles (#7106)
  fix(ci): salvage Codex review output on PTY-shutdown hang (#7042)
  fix: retrieving cold memories; add regression task (#6950)
  Enforce NIP-OA authorization time bounds (#7004)
  feat(db): configurable writer session timeouts (lock, idle-txn, statement) (#6229)
  feat(desktop): use segmented controls for channel creation (#6845)
  feat(buzz-agent): surface stop reason and silent-turn WARN in telemetry (#7038)
  fix(desktop): surface channel history load failures (#7013)
  fix(composer): polish automatic mentions (#6956)
  fix(desktop): resolve bundled sidecar on cheap path and bound login-shell spawns (#6904)
  perf(mobile): reduce cold startup and channel rendering delays (#6996)
  feat(mobile): push notifications MVP (#6269)
  refactor(db): extract domain stores from database runtime (#6987)
  feat(desktop): add team sharing to community catalog (#3995)
  Refresh mobile utility surfaces and theme picker (#6944)
  fix(desktop): complete project empty and context states (#6980)
  Fix mobile jump-to-latest flicker (#6807)
  refactor(relay): NIP-98 admin auth with Operator/Moderator roles and NIP-11 discovery (#3777)
  refactor(db): split channel membership store (#6782)
  ...

Signed-off-by: Carl <1f967df5817845a2a5d74c82ac3098dea0bb7342665352af6643c5ac5c878dd3@buzz.block.builderlab.xyz>

# Conflicts:
#	desktop/src/features/channels/ui/ChannelPane.tsx
wpfleger96 pushed a commit that referenced this pull request Aug 31, 2026
…n-surface

* origin/main:
  fix(desktop): back split thread headers (#7137)
  add public descriptions to agent personas (#7126)
  feat(desktop): add protected-build Bestie experiment (#6902)
  fix(relay): reject a frame on its own acknowledgement channel (#6961)
  fix(acp): wake agents from workflow messages (#6953)
  feat: render agent avatars as squircles (#7106)
  fix(ci): salvage Codex review output on PTY-shutdown hang (#7042)
  fix: retrieving cold memories; add regression task (#6950)
  Enforce NIP-OA authorization time bounds (#7004)
  feat(db): configurable writer session timeouts (lock, idle-txn, statement) (#6229)
  feat(desktop): use segmented controls for channel creation (#6845)
  feat(buzz-agent): surface stop reason and silent-turn WARN in telemetry (#7038)
  fix(desktop): surface channel history load failures (#7013)
  fix(composer): polish automatic mentions (#6956)
  fix(desktop): resolve bundled sidecar on cheap path and bound login-shell spawns (#6904)
  perf(mobile): reduce cold startup and channel rendering delays (#6996)
  feat(mobile): push notifications MVP (#6269)

Signed-off-by: Duncan <dcfd242e557282d7a1e2cf2e6877522682f1e5c6156dc92ca7d90eaedd3b0f95@buzz.block.builderlab.xyz>
wpfleger96 pushed a commit that referenced this pull request Aug 31, 2026
…enericize

* origin/main:
  fix(desktop): back split thread headers (#7137)
  add public descriptions to agent personas (#7126)
  feat(desktop): add protected-build Bestie experiment (#6902)
  fix(relay): reject a frame on its own acknowledgement channel (#6961)
  fix(acp): wake agents from workflow messages (#6953)
  feat: render agent avatars as squircles (#7106)
  fix(ci): salvage Codex review output on PTY-shutdown hang (#7042)
  fix: retrieving cold memories; add regression task (#6950)
  Enforce NIP-OA authorization time bounds (#7004)
  feat(db): configurable writer session timeouts (lock, idle-txn, statement) (#6229)
  feat(desktop): use segmented controls for channel creation (#6845)
  feat(buzz-agent): surface stop reason and silent-turn WARN in telemetry (#7038)
  fix(desktop): surface channel history load failures (#7013)
  fix(composer): polish automatic mentions (#6956)

Signed-off-by: Duncan <dcfd242e557282d7a1e2cf2e6877522682f1e5c6156dc92ca7d90eaedd3b0f95@buzz.block.builderlab.xyz>
wpfleger96 pushed a commit that referenced this pull request Aug 31, 2026
…n-surface

* origin/main:
  docs: add review-proven failure-path & async-state rules to AGENTS.md (#7061)
  fix(desktop): back split thread headers (#7137)
  add public descriptions to agent personas (#7126)
  feat(desktop): add protected-build Bestie experiment (#6902)
  fix(relay): reject a frame on its own acknowledgement channel (#6961)
  fix(acp): wake agents from workflow messages (#6953)
  feat: render agent avatars as squircles (#7106)
  fix(ci): salvage Codex review output on PTY-shutdown hang (#7042)
  fix: retrieving cold memories; add regression task (#6950)
  Enforce NIP-OA authorization time bounds (#7004)
  feat(db): configurable writer session timeouts (lock, idle-txn, statement) (#6229)
  feat(desktop): use segmented controls for channel creation (#6845)
  feat(buzz-agent): surface stop reason and silent-turn WARN in telemetry (#7038)
  fix(desktop): surface channel history load failures (#7013)
  fix(composer): polish automatic mentions (#6956)
  fix(desktop): resolve bundled sidecar on cheap path and bound login-shell spawns (#6904)
  perf(mobile): reduce cold startup and channel rendering delays (#6996)
  feat(mobile): push notifications MVP (#6269)

Signed-off-by: Duncan <dcfd242e557282d7a1e2cf2e6877522682f1e5c6156dc92ca7d90eaedd3b0f95@buzz.block.builderlab.xyz>
wpfleger96 pushed a commit that referenced this pull request Sep 1, 2026
* origin/main:
  feat(desktop): add thread-scoped ACP session experiment (#6909)
  fix(desktop): scope composer autocomplete to focus (#6860)
  feat(desktop): add isolated named demo builds (#6407)
  fix(model-capabilities): humanize databricks goose model names (#7135)
  feat(db): add NIP-FI identity and final-admission schema foundation (#6994)
  feat(buzz-acp): give each channel thread its own agent session (#6732)
  docs: add review-proven failure-path & async-state rules to AGENTS.md (#7061)
  fix(desktop): back split thread headers (#7137)
  add public descriptions to agent personas (#7126)
  feat(desktop): add protected-build Bestie experiment (#6902)
  fix(relay): reject a frame on its own acknowledgement channel (#6961)
  fix(acp): wake agents from workflow messages (#6953)
  feat: render agent avatars as squircles (#7106)
  fix(ci): salvage Codex review output on PTY-shutdown hang (#7042)
  fix: retrieving cold memories; add regression task (#6950)
  Enforce NIP-OA authorization time bounds (#7004)
  feat(db): configurable writer session timeouts (lock, idle-txn, statement) (#6229)
  feat(desktop): use segmented controls for channel creation (#6845)
  feat(buzz-agent): surface stop reason and silent-turn WARN in telemetry (#7038)

Co-authored-by: Will Pfleger <pfleger.will@gmail.com>
Signed-off-by: Will Pfleger <pfleger.will@gmail.com>

# Conflicts:
#	crates/buzz-acp/src/config.rs
#	crates/buzz-acp/src/pool.rs
#	crates/buzz-acp/src/relay.rs
#	desktop/src-tauri/src/commands/agent_config_tests.rs
#	desktop/src-tauri/src/commands/agent_models_tests.rs
#	desktop/src-tauri/src/commands/agents_deploy.rs
#	desktop/src-tauri/src/commands/agents_tests.rs
#	desktop/src-tauri/src/commands/personas/delete_cascade_tests.rs
#	desktop/src-tauri/src/commands/personas/inbound/inbound_tests.rs
#	desktop/src-tauri/src/commands/personas/pending.rs
#	desktop/src-tauri/src/commands/personas/sharing.rs
#	desktop/src-tauri/src/commands/personas/snapshot/fidelity_tests.rs
#	desktop/src-tauri/src/commands/personas/snapshot/tests.rs
#	desktop/src-tauri/src/commands/personas/update/name_propagation_tests.rs
#	desktop/src-tauri/src/commands/team_snapshot/tests.rs
#	desktop/src-tauri/src/managed_agents/agent_events.rs
#	desktop/src-tauri/src/managed_agents/agent_snapshot_envelope.rs
#	desktop/src-tauri/src/managed_agents/agent_snapshot_tests.rs
#	desktop/src-tauri/src/managed_agents/config_bridge/reader_tests.rs
#	desktop/src-tauri/src/managed_agents/discovery/tests.rs
#	desktop/src-tauri/src/managed_agents/effective_config/tests.rs
#	desktop/src-tauri/src/managed_agents/global_config/tests.rs
#	desktop/src-tauri/src/managed_agents/parallelism.rs
#	desktop/src-tauri/src/managed_agents/persona_events/tests.rs
#	desktop/src-tauri/src/managed_agents/personas/tests.rs
#	desktop/src-tauri/src/managed_agents/readiness.rs
#	desktop/src-tauri/src/managed_agents/runtime/test_fixtures.rs
#	desktop/src-tauri/src/managed_agents/runtime/tests.rs
#	desktop/src-tauri/src/managed_agents/spawn_snapshot/tests.rs
#	desktop/src-tauri/src/managed_agents/team_snapshot.rs
#	desktop/src-tauri/src/managed_agents/teams_tests.rs
#	desktop/src-tauri/src/managed_agents/types/requests.rs
#	desktop/src-tauri/src/managed_agents/types/tests.rs
#	desktop/src-tauri/src/migration_avatar_tests.rs
#	desktop/src/features/agents/AGENTS.md
#	desktop/src/shared/api/types.ts
storme-square pushed a commit that referenced this pull request Sep 1, 2026
…bound-membership

* origin/main: (32 commits)
  fix(model-capabilities): humanize databricks goose model names (#7135)
  feat(db): add NIP-FI identity and final-admission schema foundation (#6994)
  feat(buzz-acp): give each channel thread its own agent session (#6732)
  docs: add review-proven failure-path & async-state rules to AGENTS.md (#7061)
  fix(desktop): back split thread headers (#7137)
  add public descriptions to agent personas (#7126)
  feat(desktop): add protected-build Bestie experiment (#6902)
  fix(relay): reject a frame on its own acknowledgement channel (#6961)
  fix(acp): wake agents from workflow messages (#6953)
  feat: render agent avatars as squircles (#7106)
  fix(ci): salvage Codex review output on PTY-shutdown hang (#7042)
  fix: retrieving cold memories; add regression task (#6950)
  Enforce NIP-OA authorization time bounds (#7004)
  feat(db): configurable writer session timeouts (lock, idle-txn, statement) (#6229)
  feat(desktop): use segmented controls for channel creation (#6845)
  feat(buzz-agent): surface stop reason and silent-turn WARN in telemetry (#7038)
  fix(desktop): surface channel history load failures (#7013)
  fix(composer): polish automatic mentions (#6956)
  fix(desktop): resolve bundled sidecar on cheap path and bound login-shell spawns (#6904)
  perf(mobile): reduce cold startup and channel rendering delays (#6996)
  ...

Signed-off-by: Storme Drone <49c46e84758b2ebff4abf5abbbd44ee4ce788fc3b55db9fa703eec124eead621@buzz.block.builderlab.xyz>

# Conflicts:
#	desktop/src/testing/e2eBridge.ts
wpfleger96 pushed a commit that referenced this pull request Sep 1, 2026
…c-agent-commit-identity

* origin/main:
  Add voice notes to desktop messages (#6978)
  feat(desktop): add thread-scoped ACP session experiment (#6909)
  fix(desktop): scope composer autocomplete to focus (#6860)
  feat(desktop): add isolated named demo builds (#6407)
  fix(model-capabilities): humanize databricks goose model names (#7135)
  feat(db): add NIP-FI identity and final-admission schema foundation (#6994)
  feat(buzz-acp): give each channel thread its own agent session (#6732)
  docs: add review-proven failure-path & async-state rules to AGENTS.md (#7061)
  fix(desktop): back split thread headers (#7137)
  add public descriptions to agent personas (#7126)
  feat(desktop): add protected-build Bestie experiment (#6902)
  fix(relay): reject a frame on its own acknowledgement channel (#6961)
  fix(acp): wake agents from workflow messages (#6953)
  feat: render agent avatars as squircles (#7106)
  fix(ci): salvage Codex review output on PTY-shutdown hang (#7042)
  fix: retrieving cold memories; add regression task (#6950)
  Enforce NIP-OA authorization time bounds (#7004)
  feat(db): configurable writer session timeouts (lock, idle-txn, statement) (#6229)
  feat(desktop): use segmented controls for channel creation (#6845)
  feat(buzz-agent): surface stop reason and silent-turn WARN in telemetry (#7038)

Signed-off-by: Duncan <dcfd242e557282d7a1e2cf2e6877522682f1e5c6156dc92ca7d90eaedd3b0f95@buzz.block.builderlab.xyz>
rmichelena added a commit to rmichelena/buzz that referenced this pull request Sep 13, 2026
On a closed relay an agent that is itself a relay member never gets its
NIP-OA owner recorded, however many valid attestations it presents.
`enforce_relay_membership` returns `Ok(None)` as soon as direct membership
is established, and the only owner-extraction fallback at either call site
was gated on `!require_relay_membership` — off precisely where it is needed.

With `agent_owner_pubkey` left NULL the relay cannot tell the agent from a
human: `owner_only` policies have nothing to match, observer frames are
refused, and the connection is rate-classed as human. Closes block#4223, block#4937.

`relay_members::resolve_nip_oa_owner` settles the question once for both
call sites. Admission by delegation keeps the owner it already proved is a
member; an open relay keeps today's behaviour; a direct member on a closed
relay has its attestation resolved, with the owner required to be a relay
member.

That membership requirement is load-bearing. `materialize_nip_oa_owner` is
first-write-wins and the recorded owner selects the agent rate class, so
without it any member could attest itself with a throwaway key, raise its
own rate budget, and bind the mapping permanently against the real owner.

`allow_nip_oa_auth` deliberately does not gate this: per its own doc
comment the flag governs whether NIP-OA may *grant membership* on a closed
relay, and nothing here grants access — the caller is already in.

Time bounds now come from block#7004 (`verify_auth_tag_for_auth_event` and the
`signed_created_at` carried on `VerifiedBridgeAuth`), so this branch builds
on those primitives rather than duplicating them.

Nine tests exercise both production paths against real PostgreSQL and
Redis: `submit_event_authed` and the full `POST /events` router, plus
`handle_auth` on the WebSocket side. They live in `postgres_tests` modules
so the structural PostgreSQL discovery lane picks them up, which is why
this branch no longer patches `ci.yml`.

Co-authored-by: Ravneet Arora <rarora@squareup.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Roberto Michelena <77797875+rmichelena@users.noreply.github.com>
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