> For the complete documentation index, see [llms.txt](https://docs.firefly.ai/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.firefly.ai/detailed-guides/workflows/wiz-policy-integration.md).

# Wiz Policy Integration

> **Related Guides and Examples:**
>
> * [Overview: Firefly Workflows and Guardrails](/detailed-guides/workflows.md): High-level concepts and options.
> * [Creating Guardrail Rules in Firefly](/detailed-guides/workflows/creating-guardrail-rules.md): How to define and enforce Firefly's own policies and best practices.
> * [Creating Variable Sets](/detailed-guides/workflows/creating-variable-sets.md): Managing reusable variable collections, including the `Wiz Policy Integration Authentication` template.
> * [Creating New Firefly Workflows](/detailed-guides/workflows/creating-workflows.md): How to set up managed workflows.
> * [Integrating Existing CI/CD Pipelines with Firefly Workflows](/integrations/workflows.md): Setting up `fireflyci` in your own pipeline.

Firefly can delegate Infrastructure-as-Code policy evaluation to [Wiz](https://www.wiz.io/). When a workspace resolves Wiz credentials, its runs are scanned by Wiz instead of by Firefly's built-in policy engine, and the run is blocked if Wiz returns a failing verdict.

This is intended for organizations that already treat Wiz as the authority for cloud security policy and want the same policies enforced at the IaC level, before infrastructure is applied — without maintaining a parallel policy set in Firefly.

Wiz remains the policy authority throughout. Firefly does not interpret Wiz rules, choose which Wiz policies run, or remap Wiz verdicts into its own vocabulary. It runs the scan, presents the result verbatim, and enforces the outcome.

## How It Works

For a Wiz-integrated workspace, a run proceeds through the following stages:

1. **Checking Integrations:** Before `init`, Firefly validates the Wiz connection using the resolved credentials. The run displays a dedicated **Checking Integrations** status while this happens. If validation fails, the run stops with **Init Failed**.
2. **Init and Plan:** `terraform init` and `terraform plan` (or the OpenTofu/Terragrunt equivalents) run as usual.
3. **Wiz Scan:** After `plan`, the plan is exported to JSON and scanned by Wiz. The scan is plan-aware — Wiz evaluates the changes the plan will make, not just the static configuration.
4. **Guardrails Step:** Wiz results are displayed alongside any Firefly custom policy results.
5. **Gate:** If Wiz returns a failing verdict, the run is blocked before `apply`. Otherwise it proceeds to `apply` (or awaits approval, per your existing workflow configuration).

### What Changes for an Integrated Workspace

| Scan type                     | Behavior                                                                                                |
| ----------------------------- | ------------------------------------------------------------------------------------------------------- |
| Wiz scan                      | **Runs.** Blocking on the Wiz verdict.                                                                  |
| Firefly built-in policy scans | **Skipped.** Wiz is the policy authority.                                                               |
| Kicks scans                   | **Skipped.**                                                                                            |
| Firefly custom policy scans   | **Runs.** Reported but non-blocking, unless the policy's Violation Behavior is set to **Strict Block**. |

Workspaces that do not resolve Wiz credentials are entirely unaffected — kicks and built-in policy scans run exactly as before.

### Execution Models

The integration supports two execution models. Both use the same Wiz scan output, the same blocking rules, and the same UI. They differ in who runs the Wiz CLI:

* **Firefly-managed workspaces.** Firefly provisions the Wiz CLI, authenticates, runs the scan, and enforces the gate. See [Setting Up for Firefly-Managed Workspaces](#setting-up-for-firefly-managed-workspaces).
* **Your existing CI/CD pipeline.** Your pipeline owns and runs the Wiz CLI, then hands the scan result to Firefly through `fireflyci`. See [Setting Up in an Existing CI/CD Pipeline](#setting-up-in-an-existing-cicd-pipeline).

## Prerequisites

* **A Wiz tenant** with IaC scanning enabled.
* **A Wiz OAuth2 service account.** Create a service account in the Wiz portal and record its **Client ID** and **Client Secret**. The service account only needs **read-only** permissions — it scans, it does not modify your Wiz tenant.
* **Network egress to Wiz.** Whatever environment runs the scan needs outbound HTTPS access to the Wiz authentication and API hosts (`auth.app.wiz.io` and `api.*.wiz.io`, or their GovCloud/FedRAMP equivalents). For Firefly-managed runs this applies to Firefly's runners; if you use a [self-hosted runner pool](/detailed-guides/workflows/creating-self-hosted-runner.md), ensure your network policy allows it.
* **Linux amd64 or arm64 runners.** The Wiz CLI is distributed only as a Linux amd64/arm64 binary. This constrains self-hosted runner pools used for Wiz-integrated workspaces, and your CI/CD job images in the pipeline model.

## Setting Up for Firefly-Managed Workspaces

Wiz is enabled through a variable set. There is **no separate enable toggle** — a workspace becomes Wiz-integrated as soon as `WIZ_CLIENT_ID` and `WIZ_CLIENT_SECRET` resolve for it, whether directly or through inheritance.

### Step 1: Create the Variable Set

1. In the Firefly UI, navigate to **Workflows > Projects & Variables**.
2. Click **+ Create new variable set**.
3. Select the **`Wiz Policy Integration Authentication`** template. This pre-populates the set with the three Wiz variables.
4. Give the set a name and, optionally, assign it to specific projects to control which workspaces can consume it.
5. Fill in the variable values:

| Variable            | Description                                                                                                      | Required |
| ------------------- | ---------------------------------------------------------------------------------------------------------------- | -------- |
| `WIZ_CLIENT_ID`     | The OAuth2 service account client ID from the Wiz portal.                                                        | Yes      |
| `WIZ_CLIENT_SECRET` | The OAuth2 service account client secret. Must be marked **Sensitive**.                                          | Yes      |
| `WIZ_ENV`           | Set to `gov` for Wiz GovCloud (`gov.wiz.io`) or `fedramp` for Wiz FedRAMP (`app.wiz.us`). Omit for standard Wiz. | No       |

6. Click **Create**.

`WIZ_CLIENT_SECRET` is held in Firefly's secret store and encrypted at rest. It is never written to logs, API responses, or run output.

For full details on creating and managing variable sets, see [Creating Variable Sets](/detailed-guides/workflows/creating-variable-sets.md).

### Step 2: Consume the Variable Set at the Right Scope

The Wiz variable set can be consumed at **Organization**, **Project**, or **Workspace** scope, and standard variable inheritance applies — a more specific scope overrides a broader one. This determines how widely the integration takes effect:

* **Organization Variables:** every workspace in the organization becomes Wiz-integrated.
* **Project:** all workspaces in that project and its sub-projects become Wiz-integrated.
* **Workspace:** only that workspace becomes Wiz-integrated.

Consuming at organization scope is the most direct way to make Wiz the policy authority everywhere. Consuming at project or workspace scope lets you roll the integration out incrementally, or keep it scoped to the environments that need it.

### Step 3: Verify

Open the workspace and check the **Workspace Summary**. A Wiz-integrated workspace displays a **Wiz Integrations** indication confirming the connection.

The indication reports only that the workspace is integrated. It does not list policies — those live in your Wiz tenant and are not known to Firefly.

Then trigger a run. A correctly configured workspace passes through the **Checking Integrations** status and reaches the Guardrails step with Wiz results present.

## Setting Up in an Existing CI/CD Pipeline

In this model your pipeline runs the Wiz CLI and passes the result to Firefly. Firefly ingests, persists, gates on, and displays the result, but does not run the scan itself. There is no pre-init connection check in this model and no **Checking Integrations** status — validating that Wiz is reachable is your pipeline's responsibility.

This section assumes you already have `fireflyci` integrated into your pipeline. If you don't, set that up first — see [Integrating Existing CI/CD Pipelines with Firefly Workflows](/integrations/workflows.md).

> **Verified versions:** The steps below were verified end-to-end on a live GitLab CI pipeline using `fireflyci` v0.6.26 and Wiz CLI 0.109.16. The `--wiz-scan-file` flag requires `fireflyci` v0.6.26 or later.

Add the following three steps to the job that runs your plan, before your `fireflyci post-plan` step.

### Step 1: Install the Wiz CLI

Pin the version and verify the checksum rather than tracking `latest`, so a Wiz-side release cannot change your gate's behavior mid-pipeline:

```sh
WIZCLI_VERSION=0.109.16
WIZCLI_SHA256=29284fdc93e09ae2108cf06c0206b4be8eaff2a2280eecf2422209787a7d451d

curl -fsSL -o wizcli "https://downloads.wiz.io/wizcli/${WIZCLI_VERSION}/wizcli-linux-amd64"
echo "${WIZCLI_SHA256}  wizcli" | sha256sum -c -
chmod a+x wizcli && ln -s "$(pwd)/wizcli" /usr/local/bin/wizcli
```

Version `0.109.16` is the version Firefly pins in its own runner image.

> **Note:** The SHA256 above is specific to version `0.109.16` of the `linux-amd64` binary. If you bump `WIZCLI_VERSION`, you must update `WIZCLI_SHA256` to match, or `sha256sum -c` will fail the job. Obtain the checksum for a different version or architecture from Wiz.

### Step 2: Authenticate

```sh
export WIZ_DIR="$CI_PROJECT_DIR/.wiz-$CI_JOB_ID"
mkdir -p "$WIZ_DIR"
wizcli auth
```

Two details matter here:

* **Pass credentials through the environment, not as flags.** `wizcli auth` reads `WIZ_CLIENT_ID` and `WIZ_CLIENT_SECRET` (and optionally `WIZ_ENV`) directly from the environment. The `--id` and `--secret` flags exist but should not be used: command-line arguments are visible to any process on the host through `/proc/<pid>/cmdline` and `ps`, which exposes your Wiz secret to anything else sharing the runner. Store the credentials as masked/protected CI/CD variables instead.
* **Set a per-job `WIZ_DIR`.** The Wiz CLI writes its authentication token into `WIZ_DIR`. If several jobs share a runner and share the default location — which is exactly what happens in a pipeline that fans out one job per module — they will overwrite each other's token, and jobs will fail to authenticate intermittently. Deriving `WIZ_DIR` from the job ID, as above, isolates them.

### Step 3: Scan and Pass the Result to Firefly

Run the scan after `terraform plan`, then point `fireflyci post-plan` at the resulting file:

```sh
rm -f "$PWD/wiz_scan.json"
wizcli iac scan --path . -f json -o "$PWD/wiz_scan.json,json" --name "${CI_PROJECT_NAME}-${CI_JOB_ID}"

fireflyci post-plan \
  -l plan_log.json \
  -f plan.json \
  --plan-output-raw-log-file plan_output_raw.log \
  -w "<YOUR_UNIQUE_WORKSPACE_NAME>" \
  --wiz-scan-file "$PWD/wiz_scan.json"
```

* `rm -f` clears any stale result from a previous run in a reused workspace directory, so a failed scan cannot be silently gated on an old passing result.
* `--name` gives the scan a label in the Wiz dashboard. Use something unique per run so scans are traceable.
* `--wiz-scan-file` is the flag that hands the result to Firefly. If `post-plan` determines the run should be blocked, it exits non-zero, which stops your pipeline before `apply`.

> **Important: `-o "$PWD/wiz_scan.json,json"` must be written exactly as shown.** Both halves of that value are load-bearing, and both fail silently if you get them wrong.
>
> **The `,json` suffix is what makes the file JSON.** The output file's format is set by `-o` itself, not by `-f`. The `-f json` flag only controls how results are styled on stdout. A bare `-o wiz_scan.json` writes a human-readable report instead: Firefly parses it as zero coverage, discards it, and then fail-closed blocks the run. The result is that **every** run is blocked, and nothing in the error message points at the flag that caused it.
>
> **The path must be absolute.** A relative path is resolved against the working directory of whichever command is using it, and `post-plan` may not share the scan's working directory. Any pipeline that `cd`s into a module directory — which every per-module pipeline does — will have the two diverge, and the run will be blocked with `expected a valid Wiz scan result and did not receive one`. Using `$PWD` keeps the path absolute and unambiguous.

### Step 4: Report the Apply

Your existing `fireflyci post-apply` step needs no Wiz-specific changes. It continues to report apply results to Firefly for visibility.

### Limits of Enforcement in This Model

Firefly can only gate a run it is told about. If a pipeline never invokes `fireflyci post-plan`, or invokes it but ignores its exit code, the `apply` will proceed regardless of the Wiz verdict.

This is a weaker guarantee than the Firefly-managed model, where Firefly controls the run end to end. If your requirement is that a failing Wiz verdict can never be bypassed, use Firefly-managed workspaces, or protect the pipeline definition itself so the `fireflyci` step cannot be removed.

## Understanding Wiz Results in the Guardrails Step

Open a run and select the **Guardrails** step. For a Wiz-integrated workspace it shows a **Wiz policies** panel, with a green **Connected** chip confirming the integration is active.

### Overall Verdict

Wiz returns a single verdict for the scan, which Firefly displays verbatim without remapping:

| Verdict            | Meaning                                                     | Blocks the run? |
| ------------------ | ----------------------------------------------------------- | --------------- |
| `PASSED_BY_POLICY` | No policy failures.                                         | No              |
| `WARN_BY_POLICY`   | Findings exist, but not at a level Wiz treats as a failure. | No              |
| `FAILED_BY_POLICY` | At least one Wiz policy failed.                             | **Yes**         |

### Per-Policy Breakdown

Beneath the overall verdict is one row per policy Wiz evaluated, each with a result indicator, a severity, and the verdict Wiz returned:

* **Red ✕ — `Failed by Policy`:** a hard failure. This blocks the run.
* **Amber ⚠ — `Passed`:** a soft failure. The policy flagged something, but the Wiz verdict still passed, so this is informational and does not block. This is the `WARN_BY_POLICY` case.
* **Green ✓ — `Passed`:** no findings.

When any policy shows `Failed by Policy`, the **Apply** action is disabled and marked with a lock badge.

### Findings

Individual findings are listed below the policy breakdown:

* **Rule matches:** the rule name plus the location in your configuration, as `fileName:lineNumber`.
* **Secrets:** any secrets Wiz detected in the scanned configuration, with their type and location.
* **Report link:** a deep link to the full report in the Wiz dashboard, for the complete detail Wiz holds on the scan.

A scan with no findings at all is a valid, successful result — not an error.

### Firefly Custom Policy Results

Firefly custom policy results appear in the same Guardrails step, alongside the Wiz results. Both are shown because a run can be blocked by either a Wiz `FAILED_BY_POLICY` verdict or a Firefly custom policy set to **Strict Block**, and you need to see which one caused it. A blocked run is always attributable to the specific policy that blocked it.

## What Blocks a Run

A run is blocked before `apply` if any of the following is true:

* **Wiz returns `FAILED_BY_POLICY`.**
* **A Firefly custom policy with Violation Behavior = Strict Block is violated.** See [Creating Guardrail Rules](/detailed-guides/workflows/creating-guardrail-rules.md).
* **The Wiz scan cannot be completed.** If the connection check passed but the scan then crashes, exits non-zero, cannot reach Wiz, or returns malformed output, the run is blocked.
* **No valid Wiz result is available.** In the CI/CD model, if the pipeline sends no scan result, or sends one that is empty, malformed, or in the wrong format, the run is blocked with an error stating that a valid Wiz result was expected and not received.

These last two are deliberate: this is a security gate, so it **fails closed**. A scan that errors is never treated as a scan that passed.

`WARN_BY_POLICY` and `PASSED_BY_POLICY` do not block, and neither does a violated custom policy that is not set to Strict Block.

## Limitations and Considerations

* **Firefly does not control which Wiz policies run.** Policy selection is entirely a function of your Wiz tenant configuration. This is intentional: it means policy changes you make in Wiz take effect on Firefly runs immediately, with no corresponding change in Firefly. It also means Firefly cannot scope, exclude, or threshold Wiz policies for a particular workspace — do that in Wiz.
* **Severity thresholds are not configurable in Firefly.** Firefly blocks on the verdict Wiz returns. If you want severity-based gating, configure it in your Wiz policies.
* **Built-in Firefly policy scans and kicks scans are skipped** for integrated workspaces. If you rely on specific Firefly built-in policies today, reproduce them as Wiz policies or as Firefly custom policies before enabling the integration.
* **The Wiz CLI is Linux amd64/arm64 only**, which constrains self-hosted runner pools and CI/CD job images.
* **Enabling is implicit.** Because resolved credentials are the trigger, consuming the Wiz variable set at organization scope silently changes scan behavior for every workspace in the organization. Roll out at project or workspace scope first if you want to stage the change.

## Troubleshooting

| Symptom                                                                                                                          | Likely cause                                                                                                 | Resolution                                                                                                                                                                                                                                 |
| -------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| Run fails at **Checking Integrations** with **Init Failed**                                                                      | Invalid or missing credentials, or Wiz is unreachable.                                                       | Verify `WIZ_CLIENT_ID` and `WIZ_CLIENT_SECRET` resolve for the workspace and are correct. If you use Wiz GovCloud or FedRAMP, confirm `WIZ_ENV` is set to `gov` or `fedramp`. Confirm the runner has egress to the Wiz auth and API hosts. |
| **Init Failed** with no Wiz output at all                                                                                        | The Wiz CLI binary could not be provisioned on the runner.                                                   | Confirm the runner can reach `downloads.wiz.io`, and that a self-hosted runner is Linux amd64 or arm64.                                                                                                                                    |
| Every CI/CD run is blocked with `expected a valid Wiz scan result and did not receive one`, and the scan itself looks successful | The `,json` suffix is missing from `-o`, so the file is a human-readable report rather than JSON.            | Use `-o "$PWD/wiz_scan.json,json"` exactly. See [Step 3](#step-3-scan-and-pass-the-result-to-firefly).                                                                                                                                     |
| Same error, in a pipeline that runs one job per module                                                                           | A relative path to `wiz_scan.json` is resolving against a different working directory than `post-plan` uses. | Use an absolute path — `"$PWD/wiz_scan.json"` — in both the `-o` value and `--wiz-scan-file`.                                                                                                                                              |
| `fireflyci: unknown flag: --wiz-scan-file`                                                                                       | `fireflyci` predates the flag.                                                                               | Upgrade to `fireflyci` v0.6.26 or later.                                                                                                                                                                                                   |
| Jobs fail to authenticate to Wiz intermittently when several run at once                                                         | Concurrent jobs on a shared runner are overwriting each other's auth token in a shared `WIZ_DIR`.            | Set a per-job `WIZ_DIR`, as in [Step 2](#step-2-authenticate).                                                                                                                                                                             |
| `sha256sum -c` fails during install                                                                                              | `WIZCLI_VERSION` was changed without updating `WIZCLI_SHA256`, or the architecture differs.                  | Update the checksum to match the version and architecture you are downloading.                                                                                                                                                             |
| Run is blocked but the Guardrails step shows no failing policy                                                                   | The scan could not be completed or returned unparseable output, so the fail-closed gate applied.             | Check the Wiz CLI exit code and output in the job log for the underlying failure.                                                                                                                                                          |
| A policy shows amber ⚠ but the run proceeds                                                                                      | Expected behavior — this is the `WARN_BY_POLICY` soft-fail case, which is informational.                     | To make these block, raise their severity or strictness in your Wiz policy configuration.                                                                                                                                                  |
| Firefly built-in policy violations no longer appear                                                                              | Expected behavior — built-in policy scans are skipped for Wiz-integrated workspaces.                         | Reproduce the checks you need as Wiz policies or Firefly custom policies.                                                                                                                                                                  |

## Security Considerations

* **Secret handling.** In the Firefly-managed model, `WIZ_CLIENT_SECRET` is stored in Firefly's secret store, encrypted at rest, and never written to logs, API responses, or run output. In the CI/CD model, Firefly never receives your Wiz credentials at all — they stay in your CI/CD environment, and Firefly receives only the scan output.
* **Least privilege.** The Wiz service account requires read-only permissions.
* **Do not pass credentials as CLI flags.** See [Step 2](#step-2-authenticate).
* **Scan result contents.** Wiz results may include resource names, configuration detail, and the location of detected secrets. Firefly applies the same access controls to them as to other run data, and they are visible to anyone who can view the run.
* **Binary integrity.** Pin the Wiz CLI version and verify its checksum, as shown in [Step 1](#step-1-install-the-wiz-cli).


---

# 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://docs.firefly.ai/detailed-guides/workflows/wiz-policy-integration.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.
