> ## Documentation Index
> Fetch the complete documentation index at: https://docs.algovoi.co.uk/llms.txt
> Use this file to discover all available pages before exploring further.

# Security Suite

> Layered, verifiable defence for agentic payment infrastructure: input integrity hardening before canonicalization, plus IP, geo and rate limit at the edge.

<Note>
  **Also in the [Payment Rails bundle](/payment-rails-sqlite).** Its commercial tools (Substrate Guard Pro and Edge Sentinel) ship inside the self-hosted payment-rails estate under one commercial licence. They are also available together as the standalone Security Suite bundle.
</Note>

The AlgoVoi Security Suite protects an agentic payment stack in two layers over one verifiable evidence spine. Layer 1 secures **input integrity**: it stops malformed and resource hostile payloads before they reach canonicalization. Layer 2 is **runtime edge defence**: it decides who, and what, may reach the service at all.

What sets the suite apart from a conventional gateway or WAF is the spine. **Every allow and deny is a Falcon-1024 (optionally hybrid ML-DSA-65) signed, content addressed, hash linked decision** that the [Compliance Command Center](/compliance-command-center) ingests. So you can prove, offline and after the fact, what your defences admitted, what they refused, and under exactly which policy. The geo and rate mechanics are commodity. The verifiable, post quantum signed, no PII evidence is not.

## The tools

| Tool                                | Layer              | Tier              | Package                       | What it does                                                                                                                                                                                             |
| ----------------------------------- | ------------------ | ----------------- | ----------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [Substrate Guard](/substrate-guard) | 1, input integrity | Open (Apache 2.0) | `algovoi-substrate-guard`     | Deterministic input bounds run before canonicalization: size, depth, object keys, array length, string length, total nodes, number safety. The limits in force are content addressed (`profile_ref`).    |
| Substrate Guard Pro                 | 1, input integrity | Commercial        | `algovoi-substrate-guard-pro` | Everything in the open tier, plus a UTF-8 string safety bound (rejects lone surrogates and non scalar code units), and every admit or reject recorded as a signed, content addressed admission decision. |
| Edge Sentinel                       | 2, runtime edge    | Commercial        | `algovoi-edge-sentinel`       | IP, geo and ASN blocking; rate and velocity limiting; identity allow and deny; replay, nonce and freshness. First block wins, fail closed. Every decision signed, with a no PII subject.                 |

