Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 52 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,58 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Added

- **Phase 9.6 — `sovereign-sdk-airlock` outbound governance boundary** (new workspace
member `packages/sovereign-airlock/`): Introduces the model-neutral Airlock
lifecycle boundary that inspects, evaluates, minimises, and records structured
payloads before they cross a sovereign perimeter (SAR-0004).

- **`NormalizedPayload` frozen dataclass** (`payload.py`): Provider-neutral
inspection surface extracted from any transport-specific request format.
Factory functions `normalize_openai()`, `normalize_anthropic()`, and
`normalize_raw()` translate protocol-specific schemas into the stable governance
surface without leaking transport state.

- **`AirlockTelemetry` frozen dataclass** (`telemetry.py`): Four Component C sieve
metrics (`raw_tokens`, `sieved_tokens`, `tax_savings_percentage`, `payload_hash`).
`from_sieve_output()` classmethod includes an explicit `raw_tokens == 0` guard
defaulting `tax_savings_percentage` to `0.0`, preventing ZeroDivisionError on
zero-token or null-pass payloads.

- **`PolicyEngine(config_path)`** (`policy.py`): Deterministic, fully offline YAML
rule evaluator supporting `raw`, `fields`, and `telemetry` evaluation scopes with
`allow`, `warn`, and `deny` actions. Global `max_token_ceiling` and
`prose_tax_warning_threshold` configuration. `AirlockConfigurationError` raised
on malformed, structurally invalid, or regex-invalid configuration. All regex
patterns pre-compiled via `re.compile()` at init time; malformed patterns raise
`AirlockConfigurationError` immediately rather than deferring to a runtime
`re.error`. `check_prose_tax_threshold(telemetry)` evaluates post-sieve savings
against the configured fractional threshold and returns non-fatal warning messages.

- **`NormalizedPayload` deep immutability** (`payload.py`): `__post_init__` converts
`content` to `tuple[str, ...]`, `metadata` to `types.MappingProxyType[str, Any]`,
and each `tools` entry to `types.MappingProxyType[str, Any]`. Constructor still
accepts mutable `list`/`dict` equivalents; conversion is transparent to all
factory functions.

- **`ReceiptBuilder(key_manager, ledger)`** (`receipt.py`): Assembles boundary
crossing metadata and produces a signed `ForensicReceipt` via
`SovereignKeyManager.generate_receipt()`. Ledger write failure is non-fatal —
a `WARNING` log is emitted and the receipt is returned regardless, so outbound
transmission is never blocked by a storage-tier anomaly.

- **`AirlockBoundary(policy_path, signing_key, ledger)`** (`boundary.py`):
Async orchestrator implementing the four-component transaction lifecycle. `deny`
verdict raises `AirlockPolicyViolation` before any sieve or ledger operation.
Post-sieve prose tax threshold check via `PolicyEngine.check_prose_tax_threshold()`;
threshold warnings appended to `verdict.warnings` before evidence generation and
sealed in receipt metadata.

- **66-case test suite** across `test_policy.py` (22), `test_telemetry.py` (10),
`test_receipts.py` (10), and `test_boundary.py` (24). Round 1 PR remediation adds
7 cases: `test_raises_on_malformed_regex_pattern` (`TestPolicyLoading`),
`TestProseTaxThreshold` (2 cases), and `TestNormalizedPayloadImmutability` (4 cases).
**66 passed, 0 failed (airlock); 476 passed, 1 skipped (workspace).**

- **Phase 9.5 — `sovereign-edge` sensor ingestion bridge** (new workspace member
`packages/sovereign-edge/`): Introduces the middleware pipeline that intercepts
sealed sensor wire frames from `sovereign-sensor`, applies the `sovereign-sieve`
Expand Down
53 changes: 53 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,21 @@ This repository is managed as an integrated `uv` workspace separating the crypto
│ │ └── tests/
│ │ └── test_edge.py
│ │
│ ├── sovereign-airlock/ # Outbound governance boundary (SAR-0004)
│ │ ├── src/sovereign_airlock/
│ │ │ ├── boundary.py # AirlockBoundary — async 4-component orchestrator
│ │ │ ├── payload.py # NormalizedPayload — provider-neutral inspection surface
│ │ │ ├── policy.py # PolicyEngine — YAML rule evaluation (raw/fields/telemetry)
│ │ │ ├── telemetry.py # AirlockTelemetry — sieve convergence metrics
│ │ │ ├── receipt.py # ReceiptBuilder — evidence assembly and ledger commit
│ │ │ ├── exception.py # AirlockPolicyViolation, AirlockConfigurationError
│ │ │ └── __init__.py
│ │ └── tests/
│ │ ├── test_boundary.py
│ │ ├── test_policy.py
│ │ ├── test_receipts.py
│ │ └── test_telemetry.py
│ │
│ ├── sovereign-runtime/ # Compute/Execution tier (tool & model isolation)
│ │ └── src/sovereign_runtime/
│ │ ├── router.py # Intent-based pre-flight namespace exposure
Expand Down Expand Up @@ -215,6 +230,44 @@ Three fortification properties are enforced at the architecture level:

