Artifact approval
Set up planning, administrator review, and approved artifact execution.
Local Docker/Podman steps can save an artifact and pause before a later step.
Set approval_artifact_path and approval_review_path to distinct relative
paths under DURPDEPLOY_STAGE_DIR. Set approval_review_format to terraform
for terraform show -json, or summary for nonnegative create, update,
delete, and read counts in a nonempty JSON object. Omitted counts are zero;
unknown keys, null counts, and non-object summaries are rejected.
The count summary is available to viewers. Write-capable project members can
open View resource changes on the deployment page to inspect Terraform
resource addresses, actions, and before/after values. Sensitive subtrees are
masked using Terraform’s sensitivity metadata; missing or malformed metadata
hides the affected subtree. Known secret release variables are scrubbed too.
Unknown values are labelled (known after apply). Configuration, variables,
and outputs are omitted from the resource review. Gated scripts and logs use
the same display rules as other deployments, including normal secret-variable
log redaction. Terraform’s JSON output can contain plaintext sensitive values;
write it to the review file rather than printing it. Both paths and an
explicit review format are required together; an empty format is rejected.
Review counts are unverified claims supplied by the deployment step. The API
reports review_source: "step_output" and review_verified: false. A separate
review file can be stale or misleading even when every checksum is valid.
Before approval, download and independently inspect the exact artifact using
trusted tools. For Terraform, run terraform show with a trusted toolchain and
providers, then compare the result with the review. Checksums bind immutable
bytes; they do not establish that the summary accurately describes those bytes.
The rotation CLI re-encrypts retained artifact chunks in the same transaction
as variables, package credentials, and verification targets. It currently skips
TOTP seeds, stored agent identity ciphertext, and remote log scrub buffers;
do not rotate instances containing those records. See the
rotation limitation.
--plaintext cannot migrate encrypted artifact gates, package credentials,
or verification targets. Eligible instances must stop the server for rotation
and install the exact CLI-generated key before restarting.
Generation and continuation scripts, container images, and credentials belong
to the existing trusted-team deployment model. Gates do not constrain a
malicious script to only plan, or prove that it applies the approved artifact.
Set network_mode: "bridge" on each step that needs network access. The
default remains none. Host networking, privileged containers, and host
mounts are not allowed. Network access can reach services accessible from
the container network, so grant it only to trusted scripts.
For Terraform, use an image containing Bash and Terraform. The generation step can run:
mkdir /tmp/terraform-context
cd /tmp/terraform-context
# Write main.tf here, including the remote backend configuration.
terraform init -input=false
terraform plan -input=false -out=tfplan
terraform show -json tfplan > review.json
cp -a /tmp/terraform-context/. "$DURPDEPLOY_STAGE_DIR/"
Configure paths tfplan and review.json. The later apply step runs:
cp -a "$DURPDEPLOY_APPROVED_DIR/." /tmp/approved-context
cd /tmp/approved-context
terraform apply -input=false "$DURPDEPLOY_APPROVED_DIR/tfplan"
Staging is noexec. Execute Terraform and provider plugins from /tmp, then
copy the generated files into staging. Gated generation and continuation steps
have 364 MiB of bounded executable scratch space; other steps have 64 MiB.
The approved directory is read-only. The copied working directory preserves
configuration, initialized backend data, modules, and provider lock files.
Terraform applies the saved plan; it must not generate a replacement plan.
Terraform rejects stale backend state. Follow the backend’s locking guidance.
Saved plans
and HTTP backend locking
describe these contracts. Review JSON may contain plaintext sensitive values;
never publish it as a log or separate public artifact.
The server pins every step image ID and release variables before generation.
Stopped container references retain those exact images through approval waits
and server restarts, including locally built images. Minute maintenance removes
the references after terminal decisions. Explicit container removal can remove
these references; image pruning alone preserves them.
It encrypts the whole staging context in authenticated database chunks.
Unlinked temporary descriptors are used during capture, restore, and download.
Approval bundles and review JSON have no application byte limits.
API and browser previews show up to 100 resources and 1 MiB of resource text.
Each value or sensitivity field uses a 64 KiB input budget and 64 nesting levels.
Addresses use a 4 KiB input budget. Each action list shows up to 16 actions.
Oversized values are omitted in full. Oversized sensitivity metadata omits the affected side.
The API reports preview_truncated, resources_omitted, and per-resource omitted_fields.
The browser shows an omission notice. Preview bounds do not change approval counts, stored context, or artifact downloads.
Download and independently inspect the exact artifact before approval.
Runtime staging capacity, scratch capacity, disk space, and memory still constrain execution.
Unsafe archive entries, missing files, and altered ciphertext or checksums fail closed.
Sparse staging files are rejected before export because tar can expand holes beyond the allocated staging space.
If capture, publication, or cleanup fails, the generation step reports failed.
Deployment logs include an Artifact approval failed: diagnostic.
Read this diagnostic in the deployment page or GET /api/v1/deployments/{id}/logs.txt.
Diagnostics do not include review contents or archive entry names.
An administrator reviews and approves the exact revision and SHA-256 in the
deployment page or API once decision_ready is true. A saved gate can have
status awaiting while its deployment is still publishing_artifact and
cleaning up containers. The decision buttons appear only after cleanup has
finished and the deployment is awaiting_artifact_approval. The panel polls
every three seconds, so no manual refresh is needed. Failed web decisions
return to deployment details with a warning and current gate state; failed
decisions do not create successful approval/rejection audit entries.
Approval expires after 24 hours. Project members with write access can download the sensitive artifact; viewers can see the count summary only. Rejection, cancellation, and expiry stop the deployment. The minute worker records expiry and advances queues; polling reads state only. Expired artifacts and decisions are blocked immediately, before that worker runs. Terminal bundle chunks are deleted after seven days. Audit records retain the decision, and gate records retain checksums, counts, times, and approver ID.
An active gated deployment reserves its project/environment pair, including while waiting. Later jobs for that pair enter its FIFO queue. Other projects can deploy to the same environment concurrently, and that project can deploy to other environments concurrently. Approval resumes the same deployment without giving up its slot; rejection, cancellation, or expiry releases the slot for the next deployment.
Gate producers must run locally and have a later continuation step in a deployment release. Gated deployments cannot use automatic retries or runbook releases. Gated deployments can include agent steps before or after local approval steps. The server pins images for local steps only.
Local steps receive approved artifacts through the read-only DURPDEPLOY_APPROVED_DIR directory.
Agent steps receive shared files through DURPDEPLOY_STAGE_DIR.
If agent delivery needs apply results, write those files to DURPDEPLOY_STAGE_DIR in the local apply step.
Restart resumes a waiting review or an approved pending continuation. A crash during execution fails the run and does not replay an uncertain apply.
API routes under /api/v1/deployments/{id}/artifact-gates:
GET /: review metadata and counts.GET /{stepIndex}/artifact: exact binary download, withCache-Control: no-store.GET /{stepIndex}/review: writer-only redacted Terraform resource changes, withreview_source: "step_output",review_verified: false, andCache-Control: no-store. The web equivalent renders the same changes on demand. Summary-format gates return an empty resource list.POST /{stepIndex}/approve:{"revision":1,"sha256":"..."}.POST /{stepIndex}/reject: the same checksum-bound body.
Step indices start at zero. Decisions require an administrator API token or an administrator session with CSRF. Duplicate or stale decisions return 409. Changing steps requires a new release and deployment; approval is never reused.