diff --git a/images/busybox/tests/main.tf b/images/busybox/tests/main.tf index 25d2af27aa..50271674cc 100644 --- a/images/busybox/tests/main.tf +++ b/images/busybox/tests/main.tf @@ -1,14 +1,26 @@ -terraform { - required_providers { - oci = { source = "chainguard-dev/oci" } - } -} - variable "digest" { description = "The image digest to run tests over." } -data "oci_exec_test" "runs" { - digest = var.digest - script = "${path.module}/runs.sh" +variable "target_repository" {} + +module "bash_sandbox" { + source = "../../../tflib/imagetest/sandboxes/bash" + target_repository = var.target_repository +} + +module "dind_test" { + source = "../../../tflib/imagetest/tests/docker-in-docker" + + images = { busybox = var.digest } + + tests = [ + { + name = "basic functionality" + image = module.bash_sandbox.image_ref + content = [{ source = path.module }] + cmd = "./test.sh" + } + ] } + diff --git a/images/busybox/tests/runs.sh b/images/busybox/tests/test.sh similarity index 71% rename from images/busybox/tests/runs.sh rename to images/busybox/tests/test.sh index 3e3db57aab..b7554eedf9 100755 --- a/images/busybox/tests/runs.sh +++ b/images/busybox/tests/test.sh @@ -2,20 +2,23 @@ set -o errexit -o nounset -o errtrace -o pipefail -x -docker run --rm $IMAGE_NAME ls >/dev/null +image=$(echo "$IMAGES" | jq -r '.busybox.ref') + +docker run --rm "$image" ls >/dev/null # The image runs as nonroot by default. -docker run --rm --entrypoint '' $IMAGE_NAME whoami | grep "^nonroot$" +docker run --rm --entrypoint '' "$image" whoami | grep "^nonroot$" # The image contains many common utilities (some in /usr/bin and some in /bin) for cmd in awk basename cat chmod chown cp cut date dirname du echo egrep expr find grep head id ln ls mkdir mktemp mv printf pwd rm rmdir sed sh sort tail tar tee test touch tr uname uniq wc xargs; do - docker run --rm $IMAGE_NAME which $cmd | grep "/bin/$cmd$" + docker run --rm "$image" which "$cmd" | grep "/bin/$cmd$" done # The image can be used as a base image. cat < /usr/local/bin/hello && \ - echo 'go version' >> /usr/local/bin/hello && \ - chmod +x /usr/local/bin/hello -ENTRYPOINT ["hello"] -EOF - -docker run --rm go-version-entrypoint | grep "go version" diff --git a/images/go/tests/base-image.sh b/images/go/tests/base-image.sh deleted file mode 100755 index c10f8f6d50..0000000000 --- a/images/go/tests/base-image.sh +++ /dev/null @@ -1,13 +0,0 @@ -#!/usr/bin/env bash - -set -o errexit -o nounset -o errtrace -o pipefail -x - -docker pull ${IMAGE_NAME} - -cat < /usr/local/bin/hello && \ + echo 'go version' >> /usr/local/bin/hello && \ + chmod +x /usr/local/bin/hello +ENTRYPOINT ["hello"] +EOF + +docker run --rm go-version-entrypoint | grep "go version" + +mkdir -p /workspace +cp -r hello /workspace/ +cd /workspace/hello +docker run --rm \ + -v $(pwd):/hello \ + -w /hello \ + "${image}" build . + diff --git a/images/gradle/main.tf b/images/gradle/main.tf index 4a569e489c..ccb9fcdc09 100644 --- a/images/gradle/main.tf +++ b/images/gradle/main.tf @@ -29,9 +29,10 @@ module "latest" { } module "test-latest" { - source = "./tests" - digest = module.latest.image_ref - java-version = "23" + source = "./tests" + digest = module.latest.image_ref + java-version = "23" + target_repository = var.target_repository } resource "oci_tag" "latest" { diff --git a/images/gradle/tests/build.sh b/images/gradle/tests/build.sh deleted file mode 100755 index eb38aa096b..0000000000 --- a/images/gradle/tests/build.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/usr/bin/env bash - -set -o errexit -o nounset -o errtrace -o pipefail -x - -docker run --rm --entrypoint "" "${IMAGE_NAME}" sh -c "gradle init --type java-application --dsl kotlin --test-framework junit-jupiter --package my.project --project-name my-project --no-split-project --incubating --java-version ${JAVA_VERSION} && gradle build" diff --git a/images/gradle/tests/main.tf b/images/gradle/tests/main.tf index 9d6b0e3a86..b3ad0a063d 100644 --- a/images/gradle/tests/main.tf +++ b/images/gradle/tests/main.tf @@ -1,9 +1,3 @@ -terraform { - required_providers { - oci = { source = "chainguard-dev/oci" } - } -} - variable "digest" { description = "The image digest to run tests over." } @@ -12,18 +6,28 @@ variable "java-version" { description = "Java version" } -data "oci_exec_test" "version" { - digest = var.digest - script = "docker run --rm $IMAGE_NAME --version" +variable "target_repository" {} + +module "bash_sandbox" { + source = "../../../tflib/imagetest/sandboxes/bash" + target_repository = var.target_repository } -data "oci_exec_test" "build" { - digest = var.digest - script = "${path.module}/build.sh" - env = [ +module "dind_test" { + source = "../../../tflib/imagetest/tests/docker-in-docker" + + images = { gradle = var.digest } + + tests = [ { - name = "JAVA_VERSION" - value = var.java-version + name = "smoke test" + image = module.bash_sandbox.image_ref + content = [{ source = path.module }] + cmd = "./test.sh" + envs = { + JAVA_VERSION = var.java-version + } } ] } + diff --git a/images/gradle/tests/test.sh b/images/gradle/tests/test.sh new file mode 100644 index 0000000000..0b3854b240 --- /dev/null +++ b/images/gradle/tests/test.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env bash + +set -o errexit -o nounset -o errtrace -o pipefail -x + +image=$(echo "$IMAGES" | jq -r '.gradle.ref') + +docker run --rm --entrypoint "" "$image" sh -c "gradle init --type java-application --dsl kotlin --test-framework junit-jupiter --package my.project --project-name my-project --no-split-project --incubating --java-version ${JAVA_VERSION} && gradle build" diff --git a/images/grype/config/main.tf b/images/grype/config/main.tf index 7265406d04..fa9a9b3940 100644 --- a/images/grype/config/main.tf +++ b/images/grype/config/main.tf @@ -17,5 +17,13 @@ output "config" { command = "/usr/bin/grype" } cmd = "help" + paths = [{ + path = "/var/lib/grype" + type = "directory" + uid = module.accts.block.run-as + gid = module.accts.block.run-as + permissions = 511 // 0o777 (HCL explicitly does not support octal literals) + }] }) -} \ No newline at end of file +} + diff --git a/images/grype/main.tf b/images/grype/main.tf index 982119fc0b..81882b78cd 100644 --- a/images/grype/main.tf +++ b/images/grype/main.tf @@ -19,8 +19,9 @@ module "latest" { } module "test-latest" { - source = "./tests" - digest = module.latest.image_ref + source = "./tests" + digest = module.latest.image_ref + target_repository = var.target_repository } resource "oci_tag" "latest" { @@ -33,4 +34,5 @@ resource "oci_tag" "latest-dev" { depends_on = [module.test-latest] digest_ref = module.latest.dev_ref tag = "latest-dev" -} \ No newline at end of file +} + diff --git a/images/grype/tests/main.tf b/images/grype/tests/main.tf index 34963a1f7c..f94d5450d2 100644 --- a/images/grype/tests/main.tf +++ b/images/grype/tests/main.tf @@ -8,7 +8,24 @@ variable "digest" { description = "The image digest to run tests over." } -data "oci_exec_test" "version" { - digest = var.digest - script = "docker run --rm $IMAGE_NAME help" -} \ No newline at end of file +variable "target_repository" {} + +module "bash_sandbox" { + source = "../../../tflib/imagetest/sandboxes/bash" + target_repository = var.target_repository +} + +module "dind_test" { + source = "../../../tflib/imagetest/tests/docker-in-docker" + + images = { grype = var.digest } + + tests = [ + { + name = "smoke" + image = module.bash_sandbox.image_ref + content = [{ source = path.module }] + cmd = "./smoke.sh" + } + ] +} diff --git a/images/grype/tests/smoke.sh b/images/grype/tests/smoke.sh new file mode 100644 index 0000000000..5855118841 --- /dev/null +++ b/images/grype/tests/smoke.sh @@ -0,0 +1,25 @@ +#!/usr/bin/env bash + +set -o errexit -o nounset -o errtrace -o pipefail + +image=$(echo "$IMAGES" | jq -r '.grype.ref') + +# Test help command works +docker run --rm "${image}" help + +# Test version command works +docker run --rm "${image}" version + +# Test db status and update +docker run --rm "${image}" db update + +# Test scanning various images +# Use a known minimal image +docker run --rm "${image}" cgr.dev/chainguard/static:latest + +# Test scanning with different output formats +docker run --rm "${image}" cgr.dev/chainguard/static:latest -o table +docker run --rm "${image}" cgr.dev/chainguard/static:latest -o json + +# Test scanning with specific severity threshold +docker run --rm "${image}" cgr.dev/chainguard/static:latest --fail-on high diff --git a/images/rust/main.tf b/images/rust/main.tf index fd77dc9689..5d03406e8f 100644 --- a/images/rust/main.tf +++ b/images/rust/main.tf @@ -27,16 +27,18 @@ module "versioned" { } module "test-versioned" { - digest = module.versioned[each.key].image_ref - for_each = module.versions.versions - source = "./tests" + digest = module.versioned[each.key].image_ref + for_each = module.versions.versions + source = "./tests" + target_repository = var.target_repository } module "test-versioned-dev" { - check-dev = true - digest = module.versioned[each.key].dev_ref - for_each = module.versions.versions - source = "./tests" + check-dev = true + digest = module.versioned[each.key].dev_ref + for_each = module.versions.versions + source = "./tests" + target_repository = var.target_repository } module "tagger" { diff --git a/images/rust/tests/main.tf b/images/rust/tests/main.tf index 3d941fa195..112ef21d11 100644 --- a/images/rust/tests/main.tf +++ b/images/rust/tests/main.tf @@ -1,6 +1,6 @@ terraform { required_providers { - oci = { source = "chainguard-dev/oci" } + imagetest = { source = "chainguard-dev/imagetest" } } } @@ -13,14 +13,24 @@ variable "check-dev" { description = "Whether to check for dev extensions" } -data "oci_exec_test" "version" { - digest = var.digest - script = "docker run --rm $IMAGE_NAME --version" +variable "target_repository" { } -data "oci_exec_test" "dev" { - count = var.check-dev ? 1 : 0 - digest = var.digest - script = "docker run --rm --entrypoint rustup $IMAGE_NAME --version" +module "bash_sandbox" { + source = "../../../tflib/imagetest/sandboxes/bash" + target_repository = var.target_repository +} + +module "dind_test" { + images = { rust = var.digest } + source = "../../../tflib/imagetest/tests/docker-in-docker" + tests = [ + { + name = "smoke" + image = module.bash_sandbox.image_ref + content = [{ source = path.module }] + cmd = "./smoke.sh" + } + ] } diff --git a/images/rust/tests/smoke.sh b/images/rust/tests/smoke.sh new file mode 100755 index 0000000000..727c1d3805 --- /dev/null +++ b/images/rust/tests/smoke.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env bash + +set -o errexit -o nounset -o errtrace -o pipefail -x + +image=$(echo "$IMAGES" | jq -r '.rust.ref') + +docker run --rm "${image}" --version + +if docker run --rm --entrypoint sh "${image}" -c 'command -v rustup'; then + docker run --rm --entrypoint rustup "${image}" --version +fi diff --git a/images/wordpress/main.tf b/images/wordpress/main.tf index 6a82a8d48c..3cf5fc63b3 100644 --- a/images/wordpress/main.tf +++ b/images/wordpress/main.tf @@ -24,13 +24,15 @@ module "latest-dev" { } module "test-latest" { - digest = module.latest.image_ref - source = "./tests" + digest = module.latest.image_ref + source = "./tests" + target_repository = var.target_repository } module "test-latest-dev" { - digest = module.latest-dev.image_ref - source = "./tests" + digest = module.latest-dev.image_ref + source = "./tests" + target_repository = var.target_repository } module "tagger" { diff --git a/images/wordpress/tests/main.tf b/images/wordpress/tests/main.tf index f1d7c86db0..204ac1aa68 100644 --- a/images/wordpress/tests/main.tf +++ b/images/wordpress/tests/main.tf @@ -1,49 +1,25 @@ -terraform { - required_providers { - imagetest = { source = "chainguard-dev/imagetest" } - oci = { source = "chainguard-dev/oci" } - } -} - variable "digest" { description = "The image digest to run tests over." } -data "imagetest_inventory" "inventory" { -} - -resource "random_id" "id" { - byte_length = 4 +variable "target_repository" { } -resource "imagetest_harness_docker" "docker" { - envs = { - IMAGE_NAME : var.digest - WP_CONTAINER_NAME : "wordpress-${random_id.id.hex}" - } - inventory = data.imagetest_inventory.inventory - name = "docker-wordpress" +module "bash_sandbox" { + source = "../../../tflib/imagetest/sandboxes/bash" + target_repository = var.target_repository } -resource "imagetest_feature" "wordpress-basic" { - harness = imagetest_harness_docker.docker - name = "docker-test-wordpress" - steps = [{ - name = "Start up WordPress container" - cmd = <&1 | grep -q "ready to handle connections" -EOT - retry = { attempts = 15, delay = "30s" } - }, { - name = "stop container" - cmd = <&1 | grep -q "ready to handle connections"; then + echo "WordPress is ready!" + break + fi + + echo "Attempt $attempt failed. Retrying in $delay seconds..." + sleep $delay + attempt=$((attempt + 1)) + + if [ $attempt -gt $max_attempts ]; then + echo "Failed after $max_attempts attempts" + exit 1 + fi +done diff --git a/tflib/imagetest/tests/docker-in-docker/main.tf b/tflib/imagetest/tests/docker-in-docker/main.tf index a26f7ddeb5..8b67a7ee2d 100644 --- a/tflib/imagetest/tests/docker-in-docker/main.tf +++ b/tflib/imagetest/tests/docker-in-docker/main.tf @@ -14,10 +14,9 @@ variable "images" { type = map(string) } -# TODO: We can remove this if we ever make docker-dind public variable "dind_image" { description = "The dind image to use." - default = "cgr.dev/chainguard-private/docker-dind:latest" + default = "cgr.dev/chainguard/docker-dind:latest" } variable "tests" { diff --git a/tflib/imagetest/tests/k3s-in-docker/main.tf b/tflib/imagetest/tests/k3s-in-docker/main.tf new file mode 100644 index 0000000000..47fba485ae --- /dev/null +++ b/tflib/imagetest/tests/k3s-in-docker/main.tf @@ -0,0 +1,41 @@ +terraform { + required_providers { + imagetest = { source = "chainguard-dev/imagetest" } + } +} + +variable "name" { + description = "The name of the test." + default = null +} + +variable "images" { + description = "The map of images to test." + type = map(string) +} + +variable "tests" { + description = "The list of tests to run with the docker in docker driver." + type = list(object({ + name = string + image = string + cmd = string + content = list(object({ + source = string + })) + envs = optional(map(string), null) + })) +} + +resource "imagetest_tests" "k3sindocker" { + name = var.name + driver = "k3s_in_docker" + + drivers = { + k3s_in_docker = {} + } + + images = var.images + + tests = var.tests +}