Skip to content

feat: add Click-based CLI with full env var parity#128

Merged
vpetersson merged 17 commits intomasterfrom
cli-ification
Jan 18, 2026
Merged

feat: add Click-based CLI with full env var parity#128
vpetersson merged 17 commits intomasterfrom
cli-ification

Conversation

@vpetersson
Copy link
Contributor

Add a proper CLI interface using Click that provides command-line argument support while maintaining full backward compatibility with environment variable configuration.

Changes:

  • Add Click decorators to create CLI with all configuration options
  • Each CLI arg has corresponding env var fallback via Click's envvar
  • CLI args take precedence over environment variables
  • Refactor main.py: cli() -> build_config() -> run_pipeline()
  • Add --verbose/-v and --quiet/-q for log level control
  • Add --version flag
  • Add --telemetry/--no-telemetry to control Sentry
  • Extract helper functions for deprecated env var handling

The existing env var workflow (GitHub Action, Docker) continues to work unchanged since Click automatically reads from env vars when no CLI args are provided.

Usage examples:
sbomify-action --lock-file requirements.txt --enrich --no-upload
sbomify-action --docker-image nginx:latest -f spdx -o sbom.spdx.json

Add a proper CLI interface using Click that provides command-line
argument support while maintaining full backward compatibility with
environment variable configuration.

Changes:
- Add Click decorators to create CLI with all configuration options
- Each CLI arg has corresponding env var fallback via Click's envvar
- CLI args take precedence over environment variables
- Refactor main.py: cli() -> build_config() -> run_pipeline()
- Add --verbose/-v and --quiet/-q for log level control
- Add --version flag
- Add --telemetry/--no-telemetry to control Sentry
- Extract helper functions for deprecated env var handling

The existing env var workflow (GitHub Action, Docker) continues to
work unchanged since Click automatically reads from env vars when
no CLI args are provided.

Usage examples:
  sbomify-action --lock-file requirements.txt --enrich --no-upload
  sbomify-action --docker-image nginx:latest -f spdx -o sbom.spdx.json
Copilot AI review requested due to automatic review settings January 18, 2026 18:12
Copy link
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 adds a Click-based CLI to sbomify-action while maintaining full backward compatibility with the existing environment variable workflow. The refactoring separates configuration building from pipeline execution, enabling both CLI argument and environment variable-based configuration.

Changes:

  • Introduced Click decorators for CLI with comprehensive options matching all existing env vars
  • Refactored main.py to separate concerns: cli()build_config()run_pipeline()
  • Added helper functions for deprecated env var handling and upload destination parsing

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
sbomify_action/cli/main.py Added Click CLI with all configuration options, refactored main() to use cli(), extracted build_config() and run_pipeline() functions
sbomify_action/cli/init.py Added module exports for new CLI functions
tests/test_cli.py Comprehensive test suite for CLI argument parsing, env var fallback, boolean flags, and deprecated env var handling
tests/test_config.py Added tests for build_config() function and parity testing with load_config()
tests/test_integration.py Updated integration test to use CliRunner and CLI arguments instead of environment variables

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

- Fix parameter naming mismatch: rename CLI function parameter from
  `product_release` to `product_releases` to match internal field name
- Add explicit mapping in Click option decorator for clarity
- Expand test coverage for evaluate_boolean case sensitivity (Yes, YES,
  Yeah, YEAH)

The CLI option remains `--product-release` (singular) to maintain parity
with the PRODUCT_RELEASE environment variable.
The __init__.py exports `main` (the function), which shadows the `main`
module when using standard import syntax. This caused patch decorators
like `@patch("sbomify_action.cli.main.initialize_sentry")` to fail on
Python 3.10 in CI because Python resolved the path to the function
instead of the module.

Fix by using `importlib.import_module()` to explicitly import the module
and `patch.object()` with the module reference for all test patches.
Copilot AI review requested due to automatic review settings January 18, 2026 18:39
Copy link
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

Copilot reviewed 5 out of 5 changed files in this pull request and generated 1 comment.

Comments suppressed due to low confidence (1)

tests/test_config.py:1

  • The cleanup file list has grown to six files. Consider extracting this list to a class-level constant to avoid duplication if other test methods need the same cleanup logic, and to make it easier to maintain when new temporary files are added.
import os

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

@vpetersson vpetersson requested a review from Copilot January 18, 2026 18:46
Copy link
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

