From d72e21cc19acab9516670d2bd669d8363d8a0146 Mon Sep 17 00:00:00 2001 From: sbp-bvanb Date: Sat, 21 Mar 2026 23:39:33 +0100 Subject: [PATCH 1/3] docs: add CLAUDE.md and remove incorrect Trivy references - Add CLAUDE.md for Claude Code guidance on architecture and workflows - Remove non-existent Trivy inputs from README (action uses Anchore) - Remove unused Trivy scanning steps from action.yml - Update dependabot to weekly schedule with grouped updates - Add release and license badges to README Co-Authored-By: Claude Opus 4.6 --- .github/dependabot.yml | 12 +++-- CLAUDE.md | 112 +++++++++++++++++++++++++++++++++++++++++ README.md | 13 ++--- action.yml | 31 ++---------- 4 files changed, 132 insertions(+), 36 deletions(-) create mode 100644 CLAUDE.md diff --git a/.github/dependabot.yml b/.github/dependabot.yml index f253916..1220252 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -1,7 +1,13 @@ --- version: 2 updates: - - package-ecosystem: 'github-actions' - directory: '/' + - package-ecosystem: github-actions + directory: / schedule: - interval: 'daily' + interval: weekly + cooldown: + default-days: 5 + groups: + github-actions-all: + patterns: + - "*" diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..abfb040 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,112 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Project Overview + +This is a **composite GitHub Action** (not a standalone application) that provides the Mission Critical Vulnerability Scanner (MCVS) for Python projects. The action performs security scanning, linting, testing, and optional binary building for Python codebases. + +## Architecture + +### Composite Action Structure + +The action is defined in `action.yml` and executes as a series of composite steps: + +1. **YAML Linting**: Validates YAML files using yamllint +2. **Python Environment Setup**: Installs Python version from `.python-version` +3. **Security Scanning**: Uses Anchore scan-action to detect vulnerabilities +4. **Dependency Installation**: Installs packages from `requirements.txt` if present +5. **Testing**: Runs pytest if tests are detected +6. **Code Linting**: Uses Flake8 with a configurable error threshold +7. **Binary Building**: Conditionally builds PyInstaller binaries on tag releases + +### Key Design Decisions + +- **Composite vs Docker**: Uses `using: composite` to avoid Docker overhead and enable caching +- **Conditional Execution**: Steps like testing and binary building only run when applicable +- **Token Authentication**: Requires GitHub token for package registry and Docker registry access +- **Version Pinning**: All tools are pinned to specific versions for reproducibility + +## Version Constraints + +**CRITICAL**: The following versions are pinned in `action.yml`: + +- `yamllint==1.37.1` (action.yml:21) +- `actions/setup-python@v5.6.0` (action.yml:28) +- `anchore/scan-action@v6.2.0` (action.yml:34) +- `flake8==7.2.0` (action.yml:75) +- `pyinstaller==v6.13.0` (action.yml:102) +- `svenstaro/upload-release-action@2.9.0` (action.yml:106) + +When updating dependencies: +- Update the version in `action.yml` +- Dependabot automatically creates PRs for GitHub Actions updates (see `.github/dependabot.yml`) +- Python package versions must be updated manually + +## Testing Changes + +This action is tested via PR validation: + +```yaml +# Validation happens automatically on PRs via .github/workflows/mcvs-pr-validation.yml +# Uses schubergphilis/mcvs-pr-validation-action@v0.2.0 +``` + +To test locally before committing: + +```bash +# Test YAML linting (matches action behavior) +pip install yamllint==1.37.1 +yamllint . + +# Validate action.yml structure +# No local validation tool - rely on PR validation workflow +``` + +## Dependency Management + +### Dependabot Configuration + +Dependabot is configured for GitHub Actions only (`.github/dependabot.yml`): +- Runs weekly checks +- 5-day cooldown between updates +- Groups all GitHub Actions updates together + +**Note**: Python package dependencies (yamllint, flake8, pyinstaller) are NOT managed by Dependabot and must be updated manually in `action.yml`. + +## Flake8 Configuration + +The action has a **configurable error threshold** for Flake8: + +```bash +# Current threshold: 4 errors/warnings maximum +--max-line-length=150 +--exclude=client/,.venv/,venv/ +``` + +Pipeline fails if error count > 4 (action.yml:81-83). This threshold may need adjustment when adding strict linting rules. + +## PyInstaller Binary Building + +Binary building is **conditional** and requires: +1. Push event to a tag (`refs/tags/*`) +2. Non-empty `pyinstaller-binary-name` input + +The binary is automatically attached to GitHub releases (action.yml:89-111). + +## Action Inputs + +Required inputs when using this action: + +| Input | Required | Purpose | +|-------|----------|---------| +| `token` | Yes | GitHub token for package registry and Docker login | +| `pyinstaller-binary-name` | No | If set, builds and releases a binary | + +## Important Workflow Notes + +- Projects using this action must have a `.python-version` file to specify Python version +- `requirements.txt` is optional - only installed if present +- Tests only run if `import pytest` is found in Python files +- Security scanning uses severity cutoff of "high" (action.yml:39) +- Docker login required for security scanning (action.yml:40-44) diff --git a/README.md b/README.md index d50b220..0ab9bce 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,8 @@ # MCVS-python-action +[![GitHub release](https://img.shields.io/github/v/release/schubergphilis/mcvs-python-action)](https://github.com/schubergphilis/mcvs-python-action/releases) +[![License](https://img.shields.io/github/license/schubergphilis/mcvs-python-action)](LICENSE) + Mission Critical Vulnerability Scanner (MCVS) Python Action. Create Python code without high and critical vulnerabilities. ## Usage @@ -24,12 +27,10 @@ jobs: -| Option | Default | Required | Description | -| :---------------------- | :----------------------------------- | -------- | :---------------------------------------------------------------------------------------------------------------- | -| pyinstaller-binary-name | | | If populated, then a binary will be created using pyinstaller and attached to a release | -| token | ' ' | x | GitHub token that is required to push a package to the registry of the project and to pull cached Trivy DB images | -| trivy-action-db | ghcr.io/aquasecurity/trivy-db:2 | | Replace this with a cached image to prevent bump into pull rate limiting issues | -| trivy-action-java-db | ghcr.io/aquasecurity/trivy-java-db:1 | | Replace this with a cached image to prevent bump into pull rate limiting issues | +| Option | Default | Required | Description | +| :---------------------- | :------ | -------- | :--------------------------------------------------------------------------------------------------------- | +| pyinstaller-binary-name | | | If populated, then a binary will be created using pyinstaller and attached to a release | +| token | | x | GitHub token required for Docker registry authentication and uploading release assets (if building binary) | diff --git a/action.yml b/action.yml index 414642d..1a1cdf6 100644 --- a/action.yml +++ b/action.yml @@ -5,23 +5,14 @@ description: | inputs: pyinstaller-binary-name: description: The name of the binary that is created using pyinstaller. - trivy-action-db: - default: 'ghcr.io/aquasecurity/trivy-db:2' - description: | - OCI repository to retrieve trivy-db from. - trivy-action-java-db: - description: | - OCI repository to retrieve trivy-java-db from. - default: 'ghcr.io/aquasecurity/trivy-java-db:1' token: description: | A token is required to allow the mcvs-python-action to push the package that it has been built, to the packages repository of the GitHub - repository where the action has been run and to pull the cached trivy DBs - to prevent bump into pull rate limits. + repository where the action has been run. required: true runs: - using: 'composite' + using: composite steps: # # YAML linting. @@ -36,7 +27,7 @@ runs: # - uses: actions/setup-python@v5.6.0 with: - cache: 'pip' + cache: "pip" # # Code security scanning. # @@ -44,27 +35,13 @@ runs: with: only-fixed: false output-format: table - path: '.' + path: "." severity-cutoff: high - - uses: 030/trivyignore-validator-action@v0.1.2 - name: Log in to GitHub Packages Docker registry shell: bash run: | echo "${{ inputs.token }}" |\ docker login ghcr.io -u ${{ github.actor }} --password-stdin - - uses: aquasecurity/trivy-action@0.30.0 - env: - TRIVY_DB_REPOSITORY: ${{ inputs.trivy-action-db }} - TRIVY_JAVA_DB_REPOSITORY: ${{ inputs.trivy-action-java-db }} - TRIVY_PASSWORD: ${{ inputs.token }} - TRIVY_USERNAME: ${{ github.actor }} - with: - scan-type: 'fs' - scan-ref: '.' - exit-code: '1' - ignore-unfixed: true - severity: 'CRITICAL,HIGH' - trivyignores: .trivyignore # # If a requirements file exists in the project, then install the packages. # From ab50236444d3e3d7716c65fef1b03ce09b775103 Mon Sep 17 00:00:00 2001 From: sbp-bvanb Date: Sat, 21 Mar 2026 23:46:36 +0100 Subject: [PATCH 2/3] build: use general action to check git lint etc --- .github/workflows/general.yml | 22 ++++++++++++++++++++++ .github/workflows/mcvs-pr-validation.yml | 4 ++-- action.yml | 24 ++++++------------------ 3 files changed, 30 insertions(+), 20 deletions(-) create mode 100644 .github/workflows/general.yml diff --git a/.github/workflows/general.yml b/.github/workflows/general.yml new file mode 100644 index 0000000..4800f1c --- /dev/null +++ b/.github/workflows/general.yml @@ -0,0 +1,22 @@ +--- +name: general +"on": pull_request +permissions: + contents: read + packages: read +jobs: + MCVS-general-action: + strategy: + matrix: + args: + - testing-type: lint-commit + - testing-type: lint-git + - testing-type: security-file-system + - testing-type: yamllint + runs-on: ubuntu-slim + steps: + - uses: actions/checkout@v6.0.2 + # yamllint disable-line rule:line-length + - uses: schubergphilis/mcvs-general-action@f52c4433add29d8eff9036bf37b5b69a2c4cf28b # v0.5.8 + with: + testing-type: ${{ matrix.args.testing-type }} diff --git a/.github/workflows/mcvs-pr-validation.yml b/.github/workflows/mcvs-pr-validation.yml index 216ce24..ddddd42 100644 --- a/.github/workflows/mcvs-pr-validation.yml +++ b/.github/workflows/mcvs-pr-validation.yml @@ -1,6 +1,6 @@ --- name: MCVS-PR-validation-action -'on': +"on": pull_request: types: - edited @@ -13,7 +13,7 @@ permissions: pull-requests: read jobs: MCVS-PR-validation-action: - runs-on: ubuntu-22.04 + runs-on: ubuntu-slim steps: - uses: actions/checkout@v4.2.2 - uses: schubergphilis/mcvs-pr-validation-action@v0.2.0 diff --git a/action.yml b/action.yml index 1a1cdf6..dcd3622 100644 --- a/action.yml +++ b/action.yml @@ -15,33 +15,21 @@ runs: using: composite steps: # - # YAML linting. - # - - run: | - pip install --user yamllint==1.37.1 - yamllint . - shell: bash - # # Install the python version that has been defined in the .python-version # file. # - - uses: actions/setup-python@v5.6.0 + - uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 with: - cache: "pip" + cache: pip # # Code security scanning. # - - uses: anchore/scan-action@v6.2.0 + - uses: anchore/scan-action@e1165082ffb1fe366ebaf02d8526e7c4989ea9d2 # v6.2.0 with: only-fixed: false output-format: table - path: "." + path: . severity-cutoff: high - - name: Log in to GitHub Packages Docker registry - shell: bash - run: | - echo "${{ inputs.token }}" |\ - docker login ghcr.io -u ${{ github.actor }} --password-stdin # # If a requirements file exists in the project, then install the packages. # @@ -69,6 +57,7 @@ runs: # # Lint code with Flake8 # + # yamllint disable rule:line-length - name: Code linting with Flake8 shell: bash run: | @@ -88,7 +77,6 @@ runs: # Build binary using pyinstaller and attach it to a release once a tag has # been created. # - # yamllint disable rule:line-length - name: Check Conditions id: condition_check run: echo "Checking conditions..." @@ -103,7 +91,7 @@ runs: pyinstaller --onefile main.py --name gomod-go-version-updater - name: Attach a binary to a release if: ${{ steps.condition_check.outcome == 'success' }} - uses: svenstaro/upload-release-action@2.9.0 + uses: svenstaro/upload-release-action@04733e069f2d7f7f0b4aebc4fbdbce8613b03ccd # 2.9.0 with: repo_token: ${{ inputs.token }} file: dist/${{ inputs.pyinstaller-binary-name }} From a07d7b40bc36fb54bc4908a7493e40394a753046 Mon Sep 17 00:00:00 2001 From: sbp-bvanb Date: Sun, 22 Mar 2026 14:01:03 +0100 Subject: [PATCH 3/3] fix: install pyinstaller and flake8 using a hash for security reasons --- .github/dependabot.yml | 20 ++++++++++++++++++++ .github/workflows/general.yml | 2 +- .github/workflows/mcvs-pr-validation.yml | 5 +++-- .github/workflows/python.yml | 14 ++++++++++++++ README.md | 4 ++-- action.yml | 20 ++++++++++++++++---- configs/pip/flake8/requirements.txt | 4 ++++ configs/pip/pyinstaller/requirements.txt | 1 + 8 files changed, 61 insertions(+), 9 deletions(-) create mode 100644 .github/workflows/python.yml create mode 100644 configs/pip/flake8/requirements.txt create mode 100644 configs/pip/pyinstaller/requirements.txt diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 1220252..e9c9aa9 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -11,3 +11,23 @@ updates: github-actions-all: patterns: - "*" + - package-ecosystem: pip + directory: /configs/pip/flake8 + schedule: + interval: weekly + cooldown: + default-days: 5 + groups: + github-actions-all: + patterns: + - "*" + - package-ecosystem: pip + directory: /configs/pip/pyinstaller + schedule: + interval: weekly + cooldown: + default-days: 5 + groups: + github-actions-all: + patterns: + - "*" diff --git a/.github/workflows/general.yml b/.github/workflows/general.yml index 4800f1c..1f5658b 100644 --- a/.github/workflows/general.yml +++ b/.github/workflows/general.yml @@ -15,7 +15,7 @@ jobs: - testing-type: yamllint runs-on: ubuntu-slim steps: - - uses: actions/checkout@v6.0.2 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 # yamllint disable-line rule:line-length - uses: schubergphilis/mcvs-general-action@f52c4433add29d8eff9036bf37b5b69a2c4cf28b # v0.5.8 with: diff --git a/.github/workflows/mcvs-pr-validation.yml b/.github/workflows/mcvs-pr-validation.yml index ddddd42..2c5f07a 100644 --- a/.github/workflows/mcvs-pr-validation.yml +++ b/.github/workflows/mcvs-pr-validation.yml @@ -15,5 +15,6 @@ jobs: MCVS-PR-validation-action: runs-on: ubuntu-slim steps: - - uses: actions/checkout@v4.2.2 - - uses: schubergphilis/mcvs-pr-validation-action@v0.2.0 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + # yamllint disable-line rule:line-length + - uses: schubergphilis/mcvs-pr-validation-action@b1c337a896fea52b52a93335713a435d5a07ea72 # v0.2.0 diff --git a/.github/workflows/python.yml b/.github/workflows/python.yml new file mode 100644 index 0000000..e5b42de --- /dev/null +++ b/.github/workflows/python.yml @@ -0,0 +1,14 @@ +--- +name: python +"on": pull_request +permissions: + contents: read + packages: read +jobs: + mcvs-python-action: + runs-on: ubuntu-slim + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: ./ + with: + token: ${{ secrets.GITHUB_TOKEN }} diff --git a/README.md b/README.md index 0ab9bce..f4282e7 100644 --- a/README.md +++ b/README.md @@ -19,8 +19,8 @@ jobs: MCVS-python-action: runs-on: ubuntu-24.04 steps: - - uses: actions/checkout@v4.2.2 - - uses: schubergphilis/mcvs-python-action@v0.2.1 + - uses: actions/checkout@some-hash # v4.2.2 + - uses: schubergphilis/mcvs-python-action@some-hash # v0.2.1 with: token: ${{ secrets.GITHUB_TOKEN }} ``` diff --git a/action.yml b/action.yml index dcd3622..7aa69e5 100644 --- a/action.yml +++ b/action.yml @@ -18,12 +18,14 @@ runs: # Install the python version that has been defined in the .python-version # file. # + # yamllint disable-line rule:line-length - uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 with: cache: pip # # Code security scanning. # + # yamllint disable-line rule:line-length - uses: anchore/scan-action@e1165082ffb1fe366ebaf02d8526e7c4989ea9d2 # v6.2.0 with: only-fixed: false @@ -39,7 +41,7 @@ runs: requirements_file=requirements.txt if [ -f ${requirements_file} ]; then pip install \ - -r ${requirements_file} + --requirement ${requirements_file} fi # # Run pytest if 'import pytest' is found. @@ -61,7 +63,11 @@ runs: - name: Code linting with Flake8 shell: bash run: | - pip install flake8==7.2.0 + python3 -m pip install \ + --require-hashes \ + --user \ + --requirement \ + ${GITHUB_ACTION_PATH}/configs/pip/flake8/requirements.txt errors=$(flake8 -v --max-line-length=150 --exclude=client/,.venv/,venv/ --count --statistics --exit-zero .) echo "Flake8 reported $errors errors/warnings." @@ -88,10 +94,16 @@ runs: shell: bash run: | pip install pyinstaller==v6.13.0 + python3 -m pip install \ + --require-hashes \ + --user \ + --requirement \ + ${GITHUB_ACTION_PATH}/configs/pip/pyinstaller/requirements.txt pyinstaller --onefile main.py --name gomod-go-version-updater - - name: Attach a binary to a release + # yamllint disable-line rule:line-length + - uses: svenstaro/upload-release-action@04733e069f2d7f7f0b4aebc4fbdbce8613b03ccd # 2.9.0 + name: Attach a binary to a release if: ${{ steps.condition_check.outcome == 'success' }} - uses: svenstaro/upload-release-action@04733e069f2d7f7f0b4aebc4fbdbce8613b03ccd # 2.9.0 with: repo_token: ${{ inputs.token }} file: dist/${{ inputs.pyinstaller-binary-name }} diff --git a/configs/pip/flake8/requirements.txt b/configs/pip/flake8/requirements.txt new file mode 100644 index 0000000..df3e101 --- /dev/null +++ b/configs/pip/flake8/requirements.txt @@ -0,0 +1,4 @@ +flake8==7.2.0 --hash=sha256:93b92ba5bdb60754a6da14fa3b93a9361fd00a59632ada61fd7b130436c40343 +pycodestyle==2.13.0 --hash=sha256:35863c5974a271c7a726ed228a14a4f6daf49df369d8c50cd9a6f58a5e143ba9 +pyflakes==3.3.2 --hash=sha256:5039c8339cbb1944045f4ee5466908906180f13cc99cc9949348d10f82a5c32a +mccabe==0.7.0 --hash=sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e diff --git a/configs/pip/pyinstaller/requirements.txt b/configs/pip/pyinstaller/requirements.txt new file mode 100644 index 0000000..108e259 --- /dev/null +++ b/configs/pip/pyinstaller/requirements.txt @@ -0,0 +1 @@ +pyinstaller==v6.13.0 --hash=sha256:bc09795f5954135dd4486c1535650958c8218acb954f43860e4b05fb515a21c0