npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@aurite-ai/attestation-verifier

v0.8.0

Published

Standalone offline verifier for Kahuna attestation evidence packages. Verifies ed25519 signatures and chain linkage using public keys embedded in the package — no network access to Kahuna required.

Downloads

805

Readme

@aurite-ai/attestation-verifier

External verifier package for Kahuna attestation events.

What this is

This package lets any party — Kahuna customers, third-party auditors, compliance scanners — independently verify the integrity of attestation chains produced by Kahuna agents. It wraps the verify operations from @kahuna/shared-attestation with a public API designed for standalone consumption.

The verifier is pure — given the same inputs (an event and a public key bundle), it returns the same outputs. No network calls during verification. No environment dependencies. No side effects.

Two questions, both answered offline

| Question | Command | Needs | |---|---|---| | Are these events authentic and linked? | verify evidence.json | the package | | Is this all of them? | verify evidence.json --countersigned-head head.json | the package + a file from the customer |

Neither touches the network. The signing keys travel inside the package, and a countersigned head is a local file. Adding the scope check does not make verification less offline — it adds a second local input.

The two questions are genuinely different, and only the first is answerable from the package alone. A curated subset answers "yes" to the first and hides the second.

Why open verification matters

Per the architectural decision baked into the v1 schema (see docs/attestation/event-schema.md §11), Kahuna attestation chains are designed for independent verification. The cryptographic guarantee — "events were produced by the named signing key" — only matters if parties other than Kahuna can verify it.

For evidence packages, the keys travel inside the package, so verification needs no network access at all and no cooperation from whoever operates the chain. That is the point: the party you are auditing is not in the loop when you check their work.

Correction (2026-08-27). This section previously said "Public key bundles are openly accessible (no API key required). Anyone can fetch any organization's bundle." That was not true and has never been true. The /.well-known/kahuna/public-keys/<org> route exists and is unauthenticated on the server, but in a deployed cluster it sits behind an authenticating load balancer, so an unauthenticated request is redirected to a login page and never reaches it. Making it publicly reachable is tracked as G51(a) and is not in this release.

Nothing about offline verification depended on it: the keys are in the package. What it affects is only the optional --against cross-check below.

Checking the scope claim — read this before trusting "COMPLETE chain"

Everything an evidence package says about its own extent is written by the party being audited. A genuine 10-event prefix of a 60-event chain can declare itself the complete chain and pass every offline check — real signatures, linked hashes, self-consistent metadata. This was demonstrated, not theorised.

Offline verification answers "are these events authentic and linked?" It does not answer "is this all of them?" Those are different questions and only the first is answerable from the file alone.

The countersigned chain head

The second question needs one number the package cannot contain: a chain head observed by someone other than the operator. A countersigned head is a signed statement by the customer about what they saw:

{
  "assertion": {
    "kind": "kahuna.chain-head-attestation/v1",
    "organization_id": "3f2504e0-4f89-11d3-9a0c-0305e82c3301",
    "chain_head_position": 59,
    "head_event_hash": null,
    "observed_at": "2026-08-20T10:00:00.000Z",
    "observer_id": "spiffe://customer.example/agent/attestation_consumer"
  },
  "signature": "<base64 Ed25519 over the JCS serialization of `assertion`>",
  "signer_public_key": "<base64 raw Ed25519 public key>"
}

It is not a public key, though it carries one so the signature is checkable. It is a dated, signed claim that the chain had reached position 59.

head_event_hash may be null. The observer records a hash only if it saw the head event; observing only a position is honest and still sufficient for the check below. It is never invented.

Why it works

The chain is append-only, so head position only increases. If the customer observed position 59 at time T, then a package assembled at or after T claiming the complete chain ends at position 9 is self-contradictory. That contradiction is what the check reports.

Producing one (customer side)

Runs as a workload in the customer's own environment, signing with a customer-held Ed25519 key — not a Kahuna key, and not the workload's SVID key, which is short-lived by design.

