dozeGitHubGet doze
Registry
Check against your doze

Which doze do you run?

doze 0.1.1newest · 2 Jul 2026doze 0.1.02 Jul 2026Stop checkingKept in this browser only. Nothing is sent anywhere.

How doze decides to run something

doze up downloads programs and runs them on the machine that holds your source code and your credentials. So every byte is checked against a key doze already carries before it runs, and once a project is pinned, nothing on the network can change what it runs.

One keyCompiled into doze, never fetchedA registry host cannot hand you a key of its own.
Two signaturesEach archive, and the index as a wholeWhat runs, and the facts that choose it.
One lockfiledoze.lock pins every hashPinned and cached runs with no network at all.
The chain

Six steps from source to a running Postgres

Every arrow assumes the step before it might be hostile. The example is the postgres module, release 0.2.4, on an Apple silicon Mac.

Before it reaches youpublic CI, public source
1

The engine is built

github.com/doze-dev/doze-binaries

Postgres, Kvrocks and Valkey for macOS are built from upstream source in public CI; engines upstream already ships are re-hosted. Published once, never rebuilt.

sha256 per platformnot signed
2

The module is built

github.com/doze-dev/doze-modules

CI cross-compiles the plugin for three platforms with the SDK's release tool and uploads the archives and an unsigned index.yaml to a GitHub release. doze AWS and doze Kafka ship their modules the same way from their own repos.

3 platformsunsigned on purpose
3

The registry signs it

github.com/doze-dev/doze-registry

The one place the private key lives (a CI secret). It signs each archive's sha256 with ed25519, then the whole index: module, releases, engine majors, protocol, channels. validate re-checks every signature before deploy.

ed25519 × 2git history is the ledger

The network. registry.doze-dev.com serves the signed index; GitHub releases serve the archives. Neither is trusted: they can be slow or down, and nothing they say is believed without a signature.

untrusted by design
On your machinedoze, before anything runs
4

Check the index

/doze/postgres/index.yaml

doze fetches the index and checks its signature against the key compiled into doze. Only then does it pick a release: newest that speaks its plugin protocol, supports every Postgres major you declared, and runs on this doze.

index signature
5

Check the archive

postgres-plugin-0.2.4-aarch64-apple-darwin.tar.gz

The download's sha256 must equal the one in the signed index, and the archive's own signature over that sha256 must verify. Nothing is unpacked until both pass.

sha256archive signature
6

Pin it, then run offline

doze.lock, next to doze.hcl

The lock records the module release, protocol, engine majors and every platform's sha256, plus the engine's exact version and hashes. From then on a cached project resolves with no network, not even the index. Only doze modules upgrade moves a pin.

pinnedoffline
What step 6 writes · doze.lock
modules:
    doze/postgres:
        version: 0.2.4             # the module release, chosen for you
        protocol: 1                # doze plugin protocol it speaks
        engines:
            - "14"
            - "15"
            - "16"
            - "17"
            - "18"
        hashes:                    # every platform, from the signed index
            aarch64-apple-darwin: sha256:a07134d07cf988862f5b2d1a288cc43a40ace5b96e88e190b5d66ca8b207b89a
            aarch64-unknown-linux-gnu: sha256:f29c48e5dab175d6f1b2991f274e2e5aedb55a9993eff90128feb423380fd2a2
            x86_64-unknown-linux-gnu: sha256:7c920599a5a52f4ed4306963797e88de7ed6beb0be130b8b1039f7c7d0354f68

The registry's key itself is not in the lock: for the doze namespace it is compiled into doze, so there is nothing to pin and no key is ever trusted on first use. Every module is signed with that one key: modules arrive as pull requests to doze-modules.

Threats

What each check stops

Signatures prove who published, not that the code is harmless. These are the attacks the chain is built for, and what is left over.

