For the complete documentation index, see llms.txt. This page is also available as Markdown.

CI scan workflow

The workflow proceeds from embedding the gate, through verifying that the gate fires, to investigating a failed build and separating security failures from tooling failures.

Embed the CI scan in a pipeline

A pipeline without a Cortex CLI step is ungated regardless of which policies are enabled at the tenant level.

Prerequisites: An API key with write permission, and permission to modify the pipeline definition in your CI/CD system.

  1. Add a Cortex CLI scan step to the pipeline definition, positioned before the step that publishes or deploys the artifact. Placing the scan after the artifact is published records the finding without preventing distribution.

  2. Configure authentication with an API key carrying write permission. A key without write permission silently downgrades the scan to no-upload mode, which produces no inventory row and no governance record.

  3. Leave the default upload mode in place, so results reach the CI Scans inventory.

  4. Confirm that the pipeline treats a non-zero exit code as a build failure. This is the step that converts the scan from a report into a gate. Most CI/CD systems fail a step on a non-zero exit by default; a step configured with a continue-on-error setting, or a command wrapped so that the exit code is swallowed, reports the block in Cortex Cloud while the build proceeds.

  5. Run the pipeline once, and verify that a row appears in the CI Scans inventory under Application Security > Scans > CI Scans for the expected repository and branch.

  6. Verify that the gate actually stops a build before declaring enforcement live. Confirm that --soft-fail is not set, then run the pipeline against a branch carrying a finding that matches an enabled Block CI/CD policy. The build must fail. A run that reports Blocked in the inventory while the pipeline goes green means the scan is reporting and not enforcing.

Result: Each pipeline run produces a CI scan row, and a run whose findings match a Block CI/CD policy returns exit code 1 and fails the build.

Important: If the pipeline succeeded and no row appears in the inventory, the scan did not report. Check the upload mode and the API key permission before concluding the run was clean. An unreported scan produces no row and no warning.

Caution: Configure blocking policies before enforcing a non-zero exit code across production pipelines. Enabling both at once fails every build carrying pre-existing findings, and the usual response is to disable the scan step — which removes the gate entirely. Introduce the scan in reporting mode first, establish the backlog, then enforce. The --soft-fail flag supports this sequence by reporting policy matches while always returning exit code 0.

Important: A pipeline running with --soft-fail is indistinguishable from an enforcing pipeline in the CI Scans inventory. Both produce rows, and both can report Blocked, because the status records the policy verdict rather than what the pipeline did with the exit code. Track which pipelines still carry --soft-fail outside the inventory, and complete step 6 when removing the flag. Until step 6 passes for a pipeline, treat that pipeline as reporting, not gating.

Note: For CLI installation, flags, environment variables, and platform-specific pipeline examples, see Cortex CLI. For scanner settings, see Branch periodic scans.

Verify that the build gate is firing across the portfolio

A pipeline that runs the scan and a pipeline that enforces the result are different states. Establish which repositories are reporting CI scans before claiming build-stage coverage.

  1. Navigate to Application Security > Scans > CI Scans.

  2. Use the filter bar to filter by repository, organization, scanned branch, CI status, and scan health. Bound the assessment to the period under review, so the returned rows are the builds of that period rather than every build the inventory has accumulated. Where the inventory exposes a Scan Date range filter, apply it — see Scan Date filter for availability and limitations.

  3. Filter CI Status to Blocked. The returned rows are the commit scans the gate stopped, and one branch contributes several rows across successive commits. Zero Blocked rows for a repository that ships artifacts has four possible causes, and the row count distinguishes none of them: the code is clean; no enabled policy carries the Block CI/CD action for the finding types that repository produces; a matching policy is inside its grace period and therefore reports without blocking; or the pipeline runs the scan without enforcing the exit code. Resolve the second and third causes against the policy set — filter the policy table by the CI Scan trigger and the Block CI/CD action, and check the scope and grace period of each matching policy. Resolve the fourth against the pipeline definition. A fifth cause is possible and cannot yet be ruled in or out: CI Status carries an N/A value, and a build reporting N/A is not returned by a Blocked filter — but the conditions that produce N/A are unconfirmed, so whether N/A rows account for part of a zero Blocked count is undetermined. Establish whether the repository produces N/A rows before treating the four causes above as exhaustive, and see the TODO in Reference D: CI status values. The rows that remain are not a clean population — Passed covers both a scan that found nothing and a scan whose issues matched no blocking policy, and the column does not separate them. Read the Issues Found count on a Passed row to distinguish the two.

  4. Establish the pipeline population. Cortex Cloud discovers CI/CD pipeline definitions in onboarded repositories and lists them under Assets > Asset Inventory > Code > CI/CD Pipelines — see CI/CD pipeline as an asset. Use that inventory to identify the pipelines that exist, then compare against the repositories returning CI scan rows. The comparison is approximate in one direction: the CI scans inventory reports per repository and branch rather than per pipeline, so a repository carrying several pipelines returns rows when any one of them scans. Treat a repository with no rows as definitely ungated, and a repository with rows as partially verified until you confirm which pipeline produced them.

  5. Filter Scan Health to Error and to Partially Completed. These rows are builds evaluated on incomplete evidence. Treat the resulting artifacts as ungoverned regardless of the CI status reported.

  6. Filter Business Application Names to one business-critical application at a time, and address the returned gaps before moving to the next application. The inventory carries application names but not application criticality, and the column supports neither sorting nor grouping because a repository can belong to several applications. Establish the criticality ordering outside this inventory first: navigate to Application Security > Application Management > Business Applications, sort the table by the Business Criticality column, and record the application names in descending criticality order. The criticality tiers that qualify as business-critical are a governance decision — confirm the threshold with the AppSec Manager rather than setting the threshold at the filter. A repository with no business application mapping returns an empty value — treat an empty value as unknown criticality requiring mapping. To map repositories to applications, see Criteria.

Result: You hold the commit scans the gate stopped, the repositories shipping artifacts without a build-stage gate, and the builds that passed on incomplete evidence, each sequenced by the business criticality of the owning application.

Important: This filter applies to the CI Scans inventory and therefore reaches only the repositories that return rows. The ungated population established in step 4 returns no rows and cannot be sequenced here — apply the same criticality ordering to that population in the CI/CD Pipelines asset inventory, or in the exported list, before delegating it. Sequencing only the repositories that report leaves the definitely ungated repositories unprioritized.

Important: Completing this section does not establish that the gate enforces. A pipeline running with --soft-fail returns the same rows as an enforcing pipeline, as stated in Embed the CI scan in a pipeline. Confirm enforcement per pipeline against the pipeline definition, and treat the portfolio pass as establishing which repositories report, not which repositories gate.

Note: Embedding a CI scan requires permission to modify the pipeline definition in the CI/CD system and a Cortex Cloud API key carrying write permission — neither of which the scan-viewing permissions grant. Confirm the assignee holds both before delegating a coverage gap, and verify closure by repeating steps 3 and 4 and confirming that the repositories handed over now return rows. For API key creation and the roles that permit it, see Cortex CLI.

Important: CI scan counts and CI scan rows do not always agree. Scans originating from the Cortex CLI are excluded from some aggregate scan counts by product decision, while appearing as rows in this inventory. When an aggregate figure and a row count disagree, treat the inventory rows as the record of individual scans and do not reconcile the two by adjusting filters.

Note: Prevention Rate — the share of findings blocked at the PR and CI enforcement points — is reported in the ASPM Command Center over a defined window and scope, alongside a Blocked in Build figure. To compute prevention across a custom period, use the method in API workflows for Code Security issues. A figure derived from this inventory counts commit scans unless deduplicated — do not report it as a count of pipelines or repositories blocked. For the inventory columns, see Reference B: Inventory columns.

Note: Coverage gaps can be tracked as issues rather than as a manual list. The Coverage page carries built-in detection rules that create an issue for an uncovered CI/CD pipeline (COVERAGE-11) and for a partially covered CI/CD pipeline (COVERAGE-12). Both rules evaluate scanner activation, not scan execution, so a pipeline that carries a scanner association without running a Cortex CLI step is counted as covered and generates no issue. Treat these issues as a configuration record, and confirm build-stage enforcement from the CI Scans inventory.

Investigate a failed build

