Skip to content

debugmcp/passportsign

Repository files navigation

passportsign

Personhood attestations on the Sigstore transparency log.

passportsign binds a GitHub account to a passport-holding human, without revealing the human's identity, and publishes that binding to the public Sigstore Rekor log as an in-toto attestation with a custom predicateType of https://passportsign.dev/personhood/v1.

It is Sigstore-adjacent in the same way that gitsign is. gitsign signs Git commits with OIDC identity and logs to Rekor — but it doesn't establish personhood. An AI agent with a GitHub account passes gitsign trivially. passportsign fills that gap.

What the badge claims

At time T, a human holding a valid government-issued passport (and optionally: from country X, if the subject chose to disclose) was in control of the GitHub account @username.

That's it. See docs/passportsign.md §1 for the full list of things the badge does not claim, and §8 for the limits of its Sybil resistance.

Status

v0 — pre-alpha, CLI proof-of-concept. v0 shipped 2026-05-25; six-point acceptance walkthrough green, including a real-passport bind on the public Sigstore Rekor log:

passportsign verified · CAN · 2026-05-25

That badge is the v0-shipped evidence for @cynarlab — the maintainer behind debugmcp/mcp-debugger. Other users generate their own by running passportsign bind (see Quick start below); your badge will have your own username, country, and date baked in.

The companion bundle is at docs/evidence/binding.passportsign.json — run passportsign verify against it to re-derive the proof yourself.

Quick start

You'll need:

  • Node 22.5+ (uses node:sqlite).
  • The ZKPassport mobile app (iOS / Android) with your real e-passport loaded.
  • A GitHub account you can create a public gist on (you'll create one during the bind).

Bind a GitHub username to your passport

npx @passportsign/cli bind <your-github-username> --country

The CLI walks four steps:

  1. Gist — prints a nonce and a filename (passportsign.txt); you create a public gist on gist.github.com with that exact content under the username you're binding.
  2. Scan — renders a QR; you scan with the ZKPassport mobile app, approve the disclosure on your phone.
  3. Submit — submits the resulting in-toto attestation to public Sigstore Rekor.
  4. Bundle + badge + index — writes binding.passportsign.json, passportsign-badge.svg, and passportsign-index.json next to where you ran the command. Commit the index to the root of your profile repo (github.com/<you>/<you>) — it's how badge services and passportsign list discover your binding (public Rekor isn't searchable by predicate type).

List a user's bindings

npx @passportsign/cli list <github-username>          # via their published index
npx @passportsign/cli list <github-username> --entry <rekor-uuid>   # direct inspection

Fetches every entry the index references, integrity-checks it against the log, verifies its inclusion proof, and prints the state of each binding: active, stale (older than 12 months), or revoked. --json for scripting.

Revoke a binding

npx @passportsign/cli revoke <github-username>

Needs only a fresh scan of the same passport — no GitHub access (that's the recovery property: if your account is hijacked, you can still revoke). Submits a revocation entry to Rekor and updates your passportsign-index.json; commit the updated index or nobody learns of the revocation. Conversely: anyone with brief access to your passport can do this, and the harm is reversible by re-binding.

Verify someone else's binding

npx @passportsign/cli verify ./binding.passportsign.json

Four checks, all run without any dependency on a passportsign.dev operator — verification needs only public Sigstore Rekor and a local zkPassport SDK:

  • statement bytes hash to the Rekor entry's recorded payloadHash
  • inclusion proof verifies against the captured root
  • captured root is consistent with the current witnessed root (no log rewrite that orphans the entry)
  • zkPassport SDK accepts the proof + the returned uniqueIdentifier matches the statement

Add --no-rekor-refetch for offline structural verification only (skips the consistency check). Add --gist-recheck to also re-fetch the captured gist URL as a liveness signal.

Network requirements

  • Bind: the laptop and phone both need internet. They do not need to be on the same LAN — the zkPassport SDK uses a hosted relay (@obsidion/bridge) to ferry the proof from phone to laptop. Mobile data on the phone + any internet on the laptop works.
  • Verify: any internet (to talk to rekor.sigstore.dev for the online checks). Pure offline verification — --no-rekor-refetch — needs only the bundle plus the zkPassport SDK (downloaded with the CLI install).

Repo layout

packages/
├── core/    shared state machine: canonical serialization, in-toto
│            statement builder, bundle format, GitHub gist check,
│            Rekor client, RFC 6962 Merkle, verifier, profile-index
│            convention, state classification. Runtime-neutral —
│            `@passportsign/core/web` runs on Workers and browsers.
├── cli/     `passportsign` binary: bind, verify, list, revoke.
└── web/     hosted surface: Cloudflare Worker serving live-state
             badges (/badge/<u>.svg), /verify/<u>, and the static
             /bind browser flow. No database, no keys.

docs/
├── passportsign.md        v0.6 spec
├── roadmap.md             v0.5 / v1.0 / v2 milestones + status
├── v0-acceptance.md       six-criteria walkthrough + living evidence
├── evidence/              real-passport bundle + badge from v0 ship
├── index/                 operator overlay indexes (append via PR)
└── upstream-issues/       drafts for SDK fixes filed at zkpassport

License

Apache-2.0. See LICENSE.

About

No description, website, or topics provided.

Resources

License

Stars

1 star

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors