feat(security): enforce scan policies as a pre-deploy gate (#719)

Policies with block_on_deploy=1 now scan every stack image before
docker compose up runs and reject the deploy with HTTP 409 on violation.
The UI opens a dialog listing offending images; admins can override per
deploy with ?ignorePolicy=true, and every bypass is recorded in the
audit log with the originating route, actor, policy, and image list.

When Trivy is not installed on the target node the gate fails open with
a warning notification, so teams are never locked out by tooling state.
Post-deploy and scheduled scans still evaluate matching policies and
dispatch warnings on violations to surface drift on long-running stacks.

Public API additions: policy and suppression CRUD under /api/security,
plus the documented 409 block-response shape on all deploy paths.
This commit is contained in:
Anso
2026-04-21 00:14:11 -04:00
committed by GitHub
parent aa10db1d09
commit 661b9c638b
17 changed files with 1772 additions and 44 deletions
+47 -2
View File
@@ -129,7 +129,9 @@ Failures are typically transient (registry timeouts, missing credentials) and do
Scan policies require a **Skipper** or **Admiral** license.
</Note>
Policies let you define severity thresholds that the post-deploy scanner evaluates against. When a deploy's scan exceeds a policy's threshold, Sencho dispatches an alert. The policy's **Block on deploy** toggle controls the alert severity: warning when off, critical when on.
Policies let you define severity thresholds that govern whether a stack can deploy at all. A policy with **Block on deploy** enabled runs a pre-flight scan on every image in the stack before `docker compose up` executes; if any image meets or exceeds the threshold, the deploy is rejected with a dialog listing the offending images. Policies with **Block on deploy** disabled still evaluate every post-deploy and scheduled scan, and dispatch warning alerts when the threshold is exceeded.
See [Deploy Enforcement](/features/deploy-enforcement) for the full pre-flight flow, admin bypass path, and audit-log behavior.
<Frame>
<img src="/images/vulnerability-scanning/security-settings.png" alt="Security section of Settings showing the scan policies list with add policy button" />
@@ -144,7 +146,7 @@ Go to **Settings → Security** and click **Add Policy**.
| **Name** | A descriptive label (e.g. "Production critical block"). |
| **Stack pattern** | Optional glob against stack names (e.g. `prod-*`). Leave empty to match every stack. |
| **Max severity** | The threshold. If a scan finds any vulnerability at or above this severity, the policy fires. |
| **Block on deploy** | When enabled, policy violations are dispatched as critical (error) alerts. When disabled, they are dispatched as warnings. |
| **Block on deploy** | When enabled, deploys are rejected before `docker compose up` runs if any image violates the threshold. When disabled, the policy still evaluates post-deploy and scheduled scans and dispatches warning alerts on violations. |
| **Enabled** | Disabled policies are skipped during evaluation. |
### Policy scoping
@@ -157,6 +159,41 @@ When multiple policies match a deploy, Sencho picks the most specific one:
Only one policy is evaluated per deploy; use a single tight pattern rather than overlapping policies for clarity.
### Example policies
**Block criticals and highs in production.** A tight gate that keeps known vulnerable base images out of your production fleet.
- **Name:** `prod-high-gate`
- **Stack pattern:** `prod-*`
- **Max severity:** `HIGH`
- **Block on deploy:** On
- **Enabled:** On
**Alert on criticals in staging, never block.** Lets engineers iterate without friction while still surfacing critical findings for triage.
- **Name:** `staging-critical-alert`
- **Stack pattern:** `staging-*`
- **Max severity:** `CRITICAL`
- **Block on deploy:** Off
- **Enabled:** On
### Creating a policy via the API
Policy CRUD endpoints are documented in the [Security API reference](/api-reference/security). A typical create call from CI looks like this:
```bash
curl -X POST https://your-sencho-instance:3000/api/security/policies \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "prod-high-gate",
"stack_pattern": "prod-*",
"max_severity": "HIGH",
"block_on_deploy": 1,
"enabled": 1
}'
```
## SBOM generation
<Note>
@@ -312,6 +349,14 @@ Enable **Developer Mode** under **Settings → Developer** and trigger the faili
When a post-deploy scan fails for a specific image (for example because Trivy could not resolve a private registry pull), Sencho dispatches a warning-level alert through your configured notification channels. The deploy itself is never blocked by a scan failure.
### A deploy was blocked by a policy I did not expect
The block dialog names the policy that fired and lists every image that violated the threshold. Open **Settings → Security → Scan Policies** and review the matching policy: check the stack pattern glob and the max severity. If the policy should not apply, tighten the pattern (for example `staging-*` instead of `*`) or turn **Block on deploy** off to keep the evaluation in alert-only mode. Admins can also bypass a single deploy with the **Deploy anyway** button; every bypass is recorded in the [Audit Log](/features/audit-log) with the actor, policy, and violation list.
### Trivy is not installed and a deploy with a block policy went through
Sencho fails open when Trivy is not installed on the target node, so users are never locked out by tooling state. A warning alert is dispatched through your configured notification channels with the message `Pre-deploy scan for "<stack>" skipped: Trivy not installed on this node`. Install Trivy from **Settings → Security** to enforce the policy; see [Installing Trivy](/operations/trivy-setup) for options.
### Compare button is disabled
Scan comparison is a Skipper feature; on Community, the Compare button stays disabled with a tooltip explaining the upgrade path. If your license is Skipper or Admiral, make sure you have ticked exactly two completed scans: selecting zero, one, or three scans leaves the button disabled. If you have only one scan for an image, trigger a second scan from the Resources Hub (or wait for a scheduled scan), then return to the Scan history page and tick both.