From a2b9659256254b768d4e4f6e6efb734aaad4521f Mon Sep 17 00:00:00 2001 From: Joe Blau Date: Mon, 26 Oct 2026 18:37:35 -0700 Subject: [PATCH 1/2] ci(security): pin actions to SHAs, enforce workflow lint, add weekly Semgrep Signed-off-by: Joe Blau --- .github/workflows/coverage.yml | 8 +++--- .github/workflows/docs.yml | 12 +++++---- .github/workflows/publish_npm.yml | 6 +++-- .github/workflows/security-nightly.yml | 3 +++ .github/workflows/security-weekly.yml | 36 ++++++++++++++++++++++++++ .github/workflows/tests.yml | 6 +++-- 6 files changed, 59 insertions(+), 12 deletions(-) create mode 100644 .github/workflows/security-weekly.yml diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index b4ff85e..d187df3 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -23,9 +23,11 @@ jobs: # Job-level env cannot use the runner context; RUNNER_TEMP is set by the runner. - name: Point TMPDIR at runner temp run: echo "TMPDIR=$RUNNER_TEMP" >> "$GITHUB_ENV" - - uses: actions/checkout@v7 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false # Minis persist ~/.npm on disk. GitHub's remote cache is 0.4–1 MB/s for ~1.4 GB. - - uses: actions/setup-node@v7 + - uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0 with: node-version: '24' package-manager-cache: false @@ -38,7 +40,7 @@ jobs: test -s packages/chart/coverage/lcov.info - name: Upload coverage reports to Codecov - uses: codecov/codecov-action@v5 + uses: codecov/codecov-action@0fb7174895f61a3b6b78fc075e0cd60383518dac # v5.5.5 with: token: ${{ secrets.CODECOV_TOKEN }} files: ./packages/chart/coverage/lcov.info diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 9fd1106..46d7624 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -44,9 +44,11 @@ jobs: run: | echo "TMPDIR=$RUNNER_TEMP" >> "$GITHUB_ENV" echo "PLAYWRIGHT_BROWSERS_PATH=$RUNNER_TEMP/ms-playwright" >> "$GITHUB_ENV" - - uses: actions/checkout@v7 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false # Minis persist ~/.npm on disk. GitHub's remote cache is 0.4–1 MB/s for ~1.4 GB. - - uses: actions/setup-node@v7 + - uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0 with: node-version: '24' package-manager-cache: false @@ -67,7 +69,7 @@ jobs: echo '::error::gtar (GNU tar) is required for actions/upload-pages-artifact on macOS. Install with: brew install gnu-tar' exit 1 fi - - uses: actions/upload-pages-artifact@v5 + - uses: actions/upload-pages-artifact@fc324d3547104276b827a68afc52ff2a11cc49c9 # v5.0.0 if: github.event_name != 'pull_request' with: path: apps/docs/out @@ -84,7 +86,7 @@ jobs: name: github-pages url: ${{ steps.deployment.outputs.page_url }} steps: - - uses: actions/configure-pages@v6 + - uses: actions/configure-pages@45bfe0192ca1faeb007ade9deae92b16b8254a0d # v6.0.0 - name: Deploy to GitHub Pages id: deployment - uses: actions/deploy-pages@v5 + uses: actions/deploy-pages@368f82528645a54fb793d4d04e342629a3f51346 # v5.0.1 diff --git a/.github/workflows/publish_npm.yml b/.github/workflows/publish_npm.yml index 50c4a84..bf83285 100644 --- a/.github/workflows/publish_npm.yml +++ b/.github/workflows/publish_npm.yml @@ -45,9 +45,11 @@ jobs: # Job-level env cannot use the runner context; RUNNER_TEMP is set by the runner. - name: Point TMPDIR at runner temp run: echo "TMPDIR=$RUNNER_TEMP" >> "$GITHUB_ENV" - - uses: actions/checkout@v7 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false # Minis persist ~/.npm on disk. GitHub's remote cache is 0.4–1 MB/s for ~1.4 GB. - - uses: actions/setup-node@v7 + - uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0 with: node-version: '24' registry-url: 'https://registry.npmjs.org' diff --git a/.github/workflows/security-nightly.yml b/.github/workflows/security-nightly.yml index 64214f3..853bf4e 100644 --- a/.github/workflows/security-nightly.yml +++ b/.github/workflows/security-nightly.yml @@ -15,6 +15,8 @@ on: pull_request: paths: - .github/workflows/security-nightly.yml + - .github/workflows/** # enforced workflow lint runs on workflow changes + - .github/actions/** - osv-scanner.toml - .gitleaksignore - .gitleaks.toml @@ -35,6 +37,7 @@ jobs: with: runs-on: '["self-hosted","macOS","ARM64"]' profile: nightly + enforce-workflow-lint: true # actionlint + zizmor (medium+) must pass; clean as of 2026-10-26 secrets-mode: ${{ inputs.secrets-mode || (github.event.schedule == '31 12 * * 0' && 'full' || 'incremental') }} upload-sarif: false # no GHAS code scanning upload-secret-report: false diff --git a/.github/workflows/security-weekly.yml b/.github/workflows/security-weekly.yml new file mode 100644 index 0000000..a0c0b38 --- /dev/null +++ b/.github/workflows/security-weekly.yml @@ -0,0 +1,36 @@ +# Weekly SAST (Semgrep, report-only). Shared logic: bloxwap/.github/.github/workflows/security-scan.yml +# Never fails and never gates a release. Findings go to the job summary; Slack only for High findings. +name: security-weekly + +on: + schedule: + - cron: "3 15 * * 6" # Saturdays 15:03 UTC, staggered across repos after the nightlies + workflow_dispatch: + pull_request: + paths: + - .github/workflows/security-weekly.yml + - .semgrepignore + +permissions: {} + +concurrency: + group: security-weekly-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +jobs: + semgrep: + # Fork guard: never run fork PR code on self-hosted minis + if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository + uses: bloxwap/.github/.github/workflows/security-scan.yml@1584396e3f22d28d755396ffbdcb592e4e3b035f # v1.1.0 (pre-release test; bumped to the tag before merge) + permissions: + contents: read + with: + runs-on: '["self-hosted","macOS","ARM64"]' + profile: nightly + deps: false + secrets-scan: false + workflow-lint: false + semgrep: true + semgrep-config: p/default + secrets: + SLACK_WEBHOOK_URL: ${{ secrets.SLACK_SECURITY_WEBHOOK_URL }} # optional; without it Slack is skipped diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 2fda5f9..da1fcb2 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -55,9 +55,11 @@ jobs: # Job-level env cannot use the runner context; RUNNER_TEMP is set by the runner. - name: Point TMPDIR at runner temp run: echo "TMPDIR=$RUNNER_TEMP" >> "$GITHUB_ENV" - - uses: actions/checkout@v7 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false # Minis persist ~/.npm on disk. GitHub's remote cache is 0.4–1 MB/s for ~1.4 GB. - - uses: actions/setup-node@v7 + - uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0 with: node-version: '24' package-manager-cache: false From 4bc93e2d1c3338774fc4f2209c51d95ef5dfb5e5 Mon Sep 17 00:00:00 2001 From: Joe Blau Date: Mon, 26 Oct 2026 18:44:49 -0700 Subject: [PATCH 2/2] ci(security): bump weekly Semgrep caller to v1.1.0 tag SHA Signed-off-by: Joe Blau --- .github/workflows/docs.yml | 2 +- .github/workflows/publish_npm.yml | 2 +- .github/workflows/security-nightly.yml | 2 +- .github/workflows/security-pr.yml | 2 +- .github/workflows/security-weekly.yml | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 46d7624..48849f9 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -20,7 +20,7 @@ jobs: security: # Release scan, parallel with build. Skipped on PRs. if: github.event_name != 'pull_request' - uses: bloxwap/.github/.github/workflows/security-scan.yml@6755bcc6a591531ae95a5babfa389c329f71ba0b # v1.0.2 + uses: bloxwap/.github/.github/workflows/security-scan.yml@2a70724cd0d803abef5f5a7c64c46065f4fda19b # v1.1.0 permissions: contents: read with: diff --git a/.github/workflows/publish_npm.yml b/.github/workflows/publish_npm.yml index bf83285..8500d49 100644 --- a/.github/workflows/publish_npm.yml +++ b/.github/workflows/publish_npm.yml @@ -22,7 +22,7 @@ concurrency: jobs: security: # Single-job publish: adds the scan serially. - uses: bloxwap/.github/.github/workflows/security-scan.yml@6755bcc6a591531ae95a5babfa389c329f71ba0b # v1.0.2 + uses: bloxwap/.github/.github/workflows/security-scan.yml@2a70724cd0d803abef5f5a7c64c46065f4fda19b # v1.1.0 permissions: contents: read with: diff --git a/.github/workflows/security-nightly.yml b/.github/workflows/security-nightly.yml index 853bf4e..a274a69 100644 --- a/.github/workflows/security-nightly.yml +++ b/.github/workflows/security-nightly.yml @@ -31,7 +31,7 @@ jobs: scan: # Fork guard: never run fork PR code on self-hosted minis if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository - uses: bloxwap/.github/.github/workflows/security-scan.yml@6755bcc6a591531ae95a5babfa389c329f71ba0b # v1.0.2 + uses: bloxwap/.github/.github/workflows/security-scan.yml@2a70724cd0d803abef5f5a7c64c46065f4fda19b # v1.1.0 permissions: contents: read with: diff --git a/.github/workflows/security-pr.yml b/.github/workflows/security-pr.yml index 41b520b..1af5d00 100644 --- a/.github/workflows/security-pr.yml +++ b/.github/workflows/security-pr.yml @@ -16,7 +16,7 @@ jobs: gate: # Fork guard: never run fork PR code on self-hosted minis if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository - uses: bloxwap/.github/.github/workflows/security-pr-gate.yml@6755bcc6a591531ae95a5babfa389c329f71ba0b # v1.0.2 + uses: bloxwap/.github/.github/workflows/security-pr-gate.yml@2a70724cd0d803abef5f5a7c64c46065f4fda19b # v1.1.0 permissions: contents: read with: diff --git a/.github/workflows/security-weekly.yml b/.github/workflows/security-weekly.yml index a0c0b38..ff063dd 100644 --- a/.github/workflows/security-weekly.yml +++ b/.github/workflows/security-weekly.yml @@ -21,7 +21,7 @@ jobs: semgrep: # Fork guard: never run fork PR code on self-hosted minis if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository - uses: bloxwap/.github/.github/workflows/security-scan.yml@1584396e3f22d28d755396ffbdcb592e4e3b035f # v1.1.0 (pre-release test; bumped to the tag before merge) + uses: bloxwap/.github/.github/workflows/security-scan.yml@2a70724cd0d803abef5f5a7c64c46065f4fda19b # v1.1.0 permissions: contents: read with: