diff --git a/.ci/container_setup.d/10-install-signing-service.sh b/.ci/container_setup.d/10-install-signing-service.sh new file mode 100644 index 0000000..9d388af --- /dev/null +++ b/.ci/container_setup.d/10-install-signing-service.sh @@ -0,0 +1,30 @@ +#!/bin/sh + +set -eu + +pulp --config "${PULP_CLI_CONFIG}" debug has-plugin --name "deb" && HAS_DEB=true || HAS_DEB="" +if [ "$HAS_DEB" ] +then + if [ ! -f pytest_pulp_cli/GPG-PRIVATE-KEY-fixture-signing ] + then + curl -L https://github.com/pulp/pulp-fixtures/raw/master/common/GPG-PRIVATE-KEY-fixture-signing > pytest_pulp_cli/GPG-PRIVATE-KEY-fixture-signing + fi + echo "Setup the signing services" + if "${CONTAINER_RUNTIME}" exec "pulp-ephemeral" id pulp + then + PULP_USER="pulp" + else + PULP_USER="root" + fi + "${CONTAINER_RUNTIME}" exec "pulp-ephemeral" mkdir -p /var/lib/pulp/scripts/ + # Setup key on the Pulp container + echo "0C1A894EBB86AFAE218424CADDEF3019C2D4A8CF:6:" | "${CONTAINER_RUNTIME}" exec -i "pulp-ephemeral" su "${PULP_USER}" -c "gpg --import-ownertrust" + "${CONTAINER_RUNTIME}" exec -i "pulp-ephemeral" su "${PULP_USER}" -c "gpg --import" < pytest_pulp_cli/GPG-PRIVATE-KEY-fixture-signing + if [ "$HAS_DEB" ] + then + echo "Setup deb release signing service" + "${CONTAINER_RUNTIME}" exec -i "pulp-ephemeral" bash -c "cat > /var/lib/pulp/scripts/sign_deb_release.sh" < "${BASEPATH}/../tests/assets/sign_deb_release.sh" + "${CONTAINER_RUNTIME}" exec "pulp-ephemeral" chmod a+x /var/lib/pulp/scripts/sign_deb_release.sh + "${CONTAINER_RUNTIME}" exec "pulp-ephemeral" su "${PULP_USER}" -c "pulpcore-manager add-signing-service --class deb:AptReleaseSigningService sign_deb_release /var/lib/pulp/scripts/sign_deb_release.sh 'pulp-fixture-signing-key'" + fi +fi diff --git a/CHANGES/54.feature b/CHANGES/54.feature new file mode 100644 index 0000000..0ab8989 --- /dev/null +++ b/CHANGES/54.feature @@ -0,0 +1 @@ +Add signing-service as an argument to repository creation and updation diff --git a/pulpcore/cli/deb/repository.py b/pulpcore/cli/deb/repository.py index f1c40e8..04b0bac 100644 --- a/pulpcore/cli/deb/repository.py +++ b/pulpcore/cli/deb/repository.py @@ -34,6 +34,7 @@ PulpRepositoryContext, ) from pulp_glue.common.i18n import get_translation +from pulp_glue.core.context import PulpSigningServiceContext from pulp_glue.deb.context import ( PulpAptRemoteContext, PulpAptRepositoryContext, @@ -52,6 +53,18 @@ def _content_callback(ctx: click.Context, param: click.Parameter, value: Any) -> return value +def _signing_service_callback(ctx: click.Context, param: click.Parameter, values: Any) -> Any: + result: dict[str, str] = {} + if not values: + return result + for arg in values: + if "=" not in arg: + raise click.BadParameter(f"must be in the format 'distribution=pulp_href', got '{arg}'") + key, value = arg.split("=", 1) + result[key] = value + return result + + CONTENT_LIST_SCHEMA = s.Schema([{"pulp_href": str}]) package_options = [ @@ -126,6 +139,23 @@ def repository(ctx: click.Context, pulp_ctx: PulpCLIContext, /, repo_type: str) # default=None, # ), retained_versions_option, + resource_option( + "--signing-service", + default_plugin="deb", + default_type="apt", + context_table={"deb:apt": PulpSigningServiceContext}, + help=_("Apt only: Signing service to use, pass in name or href"), + ), + click.option( + "--signing-service-release-overrides", + multiple=True, + callback=_signing_service_callback, + help=_( + "Apt only: Override signing service to use for a distribution. " + "Accepts values in distribution=pulp_href format. " + "Accepts multiple such entries." + ), + ), ] create_options = update_options + [click.option("--name", required=True)] diff --git a/tests/assets/sign_deb_release.sh b/tests/assets/sign_deb_release.sh new file mode 100755 index 0000000..9830ea0 --- /dev/null +++ b/tests/assets/sign_deb_release.sh @@ -0,0 +1,30 @@ +#!/bin/bash + +set -e + +RELEASE_FILE="$(/usr/bin/readlink -f "$1")" +OUTPUT_DIR="$(/usr/bin/mktemp -d)" +DETACHED_SIGNATURE_PATH="${OUTPUT_DIR}/Release.gpg" +INLINE_SIGNATURE_PATH="${OUTPUT_DIR}/InRelease" +GPG_KEY_ID="pulp-fixture-signing-key" + +# Create a detached signature +/usr/bin/gpg --batch --armor --digest-algo SHA256 \ + --detach-sign \ + --output "${DETACHED_SIGNATURE_PATH}" \ + --local-user "${GPG_KEY_ID}" \ + "${RELEASE_FILE}" + +# Create an inline signature +/usr/bin/gpg --batch --armor --digest-algo SHA256 \ + --clearsign \ + --output "${INLINE_SIGNATURE_PATH}" \ + --local-user "${GPG_KEY_ID}" \ + "${RELEASE_FILE}" + +echo "{" \ + \"signatures\": "{" \ + \"inline\": \""${INLINE_SIGNATURE_PATH}"\", \ + \"detached\": \""${DETACHED_SIGNATURE_PATH}"\" \ + "}" \ + "}" diff --git a/tests/scripts/pulp_deb/test_deb_repository_signing.sh b/tests/scripts/pulp_deb/test_deb_repository_signing.sh new file mode 100755 index 0000000..b7d9e2e --- /dev/null +++ b/tests/scripts/pulp_deb/test_deb_repository_signing.sh @@ -0,0 +1,55 @@ +#!/bin/bash + +set -eu + +# shellcheck source=tests/scripts/config.source +. "$(dirname "$(dirname "$(realpath "$0")")")/config.source" + +ENTITIES_NAME="test_deb_repository_signing" + +cleanup() { + pulp deb repository destroy --name "${ENTITIES_NAME}_repo" || true +} +trap cleanup EXIT + +# Check .ci/container_setup.d/10-install-signing-service.sh on how to setup the +# signing service +expect_succ pulp signing-service list +expect_succ test "$(echo "$OUTPUT" | jq -r length)" -ge "1" +expect_succ pulp signing-service show --name "sign_deb_release" +signing_service_href=$(echo "$OUTPUT" | jq -r '.pulp_href') + +# Test repository creation without signing service (baseline) +expect_succ pulp deb repository create \ + --name "${ENTITIES_NAME}_repo" +expect_succ pulp deb repository show --name "${ENTITIES_NAME}_repo" +assert "$(echo "$OUTPUT" | jq -r .signing_service)" == "null" +assert "$(echo "$OUTPUT" | jq -r .signing_service_release_overrides)" == "{}" + +cleanup + +# Test repository creation with signing service +expect_succ pulp deb repository create \ + --name "${ENTITIES_NAME}_repo" \ + --signing-service "sign_deb_release" +expect_succ pulp deb repository show --name "${ENTITIES_NAME}_repo" +assert "$(echo "$OUTPUT" | jq -r .signing_service)" = "${signing_service_href}" +assert "$(echo "$OUTPUT" | jq -r .signing_service_release_overrides)" = "{}" + +cleanup + +# Test --signing-service-release-overrides validation: must be in distribution=pulp_href format +expect_fail pulp deb repository create \ + --name "${ENTITIES_NAME}_repo" \ + --signing-service-release-overrides "invalid_format" +assert "${ERROUTPUT}" =~ "must be in the format 'distribution=pulp_href'" + +# Test --signing-service-release-overrides validation - valid format +expect_succ pulp deb repository create \ + --name "${ENTITIES_NAME}_repo" \ + --signing-service-release-overrides "jammy=${signing_service_href}" +expect_succ pulp deb repository show --name "${ENTITIES_NAME}_repo" +assert "$(echo "$OUTPUT" | jq -r .signing_service)" == "null" +assert "$(echo "$OUTPUT" | jq -r .signing_service_release_overrides.jammy)" == "${signing_service_href}" + +cleanup