Risk Management Module (hierachain/risk_management/*)
Overview
The Risk Management package currently provides audit logging and integrity reporting for operational events.
Main Component
-
Audit Logger
File:
audit_logger.py- Stores audit events in the configured backend; Arrow Parquet is the default, and
FileAuditStoragewrites JSONL. - Computes a SHA-256 digest over every
AuditEventfield. - Supports querying and creating reports for compliance auditing.
- Stores audit events in the configured backend; Arrow Parquet is the default, and
Audit Logging and Integrity
Audit event integrity uses a separate trusted digest manifest:
- Set
HRC_AUDIT_MANIFEST_WRITE_URLto the PostgreSQL URL used to record digests. In production,AuditLoggerrefuses to start without this URL or an explicitintegrity_digest_writer(event_id, digest)callback. To enable built-in read verification, setHRC_AUDIT_MANIFEST_READ_URLseparately to a URL that can read the manifest; the writer URL is not reused as a reader credential. - Keep the manifest database outside the archive's mutable host or volume, with separate access controls. Give the application role only
INSERTon the table and a separate verifier role onlySELECT; both need schemaUSAGE. A sidecar that can be edited alongside the archive does not provide tamper evidence. -
Create the two roles and the manifest table in that database before starting the logger:
CREATE TABLE public.audit_event_digests ( event_id TEXT PRIMARY KEY, digest TEXT NOT NULL CHECK (digest ~ '^[0-9a-f]{64}$'), recorded_at TIMESTAMPTZ NOT NULL DEFAULT now() ); REVOKE ALL ON public.audit_event_digests FROM PUBLIC; GRANT USAGE ON SCHEMA public TO audit_manifest_writer, audit_manifest_reader; GRANT INSERT ON public.audit_event_digests TO audit_manifest_writer; GRANT SELECT ON public.audit_event_digests TO audit_manifest_reader; -
query_events()andgenerate_report()return archive data without a trusted-manifest status. Do not treat those results as verified. Callquery_events_with_integrity(filter_criteria, limit)for an explicitAuditReadResult: it returnsverifiedonly after checking the full archive against the manifest, returnsunverifiedwhen no digest reader is configured, and returnsfailedwith no events when the manifest cannot be read or any archive record is missing, extra, duplicated, or changed. - The explicit API can use
HRC_AUDIT_MANIFEST_READ_URLor anintegrity_digest_reader()callback. A write-only URL is not used to read digests. For lower-level verification, passmanifest.load_hashes()and the complete archive event set toverify_integrity(events, expected_hashes). verify_integrity(events, expected_hashes)returnsFalsewhen the manifest is missing or when event IDs or digests differ. Pass the complete event set represented by the manifest; missing, extra, duplicate, or changed records fail verification.- If archive storage or the digest writer fails, the exception reaches the caller and no success statistics or alerts are emitted. A failure after archive storage can leave an event without a manifest entry; verification rejects it.
- Arrow audit files rotate at 100 MB.
get_event_count()uses Parquet row counts for an unfiltered count and scans only the selected filter columns in bounded batches otherwise. SQLite and Arrow apply the same event type, severity, source, user, and inclusive time-range filters. - Arrow retention is explicit:
ArrowAuditStorage.cleanup_old_events(max_age_seconds)removes a Parquet archive only when every event in it is older than the cutoff. It returns the number of deleted events. Mixed-age archives and legacy.arrow,.log, or.jsonlfiles remain; no automatic cleanup runs. Coordinate archive deletion with the independently stored digest manifest before using full-manifest integrity verification. FileAuditStoragewrites daily JSONL files.- Audit retrieval and counting fail with
RuntimeErrorwhen a database, archive, or decoded record cannot be read. They do not convert a failed search into[],0, or a partial result. Corrupt Parquet files are not retried as legacy Arrow frames; truncated legacy frames and malformed JSONL records also fail. A valid empty search still returns[]or0. Consumers must handle the error before presenting a report. A limited query validates only the records it reads, and an unfiltered Parquet count uses metadata; neither replaces complete archive integrity verification.
Related
CSV report export
AuditLogger.generate_report(..., output_format="csv") uses CSV quoting for commas, quotes and line breaks in every cell. Text cells whose first non-whitespace character is =, +, - or @ receive an apostrophe prefix to prevent spreadsheet formula interpretation. This export policy changes those CSV text cells; the stored events and JSON export retain the original values. CSV export does not imply trusted-manifest verification.