devproof

module
v0.2.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 13, 2026 License: Apache-2.0

README

DevProof

ci Go Reference Go Report Card License

Package files into OCI artifacts that have the same digest on every machine, carry signed proof of where they came from, and unpack safely.

Configuration, policies, scripts, and catalogs get assembled from several places that all move independently. Put them in a tarball and you have bytes nobody can say much about: not what was selected, not where it came from, not whether it changed, not who stands behind it.

DevProof gives that pile a name derived from its content — a digest that is the same on every machine, forever — then lets you attach signed evidence to that name and check it against your own rules before anything touches disk.

Install

brew install thingzio/tap/devproof

Or with Go:

go install github.com/thingzio/devproof/cmd/devproof@latest

Prebuilt binaries for Linux and macOS (amd64 and arm64) ship with each release, each covered by a signed checksum file and an SBOM. Windows is not supported — use WSL (DP-035).

Quickstart

$ devproof init --src ./content
manifest:        devproof.yaml
source:          ./content
next:            edit metadata.name, then run devproof lock

$ devproof build ./content --to oci-layout://./artifact --tag v1
reference:       oci-layout://./artifact@sha256:e3d8f68bd8c485...
subject:         sha256:e3d8f68bd8c485...
tree digest:     sha256:168de0126f4a8c...
format:          devproof-bundle-v1
files:           2

$ devproof verify oci-layout://./artifact:v1
subject:         sha256:e3d8f68bd8c485...
integrity:       pass
trust:           not-evaluated
semantics:       not-evaluated

$ devproof expand oci-layout://./artifact:v1 --to ./expanded

$ devproof diff oci-layout://./artifact:v1 ./content
from:            sha256:168de0126f4a8c...
to:              sha256:168de0126f4a8c...
result:          identical

Run the build again — different directory, different machine, next year — and the subject digest is the same. Everything else here rests on that.

devproof init writes a commented manifest so a first one does not require reading a schema, and devproof diff answers "has anything changed since I built this?" — exit 0 when the two sides are identical, exit 1 when they differ.

For a five-minute walkthrough that alters a stored artifact and watches verification catch it, see the demo. It runs entirely on your machine, and it runs in CI, so what it claims stays true.

Swap oci-layout:// for oci://registry.example.com/team/config to work against a registry. Credentials come from your Docker configuration, so docker login, gh auth login, or gcloud auth configure-docker is the whole setup.

Use it from Go

The SDK is the primary API and the CLI is a thin adapter over it, so anything you can do at the command line you can do in-process, without shelling out.

import "github.com/thingzio/devproof/pkg/devproof"

client, err := devproof.New()
if err != nil {
	return err
}
defer func() { _ = client.Close() }()

built, err := client.Build(ctx, devproof.BuildRequest{
	SourcePath:  "./content",
	Destination: "oci://registry.example.com/team/config",
	Tag:         "v1",
})
if err != nil {
	return err
}

// Expansion is gated: if the policy is not satisfied, nothing is written.
_, err = client.Expand(ctx, devproof.ExpandRequest{
	Reference:   built.Reference,
	Destination: "./expanded",
	PolicyPath:  "policy.yaml",
})

Full reference on pkg.go.dev.

Verification answers three separate questions

Most tools collapse these into one boolean. Keeping them apart is the point.

Dimension Question Needs
integrity Are these the bytes the artifact claims? nothing — always checked
trust Who produced them, and do I accept that? a policy
semantics Is the content valid for my use? reserved for v1; always not-evaluated

A dimension you did not ask about reports not-evaluated, never pass. If your trust configuration silently failed to load, you will see trust: not-evaluated rather than a green check — which is the difference between knowing and assuming.

Semantics is reserved. The validator interface is deliberately unexported in v1 (DP-026), so this dimension always reports not-evaluated — it is in the report because a consumer should see that nothing checked content meaning, not because you can plug something in yet.

apiVersion: devproof.thingz.io/v1alpha1
kind: VerificationPolicy
metadata:
  name: release-gate
spec:
  subject:
    requireDigestReference: true
  signatures:
    threshold: 1
    identities:
      - issuer: https://token.actions.githubusercontent.com
        subjectPattern: ^https://github\.com/example/config/\.github/workflows/release\.yaml@refs/tags/v.*$
  provenance:
    required: true
    requireLockDigest: true
devproof verify oci://registry.example.com/team/config@sha256:... --policy policy.yaml

Exit code 0 means the policy was satisfied. A failed policy exits non-zero, so a CI gate built on this cannot pass by accident.

How it works

sources ──▶ manifest ──▶ lock ──▶ canonical tree ──▶ OCI subject @ sha256:…
                                                            │
                                        signed provenance, attached as
                                        referrers — identity unchanged
                                                            │
                                        verify ──▶ safely expand to disk

A manifest says what you want, and may name moving things — a branch, a local directory. A lock records what those resolved to, so "what did you ask for" and "what did you get" stay independently reviewable. The files are normalized into a canonical tree, encoded deterministically, and named by digest.

Evidence is attached to that name, not baked into it. Signing, re-signing, or copying an artifact never changes its digest — so a signature can be added later without invalidating every reference to the content.

Multi-source builds compose through explicit mount paths, with one owner per path. Collisions fail loudly, even when the colliding bytes are identical.

apiVersion: devproof.thingz.io/v1alpha1
kind: Bundle
metadata:
  name: example-config
spec:
  sources:
    - name: application
      type: git
      mountPath: app
      config:
        url: https://github.com/example/application.git
        # A branch, a tag, or a full commit SHA. A branch is fine here
        # precisely because the lock pins whatever it resolved to, and a
        # locked build fails rather than quietly following it somewhere new.
        ref: main
        subPath: deploy
    - name: environment
      type: path
      mountPath: environment
      config:
        path: ./production

Safe by construction

  • Expansion is staged and atomic. Files land in a private directory and are published with an exclusive rename. A failed, canceled, or hostile extraction leaves no destination — not a partial one that looks finished.
  • A gated expansion writes nothing when the policy fails. Content that is written and then deleted was already readable.
  • Nothing from a bundle is executed. No hooks, no validators, no plugins.
  • The portable profile rejects symlinks, device files, path aliases, Windows reserved names, and case-fold collisions, so a bundle that builds is a bundle that expands everywhere.
  • Bounded by default — file counts, sizes, compression ratios, and path depth all have documented limits, and memory does not scale with payload size.

Works with what you already have

A DevProof artifact is an ordinary OCI artifact. skopeo, crane, and oras copy it with the digest intact; GHCR, Google Artifact Registry, and distribution all store and serve it, referrers API included. The layer is plain tar+gzip — GNU, BSD, and busybox tar all unpack it directly.

Verified results and commands to reproduce them: interoperability.

What it is not

Not a deployment engine, dependency solver, registry server, container runtime, secrets manager, or package manager.

DevProof proves identity, integrity, provenance, and policy compliance. It makes no claim that the content inside is correct, safe, or free of vulnerabilities — a perfectly valid signature on malware is still a valid signature.

Don't take our word for it

The conformance package is a second, independent reader of the bundle format, built only from the Go standard library and the written specification. It imports nothing else from this project, so it is free to disagree with the main implementation — and when it did, it was the specification that turned out to be wrong.

import "github.com/thingzio/devproof/pkg/conformance"

report, err := conformance.VerifyLayout("./artifact", "v1")

Documentation

Demo a five-minute walkthrough, executed in CI
Architecture components, data flow, failure behavior
Bundle format canonical model, tree digest, OCI encoding
Manifest and lock sources, resolution, filtering, composition
Go SDK · CLI operations, errors, exit codes, streams
Verification policy trust rules and result semantics
Security threat model, trust boundaries, safe extraction
JSON Schemas normative schemas for every document, and what they cannot express
Decisions every accepted design decision, and why
Compatibility what each version number promises
Interoperability verified results against other tooling
Testing golden vectors, determinism matrix, fuzzing

Contributing

