Qirava Cloud docs
Audit trail: control-plane action logging
Every control-plane action that mutates the fleet is recorded in the _cp_audit catalog: who did it, what they did, which tenant and node it affected, and the result. Each cloud.* function writes its own audit row as the last step, using a best-effort helper so an audit write can never block or roll back the action — the action's own write already committed through the engine's write funnel. The Governance screen renders the most recent audit rows live through the planner, so a cloud custodian can review the full history of provisioning, scaling, mode switches, suspends, terminations, and invoice generation.
The _cp_audit row#
_cp_audit is a schemaless table in the control DMS's own store, distinct from any tenant's _sys_* catalogs. Each row records one control-plane action.
- id
- Unique row id, formatted aud-<microseconds> (e.g. aud-1719480000000000).
- ts_us
- The timestamp in microseconds (now_us at write time). The Governance screen sorts by this, newest first.
- operator
- The cloud operator who performed the action (from ctx.user). Empty if unauthenticated, though the role gate denies those before they reach the audit.
- action
- The action name: provision, scale_vertical, scale_horizontal, switch_mode, suspend, resume, terminate, or generate_invoice.
- tenant_id
- The tenant the action targeted.
- node_id
- The node involved (the tenant's placed node), or empty when none.
- result
- The outcome string, which varies by action — see the table below.
| Action | Typical result value |
|---|---|
| provision | the resulting status: active, or pending_capacity when no node had headroom |
| scale_vertical | ok |
| scale_horizontal | ok |
| switch_mode | the target mode: standalone or cluster |
| suspend | suspended |
| resume | active, or pending_capacity |
| terminate | terminated |
| generate_invoice | the invoice total as a string (e.g. 8.06) |
The audit() helper is best-effort#
Each cloud.* function calls audit(db, operator, action, tenant_id, node_id, result) as its final step before returning. The helper builds the row id from now_us(), escapes every string value through a QQL literal helper, and INSERTs into _cp_audit. Its write is intentionally best-effort: the result is discarded, so an audit failure never blocks or fails the action. By the time audit() runs, the action's own _cp_* write has already committed through the engine's write funnel — the row is the truth either way.
fn audit(db: &Qdb, operator: &str, action: &str, tenant_id: &str, node_id: &str, result: &str) {
let id = format!("aud-{}", now_us());
let _ = db.execute(&format!(
"INSERT INTO {tbl} {{ id: {id}, ts_us: {ts}, operator: {op}, action: {ac}, \
tenant_id: {tn}, node_id: {nd}, result: {rs} }}",
tbl = cp::CP_AUDIT, id = lit(&id), ts = now_us(),
op = lit(operator), ac = lit(action),
tn = lit(tenant_id), nd = lit(node_id), rs = lit(result),
));
}What gets audited#
Every fleet mutation writes exactly one audit row. Reads (page renders) are not audited; only the cloud.* mutations are. A typical provision -> switch -> switch -> scale -> suspend -> resume -> terminate flow produces one row per step.
Request
runtime.execute("cloud.provision", {
ctx: { user: "op", role: "admin" },
id: "acme", owner: "acme-corp", mode: "standalone",
storage: "dynamic", threads: 2, mem_gb: 4, storage_gb: 20
})Response
// row appended to _cp_audit:
{
"id": "aud-1719480000000000",
"ts_us": 1719480000000000,
"operator": "op",
"action": "provision",
"tenant_id": "acme",
"node_id": "node-eu-1",
"result": "active"
}Output
On the Governance screen this appears (newest first) as a row:
Operator: op | Action: provision | Tenant: acme | Node: node-eu-1 | Result: activeViewing the trail on the Governance screen#
The Governance screen (/cloud/governance, custodian only) renders the audit trail live. It reads all _cp_audit rows through the planner, sorts them by ts_us descending (newest first), and shows the 25 most recent in a table titled "Control-plane audit (_cp_audit)". An empty trail shows the note "No control-plane actions recorded yet."
| Column | Source field |
|---|---|
| Operator | operator |
| Action | action |
| Tenant | tenant_id |
| Node | node_id (rendered as — when empty) |
| Result | result |
The same Governance screen also lists the cloud operators (read live from the control DMS's _sys_users: username, role, enabled) and explains the cloud authority domain. Minting new operators from the UI and the M-of-N custodian seed ceremony are badged PLANNED — operators authenticate via /cloud/login today.