Security #24
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Security | |
| # Static analysis and supply-chain checks that are not part of the preset verification in ci.yml. | |
| # | |
| # Every action is pinned to a full commit SHA. CodeQL covers the JavaScript and Python sources; it has | |
| # no PHP analyser, so the PHP presets rely on PHPStan in ci.yml instead. | |
| on: | |
| push: | |
| branches: [main] | |
| pull_request: | |
| schedule: | |
| # Catch newly published advisories against code that has not changed. Off-peak, midweek. | |
| - cron: '27 4 * * 3' | |
| permissions: | |
| contents: read | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.ref }} | |
| cancel-in-progress: true | |
| jobs: | |
| codeql: | |
| name: CodeQL (${{ matrix.language }}) | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| security-events: write | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| language: [javascript-typescript, python, actions] | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| persist-credentials: false | |
| - name: Initialise | |
| uses: github/codeql-action/init@f205ea1c3313d32999d8d6a48b4f6530d4437b38 # v4 | |
| with: | |
| languages: ${{ matrix.language }} | |
| # security-and-quality is broader than the default security-extended and worth the extra | |
| # runtime on a repository this small. | |
| queries: security-and-quality | |
| - name: Analyse | |
| uses: github/codeql-action/analyze@f205ea1c3313d32999d8d6a48b4f6530d4437b38 # v4 | |
| with: | |
| category: /language:${{ matrix.language }} | |
| dependency-review: | |
| name: Dependency review | |
| if: github.event_name == 'pull_request' | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| pull-requests: write | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| persist-credentials: false | |
| # Blocks a pull request that introduces a dependency with a known advisory, or one whose licence | |
| # is incompatible with shipping an MIT package. | |
| - name: Review | |
| uses: actions/dependency-review-action@a1d282b36b6f3519aa1f3fc636f609c47dddb294 # v4 | |
| with: | |
| fail-on-severity: moderate | |
| comment-summary-in-pr: on-failure | |
| deny-licenses: AGPL-1.0-or-later, AGPL-3.0-or-later, GPL-2.0-or-later, GPL-3.0-or-later, LGPL-3.0-or-later, SSPL-1.0 | |
| scorecard: | |
| name: OpenSSF Scorecard | |
| # Skipped on pull requests: the action needs to write to the security dashboard, which a fork PR | |
| # cannot be granted. | |
| if: github.event_name != 'pull_request' | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| security-events: write | |
| id-token: write | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| persist-credentials: false | |
| - name: Run analysis | |
| uses: ossf/scorecard-action@2d1146689b8cda280b9bc96326124645441f03bc # v2.4.4 | |
| with: | |
| results_file: results.sarif | |
| results_format: sarif | |
| # Publishes the score so the badge resolves and the result is independently checkable. | |
| publish_results: true | |
| - name: Upload to the security dashboard | |
| uses: github/codeql-action/upload-sarif@f205ea1c3313d32999d8d6a48b4f6530d4437b38 # v4 | |
| with: | |
| sarif_file: results.sarif | |
| pinned-actions: | |
| name: Actions are pinned to commit SHAs | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| persist-credentials: false | |
| # A tag is mutable: whoever controls the action's repository can move it to different code, and | |
| # that code runs with this repository's token. Scorecard checks this too, but a hard failure | |
| # here is what actually keeps it true. | |
| - name: Check every `uses:` is a 40-character SHA | |
| run: | | |
| status=0 | |
| while IFS= read -r line; do | |
| reference="${line#*uses:}" | |
| reference="$(printf '%s' "${reference}" | tr -d ' ' | cut -d'#' -f1)" | |
| # Local composite actions and docker refs are out of scope. | |
| case "${reference}" in | |
| ./*|docker://*) continue ;; | |
| esac | |
| version="${reference##*@}" | |
| if ! printf '%s' "${version}" | grep -Eq '^[0-9a-f]{40}$'; then | |
| echo "::error::unpinned action: ${reference}" | |
| status=1 | |
| fi | |
| done < <(grep -rhE '^\s*-?\s*uses:' .github/workflows/) | |
| if [ "${status}" -eq 0 ]; then | |
| echo "All actions are pinned to commit SHAs" | |
| fi | |
| exit "${status}" |