If someone…What stops itWhat is left
Changes an archive on GitHubThe archive's signature covers its sha256, and doze.lock pins the same hash. Changed bytes fail before anything is unpacked.Nothing runs. The host can only make the download fail.
Swaps or edits an indexThe index signature covers every release, engine major, protocol and channel. Claiming Postgres 19 support, adding a release, or editing a URL breaks it.The oldest-doze field sits outside the signed part today. See known gaps.
Rolls a release backThe stable channel is inside the signature. The registry's CI refuses any change that drops or alters a published release. A pinned project never reads the channel.A host can replay an older, validly signed index to a fresh resolve: indexes carry no expiry yet.
Takes over the mirror or CDNEverything it serves is checked against the key in doze, so it cannot forge an index or an archive.It can refuse service. Locked and cached projects never contact it.
Changes the keydoze never fetches a key: it is a constant in the doze binary. A new keys.json on the host changes nothing; anything signed by another key fails.A real rotation takes a doze release. See the rotation question.
Steals the registry keyThey could sign new releases. They could not change what a locked project runs: locks pin checksums, and pins move only on doze modules upgrade.A fresh resolve or an upgrade could pick the forged release until the key is rotated.
Failures

What a failure looks like

doze stops and says which check failed. These are the messages in the code, filled in for postgres 0.2.4.

The index was editedstops
module index for doze/postgres: index signature does not match the publisher key
The archive was changedstops
signature check failed for postgres 0.2.4 (aarch64-apple-darwin): signature does not match the publisher key
The bytes differ from doze.lockstops
checksum mismatch for postgres 0.2.4 (aarch64-apple-darwin): locked sha256:a07134d0…b89a, got sha256:[the hash of what arrived]
A pinned release is gone from the indexsays the fix
module doze/postgres 0.2.4 (pinned in doze.lock) is no longer published — run 'doze modules upgrade postgres'
The lock was written by a newer dozedoze 0.2 and later
module doze/postgres 0.3.1 (pinned in doze.lock) needs doze 0.3.0 or newer; this doze is 0.2.0. Update doze (in the app: Settings › About); the lock was written by a newer doze
The index has no signaturestops
module index for doze/postgres: module index is unsigned

[The prefix doze up prints before these lines is not shown.] The "needs doze 0.3.0" example is a future release, to show the shape; doze 0.2.0 and later print it, with three-part versions.

Don't take our word

Verify it yourself

Everything doze checks, you can check with stock tools. These commands were run against postgres 0.2.4 and pass.

You needcurl, shasum, and OpenSSL 3. The openssl that ships with macOS is LibreSSL and cannot verify ed25519; brew install openssl@3 can.
One command for all of itnew
doze modules verify [not a command yet]: would re-check every pinned module in doze.lock against the registry and print each key, hash and signature.
1

Save the registry's key

The same 32 bytes as RegistryKey in doze's source, wrapped as PEM.

doze.pem
-----BEGIN PUBLIC KEY-----
MCowBQYDK2VwAyEANu5y8mbjYv7XEtNFBXwPVl+C8SBteVApIROefBwGWjw=
-----END PUBLIC KEY-----
2

Download an archive and hash it

Compare with releases.0.2.4.artifacts.aarch64-apple-darwin.sha256 in the index.

Terminal
$ curl -sLO https://github.com/doze-dev/doze-modules/releases/download/postgres/postgres-plugin-0.2.4-aarch64-apple-darwin.tar.gz
$ shasum -a 256 postgres-plugin-0.2.4-aarch64-apple-darwin.tar.gz
a07134d07cf988862f5b2d1a288cc43a40ace5b96e88e190b5d66ca8b207b89a  postgres-plugin-0.2.4-aarch64-apple-darwin.tar.gz
3

Check the signature over that hash

The signed message is the lowercase hex sha256, with no newline. The signature is the artifact's sig.

Terminal
$ printf %s a07134d07cf988862f5b2d1a288cc43a40ace5b96e88e190b5d66ca8b207b89a > sum.txt
$ echo MiZYLas0hSExnTF4jGo17Do0qjJ+O4XbkzBxqs2oRSJn5FuVo6rl6jC069xgafSKSP/AI4mUAJitsNcsdbDyBQ== | base64 -d > sig.bin
$ openssl pkeyutl -verify -pubin -inkey doze.pem -rawin -in sum.txt -sigfile sig.bin
Signature Verified Successfully
4

Check every index and every archive at once

The index signature is over a canonical JSON form of the index, which is fiddly by hand. The registry's own validator does exactly what doze does; validate:remote also re-downloads every archive.

Terminal
$ git clone https://github.com/doze-dev/doze-registry && cd doze-registry
$ npm install
$ npm run validate          # structure + every signature, offline
$ npm run validate:remote   # + each archive's sha256 as served
5

Ask your project

Runs the real client path, signatures included, and changes nothing. Exits 1 if a newer compatible release exists.

Terminal
$ doze modules upgrade --check
The registry's keyActive

Namespace doze

ed25519 public key, base64Nu5y8mbjYv7XEtNFBXwPVl+C8SBteVApIROefBwGWjw=
In use since
26 Jun 2026
Signs
All 8 modules, every release
Private half
One CI secret in doze-registry. Never on the archive host, the module repos or a build machine.
Public half
Compiled into doze; also at /doze/keys.json for people and the validator.
History
One key, no rotations
Open question[to decide]

Key rotation policy

Decided so far: no rotation on a calendar; rotate on suspected compromise. A rotation is a doze release carrying the new key, then the registry is re-signed. Locked and cached projects keep working throughout; only fresh contact with the registry fails until doze is updated.

On compromise, in order: rotate, audit what the old key signed (the registry's git history), republish clean indexes, announce on the publisher's notices.

Still open
  • Should doze carry the next key ahead of time, so a rotation does not need an emergency release? [to decide]
  • Should the old key sign a statement naming the new one? [to decide]
  • How long a superseded key stays listed, and what doze says when it sees it. [to decide]
Files

Where the files live

The registry is static files and signatures: no server, no database, no login. A browser that opens registry.doze-dev.com is sent here.

PathWhat it holdsTrust
registry.doze-dev.com/doze/<module>/index.yamlReleases, engine majors, protocol, archive URLs, each sha256 and signature, channels.signed, twice
registry.doze-dev.com/doze/<module>/meta.yamlThe docs on each module page, generated from the module's Describe().unsigned, prose only
registry.doze-dev.com/doze/keys.jsonThe namespace and its public key. doze does not read it; its copy is compiled in.reference copy
registry.doze-dev.com/index.jsonThe catalog this site's search reads, generated from the indexes at build.derived
github.com/doze-dev/doze-modules/releases/download/<module>/…tar.gzThe plugin archives, one per platform. doze AWS and doze Kafka host theirs in their own repos.untrusted host
github.com/doze-dev/doze-binaries/releasesEngine archives (Postgres 14.0 to 18.6 and the rest), pinned by sha256 in doze.lock.checksum only

doze 0.2 and later fetch from registry.doze-dev.com. Older doze (0.1.1) has doze.nerdmenot.in/registry compiled in; that address keeps serving the same signed files, so it keeps working.

Honesty

Known gaps

What this chain does not do yet. None of them lets a host change what a locked, cached project runs.

The oldest-doze field is not signed

Each release can say which doze it needs (doze: "0.2.0"). It sits beside the signed part so that a doze from before the field still verifies. A host could strip it; the worst case is an older doze choosing a release it then cannot run. The next index schema moves it inside the signature.

fix designed

No transparency log

There is no public append-only log of what the key signed. The ledger is the doze-registry git history, and its CI refuses a change that drops or edits a published release.

[not planned yet]

Indexes do not expire

A signed index carries no timestamp, so a hostile host can serve last month's valid index to a fresh resolve and hide a newer release. Pinned projects are unaffected.

[to decide]

Engine binaries are checked, not signed

Postgres and the other engines are verified by sha256 from the doze-binaries index and pinned in doze.lock, but the index itself is not signed. Some engines are re-hosted upstream builds, not rebuilt from source.

[to decide]

No build provenance

Releases are built in public CI, but no release links to the exact CI run that built it, and there is no signed build attestation.

new: link each release to its run

One key for everything

A single ed25519 key signs every module. There is no second signer and no threshold. Rotating it takes a doze release.

see rotation, above