← Discovery Agent
Complete Guide
Dashboard →

1. Overview

The Discovery Agent is a single, read-only, cross-platform Rust binary that inventories every cryptographic asset it can reach — certificates and keys on disk, SSH keys, live TLS endpoints, database columns, F5/NetScaler appliance certificate stores, and weak-crypto calls in source code — then classifies each by post-quantum readiness and remediation ownership. It has no installer, no daemon, and no dependencies: download it, point it at a config, run it once.

It operates in one of three modes: submit results to the PQCrypta API, write a raw JSON file, or produce a complete self-contained assessment entirely offline (§7).

2. Install

Binaries are public — no account or API key required to download. Pick your platform:

🐧 Linux — x86_64 curl -o pqcrypta-discovery https://api.pqcrypta.com/stream/downloads/discovery-agent/linux chmod +x pqcrypta-discovery
🍎 macOS — Apple Silicon (arm64) curl -o pqcrypta-discovery https://api.pqcrypta.com/stream/downloads/discovery-agent/macos chmod +x pqcrypta-discovery
🍏 macOS — Intel (x86_64) curl -o pqcrypta-discovery https://api.pqcrypta.com/stream/downloads/discovery-agent/macos-intel chmod +x pqcrypta-discovery
🪟 Windows — x86_64 (PowerShell) Invoke-WebRequest https://api.pqcrypta.com/stream/downloads/discovery-agent/windows -OutFile pqcrypta-discovery.exe
⚡ One-line bootstrap (Linux / macOS) curl -sSL https://api.pqcrypta.com/stream/downloads/discovery-agent/install.sh | bash

Every binary is built on a native per-platform CI runner (Windows on Windows, both macOS builds on genuine Apple hardware). The agent needs no runtime, no admin rights to run, and touches nothing it scans — it only reads.

2a. Verify Your Download

Every release is hybrid-signed — a classical Ed25519 signature and a post-quantum ML-DSA-65 (NIST FIPS 204) signature over a SHA256SUMS manifest. The install.sh path verifies the Ed25519 signature (against a key pinned in the script) and the checksum before it ever marks the binary executable — it fails closed. For the removable-media / air-gap workflow, verify by hand on the destination host after transfer:

# Fetch the binary + integrity files BASE=https://api.pqcrypta.com/stream/downloads/discovery-agent curl -o pqcrypta-discovery $BASE/linux curl -o SHA256SUMS $BASE/verify/SHA256SUMS curl -o SHA256SUMS.sig $BASE/verify/SHA256SUMS.sig curl -o SHA256SUMS.mldsa.sig $BASE/verify/SHA256SUMS.mldsa.sig # Fetch the public keys from a DIFFERENT origin than the binary — the # out-of-band key repo at github.com/PQCrypta/discovery-agent-keys KEYS=https://raw.githubusercontent.com/PQCrypta/discovery-agent-keys/main curl -o signing.pub $KEYS/pqcrypta-agent-signing.pub curl -o signing-mldsa.pub $KEYS/pqcrypta-agent-signing-mldsa.pub # 1. Classical: verify the Ed25519 signature over the manifest (any OpenSSL) openssl pkeyutl -verify -pubin -inkey signing.pub -rawin \ -in SHA256SUMS -sigfile SHA256SUMS.sig # 2. Post-quantum: verify the ML-DSA-65 signature (OpenSSL 3.5+ / FIPS 204) # (if your openssl.cnf loads an older oqsprovider and the key fails to load, # prefix with OPENSSL_CONF=/dev/null to use the built-in provider) openssl pkeyutl -verify -pubin -inkey signing-mldsa.pub -rawin \ -in SHA256SUMS -sigfile SHA256SUMS.mldsa.sig # 3. Confirm the binary matches the now-trusted manifest sha256sum -c SHA256SUMS --ignore-missing

Windows (PowerShell)

