Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Asset Inventory & System Spec

Auditors require five “system spec” artifacts: an asset inventory plus four snapshot kinds (data flow, network topology, threat model, hardware/software baseline). The platform exposes these as typed entities so the inventory can evolve over time and each snapshot can be attested independently.

This page covers the CLI / MCP surface for the asset inventory specifically. The four snapshot kinds are authored in the platform UI today; toggling them required/optional is the only CLI touchpoint.

CLI commands

All commands live under pretorin scope artifacts. They wrap the public /api/v1/public/systems/{id}/spec/* endpoints and require a token with the system_spec.read (reads) or system_spec.write (writes) scope.

# 1. List the 5 artifact kinds with their required / toggle / attest state.
pretorin scope artifacts list

# 2. Inspect the current asset inventory (or replay history).
pretorin scope artifacts inventory show
pretorin scope artifacts inventory show --as-of 2026-04-01T00:00:00Z

# 3. Upload a CSV.
#    The CLI fetches the current platform inventory first, classifies your CSV
#    rows into added / modified / decommissioned, shows a diff preview, and
#    posts a single diff.
pretorin scope artifacts inventory upload assets.csv

# 4. Scan a source and apply the resulting diff.
pretorin scope artifacts inventory scan aws            # live AWS account
pretorin scope artifacts inventory scan azure          # live Azure subscription
pretorin scope artifacts inventory scan k8s            # live K8s via kubectl
pretorin scope artifacts inventory scan iac-workspace  # local .tf / k8s YAML files
pretorin scope artifacts inventory scan aws --dry-run  # show diff without applying

# 5. Toggle an artifact kind required/optional.
#    Rationale is required when toggling off.
pretorin scope artifacts toggle threat_model --optional \
    --rationale "single-tenant scope; threat model lives in linked vendor SSP"

Scan sources

Each inventory scan <source> runs a built-in recipe that lives under src/pretorin/recipes/_recipes/asset-inventory-<source>/:

SourceRecipeWhat it reads
awsasset-inventory-aws-baselineLive AWS API (boto3) — EC2 instances in v1
azureasset-inventory-azure-baselineLive Azure Resource Manager — Compute VMs in v1
k8sasset-inventory-k8s-baselinekubectl get against the active context — nodes + Deployment/StatefulSet/DaemonSet
iac-workspaceasset-inventory-iac-workspaceStatic parse of .tf, .tf.json, K8s YAML, and cloudformation.{json,yaml} files in the cwd

The iac-workspace recipe is the generalized “look at the IaC checked into this repo” path — it does not call any cloud API and does not require any cloud credentials. Use it when you want the inventory to match the desired state in source control rather than current cloud state.

Adding a new source means adding a new recipe directory and updating SCAN_SOURCE_TO_RECIPE_ID in src/pretorin/spec.py. Community recipes can live under ~/.pretorin/recipes/ and override built-ins by id.

Decommission semantics

The diff endpoint never silently revives a decommissioned asset. If you upload a CSV (or scan) that contains an external_id matching a previously-decommissioned row, the platform returns an outcome: "not_found" item with a message telling you to re-activate via the UI rather than re-scan. The CLI surfaces this clearly in the diff response — look for the yellow “Some rows did not apply cleanly” block.

MCP tools

Three tools mirror the read + diff endpoints for AI agents:

  • list_artifact_requirements(system_id) — wraps the kinds endpoint.
  • get_asset_inventory(system_id, as_of?) — wraps the inventory read.
  • submit_asset_inventory_diff(system_id, recipe_id, added?, modified?, decommissioned?, idempotency_key?, recipe_context_id?) — posts the diff. recipe_id is a free-form string (the platform records cli:<recipe_id> as per-row provenance). idempotency_key defaults to sha256(system_id, recipe_id, scan_timestamp)[:32]; pass your own when replaying a scan. recipe_context_id is optional — set it when the diff is being produced inside an active recipe context opened via start_recipe.

The diff endpoint accepts recipe_context_id cleanly but does not require it, unlike the create_evidence write surface. There’s no 11-field audit metadata envelope required for inventory diffs.