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, plus 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 name of every Dockerfile found anywhere in the working directory, to narrow which ones are described. Discovery itself is fixed, so a glob here can only remove files, never add them. | 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 not a SARIF document is skipped. | hadolint*.sarif,hadolint*.json,*hadolint*.sarif | GUARDRAIL_INPUT_REPORTS |
maxFindings | Maximum number of lint findings to carry in the facts. lint.total still includes findings that are dropped. | 200 | GUARDRAIL_INPUT_MAXFINDINGS |
When a guardrail declares an input with the same name, it passes its value through. That means you set these values in the guardrail's configuration in buildnote.json.
A guardrail asks for these facts by name and reads them back by the same name:
{
"collect": ["docker"]
}docker = guardrail.facts("docker")Facts
These are the fields of the document docker collects. In a path, [] means each entry of the list before it, and [path] means a key of the object before it.
| Fact | Meaning |
|---|---|
dockerfiles | Every Dockerfile that was parsed, in path order. The collector does its own parsing, so these facts are present 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, in ISO 8601, so you can spot a stale report. |
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, exactly as the report recorded it rather than resolved by this collector, 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. |
If a collector can't finish, it prints what it gathered so far along with an incomplete key that says why. Facts after the point where it stopped are missing, so a check that depends on them should read incomplete first.
Example facts
Here are the facts the docker collector gathers from an example project:
{
"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 |
|---|---|---|
docker/base-pinned | docker | none |
docker/healthcheck | docker | none |
docker/lint-clean | docker | none |
docker/no-build-secrets | docker | none |
docker/nonroot-user | docker | none |