From bec94b46611ef2b4f78803643b0da6aa9e555911 Mon Sep 17 00:00:00 2001 From: Eli Bosley Date: Tue, 16 Sep 2025 11:35:59 -0400 Subject: [PATCH 1/2] chore: cleanup PR builds --- .github/workflows/pr-plugin-cleanup.yml | 94 +++++++++++++++++++++++++ 1 file changed, 94 insertions(+) create mode 100644 .github/workflows/pr-plugin-cleanup.yml diff --git a/.github/workflows/pr-plugin-cleanup.yml b/.github/workflows/pr-plugin-cleanup.yml new file mode 100644 index 000000000..22b0aa1f5 --- /dev/null +++ b/.github/workflows/pr-plugin-cleanup.yml @@ -0,0 +1,94 @@ +name: Cleanup PR Plugin from R2 + +on: + pull_request: + types: [closed] + workflow_dispatch: + inputs: + pr_number: + description: 'Pull Request number to cleanup' + required: true + type: string + +permissions: + contents: read + pull-requests: write + +jobs: + cleanup-r2: + runs-on: ubuntu-latest + defaults: + run: + shell: bash + env: + SHELLOPTS: errexit:pipefail + + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ github.event.repository.default_branch }} + repository: ${{ github.repository }} + + - name: Determine PR number + id: pr + run: | + set -Eeuo pipefail + IFS=$'\n\t' + + if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then + PR_NUMBER="${{ inputs.pr_number }}" + else + PR_NUMBER="${{ github.event.pull_request.number }}" + fi + + echo "pr_number=$PR_NUMBER" >> $GITHUB_OUTPUT + echo "Cleaning up PR #$PR_NUMBER" + + - name: Delete PR folder from R2 + env: + PR_NUMBER: ${{ steps.pr.outputs.pr_number }} + CLOUDFLARE_PREVIEW_BUCKET_NAME: ${{ secrets.CLOUDFLARE_PREVIEW_BUCKET_NAME }} + CLOUDFLARE_S3_URL: ${{ secrets.CLOUDFLARE_S3_URL }} + AWS_ACCESS_KEY_ID: ${{ secrets.CLOUDFLARE_PREVIEW_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.CLOUDFLARE_PREVIEW_SECRET_ACCESS_KEY }} + AWS_DEFAULT_REGION: auto + AWS_EC2_METADATA_DISABLED: true + AWS_SHARED_CREDENTIALS_FILE: /dev/null + AWS_CONFIG_FILE: /dev/null + run: | + set -Eeuo pipefail + IFS=$'\n\t' + + PR_FOLDER="pr-plugins/pr-${PR_NUMBER}/" + + echo "Deleting folder: $PR_FOLDER" + + # List all objects in the PR folder + aws s3 ls "s3://$CLOUDFLARE_PREVIEW_BUCKET_NAME/$PR_FOLDER" \ + --endpoint-url "$CLOUDFLARE_S3_URL" \ + --recursive || { + echo "No files found for PR #$PR_NUMBER (folder may not exist)" + exit 0 + } + + # Delete all objects in the PR folder + aws s3 rm "s3://$CLOUDFLARE_PREVIEW_BUCKET_NAME/$PR_FOLDER" \ + --endpoint-url "$CLOUDFLARE_S3_URL" \ + --recursive + + echo "Successfully deleted all files for PR #$PR_NUMBER" + + - name: Comment on PR + if: github.event_name == 'pull_request' + uses: marocchino/sticky-pull-request-comment@v2 + with: + number: ${{ steps.pr.outputs.pr_number }} + header: pr-plugin-cleanup + message: | + ## 🧹 PR Test Plugin Cleaned Up + + The test plugin and associated files for this PR have been removed from the preview environment. + + --- + 🤖 This comment is automatically generated when a PR is closed. \ No newline at end of file From c445e1448471c8e6745ea2cb3359b3d80604c280 Mon Sep 17 00:00:00 2001 From: Eli Bosley Date: Tue, 16 Sep 2025 15:02:09 -0400 Subject: [PATCH 2/2] chore: add validation and error handling for PR number and folder in cleanup workflow --- .github/workflows/pr-plugin-cleanup.yml | 70 +++++++++++++++++++++---- 1 file changed, 61 insertions(+), 9 deletions(-) diff --git a/.github/workflows/pr-plugin-cleanup.yml b/.github/workflows/pr-plugin-cleanup.yml index 22b0aa1f5..21e85e530 100644 --- a/.github/workflows/pr-plugin-cleanup.yml +++ b/.github/workflows/pr-plugin-cleanup.yml @@ -42,6 +42,18 @@ jobs: PR_NUMBER="${{ github.event.pull_request.number }}" fi + # Validate PR_NUMBER is non-empty and purely numeric + if [[ -z "$PR_NUMBER" ]]; then + echo "Error: PR_NUMBER is empty" >&2 + exit 1 + fi + + if ! [[ "$PR_NUMBER" =~ ^[0-9]+$ ]]; then + echo "Error: PR_NUMBER '$PR_NUMBER' is not a valid number (must be purely numeric)" >&2 + exit 1 + fi + + # Only proceed with output and cleanup if validation passes echo "pr_number=$PR_NUMBER" >> $GITHUB_OUTPUT echo "Cleaning up PR #$PR_NUMBER" @@ -60,22 +72,62 @@ jobs: set -Eeuo pipefail IFS=$'\n\t' + # Validate PR_NUMBER is numeric (double-check) + if ! [[ "$PR_NUMBER" =~ ^[0-9]+$ ]]; then + echo "Error: PR_NUMBER '$PR_NUMBER' is not numeric" >&2 + exit 1 + fi + + # Construct PR folder with expected prefix PR_FOLDER="pr-plugins/pr-${PR_NUMBER}/" - echo "Deleting folder: $PR_FOLDER" + # Validate the folder prefix for safety + if ! [[ "$PR_FOLDER" =~ ^pr-plugins/pr-[0-9]+/$ ]]; then + echo "Error: Invalid PR_FOLDER format: '$PR_FOLDER'" >&2 + exit 1 + fi - # List all objects in the PR folder - aws s3 ls "s3://$CLOUDFLARE_PREVIEW_BUCKET_NAME/$PR_FOLDER" \ + echo "Checking for objects in folder: $PR_FOLDER" + + # Use list-objects-v2 for safer existence check + RESPONSE=$(aws s3api list-objects-v2 \ + --bucket "$CLOUDFLARE_PREVIEW_BUCKET_NAME" \ + --prefix "$PR_FOLDER" \ --endpoint-url "$CLOUDFLARE_S3_URL" \ - --recursive || { - echo "No files found for PR #$PR_NUMBER (folder may not exist)" - exit 0 - } + --max-keys 1 \ + 2>&1) || { + EXIT_CODE=$? + echo "Error: Failed to list objects (exit code: $EXIT_CODE)" >&2 + echo "Response: $RESPONSE" >&2 + exit $EXIT_CODE + } - # Delete all objects in the PR folder + # Check if any objects exist + KEY_COUNT=$(echo "$RESPONSE" | grep -o '"KeyCount":[0-9]*' | cut -d: -f2 || echo "0") + + if [[ "$KEY_COUNT" == "0" ]]; then + echo "No objects found in $PR_FOLDER - nothing to delete" + exit 0 + fi + + echo "Found objects in $PR_FOLDER - proceeding with deletion" + + # Delete all objects recursively aws s3 rm "s3://$CLOUDFLARE_PREVIEW_BUCKET_NAME/$PR_FOLDER" \ --endpoint-url "$CLOUDFLARE_S3_URL" \ - --recursive + --recursive || { + EXIT_CODE=$? + echo "Error: Failed to delete objects (exit code: $EXIT_CODE)" >&2 + exit $EXIT_CODE + } + + # Remove directory marker object if it exists (the key with trailing slash) + DIR_MARKER="${PR_FOLDER%/}" # Remove trailing slash for the marker + aws s3api delete-object \ + --bucket "$CLOUDFLARE_PREVIEW_BUCKET_NAME" \ + --key "$DIR_MARKER/" \ + --endpoint-url "$CLOUDFLARE_S3_URL" \ + 2>/dev/null || true # Ignore if marker doesn't exist echo "Successfully deleted all files for PR #$PR_NUMBER"