Repository navigation
feat(mitigations): extend FlowSpec lifetime with an audit trail - #326
Merged
Merged
Conversation
There was a problem hiding this comment.
🔵 Needs a closer look
Unresolved lifetime monotonicity and lifecycle-lock risks require fixes and final human routing-safety review.
2 open issues
What changed in this PR
Adds an operator workflow to extend an existing FlowSpec rule’s saved lifetime without changing its match/action or sending speaker mutations.
Changes:
- Adds an authenticated extension endpoint with eligibility checks and atomic expiry/audit updates.
- Adds a confirmation dialog showing the complete rule, exact police rate and expiry estimate.
- Adds backend, PostgreSQL and frontend coverage, plus operator documentation.
| File | Description |
|---|---|
tests/integration_lifetime.rs |
Tests transactional updates, rollback and lock-wait safety. |
src/guardrails/mod.rs |
Separates reusable rule checks from creation quotas. |
src/domain/mod.rs |
Exports lifetime-extension types and logic. |
src/domain/lifetime.rs |
Implements extension eligibility, safety checks and domain tests. |
src/db/traits.rs |
Defines the atomic extension repository contract. |
src/db/repository.rs |
Implements PostgreSQL expiry and audit transactions. |
src/db/mock.rs |
Implements mock extension behavior and audit-failure simulation. |
src/api/routes.rs |
Registers the extension endpoint. |
src/api/openapi.rs |
Registers endpoint documentation and schemas. |
src/api/handlers/lifetime.rs |
Handles authentication, requests and extension responses. |
src/api/handlers.rs |
Exports the lifetime handler and schemas. |
frontend/lib/api.ts |
Adds the extension client and error-status helper. |
frontend/components/dashboard/extend-lifetime-dialog.tsx |
Adds preview, validation and confirmation controls. |
frontend/app/(dashboard)/mitigations/[id]/page.tsx |
Integrates extension into mitigation details. |
frontend/__tests__/extend-lifetime.test.tsx |
Tests confirmation, eligibility, no-op and error states. |
docs/reference/api.md |
Documents the extension API contract. |
docs/README.md |
Links the extension workflow. |
docs/how-to/extending-mitigations.md |
Explains operator steps and safety boundaries. |
docs/cookbook/manual-mitigation.md |
Links extension guidance and corrects documented port limits. |
CHANGELOG.md |
Records the lifetime-extension feature. |
Review effort: Balanced
lance0
force-pushed
the
feature/flowspec-destination-cidrs
branch
from
October 24, 2026 03:22
b2fd374 to
5fffa9c
Compare
This was referenced Oct 24, 2026
lance0
force-pushed
the
feature/flowspec-lifetime-extension
branch
from
October 24, 2026 03:24
803f413 to
064e146
Compare
lance0
changed the base branch from
feature/flowspec-destination-cidrs
to
feature/flowspec-admission-preview
October 24, 2026 03:25
lance0
force-pushed
the
feature/flowspec-lifetime-extension
branch
from
October 24, 2026 03:37
064e146 to
e80c203
Compare
lance0
force-pushed
the
feature/flowspec-lifetime-extension
branch
from
October 24, 2026 03:39
e80c203 to
37011af
Compare
lance0
force-pushed
the
feature/flowspec-lifetime-extension
branch
from
October 24, 2026 04:24
37011af to
d56b8c4
Compare
lance0
marked this pull request as ready for review
October 24, 2026 04:47
… violations A safelist entry committed while the Postgres extension transaction waited returned 409 Conflict, while preparation and the mock repository return the documented 422 safelist refusal. Split the in-transaction checks so a pending withdrawal or expiry remains 409 and a safelist match maps to the same guardrail error as preparation. Keep a cleared lifetime field empty instead of showing 0.
lance0
changed the base branch from
feature/flowspec-admission-preview
to
main
October 24, 2026 16:09
…time-extension # Conflicts: # CHANGELOG.md # docs/how-to/upgrading.md # docs/project/scrubber-diversion-contract.md # docs/reference/api.md # src/api/handlers.rs # src/api/handlers/manual_flowspec.rs # src/api/openapi.rs # src/config/inventory.rs # src/db/repository.rs # src/db/traits.rs # src/scheduler/reconcile.rs # tests/integration.rs # tests/integration_admission.rs
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.


Add an authenticated Operator action to extend the saved lifetime of a live ordinary enforced FlowSpec rule. Preserve the exact match, action, rule identity and creation history; refuse expired, withdrawn, blackhole, simulation, foreign-POP or unsafe intent. Fresh ownership, safelist, policy, binding and fence checks precede an atomic expiry/audit update. No speaker mutation or new quota slot is used.
The modal shows current/proposed expiry, the full rule and exact police bps, and requires a reason. An open modal retains precise refusals and uncertain-update warnings after eligibility changes; it blocks further submission until the operator closes it. Read-only preparation uses one five-second budget, server-side statement deadlines and discarded read connections; atomic mutation and COMMIT remain outside cancellation.
Validation on
d56b8c4: all 575 library tests, 7 lifetime and 2 admission database tests, all 64 PostgreSQL lifecycle cases, both strict Clippy configurations and the Rust 1.89 all-target check pass. One-connection blocked-read tests recover before blocker release; the old preparation fails the negative control. Mutation SQL and UI preservation were verified. Pinned frontend lint/types, 574 tests and production build pass; both eligibility-loss races fail under the old dialog guard. Desktop/mobile browser checks pass in both themes with reduced motion. All 18 hosted checks pass on this exact head; the PR is clean and ready for review.This PR targets #325 and contains only lifetime extension. Merge order: #323 → #327 → #322 → #324 → #325 → #326. Use merge commits; after the predecessor lands, retarget the next PR to
mainbefore merging.