From 435e3d82324bf7a2f42e7c056fafd751221c2af8 Mon Sep 17 00:00:00 2001 From: jbkieffer Date: Tue, 6 Sep 2022 01:03:52 +0000 Subject: [PATCH 1/3] [actions] update sandpaper workflow to version 0.9.5 --- .github/workflows/README.md | 45 ++++++++++++++----- .github/workflows/deploy-aws.yaml | 60 +++++++++++++++++++++++++ .github/workflows/pr-comment.yaml | 41 ++++++++++++----- .github/workflows/pr-preflight.yaml | 35 +++++++++++++++ .github/workflows/pr-receive.yaml | 50 +++++++++------------ .github/workflows/sandpaper-main.yaml | 5 ++- .github/workflows/sandpaper-version.txt | 2 +- 7 files changed, 187 insertions(+), 51 deletions(-) create mode 100644 .github/workflows/deploy-aws.yaml create mode 100644 .github/workflows/pr-preflight.yaml diff --git a/.github/workflows/README.md b/.github/workflows/README.md index bef22e40..a29715dc 100644 --- a/.github/workflows/README.md +++ b/.github/workflows/README.md @@ -49,6 +49,16 @@ the `renv.lock` file, respectively. If there is a problem with the cache, manual invaliation is necessary and can be done by setting the `CACHE_VERSION` secret to the current date. +### Deploy to AWS (deploy-aws.yaml) + +If you have an AWS bucket that is set up to deploy the site from a folder, this +workflow will deploy the site to that folder after `01 Build and Deploy` runs. +It can also be triggered manually. + +Note: for this to work, you must have the `AWS_S3_BUCKET`, `AWS_ACCESS_KEY_ID`, +and `AWS_SECRET_ACCESS_KEY` in your repository secrets. If any of these are +missing, the workflow will not run. + ## Updates ### Setup Information @@ -56,7 +66,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 +74,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 +127,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 +170,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/deploy-aws.yaml b/.github/workflows/deploy-aws.yaml new file mode 100644 index 00000000..d154a7da --- /dev/null +++ b/.github/workflows/deploy-aws.yaml @@ -0,0 +1,60 @@ +name: "Deploy to AWS" + +on: + workflow_run: + workflows: ["01 Build and Deploy Site"] + types: + - completed + workflow_dispatch: + +jobs: + preflight: + name: "Preflight Check" + runs-on: ubuntu-latest + outputs: + ok: ${{ steps.check.outputs.ok }} + folder: ${{ steps.check.outputs.folder }} + steps: + - id: check + run: | + if [[ -z "${{ secrets.AWS_S3_BUCKET }}" || -z "${{ secrets.AWS_ACCESS_KEY_ID }}" || -z "${{ secrets.AWS_SECRET_ACCESS_KEY }}" ]]; then + echo ":information_source: No site configured" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "To deploy on AWS, you need the `AWS_S3_BUCKET`, `AWS_ACCESS_KEY_ID`, and `AWS_SECRET_ACCESS_KEY` secrets set up" >> $GITHUB_STEP_SUMMARY + else + echo "::set-output name=folder::"$(sed -E 's^.+/(.+)^\1^' <<< ${{ github.repository }}) + echo "::set-output name=ok::true" + fi + + full-build: + name: "Deploy to AWS" + needs: [preflight] + if: ${{ needs.preflight.outputs.ok }} + runs-on: ubuntu-latest + steps: + + - name: "Checkout site folder" + uses: actions/checkout@v3 + with: + ref: 'gh-pages' + path: 'source' + + - name: "Deploy to Bucket" + uses: jakejarvis/s3-sync-action@v0.5.1 + with: + args: --acl public-read --follow-symlinks --delete --exclude '.git/*' + env: + AWS_S3_BUCKET: ${{ secrets.AWS_S3_BUCKET }} + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + SOURCE_DIR: 'source' + DEST_DIR: ${{ needs.preflight.outputs.folder }} + + - name: "Invalidate CloudFront" + uses: chetan/invalidate-cloudfront-action@master + env: + PATHS: /* + AWS_REGION: 'us-east-1' + DISTRIBUTION: ${{ secrets.DISTRIBUTION }} + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} diff --git a/.github/workflows/pr-comment.yaml b/.github/workflows/pr-comment.yaml index 6b3d81a0..b57d816f 100644 --- a/.github/workflows/pr-comment.yaml +++ b/.github/workflows/pr-comment.yaml @@ -21,6 +21,7 @@ jobs: 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 +43,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 +137,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-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..b0bb8785 100644 --- a/.github/workflows/sandpaper-version.txt +++ b/.github/workflows/sandpaper-version.txt @@ -1 +1 @@ -0.5.7 +0.9.5 From e92a2de92584ba6f7dc8bf623a285f59b0565337 Mon Sep 17 00:00:00 2001 From: jbkieffer Date: Tue, 20 Sep 2022 01:05:54 +0000 Subject: [PATCH 2/3] [actions] update sandpaper workflow to version 0.10.0 --- .github/workflows/README.md | 45 +++++++++++---- .github/workflows/deploy-aws.yaml | 60 ++++++++++++++++++++ .github/workflows/pr-comment.yaml | 45 +++++++++++---- .github/workflows/pr-post-remove-branch.yaml | 4 +- .github/workflows/pr-preflight.yaml | 35 ++++++++++++ .github/workflows/pr-receive.yaml | 50 +++++++--------- .github/workflows/sandpaper-main.yaml | 5 +- .github/workflows/sandpaper-version.txt | 2 +- 8 files changed, 192 insertions(+), 54 deletions(-) create mode 100644 .github/workflows/deploy-aws.yaml create mode 100644 .github/workflows/pr-preflight.yaml diff --git a/.github/workflows/README.md b/.github/workflows/README.md index bef22e40..a29715dc 100644 --- a/.github/workflows/README.md +++ b/.github/workflows/README.md @@ -49,6 +49,16 @@ the `renv.lock` file, respectively. If there is a problem with the cache, manual invaliation is necessary and can be done by setting the `CACHE_VERSION` secret to the current date. +### Deploy to AWS (deploy-aws.yaml) + +If you have an AWS bucket that is set up to deploy the site from a folder, this +workflow will deploy the site to that folder after `01 Build and Deploy` runs. +It can also be triggered manually. + +Note: for this to work, you must have the `AWS_S3_BUCKET`, `AWS_ACCESS_KEY_ID`, +and `AWS_SECRET_ACCESS_KEY` in your repository secrets. If any of these are +missing, the workflow will not run. + ## Updates ### Setup Information @@ -56,7 +66,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 +74,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 +127,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 +170,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/deploy-aws.yaml b/.github/workflows/deploy-aws.yaml new file mode 100644 index 00000000..d154a7da --- /dev/null +++ b/.github/workflows/deploy-aws.yaml @@ -0,0 +1,60 @@ +name: "Deploy to AWS" + +on: + workflow_run: + workflows: ["01 Build and Deploy Site"] + types: + - completed + workflow_dispatch: + +jobs: + preflight: + name: "Preflight Check" + runs-on: ubuntu-latest + outputs: + ok: ${{ steps.check.outputs.ok }} + folder: ${{ steps.check.outputs.folder }} + steps: + - id: check + run: | + if [[ -z "${{ secrets.AWS_S3_BUCKET }}" || -z "${{ secrets.AWS_ACCESS_KEY_ID }}" || -z "${{ secrets.AWS_SECRET_ACCESS_KEY }}" ]]; then + echo ":information_source: No site configured" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "To deploy on AWS, you need the `AWS_S3_BUCKET`, `AWS_ACCESS_KEY_ID`, and `AWS_SECRET_ACCESS_KEY` secrets set up" >> $GITHUB_STEP_SUMMARY + else + echo "::set-output name=folder::"$(sed -E 's^.+/(.+)^\1^' <<< ${{ github.repository }}) + echo "::set-output name=ok::true" + fi + + full-build: + name: "Deploy to AWS" + needs: [preflight] + if: ${{ needs.preflight.outputs.ok }} + runs-on: ubuntu-latest + steps: + + - name: "Checkout site folder" + uses: actions/checkout@v3 + with: + ref: 'gh-pages' + path: 'source' + + - name: "Deploy to Bucket" + uses: jakejarvis/s3-sync-action@v0.5.1 + with: + args: --acl public-read --follow-symlinks --delete --exclude '.git/*' + env: + AWS_S3_BUCKET: ${{ secrets.AWS_S3_BUCKET }} + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + SOURCE_DIR: 'source' + DEST_DIR: ${{ needs.preflight.outputs.folder }} + + - name: "Invalidate CloudFront" + uses: chetan/invalidate-cloudfront-action@master + env: + PATHS: /* + AWS_REGION: 'us-east-1' + DISTRIBUTION: ${{ secrets.DISTRIBUTION }} + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} 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..78bc1abd 100644 --- a/.github/workflows/sandpaper-version.txt +++ b/.github/workflows/sandpaper-version.txt @@ -1 +1 @@ -0.5.7 +0.10.0 From 9a9f69e56ab2d9a6d9d5868b9597e949824ad72a Mon Sep 17 00:00:00 2001 From: jbkieffer Date: Tue, 4 Oct 2022 01:14:53 +0000 Subject: [PATCH 3/3] [actions] update sandpaper workflow to version 0.10.1 --- .github/workflows/README.md | 45 +++++++++++---- .github/workflows/deploy-aws.yaml | 60 ++++++++++++++++++++ .github/workflows/pr-comment.yaml | 45 +++++++++++---- .github/workflows/pr-post-remove-branch.yaml | 4 +- .github/workflows/pr-preflight.yaml | 35 ++++++++++++ .github/workflows/pr-receive.yaml | 50 +++++++--------- .github/workflows/sandpaper-main.yaml | 5 +- .github/workflows/sandpaper-version.txt | 2 +- 8 files changed, 192 insertions(+), 54 deletions(-) create mode 100644 .github/workflows/deploy-aws.yaml create mode 100644 .github/workflows/pr-preflight.yaml diff --git a/.github/workflows/README.md b/.github/workflows/README.md index bef22e40..a29715dc 100644 --- a/.github/workflows/README.md +++ b/.github/workflows/README.md @@ -49,6 +49,16 @@ the `renv.lock` file, respectively. If there is a problem with the cache, manual invaliation is necessary and can be done by setting the `CACHE_VERSION` secret to the current date. +### Deploy to AWS (deploy-aws.yaml) + +If you have an AWS bucket that is set up to deploy the site from a folder, this +workflow will deploy the site to that folder after `01 Build and Deploy` runs. +It can also be triggered manually. + +Note: for this to work, you must have the `AWS_S3_BUCKET`, `AWS_ACCESS_KEY_ID`, +and `AWS_SECRET_ACCESS_KEY` in your repository secrets. If any of these are +missing, the workflow will not run. + ## Updates ### Setup Information @@ -56,7 +66,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 +74,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 +127,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 +170,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/deploy-aws.yaml b/.github/workflows/deploy-aws.yaml new file mode 100644 index 00000000..d154a7da --- /dev/null +++ b/.github/workflows/deploy-aws.yaml @@ -0,0 +1,60 @@ +name: "Deploy to AWS" + +on: + workflow_run: + workflows: ["01 Build and Deploy Site"] + types: + - completed + workflow_dispatch: + +jobs: + preflight: + name: "Preflight Check" + runs-on: ubuntu-latest + outputs: + ok: ${{ steps.check.outputs.ok }} + folder: ${{ steps.check.outputs.folder }} + steps: + - id: check + run: | + if [[ -z "${{ secrets.AWS_S3_BUCKET }}" || -z "${{ secrets.AWS_ACCESS_KEY_ID }}" || -z "${{ secrets.AWS_SECRET_ACCESS_KEY }}" ]]; then + echo ":information_source: No site configured" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "To deploy on AWS, you need the `AWS_S3_BUCKET`, `AWS_ACCESS_KEY_ID`, and `AWS_SECRET_ACCESS_KEY` secrets set up" >> $GITHUB_STEP_SUMMARY + else + echo "::set-output name=folder::"$(sed -E 's^.+/(.+)^\1^' <<< ${{ github.repository }}) + echo "::set-output name=ok::true" + fi + + full-build: + name: "Deploy to AWS" + needs: [preflight] + if: ${{ needs.preflight.outputs.ok }} + runs-on: ubuntu-latest + steps: + + - name: "Checkout site folder" + uses: actions/checkout@v3 + with: + ref: 'gh-pages' + path: 'source' + + - name: "Deploy to Bucket" + uses: jakejarvis/s3-sync-action@v0.5.1 + with: + args: --acl public-read --follow-symlinks --delete --exclude '.git/*' + env: + AWS_S3_BUCKET: ${{ secrets.AWS_S3_BUCKET }} + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + SOURCE_DIR: 'source' + DEST_DIR: ${{ needs.preflight.outputs.folder }} + + - name: "Invalidate CloudFront" + uses: chetan/invalidate-cloudfront-action@master + env: + PATHS: /* + AWS_REGION: 'us-east-1' + DISTRIBUTION: ${{ secrets.DISTRIBUTION }} + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} 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..57121573 100644 --- a/.github/workflows/sandpaper-version.txt +++ b/.github/workflows/sandpaper-version.txt @@ -1 +1 @@ -0.5.7 +0.10.1