Deployment checks
Deployment checks hold a release back from production until what you require of it (tests, a scan, a review) has been reported as passed. This page explains where required checks are declared, how CI satisfies them, who can bypass them and how that is recorded. It also describes progressive rollout, declared in the same file.
Concepts
- Check: a requirement named by a stable identifier you choose (
unit-tests,static-analysis). It describes no command: your CI reports it, under that identifier, whatever its provider. - Required: a required check holds the release back; an informational check is shown and holds nothing.
- State of a check on a release:
pending,passedorbypassed. - Release on hold: built (
built) and not served, because it is waiting for its checks.
Declare checks
Checks are declared in the .bastide/controles.yaml file, at the project's build root (the « Racine du projet » setting, or the repository root). There is no other place: neither the console nor the API configures them, and switching CI provider changes nothing here.
version: 1
controles:
- id: unit-tests
- id: end-to-end-tests
- id: static-analysis
obligatoire: false
description: Informational only
| Field | Rule |
|---|---|
version | Required, equals 1. |
controles | Twenty at most, no duplicates. |
id | A lowercase letter or digit, then up to 62 lowercase letters, digits, dots, underscores or hyphens. |
obligatoire | True by default: forgetting the line holds the release back rather than letting it through. |
description | For whoever reads the file, 200 characters at most; neither stored nor served. |
The file weighs 16 KiB at most. If it is absent, the release requires nothing. If it is present but unreadable (invalid YAML, unknown field, identifier outside the grammar, duplicate, symbolic link), the build is refused with controles_refuses: a production gate the platform cannot read is not ignored.
Checks are frozen onto the release when it is built. Rebuilding the same commit does not reset a check that has already been reported.
What checks hold back
- Towards production, a release with a required check neither passed nor bypassed stays on hold: it is built, and the live version does not change. A check that has reported nothing holds as much as a failure.
- Outside production (preview, staging, custom environment), checks are shown and hold nothing back: a preview is precisely where you watch them fail.
A release's checks are read in checks from deployment_read, and enAttente says whether it is on hold. The console does not show checks yet: the promotion screen that will carry them is still to come.
Satisfy checks
Once your jobs have passed, promote the release while declaring the checks passed, with deployment_create, releaseId and passedChecks:
{
"projectId": "prj_01JQ8ZK4M7NP2RSTVWXYZ34567",
"environmentId": "env_01JQ8ZK4M7NP2RSTVWXYZ34567",
"releaseId": "rel_01JQ8ZK4M7NP2RSTVWXYZ34567",
"passedChecks": ["unit-tests", "end-to-end-tests"],
"idempotencyKey": "promotion-rel-2026-10-28"
}
The same promotion from a CI job, under a service account holding the deploy:write scope:
export BASTIDE_TOKEN=<service account token>
bastide deployment create --project-id prj_01JQ8ZK4M7NP2RSTVWXYZ34567 \
--environment-id env_01JQ8ZK4M7NP2RSTVWXYZ34567 \
--release-id rel_01JQ8ZK4M7NP2RSTVWXYZ34567 \
--passed-checks unit-tests --passed-checks end-to-end-tests
Promotion rebuilds nothing: production serves the exact image that was built (see Deploy). If a required check is still pending, the promotion is refused with controles_non_satisfaits, which names the missing checks; the live version does not change.
passedChecks and bypassChecks only apply together with releaseId.
Who can report, and who can bypass
| Action | A person | A service account | An agent (agent session, or the MCP channel) |
|---|---|---|---|
Report passed checks (passedChecks) | yes | yes | no |
Bypass checks (bypassChecks) | yes | no | no |
An agent does not declare the checks that block it as passed itself, and does not bypass them: it proposes, the person decides. The refusal comes as contournement_reserve (403), before anything is written, and the attempt is logged. The role required is that of deployment_create: developer (developer).
Bypass
Bypassing is the act of a person who answers for it, with a reason of 10 to 500 characters:
{
"projectId": "prj_01JQ8ZK4M7NP2RSTVWXYZ34567",
"environmentId": "env_01JQ8ZK4M7NP2RSTVWXYZ34567",
"releaseId": "rel_01JQ8ZK4M7NP2RSTVWXYZ34567",
"bypassChecks": { "reason": "Urgent security fix, tests rerun after going live." }
}
It covers this release's required checks that are still pending. Each moves to bypassed, with the person's name and the reason; a bypassed check stays bypassed, even if a job later reports it passed.
How it is recorded
- The promotion's audit log entry names the person, the promoted release, the original deployment, the bypassed checks and the reason.
- Each check on the release keeps who reported or bypassed it, and when.
- An attempt refused with
contournement_reserveis logged too.
Read these entries on the project's Audit screen, or with audit_read.
Progressive rollout
The same file can declare that a production deployment first receives a share of the traffic, and is cancelled on its own if errors or latency exceed a threshold:
version: 1
mise_en_service:
paliers: [10, 50, 100]
erreurs_5xx_max_pct: 2
p95_max_ms: 1000
palier_minutes: 5
echantillon_min: 50
controles: []
| Field | Meaning | Default |
|---|---|---|
paliers | Successive traffic shares, in percent, increasing, the last at 100; ten at most. | 10, 50, 100 |
erreurs_5xx_max_pct | Rate of 5xx responses beyond which the release is cancelled. | 2 |
p95_max_ms | p95 latency beyond which it is cancelled. | 1,000 ms |
palier_minutes | Duration of a step. | 5 |
echantillon_min | Number of requests below which a measurement does not decide. | 50 |
Declaring the block is enough: each field has its default. It only applies in production, and only when a previous release is already serving. A threshold crossed on a sufficient sample cancels at once, and the previous release takes back all the traffic. If there is no traffic after three steps, the share moves on, and the platform says so.
Common errors
| Code | Remedy |
|---|---|
controles_refuses | .bastide/controles.yaml is unreadable: read the reason (line and code), fix it, redeploy. Removing it removes the checks. |
controles_non_satisfaits | Report the missing checks with passedChecks, or have a person bypass them. |
contournement_reserve | An agent tried to report or bypass: ask a person to promote, through the API or the command line. |
promotion_impossible | Release already served, environment pinned, not routable, or a deployment of the same commit in progress. |
See also: Deploy, Builds, Service accounts, Agent safety, Audit.