Share feedback
Answers are generated based on the documentation.

Test build policies

The docker buildx policy test command runs unit tests for build policies using OPA's standard test framework.

$ docker buildx policy test <path>

This validates policy logic with mocked inputs.

For testing against real sources (actual image metadata, Git repositories), use docker buildx policy eval instead. You can use the eval --print option to resolve input for a specific source for writing a test case.

Basic example

Start with a simple policy that only allows alpine images:

Dockerfile.rego
package docker

default allow = false

allow if {
    input.image.repo == "alpine"
}

decision := {"allow": allow}

Create a test file with the *_test.rego suffix. Test functions must start with test_:

Dockerfile_test.rego
package docker

test_alpine_allowed if {
    decision.allow with input as {"image": {"repo": "alpine"}}
}

test_ubuntu_denied if {
    not decision.allow with input as {"image": {"repo": "ubuntu"}}
}

Run the tests:

$ docker buildx policy test .
test_alpine_allowed: PASS (allow=true)
test_ubuntu_denied: PASS (allow=false)

PASS indicates that the tests defined in Dockerfile_test.rego executed successfully and all assertions were satisfied.

Command options

Filter tests by name with --run:

$ docker buildx policy test --run alpine .
test_alpine_allowed: PASS (allow=true)

Test policies with non-default filenames using --filename:

$ docker buildx policy test --filename app.Dockerfile .

This loads app.Dockerfile.rego and runs *_test.rego files against it.

Test output

Passed tests show the allow status and any deny messages:

test_alpine_allowed: PASS (allow=true)
test_ubuntu_denied: PASS (allow=false, deny_msg=only alpine images are allowed)

Failed tests show input, decision output, and missing fields:

test_invalid: FAIL (allow=false)
input:
  {
    "image": {}
  }
decision:
  {
    "allow": false,
    "deny_msg": [
      "only alpine images are allowed"
    ]
  }
missing_input: input.image.repo

Test deny messages

To test custom error messages, capture the full decision result and assert on the deny_msg field.

For a policy with deny messages:

Dockerfile.rego
package docker

default allow = false

allow if {
    input.image.repo == "alpine"
}

deny_msg contains msg if {
    not allow
    msg := "only alpine images are allowed"
}

decision := {"allow": allow, "deny_msg": deny_msg}

Test the deny message:

Dockerfile_test.rego
test_deny_message if {
    result := decision with input as {"image": {"repo": "ubuntu"}}
    not result.allow
    "only alpine images are allowed" in result.deny_msg
}

Test patterns

Test environment-specific rules:

test_production_requires_digest if {
    decision.allow with input as {
        "env": {"target": "production"},
        "image": {"isCanonical": true}
    }
}

test_development_allows_tags if {
    decision.allow with input as {
        "env": {"target": "development"},
        "image": {"isCanonical": false}
    }
}

Test multiple registries:

test_dockerhub_allowed if {
    decision.allow with input as {
        "image": {
            "ref": "docker.io/library/alpine",
            "host": "docker.io",
            "repo": "alpine"
        }
    }
}

test_ghcr_allowed if {
    decision.allow with input as {
        "image": {
            "ref": "ghcr.io/myorg/myapp",
            "host": "ghcr.io",
            "repo": "myorg/myapp"
        }
    }
}

For available input fields, see the Input reference.

Organize test files

The test runner discovers all *_test.rego files recursively:

build-policies/
├── Dockerfile.rego
├── Dockerfile_test.rego
└── tests/
    ├── registries_test.rego
    ├── signatures_test.rego
    └── environments_test.rego

Run all tests:

$ docker buildx policy test .

Or test specific files:

$ docker buildx policy test tests/registries_test.rego