Skip to content
Open
2 changes: 2 additions & 0 deletions .github/actions/pr-open-check/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -57,10 +57,12 @@ runs:
pr_url=$(jq -r '[.[] | select(.state == "open")][0].html_url // empty' <<<"$pr_json")

if [[ -n "$pr_number" ]]; then
echo "Found open PR #$pr_number for commit '$COMMIT'"
echo "pr_exists=true" >> "$GITHUB_OUTPUT"
echo "pr_number=$pr_number" >> "$GITHUB_OUTPUT"
echo "pr_url=$pr_url" >> "$GITHUB_OUTPUT"
else
echo "No open PR found for commit '$COMMIT'"
echo "pr_exists=false" >> "$GITHUB_OUTPUT"
echo "pr_number=" >> "$GITHUB_OUTPUT"
echo "pr_url=" >> "$GITHUB_OUTPUT"
Expand Down
18 changes: 18 additions & 0 deletions .github/actions/upsert-pr-comment/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# upsert-pr-comment action Changelog

All notable changes to the **upsert-pr-comment** action are documented in this file.

## 1.0.0

### Added

- Initial release of the reusable composite action for upserting PR comments.
- Supports creating or updating a PR comment based on a unique hidden marker.
- Accepts the following required inputs:
- `github-token`: GitHub token with repo scope
- `pr-number`: Pull Request number
- `comment-marker`: Unique marker to identify the comment
- `body-content`: Markdown content for the comment body
- Uses `actions/github-script@v7` to interact with the GitHub REST API.
- Automatically updates an existing comment if the marker is found, or creates a new comment if not.
- No external dependencies required beyond GitHub Actions standard runners.
67 changes: 67 additions & 0 deletions .github/actions/upsert-pr-comment/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
# Upsert PR Comment Action

## 🧭 Summary

Creates or updates a comment on a GitHub Pull Request. The comments are identified by a unique hidden marker. This ensures only one comment per marker is present, updating the comment if one already exists for the marker or creating a new one if not.

## Scope/Limitations

- Supports upserting comments on an open PR in any repository where the action is used.
- Only works for PRs (not issues or other event types).
- Requires a GitHub token with appropriate permissions.
- The marker must be unique per comment type to avoid accidental overwrites.

## 🔒 Permissions

The following GitHub Actions permissions are required:

```yaml
permissions:
contents: read
pull-requests: write
```

## Dependencies

- Uses `actions/github-script@v7`
- Uses the GitHub REST API
- Runs on any GitHub-hosted runner

## ⚙️ Inputs

| Name | Required | Description |
| ---------------- | -------- | ---------------------------------------------------------------- |
| `github-token` | ✅ | GitHub token with repo scope (use `${{ secrets.GITHUB_TOKEN }}`) |
| `pr-number` | ✅ | Pull Request number |
| `comment-marker` | ✅ | Unique marker to identify the comment (hidden in HTML comment) |
| `body-content` | ✅ | Markdown content for the comment body |

## 📤 Outputs

This action does not set any outputs.

## 🚀 Usage

Basic usage example:

```yaml
- name: Upsert PR summary comment
uses: ./.github/actions/upsert-pr-comment
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
pr-number: ${{ github.event.pull_request.number }}
comment-marker: 'my-unique-marker'
body-content: |
## PR Scan Results
- All checks passed!
```

## 🧠 Notes

- The comment marker is embedded as an HTML comment and should be unique for each comment type you want to upsert.
- If multiple workflows use the same marker, they will overwrite each other's comments.
- The action uses the GitHub REST API to list, update, or create comments.

## Versioning

This action uses namespaced tags for versioning and is tracked in the repository CHANGELOG.
55 changes: 55 additions & 0 deletions .github/actions/upsert-pr-comment/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
name: Upsert PR Comment
description: Creates or updates a PR comment based on a unique marker
inputs:
github-token:
description: GitHub token with repo scope (use GITHUB_TOKEN)
required: true
pr-number:
description: PR number
required: true
comment-marker:
description: Unique marker to identify the comment for upsert, value will be hidden in HTML comment
required: true
body-content:
description: Markdown content for the comment body
required: true
runs:
using: composite
steps:
- name: Upsert PR summary comment
uses: actions/github-script@v7
env:
PR_NUMBER: ${{ inputs.pr-number }}
COMMENT_MARKER: ${{ inputs.comment-marker }}
BODY_CONTENT: ${{ inputs.body-content }}
with:
github-token: ${{ inputs.github-token }}
script: |
const body = `<!-- ${process.env.COMMENT_MARKER} -->
${process.env.BODY_CONTENT}
`;

// Upsert by hidden marker to avoid duplicate comments
const { data: comments } = await github.rest.issues.listComments({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: process.env.PR_NUMBER,
per_page: 100,
});

const existing = comments.find(c => c.body && c.body.includes(`<!-- ${process.env.COMMENT_MARKER} -->`));
if (existing) {
await github.rest.issues.updateComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: existing.id,
body,
});
} else {
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: process.env.PR_NUMBER,
body,
});
}
17 changes: 17 additions & 0 deletions .github/workflows/CHANGELOGS/run_semgrep_scan.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Run Semgrep Scan Workflow Changelog

All notable changes to the **run_semgrep_scan** callable workflow are documented in this file.

## 1.0.0

### Added

