From 78e8a6d971034e94a318f4d62f4f9f3c35b5aee1 Mon Sep 17 00:00:00 2001 From: Michael D'Angelo Date: Wed, 11 Nov 2026 08:11:43 +0000 Subject: [PATCH 1/2] feat(plugin): guide Codex through scanner acquisition and reviewed publication --- docs/scanner-imports/README.md | 5 + docs/scanner-imports/workbench.md | 126 ++++++++++++ evals/workflow-routing/cases.mts | 12 ++ examples/normalized-import/README.md | 41 ++++ .../skills/publish-findings/SKILL.md | 185 +++--------------- .../publish-findings/agents/openai.yaml | 4 +- .../references/checkmarx-import.md | 4 +- sdk/typescript/src/cli-help.ts | 10 + sdk/typescript/src/cli.ts | 2 +- sdk/typescript/tests-ts/cli-help.test.ts | 2 + 10 files changed, 224 insertions(+), 167 deletions(-) create mode 100644 docs/scanner-imports/workbench.md create mode 100644 examples/normalized-import/README.md diff --git a/docs/scanner-imports/README.md b/docs/scanner-imports/README.md index ca4f926b6f..98a5fbc7c3 100644 --- a/docs/scanner-imports/README.md +++ b/docs/scanner-imports/README.md @@ -3,6 +3,11 @@ Preview a scanner report with the CLI, then save the findings in the local workbench or send a supported report to Codex Security Cloud. +In Codex, ask to import a saved report or fetch selected findings with an +available CLI, API, or MCP connection. You can publish selected findings from +the local workbench in a later session using their stored IDs and versions. +[Walk through acquisition, local import, and publication in Codex](workbench.md) + ## Choose your input | Starting point | Command | diff --git a/docs/scanner-imports/workbench.md b/docs/scanner-imports/workbench.md new file mode 100644 index 0000000000..b20136149f --- /dev/null +++ b/docs/scanner-imports/workbench.md @@ -0,0 +1,126 @@ +# Import with Codex and publish from the workbench + +Open the target checkout in Codex with the Codex Security plugin enabled and its matching `@openai/codex-security` SDK available. Say what to collect, identify the repository or upstream project, and specify any ref or finding IDs that matter. Codex can choose a tool and write the findings to your local workbench from that one request. To inspect the results before saving, ask for a preview only. [Plugin setup](../agent-workflows.md#get-started) + +```mermaid +flowchart LR + Request["Import findings for this checkout"] --> Codex + Codex -->|Fresh scan| CLI["Installed scanner CLI"] + Codex -->|Existing upstream findings| Hosted["Authenticated collector, MCP tool or vendor API"] + Codex -->|Existing scan| File["Saved report or CI artifact"] + CLI --> Reader["Built-in reader or agent-written parser"] + Hosted --> Reader + File --> Reader + Reader --> Preview["Review scope, findings and exclusions"] + Preview -->|Save locally| DB[("SQLite workbench")] + DB --> IDs["Import ID and finding versions"] +``` + +## Run a scanner or import a saved result + +> Run Trivy on this checkout and import its dependency findings. + +Codex checks for the executable, runs the scanner in the selected directory, and imports its native report. These are the equivalent terminal commands from the checkout root. The last command previews the import. Remove `--dry-run` and confirm to save it. + +```sh +reports=$(mktemp -d) +trivy fs --scanners vuln --format json --output "$reports/trivy.json" . +cs publish findings "$reports/trivy.json" --provider trivy --source-key acme/payments/fs \ + --repository . --trivy-scan-root . --to local --dry-run --format json +``` + +> Run Semgrep with `./rules.yml` and import the matches. + +Codex can run `semgrep scan --config ./rules.yml --json-output "$reports/semgrep.json" .` and feed the export to the Semgrep reader. If you say “import the Semgrep report from yesterday’s CI run,” it reads that artifact. For OpenGrep, it uses the OpenGrep reader and includes scanner errors in the preview. [Semgrep formats](semgrep.md) · [OpenGrep formats](opengrep.md) + +## Collect existing upstream findings + +The following commands show what Codex can run for each built-in collector. You can also run them yourself. The GitHub, Snyk and Semgrep commands return reports on stdout. Codex can save the report privately and import it with the matching reader and a stable source key. Sonar returns a replayable capture and can write directly to the workbench. + +| What you ask Codex | Collector and what happens | +| ---------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| “Import GitHub code-scanning alert 17 from acme/payments.” | `cs import github acme/payments --github-alert 17 --format json` uses the signed-in `gh` CLI to fetch the alert and its instance. | +| “Import published repository advisories for acme/payments.” | `cs import github-advisories acme/payments --format json` uses `gh` to fetch published advisories. For a global advisory, give its exact GHSA ID and use `--github-advisory-source global --github-advisory ID`. | +| “Import monitored Snyk Code issues for project P in organization O into this checkout.” | `cs import snyk P --org O --snyk-product code --source-repository-url https://github.com/acme/payments --format json` uses `SNYK_TOKEN` to page through the Snyk API. | +| “Import the Semgrep Platform SAST backlog for acme/payments on main in deployment acme.” | `cs import semgrep acme/payments --deployment acme --ref refs/heads/main --format json` uses the Web API with `SEMGREP_APP_TOKEN` to collect the project and ref. | +| “Import Sonar issue ISSUE_A from project payments on main.” | `cs import sonar --sonar-project payments --sonar-branch main --sonar-issue ISSUE_A --dry-run --format json` uses the active `sonar` login. Codex reads the returned capture path and can save it with `cs import sonar "$capture" --yes`. [Sonar capture and Cloud replay](sonar.md#import-and-verify) | + +> Import Guardian SAST findings `101` and `103` for acme/payments on `refs/heads/main` in deployment acme. + +Codex inspects the connected tools and calls `get_semgrep_sast_findings` with the requested scope, retaining the selected rows and their exact string IDs. For Guardian Supply Chain it calls `get_semgrep_supply_chain_findings`. For the separate hosted Semgrep Platform MCP, it verifies the project’s SCM URL and uses `IssuesService_ListIssues` with the project, ref and SAST IDs. A missing connection or ID is reported. The two services have separate ID namespaces. [Guardian and hosted MCP examples](semgrep.md) + +**Check a hosted collection.** For GitHub, match the requested alert number and ref, or the advisory’s GHSA ID and publication state. For a Snyk or Semgrep backlog, use a two-page fixture and verify that both pages belong to the selected project. Replay the Sonar capture after disconnecting the vendor CLI and compare issue keys. For MCP, return two neighboring string IDs, request one, and verify the tool arguments and the single stored ID. + +## Other scanner inputs + +For a saved export, say which checkout and report to use. For an upstream read, identify the account, repository and selection. These requests use the same local preview and import. [All readers and supported report formats](README.md#choose-your-scanner) + +| What you say | What Codex calls or reads | What to check in QA | +| ------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- | +| “Import Dependabot alerts for acme/payments.” | Pages through `GET /repos/acme/payments/dependabot/alerts` via the GitHub connection or an authorized REST client. | Two alerts sharing one advisory retain distinct alert numbers. [Dependabot](github-dependabot.md) | +| “Run OpenGrep with rules.yml and import the results.” | Runs `opengrep scan` with JSON output and uses the `opengrep` reader. | A parse error alongside a match remains in `report.errors`; the match records OpenGrep as its scanner. [OpenGrep](opengrep.md) | +| “Scan package.json for Snyk dependency issues.” | Runs the signed-in `snyk test --file=package.json` with JSON file output and imports the native dependency report. | A findings exit code of 1 still produces findings with the reported dependency paths. [Snyk CLI](snyk.md#native-cli-json) | +| “Import Wiz package occurrences A and B for this repo.” | Fetches those occurrences through the connected Wiz tool or reads a detailed package vulnerability export. | Compare the stored Wiz occurrence IDs with A and B, including when both share a CVE. [Wiz](wiz.md) | +| “Get Inspector findings for this Code Security repository in us-east-1.” | Runs `aws inspector2 list-findings` for the account and exact `CODE_REPOSITORY` resource. | A fixture containing EC2 findings imports only the eligible repository findings, identified by finding ARN. [Inspector](inspector.md) | +| “Import Continuum finding F from environment E.” | Runs `aws continuum get-code-finding` for E and F after verifying the owning repository. | Import the summary, then the detail under the same source key. The same ARN gains the reported location. [Continuum](continuum.md) | +| “Import this Black Duck project version’s vulnerable components.” | Reads the complete BOM-6 collection for that version and verifies the Git repository. | The stored `source_data.projectVersionUrl` identifies the selected version. [Black Duck](blackduck.md) | +| “Import completed Checkmarx scan S for payments.” | Exports Checkmarx One JSON with `cx results show`, or reads the self-managed CxSAST scan’s XML. | The retained scan ID is S and the result’s ordered path nodes match the export. [Checkmarx](checkmarx.md) | +| “Get Endor Findings A and B from this project and namespace.” | Filters `endorctl api list --resource Finding` to the project, scan context and requested UUIDs. | The preview contains both requested finding UUIDs once. [Endor Labs](endor.md) | +| “Import Veracode STATIC policy flaws for application A.” | Reads the application’s Findings API pages for `scan_type=STATIC`, retaining pagination and application links. | A flaw on the last page retains its native `issue_id` and application URL. [Veracode](veracode.md) | +| “Import Tenable findings A and B from this Code Repository asset.” | Uses the Inventory export or existing CSVs, selects the asset and finding UUIDs, and checks the Git remote before saving locally. | Only A and B belong to the import. Cloud preview identifies Tenable as local-only. [Tenable One](tenable.md) | + +For the fresh-scan examples above, check the manifest path and installed version for Trivy and the rule ID and source line for Semgrep. For a CI artifact, edit the affected source file after the scan and check that the preview retains the line recorded in the report. + +## Import an unfamiliar format + +> Import this AcmeScanner JSON for acme/payments. Use its occurrence keys and show me any rows you skip. + +For an unfamiliar format, Codex inspects sample records and writes a parser. It emits `{ read, findings, excluded }` with a stable string `source_finding_id` and evidence for each finding. It passes the result to `prepareNormalizedLocalImport(data, { provider, sourceKey, repository, sourceRepositoryUrl })`, inspects `.preview`, then calls `.import()` for the requested write. A nonempty import records its membership, including findings already stored at the same version. Tenable and custom provider names can be used locally. [SDK import contract](../../sdk/typescript/docs/sdk.md#import-external-findings) + +## Publish in a later session + +> Publish the high-severity findings from my Trivy and Semgrep imports for acme/payments to its connected Cloud repository. + +Codex uses the import history and the requested severity to select stored finding IDs and versions. You can also give it an import ID to select the whole batch. The vendor login and original report are no longer needed. Codex calls `prepareStoredFindingsPublication(selection, { repository: cloudRepository })` and shows the destination, source groups, evidence and exclusions. A group is one provider and source key. Cloud eligibility depends on the provider, selected evidence and destination. + +```mermaid +flowchart LR + DB[("Workbench")] --> Pins["Select import or exact finding versions"] + Pins --> Preview["Preview groups and exclusions"] + Preview --> Approval["User confirms the displayed upload"] + Approval --> Group["Publish each approved source group"] + Group -->|Acknowledged| Receipt["Record receipt against local versions"] + Group -->|Connection lost| Retry["Reopen that group's selection and checkpoint"] + Retry -->|Same approved review ID| Group + Retry -->|Changed preview| Preview +``` + +You can confirm the displayed groups together. Codex retains each approved group’s `.selection` and `.reviewId` and calls `group.publish(savedReviewId)`. If a later group is interrupted, it reopens that group and resumes the existing submission. Completed groups keep their receipts. A changed selection or destination requires reviewing the new preview. + +For a terminal-only upload of an existing report, `cs publish findings FILE --to cloud` accepts the provider, source key and Cloud repository. For a Codex Security CSV or JSON export of a completed scan, `cs scan import` saves it in scan history. [CLI input choices](README.md#choose-your-input) + +## Test each part + +Run these from the repository root after installing the pinned SDK/plugin dependencies and building the SDK and bundled plugin. Use a disposable checkout and private state directory. The publication tests start a local HTTP server and use real SQLite. [Test setup and native payload](../../sdk/typescript/TESTING.md#install-dependencies) + +**Local import and selection.** Import the same evidence twice. Expect two import IDs and the same finding version. Change the evidence, then try the first import ID. The SDK should ask for a new selection. Also try a different checkout and a parser row with a missing occurrence ID or a conflicting repository. + +```sh +(cd plugins/codex-security/mcp-app && node --experimental-strip-types --test tests/test_external_findings.ts tests/test_workbench_findings.ts) +(cd sdk/typescript && bun test --timeout 60000 tests-ts/local-finding-report.test.ts tests-ts/semgrep-platform-collector.test.ts tests-ts/semgrep-guardian-findings.test.ts) +``` + +**Publish and resume.** Import Trivy and Guardian, delete the files, and preview a subset across both sources. Drop the response after the server accepts the second source. Resume using that group's original approval. Check that the first group was sent once, the second receives its receipt, and the unselected row has none. Change the destination or remote version and check that the old approval is rejected before any upload. + +For each Cloud-supported reader, preview a native file with `prepareExternalPublication`, then import the same file locally. Delete the file and preview the import ID with `prepareStoredFindingsPublication` using the same Cloud repository and source key. Compare the destination, occurrence IDs, evidence, report metadata and exclusions. Publish to a disposable destination and verify a receipt for each accepted local version. For Tenable and a custom provider, check the exclusion reason and zero uploads. + +```sh +(cd sdk/typescript && bun test --timeout 60000 tests-ts/external-findings-publish.test.ts tests-ts/stored-finding-projection.test.ts tests-ts/stored-native-private-report.test.ts tests-ts/sonar-import.test.ts) +``` + +**Codex and CLI.** Run the two-source example and inspect `cs import --help`. In a plugin-enabled session, ask for one finding ID from an MCP response containing two. Verify the actual tool call, repository and ref, then inspect import membership in a fresh process. For a fresh scanner, check the executable invocation. For an unfamiliar format, check the parser's occurrence IDs and exclusions. The routing tests exercise skill discovery. These acquisition checks exercise what the agent does after discovery. [Runnable example](../../examples/normalized-import/README.md) · [Model routing evaluation](../../evals/workflow-routing/README.md) + +```sh +node --experimental-strip-types --test evals/workflow-routing/test_*.mts +(cd sdk/typescript && bun test --timeout 60000 tests-ts/cli-help.test.ts tests-ts/cli-external-imports.test.ts tests-ts/cli-local-import.test.ts) +``` diff --git a/evals/workflow-routing/cases.mts b/evals/workflow-routing/cases.mts index 86c67cf293..6b3e6cd263 100644 --- a/evals/workflow-routing/cases.mts +++ b/evals/workflow-routing/cases.mts @@ -20,6 +20,18 @@ export const cases = [ "Triage this reported vulnerability against this repository: GET /invoices/:id exposes another user's invoice without checking ownership. Assess the claim; do not fix it.", skill: "triage-finding", }, + { + id: "acquire-scanner-evidence", + request: + "Fetch the two existing Guardian findings I selected on main and preview importing them into this checkout.", + skill: "publish-findings", + }, + { + id: "publish-stored-evidence", + request: + "Publish the high-severity scanner findings from yesterday’s local import to the connected Cloud repository.", + skill: "publish-findings", + }, { id: "dependency-alert", request: diff --git a/examples/normalized-import/README.md b/examples/normalized-import/README.md new file mode 100644 index 0000000000..a8c2f68a48 --- /dev/null +++ b/examples/normalized-import/README.md @@ -0,0 +1,41 @@ +# Import Trivy and Guardian findings offline + +Run this from the repository root with the SDK and plugin built. Set `TMPDIR` to a directory outside any Git worktree. The example uses a saved Trivy report and a recorded Guardian tool response, so it needs no vendor credentials. + +```sh +demo=$(mktemp -d "${TMPDIR:-/tmp}/stored-findings.XXXXXXXX") +git init -q "$demo/checkout" +git -C "$demo/checkout" remote add origin https://github.com/example/project +export CODEX_SECURITY_STATE_DIR="$demo/state" DEMO_REPOSITORY="$demo/checkout" +cd sdk/typescript + +node bin/codex-security.mjs publish findings ../../examples/normalized-import/trivy-report.json \ + --to local --repository "$DEMO_REPOSITORY" --provider trivy \ + --source-key example/project/main --trivy-scan-root . --yes --format json + +node --input-type=module <<'JS' +import { readFile } from "node:fs/promises"; +import { + collectSelectedSemgrepGuardianFindings, normalizeSemgrepFindings, + listLocalExternalImports, prepareNormalizedLocalImport, +} from "@openai/codex-security"; + +const repository = process.env.DEMO_REPOSITORY; +const json = async name => JSON.parse(await readFile("../../examples/normalized-import/" + name, "utf8")); +const selected = await json("guardian-selection.json"); +const capture = await collectSelectedSemgrepGuardianFindings(selected, { + callTool: () => json("guardian-response.json"), +}); +const local = await prepareNormalizedLocalImport( + normalizeSemgrepFindings(capture, {}, "local"), + { repository, provider: "semgrep", sourceKey: selected.sourceKey }, +); +console.log(local.preview); +await local.import(); +console.table(await listLocalExternalImports({ repository })); +JS +``` + +The history shows two imports. The Guardian request selected string ID `9007199254740993` from a response containing two findings. A live MCP connection supplies the same collector's `callTool`. + +In Codex, open the same checkout with the same workbench state and say **“Preview the high-severity findings from these two imports for publication to my Cloud repository.”** Codex reads the stored versions and shows the source groups and exclusions for review. [User walkthrough](../../docs/scanner-imports/workbench.md) · [SDK selection and publication](../../sdk/typescript/docs/sdk.md#import-external-findings) diff --git a/plugins/codex-security/skills/publish-findings/SKILL.md b/plugins/codex-security/skills/publish-findings/SKILL.md index d521a5e3cb..ad44dce0f9 100644 --- a/plugins/codex-security/skills/publish-findings/SKILL.md +++ b/plugins/codex-security/skills/publish-findings/SKILL.md @@ -1,182 +1,43 @@ --- name: publish-findings -description: Preview and import scanner findings, including issues selected in the SonarQube plugin, into the local workbench or Codex Security Cloud. +description: Import findings from scanners, CI reports, vendor CLIs, APIs, or connected tools into the local workbench. Publish a selection of stored vendor findings to Codex Security Cloud. --- # Publish external findings -Use `codex-security import sonar` for [live SonarQube Cloud issues](#sonarqube-cloud-issues) or a capture saved by that command. Use `codex-security publish findings` for native scanner exports, including Sonar `/api/issues/search` pages with `--provider sonar`. Select the requested destination. The CLI owns source mapping, persistence, and Cloud authentication and retries. Do not implement another store or uploader or put credentials in command arguments. +Use this workflow for third-party scanner evidence. For “publish these findings,” start with the local workbench. For “import,” acquire the requested records and store them locally. For “import and publish,” publish the selection returned by the import. Use the “Import external findings” section of `docs/sdk.md` in the installed `@openai/codex-security` package. For a global npm install, its directory is `$(npm root --global)/@openai/codex-security`. Run SDK snippets from that trusted directory with absolute paths to the checkout and reports. ## Select the evidence -Use a supplied report, connected tool or signed-in CLI that provides the requested native records for the selected account, repository and ref. Follow the [scanner import guide](https://github.com/openai/codex-security/blob/main/docs/scanner-imports/README.md) to narrow broader reports and verify the selection in the JSON preview. Use a direct API only when the provider guide supports its response for the selected destination. Otherwise ask for a supported report. A fresh scan produces new findings. Keep the original records and complete the requested pagination. A JSON summary or a different product's API response is not interchangeable with the documented report. Use SARIF or CSV only when the installed provider reader supports that profile and native JSON is unavailable or the user supplies that format. Do not convert a richer JSON report to SARIF for import. +Identify whether the user wants a fresh scan, a previous scan or CI artifact, existing upstream issues, or records already in the workbench. Carry forward the selected repository, project, ref, products, filters, and exact finding IDs. A local scan can produce different findings from a hosted backlog or an earlier build. -Use the same acquisition format for repeated imports. Check the provider's identity rules before switching formats: another format can create a separate record or replace a richer snapshot with less detail. Importing findings does not reconcile equivalent vulnerabilities across formats. `--format json` controls command output, not the input report format; readers detect their supported inputs. +For a fresh scan, look for the relevant executable in the environment where it will run. Inspect its help when needed. For an existing hosted selection, inspect the tools actually available in this session or use a signed-in vendor CLI or authorized read API. Verify access with a scoped read or a documented status command. Use the vendor’s credential store or supported environment variables and keep credentials out of command arguments and imported evidence. Reuse a complete previous result from the same scope. Follow pagination, retain native records, and explain missing IDs or incomplete coverage. Ask for a missing account or repository only when the selection cannot be resolved from the available evidence. -## Import locally - -Use the checkout path with `--repository`. A saved report can be imported locally offline. Use this destination for Tenable One Code Repository captures. [Supported inputs by provider](https://github.com/openai/codex-security/blob/main/docs/scanner-imports/README.md#choose-your-scanner) - -```sh -codex-security publish findings /path/to/selected-wiz-findings.json \ - --to local --repository /path/to/project --provider wiz \ - --source-key TENANT_ID/vulnerability-finding --dry-run --format json -``` - -Show the repository, source namespace, normalized evidence, and exclusions. For a zero-record preview, report whether the input is empty or failed and stop. After confirmation, repeat without `--dry-run`, adding `--yes`. Keep approval when the user already approved this preview and the input and destination are unchanged. - -Read the stored evidence with `codex-security findings imported /path/to/project --format json`; the repository defaults to the current directory. Report created, updated, unchanged, and excluded counts, including exclusion reasons when the command exits 1. - -Local records remain unassessed source evidence, separate from `findings list` and completed scans. Repeated imports use the same repository/provider/source-key/source-ID identity; omitted records remain stored. When a source repository URL and local Git remotes are available, the URL must match a remote. Local import does not publish to Cloud or automatically investigate or patch findings. - -## Trivy dependency vulnerabilities - -Use `--provider trivy` with a saved schema-v2 repository or filesystem report (JSON or gzip). Preview with a stable project/branch source key and `--trivy-scan-root` relative to the checkout (`.` for the whole checkout). Omit the root only when the report's Git metadata corroborates a remote repository scan. Check the source, package paths and exclusions before importing. Trivy's `fixed` status identifies an available upstream fix. [Trivy import guide](https://github.com/openai/codex-security/blob/main/docs/scanner-imports/trivy.md) - -## Amazon Inspector repository findings - -Use `--provider inspector` and `--source-repository-url` with a complete Inspector2 ListFindings export for one Code Security repository. If it contains only a project ARN and name, pass the full `--inspector-project-arn ARN` verified for that Git URL in the SCM integration. Supply the same ARN when resuming a pending Cloud submission. Self-managed GitLab is supported locally. - -## AWS Continuum code findings - -Use `--provider continuum` and `--source-repository-url` for an AWS Continuum for Code Vulnerabilities export. Verify which repository owns each selected finding. Use `aws continuum get-code-finding` for a selected ID, or `list-code-findings` with automatic pagination when every row belongs to the requested repository. Reuse the same source key for that environment and repository. [Continuum import guide](https://github.com/openai/codex-security/blob/main/docs/scanner-imports/continuum.md) - -## Black Duck SCA project-version vulnerabilities - -Use `--provider blackduck` for a BOM-6 vulnerable-components export from one project version. Supply `--source-repository-url` after verifying the project version maps to that repository. Keep the same source key on replay and preview the destination before importing. - -## Checkmarx SAST - -Use `--provider checkmarx` for a Checkmarx One CLI JSON or self-managed CxSAST XML report. To retrieve a completed scan, follow the [Checkmarx collection instructions](references/checkmarx-import.md). Collection retrieves the full scan. If the user wants a subset, ask for a filtered vendor export. Before fetching CxSAST XML, verify the scan ID, project and owning team on the selected server. - -Preview the report for the verified repository and ref with `--dry-run --format json`. After confirmation, use the same report path and source key for the import and any retries. - -## Veracode Static Analysis policy findings - -Use `--provider veracode` with all Findings API pages for one application’s STATIC policy findings. Verify that the application maps to the repository named by `--source-repository-url`. Keep the source key stable for that application and preview the import before writing. - -## Endor Labs findings - -Use authenticated `endorctl` for one verified project and context. Omit `--field-mask` to keep complete native Finding objects. Replace `/path/to/private/reports` with a private directory outside the checkout. - -```sh -out=$(mktemp -d "/path/to/private/reports/endor.XXXXXX") && - endorctl api list --resource Finding --namespace "YOUR_NAMESPACE" \ - --filter 'context.type==CONTEXT_TYPE_MAIN and spec.project_uuid=="PROJECT_UUID"' \ - --list-all --output-type json > "$out/findings.tmp" && - mv "$out/findings.tmp" "$out/endor-findings.json" && - printf '%s\n' "$out/endor-findings.json" -``` - -Preview the completed file with `--provider endor` and a stable source key such as `YOUR_NAMESPACE/PROJECT_UUID/main`. Match the project to the destination repository. For another branch or scan context, change the filter and use a distinct source key. The [official Endor Labs Agent Kit for Codex](https://github.com/endorlabs/ai-plugins/tree/main/plugins/codex/endor-labs-agent-kit) can help with setup and investigation; its summaries, counts and field-masked results do not replace complete Finding objects. The [CLI API](https://docs.endorlabs.com/developers-api/cli/commands/api) supplies the export. The importer reads that saved file; it does not maintain an Endor API connection or write changes back to Endor. - -Native JSON retains severity, scanned commit, package and advisory data, and primary SAST/AI SAST locations. Existing self-contained endorctl SARIF is a lossy compatibility format that retains finding UUIDs and links; unavailable severity or revisions stay unknown. Both formats use the Endor UUID within the selected repository and source key as identity. Importing SARIF after native JSON updates the same record by replacing its evidence snapshot, not merging it: native detail absent from SARIF is removed from that snapshot. Use native JSON consistently for ongoing imports. Keep the original evidence and inspect exclusions. Imported records remain unassessed source evidence. Follow the [local](#import-locally) or [Cloud](#publish-to-cloud) workflow for the chosen destination. - -## Wiz findings - -Read [Wiz import formats](references/wiz-import.md#finding-formats) before preparing input. Use an authorized [Wiz MCP](https://www.wiz.io/blog/introducing-wiz-mcp) or Wiz API connection; a configured plugin may provide it, but do not assume an official Codex plugin is available. Prefer supported native JSON. Inspect actual records, finish the requested pagination, and save only the selected evidence with its original occurrence IDs. A supplied export is also supported. Summaries, Wiz Issues, and local CLI scan results are not automatically supported finding records. - -Validate the acquisition path against actual responses from an authorized Wiz tenant; local parser checks do not establish that qualification. Direct CSV input covers repository package vulnerabilities (SCA) only, not SAST or cloud posture findings, and does not provide a complete Wiz code-to-cloud integration. - -Use a stable Wiz tenant/finding namespace as `--source-key`; a project filter does not create a new identity. Confirm the selected assets or builds belong to the destination repository. Do not infer source branches or revisions from the current checkout, invent missing evidence, or import vendor credentials, unrelated records, or local assessments as original scanner evidence. Do not retrieve or test credentials or apply suggested fixes. - -## Snyk findings - -For an existing monitored Open Source or Code project, follow the [Snyk Issues API import guide](https://github.com/openai/codex-security/blob/main/docs/scanner-imports/snyk.md#existing-issues-from-snyk). With a read-authorized `SNYK_TOKEN`, run `codex-security import snyk PROJECT_ID --org ORG_ID --source-repository-url URL --format json`. Add `--snyk-product code` for a Code project and `--snyk-api-origin` for a regional deployment. Save the complete successful JSON output, preview with `publish findings --provider snyk` and the requested `--to local` or `--to cloud` destination, then confirm the import. - -Prefer the [official Snyk Codex plugin](https://github.com/snyk/studio-recipes/tree/main/plugins/codex) when available. Ask its `snyk-findings-export` skill for **SCA only from the repository’s Git root** and save the `snyk-findings-export/v1` bundle. It scans the current workspace through local MCP; it cannot list existing platform projects or retrieve earlier findings. Do not substitute a fresh scan for a request to read a platform backlog. Authentication, relevant Snyk access and the project's package tooling are required. - -Import the bundle with `--provider snyk`, choosing `--to local --repository /path/to/project` or `--to cloud --repository https://github.com/example/project`. Use a stable repository/branch/scan-target/acquisition namespace such as `github.com/example/project/main/root/plugin-sca`. Check the bundle's scan outcomes, collection completeness and limitations alongside the preview. Only Open Source SCA vulnerability records are supported; other categories are explicit exclusions. Preserve the native MCP record and unavailable fields. MCP descriptions may be shortened and alternate dependency paths omitted; do not reconstruct missing evidence. Plugin v1 paths are target-relative without a Git-root offset, so the importer keeps them in original evidence instead of repository locations. Use a distinct source key for each scan target. Ignore status is a source policy decision, not a Codex assessment or a fix. - -For CLI automation, prefer `snyk test --file=package.json --json-file-output=snyk-open-source.json` from the selected repository root. Exit 1 means vulnerabilities were found; stop on other nonzero exits instead of importing a stale file. The existing `--provider snyk` autodetects native JSON (one project or an `--all-projects` array), plugin JSON and Open Source SARIF. Native JSON preserves per-dependency-path records and remediation fields; do not use `--group-issues`. Project errors stop import. Native JSON paths also lack a Git-root offset and stay in original evidence. These workspace scan formats import Open Source SCA vulnerabilities. - -Use one format consistently per repository, branch and scan target, with a stable source key such as `github.com/example/project/main/root/native-sca`. Plugin, native JSON and SARIF have distinct identities; use separate keys when switching, without claiming cross-format deduplication or removal of older records. Existing `snyk test --sarif-file-output=snyk-open-source.sarif` reports remain a compatibility path. SARIF groups advisory occurrences and exposes one package coordinate, so prefer JSON for acquisition. Its target-relative manifest paths lack a Git-root offset and stay in original evidence with synthetic line numbers, without being projected as repository locations or package manifest paths. +| Source | Acquisition guidance | +| --- | --- | +| Trivy | For a fresh filesystem vulnerability scan, run `trivy fs --scanners vuln --format json --output REPORT.json .` from the chosen directory. For an earlier scan, read its repository or filesystem schema-v2 JSON or gzip artifact. Supply the checkout-relative `--trivy-scan-root` for filesystem reports. | +| Semgrep CLI or CI | For a fresh Code scan, use the installed CLI with the selected rules, e.g. `semgrep scan --config RULES --json-output REPORT.json .`. For an existing CI job, use its Code JSON or self-contained SARIF artifact. | +| Semgrep Guardian MCP | Use the connected Guardian tool `get_semgrep_sast_findings` or `get_semgrep_supply_chain_findings` with the deployment, repository, full ref, and selected filters. Match exact string finding IDs. Preserve the original request and selected tool rows in the [Guardian capture](https://github.com/openai/codex-security/blob/main/docs/scanner-imports/semgrep.md#import-selected-guardian-findings). | +| Semgrep hosted AppSec Platform MCP | Use `semgrep_account` and `ProjectsService_GetProject` to verify the project SCM URL. Use `IssuesService_ListIssues` scoped to that project, full ref, and `ISSUE_TYPE_SAST`, and retain the selected string issue IDs and original rows. Follow the [hosted MCP capture format](https://github.com/openai/codex-security/blob/main/docs/scanner-imports/semgrep.md#import-selected-code-findings-from-the-hosted-mcp). Guardian and hosted Platform IDs use distinct namespaces. | +| Semgrep Platform Web API | For a whole project and ref use `codex-security import semgrep PROJECT --deployment DEPLOYMENT --ref REF --format json`. For selected SAST IDs use the original project response and selected findings pages. | +| GitHub | The signed-in GitHub CLI collector `codex-security import github OWNER/REPO` accepts repeated `--github-alert NUMBER` or a `--github-ref REF`. Use `import github-advisories` for advisories. For Dependabot, export full paginated repository REST alert objects through the available GitHub connection. Keep separate source keys for these three families. | +| Snyk | For monitored Open Source or Code projects use `codex-security import snyk PROJECT_ID --org ORG_ID --source-repository-url URL --format json`. For a fresh dependency scan use native `snyk test` JSON or the signed-in Snyk plugin's SCA export from the requested root. Keep acquisition formats in distinct namespaces. | +| Checkmarx | Export a completed Checkmarx One scan as CLI JSON or self-managed CxSAST as XML. Follow the [collector instructions](references/checkmarx-import.md) for the selected product, scan, and verified owning project. | +| Wiz | Use the connected Wiz tools or API to retrieve the selected repository findings by occurrence ID, or use a detailed report. JSON covers multiple finding families. Detailed CSV covers repository package vulnerabilities. [Wiz input profiles](references/wiz-import.md) | +| Other built-in readers | OpenGrep accepts native scan JSON including scanner errors. Endor uses `endorctl` Finding JSON with complete records. Inspector uses Inspector2 ListFindings for one Code Security repository. Continuum uses GetCodeFinding details or repository-specific summaries. Black Duck uses BOM-6 vulnerable components for one project version. Veracode uses paginated STATIC policy findings for one application. Tenable uses a selected Code Repository inventory capture and verified HTTPS clone URL. [Provider guides and identity rules](https://github.com/openai/codex-security/blob/main/docs/scanner-imports/README.md#choose-your-scanner) | -Retain package versions, reported fixed versions, provenance and original evidence without claiming a fix was applied. Known repository claims must match the selected Cloud repository or, when available, a configured local Git remote. Resolve an unknown repository with the user; never infer that an export belongs to the current checkout. Follow [local imports](#import-locally) for preview, confirmation and readback or [Cloud publication](#publish-to-cloud) for upload authorization. Snyk workspace reports and monitored-project exports support local and Cloud import. +### SonarQube Cloud issues -## Semgrep Code +Retrieve existing Sonar issues with the signed-in `sonar` CLI. The Sonar plugin can supply selected issue keys; collect full issue and flow evidence for that same project, branch or pull request. Preview with `codex-security import sonar --sonar-project PROJECT --sonar-branch BRANCH --sonar-issue KEY --dry-run --format json` (repeat `--sonar-issue` for more keys). Use the preview's saved capture for an approved import. For findings already stored in the workbench, select them directly. [Sonar workflow](https://github.com/openai/codex-security/blob/main/docs/scanner-imports/sonar.md#import-and-verify) -Prefer native Code/SAST CLI or CI JSON for this reader; use self-contained SARIF 2.1.0 as a compatibility path. JSON retains the original severity better than SARIF. Select SAST rules or Code-only CI output; identifiable non-SAST records are excluded, but SARIF may omit the product metadata needed to distinguish Secrets. - -For a user-requested new scan, use the installed Semgrep CLI from the source repository root with the selected SAST rules: `semgrep scan --config /path/to/sast-rules.yaml --json-output /path/to/semgrep.json .`. Existing CI jobs can produce the same artifact using `--json-output`; authenticated `semgrep ci --code` follows the job's policy and baseline scope. Explain that this generates fresh scan findings, and do not substitute it for a request to retrieve existing Platform findings. - -For selected rule-based Code findings from the hosted Semgrep AppSec Platform MCP, call `semgrep_account` and match the project's SCM URL to the requested repository. Fetch the project with `ProjectsService_GetProject` and the requested string issue IDs with `IssuesService_ListIssues`, scoped to the project ID, full ref and `ISSUE_TYPE_SAST`. Copy the original selected issue rows into a private capture with `deploymentId`, `project`, `ref`, `findingIds` and `issues`. Follow the [hosted MCP SDK example](https://github.com/openai/codex-security/blob/main/docs/scanner-imports/semgrep.md#import-selected-code-findings-from-the-hosted-mcp) to preview and save to the verified local checkout or the explicitly selected Cloud destination. Verify the private inbox job or the connected repository’s receipts and readback, as shown in the preview. - -For a selection of existing Code or Supply Chain findings from Guardian, use the signed-in [Semgrep Guardian plugin](https://docs.semgrep.dev/semgrep-guardian/quickstart). Call its `get_semgrep_sast_findings` or `get_semgrep_supply_chain_findings` tool with the selected `deployment_name`, `repository_name` and full `ref`. Preserve any state and severity filters used for that selection. Reuse an existing successful tool result when its scope is explicit. If a selected ID is missing, report it and check the query scope and filters with the user. A project-wide fetch is a separate request. - -Save a private JSON capture outside the checkout with `format: "semgrep-guardian-selection/v1"`, the verified `sourceRepositoryUrl`, the MCP `request` (tool `name` and `arguments`), the exact selected string `findingIds`, and `structuredContent: { findings: [...] }` containing the original selected tool rows. Match IDs exactly and keep the tool's repository, ref and evidence. Guardian returns a repository name, so verify its SCM URL for the local checkout or selected Cloud repository. Use the [Guardian preview command](https://github.com/openai/codex-security/blob/main/docs/scanner-imports/semgrep.md#import-selected-guardian-findings) for the intended destination and confirm after reviewing the selection. Guardian handles sign-in for this workflow. Guardian and Web API IDs remain separate even when the strings match. - -For a whole project and ref, use the [Web API collector](https://github.com/openai/codex-security/blob/main/docs/scanner-imports/semgrep.md#collect-a-platform-project-and-branch) with its read-capable token. If the user supplies [saved Web API responses](https://github.com/openai/codex-security/blob/main/docs/scanner-imports/semgrep.md#existing-platform-findings), use the IDs from those records. Preview Web API findings against the requested local or Cloud repository. - -Import the native report with `--provider semgrep`, a stable organization/project/branch `--source-key`, and `--source-repository-url` identifying the actual source repository. Use `--to local --repository /path/to/project` for local storage or `--to cloud --repository URL_OR_ID` for Cloud. The source URL is checked against configured local Git remotes or the Cloud destination. Preview with `--dry-run --format json` before confirming the import. - -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. - -## SonarQube Cloud issues - -For “import these Sonar findings,” carry over the Sonar project, branch or PR, and the exact issue keys selected in the [SonarQube plugin for Codex](https://www.sonarsource.com/blog/now-available-sonarqube-plugin-for-codex/). Use the keys from the underlying Sonar result. If only a formatted table remains, resolve the selected rows against the same project and ref and ask about ambiguous matches. A rule can occur more than once. Never turn a selection into a project-wide import. - -From the intended checkout, preview the selection using the developer's authenticated `sonar` CLI. Use `--sonar-pull-request` in place of `--sonar-branch` for a PR. Omit `--sonar-issue` only when the user wants the project's open security issues. If the project has no verified SCM binding, confirm the repository URL that belongs to the project and pass it with `--source-repository-url`. - -```sh -codex-security import sonar --sonar-project example_project --sonar-branch main \ - --sonar-issue ISSUE_A --sonar-issue ISSUE_B --dry-run --format json -``` - -Pass `--to cloud` at preview time if the user also requested Cloud publication. Show the selected issues and exclusions, the local repository, and any Cloud destination as described under [Publish to Cloud](#publish-to-cloud). The preview returns a private evidence file in `capture`. After confirmation, run `codex-security import sonar CAPTURE --yes` for local import. For Cloud, use the exact `capture` from the successful Cloud preview and add `--to cloud`. If the account, repository, or environment changes, show a fresh preview and ask for confirmation. If Cloud is unavailable, finish the requested local import and report the Cloud error. For a request to publish an existing import, start with its capture. Report the saved path so the developer can resume. - -Sonar authentication is required only for a live fetch. If the local CLI lacks a login, direct the user to `sonar auth login` and keep the selection. A hosted MCP connection can help identify issues, but its issue summaries omit flow evidence. Use the signed-in CLI or a saved Codex Security Sonar capture to complete the import. If `codex-security` is absent, ask the user to install it from a trusted directory and invoke that installed executable in the checkout. - -## 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 a code-scanning import envelope from MCP summaries. Use the saved collector output for code-scanning alerts. - -The importer uses the user's GitHub CLI authentication and `GH_HOST`; plugin authentication is separate. It defaults to open alerts on the default branch. Use repeated `--github-alert NUMBER` for exact alerts or `--github-ref REF` for another ref. Save complete output without field/token filters or `--full-output`. Reading code-scanning alerts requires a token with Code scanning alerts read permission (classic: `security_events`, or `public_repo` for public repositories), along with repository access. - -For Dependabot, follow the [repository alert export guide](https://github.com/openai/codex-security/blob/main/docs/scanner-imports/github-dependabot.md) to save the native REST alert records from one repository. The read-only export requires Dependabot alerts read permission. Preview the file with `publish findings FILE --provider github`, the intended destination and a separate source key such as `github.com/example/project/dependabot`. - -**GHSA import stages advisory evidence for investigation; it does not establish an installed dependency or applicability to the destination repository.** Keep advisories separate from code scanning. `codex-security import github-advisories OWNER/REPO --format json` reads published repository disclosures by default. Repeated `--github-advisory GHSA-xxxx-xxxx-xxxx` selects exact IDs; `--github-state draft|triage|closed` explicitly selects an unpublished list and cannot be combined with exact IDs. Add `--github-advisory-source global` for exact public database IDs. This does not enumerate the global database. Private advisory access needs Repository security advisories read permission and access to those records. Stop on a read failure instead of publishing an incomplete selection. +## Import locally -Save the selected collector’s output in a private file outside the checkout. After collection succeeds, use `--provider github` and the [local](#import-locally) or [Cloud](#publish-to-cloud) workflow for the requested destination. Keep a separate stable source key for each family, such as `github.com/example/project/code-scanning` or `github.com/example/project/security-advisories`. +Use the matching native SDK reader or the existing CLI, for example `codex-security publish findings REPORT.json --to local --provider trivy --source-key PROJECT/BRANCH --repository CHECKOUT --trivy-scan-root . --dry-run --format json`. Use a source key stable across repeated imports of this selection. Review the repository, evidence, exclusions and scanner errors. For the requested write, drop `--dry-run` and use `--yes` when approved. Record the import ID and finding IDs and versions from the result. -Code-scanning identities include the ref; repository alerts and advisories must match the selected Cloud repository or, when available, a configured local Git remote. Global advisories omit source-repository provenance and are bound to the explicit local or Cloud destination for investigation. Preserve original evidence, package ranges and patches; do not infer installed packages or source locations from an advisory. Missing security severity stays `unknown`. Dismissal, resolution and withdrawal are source state, not Codex assessment. Secret-scanning alerts and writeback to GitHub are outside this workflow. +For an unfamiliar format, inspect actual rows and write a parser in the language appropriate to the source. Pass the findings, read count and exclusions to `prepareNormalizedLocalImport` with the checkout, provider and source key. Give each occurrence a stable source ID, preserve relevant native evidence and repository identity, and account for every selected row with either evidence or a numbered exclusion. Report skipped or missing items. A repeated import can include unchanged findings; the import ID identifies the entire stored selection. ## Publish to Cloud -Resolve the user's destination to a connected GitHub or GitHub Enterprise repository URL or Cloud repository ID, including custom Enterprise hosts. Confirm the intended Cloud account and authorized repository environment before running a preview that can contact Cloud. Use the existing file-backed ChatGPT login; explain a missing or incompatible login rather than changing credential storage automatically. - -For an alternate Cloud deployment, configure the [deployment settings](#deployment-settings) before previewing. Keep the selected deployment and login throughout the upload. - -### Preview and approve - -```sh -codex-security publish findings /path/to/selected-wiz-findings.json \ - --to cloud --repository https://github.com/example/project --provider wiz \ - --source-key TENANT_ID/vulnerability-finding --dry-run --format json -``` - -When the preview returns `status: "empty"`, report that there is nothing to upload. For a nonempty preview, show the endpoint, account, repository, source key, severity counts and exclusions. The `privateImport` entry describes the report for the user’s private inbox. For the repository publisher, `requests` identifies the environments that will receive the records. Identify the evidence file and make the complete JSON preview available for inspection without pasting a large report into the conversation. Explain that vendor evidence is not a Codex assessment. - -Obtain explicit confirmation for this concrete upload, including skipped records. Then run the same command without `--dry-run`, adding `--yes`. Authorization to inspect or assess findings alone does not authorize sending them to Cloud. Keep approval when the user already approved this preview and the input and destination are unchanged. - -### Upload and report - -Read the structured result even when the process exits nonzero. Progress appears on stderr. For a private inbox import, check `privateJob.status`, the job counts, errors and unprocessed records. A completed job can have `verified: 0`. - -For the repository publisher, report `verified` for findings the CLI confirmed by readback and `unacknowledged` for records without a receipt. Use `failures` to identify records the publisher rejected. For either destination, include exclusions and any `savedSubmission` checkpoint. [Result fields and exit codes](https://github.com/openai/codex-security/blob/main/sdk/typescript/docs/cli.md#results-and-exit-codes) - -A private finding can be assessed against the repository and published to shared Findings. Link to the returned `cloudUrl` when available. - -### Resume an interrupted upload - -Preview the original file again with the same source key, repository, account, endpoint and state directory. If `resumed` is true, the CLI reuses the saved submission. If a reset or changed destination requires a new submission, review the new preview before confirming. [Retry a Cloud submission](https://github.com/openai/codex-security/blob/main/docs/scanner-imports/schema-guide.md#retry-a-cloud-submission) - -### Deployment settings - -Set `CODEX_SECURITY_CLOUD_BASE_URL` to the deployment's API root for preview and upload. Use its login and an isolated state directory for tests. If the user or Cloud page supplies an app URL, set `CODEX_SECURITY_CLOUD_WEB_URL` to that full URL. This setting controls the returned UI link. The API root and login still determine routing and authentication. +Resolve an import ID or the selected stored finding IDs and versions for the requested checkout. For relative times such as “yesterday,” use the import history's timestamps and membership; a finding's update time may predate an import that included it. Show the account, Cloud repository and inbox or repository environments, findings, and exclusions. Obtain explicit confirmation for that concrete upload, retaining existing approval when the preview and destination match. Report group receipts, failures and any remaining local-only findings. Vendor evidence starts unassessed. -Check the preview's `cloudApiUrl` and any `cloudUrl` against the intended API endpoint and app. Saved retries are scoped to the deployment. `CODEX_SECURITY_CLOUD_PUBLISH_URL` applies only to native scan publication. +For a private inbox, check the import job status and counts. For repository requests, check verification, unacknowledged records and failures. Keep each approved group’s selection, destination and review ID. On interruption, reprepare the interrupted and unstarted groups, using the saved review IDs. For an earlier client’s pending upload, finish with its original build or verify which findings reached Cloud before preparing another submission. Report completed groups from their receipts. A changed review ID requires a fresh preview. [Cloud receipts and retry behavior](https://github.com/openai/codex-security/blob/main/docs/scanner-imports/schema-guide.md#retry-a-cloud-submission) diff --git a/plugins/codex-security/skills/publish-findings/agents/openai.yaml b/plugins/codex-security/skills/publish-findings/agents/openai.yaml index 0bce48a54b..d54efb0641 100644 --- a/plugins/codex-security/skills/publish-findings/agents/openai.yaml +++ b/plugins/codex-security/skills/publish-findings/agents/openai.yaml @@ -1,6 +1,6 @@ interface: display_name: "Publish Findings" - short_description: "Import vendor findings locally or to Cloud" - default_prompt: "Use $publish-findings to preview selected vendor findings for my repository and import them to my chosen destination." + short_description: "Import and publish stored scanner findings" + default_prompt: "Use $publish-findings to import the selected scanner findings or publish a selection from my local workbench." policy: allow_implicit_invocation: true diff --git a/plugins/codex-security/skills/publish-findings/references/checkmarx-import.md b/plugins/codex-security/skills/publish-findings/references/checkmarx-import.md index 5e9ede8dd7..5552162fda 100644 --- a/plugins/codex-security/skills/publish-findings/references/checkmarx-import.md +++ b/plugins/codex-security/skills/publish-findings/references/checkmarx-import.md @@ -32,6 +32,6 @@ Use native Java, a released CxFlow JAR (1.6.37+), and a trusted SAST-only profil ## Preview and import -Pass the successful helper's printed path as the quoted file argument to `codex-security publish findings` in the next tool call. Use `--provider checkmarx`, the requested destination, verified `--source-repository-url`, a stable product/tenant/project/ref `--source-key`, and `--dry-run --format json`. Review the scope, findings and exclusions. Verify native paths against the checkout before opening source files. +Pass the successful helper's printed path as the quoted file argument to `codex-security publish findings` in the next tool call. Use `--provider checkmarx --to local --repository CHECKOUT`, the verified `--source-repository-url`, a stable product/tenant/project/ref `--source-key`, and `--dry-run --format json`. Review the scope, findings and exclusions. Verify native paths against the checkout before opening source files. -After confirmation, reuse that file and those options for [local import](../SKILL.md#import-locally), [Cloud publication](../SKILL.md#publish-to-cloud) and retries. Remove the helper’s temporary directory after readback unless the operator wants it retained. Keep operator-supplied files. [User guide](https://github.com/openai/codex-security/blob/main/docs/scanner-imports/checkmarx.md) +After confirmation, reuse that file and those options for the [local import](../SKILL.md#import-locally). Use its stored selection for [Cloud publication](../SKILL.md#publish-to-cloud) and retries. Remove the helper’s temporary directory after readback unless the operator wants it retained. Keep operator-supplied files. [User guide](https://github.com/openai/codex-security/blob/main/docs/scanner-imports/checkmarx.md) diff --git a/sdk/typescript/src/cli-help.ts b/sdk/typescript/src/cli-help.ts index 1533c1bde6..dcf9c9855c 100644 --- a/sdk/typescript/src/cli-help.ts +++ b/sdk/typescript/src/cli-help.ts @@ -305,6 +305,16 @@ export function formatCliHelp(text: string, columns = 80): string | undefined { label: "Live provider", description: "Choose a collector below.", }, + { + label: "CLI, API, or MCP source", + description: + "Ask Codex to import it using the publish-findings skill.", + }, + { + label: "Workbench findings", + description: + "Ask Codex to publish a stored import or selected finding versions.", + }, { label: "Saved vendor report", description: diff --git a/sdk/typescript/src/cli.ts b/sdk/typescript/src/cli.ts index 7535ffd731..fcaf3ce03e 100644 --- a/sdk/typescript/src/cli.ts +++ b/sdk/typescript/src/cli.ts @@ -4116,7 +4116,7 @@ export async function main( }, }, ], - hint: "Choose your scanner with --provider. Reuse --source-key for later imports from the same source. See the scanner import guide for supported formats, repository setup, and export examples: https://github.com/openai/codex-security/blob/main/docs/scanner-imports/README.md. Gzip files are supported. Use --to local to save unassessed findings without a Cloud login. Use --full-output with --format json or --format jsonl.", + hint: "Choose your scanner with --provider. Reuse --source-key for later imports from the same source. For findings already in the workbench, use the SDK's prepareStoredFindingsPublication. The installed @openai/codex-security package includes the workflow in docs/sdk.md under Import external findings. See the scanner import guide for supported formats, repository setup, and export examples: https://github.com/openai/codex-security/blob/main/docs/scanner-imports/README.md. Gzip files are supported. Use --to local to save unassessed findings without a Cloud login. Use --full-output with --format json or --format jsonl.", destructive: true, args: z.object({ file: z diff --git a/sdk/typescript/tests-ts/cli-help.test.ts b/sdk/typescript/tests-ts/cli-help.test.ts index 3db5a5385d..be83c96d1f 100644 --- a/sdk/typescript/tests-ts/cli-help.test.ts +++ b/sdk/typescript/tests-ts/cli-help.test.ts @@ -515,6 +515,8 @@ describe("CLI help", () => { const menu = (await help(["import", "--help"])).replace(/\s+/gu, " "); expect(menu).toContain("publish findings --help"); expect(menu).toContain("scan import --help"); + expect(menu).toContain("publish-findings skill"); + expect(menu).toContain("publish a stored import"); const vendor = await help(["publish", "findings", "--help"], 60); const preview = vendor .split("\n") From 1f710a322be1aff63f5f0961c74a89d9444745b7 Mon Sep 17 00:00:00 2001 From: Michael D'Angelo Date: Wed, 11 Nov 2026 13:36:30 +0000 Subject: [PATCH 2/2] docs(plugin): name the stored publication calls and explain partial imports --- docs/scanner-imports/workbench.md | 6 +++--- plugins/codex-security/skills/publish-findings/SKILL.md | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/scanner-imports/workbench.md b/docs/scanner-imports/workbench.md index b20136149f..24e75468ab 100644 --- a/docs/scanner-imports/workbench.md +++ b/docs/scanner-imports/workbench.md @@ -41,8 +41,8 @@ The following commands show what Codex can run for each built-in collector. You | ---------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | “Import GitHub code-scanning alert 17 from acme/payments.” | `cs import github acme/payments --github-alert 17 --format json` uses the signed-in `gh` CLI to fetch the alert and its instance. | | “Import published repository advisories for acme/payments.” | `cs import github-advisories acme/payments --format json` uses `gh` to fetch published advisories. For a global advisory, give its exact GHSA ID and use `--github-advisory-source global --github-advisory ID`. | -| “Import monitored Snyk Code issues for project P in organization O into this checkout.” | `cs import snyk P --org O --snyk-product code --source-repository-url https://github.com/acme/payments --format json` uses `SNYK_TOKEN` to page through the Snyk API. | -| “Import the Semgrep Platform SAST backlog for acme/payments on main in deployment acme.” | `cs import semgrep acme/payments --deployment acme --ref refs/heads/main --format json` uses the Web API with `SEMGREP_APP_TOKEN` to collect the project and ref. | +| “Import monitored Snyk Code issues for project P in organization O into this checkout.” | `cs import snyk P --org O --snyk-product code --source-repository-url https://github.com/acme/payments --format json` uses `SNYK_TOKEN` to page through the Snyk API. | +| “Import the Semgrep Platform SAST backlog for acme/payments on main in deployment acme.” | `cs import semgrep acme/payments --deployment acme --ref refs/heads/main --format json` uses the Web API with `SEMGREP_APP_TOKEN` to collect the project and ref. | | “Import Sonar issue ISSUE_A from project payments on main.” | `cs import sonar --sonar-project payments --sonar-branch main --sonar-issue ISSUE_A --dry-run --format json` uses the active `sonar` login. Codex reads the returned capture path and can save it with `cs import sonar "$capture" --yes`. [Sonar capture and Cloud replay](sonar.md#import-and-verify) | > Import Guardian SAST findings `101` and `103` for acme/payments on `refs/heads/main` in deployment acme. @@ -97,7 +97,7 @@ flowchart LR You can confirm the displayed groups together. Codex retains each approved group’s `.selection` and `.reviewId` and calls `group.publish(savedReviewId)`. If a later group is interrupted, it reopens that group and resumes the existing submission. Completed groups keep their receipts. A changed selection or destination requires reviewing the new preview. -For a terminal-only upload of an existing report, `cs publish findings FILE --to cloud` accepts the provider, source key and Cloud repository. For a Codex Security CSV or JSON export of a completed scan, `cs scan import` saves it in scan history. [CLI input choices](README.md#choose-your-input) +To preview an existing report for upload from the terminal, run `cs publish findings FILE --provider PROVIDER --source-key KEY --repository CLOUD_REPO --to cloud --dry-run` with the report's scanner options. Remove `--dry-run` and confirm to publish. For a Codex Security CSV or JSON export of a completed scan, `cs scan import FILE` saves it in scan history. [CLI input choices](README.md#choose-your-input) ## Test each part diff --git a/plugins/codex-security/skills/publish-findings/SKILL.md b/plugins/codex-security/skills/publish-findings/SKILL.md index ad44dce0f9..c5e70d9c5b 100644 --- a/plugins/codex-security/skills/publish-findings/SKILL.md +++ b/plugins/codex-security/skills/publish-findings/SKILL.md @@ -21,7 +21,7 @@ For a fresh scan, look for the relevant executable in the environment where it w | Semgrep hosted AppSec Platform MCP | Use `semgrep_account` and `ProjectsService_GetProject` to verify the project SCM URL. Use `IssuesService_ListIssues` scoped to that project, full ref, and `ISSUE_TYPE_SAST`, and retain the selected string issue IDs and original rows. Follow the [hosted MCP capture format](https://github.com/openai/codex-security/blob/main/docs/scanner-imports/semgrep.md#import-selected-code-findings-from-the-hosted-mcp). Guardian and hosted Platform IDs use distinct namespaces. | | Semgrep Platform Web API | For a whole project and ref use `codex-security import semgrep PROJECT --deployment DEPLOYMENT --ref REF --format json`. For selected SAST IDs use the original project response and selected findings pages. | | GitHub | The signed-in GitHub CLI collector `codex-security import github OWNER/REPO` accepts repeated `--github-alert NUMBER` or a `--github-ref REF`. Use `import github-advisories` for advisories. For Dependabot, export full paginated repository REST alert objects through the available GitHub connection. Keep separate source keys for these three families. | -| Snyk | For monitored Open Source or Code projects use `codex-security import snyk PROJECT_ID --org ORG_ID --source-repository-url URL --format json`. For a fresh dependency scan use native `snyk test` JSON or the signed-in Snyk plugin's SCA export from the requested root. Keep acquisition formats in distinct namespaces. | +| Snyk | For a monitored Open Source project use `codex-security import snyk PROJECT_ID --org ORG_ID --source-repository-url URL --format json`. Add `--snyk-product code` for a monitored Code project. For a fresh dependency scan use native `snyk test` JSON or the signed-in Snyk plugin's SCA export from the requested root. Keep acquisition formats in distinct namespaces. | | Checkmarx | Export a completed Checkmarx One scan as CLI JSON or self-managed CxSAST as XML. Follow the [collector instructions](references/checkmarx-import.md) for the selected product, scan, and verified owning project. | | Wiz | Use the connected Wiz tools or API to retrieve the selected repository findings by occurrence ID, or use a detailed report. JSON covers multiple finding families. Detailed CSV covers repository package vulnerabilities. [Wiz input profiles](references/wiz-import.md) | | Other built-in readers | OpenGrep accepts native scan JSON including scanner errors. Endor uses `endorctl` Finding JSON with complete records. Inspector uses Inspector2 ListFindings for one Code Security repository. Continuum uses GetCodeFinding details or repository-specific summaries. Black Duck uses BOM-6 vulnerable components for one project version. Veracode uses paginated STATIC policy findings for one application. Tenable uses a selected Code Repository inventory capture and verified HTTPS clone URL. [Provider guides and identity rules](https://github.com/openai/codex-security/blob/main/docs/scanner-imports/README.md#choose-your-scanner) | @@ -32,12 +32,12 @@ Retrieve existing Sonar issues with the signed-in `sonar` CLI. The Sonar plugin ## Import locally -Use the matching native SDK reader or the existing CLI, for example `codex-security publish findings REPORT.json --to local --provider trivy --source-key PROJECT/BRANCH --repository CHECKOUT --trivy-scan-root . --dry-run --format json`. Use a source key stable across repeated imports of this selection. Review the repository, evidence, exclusions and scanner errors. For the requested write, drop `--dry-run` and use `--yes` when approved. Record the import ID and finding IDs and versions from the result. +Use the matching native SDK reader or the existing CLI, for example `codex-security publish findings REPORT.json --to local --provider trivy --source-key PROJECT/BRANCH --repository CHECKOUT --trivy-scan-root . --dry-run --format json`. Use a source key stable across repeated imports of this selection. Review the repository, evidence, exclusions and scanner errors. For the requested write, drop `--dry-run` and use `--yes` when approved. Keep the import ID and finding versions from the result. A partial import exits with code 1. Check the saved findings and report the exclusions before retrying. For an unfamiliar format, inspect actual rows and write a parser in the language appropriate to the source. Pass the findings, read count and exclusions to `prepareNormalizedLocalImport` with the checkout, provider and source key. Give each occurrence a stable source ID, preserve relevant native evidence and repository identity, and account for every selected row with either evidence or a numbered exclusion. Report skipped or missing items. A repeated import can include unchanged findings; the import ID identifies the entire stored selection. ## Publish to Cloud -Resolve an import ID or the selected stored finding IDs and versions for the requested checkout. For relative times such as “yesterday,” use the import history's timestamps and membership; a finding's update time may predate an import that included it. Show the account, Cloud repository and inbox or repository environments, findings, and exclusions. Obtain explicit confirmation for that concrete upload, retaining existing approval when the preview and destination match. Report group receipts, failures and any remaining local-only findings. Vendor evidence starts unassessed. +Use `listLocalExternalImports({ repository })` to find an import by its timestamp, including imports of unchanged findings. Call `prepareStoredFindingsPublication(selection, { repository: cloudRepository })` with that import ID or the selected finding IDs and versions. Show the account, destination, evidence and exclusions. After the user confirms the preview, call `group.publish(group.reviewId)` for each approved group. For a private inbox, check the import job status and counts. For repository requests, check verification, unacknowledged records and failures. Keep each approved group’s selection, destination and review ID. On interruption, reprepare the interrupted and unstarted groups, using the saved review IDs. For an earlier client’s pending upload, finish with its original build or verify which findings reached Cloud before preparing another submission. Report completed groups from their receipts. A changed review ID requires a fresh preview. [Cloud receipts and retry behavior](https://github.com/openai/codex-security/blob/main/docs/scanner-imports/schema-guide.md#retry-a-cloud-submission)