diff --git a/.dockerignore b/.dockerignore index 3907951d33..2f1a5eae1a 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,5 +1,7 @@ -# Ignore everything that starts with a dot -.* +# Ignore everything that starts with a dot ('.?*' instead of '.*' so the +# pattern does not match the build context root '.' itself, which trips +# the CopyIgnoredFile check on 'COPY . .') +.?* # Readme files and docs README.rst README_template.rst diff --git a/Dockerfile b/Dockerfile index d9ac33eaea..2730552396 100644 --- a/Dockerfile +++ b/Dockerfile @@ -20,18 +20,14 @@ RUN go mod download && go mod verify COPY . . RUN GOOS=$TARGETOS GOARCH=$TARGETARCH go build -ldflags="-w -s -X 'github.com/nuts-foundation/nuts-node/v6/core.GitCommit=${GIT_COMMIT}' -X 'github.com/nuts-foundation/nuts-node/v6/core.GitBranch=${GIT_BRANCH}' -X 'github.com/nuts-foundation/nuts-node/v6/core.GitVersion=${GIT_VERSION}'" -o /opt/nuts/nuts -# alpine -FROM alpine:3.24.1 -RUN apk update \ - && apk add --no-cache \ - tzdata \ - curl +# distroless static: contains CA certificates and tzdata, but no shell or package manager +FROM gcr.io/distroless/static-debian13:latest@sha256:9197324ba51d9cd071af8505989365c006adf9d6d2067eada25aef00abbb5278 COPY --from=builder /opt/nuts/nuts /usr/bin/nuts +# exec form (no shell in this image); 'nuts status' GETs the internal API on localhost:8081 HEALTHCHECK --start-period=30s --timeout=5s --interval=10s \ - CMD curl -f http://localhost:8081/status || exit 1 + CMD ["/usr/bin/nuts", "status"] -RUN adduser -D -H -u 18081 nuts-usr USER 18081:18081 WORKDIR /nuts diff --git a/e2e-tests/nuts-network/private-transactions/run-test.sh b/e2e-tests/nuts-network/private-transactions/run-test.sh index 6676fe73ee..1ec2b91ff0 100755 --- a/e2e-tests/nuts-network/private-transactions/run-test.sh +++ b/e2e-tests/nuts-network/private-transactions/run-test.sh @@ -57,9 +57,10 @@ echo "Restarting with NodeDID set..." echo "------------------------------------" # Start without bootstrap node, to enforce authenticated, discovered connections (required for private transactions) export BOOTSTRAP_NODES= -# Delete nodes' address books to avoid persisting initial "new node" delay, allowing to connect to each other immediately -docker compose exec nodeA rm -f /opt/nuts/data/network/connections.db -docker compose exec nodeB rm -f /opt/nuts/data/network/connections.db +# Delete nodes' address books to avoid persisting initial "new node" delay, allowing to connect to each other immediately. +# Deleted from the host (data dirs are bind mounts): the distroless image contains no 'rm'. +rm -f ./node-A/data/network/connections.db +rm -f ./node-B/data/network/connections.db docker compose stop docker compose up --wait diff --git a/e2e-tests/oauth-flow/openid4vp/do-test.sh b/e2e-tests/oauth-flow/openid4vp/do-test.sh index db68dc0115..4f43fb2eed 100755 --- a/e2e-tests/oauth-flow/openid4vp/do-test.sh +++ b/e2e-tests/oauth-flow/openid4vp/do-test.sh @@ -154,7 +154,8 @@ DPOP=$(cat ./node-B/dpop.txt) echo "------------------------------------" echo "Retrieving data..." echo "------------------------------------" -RESPONSE=$(docker compose exec nodeB-backend curl http://resource:80/resource -H "Authorization: DPoP $ACCESS_TOKEN" -H "DPoP: $DPOP" -v) +# curl runs in a dedicated helper container on the compose network (the nuts-node image contains no curl) +RESPONSE=$(docker compose run --rm curl http://resource:80/resource -H "Authorization: DPoP $ACCESS_TOKEN" -H "DPoP: $DPOP" -v) if echo $RESPONSE | grep -q "OK"; then echo "success!" else diff --git a/e2e-tests/oauth-flow/openid4vp/docker-compose.yml b/e2e-tests/oauth-flow/openid4vp/docker-compose.yml index 1540010e7e..2dc5076a8a 100644 --- a/e2e-tests/oauth-flow/openid4vp/docker-compose.yml +++ b/e2e-tests/oauth-flow/openid4vp/docker-compose.yml @@ -56,3 +56,8 @@ services: - "../../scripts/oauth2.js:/etc/nginx/oauth2.js:ro" depends_on: - nodeA-backend + # helper for do-test.sh, invoked via 'docker compose run --rm curl' (the nuts-node image contains no curl); + # the 'tools' profile keeps it from being started by 'docker compose up' + curl: + image: curlimages/curl:8.18.0 + profiles: [ tools ] diff --git a/e2e-tests/oauth-flow/rfc002/docker-compose.yml b/e2e-tests/oauth-flow/rfc002/docker-compose.yml index 8639312014..397fdeb8dc 100644 --- a/e2e-tests/oauth-flow/rfc002/docker-compose.yml +++ b/e2e-tests/oauth-flow/rfc002/docker-compose.yml @@ -35,3 +35,10 @@ services: - "../../tls-certs/truststore.pem:/opt/nuts/truststore.pem:ro" healthcheck: interval: 1s # Make test run quicker by checking health status more often + # helper for run-test.sh, invoked via 'docker compose run --rm curl' (the nuts-node image contains no curl); + # the 'tools' profile keeps it from being started by 'docker compose up' + curl: + image: curlimages/curl:8.18.0 + profiles: [ tools ] + volumes: + - "../../tls-certs/nodeB-certificate.pem:/certs/nodeB-client.pem:ro" diff --git a/e2e-tests/oauth-flow/rfc002/run-test.sh b/e2e-tests/oauth-flow/rfc002/run-test.sh index 9d0886de7e..0708c2f96f 100755 --- a/e2e-tests/oauth-flow/rfc002/run-test.sh +++ b/e2e-tests/oauth-flow/rfc002/run-test.sh @@ -147,7 +147,8 @@ echo "------------------------------------" echo "Retrieving data..." echo "------------------------------------" -RESPONSE=$(docker compose exec nodeB curl --insecure --cert /opt/nuts/certificate-and-key.pem --key /opt/nuts/certificate-and-key.pem https://nodeA:443/ping -H "Authorization: bearer $(cat ./node-B/data/accesstoken.txt)" -v) +# curl runs in a dedicated helper container on the compose network, using nodeB's client cert to act as nodeB +RESPONSE=$(docker compose run --rm curl --insecure --cert /certs/nodeB-client.pem --key /certs/nodeB-client.pem https://nodeA:443/ping -H "Authorization: bearer $(cat ./node-B/data/accesstoken.txt)" -v) if echo $RESPONSE | grep -q "pong"; then echo "success!" else diff --git a/e2e-tests/oauth-flow/rfc021/do-test.sh b/e2e-tests/oauth-flow/rfc021/do-test.sh index 04fee13675..268d3791d8 100755 --- a/e2e-tests/oauth-flow/rfc021/do-test.sh +++ b/e2e-tests/oauth-flow/rfc021/do-test.sh @@ -69,7 +69,8 @@ fi STATUS_LIST_CREDENTIAL=$(echo $VENDOR_B_CREDENTIAL | jq -r .credentialStatus.statusListCredential) echo "Status list credential: $STATUS_LIST_CREDENTIAL" # Get status list credential -RESPONSE=$($db_dc exec nodeB-backend curl -s -k $STATUS_LIST_CREDENTIAL) +# curl runs in a dedicated helper container on the compose network (the nuts-node image contains no curl) +RESPONSE=$($db_dc run --rm curl -s -k $STATUS_LIST_CREDENTIAL) # Check response HTTP 200 OK if echo $RESPONSE | grep -q "\"id\":\"$STATUS_LIST_CREDENTIAL\"" ; then echo "Status list credential retrieved" diff --git a/e2e-tests/oauth-flow/rfc021/docker-compose.yml b/e2e-tests/oauth-flow/rfc021/docker-compose.yml index 36543dd3ea..36525f1ac2 100644 --- a/e2e-tests/oauth-flow/rfc021/docker-compose.yml +++ b/e2e-tests/oauth-flow/rfc021/docker-compose.yml @@ -53,4 +53,9 @@ services: - "../../tls-certs/nodeB-certificate.pem:/etc/nginx/ssl/server.pem:ro" - "../../tls-certs/nodeB-certificate.pem:/etc/nginx/ssl/key.pem:ro" - "../../tls-certs/truststore.pem:/etc/nginx/ssl/truststore.pem:ro" - - "./node-B/html:/etc/nginx/html:ro" \ No newline at end of file + - "./node-B/html:/etc/nginx/html:ro" + # helper for do-test.sh, invoked via 'docker compose run --rm curl' (the nuts-node image contains no curl); + # the 'tools' profile keeps it from being started by 'docker compose up' + curl: + image: curlimages/curl:8.18.0 + profiles: [ tools ] diff --git a/e2e-tests/openid4vci/network-issuance/run-test.sh b/e2e-tests/openid4vci/network-issuance/run-test.sh index fbc77782a6..9a2ae112bb 100755 --- a/e2e-tests/openid4vci/network-issuance/run-test.sh +++ b/e2e-tests/openid4vci/network-issuance/run-test.sh @@ -39,9 +39,10 @@ echo "Restarting with NodeDID set..." echo "------------------------------------" # Start without bootstrap node, to enforce authenticated, discovered connections (required for private transactions) export BOOTSTRAP_NODES= -# Delete nodes' address books to avoid persisting initial "new node" delay, allowing to connect to each other immediately -docker compose exec nodeA-backend rm -f /opt/nuts/data/network/connections.db -docker compose exec nodeB-backend rm -f /opt/nuts/data/network/connections.db +# Delete nodes' address books to avoid persisting initial "new node" delay, allowing to connect to each other immediately. +# Deleted from the host (data dirs are bind mounts): the distroless image contains no 'rm'. +rm -f ./node-A/data/network/connections.db +rm -f ./node-B/data/network/connections.db docker compose stop docker compose up --wait diff --git a/main.go b/main.go index 5910d413da..e9e13d77da 100644 --- a/main.go +++ b/main.go @@ -36,5 +36,6 @@ func main() { err := cmd.Execute(ctx, cmd.CreateSystem(cancelNotify)) if err != nil { logrus.Error(err) + os.Exit(1) } }