Skip to content

security(approvals): expires_at is stored but not enforced — a past-expiry approval can still be approved and resumed #18412

Open

Description

@mrveiss

Found by the Opus review of #18404 (#13421 S1). The approval expires_at field is stored but not enforced at decision time. In services/approval_gate_service.py, _transition (~L380-417) does not check it, so a past-expiry approval can still be approved and resumed. #18404's body says so, but nothing tracked it.

Acceptance criteria

  • _transition refuses to approve or resume a record whose expires_at <= now_utc(), and moves it to an expired state.
  • Optionally, a sweeper expires stale pending records so they leave GET /approval-gates/pending.
  • Tests: a past-expiry approve is refused; a just-before-expiry approve succeeds.

Refs #13421

Activity

  1. mrveiss commented on Oct 12, 2026

    @mrveiss
    OwnerAuthor

    Partial delivery in #18404: decision-time enforcement (a past-expiry approve is refused, the row moves to EXPIRED and its source is resumed as expired), expired rows hidden from the pending list, and a service-level expire_stale() with a once-only test. NOT delivered: the periodic scheduler that calls expire_stale(). It is a lifespan change (shutdown-order tests apply) and no emitter sets an expires_at until S2, so it is left open here.

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

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions