diff --git a/.github/workflows/dependabot-auto-merge.yml b/.github/workflows/dependabot-auto-merge.yml index 41e3ad7..c5c761f 100644 --- a/.github/workflows/dependabot-auto-merge.yml +++ b/.github/workflows/dependabot-auto-merge.yml @@ -17,7 +17,7 @@ jobs: if: github.event.pull_request.user.login == 'dependabot[bot]' runs-on: ubuntu-latest steps: - - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 with: repository: ${{ github.event.pull_request.head.repo.full_name }} ref: ${{ github.event.pull_request.head.ref }} diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index d50a276..14815c9 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -15,5 +15,3 @@ jobs: uses: ./.github/workflows/reusable-quality.yml with: run-dependency-review: false - secrets: inherit - diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index e56692b..c96d253 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -12,7 +12,6 @@ jobs: uses: ./.github/workflows/reusable-quality.yml with: run-dependency-review: true - secrets: inherit required-quality: name: Quality diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index a0bfeb3..8ad23e5 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -55,7 +55,6 @@ jobs: uses: ./.github/workflows/reusable-quality.yml with: run-dependency-review: false - secrets: inherit publish-cli: runs-on: ubuntu-latest @@ -66,8 +65,8 @@ jobs: contents: read id-token: write steps: - - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 - - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 + - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 + - uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6.5.0 with: node-version: 24 registry-url: https://registry.npmjs.org @@ -91,7 +90,7 @@ jobs: permissions: contents: write steps: - - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: name: sbom-cyclonedx diff --git a/.github/workflows/reusable-quality.yml b/.github/workflows/reusable-quality.yml index 3626ae2..bb7dbb8 100644 --- a/.github/workflows/reusable-quality.yml +++ b/.github/workflows/reusable-quality.yml @@ -61,8 +61,8 @@ jobs: playwright: docs ci: true steps: - - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 - - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 + - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 + - uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6.5.0 with: node-version: 24 - run: corepack enable @@ -80,8 +80,8 @@ jobs: name: CLI Connector E2E runs-on: ubuntu-latest steps: - - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 - - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 + - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 + - uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6.5.0 with: node-version: 24 - run: corepack enable @@ -95,8 +95,8 @@ jobs: markdown: runs-on: ubuntu-latest steps: - - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 - - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 + - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 + - uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6.5.0 with: node-version: 24 - run: corepack enable @@ -107,8 +107,8 @@ jobs: spellcheck: runs-on: ubuntu-latest steps: - - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 - - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 + - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 + - uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6.5.0 with: node-version: 24 - run: corepack enable @@ -119,8 +119,8 @@ jobs: links: runs-on: ubuntu-latest steps: - - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 - - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 + - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 + - uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6.5.0 with: node-version: 24 - run: corepack enable @@ -132,21 +132,21 @@ jobs: - id: lychee-cache-bucket run: echo "bucket=$(date -u +%Y-%m-%d)" >> "$GITHUB_OUTPUT" - id: restore-lychee-cache - uses: actions/cache/restore@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 + uses: actions/cache/restore@caa296126883cff596d87d8935842f9db880ef25 # v5.1.0 with: path: .lycheecache key: lychee-${{ runner.os }}-v1-${{ steps.lychee-cache-bucket.outputs.bucket }} restore-keys: | lychee-${{ runner.os }}-v1- - - uses: lycheeverse/lychee-action@8646ba30535128ac92d33dfc9133794bfdd9b411 # v2.8.0 + - uses: lycheeverse/lychee-action@e7477775783ea5526144ba13e8db5eec57747ce8 # v2.9.0 with: args: --cache --max-cache-age 14d --verbose --no-progress --config .github/lychee.toml "./README.md" fail: true - - uses: lycheeverse/lychee-action@8646ba30535128ac92d33dfc9133794bfdd9b411 # v2.8.0 + - uses: lycheeverse/lychee-action@e7477775783ea5526144ba13e8db5eec57747ce8 # v2.9.0 with: args: --cache --max-cache-age 14d --verbose --no-progress --config .github/lychee.toml --base-url "http://127.0.0.1:4174/" "./docs/.vitepress/dist/**/*.html" fail: true - - uses: actions/cache/save@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 + - uses: actions/cache/save@caa296126883cff596d87d8935842f9db880ef25 # v5.1.0 if: always() with: path: .lycheecache @@ -155,8 +155,8 @@ jobs: trivy: runs-on: ubuntu-latest steps: - - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 - - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 + - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 + - uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6.5.0 with: node-version: 24 - run: corepack enable @@ -171,8 +171,8 @@ jobs: semgrep: runs-on: ubuntu-latest steps: - - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 - - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 + - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 + - uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6.5.0 with: node-version: 24 - run: corepack enable @@ -187,8 +187,8 @@ jobs: gitleaks: runs-on: ubuntu-latest steps: - - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 - - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 + - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 + - uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6.5.0 with: node-version: 24 - run: corepack enable @@ -203,7 +203,7 @@ jobs: sbom: runs-on: ubuntu-latest steps: - - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 - uses: anchore/sbom-action@e22c389904149dbc22b58101806040fa8d37a610 # v0.24.0 with: path: . @@ -217,8 +217,8 @@ jobs: dast: runs-on: ubuntu-latest steps: - - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 - - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 + - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 + - uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6.5.0 with: node-version: 24 - run: corepack enable @@ -254,5 +254,5 @@ jobs: contents: read pull-requests: read steps: - - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 - uses: actions/dependency-review-action@2031cfc080254a8a887f58cffee85186f0e49e48 # v4.9.0 diff --git a/.semgrep.yml b/.semgrep.yml new file mode 100644 index 0000000..f082f7a --- /dev/null +++ b/.semgrep.yml @@ -0,0 +1,76 @@ +rules: + - id: slide-spec.dependabot-minimum-cooldown + message: >- + Each Dependabot package ecosystem must set cooldown.default-days to at + least 5. + severity: ERROR + languages: + - yaml + paths: + include: + - "**/.github/dependabot.yml" + - "**/.github/dependabot.yaml" + pattern-either: + - patterns: + - pattern-inside: | + updates: + ... + - pattern: | + - package-ecosystem: $ECOSYSTEM + ... + - pattern-not: | + - package-ecosystem: $ECOSYSTEM + ... + cooldown: + ... + ... + - patterns: + - pattern-inside: | + updates: + ... + - pattern-regex: 'default-days\s*:\s*(?P\d+)' + - metavariable-comparison: + metavariable: $DAYS + comparison: int($DAYS) < 5 + - focus-metavariable: $DAYS + - patterns: + - pattern-inside: | + updates: + ... + - pattern: | + cooldown: + default-days: $DAYS + - metavariable-regex: + metavariable: $DAYS + regex: ^\D + - focus-metavariable: $DAYS + + - id: slide-spec.pnpm-minimum-release-age + message: >- + pnpm-workspace.yaml must set minimumReleaseAge to at least 7200 minutes + (5 days). + severity: ERROR + languages: + - yaml + paths: + include: + - "**/pnpm-workspace.yaml" + pattern-either: + - patterns: + - pattern-regex: >- + (?ms)(?:\A|^---$\n)(?:(?!^minimumReleaseAge\s*:)(?!^---$)[\s\S])*?(?P^(?:packages|catalog)\s*:)(?:(?!^minimumReleaseAge\s*:)(?!^---$)[\s\S])*?(?=^---$|\z) + - focus-metavariable: $TARGET + - patterns: + - pattern-regex: '^\s*minimumReleaseAge\s*:\s*(?P\d+)' + - metavariable-comparison: + metavariable: $AGE + comparison: int($AGE) < 7200 + - focus-metavariable: $AGE + - patterns: + - pattern: | + minimumReleaseAge: $AGE + - metavariable-regex: + metavariable: $AGE + regex: ^\D + - focus-metavariable: $AGE + - pattern-regex: '(?m)^\s*minimumReleaseAge\s*:\s*$' diff --git a/cli/scripts/run-semgrep.ts b/cli/scripts/run-semgrep.ts index 411c4d6..ec5cba7 100644 --- a/cli/scripts/run-semgrep.ts +++ b/cli/scripts/run-semgrep.ts @@ -15,6 +15,12 @@ class SemgrepLocalRunner { 'scan', '--config', 'auto', + '--config', + '/src/.semgrep.yml', + '--exclude-rule', + 'package_managers.dependabot.dependabot-missing-cooldown.dependabot-missing-cooldown', + '--exclude-rule', + 'package_managers.pnpm.pnpm-missing-minimum-release-age.pnpm-minimum-release-age', '--error', '/src', ]) diff --git a/docs/meta/supply-chain.md b/docs/meta/supply-chain.md index c8961c8..4d07625 100644 --- a/docs/meta/supply-chain.md +++ b/docs/meta/supply-chain.md @@ -37,6 +37,8 @@ pnpm -r update --latest `pnpm-workspace.yaml` sets `minimumReleaseAge: 7200`, so installs reject package versions published less than 5 days ago. Dependabot also waits 5 days before opening dependency update PRs. +The local Semgrep policy in `.semgrep.yml` enforces the same 5-day minimum for both settings. + For an urgent security update before that wait, add an exact, reviewed `minimumReleaseAgeExclude` entry for that package version, then run the normal add/update command and `pnpm verify`. Latest release assets: diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index f944723..662648e 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -7,6 +7,8 @@ packages: minimumReleaseAge: 7200 minimumReleaseAgeStrict: true minimumReleaseAgeIgnoreMissingTime: false +trustPolicy: no-downgrade +blockExoticSubdeps: true catalogMode: strict saveWorkspaceProtocol: rolling sharedWorkspaceLockfile: true diff --git a/scripts/run-semgrep-docker.ts b/scripts/run-semgrep-docker.ts index 4d8d762..ad0b91b 100644 --- a/scripts/run-semgrep-docker.ts +++ b/scripts/run-semgrep-docker.ts @@ -24,6 +24,12 @@ args.push( 'scan', '--config', 'auto', + '--config', + '/src/.semgrep.yml', + '--exclude-rule', + 'package_managers.dependabot.dependabot-missing-cooldown.dependabot-missing-cooldown', + '--exclude-rule', + 'package_managers.pnpm.pnpm-missing-minimum-release-age.pnpm-minimum-release-age', '--error', '--json', '--output',