Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
0494b1e
feat(auths-keri): model Ed25519 verkey transferability (accept B/Ed25…
bordumb Jun 13, 2026
b470aba
feat(auths-keri): emit/ingest the KERI key-state notice wire record
bordumb Jun 13, 2026
766e33b
feat(witness-node): operator node crate behind an additive witness-no…
bordumb Jun 13, 2026
5331ab9
feat(witness-node): real one-command standup — up reaches a healthy n…
bordumb Jun 13, 2026
9e0584a
feat(witness-node): one-command standup reaches a healthy node
bordumb Jun 13, 2026
c4af251
feat(verifier): offline self-contained witness-receipt verification
bordumb Jun 13, 2026
13767be
feat(witness): serve a conformant key-state notice from a running node
bordumb Jun 13, 2026
aa5eeb4
feat(witness): a node proves which binary it runs (signed build attes…
bordumb Jun 14, 2026
464ee68
witness-node: one source of truth for the operator-vocabulary rule
bordumb Jun 14, 2026
0f74dcf
fix(auths-keri): SAID a basic-prefix inception with i kept, matching …
bordumb Jun 14, 2026
ba473d2
feat(did-webs): emit a did:webs DID document for an AID
bordumb Jun 14, 2026
b3682bc
feat(keri): OOBI discovery — resolve + serve KERI Out-Of-Band Introdu…
bordumb Jun 14, 2026
2090092
feat(keri): IPEX grant/admit — exchange an ACDC credential over KERI
bordumb Jun 14, 2026
8cfadc8
feat(pairing): bind session proofs to the TLS channel (RFC 9266 tls-e…
bordumb Jun 14, 2026
d9e40af
feat(keri): KEL-rooted X.509 leaf certs for TLS composition
bordumb Jun 14, 2026
9bb70cc
feat(tls-cert): read the did:keri identity out of a leaf's SAN
bordumb Jun 14, 2026
0240249
feat(tls-cert): AID authorizes its TLS key — adversarial verifier rej…
bordumb Jun 14, 2026
66b2bc1
feat(quic): carry the KEL-rooted leaf + channel binding over QUIC/HTTP3
bordumb Jun 14, 2026
f4db1e6
test(conformance): keripy 1.3.4 cross-implementation gate + CI
bordumb Jun 14, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Keep the Docker build context to source only. Without this, `COPY . .` ships
# the entire working tree — compiled `target/` trees, local worktrees, Python
# virtualenvs under examples/, and node_modules — which can be tens of GB and
# makes the image build slow or fail outright on context transfer. None of it is
# needed to compile a binary from source.

# Rust build output (every crate's, and the root's)
target/
**/target/

# Local git worktrees and VCS metadata
.worktrees/
.git/

# Example/app sandboxes: Python venvs and JS deps
**/.venv/
**/venv/
**/node_modules/

# Editor / OS noise
**/.DS_Store
**/*.swp

# Build artifacts that are regenerated, never sources
**/*.profraw
coverage/
dist/
35 changes: 35 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,41 @@ jobs:
working-directory: crates/auths-verifier
run: wasm-pack build --target bundler --no-default-features --features wasm

conformance:
name: KERI conformance (keripy 1.3.4)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@1.93
- uses: actions/cache@v4
with:
path: |
~/.cargo/registry
~/.cargo/git
target
key: ${{ runner.os }}-conformance-${{ hashFiles('**/Cargo.lock') }}
restore-keys: ${{ runner.os }}-conformance-
- uses: astral-sh/setup-uv@v4
# keripy's crypto (pysodium) loads libsodium via ctypes at runtime.
- name: Install libsodium (keripy runtime dependency)
run: sudo apt-get update && sudo apt-get install -y libsodium-dev
- name: Build auths CLI
run: cargo build --package auths-cli
# Drives the real auths binary against the keripy 1.3.4 reference for every
# interop surface (ksn, did:webs, OOBI, IPEX) and fails the build on any
# byte/structural divergence. uv installs the pinned keri==1.3.4 oracle.
- name: Run keripy conformance gate
working-directory: tests/conformance
run: uv run pytest -v --junitxml=../../conformance-results.xml
env:
AUTHS_BIN: ${{ github.workspace }}/target/debug/auths
- name: Upload conformance results
if: always()
uses: actions/upload-artifact@v4
with:
name: conformance-results
path: conformance-results.xml

e2e-tests:
name: E2E Tests (${{ matrix.os }})
needs: [test]
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -152,3 +152,4 @@ jnkn.db
.mcp.json
.chunkhound.json
.worktrees/
.recurve/
25 changes: 25 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ members = [
"crates/auths-rp",
"crates/xtask", "crates/auths-api",
"crates/auths-witness",
"crates/auths-witness-node",
"crates/auths-checkpoint-cosigner",
"crates/auths-monitor",
]
Expand Down Expand Up @@ -96,6 +97,8 @@ auths-pairing-protocol = { path = "crates/auths-pairing-protocol", version = "0.
auths-storage = { path = "crates/auths-storage", version = "0.1.3" }
auths-transparency = { path = "crates/auths-transparency", version = "0.1.3", default-features = false }
auths-utils = { path = "crates/auths-utils", version = "0.1.3" }
auths-witness = { path = "crates/auths-witness", version = "0.1.3" }
auths-witness-node = { path = "crates/auths-witness-node", version = "0.1.3" }
insta = { version = "1", features = ["json"] }

# Compile crypto-heavy crates with optimizations even in dev/test builds.
Expand Down
17 changes: 16 additions & 1 deletion crates/auths-cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,10 @@ name = "auths-verify"
path = "src/bin/verify.rs"

[dependencies]
auths-keri.workspace = true
# `tls-cert` powers `auths tls-cert` (KEL-rooted X.509 leaf certs for TLS
# composition); `quic` carries the same leaf + channel binding over QUIC/HTTP3.
# The wire/crypto definition lives in auths-keri.
auths-keri = { workspace = true, features = ["tls-cert", "quic"] }
clap = { version = "4", features = ["derive", "env"] }
clap_complete = "4"
colored = "3.1.1"
Expand Down Expand Up @@ -82,9 +85,21 @@ auths-pairing-daemon = { workspace = true, optional = true }
axum = { version = "0.8", optional = true }
tokio-util = { version = "0.7", optional = true }

# Witness-node operator surface (optional, default-OFF). The `auths witness`
# subcommand *surface* always compiles (thin clap defs, no heavy deps); only the
# node *handler* and this crate are feature-gated, so the lean default install
# stays lean. The dependency arrow is one-way: this crate composes the node
# crate, never the reverse.
auths-witness-node = { workspace = true, optional = true }

[features]
default = ["lan-pairing"]
lan-pairing = ["dep:auths-pairing-daemon", "dep:axum", "dep:tokio-util", "auths-sdk/lan-pairing"]
# Enables the real `auths witness up|down|status|register|logs` handlers by
# pulling the node-operator crate. A build without it keeps these verbs (help
# and parsing are identical) but the handlers return a "install the witness
# build" error.
witness-node = ["dep:auths-witness-node"]

[target.'cfg(unix)'.dependencies]
nix = { version = "0.29", features = ["signal", "process"] }
Expand Down
15 changes: 15 additions & 0 deletions crates/auths-cli/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,20 @@ use crate::commands::debug::DebugCmd;
use crate::commands::demo::DemoCommand;
use crate::commands::device::DeviceCommand;
use crate::commands::device::pair::PairCommand;
use crate::commands::did_webs::DidWebsCommand;
use crate::commands::doctor::DoctorCommand;
use crate::commands::emergency::EmergencyCommand;
use crate::commands::error_lookup::ErrorLookupCommand;
use crate::commands::id::IdCommand;
use crate::commands::init::InitCommand;
use crate::commands::ipex::IpexCommand;
use crate::commands::key::KeyCommand;
use crate::commands::key_state::KeyStateCommand;
use crate::commands::learn::LearnCommand;
use crate::commands::log::LogCommand;
use crate::commands::multi_sig::MultiSigCommand;
use crate::commands::namespace::NamespaceCommand;
use crate::commands::oobi::OobiCommand;
use crate::commands::org::OrgCommand;
use crate::commands::policy::PolicyCommand;
use crate::commands::publish::PublishCommand;
Expand All @@ -38,6 +42,7 @@ use crate::commands::scim::ScimCommand;
use crate::commands::sign::SignCommand;
use crate::commands::sign_commit::SignCommitCommand;
use crate::commands::status::StatusCommand;
use crate::commands::tls_cert::TlsCertCommand;
use crate::commands::trust::TrustCommand;
use crate::commands::unified_verify::UnifiedVerifyCommand;
use crate::commands::whoami::WhoamiCommand;
Expand Down Expand Up @@ -122,6 +127,16 @@ pub enum RootCommand {
Device(DeviceCommand),
#[command(hide = true)]
Key(KeyCommand),
#[command(hide = true, name = "key-state")]
KeyState(KeyStateCommand),
#[command(hide = true, name = "did-webs")]
DidWebs(DidWebsCommand),
#[command(hide = true, name = "tls-cert")]
TlsCert(TlsCertCommand),
#[command(hide = true)]
Oobi(OobiCommand),
#[command(hide = true)]
Ipex(IpexCommand),
#[command(hide = true)]
Approval(ApprovalCommand),
#[command(hide = true)]
Expand Down
63 changes: 63 additions & 0 deletions crates/auths-cli/src/commands/did_webs.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
//! `auths did-webs` — emit a `did:webs` DID document for an AID.
//!
//! `did:webs` anchors a KERI AID into a **web-resolvable** DID document so a
//! standard DID resolver verifies the identifier without speaking KERI. The
//! document is derived by replaying the AID's KEL into its current key-state, so
//! the verification material is exactly the AID's current signing keys — the KEL
//! stays the source of truth. The document auths emits is byte-compatible with
//! the ToIP did:webs reference resolver's `didDocument`
//! (`{id, verificationMethod, service, alsoKnownAs}`). The crypto/wire definition
//! lives in `auths-keri::did_webs`; this is a thin CLI adapter over it.

use std::path::{Path, PathBuf};

use anyhow::{Result, anyhow};
use auths_keri::{DidWebsDocument, TrustedKel, parse_kel_json};
use auths_utils::path::expand_tilde;
use clap::Parser;

use crate::config::CliConfig;

/// Emit a `did:webs` DID document for an AID (KEL-anchored).
#[derive(Parser, Debug, Clone)]
#[command(
about = "Emit a did:webs DID document for an AID — resolvable under a standard did:webs resolver",
after_help = "Examples:
auths did-webs --from-kel kel.json --domain example.com
auths did-webs --from-kel kel.json --domain 'example.com%3A3901:dids'"
)]
pub struct DidWebsCommand {
/// Replay this KEL file and project its current key-state into a `did:webs`
/// DID document (the shape a did:webs/DID-core resolver reads).
#[clap(long, value_name = "KEL.json")]
pub from_kel: PathBuf,

/// The web domain the `did:webs` is anchored at — the host (optionally
/// `host%3Aport` and path segments) before the AID in `did:webs:<domain>:<aid>`.
#[clap(long, value_name = "DOMAIN")]
pub domain: String,
}

impl DidWebsCommand {
/// Run the command: replay the KEL and print the `did:webs` DID document.
pub fn execute(&self, _ctx: &CliConfig) -> Result<()> {
self.emit(&self.from_kel)
}

/// Replay a KEL file and print the projected `did:webs` DID document.
fn emit(&self, kel_path: &Path) -> Result<()> {
let path = expand_tilde(kel_path)?;
let json = std::fs::read_to_string(&path)
.map_err(|e| anyhow!("read KEL {}: {e}", path.display()))?;
let events = parse_kel_json(&json).map_err(|e| anyhow!("parse KEL: {e}"))?;
// A KEL file the operator hands us is a local, self-owned artifact — the
// reviewable trust assertion that structural replay requires.
let state = TrustedKel::from_trusted_source(&events)
.replay()
.map_err(|e| anyhow!("replay KEL: {e}"))?;
let doc = DidWebsDocument::from_key_state(&state, &self.domain)
.map_err(|e| anyhow!("project key-state into a did:webs document: {e}"))?;
println!("{}", serde_json::to_string_pretty(&doc)?);
Ok(())
}
}
Loading
Loading