> For the complete documentation index, see [llms.txt](https://docs.xygeni.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.xygeni.io/xygeni-products/application-security-posture-management-aspm/importing-reports-from-3rd-party-tools/pull-mode-fetch.md).

# Pull-mode fetch

Pull mode lets the Xygeni scanner call a third-party tool's API directly, fetch the findings, and route them through the same loader+converter pipeline that processes file uploads. No intermediate report file on disk; credentials read from environment variables; resolved auth headers and tokens redacted from logs.

When you'd use it over [convert+upload](/xygeni-products/application-security-posture-management-aspm/importing-reports-from-3rd-party-tools.md#report_upload):

* The tool exposes a documented findings API and your pipeline doesn't already collect a report file.
* You'd rather not stage credentials inside a CI artifact or a checked-in JSON.
* You want one CLI invocation to drive both the fetch and the conversion.

When **not** to use it:

* The tool only writes to disk — keep using convert+upload.
* The tool actively pushes to consumers — see the [push (webhook) mode](/xygeni-products/application-security-posture-management-aspm/importing-reports-from-3rd-party-tools.md#the-three-ingestion-modes); the per-adapter setup guide will be added to this section as each webhook integration ships.

## How to invoke

```bash
xygeni report-upload --pull --format <id> \
  --selector key=value [--selector ...] \
  --filter  key=value [--filter ...] \
  [--name <project>] [--no-upload] [--output <path>]
```

* `--pull` switches the command from reading `--report` files to fetching from the API.
* `--format` (exactly one) selects the registry entry; the entry must declare a `pull:` block (i.e. one of the formats listed below).
* `--selector` carries **per-scan identifiers** the tool needs — project key, branch, application name, organization, scan id, tenant. Always required for tools that scope findings to a project.
* `--filter` carries **tool-specific findings filters** — severity, status, time window, cloud platform. Optional; each fetcher documents its own filter keys.
* `--no-upload` runs the fetch + conversion but skips the upload to Xygeni. Pair with `--output <file>` to inspect the converted payload before wiring the command into CI.

## Credentials and environment variables

Each tool reads its credentials from environment variables. The scanner refuses to start if a referenced variable is unset (fail-closed); it never embeds the resolved secret into the converted output; and it registers the resolved value with the log redactor so any subsequent log line that would print it shows `***` instead.

The naming convention is `<TOOL>_URL`, `<TOOL>_TOKEN` / `<TOOL>_CLIENT_ID` / `<TOOL>_CLIENT_SECRET`, etc. — the exact set is listed per-tool below.

{% hint style="info" %}
You can also pass `-Dname=value` on the Java command line as a fall-through when an environment variable can't be exported (e.g. some containerised runners). The framework checks env vars first, then Java system properties.
{% endhint %}

## Worked examples per tool

### SonarQube / SonarCloud

Two registry entries — `sast-sonarcloud` (bearer-token auth) and `sast-sonarqube` (basic auth with the API token as the username and an empty password, per SonarQube Server's traditional auth scheme).

**SonarCloud**

```bash
export SONARCLOUD_URL=https://sonarcloud.io
export SONARCLOUD_TOKEN=squ_xxxxxxxxxxxxxxxxxxxxxxxxxx

xygeni report-upload --name MyApp --pull \
  -f sast-sonarcloud \
  --selector project_key=acme/web \
  --selector branch=main \
  --selector organization=acme            # SonarCloud only; required for org-scoped projects
```

**SonarQube Server**

```bash
export SONARQUBE_URL=https://sonarqube.internal.example.com
export SONARQUBE_TOKEN=sq-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

xygeni report-upload --name MyApp --pull \
  -f sast-sonarqube \
  --selector project_key=acme:web \
  --selector branch=main
```

Both invocations pull security issues from `/api/issues/search` and security hotspots from `/api/hotspots/search`, merge and deduplicate, and write a single document in the same shape the existing `sast-sonarqube` / `sast-sonarcloud` loaders consume for file uploads. Pagination, retry/backoff and log redaction are handled by the framework.

| Selector       | Required | Notes                              |
| -------------- | :------: | ---------------------------------- |
| `project_key`  |    yes   | SonarQube / SonarCloud project key |
| `branch`       |    no    | Branch analysis to query           |
| `pullRequest`  |    no    | PR analysis id                     |
| `organization` |    no    | SonarCloud only                    |

| Filter     | Notes                                                                                                                                                           |
| ---------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `severity` | Comma-separated severities (e.g. `HIGH,CRITICAL`). Applied to issues; hotspots use a different vulnerability-probability filter that isn't currently forwarded. |
| `status`   | Comma-separated for issues. Hotspots accept only `TO_REVIEW` / `REVIEWED` — when multiple values are supplied, only the first is forwarded to that endpoint.    |

### Kiuwan

Two registry entries:

* `sast-kiuwan` — **file upload** of the XML report produced by the Kiuwan Local Analyzer custom `ExportRule`. Documented in the [Report upload for Kiuwan](/xygeni-products/application-security-posture-management-aspm/importing-reports-from-3rd-party-tools/external-scanners-supported/report-upload-for-kiuwan.md) page; recommended only if you already have that pipeline set up.
* `sast-kiuwan-api` — **pull mode**, calling Kiuwan's native REST API. **Recommended for new integrations**: no Kiuwan-side install, no Local Analyzer custom rule, no quality-model edits. Carries source/sink data-flow detail that SARIF / CSV exports drop.

```bash
export KIUWAN_URL=https://api.kiuwan.com              # SaaS; on-prem tenants use their own URL
export KIUWAN_USER=<your Kiuwan API user code>
export KIUWAN_TOKEN=<your Kiuwan API token>

xygeni report-upload --name MyApp --pull \
  -f sast-kiuwan-api \
  --selector application='My Application'
```

With an explicit analysis + filters:

```bash
xygeni report-upload --name MyApp --pull \
  -f sast-kiuwan-api \
  --selector application='My Application' \
  --selector analysisCode=A-1234567890123 \
  --filter priority='High,Very high'
```

| Selector       | Required | Notes                                                                     |
| -------------- | :------: | ------------------------------------------------------------------------- |
| `application`  |    yes   | Kiuwan application name                                                   |
| `analysisCode` |    no    | Specific scan to fetch. Default: result of `/applications/last_analysis`. |

| Filter           | Notes                                                                                             |
| ---------------- | ------------------------------------------------------------------------------------------------- |
| `priority`       | Comma-separated. `Very low,Low,Normal,High,Very high`.                                            |
| `characteristic` | Comma-separated. Defaults to `Security` (SAST scope); pass to widen, e.g. `Security,Reliability`. |
| `language`       | Comma-separated tool-defined language list (e.g. `java,javascript`).                              |
| `muted`          | `true` / `false`.                                                                                 |

Auth is HTTP Basic with the Kiuwan API user code as the username and the token as the password.

### Checkmarx One — SAST + SCA + IaC

Pull mode is wired on **three** registry entries — `sast-checkmarx-one`, `sca-checkmarx-one`, `iac-checkmarx-one`. They share a single fetcher; Checkmarx One's `/api/results` endpoint returns all three engines' findings in one document and each entry's converter slices its own engine out.

```bash
export CHECKMARX_URL=https://ast.checkmarx.net          # SaaS regions: ast / eu.ast / anz.ast / etc.
export CHECKMARX_CLIENT_ID=<OAuth2 client id>
export CHECKMARX_CLIENT_SECRET=<OAuth2 client secret>

# SAST findings:
xygeni report-upload --pull -f sast-checkmarx-one \
  --selector tenant=acme --selector project_name='My App'

# SCA findings (same project, refetched independently):
xygeni report-upload --pull -f sca-checkmarx-one \
  --selector tenant=acme --selector project_name='My App'

# IaC (KICS) findings:
xygeni report-upload --pull -f iac-checkmarx-one \
  --selector tenant=acme --selector project_name='My App'
```

With an explicit scan + filters:

```bash
xygeni report-upload --pull -f sast-checkmarx-one \
  --selector tenant=acme \
  --selector project_id=11111111-2222-3333-4444-555555555555 \
  --selector scan_id=99999999-8888-7777-6666-555555555555 \
  --filter severity='HIGH,MEDIUM'
```

| Selector       | Required | Notes                                                                      |
| -------------- | :------: | -------------------------------------------------------------------------- |
| `tenant`       |    yes   | Checkmarx One tenant name; interpolated into the OAuth2 token endpoint URL |
| `project_id`   |  one of  | UUID of the Checkmarx One project                                          |
| `project_name` |  one of  | Human-readable name; resolved to `project_id` via `/api/projects?name=…`   |
| `scan_id`      |    no    | Specific scan to fetch. Default: latest scan for the project.              |

| Filter     | Notes                                                              |
| ---------- | ------------------------------------------------------------------ |
| `severity` | Comma-separated `HIGH,MEDIUM,LOW,INFO`                             |
| `state`    | Result state enum (`TO_VERIFY`, `NOT_EXPLOITABLE`, `CONFIRMED`, …) |
| `status`   | `NEW`, `RECURRENT`, `FIXED`                                        |

Auth: OAuth2 client credentials. The framework caches the access token by its declared `expires_in` and refreshes it automatically.

### Prisma Cloud — CSPM alerts + asset inventory

Two registry entries — `iac-prisma-cloud` (CSPM security alerts / policy violations) and `inventory-prisma-cloud` (cloud asset inventory). One fetcher drives both; each entry picks its endpoint internally.

```bash
export PRISMACLOUD_URL=https://api.prismacloud.io            # api.eu.prismacloud.io, api.anz.prismacloud.io, …
export PRISMACLOUD_ACCESS_KEY=<access key>
export PRISMACLOUD_SECRET_KEY=<secret key>

# Security alerts (CSPM policy violations):
xygeni report-upload --pull -f iac-prisma-cloud

# Cloud asset inventory:
xygeni report-upload --pull -f inventory-prisma-cloud
```

With filters:

```bash
xygeni report-upload --pull -f iac-prisma-cloud \
  --filter status=open \
  --filter severity=critical,high \
  --filter cloud=aws,azure \
  --filter time_range_days=7
```

| Filter               | Applies to | Notes                                                                                                                                                                             |
| -------------------- | ---------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `time_range_days`    | both       | Window length. Default `30` for alerts, `1` for inventory.                                                                                                                        |
| `cloud`              | both       | Comma-separated cloud providers (`aws`, `azure`, `gcp`, `alibaba_cloud`, `oci`).                                                                                                  |
| `status`             | alerts     | Single value: `open`, `dismissed`, `resolved`, `snoozed`. Default `open`.                                                                                                         |
| `severity`           | alerts     | Comma-separated `critical,high,medium,low,informational`.                                                                                                                         |
| `resource_type`      | inventory  | Comma-separated resource types (e.g. `aws_ec2_instance,gcp_compute_instance`).                                                                                                    |
| `rql`                | inventory  | Raw RQL query used verbatim (escape hatch — disables the `cloud` / `resource_type` composition). Example: `--filter rql="config from cloud.resource where finding.type = 'CVE'"`. |
| `with_resource_json` | inventory  | `true` (default) embeds the full provider-specific resource JSON in each item; set to `false` for a leaner payload.                                                               |

Inventory uses Prisma Cloud's [RQL (Resource Query Language)](https://docs.prismacloud.io/en/enterprise-edition/content-collections/search-and-investigate/rql-reference/rql-reference). Auth is handled by the fetcher (POST `/login` for an `x-redlock-auth` token; transparent re-auth on 401); the registry declares `auth.type: basic` only to flow the access key + secret key through env-var resolution and log redaction.

### Wiz CNAPP

Four registry entries — `iac-wiz-issues`, `sca-wiz-cnapp`, `iac-wiz-config`, `inventory-wiz-cnapp`. A single fetcher drives all four via per-entry `selectorDefaults.mode`. Wiz is the first GraphQL fetcher in the pull framework; the GraphQL endpoint and OAuth2 token URL are both configurable so any region (US / EU / Gov) works without code changes.

```bash
export WIZ_API_URL=https://api.us1.app.wiz.io/graphql              # full GraphQL endpoint
export WIZ_CLIENT_ID=<service-account client id>
export WIZ_CLIENT_SECRET=<service-account client secret>
# Optional — defaults to Cognito; legacy Auth0 tenants use https://auth.wiz.io/oauth/token
# export WIZ_TOKEN_URL=https://auth.app.wiz.io/oauth/token

# Issues (Toxic Combinations, Threats, Cloud Misconfigurations):
xygeni report-upload --pull -f iac-wiz-issues

# CVEs detected on cloud workloads:
xygeni report-upload --pull -f sca-wiz-cnapp --filter severity=CRITICAL,HIGH

# CSPM policy violations:
xygeni report-upload --pull -f iac-wiz-config --filter result=FAIL,ERROR

# Cloud asset inventory:
xygeni report-upload --pull -f inventory-wiz-cnapp --filter cloud_platform=AWS
```

| Filter           | Applies to                                  | Notes                                                                                                                    |
| ---------------- | ------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------ |
| `status`         | issues / vulnerabilities / config\_findings | Filtering the resolution state                                                                                           |
| `severity`       | issues / vulnerabilities / config\_findings | Wiz severity enum. The fetcher remaps the filter key to `vendorSeverity` for the vulnerabilities mode (Wiz schema quirk) |
| `type`           | issues / cloud\_resources                   | Issue category for issues; Wiz resource type for inventory                                                               |
| `result`         | config\_findings                            | `FAIL`, `ERROR`                                                                                                          |
| `cloud_platform` | cloud\_resources                            | `AWS`, `AZURE`, `GCP`, …                                                                                                 |
| `page_size`      | all                                         | Page size — clamped to Wiz's documented 500 max                                                                          |

Auth: OAuth2 client credentials with the `audience=wiz-api` claim. The framework caches the access token by `expires_in` and refreshes it automatically; the token URL is configurable so the same registry entry works against both Cognito-backed and legacy Auth0-backed Wiz tenants.

### Prowler

Two registry entries — `iac-prowler` (check results) and `inventory-prowler` (cloud asset inventory). One fetcher drives both; each entry picks its endpoint internally.

Prowler authenticates with a long-lived API key, so there is no login step and no token to refresh. Point `PROWLER_API_URL` at Prowler Cloud or at your own deployment.

```bash
export PROWLER_API_URL=https://api.prowler.com/api/v1     # or your self-hosted API
export PROWLER_API_KEY=<your API key>

# Check results (cloud misconfigurations):
xygeni report-upload --pull -f iac-prowler

# Cloud asset inventory:
xygeni report-upload --pull -f inventory-prowler
```

With filters:

```bash
xygeni report-upload --pull -f iac-prowler \
  --filter severity=critical,high \
  --filter provider_type=aws,azure \
  --filter updated_after=2026-09-01T00:00:00Z
```

| Filter                      | Applies to | Notes                                                                             |
| --------------------------- | ---------- | --------------------------------------------------------------------------------- |
| `lookback_days`             | findings   | How far back to look. Default `30`, and used only when `updated_after` is absent. |
| `updated_after`             | both       | ISO-8601 timestamp. Replaces the look-back window.                                |
| `status`                    | findings   | `FAIL`, `PASS`, `MANUAL`. Only failed checks are converted into findings.         |
| `severity`                  | findings   | Comma-separated `critical,high,medium,low,informational`.                         |
| `delta`                     | findings   | `new`, `changed` — restricts to findings that changed in the last scan.           |
| `provider_type`             | both       | `aws`, `azure`, `gcp`, `kubernetes`, `m365`, `github`.                            |
| `region`, `service`, `type` | inventory  | Narrow the inventory by location, service or resource type.                       |
| `page_size`                 | both       | Page size. Default `100`, capped at `1000`.                                       |

Prowler's findings API requires a time window, so the fetcher always sends one — the 30-day look-back applies unless you give `updated_after`. For a daily job, pass the timestamp of the previous run.

Note Prowler is not limited to cloud accounts: Kubernetes, Microsoft 365 and GitHub scans arrive through the same two entries.

Auth: an API key sent as `Authorization: Api-Key <key>`. Create it in Prowler under **API keys**; read access to findings and resources is enough.

### Bright Security (Bright DAST)

One registry entry — `dast-brightsec`. It pulls findings from Bright's REST API (`GET /api/v1/scans/{id}/issues`) and normalises them to the Xygeni DAST report. Bright's API is **regional**, so set `BRIGHTSEC_URL` to your cluster (e.g. `https://eu.brightsec.com` or `https://app.brightsec.com`). Auth is `Authorization: Api-Key <token>` — a personal, project, or organization API key works.

**Required API key scopes** (least-privilege, read-only): `user` (mandatory for API authorization), `projects:read`, `scans:read`, and `issues:read`. The integration only *reads* completed scans — it never runs, edits, or deletes anything in Bright, so no `scans:run` / `*:write` / `auth-objects` scopes are needed. If your organization restricts visibility, you may also need `org:read`.

```bash
export BRIGHTSEC_URL=https://eu.brightsec.com          # your Bright regional cluster
export BRIGHTSEC_TOKEN=<your Bright API key>

# By scan id (from the scan URL or the API):
xygeni report-upload --name MyApp --pull \
  -f dast-brightsec \
  --selector scan_id=iQ6pnfbHBNZqeVcRvob9CT

# By project + scan name (resolves the latest COMPLETED scan with that name in that project):
xygeni report-upload --name MyApp --pull \
  -f dast-brightsec \
  --selector project='My Project' \
  --selector scan='Nightly authenticated scan'
```

The fetcher accepts only a scan in the **completed** (`done`) state — a running or stopped scan is rejected, so a partial finding set is never uploaded. It composes the scan and project metadata with the issues, so the report carries the scan target, timing, statistics, and the Bright project name.

| Selector           | Required | Notes                                                                                                                                                                                             |
| ------------------ | :------: | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `scan_id`          |  one of  | A Bright scan id.                                                                                                                                                                                 |
| `project` + `scan` |  one of  | Bright **project name** and **scan name**; resolves the latest completed scan with that name. An application often has several scans (different navigations / use cases) — name the one you want. |

No tool-specific `--filter` keys.

{% hint style="info" %}
**Branch.** Bright DAST findings have no VCS branch. When you don't pass `--branch`, the upload uses `unknown`.

**Project name.** With no `--name`, the Xygeni project is taken from the Bright **project name**.
{% endhint %}

{% hint style="warning" %}
**File alternative (reduced).** You can upload a saved API issues file — the JSON from `GET /api/v1/scans/{id}/issues` — with `-f dast-brightsec -r issues.json`. The findings are complete, but a bare file carries **no scan/project metadata or statistics** (the scanner logs a warning); use pull mode for a full report. The Bright **UI "summary export"** is *not* supported — it lacks the target URL and HTTP request/response evidence, and the loader rejects it with guidance to use pull mode or the `/issues` JSON.
{% endhint %}

## Dry-run and inspecting the converted payload

Before wiring the command into CI, run it once with `--no-upload --output <path>` to inspect the converted JSON:

```bash
xygeni report-upload --pull -f sast-sonarcloud \
  --selector project_key=acme/web --selector branch=main \
  --no-upload --output /tmp/sonarcloud-converted.json
```

The output file holds the same payload that would have been uploaded — useful for verifying severity mapping, project name inference, or filter coverage.

## Troubleshooting

**"No value for `${env:X}` — set the Java system property `-DX=…` or export the env var X"** The scanner refuses to run with an unresolved secret. Export the variable in the same shell that invokes `xygeni`, or pass `-DX=value` on the Java command line if your runner can't export environment variables.

**"Format '' has no pull: block configured"** The format you passed to `-f` exists as a convert+upload entry but doesn't yet support pull mode. Either drop `--pull` and supply `--report`, or pick a format from the supported list above.

**"--pull requires exactly one --format"** Pull mode takes one format per invocation. If you need to fetch from multiple tools, issue multiple commands.

**HTTP 401 / 403** The token doesn't have permission for the resource you asked for. The error message includes the path that failed — verify the project key / scan id / tenant against the tool's UI, and check the token's scope.

**Retries exhausted** The fetcher retries transient failures (HTTP 5xx, network errors) with exponential backoff. If retries exhaust, the tool's API is likely down — check the tool's status page and rerun. Pull mode is idempotent; re-invoking after a transient failure is safe.


---

# 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 by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.xygeni.io/xygeni-products/application-security-posture-management-aspm/importing-reports-from-3rd-party-tools/pull-mode-fetch.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

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.
