Skip to content

engine: report the grant rows a rotation drops as an attributable abuse event #1351

Description

@FSM1

The gap

#1143 brought each grant-ledger row's recipientEncPk/recipientIdentityPk under owner authority (per-row ownerSig) and decided the policy for a row that fails it: skip, not abort.

  • crates/engine/src/rotation/reseal.rs::adopt_recipients seals no grant blob for an unattested row.
  • crates/engine/src/net/rotation.rs::remint_grants drops it from the moved root's set.

Both are correct — refusing would let the grantee a rotation is cutting veto its own revocation — but neither is reported to the host. The only trace is the published record itself: a committed tag with no blob, which grants::revocation::classify reads as revocation. The owner's UI therefore shows an innocent co-grantee as revoked with no indication that a rogue writer caused it.

#1143's Fix section named this explicitly: "publish no blob for that tag while leaving the committed set intact and raising an attributable abuse event". The event half is not landed.

Checkable condition

  • A skipped or dropped row produces a grants::AbuseEvent (the type already exists in crates/engine/src/grants/owner_entry.rs and maps to the facade's AttributableAbuse) carrying the tag and no key material.
  • The event reaches the host through the re-seal's and the re-mint's own return channel, not a log line. reseal_scope_root currently returns Result<GrantSection, ResealError> with 44 call sites, so this is a return-type change plus its mechanical tail.
  • Attribution: the write body that carried the poisoned row is structure-signed by a committed writer pseudonym, so the event can name which committed pseudonym authored it.
  • A test at each boundary asserts the event is raised alongside the skip, and that no key material appears in it.

Why it is not in the PR that found it

Sized out of the #1143/#1294/#1295 batch: the return-type change touches 44 call sites across seven engine files, on top of a crates/core wire change and a KAT regeneration. The security-relevant half — never wrapping a scope seed to a writer-chosen key — landed there; this is the observability half.

Metadata

Metadata

Assignees

No one assigned

    Labels

    comp:enginecrates/engine — the stateful client brainv2-buildv2 rewrite build slice

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions