Class FileAuditSink

java.lang.Object
zeroecho.pki.impl.audit.FileAuditSink
All Implemented Interfaces:
AutoCloseable, AuditIntegrityService, AuditService, AuditSink

public final class FileAuditSink extends Object implements AuditSink, AuditService, AuditIntegrityService
Persistent AuditSink provider storing audit events as daily gzip files.

ServiceLoader compatibility

This sink supports ServiceLoader by providing a public no-arg constructor.

Storage layout

baseDir/
  YYYY/
    MM/
      YYYY-MM-DD.audit.log.gz

Encoding

Each event is encoded as a single UTF-8 line and appended as its own gzip member. Members are concatenated to enable append-only writes.

Security properties

  • Best-effort permissions: directories 0700, files 0600 on POSIX.
  • No event payload is logged. Corrupted records are skipped without logging the record content.
  • Constructor Details

    • FileAuditSink

      public FileAuditSink(Path baseDir)
      Creates the sink with an explicit base directory.
      Parameters:
      baseDir - base directory
  • Method Details

    • record

      public void record(AuditEvent event)
      Description copied from interface: AuditSink
      Persists an audit event.
      Specified by:
      record in interface AuditService
      Specified by:
      record in interface AuditSink
      Parameters:
      event - audit event
    • verifyIntegrity

      public AuditIntegrityReport verifyIntegrity(Optional<AuditChainHead> expectedHead)
      Verifies the tamper-evident hash chain over the entire durable audit log.

      Records are recovered from every daily file and ordered by their global sequence, so verification is independent of physical file placement. It detects content mutation, deletion (a sequence gap), duplication, and broken links; when an expectedHead anchor is supplied it additionally detects whole-tail truncation. The returned report is payload-free.

      Specified by:
      verifyIntegrity in interface AuditIntegrityService
      Parameters:
      expectedHead - optional independently-retained trusted head anchor
      Returns:
      a safe integrity report
    • verifyAnchoredPrefix

      public AuditIntegrityReport verifyAnchoredPrefix(AuditChainHead anchor)
      Description copied from interface: AuditIntegrityService
      Verifies internal chain consistency and that anchor is an authentic prefix of the log.

      Unlike AuditIntegrityService.verifyIntegrity(Optional), which requires the supplied head to equal the current final head, this tolerates records appended after the anchored sequence (legitimate growth, including after a crash restart). It fails when the anchored sequence is missing (truncation below the anchor), when its record hash differs (history before the anchor was rewritten), or when the chain is internally broken. A genesis anchor (AuditChainHead.empty()) is a valid prefix of any consistent chain.

      Specified by:
      verifyAnchoredPrefix in interface AuditIntegrityService
      Parameters:
      anchor - durable trusted prefix anchor from a separate store
      Returns:
      payload-free integrity report whose observed head is the current log head
    • currentHead

      public AuditChainHead currentHead()
      Recovers and returns the current chain head, seeding it from disk if needed.
      Returns:
      the current tamper-evident head anchor
    • search

      public List<AuditEvent> search(AuditQuery query)
      Description copied from interface: AuditService
      Searches audit events by query constraints.
      Specified by:
      search in interface AuditService
      Parameters:
      query - query constraints
      Returns:
      matching audit events
    • get

      public Optional<AuditEvent> get(PkiId eventId)
      Description copied from interface: AuditService
      Retrieves an audit event by id if the implementation assigns stable ids.
      Specified by:
      get in interface AuditService
      Parameters:
      eventId - event id
      Returns:
      audit event if present
    • getById

      public Optional<AuditEvent> getById(PkiId eventId)