---

## `sovereign-sdk-airlock` — Outbound Governance Boundary

For applications and agentic runtimes that must govern what leaves the sovereign perimeter,
`sovereign-sdk-airlock` provides the deliberate inspection and containment boundary defined
by SAR-0004 (Airlock, Not Gateway):

```python
import asyncio
from sovereign_ledger import SovereignLedger
from sovereign_airlock import AirlockBoundary, AirlockPolicyViolation, normalize_openai

ledger = SovereignLedger(".keys/sovereign_audit.db")
boundary = AirlockBoundary(
policy_path="policy.yaml",
signing_key=".keys/",
ledger=ledger,
)

try:
result = await boundary.process(normalize_openai(request))
# result.sieved_content — minimised payload ready for transmission
# result.telemetry.payload_hash — SHA-256 of the raw pre-sieve content
# result.receipt["signature"] — Ed25519 boundary crossing evidence
# result.policy_warnings — non-fatal warn-rule messages
except AirlockPolicyViolation as exc:
# Payload blocked by a deny rule — do not transmit
raise
```

Policy rules are declared in a local YAML file and evaluated in three scopes:
- `raw` — regex pattern matched against the flat combined content string
- `fields` — pattern matched against named structured fields (`messages.content`, `tools.description`, etc.)
- `telemetry` — numeric threshold applied to `raw_tokens`, `sieved_tokens`, or `tax_savings_percentage`

Airlock is transport-agnostic. `normalize_openai()`, `normalize_anthropic()`, and `normalize_raw()` convert any request format into the provider-neutral `NormalizedPayload` before governance evaluation begins.

---

## `sovereign-sensor` — Bare-Metal Write-Side Custody

For IoT and embedded systems where data must be sealed cryptographically at the exact point of genesis — before any network hop or cloud ingestion — `sovereign-sensor` provides a MicroPython-compatible Hardware Abstraction Layer that runs on ESP32 and Raspberry Pi Pico with zero external dependencies:
Expand Down
81 changes: 81 additions & 0 deletions ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -1225,6 +1225,87 @@ committed = pipeline.drain_buffer()

---

## Phase 9.6 — Outbound Governance Boundary (`sovereign-sdk-airlock`) — Shipped ✓

**Target:** Introduce the model-neutral outbound governance boundary that inspects,
evaluates, minimises, and records structured payloads before they cross a sovereign
perimeter and enter an external computational system. Implements the four-component
Airlock lifecycle defined in SAR-0004 (Airlock, Not Gateway).

```python
import asyncio
from sovereign_ledger import SovereignLedger
from sovereign_airlock import AirlockBoundary, normalize_openai

ledger = SovereignLedger(".keys/sovereign_audit.db")
boundary = AirlockBoundary(
policy_path="policy.yaml",
signing_key=".keys/",
ledger=ledger,
)

result = await boundary.process(normalize_openai(request))
# result.sieved_content — Prose-Tax-minimised payload for transmission
# result.telemetry.payload_hash — SHA-256 of the raw pre-sieve content
# result.receipt["signature"] — Ed25519 boundary crossing evidence
# result.policy_warnings — non-fatal warn-rule messages
```

**Delivered:**

