Skip to content

Guardrails / Collectors

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 keydocker
Versionv1
Scriptdocker.py
Timeout60 seconds

Inputs ​

InputDescriptionDefaultEnvironment
dockerfilesComma 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.*,*.DockerfileGUARDRAIL_INPUT_DOCKERFILES
reportsComma 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*.sarifGUARDRAIL_INPUT_REPORTS
maxFindingsMaximum number of lint findings to carry in the facts. lint.total still includes findings that are dropped.200GUARDRAIL_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:

json
{
  "collect": ["docker"]
}
python
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.

FactMeaning
dockerfilesEvery 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[].pathPath of the Dockerfile, relative to the directory the CLI runs in.
dockerfiles[].stagesEvery stage the file builds, in the order its FROM instructions declare them.
dockerfiles[].stages[].nameName the stage was given with AS, or null when it was given none.
dockerfiles[].stages[].imageThe 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[].registryRegistry host the image names, or null when it names none and Docker Hub is implied.
dockerfiles[].stages[].repositoryRepository within that registry, without the tag or the digest.
dockerfiles[].stages[].tagTag the FROM names, or null when it names none, which Docker resolves as latest.
dockerfiles[].stages[].digestDigest the FROM pins the image to, or null when it pins none.
dockerfiles[].stages[].platformPlatform given with --platform, or null when the stage builds for the host's.
dockerfiles[].userArgument of the last USER instruction, or null when the file sets none and the image runs as root.
dockerfiles[].exposedPortsEvery port EXPOSE declares, as written, so 8080/tcp keeps its protocol.
dockerfiles[].healthcheckWhether the file declares a HEALTHCHECK. HEALTHCHECK NONE disables one, and reads as false.
dockerfiles[].buildArgsNames 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[].envKeysNames of the variables ENV sets. Names only, never the values beside them, for the same reason.
dockerfiles[].copiedPathsEvery source path COPY and ADD name, without the destination they are copied to.
dockerfiles[].instructionsHow many times each instruction appears, by instruction name.
dockerfiles[].unparsedWhich lines could not be read as an instruction, present only when a line could not be. Line numbers only, never what the line said.
sourcereport when a hadolint report was read, none when there was none. The Dockerfile facts above are collected either way.
reasonWhy no findings were read, present only when source is none.
reportsEvery hadolint report that was read, in path order.
reports[].pathPath of the report, relative to the directory the CLI runs in.
reports[].modifiedWhen the report was last written, in ISO 8601, so you can spot a stale report.
reports[].formatFormat it was read as, always sarif.
reports[].producer.nameLinter that wrote it, as the report names itself, or null when it names none.
reports[].producer.versionVersion of that linter, or null when the report carries none.
lint.findingsThe findings the reports carried, up to maxFindings.
lint.findings[].idRule the finding breaks, such as DL3008.
lint.findings[].severitycritical, high, medium, low, info or unknown, as the report rated it.
lint.findings[].messageWhat the linter said, truncated to 500 characters.
lint.findings[].pathDockerfile it was found in, exactly as the report recorded it rather than resolved by this collector, or null.
lint.findings[].lineLine it was found on, or null.
lint.totalFindings across every report that was read, whole even when findings were dropped.
lint.droppedFindings 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:

json
{
  "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 ​

GuardrailCategoryInputs
docker/base-pinneddockernone
docker/healthcheckdockernone
docker/lint-cleandockernone
docker/no-build-secretsdockernone
docker/nonroot-userdockernone

All collectors

Buildnote Limited
Registered in England and Wales, Reg: 16140412