Skip to content

SmooAI/audit

Repository files navigation

@smooai/audit

A polyglot client SDK for tamper-evident, SQL-queryable audit logging.

@smooai/audit gives every service — in any language — one shared way to emit audit events that are:

  • Canonical — a single AuditEvent schema, serialized to byte-identical canonical JSON regardless of language, so events are comparable and hashable everywhere.
  • Tamper-evident — each event is chained into a per-org-per-day SHA-256 hash chain: every event's hash covers the previous event's hash, so any retroactive edit or deletion breaks every subsequent link.
  • SQL-queryable — events land in a structured store you can query with plain SQL.

It ships as a native package for five languages — TypeScript, Python, Rust, Go, and .NET — with identical semantics. All implementations are verified byte-for-byte against a shared parity corpus, so a hash computed in Go matches one computed in Rust or TypeScript for the same event.

Status: all five language implementations are complete and verified byte-for-byte against the shared parity corpus (spec/parity-corpus.json).

The shared surface

Every language exposes the same four things:

Concept What it does
AuditEvent The canonical event schema (id, organizationId, timestamp, actorType, actorId, action, resource?, metadata?, hashPrevious?, hashCurrent?).
canonicalJson(event) Deterministic, byte-identical JSON serialization.
computeEventHash(event) / buildHashChain(events) The per-org-per-day SHA-256 hash chain.
AuditClient / emit(event) POSTs an event to a configurable ingest endpoint with a bearer token.

Install

TypeScript / Node

pnpm add @smooai/audit

Python

uv add smooai-audit   # or: pip install smooai-audit

Rust

cargo add smooai-audit

Go

go get github.com/SmooAI/audit/go

.NET

dotnet add package SmooAI.Audit

Usage

TypeScript

import { AuditClient, type AuditEvent } from "@smooai/audit";

const client = new AuditClient({
  endpoint: process.env.AUDIT_ENDPOINT!,
  token: process.env.AUDIT_TOKEN!,
});

const event: AuditEvent = {
  id: crypto.randomUUID(),
  orgId: "org_123",
  timestamp: new Date().toISOString(),
  actor: "user_abc",
  action: "record.delete",
  resource: "contact:xyz",
  metadata: { reason: "gdpr" },
};

await client.emit(event);

Python

from smooai_audit import AuditClient, AuditClientOptions, AuditEvent

client = AuditClient(AuditClientOptions(endpoint=endpoint, token=token))
client.emit(AuditEvent(id=..., org_id="org_123", timestamp=..., actor="user_abc", action="record.delete"))

Rust

use smooai_audit::{AuditClient, AuditClientOptions, AuditEvent};

let client = AuditClient::new(AuditClientOptions { endpoint, token });
client.emit(&event)?;

Go

import audit "github.com/SmooAI/audit/go"

client := audit.NewClient(audit.ClientOptions{Endpoint: endpoint, Token: token})
err := client.Emit(event)

.NET

using SmooAI.Audit;

var client = new AuditClient(new AuditClientOptions { Endpoint = endpoint, Token = token });
await client.EmitAsync(evt);

Cross-language parity

Audit trails are only trustworthy if a hash means the same thing everywhere. The canonical serializer and hash chain are held to a shared parity corpus: a set of fixed input events with expected canonical JSON and expected hashes. Every language's test suite runs the corpus and asserts byte-for-byte equality, so a chain written by a Go service verifies cleanly in a Rust or TypeScript reader.

Development

This is a single repo housing all five language implementations. See CLAUDE.md / AGENTS.md for build, test, and release commands. The short version:

pnpm install
pnpm check-all   # typecheck + lint + test + build across all languages

License

MIT © SmooAI

About

Polyglot client SDK for tamper-evident, SQL-queryable audit logging — canonical event schema + per-org-per-day SHA-256 hash chain + emit client. TypeScript, Python, Rust, Go, .NET.

Resources

License

Stars

0 stars

Watchers

0 watching

Forks

Packages

 
 
 

Contributors