feat: add Click-based CLI with full env var parity#128
Conversation
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
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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).
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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
feat: add CDX/SPDX license sanitization parity and expanded lifecycle data
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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".
Add a proper CLI interface using Click that provides command-line argument support while maintaining full backward compatibility with environment variable configuration.
Changes:
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