Review workflows.
Last updated
Review plans
What it is. The approval policy attached to a datasource — it decides how a submitted query gets from "submitted" to "executed". Use it to require AI scoring, one or more human sign-offs, or both, and to auto-approve low-risk reads. Each plan is a sequence of stages; each stage names approvers (by role or specific user) and a minimum number of approvals before the query advances.
Configure it. Build plans at /admin/review-plans — start
from a built-in template or from scratch:
/admin/review-plans → caret next to Add review plan exposes four built-in templates that prefill the create modal.
/admin/review-plans → Add review plan. Stack approver rows to build multi-stage chains.- Open
/admin/review-plansand click Add review plan, or pick a built-in template from the dropdown caret next to it (Strict — writes need 2 approvals, Lenient — reads auto-approved, AI-only — no human approval, Standard — AI + 1 reviewer) to prefill the modal with sensible defaults. - Name and describe the policy — e.g. "Production writes — two reviewers".
- Pick the gates. Toggle Require AI review to score every query before it queues for humans; toggle Require human approval to demand at least one reviewer sign-off. Auto-approve LOW-risk reads lets
SELECTs skip humans entirely when AI risk is below the threshold. - Set thresholds. Minimum approvals is the number of distinct reviewers needed before the query advances; Approval timeout (hours) is when AccessFlow auto-rejects an idle
PENDING_REVIEWquery (it scans on a cadence set byACCESSFLOW_WORKFLOW_TIMEOUT_POLL_INTERVAL, defaultPT5M). - Build the approver chain. Click Add approver for each stage; each row names a role (or a specific user) and a stage number. Stages advance sequentially, and a single REJECTED decision at any stage terminates the query.
What can a review plan control?
A review plan is six settings plus an approver chain. Together they decide whether a query needs AI scoring, how many humans must sign off, which of them, and what happens if nobody does. Every setting below is per-plan, and a plan attaches to a datasource.
| Setting | What it does | When disabled / unset |
|---|---|---|
| Require AI review | Every query is scored for risk before it queues for humans. | The query skips PENDING_AI and goes straight to review. |
| Require human approval | At least one reviewer must sign off before execution. | The query is approved without a human — AI-only gating. |
| Auto-approve LOW-risk reads | SELECTs below the AI risk threshold skip human approval. |
Reads queue for review like any other statement. |
| Minimum approvals | How many distinct reviewers must approve before the query advances. | Defaults to one approval per stage. |
| Approval timeout (hours) | How long an idle PENDING_REVIEW query waits before auto-rejection. |
The query waits indefinitely for a decision. |
| Approver chain | Ordered stages, each naming a role or a specific user as approver. | No chain means no staged escalation — one flat approval step. |
Stages advance sequentially and a single Reject at any stage terminates the query. A user can never approve their own query, whatever their role.
Reviewer decisions. Reviewers can Approve, Reject, or
Request changes. Reject and Request changes both require a
non-empty comment — the server enforces this (HTTP 400 VALIDATION_ERROR),
and the UI disables the confirm button until the textarea is populated. The comment is
persisted on the decision row, rendered on the rejected stage of the timeline on
/queries/<id>, and surfaced to the submitter as a "Changes requested"
alert whenever the latest decision is REQUESTED_CHANGES and the query is
still PENDING_REVIEW. Approve still treats the comment as
optional.
Query status transitions. A query moves through these states:
PENDING_AI → PENDING_REVIEW → APPROVED → EXECUTED
↘ REJECTED (manual reviewer rejection)
↘ TIMED_OUT (approval-timeout auto-reject)
PENDING_REVIEW → CANCELLED (submitter only)
APPROVED → FAILED (execution error)
A single REJECTED decision at any stage terminates the query. If a query
sits in PENDING_REVIEW past the plan's approval timeout, AccessFlow
auto-rejects it (it scans on a cadence set by
ACCESSFLOW_WORKFLOW_TIMEOUT_POLL_INTERVAL, default PT5M).
Auto-approve reads lets SELECTs skip human approval entirely;
Require AI review still scores the read but won't block on a human.
Escalation & reminders
What it is. Between a request arriving and the approval timeout auto-rejecting it, nothing used to happen — a stalled chain was silent until the submitter found out by being rejected. Two optional settings on a review plan add the warning shots.
Where. Admin → Review plans, alongside Approval timeout: Escalate after (hours) and Nudge every (hours). Both are blank by default, and blank means off — an existing plan behaves exactly as it did before you set them.
-
Escalate after — when nobody has decided within this window, the
request is raised to the reviewers it is waiting on and your organization's admins,
once. It appears with an escalation notice on the request page and goes out over the
plan's notification channels; PagerDuty pages for it on channels that enable the
REVIEW_STALLEDtrigger. It must be shorter than the approval timeout — a longer window could never fire, so AccessFlow rejects it rather than letting you save a setting that quietly does nothing. - Nudge every — re-notifies the reviewers who still have not decided, on this cadence. It reaches only the people already on the hook, never admins, and never pages: a reminder is not an incident.
What it does not do. Escalation is notify-only. It never changes who is allowed to approve, and it never approves, rejects, or times out anything — waiting must not become a way around the approvers you configured. The request stays exactly where it was, with the same people able to act on it.
Grouped requests have no plan of their own, so a bundle uses the shortest escalation window among its members' plans. A member whose plan has escalation switched off simply does not contribute one. For bundles the escalation is recorded on the request group and nothing more — no notification and no queue badge yet, since grouped requests have no notification path at all.
Out-of-office delegation
What it is. An approval chain moves at the speed of its slowest human.
When a named reviewer goes on holiday, a request sits in PENDING_REVIEW
until the approval timeout auto-rejects it. Delegation lets a reviewer hand their review
duty to a named colleague for a set window instead.
Where. Any reviewer sets this themselves on Profile settings → Out-of-office delegation. No admin involvement, and no permission is required to delegate — a delegation from someone with no review rights simply confers nothing.
How to set one up. Choose a colleague, optionally narrow the delegation to a single datasource, pick a start and end time, and save. During the window the delegate becomes an eligible approver everywhere you were — query review, governed API requests, and grouped requests — and the requests show up in their review queue with a Delegated tag. Revoking is immediate and takes effect on the next decision; the record itself is kept as evidence for anything already approved under it.
What it cannot do. These limits are enforced by the server, not the interface:
- A delegation never grants a permission. The delegate still needs review rights of their own; delegation only widens which requests they may act on.
- The delegate can never act on a request the delegator submitted — the no-self-approval rule follows the borrowed identity, not just the person clicking.
- Delegation does not chain. If A delegates to B and B delegates to C, C gains nothing from A.
- One human still gets one vote. Covering for two absent approvers at once does not let someone satisfy a two-approval requirement alone.
- It stops the moment either party is deactivated, including via SCIM deprovisioning.
Audit. Every decision made under a delegation records both people — who clicked approve, and whose authority they used — so the trail never implies the absent reviewer acted. Admins can see every delegation in the organization under Admin, which is what makes an “on behalf of” entry interpretable months later.
Routing policies
What it is. Policy-as-code that decides a query's path automatically, after AI analysis and before reviewers see it. Use it to auto-approve routine reads, hard-block dangerous patterns, or escalate sensitive ones — instead of sending everything through the same review plan. Policies run in ascending priority and the first enabled one whose condition matches wins; anything unmatched falls through to the datasource's review plan exactly as before.
Configure it. Manage them at /admin/routing-policies (the
Routing policies entry in the Security nav group):
- Open
/admin/routing-policies(the Routing policies entry in the Security nav group, next to Review plans) and click Add policy. - Name the policy and optionally scope it to one datasource — leave the datasource blank for an org-wide rule. Set its priority (unique per organisation; lower runs first) and the enabled toggle.
- Build the condition with the guided builder: pick match ALL (AND) or match ANY (OR), then add leaf conditions — each can be negated (NOT). Operands include query type, referenced tables (glob, e.g.
payroll.*), AI risk level, AI risk score (with a comparison operator), requester role, requester group, time-of-day window, day-of-week, presence of aWHEREclause, presence of aLIMITclause, the transactional (BEGIN…COMMIT) flag, and the pre-flight cost estimate — estimated rows (comparison against the engine's own EXPLAIN estimate, or the exact affected-row count for UPDATE/DELETE) and scan type (glob match on the plan's root operation, e.g.Seq*) — so a policy can route a 10-million-row sequential-scan DELETE differently from a 10-row indexed one. - Choose the action. Auto-approve (skip human review), Auto-reject (block the query), Require approvals (force human review with an absolute minimum number of approvers), or Escalate (force human review, adding a delta on top of the review plan's minimum). The approver count applies only to the last two actions.
- Reorder policies any time with the per-row up/down controls — the order is the evaluation order.
QUERY_APPROVED /
QUERY_REJECTED with source: "ROUTING_POLICY"), and the query detail page
shows which policy matched. Routing policies are managed via the ADMIN-only
/api/v1/admin/routing-policies CRUD and /reorder endpoints.
/admin/routing-policies — ordered, attribute-based auto-decision rules; first match by priority wins, unmatched falls through to the review plan.Access recertification campaigns
What it is. Recurring attestation campaigns that make someone periodically
re-confirm who still needs standing datasource access — the review control SOC 2 and
ISO 27001 auditors ask for. An admin schedules an org- or datasource-scoped campaign;
when it opens it snapshots the current standing grants into one item per
grant and notifies the eligible reviewers (multi-channel, plus an
attestation.campaign_opened WebSocket event). Reviewers work a
certify / revoke worklist that reuses the review-queue patterns
(self-review blocked, bulk-certify); a revoke routes through the normal
permission-revoke path, so access is actually removed.
Configure it. Manage campaigns from /admin/attestation and
certify items from the reviewer worklist at /reviews/attestations. Two
clustered-safe jobs run the lifecycle: one opens SCHEDULED campaigns at their
scheduled_open_at, the other closes OPEN campaigns at their
due_at and applies each campaign's pending-default (KEEP or
REVOKE) to anything a reviewer never got to. A completed campaign exports as a
CSV evidence file (who reviewed what, decisions, timestamps), and every
transition — ATTESTATION_CAMPAIGN_OPENED/CLOSED,
ATTESTATION_ITEM_CERTIFIED/REVOKED — lands in the tamper-evident
audit log.
Tune it. ACCESSFLOW_ATTESTATION_OPEN_POLL_INTERVAL and
ACCESSFLOW_ATTESTATION_CLOSE_POLL_INTERVAL (open / close scan cadence, both
default PT5M) and ACCESSFLOW_ATTESTATION_MAX_EVIDENCE_ROWS (row
cap before an evidence CSV is marked truncated, default 50000).
/admin/attestation — admins schedule recurring access-recertification campaigns; reviewers certify or revoke each snapshotted grant.
Unused-grant analytics. Certifying access is easier when you know which
grants nobody is using, so a clustered-safe background job folds the audit log's executed
queries and executed API calls into a per-grant usage summary — last used, how often, and
which of the granted tables (datasource grants) or operations (API-connector grants) were
ever actually exercised — and labels each grant NEVER_USED,
STALE, OVER_SCOPED, ACTIVE, or
INSUFFICIENT_DATA. The label shows on every attestation item and sorts the
reviewer worklist staleness-first, so never-used grants land on page one; admins and
auditors also get the standing report at /admin/over-provisioned-access
(filter by resource, holder, or recommendation, and export as CSV — gated on the
ACCESS_USAGE_REPORT_VIEW permission, held by ADMIN and
AUDITOR), and an opt-out notification nudges org admins once per cooldown
when a grant crosses the staleness threshold. It is advisory only:
nothing is ever revoked automatically, and a recommendation is never an input to routing,
grant coverage, or any other decision path. Grants inherited from a user group are not
covered.
Tune it. Grant-usage analytics reads nothing but the audit log, so the knobs are all about how far back it looks and how patient it is (defaults shown):
- Cadence & window:
ACCESSFLOW_ACCESS_USAGE_AGGREGATION_POLL_INTERVAL(PT1H— how often the job folds new audit events),ACCESSFLOW_ACCESS_USAGE_BACKFILL_WINDOW(P90D— how far back a newly-summarised grant starts observing). - Verdict thresholds:
ACCESSFLOW_ACCESS_USAGE_STALENESS_THRESHOLD(P60D— unused for longer than this isSTALE),ACCESSFLOW_ACCESS_USAGE_MIN_OBSERVATION_WINDOW(P14D— below this a grant isINSUFFICIENT_DATArather thanNEVER_USED),ACCESSFLOW_ACCESS_USAGE_OVER_SCOPED_THRESHOLD(0.5— exercised/granted ratio below which an active grant isOVER_SCOPED). - Caps:
ACCESSFLOW_ACCESS_USAGE_MAX_ROWS_PER_TICK(50000— audit events folded per organization per run; the remainder is picked up next run),ACCESSFLOW_ACCESS_USAGE_MAX_TRACKED_TARGETS(200— distinct exercised tables/operations retained per grant),ACCESSFLOW_ACCESS_USAGE_MAX_REPORT_ROWS(50000— row cap before a report CSV is marked truncated). - Staleness nudge:
ACCESSFLOW_ACCESS_USAGE_NUDGE_ENABLED(true— setfalseto switch the notification off),ACCESSFLOW_ACCESS_USAGE_NUDGE_COOLDOWN(P30D— minimum time between nudges for the same grant).
Deployment pipelines
What it is. The same review machinery, applied to CI/CD
deployments. A deployment pipeline names a provider (GitHub
Actions, GitLab CI, Azure Pipelines, Jenkins, CircleCI, Bitbucket Pipelines, or generic)
and holds ordered environments — dev,
staging, production — each of which can require review, set its
own approval count, override the review plan, and opt in
to break-glass. A CI job asks AccessFlow for permission to release, the request flows
through AI release-risk analysis, routing policies and
human approval, and the job blocks on a fail-closed gate until every
required approval is granted. The submitter — for a pipeline, the user who owns the API
key — can never approve their own deployment.
/deployments — every deployment you submitted, with its status, target environment and release version.
/deployments/<id> — release metadata, the AI risk verdict, the approval timeline and the fail-closed releasability banner.
/deployment-reviews — the reviewer queue. A deployment never appears here for its own submitter.
Configure it. Create pipelines at
/admin/deployment-pipelines (requires the
DEPLOYMENT_PIPELINE_MANAGE permission, held by ADMIN). Each
pipeline's settings page carries six tabs. Alongside General and the
CI setup snippet sit Environments (promotion
order, required approvals, review-plan override, break-glass opt-in),
Permissions (per-user and per-group can_trigger /
can_break_glass grants with an optional expiry — a user's effective grant is
the most-permissive union of their direct grant and every unexpired group grant),
Freeze windows, and Routing policies. The CI setup
tab renders a copy-paste snippet for the pipeline's provider. Reviewers work
deployments at /deployment-reviews (requires DEPLOYMENT_REVIEW,
held by ADMIN and REVIEWER); everyone sees their own at
/deployments.
/admin/deployment-pipelines — one row per pipeline, with its CI provider and environment count.
Freeze windows. A freeze window suspends releases for the whole
organization, one pipeline, or a single environment. It is either one-off
(a start and end instant) or recurring weekly (days of the week plus a
start and end time in a named IANA timezone — an end time before the start time spans
midnight). HOLD lets a deployment be submitted, analyzed and approved but
withholds releasability until the window closes, so the release proceeds by itself
afterwards with no re-approval. REJECT auto-rejects at submission instead.
Where several windows are active at once the most specific scope wins, and
REJECT beats HOLD. A window whose definition cannot be evaluated
— a bad timezone, say — counts as an active HOLD, never a
REJECT: a broken rule can stall a release but can never destroy a request.
Break-glass and rollbacks. An emergency deploy needs
both a can_break_glass grant on the pipeline and
allow_break_glass on the target environment — for everyone, with no admin
bypass. It skips AI analysis, routing and review, and pays for that with an instant
notification to every org admin, a prominent audit row naming any freeze window it
bypassed, and a mandatory retro-review an admin who is never the submitter must
acknowledge. After a deploy the pipeline reports its outcome; a
rollback on a review-required environment opens a follow-up review in the
reviewer queue that the submitter can never close.
/deployment-reviews?tab=rollbacks — the follow-up worklist a rolled-back deployment opens.Wire up CI. See the deployment gate in CI for the GitHub Action, the GitLab CI template, the Azure Pipelines step template, and the plain-curl path, plus how to mint the service-account API key a pipeline authenticates with.
Tune it. ACCESSFLOW_DEPLOYGOV_TIMEOUT_CHECK (how often
deployments awaiting review are checked against their review plan's approval timeout,
default PT5M) and ACCESSFLOW_DEPLOYGOV_RELEASE_CHECK (how often
approved deployments are scanned to announce that they have become releasable, default
PT1M). Every transition lands in the
audit log.