Issues and pull requests are welcome — see CONTRIBUTING for the development workflow, and SECURITY to report a vulnerability privately.

License

Apache License 2.0. Dependency licenses and notices are reproduced in THIRD_PARTY_NOTICES.md.

Directories

Path Synopsis
cmd
devproof command
Command devproof builds, verifies, and expands immutable bundles.
Command devproof builds, verifies, and expands immutable bundles.
internal
canonical
Package canonical produces the exact bytes a DevProof subject commits to: path normalization, tree records, JSON, tar, and gzip.
Package canonical produces the exact bytes a DevProof subject commits to: path normalization, tree records, JSON, tar, and gzip.
canonical/deflate
Package deflate is a frozen copy of the Go standard library's DEFLATE encoder.
Package deflate is a frozen copy of the Go standard library's DEFLATE encoder.
cli
Package cli implements the devproof command line.
Package cli implements the devproof command line.
compose
Package compose merges several resolved sources into one canonical tree.
Package compose merges several resolved sources into one canonical tree.
golden
Package golden compares produced bytes against frozen fixtures.
Package golden compares produced bytes against frozen fixtures.
oci
Package oci stores and retrieves DevProof subjects as OCI objects.
Package oci stores and retrieves DevProof subjects as OCI objects.
repo
Package repo locates the repository and holds tests for the contracts its non-Go files make.
Package repo locates the repository and holds tests for the contracts its non-Go files make.
safefs
Package safefs contains DevProof's filesystem boundaries: private workspaces, snapshotting a source tree, and extracting a verified payload.
Package safefs contains DevProof's filesystem boundaries: private workspaces, snapshotting a source tree, and extracting a verified payload.
schema
Package schema names the published JSON Schemas and locates them on disk.
Package schema names the published JSON Schemas and locates them on disk.
version
Package version reports the build identity of this DevProof binary.
Package version reports the build identity of this DevProof binary.
pkg
artifact
Package artifact holds the OCI-facing types DevProof exchanges with registries and local layouts: descriptors, references, and the image manifest that is a bundle's subject.
Package artifact holds the OCI-facing types DevProof exchanges with registries and local layouts: descriptors, references, and the image manifest that is a bundle's subject.
bundle
Package bundle defines the DevProof bundle format: its version identifiers, media types, and the manifest, lock, and inventory documents that describe what a bundle contains.
Package bundle defines the DevProof bundle format: its version identifiers, media types, and the manifest, lock, and inventory documents that describe what a bundle contains.
conformance
Package conformance is an independent reader for the DevProof bundle format.
Package conformance is an independent reader for the DevProof bundle format.
credentials
Package credentials resolves registry credentials from the environment a developer or a CI runner already has.
Package credentials resolves registry credentials from the environment a developer or a CI runner already has.
devproof
Package devproof is a Go-embeddable, extensible, multi-source artifact bundler with canonical identity across platforms, provenance evidence, policy-based verification, and safe deterministic expansion.
Package devproof is a Go-embeddable, extensible, multi-source artifact bundler with canonical identity across platforms, provenance evidence, policy-based verification, and safe deterministic expansion.
evidence
Package evidence describes where a bundle came from, in a form that can be verified independently of the bundle itself.
Package evidence describes where a bundle came from, in a form that can be verified independently of the bundle itself.
fault
Package fault is DevProof's typed error model.
Package fault is DevProof's typed error model.
policy
Package policy defines DevProof's verification result model and, in later phases, the verification policy document and its evaluator.
Package policy defines DevProof's verification result model and, in later phases, the verification policy document and its evaluator.
source
Package source defines how DevProof obtains material, and ships the built-in resolvers for local paths and HTTPS Git.
Package source defines how DevProof obtains material, and ships the built-in resolvers for local paths and HTTPS Git.
source/git
Package git resolves an HTTPS Git repository into a frozen snapshot.
Package git resolves an HTTPS Git repository into a frozen snapshot.
source/path
Package path resolves a local directory into a frozen snapshot.
Package path resolves a local directory into a frozen snapshot.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL