Skip to content

feat: audit logging for admin actions, validation for external IDs, learn-mode review gate #14

Description

Summary

Several operations that should be audited via AGT audit chain are not:

Operation File:Line Risk
Model override via /admin/model routes.rs:651-673 Model switch to expensive/unsafe model unlogged
Heartbeat frequency plugin.ts:59-62 No rate limit on mesh heartbeat spam
Foundry agent ID injection reconciler.rs:566-573 External ID accepted without format validation
Learn mode bulk promote routes.rs:1789-1821 50+ domains auto-promoted to allowlist without review gate

Proposed Fix

Each operation should call governance.audit.append() and optionally require policy evaluation:

// Model switch
governance.audit.append("admin:model_switch", &format!("to {}", model)).await;
let decision = governance.evaluate_action(&format!("switch_model:{}", model)).await;

// Foundry agent ID validation
if !agent_id.chars().all(|c| c.is_ascii_hexdigit() || c == '-') {
    return Err("Invalid agent ID format");
}

// Learn mode promote gate
if learned_domains.len() > 50 {
    let decision = governance.evaluate_action("egress:bulk_promote").await;
    if decision == RequiresApproval { return pending(); }
}

AGT's hash-chain audit log with Ed25519 signatures would make all these operations tamper-evident.

References

  • AGT: AuditChain, PolicyEngine

Activity

  1. pallakatos commented on Mar 31, 2026

    @pallakatos
    Collaborator

    Resolved in main (merge commit 8f90e58)

    Old governance.rs used SipHash (a non-cryptographic hash) for the audit chain. Replaced with AGT SDK AuditLog which uses a SHA-256 Merkle tree with hash chaining.

    Implementation: sidecar-images/agt-governance/server.py

    # Line 28 — import
    from agentmesh import AgentDID, AuditLog
    
    # Line 80-81 — initialization
    audit_log = AuditLog()
    
    # Lines 128-142 — audit entries on every policy decision
    audit_log.log("policy_check", agent_did, action_str,
                  outcome=outcome, policy_decision=decision.action,
                  data={"rule": decision.rule_name})
    
    # Lines 254-262 — tamper-evident verification endpoint
    valid, msg = audit_log.verify_integrity()
    # GET /audit/verify → {"integrity": "valid"|"COMPROMISED", "entries": N}

    Tamper-evidence proof:
    Each entry contains previous_hash (link to prior) and entry_hash (SHA-256 of canonical JSON). verify_integrity() walks the chain — mutating any field breaks the hash and returns "COMPROMISED".

    Tested live: created 3-entry chain, tampered entry #2 action field → verify_integrity() returned False, "Entry 1 hash mismatch".

    Verified on AKS: Both my-assistant (13 entries) and agent-alice (9 entries) report {"integrity": "valid"}.

    Old code deleted in commit a2a6970.

    Key commits: abbc2b3 (Phase 4: policy YAML), a2a6970 (delete governance.rs)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions