From cf0893d48ac2daa7b68170f2e1f0314d3643e5bc Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Sat, 7 Mar 2026 18:49:37 +0000 Subject: [PATCH] feat: send commit SHA with scan dispatch - Add getCommitShaEnvVar() to auto-detect from GITHUB_SHA, CI_COMMIT_SHA, BITBUCKET_COMMIT, or PENSAR_COMMIT_SHA - Add commitSha to DispatchScanParams and RunScanParams interfaces - Include commitSha in /ci/dispatch POST body - Auto-resolve commitSha in runScan() from env when not explicitly provided - Add -c/--commit CLI option to pentest command - Read CI_COMMIT_SHA in GitLab integration and forward to runScan() - Document --commit option and new env vars in README Co-authored-by: Josh Kotrous --- README.md | 28 ++++++++++++++++------------ src/bin/index.ts | 5 +++++ src/lib/ci.ts | 15 +++++++++++++++ src/lib/gitlab.ts | 7 ++++++- 4 files changed, 42 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 8af86f5..9b02aa9 100644 --- a/README.md +++ b/README.md @@ -20,21 +20,25 @@ pensar status ### Options -| Option | Description | -| ------------------- | ----------------------------------------------------- | -| `-p, --project` | Project ID (or set `PENSAR_PROJECT_ID`) | -| `-b, --branch` | Branch to pentest | -| `-l, --level` | Pentest level: `priority` or `full` | -| `-e, --environment` | Target environment: `dev`, `staging`, or `production` | -| `--no-wait` | Don't wait for pentest to complete | +| Option | Description | +| ------------------- | --------------------------------------------------------------------------- | +| `-p, --project` | Project ID (or set `PENSAR_PROJECT_ID`) | +| `-b, --branch` | Branch to pentest | +| `-l, --level` | Pentest level: `priority` or `full` | +| `-e, --environment` | Target environment: `dev`, `staging`, or `production` | +| `-c, --commit` | Commit SHA (auto-detected from CI env vars, or set `PENSAR_COMMIT_SHA`) | +| `-s, --severity` | Minimum severity threshold to error on (or set `PENSAR_ERROR_SEVERITY_THRESHOLD`) | +| `--no-wait` | Don't wait for pentest to complete | ## Environment Variables -| Variable | Description | -| -------------------- | ------------------------------------------------------ | -| `PENSAR_API_KEY` | Your Pensar API key | -| `PENSAR_PROJECT_ID` | Your Pensar project ID | -| `PENSAR_ENVIRONMENT` | Target environment (`dev`, `staging`, or `production`) | +| Variable | Description | +| -------------------------------- | ------------------------------------------------------ | +| `PENSAR_API_KEY` | Your Pensar API key | +| `PENSAR_PROJECT_ID` | Your Pensar project ID | +| `PENSAR_ENVIRONMENT` | Target environment (`dev`, `staging`, or `production`) | +| `PENSAR_COMMIT_SHA` | Commit SHA override (auto-detected from `GITHUB_SHA`, `CI_COMMIT_SHA`, `BITBUCKET_COMMIT`) | +| `PENSAR_ERROR_SEVERITY_THRESHOLD`| Minimum severity to trigger a non-zero exit (`critical`, `high`, `medium`, `low`, `info`) | ## CI/CD Integration diff --git a/src/bin/index.ts b/src/bin/index.ts index 53c6f9a..bea8ed8 100755 --- a/src/bin/index.ts +++ b/src/bin/index.ts @@ -20,6 +20,10 @@ program .option("-l, --level ", "Pentest level: priority or full", "full") .option("--no-wait", "Don't wait for pentest to complete") .option("-e, --environment ", "Environment: dev, staging, or production") + .option( + "-c, --commit ", + "Commit SHA (auto-detected from GITHUB_SHA, CI_COMMIT_SHA, BITBUCKET_COMMIT, or PENSAR_COMMIT_SHA)" + ) .option( "-s, --severity ", "Minimum severity threshold to trigger error (critical, high, medium, low, info). Or set PENSAR_ERROR_SEVERITY_THRESHOLD env var.", @@ -48,6 +52,7 @@ program wait: options.wait, environment: options.environment as Environment | undefined, errorSeverityThreshold: severityThreshold, + commitSha: options.commit, }); if (result.status === "completed") { diff --git a/src/lib/ci.ts b/src/lib/ci.ts index 1fa2ff4..cbaa295 100644 --- a/src/lib/ci.ts +++ b/src/lib/ci.ts @@ -33,6 +33,16 @@ export function getEnvironmentEnvVar(): Environment { return (process.env.PENSAR_ENVIRONMENT as Environment) ?? null; } +export function getCommitShaEnvVar(): string | undefined { + return ( + process.env.GITHUB_SHA ?? + process.env.CI_COMMIT_SHA ?? + process.env.BITBUCKET_COMMIT ?? + process.env.PENSAR_COMMIT_SHA ?? + undefined + ); +} + export function getErrorSeverityThresholdEnvVar(): SeverityLevel { const value = process.env.PENSAR_ERROR_SEVERITY_THRESHOLD; if (!value) return 'critical'; // Default to critical @@ -123,6 +133,7 @@ export interface DispatchScanParams { branch?: string; scanLevel?: "priority" | "full"; environment?: Environment; + commitSha?: string; } export async function dispatchScan( @@ -148,6 +159,7 @@ export async function dispatchScan( : { repoId: params.repoId }), branch: params.branch, scanLevel: params.scanLevel, + commitSha: params.commitSha, }), }); @@ -249,6 +261,7 @@ export interface RunScanParams { wait?: boolean; pollIntervalMs?: number; errorSeverityThreshold?: SeverityLevel; + commitSha?: string; } export async function runScan(params: RunScanParams = {}): Promise { @@ -257,6 +270,7 @@ export async function runScan(params: RunScanParams = {}): Promise { const repoId = params.repoId ?? getRepoIdEnvVar(); const environment = params.environment ?? getEnvironmentEnvVar(); const wait = params.wait ?? true; + const commitSha = params.commitSha ?? getCommitShaEnvVar(); if (!projectId && !repoId) { throw new Error( @@ -274,6 +288,7 @@ export async function runScan(params: RunScanParams = {}): Promise { branch: params.branch, scanLevel: params.scanLevel, environment, + commitSha, }); console.log(`Pentest ${label} dispatched (ID: ${scanId})`); diff --git a/src/lib/gitlab.ts b/src/lib/gitlab.ts index 8bb3731..46248d5 100644 --- a/src/lib/gitlab.ts +++ b/src/lib/gitlab.ts @@ -13,6 +13,9 @@ function getGitLabEnvVars() { // GitLab CI provides the branch name in CI_COMMIT_REF_NAME const branch = process.env.CI_COMMIT_REF_NAME ?? undefined; + // GitLab CI provides the commit SHA in CI_COMMIT_SHA + const commitSha = process.env.CI_COMMIT_SHA ?? undefined; + // Check if we should wait for completion const wait = process.env.PENSAR_WAIT !== "false"; @@ -27,6 +30,7 @@ function getGitLabEnvVars() { environment, wait, scanLevel, + commitSha, }; } @@ -35,7 +39,7 @@ function getGitLabEnvVars() { */ export async function runScan(): Promise { try { - const { apiKey, projectId, branch, environment, wait, scanLevel } = + const { apiKey, projectId, branch, environment, wait, scanLevel, commitSha } = getGitLabEnvVars(); console.log("Starting Pensar security pentest from GitLab CI..."); @@ -47,6 +51,7 @@ export async function runScan(): Promise { scanLevel, environment, wait, + commitSha, }); if (result.status === "completed") {