diff --git a/CHANGES/1272.feature b/CHANGES/1272.feature new file mode 100644 index 000000000..874b7ac70 --- /dev/null +++ b/CHANGES/1272.feature @@ -0,0 +1 @@ +Added support to vulnerability report for pulp_python plugin. diff --git a/pulp-glue/pulp_glue/common/context.py b/pulp-glue/pulp_glue/common/context.py index 77f3f521f..fff028eff 100644 --- a/pulp-glue/pulp_glue/common/context.py +++ b/pulp-glue/pulp_glue/common/context.py @@ -1417,6 +1417,10 @@ def repair(self) -> t.Any: """ return self.call("repair", parameters={self.HREF: self.pulp_href}, body={}) + def scan(self) -> t.Any: + self.needs_capability("scan") + return self.call("scan", parameters={self.HREF: self.pulp_href}) + class PulpRepositoryContext(PulpEntityContext): """Base class for repository contexts.""" diff --git a/pulp-glue/pulp_glue/core/context.py b/pulp-glue/pulp_glue/core/context.py index dcd514ec7..de4e7c4d6 100644 --- a/pulp-glue/pulp_glue/core/context.py +++ b/pulp-glue/pulp_glue/core/context.py @@ -618,3 +618,11 @@ def find(self, **kwargs: t.Any) -> t.Any: def replicate(self) -> t.Any: return self.call("replicate", parameters={self.HREF: self.pulp_href}) + + +class PulpVulnerabilityReportContext(PulpEntityContext): + ENTITY = _("vulnerability report") + ENTITIES = _("vulnerability reports") + ID_PREFIX = "vuln_report" + HREF = "vulnerability_report_href" + NEEDS_PLUGINS = [PluginRequirement("core", specifier=">=3.85.3")] diff --git a/pulp-glue/pulp_glue/python/context.py b/pulp-glue/pulp_glue/python/context.py index 38eec9fcb..acf1b6b34 100644 --- a/pulp-glue/pulp_glue/python/context.py +++ b/pulp-glue/pulp_glue/python/context.py @@ -101,6 +101,7 @@ class PulpPythonRepositoryVersionContext(PulpRepositoryVersionContext): HREF = "python_python_repository_version_href" ID_PREFIX = "repositories_python_python_versions" NEEDS_PLUGINS = [PluginRequirement("python", specifier=">=3.1.0")] + CAPABILITIES = {"scan": [PluginRequirement("python", specifier=">=3.21.0")]} class PulpPythonRepositoryContext(PulpRepositoryContext): diff --git a/pulp_cli/generic.py b/pulp_cli/generic.py index 2e8806cc5..72cfd1743 100644 --- a/pulp_cli/generic.py +++ b/pulp_cli/generic.py @@ -1515,7 +1515,7 @@ def version_command(**kwargs: t.Any) -> click.Command: """ A factory that creates a repository version command group. - This group contains `list`, `show`, `destroy` and `repair` subcommands. + This group contains `list`, `show`, `destroy`, `repair` and `scan` subcommands. If `list_only=True` is passed, only the `list` command will be instantiated. Repository lookup options can be provided in `decorators`. """ @@ -1549,6 +1549,19 @@ def repair( result = repository_version_ctx.repair() pulp_ctx.output_result(result) + @callback.command() + @repository_lookup_option + @version_option + @pass_repository_version_context + @pass_pulp_context + def scan( + pulp_ctx: PulpCLIContext, + repository_version_ctx: PulpRepositoryVersionContext, + /, + ) -> None: + result = repository_version_ctx.scan() + pulp_ctx.output_result(result) + return callback diff --git a/pulpcore/cli/core/__init__.py b/pulpcore/cli/core/__init__.py index 643b6775c..d57637cb8 100644 --- a/pulpcore/cli/core/__init__.py +++ b/pulpcore/cli/core/__init__.py @@ -25,6 +25,7 @@ from pulpcore.cli.core.upload import upload from pulpcore.cli.core.upstream_pulp import upstream_pulp from pulpcore.cli.core.user import user +from pulpcore.cli.core.vulnerability_report import vulnerability_report from pulpcore.cli.core.worker import worker @@ -52,6 +53,7 @@ def mount(main: click.Group, **kwargs: t.Any) -> None: main.add_command(upload) main.add_command(upstream_pulp) main.add_command(user) + main.add_command(vulnerability_report) main.add_command(worker) _orig_get_command = main.get_command diff --git a/pulpcore/cli/core/vulnerability_report.py b/pulpcore/cli/core/vulnerability_report.py new file mode 100644 index 000000000..c04415005 --- /dev/null +++ b/pulpcore/cli/core/vulnerability_report.py @@ -0,0 +1,28 @@ +import click +from pulp_glue.common.i18n import get_translation +from pulp_glue.core.context import PulpVulnerabilityReportContext + +from pulpcore.cli.common.generic import ( + PulpCLIContext, + href_option, + list_command, + pass_pulp_context, + pulp_group, + show_command, +) + +translation = get_translation(__package__) +_ = translation.gettext + +lookup_options = [href_option] + + +@pulp_group() +@pass_pulp_context +@click.pass_context +def vulnerability_report(ctx: click.Context, pulp_ctx: PulpCLIContext, /) -> None: + ctx.obj = PulpVulnerabilityReportContext(pulp_ctx) + + +vulnerability_report.add_command(list_command()) +vulnerability_report.add_command(show_command(decorators=lookup_options)) diff --git a/tests/scripts/pulp_python/test_vulnerability_report.sh b/tests/scripts/pulp_python/test_vulnerability_report.sh new file mode 100755 index 000000000..419cc108a --- /dev/null +++ b/tests/scripts/pulp_python/test_vulnerability_report.sh @@ -0,0 +1,29 @@ +#!/bin/bash + +set -eu +# shellcheck source=tests/scripts/config.source +. "$(dirname "$(dirname "$(realpath "$0")")")"/config.source + +cleanup() { + pulp python repository destroy --name python || true + pulp python remote destroy --name python || true + pulp file repository destroy --name file-repo || true + pulp orphan cleanup --protection-time=0 +} +trap cleanup EXIT + +pulp debug has-plugin --name "core" --specifier ">=3.85.3" || exit 0 +pulp debug has-plugin --name "python" --specifier ">=3.21.0" || exit 0 + +# create a test repository +pulp python repository create --name python +pulp python remote create --name python --url "https://pypi.org/" --includes '["django==5.2.1"]' +pulp python repository sync --name python --remote python + +expect_succ pulp python repository version scan --repository python +VULN_REPORT=$(echo "$OUTPUT" | jq .pulp_href -r) +expect_succ pulp vulnerability-report show --href "$VULN_REPORT" + +# test with non-implemented content type +pulp file repository create --name file-repo +expect_fail pulp file repository version scan --repository file-repo