* [x] `NormalizedPayload` frozen dataclass (`payload.py`) — provider-neutral inspection
surface with `source`, `content`, `metadata`, `tools`, and `token_estimate` fields;
factory functions `normalize_openai()`, `normalize_anthropic()`, and `normalize_raw()`
translate transport-specific request schemas to the common governance surface
* [x] `AirlockTelemetry` frozen dataclass (`telemetry.py`) — four Component C sieve
metrics (`raw_tokens`, `sieved_tokens`, `tax_savings_percentage`, `payload_hash`);
`from_sieve_output()` classmethod re-derives `tax_savings_percentage` independently
of `SieveOutput` with an explicit `raw_tokens == 0` guard defaulting to `0.0`
* [x] `PolicyEngine(config_path)` (`policy.py`) — deterministic, offline YAML rule
evaluator supporting `raw` (regex over flat content), `fields` (dot-notation field
extraction), and `telemetry` (numeric metric threshold) scopes; actions `allow`,
`warn`, `deny`; global `max_token_ceiling` check; `AirlockConfigurationError` on
invalid YAML or unrecognised scope/action values
* [x] `PolicyRule` and `PolicyVerdict` frozen and mutable dataclasses (`policy.py`) —
immutable rule descriptor and mutable evaluation result carrying `allowed`,
`violations`, and `warnings` lists
* [x] `ReceiptBuilder(key_manager, ledger)` (`receipt.py`) — assembles boundary
crossing metadata (`boundary`, `source_transport`, `prose_tax_summary`,
`policy_warnings`), signs via `SovereignKeyManager.generate_receipt()`, and commits
to `SovereignLedger.append_receipt()`; ledger write failure emits `WARNING`-level
log and returns the receipt regardless — outbound transmission is never blocked
* [x] `AirlockBoundary(policy_path, signing_key, ledger)` (`boundary.py`) — async
orchestrator implementing the four-component transaction lifecycle: policy evaluation
→ sieve convergence → telemetry assembly → evidence generation; `deny` verdict raises
`AirlockPolicyViolation` before any sieve or ledger operation; receipt generation
failure is non-fatal (logged, `receipt=None` in result)
* [x] `AirlockResult` dataclass (`boundary.py`) — structured result carrying
`sieved_content`, `telemetry`, `receipt`, and `policy_warnings`
* [x] `AirlockPolicyViolation(RuntimeError)` and `AirlockConfigurationError(ValueError)`
(`exception.py`) — domain exceptions for deny-action enforcement and configuration
invariant violations respectively
* [x] `packages/sovereign-airlock/pyproject.toml` — workspace member at version
`1.4.0`; runtime dependencies: `sovereign-sdk-core>=1.3.0`,
`sovereign-sdk-ledger>=1.3.0`, `sovereign-sdk-sieve>=1.3.0`, `pyyaml>=6.0`
* [x] 66-case test suite across four files (`TestAirlockTelemetry`: 10;
`TestPolicyLoading` + `TestRawScopeEvaluation` + `TestFieldsScopeEvaluation` +
`TestTelemetryScopeEvaluation` + `TestGlobalCeiling`: 22; `TestReceiptBuilder`: 10;
`TestAirlockBoundaryHappyPath` + `TestAirlockBoundaryPolicyDenial` +
`TestAirlockBoundaryPolicyWarning` + `TestAirlockBoundaryTransportNeutrality` +
`TestAirlockBoundaryResiliency` + `TestProseTaxThreshold` +
`TestNormalizedPayloadImmutability`: 24) covering frozen telemetry dataclass
immutability, zero-token ZeroDivisionError guard, payload hash derivation,
YAML config loading, all three rule scopes, all three policy actions, global
ceiling enforcement, regex boot-time compilation with `AirlockConfigurationError`
on malformed patterns, prose tax threshold warning lifecycle, deep payload
immutability (`tuple` + `MappingProxyType`), receipt metadata invariants,
cryptographic verifiability, non-fatal ledger write failure, transport-neutral
normalisation (OpenAI, Anthropic, raw), deny/warn/allow lifecycle correctness,
and full async `AirlockBoundary.process()` transaction lifecycle end-to-end.
**66 passed, 0 failed (airlock); 476 passed, 1 skipped (workspace).**

---

## Phase 10 — Isolated Context Vault & Governance Server (`sovereign-vault`)

**Target:** Implement the "Sovereign Vault" architecture as an isolated local orchestration
Expand Down
120 changes: 120 additions & 0 deletions packages/sovereign-airlock/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
# sovereign-sdk-airlock

Model-neutral outbound governance boundary for the Sovereign Systems SDK.

