Skip to content

Add repository-level vulnerability summary to vulnerabilities command#282

Open
colinmoynes wants to merge 10 commits intomasterfrom
ceng-747-cloudsmith-cli-repo-level-vulnerability-summary-for
Open

Add repository-level vulnerability summary to vulnerabilities command#282
colinmoynes wants to merge 10 commits intomasterfrom
ceng-747-cloudsmith-cli-repo-level-vulnerability-summary-for

Conversation

@colinmoynes
Copy link
Copy Markdown
Contributor

@colinmoynes colinmoynes commented Mar 27, 2026

This pull request introduces improvements to the vulnerability command. It adds a repository-level vulnerability summary capability, allowing users to aggregate and filter vulnerability data across all packages in a repository.

Type of Change

  • Bug fix
  • New feature
  • Breaking change
  • Documentation update
  • Refactoring
  • Other (please describe)

Additional Notes

@colinmoynes colinmoynes requested a review from a team as a code owner March 27, 2026 16:53
Copilot AI review requested due to automatic review settings March 27, 2026 16:53
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR expands the CLI’s vulnerability reporting to support repository-level aggregation, and also introduces download-command enhancements (filename filtering and multi-package downloads), along with associated version/dependency bumps.

Changes:

  • Add cloudsmith vulnerabilities OWNER/REPO mode to aggregate vulnerability counts across all packages in a repository (with filtering and JSON output).
  • Enhance cloudsmith download with --filename filtering (including glob patterns) and --download-all, plus improved multi-match display.
  • Bump CLI version metadata to 1.16.0 and update cloudsmith-api dependency to 2.0.25.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
cloudsmith_cli/cli/commands/vulnerabilities.py Adds repo-level summary mode, aggregation/filtering, and rich table output.
cloudsmith_cli/core/api/vulnerabilities.py Updates summary table rendering and adjusts scan identifier handling.
cloudsmith_cli/cli/validators.py Adds validator to accept OWNER/REPO[/SLUG_PERM] for vulnerabilities command arg.
cloudsmith_cli/core/download.py Adds filename filtering (server/client side) and refactors multi-match output via rich table; adds resolve-all helper.
cloudsmith_cli/cli/commands/download.py Adds --filename and --download-all, refactors download flow, and adds safe path joining.
cloudsmith_cli/core/tests/test_download.py Adds unit tests for filename filtering, resolve-all behavior, and multi-match display.
cloudsmith_cli/cli/tests/commands/test_download.py Adds integration-style CLI tests for new download flags/behavior.
cloudsmith_cli/cli/commands/upstream.py Adds alpine to supported upstream formats list.
README.md Documents new download flags (--filename, --download-all).
CHANGELOG.md Adds entries for new features/releases (but currently with duplicated 1.14.0 sections).
setup.py / requirements.txt Bumps cloudsmith-api dependency from 2.0.24 to 2.0.25.
cloudsmith_cli/data/VERSION / .bumpversion.cfg Bumps version to 1.16.0.
Comments suppressed due to low confidence (2)

CHANGELOG.md:60

  • The changelog now contains two separate ## [1.14.0] sections (with different dates), which makes it ambiguous which entry is authoritative. Consider consolidating these into a single 1.14.0 section (or correcting the version/date as appropriate).
## [1.14.0] - 2026-03-11

### Added

- Added `vulnerabilities` command to retrieve security scan results for a package
  - Summary View (Default): Displays a high-level count of vulnerabilities broken down by severity (Critical, High, Medium, Low, Unknown).
  - Assessment View `--show-assessment` (`-A`): Provides a detailed breakdown where vulnerabilities are:
    - Grouped by the specific affected upstream package / dependency.
    - Sorted by severity (Critical first).
    - Richly formatted tables.
  - Filtering Capabilities:
    - By Severity: `--severity` Show only specific levels (e.g., just Critical and High).
    - By Status: `--fixable | --non-fixable` Filter to show only "Fixable" vulnerabilities (where a patch exists) or "Non-Fixable" ones.
  - Supports `--output-format json | pretty_json` for programmatic usage

## [1.14.0] - 2026-03-13

### Added

- Added `vulnerabilities` command to retrieve security scan results for a package
  - Summary View (Default): Displays a high-level count of vulnerabilities broken down by severity (Critical, High, Medium, Low, Unknown).
  - Assessment View `--show-assessment` (`-A`): Provides a detailed breakdown where vulnerabilities are:
    - Grouped by the specific affected upstream package / dependency.
    - Sorted by severity (Critical first).
    - Richly formatted tables.
  - Filtering Capabilities:

CHANGELOG.md:23

  • cloudsmith_cli/data/VERSION and .bumpversion.cfg are bumped to 1.16.0, but the new vulnerability summary entry is still under [Unreleased] rather than the 1.16.0 release section. If this change is part of 1.16.0, consider moving it into the ## [1.16.0] section; otherwise consider not bumping the version yet.
## [Unreleased]

### Added

