diff --git a/gh-mq-action/.github/workflows/snyk-merge-queue-bypass.yml b/gh-mq-action/.github/workflows/snyk-merge-queue-bypass.yml new file mode 100644 index 0000000..8235c2d --- /dev/null +++ b/gh-mq-action/.github/workflows/snyk-merge-queue-bypass.yml @@ -0,0 +1,96 @@ +# ----------------------------------------------------------------------------- +# Snyk + GitHub merge queue — required check bypass (pattern #2 from Snyk) +# +# Context: Snyk's native PR checks are not reported on merge_group events, so a +# branch protection rule that requires "code/snyk (Your Org)" blocks the merge +# queue (the check never appears for the merge-group commit). +# +# This workflow runs only on merge_group and publishes a *successful* GitHub +# Check Run whose `name` exactly matches your Snyk required check. That satisfies +# merge queue / branch protection while you keep real Snyk results on pull_request. +# +# Prerequisites +# 1. Snyk still runs on pull_request (or CI) before PRs enter the queue — this +# job does not replace scanning; it only supplies the missing status name. +# 2. In GitHub: Settings → Secrets and variables → Actions → Variables +# Add: SNYK_REQUIRED_CHECK_NAME = exact string from Branch protection, e.g. +# code/snyk (your-org-name) +# 3. Branch protection: add that same name as a required status check, and do +# not restrict the source (per Snyk guidance: do not tie the rule to only +# the Snyk GitHub App). +# +# Why the Checks API: A plain Actions job shows up as "Workflow name / Job name" +# (with spaces). Snyk's check is often a single string like code/snyk (Org). +# Creating a check run via the API sets `name` to match byte-for-byte. +# ----------------------------------------------------------------------------- + +name: Snyk merge-queue required check + +on: + merge_group: + types: [checks_requested] + # Optional: limit to your default branch queue + # branches: + # - main + +permissions: + contents: read + checks: write + +concurrency: + group: snyk-mq-bypass-${{ github.event.merge_group.head_sha }} + cancel-in-progress: true + +jobs: + snyk-merge-queue-status: + name: Publish Snyk placeholder check for merge queue + runs-on: ubuntu-latest + steps: + - name: Ensure SNYK_REQUIRED_CHECK_NAME is configured + env: + SNYK_CHECK_NAME: ${{ vars.SNYK_REQUIRED_CHECK_NAME }} + run: | + if [ -z "${SNYK_CHECK_NAME}" ]; then + echo "::error title=Missing configuration::Set repository variable SNYK_REQUIRED_CHECK_NAME to the exact required status check name (e.g. code/snyk (your-org))." + exit 1 + fi + + - name: Create successful check run (matches Snyk required check name) + uses: actions/github-script@v7 + env: + SNYK_CHECK_NAME: ${{ vars.SNYK_REQUIRED_CHECK_NAME }} + with: + script: | + const checkName = process.env.SNYK_CHECK_NAME; + const sha = context.payload.merge_group.head_sha; + const { owner, repo } = context.repo; + + await github.rest.checks.create({ + owner, + repo, + name: checkName, + head_sha: sha, + status: 'completed', + conclusion: 'success', + details_url: `${context.serverUrl}/${owner}/${repo}/actions/runs/${context.runId}`, + output: { + title: 'Snyk — merge queue placeholder', + summary: + 'Native Snyk integration does not run on `merge_group`. This check exists only so the merge queue can satisfy the same required status name as on pull requests. **Rely on Snyk results from the pull request (or CI) before merging.**', + }, + }); + +# ----------------------------------------------------------------------------- +# Alternative (Snyk doc): single always-green job — only if the displayed +# Actions check name exactly equals your Snyk check (often it will not). +# +# on: +# merge_group: +# types: [checks_requested] +# jobs: +# snyk: +# name: code/snyk (your-org) # must match required check exactly +# runs-on: ubuntu-latest +# steps: +# - run: echo "Merge queue bypass; Snyk validated on the PR." +# ----------------------------------------------------------------------------- diff --git a/gh-mq-action/.gitignore b/gh-mq-action/.gitignore new file mode 100644 index 0000000..75ec3f0 --- /dev/null +++ b/gh-mq-action/.gitignore @@ -0,0 +1 @@ +.vscode/* \ No newline at end of file diff --git a/gh-mq-action/README.md b/gh-mq-action/README.md new file mode 100644 index 0000000..952fa1b --- /dev/null +++ b/gh-mq-action/README.md @@ -0,0 +1,74 @@ +# GitHub merge queues with Snyk required checks + +**Solution note — GitHub Actions workaround for merge queue status checks** + +| | | +|---|---| +| **Audience** | Teams using **GitHub merge queues** and **Snyk** with **required status checks** on protected branches | +| **Scope** | Supplies a passing check **name** on `merge_group`; does **not** replace Snyk scanning on pull requests | +| **Artifact** | [`.github/workflows/snyk-merge-queue-bypass.yml`](.github/workflows/snyk-merge-queue-bypass.yml) | + +--- + +## Overview + +Snyk’s native GitHub integration does not report status checks on **merge queue** (`merge_group`) runs. If branch protection requires a Snyk check by name, the merge queue can stall because that check never appears for the merge-group commit. + +This repository provides a **GitHub Actions workflow** that implements the **merge-queue bypass pattern** Snyk describes when native PR checks cannot run on `merge_group`: on merge queue, it publishes a **successful** GitHub check whose **name exactly matches** your required Snyk check, so merge queues can complete. **It does not run Snyk**; you still rely on Snyk results from the pull request (native PR checks and/or CI on `pull_request`). For general PR check behavior, see [Snyk’s pull request checks documentation](https://docs.snyk.io/scan-with-snyk/pull-requests/pull-request-checks/configure-pull-request-checks). + +## What you keep + +- **Snyk native PR checks** can stay enabled. They continue to run on normal pull requests as they do today. +- The workflow only runs on **merge queue** events and fills the missing status **name** for that path. + +## Setup + +### 1. Add the workflow to your repo + +Copy [`.github/workflows/snyk-merge-queue-bypass.yml`](.github/workflows/snyk-merge-queue-bypass.yml) into the **default branch** (and any protected branch that uses a merge queue) so GitHub can run it when a merge group is built. + +### 2. Configure the check name + +The workflow uses the GitHub Checks API so the status name matches Snyk’s app check **character for character** (a plain Actions job name often does not, because GitHub labels jobs as `Workflow name / Job name`). + +1. In GitHub: **Settings** → **Branches** → your protected branch → **Required status checks**. +2. Find the Snyk line (for example `code/snyk (your-org)`) and copy it **exactly**. +3. **Settings** → **Secrets and variables** → **Actions** → **Variables** → **New repository variable**: + - **Name:** `SNYK_REQUIRED_CHECK_NAME` + - **Value:** that exact string. + +For the same name at the organization level, create an organization variable with the same name (repository variables override organization variables when both exist; use whichever matches your standards). + +### 3. Branch protection + +- Require the **same** status check name as in step 2. +- Per Snyk’s guidance, **do not** restrict that required check to only the Snyk GitHub App as its source. The merge-queue run is satisfied by a check created by **GitHub Actions**; the rule must allow that source (typically “any” / name-only). + +### 4. Optional: limit which branches use the workflow + +If only certain branches use a merge queue, open the workflow file and uncomment the `branches:` list under `merge_group`. + +## Security and process + +The merge-queue check is a **placeholder** so automation can proceed. Your real security gate should remain **Snyk (and review) on the pull request** before code enters the queue. The workflow’s check output states this for anyone reviewing check details or audits. + +## Files + +| Item | Purpose | +|------|---------| +| `.github/workflows/snyk-merge-queue-bypass.yml` | Runs on `merge_group`, creates a successful check named `SNYK_REQUIRED_CHECK_NAME` | + +For implementation notes (why the Checks API is used, and a commented “simple job” alternative), see the comments at the top of the workflow file. + +--- + +## Support + +| Resource | Link | +|----------|------| +| Configure Snyk pull request checks | [docs.snyk.io — Configure pull request checks](https://docs.snyk.io/scan-with-snyk/pull-requests/pull-request-checks/configure-pull-request-checks) | +| Troubleshoot PR checks | [docs.snyk.io — Troubleshoot PR checks](https://docs.snyk.io/scan-with-snyk/pull-requests/pull-request-checks/troubleshoot-pr-checks) | +| GitHub merge queues | [docs.github.com — Managing a merge queue](https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/configuring-pull-request-merges/managing-a-merge-queue) | +| Snyk Support | [support.snyk.io](https://support.snyk.io) | + +This document describes a common integration pattern for GitHub merge queues and Snyk. It is not a substitute for [Snyk Support](https://support.snyk.io) or your account team when you need guidance specific to your organization, contract, or GitHub Enterprise settings.