> 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-scanner-cli/xygeni-cli-overview/airgapped-scanning/the-unlock-ceremony.md).

# The Unlock Ceremony

An airgapped scan writes its reports **encrypted** (`*.json.enc`) and, per scan type, a tiny **key request** (`*.unlock-req`). The encrypted report stays inside the enclave; to read it you exchange only the key request for a key response with Xygeni, from a connected host. Think of it as a self-locking strongbox (the `.enc` report) and a sealed envelope only Xygeni can open (the `.unlock-req`).

The round-trip has three steps:

```
ISOLATED ENCLAVE                    SNEAKERNET            CONNECTED HOST
────────────────                    ──────────            ──────────────
xygeni --airgap-mode … sast …
  ├─ my-project.sast.json.enc  (stays in the enclave)
  └─ sast.unlock-req ──────────[ carry out ]──►  xygeni util airgap unlock sast.unlock-req
                                               → returns sast.unlock-resp
                               ◄──[ carry back ]──  (a few KB, no findings)
xygeni util airgap decrypt my-project.sast.json.enc sast.unlock-resp
  └─ my-project.sast.json      (plaintext, stays in the enclave)
```

### 1. Carry out the key requests

Copy only the `*.unlock-req` files out of the enclave on your approved media. **Do not** copy the `*.enc` reports — they never need to leave, and the plaintext is never exposed outside the air gap. The `*.unlock-req` files are a few KB and contain **no findings**.

### 2. Unlock on a connected host

On an internet-connected machine with the scanner installed, run:

```bash
xygeni util airgap unlock sast.unlock-req
```

This calls the Xygeni unlock service, which **meters the scan**, verifies your account is entitled and the request comes from an approved host, and returns a `sast.unlock-resp`. Authentication uses the Xygeni **API token** configured on the connected host (in `xygeni.yml` or `XYGENI_TOKEN`) — the isolated scan host never needs it.

{% hint style="info" %}
The connected host does **not** need the air-gapped licence — only the scanner and your API token. You can pass several files or a glob; each is unlocked in one call:

```bash
xygeni util airgap unlock *.unlock-req
```

{% endhint %}

### 3. Decrypt back in the enclave

Carry the `*.unlock-resp` files back into the enclave and pair each encrypted report with its response:

```bash
xygeni util airgap decrypt my-project.sast.json.enc sast.unlock-resp
```

This recovers the report locally and writes the plaintext `my-project.sast.json` **inside the enclave**. Globs work here too, and files are matched by scan id:

```bash
xygeni util airgap decrypt *.json.enc *.unlock-resp
```

## One-pass unlock-and-decrypt

If your workflow allows the reports to be decrypted **outside** the enclave (i.e. on the connected host itself), a single command does both steps:

```bash
xygeni util airgap unlock-decrypt *.json.enc *.unlock-req
```

{% hint style="warning" %}
`unlock-decrypt` writes the **plaintext reports on the connected host**, so the findings leave the enclave. Use it only when that is acceptable for your environment; otherwise keep the two steps separate and decrypt inside the air gap.
{% endhint %}

## Metering

Each scan type is **one metered unlock**, regardless of how many report files it produced (JSON, SARIF, SBOM/CBOM all share one key). A grouped scan of N scan types produces N key requests and counts as N unlocks. Re-decrypting a report you have already unlocked is **free** — the key is reused; only a new scan needs a new unlock.

## Command reference

| Command                                                    | Where     | What it does                                                           |
| ---------------------------------------------------------- | --------- | ---------------------------------------------------------------------- |
| `xygeni util airgap fingerprint`                           | any host  | Prints the host fingerprint to send to Xygeni for licence binding.     |
| `xygeni util airgap unlock <*.unlock-req>`                 | connected | Meters and exchanges key requests for key responses (`*.unlock-resp`). |
| `xygeni util airgap decrypt <*.enc> <*.unlock-resp>`       | enclave   | Decrypts reports locally using the key responses.                      |
| `xygeni util airgap unlock-decrypt <*.enc> <*.unlock-req>` | connected | Unlocks **and** decrypts in one step (plaintext leaves the enclave).   |

## Troubleshooting

| Symptom                                | Cause / fix                                                                                                                                         |
| -------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- |
| *Licence has expired*                  | Air-gapped licences are short-lived. Request a renewal from Xygeni and reinstall `conf/xygeni.lic`.                                                 |
| *Host fingerprint … not approved*      | The host is not bound to the licence. Run `xygeni util airgap fingerprint` and send the value to Xygeni.                                            |
| Unlock refused                         | The account is not entitled / over its allowance, the API token lacks access, or the request was tampered with. Check the token and account status. |
| Console shows counts but no findings   | Expected under air-gap — the findings are in the encrypted report and appear only after you decrypt it.                                             |
| `reduced coverage - N host(s) skipped` | Enrichment lookups were blocked. Add those hosts to `conf/airgap-allowlist.txt` and re-run in `filtered` mode, or use `no-upload`.                  |
| SCA produced nothing                   | SCA needs the Xygeni vulnerability database; run it under `--airgap-mode no-upload`.                                                                |


---

# 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.xygeni.io/xygeni-scanner-cli/xygeni-cli-overview/airgapped-scanning/the-unlock-ceremony.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.
