Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGES/+overwrite-signing-noop.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Added support for the new `overwrite` parameter on the APT repository modify
endpoint. Packages already produced by Pulp's signing workflow (tracked via
`DebPackageSigningResult`) and present in the repository version are exempted
from the overwrite check so the operation remains a NOOP.
23 changes: 23 additions & 0 deletions pulp_deb/app/models/repository.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
SourcePackage,
SourcePackageReleaseComponent,
)
from pulp_deb.app.models.signing_service import DebPackageSigningResult

log = logging.getLogger(__name__)

Expand Down Expand Up @@ -148,6 +149,28 @@ def package_signing_fingerprint_release_overrides_map(self):
for override in self.package_signing_fingerprint_release_overrides.all()
}

def check_content_overwrite(self, version, add_content_pks, remove_content_pks=None):
"""
Exempt signing-NOOP packages from the overwrite check.

A previously-signed package returned from the signing-result cache may already
be in the version, making the add a NOOP. Skip those so genuine overwrites are
still rejected.
"""
# If package signing is enabled, filter previously signed packages from the add list.
if self.package_signing_service_id is not None:
existing_pks = set(version.content.values_list("pk", flat=True))
signing_noop_pks = set(
DebPackageSigningResult.objects.filter(
result__in=[pk for pk in add_content_pks if pk in existing_pks],
).values_list("result", flat=True)
)
add_content_pks = [pk for pk in add_content_pks if pk not in signing_noop_pks]

super().check_content_overwrite(
version, add_content_pks, remove_content_pks=remove_content_pks
)

def initialize_new_version(self, new_version):
"""
Remove old metadata from the repo before performing anything else for the new version. This
Expand Down
10 changes: 8 additions & 2 deletions pulp_deb/app/tasks/signing.py
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@ def _sign_package(package, signing_service, signing_fingerprint, package_release


def signed_add_and_remove(
repository_pk, add_content_units, remove_content_units, base_version_pk=None
repository_pk, add_content_units, remove_content_units, base_version_pk=None, overwrite=True
):
repo = AptRepository.objects.get(pk=repository_pk)

Expand Down Expand Up @@ -270,4 +270,10 @@ async def _bounded_sign(pkg_tuple):
if str(new_prc.pk) not in add_content_units:
add_content_units.append(str(new_prc.pk))

return add_and_remove(repository_pk, add_content_units, remove_content_units, base_version_pk)
return add_and_remove(
repository_pk,
add_content_units,
remove_content_units,
base_version_pk,
overwrite=overwrite,
)
76 changes: 76 additions & 0 deletions pulp_deb/tests/functional/api/test_package_signing.py
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,82 @@ def test_signed_repo_modify(
assert [signed_package_href] == [pkg.pulp_href for pkg in results]


def test_signed_repo_modify_overwrite_false_noop(
tmp_path,
monitor_task,
signing_gpg_metadata,
deb_package_signing_service,
deb_repository_factory,
deb_package_factory,
deb_release_component_factory,
deb_package_release_component_factory,
apt_repository_api,
apt_package_api,
):
"""
Re-adding an unsigned package with overwrite=False should NOOP, not raise.

The first add transparently signs the package and caches the result. A second
add of the same unsigned package would normally produce the same signed
package (already in the version) and trigger the pulpcore overwrite check.
The deb-specific override should exempt this signing-NOOP case.
"""
_, fingerprint, _ = signing_gpg_metadata

repository = deb_repository_factory(
package_signing_service=deb_package_signing_service.pulp_href,
package_signing_fingerprint=fingerprint,
)

file_to_upload = shutil.copy(
get_local_package_absolute_path("frigg_1.0_ppc64.deb"),
tmp_path,
)
created_package = deb_package_factory(file=file_to_upload)
package_href = created_package.pulp_href

release_component = deb_release_component_factory(
distribution=str(uuid.uuid4()), component="main"
).pulp_href
prc = deb_package_release_component_factory(
package=package_href,
release_component=release_component,
).pulp_href

# First add: package gets signed and the result gets stored.
monitor_task(
apt_repository_api.modify(
repository.pulp_href,
{
"add_content_units": [package_href, release_component, prc],
"overwrite": False,
},
).task
)
repository = apt_repository_api.read(repository.pulp_href)
signed_package = apt_package_api.list(
repository_version=repository.latest_version_href
).results[0]
first_version_href = repository.latest_version_href

# Second add of the same unsigned package: should NOOP rather than raise
# ContentOverwriteError, because the already signed package is already present.
task_result = monitor_task(
apt_repository_api.modify(
repository.pulp_href,
{
"add_content_units": [package_href, release_component, prc],
"overwrite": False,
},
).task
)
repository = apt_repository_api.read(repository.pulp_href)
assert repository.latest_version_href == first_version_href
assert task_result.created_resources == []
results = apt_package_api.list(repository_version=repository.latest_version_href).results
assert [signed_package.pulp_href] == [pkg.pulp_href for pkg in results]


def test_already_signed_package(
tmp_path,
add_package_to_repo,
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ requires-python = ">=3.11"
dependencies = [
# All things django and asyncio are deliberately left to pulpcore
# Example transitive requirements: asgiref, asyncio, aiohttp
"pulpcore>=3.107.0,<3.115",
"pulpcore>=3.111.1,<3.115",
"python-debian>=0.1.44,<0.2.0",
"python-gnupg>=0.5,<0.6",
"jsonschema>=4.6,<5.0",
Expand Down
Loading