Open a scan result to determine whether the build failed on policy or on tooling, and what to change.

  1. Confirm the exit code in the pipeline log first. Exit code 1 is a policy decision and the investigation continues in Cortex Cloud. Exit code 2 is an internal, network, or authentication error — the scan did not evaluate the code, and the fix is in the pipeline or the integration rather than in the source.

  2. Select the scan row in the CI Scans inventory. The side panel opens, titled with the repository name and the branch name in parentheses.

  3. Review the Overview tab:

    • Organization, Repository, and Scanned Branch identify the code context of the build.

    • CI Status reports the policy evaluation result that determined the build outcome.

    • Scan Health reports execution health. No Rescan control is present for a CI scan.

    • Scan Date records when the scan started.

    • Issues and Issues By Type report the actionable records by severity and by scanner category.

    • Findings and Findings By Type report the raw detections by severity and by scanner category.

  4. Identify the policy that failed the build, using whichever path matches your access:

    • Pipeline output — The Cortex CLI prints the blocking policy at the point of failure. This is the fastest path, and the only one that requires no Cortex Cloud access.

    • CI scans APIGET /public_api/appsec/v1/scans/ci returns blockingPoliciesNames and blockingPoliciesIds for each scan. Use the API when you hold the scan but not the pipeline log. See Manage scans through public APIs.

  5. Select the issue category tab that matches the detection — Vulnerabilities, Configurations, Secrets, or Package Integrity — then select an issue to open the issue side card, and the Findings tab to review the underlying evidence.

  6. Route the issue to the inventory that owns resolution for the category. See Reference E: Issue category routing.

  7. Re-run the pipeline to confirm the fix. There is no rescan action in the inventory, and no suppression path — a CI scan is re-evaluated only by running the pipeline again against changed code or a changed policy.

Result: The build failure is attributed either to a specific policy and finding, or to a tooling cause, and the correction is directed accordingly.

Important: A build failed by policy and a build failed by a CLI error are different incidents with different owners. Resolving a policy failure means changing the code or the policy; resolving a tooling failure means restoring authentication or connectivity. Use --no-fail-on-crash to keep transient platform errors from failing builds, and accept the trade-off: a crashed scan then permits the build.

Note: A CI scan issue receives no automatic fix pull request and no Urgency classification. Prioritize by severity, and remediate in the branch the pipeline built.

Strengthen the earlier gate after a CI block

A CI block is a successful outcome and a diagnostic signal. Risk stopped at the build stage is risk the merge gate did not stop.

  1. Determine how the finding entered the branch. A finding present in code that no pull request covered indicates a direct-push path; a finding introduced through a merged pull request indicates a gap in the pull request policy set.

  2. Compare the policy that blocked the build against the policies enabled for the PR Scan trigger. Enumerate the policy set from the policy table, which exposes Triggers and Actions columns, or programmatically with GET /public_api/appsec/v1/policies filtered by triggers and actions. A finding type blocked at CI and not at PR is a candidate for earlier enforcement. See Unified Application Security policies.

  3. Extend the corresponding policy to the PR Scan trigger with the Block PR action, so the next occurrence is stopped at merge time rather than at build time. See Unified Application Security policies.

  4. Verify branch protection covers the path that bypassed the merge gate. A finding that arrived by direct push to a protected branch indicates a branch protection gap that no Cortex Cloud policy can close.

Result: The enforcement point moves left, and the same finding pattern is stopped before the merge rather than after it.

Important: Every commit is a new scan and produces a new row in the CI Scans inventory. A count of Blocked rows is therefore a count of blocked commit scans, not a count of blocked pipelines and not a count of repositories. A branch that received five commits and was blocked on three of them contributes three Blocked rows. Any prevention or gate-effectiveness figure taken by counting rows has scans in the numerator — deduplicate before reporting the figure as a count of pipelines or repositories blocked.

TODO — confirm against the shipped product: Confirm whether a pipeline re-run against an unchanged commit appends a new inventory row or replaces the existing row. The new-commit case is confirmed — each commit produces a new scan and a new row — and only the same-commit re-run remains open. The answer determines whether a Blocked row count for a single commit can exceed one.

TODO — confirm against the shipped product: Confirm whether the Blocking Policy column is available in the CI Scans inventory as it is in the Pull Request Scans inventory. The blocking policy is recorded on the CI scan record and returned by the CI scans API, but the column is not confirmed present in the CI Scans column set. Until confirmed, the pipeline output and the CI scans API are the only documented paths from a failed build to a policy name.

TODO — confirm against the shipped product: Confirm whether the Run ID column is populated for CLI-sourced CI scans and whether the value is exposed through the public API, which currently returns no run identifier field. Correlating an inventory row to a specific pipeline run depends on the Run ID field, and — where successive runs build the same unchanged commit — additionally on the residual same-commit re-run question above.

Note: The ERROR and IN_PROGRESS wire values resolve differently in the console. IN_PROGRESS renders as In Progress and is available as a CI Status value. ERROR renders as no CI Status value at all — the console surfaces no Error CI status, and an errored scan reports Error under Scan Health instead. The ERROR wire value nevertheless remains part of the API contract, so automation reading the status field must handle ERROR without assuming a console CI Status counterpart exists for the value. Reconcile automation against Reference D: CI status values and Manage scans through public APIs.

Last updated

Was this helpful?