Skip to content

feat(settings): record every authorization decision to a hash-chained local log - #2216

Merged
datlechin merged 2 commits into
mainfrom
feat/execution-audit-log
Aug 19, 2026
Merged

feat(settings): record every authorization decision to a hash-chained local log#2216
datlechin merged 2 commits into
mainfrom
feat/execution-audit-log

Conversation

@datlechin

Copy link
Copy Markdown
Member

Every database operation TablePro performs passes one authorization step, including the ones the AI assistant and the 19 MCP tools ask for. This records each decision, allowed or refused, to a local hash-chained log.

Not 16 call sites

The obvious reading of this task is that OperationDecision.denied(reason:) carries no connection, kind or timestamp, so logging denials means widening it across every authorize call site, which under the atomic-API rule is one large commit.

That is not needed. DefaultExecutionGate.authorize already holds the whole OperationRequest and produces all seven outcomes itself, so everything a record needs is in scope inside that one function. The gate is precisely where the request and the decision exist at the same moment; reconstructing either at the call sites is what would have been expensive.

authorize is now a wrapper over a private decide, which keeps the seven returns and gains none of the logging. One write point instead of seven, so a return added later cannot quietly skip the log.

What a record holds

Time, connection, operation kind, who asked, whether it was a write, and the outcome.

The caller matters most. OperationCaller already distinguishes userInterface, mcpClient, aiAssistant, importPipeline and backgroundMaintenance, and telling a person clicking Save apart from an agent is the first thing anyone reading an audit trail wants. Only the channel is stored: an MCP client's label and an AI session id are caller-supplied strings and do not belong in an audit record.

The statement is stored as a SHA-256 digest, never as text. A query holds customer data, and an audit trail that stored it would be a second copy of the database sitting in Application Support. A test asserts the digest of a query containing an email address does not contain that address.

The honest limit, asserted in a test

Each record carries the previous record's hash, so an edit, a reorder or a deletion breaks the chain and verify() names the first record that disagrees.

It is tamper evident, not tamper proof. Anyone who can write the file can recompute every hash after the record they changed, and truncating the tail leaves a chain that still verifies. truncationIsNotDetected asserts exactly that, so nobody later mistakes this for something stronger. Only an append-only store the audited person cannot write would be stronger, and TablePro runs no server. The docs say this in a Warning rather than implying more.

Not gated

Deliberately free. The MCP activity log already ships with no LicenseTier check anywhere in TablePro/Core/MCP/, and repo issue #2107's hard rule is that nothing already free moves behind a paywall. Shipping this as a paid tier would have broken that rule for a feature users already have most of.

Notes

ExecutionAuditLog is an actor rather than a lock-guarded class: the sequence number and the previous hash have to be read and advanced together, or two concurrent decisions produce two records claiming the same position. A test runs 20 concurrent decisions and asserts 20 distinct sequence numbers and an intact chain.

A log file that cannot be decoded is reported through OSLog and left alone rather than replaced with a fresh chain, since silently starting over destroys the evidence.

No UI yet. The log is written and verifiable; presenting and exporting it is separate work.

Verification

  • build PASS
  • test 13 executed, 13 passed
  • lint TablePro 0 violations

@mintlify

mintlify Bot commented Aug 18, 2026

Copy link
Copy Markdown

Preview deployment for your docs. Learn more about Mintlify Previews.

Project Status Preview Updated (UTC)
TablePro 🟢 Ready View Preview Aug 18, 2026, 8:57 PM

💡 Tip: Enable Workflows to automatically generate PRs for you.

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

Signed-off-by: Ngô Quốc Đạt <datlechin@gmail.com>
@datlechin
datlechin merged commit e0c73ce into main Aug 19, 2026
3 checks passed
@datlechin
datlechin deleted the feat/execution-audit-log branch August 19, 2026 02:09
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.

1 participant