Dockerfiles
Every Dockerfile in the tree, parsed without a tool: the stages it builds, the image each one starts from and how that image is pinned, the user the image ends as, the ports it exposes, the paths it copies in and the names of the build arguments and environment variables it declares, enriched with the findings of a hadolint report when the build already left one behind.
| Facts key | docker |
| Version | v1 |
| Script | docker.py |
| Timeout | 60 seconds |
Inputs
| Input | Description | Default | Environment |
|---|---|---|---|
dockerfiles | Comma separated globs, matched against the path and the name of every Dockerfile found anywhere in the working directory, narrowing which of them are described. Discovery itself is fixed, so a glob here only ever takes files away. | Dockerfile,Dockerfile.*,*.Dockerfile | GUARDRAIL_INPUT_DOCKERFILES |
reports | Comma separated globs naming the hadolint SARIF reports to read. A report the build produced is read, never rerun, and a file that is no SARIF document is passed over. | hadolint*.sarif,hadolint*.json,*hadolint*.sarif | GUARDRAIL_INPUT_REPORTS |
maxFindings | Most lint findings to carry in the facts. lint.total stays whole when findings are dropped. | 200 | GUARDRAIL_INPUT_MAXFINDINGS |
A guardrail that declares an input of the same name passes it through, so the guardrail's configuration in buildnote.json is what decides these values.
A guardrail asks for these facts by name, and reads them back the same way:
{
"collect": ["docker"]
}docker = guardrail.facts("docker")Facts
The document docker collects. A path carrying [] is an entry of the list before it, and one carrying [path] is a key of the object before it.
| Fact | Meaning |
|---|---|
dockerfiles | Every Dockerfile that was parsed, in path order. Parsing is the collector's own, so these facts are there whether or not a linter ever ran. |
dockerfiles[].path | Path of the Dockerfile, relative to the directory the CLI runs in. |
dockerfiles[].stages | Every stage the file builds, in the order its FROM instructions declare them. |
dockerfiles[].stages[].name | Name the stage was given with AS, or null when it was given none. |
dockerfiles[].stages[].image | The FROM argument exactly as it is written, so a stage based on $BASE_IMAGE or on an earlier stage reads as it does in the file. |
dockerfiles[].stages[].registry | Registry host the image names, or null when it names none and Docker Hub is implied. |
dockerfiles[].stages[].repository | Repository within that registry, without the tag or the digest. |
dockerfiles[].stages[].tag | Tag the FROM names, or null when it names none, which Docker resolves as latest. |
dockerfiles[].stages[].digest | Digest the FROM pins the image to, or null when it pins none. |
dockerfiles[].stages[].platform | Platform given with --platform, or null when the stage builds for the host's. |
dockerfiles[].user | Argument of the last USER instruction, or null when the file sets none and the image runs as root. |
dockerfiles[].exposedPorts | Every port EXPOSE declares, as written, so 8080/tcp keeps its protocol. |
dockerfiles[].healthcheck | Whether the file declares a HEALTHCHECK. HEALTHCHECK NONE disables one, and reads as false. |
dockerfiles[].buildArgs | Names of the arguments ARG declares. Names only, never the defaults beside them, because a default can be a credential and these facts are evidence. |
dockerfiles[].envKeys | Names of the variables ENV sets. Names only, never the values beside them, for the same reason. |
dockerfiles[].copiedPaths | Every source path COPY and ADD name, without the destination they are copied to. |
dockerfiles[].instructions | How many times each instruction appears, by instruction name. |
dockerfiles[].unparsed | Which lines could not be read as an instruction, present only when a line could not be. Line numbers only, never what the line said. |
source | report when a hadolint report was read, none when there was none. The Dockerfile facts above are collected either way. |
reason | Why no findings were read, present only when source is none. |
reports | Every hadolint report that was read, in path order. |
reports[].path | Path of the report, relative to the directory the CLI runs in. |
reports[].modified | When the report was last written, ISO 8601, so a stale report is recognisable. |
reports[].format | Format it was read as, always sarif. |
reports[].producer.name | Linter that wrote it, as the report names itself, or null when it names none. |
reports[].producer.version | Version of that linter, or null when the report carries none. |
lint.findings | The findings the reports carried, up to maxFindings. |
lint.findings[].id | Rule the finding breaks, such as DL3008. |
lint.findings[].severity | critical, high, medium, low, info or unknown, as the report rated it. |
lint.findings[].message | What the linter said, truncated to 500 characters. |
lint.findings[].path | Dockerfile it was found in, or null. |
lint.findings[].line | Line it was found on, or null. |
lint.total | Findings across every report that was read, whole even when findings were dropped. |
lint.dropped | Findings left out because maxFindings was reached. |
A collector that cannot finish prints what it had along with an incomplete key saying why, so the facts below the point it stopped are absent. A check that cares reads incomplete before the rest.
Example facts
The example facts collected by docker collector:
{
"dockerfiles": [
{
"path": "Dockerfile",
"stages": [
{
"name": "build",
"image": "gradle:8.14-jdk21",
"registry": null,
"repository": "gradle",
"tag": "8.14-jdk21",
"digest": null,
"platform": null
},
{
"name": "runtime",
"image": "eclipse-temurin:21.0.3_9-jre-alpine@sha256:4f2b3c1e9a0d5c7b8e6f1a2d3c4b5a69788899aabbccddeeff00112233445566",
"registry": null,
"repository": "eclipse-temurin",
"tag": "21.0.3_9-jre-alpine",
"digest": "sha256:4f2b3c1e9a0d5c7b8e6f1a2d3c4b5a69788899aabbccddeeff00112233445566",
"platform": null
}
],
"user": "widget",
"exposedPorts": [
"8080/tcp"
],
"healthcheck": true,
"buildArgs": [
"WIDGET_VERSION"
],
"envKeys": [
"WIDGET_PORT",
"JAVA_TOOL_OPTIONS"
],
"copiedPaths": [
"settings.gradle.kts",
"build.gradle.kts",
"service",
"/home/gradle/widget/service/build/install/service"
],
"instructions": {
"FROM": 2,
"WORKDIR": 2,
"COPY": 3,
"RUN": 2,
"ARG": 1,
"ENV": 1,
"EXPOSE": 1,
"USER": 1,
"HEALTHCHECK": 1,
"ENTRYPOINT": 1
}
}
],
"source": "none",
"reason": "no hadolint report matched hadolint*.sarif, hadolint*.json, *hadolint*.sarif",
"reports": []
}Collected for
| Guardrail | Category | Inputs |
|---|---|---|
iac/dockerfile-base-pinned | iac | none |
iac/dockerfile-healthcheck | iac | none |
iac/dockerfile-lint-clean | iac | none |
iac/dockerfile-no-build-secrets | iac | none |
iac/dockerfile-nonroot-user | iac | none |