Spanda separates language-level agent capabilities, robot-level package permissions, trust tiers, secrets, and secure communication policies. Audit and blockchain-related libraries integrate through the package capability system and spanda-security runtime.
Agent can [...] → runtime ACL for AI / comm actions
Robot permissions [...] → package capability grants at runtime
Package [capabilities] → manifest validation (spanda-package)
Trust level → device / endpoint policy tier
Secure { ... } → signed + capability-gated topics/services/actions
Audit integration → security events recorded via AuditRuntime
The spanda-security crate (crates/spanda-security/) provides:
| Module | Purpose |
|---|---|
identity |
RobotIdentity with trust metadata |
secrets |
SecretStore, env/literal secret resolution |
capability |
CapabilitySet, Permission, runtime enforcement |
signed |
SignedMessage envelopes for secure comm |
trust |
TrustLevel (untrusted … certified) |
permissions |
PackagePermissions bridge |
secure_comm |
SecurePolicy for topics/services/actions |
runtime |
SecurityContext used by the interpreter |
agent planner {
can [ read(lidar), publish(cmd), subscribe(scan), plan ];
plan { ... }
}
Enforced at runtime for sensor reads, AI actions, and communication (publish, subscribe, call, execute, discover).
robot Rover {
permissions [ audit.write, identity.sign, identity.verify, ledger.anchor ];
}
Grants package-level capabilities to the running program. When an audit, identity, or mock_ledger block is declared without an explicit permissions block, the runtime auto-grants the corresponding caps for backward compatibility.
[capabilities]
required = [
"camera.read",
"audit.write",
"identity.sign",
"ledger.anchor",
"network.outbound"
]Validated by spanda-package before install/publish.
| Capability | Risk | Description |
|---|---|---|
audit.write |
High | Append tamper-evident audit records |
audit.read |
Low | Export/read audit logs |
identity.sign |
High | Sign telemetry and mission logs |
identity.verify |
Low | Verify device signatures |
ledger.anchor |
High | Anchor content hashes (async, non-control-path) |
network.outbound |
High | Outbound network access |
actuator.execute |
High | Direct actuator control |
actuator.execute.safe |
Medium | Actuator control via SafeAction only |
High-risk capabilities produce validation warnings when packages declare them without application approval.
identity RobotIdentity {
id: "rover-001";
public_key: "pub-key-rover-001";
}
Device identity is attached to SecurityContext and used for signing audit records, secure topics, and provenance.
secret api_key from env("API_KEY");
secret dev_key from "literal-dev-key";
Secrets resolve at runtime through SecretStore. Values are never logged in plaintext; audit entries use redacted labels. Secret names are available as opaque Secret bindings in robot scope and can be passed to sign(data, key).
trust trusted; // untrusted | restricted | trusted | certified
Trust tiers gate secure endpoints. A robot at restricted cannot publish to a topic with min_trust = trusted.
topic cmd: Velocity publish on "/cmd" secure {
signed = true;
min_trust = trusted;
requires = [ identity.verify, identity.sign ];
};
service reset: ResetService secure {
signed = true;
requires = [ identity.verify ];
};
At runtime:
- Outbound (
publish,send_goal,execute): checks capabilities, trust, and signs payload whensigned = true - Inbound (
subscribe,call): verifies trust and signature policy - Audit: security events (
security.publish,security.audit.record, …) append to the audit log when configured
Spanda uses Ed25519 signatures (via ed25519-dalek in Rust, @noble/ed25519 in TypeScript):
sha256(data)— SHA-256 content hash (hex)sign(data, key_material)— Ed25519 signature (hex, 128 chars)verify_signature(data, signature, public_key_or_material)— verify signature
Signing material is hashed to a 32-byte seed. A 64-character hex string is treated as a raw public key for verification.
When a robot declares permissions [ ... ], strict mode is enabled: capability auto-grants from identity, audit, and mock_ledger blocks are disabled. You must explicitly list every capability the program needs.
robot R {
permissions [ audit.write, audit.read ]; // strict — no auto-grant
audit A { record robot.pose; }
}
Security events flow through SecurityContext::audit_event() into AuditRuntime:
- Capability denials (when checked before operations)
- Secure publish/subscribe operations
audit.record/audit.export/audit.create_provenancegated byaudit.write,audit.read,identity.sign
See audit-provenance.md for audit block syntax and provenance.
Package safety levels (experimental → certified) are validated in spanda-package and documented separately. Runtime TrustLevel complements package safety for communication policy.
Official framework packages (spanda-mqtt, spanda-ros2, …) are defined in a static catalog, but runtime provider wiring and trust scoring require registry provenance:
- Registry version constraints and lockfile
registrysources qualify - Path to
packages/registry/<name>qualifies for monorepo development - Path/git overrides of an official name elsewhere do not qualify
spanda trust --project scores path/git name squatting at 0 on the official_framework factor. spanda deploy gate --policy production fails the official_provenance and registry_signatures gates when overrides exist or when SPANDA_REGISTRY_REQUIRE_SIGNATURE=1 is unset / signatures do not verify.
See how-packages-work.md · deployment-gates.md · package-trust.md.
- Never block robot control on ledger confirmation
- Never send actuation commands through blockchain transports
- Declare all required capabilities in
spanda.tomland grant them via robotpermissions - Use
AuditBackend/LedgerBackendtraits — do not extend core syntax for chain-specific features - Prefer
hardware_safeorcertifiedsafety levels for production audit packages