From 5d257ffc38669098e24e840c5e1a190ee9d58f10 Mon Sep 17 00:00:00 2001 From: Ian Lewis Date: Wed, 12 Oct 2022 05:14:38 +0900 Subject: [PATCH] Add secure-checkout action (#971) * Add secure checkout action Signed-off-by: Ian Lewis * Update checkout pre-submit check Signed-off-by: Ian Lewis * Rename script Signed-off-by: Ian Lewis * Update checkout pre-submit Signed-off-by: Ian Lewis * Don't call verify-checkout and add comment * Remove verify-checkout Signed-off-by: Ian Lewis * fix script path Signed-off-by: Ian Lewis * Update checkout.sh Signed-off-by: Ian Lewis --- .github/actions/checkout-go/action.yml | 4 +- .github/actions/checkout-node/action.yml | 4 +- .github/actions/secure-checkout/action.yaml | 66 +++++++++++++++++++ .github/actions/verify-checkout/action.yaml | 30 --------- .github/workflows/pre-submit.actions.yml | 16 +---- .../scripts/pre-submit.actions/checkout.sh | 28 ++++++++ 6 files changed, 97 insertions(+), 51 deletions(-) create mode 100644 .github/actions/secure-checkout/action.yaml delete mode 100644 .github/actions/verify-checkout/action.yaml create mode 100755 .github/workflows/scripts/pre-submit.actions/checkout.sh diff --git a/.github/actions/checkout-go/action.yml b/.github/actions/checkout-go/action.yml index 9274c37a64..27ba6e0ca3 100644 --- a/.github/actions/checkout-go/action.yml +++ b/.github/actions/checkout-go/action.yml @@ -49,6 +49,7 @@ runs: - name: Checkout the repository with default ref if: inputs.ref == '' + # TODO(github.com/slsa-framework/slsa-github-generator/issues/968) use secure-checkout uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b # tag=v3.0.2 with: fetch-depth: 1 @@ -56,9 +57,6 @@ runs: repository: "${{ inputs.repository }}" token: "${{ inputs.token }}" - - name: Verify checkout - uses: slsa-framework/slsa-github-generator/.github/actions/verify-checkout@e3220805577deb9d193f64e519abcb3b50851df5 - - name: Set up Go environment uses: actions/setup-go@268d8c0ca0432bb2cf416faae41297df9d262d7f # tag=v3.3.0 with: diff --git a/.github/actions/checkout-node/action.yml b/.github/actions/checkout-node/action.yml index 858d397715..386a07cd93 100644 --- a/.github/actions/checkout-node/action.yml +++ b/.github/actions/checkout-node/action.yml @@ -49,6 +49,7 @@ runs: - name: Checkout the repository with default ref if: inputs.ref == '' + # TODO(github.com/slsa-framework/slsa-github-generator/issues/968) use secure-checkout uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b # tag=v3.0.2 with: fetch-depth: 1 @@ -56,9 +57,6 @@ runs: repository: "${{ inputs.repository }}" token: "${{ inputs.token }}" - - name: Verify checkout - uses: slsa-framework/slsa-github-generator/.github/actions/verify-checkout@e3220805577deb9d193f64e519abcb3b50851df5 - - name: Set up Node environment uses: actions/setup-node@2fddd8803e2f5c9604345a0b591c3020ee971a93 # tag=v3.4.1 with: diff --git a/.github/actions/secure-checkout/action.yaml b/.github/actions/secure-checkout/action.yaml new file mode 100644 index 0000000000..6e50142344 --- /dev/null +++ b/.github/actions/secure-checkout/action.yaml @@ -0,0 +1,66 @@ +name: "secure-checkout" +description: "Checkout and verify a commit sha for a GitHub repo" + +input: + repository: + description: "The repository to check out." + required: false + default: ${{ github.repository }} }} + sha: + description: "The SHA to checkout." + required: false + # NOTE: different from actions/checkout which takes any git ref. + # Users must provide a sha1 digest explicitly if not checking out the + # commit that triggered the event. + default: ${{ github.sha }} }} + token: + description: "Token used to fetch the repository." + required: false + default: ${{ github.token }} + persist-credentials: + description: "Whether to configure the token or SSH key with the local git config" + # NOTE: different from actions/checkout which defaults to true. + default: false + fetch-depth: + description: "Number of commits to fetch. 0 indicates all history for all branches and tags." + default: 1 + strict: + description: "Whether to only allow checkouts from repositories that triggered the workflow." + default: true +runs: + using: "composite" + steps: + - name: Verify input sha + env: + EXPECTED_SHA: "${{ inputs.sha }}" + # Verify that the input sha is a git digest (sha1). + run: | + [[ "${EXPECTED_SHA}" =~ ^[a-fA-F0-9]{40}$ ]] + + - name: Checkout the repository + uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b # tag=v3.0.2 + with: + fetch-depth: 1 + ref: ${{ inputs.sha }} + persist-credentials: ${{ inputs.persist-credentials }} + repository: ${{ inputs.repository }} + token: ${{ inputs.token }} + + - name: Verify checkout + shell: bash + env: + CONTEXT: "${{ toJSON(github) }}" + EXPECTED_SHA: "${{ inputs.sha }}" + run: | + set -euo pipefail + + git_sha="$(git log -1 --format='%H')" + if [[ "$git_sha" != "$EXPECTED_SHA" ]]; then + echo "mismatch git sha \"$git_sha\" != \"$EXPECTED_SHA\"" + echo "GitHub context:" + echo "$CONTEXT" + echo + echo "Last 20 commits:" + git log -20 + exit 1 + fi diff --git a/.github/actions/verify-checkout/action.yaml b/.github/actions/verify-checkout/action.yaml deleted file mode 100644 index 82e8fe33de..0000000000 --- a/.github/actions/verify-checkout/action.yaml +++ /dev/null @@ -1,30 +0,0 @@ -name: "Verify a checkout's sha" -description: "verify commit sha for a GitHub repo" - -runs: - using: "composite" - steps: - - name: Verify commit sha - shell: bash - env: - CONTEXT: "${{ toJSON(github) }}" - PULL_REQUEST_SHA: "${{ github.event.pull_request.head.sha }}" - run: | - set -euo pipefail - - git_sha="$(git log -1 --format='%H')" - github_sha="$GITHUB_SHA" - - if [[ "$GITHUB_EVENT_NAME" == "pull_request" ]]; then - github_sha="$PULL_REQUEST_SHA" - fi - - if [[ "$git_sha" != "$github_sha" ]]; then - echo "mismatch git sha \"$git_sha\" != \"$github_sha\"" - echo "GitHub context:" - echo "$CONTEXT" - echo - echo "Last 20 commits:" - git log -20 - exit 1 - fi diff --git a/.github/workflows/pre-submit.actions.yml b/.github/workflows/pre-submit.actions.yml index ca5978c952..a5254b7cf8 100644 --- a/.github/workflows/pre-submit.actions.yml +++ b/.github/workflows/pre-submit.actions.yml @@ -13,21 +13,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b # tag=v3.0.2 - - run: | - - set -euo pipefail - - # Verify that no internal Actions are using `actions/checkout` - # See reasoning in ./github/actions/README.md - - # Split the command to ignore the `1` error `grep` returns when there is no match. - results=$(grep -r --include='*.yml' --include='*.yaml' -e 'actions/checkout@\|actions/checkout-go@\|actions/checkout-node@' .github/actions/* || true) - results=$(grep -v 'checkout-go\|checkout-node\|generate-builder' <<<"$results" || true) - if [[ "$results" != "" ]]; then - echo "Some Actions are using 'actions/checkout'" - echo "$results" - exit -1 - fi + - run: ./.github/workflows/scripts/pre-submit.actions/checkout.sh check-dist-matrix: runs-on: ubuntu-latest diff --git a/.github/workflows/scripts/pre-submit.actions/checkout.sh b/.github/workflows/scripts/pre-submit.actions/checkout.sh new file mode 100755 index 0000000000..6f3140a9f2 --- /dev/null +++ b/.github/workflows/scripts/pre-submit.actions/checkout.sh @@ -0,0 +1,28 @@ +#!/bin/bash + +# Verify that no internal Actions are using `actions/checkout` +# See reasoning in ./github/actions/README.md + +set -euo pipefail + +# NOTE: All actions and workflows should not use actions/checkout. They should +# use an action that uses secure-checkout such as checkout-go, checkout-node +# etc. or use secure-checkout directly. +# TODO(github.com/slsa-framework/slsa-github-generator/issues/626): Check workflows as well and not just actions. +# TODO(github.com/slsa-framework/slsa-github-generator/issues/626): Disallow checkouts for repos other than the repo that triggered the action(i.e. github.repository). +results=$( + grep -r \ + --include='*.yml' \ + --include='*.yaml' \ + --exclude-dir='node_modules' \ + --exclude-dir='secure-checkout' \ + --exclude-dir='checkout-go' \ + --exclude-dir='checkout-node' \ + -e 'uses: *actions/checkout' \ + .github/actions/* || true +) +if [[ "$results" != "" ]]; then + echo "Some Actions are using 'actions/checkout'" + echo "$results" + exit 1 +fi