Deployment approval governance — gate every CI/CD release
Shipping to production is an access decision. Most pipelines record it as a protected-branch rule or a chat message, which is neither reviewable nor auditable after the fact. AccessFlow puts a release request through the same machinery as a database query — AI analysis, routing policies, named approvers, an audit trail — and gives your CI job a gate to block on that answers not releasable whenever it is unsure.
Pipelines, environments and who may trigger them
A deployment pipeline is the governed unit — a name, a provider (GitHub Actions, GitLab CI, Azure Pipelines, Jenkins, CircleCI, Bitbucket Pipelines, or generic), an optional repository reference, a review plan, and its own AI switch. Under it sit ordered environments: dev, staging, production. Each environment can require review, override the required approval count and the review plan, and opt in to break-glass, which is off by default.
Who may trigger a release is a per-pipeline grant rather than a global role: a non-admin needs one, and an org admin short-circuits that check — but never the break-glass one. Grants exist per user and per group, each carrying trigger and break-glass flags and an optional expiry, and the effective answer is the most-permissive union of a user's direct grant and their unexpired group grants. The trigger endpoint, the gate and the outcome endpoint all resolve permission through that one path, so they cannot disagree. Administration needs a deployment-pipeline permission, reviewing needs a deployment-review permission, and every read is organization-scoped: an id from another organization returns 404, never 403, so no endpoint can be used to probe for what exists.
Deleting a pipeline removes its configuration but not its history — past requests, decisions and rollback reviews survive as evidence.
The gate is fail-closed by construction
A CI job opens a request by calling AccessFlow with an ordinary API key — no deployment-specific token, and the key's owning user is the submitter, which is what makes the self-approval ban meaningful for a machine-triggered release. The trigger is idempotent on the CI run id at the database level, so a retried step never opens a second review.
From there the request behaves like any other: the AI analyzer scores the release metadata, routing policies keyed on environment, provider, version glob, risk or time window can auto-approve, auto-reject or raise the approval bar, and reviewers decide in the UI. Review is single-stage, a rejection is immediately terminal, and self-approval is refused first and always — including for the submitting API key's owner, and including for an admin. Where the resolved review plan names approvers, only those users may decide.
The job then polls one endpoint and branches on one field. A release is releasable only when all three hold: the request is exactly approved, no freeze window is active, and any scheduled time has already passed. Everything else answers not releasable — a pending request, a rejected one, an unknown pipeline or version, a caller who may not see the request, and any internal error at all. A failure to evaluate degrades to a refusal, never to an accidental yes.
/deployments/<id> — this one is still pending review, so the gate answers not releasable; approval is what flips it.Freeze windows, and the emergency exit
A freeze window suspends releases across an organization, one pipeline, or a single environment. It is either one-off — a start and an end — or recurring on chosen weekdays in a named timezone, evaluated as local wall-clock so a window that crosses midnight behaves the way an operator means it to. Among simultaneously active windows the most specific scope wins.
Windows come in two behaviours. A rejecting window turns a release away at submission. A holding window lets the request be analyzed, reviewed and approved as normal and only withholds releasability at the gate — so the release proceeds the moment the window closes, with no re-approval. A window that cannot be evaluated at all fails closed to a hold, never to a rejection: a broken definition can stall deployments but can never destroy requests.
Break-glass deploys are gated twice with no admin bypass — the submitter needs a break-glass grant on the pipeline and the environment must allow it. In exchange they fan out instantly to every org admin, record an audit entry naming any freeze window they bypassed, and open a mandatory retro-review that an admin, never the submitter, must acknowledge. Deployment pipeline docs →
What happened after the deploy
Approval without an outcome is half a record, so the pipeline reports back: succeeded, failed, or rolled back. Repeating the same report is idempotent; reporting a different outcome is a conflict rather than a silent overwrite. A failure report flips the request from executed to failed — the one post-terminal transition the state machine allows.
A rollback on an environment that requires review opens a follow-up review in the same transaction, so a governed rollback can never exist without one. As everywhere else, the submitter cannot close their own: acknowledgement is somebody else's, and it is a latch rather than a contested decision.
One step in your pipeline
The wiring is deliberately small. AccessFlow ships composite GitHub Actions, hidden GitLab CI jobs, and an Azure Pipelines step template that each do the same four things: submit the request idempotently by run id, poll the gate, confirm execution, and report the outcome. There is a documented plain-curl walkthrough for everything else.
All of them are fail-closed in the direction that matters: an unknown release or any non-retryable error fails the job rather than letting it through. Pipelines are addressed by id rather than by name, because a trigger-only key is not permitted to resolve names — which is the same fail-closed instinct applied to identifiers. CI gate setup → Service-account API keys →
The teams that reach for this are usually the same ones removing shared production credentials elsewhere — see the platform-engineering use case. Pipelines and environments are configured in the admin UI; the Terraform provider covers the rest of the estate — datasources, review plans, routing, masking and row-security policies, AI configs and notification channels. Terraform provider docs →