$BASE = "https://api.pqcrypta.com/stream/downloads/discovery-agent" Invoke-WebRequest "$BASE/windows" -OutFile pqcrypta-discovery.exe Invoke-WebRequest "$BASE/verify/SHA256SUMS" -OutFile SHA256SUMS Invoke-WebRequest "$BASE/verify/SHA256SUMS.sig" -OutFile SHA256SUMS.sig Invoke-WebRequest "$BASE/verify/SHA256SUMS.mldsa.sig" -OutFile SHA256SUMS.mldsa.sig # Public keys come from a DIFFERENT origin than the binary — the # out-of-band key repo at github.com/PQCrypta/discovery-agent-keys $KEYS = "https://raw.githubusercontent.com/PQCrypta/discovery-agent-keys/main" Invoke-WebRequest "$KEYS/pqcrypta-agent-signing.pub" -OutFile signing.pub Invoke-WebRequest "$KEYS/pqcrypta-agent-signing-mldsa.pub" -OutFile signing-mldsa.pub # Signature verification (needs openssl on PATH; OpenSSL 3.5+ for the ML-DSA step) openssl pkeyutl -verify -pubin -inkey signing.pub -rawin -in SHA256SUMS -sigfile SHA256SUMS.sig openssl pkeyutl -verify -pubin -inkey signing-mldsa.pub -rawin -in SHA256SUMS -sigfile SHA256SUMS.mldsa.sig # Checksum — compare against the SHA256SUMS entry for the .exe (Get-FileHash -Algorithm SHA256 pqcrypta-discovery.exe).Hash.ToLower() Select-String -Path SHA256SUMS -Pattern 'pqcrypta-discovery.exe'
Bootstrap trust out-of-band. The commands above already fetch the keys from different infrastructure than the binary: the third-party-hosted repo github.com/PQCrypta/discovery-agent-keys, which also keeps an append-only history of every release's signed manifest. (The same keys are mirrored at $BASE/verify/ on api.pqcrypta.com for environments that can't reach GitHub — if you use that mirror, fingerprint checking below is essential, since key and binary then share an origin.) Before trusting a fetched key, cross-check its fingerprint against the other anchors, each on separate infrastructure: (1) this documentation page (served from pqcrypta.com); (2) the GitHub repo above; and (3) a DNSSEC-signed DNS TXT record on _pqcrypta-signing.pqcrypta.com — the zone is DNSSEC-signed (DS in the .com root), so that record is cryptographically authenticated end-to-end, not spoofable by an on-path attacker:
delv TXT _pqcrypta-signing.pqcrypta.com # expect: "fully validated"
# The three published fingerprints (all three must agree): # Ed25519 (classical) sha256(pqcrypta-agent-signing.pub) c46d2fac1a3039e9a8aee8637e21eb39d6558da25a5814b97a29f7fb9237dee0 # ML-DSA-65 (FIPS 204, PQC) sha256(pqcrypta-agent-signing-mldsa.pub) 68ceb2dc10b4789eabef1f903d879408a15b3fe8cf2dc15eec3cb839fb981ddf # verify a downloaded key matches (Unix): sha256sum signing.pub # (PowerShell): (Get-FileHash -Algorithm SHA256 signing.pub).Hash.ToLower()
If a fetched key's fingerprint doesn't match all independent sources, do not run the binary.
The post-quantum signature is the point: we sign our own supply chain with the same hybrid classical-plus-ML-DSA transition we recommend to customers. Both signatures cover the same manifest, so a classical-only verifier is fully protected today, and a quantum-capable one gets FIPS 204 assurance — verifiable entirely offline, no certificate authority involved.

The scanner ships its own CBOM

The agent publishes a CycloneDX 1.6 Cryptographic Bill of Materials of itself at verify/agent-cbom.json (covered by the same signed SHA256SUMS). It documents, honestly, the cryptography the scanner itself uses: its transport is standard classical TLS 1.2/1.3 (via rustls), and its release supply-chain signatures are hybrid classical + ML-DSA-65. So the tool that inventories your cryptography discloses its own — answering the FAR-rule question about your vendors' cryptography before it's asked.

3. Run Modes

Exactly one of these three is required each run:

ModeFlagUse when
Submit--api-url + --api-key (or in config)Normal operation — results flow into the Compliance Dashboard.
Raw JSON--output results.jsonYou want the raw inventory as a file to process yourself.
Offline / air-gap--offline-report ./assessmentIsolated network — a complete report + CBOM computed locally, no network (§7).
# Submit to the dashboard ./pqcrypta-discovery --config agent-config.toml \ --api-url https://api.pqcrypta.com --api-key YOUR_KEY # Raw JSON, no submission ./pqcrypta-discovery --config agent-config.toml --output results.json # Offline air-gap bundle, zero network ./pqcrypta-discovery --config agent-config.toml --offline-report ./assessment

Command-line flags

FlagMeaning
--config <file>Config file (default agent-config.toml). Its scan_paths are authoritative.
--api-url / --api-keySubmission endpoint and key (also settable in config or the PQCRYPTA_API_URL/PQCRYPTA_API_KEY env vars).
--targets <t>Replaces the config's scan_paths (or the built-in defaults) for this run — the given targets become the authoritative list, not an addition to it.
--deep-scanSlower, more thorough traversal.
--full-disk-scanAdd the filesystem root (/ or C:\). Pair with a config whose excluded_paths skips pseudo-filesystems and noise.
--output <file>Write raw JSON instead of submitting.
--offline-report <dir>Air-gap bundle: report.html + cbom.json + inventory.json, no network.
--verboseDebug logging (including per-connection TLS timing).

4. Configuration Reference

The agent is fully config-driven. With --config, that file's scan_paths are exactly what gets scanned — nothing hidden. With no --config it falls back to a built-in per-OS default set, which is the same reference-{linux,windows,macos}.toml you can download and edit. Start from a role preset and adjust.

KeyTypePurpose
api_url / api_keystringSubmission target (omit for --output/--offline-report).
scan_paths[string]Directories/files to scan for certs, keys, SSH keys, keystores. Authoritative.
excluded_paths[string]Opt-in exclusions. A run skips nothing unless listed (recommended before --full-disk-scan).
deep_scanboolThorough traversal.
code_scan_paths[string]Source trees to scan for weak-crypto calls (CBOM). Off by default.
[[network_targets]]tablehost + port — a live TLS handshake inspecting the cert actually served.
[[database_connections]]tablename, db_type, dsn — parses cert/key column values, never storing the raw value.
[[appliance_targets]]tableF5/NetScaler management-API scan (§6).

5. What It Scans

Seven distinct sources, each real and tested:

Every asset is then classified by post-quantum status (compliant / legacy / forbidden), risk, and remediation ownership — who can actually fix it (you, a public CA, an OS vendor, a package manager, or a hardware vendor).

6. F5 / NetScaler Appliances

F5 BIG-IP and Citrix NetScaler are closed devices — no agent runs on them. Instead the agent queries each device's own management API remotely, from any host that can reach the management interface (a jump host is typical):

A read-only account is sufficient (F5 Auditor role / NetScaler read-only command policy). Beyond the certificate store, the agent collects the device's own facts — software version, platform (Virtual Edition detection), CPU/memory, management IP, self-IPs, subnets, gateway, and interfaces with MACs — so each appliance appears as its own first-class device in the dashboard. It also resolves, per certificate, which virtual servers actually serve it, or flags it as an unbound spare — the difference between a live cert and a forgotten one, which a live TLS scan of the VIP can't see. Factory certs (F5's ca-bundle/f5-irule/default, NetScaler's ns-server-certificate) classify as hardware-vendor; certs your org installed classify as internal.

