Skip to content

fix(tui/audit): scope delete-all to the active filter and export every matching row - #169

Merged
codeyevsky merged 3 commits into
solongate:mainfrom
tnalbant:fix/audit-filter-and-export-145
Oct 27, 2026
Merged

codeyevsky merged 3 commits into
solongate:mainfrom
tnalbant:fix/audit-filter-and-export-145

Conversation

@tnalbant

Copy link
Copy Markdown
Contributor

What this fixes

Two silent scope bugs in the audit view, both from #145:

  1. X (delete all) ignored the active filter. The confirmation says
    X = delete ALL matched entries, every one of the 3! and then called
    tui.ClearLocalLog(), which empties the whole file. Filtering the view down to
    one agent or one DLP signal and pressing X deleted entries that were never on
    screen.
  2. E (export all) stopped at 1000 rows without saying so. It asked
    Audit.List for Limit: 10_000, but Audit.List clamps the limit to 1000, so
    1105 matching entries produced a 1000-row file reported as ✓ exported 1000 rows.

How

  • client.AuditQuery.Matches() — the filter that used to be inlined in
    Audit.List is now a single method. List uses it, and so do the bulk actions.
    Limit/Offset are deliberately excluded: they window the result, they do not
    select entries.
  • client.AuditEntryFromLocalLine() decodes one raw local-log line into the same
    AuditEntry shape List returns, so the TUI can apply that exact filter while
    rewriting the file.
  • tui.DeleteLocalLogMatching(predicate) deletes only the accepted lines, through
    the same lock-and-rewrite path DeleteLocalEntry uses. Lines that do not parse
    are kept; a nil predicate deletes nothing.
  • doDelete("all") passes p.query(); panel state is read before the command
    goroutine starts, like the existing gen capture.
  • doExport("all") walks pages of client.MaxAuditPage until the matching set is
    complete, and reports exported N of M matching rows (timed out) if the existing
    120s budget ends first instead of pretending the file is complete.
  • client.MaxAuditPage is the new named constant for the 1000-row clamp, so the
    number is not duplicated in the TUI.
  • Behaviour without a filter is unchanged: X still clears the whole log and says
    so.

Verification

Both tests fail on the parent commit and pass with the change:

test before after
TestDoDeleteAllOnlyDeletesEntriesMatchingTheActiveFilter whole log emptied, the out-of-filter entry gone 2 filtered entries deleted, out-of-filter entry kept
TestDoExportAllExportsEveryMatchingRowPastTheClientPageLimit ✓ exported 1000 rows of 1105 1105 rows
  • packages/tui: go test -count=1 ./... → all four packages ok; go test -race ./audit/ . ok; go vet ./... clean.
  • packages/core: go test -count=1 ./client/ → 100 tests pass; go vet ./client/ clean.
  • New unit tests for the primitive: DeleteLocalLogMatching keeps lines it cannot parse and deletes nothing for a nil predicate; AuditQuery.Matches ignores the paging window.
  • gofmt introduces no formatting changes in the touched files.

Not related to this change, for transparency: packages/core/config and
packages/core/health fail on macOS with chmod/immutable-flag assertions
(TestLockFileThenUnlockFileRoundTrip,
TestWriteProtectedFileOverLockedFileUnlocksRewritesAndRelocks,
TestLockPathCheckLockUnlockPathOnFile, TestLockPathAndUnlockPathOnDirectory,
TestProtectedCheckChmodOnlyLock). The same five failures reproduce on a clean
checkout of b2b4a54, and neither package is touched here.

Closes #145

AI assistance

Implemented with AI assistance (Hermes agent) at my direction, including the tests
above run against both revisions. I reviewed the change and the evidence above
before submitting it.

… row

"X" promised "delete ALL matched entries, every one of the N" and then called
ClearLocalLog(), which empties the whole file: a user who filtered the view lost
entries that were never on screen. Deletion now runs through the same
client.AuditQuery the view used, so only the visible subset is removed.

"E" asked Audit.List for 10_000 rows, but List clamps Limit to 1000, so every
export above 1000 matching entries was cut off with no warning. The export now
walks pages of client.MaxAuditPage until the matching set is complete, and says
so explicitly if the 120s budget ends first.

The filter lives in one place: AuditQuery.Matches() is what List uses, and the
TUI applies it to raw log lines via AuditEntryFromLocalLine(), so the view and
the bulk actions cannot drift apart again.

Signed-off-by: Turgay Nalbant <182372382+tnalbant@users.noreply.github.com>
tnalbant and others added 2 commits October 27, 2026 16:54
Routing every delete through the query predicate also kept lines that no longer
parse, so an unfiltered "X" left corrupted rows behind while still reporting
that the whole log was deleted. With no filter active, keep the previous
ClearLocalLog() path; the predicate is only for a narrowed view, where a line
that cannot be parsed cannot match the filter anyway.

Signed-off-by: Turgay Nalbant <182372382+tnalbant@users.noreply.github.com>
@codeyevsky
codeyevsky merged commit aa46149 into solongate:main Oct 27, 2026
34 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

tui/audit: delete-all and export-all silently ignore the active filter and a 1000-row cap

3 participants