Decisões e armadilhas
As escolhas que parecem estranhas na primeira leitura, e o motivo de cada uma. Esta seção é a que mais
@@ -1416,11 +2154,123 @@
Duas pegadinhas menores
GitLab não permite que um input omita uma palavra-chave, e lista vazia é como se diz “qualquer
runner”. Pipelines aceitam; apenas o schema JSON do editor do GitLab reclama.
+
+
+
+
Decisions and traps
+
+ The choices that look strange on a first read, and the reason behind each. This is the section that
+ saves the most time when something goes wrong.
+
+
+
The precedence rule — why default: "" everywhere
+
+
input > CI variable / job env > image default
+
+
+ An empty input is never forwarded. That lets a project set
+ TRIVY_SEVERITY once as a global variable and leave the input blank in every job, instead
+ of repeating it. Set both and the input wins.
+
+
+ If an empty input were forwarded, it would overwrite the global variable with an empty string and
+ break that pattern. It is the difference between undefined and "" — and the
+ project handles it explicitly on both platforms, with add_env() in bash and
+ ark_apply_inputs in the templates.
+
+
+
The Trivy cache, and the separate save step
+
+ Trivy's CVE database is large. Downloading it on every build is the slowest part of a scan and the
+ easiest way to hit a registry rate limit. Both platforms cache it, with different strategies: GitLab
+ points TRIVY_CACHE_DIR at .cache/trivy inside the project and uses a fixed
+ key shared by every branch; GitHub uses actions/cache with one entry per day per scanner
+ version, falling back to the previous day — so Trivy refreshes an existing database instead
+ of fetching a whole one.
+
+
+
+
The subtlety that explains the extra step
+
+ On GitHub, the normal actions/cache saves in a post step, and post steps
+ are skipped when an earlier step failed. But this Action fails by design when it
+ finds a vulnerability. Without the separate save step, only repositories that find nothing would
+ ever populate the cache — precisely the ones that need it least.
+
+
+
+
+ An operational detail for self-hosted GitLab instances: by default the runner cache lives on the
+ runner's own disk. With several runners, a job only hits the cache if it lands on the runner that
+ wrote it. Configuring distributed caching (S3 or equivalent) in config.toml is
+ what makes the hit rate consistent.
+
+
+
entrypoint: [""] in every GitLab template
+
+ The image has an entrypoint that execs ark-tools directly. GitLab Runner keeps the image
+ entrypoint and attaches a shell to it. Without clearing it, the job dies before the script runs.
+
+
+
GIT_DEPTH: "0" / fetch-depth: 0
+
+ By default CI does a shallow clone (only the last commit) because it is faster. But
+ Betterleaks looks for secrets in the history — and the classic case is exactly the
+ key that was committed and “removed” afterwards.
+
+
+
+
Silent failure
+
+ With a shallow clone, Betterleaks sees almost nothing and does not complain. The
+ job passes green and you believe you are protected. That is why every template and every example
+ forces full depth.
+
+
+
+
docker-socket: "true" hands over root on the runner
+
+ Mounting /var/run/docker.sock gives the container full control of the host's Docker
+ daemon — it can start a privileged container and read the whole machine. It is off by default. It is
+ only needed to scan an image built in the same job; an image already pushed to a registry
+ does not need it. On a shared self-hosted runner, the recommendation is to push to the registry and
+ scan from there.
+
+
+
Reports can contain the secrets they found
+
+ Two settings turn an artifact into a disclosure: betterleaks_redact: "0" writes detected
+ secrets in cleartext, and adding secret to trivy_scanners puts Trivy's
+ findings in the report. Artifacts are downloadable by anyone with read access to the repository. The
+ default is 100% redaction, and the log prints only rule, file, line and short commit — never the
+ secret.
+
+
+
File ownership on the GitHub runner
+
+ The image runs as uid 1000, which is not the runner user. The script creates the reports directory
+ with broad permissions during the scan, hands ownership back at the end and tightens the permissions
+ again; the workspace is declared a git safe directory through environment variables. On an
+ ephemeral runner this is immaterial; on a self-hosted one with concurrent jobs there is a short
+ window in which another job could write there.
+
+
+
Two smaller gotchas
+
+ dockerfile-lint handles one file per job. For several, use
+ full-scan with dockerfiles: "a,b,c", or include the template once per
+ file with a different job_name.
+ - The empty default of
tags renders as tags: []. GitLab
+ has no way for an input to omit a keyword, and an empty list is how you say “any runner”.
+ Pipelines accept it; only GitLab's editor JSON schema objects.
+
+