- Added repository-level vulnerability summary (`cloudsmith vulnerabilities OWNER/REPO`)
  - Aggregates scan results across all packages into a single color-coded table
  - Packages sorted by total vulnerability count (descending)
  - Packages without scan results are silently omitted
  - Supports `--severity` and `--fixable/--non-fixable` filters

## [1.16.0] - 2026-03-24

### Added

- Added Alpine Upstream support for managing upstream configurations.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +22 to +31
try:
packages, _ = list_packages(
opts=opts, owner=owner, repo=repo, query=None, sort=None
)
except Exception as exc:
raise click.ClickException(
f"Failed to list packages for '{owner}/{repo}'. "
f"Please check the owner and repository names are correct. "
f"Detail: {exc}"
) from exc
Copy link

Copilot AI Mar 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Catching a broad Exception here and re-raising click.ClickException bypasses handle_api_exceptions, which is responsible for structured JSON errors when --output-format json|pretty_json is used. To keep error output consistent across the CLI, consider either wrapping the API call in handle_api_exceptions(...) (pass ctx into this helper) or letting ApiException propagate to a higher-level handler instead of converting everything into a ClickException.

Suggested change
try:
packages, _ = list_packages(
opts=opts, owner=owner, repo=repo, query=None, sort=None
)
except Exception as exc:
raise click.ClickException(
f"Failed to list packages for '{owner}/{repo}'. "
f"Please check the owner and repository names are correct. "
f"Detail: {exc}"
) from exc
packages, _ = list_packages(
opts=opts,
owner=owner,
repo=repo,
query=None,
sort=None,
)

Copilot uses AI. Check for mistakes.
Comment on lines +330 to +368
# Repo summary mode: collect with progress bar, then output once
if repo_summary:
slugs = get_packages_in_repo(opts, owner, repo)

repo_summary_rows = _collect_repo_scan_data(
opts, owner, repo, slugs, severity_filter, fixable
)

if not repo_summary_rows:
click.secho(
f"No vulnerability scan results found for any packages "
f"in '{owner}/{repo}'.",
fg="yellow",
err=use_stderr,
)
return

json_output = {
"owner": owner,
"repository": repo,
"packages": [
{
"slug_perm": slug_perm,
"package": label,
"vulnerabilities": counts,
}
for slug_perm, label, counts in repo_summary_rows
],
}

if utils.maybe_print_as_json(opts, json_output):
return

# Table only needs label and counts
_print_repo_summary_table(
[(label, counts) for _, label, counts in repo_summary_rows],
severity_filter,
)
return
Copy link

Copilot AI Mar 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The repo-level summary path (cloudsmith vulnerabilities OWNER/REPO) introduces new behavior (listing packages, aggregating counts, filtering, JSON shape), but the existing CLI tests only cover the single-package invocation. Consider adding tests for the OWNER/REPO mode (including pagination/multiple packages, empty repo, and --show-assessment rejection).

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will add this shortly.

Comment on lines +238 to 244
if not data:
# click.echo(
# f"No vulnerability scan results found for package: {package}", err=True
# )
return None

return data[0].identifier
Copy link

Copilot AI Mar 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

get_package_scan_identifier() now returns None when no scan results exist, but get_package_scan_result() still uses the returned value as the identifier parameter for vulnerabilities_read_with_http_info(...). Unless None is explicitly supported by the API, this will likely turn a "no scan" situation into an API error. Consider handling the None return in get_package_scan_result() (e.g., return None early) so the CLI can display the intended "No scan results found" message.

Copilot uses AI. Check for mistakes.
Comment on lines 374 to +389
@@ -92,45 +382,43 @@ def vulnerabilities(
severity_filter=severity_filter,
fixable=fixable,
)
except Exception as exc: # pylint: disable=broad-exception-caught
raise click.ClickException(
f"Failed to retrieve vulnerability report for "
f"'{owner}/{repo}/{slug}': {exc}"
) from exc
Copy link

Copilot AI Mar 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This broad except Exception + ClickException re-wrap can break the CLI’s standard API error handling (notably JSON-formatted error responses via handle_api_exceptions) and also makes it harder to distinguish API failures from "no scan results". Consider using handle_api_exceptions(ctx, ...) around get_package_scan_result() (as other commands do) and only handling the "no scan" case via return values.

Copilot uses AI. Check for mistakes.
Comment on lines +371 to +373
slugs = [slug]
data = None

Copy link

Copilot AI Mar 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

slugs = [slug] is assigned but never used in single-package mode. Removing it would avoid dead code and keep the command logic clearer.

Suggested change
slugs = [slug]
data = None

Copilot uses AI. Check for mistakes.
@colinmoynes colinmoynes force-pushed the ceng-747-cloudsmith-cli-repo-level-vulnerability-summary-for branch from 842b05e to df3070c Compare March 27, 2026 17:03
@colinmoynes colinmoynes force-pushed the ceng-747-cloudsmith-cli-repo-level-vulnerability-summary-for branch from df3070c to 0f5ee19 Compare March 27, 2026 17:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Development

Successfully merging this pull request may close these issues.

2 participants