> For the complete documentation index, see [llms.txt](https://cortex-docs.paloaltonetworks.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://cortex-docs.paloaltonetworks.com/application-security/code-security/application-security-scans-management/manage-scans-through-the-tenant-ui/ci-scans/ci-scan-workflow.md).

# 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.

```mermaid
flowchart TD
    A[Add the Cortex CLI step to the pipeline] --> B[Pipeline runs and the CLI scans the code]
    B --> C{Exit code?}
    C -->|1 - policy match| D[Build fails: investigate the blocking policy]
    C -->|0 - pass| E[Build continues]
    C -->|2 - tooling error| F[Build fails for a non-security cause]
    D --> G[Remediate, or adjust the policy]
    G --> B
    F --> H[Correct authentication or connectivity]
    H --> B
    E --> I{Scan health degraded?}
    I -->|Yes| J[Treat the artifact as ungoverned]
    I -->|No| K[Enforcement confirmed]
```

## 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](/application-security/application-security/onboard-data-sources/integrate-ci-tools/connect-cortex-cli.md). For scanner settings, see [Branch periodic scans](/application-security/code-security/application-security-scans-management/manage-scans-through-the-tenant-ui/branch-periodic-scans.md).

## 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](/application-security/code-security/application-security-scans-management/manage-scans-through-the-tenant-ui/ci-scans/references/reference-b-inventory-columns.md#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](/application-security/code-security/application-security-scans-management/manage-scans-through-the-tenant-ui/ci-scans/references/reference-d-ci-status-values.md). 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](/application-security/software-supply-chain-security/visibililty-and-inventory/supply-chain-assets/cicd-pipeline-as-an-asset.md). 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](/application-security/application-security-posture-management-aspm/applications/defining-business-applications.md).

**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](/application-security/application-security/onboard-data-sources/integrate-ci-tools/connect-cortex-cli.md).

> **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](/application-security/application-security-posture-management-aspm/aspm-command-center.md) 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](/application-security/code-security/api-workflows-for-code-security-issues.md). 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](/application-security/code-security/application-security-scans-management/manage-scans-through-the-tenant-ui/ci-scans/references/reference-b-inventory-columns.md).

> **Note:** Coverage gaps can be tracked as issues rather than as a manual list. The [Coverage](/application-security/application-security-posture-management-aspm/coverage.md) 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 API** — `GET /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](/application-security/code-security/application-security-scans-management/manage-scans-through-public-apis.md).
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](/application-security/code-security/application-security-scans-management/manage-scans-through-the-tenant-ui/ci-scans/references/reference-e-issue-category-routing.md).
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](/application-security/application-security-posture-management-aspm/unified-application-security-policies.md).
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](/application-security/application-security-posture-management-aspm/unified-application-security-policies.md).
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](/application-security/code-security/application-security-scans-management/manage-scans-through-the-tenant-ui/ci-scans/references/reference-d-ci-status-values.md) and [Manage scans through public APIs](/application-security/code-security/application-security-scans-management/manage-scans-through-public-apis.md).


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://cortex-docs.paloaltonetworks.com/application-security/code-security/application-security-scans-management/manage-scans-through-the-tenant-ui/ci-scans/ci-scan-workflow.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
