Skip to content

audit verify says OK over a wiped log, so an empty store and a deleted one read the same #338

Description

@vladimirrott

sysknife audit verify reports success over a database whose rows have all been deleted.

$ sqlite3 daemon.sqlite 'DELETE FROM transactions; DELETE FROM audit_events;'
$ sysknife audit verify
OK: 0 row(s) verified in .../daemon.sqlite
NOTE: no independent checkpoint anchor is configured, so removal of the newest rows
      would not be detectable — a truncated chain still verifies. Set SYSKNIFE_CHECKPOINT_DB
      and run `sysknife audit checkpoint` periodically; see docs/the-audit-chain.md.
OK: 0 approval event(s) verified
OK: 0 row(s) still match the approval event they committed to
$ echo $?
0

Three previously signed actions were deleted. The verdict is OK and the exit code is 0.

Why this is not simply a bug

A forward hash chain cannot detect the removal of its own tail without an external anchor. That is what checkpoint anchoring exists for, the tool says so in the NOTE, and docs/the-audit-chain.md explains it. Nothing here is hidden.

The problem is what an operator reads. Two very different states produce the same headline:

  • a fresh install where nothing has run yet
  • a host where the entire trail was deleted

Both print OK and exit 0. The one line that distinguishes them is a NOTE the reader has to interpret, below a verdict that already told them everything is fine.

Scope

Make the verdict carry the distinction the tool already knows:

  • Zero rows and no anchor configured is not OK. It is "nothing to verify, and this command cannot tell an empty log from a deleted one". A distinct exit code, or at minimum a different word than OK, gives a monitoring script something to alert on.
  • Zero rows with an anchor configured genuinely is verifiable: the anchor either names a tip that should exist or it does not. That case can stay OK or become an explicit failure, and the anchor is what makes the difference.
  • The --json shape should carry the same distinction, since that is what automation reads.

Worth considering alongside it: whether the daemon should anchor on a schedule by default rather than only when SYSKNIFE_CHECKPOINT_DB is set, so the mitigating control is not opt-in on a product whose subject is tamper evidence. That is a bigger decision and can be split out.

Tests first

A test that writes rows, deletes them, and asserts the verdict is not the same one a fresh store produces. Then a second that configures an anchor and asserts the truncation is caught, so the fix is proved to add detection rather than only to change wording.

Difficulty

medium. The verdict logic is small; deciding the exit-code contract is the part that needs care, and #335 is already open on exit codes generally.

Getting started

CONTRIBUTING.md has the build and test commands, and docs/the-audit-chain.md covers what the chain does and does not protect. No CLA and no copyright waiver. The project is MIT.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workinghelp wantedExtra attention is neededmediumDifficulty: needs familiarity with one subsystem

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions