diff --git a/.github/workflows/README.md b/.github/workflows/README.md index bef22e40..cc4a94de 100644 --- a/.github/workflows/README.md +++ b/.github/workflows/README.md @@ -56,7 +56,7 @@ secret to the current date. These workflows run on a schedule and at the maintainer's request. Because they create pull requests that update workflows/require the downstream actions to run, they need a special repository/organization secret token called -`SANDPAPER_WORKFLOW` and it must have the `repo` and `workflow` scope. +`SANDPAPER_WORKFLOW` and it must have the `public_repo` and `workflow` scope. This can be an individual user token, OR it can be a trusted bot account. If you have a repository in one of the official Carpentries accounts, then you do not @@ -64,7 +64,7 @@ need to worry about this token being present because the Carpentries Core Team will take care of supplying this token. If you want to use your personal account: you can go to - + to create a token. Once you have created your token, you should copy it to your clipboard and then go to your repository's settings > secrets > actions and create or edit the `SANDPAPER_WORKFLOW` secret, pasting in the generated token. @@ -117,7 +117,24 @@ pull requests that do not pass checks and do not have bots commented on them.** This series of workflows all go together and are described in the following diagram and the below sections: -![Graph representation of a pull request](../../vignettes/articles/img/pr-flow.dot.svg) +![Graph representation of a pull request](https://carpentries.github.io/sandpaper/articles/img/pr-flow.dot.svg) + +### Pre Flight Pull Request Validation (pr-preflight.yaml) + +This workflow runs every time a pull request is created and its purpose is to +validate that the pull request is okay to run. This means the following things: + +1. The pull request does not contain modified workflow files +2. If the pull request contains modified workflow files, it does not contain + modified content files (such as a situation where @carpentries-bot will + make an automated pull request) +3. The pull request does not contain an invalid commit hash (e.g. from a fork + that was made before a lesson was transitioned from styles to use the + workbench). + +Once the checks are finished, a comment is issued to the pull request, which +will allow maintainers to determine if it is safe to run the +"Receive Pull Request" workflow from new contributors. ### Recieve Pull Request (pr-recieve.yaml) @@ -143,18 +160,16 @@ process as the sandpaper-main workflow with the same caching mechanisms. The artifacts produced are used by the next workflow. -# sandpaper 0.5.5 ### Comment on Pull Request (pr-comment.yaml) This workflow is triggered if the `pr-recieve.yaml` workflow is successful. The steps in this workflow are: -1. Test if the workflow is valid -2. If it is valid: create an orphan branch with two commits: the current state of - the repository and the proposed changes. -3. If it is valid: comment on the pull request with the summary of changes -4. If it is NOT valid: comment on the pull request that it is not valid, - warning the maintainer that more scrutiny is needed. +1. Test if the workflow is valid and comment the validity of the workflow to the + pull request. +2. If it is valid: create an orphan branch with two commits: the current state + of the repository and the proposed changes. +3. If it is valid: update the pull request comment with the summary of changes Importantly: if the pull request is invalid, the branch is not created so any malicious code is not published. diff --git a/.github/workflows/pr-comment.yaml b/.github/workflows/pr-comment.yaml index 6b3d81a0..dff6e26b 100644 --- a/.github/workflows/pr-comment.yaml +++ b/.github/workflows/pr-comment.yaml @@ -16,11 +16,14 @@ jobs: test-pr: name: "Test if pull request is valid" runs-on: ubuntu-latest - if: ${{ github.event.workflow_run.event == 'pull_request' && github.event.workflow_run.conclusion == 'success' }} + if: > + github.event.workflow_run.event == 'pull_request' && + github.event.workflow_run.conclusion == 'success' outputs: is_valid: ${{ steps.check-pr.outputs.VALID }} payload: ${{ steps.check-pr.outputs.payload }} number: ${{ steps.get-pr.outputs.NUM }} + msg: ${{ steps.check-pr.outputs.MSG }} steps: - name: 'Download PR artifact' id: dl @@ -42,14 +45,19 @@ jobs: run: | echo '::error::A pull request number was not recorded. The pull request that triggered this workflow is likely malicious.' exit 1 - + - name: "Get Invalid Hashes File" + id: hash + run: | + echo "::set-output name=json::"$(curl -sL https://files.carpentries.org/invalid-hashes.json) - name: "Check PR" id: check-pr if: ${{ steps.dl.outputs.success == 'true' }} uses: carpentries/actions/check-valid-pr@main with: pr: ${{ steps.get-pr.outputs.NUM }} - sha: ${{ github.events.workflow_run.head_commit.sha }} + sha: ${{ github.event.workflow_run.head_sha }} + invalid: ${{ fromJSON(steps.hash.outputs.json)[github.repository] }} + fail_on_error: true # Create an orphan branch on this repository with two commits # - the current HEAD of the md-outputs branch @@ -131,18 +139,33 @@ jobs: name: "Comment if workflow files have changed" needs: test-pr runs-on: ubuntu-latest - if: ${{ needs.test-pr.outputs.is_valid == 'false' }} + if: ${{ always() && needs.test-pr.outputs.is_valid == 'false' }} env: - NR: ${{ needs.test-pr.outputs.number }} + NR: ${{ github.event.workflow_run.pull_requests[0].number }} + body: ${{ needs.test-pr.outputs.msg }} steps: + - name: 'Check for spoofing' + id: dl + uses: carpentries/actions/download-workflow-artifact@main + with: + run: ${{ github.event.workflow_run.id }} + name: 'built' + + - name: 'Alert if spoofed' + id: spoof + if: ${{ steps.dl.outputs.success == 'true' }} + run: | + echo 'body<> $GITHUB_ENV + echo '' >> $GITHUB_ENV + echo '## :x: DANGER :x:' >> $GITHUB_ENV + echo 'This pull request has modified workflows that created output. Close this now.' >> $GITHUB_ENV + echo '' >> $GITHUB_ENV + echo 'EOF' >> $GITHUB_ENV + - name: "Comment on PR" - if: ${{ needs.test-pr.outputs.payload }} id: comment-diff uses: carpentries/actions/comment-diff@main with: - pr: ${{ env.NR }} - body: | - This pull request contains modified workflows and no preview will be created. - - **Please inspect the changes for any malicious content.** + pr: ${{ env.NR }} + body: ${{ env.body }} diff --git a/.github/workflows/pr-post-remove-branch.yaml b/.github/workflows/pr-post-remove-branch.yaml index 04545796..2225f129 100644 --- a/.github/workflows/pr-post-remove-branch.yaml +++ b/.github/workflows/pr-post-remove-branch.yaml @@ -11,8 +11,8 @@ jobs: name: "Delete branch from Pull Request" runs-on: ubuntu-latest if: > - ${{ github.event.workflow_run.event == 'pull_request' && - github.event.workflow_run.conclusion == 'success' }} + github.event.workflow_run.event == 'pull_request' && + github.event.workflow_run.conclusion == 'success' steps: - name: 'Download artifact' uses: carpentries/actions/download-workflow-artifact@main diff --git a/.github/workflows/pr-preflight.yaml b/.github/workflows/pr-preflight.yaml new file mode 100644 index 00000000..47d5b03d --- /dev/null +++ b/.github/workflows/pr-preflight.yaml @@ -0,0 +1,35 @@ +name: "Pull Request Preflight Check" + +on: + pull_request_target: + branches: + ["main"] + types: + ["opened", "synchronize", "reopened"] + +jobs: + test-pr: + name: "Test if pull request is valid" + if: ${{ github.event.action != 'closed' }} + runs-on: ubuntu-latest + outputs: + is_valid: ${{ steps.check-pr.outputs.VALID }} + steps: + - name: "Get Invalid Hashes File" + id: hash + run: | + echo "::set-output name=json::"$(curl -sL https://files.carpentries.org/invalid-hashes.json) + - name: "Check PR" + id: check-pr + uses: carpentries/actions/check-valid-pr@main + with: + pr: ${{ github.event.number }} + invalid: ${{ fromJSON(steps.hash.outputs.json)[github.repository] }} + fail_on_error: true + - name: "Comment result of validation" + id: comment-diff + if: ${{ always() }} + uses: carpentries/actions/comment-diff@main + with: + pr: ${{ github.event.number }} + body: ${{ steps.check-pr.outputs.MSG }} diff --git a/.github/workflows/pr-receive.yaml b/.github/workflows/pr-receive.yaml index 9b1c1cf0..0448e977 100644 --- a/.github/workflows/pr-receive.yaml +++ b/.github/workflows/pr-receive.yaml @@ -7,20 +7,40 @@ on: jobs: test-pr: - name: "Test if pull request is valid" + name: "Record PR number" if: ${{ github.event.action != 'closed' }} runs-on: ubuntu-latest outputs: is_valid: ${{ steps.check-pr.outputs.VALID }} steps: + - name: "Record PR number" + id: record + if: ${{ always() }} + run: | + echo ${{ github.event.number }} > ${{ github.workspace }}/NR # 2022-03-02: artifact name fixed to be NR + - name: "Upload PR number" + id: upload + if: ${{ always() }} + uses: actions/upload-artifact@v2 + with: + name: pr + path: ${{ github.workspace }}/NR + - name: "Get Invalid Hashes File" + id: hash + run: | + echo "::set-output name=json::"$(curl -sL https://files.carpentries.org/invalid-hashes.json) + - name: "echo output" + run: | + echo ${{ steps.hash.outputs.json }} - name: "Check PR" id: check-pr uses: carpentries/actions/check-valid-pr@main with: pr: ${{ github.event.number }} + invalid: ${{ fromJSON(steps.hash.outputs.json)[github.repository] }} build-md-source: - name: "Build markdown source files" + name: "Build markdown source files if valid" needs: test-pr runs-on: ubuntu-latest if: ${{ needs.test-pr.outputs.is_valid == 'true' }} @@ -105,29 +125,3 @@ jobs: - name: "Teardown" run: sandpaper::reset_site() shell: Rscript {0} - - comment-changed-workflow: - name: "Comment if workflow files have changed" - needs: test-pr - runs-on: ubuntu-latest - if: ${{ needs.test-pr.outputs.is_valid != 'true' }} - steps: - - name: "Record PR number" - id: record - run: | - echo ${{ github.event.number }} > ${{ github.workspace }}/NR # 2022-03-02: artifact name fixed to be NR - - name: "Upload PR number" - id: upload - uses: actions/upload-artifact@v2 - with: - name: pr - path: ${{ github.workspace }}/NR - - name: "Comment on PR" - id: comment-diff - uses: carpentries/actions/comment-diff@main - with: - pr: ${{ github.event.number }} - body: | - This pull request contains modified workflows and no preview will be created. - - Unless these changes come from a trusted source, please inspect the changes for any malicious content. diff --git a/.github/workflows/sandpaper-main.yaml b/.github/workflows/sandpaper-main.yaml index 70aca012..1e5ff0fd 100644 --- a/.github/workflows/sandpaper-main.yaml +++ b/.github/workflows/sandpaper-main.yaml @@ -14,9 +14,10 @@ on: required: true default: 'Maintainer (via GitHub)' reset: - description: 'Should the cached markdown files be reset? (true/false)' - required: true + description: 'Reset cached markdown files' + required: false default: false + type: boolean jobs: full-build: name: "Build Full Site" diff --git a/.github/workflows/sandpaper-version.txt b/.github/workflows/sandpaper-version.txt index d3532a10..69da6ebc 100644 --- a/.github/workflows/sandpaper-version.txt +++ b/.github/workflows/sandpaper-version.txt @@ -1 +1 @@ -0.5.7 +0.10.6