Skip to content

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.
ActionTypical result value
provisionthe resulting status: active, or pending_capacity when no node had headroom
scale_verticalok
scale_horizontalok
switch_modethe target mode: standalone or cluster
suspendsuspended
resumeactive, or pending_capacity
terminateterminated
generate_invoicethe 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.

rust
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: active

Viewing 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."

ColumnSource field
Operatoroperator
Actionaction
Tenanttenant_id
Nodenode_id (rendered as — when empty)
Resultresult

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.