Inspects, evaluates, minimises, and records structured payloads before they cross
a sovereign perimeter and enter an external computational system.

---

## Architecture

`sovereign-sdk-airlock` implements the four-component lifecycle defined in the
Airlock Specification (SAR-0004):

| Component | Responsibility |
|---|---|
| **Boundary Interception** | Capture normalised outbound payloads; transport-agnostic |
| **Policy Engine** | Evaluate local YAML governance rules (`raw`, `fields`, `telemetry` scopes) |
| **Sieve Convergence** | Deterministic context minimisation via `sovereign-sdk-sieve` |
| **Evidence Generation** | Immutable `ForensicReceipt` committed to `sovereign-sdk-ledger` |

---

## Quick Start

```python
import asyncio
from sovereign_ledger import SovereignLedger
from sovereign_airlock import AirlockBoundary, normalize_openai

ledger = SovereignLedger(".keys/sovereign_audit.db")
boundary = AirlockBoundary(
policy_path="policy.yaml",
signing_key=".keys/",
ledger=ledger,
)

request = {
"model": "gpt-4o",
"messages": [{"role": "user", "content": "Analyse the quarterly report."}],
}

async def main():
result = await boundary.process(normalize_openai(request))
print(result.sieved_content)
print(result.telemetry.tax_savings_percentage, "% Prose Tax savings")
print(result.receipt["payload_hash"])

asyncio.run(main())
```

---

## Policy Configuration

```yaml
version: "1.0"

global:
max_token_ceiling: 40000
prose_tax_warning_threshold: 0.35

rules:

- name: block_private_keys
scope: raw
pattern: "-----BEGIN PRIVATE KEY-----"
action: deny

- name: guard_internal_namespaces
scope: fields
fields:
- messages.content
- tools.description
pattern: "internal\\.sovereign\\.local"
action: warn

- name: excessive_context
scope: telemetry
metric: raw_tokens
threshold: 30000
action: warn
```

### Policy Actions

| Action | Behaviour |
|---|---|
| `allow` | Explicit pass-through — no effect on verdict |
| `warn` | Appends to `AirlockResult.policy_warnings`; transmission continues |
| `deny` | Raises `AirlockPolicyViolation`; payload blocked |

---

## Transport Normalisation

Airlock governs boundaries, not transports. Use the factory functions to convert
provider-specific request formats into the provider-neutral `NormalizedPayload`:

```python
from sovereign_airlock import normalize_openai, normalize_anthropic, normalize_raw

# OpenAI-compatible chat completion request
payload = normalize_openai({"messages": [...], "model": "gpt-4o"})

# Anthropic-compatible messages API request
payload = normalize_anthropic({"messages": [...], "system": "...", "model": "claude-sonnet-4-6"})

# Raw string
payload = normalize_raw("plain text to govern")
```

---

## Invariants

- Zero external network dependencies — all operations execute on local silicon.
- Ledger write failure is non-fatal; outbound transmission is never blocked by a storage anomaly.
- Context minimisation uses `sovereign-sdk-sieve` exclusively — no model-based compression.
- All policy evaluation is deterministic and auditable.
32 changes: 32 additions & 0 deletions packages/sovereign-airlock/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
[build-system]
requires = ["setuptools>=77.0.0"]
build-backend = "setuptools.build_meta"

[project]
name = "sovereign-sdk-airlock"
version = "1.4.0"
description = "Model-neutral outbound governance boundary for sovereign perimeter inspection, policy enforcement, and evidence generation"
readme = "README.md"
requires-python = ">=3.12"
license = { text = "MIT" }
dependencies = [
"sovereign-sdk-core>=1.3.0",
"sovereign-sdk-ledger>=1.3.0",
"sovereign-sdk-sieve>=1.3.0",
"pyyaml>=6.0",
]
classifiers = [
"License :: OSI Approved :: MIT License",
"Programming Language :: Python :: 3.12",
"Intended Audience :: Developers",
"Topic :: Security",
"Topic :: Software Development :: Libraries",
]

[project.urls]
Homepage = "https://github.com/kenwalger/sovereign-sdk"
Repository = "https://github.com/kenwalger/sovereign-sdk"
Changelog = "https://github.com/kenwalger/sovereign-sdk/blob/main/CHANGELOG.md"

[tool.setuptools.packages.find]
where = ["src"]
Loading
Loading