import { startHeadObserver } from "@aurite-ai/attestation-verifier";

startHeadObserver({
  serverBase: "http://kahuna-server:9100", // in-cluster; no ingress needed
  organizationId: "<org-uuid>",
  signingKey: customerEd25519PrivateKey,   // 32 bytes, customer-held
  observerId: "spiffe://customer.example/agent/attestation_consumer",
  intervalMs: 60 * 60 * 1000,
  onAttestation: (a) => persistSomewhereTheCustomerControls(a),
});

Retention is the whole mechanism. An attestation stored only where the operator can reach it buys nothing — the point is a reference they cannot revise. Frequency sets resolution: hourly bounds any curated package to within an hour of the truth. Infrequent is fine, because the chain only grows, so an old attestation stays valid evidence of a position already reached.

Using one (auditor side)

npx @aurite-ai/attestation-verifier verify evidence.json \
  --countersigned-head head.json

Obtain head.json from the customer, not from the package. A countersigned head that arrived inside the evidence bundle proves nothing — the operator assembled both.

Outcomes:

| Result | Meaning | |---|---| | exit 0, "a reference this platform does not control" | The package's scope claim is consistent with what the customer observed | | exit 2, "claims the COMPLETE chain ends at N" | Contradicted. The customer had already observed a later position | | exit 2, "No verdict was reached" | The package claims to predate the observation, so nothing follows. Get an attestation observed before the package was assembled | | exit 2, "countersignature did not verify" | The file is not usable as evidence |

Note the third row: a check that cannot reach a verdict fails. Silence must not read as agreement.

What this still does not close

  • Whose key is it? The verifier checks that the signature matches the embedded key. It cannot know the key is the customer's. That is the auditor's job, and it is why the file must come from the customer through a channel the operator does not control.
  • assembled_at is operator-supplied. An operator can claim a package predates the attestation and escape the comparison — which reports stale_attestation rather than passing. Closing it needs a timestamp the operator does not control (a transparency log). Tracked as G51(c).

--against <server> — deferred

An earlier design fetched the live head from the server. It is weaker (the same party serves the package and the head, so it defeats a curated file but not a determined operator) and it is not reachable in a deployed cluster — see the correction above. Deferred to a future release; the countersigned head is the stronger check and needs no ingress change.

Setting this up (customer, once)

Three steps. After this, every audit is a file handover.

1. Generate a signing key you control

npx @aurite-ai/attestation-verifier keygen --out observer-key.json

Writes a 0600 file and prints the public key:

Wrote observer-key.json (mode 0600).

  PRIVATE half — never send this to Kahuna or anyone else.
  PUBLIC key, base64 — give this to your auditors:

    iptR2KuIx9Nye3VbFUqM34dwUBbuQRZCAW1WzPrgaoM=

It runs entirely on your machine. Kahuna never sees the private half — that is the property the whole mechanism rests on, which is also why there is no "generate a key" button in the Kahuna console: a console page would put our code in your key path, and an auditor could not rule out that we kept a copy.

Load observer-key.json into your observer workload the way you load any other secret — a Kubernetes Secret, your secret manager, a mounted file.

Losing this key is cheap. Everything already signed stays valid, and old attestations remain good evidence of positions the chain had already reached. Generate a new one and carry on. That is also why we do not derive it from a passphrase: the key would be only as strong as the phrase, a guessed phrase forges countersignatures, and there is no recovery need to justify the risk.

1b. Declare the public half to Kahuna (optional, and not a trust root)

Recording your public key with Kahuna lets you check that the key we show alongside an evidence package is the one you actually hold. Declaring requires a possession proof:

npx @aurite-ai/attestation-verifier prove \
  --key observer-key.json \
  --org <your-organization-id> \
  --observer-id <your-reference>

Send the printed JSON as possession_proof to POST /management/v1/observer-keys. The proof contains your public key and a signature; your private key is used to sign and never leaves the process. It is valid for five minutes.

