feat(casan): establish assurance kernel and harden control plane
This commit is contained in:
@@ -0,0 +1,141 @@
|
||||
# CASAN Assurance Kernel
|
||||
|
||||
Status: implemented contract layer, version `1.0.0` (2026-08-02).
|
||||
|
||||
## Purpose and maturity
|
||||
|
||||
CASAN now has a framework-independent wire contract and deterministic policy
|
||||
primitives outside the native Bash topology. The native harness remains
|
||||
operational and is the first compatibility adapter; the Agentic Bridge is the
|
||||
second adapter. This is an incremental extraction, not a rewrite of H1–H7.
|
||||
|
||||
CASAN may describe this layer as an **Assurance Kernel contract and policy
|
||||
foundation with two conforming adapters**. It must not claim that every legacy
|
||||
loop, graph, report, or third-party runtime has migrated to the kernel.
|
||||
|
||||
## Boundary
|
||||
|
||||
```text
|
||||
Execution runtime
|
||||
-> runtime adapter
|
||||
-> canonical Assurance Kernel envelope
|
||||
-> deterministic policy / verification / evidence services
|
||||
-> runtime-specific enforcement mechanisms
|
||||
```
|
||||
|
||||
The kernel does not execute models. It does not infer security decisions from
|
||||
model output. Runtime-specific data is allowed only under a namespace such as
|
||||
`casan.runtime.casan-native-harness` or `casan.runtime.agentic-bridge`.
|
||||
|
||||
## Canonical contract
|
||||
|
||||
The canonical source is
|
||||
`packages/casan-harness/schemas/assurance-kernel.schema.json`. It is JSON Schema
|
||||
Draft 2020-12 and uses `schema_version: 1.0.0`.
|
||||
|
||||
The envelope defines:
|
||||
|
||||
- `ExecutionRun`: identity, parent, scope, environment, runtime, mode, goal,
|
||||
timestamps, status, risk summary, evidence manifest and correlation.
|
||||
- `ExecutionStep`: causal position, actor/action/resource, context references,
|
||||
policy decisions, tool invocation, verification, evidence and outcome.
|
||||
- `Actor`: human, agent, child agent, model, tool, service account, runtime,
|
||||
approver or policy engine with issuer, trust and authentication evidence.
|
||||
- `Delegation`: authority, resource scope, expiry, maximum depth, parent,
|
||||
revocation and approval.
|
||||
- `ContextItem`: origin, trust, content hash, transforms, compression lineage,
|
||||
instruction/data classification and injection scan.
|
||||
- `Action` and `ResourceAccess`: canonical class, operation, authority,
|
||||
side-effect level, resource and environment.
|
||||
- `PolicyDecision`: versioned policy, structured decision, reason codes, risk
|
||||
facts, enforcement point, engine identity, time and evidence reference.
|
||||
- `RuntimeConstraint` and `RuntimeCapabilities`: honest limits and supported
|
||||
cancellation/intervention mechanisms.
|
||||
- `VerificationRequirement` and `VerificationResult`: expected versus actual
|
||||
result, evidence, independence and failure severity.
|
||||
- `Claim`, `EvidenceItem` and `TraceLink`: bidirectional claim support,
|
||||
integrity metadata, producer, artifact, validation, retention and typed links.
|
||||
- `Approval` and `Intervention`: explicit decisions and runtime support status.
|
||||
- `Outcome`: four independent results for execution, assurance,
|
||||
certification and business effect.
|
||||
|
||||
## Deterministic kernel services
|
||||
|
||||
The stdlib-only Python implementation is under
|
||||
`packages/casan-harness/kernel/`.
|
||||
|
||||
`policy.py` provides:
|
||||
|
||||
- Machine-readable action classification from
|
||||
`config/action-classes.json`.
|
||||
- Effective risk as the maximum of content, action, resource, identity and
|
||||
environment risk.
|
||||
- H2 registry configuration validation and fail-closed dependency decisions.
|
||||
- Single-step failure-policy selection with `halt`, `quarantine`,
|
||||
`require_approval` and `record_only`.
|
||||
- Production trust capability evaluation.
|
||||
|
||||
`contracts.py` provides builders and an enforcement-boundary verifier. The
|
||||
verifier rejects unsupported schema versions, invalid actor/step references,
|
||||
observed-only certification, broken claim/evidence links, evidence digest
|
||||
tampering, delegation cycles and excess delegation depth.
|
||||
|
||||
`taxonomy.py` separates `RuntimeControl.Hn`, `ReadinessCheck.Hn`,
|
||||
`ReportDimension.Hn` and `CertificationClaim.Hn`. A legacy `Hn` remains a
|
||||
display alias only and never authorizes cross-category interpretation.
|
||||
|
||||
`supervision.py` negotiates interventions against declared runtime
|
||||
capabilities. Unsupported pause, rollback, cancellation, authority reduction
|
||||
or quarantine returns `unsupported`; it never reports a fictitious success.
|
||||
|
||||
## Action policy
|
||||
|
||||
The action registry includes read, write, delete, database mutation,
|
||||
migration, deployment, release, credential access, identity/permission change,
|
||||
external network side effect, infrastructure modification and unknown actions.
|
||||
|
||||
High-impact actions have a high minimum risk, require an identified actor,
|
||||
explicit approval and evidence. Benign text cannot reduce that floor. Unknown
|
||||
shell operations also fail toward high risk. H2 registry enforcement and H5
|
||||
approval remain separate defense-in-depth decisions.
|
||||
|
||||
## Outcome semantics
|
||||
|
||||
The following states are deliberately distinct:
|
||||
|
||||
```text
|
||||
execution_result = success | failed | cancelled | quarantined | ...
|
||||
assurance_result = passed | failed | degraded | not_evaluated | ...
|
||||
certification_result = certified | non_certified | ineligible | ...
|
||||
business_result = achieved | not_achieved | partial | not_evaluated | ...
|
||||
```
|
||||
|
||||
A telemetry append can succeed while `execution_result=failed`. A failed
|
||||
side-effecting command defaults to `halt` in enforce/production mode and cannot
|
||||
produce a successful completion or normal certification.
|
||||
|
||||
## Evidence integrity and trust
|
||||
|
||||
Canonical evidence metadata is linked to claims and carries a SHA-256 digest.
|
||||
This detects local mutation and broken references. It is not, by itself, an
|
||||
external trust root or WORM guarantee. Production certification separately
|
||||
requires external signing and an external immutable anchor.
|
||||
|
||||
## Compatibility rules
|
||||
|
||||
- New envelopes use semantic version `1.0.0`; incompatible schema changes
|
||||
require a new major version.
|
||||
- Additive runtime fields belong under a namespaced `extensions` object.
|
||||
- The native and Agentic Bridge formats remain readable and are dual-emitted
|
||||
with canonical envelopes during migration.
|
||||
- Legacy evidence is not silently reinterpreted as kernel-validated evidence.
|
||||
- Observe-mode and unsafe-development-bypass runs are never certified.
|
||||
- Audit chain format v1 remains verifiable while new records use v2 fields.
|
||||
|
||||
## Claims and residual limits
|
||||
|
||||
CASAN can claim deterministic shared action policy, canonical execution and
|
||||
evidence contracts, and cross-runtime conformance for the native harness and
|
||||
Agentic Bridge. It cannot yet claim universal runtime adoption, complete
|
||||
multi-runtime supervision, external infrastructure availability, or
|
||||
data-backed H1–H7 dossiers beyond the reports actually backed by evidence.
|
||||
@@ -0,0 +1,113 @@
|
||||
# CASAN Control Plane
|
||||
|
||||
Status: production-capable packaged authentication and trust configuration;
|
||||
external infrastructure remains operator-provisioned.
|
||||
|
||||
## Deployment modes
|
||||
|
||||
### Local development
|
||||
|
||||
- Default bind: `127.0.0.1`.
|
||||
- `CASAN_CP_AUTH_MODE=local` is allowed only on loopback and outside production.
|
||||
- Local actor headers are explicitly development identity and are not a
|
||||
production authentication claim.
|
||||
|
||||
### Networked or production
|
||||
|
||||
- `CASAN_CP_AUTH_MODE=jwt` is mandatory.
|
||||
- Production requires RS256 verification, a mounted public key, exact issuer
|
||||
and audience, and a clock skew from 0 through 300 seconds.
|
||||
- Missing or invalid configuration refuses startup before NestJS listens.
|
||||
- HS256 is retained only for deterministic non-production tests.
|
||||
|
||||
## Packaged identity boundary
|
||||
|
||||
```text
|
||||
Browser
|
||||
-> enterprise OIDC
|
||||
-> oauth2-proxy session
|
||||
-> Nginx auth_request
|
||||
removes X-CASAN-* and forwarded identity headers
|
||||
forwards signed Bearer access token
|
||||
-> NestJS AuthProvider
|
||||
verifies RS256 signature, iss, aud, sub, exp, nbf and iat
|
||||
-> VerifiedClaims
|
||||
-> CASAN RBAC role mapping and scoped request identity
|
||||
```
|
||||
|
||||
Nginx is a TLS/session boundary, not the identity authority for the API. The
|
||||
API ignores caller-supplied identity assertions and derives actor, role,
|
||||
tenant and project only after token verification.
|
||||
|
||||
## Authentication implementation
|
||||
|
||||
`backend/src/common/auth-provider.ts` defines:
|
||||
|
||||
- `AuthProvider` and `JwtAuthProvider`.
|
||||
- Typed `VerifiedClaims` and `AuthenticationDecision`.
|
||||
- RS256/HS256 signature verification using Node's standard crypto APIs.
|
||||
- Issuer, audience, expiry, not-before, issued-at and bounded-skew checks.
|
||||
- Safe tenant/project syntax validation.
|
||||
- Structured authentication audit evidence without raw tokens.
|
||||
- Middleware that overwrites request identity only from verified claims.
|
||||
|
||||
`auth-context.ts` refuses direct header use in JWT mode unless the middleware
|
||||
has marked the identity verified. Existing RBAC services then map verified
|
||||
groups and continue to produce governance/authorization evidence.
|
||||
|
||||
## Production configuration
|
||||
|
||||
Required runtime variables:
|
||||
|
||||
```text
|
||||
CASAN_PROFILE=prod
|
||||
CASAN_CP_AUTH_MODE=jwt
|
||||
CASAN_CP_JWT_ISSUER=https://...
|
||||
CASAN_CP_JWT_AUDIENCE=...
|
||||
CASAN_CP_JWT_PUBLIC_KEY_FILE=/run/casan-idp/idp-public.pem
|
||||
CASAN_CP_JWT_ROLE_CLAIM=groups
|
||||
CASAN_CP_JWT_TENANT_CLAIM=casan_tenant
|
||||
CASAN_CP_JWT_PROJECT_CLAIM=casan_project
|
||||
CASAN_CP_JWT_CLOCK_SKEW_SECONDS=60
|
||||
```
|
||||
|
||||
The host path is configured as `CASAN_CP_IDP_PUBLIC_KEY` and mounted read-only.
|
||||
oauth2-proxy must set xauthrequest output and pass the access token. Images for
|
||||
API, UI and oauth2-proxy must be digest-pinned.
|
||||
|
||||
`production-preflight.sh` validates:
|
||||
|
||||
- TLS hostname, expiry and matching private key.
|
||||
- IdP public key readability and RSA public-key format.
|
||||
- HTTPS OIDC issuer, secure cookies and token forwarding.
|
||||
- Matching oauth2-proxy client ID and API audience.
|
||||
- Matching issuer and bounded JWT clock skew.
|
||||
- External Vault/KMS signing and S3 Object Lock provider selection.
|
||||
- Live short-lived non-root Vault token lookup.
|
||||
- A real Object Lock COMPLIANCE anchor write.
|
||||
- Digest-pinned images and valid Compose/Nginx configuration.
|
||||
|
||||
## Authentication evidence
|
||||
|
||||
Each production authentication decision appends a JSONL record under
|
||||
`CASAN_STATE_ROOT/logs/auth/decisions.jsonl` with category, policy, decision,
|
||||
reason, actor, issuer, scope and request method/path. Tokens and secrets are
|
||||
never written. A failure to authenticate returns HTTP 401 with a stable reason
|
||||
code; it is not converted to viewer access.
|
||||
|
||||
## Local production-like smoke
|
||||
|
||||
`docker-compose.control-panel.local.yml` uses the same bearer-token path. The
|
||||
smoke script generates an ephemeral RSA keypair, mounts the private key into
|
||||
the mock IdP and the public key into the API, and enables token forwarding.
|
||||
This validates the boundary without treating the mock IdP as production.
|
||||
|
||||
## Residual limitations
|
||||
|
||||
- Public-key rotation currently requires replacing the mounted key and
|
||||
restarting the API; automated JWKS discovery and rollover are not present.
|
||||
- Enterprise IdP, managed TLS, Vault and S3 are not provisioned by the repo.
|
||||
- Local tests validate crypto and provider contracts, but do not prove a real
|
||||
tenant's claim mapping, token lifecycle, network policy or key rotation.
|
||||
- The Control Plane is production-capable for this packaged deployment model;
|
||||
it is not yet a universal multi-runtime scheduler or supervisor.
|
||||
@@ -0,0 +1,95 @@
|
||||
# CASAN Execution Adapters
|
||||
|
||||
## Adapter contract
|
||||
|
||||
An execution adapter translates runtime events into the canonical Assurance
|
||||
Kernel envelope without replacing H2, H4, H5 or other existing controls.
|
||||
|
||||
```text
|
||||
runtime event
|
||||
-> adapter mapping
|
||||
-> ExecutionRun / ExecutionStep / Actor / Action
|
||||
-> PolicyDecision / VerificationResult / EvidenceItem / Outcome
|
||||
-> common verifier
|
||||
```
|
||||
|
||||
Adapter code lives in `packages/casan-harness/kernel/adapters.py`. The canonical
|
||||
schema and policy code must not import a native runtime.
|
||||
|
||||
## Native harness adapter
|
||||
|
||||
`NativeHarnessAdapter` maps the Bash harness execution identity, action,
|
||||
command, actor, environment, policy decisions, evidence and final outcome. The
|
||||
native entrypoint in `scripts/bash/casan-harness.sh` continues to emit its
|
||||
existing metrics and completion protocol while atomically writing a canonical
|
||||
bundle to `CASAN_STATE_ROOT/logs/kernel/`.
|
||||
|
||||
If a phase exits non-zero, the harness best-effort emits a canonical failed
|
||||
bundle before propagating the original exit code. This emission never masks
|
||||
the command failure. A successful run reports execution, assurance and
|
||||
certification separately.
|
||||
|
||||
The adapter is compatibility code: existing H gates remain the enforcement
|
||||
implementation. The kernel does not duplicate them.
|
||||
|
||||
## Agentic Bridge adapter
|
||||
|
||||
`AgenticBridgeAdapter` maps lifecycle admission, pre-tool, post-tool, telemetry
|
||||
and finalize events. The bridge now:
|
||||
|
||||
- Uses the shared action classifier and risk floors.
|
||||
- Defaults H2 registry enforcement on in enforce mode.
|
||||
- Converts missing, unreadable, timed-out, malformed or failed H2 dependencies
|
||||
into structured policy decisions.
|
||||
- Distinguishes failed tool outcome from successful telemetry recording.
|
||||
- Applies the single-step failure policy.
|
||||
- Restricts certification using enforcement mode, assurance strength and trust
|
||||
capability.
|
||||
- Dual-emits the canonical bundle alongside its v20 lifecycle records.
|
||||
|
||||
The Agentic Bridge remains a single-model integration: it performs admission,
|
||||
policy, evidence and finalization but does not invoke a model itself.
|
||||
|
||||
## Cross-runtime conformance
|
||||
|
||||
`tests/assurance-kernel-tests.py` runs the same invariants through both
|
||||
adapters. It proves:
|
||||
|
||||
1. Dangerous action classification is identical.
|
||||
2. Missing actor identity denies the same high-impact action.
|
||||
3. Missing H2 enforcement denies in enforce mode.
|
||||
4. Approval and evidence requirements are identical.
|
||||
5. Claim/evidence relationships use the same contract.
|
||||
6. Observed-only execution cannot be certified.
|
||||
7. Execution, assurance and certification outcomes remain distinct.
|
||||
8. Correlation and parent causation are preserved.
|
||||
9. The same verifier detects evidence tampering.
|
||||
10. Runtime details are namespaced extensions rather than kernel assumptions.
|
||||
|
||||
The conformance suite currently covers two paths. A future adapter must pass
|
||||
the same suite before being described as kernel-conforming.
|
||||
|
||||
## Capability negotiation
|
||||
|
||||
Adapters declare `canCancel`, `canPause`, `canResume`, `canRollback`,
|
||||
`canReduceAuthority` and `canQuarantine`. These are conservative. The native
|
||||
harness currently declares no general asynchronous intervention capability;
|
||||
the Agentic Bridge declares quarantine support only where its lifecycle can
|
||||
represent it. Unsupported interventions return an explicit result.
|
||||
|
||||
## Adding an adapter
|
||||
|
||||
1. Preserve the runtime's existing security controls.
|
||||
2. Map stable run, step, actor, correlation and causation identities.
|
||||
3. Use the shared action policy; do not create a weaker parallel classifier.
|
||||
4. Emit policy decisions and evidence references, not boolean-only results.
|
||||
5. Put runtime-only fields in `casan.runtime.<adapter>` extensions.
|
||||
6. Validate with `validate_bundle` and the JSON Schema.
|
||||
7. Add the full cross-runtime invariant matrix.
|
||||
8. Do not mark legacy or observe-only records certified.
|
||||
|
||||
## Residual migration scope
|
||||
|
||||
Custom loop runners, graphs and every historical event producer have not been
|
||||
rewritten. They may continue using legacy formats, but they cannot inherit
|
||||
kernel-conformance claims until they receive an adapter and pass conformance.
|
||||
@@ -0,0 +1,109 @@
|
||||
# CASAN Trust Boundaries
|
||||
|
||||
## Trust model
|
||||
|
||||
CASAN separates enforcement, evidence, identity, execution isolation and
|
||||
external trust. Passing one boundary never implies that another passed.
|
||||
|
||||
| Boundary | Development/local | Production/strict |
|
||||
|---|---|---|
|
||||
| Control Plane identity | Explicit loopback local identity | In-process RS256 JWT verification required |
|
||||
| H2 tool authority | Enforce defaults on; explicit bypass is high-severity/non-certifiable | Enforce on; bypass configuration rejected |
|
||||
| H5 high-impact action | Approval and actor required by action floor | Strict signed approval plus external trust requirements |
|
||||
| Tool isolation | Static fallback only when explicitly enabled in dev/test | Container isolation required; unavailable backend denies |
|
||||
| Audit signing | Local OpenSSL permitted and labelled local | Vault/KMS external signing required |
|
||||
| Immutable anchor | Local hash chain permitted and labelled local | External Object Lock/WORM provider required |
|
||||
| Certification | Local/observed limitations disclosed | Unsafe fallback or emergency override cannot normally certify |
|
||||
|
||||
## H2 enforcement dependency
|
||||
|
||||
H2 returns a structured `PolicyDecision`, never a boolean-only decision. Missing
|
||||
file, unreadable file, timeout, malformed protocol, missing runtime and internal
|
||||
execution errors have stable reason codes. In enforce mode all dependency
|
||||
errors deny. In observe mode the operation may be observed, but assurance is
|
||||
degraded and certification is forbidden.
|
||||
|
||||
Registry enforcement defaults on for side-effecting native and Agentic Bridge
|
||||
paths. `CASAN_H2_REGISTRY=0` or `CASAN_AGENTIC_H2_REGISTRY=0` is an explicit
|
||||
unsafe development/test bypass. Production treats the bypass as invalid.
|
||||
|
||||
## H5 governance and action risk
|
||||
|
||||
`config/action-classes.json` is the common policy source. Effective risk is the
|
||||
maximum of content, action, resource, identity and environment factors.
|
||||
Deployment, release, migration, database mutation, delete,
|
||||
identity/permission modification and infrastructure modification cannot be
|
||||
downgraded by benign wording. Credential access and unknown commands are also
|
||||
high-risk. High-impact operations require actor identity, approval and
|
||||
evidence.
|
||||
|
||||
Production governance requires strict approval and external signing/anchor
|
||||
capability. Governance audit format v2 binds action class, risk factors and
|
||||
evidence requirements into the hash. The verifier continues to recognize
|
||||
legacy v1 records without upgrading their claims.
|
||||
|
||||
## Execution isolation
|
||||
|
||||
`sandbox-run.sh` detects its selected capability and writes structured sandbox
|
||||
evidence. In enforce/production mode a side-effecting path requires the
|
||||
container backend. If Docker or the required backend is unavailable, execution
|
||||
is denied with `sandbox_isolation_backend_unavailable`; there is no silent
|
||||
timeout/static fallback.
|
||||
|
||||
The implemented container contract uses:
|
||||
|
||||
- Read-only root filesystem.
|
||||
- Explicit workspace bind mount as the writable scope.
|
||||
- Network disabled by default.
|
||||
- Non-root container user.
|
||||
- Dropped Linux capabilities and `no-new-privileges`.
|
||||
- PID, memory, CPU and timeout limits.
|
||||
- Restricted working directory and filtered environment.
|
||||
- Output-size and exit-code capture at the harness boundary.
|
||||
- Rootless Docker requirement in production.
|
||||
|
||||
CASAN does not claim AppArmor, SELinux, a custom seccomp profile, per-domain
|
||||
network allowlisting or complete host isolation where those mechanisms are not
|
||||
configured. Development static fallback is policy filtering, not isolation.
|
||||
|
||||
## Control Plane identity boundary
|
||||
|
||||
Arbitrary `X-CASAN-*`, `X-Forwarded-User` and similar headers are untrusted.
|
||||
Nginx removes them, oauth2-proxy provides a signed access token, and the API
|
||||
verifies the token before creating `VerifiedClaims`. A non-loopback local mode
|
||||
or an invalid production verifier refuses startup.
|
||||
|
||||
## Signing and immutable evidence boundary
|
||||
|
||||
Local SHA-256 chains and evidence digests provide tamper detection under the
|
||||
local host's trust. They are not externally trusted immutability. Normal
|
||||
production certification requires both:
|
||||
|
||||
1. `CASAN_SIGNING_PROVIDER=vault_kms` (or another explicitly supported external
|
||||
trust provider) with an HTTPS endpoint and short-lived credential.
|
||||
2. `CASAN_IMMUTABLE_ANCHOR_PROVIDER=s3_object_lock` (or an explicitly supported
|
||||
external WORM provider) with bucket and KMS configuration.
|
||||
|
||||
The packaged production path verifies Vault Transit readiness and performs an
|
||||
S3 Object Lock COMPLIANCE anchor write. It does not provision either service.
|
||||
|
||||
`CASAN_TRUST_EMERGENCY_OVERRIDE=1` is break-glass behavior. It emits critical
|
||||
evidence, keeps readiness failed and makes the run non-certifiable. It is not a
|
||||
normal production fallback.
|
||||
|
||||
## Secret and evidence handling
|
||||
|
||||
- Raw JWTs and authentication secrets are not logged.
|
||||
- Tool and prompt evidence remains subject to existing redaction/scanning.
|
||||
- Authentication evidence records identity metadata and stable reason codes.
|
||||
- Canonical evidence digests detect local metadata tampering, while external
|
||||
signing/anchoring supplies production trust.
|
||||
- A successful evidence append never changes a failed execution into success.
|
||||
|
||||
## Infrastructure not proven by repository tests
|
||||
|
||||
Repository-local tests use cryptographic fixtures and narrow service stubs.
|
||||
Docker isolation tests are skip-aware when Docker is absent. Real enterprise
|
||||
OIDC traffic, Vault policy enforcement, KMS/HSM custody, S3 retention policy,
|
||||
rootless Docker host hardening and managed network controls require deployment
|
||||
evidence before production claims are made.
|
||||
Reference in New Issue
Block a user