From 3fa2e2d8d97a4b1f8776299323367ce3ae7b8225 Mon Sep 17 00:00:00 2001 From: Steven Pritchard Date: Thu, 23 May 2024 11:55:22 -0500 Subject: [PATCH] [puppetsync] Remove GitLab CI hooks from GitHub Actions (#86) --- .github/workflows/pr_glci.yml | 190 -------------------------- .github/workflows/pr_glci_cleanup.yml | 105 -------------- .github/workflows/pr_glci_manual.yml | 143 ------------------- .github/workflows/validate_tokens.yml | 17 --- 4 files changed, 455 deletions(-) delete mode 100644 .github/workflows/pr_glci.yml delete mode 100644 .github/workflows/pr_glci_cleanup.yml delete mode 100644 .github/workflows/pr_glci_manual.yml diff --git a/.github/workflows/pr_glci.yml b/.github/workflows/pr_glci.yml deleted file mode 100644 index 334f65a..0000000 --- a/.github/workflows/pr_glci.yml +++ /dev/null @@ -1,190 +0,0 @@ -# Push/Trigger a GitLab CI pipeline for the PR HEAD, **ONLY IF:** -# -# 1. The .gitlab-ci.yaml file exists and validates -# 2. The PR submitter has write access to the target repository. -# -# ------------------------------------------------------------------------------ -# -# NOTICE: **This file is maintained with puppetsync** -# -# This file is updated automatically as part of a puppet module baseline. -# -# The next baseline sync will overwrite any local changes to this file! -# -# ============================================================================== -# -# GitHub Action Secrets variables available for this pipeline: -# -# GitHub Secret variable Type Notes -# ------------------------ -------- ---------------------------------------- -# GITLAB_API_PRIVATE_TOKEN Secure Should have `api` scope -# GITLAB_API_URL Optional -# -# The secure vars will be filtered in GitHub Actions log output, and aren't -# provided to untrusted builds (i.e, triggered by PR from another repository) -# -# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -# WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING -# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!V!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -# -# DO NOT MODIFY this workflow, unless you **REALLY** know what you are doing. -# -# This workflow bypasses some of the built-in protections of the -# `pull_request_target` event by explicitly checking out the PR's **HEAD**. -# Without being VERY CAREFUL, this could easily allow a malcious PR -# contributor the chance to access secrets or a GITHUB_TOKEN with write scope!! -# -# The jobs in this workflow are designed to handle this safely -- but DO NOT -# assume any alterations will also be safe. -# -# For general information, see: -# -# https://docs.github.com/en/actions/reference/events-that-trigger-workflows#pull_request_target -# -# For further information, or if ANY of this seems confusing or unecessary: -# -# ASK FOR ASSISTANCE **BEFORE** ATTEMPTING TO MODIFY THIS WORKFLOW. -# -# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -# WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING -# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!V!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -# -# https://docs.github.com/en/actions/reference/events-that-trigger-workflows -# ---- -name: PR GLCI -on: - pull_request_target: - types: [opened, reopened, synchronize] - -jobs: - - # The ONLY reason we can validate the PR HEAD's content safely here is that - # we restrict ourselves to sending data elsewhere. - glci-syntax: - name: '.gitlab-ci.yml Syntax' - runs-on: ubuntu-latest - outputs: - valid: ${{ steps.validate-glci-file.outputs.valid }} - steps: - - uses: actions/checkout@v3 - with: - repository: ${{ github.event.pull_request.head.repo.full_name }} - ref: ${{ github.event.pull_request.head.ref }} - - name: 'Validate GLCI file syntax' - id: validate-glci-file - uses: simp/github-action-gitlab-ci-syntax-check@main - with: - gitlab_api_private_token: ${{ secrets.GITLAB_API_PRIVATE_TOKEN }} - gitlab_api_url: ${{ secrets.GITLAB_API_URL }} # https://gitlab.com/api/v4 - - contributor-permissions: - name: 'PR contributor check' - runs-on: ubuntu-latest - outputs: - permitted: ${{ steps.user-repo-permissions.outputs.permitted }} - steps: - - uses: actions/github-script@v6 - id: user-repo-permissions - with: - github-token: ${{secrets.GITHUB_TOKEN}} - # See: - # - https://octokit.github.io/rest.js/ - # - https://docs.github.com/en/free-pro-team@latest/rest/reference/repos#get-repository-permissions-for-a-user - script: | - const project_permission = await github.request('GET /repos/{owner}/{repo}/collaborators/{username}/permission', { - headers: { - accept: 'application/vnd.github.v3+json' - }, - owner: context.repo.owner, - repo: context.repo.repo, - username: context.payload.sender.login, - }) - const has_write_access = perm_lvl => (perm_lvl == "admin" || perm_lvl == "write" ) - const write_access_desc = perm_bool => (perm_bool ? "PERMISSION OK" : "PERMISSION DENIED" ) - if( has_write_access(project_permission.data.permission )){ - core.setOutput( 'permitted', 'true' ) - } else { - core.setOutput( 'permitted', 'false' ) - console.log(`::error ::payload user '${context.payload.sender.login}' does not have CI trigger permission for '${context.repository}; not triggering external CI'`) - } - console.log(`== payload user '${context.payload.sender.login}' CI trigger permission for '${context.repo.owner}': ${write_access_desc(has_write_access(project_permission.data.permission))}`) - - - trigger-when-user-has-repo-permissions: - name: 'Trigger CI [trusted users only]' - needs: [ glci-syntax, contributor-permissions ] - # This conditional provides an extra safety control, in case the workflow's - # `on` section is inadventently modified without considering the security - # implications. - # - # This job will ONLY trigger on: - # - # - [x] pull_request_target event: github.event_name == 'pull_request_target' - # AND: - # - [x] Newly-opened PRs: github.event.action == 'opened' - # - [x] Re-opened PRs: github.event.action == 'reopened' - # - [x] Commits are added to PR: github.event.action == 'synchronize' - # AND: - # - [x] .gitlab-ci.yml exists/ok: needs.glci-syntax.outputs.valid == 'true' - # - # [Not implemented] It should NEVER trigger on: - # - # - [ ] Merged PRs: github.event.pull_request.merged == 'false' - # - (the downstream GitLab mirror will take care of that) - # - Not implemented: For some reason, this conditional always fails - # - Unnecessary if on>pull_request_target>types doesn't include 'closed' - if: github.event_name == 'pull_request_target' && ( github.event.action == 'opened' || github.event.action == 'reopened' || github.event.action == 'synchronize' ) && github.event.pull_request.merged != 'true' && needs.glci-syntax.outputs.valid == 'true' && needs.contributor-permissions.outputs.permitted == 'true' - runs-on: ubuntu-latest - steps: - # Things we'd like to do: - # - [ ] if there's no GitLab mirror, make one - # - [ ] if there's no GitLab <-> GitHub integration, make one - # - [ ] if there's no PR check on the main GitHub branch, make one (?) - # - [x] Cancel any GLCI pipelines already pending/running for this branch - # - "created|waiting_for_resource|preparing|pending|running" - # - Exception: don't cancel existing pipeline for our own commit - # - [x] if PR: force-push branch to GitLab - - uses: actions/checkout@v3 - if: needs.contributor-permissions.outputs.permitted == 'true' - with: - clean: true - fetch-depth: 0 # Need full checkout to push to gitlab mirror - repository: ${{ github.event.pull_request.head.repo.full_name }} - ref: ${{ github.event.pull_request.head.ref }} - - - name: Trigger CI when user has Repo Permissions - if: needs.contributor-permissions.outputs.permitted == 'true' - uses: simp/github-action-gitlab-ci-pipeline-trigger@v1 - with: - git_branch: ${{ github.event.pull_request.head.ref }} # TODO check for/avoid protected branches? - git_hashref: ${{ github.event.pull_request.head.sha }} - gitlab_api_private_token: ${{ secrets.GITLAB_API_PRIVATE_TOKEN }} - gitlab_group: ${{ github.event.organization.login }} - github_repository: ${{ github.repository }} - github_repository_owner: ${{ github.repository_owner }} - - - name: When user does NOT have Repo Permissions - if: needs.contributor-permissions.outputs.permitted == 'false' - continue-on-error: true - run: | - echo "Ending gracefully; Contributor $GITHUB_ACTOR does not have permission to trigger CI" - false - -### examine_contexts: -### name: 'Examine Context contents' -### if: always() -### runs-on: ubuntu-latest -### needs: [ glci-syntax, contributor-permissions ] -### steps: -### - name: Dump contexts -### env: -### GITHUB_CONTEXT: ${{ toJson(github) }} -### run: echo "$GITHUB_CONTEXT" -### - name: Dump needs context -### env: -### ENV_CONTEXT: ${{ toJson(needs) }} -### run: echo "$ENV_CONTEXT" -### - name: Dump env vars -### run: env | sort - diff --git a/.github/workflows/pr_glci_cleanup.yml b/.github/workflows/pr_glci_cleanup.yml deleted file mode 100644 index a406360..0000000 --- a/.github/workflows/pr_glci_cleanup.yml +++ /dev/null @@ -1,105 +0,0 @@ -# When a PR is closed, clean up any associated GitLab CI pipelines & branch -# -# * Cancels all GLCI pipelines associated with the PR HEAD ref (branch) -# * Removes the PR HEAD branch from the corresponding gitlab.com/org/ project -# -# ------------------------------------------------------------------------------ -# -# NOTICE: **This file is maintained with puppetsync** -# -# This file is updated automatically as part of a standardized asset baseline. -# -# The next baseline sync will overwrite any local changes to this file! -# -# ============================================================================== -# -# GitHub Action Secrets variables available for this pipeline: -# -# GitHub Secret variable Type Notes -# ------------------------ -------- ---------------------------------------- -# GITLAB_API_PRIVATE_TOKEN Secure Should have `api` scope -# GITLAB_API_URL Optional -# -# The secure vars will be filtered in GitHub Actions log output, and aren't -# provided to untrusted builds (i.e, triggered by PR from another repository) -# -# ------------------------------------------------------------------------------ -# -# https://docs.github.com/en/actions/reference/events-that-trigger-workflows -# ---- -name: PR GLCI Cleanup -on: - pull_request_target: - types: [closed] - -jobs: - cleanup-glci-branch: - name: 'Clean up GLCI' - # This conditional provides an extra safety control, in case the workflow's - # `on` section is inadventently modified without considering the security - # implications. - if: github.event_name == 'pull_request_target' && github.event.action == 'closed' - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - with: - repository: ${{ github.event.pull_request.head.repo.full_name }} - ref: ${{ github.event.pull_request.head.ref }} - - name: Trigger CI when user has Repo Permissions - env: - GITLAB_SERVER_URL: ${{ secrets.GITLAB_SERVER_URL }} # https://gitlab.com - GITLAB_API_URL: ${{ secrets.GITLAB_API_URL }} # https://gitlab.com/api/v4 - GITLAB_ORG: ${{ github.event.organization.login }} - GITLAB_API_PRIVATE_TOKEN: ${{ secrets.GITLAB_API_PRIVATE_TOKEN }} - GIT_BRANCH: ${{ github.event.pull_request.head.ref }} - run: | - GITLAB_SERVER_URL="${GITLAB_SERVER_URL:-https://gitlab.com}" - GITLAB_API_URL="${GITLAB_API_URL:-${GITLAB_SERVER_URL}/api/v4}" - GIT_BRANCH="${GIT_BRANCH:-GITHUB_HEAD_REF}" - GITXXB_REPO_NAME="${GITHUB_REPOSITORY/$GITHUB_REPOSITORY_OWNER\//}" - GITLAB_PROJECT_ID="${GITLAB_ORG}%2F${GITXXB_REPO_NAME}" - # --http1.0 avoids an HTTP/2 load balancing issue when run from GA - CURL_CMD=(curl --http1.0 --fail --silent --show-error \ - --header "Authorization: Bearer $GITLAB_API_PRIVATE_TOKEN" \ - --header "Content-Type: application/json" \ - --header "Accept: application/json" \ - ) - - # Cancel any active/pending GitLab CI pipelines for the same project+branch - active_pipeline_ids=() - for pipe_status in created waiting_for_resource preparing pending running; do - echo " ---- checking for CI pipelines with status '$pipe_status' for project '$GITLAB_PROJECT_ID', branch '$GIT_BRANCH'" - url="${GITLAB_API_URL}/projects/${GITLAB_PROJECT_ID}/pipelines?ref=${GIT_BRANCH}&status=${pipe_status}" - active_pipelines="$("${CURL_CMD[@]}" "$url" | jq -r '.[] | .id , .web_url')" - active_pipeline_ids+=($(echo "$active_pipelines" | grep -E '^[0-9]*$')) - printf "$active_pipelines\n\n" - done - if [ "${#active_pipeline_ids[@]}" -gt 0 ]; then - printf "\nFound %s active pipeline ids:\n" "${#active_pipeline_ids[@]}" - echo "${active_pipeline_ids[@]}" - for pipe_id in "${active_pipeline_ids[@]}"; do - printf "\n ------ Cancelling pipeline ID %s...\n" "$pipe_id" - "${CURL_CMD[@]}" --request POST "${GITLAB_API_URL}/projects/${GITLAB_PROJECT_ID}/pipelines/${pipe_id}/cancel" - done - else - echo No active pipelines found - fi - - echo "== Removing $GIT_BRANCH from gitlab" - git remote add gitlab "https://oauth2:${GITLAB_API_PRIVATE_TOKEN}@${GITLAB_SERVER_URL#*://}/${GITLAB_ORG}/${GITXXB_REPO_NAME}.git" - git push gitlab ":${GIT_BRANCH}" -f || : # attempt to un-weird GLCI's `changed` tracking - -### examine_contexts: -### name: 'Examine Context contents' -### if: always() -### runs-on: ubuntu-latest -### steps: -### - name: Dump contexts -### env: -### GITHUB_CONTEXT: ${{ toJson(github) }} -### run: echo "$GITHUB_CONTEXT" -### run: echo "$ENV_CONTEXT" -### - name: Dump env vars -### run: env | sort - diff --git a/.github/workflows/pr_glci_manual.yml b/.github/workflows/pr_glci_manual.yml deleted file mode 100644 index 3a4f3f4..0000000 --- a/.github/workflows/pr_glci_manual.yml +++ /dev/null @@ -1,143 +0,0 @@ -# Manually trigger GLCI pipelines for a PR -# ------------------------------------------------------------------------------ -# -# NOTICE: **This file is maintained with puppetsync** - -# This file is updated automatically as part of a standardized asset baseline. -# -# The next baseline sync will overwrite any local changes to this file! -# -# ============================================================================== -# -# This pipeline uses the following GitHub Action Secrets: -# -# GitHub Secret variable Type Notes -# ------------------------ -------- ---------------------------------------- -# GITLAB_API_PRIVATE_TOKEN Required GitLab token (should have `api` scope) -# NO_SCOPE_GITHUB_TOKEN Required GitHub token (should have no scopes) -# GITLAB_SERVER_URL Optional Specify a GL server other than gitlab.com -# The secure vars will be filtered in GitHub Actions log output, and aren't -# provided to untrusted builds (i.e, triggered by PR from another repository) -# -# ------------------------------------------------------------------------------ -# -# NOTES: -# It is necessary to provide NO_SCOPE_GITHUB_TOKEN because $secrets.GITHUB_AUTO -# is NOT provide to manually-triggered (`workflow_dispatch`) events, in order -# to prevent recursive triggers between workflows -# -# Reference: -# -# https://docs.github.com/en/actions/reference/events-that-trigger-workflows#triggering-new-workflows-using-a-personal-access-token ---- -name: 'Manual: PR GLCI' - -on: - workflow_dispatch: - inputs: - pr_number: - description: "PR number to trigger GLCI" - required: true - -jobs: - glci-syntax: - name: '.gitlab-ci.yml Syntax' - runs-on: ubuntu-latest - outputs: - valid: ${{ steps.validate-glci-file.outputs.valid }} - pr_head_ref: ${{ steps.get-pr.outputs.pr_head_ref }} - pr_head_sha: ${{ steps.get-pr.outputs.pr_head_sha }} - pr_head_label: ${{ steps.get-pr.outputs.pr_head_label }} - pr_head_full_name: ${{ steps.get-pr.outputs.pr_full_name }} - steps: - - uses: actions/github-script@v6 - id: get-pr - with: - github-token: ${{secrets.NO_SCOPE_GITHUB_TOKEN}} - # See: - # - https://octokit.github.io/rest.js/ - script: | - console.log(`== pr number: ${context.payload.inputs.pr_number}`) - const pr = await github.request('get /repos/{owner}/{repo}/pulls/{pull_number}', { - headers: { - accept: 'application/vnd.github.v3+json' - }, - owner: context.repo.owner, - repo: context.repo.repo, - pull_number: context.payload.inputs.pr_number - }); - - console.log("\n\n== pr\n"); - console.log(pr); - console.log("\n\n== pr.data.head\n"); - console.log(pr.data.head); - console.log(pr.status); - - // PR must have been returned - if ( pr.status != 200 ) { - //#console.log(`::error ::Error looking up PR \#${context.payload.inputs.pr_number}: HTTP Response ${pr.status}`) - return(false) - } - - // TODO: should either of these conditions really prevent a GLCI trigger? - if ( pr.data.state != 'open' ) { - console.log(`::error ::PR# ${context.payload.inputs.pr_number} is not open`) - } - if ( pr.data.merged ) { - console.log(`::error ::PR# ${context.payload.inputs.pr_number} is already merged`) - } - core.setOutput( 'pr_head_sha', pr.data.head.sha ) - core.setOutput( 'pr_head_ref', pr.data.head.ref ) - core.setOutput( 'pr_head_label', pr.data.head.label ) - core.setOutput( 'pr_head_full_name', pr.data.head.full_name ) - - uses: actions/checkout@v3 - with: - repository: ${{ steps.get-pr.outputs.pr_head_full_name }} - ref: ${{ steps.get-pr.outputs.pr_head_sha }} - token: ${{secrets.NO_SCOPE_GITHUB_TOKEN}} - clean: true - - name: 'Validate GLCI file syntax' - id: validate-glci-file - uses: simp/github-action-gitlab-ci-syntax-check@main - with: - gitlab_api_private_token: ${{ secrets.GITLAB_API_PRIVATE_TOKEN }} - gitlab_api_url: ${{ secrets.GITLAB_API_URL }} # https://gitlab.com/api/v4 - - trigger-when-user-has-repo-permissions: - name: 'Trigger CI' - needs: [ glci-syntax ] - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - with: - repository: ${{ needs.glci-syntax.outputs.pr_head_full_name }} - ref: ${{ needs.glci-syntax.outputs.pr_head_sha }} - token: ${{secrets.NO_SCOPE_GITHUB_TOKEN}} - fetch-depth: 0 # Need full checkout to push to gitlab mirror - clean: true - - name: Trigger CI when user has Repo Permissions - uses: simp/github-action-gitlab-ci-pipeline-trigger@v1 - with: - git_hashref: ${{ needs.glci-syntax.outputs.pr_head_sha }} - git_branch: ${{ needs.glci-syntax.outputs.pr_head_ref }} - gitlab_api_private_token: ${{ secrets.GITLAB_API_PRIVATE_TOKEN }} - gitlab_group: ${{ github.event.organization.login }} - github_repository: ${{ github.repository }} - github_repository_owner: ${{ github.repository_owner }} - -### examine_contexts: -### needs: [ glci-syntax ] -### name: 'Examine Context contents' -### if: always() -### runs-on: ubuntu-latest -### steps: -### - name: Dump contexts -### env: -### GITHUB_CONTEXT: ${{ toJson(github) }} -### run: echo "$GITHUB_CONTEXT" -### - name: Dump 'needs' context -### env: -### ENV_CONTEXT: ${{ toJson(needs) }} -### run: echo "$ENV_CONTEXT" -### - name: Dump env vars -### run: env | sort diff --git a/.github/workflows/validate_tokens.yml b/.github/workflows/validate_tokens.yml index 0650ac5..11dd5f3 100644 --- a/.github/workflows/validate_tokens.yml +++ b/.github/workflows/validate_tokens.yml @@ -14,9 +14,7 @@ # GitHub Secret variable Type Notes # ------------------------ -------- ---------------------------------------- # PUPPETFORGE_API_TOKEN Required -# GITLAB_API_PRIVATE_TOKEN Required GitLab token (should have `api` scope) # NO_SCOPE_GITHUB_TOKEN Required GitHub token (should have no scopes) -# GITLAB_SERVER_URL Optional Specify a GL server other than gitlab.com # The secure vars will be filtered in GitHub Actions log output, and aren't # provided to untrusted builds (i.e, triggered by PR from another repository) # @@ -40,21 +38,6 @@ jobs: --header "Authorization: Bearer ${PUPPETFORGE_API_TOKEN:-default_content_to_cause_401_response}" \ https://forgeapi.puppet.com/v3/users > /dev/null - gitlab: - name: 'GitLab token has scope for developer' - runs-on: ubuntu-latest - env: - GITLAB_API_PRIVATE_TOKEN: ${{ secrets.GITLAB_API_PRIVATE_TOKEN }} - GITLAB_API_URL: ${{ secrets.GITLAB_API_URL }} - GITLAB_ORG: ${{ github.event.organization.login }} - steps: - - run: | - GITLAB_API_URL="${GITLAB_API_URL:-https://gitlab.com/api/v4}" - curl -I --http1.1 --fail --silent --show-error \ - --header 'Content-Type: application/json' \ - --header "Authorization: Bearer $GITLAB_API_PRIVATE_TOKEN" \ - "${CURL_CMD[@]}" "${GITLAB_API_URL}/groups/$GITLAB_ORG/audit_events" - github-no-scope: name: 'No-scope GitHub token has NO scopes' runs-on: ubuntu-latest