diff --git a/CHANGELOG.md b/CHANGELOG.md index c257f5a..a1b72c5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,15 @@ # Changelog +## [3.1.0] - 2024-01-27 + +### Added + +- Allow pushing without a token (`--allowNoPushAuth`) to registries that allow it + +### Fixed + +- Fixed an error with failed push (using a token) when pulling without a token + ## [3.0.1] - 2024-01-18 ### Fixed diff --git a/README.md b/README.md index c9ba59a..ad0be17 100644 --- a/README.md +++ b/README.md @@ -80,6 +80,7 @@ Options: --setTimeStamp Optional: Set a specific ISO 8601 timestamp on all entries (e.g. git commit hash). Default: 1970 in tar files, and current time on manifest/config --verbose Verbose logging --allowInsecureRegistries Allow insecure registries (with self-signed/untrusted cert) + --allowNoPushAuth Allow pushing images without authentication/token if the registry allows it --customContent Optional: Skip normal node_modules and applayer and include specified root folder files/directories instead. You can specify as local-path:absolute-container-path if you want to place it in a specific location --extraContent Optional: Add specific content. Specify as local-path:absolute-container-path,local-path2:absolute-container-path2 etc diff --git a/package.json b/package.json index 4592f41..ee1fbeb 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "containerify", - "version": "3.0.1", + "version": "3.1.0", "description": "Build node.js docker images without docker", "main": "./lib/cli.js", "scripts": { @@ -19,6 +19,9 @@ "containerify": "./lib/cli.js" }, "author": "Erlend Oftedal ", + "contributors": [ + "Vegard S. Hagen " + ], "license": "Apache-2.0", "repository": { "type": "git", diff --git a/src/cli.ts b/src/cli.ts index fb60d1e..46d4768 100755 --- a/src/cli.ts +++ b/src/cli.ts @@ -52,6 +52,7 @@ const possibleArgs = { "Optional: Set a specific ISO 8601 timestamp on all entries (e.g. git commit hash). Default: 1970 in tar files, and current time on manifest/config", "--verbose": "Verbose logging", "--allowInsecureRegistries": "Allow insecure registries (with self-signed/untrusted cert)", + "--allowNoPushAuth": "Allow pushing images without a authentication/token to registries that allow it", "--customContent ": "Optional: Skip normal node_modules and applayer and include specified root folder files/directories instead. You can specify as local-path:absolute-container-path if you want to place it in a specific location", "--extraContent ": @@ -242,7 +243,7 @@ exitWithErrorIf( !options.toRegistry && !options.toTar && !options.toDocker, "Must specify either --toTar, --toRegistry or --toDocker", ); -exitWithErrorIf(!!options.toRegistry && !options.toToken, "A token must be given when uploading to docker hub"); +exitWithErrorIf(!!options.toRegistry && !options.toToken && !options.allowNoPushAuth, "A token must be provided when uploading images"); if (options.toRegistry && !options.toRegistry.endsWith("/")) options.toRegistry += "/"; if (options.fromRegistry && !options.fromRegistry.endsWith("/")) options.fromRegistry += "/"; @@ -304,9 +305,6 @@ async function run(options: Options) { await tarExporter.saveToTar(todir, tmpdir, options.toTar, [options.toImage], options); } if (options.toRegistry) { - if (!options.token && allowInsecure == InsecureRegistrySupport.NO) { - throw new Error("Need auth token to upload to " + options.toRegistry); - } const toRegistry = await createRegistry( options.toRegistry, options.toImage, diff --git a/src/registry.ts b/src/registry.ts index a54830e..5e06e29 100644 --- a/src/registry.ts +++ b/src/registry.ts @@ -126,11 +126,12 @@ function uploadContent( logger.debug("Uploading: ", file); let url = uploadUrl; if (fileConfig.digest) url += (url.indexOf("?") == -1 ? "?" : "&") + "digest=" + fileConfig.digest; - const options = createHttpOptions("PUT", url, { - authorization: auth, + const headers: OutgoingHttpHeaders = { "content-length": fileConfig.size, "content-type": contentType, - }); + } + if (auth) headers.authorization = auth + const options = createHttpOptions("PUT", url, headers) logger.debug(options.method, url); const req = request(options, allowInsecure, (res) => { logger.debug(res.statusCode, res.statusMessage, res.headers["content-type"], res.headers["content-length"]); @@ -222,7 +223,7 @@ export async function createRegistry( const url = `${registryBaseUrl}${image.path}/blobs/uploads/${parameters.size > 0 ? "?" + parameters : ""}`; const options: https.RequestOptions = URL.parse(url); options.method = "POST"; - options.headers = { authorization: auth }; + if (auth) options.headers = { authorization: auth }; request(options, allowInsecure, (res) => { logger.debug("POST", `${url}`, res.statusCode); if (res.statusCode == 202) { diff --git a/src/types.ts b/src/types.ts index 9df27c3..4f98e85 100644 --- a/src/types.ts +++ b/src/types.ts @@ -91,6 +91,7 @@ export type Options = { setTimeStamp?: string; verbose?: boolean; allowInsecureRegistries?: boolean; + allowNoPushAuth?: boolean; customContent: Record; extraContent: Record; layerOwner?: string; diff --git a/src/version.ts b/src/version.ts index b7ea020..4fe4e83 100644 --- a/src/version.ts +++ b/src/version.ts @@ -1 +1 @@ -export const VERSION = "3.0.1"; +export const VERSION = "3.1.0"; diff --git a/tests/localtest/test-insecure.sh b/tests/localtest/test-insecure.sh new file mode 100644 index 0000000..c8713c1 --- /dev/null +++ b/tests/localtest/test-insecure.sh @@ -0,0 +1,56 @@ +#!/bin/bash + +set -e + +export DOCKER_CONFIG=tmp +LOCAL_REGISTRY=127.0.0.1 + +rm -rf tmp +mkdir tmp + +printf "* Stopping any running local containerify test registry...\n" +docker stop registry-containerify-insecure-test >/dev/null 2>&1 || echo "No running container registry, so nothing to stop" + +printf "* Starting local containerify test registry on port 5443...\n" +docker run -d \ + --rm \ + --name registry-containerify-insecure-test \ + -e REGISTRY_HTTP_ADDR=0.0.0.0:5443 \ + -p 5443:5443 \ + registry:2 > /dev/null + +printf "* Pulling node:alpine as base image...\n" +docker pull node:alpine &> /dev/null + +printf "* Pushing base image to local containerify test registry...\n" +docker tag node:alpine ${LOCAL_REGISTRY}:5443/node > /dev/null +docker push ${LOCAL_REGISTRY}:5443/node > /dev/null + +printf "* Running containerify to pull from and push result to the local containerify test registry...\n" +cd ../integration/app +npm ci +cd ../../localtest +../../lib/cli.js \ + --fromRegistry http://${LOCAL_REGISTRY}:5443/v2/ \ + --fromImage node \ + --toRegistry http://${LOCAL_REGISTRY}:5443/v2/ \ + --toImage containerify-integration-test:localtest \ + --doCrossMount \ + --allowInsecureRegistries \ + --allowNoPushAuth \ + --folder ../integration/app --setTimeStamp "2024-01-18T13:33:33.337Z" \ + +printf "\n* Pulling image from registry to local docker daemon...\n" +docker pull ${LOCAL_REGISTRY}:5443/containerify-integration-test:localtest &> /dev/null + +printf "* Running image on local docker daemon...\n" +docker run --rm -it ${LOCAL_REGISTRY}:5443/containerify-integration-test:localtest + +printf "\n* Deleting image from registry to local docker daemon...\n" +docker rmi ${LOCAL_REGISTRY}:5443/containerify-integration-test:localtest > /dev/null + +printf "* Stopping local containerify test registry...\n" +docker stop registry-containerify-insecure-test > /dev/null +rm -rf tmp + +printf "\nSUCCESS!\n" diff --git a/tests/localtest/test.sh b/tests/localtest/test.sh index dcabd6b..d82b73e 100755 --- a/tests/localtest/test.sh +++ b/tests/localtest/test.sh @@ -15,7 +15,7 @@ mkdir -p tmp/auth printf "* Generating key for local registry...\n" openssl req \ -newkey rsa:4096 -nodes -sha256 -keyout tmp/certs/domain.key \ - -addext "subjectAltName = DNS:myregistry.domain.com" \ + -addext "subjectAltName = IP:${LOCAL_REGISTRY}" \ -subj "/C=NO/ST=containerify/L=containerify/O=containerify Integration/OU=Test Department/CN=containerify.test" \ -x509 -days 365 -out tmp/certs/domain.crt > /dev/null 2>&1 @@ -54,9 +54,15 @@ docker push ${LOCAL_REGISTRY}:5443/node > /dev/null printf "* Running containerify to pull from and push result to the local containerify test registry...\n" cd ../integration/app -npm install +npm ci cd ../../localtest -../../lib/cli.js --fromImage node --doCrossMount --registry https://${LOCAL_REGISTRY}:5443/v2/ --toImage containerify-integration-test:localtest --folder ../integration/app --setTimeStamp "2023-03-07T12:53:10.471Z" --allowInsecureRegistries --token "Basic $BASICAUTH" +NODE_EXTRA_CA_CERTS=tmp/certs/domain.crt ../../lib/cli.js \ + --fromImage node \ + --doCrossMount \ + --registry https://${LOCAL_REGISTRY}:5443/v2/ \ + --toImage containerify-integration-test:localtest \ + --folder ../integration/app --setTimeStamp "2023-03-07T12:53:10.471Z" \ + --token "Basic $BASICAUTH" printf "\n* Pulling image from registry to local docker daemon...\n"