Skip to content

Define explicit authorization for releasing confidential data and derived outputs #660

Description

@imran-siddique

Parent tracker: agentrust-io/.github#41

Problem and scope

A tool or ordinary API outside the approved confidential boundary may require a deliberate disclosure. Current sink ceilings in merged #657 conservatively propagate known labels; they do not decide whether a model-generated summary is safe to declassify.

Define a generic release-authorization contract before implementing one policy adapter. Model judgment is not an authorization source.

Acceptance criteria

  • Bind authorization to a principal with release authority, the recipient/audience, data or derivation scope, purpose where enforced, validity and policy version.
  • Distinguish unchanged confidentiality, authorized disclosure and unavailable evidence. Unknown labels or missing authorization cannot silently become a release.
  • Specify how derived outputs retain restrictions and what independently authorized transformation, if any, may lower them.
  • Bind approval to the actual released bytes or a precisely defined transformation contract; test output/recipient substitution, replay and policy changes.
  • Test prompt-injection attempts that ask the model to relabel or summarize secrets for an unapproved sink.
  • Record the boundary change without leaking the protected contents into audit evidence, and state that disclosure cannot be undone.

Relationships

Builds on #657 and depends on confinement for a deployment-wide claim. Reuse existing principal/delegation semantics from #568 and existing human-approval mechanisms where applicable. This issue does not authorize any disclosure itself.

Activity

  1. altrudev commented on Sep 19, 2026

    @altrudev
    Contributor

    I ran a boundary/failure-mode review of the merged exact-output milestone (#672). The authorization and replay properties look strong, but I think one acceptance criterion still has a crash-window gap:

    Record the boundary change without leaking the protected contents into audit evidence.

    Today ReplayStore durably records only request_id. The minimized ReleaseObservation is constructed after recipient.deliver(request.payload) and exists only as the return value.

    That leaves this sequence:

    1. approval verifies;
    2. request ID is durably consumed;
    3. recipient adapter performs the irreversible external side effect;
    4. process terminates before release() returns (for example a BaseException, SIGKILL, host loss, etc.).

    After restart, replay is correctly blocked, but the durable store contains only the consumed request ID. There is no durable minimized record that an authorized disclosure attempt crossed the boundary. This is not a replay bypass or second disclosure; it is an evidence gap at the irreversible transition.

    A minimal invariant that seems to close it without logging protected material:

    Before invoking an irreversible disclosure callback, persist a minimized attempt record durably. It can contain only an independent random event ID, disposition, reason and conservative delivery=unknown. On normal callback return, upgrade that event to acknowledged. If the process dies or the post-delivery update fails, the durable record remains unknown.

    Important ordering detail: keep the existing post-reservation validity recheck before creating the disclosure-attempt record, so an approval that expires while waiting on the replay lock is consumed but is not falsely recorded as a boundary-crossing attempt.

    That gives the sequence:

    verify -> consume request ID -> recheck validity -> persist minimized attempt(unknown) -> deliver exact bytes -> best-effort durable acknowledge

    If the pre-delivery audit write fails, do not call the recipient. If the post-delivery acknowledgement write fails, report/retain unknown; the disclosure cannot be undone.

    The durable audit row should not contain payload, payload digest, principal, recipient, purpose, source scope, labels or approval. Those remain in the private authorization/replay context, while the audit-facing record stays minimized as #672 intended.

    This seems separable from #659 confinement and from downstream installation/execution proof: it only closes the local durable evidence boundary around the release adapter itself.

  2. imran-siddique commented on Sep 20, 2026

    @imran-siddique
    MemberAuthor

    @altrudev I checked the code and agree this gap exists. Please send a focused PR that saves the minimal attempt record before delivery, after the validity recheck. If that save fails, do not deliver. If delivery or the later audit update is interrupted, keep the outcome unknown. Include restart and storage-failure tests, and keep protected data out of the audit record.

  3. imran-siddique commented on Sep 29, 2026

    @imran-siddique
    MemberAuthor

    @altrudev still wanted: the attempt record saved before recipient.deliver(), as above. Can you have a PR up by 9 October? If you would rather hand it back, say so and I will take it, crediting your finding.

  4. altrudev commented on Oct 3, 2026

    @altrudev
    Contributor

    @imran-siddique PR #721 is up from the exact current upstream baseline.

    It implements the requested ordering:
    verify -> consume -> recheck validity -> persist minimized attempt(unknown) -> deliver -> best-effort acknowledge.

    The durable audit row contains only event ID, disposition, reason and delivery; protected release context stays out of it. Pre-delivery audit failure fails closed. Delivery interruption or post-delivery audit failure leaves the durable outcome unknown.

    Validation:

    • focused disclosure/sink tests: 82 passed
    • full repository suite: 2410 passed, 37 skipped
    • git diff --check: clean

    PR: #721

  5. imran-siddique commented on Oct 6, 2026

    @imran-siddique
    MemberAuthor

    The attempt record before recipient.deliver() landed in #721: the row is persisted as unknown before delivery, acknowledged after, and corrected to not_attempted when the final validity recheck refuses. Keeping this open for the remaining criteria, derived-output restrictions and the prompt-injection relabelling tests.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions