Provenry

The facts and provenance engine behind Sourcey. It gives the facts you publish a history anyone can verify from the files alone.

Licence
MIT
Runtime
Node 22.12+
Dependencies
zod

Install and run

Terminal · provenry 0.1.1
$ npm install provenry
› added 2 packages
$ node node_modules/provenry/examples/basic.mjs
{"bundle_digest":"sha256:78fa2c913c408cf23b606e157be086af340a2b062fe6e2bc2a55fef928aae8f0","release_id":"sha256:bc9094614426c3b2912b43042258f0e39fbf7657a140b88b1db7dfe6848b627f","objects":1}

The digests are the same on every machine, because every input has exactly one byte form.

The example

This is examples/basic.mjs from the v0.1.1 tag. It composes an instance with one adapter, seals its first release and verifies it from the bytes, using only the package's public exports.

import {
  encodePublicationJson,
  publicationChangeSchema,
  publicationEnvelopeSchemas,
  publicationOwnershipRegistry,
} from "provenry/contracts/publication";
import { digest } from "provenry/primitives";
import { sealPublicationChange } from "provenry/publication/changes";
import { createPublicationEnvelope } from "provenry/publication/envelope";
import { z } from "zod";

// Contract identifiers and adapter vocabulary belong to the composition.
const contracts = {
  manifest: "example.object-manifest/v1",
  snapshot: "example.snapshot/v1",
  artifact: "example.artifact/v1",
  release: "example.release/v1",
  descriptor: "example.descriptor/v1",
  diff: "example.diff/v1",
  bundle: "example.bundle/v1",
  resourceTransition: "example.resource-transition/v1",
};
const changes = publicationChangeSchema({
  kind: z.literal("note.added"),
  subjectTypes: ["note"],
  tombstone: z.object({}).strict(),
});
const ownership = publicationOwnershipRegistry({
  instanceId: "example",
  adapters: [
    { adapterId: "notes", resources: ["note-index"], objects: ["notes/"], subjectTypes: ["note"] },
  ],
});
const envelope = createPublicationEnvelope({
  schemas: publicationEnvelopeSchemas(contracts, changes),
  ownership,
});

const note = { id: "n1", text: "A verifiable note" };
const change = sealPublicationChange({
  kind: "note.added",
  subject_type: "note",
  subject_id: note.id,
  revision_digest: digest(note),
  basis_event_ids: [],
});
const initialIndex = digest({ notes: [] });
const draft = envelope.begin(new Map([["notes/n1.json", encodePublicationJson(note)]]));
const sealed = draft.seal({
  snapshotCore: {
    snapshot_contract: contracts.snapshot,
    release_sequence: 1,
    compiler_version: "example/1",
    artifact_contract: contracts.artifact,
    input_set_digest: digest({ input: note }),
    artifact_digest: digest(note),
    resource_digests: {
      "note-index": envelope.resourceTransitionDigest("note-index", initialIndex, [change]),
    },
    root_set_digest: digest({ trusted_roots: ["example"] }),
    signer_registry_digest: digest({ signers: ["example"] }),
    trust_transition_digest: null,
    policy_as_of: "2026-01-01T00:00:00Z",
  },
  parent: null,
  changes: [change],
  admittedInputDigests: [digest({ input: note })],
  verifierDigest: digest({ verifier: "example/1" }),
  resourceDigests: {},
});

// A real composition would retain these exact files and install its own
// semantic validator and trust roots before admitting a publication.
const files = new Map([...sealed.files].map(([path, bytes]) => [path, Buffer.from(bytes)]));
files.set("bundle.json", Buffer.from(sealed.bundleBytes));
const verified = envelope.verify(files);
envelope.assertSuccessor({ descriptor: verified.descriptor, diff: verified.diff, parent: null });
console.log(
  JSON.stringify({
    bundle_digest: verified.bundle.bundle_digest,
    release_id: verified.descriptor.release_id,
    objects: Object.keys(verified.manifest.objects).length,
  }),
);

Sourcey runs on it

Sourcey seals its releases with Provenry. This is the current one.

Release 123
verifier
sha256:c6d6f5a0f63d…
published
  • Release pages

    The release digest, its parent, the bundle and the verifier listed for a release are the envelope Provenry sealed.

  • Captures

    Evidence is reserved before the fetch, sealed after it, and signed by a key the registry can place in time.

  • Identities

    Companies merge, split and retire. Each transition is a record, and every reference keeps the exact revision it named.

Modules

Each module is its own subpath export.

  • provenry/primitives

    Canonical JSON, SHA-256 digests, canonical string order and identifiers.

  • provenry/identity

    Identity transitions: merges, splits, successions and retirements.

  • provenry/records/references

    Typed references between records, bound to an exact revision.

  • provenry/capture/methods

    The capture methods an instance installs.

  • provenry/capture/start

    The reservation made before any capture happens.

  • provenry/capture/attempts

    The sealed result of a capture attempt.

  • provenry/capture/attestation

    Ed25519 attestations of capture attempts, checked against a signer registry with history.

  • provenry/contracts/publication

    Envelope schemas, the change vocabulary and the ownership registry of an instance.

  • provenry/publication/envelope

    Sealing and verifying a release: manifest, change log, diff, descriptor and bundle.

  • provenry/publication/changes

    Ordering and sealing the changes in a release.

  • provenry/publication/objects

    Writing release files to disk and reading them back within limits.

  • provenry/publication/delivery

    Content-addressed delivery of release files.

  • provenry/publication/preparation

    Building a release, then verifying it over the installed code.

Files

README.md
What it proves, the install and the example.
FORMAT.md
The exact byte contract: preimages, verification stages and read limits.
examples/basic.mjs
Seal and verify a release in one file.
CHANGELOG.md
What changed in each release.
RELEASING.md
How a version is checked, tagged and published.
SECURITY.md
How to report a vulnerability privately.
CONTRIBUTING.md
Where a change belongs and what it has to show.