Copilot reviewed 5 out of 5 changed files in this pull request and generated 3 comments.


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

… data

Ensures full parity between CycloneDX and SPDX for both license
sanitization and CLE lifecycle enrichment. Previously, SPDX SBOMs
from Syft would fail validation due to invalid license IDs and
would not receive lifecycle data during enrichment.

Changes:
- Add `_sanitize_spdx_license_expression()` using license-expression
  library for proper SPDX expression parsing
- Extend `sanitize_cyclonedx_licenses()` to handle expression fields
- Add `sanitize_spdx_licenses()` for SPDX format parity
- Add pre-validation sanitization in generator registry
- Add `_enrich_spdx_os_packages()` for SPDX lifecycle enrichment
  (handles both Trivy OPERATING_SYSTEM and Syft CONTAINER fallback)
- Add lifecycle data for openSUSE Leap, Oracle Linux
- Add CentOS Stream version mapping and distro aliases
- Replace test data with comprehensive 28-distro × 3-tool dataset
- Add comprehensive SBOM analysis and generation scripts

Invalid licenses sanitized:
- GPL-2.0-with-classpath-exception (deprecated)
- GPL-3.0-with-GCC-exception (deprecated)
- SMAIL-GPL (non-standard)

Results:
- License sanitization: 24 invalid → 0 remaining
- CycloneDX lifecycle: 50/85 (59%)
- SPDX lifecycle: 43/57 (75%, up from 44%)
- Use logger.setLevel() instead of logging.getLogger().setLevel()
  for consistency with how logger is used elsewhere
- Simplify evaluate_boolean tests by reducing redundant case variations
  (function uses .lower() so testing all cases is unnecessary)
- Split test into separate methods for clarity
New ASCII art banner that includes "Action" in the branding while
maintaining the same gradient color scheme (blue -> purple -> pink
-> peach -> orange).
@vpetersson vpetersson requested a review from Copilot January 18, 2026 20:30
Copy link
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

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


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

- Extract VALID_SBOM_FORMATS constant to avoid duplication between
  CLI validation and Config.validate()
- Add test_false_values_case_insensitive() for complete case coverage
- Both CLI and config validation now use the shared constant
@vpetersson vpetersson requested a review from Copilot January 18, 2026 20:35
Copy link
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

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


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

- Use <your-token> placeholder instead of $TOKEN for cross-platform docs
- Add _make_bool_envvar_callback() for proper string-to-bool conversion
  of environment variables (e.g., UPLOAD="true" now works correctly)
- Clarify comment about module imports in test_cli.py
- Add test_mixed_case_values() for complete case-sensitivity coverage
@vpetersson vpetersson requested a review from Copilot January 18, 2026 20:40
feat: add CDX/SPDX license sanitization parity and expanded lifecycle data
Copy link
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

Copilot reviewed 34 out of 168 changed files in this pull request and generated 2 comments.


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

- Use "sbomify Action" for prog_name to match banner capitalization
- Update test_version_option to expect "sbomify Action"
- Remove test_mixed_case_values (redundant with case-insensitive tests)
- Update CONTAINER_IMAGES to use new versioned file names
- Change file pattern from {image}-tool.format.json to {image}_tool.format.json
- Replace redhat with fedora_41 (no redhat test data available)
- Update docstring to reflect tested images
Copilot AI review requested due to automatic review settings January 18, 2026 20:48
Copy link
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

Copilot reviewed 34 out of 169 changed files in this pull request and generated no new comments.


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

- Move _format_display_name helper to top of file for early use
- Replace .upper() with _format_display_name() for proper capitalization
- Output now shows "CycloneDX" instead of "CYCLONEDX"
Add canonical format_display_name() to sbomify_action/__init__.py and
use it everywhere SBOM format is displayed to users:

- cli/main.py: import shared function, remove local duplicate
- enrichment.py: validation log messages
- generation.py: generation success message
- validation.py: validation success message
- _generation/registry.py: validation success message
- _generation/generators/trivy.py: scanner log messages
- _generation/generators/syft.py: scanner log messages
- _upload/orchestrator.py: upload log message

All format displays now show "CycloneDX" or "SPDX" with proper
capitalization instead of "cyclonedx" or "CYCLONEDX".
@vpetersson vpetersson merged commit 531192f into master Jan 18, 2026
11 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant