Add sanitized audit logging and operational hardening #59

Merged
lost-rob0t merged 69 commits from agent/issue-12-audit-hardening into main 2026-07-21 23:30:02 +00:00
lost-rob0t commented 2026-07-19 01:55:19 +00:00 (Migrated from github.com)

What changed

  • Added a closed, typed audit schema with fixed category, action, outcome, and reason enums.
  • Added action/category and action-specific field invariants so malformed but superficially valid audit records fail before persistence.
  • Added typed lifecycle source/destination states, UUIDv4 event/correlation/record identifiers, positive generation/key versions, bounded provider identifiers, and allowlisted numeric/boolean attributes.
  • Added one-way BLAKE2b digests for configuration revisions and key references.
  • Added an AuditRecorder facade for lifecycle, capture, policy, provider routing, rejected/deleted records, export decisions, key operations, and runtime hardening.
  • Added adapters and decorators for:
    • lifecycle transitions;
    • accepted, overloaded, coalesced, and rejected pipeline work;
    • policy allow/deny/failure;
    • local, authorized-remote, and rejected provider routing;
    • successful, missing, and failed deletion attempts;
    • key rotation and destruction success/failure.
  • Added an owner-only canonical JSONL sink with strict path validation, bounded event/file sizes, opaque rotation names, age/count retention, atomic rename, and directory synchronization.
  • Added descriptor-safe fail-closed rotation behavior and a debug entry point that uses the identical serializer.
  • Added runtime hardening that installs umask 0077, disables and verifies core dumps, disables Python's fault handler, and validates configured storage trees before capture startup.
  • Added recursive storage permission validation: directories must be owner-owned 0700; regular files must be owner-owned 0600; symlinks and special files are rejected.
  • Added documentation plus synthetic unit and security regression tests.

Security behavior

  • Screenshots, OCR text, titles, URLs, command lines, usernames, prompts, model output, tokens, exception text, and free-form messages have no audit-event field.
  • Debug logging cannot widen the schema or bypass validation.
  • Existing group/world-accessible audit or storage paths fail closed rather than being silently repaired.
  • Rotated logs are validated before the active log is opened.
  • Failed rotation closes the sink without leaking or double-closing descriptors.
  • Core-dump and fault-handler output are disabled before storage-tree traversal.
  • Audit and hardening failures expose fixed codes only.

Test coverage

Synthetic tests cover:

  • arbitrary reason and attribute rejection;
  • action/category mismatch and incomplete lifecycle transitions;
  • lifecycle state serialization and secret-reference hashing;
  • seeded screenshot-title, OCR, URL, command-line, username, token, and prompt values never appearing in logs;
  • active and rotated file permissions, symlink rejection, bounded rotation, and failed-rotation closure;
  • policy, routing, pipeline, deletion, and key audit wrappers;
  • storage-tree permission validation;
  • core-dump, umask, and fault-handler hardening order.

Validation

GitHub Actions CI run #242 passed on head 8d5beb3f460b69e94756c7f08c6c06bdb53c1bcf.

The authoritative CPython 3.14 matrix passed formatting, Ruff lint, shell checks, strict Pyright, unit, contract, integration, and security tests, security scans, and failure-propagation verification.

Closes #12

## What changed - Added a closed, typed audit schema with fixed category, action, outcome, and reason enums. - Added action/category and action-specific field invariants so malformed but superficially valid audit records fail before persistence. - Added typed lifecycle source/destination states, UUIDv4 event/correlation/record identifiers, positive generation/key versions, bounded provider identifiers, and allowlisted numeric/boolean attributes. - Added one-way BLAKE2b digests for configuration revisions and key references. - Added an `AuditRecorder` facade for lifecycle, capture, policy, provider routing, rejected/deleted records, export decisions, key operations, and runtime hardening. - Added adapters and decorators for: - lifecycle transitions; - accepted, overloaded, coalesced, and rejected pipeline work; - policy allow/deny/failure; - local, authorized-remote, and rejected provider routing; - successful, missing, and failed deletion attempts; - key rotation and destruction success/failure. - Added an owner-only canonical JSONL sink with strict path validation, bounded event/file sizes, opaque rotation names, age/count retention, atomic rename, and directory synchronization. - Added descriptor-safe fail-closed rotation behavior and a debug entry point that uses the identical serializer. - Added runtime hardening that installs umask `0077`, disables and verifies core dumps, disables Python's fault handler, and validates configured storage trees before capture startup. - Added recursive storage permission validation: directories must be owner-owned `0700`; regular files must be owner-owned `0600`; symlinks and special files are rejected. - Added documentation plus synthetic unit and security regression tests. ## Security behavior - Screenshots, OCR text, titles, URLs, command lines, usernames, prompts, model output, tokens, exception text, and free-form messages have no audit-event field. - Debug logging cannot widen the schema or bypass validation. - Existing group/world-accessible audit or storage paths fail closed rather than being silently repaired. - Rotated logs are validated before the active log is opened. - Failed rotation closes the sink without leaking or double-closing descriptors. - Core-dump and fault-handler output are disabled before storage-tree traversal. - Audit and hardening failures expose fixed codes only. ## Test coverage Synthetic tests cover: - arbitrary reason and attribute rejection; - action/category mismatch and incomplete lifecycle transitions; - lifecycle state serialization and secret-reference hashing; - seeded screenshot-title, OCR, URL, command-line, username, token, and prompt values never appearing in logs; - active and rotated file permissions, symlink rejection, bounded rotation, and failed-rotation closure; - policy, routing, pipeline, deletion, and key audit wrappers; - storage-tree permission validation; - core-dump, umask, and fault-handler hardening order. ## Validation GitHub Actions CI run #242 passed on head `8d5beb3f460b69e94756c7f08c6c06bdb53c1bcf`. The authoritative CPython 3.14 matrix passed formatting, Ruff lint, shell checks, strict Pyright, unit, contract, integration, and security tests, security scans, and failure-propagation verification. Closes #12
lost-rob0t commented 2026-07-19 02:47:24 +00:00 (Migrated from github.com)

CI rerun attempted on workflow run #223 (run ID 29670337247). The rerun failed identically before runner execution: Checks (ubuntu-22.04), Checks (ubuntu-24.04), and Failure propagation all completed with steps = null and no job log URL. No checkout, lint, type-check, or pytest command ran.

GitHub currently reports Actions operational, so this is most consistent with an account-level Actions billing/budget restriction rather than a workflow or PR-code failure. PR remains draft and will not be merged until the complete matrix executes and passes.

CI rerun attempted on workflow run #223 (run ID `29670337247`). The rerun failed identically before runner execution: `Checks (ubuntu-22.04)`, `Checks (ubuntu-24.04)`, and `Failure propagation` all completed with `steps = null` and no job log URL. No checkout, lint, type-check, or pytest command ran. GitHub currently reports Actions operational, so this is most consistent with an account-level Actions billing/budget restriction rather than a workflow or PR-code failure. PR remains draft and will not be merged until the complete matrix executes and passes.
Sign in to join this conversation.
No description provided.