Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 29 additions & 3 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,33 @@
---
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:
- "*"
- 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:
- "*"
22 changes: 22 additions & 0 deletions .github/workflows/general.yml
Original file line number Diff line number Diff line change
@@ -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@de0fac2e4500dabe0009e67214ff5f5447ce83dd # 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 }}
9 changes: 5 additions & 4 deletions .github/workflows/mcvs-pr-validation.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
name: MCVS-PR-validation-action
'on':
"on":
pull_request:
types:
- edited
Expand All @@ -13,7 +13,8 @@ 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
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
# yamllint disable-line rule:line-length
- uses: schubergphilis/mcvs-pr-validation-action@b1c337a896fea52b52a93335713a435d5a07ea72 # v0.2.0
14 changes: 14 additions & 0 deletions .github/workflows/python.yml
Original file line number Diff line number Diff line change
@@ -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 }}
112 changes: 112 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -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)
17 changes: 9 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -16,20 +19,18 @@ 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 }}
```

<!-- markdownlint-disable MD013 -->

| 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) |

<!-- markdownlint-enable MD013 -->

Expand Down
69 changes: 23 additions & 46 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,66 +5,33 @@ 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.
#
- 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
# yamllint disable-line rule:line-length
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0
with:
cache: 'pip'
cache: pip
#
# Code security scanning.
#
- uses: anchore/scan-action@v6.2.0
# yamllint disable-line rule:line-length
- uses: anchore/scan-action@e1165082ffb1fe366ebaf02d8526e7c4989ea9d2 # v6.2.0
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.
#
Expand All @@ -74,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.
Expand All @@ -92,10 +59,15 @@ runs:
#
# Lint code with Flake8
#
# yamllint disable rule:line-length
- 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."
Expand All @@ -111,7 +83,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..."
Expand All @@ -123,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@2.9.0
with:
repo_token: ${{ inputs.token }}
file: dist/${{ inputs.pyinstaller-binary-name }}
Expand Down
4 changes: 4 additions & 0 deletions configs/pip/flake8/requirements.txt
Original file line number Diff line number Diff line change
@@ -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
1 change: 1 addition & 0 deletions configs/pip/pyinstaller/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pyinstaller==v6.13.0 --hash=sha256:bc09795f5954135dd4486c1535650958c8218acb954f43860e4b05fb515a21c0
Loading