ci: require manual gated releases from main
All checks were successful
Build and deploy / Validate source (push) Successful in 1m28s
Build and deploy / Integration suite on a real stack (push) Successful in 4m3s
Build and deploy / Secret scan and release gate (push) Successful in 11s
Build and deploy / Publish images and notify Portainer (push) Has been skipped

This commit is contained in:
Cauê Faleiros
2026-09-23 11:27:18 -03:00
parent 24013458c9
commit cfcbe545f1
9 changed files with 137 additions and 93 deletions

View File

@@ -17,8 +17,9 @@ Cloudflare R2, so MinIO is not part of this stack.
The single workflow is `.gitea/workflows/deploy.yml`. Every push and pull request
runs static validation, the integration suite against a real stack, and a secret
scan. A push to `main` then builds the production images, publishes both `latest`
and the full commit SHA, reports their vulnerabilities, and calls Portainer.
scan. A push to `main` does not publish or deploy. A manual workflow run on
`main` repeats those checks, builds and scans the images, then publishes both
`latest` and the full commit SHA and calls Portainer.
What actually gates a deployment:
@@ -26,17 +27,19 @@ What actually gates a deployment:
|---|---|
| `py_compile` and the unit tests | yes |
| Integration suite on a live stack (smoke, workflow, security, scanning, retention, runtime) | yes |
| Browser suites | only when the runner has Chrome; otherwise warns and continues |
| Browser suites | yes; Chrome runs in the Compose test container |
| Trivy secret scan (HIGH/CRITICAL) | yes |
| Source preflight (`deploy/production_preflight.py --source-only`) | only when `ENFORCE_PRODUCTION_PREFLIGHT` is `true` |
| Source preflight (`deploy/production_preflight.py --source-only`) | yes for manual release; advisory on pushes unless `ENFORCE_PRODUCTION_PREFLIGHT` is `true` |
| Trivy image vulnerabilities, CRITICAL | yes |
| Trivy image vulnerabilities, HIGH | no — reported after the build |
| Trivy image vulnerabilities, HIGH | no — reported before publication |
| Configured Portainer webhook | yes for manual release |
The source preflight is advisory by default because it refuses a release while
the payment and messaging adapters are fake, which is the deliberate state the
stack runs in today. Enforcing it now would block every deployment. Set the
repository variable `ENFORCE_PRODUCTION_PREFLIGHT` to `true` once real adapters
land, and it becomes a hard gate.
The source preflight refuses a release while the payment and messaging adapters
are fake. It remains advisory on push checks so development can continue, but a
manual release is blocked until those adapters are replaced. Set the repository
variable `ENFORCE_PRODUCTION_PREFLIGHT` to `true` when all pushes should also
fail on those blockers. Before a manual release, run the full configuration
preflight below against the actual Portainer values; CI checks source only.
CRITICAL image findings block. Both images carry none: the bases are pinned by
digest, both Dockerfiles upgrade their OS packages, and the web image moved off
@@ -60,10 +63,10 @@ Repository secrets:
- `REGISTRY_USERNAME` and `REGISTRY_TOKEN` — package write credentials.
- `PORTAINER_WEBHOOK` — webhook generated by the `dtf-cloud` Portainer stack.
The webhook is called only after the gating checks in the table above pass.
The webhook is called only after the release gates above pass.
`ENFORCE_PRODUCTION_PREFLIGHT` and `TRIVY_IMAGE` are optional repository
variables; without them the preflight is advisory and a pinned default scanner
image is used.
variables; the former affects push checks and the latter defaults to a pinned
scanner image.
## 2. One-time Portainer resources
@@ -124,10 +127,13 @@ The `db-init` service completing and stopping is expected. The other six
services must be healthy. A failed `db-init` task or an unhealthy service blocks
acceptance.
## 4. Normal deployment
## 4. Manual deployment
Push to `main`. Gitea validates, tests, scans, publishes these images, and calls
the webhook:
Push the reviewed commit to `main` and wait for its validation workflow to pass.
After validating the actual Portainer configuration with the full preflight in
section 3, use Gitea Actions to manually run **Build and deploy** on `main` at
that commit. The workflow repeats validation, tests and scans, then publishes
these images and calls the webhook:
```text
gitea.blyzer.com.br/blyzer/dtf-api:latest

View File

@@ -14,6 +14,9 @@ kept through the approved order; 4.6 now pages pending and approved unpaid
quotes, including a tested 101st pending quote. Operational entrypoints in
5.12 are repaired and locally exercised. Image decoding, mixed-sheet grading,
rotation-sensitive DPI, and PDF page geometry are corrected in 3.9/4.4.
`main` pushes now validate without publishing; manual release requires a passing
source preflight. The containerized browser gate passes locally, pending a Gitea
runner run.
Next address the upload/scanner safety gate and unsupported PDF image evidence.
The customer/API upload admission now stops above the scanner's effective limit
before transfer; the 5 GiB large-file product path still needs agreement and
@@ -598,14 +601,9 @@ print-file evidence still need correction before this item can close.
integration job should run `down -v` before `up` — or a dedicated step should
apply `schema.sql` twice to a fresh database, proving both a first install and
a re-run.
- `[ ]` 5.10 — The browser suites do not run in CI. Chrome runs in the runner
container and can only reach the stack through ports published on the host, which
is a different network namespace when the runner is itself a container. The API,
workflow, security, scanning, retention and runtime suites were moved inside the
stack's network and do gate. The browser suites are the only coverage for the
artwork editor and the full customer journey, so they need either Chrome in a
container on that network, or a runner with host networking. Until then they gate
locally only, and CI warns when it skips them.
- `[ ]` 5.10 — The browser suites were moved into a Chrome container on the
Compose network and made required in CI. Confirm the complete checkout journey
passes in that topology and on the actual Gitea runner before closing this item.
- `[ ]` 5.9 — `local/browser_test.mjs` failed once and passed on an immediate
re-run, with no code change in between (2026-09-21). It is a deploy gate when the
runner has Chrome, so an intermittent failure there blocks releases for no reason.
@@ -627,10 +625,12 @@ print-file evidence still need correction before this item can close.
- `[ ]` 5.13 — Define production recovery: scheduled encrypted offsite database
and object backups, a consistent snapshot boundary, Swarm data placement and
a restore rehearsal that opens every required live order file.
- `[ ]` 5.14 — Promote and verify one immutable release. Scan before publishing
mutable tags, make the source preflight validate the active stack, require the
browser tests to run, test clean install and upgrade, and check application
readiness after Portainer redeploys. Isolate concurrent CI stacks.
- `[ ]` 5.14 — Promote and verify one immutable release. Normal `main` pushes
now run checks only; manual dispatch requires source preflight and a configured
webhook, and scans images before publishing. Still make the full preflight
validate the active stack, deploy the tested immutable image references, test
clean install and upgrade, check application readiness after Portainer
redeploys, and isolate concurrent CI stacks.
---

View File

@@ -132,15 +132,12 @@ change when the advisory database or selected base digest changes.
The files in `deploy/` and `.gitea/workflows/` are a guarded delivery mechanism,
not an approval to operate the current application on the public internet.
Corrected 2026-09-21: an earlier version of this section described gates the
workflow did not contain. The workflow now runs static validation, the
integration suite against a live stack, and a blocking Trivy secret scan before
publishing. The source preflight is advisory unless
`ENFORCE_PRODUCTION_PREFLIGHT` is set, and image vulnerabilities are reported
rather than enforced, because the current bases carry HIGH/CRITICAL findings
with no upstream fix. Base images are still mutable tags, not digests.
`PORTAINER.md` holds the authoritative table of what gates and what does not.
It publishes both `latest` and the full commit SHA, then calls the Portainer
Updated 2026-09-23: pushes to `main` run checks only. A manual workflow run on
`main` requires the source preflight and a configured Portainer webhook before
building. It scans built images before publication; CRITICAL findings block and
HIGH findings are reported. The browser suites run in a required Compose Chrome
container. `PORTAINER.md` holds the authoritative gate table. A permitted release
publishes both `latest` and the full commit SHA, then calls the Portainer
webhook. Application/provider secrets are created directly as versioned external
Swarm secrets and never cross the workflow. Rollback selects the prior commit SHA
in Portainer and does not roll back the database.