cdso_config.yml¶
One file at the root of the application repository. The pipeline reads it on every run; the reviewer sees what it carries. It is the only file a developer edits to configure scanning and to record every justification.
Top level¶
deployment_level: "PRODUCTION" # DEVELOPMENT, STAGING, PRODUCTION
security_group: "acme" # the reviewing security group
organization: "acme"
software_name: "my-service" # filing directory in the security group's scans project
| Field | Meaning |
|---|---|
deployment_level |
Where the container will run. Changes the container spec gate: a root user passes at DEVELOPMENT and fails at PRODUCTION. |
security_group |
The security group whose reviewers assess this application. Scan output publishes to that group's security repository. |
organization |
The organization the application belongs to. With security_group and the container key, this is how Attest knows who owns the evidence. |
software_name |
The directory the scan record files under in the security repository. |
The container key¶
One block per container, keyed by the container name. It must match the name input on the review component in .gitlab-ci.yml. Where the name contains dashes, the YAML key uses underscores.
my_service:
project_type: "container" # container, tool, base
dockerfile_folder: "."
container_lifespan: "PERSISTENT" # PERSISTENT or EPHEMERAL
connection_context: "EXTERNAL" # EXTERNAL (internet facing) or INTERNAL
| Field | Meaning |
|---|---|
project_type |
container for an application, tool for a build or scan tool, base for an image others build on. |
dockerfile_folder |
Where the Dockerfile is, relative to the repository root. |
container_lifespan |
PERSISTENT for a long running service, EPHEMERAL for a job. |
connection_context |
EXTERNAL for anything internet facing, INTERNAL otherwise. Reviewers weigh reachability against it. |
Per scan blocks¶
Added under the container key once the first scan has reported. Each one is read by the pipeline and carried into the scan record verbatim.
Vulnerability mitigations¶
my_service:
mitigations:
- CVE_2025_12345: >-
Why this image is not affected, the upgrade path, and what
limits it in the meantime.
Key by the CVE id with dashes as underscores, never a GHSA id. The text is read verbatim by the reviewer. A Critical is never listed here; a High only when no fixed release exists. An entry that reads "Mitigation pending" or is empty is not ready for review.
Static analysis exclusions¶
Use the map form, not a plain list, so the reason travels into the scan record.
Credential pattern exclusions¶
Only for unverified matches. A verified live credential is never excluded; it is revoked, rotated, and removed.
Dockerfile ignores¶
An ignore silences the rule for the whole Dockerfile, not one line.
Root user¶
my_service:
container_spec:
root_user: >-
What needs root, what is done to limit it, and what would remove
the need.
Accepted only at a level where root fails and only with a reason a reviewer can check.
Dynamic scan¶
my_service:
zap:
skip_reason: >-
Why the dynamic scan does not apply, or the mitigation for each alert.
Rules the pipeline enforces¶
- The schema is validated on every run. A missing required field fails the run with the field named.
- Ownership is self declared:
organization,security_group, and the container key say who owns the evidence, and Attest shows unassigned rather than guess when a field is missing. - Access to a container's evidence in Attest is controlled by matching the signed in person's group claims against the declared organization and application.
Where Attest helps¶
The finding page for any justifiable finding shows the exact lines to add and which section they go in, and says whether the section already exists in the file. The text itself is the developer's to write.