This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
This is a collection of reusable GitHub Actions workflows designed to provide comprehensive CI/CD automation for multiple languages and platforms. The workflows support Node.js, Python, Java, Gradle, Maven, and Bash projects with automated testing, building, and publishing to various registries (Docker, npm, PyPI, Firefox Add-ons, Android APK releases).
The repository follows a hierarchical workflow structure:
- Universal Orchestrator (
build-test-publish.yml): Main entry point that orchestrates all other workflows based on inputs - Core Build Workflow (
test-and-build.yml): Handles testing, building, and artifact creation - Publishing Workflows: Specialized workflows for different publication targets
- Third-party Actions: External actions for artifact existence checking and downloading
build-test-publish.yml (orchestrator)
├── lint.yml (validates workflows)
├── security-scan-source.yml (pre-build security scanning)
├── test-and-build.yml (always runs)
├── security-scan-artifacts.yml (post-build filesystem/artifact scanning)
├── publish-docker-image.yml (conditional)
├── publish-npm-libraries.yml (conditional)
├── publish-python-libraries.yml (conditional)
├── publish-firefox-extension.yml (conditional)
├── release-android-apk.yml (conditional)
├── release-github.yml (conditional)
├── post-publish-verification.yml (verifies published Docker images)
└── summarize-workflow.yml (always runs after all jobs)
The main orchestrator that:
- Takes comprehensive inputs for all supported tools and platforms
- Conditionally triggers publishing workflows based on
event_nameand input parameters - Supports multi-tool builds (npm, yarn, uv, ./gradlew, mvn, bash)
Core workflow that:
- Sets up language-specific environments (Node.js v24.15.0, Python via pyproject.toml, Java 21)
- Implements comprehensive caching for dependencies across all tools (tool-specific cache keys)
- Supports Nx monorepos with SHA optimization
- Handles Playwright E2E testing automatically (supports .ts, .js, and .mjs config variants)
- Creates build artifacts for downstream workflows with descriptive suffixes
Each specialized for different targets:
- Docker: Multi-platform builds (amd64/arm64), registry flexibility, fail-fast: false for matrix builds
- npm: Version comparison, multi-library support, input sanitization, dry-run validation, uses OIDC Trusted Publishing (no NPM_TOKEN required), SBOM generation and attestation with Sigstore
- Python: UV-based publishing to PyPI with explicit artifact validation, uses OIDC Trusted Publishing (no UV_TOKEN required)
- Firefox: XPI packaging and AMO publishing
- Android: APK building with keystore management
- GitHub: Release creation with artifact attachment, supports
overwrite_releasefor non-semver workflows
The npm publishing workflow generates and attests Software Bill of Materials (SBOM) for supply chain security:
- Automatic SBOM generation: Creates SBOM from package-lock.json/yarn.lock using CycloneDX
- Sigstore attestation: Signs SBOM with keyless signing via GitHub's OIDC (eliminates need for signing keys)
- Format support: SPDX (default) or CycloneDX formats
- Artifact retention: SBOM uploaded as workflow artifact with 90-day retention
- Verification: Consumers can verify attestations using
npm audit signatures
Configuration:
inputs:
enable_sbom_attestation: "true" # Enable/disable (default: enabled)
sbom_format: "spdx" # spdx or cyclonedx (default: spdx)Verifying SBOM attestations as a consumer:
# Download attestation bundle for a published package
npm audit signatures <package-name>
# View SBOM details
gh attestation verify oci://registry.npmjs.org/<namespace>/<package>@<version> \
--owner <github-org>Benefits:
- ✅ Supply chain transparency: Full visibility into all dependencies
- ✅ Vulnerability tracking: Quick querying against known malicious packages
- ✅ Compliance: Meet SLSA/SSDF regulatory requirements
- ✅ Incident response: Rapid impact analysis during supply chain attacks
Triple-layer defense-in-depth security approach with 100% free, open-source tools:
Scans source code and dependencies before building:
- Semgrep: Fast SAST for all languages (configurable rulesets)
- Bandit: Python-specific source code security analysis
- pip-audit: Python dependency vulnerability scanning (official PyPA tool)
- npm audit / yarn audit: Node.js dependency vulnerability scanning
- Uploads SARIF reports to GitHub Security tab
- Fails fast to prevent building vulnerable code
Scans build artifacts before publishing:
- Trivy: Comprehensive filesystem scanner for packages and dependencies
- Grype: Alternative vulnerability scanner for redundancy
- Scans filesystem artifacts from
artifact_path - Generates security summary tables in workflow output
- Acts as security gate before publishing
Verifies published Docker images after deployment:
- Trivy: Scans published Docker images pulled from registry
- Authenticates to GHCR using GitHub OIDC token
- Runs after
publish_docker_imagejob completes - Scans actual published images to detect post-build supply chain attacks
- Uploads SARIF reports to GitHub Security tab
- Only runs when
docker_metais provided and publishing is enabled
Configuration:
inputs:
enable_security_scanning: "true" # Enable/disable (default: enabled)
semgrep_rules: "auto" # auto, p/security-audit, p/owasp-top-ten, p/ci
trivy_severity: "MEDIUM,HIGH,CRITICAL" # Severity threshold
trivy_exit_code: "1" # 0=warn only, 1=fail buildAll security tools are:
- ✅ Completely free for open source (no signup, no limits)
- ✅ Open source projects with active maintenance
- ✅ Industry-standard tools used by major projects
Dedicated workflow for result aggregation that:
- Collects status from all workflows including security scans
- Generates comprehensive workflow summary with status table
- Tracks and outputs published artifacts list
- Provides visual status indicators (✅ Published, ⏭️ Skipped, 🔒 Security Passed)
- Recently refactored from 90 lines to 30 lines (67% reduction) using helper functions
Since this repository contains reusable workflows, testing requires:
- Create a test repository that references the workflows
- Use the
@mainor specific branch/tag when referencing workflows - Test with minimal example projects for each supported tool
This repository doesn't contain traditional build commands since it's pure GitHub Actions YAML. Instead:
# Lint workflows with actionlint (recommended)
actionlint .github/workflows/*.yml
# Validate YAML syntax
yamllint .github/workflows/
# Test workflow locally (if using act)
act -W .github/workflows/test-and-build.yml
# Check workflow references
grep -r "uses.*/.github/workflows" .github/workflows/The repository uses actionlint for static analysis of workflow files:
- Pre-execution validation gate: The
lint.ymlworkflow is called as the first job inbuild-test-publish.yml - Safety mechanism: All jobs depend on successful lint validation - invalid workflows cannot execute
- Automated CI: Also runs independently on every push/PR affecting workflow files
- Local validation: Run
actionlint .github/workflows/*.ymlbefore committing - Reusable workflow support: actionlint validates inputs/outputs/secrets in reusable workflows
- Installation:
bash <(curl https://raw.githubusercontent.com/rhysd/actionlint/main/scripts/download-actionlint.bash)
build-test-publish.yml execution flow:
1. lint (validates all workflows) ← MUST PASS
├─ Generate hash of all workflow files
├─ Check cache for this hash
├─ If cache hit: skip validation (instant ✅)
└─ If cache miss: run actionlint + cache result
2. security_scan_source (pre-build security) ← MUST PASS
├─ Semgrep SAST (all languages)
├─ Bandit (Python source code)
├─ pip-audit (Python dependencies)
└─ npm/yarn audit (Node.js dependencies)
3. test_and_build (needs: security_scan_source) ← Only runs if security passes
4. security_scan_artifacts (pre-publish security) ← MUST PASS
├─ Trivy (filesystem artifacts)
└─ Grype (backup filesystem scanner)
5. [publishing jobs] (needs: security_scan_artifacts) ← Only runs if artifacts are secure
├─ publish_docker_image
├─ publish_npm_libraries
├─ publish_python_libraries
├─ publish_firefox_extension
├─ release_android_apk
├─ release_github
└─ publish_crates_io
6. post_publish_verification (post-publish security) ← MUST PASS
└─ Trivy (scans published Docker images from registry)
7. summarize (needs: all jobs)
This ensures that workflows on the main branch are always valid and secure before execution, during publishing, and after deployment.
The lint workflow implements intelligent caching to avoid redundant validation:
- Hash-based cache key: Generates SHA256 hash of all workflow files
- Cross-repository sharing: Cache is shared across ALL repositories using these workflows
- Automatic invalidation: Cache key changes when any workflow file is modified
- Performance: Subsequent runs skip validation if workflows haven't changed (1-2 second overhead vs 30+ seconds)
Example flow:
- Repository A runs workflow → cache miss → validates workflows → caches result with hash
abc123 - Repository B runs workflow (same workflow version) → cache hit for
abc123→ skips validation ✅ - Workflow updated in main → hash becomes
def456→ next run is cache miss → validates → caches new result - All repositories using updated workflows → cache hit for
def456→ skip validation ✅
This dramatically reduces validation overhead while maintaining safety guarantees.
- All workflows implement input validation and sanitization
- Enhanced security with minimal permissions (contents: read by default)
- Early secret validation with categorized exit codes (2: missing secrets, 3: invalid input)
- Secrets are conditionally used (workflows only run when secrets exist)
- Optimized timeouts prevent runaway builds (5-60 minutes depending on complexity)
- Minimal permissions principle applied to all jobs
IMPORTANT: All calling workflows MUST include these permissions:
jobs:
build_and_deploy:
uses: tehw0lf/workflows/.github/workflows/build-test-publish.yml@main
permissions:
id-token: write # REQUIRED - Always needed for OIDC (npm Trusted Publishing + future integrations)
actions: write # Required for workflow management
contents: write # Required for GitHub releases
packages: write # Required for Docker/GHCR publishing
security-events: write # Required for SARIF uploads (security scanning)
with:
# ... inputsWhy is id-token: write always required?
- Currently used for npm and Python Trusted Publishing (eliminates need for NPM_TOKEN and UV_TOKEN secrets)
- Planned for future OIDC integrations with other publishing targets (Docker registries, etc.)
- Due to GitHub Actions limitations, permissions cannot be conditionally granted in reusable workflows
- Must be set at the top-level calling workflow, even if not publishing to npm or PyPI
- Cannot be controlled with
ifconditions - permissions are evaluated before job execution
Why is security-events: write required?
- Enables SARIF uploads to GitHub Security tab for code scanning alerts
- Provides centralized security vulnerability tracking across repositories
- Required for Semgrep, Bandit, Trivy, and Grype security reports
Key input parameters across workflows:
tool: Determines build system (npm, yarn, uv, ./gradlew, mvn, bash)artifact_path: Where build outputs are stored/retrievedevent_name: Controls conditional execution (push vs pull_request)enable_security_scanning: Enable/disable dual-layer security scanning (default: "true")semgrep_rules: Semgrep ruleset configuration (default: "auto")trivy_severity: Minimum severity threshold (default: "MEDIUM,HIGH,CRITICAL")trivy_exit_code: Fail build on vulnerabilities (default: "1")- Platform-specific metadata (docker_meta, addon_guid, etc.)
Releases use automatic version extraction from the project manifest — no release_tag input needed:
- npm/yarn: reads
versionfrompackage.jsonviajq - uv: reads
versionfrompyproject.toml(falls back toversion.jsonin artifact path) - cargo: reads
versionfromCargo.tomlviagrep - other tools: not supported for GitHub releases (fails with clear error)
The pipeline tags vX.Y.Z and creates the release. If the tag already exists, the workflow fails — bump the version in the manifest to create a new release.
Example usage:
uses: ./.github/workflows/build-test-publish.yml
with:
publish_github_release: "true"
# No release_tag needed — version is read from package.json / pyproject.tomlPublishing only occurs on:
pushevents (typically main branch)- When required secrets are available
- When relevant input parameters are provided
- When build artifacts exist from prior jobs
The workflows dynamically adapt based on tool parameter:
- npm/yarn: Node.js v24.15.0, package-lock.json/yarn.lock caching
- uv: Python setup from pyproject.toml, uv.lock caching
- ./gradlew: JDK 21 Temurin, Gradle caching
- mvn: JDK 21 Temurin, Maven repository caching
- bash: Shell script execution with basic environment setup
Consistent pattern across all publishing workflows:
- Check if build artifact exists using
softwareforgood/check-artifact-v4-existence@v0 - Download artifact if available using
actions/download-artifact@v4 - Conditional execution of publishing steps based on artifact existence
This ensures publishing workflows only run when there are actual build outputs to publish.
The repository includes Dependabot configuration (.github/dependabot.yml) for:
- Weekly automated updates to GitHub Actions versions
- Ensures security patches are applied promptly
- Reduces manual maintenance burden
Key improvements made to the workflow suite:
- Artifact clarity: Added descriptive suffixes to artifact uploads
- Output cleanup: Removed unused workflow outputs
- Validation: Added explicit artifact validation in Python workflow
- Resilience: Added fail-fast: false to Docker matrix builds
- Playwright support: Extended config detection to .ts, .js, and .mjs variants
- Code reduction: Refactored summary workflow (67% line reduction)
- Automation: Added Dependabot for weekly action updates
- OIDC Integration: Migrated npm and Python publishing to Trusted Publishing (eliminates NPM_TOKEN and UV_TOKEN secret requirements)
- Security Scanning: Implemented triple-layer defense-in-depth security with free open-source tools (Semgrep, Bandit, pip-audit, npm audit, Trivy, Grype)
- Post-Publish Verification: Added dedicated workflow to scan published Docker images from registry (prevents timing issues and authentication failures)
- Automatic release versioning: Removed
release_tagandoverwrite_releaseinputs; version is now read from the manifest (package.json / pyproject.toml) and used as the git tag — forces proper semver and auto-generates release notes
These patterns are intentionally designed and verified as correct:
- Docker/Python workflows use artifact path without root_dir prefix
- NPM workflow uses root_dir prefix (required for Nx monorepos)
- Tool-specific caching already optimized with ${{ inputs.tool }} in cache keys
- npm dry-run serves validation purpose (catches errors before publish)
- All checkout steps are necessary for their specific purposes