diff --git a/go.mod b/go.mod index a32fc6b3..f1e5338c 100644 --- a/go.mod +++ b/go.mod @@ -29,7 +29,7 @@ require ( github.com/fsnotify/fsnotify v1.9.0 github.com/go-ldap/ldap/v3 v3.4.12 github.com/go-redis/redismock/v9 v9.2.0 - github.com/go-redsync/redsync/v4 v4.13.0 + github.com/go-redsync/redsync/v4 v4.14.0 github.com/go-viper/mapstructure/v2 v2.4.0 github.com/gofrs/uuid v4.4.0+incompatible github.com/golang-jwt/jwt/v5 v5.3.0 diff --git a/go.sum b/go.sum index 8bbc393c..d9278b9c 100644 --- a/go.sum +++ b/go.sum @@ -1247,8 +1247,8 @@ github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo= github.com/go-redis/redismock/v9 v9.2.0 h1:ZrMYQeKPECZPjOj5u9eyOjg8Nnb0BS9lkVIZ6IpsKLw= github.com/go-redis/redismock/v9 v9.2.0/go.mod h1:18KHfGDK4Y6c2R0H38EUGWAdc7ZQS9gfYxc94k7rWT0= -github.com/go-redsync/redsync/v4 v4.13.0 h1:49X6GJfnbLGaIpBBREM/zA4uIMDXKAh1NDkvQ1EkZKA= -github.com/go-redsync/redsync/v4 v4.13.0/go.mod h1:HMW4Q224GZQz6x1Xc7040Yfgacukdzu7ifTDAKiyErQ= +github.com/go-redsync/redsync/v4 v4.14.0 h1:zyxzFJsmQHIPBl8iBT7KFKohWsjsghgGLiP8TnFMLNc= +github.com/go-redsync/redsync/v4 v4.14.0/go.mod h1:twMlVd19upZ/juvJyJGlQOSQxor1oeHtjs62l4pRFzo= github.com/go-rod/rod v0.116.2 h1:A5t2Ky2A+5eD/ZJQr1EfsQSe5rms5Xof/qj296e+ZqA= github.com/go-rod/rod v0.116.2/go.mod h1:H+CMO9SCNc2TJ2WfrG+pKhITz57uGNYU43qYHh438Mg= github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg= @@ -1883,8 +1883,10 @@ github.com/redis/go-redis/extra/redisotel/v9 v9.0.5 h1:EfpWLLCyXw8PSM2/XNJLjI3Pb github.com/redis/go-redis/extra/redisotel/v9 v9.0.5/go.mod h1:WZjPDy7VNzn77AAfnAfVjZNvfJTYfPetfZk5yoSTLaQ= github.com/redis/go-redis/v9 v9.14.0 h1:u4tNCjXOyzfgeLN+vAZaW1xUooqWDqVEsZN0U01jfAE= github.com/redis/go-redis/v9 v9.14.0/go.mod h1:huWgSWd8mW6+m0VPhJjSSQ+d6Nh1VICQ6Q5lHuCH/Iw= -github.com/redis/rueidis v1.0.19 h1:s65oWtotzlIFN8eMPhyYwxlwLR1lUdhza2KtWprKYSo= -github.com/redis/rueidis v1.0.19/go.mod h1:8B+r5wdnjwK3lTFml5VtxjzGOQAC+5UmujoD12pDrEo= +github.com/redis/rueidis v1.0.64 h1:XqgbueDuNV3qFdVdQwAHJl1uNt90zUuAJuzqjH4cw6Y= +github.com/redis/rueidis v1.0.64/go.mod h1:Lkhr2QTgcoYBhxARU7kJRO8SyVlgUuEkcJO1Y8MCluA= +github.com/redis/rueidis/rueidiscompat v1.0.64 h1:M8JbLP4LyHQhBLBRsUQIzui8/LyTtdESNIMVveqm4RY= +github.com/redis/rueidis/rueidiscompat v1.0.64/go.mod h1:8pJVPhEjpw0izZFSxYwDziUiEYEkEklTSw/nZzga61M= github.com/regclient/regclient v0.9.2 h1:5mJYY3NSV7xtBCv+Me3mbfcNJg9u7nrNt/Z6Od7QjVM= github.com/regclient/regclient v0.9.2/go.mod h1:QOi29pa84xH+AA56bQwQbzw3RZDwqHrG15KTXGeO+Q8= github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= diff --git a/pkg/api/controller.go b/pkg/api/controller.go index b81bb557..46abe4f5 100644 --- a/pkg/api/controller.go +++ b/pkg/api/controller.go @@ -2,6 +2,7 @@ package api import ( "context" + "crypto/fips140" "crypto/tls" "crypto/x509" goerrors "errors" @@ -254,6 +255,11 @@ func (c *Controller) Run() error { } func (c *Controller) Init() error { + // report if fips140 mode is enabled + if fips140.Enabled() { + c.Log.Info().Msg("fips140 is currently enabled") + } + // print the current configuration, but strip secrets c.Log.Info().Interface("params", c.Config.Sanitize()).Msg("configuration settings") diff --git a/test/blackbox/fips140.bats b/test/blackbox/fips140.bats new file mode 100644 index 00000000..88400180 --- /dev/null +++ b/test/blackbox/fips140.bats @@ -0,0 +1,391 @@ +# Note: Intended to be run as "make run-blackbox-tests" or "make run-blackbox-ci" +# Makefile target installs & checks all necessary tooling +# Extra tools that are not covered in Makefile target needs to be added in verify_prerequisites() + +load helpers_zot +load ../port_helper + +function verify_prerequisites { + if [ ! $(command -v curl) ]; then + echo "you need to install curl as a prerequisite to running the tests" >&3 + return 1 + fi + + if [ ! $(command -v jq) ]; then + echo "you need to install jq as a prerequisite to running the tests" >&3 + return 1 + fi + + return 0 +} + +function setup_file() { + # Verify prerequisites are available + if ! $(verify_prerequisites); then + exit 1 + fi + # Download test data to folder common for the entire suite, not just this file + skopeo --insecure-policy copy --format=oci docker://ghcr.io/project-zot/golang:1.20 oci:${TEST_DATA_DIR}/golang:1.20 + # Setup zot server + local zot_root_dir=${BATS_FILE_TMPDIR}/zot + local zot_config_file=${BATS_FILE_TMPDIR}/zot_config.json + local oci_data_dir=${BATS_FILE_TMPDIR}/oci + mkdir -p ${zot_root_dir} + mkdir -p ${oci_data_dir} + zot_port=$(get_free_port_for_service "zot") + echo ${zot_port} > ${BATS_FILE_TMPDIR}/zot.port + cat > ${zot_config_file}< config.json + echo "hello world" > artifact.txt + run oras push --plain-http 127.0.0.1:${zot_port}/hello-artifact:v2 \ + --config config.json:application/vnd.acme.rocket.config.v1+json artifact.txt:text/plain -d -v + [ "$status" -eq 0 ] + rm -f artifact.txt + rm -f config.json +} + +@test "pull oras artifact" { + zot_port=`cat ${BATS_FILE_TMPDIR}/zot.port` + run oras pull --plain-http 127.0.0.1:${zot_port}/hello-artifact:v2 -d -v + [ "$status" -eq 0 ] + grep -q "hello world" artifact.txt + rm -f artifact.txt +} + +@test "attach oras artifacts" { + zot_port=`cat ${BATS_FILE_TMPDIR}/zot.port` + # attach signature + echo "{\"artifact\": \"\", \"signature\": \"pat hancock\"}" > ${BATS_FILE_TMPDIR}/signature.json + run oras attach --disable-path-validation --plain-http 127.0.0.1:${zot_port}/golang:1.20 --artifact-type 'signature/example' ${BATS_FILE_TMPDIR}/signature.json:application/json + [ "$status" -eq 0 ] + # attach sbom + echo "{\"version\": \"0.0.0.0\", \"artifact\": \"'127.0.0.1:${zot_port}/golang:1.20'\", \"contents\": \"good\"}" > ${BATS_FILE_TMPDIR}/sbom.json + run oras attach --disable-path-validation --plain-http 127.0.0.1:${zot_port}/golang:1.20 --artifact-type 'sbom/example' ${BATS_FILE_TMPDIR}/sbom.json:application/json + [ "$status" -eq 0 ] +} + +@test "discover oras artifacts" { + zot_port=`cat ${BATS_FILE_TMPDIR}/zot.port` + run oras discover --plain-http --format json 127.0.0.1:${zot_port}/golang:1.20 + [ "$status" -eq 0 ] + [ $(echo "$output" | jq -r ".manifests | length") -eq 2 ] +} + +@test "add and list tags using oras" { + zot_port=`cat ${BATS_FILE_TMPDIR}/zot.port` + run skopeo --insecure-policy copy --dest-tls-verify=false \ + oci:${TEST_DATA_DIR}/golang:1.20 \ + docker://127.0.0.1:${zot_port}/oras-tags:1.20 + [ "$status" -eq 0 ] + run oras tag --plain-http 127.0.0.1:${zot_port}/oras-tags:1.20 1 new latest + [ "$status" -eq 0 ] + run oras repo tags --plain-http 127.0.0.1:${zot_port}/oras-tags + [ "$status" -eq 0 ] + echo "$output" + [ $(echo "$output" | wc -l) -eq 4 ] + [ "${lines[-1]}" == "new" ] + [ "${lines[-2]}" == "latest" ] + [ "${lines[-3]}" == "1.20" ] + [ "${lines[-4]}" == "1" ] + run oras repo tags --plain-http --last new 127.0.0.1:${zot_port}/oras-tags + [ "$status" -eq 0 ] + echo "$output" + [ -z $output ] + run oras repo tags --plain-http --last latest 127.0.0.1:${zot_port}/oras-tags + [ "$status" -eq 0 ] + echo "$output" + [ $(echo "$output" | wc -l) -eq 1 ] + [ "${lines[-1]}" == "new" ] + run oras repo tags --plain-http --last "1.20" 127.0.0.1:${zot_port}/oras-tags + [ "$status" -eq 0 ] + echo "$output" + [ $(echo "$output" | wc -l) -eq 2 ] + [ "${lines[-2]}" == "latest" ] + [ "${lines[-1]}" == "new" ] + run oras repo tags --plain-http --last "1" 127.0.0.1:${zot_port}/oras-tags + [ "$status" -eq 0 ] + echo "$output" + [ $(echo "$output" | wc -l) -eq 3 ] + [ "${lines[-3]}" == "1.20" ] + [ "${lines[-2]}" == "latest" ] + [ "${lines[-1]}" == "new" ] +} + +@test "push helm chart" { + zot_port=`cat ${BATS_FILE_TMPDIR}/zot.port` + run helm package ${BATS_FILE_TMPDIR}/helm-charts/charts/zot -d ${BATS_FILE_TMPDIR} + [ "$status" -eq 0 ] + local chart_version=$(awk '/version/{printf $2}' ${BATS_FILE_TMPDIR}/helm-charts/charts/zot/Chart.yaml) + run helm push ${BATS_FILE_TMPDIR}/zot-${chart_version}.tgz oci://localhost:${zot_port}/zot-chart + [ "$status" -eq 0 ] +} + +@test "pull helm chart" { + zot_port=`cat ${BATS_FILE_TMPDIR}/zot.port` + local chart_version=$(awk '/version/{printf $2}' ${BATS_FILE_TMPDIR}/helm-charts/charts/zot/Chart.yaml) + run helm pull oci://localhost:${zot_port}/zot-chart/zot --version ${chart_version} -d ${BATS_FILE_TMPDIR} + [ "$status" -eq 0 ] +} + +@test "push image with regclient" { + zot_port=`cat ${BATS_FILE_TMPDIR}/zot.port` + run regctl registry set localhost:${zot_port} --tls disabled + [ "$status" -eq 0 ] + run regctl image copy ocidir://${TEST_DATA_DIR}/golang:1.20 localhost:${zot_port}/test-regclient + [ "$status" -eq 0 ] +} + +@test "pull image with regclient" { + zot_port=`cat ${BATS_FILE_TMPDIR}/zot.port` + run regctl image copy localhost:${zot_port}/test-regclient ocidir://${TEST_DATA_DIR}/golang:1.20 + [ "$status" -eq 0 ] +} + +@test "list repositories with regclient" { + zot_port=`cat ${BATS_FILE_TMPDIR}/zot.port` + run regctl repo ls localhost:${zot_port} + [ "$status" -eq 0 ] + + found=0 + for i in "${lines[@]}" + do + + if [ "$i" = 'test-regclient' ]; then + found=1 + fi + done + [ "$found" -eq 1 ] + + run regctl repo ls --limit 2 localhost:${zot_port} + [ "$status" -eq 0 ] + echo "$output" + [ $(echo "$output" | wc -l) -eq 2 ] + [ "${lines[-2]}" == "busybox" ] + [ "${lines[-1]}" == "golang" ] + + run regctl repo ls --last busybox --limit 1 localhost:${zot_port} + [ "$status" -eq 0 ] + echo "$output" + [ $(echo "$output" | wc -l) -eq 1 ] + [ "${lines[-1]}" == "golang" ] +} + +@test "list image tags with regclient" { + zot_port=`cat ${BATS_FILE_TMPDIR}/zot.port` + run regctl tag ls localhost:${zot_port}/test-regclient + [ "$status" -eq 0 ] + + found=0 + for i in "${lines[@]}" + do + + if [ "$i" = 'latest' ]; then + found=1 + fi + done + [ "$found" -eq 1 ] +} + +@test "push manifest with regclient" { + zot_port=`cat ${BATS_FILE_TMPDIR}/zot.port` + manifest=$(regctl manifest get localhost:${zot_port}/test-regclient --format=raw-body) + run regctl manifest put localhost:${zot_port}/test-regclient:1.0.0 --format oci --content-type application/vnd.oci.image.manifest.v1+json --format oci < Dockerfile < /testfile +EOF + docker build -f Dockerfile . -t localhost:${zot_port}/test + run docker push localhost:${zot_port}/test + [ "$status" -eq 1 ] + run docker pull localhost:${zot_port}/test + [ "$status" -eq 1 ] +}