- First official release of the `run_semgrep_scan` workflow.
- Supports both full and diff/baseline scan modes.
- Configurable via `workflow_call` inputs for rulesets, targets, fail severity, and more.
- Integrates with PRs and pushes, posting findings to Actions UI, Job Summary, PR comments, and Reviewdog.
- Outputs scan results, config summary, and normalized baseline for downstream jobs.
- Replaces previous usage under the `legacy-stable` tag with a versioned, documented workflow.
- Refactored code for maintainability.
- Added support for specifying Semgrep version, multiple rulesets, specific targets, and extra arguments.
- Note: Some input defaults have changed and may be breaking for consumers.
47 changes: 41 additions & 6 deletions .github/workflows/README.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,44 @@
# GitHub Action Workflows
# GitHub Workflows Directory

## Naming Convention
This directory contains externally reusable and internal, project-specific GitHub Actions workflows for this repository.

- **Reusable workflows** (those that expose `workflow_call`) are treated as **products** of this repo.
Their filenames should describe what they do, e.g. `deploy_environment.yml`, `tf_apply.yml`.
## Internal Workflows

- **Internal workflows** (used only by this repository and never exposed via `workflow_call`)
must be prefixed with: `internal_`
Internal workflows are used by this repository for the pipeline of its products. They must never expose `workflow_call` and must be prefixed with `internal_`

## Reusable Workflows

This repository exposes externally reusable workflows, those that expose `workflow_call`. These workflows are treated as **products** of this repo.

### Requirements

- Only `.yml` files are considered valid workflow definitions.
- Workflow, changelog, and README file names must match the workflow name (excluding the `.yml` extension).
- CHANGELOGs and READMEs must be kept up to date with any changes to the workflow.

- **Workflow YAML files:**
- Workflow definitions must be placed directly in this directory.
- Their filenames should describe what they do, e.g. `deploy_environment.yml`, `tf_apply.yml`.
- File name: `{workflow_name}.yml`
- Example: `run_semgrep_scan.yml`

- **Changelog files:**
- Each workflow must have a corresponding changelog documenting all notable changes.
- Path: `CHANGELOGS/{workflow_name}.md`
- Example: `CHANGELOGS/run_semgrep_scan.md`

- **README files:**
- Each workflow should have a README describing its purpose, usage, inputs, and outputs.
- Path: `READMEs/{workflow_name}.md`
- Example: `READMEs/run_semgrep_scan.md`

### Example Structure

```text
.github/workflows/
run_semgrep_scan.yml
CHANGELOGS/
run_semgrep_scan.md
READMEs/
run_semgrep_scan.md
```
69 changes: 69 additions & 0 deletions .github/workflows/READMES/run_semgrep_scan.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
# Run Semgrep Scan

This workflow runs [Semgrep](https://semgrep.dev/) on your repository to perform static code analysis, to report security issues, bugs, and code quality problems.

## Purpose

The `run_semgrep_scan` workflow designed to be reusable and configurable for different scan scenarios. It supports both full and differential scans, integrates with pushes and PRs, and can be customized for different rule sets, targets, and failure thresholds. The workflow is intended to:

- Enforce code security and quality standards
- Catch issues early in the development lifecycle
- Provide actionable feedback directly in GitHub

## Usage

This workflow is intended to be called by other workflows using `workflow_call`.

### Inputs

You can customize the scan by providing the following inputs:

| Input Name | Type | Default | Description |
|-------------------------|---------|-------------------|-------------------------------------------------------------------|
| `commit_identifier` | string | (required) | Commit SHA or ref to scan |
| `cancel_in_progress` | boolean | true | Cancel in-progress run for the same ref |
| `semgrep_config` | string | p/default | Semgrep rulesets to use (YAML array, newline, or space-separated) |
| `semgrep_targets` | string | . | Files/directories to scan |
| `extra_args` | string | '' | Additional arguments to pass to Semgrep |
| `semgrep_version` | string | '' | Semgrep version to install |
| `fail_severity` | string | error | Minimum severity to fail the workflow (`error`, `warning`, `info`)|
| `semgrep_scan_mode` | string | full | Scan mode: `full`, `diff`, or `baseline` |
| `baseline_ref` | string | origin/main | Ref for diff/baseline scans |
| `reviewdog_filter_mode` | string | nofilter | Reviewdog display filter: `added`, `diff_context`, `nofilter` |
| `reviewdog_reporter` | string | github-pr-review | Reviewdog reporter type |

See the workflow file for full input documentation and defaults.

### How it works

1. Checks out the code at the specified commit or ref.
2. Checks for an open PR and normalizes settings if one is found.
3. Installs dependencies and Semgrep (customizable version).
4. Runs Semgrep with the provided configuration and scan mode.
5. Summarizes findings and posts results to the Actions UI, Job Summary, and if applicable, PR comments and Reviewdog review.
6. Fails the workflow if findings meet or exceed the configured severity threshold.

## Outputs

The workflow provides the following outputs for use in downstream jobs or for reporting:

- `total_findings`: Total number of findings
- `error_count`: Number of ERROR findings
- `warning_count`: Number of WARNING findings
- `info_count`: Number of INFO findings
- `scan_status`: `success` or `failure` based on findings and fail threshold
- `scan_md_summary`: Markdown summary of findings
- `config_md_summary`: Markdown summary of the config settings used
- `normalized_baseline`: The resolved baseline ref used for diff/baseline scans

Findings are also posted as PR comments and Reviewdog annotations (if enabled), and a summary is written to the GitHub Actions job summary.

## Contribution

- Update the workflow file and related javascript file
- Update the README and CHANGELOG
- Create a PR and set a version label following [versioning instructions](../../../VERSIONING.md)

## References

- [Semgrep Documentation](https://semgrep.dev/docs/)
Loading
Loading