Skip to content
Open
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
146 changes: 146 additions & 0 deletions docs/scanner-imports/opengrep.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
# Import OpenGrep findings

Set `CODEX_SECURITY_ENABLE_EXTERNAL_IMPORTS=1` in the command environment to enable external imports.

Import native OpenGrep JSON, including gzip-compressed reports, into the local
workbench or Cloud. This reader accepts scanner output, not SARIF, normalized
JSONL, or an API summary. It preserves findings as unassessed scanner evidence.

From the source repository root, use a fresh report directory outside the
checkout. The following commands use the shell's temporary directory:

```sh
report_dir=$(mktemp -d) &&
opengrep scan --config /path/to/rules.yaml --json --output "$report_dir/opengrep.json" . &&
codex-security publish findings "$report_dir/opengrep.json" --to local \
--provider opengrep --source-key opengrep/ORGANIZATION/PROJECT/BRANCH \
--source-repository-url https://github.com/example/project \
--repository . --dry-run --format json
```

Native JSON includes dataflow traces when the scanner produces them.
`--dataflow-traces` controls text and SARIF rendering; it is not required for JSON.
See OpenGrep's [output options](https://github.com/opengrep/opengrep/blob/main/src/osemgrep/cli_scan/Scan_CLI.ml)
and [JSON formatter](https://github.com/opengrep/opengrep/blob/main/src/osemgrep/reporting/Cli_json_output.ml).

Review the source repository, findings, exclusions, diagnostics, and destination.
Repeat the import without `--dry-run` to confirm interactively, or add `--yes`
after reviewing the preview. Local imports require no Cloud login or model call.
Read the stored evidence with:

```sh
codex-security findings imported . --format json
```

For Cloud, use the same report and source namespace with a Cloud destination:

```sh
codex-security publish findings "$report_dir/opengrep.json" --to cloud \
--provider opengrep --source-key opengrep/ORGANIZATION/PROJECT/BRANCH \
--source-repository-url https://github.com/example/project \
--repository https://github.com/example/project --dry-run --format json
```

`--source-repository-url` is required and declares where the report came from.
The importer checks it against configured local Git remotes or the selected
Cloud repository. It does not infer the scanner's revision from the current
checkout. Cloud preview requires the existing ChatGPT login and an authorized
repository and environment; review the preview before approving the upload.

## Provider identity and evidence

`--provider opengrep` selects the OpenGrep reader. Local storage and Cloud use the
existing `semgrep` source-provider contract for compatibility, while typed
`scanner_origin` identifies **OpenGrep**. The preview shows this mapping. This
does not add a native OpenGrep provider to the Cloud service. Cloud publication
requires that deployment to support the existing Semgrep import contract;
successful local imports do not verify hosted availability.

Keep an OpenGrep-specific source key, such as
`opengrep/ORGANIZATION/PROJECT/BRANCH`, stable across runs. Occurrence IDs use the
rule, path, and source range. The importer normalizes redundant slash-separated
components in repository-relative paths and preserves literal backslashes in
filenames. An unmapped path keeps its original spelling in the occurrence ID.
Keep Windows path spellings consistent across runs because changing them can
create a second record. Multiple dataflow traces for the same occurrence are
grouped into one finding. For Cloud imports, check `excluded` for traces that
could not fit. If independently valid traces exceed the 256 KiB limit together,
the whole occurrence is excluded. Moving a match creates a new record and leaves
its earlier record intact. The raw scanner
fingerprints remain evidence and do not override this location-based identity.
Omitting a finding from a later report does not close or delete it.

The adapter retains rule metadata, source ranges, snippets, traces, ignored state,
and original severity. Normalized severity is `unknown`: OpenGrep rule levels
such as `ERROR` or `WARNING` are not a verified vulnerability severity. Ignored
matches remain source evidence, separate from a Codex assessment. Importing a
report does not assess findings, apply fixes, or create a completed Codex scan.

## Diagnostics and coverage

OpenGrep can return matches alongside parse failures, partial parsing, timeouts,
and other diagnostics. Warning diagnostics can accompany exit code 0 with the
default `--no-strict`; `--strict` changes warning handling, while `--error`
separately makes findings produce exit code 1. Inspect the report's diagnostics
and the scanner's exit status. Neither zero findings nor a successful exit
establishes complete coverage. See OpenGrep's
[error classification](https://github.com/opengrep/opengrep/blob/main/src/core/Core_error.ml).

The JSON preview and result retain the native report envelope, without `results`,
in `report`, including diagnostics and path metadata for an empty local report.
Individual stored findings retain the original observations in
`source_data.results` and a `source_data.scan_error_count`. Their compact
`source_data.report` retains only the scanner version, keeping scan-wide metadata
such as diagnostics and matching explanations outside each finding's evidence
budget. Full report metadata is
returned by the SDK and CLI; it is not saved as a separate durable scan record.
Keep the original JSON if you need the complete run metadata later.
Add OpenGrep's `--verbose` when collecting
skipped-target details; its [output handling](https://github.com/opengrep/opengrep/blob/main/src/osemgrep/reporting/Output.ml)
can omit those details otherwise.

Publication status describes import processing and acknowledged records, not
scanner coverage. A `complete` publication does not resolve scan diagnostics or
establish a clean security result. Cloud publication requires at least one
supported finding; an empty report can still be previewed locally with its
metadata. Review exclusions before approving either destination.

## Assess an imported finding locally

Copy an imported record's `id` from `findings imported --format json`. Use an
authorized checkout corresponding to the report's revision, then pass its
evidence to the existing SDK validator:

```ts
import {
CodexSecurity,
listLocalExternalFindings,
} from "@openai/codex-security";

const repositoryPath = "/path/to/repository";
const [record] = await listLocalExternalFindings({
repository: repositoryPath,
id: "IMPORTED_FINDING_ID",
});
if (!record) throw new Error("Imported finding not found.");

const security = new CodexSecurity();
try {
const assessment = await security.validate({
repositoryPath,
finding: record.evidence,
});
console.log(record.id, assessment.disposition);
console.log(assessment.report);
} finally {
await security.close();
}
```

Validation sends the finding evidence, including snippets and traces, to the
configured Codex model provider. A hosted provider requires network connectivity.
The validator reads the checkout in a read-only tool sandbox with network access
disabled. It returns an assessment and leaves the stored import `not_assessed`. See
[standalone validation](../../sdk/typescript/README.md#validate-an-existing-finding)
for dispositions and report handling. Hosts that already provide model execution
can use [validateRecords](../../sdk/typescript/docs/validate-records.md) instead.
6 changes: 5 additions & 1 deletion plugins/codex-security/skills/publish-findings/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
name: publish-findings
description: Disabled by default; requires user opt-in with CODEX_SECURITY_ENABLE_EXTERNAL_IMPORTS=1. Import selected Snyk Open Source findings, Semgrep Code CLI/CI reports, Endor Labs findings, GitHub code-scanning alerts or GHSA advisories, or Wiz package vulnerabilities, SAST, repository secrets, and IaC findings locally or to Codex Security Cloud after previewing the destination and evidence. Prefers native JSON; also supports Snyk plugin SCA bundles, Snyk Open Source and Semgrep Code SARIF, endorctl SARIF, saved GitHub JSON/JSONL, Wiz normalized JSONL and repository package-vulnerability CSV, and gzip; does not import workload secrets or cloud configuration, run a scan, assess findings, or synchronize triage decisions.
description: Requires explicit opt-in with CODEX_SECURITY_ENABLE_EXTERNAL_IMPORTS=1. Preview and import supported findings from Snyk Open Source, Semgrep Code, OpenGrep, Endor Labs, GitHub, or Wiz into the local workbench or Codex Security Cloud. Use each provider's documented native JSON, SARIF, plugin bundle, JSONL or CSV format, including gzip-compressed reports.
---

# Publish external findings
Expand Down Expand Up @@ -80,6 +80,10 @@ Import the native report with `--provider semgrep`, a stable organization/projec

Keep supplied fingerprints. Reimporting the same fingerprint after code moves updates the existing source record with the new range. If the fingerprint is absent or `requires login`, the fallback uses rule, literal path and range: movement creates a second retained record, and the earlier record remains stored. Do not infer a merge or deletion. Read the persisted evidence with `codex-security findings imported /path/to/project --format json` before assessment. Source rule, CWE, snippets, traces and status are vendor evidence, not Codex assessments. Do not infer a report revision from the current checkout. Resolve scan errors and review all exclusions before uploading; do not remove error metadata to force acceptance.

## OpenGrep

Import native OpenGrep JSON with `--provider opengrep`, `--source-repository-url`, and a stable OpenGrep-specific `--source-key`. Preview the destination and scan diagnostics before importing. Local and Cloud imports use the Semgrep provider and retain OpenGrep as the scanner origin.

## GitHub alerts and advisories

Acquire code-scanning findings with `codex-security import github OWNER/REPO --format json` and save its complete JSON output for local import or Cloud publication. This existing collector completes pagination, fetches alert details, and retains the selected ref's instance. In Codex, use the official [GitHub Codex plugin](https://github.com/openai/plugins/tree/main/plugins/github) for discovery and selecting alerts, then pass that selection to the collector. Its GitHub MCP server paginates each list call separately. Do not ask the user to download JSON from a website or reconstruct an import envelope from MCP summaries; raw MCP/API responses are not accepted by `--provider github`.
Expand Down
6 changes: 6 additions & 0 deletions sdk/typescript/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -667,6 +667,12 @@ options where supported, and changing formats can change record identities or
replace richer evidence with less detail. See the
[import guide](docs/cli.md#import-vendor-findings-locally) for format selection.

For OpenGrep, use `--provider opengrep` with native JSON or gzip and an explicit
`--source-repository-url`. Local and Cloud imports retain unassessed OpenGrep
evidence through the existing Semgrep source-provider contract. See the
[OpenGrep guide](https://github.com/openai/codex-security/blob/main/docs/scanner-imports/opengrep.md) for preview commands,
coverage diagnostics, stable source identities, and local SDK assessment.

For Wiz, prefer supported native JSON acquired through an authorized MCP or API
connection. The [CSV compatibility reader](docs/cli.md#import-wiz-findings) covers
repository package vulnerabilities (SCA) only; it does not add SAST, CSPM or
Expand Down
10 changes: 10 additions & 0 deletions sdk/typescript/docs/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -1303,6 +1303,7 @@ repository path instead of a Cloud repository ID or URL. Supported inputs includ
Wiz findings, [Snyk Open Source JSON and SARIF](#import-snyk-open-source-findings),
[Endor Labs Finding JSON and SARIF](#import-endor-labs-findings),
[Semgrep Code JSON and SARIF](https://github.com/openai/codex-security/blob/main/docs/scanner-imports/semgrep.md),
[OpenGrep native JSON](https://github.com/openai/codex-security/blob/main/docs/scanner-imports/opengrep.md),
and [saved GitHub alerts and GHSA advisories](#import-github-findings-locally-or-to-cloud):

```bash
Expand Down Expand Up @@ -1338,6 +1339,15 @@ remain stored; omission does not resolve or delete a finding. Excluded records
are reported, and an import with exclusions exits with status 1. The same
supported vendor formats and evidence requirements apply locally and in Cloud.

For OpenGrep, use `--provider opengrep` and supply `--source-repository-url`.
The reader supports native JSON and gzip for both destinations. It uses the
existing `semgrep` source-provider contract while retaining `OpenGrep` as the
scanner origin; keep a stable OpenGrep-specific source key. Review report
diagnostics as well as findings: import completion does not establish scan
coverage. The [OpenGrep guide](https://github.com/openai/codex-security/blob/main/docs/scanner-imports/opengrep.md)
covers evidence identity, empty reports, and assessing an imported finding with
the existing SDK validator.

`scan import --json` and `scan import --csv` remain separate commands for importing
Codex Security's findings schema as a saved scan; they do not accept vendor
exports.
Expand Down
5 changes: 4 additions & 1 deletion sdk/typescript/scripts/fixtures/package-consumer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -306,7 +306,10 @@ export async function externalPublication(
const fromFile = await prepareExternalPublication(file, options);
fromFile.preview.requests[0]?.source.provider satisfies
"wiz" | "endor" | "snyk" | "github" | "semgrep" | undefined;
const prepared = await prepareNormalizedExternalPublication(input, options);
const prepared = await prepareNormalizedExternalPublication(input, {
...options,
provider: fromFile.preview.source.provider,
});
return prepared.publish();
}

Expand Down
2 changes: 2 additions & 0 deletions sdk/typescript/scripts/package-dist-files.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ const distModules = [
"scanner-import",
"snyk-findings",
"semgrep-findings",
"native-json-findings",
"opengrep-findings",
"external-findings-publish",
"external-import-contract",
"external-import-models",
Expand Down
2 changes: 1 addition & 1 deletion sdk/typescript/scripts/smoke-package.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -396,7 +396,7 @@ try {
"--input-type=module",
"--eval",
`const sdk = await import(${JSON.stringify(packageManifest.name)});
for (const name of ["CodexSecurity", "publishScan", "publishScanToCustom", "checkScanPublication", "deduplicateScan", "deduplicateRecords", "classifySeverity", "classifyScanSeverity", "classifyScanDirectorySeverity", "matchScanFindings", "securityPolicyDiff", "loadProjectConfig", "resolveProjectConfig", "prepareExternalPublication", "prepareNormalizedExternalPublication"]) {
for (const name of ["CodexSecurity", "publishScan", "publishScanToCustom", "checkScanPublication", "deduplicateScan", "deduplicateRecords", "classifySeverity", "classifyScanSeverity", "classifyScanDirectorySeverity", "matchScanFindings", "securityPolicyDiff", "loadProjectConfig", "resolveProjectConfig", "prepareExternalPublication", "prepareNormalizedExternalPublication", "normalizeOpenGrepFindings", "readOpenGrepFindings"]) {
if (typeof sdk[name] !== "function") {
throw new Error("The installed package does not export " + name + ".");
}
Expand Down
Loading
Loading