[[appliance_targets]] name = "F5 BIG-IP Production" appliance_type = "f5" # "f5" or "netscaler" mgmt_url = "https://f5-mgmt.example.com" username = "readonly-user" password = "your-password-here" verify_tls = true # false only for a self-signed mgmt cert
On modern NetScaler CPX, the nsroot password is randomly generated per container — read it with docker exec <container> cat /var/deviceinfo/random_id.

7. Offline / Air-Gap Mode

For isolated or classified networks, one flag produces a complete assessment entirely on-host with zero network access — no API key, no callback:

./pqcrypta-discovery --config agent-config.toml --offline-report ./assessment

This writes a self-contained bundle to ./assessment/:

FileWhat it is
report.htmlA single self-contained compliance report (all styling inlined, no external requests) — safe to open on an air-gapped host. Post-quantum readiness, risk breakdown, remediation ownership, full inventory.
cbom.jsonA CycloneDX 1.6 Cryptographic Bill of Materials.
inventory.jsonEvery asset with full detail and its local assessment.
Post-quantum scoring, risk rating, remediation-ownership classification, and CBOM assembly are all computed on the agent — the same logic the platform runs server-side — so an air-gapped report reads identically to an online one. Carry the bundle out on removable media; nothing ever leaves the host over the network. Verified by running under a network namespace with no interfaces at all.

7a. Self-Hosted / On-Prem Platform

Between hosted SaaS and single-binary offline mode is a third option: run the entire platform — API, PostgreSQL, and the Compliance Dashboard — inside your own network, and point agents at it. No inventory, CBOM, or telemetry leaves your environment.

./pqcrypta-discovery --config agent-config.toml --api-url http://your-host:3003

The agent is unchanged — only the target URL differs. The self-hosted tier ships as a docker compose stack (database + API + dashboard) with both a connected installer and a fully air-gapped bundle (images + schema + signed agent artifacts staged into one tarball, zero registry pulls on the destination). The dashboard's API base URL, CSP connect-src, and download links all follow your local API.

PieceWhere
Deployment packagedeploy/onprem/ — compose, Dockerfiles, .env.example, DB schema, scripts, README
Connected installdocker compose up -d --build after filling .env and dropping your license.json
Air-gap installscripts/build-airgap-bundle.sh → carry tarball → scripts/install-airgap.sh
Point the API basePQCRYPTA_API_BASE (dashboard) and --api-url (agents)
The self-hosted platform runs under a license post-quantum signed with ML-DSA (Dilithium3, NIST FIPS 204), verified entirely offline at startup — no phone-home, so it works in classified enclaves. A tampered license fails closed; an expired one continues in grace mode. ML/AI features are an opt-in add-on; the core platform runs without them.

8. Output & CBOM

However you run it, the inventory maps to standards-based output. In offline mode you get the CycloneDX 1.6 CBOM directly (cbom.json). Online, the dashboard's Reports tab and /crypto-assets/export/cbom produce the same CycloneDX 1.6 export, filtered by any combination of source, device, algorithm, certificate role, compliance status, and more. CSV and JSON report exports share the identical filter set, so a selection always describes the same rows.

9. Security & Least Privilege

10. Troubleshooting

SymptomCause / fix
"Specify one of --api-url, --output, or --offline-report"No mode chosen — pass one of the three (§3).
Appliance scan returns HTTP 401Wrong credentials, or (F5/NetScaler) a freshly created account whose password is flagged expired — reset it once. For CPX, read the generated nsroot password (§6).
Appliance scan can't connectRun from a host that can reach the management interface; set verify_tls = false only for a self-signed mgmt cert.
Scan finds nothingscan_paths is authoritative — confirm the paths exist and aren't all under excluded_paths.
Too much noiseEnable excluded_paths (pseudo-filesystems, temp, package caches) before a --full-disk-scan.
One appliance is unreachable but the rest matterThat's fine — an unreachable appliance only warns; the rest of the scan completes.