Invarix.Guard.Evidence
0.1.0-beta.1
See the version list below for details.
dotnet add package Invarix.Guard.Evidence --version 0.1.0-beta.1
NuGet\Install-Package Invarix.Guard.Evidence -Version 0.1.0-beta.1
<PackageReference Include="Invarix.Guard.Evidence" Version="0.1.0-beta.1" />
<PackageVersion Include="Invarix.Guard.Evidence" Version="0.1.0-beta.1" />
<PackageReference Include="Invarix.Guard.Evidence" />
paket add Invarix.Guard.Evidence --version 0.1.0-beta.1
#r "nuget: Invarix.Guard.Evidence, 0.1.0-beta.1"
#:package Invarix.Guard.Evidence@0.1.0-beta.1
#addin nuget:?package=Invarix.Guard.Evidence&version=0.1.0-beta.1&prerelease
#tool nuget:?package=Invarix.Guard.Evidence&version=0.1.0-beta.1&prerelease
Invarix.Guard.Evidence
Tamper-evident decision records for .NET AI.
Sooner or later something asks what your AI decided and whether the log can be trusted: an enterprise security review, an auditor, opposing counsel, a regulator. This package is how you answer. It records the AI decisions you instrument as an append-only audit trail inside your own process, keyed on SHA-256 hashes of the prompt and completion rather than the text itself, and gives you the primitives to seal batches of those records under a signature only you can produce. No SaaS, no outbound network calls, no model downloads.
using Invarix.Guard.Evidence; // UseJsonlStore, ToSha256Hex, DecisionOutcome
using Invarix.Guard.Evidence.Extensions; // AddInvarixGuardEvidence
builder.Services.AddInvarixGuardEvidence(options =>
{
options.AiSystemId = "invoice-classifier";
options.AiSystemVersion = "2.3.1";
options.ModelId = "gpt-4o-mini";
options.ModelVersion = "2024-07-18";
})
.UseJsonlStore("/var/evidence/decisions.jsonl");
Then, per decision, with IDecisionRecordBuilderFactory factory and IEvidenceSink sink injected from DI:
var record = factory.NewBuilder()
.WithStartTime(started)
.WithEndTime(DateTimeOffset.UtcNow)
.WithInputHashSha256(prompt.ToSha256Hex())
.WithOutputHashSha256(completion.ToSha256Hex())
.WithOutcome(DecisionOutcome.Allowed)
.Build();
await sink.WriteAsync(record);
What you get
- CloudEvents 1.0 wire format. Each record serialises as a standard CloudEvents envelope: system and model identity, use-period timestamps and content digests on every record, with detector results and human-oversight actions attached when they apply. A CloudEvents-speaking consumer (Azure Event Grid, Knative Eventing, custom Kafka topics, plain JSONL files) can take them as-is.
- Hashes, not raw content. The record has no field for the prompt or completion. It carries SHA-256 digests over canonicalised content instead, which reconciles traceability with data-minimisation obligations. Two caveats:
DetectorResult.RedactedPreviewandOversightRecord.Reasonare caller-supplied free text, and nothing validates or scrubs what you put in them. - Tamper evidence.
MerkleTreeandMerkleBatchSignerseal a batch of records into a Merkle tree and sign the root with your own Ed25519 key. You choose the batch boundary and call the signer; nothing seals automatically. The tree implements RFC 6962 (Certificate Transparency) in full, so roots and inclusion proofs verify against any conformant third-party CT tooling, not only against this library. - Retention with legal holds. Retention policies with presets for common statutory periods (six months, three years, four years). Pass your hold registry to a prune run and matching records survive it whatever the cutoff says; holds are an argument to the call rather than state stored on the record, so persisting the registry is your job.
PruneAndCertifyAsyncsigns an Ed25519 certificate for the run, recording the cutoff, tenant scope, delete count and consulted hold IDs, so a gap in the trail comes with a signed account of it. PlainPruneAsyncdeletes without signing anything. - Export endpoint.
MapEvidenceExport()serves the trail as NDJSON or a JSON array over a required time window, with an optional tenant filter, written straight out of the store rather than buffered. Add your own authorization: it ships with none on purpose. - Stores included. In-memory (tests and dev) and single-file JSONL (single-instance deployments only: one process owns the file, queries scan it end to end, and a crash can cost the last event or two) out of the box. For anything larger, implement
IDecisionRecordStoreover Postgres, blob storage, or whatever your team already trusts for regulated data.
Why in-process
An audit trail collected by an external service is only as trustworthy as that service. This one is generated at the point of decision, in your process, signed with a key only you hold. The signing key never leaves your infrastructure. To check a record, an auditor needs four things from you (the record, its inclusion proof, the signed commitment, and your public key) and nothing else: no service to call, no key server, no licence check. Because the tree is RFC 6962 conformant they can run that check with third-party Certificate Transparency tooling, so the trail's authenticity does not depend on Invarix existing.
What this is not
- Not a compliance certification. It produces evidence; whether that evidence satisfies a given obligation is a question for your counsel.
- Not automatic. Nothing is recorded, batched, sealed or pruned unless your code calls it. Coverage is whatever you instrument, and the default sink discards everything until you configure a store (a startup warning tells you so).
- Not a guardrail. Prompt-injection and PII scanning live in Invarix.Guard. The two pair well: Guard screens what goes in and comes out, Evidence records what was decided. There is no integration code between them, so the few lines that copy Guard's verdicts into a record are yours to write. Neither requires the other.
License
Elastic License 2.0. Commercial use, modification and self-hosting are all fine. The limits are the ELv2 ones: you cannot offer it to third parties as a hosted or managed service, you cannot circumvent licence key functionality, and you have to keep the licence notices intact. See the packaged LICENSE file for the text.
Built by Invarix. Questions: sales@invarix.dk
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- BouncyCastle.Cryptography (>= 2.4.0)
-
net8.0
- BouncyCastle.Cryptography (>= 2.4.0)
NuGet packages (1)
Showing the top 1 NuGet packages that depend on Invarix.Guard.Evidence:
| Package | Downloads |
|---|---|
|
Invarix.Gate.Evidence
Writes Invarix.Gate tool-call verdicts into an Invarix.Guard.Evidence decision log. Every verdict the action firewall renders becomes a CloudEvents 1.0 decision record: the tool that was asked for, the SHA-256 digest of the exact canonical arguments, each rule that matched as a detector result, the outcome, and the operator who approved or refused an escalation. Mapping runs on the tool-call thread and the write is handed to a bounded background queue, so an agent never waits on evidence I/O and a broken evidence store never breaks a run. Requires a commercial Gate license. |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 1.0.0-rc.1 | 73 | 7/26/2026 |
| 0.1.0-beta.2 | 63 | 7/23/2026 |
| 0.1.0-beta.1 | 54 | 7/20/2026 |