docs(nip-fi): rewrite NIP-FI as stateless OSS Buzz spec v2 - #7214
Merged
Conversation
Remove the relay-side authority engine (bindings, receipts, lifecycle, invalidation, leases, delegation, enrollment modes) entirely. The new spec settles exactly five things: assertion contract (JWT claims, npub binding, NIP-42 pairing), offline JWKS verification (multi-issuer, fail-closed), session policy (required finite max-lifetime knob, no in-band renewal), admin disconnect API (session-only model with an explicit non-normative note documenting the deny-until-TTL alternative for Will/Tyler to adjudicate), and the deletions surface. The PR 3 / 70895b3 multi-issuer JWKS runtime (FederatedAssertionVerifier, ProductionJwksSource, IssuerRegistry, DenialClass) is the complete implementation surface for the new spec. No Rust code changes. Companion docs (NIP-FI-CONF, DELEG, EDGE, LIFECYCLE, MODEL) and migrations 0041/0042 are flagged for deletion in separate work. Co-authored-by: Will Pfleger <pfleger.will@gmail.com> Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
wpfleger96
had a problem deploying
to
codex-review
September 1, 2026 22:19 — with
GitHub Actions
Error
NIP-FI-CONF, NIP-FI-DELEG, NIP-FI-EDGE, NIP-FI-LIFECYCLE, and NIP-FI-MODEL all presuppose relay-side binding/lifecycle state that the v2 stateless spec removes. A deferred doc that assumes removed state is worse than absence. Edge transport and delegation can be re-proposed as separate profiles if they become relevant under the stateless design. Co-authored-by: Will Pfleger <pfleger.will@gmail.com> Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
wpfleger96
had a problem deploying
to
codex-review
September 1, 2026 22:20 — with
GitHub Actions
Error
CRITICAL: replace unsigned disconnect body with signed command JWT. The disconnect endpoint now requires a command JWT verified against the same per-issuer JWKS surface as client assertions. The JWT carries iss, sub, aud, iat, exp, jti (replay guard), cmd='disconnect', and target_pubkey. The relay verifies the signature, asserts cmd and target_pubkey match the request body, checks jti replay, and confirms the caller is an authorized adapter principal — all fail-closed. IMPORTANT (time bounds): separate required JWT claims (iat, exp) from policy knobs (maximum_assertion_age required positive finite; skew non-negative finite with default 0; nbf optional). IMPORTANT (key binding honesty): document that require_attested_key in IssuerPolicy is the enforcement primitive and that NIP-FI v2 conformance requires startup validation forcing it true — a follow-on code change. Remove the 'complete implementation surface' claim from the spec text. IMPORTANT (at+jwt subject contract): restore closed v1 rule — issuer policy names one authenticated marker claim and two non-empty disjoint value sets; absent/unknown/ambiguous classification denies; client-subject acceptance requires recorded non-collision posture. IMPORTANT (residual-window formula): distinguish upstream-revocation (no disconnect call) from session-only disconnect. Upstream revocation: max(existing session remaining lifetime, assertion TTL). Disconnect: two sequential sub-windows — live session bounded by max_connection_lifetime_seconds, then reconnect bounded by min(remaining assertion TTL, max_connection_lifetime_seconds). Both places in the doc now use the same scenario-specific formula. MINOR: fix broken relative link ../crates -> ../../crates/buzz-auth/... MINOR: 'enrolled Nostr key' -> 'assertion-named Nostr key' Co-authored-by: Will Pfleger <pfleger.will@gmail.com> Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
wpfleger96
had a problem deploying
to
codex-review
September 1, 2026 22:29 — with
GitHub Actions
Error
CRITICAL: replace VerifyAssertion with dedicated VerifyCommandJwt for the disconnect command. The command JWT carries 'typ: nip-fi-command+jwt' (domain-separated from assertion types); signed 'method' and 'path' claims bind it to exactly POST /api/nip-fi/disconnect; a dedicated 'maximum_command_age' policy knob governs TTL; and jti replay prevention uses an atomic (iss, jti) reservation held until the command's effective expiry. The procedure reuses IssuerRegistry, JWKS, signature, audience, and time-bound primitives but produces a closed CommandResult — not a VerifiedAssertion. VerifyAssertion is not called. IMPORTANT (disconnect window): single correct formula in both the non-normative note and Security considerations. After a successful disconnect, old-session remainder is zero; the only residual is a reconnect bounded by min(remaining assertion authority, max_connection_lifetime_seconds, remaining key-snapshot hard deadline). Contradictory two-part sequential formulation removed. IMPORTANT (aud optionality): 'aud' promoted to unconditional required claim in the required-claims table, matching the existing verifier contract (IssuerPolicy requires non-empty audience; VerifyAssertion always validates it). MINOR: NIP-FI-MODEL added to the removed companion profiles list. Co-authored-by: Will Pfleger <pfleger.will@gmail.com> Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
wpfleger96
had a problem deploying
to
codex-review
September 1, 2026 22:35 — with
GitHub Actions
Error
IMPORTANT (reconnect window): distinguish individual-session bound from cumulative residual access. After a successful synchronous disconnect, cumulative access (assuming issuance stops) is bounded by max(0, min(exp, iat+max_assertion_age, key_snapshot_deadline) - now). max_connection_lifetime_seconds only partitions that interval into sessions; it does not shorten the total window. State explicitly that continued issuance after disconnect extends access without a protocol-level bound. Same formula used in both the non-normative note and Security considerations. IMPORTANT (jti admission ordering): reorder VerifyCommandJwt steps so AtomicReserveJti is the final admission step immediately before side effects — after signature/claim validation, principal authorization, and signed-target/body agreement. A failed-authorization or mismatched-body request no longer burns the signed command identity. Procedure now accepts request_body_pubkey as a parameter; body agreement is a pure check inside the procedure. Make maximum_command_age upper bound normative: 0 < maximum_command_age <= 60 seconds. MINOR: narrow Request prose to reference VerifyCommandJwt directly rather than re-describing steps now inside the procedure. Co-authored-by: Will Pfleger <pfleger.will@gmail.com> Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
wpfleger96
had a problem deploying
to
codex-review
September 1, 2026 22:40 — with
GitHub Actions
Error
…tions The 'no reconnect can succeed' claim was framed as a consequence of max_connection_lifetime_seconds, which does not govern reconnect availability. Restate accurately: after the live session closes naturally, reconnect requires a fresh assertion; if the adapter has stopped issuing, none can be obtained; if the adapter continues issuing, access continues. Removes the last session-bound confation from the revocation analysis. Co-authored-by: Will Pfleger <pfleger.will@gmail.com> Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
🔐 Codex Security Review
|
…not fixed The key_snapshot_hard_deadline is computed as now + configured seconds on every JWKS refresh (jwks/mod.rs), so it renews even on unchanged content and does not cap cumulative access across serial reconnects. Remove it from both residual-window formulas; the correct cumulative bound (assuming issuance stops at disconnect) is: max(0, min(exp, iat + maximum_assertion_age) - now) Add a note that snapshot failure, hard-deadline expiry, or key removal can terminate access earlier but are not reliable protocol-level bounds. Also fix the upstream-revocation paragraph: a still-valid compact JWS can reconnect without new issuance, so 'requires a fresh assertion' was wrong. Corrected to 'requires an assertion that remains valid when reverified'. Co-authored-by: Will Pfleger <pfleger.will@gmail.com> Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
Replace all 'adapter' references with 'assertion issuer' / 'issuer' throughout. The spec's trust anchor is the configured issuer registry; the entity that authenticates users and mints assertions is the assertion issuer, which is the term now used everywhere. - 'adapter' Terms entry replaced with 'assertion issuer' definition - Okta example removed; 'an OIDC identity provider integration' used instead - 'employees' -> 'users'; 'employee number' -> 'opaque user ID' - 'SCIM, HR system integration, employee offboarding automation' -> 'directory integration and account-offboarding automation' - AssertAuthorizedAdapterPrincipal -> AssertAuthorizedIssuerPrincipal - 'adapter->relay disconnect API' -> 'issuer->relay disconnect API' - 'adapter-initiated disconnect' -> 'issuer-initiated disconnect' - 'adapter principal' -> 'issuer principal' in claim table and prose - All remaining adapter/adapter-side/adapter's prose occurrences renamed - PR body updated: 'adapter concern' -> 'issuer and deployment concern'; residual-window formula corrected to drop key_snapshot_hard_deadline No normative semantic changes. Co-authored-by: Will Pfleger <pfleger.will@gmail.com> Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
wpfleger96
had a problem deploying
to
codex-review
September 1, 2026 23:00 — with
GitHub Actions
Error
…e heading IMPORTANT: the upstream-revocation paragraph incorrectly stated that stopping issuance means 'no valid assertion can be obtained and no reconnect can succeed.' Previously issued assertions that have not yet expired remain valid for reconnection until min(exp, iat + maximum_assertion_age). Stopping issuance prevents minting new assertions that extend the window; it does not invalidate already-issued ones. Replaced the false conclusion with the two correct cases. MINOR: genericize non-normative note heading from 'open product question for Will/Tyler' to 'open product question (session-only vs deny-until-TTL)'. PR body: remove Slack/parent-channel and Will/Tyler process framing. Co-authored-by: Will Pfleger <pfleger.will@gmail.com> Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
wpfleger96
had a problem deploying
to
codex-review
September 1, 2026 23:03 — with
GitHub Actions
Error
johnmatthewtennant
added a commit
that referenced
this pull request
Sep 2, 2026
…e-read-model * origin/main: fix(desktop): retain automatic mentions only in threads (#7144) feat: add databricks fable 5.1 model capabilities (#7213) docs(nip-fi): rewrite NIP-FI as stateless OSS Buzz spec v2 (#7214) feat(relay): add detailed readiness metrics (#7149) feat(desktop): add Pi agent preset (#7208) Signed-off-by: John Tennant <jtennant@squareup.com>
johnmatthewtennant
added a commit
that referenced
this pull request
Sep 2, 2026
…l' into jtennant/project-state-mutations * origin/jtennant/project-state-read-model: Fix historical migration catalog tests fix(desktop): retain automatic mentions only in threads (#7144) feat: add databricks fable 5.1 model capabilities (#7213) docs(nip-fi): rewrite NIP-FI as stateless OSS Buzz spec v2 (#7214) feat(relay): add detailed readiness metrics (#7149) feat(desktop): add Pi agent preset (#7208) Signed-off-by: John Tennant <jtennant@squareup.com>
johnmatthewtennant
added a commit
that referenced
this pull request
Sep 2, 2026
…' into jtennant/project-related-channels-desktop * origin/jtennant/project-state-mutations: Fix Project channel preservation test Fix historical migration catalog tests fix(desktop): retain automatic mentions only in threads (#7144) feat: add databricks fable 5.1 model capabilities (#7213) docs(nip-fi): rewrite NIP-FI as stateless OSS Buzz spec v2 (#7214) feat(relay): add detailed readiness metrics (#7149) feat(desktop): add Pi agent preset (#7208) Signed-off-by: John Tennant <jtennant@squareup.com>
wpfleger96
pushed a commit
that referenced
this pull request
Sep 2, 2026
…-history * origin/main: fix(acp): replace real user name in base prompt mention example (#7250) ci: split CI into reusable workflows (#7168) fix(desktop): retain automatic mentions only in threads (#7144) feat: add databricks fable 5.1 model capabilities (#7213) docs(nip-fi): rewrite NIP-FI as stateless OSS Buzz spec v2 (#7214) feat(relay): add detailed readiness metrics (#7149) feat(desktop): add Pi agent preset (#7208) feat(buzz-agent): add DatabricksAuthCoordinator single-flight OAuth (#5545) fix(desktop): preserve keyring identity during recovery (#7203) feat(mobile): prepare `buzz-push-gateway` for deployment (#7158) ci: relax file-size ceilings by surface (#6485) fix(mobile): isolate extension linker flags; complete iOS build in CI (#7187) chore(ci): lower Codex security review effort (#7179) fix(dev-mcp): extend shell timeout cap to 20 minutes and align outer budgets (#7185) fix(dev): keep the canonical profile when launching from desktop/ (#7143) Signed-off-by: Duncan <dcfd242e557282d7a1e2cf2e6877522682f1e5c6156dc92ca7d90eaedd3b0f95@buzz.block.builderlab.xyz>
wpfleger96
added a commit
that referenced
this pull request
Sep 2, 2026
Removes the dead relay-side authority ledger introduced by migrations 0041 and 0042, and the dead `require_attested_key` verifier knob from `buzz-auth`. Both are unreachable by design under NIP-FI spec v2 (#7214, squash `d4420eb47`), which makes OSS Buzz stateless for identity: the relay neither stores nor verifies an authority chain. ## What changes **`migrations/0044_drop_nip_fi_ledger.sql`** Drops all fifteen NIP-FI ledger tables and their trigger functions using `CASCADE` to resolve the circular deferred FK between `identity_bindings` and `identity_lifecycle_history`. Drops proceed in FK dependency order: selectors → history/bindings → enrollment_policies/receipts → parallel drop of auth tables. Restores `community_write_fence_excluded_table` to its pre-0041 body (removes NIP-FI table names from the exclusion array). **`schema/schema.sql`** Removes the NIP-FI section (~1885 lines of tables, functions, and triggers) and updates `community_write_fence_excluded_table` to match. **`crates/buzz-db/src/runtime/migration.rs`** - Updates the `embedded_migrator_contains_consolidated_initial_schema` sanity check: count 43→44, adds 0044 assertion block (verifies `DROP TABLE` statements and absence of NIP-FI names from `schema.sql`). - Removes ~2580 lines of NIP-FI Postgres integration tests (all `#[tokio::test] #[ignore = "requires Postgres"]` from the 0041/0042 behavioral coverage). - Removes the `extract_excluded_table_array` drift check (0042 body no longer matches `schema.sql` by design). - Adds `migration_0044_drops_populated_nip_fi_ledger_cleanly`: runs migrations to 0042, seeds rows in `authorization_operation_receipts` and `authorization_invalidation_domains`, then runs to 0044 and verifies all fifteen NIP-FI tables are absent. **`crates/buzz-auth/src/nip_fi/config.rs`** Removes `require_attested_key: bool` from `IssuerPolicy` — field, constructor parameter, accessor, and its contribution to `derive_assertion_policy_id`. **`crates/buzz-auth/src/nip_fi/verifier.rs`** `parse_nostr_pubkey_claim` no longer takes a `policy` parameter. The `None` (absent claim) arm now returns `Err(VerifierError::ClaimRejected)` unconditionally instead of conditionally on `policy.require_attested_key()`. **`crates/buzz-auth/src/nip_fi/verifier/tests.rs`** - Removes `missing_nostr_pubkey_denies_under_attested_key_policy` (the sole `require_attested_key: true` call site). - Removes `false,` from all eleven `IssuerPolicy::new` call sites. - Injects `nostr_pubkey` by default in `mint_signed_by` (spec v2 requires it unconditionally). - Updates `valid_access_token_verifies` to assert `asserted_key().is_some()`. **`crates/buzz-auth/src/nip_fi/startup/tests.rs` + `jwks/tests.rs`** Removes `false,` from all `IssuerPolicy::new` call sites and adds `nostr_pubkey` to all token-minting helpers. ## Verification - Fresh-DB migration run to head: all migrations apply cleanly in sequence. - Populated-0041/0042-DB migration through 0044: seeds rows in live NIP-FI tables, verifies all fifteen are dropped without error. Closes the dead-code inventory item from the spec-v2 cleanup plan (channel `48374f48`). Follows #7214. --------- Signed-off-by: Will Pfleger <pfleger.will@gmail.com> Signed-off-by: Duncan <dcfd242e557282d7a1e2cf2e6877522682f1e5c6156dc92ca7d90eaedd3b0f95@buzz.block.builderlab.xyz> Co-authored-by: Duncan <dcfd242e557282d7a1e2cf2e6877522682f1e5c6156dc92ca7d90eaedd3b0f95@buzz.block.builderlab.xyz>
wpfleger96
added a commit
that referenced
this pull request
Sep 2, 2026
The OSS artifact must not reference deployment-specific concepts. Replace the three remaining 'adapter' occurrences with 'issuer' to match the genericization applied in #7214. 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
Sep 2, 2026
* origin/main: feat(agents): harness-agnostic effort write path and spawn bridge (#4625) chore(db): drop Phase-A NIP-FI relay-side authority ledger (#7221) fix(acp): replace real user name in base prompt mention example (#7250) ci: split CI into reusable workflows (#7168) fix(desktop): retain automatic mentions only in threads (#7144) feat: add databricks fable 5.1 model capabilities (#7213) docs(nip-fi): rewrite NIP-FI as stateless OSS Buzz spec v2 (#7214) feat(relay): add detailed readiness metrics (#7149) feat(desktop): add Pi agent preset (#7208) Signed-off-by: Duncan <dcfd242e557282d7a1e2cf2e6877522682f1e5c6156dc92ca7d90eaedd3b0f95@buzz.block.builderlab.xyz> # Conflicts: # desktop/src-tauri/src/commands/agent_models_update.rs # desktop/src-tauri/src/commands/agents_deploy.rs # desktop/src-tauri/src/managed_agents/types/requests.rs # desktop/src/features/agents/ui/AgentInstanceEditDialog.tsx # desktop/src/shared/api/types.ts
wpfleger96
added a commit
that referenced
this pull request
Sep 2, 2026
…ress (#7254) Spec revision following two decisions: Option B admin deny (2026-09-02) and the HTTP ingress ruling (2026-09-02). Revises `docs/nips/NIP-FI.md` only. Follows #7214 (merged spec v2). ## What changed ### Admin disconnect: session-only → deny-until-TTL The disconnect operation proceeds in two steps, in order: 1. Insert a memory-resident deny entry keyed by `(iss, target_pubkey)` with absolute expiry `until` — atomically combined with the `(iss, jti)` replay-identity reservation as one all-or-nothing mutation. If the deny set is at capacity (per-issuer bound), the relay rejects `503`; neither the jti nor the deny entry is recorded, and the caller may safely retry the same signed command. 2. Close all live WebSocket connections for the target pubkey, synchronously. The single atomic admission mutation (jti reservation + deny-entry insertion) lives inside `VerifyCommandJwt` step 7, after all pure authorization checks. The endpoint only closes sessions on success. This ordering ensures a capacity failure leaves no state behind and makes the retry-safe 503 contract implementable. The deny set is RAM-cache only — no durable storage, no schema changes. The same operational posture as the JWKS snapshot. A relay restart MAY forget active entries; the issuer SHOULD re-push still-active deny entries on observed restart (same publish/cache pattern as JWKS). If the issuer stops issuing assertions and re-push completes before any expired-entry reconnection attempt, residual exposure after restart is bounded by `max(0, min(exp, iat + maximum_assertion_age) - now)`. If the issuer continues issuing or re-push does not complete in time, that formula does not apply and access may continue beyond it. **`until` claim:** Required on the disconnect command JWT. Because an assertion accepted at the future-skew boundary (`iat <= now + skew`) remains valid until `iat + maximum_assertion_age`, the latest possible authority deadline is `now + skew + maximum_assertion_age`. The relay enforces `until <= now + skew + maximum_assertion_age`. A value above this ceiling rejects `400`; a past `until` still closes live sessions — absent an active same-key entry it creates no future denial, while an active entry remains unchanged under the merge rule. **Capacity and eviction (per-issuer):** The relay MUST bound the deny set size **per issuer**. Capacity exhaustion under one issuer MUST NOT cause rejection of another issuer's commands; the `503` capacity check is evaluated against the command's own issuer bound. Implementations MUST evict only expired entries; when an issuer's partition is at capacity and all entries are still active, the relay MUST reject the new command `503` without removing any existing entry. There is no LRU eviction of active denies. **Issuer-global deny:** The deny entry applies to admission across all communities served by the relay under that issuer. Identity-level revocation is intentionally not community-partial. **Cross-replica propagation:** In a deployment with multiple relay processes, the deployment MUST propagate both the session-close and the deny entry to every process serving admissions for the issuer's communities. The mechanism is deployment-defined (e.g. the existing inter-process message bus, same posture as JWKS convergence). Propagation is asynchronous with no protocol-level completion bound. The issuer re-push duty is the recovery path for lost propagation, exactly as for relay restart. **Response shape:** A successful disconnect responds `{"disconnected": true}` regardless of how many sessions were closed. No session count is returned; a count would aggregate activity across communities and constitute an information leak. **Admission procedure:** Step 5 registers the session's proven `k` before the deny-set check (new step 6) — ensuring any connection that straddles a concurrent disconnect is caught by one side or the other. `FI-TRACE-DENY-SET` oracle covers the per-issuer capacity rule and the straddling termination requirement. ### HTTP ingress enforcement Without explicit enforcement, a protected HTTP surface (bridge, invites, media, git) with NIP-98-only authorization allows a principal holding an active key to mint fresh NIP-98 events indefinitely — NIP-98 proves key possession only, not identity. Without assertion verification there is no expiry bound; the key remains valid for as long as it is accepted. **Pairing rule:** in enforce mode, a protected HTTP request MUST carry both: ``` Authorization: Nostr <base64-NIP-98-event> Nostr-Federated-Identity: Bearer <compact-JWS> ``` The NIP-98 pubkey MUST equal the assertion `nostr_pubkey` claim. Missing, mismatched, or invalid evidence of either kind denies, fail closed. **Verification:** reuses `VerifyAssertion` unchanged — offline, same JWKS, same claim requirements, same denial classes. **Per-request:** HTTP is sessionless; every request re-verifies. No session lifetime, no cached admission. The cumulative residual bound applies per request. **Deny-set applicability:** the deny-until-TTL entry introduced above is consulted per HTTP request identically to WebSocket admission. **Protected surface:** deployment-configured set of routes, fail-closed default (unclassifiable routes treated as protected). No normative route names in the spec. `FI-TRACE-HTTP-INGRESS` oracle added. Security considerations updated with HTTP ingress bypass analysis. NIP-98 source reference added. ### Other changes - `authorization_denied` rejection table row updated to "active deny-set entry for pubkey". - Discovery: `maximum_residual_upstream_revocation_seconds` remains `null` — the deny-until-TTL model is best-effort RAM state and provides no unconditional finite revocation bound. - Rejection and privacy: explicit sentence for HTTP denial path. - Client-attached transport: opening sentence generalized to cover both WebSocket and HTTP. ## Scope Single file: `docs/nips/NIP-FI.md`. No code changes. References #7214. Channel: buzz-enterprise-identity-spec-v2 (#a6fe0b1c-987a-43c5-a974-71ee36678d78). --------- Signed-off-by: Will Pfleger <pfleger.will@gmail.com> Signed-off-by: Duncan <dcfd242e557282d7a1e2cf2e6877522682f1e5c6156dc92ca7d90eaedd3b0f95@buzz.block.builderlab.xyz> Co-authored-by: Duncan <dcfd242e557282d7a1e2cf2e6877522682f1e5c6156dc92ca7d90eaedd3b0f95@buzz.block.builderlab.xyz>
wpfleger96
pushed a commit
that referenced
this pull request
Sep 2, 2026
…agent-edit * origin/main: feat(desktop): add persistent Bestie experience (#7223) fix(desktop): harden profile batch and thread-reply fetches against relay slowness (#7188) docs(nip-fi): adopt deny-until-TTL and extend enforcement to HTTP ingress (#7254) fix(composer): align wrapped inline chip fragments (#7242) Add operation-aware database pool acquisition metrics (#7195) fix(desktop): keep explicit agent profiles bound to their exact key (#7131) fix(desktop): discover authenticated owned relay agents (#7122) feat(agents): harness-agnostic effort write path and spawn bridge (#4625) chore(db): drop Phase-A NIP-FI relay-side authority ledger (#7221) fix(acp): replace real user name in base prompt mention example (#7250) ci: split CI into reusable workflows (#7168) fix(desktop): retain automatic mentions only in threads (#7144) feat: add databricks fable 5.1 model capabilities (#7213) docs(nip-fi): rewrite NIP-FI as stateless OSS Buzz spec v2 (#7214) feat(relay): add detailed readiness metrics (#7149) feat(desktop): add Pi agent preset (#7208) Signed-off-by: Duncan <dcfd242e557282d7a1e2cf2e6877522682f1e5c6156dc92ca7d90eaedd3b0f95@buzz.block.builderlab.xyz> # Conflicts: # desktop/src/features/agents/ui/AgentInstanceEditDialog.tsx # desktop/src/features/agents/ui/agentInstanceEditPinning.test.mjs
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.
Rewrites
docs/nips/NIP-FI.mdas a stateless spec and deletes the five companion profiles (NIP-FI-CONF, NIP-FI-DELEG, NIP-FI-EDGE, NIP-FI-LIFECYCLE, NIP-FI-MODEL) that presuppose relay-side state.What changes
docs/nips/NIP-FI.md— full rewriteThe relay-side authority engine (bindings, receipts, lifecycle, invalidation, leases, delegation, enrollment modes, TOFU) is removed. The spec settles exactly five things:
Assertion contract: JWT claims (
iss,sub,nostr_pubkey,aud(required),iat/exp, finite TTL bounds), npub binding semantics, required NIP-42 proof-of-key pairing. Evidence rules (assertion-key-mismatch →authorization_denied, freshness) preserved from v1.Verification: offline against configured per-issuer JWKS snapshots; multi-issuer; fail-closed on missing/expired/unverifiable. Cites
crates/buzz-auth/src/nip_fi/(PR 3 /70895b355) as implementing the assertion-verification procedure. Therequire_attested_keyflag inIssuerPolicyis the enforcement primitive for the unconditionalnostr_pubkeyrequirement; conformance requires forcing it true for every issuer — follow-on code outside this PR.Session policy: required finite
max_connection_lifetime_secondsknob with no permissive default; re-auth on every reconnect; no in-band renewal.Admin disconnect API: session-only normative text with a dedicated
VerifyCommandJwtprocedure — distincttyp: nip-fi-command+jwt, signedmethod/pathbinding, normativemaximum_command_agebound (0 < value ≤ 60 s), atomic(iss, jti)reservation as the final admission step after all pure checks. Non-normative note documents cumulative residual access:max(0, min(exp, iat + maximum_assertion_age) - now)assuming issuance stops; states that previously issued assertions remain valid for reconnection until their authority expires; states that continued issuance extends access with no protocol-level bound. Non-normative note documents the session-only vs deny-until-TTL trade-off. This verifier and endpoint are follow-on code.Deletions: bindings, enrollment, lifecycle, receipts, leases, invalidation, delegation gone. "Out of scope" section names every issuer and deployment concern explicitly.
Companion profiles deleted
NIP-FI-CONF, NIP-FI-DELEG, NIP-FI-EDGE, NIP-FI-LIFECYCLE, NIP-FI-MODEL — all presuppose relay-side binding/lifecycle state.
What does NOT change
The entire
crates/buzz-auth/src/nip_fi/Rust crate (PR 3 /70895b355) implements the assertion-verification procedure described in this spec. No Rust code changes in this PR. Therequire_attested_keyenforcement integration and theVerifyCommandJwt/ disconnect endpoint implementation are explicit follow-on code work.Follow-on work (separate PRs after spec merges)
require_attested_keyforced-true startup enforcementVerifyCommandJwtimplementation and disconnect endpointschema.sqlNIP-FI sections removedbuzz-dbmigration test blocks cleaned up