Skip to content
Closed
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
2 changes: 1 addition & 1 deletion .github/actions/TEMPLATE/README_TEMPLATE.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ Basic usage example:
```yaml
- name: Name for step
id: <step-id>
uses: ./.github/actions/<action-name>
uses: OpenSesame/core-github-actions/.github/actions/<action-name>@actions/<action-name>/vX.Y.Z
with:
<input-name>: <value>
```
Expand Down
2 changes: 1 addition & 1 deletion .github/actions/pr-open-check/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ permissions:
```yaml
- name: Check for open PR
id: pr_check
uses: ./.github/actions/pr-check-open
uses: OpenSesame/core-github-actions/.github/actions/pr-open-check@actions/pr-open-check/2.0.0
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
commit-identifier: ${{ github.sha }}
Expand Down
4 changes: 4 additions & 0 deletions .github/actions/run-semgrep/.npmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
ignore-scripts=true
save-exact=true
audit=true
fund=false
14 changes: 14 additions & 0 deletions .github/actions/run-semgrep/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Changelog for run-semgrep Composite Action

All notable changes to the run-semgrep composite GitHub Action will be documented in this file.

## 1.0.0 - Initial Release

### Added

- Initial release of the reusable composite action for running Semgrep scans
- Inputs are passed via environment variables
- Support running on both push and pull_request events
- Standardizes baseline resolution for diff scans
- Outputs include scan summary, config summary, scan status, and finding counts
- Designed to integrate with reviewdog for annotations
113 changes: 113 additions & 0 deletions .github/actions/run-semgrep/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
# Run Semgrep Action

## 🧭 Summary

Runs a Semgrep scan normalizing the baseline for diff scans depending on push vs PR context. Outputs scan results and summaries for downstream steps.

## Scope/Limitations

- Supports both push and pull request events.
- Requires Semgrep to be installed and available in the runner environment.
- Expects environment variables for configuration (see below).

## 🔒 Permissions

The following GHA permissions are required to use this step:

```yaml
permissions:
contents: read
```

## Dependencies

- `semgrep` — must be installed in the runner environment.
- `node-fetch` — required Node.js dependency (see package.json).
- `reviewdog` — for annotation output (optional, for downstream steps).

## ⚙️ Inputs

This action is environment-driven. The following environment variables are required:

| Name | Required | Description |
| ------------------- | -------- | ------------------------------------------------------------------------------------------- |
| `HAS_PR` | ✅ | Whether the current context has an associated PR (true/false) |
| `PR_NUMBER` | ❌ | PR number if applicable |
| `PR_URL` | ❌ | PR URL if applicable |
| `INPUT_BASELINE` | ✅ | Baseline ref to use for diffing (e.g., origin/main) |
| `GITHUB_EVENT_NAME` | ✅ | GitHub provided environment variable for event name (e.g., push, pull_request) |
| `GITHUB_REF_NAME` | ✅ | GitHub provided environment variable for the branch or tag name that triggered the workflow |
| `GITHUB_BASE_REF` | ❌ | GitHub provided environment variable for the base ref of a PR (if applicable) |
| `GITHUB_REPOSITORY` | ✅ | GitHub provided environment variable for the repository (e.g., owner/repo) |
| `GITHUB_TOKEN` | ✅ | GitHub token for API access |
| `SCAN_MODE` | ✅ | 'diff' or 'full' scan mode |
| `SEMGREP_CONFIG` | ✅ | Semgrep ruleset(s) to use |
| `SEMGREP_TARGETS` | ✅ | Targets to scan (default: current directory) |
| `FAIL_LEVEL` | ✅ | Severity level to fail on (e.g., ERROR, WARNING) |
| `EXTRA_ARGS` | ❌ | Additional arguments to pass to Semgrep |

## 📤 Outputs

Along with writing files for reviewdog annotations and inputs, this action provides the following outputs:

| Name | Description |
| -------------------- | --------------------------------------------------- |
| `normalizedBaseline` | The resolved baseline ref |
| `scanSummary` | Summary of findings in markdown format |
| `configSummary` | Summary of scan config in markdown format |
| `scanStatus` | 'success' or 'failure' based on findings/fail level |
| `totalFindings` | Total number of findings |
| `numErrors` | Number of ERROR severity findings |
| `numWarnings` | Number of WARNING severity findings |
| `numInfo` | Number of INFO severity findings |

## 🚀 Usage

Basic usage example:

```yaml
- name: Run Semgrep
id: semgrep
uses: OpenSesame/core-github-actions/.github/actions/run-semgrep@actions/run-semgrep/1.0.0
env:
HAS_PR: ${{ env.HAS_PR }}
INPUT_BASELINE: ${{ env.INPUT_BASELINE }}
GITHUB_EVENT_NAME: ${{ github.event_name }}
GITHUB_REF_NAME: ${{ github.ref_name }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GITHUB_REPOSITORY: ${{ github.repository }}
SEMGREP_CONFIG: 'p/default'
SEMGREP_TARGETS: '.'
SCAN_MODE: 'full'
FAIL_LEVEL: 'error'
EXTRA_ARGS: ''
```

Example outputs:

```yaml
steps.semgrep.outputs.scanStatus
steps.semgrep.outputs.totalFindings
```

Example usage of outputs in later steps:

```yaml
if: steps.semgrep.outputs.scanStatus == 'failure'
run: echo "Semgrep scan failed at or above threshold."
```

## 🧠 Notes

- This action writes a file for reviewdog annotations (`reviewdog_input.txt`).
- Unit tests for the script are included in `run-semgrep.unit.test.js` (not used by the action, but kept for maintainability).

## Versioning

This action uses namespaced tags for versioning and is tracked in the CHANGELOG.

```text
actions/run-semgrep/vX.Y.Z
```

See the repository's versioning documentation for details on how tags are validated and created.
13 changes: 13 additions & 0 deletions .github/actions/run-semgrep/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
name: 'Run Semgrep'
description: 'Run a Semgrep scan and output results for reviewdog and future steps'
runs:
using: composite
steps:
- name: Install action dependencies
shell: bash
working-directory: ${{ github.action_path }}
run: npm ci

- name: Run Semgrep Scan
shell: bash
run: node ${{ github.action_path }}/run-semgrep.js
57 changes: 57 additions & 0 deletions .github/actions/run-semgrep/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 10 additions & 0 deletions .github/actions/run-semgrep/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"name": "@opensesame/run-semgrep-action",
"version": "1.0.0",
"main": "run-semgrep.js",
"private": true,
"description": "Composite action to run Semgrep scan for GitHub Actions.",
"dependencies": {
"node-fetch": "^2.6.7"
}
}
Original file line number Diff line number Diff line change
@@ -1,41 +1,7 @@
/*
* Run Semgrep scan
* Normalizes baseline for diff scans depending on push vs PR context
*
* Expects the following environment variables:
* HAS_PR - whether the current context has an associated PR (true/false)
* PR_NUMBER - PR number if applicable
* PR_URL - PR URL if applicable
* INPUT_BASELINE - baseline ref to use for diffing (e.g., origin/main)
* GITHUB_EVENT_NAME - GitHub provided environment variable for event name (e.g., push, pull_request)
* GITHUB_REF - Github provided environment variable for the git ref that triggered the workflow
* GITHUB_REF_NAME - GitHub provided environment variable for the branch or tag name that triggered the workflow
* GITHUB_BASE_REF - GitHub provided environment variable for the base ref of a PR (if applicable)
* GITHUB_REPOSITORY - GitHub provided environment variable for the repository (e.g., owner/repo)
* GITHUB_TOKEN - GitHub token for API access
* SCAN_MODE - 'diff' or 'full' scan mode
* SEMGREP_CONFIG - Semgrep ruleset(s) to use
* SEMGREP_TARGETS - Targets to scan (default: current directory)
* FAIL_LEVEL - Severity level to fail on (e.g., ERROR, WARNING)
* EXTRA_ARGS - Additional arguments to pass to Semgrep
*
* Outputs:
* - Writes file for reviewdog annotations, reviewdog_input.txt
* - Sets GitHub Action outputs
* - normalizedBaseline - the resolved baseline ref
* - totalFindings - total number of findings
* - numErrors - number of ERROR severity findings
* - numWarnings - number of WARNING severity findings
* - numInfo - number of INFO severity findings
* - scanSummary - summary of findings in md format
* - configSummary - summary of scan config in md format
* - scanStatus - 'success' or 'failure' based on findings and fail level
*/

const { spawnSync } = require('child_process');
const fs = require('fs');
const fetch = require('node-fetch');
const { validateEnvVar } = require('../utils/env-helpers');
const { validateEnvVar } = require('./env-helpers');

const SEMGREP_RESULTS_FILE_NAME = 'semgrep_results.json';
const REVIEWDOG_INPUT_FILE_NAME = 'reviewdog_input.txt';
Expand Down
33 changes: 33 additions & 0 deletions .github/actions/run-semgrep/run-semgrep.unit.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
const { validateEnvVar } = require('./env-helpers');
Copy link

Copilot AI Jan 30, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test file imports validateEnvVar from ./env-helpers, but based on the diff in run-semgrep.js (line 4), this module should exist. However, the env-helpers.js file is not present in the provided diffs. If this file was not moved or created as part of this PR, the tests and the main script will fail at runtime.

Suggested change
const { validateEnvVar } = require('./env-helpers');
function validateEnvVar(name) {
if (!process.env[name]) {
console.error(`::error::Environment variable ${name} is required`);
process.exit(1);
}
}

Copilot uses AI. Check for mistakes.

describe('validateEnvVar', () => {
Comment on lines +1 to +3
Copy link

Copilot AI Jan 30, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new test file only tests the validateEnvVar helper function. The original test file (scripts/gha-lib/run-semgrep.unit.test.js) contained comprehensive tests for multiple functions including getPrBaseBranch, normalizeBaseline, constructSemgrepCommand, stageResultsForReviewdog, getSemgrepMetrics, writeFindingsMarkdown, writeConfigMarkdown, and evaluateScanStatus. These tests should be preserved and updated to work with the new file location.

Copilot uses AI. Check for mistakes.
const ORIGINAL_EXIT = process.exit;
const ORIGINAL_CONSOLE_ERROR = console.error;

beforeEach(() => {
process.exit = jest.fn();
console.error = jest.fn();
});

afterEach(() => {
process.exit = ORIGINAL_EXIT;
console.error = ORIGINAL_CONSOLE_ERROR;
});

it('does not exit when env var is set', () => {
process.env.TEST_VAR = 'value';
validateEnvVar('TEST_VAR');
expect(process.exit).not.toHaveBeenCalled();
expect(console.error).not.toHaveBeenCalled();
delete process.env.TEST_VAR;
});

it('exits with error when env var is not set', () => {
delete process.env.TEST_VAR;
validateEnvVar('TEST_VAR');
expect(console.error).toHaveBeenCalledWith(
'::error::Environment variable TEST_VAR is required'
);
expect(process.exit).toHaveBeenCalledWith(1);
});
});
2 changes: 1 addition & 1 deletion .github/actions/upsert-pr-comment/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ Basic usage example:

```yaml
- name: Upsert PR summary comment
uses: ./.github/actions/upsert-pr-comment
uses: OpenSesame/core-github-actions/.github/actions/upsert-pr-comment@actions/upsert-pr-comment/1.0.0
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
pr-number: ${{ github.event.pull_request.number }}
Expand Down
6 changes: 6 additions & 0 deletions .github/workflows/CHANGELOGS/run_semgrep_scan.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@

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

## 1.0.1

### Changed

- Updated workflow to support cross-repository usage by checking out the core-github-actions repository into a subdirectory and referencing all internal actions and scripts from that subdirectory. This ensures that required actions and scripts are always available, regardless of which repository invokes the workflow.
Copy link

Copilot AI Jan 30, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The changelog description mentions 'checking out the core-github-actions repository into a subdirectory', but the actual implementation uses fully-qualified action references (e.g., OpenSesame/core-github-actions/.github/actions/pr-open-check@actions/pr-open-check/2.0.0) without checking out into a subdirectory. The description should be updated to accurately reflect that the workflow now uses repository-qualified action paths instead of checking out into subdirectories.

Suggested change
- Updated workflow to support cross-repository usage by checking out the core-github-actions repository into a subdirectory and referencing all internal actions and scripts from that subdirectory. This ensures that required actions and scripts are always available, regardless of which repository invokes the workflow.
- Updated workflow to support cross-repository usage by referencing internal actions and scripts via fully-qualified paths to the `OpenSesame/core-github-actions` repository (for example, `OpenSesame/core-github-actions/.github/actions/...@...`). This ensures that required actions and scripts are always available, regardless of which repository invokes the workflow.

Copilot uses AI. Check for mistakes.

## 1.0.0

### Added
Expand Down
8 changes: 4 additions & 4 deletions .github/workflows/run_semgrep_scan.yml
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ jobs:
normalized_baseline: ${{ steps.semgrep.outputs.normalizedBaseline }}

steps:
- name: Checkout code
- name: Checkout Calling Repo
uses: actions/checkout@v4
with:
ref: ${{ inputs.commit_identifier }}
Expand All @@ -101,7 +101,7 @@ jobs:

- name: Check for open PR (by commit)
id: pr_check
uses: ./.github/actions/pr-open-check
uses: OpenSesame/core-github-actions/.github/actions/pr-open-check@actions/pr-open-check/2.0.0
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
commit-identifier: ${{ inputs.commit_identifier }}
Expand All @@ -126,6 +126,7 @@ jobs:

- name: Run Semgrep
id: semgrep
uses: OpenSesame/core-github-actions/.github/actions/run-semgrep@actions/run-semgrep/1.0.0
env:
INPUT_BASELINE: ${{ inputs.baseline_ref }}
HAS_PR: ${{ steps.pr_check.outputs.pr_exists }}
Expand All @@ -135,7 +136,6 @@ jobs:
SEMGREP_TARGETS: ${{ inputs.semgrep_targets }}
FAIL_LEVEL: ${{ inputs.fail_severity }}
EXTRA_ARGS: ${{ inputs.extra_args }}
run: node scripts/gha-lib/run-semgrep.js

- name: Upload Artifact
if: ${{ steps.semgrep.outputs.totalFindings > 0 }}
Expand Down Expand Up @@ -265,7 +265,7 @@ jobs:

- name: Upsert PR comment
if: ${{ github.event_name == 'pull_request' || steps.pr_check.outputs.pr_exists == 'true' }}
uses: ./.github/actions/upsert-pr-comment
uses: OpenSesame/core-github-actions/.github/actions/upsert-pr-comment@actions/upsert-pr-comment/1.0.0
with:
pr-number: ${{ steps.pr_check.outputs.pr_number }}
github-token: ${{ secrets.GITHUB_TOKEN }}
Expand Down
2 changes: 1 addition & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,5 +43,5 @@

// Optional: Spell checker
"cSpell.enabled": true,
"cSpell.words": ["opensesame", "reviewdog", "semgrep", "upserting"]
"cSpell.words": ["nosemgrep", "opensesame", "reviewdog", "semgrep", "upserting"]
}
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@
"audit": "npm audit --audit-level=high --omit=dev",
"lint:check": "eslint *.js --ext .js,.json",
"lint:fix": "eslint *.js --ext .js,.json --fix",
"format:check": "prettier --check './*.js' './*.mjs' './*.json' './*.md' 'scripts/**/*.js' '.github/actions/**/*.*'",
"format:fix": "prettier --write './*.js' './*.mjs' './*.json' './*.md' 'scripts/**/*.js' '.github/actions/**/*.*'",
"format:check": "prettier --check './*.js' './*.mjs' './*.json' './*.md' 'scripts/**/*.js' '.github/actions/**/*.yml' '.github/actions/**/*.md' '.github/actions/**/*.js'",
"format:fix": "prettier --write './*.js' './*.mjs' './*.json' './*.md' 'scripts/**/*.js' '.github/actions/**/*.yml' '.github/actions/**/*.md' '.github/actions/**/*.js'",
"scan": "semgrep --config=p/ci --config=p/security-audit --config=p/javascript ./*.js ./*.mjs ./*.json scripts/ .github/actions/",
"check": "npm run audit && npm run test && npm run lint:check && npm run format:check && npm run scan"
},
Expand Down
Loading
Loading