Metadata-Version: 2.5
Name: cyberxyz-scanner
Version: 1.4.64
Summary: CyberXYZ Vulnerability Scanner CLI — real-time vulnerability intelligence, XYZ scoring, EPSS and depalert scores
Project-URL: Homepage, https://cyberxyz.io
Project-URL: Documentation, https://docs.cyberxyz.io
Author-email: CyberXYZ Security Team <support@cyberxyz.io>
License: Proprietary
License-File: LICENSE
Keywords: CVE,EPSS,GHSA,MCP,OSV,scanner,security,vulnerability
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: System Administrators
Classifier: License :: Other/Proprietary License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Security
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.8
Requires-Dist: click>=8.0
Requires-Dist: mcp<3,>=1.2; python_version >= '3.10'
Requires-Dist: pip-audit>=2.6
Requires-Dist: pipdeptree>=2.0
Requires-Dist: python-dotenv>=1.0
Requires-Dist: requests>=2.28
Requires-Dist: rich>=13.0
Requires-Dist: tabulate>=0.9
Description-Content-Type: text/markdown

# cyberxyz-scanner

CyberXYZ Security CLI. Real-time supply-chain protection for npm, PyPI, Go and .NET (NuGet) on macOS, Linux and Windows.

[![PyPI version](https://img.shields.io/pypi/v/cyberxyz-scanner.svg)](https://pypi.org/project/cyberxyz-scanner/)
[![Python](https://img.shields.io/pypi/pyversions/cyberxyz-scanner.svg)](https://pypi.org/project/cyberxyz-scanner/)
[![License](https://img.shields.io/badge/license-Proprietary-blue.svg)](LICENSE)

The CLI pairs with the CyberXYZ platform to give you per-machine package inventory, proxy
enforcement on every `npm`, `pip`, `go` and `dotnet` install, and CI/CD gating on flagged
dependencies. It is the implementer's interface to a platform that also exposes the same
controls in a web dashboard.

## Install

The package is published on PyPI as `cyberxyz-scanner`. The CLI binary it installs is named
`xyz`.

### With pip

```bash
pip install cyberxyz-scanner
```

### With uv

```bash
uv pip install cyberxyz-scanner
```

Verify the install:

```bash
xyz --help
```

## Quick start (one-time per machine)

```bash
# 1. Sign in. Opens your browser at app.cyberxyz.io; sign in the way you do on the
#    dashboard (password + authenticator app or passkey, or SSO), check the code
#    matches the terminal, and approve. The CLI never sees your password.
xyz login

# 2. Enroll this machine. One command:
#    - Registers the device with your organization
#    - Points npm (~/.npmrc), pip, Go (GOPROXY) and NuGet at the CyberXYZ proxy,
#      for each one that is installed
#    - Installs the background service for dashboard "Scan now" support
#      (LaunchAgent on macOS, systemd --user on Linux, Task Scheduler on Windows)
xyz proxy setup --machine-name "Alex's MacBook"
```

Over SSH or on a headless box, `xyz login --no-browser` prints the link and code to open
on any other device (the browser is also skipped automatically when `SSH_CONNECTION` is set
or Linux has no display). The legacy email and password prompt is still available as
`xyz login --password` (or `$XYZ_EMAIL` / `$XYZ_PASSWORD` for scripts); accounts with MFA
or an SSO-enforcing organization must use the browser login. `xyz logout` revokes the
session on the server and removes it locally.

The CLI session stays signed in while you use it and expires after 90 days without use.
While the CyberXYZ agent runs on the machine it refreshes the session daily, so you only sign in
once; a machine that stays off for 90 days signs out.
It is stored owner-only in `~/.xyz/config.json`. Each
machine's session is listed under **Settings > CLI sessions** in the dashboard, where you
(or an org admin) can revoke it. Login codes expire after 10 minutes and work once: only
approve a code you just requested yourself, never one someone sent you.

That's it. Every later install on this device goes through the CyberXYZ proxy: the exact
package version is checked before it downloads, blocked or quarantined packages are
refused with the reason, and the install shows up in your dashboard.

For fleets, skip the interactive login: an org admin creates an enrollment token in the
dashboard (Machines > Enrollment) and MDM runs
`xyz proxy setup --enrollment-token pxe_xyz_...` (or places the token at
`/Library/Application Support/CyberXYZ/enrollment-token`).

For environments that should not run a long-running background process (CI build agents,
sealed builds), pass `--no-install-daemon`.

On company-managed machines, install the agent at system level so developers cannot stop it:

```bash
sudo xyz proxy setup --system          # macOS / Linux
xyz proxy setup --system               # Windows, from an elevated PowerShell
```

This installs a root/SYSTEM service (macOS LaunchDaemon `io.cyberxyz.agent`, Linux
`cyberxyz-agent.service`, Windows scheduled task `CyberXYZAgent`) that starts at boot and
restarts if it is killed. The macOS `.pkg` does the same, and enrolls automatically when MDM
places an enrollment token at `/Library/Application Support/CyberXYZ/enrollment-token`.
Without `--system` (or without admin rights) setup installs the per-user service as before.

## Always-on protection

Every minute the background agent checks what each package manager will actually use,
repairs anything that no longer points at the CyberXYZ proxy, and reports the result to the
dashboard with its heartbeat. Repairs never remove a private or internal registry, and config
files are only written for tools that are installed:

| Tool | What is checked and repaired |
|---|---|
| npm, pnpm | `~/.npmrc` registry + token, pnpm's global rc; as root also `<npm prefix -g>/etc/npmrc` |
| yarn | `~/.yarnrc.yml` `npmRegistryServer` (token scoped to the proxy host under `npmRegistries`) and `registry` in `~/.yarnrc` |
| bun | `~/.bunfig.toml` `[install] registry` |
| pip | user `pip.conf` / `pip.ini`: the proxy is the `index-url`; extra indexes on pypi.org are removed, private indexes are kept; as root also the system file |
| uv | `uv.toml`: the proxy is the default `[[index]]`; pypi.org indexes are removed, private indexes are kept; as root also the system `uv.toml` |
| Go | `GOPROXY=<proxy>,direct` (the proxy refuses blocked modules with 403, so there is no fall-through); `<proxy>` only while the network lock is on; as root also `$GOROOT/go.env` |
| NuGet | `NuGet.Config`: the CyberXYZ source is added and nuget.org sources removed; private feeds are kept |
| Poetry | cannot be forced globally, so it is covered by the network lock only |

The system-level agent does this for every local user account, writing files owned by that
user. The machine token is stored where the agent can always read it
(`/Library/Application Support/CyberXYZ/machine-token`, `/etc/cyberxyz/machine-token`,
`%ProgramData%\CyberXYZ\machine-token`, or `~/.xyz/machine-token` per user), so deleting a
config file only gets it rewritten. Registry overrides in shell startup files
(`NPM_CONFIG_REGISTRY`, `PIP_INDEX_URL`, `GOPROXY=direct`, ...) and in the Windows user
environment are reported, never edited.

**Network lock.** When an org admin turns it on, the system-level agent also maps the public
registries (registry.npmjs.org, registry.yarnpkg.com, registry.npmmirror.com, pypi.org,
files.pythonhosted.org, proxy.golang.org) to `0.0.0.0` in the hosts file, so tools that ignore
config still cannot reach them. NuGet is not locked yet (it relies on config). Edits to the
lock are reverted and reported, and the block is removed when the org turns it off.

`xyz proxy remove` and uninstalling the service are reported to the dashboard before anything
is removed. Under the system service, only an administrator can remove it
(`sudo xyz proxy remove`). `xyz proxy status` shows the per-tool report, the service level and
the network lock state.

### If CyberXYZ is unreachable

The proxy reuses its verdict for any package it checked in the last 24 hours. For anything
else, your org's setting decides: **block** (the default; the developer sees "retry in a
minute") or **allow unchecked**. Org admins change it in Settings > Supply-chain proxy.

## Audit installed packages

Each command below audits the matching ecosystem on this machine, runs the CyberXYZ
watchlist + deep check on suspect packages, and uploads the full inventory to the
platform.

```bash
xyz audit npm                  # local + global node_modules
xyz audit python               # active Python environment via pip
xyz audit go                   # $GOPATH module cache
xyz audit nuget                # packages.lock.json files under cwd
xyz audit                      # npm + python + go back-to-back
```

By default each command uses the watchlist pre-filter for speed (~25-40s on a typical
machine). Pass `--full` to skip the pre-filter and deep-check every package (slower but
covers advisory-only matches at scan time).

## Fix, blast radius, SBOM and AI models (1.4.62+)

All four read the manifests and lockfiles in the current directory, the same ones
`depalert scan` reads: `package.json` / `package-lock.json`, `requirements*.txt`,
`Pipfile` / `Pipfile.lock`, `pyproject.toml` / `poetry.lock` / `uv.lock`,
`go.mod` / `go.sum`, and NuGet `packages.lock.json`.

### `xyz fix`: an upgrade plan for flagged dependencies

```bash
xyz fix                        # plan only: package, current, issue (KEV badge), → target, why
xyz fix --write                # show a unified diff, confirm, then edit the specs
xyz fix --write --yes          # no prompt (CI bots)
xyz fix --json
```

Every package is checked in one `/proxy/check/batch` call. For each flagged one
(block, quarantine, alert, or any advisory) the plan gives the nearest clean release
above the installed version. A clean installed version is never told to move. A
transitive package is traced to the direct dependency that pulls it ("via express →
debug, bump express"); transitive pins are never edited.

`--write` edits only direct dependency specs: `package.json` (keeps `^` / `~` / `>=`
and the file's formatting; complex ranges are listed for a manual edit) and `==` pins
in `requirements*.txt` (extras, markers and comments kept; hash-pinned lines are left
for `pip-compile`). Lockfiles are never touched: run `npm install`, `poetry lock`,
`uv lock` or `pip-compile` afterwards. Exit codes: `0` plan complete, `1` a flagged
package has no clean target, `4` backend unreachable.

### `xyz impact`: who is exposed when a package goes bad

```bash
xyz impact debug --version 2.6.8          # ecosystem guessed from the project, else npm
xyz impact requests -e pypi --json
```

Prints the direct dependents and whether each declared range admits the affected
version, how many packages reach it on a required path vs only through an optional
extra, and the top paths. Run inside a project, it also says whether this project
reaches it and through which direct dependency. "Not yet indexed" means the path is
unknown, not that there is none.

### `xyz sbom`: CycloneDX 1.5 or SPDX 2.3

```bash
xyz sbom -o sbom.cdx.json                  # CycloneDX 1.5 JSON with a vulnerabilities section
xyz sbom --format spdx -o sbom.spdx.json   # SPDX 2.3 JSON
xyz sbom --no-verdicts                     # components only, no network call
```

Components carry a purl (`pkg:npm/…`, `pkg:pypi/…`, `pkg:golang/…`, `pkg:nuget/…`),
the version and a scope (`required` / `optional`; dev dependencies are `excluded`),
and the dependency graph comes from the lockfile when it records one. Vulnerabilities
list the advisory ids, CVSS and EPSS ratings, a `cyberxyz:kev` property for CISA KEV
entries, and the safe version as the recommendation.

### `xyz audit models`: AI model artifacts

```bash
xyz audit models                           # cwd + the Hugging Face cache
xyz audit models ./ml --no-hf-cache
xyz audit models --aibom -o aibom.cdx.json # CycloneDX 1.6 ML-BOM
```

Finds model files (`.safetensors .bin .pt .pth .ckpt .gguf .onnx .pkl .h5`) and hashes
them with a streamed sha256 (files over `--max-hash-size` are listed as UNHASHED),
Hugging Face references in code (`from_pretrained`, `hf_hub_download`, `pipeline(model=…)`,
`snapshot_download`, flagging `trust_remote_code=True`), and models in
`~/.cache/huggingface/hub`. Files are never loaded or unpickled. The table shows each
repo or file with its verdict, load safety, trust_remote_code and reasons. NOT WATCHED,
PENDING and UNSCANNED are not verdicts. Exit `1` when anything is MALICIOUS.

### KEV

When an advisory is in CISA's Known Exploited Vulnerabilities catalog, a bold **KEV**
marker leads the score cell in `depalert scan`, the vulnerability tables and the
`xyz fix` plan, and SARIF results carry `"kev": true` (plus a `kev` rule tag).

## Use CyberXYZ from AI coding agents (MCP)

`xyz mcp serve` is a [Model Context Protocol](https://modelcontextprotocol.io) server:
Claude Code, Cursor, VS Code (Copilot agent mode), Windsurf, Codex CLI and Gemini CLI
call it to check packages, vulnerabilities, dependencies and AI models *before* they add
or install anything. It uses your `xyz login` session (or `XYZ_API_KEY`), needs
Python 3.10+ (the `mcp` package installs automatically there), and only ever speaks the
protocol on stdout.

```bash
xyz mcp install --client claude-code --hooks   # MCP server + install hook, user scope
xyz mcp install --client cursor --scope project --rules
xyz mcp install --client all --dry-run         # show every diff, change nothing
xyz mcp status                                 # which clients are configured, does auth work
xyz mcp serve --tools                          # list the tools
```

| Client | `--scope user` | `--scope project` |
|---|---|---|
| `claude-code` | `claude mcp add --scope user` (else `~/.claude.json`) | `claude mcp add --scope project` (else `.mcp.json`) |
| `cursor` | `~/.cursor/mcp.json` | `.cursor/mcp.json` |
| `vscode` | printed (`code --add-mcp …` / *MCP: Open User Configuration*) | `.vscode/mcp.json` (`servers`, `type: stdio`) |
| `windsurf` | `~/.codeium/windsurf/mcp_config.json` | global only |
| `codex` | `~/.codex/config.toml` `[mcp_servers.cyberxyz]` | global only |
| `gemini` | `~/.gemini/settings.json` | `.gemini/settings.json` |

Files are merged, never overwritten (other servers and settings stay), the previous
version is kept as `.bak`, and a file that is not plain JSON (comments) is left alone
with the snippet printed. `--rules` adds the CyberXYZ dependency policy where the agent
reads rules (`CLAUDE.md`, `AGENTS.md`, `GEMINI.md`, `.github/copilot-instructions.md`
between markers, after asking; `.cursor/rules/cyberxyz.mdc`, `.windsurf/rules/cyberxyz.md`).

**Tools**

| Tool | What the agent gets |
|---|---|
| `check_package` / `check_packages` | install-time decision (allow / alert / quarantine / block) with behaviour signals (malicious release, typosquat, install scripts, dependency confusion, org block), advisories with CVSS / EPSS / KEV / fixed-in, a safe version and a one-line recommendation |
| `upgrade_plan` | is the installed version affected, nearest clean release above it, latest clean |
| `scan_project` | every manifest / lockfile in the project checked, flagged packages with the path from a direct dependency, what to bump, npm overrides |
| `dependency_paths` / `package_dependencies` / `blast_radius` | why a transitive package is installed, what a package pulls in, who depends on a bad version |
| `get_vulnerability` / `search_vulnerabilities` | one advisory in full; the advisory corpus by package, text, ecosystem, severity |
| `model_risk` / `model_load_safety` / `check_model_file` | Hugging Face model dependency risk, per-file load safety, lookup by sha256 |
| `machines_with_package` | which machines in your organization installed a package, at which version |

Plus the `cyberxyz-dependency-policy` prompt and resource: check before adding, never
install block / quarantine, prefer the safe version, unknown needs a human, never
`trust_remote_code` or pickle-load a model that is not CLEAN.

**Install hook (Claude Code).** `--hooks` adds a `PreToolUse` hook on Bash that runs
`xyz hook check-install`: `npm|pnpm|yarn|bun add/install <pkg>`, `pip / uv pip install
<pkg>`, `uv add`, `poetry add`, `pipx install`, `go get / go install`, and
`dotnet add package` are checked in one call, and blocked or quarantined packages are
denied with the reason and a safe version. Lockfile installs (`npm install`, `npm ci`,
`pip install -r …`) pass: the proxy checks what they fetch. `--hook-strict` asks you on
alerts; the hook fails open with a warning if CyberXYZ is unreachable unless
`--hook-fail-closed` is set. It never auto-approves a command.

Lookups from the MCP server and the hook identify themselves (`X-XYZ-Client: mcp` /
`agent-hook`) so the platform can keep them out of the install log: asking about a
package is not installing it.

## Other useful commands

```bash
# One-off safety check on a single package + version
xyz check axios 1.14.1 -e npm

# CI/CD gate. Non-zero exit on flagged packages.
xyz depalert scan --package-lock package-lock.json --fail-on block
xyz depalert scan --requirements requirements.txt --fail-on quarantine
xyz depalert scan --requirements poetry.lock      # also Pipfile.lock, uv.lock
xyz depalert scan --go-sum go.sum
xyz depalert scan -p axios@1.14.1 -p lodash@4.17.21

# SBOM upload (CycloneDX or SPDX)
xyz inventory upload ./my-app
xyz inventory upload --sbom syft.json

# Diagnostic / housekeeping
xyz --version
xyz proxy status               # proxy config per tool, service level, network lock
xyz proxy whoami               # what (org, machine) does my token resolve to
xyz proxy remove               # restore default registries (reported to your dashboard)
xyz scans list                 # history of recent scans for your org
xyz upgrade                    # pull the latest release from PyPI
```

## Code, IaC, secrets and image scanning (`code-scan`)

`xyz code-scan` runs open-source scanners that you install yourself and merges what they
report into one table, JSON document or SARIF 2.1.0 file. It works without logging in and
sends nothing to CyberXYZ. It is separate from `xyz scan`, which checks installed packages.

```bash
xyz code-scan secrets .                 # hardcoded credentials (values always redacted)
xyz code-scan iac ./infra               # Terraform, CloudFormation, Kubernetes, Helm, Dockerfile
xyz code-scan image python:3.11-slim --sbom sbom.cdx.json   # vulns + misconfig + secrets, CycloneDX SBOM
xyz code-scan code .                    # SAST with the built-in xyz rules
xyz code-scan code . --config ./my-rules.yml                 # add your own opengrep rules
xyz code-scan all . --format sarif -o xyz.sarif --fail-on high
```

| Command | Engine | Fallback / option |
|---|---|---|
| `secrets` | gitleaks (`dir` on 8.19+, `detect --no-git` before) | trivy `fs --scanners secret`, or `--engine trivy` |
| `iac` | trivy `config` | checkov with `--engine checkov` |
| `image` | trivy `image` (vuln, misconfig, secret) | `--sbom FILE` writes CycloneDX |
| `code` | opengrep + built-in xyz rules + any `--config` | without opengrep: bandit for Python, gosec for Go |
| `all` | `secrets` + `iac` + `code`, merged | `--skip-missing` runs whatever is installed |

The built-in rules (`xyz_cli/rules/`) cover supply-chain patterns: `shell=True` and
`os.system` with dynamic commands, eval/exec of downloaded data, `curl | sh` in scripts, CI
files and Dockerfiles, `pickle.load`, `torch.load` without `weights_only=True`,
`trust_remote_code=True`, hardcoded cloud keys and private keys, disabled TLS verification
(`verify=False`, `NODE_TLS_REJECT_UNAUTHORIZED=0`, `InsecureSkipVerify`), `child_process.exec`
with template strings, and npm install scripts that download binaries. Without opengrep the
built-in rules do not run and xyz says so.

Common options: `--format table|json|sarif`, `-o FILE`, `--fail-on critical|high|medium|low|none`
(default `low`, meaning any non-info finding fails), `--timeout SECONDS` per engine (default
900). Severities are normalised to critical/high/medium/low/info, paths are relative to the
scanned directory, and duplicate findings are merged, including the same secret found by two
engines. Secret values are never printed in any format; secret findings carry no snippet.
SARIF suppressions (`# nosec`, `nosemgrep`, `gitleaks:allow`) are honoured.

| Exit | Meaning |
|---|---|
| 0 | Clean: nothing at or above `--fail-on` |
| 1 | Findings at or above `--fail-on` |
| 2 | Usage error |
| 3 | Engine not installed (the install command for your OS is printed) |
| 4 | Engine error: non-zero exit, timeout, or no report (the engine's stderr tail is printed) |

**Installing the engines.** xyz looks for them on `PATH` and never downloads them.

| Engine | macOS | Linux | Windows |
|---|---|---|---|
| trivy | `brew install trivy` | Aqua apt repo, see [trivy.dev](https://trivy.dev/latest/getting-started/installation/), then `sudo apt-get install -y trivy` | `scoop install trivy` |
| gitleaks | `brew install gitleaks` | `sudo apt-get install -y gitleaks` or `go install github.com/zricethezav/gitleaks/v8@latest` | `scoop install gitleaks` |
| opengrep | binary from [github.com/opengrep/opengrep/releases](https://github.com/opengrep/opengrep/releases), on `PATH` | same | same |
| bandit | `pip install "bandit[sarif]"` | same | same |
| gosec | `brew install gosec` | `go install github.com/securego/gosec/v2/cmd/gosec@latest` | same as Linux |
| checkov | `pip install checkov` | same | same |

**In CI.** GitHub Actions: run `xyz code-scan all . --format sarif -o xyz.sarif` and upload
the file with `github/codeql-action/upload-sarif` (set `if: always()` on the upload so
findings still show when the gate fails). Each run is tagged
`automationDetails.id = xyz-code-scan/<scan>/`, so `secrets`, `iac` and `code` can be
uploaded separately without replacing each other.

```yaml
- run: pip install cyberxyz-scanner "bandit[sarif]"
- run: go install github.com/zricethezav/gitleaks/v8@latest && echo "$(go env GOPATH)/bin" >> "$GITHUB_PATH"
- run: xyz code-scan all . --skip-missing --format sarif -o xyz.sarif --fail-on high
- uses: github/codeql-action/upload-sarif@v3
  if: always()
  with:
    sarif_file: xyz.sarif
```

GitLab CI: run the same command in a job and keep `xyz.sarif` (or `--format json`) as a job
artifact. GitLab's Security dashboard reads its own report format, not SARIF, so treat the
exit code as the gate.

**Licensing.** xyz uses Trivy (Apache-2.0), Gitleaks (MIT), Opengrep (LGPL-2.1) as external
engines, plus bandit (Apache-2.0), gosec (Apache-2.0) and checkov (Apache-2.0) when present.
They run as separate programs; none of them is bundled. The built-in rules are CyberXYZ's own,
released under MIT. xyz does not use or reference Semgrep Registry rules.

## CI/CD integrations

Set `XYZ_API_KEY` as a secret and add one of these; any push or PR that pulls in a
malicious or vulnerable package fails the build with a clear reason.

* GitHub Actions: `uses: CyberXYZSecurity/depalert-action@v1` (GitHub Marketplace)
* GitLab CI/CD catalog: `gitlab.com/cyberxyz/depalert`
* Azure DevOps Pipelines: `integrations/azure-pipelines/cyberxyz-supply-chain.yml`
* Or generate one: `xyz ci init`

### Route the job's own installs through the proxy (`protect`)

`scan` checks lockfiles after the fact. `protect` runs early in the job and points npm,
yarn, pip, uv, Go and NuGet at the CyberXYZ proxy, so a malicious version is refused at
install time, the same way it is on laptops. Recommended: `protect` before the install
steps, `scan` as the gate.

```yaml
# GitHub Actions
- uses: CyberXYZSecurity/depalert-action@v1
  with:
    api-key: ${{ secrets.XYZ_API_KEY }}
    mode: protect          # network-lock: true also blocks the public registries on the runner
- run: npm ci              # goes through the proxy
- uses: CyberXYZSecurity/depalert-action@v1
  with:
    api-key: ${{ secrets.XYZ_API_KEY }}   # mode: scan (default) gates on the lockfiles
```

GitLab: include `gitlab.com/cyberxyz/depalert/protect@1.1.0` and add
`extends: .cyberxyz-protect` (or `- !reference [.cyberxyz-protect, before_script]`) to the
jobs that install dependencies. Any other CI: `eval "$(xyz ci protect --format shell)"`
with `XYZ_API_KEY` set. If CyberXYZ is unreachable, `protect` warns and the build carries
on unprotected; pass `--strict` (`strict: true`) to fail it instead.

All of them run the same `xyz depalert scan` engine your laptops use. It reads
`package-lock.json`, `requirements*.txt`, `Pipfile.lock`, `poetry.lock`, `uv.lock` and
`go.sum`.

### `depalert scan` exit codes

| Exit | Meaning |
|---|---|
| 0 | Allowed |
| 1 | Block |
| 2 | Quarantine |
| 3 | Alert |
| 4 | Error, including a manifest that could not be read (it is never treated as clean) |

## Re-enroll, rotate, remove

To rotate the proxy token on a device, re-run `xyz proxy setup --machine-name "..."` as
the same user who enrolled it. The platform replaces the old token and the daemon picks up
the new one at next restart. A machine name registered by another member of your org
can only be re-issued by an org admin; pick a different `--machine-name` otherwise.

To remove a device cleanly, delete it from the dashboard Fleet view. The deletion sweeps
proxy_install_log, proxy_tokens, cli_scans, customer_inventory_uploads,
customer_package_inventory and scan_jobs in one transaction. Re-enroll with the same
command above.

## Platform

* Dashboard: <https://app.cyberxyz.io>
* Documentation: <https://cyberxyz.io>

## License

Proprietary. See [LICENSE](LICENSE).

## Contact

Email: amro@cyberxyz.io