<Info>
  **Open foundation, commercial depth.** Substrate Guard is open source (`pip install algovoi-substrate-guard`, `npm install @algovoi/substrate-guard`), Python and TypeScript byte for byte identical. Substrate Guard Pro and Edge Sentinel are commercial products under the AlgoVoi Commercial Licence; the open guard composes straight into the Pro tier.

  **Now available.** The two commercial tools ship together as the **Security Suite** bundle (`algovoi-security-suite`): one perpetual, one time licence installs `algovoi-substrate-guard-pro` and `algovoi-edge-sentinel` from the index with a single `pip`. Available on the [AlgoVoi Suite Store](https://api.algovoi.co.uk/suite-store).
</Info>

## Install

After buying the Security Suite on the [Suite Store](https://api.algovoi.co.uk/suite-store) you get an index token. Install both tools in one `pip` (commercial deps from the token-gated index, public deps from PyPI):

```bash theme={null}
pip install \
  --index-url https://<your-index-token>@api.algovoi.co.uk/pkgs/simple/ \
  --extra-index-url https://pypi.org/simple/ \
  algovoi-substrate-guard-pro algovoi-edge-sentinel
```

Air-gapped deployment? The suite also ships as a self-contained offline bundle: every dependency wheel vendored, a CycloneDX SBOM, SHA-256 manifest, and a signed release. No PyPI needed.

```bash theme={null}
unzip algovoi-security-suite-0.1.0.zip && cd algovoi-security-suite-0.1.0
sh install.sh        # pip install --no-index --find-links wheels/ ...
python verify.py     # self-check: both layers, signed chains, tamper detection
```

Both tools are runtime licensed and fail closed. Provide your licence offline (no phone home), either env var:

```bash theme={null}
export ALGOVOI_LICENSE_KEY="<licence key issued at purchase>"
```

## Quickstart

### Layer 1: admit or reject input, signed

```python theme={null}
from algovoi_substrate_guard_pro import GuardService, signing, verify_guard_chain

pk, sk = signing.generate_keypair()          # in production, load and persist your gate's keypair
gate = GuardService(decision_secret_key=sk, decision_public_key=pk)

r = gate.evaluate({"agent": "acct:alice", "amount": 25_000_000})
if r.admitted:
    handle(r.subject_ref)                     # subject_ref is the value's canonical content address
else:
    reject(r.reject_code)                     # e.g. REJECT_INVALID_UTF8, REJECT_UNSAFE_NUMBER

# every admit/reject is a signed, hash-linked decision; verify the chain offline, export for the CCC
assert verify_guard_chain(gate.ledger.envelopes, pk).verified
gate.export_pack("./evidence")
```

For hybrid post-quantum signing (Falcon-1024 + ML-DSA-65), pass `mldsa_secret_key=` and `mldsa_public_key=` to `GuardService`.

### Layer 2: block at the edge, signed

```python theme={null}
from algovoi_edge_sentinel import EdgeSentinel, EdgePolicy, RequestContext, signing, verify_edge_chain
from algovoi_edge_sentinel.geo import InMemoryGeoProvider

pk, sk = signing.generate_keypair()
policy = EdgePolicy(deny_countries=("KP",), rate_max=100, rate_window_s=60,
                    require_nonce=True, deny_dids=("did:web:blocked",))
geo = InMemoryGeoProvider([{"cidr": "203.0.113.0/24", "country": "KP", "asn": 64500}])
sentinel = EdgeSentinel(decision_secret_key=sk, decision_public_key=pk, policy=policy, geo_provider=geo)

r = sentinel.evaluate(RequestContext(ip="203.0.113.5", agent_did="did:web:alice", nonce="n-001"))
if not r.allowed:
    deny(403, r.reason_code)                  # e.g. BLOCK_GEO_COUNTRY, BLOCK_RATE_EXCEEDED, BLOCK_REPLAY

assert verify_edge_chain(sentinel.ledger.envelopes, pk).verified
```

Run it ahead of an ASGI app (FastAPI or Starlette) so a block happens before your handler:

```python theme={null}
from algovoi_edge_sentinel.app import EdgeMiddleware
app.add_middleware(EdgeMiddleware, sentinel=sentinel)   # BLOCK returns 403 + named reason; decision chained
```

Production swaps are all injection points: a MaxMind or IP2Location backed `GeoProvider`, a shared rate and nonce backend, and a persistent decision store (`EDGE_SENTINEL_DB`, SQLite or PostgreSQL). The signing key is injected; licence enforcement stays offline and fail closed.

## Layer 1: input integrity

Two tools, both running **before** any RFC 8785 JCS or SHA-256 work touches the payload. They either accept, or reject with a named code. They never truncate and never repair.

### Substrate Guard (open)

A deterministic, structural input bounds gate. Every bound is a pure property of the parsed value (depth, count, length), so independent implementations enforce it identically. The bounds in force are content addressed by `profile_ref`, so a record can prove which limits admitted it. See the [full Substrate Guard page](/substrate-guard).

### Substrate Guard Pro (commercial)

Substrate Guard Pro keeps every bound of the open tier and adds a **string safety** bound: a string (value or object key) that is not valid UTF-8, such as a lone surrogate, is rejected with `REJECT_INVALID_UTF8` before canonicalization, so every conforming canonicalizer behaves identically on it. Each evaluation is then recorded as a Falcon-1024 (optionally hybrid ML-DSA-65) signed, hash linked **admission decision**, bound to the `profile_ref` in force and, on admit, to the value's canonical content address (`subject_ref`). A rejected value is never canonicalized and never carried, so the record is no PII.

| Reject code            | Bound exceeded                                |
| ---------------------- | --------------------------------------------- |
| `REJECT_OVER_SIZE`     | canonical UTF-8 size                          |
| `REJECT_OVER_DEPTH`    | nesting depth                                 |
| `REJECT_TOO_MANY_KEYS` | object keys                                   |
| `REJECT_OVER_ARRAY`    | array length                                  |
| `REJECT_OVER_STRING`   | string or key length                          |
| `REJECT_OVER_NODES`    | total nodes                                   |
| `REJECT_UNSAFE_NUMBER` | integer outside the safe range, or non finite |
| `REJECT_INVALID_UTF8`  | lone surrogate or non scalar code unit (Pro)  |

## Layer 2: runtime edge defence

### Edge Sentinel (commercial)

Edge Sentinel runs four runtime checks ahead of the service, first block wins, fail closed. It is deliberately a **runtime** layer: it is stateful (rate counters, a nonce cache) and environment aware (the client IP, a geo dataset, a clock). It is not claimed as a substrate or byte parity property; that determinism guarantee lives in Layer 1. What Edge Sentinel adds over a commodity WAF is that every allow and deny is offline verifiable, signed evidence bound to a content addressed policy (`policy_ref`), with a no PII subject (the IP, agent DID, key and wallet are hash folded; country and ASN stay in the clear for audit).

| Check             | Blocks on                                                     | Reject codes                                                                               |
| ----------------- | ------------------------------------------------------------- | ------------------------------------------------------------------------------------------ |
| IP, geo, ASN      | country, ASN, IP range (allow list or deny list)              | `BLOCK_GEO_COUNTRY`, `BLOCK_GEO_ASN`, `BLOCK_IP_CIDR`, `BLOCK_GEO_NOT_ALLOWLISTED`         |
| Rate, velocity    | sliding window request count per IP or key                    | `BLOCK_RATE_EXCEEDED`                                                                      |
| Identity          | agent DID, key id, wallet                                     | `BLOCK_DID_DENIED`, `BLOCK_KEY_DENIED`, `BLOCK_WALLET_DENIED`, `BLOCK_DID_NOT_ALLOWLISTED` |
| Replay, freshness | replayed nonce, stale or unparseable timestamp, missing nonce | `BLOCK_REPLAY`, `BLOCK_STALE`, `BLOCK_MISSING_NONCE`                                       |

It ships as an ASGI middleware (a block returns 403 with the named reason code, the decision already recorded) and as an embeddable evaluator. Geo resolution is pluggable, the signing key is injected, the decision store is pluggable (SQLite or PostgreSQL), and licence enforcement is offline and fail closed.

## One verifiable spine

Both layers emit the same decision shape: a Falcon-1024 (optionally hybrid ML-DSA-65) signed envelope, hash linked into an append only chain (`prev_entry_hash`), exported as the no PII evidence pack the Compliance Command Center verifies offline. Altering or dropping one decision breaks the chain from that point. In the Command Center the two chains surface as:

| Chain                                   | Entry type       | Posture label                           |
| --------------------------------------- | ---------------- | --------------------------------------- |
| Substrate Guard Pro admission decisions | `guard_decision` | Substrate Guard, admission decisions    |
| Edge Sentinel allow and deny decisions  | `edge_decision`  | Edge Sentinel, allow and deny decisions |

## Worked example: from decision to verified evidence

Both layers export the same evidence pack, so one flow covers either. Produce decisions and export a pack:

```python theme={null}
gate.export_pack("./pack")            # Substrate Guard Pro
# or:  sentinel.export_pack("./pack") # Edge Sentinel
# -> ./pack/{guard_decision_chain.json | edge_decision_chain.json} + public_key.b64
```

**Ingest into the Compliance Command Center.** The Command Center re-verifies every signature and hash link offline, then renders the chain as posture:

```python theme={null}
from algovoi_command_center import engine, posture

pack = engine.verify_pack("./pack")
assert pack.chains[0].verified        # signatures + hash links re-checked, no AlgoVoi service
post = posture.build_posture([pack])
# posture shows: "Substrate Guard, admission decisions" or "Edge Sentinel, allow and deny decisions"
```

See [Compliance Command Center](/compliance-command-center).

**Preserve under WORM custody in Records Vault.** Notarize the pack into a post-quantum, encrypted, RFC 3161 timestamped archive. It round-trips byte-identical, and the suite chain still verifies from the retrieved bytes; a single tampered byte fails retrieval.

```python theme={null}
chain = open("./pack/edge_decision_chain.json", "rb").read()
out = await vault.notarize(data=chain, title="edge/decisions", content_type="application/json")
got = await vault.retrieve(doc_hash=out["archive"]["doc_hash"], principal=auditor, reason="audit")
assert got == chain                   # preserved intact; tampering is detected on retrieve
```

(`vault` and `auditor` are configured as in the [Records Vault](/records-vault) guide.)

The chain is the join: Substrate Guard Pro and Edge Sentinel produce it, the Command Center verifies and aggregates it, Records Vault preserves it. One signed, no-PII, offline-verifiable spine across all three.

## Honest scope

Layer 1 is a deterministic, structural property of the payload, reproducible byte for byte across independent implementations: that is what makes it a substrate guarantee. Layer 2 is runtime: stateful and environment aware, and presented as such, never as a byte parity claim. Keeping that line sharp is what keeps the substrate claims credible. Neither layer adds a new cryptographic primitive over the frozen Layer 1 substrate; both reuse the RFC 8785 JCS canonicalisation, SHA-256, and the Falcon and ML-DSA signing already in the platform.

## FAQ

<AccordionGroup>
  <Accordion title="What is the difference between Substrate Guard and Substrate Guard Pro?">
    Substrate Guard (open, Apache 2.0) is the structural input-bounds gate: size, depth, object keys, array length, string length, total nodes, and number safety, with a content-addressed `profile_ref`. Substrate Guard Pro (commercial) keeps every one of those and adds a UTF-8 string-safety bound (it rejects lone surrogates and non scalar code units), then records every admit or reject as a Falcon-1024 signed, hash-linked admission decision. The open guard composes straight into the Pro tier.
  </Accordion>

  <Accordion title="Do I need both layers?">
    No. They are independent. Layer 1 (Substrate Guard Pro) secures input integrity before canonicalization; Layer 2 (Edge Sentinel) is runtime edge defence. Use either on its own or both together. The Security Suite licence covers both.
  </Accordion>

  <Accordion title="Does Edge Sentinel give the same byte-for-byte guarantee as the substrate?">
    No, and we are explicit about it. Layer 2 is a runtime layer: stateful (rate counters, a nonce cache) and environment aware (the client IP, a geo dataset, a clock). The deterministic, cross-language, byte-for-byte guarantee lives only in Layer 1. What Edge Sentinel adds is that every allow and deny is signed, offline-verifiable evidence, not a substrate property.
  </Accordion>

  <Accordion title="Does the suite move money or sit on the payment path?">
    No. It is a decision and evidence layer. It admits, rejects, allows, or blocks, and signs the decision. It never moves funds and never settles anything.
  </Accordion>

  <Accordion title="What personal data does it store?">
    None. Decisions are no-PII. The client IP, agent DID, key id, and wallet are hash folded into a `subject_ref`; only non-PII signals (country, ASN) stay in the clear for audit. A rejected value is never canonicalized and never carried in the record.
  </Accordion>

  <Accordion title="Does it phone home or need a network connection?">
    No. Licence verification is fully offline and fail closed, signature verification is offline, and the suite installs air-gapped from the bundle with every dependency vendored. No AlgoVoi service is contacted at install, run, or verify time.
  </Accordion>

  <Accordion title="Where does the geo data come from?">
    You bring it. Edge Sentinel takes a pluggable `GeoProvider`; plug in a MaxMind GeoLite2 or IP2Location backed provider in production. A small in-memory provider is included for tests and local runs. No geo dataset is bundled.
  </Accordion>

  <Accordion title="How are rate-limit and replay state handled across multiple processes?">
    The bundled rate counter and nonce cache are in-memory, correct for a single process. For a multi-process or multi-node deployment, inject a shared backend (for example Redis or a database) behind the same small interface. The signed decision chain is persisted separately via `EdgeStore` (SQLite or PostgreSQL, set by `EDGE_SENTINEL_DB`).
  </Accordion>

  <Accordion title="What happens if the licence is missing or expired?">
    The gate fails closed: `GuardService` and `EdgeSentinel` refuse to initialise without a valid, unexpired licence. Set `ALGOVOI_LICENSE_KEY` (or `ALGOVOI_LICENSE_FILE`) to the key issued at purchase.
  </Accordion>

  <Accordion title="How does an auditor verify a decision after the fact?">
    With the public key alone, offline. Each decision is a signed envelope in an append-only, hash-linked chain. `verify_guard_chain` and `verify_edge_chain` re-check every signature and hash link; altering or dropping one decision breaks the chain from that point. The same packs ingest into the Compliance Command Center, which renders them as a verified posture.
  </Accordion>

  <Accordion title="Is it post-quantum?">
    Yes. Every decision is signed with Falcon-1024 and can be hybrid co-signed with ML-DSA-65 (FIPS 204), so a hybrid-aware verifier requires both. The two schemes rest on different hard problems, so a future break of one still leaves forgery requiring a break of the other.
  </Accordion>

  <Accordion title="Can I customise the bounds and policy, and prove which were in force?">
    Yes. Substrate Guard Pro takes a `Profile` (content-addressed by `profile_ref`); Edge Sentinel takes an `EdgePolicy` (content-addressed by `policy_ref`). Each decision carries the ref of the bounds or policy that produced it, so a verifier can prove which rules were enforced, and a changed policy is rotation-detectable.
  </Accordion>
</AccordionGroup>
