ci: add the release gates, and document the ones that do not gate

PORTAINER.md and SECURITY_REPORT.md described a pipeline that required
regressions, HIGH/CRITICAL secret, misconfiguration and image gates, and stated
that the source preflight stopped this application from publishing. None of it
ran: the workflow built and called the webhook unconditionally.

Add a blocking Trivy secret scan. Verified both ways: a planted AWS key pair,
GitHub token and private key block the job, and the repository passes clean.
Note that Trivy allowlists documented example credentials, so this gate is a
backstop, not permission to commit secrets.

The source preflight now runs on every push and always prints its verdict, but
enforces only when ENFORCE_PRODUCTION_PREFLIGHT is true. Enforcing it today
would block every deployment, because it refuses a release while the payment
and messaging adapters are fake, which is the deliberate state the stack runs
in. Set the variable when real adapters land.

Image vulnerabilities are reported after each build rather than enforced. The
current bases carry 56 HIGH and 3 CRITICAL findings, only 15 of them with an
upstream fix, so failing on them would stop releases without making anything
safer. Pinning digests and triaging the fixable ones is ROADMAP 2.6.

Both documents now carry a table of what gates and what does not, instead of
describing checks that did not exist.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Cauê Faleiros
2026-09-21 11:45:11 -03:00
parent d2f7b2c03b
commit 9da2a7dcad
3 changed files with 105 additions and 11 deletions

View File

@@ -10,10 +10,32 @@ Cloudflare R2, so MinIO is not part of this stack.
## 1. Gitea configuration
The single workflow is `.gitea/workflows/deploy.yml`. Pull requests run static
validation. A push to `main` runs the full isolated test suite, builds and scans
the production images, publishes both `latest` and the full commit SHA, then
calls Portainer.
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.
What actually gates a deployment:
| Check | Gates? |
|---|---|
| `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 |
| Trivy secret scan (HIGH/CRITICAL) | yes |
| Source preflight (`deploy/production_preflight.py --source-only`) | only when `ENFORCE_PRODUCTION_PREFLIGHT` is `true` |
| Trivy image vulnerabilities | no — reported after the build |
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 image scan is reported rather than enforced because the current bases carry
HIGH/CRITICAL findings with no upstream fix, so failing on them would stop
releases without making anything safer. Triage what is fixable and pin base
digests first; see `ROADMAP.md` 2.6.
Repository variables:
@@ -27,9 +49,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 tests and HIGH/CRITICAL secret,
misconfiguration, and image gates pass. The current local-only application
fails the source preflight intentionally, so it cannot publish yet.
The webhook is called only after the gating checks in the table 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.
## 2. One-time Portainer resources