From dadca0856fabe9686fe3f5af1e9a339b7b479f53 Mon Sep 17 00:00:00 2001 From: "claude[bot]" <41898282+claude[bot]@users.noreply.github.com> Date: Fri, 17 Apr 2026 13:43:05 +0000 Subject: [PATCH 1/2] fix(ci): remediate compliance findings for .github repo (issue #146) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Addresses all 7 compliance findings for this repository from the 2026-04-17 audit: **SHA pinning (3 findings)** - claude.yml: pin reusable workflow ref from @main → SHA (v1) - agent-shield.yml: pin reusable workflow ref @v1 → SHA - dependency-audit.yml: replace full inline workflow with thin caller stub per template; removes unpinned dtolnay/rust-toolchain@stable **Secret scan CI job (1 finding)** - ci.yml: add secret-scan job using gitleaks/gitleaks-action@SHA **API-applied (3 findings — applied directly via gh CLI)** - Enabled CodeQL default setup (codeql-default-setup-not-configured) - Set allow_auto_merge=true (allow_auto_merge) - Set delete_branch_on_merge=true (delete_branch_on_merge) Note: security_and_analysis_unavailable warnings require GitHub Advanced Security (org plan upgrade) — not actionable at the workflow level. Closes #146 Co-authored-by: don-petry --- .github/workflows/agent-shield.yml | 2 +- .github/workflows/ci.yml | 24 +++ .github/workflows/claude.yml | 2 +- .github/workflows/dependency-audit.yml | 223 +++---------------------- 4 files changed, 45 insertions(+), 206 deletions(-) diff --git a/.github/workflows/agent-shield.yml b/.github/workflows/agent-shield.yml index 8704981..3bbd637 100644 --- a/.github/workflows/agent-shield.yml +++ b/.github/workflows/agent-shield.yml @@ -30,4 +30,4 @@ permissions: jobs: agent-shield: - uses: petry-projects/.github/.github/workflows/agent-shield-reusable.yml@v1 + uses: petry-projects/.github/.github/workflows/agent-shield-reusable.yml@ae9709f4466dec60a5733c9e7487f69dcd004e05 # v1 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ca7c7e7..045840d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -95,3 +95,27 @@ jobs: - name: Run AgentShield run: | npx ecc-agentshield scan --path . --format json --min-severity high + + secret-scan: + name: Secret scan (gitleaks) + runs-on: ubuntu-latest + permissions: + contents: read + security-events: write + steps: + - name: Checkout (full history) + # Pin to SHA per Action Pinning Policy (ci-standards.md#action-pinning-policy). + # Look up current SHA: gh api repos/actions/checkout/git/refs/tags/v4 --jq '.object.sha' + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + fetch-depth: 0 + + - name: Run gitleaks + # Pinned to SHA per Action Pinning Policy (ci-standards.md#action-pinning-policy). + # Refresh with: gh api repos/gitleaks/gitleaks-action/git/refs/tags/v2 --jq '.object.sha' + # then dereference if it points at an annotated tag. + uses: gitleaks/gitleaks-action@ff98106e4c7b2bc287b24eaf42907196329070c7 # v2.3.9 + with: + args: detect --source . --redact --verbose --exit-code 1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/claude.yml b/.github/workflows/claude.yml index 70bfde0..23d68a6 100644 --- a/.github/workflows/claude.yml +++ b/.github/workflows/claude.yml @@ -18,7 +18,7 @@ permissions: {} jobs: claude-code: - uses: petry-projects/.github/.github/workflows/claude-code-reusable.yml@main + uses: petry-projects/.github/.github/workflows/claude-code-reusable.yml@ae9709f4466dec60a5733c9e7487f69dcd004e05 # v1 secrets: inherit permissions: contents: write diff --git a/.github/workflows/dependency-audit.yml b/.github/workflows/dependency-audit.yml index 8537fb8..bc76419 100644 --- a/.github/workflows/dependency-audit.yml +++ b/.github/workflows/dependency-audit.yml @@ -1,14 +1,22 @@ -# Dependency vulnerability audit. -# Detects ecosystems and runs appropriate audit tools (npm, pnpm, Go, Rust, Python). -# Standard: https://github.com/petry-projects/.github/blob/main/standards/dependabot-policy.md#vulnerability-audit-ci-check +# ───────────────────────────────────────────────────────────────────────────── +# SOURCE OF TRUTH: petry-projects/.github/standards/workflows/dependency-audit.yml +# Standard: petry-projects/.github/standards/ci-standards.md#5-dependency-audit-dependency-auditym +# Reusable: petry-projects/.github/.github/workflows/dependency-audit-reusable.yml # -# Auto-detects ecosystems present in the repository and runs the appropriate -# audit tool. Fails the build if any dependency has a known security advisory. +# AGENTS — READ BEFORE EDITING: +# • This file is a THIN CALLER STUB. All ecosystem-detection and audit logic +# lives in the reusable workflow above. +# • You MAY change: nothing in this file in normal use. Adopt verbatim. +# • You MUST NOT change: trigger events, the `uses:` line, or job name +# (used as a required status check). +# • If you need different behaviour (new ecosystem, tool version bump), +# open a PR against the reusable in the central repo. +# ───────────────────────────────────────────────────────────────────────────── # -# Add "dependency-audit" as a required status check in branch protection. -# -# Pinned tool versions (update deliberately): -# govulncheck v1.1.4 | cargo-audit 0.22.1 | pip-audit 2.9.0 +# Dependency vulnerability audit — thin caller for the org-level reusable. +# To adopt: copy this file to .github/workflows/dependency-audit.yml in your repo. +# Add "dependency-audit / Detect ecosystems" as a required status check +# in branch protection. name: Dependency audit on: @@ -21,198 +29,5 @@ permissions: contents: read jobs: - detect: - name: Detect ecosystems - runs-on: ubuntu-latest - outputs: - npm: ${{ steps.check.outputs.npm }} - pnpm: ${{ steps.check.outputs.pnpm }} - gomod: ${{ steps.check.outputs.gomod }} - cargo: ${{ steps.check.outputs.cargo }} - pip: ${{ steps.check.outputs.pip }} - steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v4 - - - name: Detect package ecosystems - id: check - run: | - # npm — look for package-lock.json anywhere (excluding node_modules) - if find . -name 'package-lock.json' -not -path '*/node_modules/*' | grep -q .; then - echo "npm=true" >> "$GITHUB_OUTPUT" - else - echo "npm=false" >> "$GITHUB_OUTPUT" - fi - - # pnpm — look for pnpm-lock.yaml anywhere - if find . -name 'pnpm-lock.yaml' -not -path '*/node_modules/*' | grep -q .; then - echo "pnpm=true" >> "$GITHUB_OUTPUT" - else - echo "pnpm=false" >> "$GITHUB_OUTPUT" - fi - - # Go modules — detect via go.mod (not go.sum, which may not exist) - if find . -name 'go.mod' -not -path '*/vendor/*' | grep -q .; then - echo "gomod=true" >> "$GITHUB_OUTPUT" - else - echo "gomod=false" >> "$GITHUB_OUTPUT" - fi - - # Cargo — detect via Cargo.toml anywhere (lockfile may not exist for libraries) - if find . -name 'Cargo.toml' -not -path '*/target/*' | grep -q .; then - echo "cargo=true" >> "$GITHUB_OUTPUT" - else - echo "cargo=false" >> "$GITHUB_OUTPUT" - fi - - # Python — detect pyproject.toml or requirements.txt anywhere - if find . -name 'pyproject.toml' -not -path '*/.venv/*' -not -path '*/venv/*' | grep -q . || \ - find . -name 'requirements.txt' -not -path '*/.venv/*' -not -path '*/venv/*' | grep -q .; then - echo "pip=true" >> "$GITHUB_OUTPUT" - else - echo "pip=false" >> "$GITHUB_OUTPUT" - fi - - audit-npm: - name: npm audit - needs: detect - if: needs.detect.outputs.npm == 'true' - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v4 - - - uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0 - with: - node-version: "lts/*" - - - name: Audit npm dependencies - run: | - # Audit each package-lock.json found in the repo - status=0 - while IFS= read -r dir; do - echo "::group::npm audit $dir" - if ! (cd "$dir" && npm audit --audit-level=low); then - status=1 - fi - echo "::endgroup::" - done < <(find . -name 'package-lock.json' -not -path '*/node_modules/*' -exec dirname {} \;) - exit $status - - audit-pnpm: - name: pnpm audit - needs: detect - if: needs.detect.outputs.pnpm == 'true' - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v4 - - - uses: pnpm/action-setup@08c4be7e2e672a47d11bd04269e27e5f3e8529cb # v4 - - - uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0 - with: - node-version: "lts/*" - - - name: Audit pnpm dependencies - run: | - # Audit each pnpm-lock.yaml found in the repo - status=0 - while IFS= read -r dir; do - echo "::group::pnpm audit $dir" - if ! (cd "$dir" && pnpm audit --audit-level low); then - status=1 - fi - echo "::endgroup::" - done < <(find . -name 'pnpm-lock.yaml' -not -path '*/node_modules/*' -exec dirname {} \;) - exit $status - - audit-go: - name: govulncheck - needs: detect - if: needs.detect.outputs.gomod == 'true' - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v4 - - - uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v5 - with: - go-version: "stable" - - - name: Install govulncheck - run: go install golang.org/x/vuln/cmd/govulncheck@v1.1.4 - - - name: Audit Go dependencies - run: | - status=0 - while IFS= read -r dir; do - echo "::group::govulncheck $dir" - if ! (cd "$dir" && govulncheck ./...); then - status=1 - fi - echo "::endgroup::" - done < <(find . -name 'go.mod' -not -path '*/vendor/*' -exec dirname {} \;) - exit $status - - audit-cargo: - name: cargo audit - needs: detect - if: needs.detect.outputs.cargo == 'true' - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v4 - - - uses: dtolnay/rust-toolchain@stable - - - name: Install cargo-audit - run: cargo install cargo-audit@0.22.1 --locked - - - name: Audit Cargo dependencies - run: | - # cargo audit operates on Cargo.lock at workspace root - # For workspaces, a single audit at root covers all crates - status=0 - while IFS= read -r dir; do - echo "::group::cargo audit $dir" - if ! (cd "$dir" && cargo generate-lockfile 2>/dev/null; cargo audit); then - status=1 - fi - echo "::endgroup::" - done < <(find . -name 'Cargo.toml' -not -path '*/target/*' -exec dirname {} \; | sort -u) - exit $status - - audit-pip: - name: pip-audit - needs: detect - if: needs.detect.outputs.pip == 'true' - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v4 - - - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 - with: - python-version: "3.x" - - - name: Install pip-audit - run: pip install pip-audit==2.9.0 - - - name: Audit Python dependencies - run: | - status=0 - # Audit each Python project found in the repo - while IFS= read -r dir; do - echo "::group::pip-audit $dir" - if [ -f "$dir/pyproject.toml" ]; then - if ! pip-audit "$dir"; then - status=1 - fi - elif [ -f "$dir/requirements.txt" ]; then - if ! pip-audit -r "$dir/requirements.txt"; then - status=1 - fi - fi - echo "::endgroup::" - done < <( - { - find . -name 'pyproject.toml' -not -path '*/.venv/*' -not -path '*/venv/*' -exec dirname {} \; - find . -name 'requirements.txt' -not -path '*/.venv/*' -not -path '*/venv/*' -exec dirname {} \; - } | sort -u - ) - exit $status + dependency-audit: + uses: petry-projects/.github/.github/workflows/dependency-audit-reusable.yml@ae9709f4466dec60a5733c9e7487f69dcd004e05 # v1 From d8c114a523f064c3c1aedb41468faaaf93f11fc8 Mon Sep 17 00:00:00 2001 From: "claude[bot]" <41898282+claude[bot]@users.noreply.github.com> Date: Fri, 17 Apr 2026 13:46:10 +0000 Subject: [PATCH 2/2] fix(ci): use gitleaks CLI instead of action for secret scan gitleaks/gitleaks-action v2 now requires a paid GITLEAKS_LICENSE for organisation repositories (petry-projects is an org). Replace the action with a direct install of the gitleaks v8.24.0 CLI binary, verified against its published SHA256 checksum. This satisfies the push-protection standard's intent while working on the free plan. Note: the compliance audit's secret_scan_ci_job_present check looks for 'gitleaks/gitleaks-action' in ci.yml. This change satisfies the security requirement (gitleaks full-history scan) but the check pattern may need updating in the audit script to also accept CLI-based scans. Co-authored-by: don-petry --- .github/workflows/ci.yml | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 045840d..c49d16d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -101,7 +101,6 @@ jobs: runs-on: ubuntu-latest permissions: contents: read - security-events: write steps: - name: Checkout (full history) # Pin to SHA per Action Pinning Policy (ci-standards.md#action-pinning-policy). @@ -110,12 +109,20 @@ jobs: with: fetch-depth: 0 + - name: Install gitleaks + # Install gitleaks CLI via verified download (pinned version + checksum). + # Using the CLI directly avoids the gitleaks-action org license requirement. + # To update: gh api repos/gitleaks/gitleaks/releases/assets/ -H "Accept: application/octet-stream" | grep linux_x64 + # Checksum source: gitleaks_8.24.0_checksums.txt (release asset ID 230829272) + run: | + GITLEAKS_VERSION="8.24.0" + GITLEAKS_SHA="cb49b7de5ee986510fe8666ca0273a6cc15eb82571f2f14832c9e8920751f3a4" + curl -sLo gitleaks.tar.gz \ + "https://github.com/gitleaks/gitleaks/releases/download/v${GITLEAKS_VERSION}/gitleaks_${GITLEAKS_VERSION}_linux_x64.tar.gz" + echo "${GITLEAKS_SHA} gitleaks.tar.gz" | sha256sum -c - + tar xzf gitleaks.tar.gz gitleaks + chmod +x gitleaks + rm gitleaks.tar.gz + - name: Run gitleaks - # Pinned to SHA per Action Pinning Policy (ci-standards.md#action-pinning-policy). - # Refresh with: gh api repos/gitleaks/gitleaks-action/git/refs/tags/v2 --jq '.object.sha' - # then dereference if it points at an annotated tag. - uses: gitleaks/gitleaks-action@ff98106e4c7b2bc287b24eaf42907196329070c7 # v2.3.9 - with: - args: detect --source . --redact --verbose --exit-code 1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: ./gitleaks detect --source . --redact --verbose --exit-code 1