Why a proof is required. An Ed25519 private key and a public key are both 32 base64 bytes, so nothing about the value itself distinguishes them. Pasting the private_key line where public_key belongs would pass every structural check and disclose the half that makes your countersignature mean anything — and you would not find out until verification failed later, looking like a broken key rather than a leaked one. The proof catches it immediately.

This does not make our copy of your key authoritative. We are the party being audited; a key an auditor learns from us is a key we could have substituted. The sound path is still the one in step 3 — you hand the key to your auditor directly. Declaring it here buys you the ability to notice a substitution, and buys an auditor nothing on its own.

2. Run the observer in your cluster

Any long-running workload will do — a small Deployment of its own is the usual shape. It needs network access to kahuna-server and read access to the key.

import { loadObserverKey, startHeadObserver } from "@aurite-ai/attestation-verifier";

const key = loadObserverKey("/etc/kahuna/observer-key.json");

startHeadObserver({
  serverBase: "http://kahuna-server:9100", // in-cluster; no ingress needed
  organizationId: process.env.KAHUNA_ORG_ID!,
  signingKey: key.privateKey,
  observerId: "spiffe://your-org.example/agent/attestation-observer",
  intervalMs: 60 * 60 * 1000,              // hourly is plenty — see below
  onAttestation: async (a) => {
    // `a` serialized IS the head.json an auditor is later handed.
    await appendToYourOwnStorage(`${JSON.stringify(a)}\n`);
  },
  onError: (e) => log.warn({ e }, "head observation failed; will retry"),
});

Each attestation looks like this — and this object, written to a file, is exactly what --countersigned-head consumes:

{
  "assertion": {
    "kind": "kahuna.chain-head-attestation/v1",
    "organization_id": "…",
    "chain_head_position": 59,
    "head_event_hash": null,
    "observed_at": "2026-08-20T10:00:00.000Z",
    "observer_id": "spiffe://your-org.example/agent/attestation-observer"
  },
  "signature": "…",
  "signer_public_key": "iptR2KuIx9Nye3VbFUqM34dwUBbuQRZCAW1WzPrgaoM="
}

Hourly is generous. The chain only grows, so an old attestation stays valid evidence of a position already reached; frequency sets how tightly a curated package can be bounded, not whether the check works.

3. Retain the output somewhere Kahuna cannot reach

This is the mechanism, not an implementation detail. An attestation stored where the operator could revise it proves nothing. Object storage in your account, your log pipeline, anywhere under your control.

You do not need all of them. One attestation older than the package under audit is enough.

Receiving an audit (auditor)

You should be handed three things. Ask for the third if it is missing.

| | What | Why | |---|---|---| | 1 | evidence.json | the events and the keys that signed them | | 2 | head.json | a countersigned chain head, from the customer | | 3 | the customer's public key, through a channel the operator does not control | so #2 means something |

Then:

npx @aurite-ai/attestation-verifier verify evidence.json \
  --countersigned-head head.json

Check the key yourself — the file carries signer_public_key, and it should equal what the customer gave you separately:

jq -r .signer_public_key head.json     # must match the key you were given

If those differ, stop. A countersigned head whose key you learned only from the file proves nothing about who observed the chain.

Why the separate channel matters. The verifier checks that the signature matches the embedded key. It cannot know whose key that is. If the operator supplied the package, the head file and the key, they supplied the entire chain of custody and the check is theatre.

Installation

npm install @aurite-ai/attestation-verifier

CLI

# Verify an exported evidence package — fully offline
npx @aurite-ai/attestation-verifier verify evidence.json

# Export a package from a running Kahuna server
npx @aurite-ai/attestation-verifier export --org <uuid> --server <url> --out evidence.json

Exit codes: 0 passed · 1 usage / unreadable file / malformed JSON · 2 verification failed (signature, chain position, or hash linkage).

