The canonical Principal

The internal primitive is a Regulus Principal carrying tenant, jurisdiction, purpose-of-processing, model-risk tier authority, and the credentials' expiry. Every plugin reads from Principal; no plugin sees raw protocol artifacts (SAML assertions, LDAP DNs, OIDC ID tokens). Adapters mint a Principal at the trust boundary and discard the protocol-specific shape on the inside.

Why this matters for compliance. An auditor will ask: "for this DENY decision, who was the principal, and how do we know the credentials hadn't expired?" If your codebase has OIDC claim parsing in one place, SAML attribute extraction in another, and LDAP lookups in a third — that answer is a spreadsheet exercise. With one canonical shape, it's a query.

IdentityAdapter SPI

Each adapter is a single class implementing IdentityAdapter. Today's shipped adapter is OIDC (Spring Boot starter regulus-ai-identity-oidc-spring-boot-starter); SAML, mTLS, and service-account JWT adapters are on the SPI surface with deterministic claim mapping. Every adapter must produce the same minimum claim set: sub, tenant, jurisdiction, purpose, tier, expires_at. The kill-switch plugin reads two of these claims (tier authority + purpose) to gate destructive operations.

RFC 9421 HTTP Message Signatures on A2A

Cross-organisation agent-to-agent calls travel over ADK's A2A protocol. Regulus wraps the outbound envelope with RFC 9421 HTTP Message Signatures over (@method, @target-uri, @body, @created) and verifies on the inbound side before invoking the receiver agent. Replay protection ships as part of the envelope: a per-keypair monotonic nonce window plus a configurable maximum clock skew.

Status today (v0.2.1). The signing surface and replay protection are wired through the SPI. Ed25519 signing implementation is on the next-milestone list — current shipping code raises UnsupportedOperationException if the signature is requested in production mode. The replay-protection + canonicalisation surface is verifiable today.

Audit integrity — SHA-256 chains, optional per-event sigs

Every RegulusEvent carries the SHA-256 hash of the previous event (within an emitter scope). Chains are offline-verifiable with regulus audit verify chain.jsonl. Per-event signatures are an opt-in v0.3 target — today's hash chain detects tampering deterministically; signed-per-event detects identity of the tamperer.

Dual-control kill switch

The kill-switch plugin requires two authorised principals (tier authority claim) to collapse the agent's tool surface. The collapse is fail-closed: once invoked, every subsequent tool call returns a structured policy decision KILL_SWITCH_ENGAGED with both principals' sub claims in the audit event. Trigger is via the RegulusKillSwitchPlugin or via the CLI regulus kill-switch engage --agent <name> --auth-token <jwt>.

Trust boundaries

The four trust boundaries explicit in the system:

  1. External IdP ↔ Regulus IdentityAdapter. Standard protocol surface (OIDC discovery, JWKS rotation).
  2. ADK runtime ↔ Regulus plugins. Internal JVM trust; assumes the ADK process is uncompromised.
  3. Regulus plugins ↔ Regulus services. Same JVM, no boundary at runtime; lint-checked via package visibility.
  4. Regulus ↔ External GRC adapters. HMAC-signed outbound POSTs; verify the bundled key on the receiver side.

Reporting a vulnerability

See the SECURITY.md in the repository ↗ for the disclosure path. We publish CVEs through GitHub's CVE service.