Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 96 additions & 0 deletions gh-mq-action/.github/workflows/snyk-merge-queue-bypass.yml
Original file line number Diff line number Diff line change
@@ -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."
# -----------------------------------------------------------------------------
1 change: 1 addition & 0 deletions gh-mq-action/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
.vscode/*
74 changes: 74 additions & 0 deletions gh-mq-action/README.md
Original file line number Diff line number Diff line change
@@ -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.