Both attestation-verifier and kahuna-verify are installed as binaries; they are the same tool.

What a pass proves — and what it does not

A pass proves every event in the file is authentically signed and that the events form an unbroken run.

It does not, on its own, prove the file contains the whole chain. A window is verified against its own first event, so a partial export passes exactly like a complete one. Compare metadata.chain_position_start and metadata.chain_position_end against the range you expected. Do not rely on metadata.window_complete — see tracker G31; it is not currently trustworthy.

Library usage

Verify a single event

import { verifyEvent, type PublicKeyBundle } from "@aurite-ai/attestation-verifier";

const bundle: PublicKeyBundle = await fetchYourOrgBundle();
const event = await fetchEventFromKahuna();

const result = await verifyEvent(event, bundle);
if (!result.valid) {
  console.error("Verification failed:", result.failure.reason);
  console.error("Message:", result.failure.message);
}

Verify a chain segment

import { verifyChainSegment } from "@aurite-ai/attestation-verifier";

const events = await fetchChainSegment(); // events in chain_position order

const result = await verifyChainSegment(events, bundle);
if (result.valid) {
  console.log("Chain head:", result.chainHead);
} else {
  console.error(
    `Verification failed at segment index ${result.failure.failed_at_segment_index}:`,
    result.failure.reason,
  );
}

Note that verifyChainSegment accepts an optional third argument, startingState. Without it, the segment is verified against its own first event — which is why a partial window passes like a complete one. Pass a ChainStartingState when you know where the segment is supposed to attach.

Verify an evidence package

import { verifyEvidencePackage, type EvidencePackage } from "@aurite-ai/attestation-verifier";

const summary = await verifyEvidencePackage(pkg);
if (!summary.valid) throw new Error(summary.failure?.message);

Failure reasons

The verifier returns structured failures per schema §9.3. The full set:

  • schema_invalid — event is malformed (missing fields, wrong types, etc.)
  • signature_invalid — Ed25519 signature didn't verify
  • key_unknown — the named signing key isn't in the bundle
  • chain_position_gap — adjacent events have non-consecutive positions
  • chain_position_duplicate — two events share a position
  • previous_hash_mismatch — a chain link is broken
  • organization_mismatch — events span multiple organizations
  • internal_inconsistency — an internal-consistency check failed (e.g., recorded_at < occurred_at)
  • bounds_exceeded — an event exceeds a size or cardinality bound

Status

Current: v0.3.0. The verify operations are real and tested. fetchPublicKeyBundle() is implemented against GET <server>/.well-known/kahuna/public-keys/<organizationId>.

Not yet done: the package is not published to any registry. Until it is, npx @aurite-ai/attestation-verifier cannot work for anyone outside this repository — see tracker G30, which is what that row exists to close.

Building and publishing (maintainers)

pnpm build runs scripts/build.mjs, which bundles the library and CLI with esbuild and emits declarations with tsc. The two @kahuna/* workspace packages are inlined into the bundle — they do not exist on npm, so a published package that imported them would fail on the customer's first run. The build asserts this rather than assuming it, and also asserts that every remaining bare import is a declared runtime dependency.

Publish with pnpm publish, never npm publish. The manifest points main/types/bin at src/ for in-repo consumers and overrides them to dist/ under publishConfig. pnpm applies those overrides; npm does not, so npm pack produces a tarball whose entry points reference TypeScript sources that are not shipped.

To check the artifact the way a customer receives it:

pnpm pack --pack-destination /tmp
mkdir /tmp/clean && cd /tmp/clean && npm init -y
npm install /tmp/aurite-ai-attestation-verifier-0.3.0.tgz
npx @aurite-ai/attestation-verifier verify <some-package.json>

Run that from outside this repository. Every defect tracked in G30 was invisible from inside it.

License

MIT — see LICENSE. This package is MIT even though the wider Kahuna repository is not: a verifier that third parties are told to run has to be one they are actually permitted to run.