diff --git a/functest_requirements.txt b/functest_requirements.txt index 774edb421..5fb29530a 100644 --- a/functest_requirements.txt +++ b/functest_requirements.txt @@ -1,6 +1,5 @@ pytest<10 -python-gnupg pytest-xdist pytest-timeout pytest-custom_exit_code -trustme~=1.2.1 \ No newline at end of file +trustme~=1.2.1 diff --git a/pulp_container/tests/functional/api/test_push_signatures.py b/pulp_container/tests/functional/api/test_push_signatures.py index 2d9e3e7f9..dd19652ba 100644 --- a/pulp_container/tests/functional/api/test_push_signatures.py +++ b/pulp_container/tests/functional/api/test_push_signatures.py @@ -1,55 +1,78 @@ """Tests that verify that an image signature can be pushed to Pulp.""" import base64 -import json +import subprocess import pytest from pulp_container.constants import SIGNATURE_TYPE +from pulp_container.tests.functional.conftest import verify_inline_signature from pulp_container.tests.functional.constants import REGISTRY_V2_REPO_PULP +def _podman_supports_sq_signing(): + """Return True if the local podman build supports --sign-by-sq-fingerprint.""" + result = subprocess.run( + ("podman", "push", "--help"), + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + ) + return "--sign-by-sq-fingerprint" in result.stdout.decode() + + @pytest.fixture -def distribution( +def signed_distribution( + signing_key_home, registry_client, local_registry, container_distribution_api, - signing_gpg_metadata, + container_namespace_api, add_to_cleanup, full_path, ): - """Return a distribution created after pushing a signed content to the Pulp Registry.""" + """Push an image signed with a Sequoia key (twice, for two distinct signatures). + + Parameterized (via `signing_key_home`) over a key that signs with its primary key and + one that signs with a dedicated subkey. + """ if registry_client.name != "podman": pytest.skip("This test requires podman to sign pulled content", allow_module_level=True) + if not _podman_supports_sq_signing(): + pytest.skip("This podman build does not support --sign-by-sq-fingerprint") image_path = f"{REGISTRY_V2_REPO_PULP}:manifest_a" registry_client.pull(image_path) - gpg, fingerprint, keyid = signing_gpg_metadata - - with registry_client.set_env(GNUPGHOME=str(gpg.gnupghome)): - local_registry.tag_and_push(image_path, full_path("test-1:manifest_a"), "--sign-by", keyid) - - # push the same image for the second time with a different signature (timestamp) - local_registry.tag_and_push(image_path, full_path("test-1:manifest_a"), "--sign-by", keyid) + # Point the Sequoia integration at the home holding our imported key. + sign_args = ("--sign-by-sq-fingerprint", signing_key_home.fingerprint) + with registry_client.set_env(SEQUOIA_HOME=str(signing_key_home.home)): + local_registry.tag_and_push(image_path, full_path("test-1:manifest_a"), *sign_args) + # push a second time to produce a distinct signature (timestamp) + local_registry.tag_and_push(image_path, full_path("test-1:manifest_a"), *sign_args) distribution = container_distribution_api.list(name="test-1").results[0] - add_to_cleanup(container_distribution_api, distribution.pulp_href) + # Clean up the namespace, which cascades to the distribution and the push repository. + add_to_cleanup(container_namespace_api, distribution.namespace) return distribution def test_assert_signed_image( + signing_key_home, local_registry, container_repository_api, container_manifest_api, container_signature_api, - signing_gpg_metadata, - distribution, + signed_distribution, full_path, ): - """Test whether an admin user can fetch a signature from the Pulp Registry.""" - gpg, fingerprint, keyid = signing_gpg_metadata + """Test whether an admin user can fetch a signature from the Pulp Registry. + + Runs against both primary-key and subkey signing. + """ + distribution = signed_distribution + fingerprint = signing_key_home.signing_fingerprint + keyid = signing_key_home.signing_keyid repository = container_repository_api.read(distribution.repository) manifest = container_manifest_api.list( @@ -75,13 +98,12 @@ def test_assert_signed_image( timestamps = [] for s in signatures: raw_s = base64.b64decode(s["content"]) - decrypted = gpg.decrypt(raw_s) - - assert decrypted.key_id == keyid - assert decrypted.fingerprint == fingerprint - assert decrypted.status == "signature valid" + sig_fingerprint, sig_key_id, json_s = verify_inline_signature( + signing_key_home.public_key, raw_s + ) - json_s = json.loads(decrypted.data) + assert sig_key_id == keyid + assert sig_fingerprint == fingerprint image_path = json_s["critical"]["identity"]["docker-reference"] assert image_path == f"{local_registry.name}/{full_path(distribution)}:manifest_a" diff --git a/pulp_container/tests/functional/api/test_sign_manifests.py b/pulp_container/tests/functional/api/test_sign_manifests.py index e0bdaea60..a30b453de 100644 --- a/pulp_container/tests/functional/api/test_sign_manifests.py +++ b/pulp_container/tests/functional/api/test_sign_manifests.py @@ -1,14 +1,48 @@ import pytest +from pulpcore.pytest_plugin import create_signing_service, remove_signing_service + from pulp_container.constants import SIGNATURE_TYPE from pulp_container.tests.functional.constants import REGISTRY_V2_REPO_PULP MANIFEST_TAG = "manifest_a" +# Builds an atomic container signature payload for the passed manifest and signs +# it with a Sequoia (sq) key, emitting an inline-signed binary OpenPGP message. +# See https://github.com/pulp/pulp_container/issues/2280. +SIGNING_SCRIPT_STRING = """#!/usr/bin/env bash + +set -e + +MANIFEST_PATH=$1 +FINGERPRINT="$PULP_SIGNING_KEY_FINGERPRINT" +SQ_HOME="{sq_home}" + +DIGEST="sha256:$(sha256sum "$MANIFEST_PATH" | awk '{{print $1}}')" + +PAYLOAD_FILE="$(mktemp)" +cat > "$PAYLOAD_FILE" <=4.4,<4.27", "pulpcore>=3.111.0,<3.130", "pyjwt[crypto]>=2.4,<2.14", - "pysequoia>=0.1.33,<0.2.0" + "pysequoia>=0.1.35,<0.2.0" ] [project.urls]