From cd0ecdbb4eebb856a134894d6def8bf553f9683a Mon Sep 17 00:00:00 2001 From: Wikid82 Date: Sat, 3 Oct 2026 00:20:43 -0400 Subject: [PATCH 1/9] ci: run privileged jobs only for trusted events and pass context via env --- .github/workflows/docs-to-issues.yml | 30 ++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/.github/workflows/docs-to-issues.yml b/.github/workflows/docs-to-issues.yml index 087845bef..1649ba52c 100644 --- a/.github/workflows/docs-to-issues.yml +++ b/.github/workflows/docs-to-issues.yml @@ -34,7 +34,12 @@ jobs: convert-docs: name: Convert Markdown to Issues runs-on: ubuntu-latest - if: github.actor != 'github-actions[bot]' && (github.event_name != 'workflow_run' || github.event.workflow_run.conclusion == 'success') + if: >- + github.actor != 'github-actions[bot]' && + (github.event_name != 'workflow_run' || + (github.event.workflow_run.conclusion == 'success' && + github.event.workflow_run.event == 'push' && + github.event.workflow_run.head_repository.full_name == github.repository)) steps: - name: Checkout repository @@ -49,13 +54,14 @@ jobs: node-version: ${{ env.NODE_VERSION }} - name: Install dependencies - run: npm install gray-matter + run: npm install --ignore-scripts --no-save gray-matter@4.0.3 - name: Detect changed files id: changes uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9 env: COMMIT_SHA: ${{ github.event.workflow_run.head_sha || github.sha }} + MANUAL_FILE: ${{ github.event.inputs.file_path }} with: script: | const fs = require('fs'); @@ -63,7 +69,7 @@ jobs: const commitSha = process.env.COMMIT_SHA || context.sha; // Manual file specification - const manualFile = '${{ github.event.inputs.file_path }}'; + const manualFile = process.env.MANUAL_FILE; if (manualFile) { if (fs.existsSync(manualFile)) { core.setOutput('files', JSON.stringify([manualFile])); @@ -98,13 +104,14 @@ jobs: uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9 env: DRY_RUN: ${{ github.event.inputs.dry_run || 'false' }} + FILES_JSON: ${{ steps.changes.outputs.files }} with: script: | const fs = require('fs'); const path = require('path'); const matter = require('gray-matter'); - const files = JSON.parse('${{ steps.changes.outputs.files }}'); + const files = JSON.parse(process.env.FILES_JSON); const isDryRun = process.env.DRY_RUN === 'true'; const createdIssues = []; const errors = []; @@ -322,9 +329,10 @@ jobs: - name: Move processed files if: steps.process.outputs.created_count != '0' && github.event.inputs.dry_run != 'true' + env: + CREATED_ISSUES: ${{ steps.process.outputs.created_issues }} run: | mkdir -p docs/issues/created - CREATED_ISSUES='${{ steps.process.outputs.created_issues }}' echo "$CREATED_ISSUES" | jq -r '.[].file' | while IFS= read -r file; do if [ -f "$file" ] && [ -n "$file" ]; then filename=$(basename "$file") @@ -336,6 +344,8 @@ jobs: - name: Commit moved files if: steps.process.outputs.created_count != '0' && github.event.inputs.dry_run != 'true' + env: + BRANCH_NAME: ${{ github.event.workflow_run.head_branch || github.ref_name }} run: | git config --local user.email "github-actions[bot]@users.noreply.github.com" git config --local user.name "github-actions[bot]" @@ -343,15 +353,15 @@ jobs: # Removed [skip ci] to allow CI checks to run on PRs # Infinite loop protection: path filter excludes docs/issues/created/** AND github.actor guard prevents bot loops git diff --staged --quiet || git commit -m "chore: move processed issue files to created/" - BRANCH="${{ github.event.workflow_run.head_branch || github.ref_name }}" - git push origin HEAD:refs/heads/${BRANCH} + git push origin "HEAD:refs/heads/${BRANCH_NAME}" - name: Summary if: always() + env: + CREATED: ${{ steps.process.outputs.created_issues }} + ERRORS: ${{ steps.process.outputs.errors }} + DRY_RUN: ${{ github.event.inputs.dry_run }} run: | - CREATED='${{ steps.process.outputs.created_issues }}' - ERRORS='${{ steps.process.outputs.errors }}' - DRY_RUN='${{ github.event.inputs.dry_run }}' { echo "## Docs to Issues Summary" From f0e108bbdb5e3a000a21a408066c2ea13143aa20 Mon Sep 17 00:00:00 2001 From: Wikid82 Date: Sat, 3 Oct 2026 00:21:37 -0400 Subject: [PATCH 2/9] ci: scope upstream-triggered scan to trusted runs and pass context via env --- .github/workflows/security-pr.yml | 88 +++++++++++++++++++------------ 1 file changed, 54 insertions(+), 34 deletions(-) diff --git a/.github/workflows/security-pr.yml b/.github/workflows/security-pr.yml index b5c1e7380..fe5d185fd 100644 --- a/.github/workflows/security-pr.yml +++ b/.github/workflows/security-pr.yml @@ -38,6 +38,7 @@ jobs: github.event_name == 'push' || (github.event_name == 'workflow_run' && github.event.workflow_run.event == 'pull_request' && + github.event.workflow_run.head_repository.full_name == github.repository && github.event.workflow_run.status == 'completed' && github.event.workflow_run.conclusion == 'success') @@ -46,6 +47,19 @@ jobs: security-events: write actions: read + env: + EVENT_NAME: ${{ github.event_name }} + REPOSITORY: ${{ github.repository }} + PR_EVENT_NUMBER: ${{ github.event.pull_request.number }} + INPUT_PR_NUMBER: ${{ inputs.pr_number }} + UPSTREAM_EVENT: ${{ github.event.workflow_run.event }} + UPSTREAM_NAME: ${{ github.event.workflow_run.name }} + UPSTREAM_HEAD_REPO: ${{ github.event.workflow_run.head_repository.full_name }} + UPSTREAM_PR_NUMBER: ${{ github.event.workflow_run.pull_requests[0].number || '' }} + UPSTREAM_RUN_ID: ${{ github.event_name == 'workflow_run' && github.event.workflow_run.id || '' }} + CONTEXT_HEAD_SHA: ${{ github.event_name == 'workflow_run' && github.event.workflow_run.head_sha || github.event.pull_request.head.sha || github.sha }} + CONTEXT_BRANCH: ${{ github.event_name == 'workflow_run' && github.event.workflow_run.head_branch || github.ref_name }} + steps: - name: Checkout repository # actions/checkout v4.2.2 @@ -58,22 +72,21 @@ jobs: env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | - if [[ "${{ github.event_name }}" == "push" ]]; then + if [[ "${EVENT_NAME}" == "push" ]]; then echo "pr_number=" >> "$GITHUB_OUTPUT" echo "is_push=true" >> "$GITHUB_OUTPUT" echo "✅ Push event detected; using local image path" exit 0 fi - if [[ "${{ github.event_name }}" == "pull_request" ]]; then - echo "pr_number=${{ github.event.pull_request.number }}" >> "$GITHUB_OUTPUT" + if [[ "${EVENT_NAME}" == "pull_request" ]]; then + echo "pr_number=${PR_EVENT_NUMBER}" >> "$GITHUB_OUTPUT" echo "is_push=false" >> "$GITHUB_OUTPUT" - echo "✅ Pull request event detected: PR #${{ github.event.pull_request.number }}" + echo "✅ Pull request event detected: PR #${PR_EVENT_NUMBER}" exit 0 fi - if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then - INPUT_PR_NUMBER="${{ inputs.pr_number }}" + if [[ "${EVENT_NAME}" == "workflow_dispatch" ]]; then if [[ -z "${INPUT_PR_NUMBER}" ]]; then echo "❌ workflow_dispatch requires inputs.pr_number" exit 1 @@ -92,31 +105,31 @@ jobs: exit 0 fi - if [[ "${{ github.event_name }}" == "workflow_run" ]]; then - if [[ "${{ github.event.workflow_run.event }}" != "pull_request" ]]; then + if [[ "${EVENT_NAME}" == "workflow_run" ]]; then + if [[ "${UPSTREAM_EVENT}" != "pull_request" ]]; then # Explicit contract validation happens in the dedicated guard step. echo "pr_number=" >> "$GITHUB_OUTPUT" echo "is_push=false" >> "$GITHUB_OUTPUT" exit 0 fi - if [[ -n "${{ github.event.workflow_run.pull_requests[0].number || '' }}" ]]; then - echo "pr_number=${{ github.event.workflow_run.pull_requests[0].number }}" >> "$GITHUB_OUTPUT" + if [[ -n "${UPSTREAM_PR_NUMBER}" ]]; then + echo "pr_number=${UPSTREAM_PR_NUMBER}" >> "$GITHUB_OUTPUT" echo "is_push=false" >> "$GITHUB_OUTPUT" - echo "✅ Found PR number from workflow_run payload: ${{ github.event.workflow_run.pull_requests[0].number }}" + echo "✅ Found PR number from workflow_run payload: ${UPSTREAM_PR_NUMBER}" exit 0 fi fi # Extract PR number from context - HEAD_SHA="${{ github.event_name == 'workflow_run' && github.event.workflow_run.head_sha || github.event.pull_request.head.sha || github.sha }}" + HEAD_SHA="${CONTEXT_HEAD_SHA}" echo "🔍 Looking for PR with head SHA: ${HEAD_SHA}" # Query GitHub API for PR associated with this commit PR_NUMBER=$(gh api \ -H "Accept: application/vnd.github+json" \ -H "X-GitHub-Api-Version: 2022-11-28" \ - "/repos/${{ github.repository }}/commits/${HEAD_SHA}/pulls" \ + "/repos/${REPOSITORY}/commits/${HEAD_SHA}/pulls" \ --jq '.[0].number // empty' 2>/dev/null || echo "") if [[ -n "${PR_NUMBER}" ]]; then @@ -131,23 +144,23 @@ jobs: - name: Validate workflow_run trust boundary and event contract if: github.event_name == 'workflow_run' run: | - if [[ "${{ github.event.workflow_run.name }}" != "Docker Build, Publish & Test" ]]; then + if [[ "${UPSTREAM_NAME}" != "Docker Build, Publish & Test" ]]; then echo "❌ reason_category=unexpected_upstream_workflow" - echo "workflow_name=${{ github.event.workflow_run.name }}" + echo "workflow_name=${UPSTREAM_NAME}" exit 1 fi - if [[ "${{ github.event.workflow_run.event }}" != "pull_request" ]]; then + if [[ "${UPSTREAM_EVENT}" != "pull_request" ]]; then echo "❌ reason_category=unsupported_upstream_event" - echo "upstream_event=${{ github.event.workflow_run.event }}" - echo "run_id=${{ github.event.workflow_run.id }}" + echo "upstream_event=${UPSTREAM_EVENT}" + echo "run_id=${UPSTREAM_RUN_ID}" exit 1 fi - if [[ "${{ github.event.workflow_run.head_repository.full_name }}" != "${{ github.repository }}" ]]; then + if [[ "${UPSTREAM_HEAD_REPO}" != "${REPOSITORY}" ]]; then echo "❌ reason_category=untrusted_upstream_repository" - echo "upstream_head_repository=${{ github.event.workflow_run.head_repository.full_name }}" - echo "expected_repository=${{ github.repository }}" + echo "upstream_head_repository=${UPSTREAM_HEAD_REPO}" + echo "expected_repository=${REPOSITORY}" exit 1 fi @@ -167,8 +180,9 @@ jobs: if: github.event_name == 'workflow_run' || github.event_name == 'workflow_dispatch' env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + PR_INFO_NUMBER: ${{ steps.pr-info.outputs.pr_number }} run: | - PR_NUMBER="${{ steps.pr-info.outputs.pr_number }}" + PR_NUMBER="${PR_INFO_NUMBER}" if [[ ! "${PR_NUMBER}" =~ ^[0-9]+$ ]]; then echo "❌ reason_category=invalid_input" echo "reason=Resolved PR number must be digits-only" @@ -176,16 +190,16 @@ jobs: fi ARTIFACT_NAME="pr-image-${PR_NUMBER}" - RUN_ID="${{ github.event_name == 'workflow_run' && github.event.workflow_run.id || '' }}" + RUN_ID="${UPSTREAM_RUN_ID}" echo "🔍 Checking for artifact: ${ARTIFACT_NAME}" - if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then + if [[ "${EVENT_NAME}" == "workflow_dispatch" ]]; then # Manual replay path: find latest successful docker-build pull_request run for this PR. RUNS_JSON=$(gh api \ -H "Accept: application/vnd.github+json" \ -H "X-GitHub-Api-Version: 2022-11-28" \ - "/repos/${{ github.repository }}/actions/workflows/docker-build.yml/runs?event=pull_request&status=success&per_page=100" 2>&1) + "/repos/${REPOSITORY}/actions/workflows/docker-build.yml/runs?event=pull_request&status=success&per_page=100" 2>&1) RUNS_STATUS=$? if [[ ${RUNS_STATUS} -ne 0 ]]; then @@ -214,7 +228,7 @@ jobs: ARTIFACTS_JSON=$(gh api \ -H "Accept: application/vnd.github+json" \ -H "X-GitHub-Api-Version: 2022-11-28" \ - "/repos/${{ github.repository }}/actions/runs/${RUN_ID}/artifacts" 2>&1) + "/repos/${REPOSITORY}/actions/runs/${RUN_ID}/artifacts" 2>&1) ARTIFACTS_STATUS=$? if [[ ${ARTIFACTS_STATUS} -ne 0 ]]; then @@ -313,9 +327,11 @@ jobs: - name: Extract charon binary from container if: steps.check-artifact.outputs.artifact_exists == 'true' || github.event_name == 'push' || github.event_name == 'pull_request' id: extract + env: + LOADED_IMAGE_REF: ${{ steps.load-image.outputs.image_ref }} run: | # Use local image for Push/PR events - if [[ "${{ github.event_name }}" == "push" || "${{ github.event_name }}" == "pull_request" ]]; then + if [[ "${EVENT_NAME}" == "push" || "${EVENT_NAME}" == "pull_request" ]]; then echo "Using local image: charon:local" CONTAINER_ID=$(docker create "charon:local") echo "container_id=${CONTAINER_ID}" >> "$GITHUB_OUTPUT" @@ -337,7 +353,7 @@ jobs: fi # For workflow_run artifact path, always use locally tagged image from loaded artifact. - IMAGE_REF="${{ steps.load-image.outputs.image_ref }}" + IMAGE_REF="${LOADED_IMAGE_REF}" if [[ -z "${IMAGE_REF}" ]]; then echo "❌ ERROR: Loaded artifact image reference is empty" exit 1 @@ -398,7 +414,7 @@ jobs: uses: github/codeql-action/upload-sarif@2892aa5e19bbd11bc0cff5427e3b750a04d9e3c2 # v4.38.2 with: sarif_file: 'trivy-binary-results.sarif' - category: ${{ steps.pr-info.outputs.is_push == 'true' && format('security-scan-{0}', github.event_name == 'workflow_run' && github.event.workflow_run.head_branch || github.ref_name) || format('security-scan-pr-{0}', steps.pr-info.outputs.pr_number) }} + category: ${{ steps.pr-info.outputs.is_push == 'true' && format('security-scan-{0}', env.CONTEXT_BRANCH) || format('security-scan-pr-{0}', steps.pr-info.outputs.pr_number) }} continue-on-error: true - name: Run Trivy filesystem scan (fail on CRITICAL/HIGH) @@ -420,26 +436,30 @@ jobs: # actions/upload-artifact v4.4.3 uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f with: - name: ${{ steps.pr-info.outputs.is_push == 'true' && format('security-scan-{0}', github.event_name == 'workflow_run' && github.event.workflow_run.head_branch || github.ref_name) || format('security-scan-pr-{0}', steps.pr-info.outputs.pr_number) }} + name: ${{ steps.pr-info.outputs.is_push == 'true' && format('security-scan-{0}', env.CONTEXT_BRANCH) || format('security-scan-pr-{0}', steps.pr-info.outputs.pr_number) }} path: | trivy-binary-results.sarif retention-days: 14 - name: Create job summary if: always() && (steps.check-artifact.outputs.artifact_exists == 'true' || github.event_name == 'push' || github.event_name == 'pull_request') + env: + IS_PUSH: ${{ steps.pr-info.outputs.is_push }} + PR_INFO_NUMBER: ${{ steps.pr-info.outputs.pr_number }} + JOB_STATUS: ${{ job.status }} run: | { - if [[ "${{ steps.pr-info.outputs.is_push }}" == "true" ]]; then - echo "## 🔒 Security Scan Results - Branch: ${{ github.event_name == 'workflow_run' && github.event.workflow_run.head_branch || github.ref_name }}" + if [[ "${IS_PUSH}" == "true" ]]; then + echo "## 🔒 Security Scan Results - Branch: ${CONTEXT_BRANCH}" else - echo "## 🔒 Security Scan Results - PR #${{ steps.pr-info.outputs.pr_number }}" + echo "## 🔒 Security Scan Results - PR #${PR_INFO_NUMBER}" fi echo "" echo "**Scan Type**: Trivy Filesystem Scan" echo "**Target**: \`/app/charon\` binary" echo "**Severity Filter**: CRITICAL, HIGH" echo "" - if [[ "${{ job.status }}" == "success" ]]; then + if [[ "${JOB_STATUS}" == "success" ]]; then echo "✅ **PASSED**: No CRITICAL or HIGH vulnerabilities found" else echo "❌ **FAILED**: CRITICAL or HIGH vulnerabilities detected" From 9adba0f2e5ca654ef450c1430cbfcbf43b78176f Mon Sep 17 00:00:00 2001 From: Wikid82 Date: Sat, 3 Oct 2026 00:21:45 -0400 Subject: [PATCH 3/9] ci: restrict upstream-triggered test jobs to trusted runs --- .github/workflows/dry-run-history-rewrite.yml | 5 ++++- .github/workflows/history-rewrite-tests.yml | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/.github/workflows/dry-run-history-rewrite.yml b/.github/workflows/dry-run-history-rewrite.yml index a2a881192..7df67ec71 100644 --- a/.github/workflows/dry-run-history-rewrite.yml +++ b/.github/workflows/dry-run-history-rewrite.yml @@ -19,7 +19,10 @@ jobs: preview-history: name: Dry-run preview for history rewrite runs-on: ubuntu-latest - if: ${{ github.event_name != 'workflow_run' || github.event.workflow_run.conclusion == 'success' }} + if: >- + ${{ github.event_name != 'workflow_run' || + (github.event.workflow_run.conclusion == 'success' && + github.event.workflow_run.head_repository.full_name == github.repository) }} steps: - name: Checkout repository uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 diff --git a/.github/workflows/history-rewrite-tests.yml b/.github/workflows/history-rewrite-tests.yml index 7be5dbde3..5079cd29f 100644 --- a/.github/workflows/history-rewrite-tests.yml +++ b/.github/workflows/history-rewrite-tests.yml @@ -25,7 +25,10 @@ permissions: jobs: test: runs-on: ubuntu-latest - if: ${{ github.event_name != 'workflow_run' || github.event.workflow_run.conclusion == 'success' }} + if: >- + ${{ github.event_name != 'workflow_run' || + (github.event.workflow_run.conclusion == 'success' && + github.event.workflow_run.head_repository.full_name == github.repository) }} steps: - name: Checkout with full history uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 From 9619da3916ac7b0cc758c541e7ef5e8f7ed56e42 Mon Sep 17 00:00:00 2001 From: Wikid82 Date: Sat, 3 Oct 2026 00:22:02 -0400 Subject: [PATCH 4/9] ci: restrict manual nightly runs to the nightly branch --- .github/workflows/nightly-build.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.github/workflows/nightly-build.yml b/.github/workflows/nightly-build.yml index f8476e61b..141a2b14d 100644 --- a/.github/workflows/nightly-build.yml +++ b/.github/workflows/nightly-build.yml @@ -35,6 +35,14 @@ jobs: agent_changed: ${{ steps.sync.outputs.agent_changed }} steps: + - name: Restrict manual runs to the nightly branch + if: github.event_name == 'workflow_dispatch' && github.ref != 'refs/heads/nightly' + env: + TRIGGER_REF: ${{ github.ref }} + run: | + echo "::error::Manual runs are only permitted from the nightly branch (got ${TRIGGER_REF})" + exit 1 + - name: Checkout nightly branch uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: From 63a3d8818dba2a15111b1d682363f2ba8d4089c4 Mon Sep 17 00:00:00 2001 From: Wikid82 Date: Sat, 3 Oct 2026 00:22:20 -0400 Subject: [PATCH 5/9] ci: restrict manual registry cleanup to the default branch --- .github/workflows/container-prune.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/container-prune.yml b/.github/workflows/container-prune.yml index 27987c02b..72a96b13f 100644 --- a/.github/workflows/container-prune.yml +++ b/.github/workflows/container-prune.yml @@ -25,6 +25,7 @@ permissions: jobs: prune-ghcr: runs-on: ubuntu-latest + if: github.event_name != 'workflow_dispatch' || github.ref == format('refs/heads/{0}', github.event.repository.default_branch) strategy: fail-fast: false matrix: @@ -108,6 +109,7 @@ jobs: prune-dockerhub: runs-on: ubuntu-latest + if: github.event_name != 'workflow_dispatch' || github.ref == format('refs/heads/{0}', github.event.repository.default_branch) strategy: fail-fast: false matrix: @@ -191,7 +193,7 @@ jobs: summarize: runs-on: ubuntu-latest needs: [prune-ghcr, prune-dockerhub] - if: always() + if: always() && (github.event_name != 'workflow_dispatch' || github.ref == format('refs/heads/{0}', github.event.repository.default_branch)) steps: - name: Download all artifacts uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8 From 9200321407ca6ea62f287ea50d24500d391e2afb Mon Sep 17 00:00:00 2001 From: Wikid82 Date: Sat, 3 Oct 2026 00:41:23 -0400 Subject: [PATCH 6/9] ci: pin installer reference and validate manual input --- .github/renovate.json | 2 +- .github/workflows/supply-chain-pr.yml | 8 ++++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/.github/renovate.json b/.github/renovate.json index c9598723c..fcb8e7b15 100644 --- a/.github/renovate.json +++ b/.github/renovate.json @@ -315,7 +315,7 @@ "/^\\.github/skills/security-scan-docker-image-scripts/run\\.sh$/" ], "matchStrings": [ - "anchore/grype/main/install\\.sh \\| sh -s -- -b /usr/local/bin v(?[0-9]+\\.[0-9]+\\.[0-9]+)", + "anchore/grype/(?:main|[0-9a-f]{40})/install\\.sh \\| sh -s -- -b /usr/local/bin v(?[0-9]+\\.[0-9]+\\.[0-9]+)", "set_default_env \\\"GRYPE_VERSION\\\" \\\"v(?[^\\\"]+)\\\"" ], "depNameTemplate": "anchore/grype", diff --git a/.github/workflows/supply-chain-pr.yml b/.github/workflows/supply-chain-pr.yml index b51bcd5b4..071ec3d4b 100644 --- a/.github/workflows/supply-chain-pr.yml +++ b/.github/workflows/supply-chain-pr.yml @@ -58,6 +58,10 @@ jobs: REPO_NAME: ${{ github.repository }} run: | if [[ -n "${INPUT_PR_NUMBER}" ]]; then + if [[ ! "${INPUT_PR_NUMBER}" =~ ^[0-9]+$ ]]; then + echo "::error::pr_number must be digits-only" + exit 1 + fi echo "pr_number=${INPUT_PR_NUMBER}" >> "$GITHUB_OUTPUT" echo "📋 Using manually provided PR number: ${INPUT_PR_NUMBER}" exit 0 @@ -335,13 +339,13 @@ jobs: echo "component_count=${COMPONENT_COUNT}" >> "$GITHUB_OUTPUT" echo "✅ SBOM generated with ${COMPONENT_COUNT} components" - # Scan for vulnerabilities using manual Grype installation (pinned to v0.113.0) + # Scan for vulnerabilities using manual Grype installation (installer pinned to the v0.119.0 release commit) - name: Install Grype if: steps.set-target.outputs.image_name != '' run: | MAX_ATTEMPTS=3 for attempt in $(seq 1 "$MAX_ATTEMPTS"); do - if curl -sSfL https://raw.githubusercontent.com/anchore/grype/main/install.sh | sh -s -- -b /usr/local/bin v0.119.0; then + if curl -sSfL https://raw.githubusercontent.com/anchore/grype/b6f5194537747ee7f705f4113069ac9eb269919f/install.sh | sh -s -- -b /usr/local/bin v0.119.0; then break fi if [[ "$attempt" -eq "$MAX_ATTEMPTS" ]]; then From 24711a02f44518e5e774a08d25d37681213ac451 Mon Sep 17 00:00:00 2001 From: Wikid82 Date: Sat, 3 Oct 2026 00:42:02 -0400 Subject: [PATCH 7/9] ci: pass context values via env in remaining workflows --- .github/workflows/e2e-tests-split.yml | 7 ++- .github/workflows/quality-checks.yml | 9 ++-- .github/workflows/supply-chain-verify.yml | 53 +++++++++++++++-------- 3 files changed, 46 insertions(+), 23 deletions(-) diff --git a/.github/workflows/e2e-tests-split.yml b/.github/workflows/e2e-tests-split.yml index f8b95d67d..38ef0f24a 100644 --- a/.github/workflows/e2e-tests-split.yml +++ b/.github/workflows/e2e-tests-split.yml @@ -146,9 +146,12 @@ jobs: steps: - name: Resolve image inputs id: resolve-image + env: + INPUT_IMAGE_REF: ${{ inputs.image_ref }} + INPUT_IMAGE_TAG: ${{ inputs.image_tag || 'charon:e2e-test' }} run: | - IMAGE_REF="${{ inputs.image_ref }}" - IMAGE_TAG="${{ inputs.image_tag || 'charon:e2e-test' }}" + IMAGE_REF="${INPUT_IMAGE_REF}" + IMAGE_TAG="${INPUT_IMAGE_TAG}" if [ -n "$IMAGE_REF" ]; then { echo "image_source=registry" diff --git a/.github/workflows/quality-checks.yml b/.github/workflows/quality-checks.yml index 42f3e4f10..b52a0f747 100644 --- a/.github/workflows/quality-checks.yml +++ b/.github/workflows/quality-checks.yml @@ -468,16 +468,19 @@ jobs: - name: Check if frontend was modified in PR id: check-frontend + env: + EVENT_NAME: ${{ github.event_name }} + BASE_REF: ${{ github.event.pull_request.base.ref }} run: | - if [ "${{ github.event_name }}" = "push" ]; then + if [ "${EVENT_NAME}" = "push" ]; then echo "frontend_changed=true" >> "$GITHUB_OUTPUT" exit 0 fi # Try to fetch the PR base ref. This may fail for forked PRs or other cases. - git fetch origin "${{ github.event.pull_request.base.ref }}" --depth=1 || true + git fetch origin "${BASE_REF}" --depth=1 || true # Compute changed files against the PR base ref, fallback to origin/main, then fallback to last 10 commits - CHANGED=$(git diff --name-only "origin/${{ github.event.pull_request.base.ref }}...HEAD" 2>/dev/null || echo "") + CHANGED=$(git diff --name-only "origin/${BASE_REF}...HEAD" 2>/dev/null || echo "") printf "Changed files (base ref):\n%s\n" "$CHANGED" if [ -z "$CHANGED" ]; then diff --git a/.github/workflows/supply-chain-verify.yml b/.github/workflows/supply-chain-verify.yml index 32122efd4..1d236e0ef 100644 --- a/.github/workflows/supply-chain-verify.yml +++ b/.github/workflows/supply-chain-verify.yml @@ -42,22 +42,37 @@ jobs: # Debug: Log workflow_run context for initial validation (can be removed after confidence) - name: Debug Workflow Run Context if: github.event_name == 'workflow_run' + env: + WR_NAME: ${{ github.event.workflow_run.name }} + WR_CONCLUSION: ${{ github.event.workflow_run.conclusion }} + WR_HEAD_BRANCH: ${{ github.event.workflow_run.head_branch }} + WR_HEAD_SHA: ${{ github.event.workflow_run.head_sha }} + WR_EVENT: ${{ github.event.workflow_run.event }} + WR_PULL_REQUESTS: ${{ toJson(github.event.workflow_run.pull_requests) }} run: | echo "Workflow Run Event Details:" - echo " Workflow: ${{ github.event.workflow_run.name }}" - echo " Conclusion: ${{ github.event.workflow_run.conclusion }}" - echo " Head Branch: ${{ github.event.workflow_run.head_branch }}" - echo " Head SHA: ${{ github.event.workflow_run.head_sha }}" - echo " Event: ${{ github.event.workflow_run.event }}" - echo " PR Count: ${{ toJson(github.event.workflow_run.pull_requests) }}" + echo " Workflow: ${WR_NAME}" + echo " Conclusion: ${WR_CONCLUSION}" + echo " Head Branch: ${WR_HEAD_BRANCH}" + echo " Head SHA: ${WR_HEAD_SHA}" + echo " Event: ${WR_EVENT}" + echo " PR Count: ${WR_PULL_REQUESTS}" - name: Determine Image Tag id: tag + env: + EVENT_NAME: ${{ github.event_name }} + RELEASE_TAG: ${{ github.event.release.tag_name }} + WR_EVENT: ${{ github.event.workflow_run.event }} + WR_HEAD_BRANCH: ${{ github.event.workflow_run.head_branch }} + WR_HEAD_SHA: ${{ github.event.workflow_run.head_sha }} + WR_PULL_REQUESTS: ${{ toJson(github.event.workflow_run.pull_requests) }} + REF_NAME: ${{ github.ref_name }} run: | - if [[ "${{ github.event_name }}" == "release" ]]; then - TAG="${{ github.event.release.tag_name }}" - elif [[ "${{ github.event_name }}" == "workflow_run" ]]; then - BRANCH="${{ github.event.workflow_run.head_branch }}" + if [[ "${EVENT_NAME}" == "release" ]]; then + TAG="${RELEASE_TAG}" + elif [[ "${EVENT_NAME}" == "workflow_run" ]]; then + BRANCH="${WR_HEAD_BRANCH}" # Extract tag from the workflow that triggered us if [[ "${BRANCH}" == "main" ]]; then TAG="latest" @@ -65,23 +80,23 @@ jobs: TAG="dev" elif [[ "${BRANCH}" == "nightly" ]]; then TAG="nightly" - elif [[ "${{ github.event.workflow_run.event }}" == "pull_request" ]]; then + elif [[ "${WR_EVENT}" == "pull_request" ]]; then # Extract PR number from workflow_run context with null handling - PR_NUMBER=$(jq -r '.pull_requests[0].number // empty' <<< '${{ toJson(github.event.workflow_run.pull_requests) }}') - SHORT_SHA=$(echo "${{ github.event.workflow_run.head_sha }}" | cut -c1-7) + PR_NUMBER=$(jq -r '.pull_requests[0].number // empty' <<< "${WR_PULL_REQUESTS}") + SHORT_SHA=$(echo "${WR_HEAD_SHA}" | cut -c1-7) if [[ -n "${PR_NUMBER}" ]]; then TAG="pr-${PR_NUMBER}-${SHORT_SHA}" else # Fallback to SHA-based tag if PR number not available - TAG="sha-$(echo "${{ github.event.workflow_run.head_sha }}" | cut -c1-7)" + TAG="sha-$(echo "${WR_HEAD_SHA}" | cut -c1-7)" fi else # For feature branches and other pushes, sanitize branch name for Docker tag # Replace / with - to avoid invalid reference format errors TAG=$(echo "${BRANCH}" | tr '/' '-') fi - elif [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then - BRANCH="${{ github.ref_name }}" + elif [[ "${EVENT_NAME}" == "workflow_dispatch" ]]; then + BRANCH="${REF_NAME}" if [[ "${BRANCH}" == "main" ]]; then TAG="latest" elif [[ "${BRANCH}" == "development" ]]; then @@ -686,8 +701,10 @@ jobs: - name: Determine Image Tag id: tag + env: + RELEASE_TAG: ${{ github.event.release.tag_name }} run: | - TAG="${{ github.event.release.tag_name }}" + TAG="${RELEASE_TAG}" echo "tag=${TAG}" >> "$GITHUB_OUTPUT" - name: Verify Cosign Signature with Rekor Fallback @@ -786,7 +803,7 @@ jobs: env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | - TAG="${{ github.event.release.tag_name }}" + TAG="${RELEASE_TAG}" mkdir -p ./release-assets gh release download "${TAG}" --dir ./release-assets || { echo "⚠️ No release assets found or download failed" From 367ece5fdb521d7735d2267d5d9a100b1ff8dabe Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sat, 3 Oct 2026 06:40:16 +0000 Subject: [PATCH 8/9] chore(main): release 0.44.1 --- .release-please-manifest.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index b470c2a90..d916aacaf 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "0.44.0" + ".": "0.44.1" } From 05241e9250bdb14d74fc2ca7f2257acfb92fed1e Mon Sep 17 00:00:00 2001 From: Wikid82 <176516789+Wikid82@users.noreply.github.com> Date: Sat, 3 Oct 2026 07:03:11 +0000 Subject: [PATCH 9/9] chore(docker): refresh bundled proxy toolchain image Rebuilds the prebuilt Caddy/CrowdSec toolchain image so the shipped binaries pick up upstream fixes, and bumps the digest pin in the Dockerfile. --- Dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index a2027ec9f..4a3020926 100644 --- a/Dockerfile +++ b/Dockerfile @@ -19,8 +19,8 @@ ARG CHARON_TOOLCHAIN_IMAGE=ghcr.io/wikid82/charon-toolchain # NOT Renovate-tracked (a content-hash tag has no series to follow, N7) — the # toolchain-image.yml bot owns these two lines. DIGEST is the arch-independent # manifest-list (OCI index) digest, so one pin covers linux/amd64 + linux/arm64. -ARG CHARON_TOOLCHAIN_TAG=caddy-crowdsec-beb3f8b2799af607 -ARG CHARON_TOOLCHAIN_DIGEST=sha256:3c9e76d2b34601fd01bfb241636610c0a1d0454bbbf42a29764f00752709bb2e +ARG CHARON_TOOLCHAIN_TAG=caddy-crowdsec-bc8619e4e914410f +ARG CHARON_TOOLCHAIN_DIGEST=sha256:1e3c18331c2b65eac0ba827d4a7cf362a7ca274616d783f9ab34c85bc9f888a5 # Stage selector — default consumes the prebuilt toolchain image (no compile). # Fork PRs / bootstrap / offline builds pass