Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 0 additions & 1 deletion .cargo/config.toml.example
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,3 @@ dpp-plugin-traits = { path = "../dpp-core/crates/dpp-plugin-traits" }
dpp-registry = { path = "../dpp-core/crates/dpp-registry" }
dpp-calc = { path = "../dpp-core/crates/dpp-calc" }
dpp-rules = { path = "../dpp-core/crates/dpp-rules" }
dpp-evidence = { path = "../dpp-core/crates/dpp-evidence" }
40 changes: 39 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,45 @@ under the pre-1.0 conventions in [VERSIONING.md](docs/governance/VERSIONING.md):
**minor** bump may contain breaking changes, each listed below under a
**Breaking** heading with a migration note.

## [Unreleased]
## [0.6.0] - 2026-07-10

### Added

- Evidence dossiers are now persisted: migration `0021_evidence_dossier.sql`
adds an append-only `odal.evidence_dossier` table, backed by
`PgEvidenceDossierRepo`.
- New evidence endpoints: `POST /api/v1/dpp/{dppId}/evidence` generates and
stores a dossier; `GET /api/v1/evidence/{id}` fetches one; `POST
/api/v1/evidence/{id}/verify` verifies a stored dossier; `POST
/api/v1/evidence/verify` verifies an uploaded dossier document.
- `odal verify <dossier-id | file>` now verifies against the node instead of
reading a local file only — same exit-code convention (0 verified, 1
tamper, 2 unreadable/unparseable/unreachable).

### Changed

- The evidence dossier wire format (`DossierV1`, `DossierManifest`,
`SignedLayer`) and the audit-trail wire type (`AuditEntry`) are now defined
in this repo's `dpp-types` crate. The verification engine (signature,
hash-chain, and transfer-chain checks) now lives in `dpp-vault`'s
`domain::verify` module and verifies JWS signatures via `dpp-crypto`
directly.
- `odal passport evidence <id>` now generates and stores a dossier (`POST`)
instead of exporting one on the fly (`GET`).

### Removed

- The `dpp-evidence` crate dependency. Its dossier format and verification
engine are dissolved into this repository (see Changed); the crate itself
was removed from `dpp-core` and its crates.io release deleted.

### Breaking

- `GET /api/v1/dpp/{dppId}/evidence` now returns stored-dossier summaries
instead of assembling a dossier on the fly. To get a dossier document,
`POST` to the same path first, then `GET /api/v1/evidence/{id}`.
- `odal verify` requires a reachable node; it no longer verifies a local
file with zero network.

## [0.5.0] - 2026-07-08

Expand Down
6 changes: 6 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ When editing existing code:

When your changes create orphans:
- Remove imports/variables/functions that YOUR changes made unused.

- Don't remove pre-existing dead code unless asked.

The test: Every changed line should trace directly to the user's request.
Expand Down Expand Up @@ -268,6 +269,11 @@ Background cleanup task runs every 6 hours, deleting completed/failed jobs older
| POST | `/vault/api/v1/dpp/{dppId}/suspend` | Bearer | Suspend |
| POST | `/vault/api/v1/dpp/{dppId}/archive` | Bearer | Archive |
| GET | `/vault/api/v1/dpp/{dppId}/history` | Bearer | Audit trail |
| POST | `/vault/api/v1/dpp/{dppId}/evidence` | Bearer | Generate + store an evidence dossier |
| GET | `/vault/api/v1/dpp/{dppId}/evidence` | Bearer | List stored dossier summaries |
| GET | `/vault/api/v1/evidence/{id}` | Bearer | Fetch a stored dossier document |
| POST | `/vault/api/v1/evidence/{id}/verify` | Bearer | Verify a stored dossier |
| POST | `/vault/api/v1/evidence/verify` | Bearer | Verify an uploaded dossier document |
| GET | `/vault/api/v1/node/state` | Bearer | Node setup state (claimed / configured) |
| GET | `/vault/api/v1/operator` | Bearer | Get operator config |
| PATCH | `/vault/api/v1/operator` | Bearer | Update operator branding |
Expand Down
3 changes: 1 addition & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ members = [
]

[workspace.package]
version = "0.5.0"
version = "0.6.0"
edition = "2024"
authors = ["Odal Node <dev@odal-node.io>"]
license = "BSL-1.1"
Expand All @@ -40,7 +40,6 @@ dpp-plugin-traits = "0.7.0"
dpp-registry = "0.7.0"
dpp-calc = "0.7.0"
dpp-rules = { version = "0.7.0", features = ["bundle"] }
dpp-evidence = "0.7.0"

# Web framework
axum = { version = "0.8", features = ["macros", "multipart"] }
Expand Down
15 changes: 7 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,14 +53,14 @@ The engine ships as a **single binary** (`dpp-node`) that fuses all services und
|---|---|---|
| `dpp-types` | lib | Platform-wide types — operator config, auth, audit, API keys |
| `dpp-dal` | lib | PostgreSQL DAL — passport repo, migrations (single-tenant; no RLS) |
| `dpp-vault` | bin+lib | DPP write engine — create, versioned lifecycle (publish / suspend / archive / end-of-life), transfer-of-responsibility handshake, hash-chained audit, evidence-dossier export |
| `dpp-vault` | bin+lib | DPP write engine — create, versioned lifecycle (publish / suspend / archive / end-of-life), transfer-of-responsibility handshake, hash-chained audit, evidence-dossier generation + verification |
| `dpp-identity` | bin+lib | `did:web` identity HTTP service — signing, key rotation |
| `dpp-resolver` | bin+lib | Public QR / Digital Link resolver, JWS-verified fail-closed |
| `dpp-integrator` | bin+lib | CSV/XLSX-to-DPP bulk import adapter with per-sector templates |
| `dpp-common` | lib | Event bus trait + well-known subjects, telemetry, RFC 7807 HTTP errors |
| `dpp-plugin-host` | lib | wasmtime sandbox — fuel metering, memory cap, deny-all WASI, signed-plugin policy |
| `dpp-node` | bin | **The single binary — fuses all services**, boot trust-report, registry outbox drain, signed-ruleset loader |
| `dpp-cli` (`cli/`) | bin | `odal` — the operator control plane, from bootstrap to evidence export and offline verification |
| `dpp-cli` (`cli/`) | bin | `odal` — the operator control plane, from bootstrap to evidence dossier generation and verification |
| `dpp-seal` | lib | eIDAS qualified-seal adapter (CSC/QTSP client scaffold) — resolves to a clearly-marked Ghost until a QTSP is configured; a production-profile node **refuses to boot** on ghost trust adapters |
| `dpp-factor-data` | lib | Licensed LCI factor store — ghost provider until a dataset licence is signed; any ghost-derived result is marked `dataset_id="ghost"` |

Expand All @@ -76,7 +76,6 @@ All core crates are consumed from crates.io (dpp-core is published independently
| `dpp-calc` | EU-methodology calculators (CO2e, repairability) |
| `dpp-plugin-traits` | Wasm plugin ABI |
| `dpp-registry` | EU registry interface types |
| `dpp-evidence` | Evidence dossier wire format + offline verification engine (`odal verify`) |

**Dependency direction**: dpp-engine -> dpp-core (one-way). dpp-core has zero knowledge of this repo.

Expand Down Expand Up @@ -120,9 +119,9 @@ cargo build -p dpp-cli # builds target/debug/odal
```

```bash
# Prove it, offline: export a signed evidence dossier and verify it with no server
./target/debug/odal passport evidence <dpp-id> > dossier.json
./target/debug/odal verify dossier.json # 8+ independent checks, exit 0 = verified
# Generate a signed evidence dossier and verify it against the node
./target/debug/odal passport evidence <dpp-id> # generates + stores a dossier
./target/debug/odal verify <dossier-id> # 8+ independent checks, exit 0 = verified
```

Full command reference: **[cli/README.md](cli/README.md)**.
Expand Down Expand Up @@ -152,13 +151,13 @@ Full command reference: **[cli/README.md](cli/README.md)**.

Docker Compose: `docker/docker-compose.dev.yml`

Migrations: `ops/pg/0001_extensions_roles_schemas.sql` through `0017_passport_transfer.sql` — applied via `PgDal::migrate` at startup if `DATABASE_MIGRATE_URL` is set. The audit table is append-only (DB trigger) and hash-chained (`0015`); the registry outbox (`0006`) is written inside the publish transaction and drained with backoff.
Migrations: `ops/pg/0001_extensions_roles_schemas.sql` through `0021_evidence_dossier.sql` — applied via `PgDal::migrate` at startup if `DATABASE_MIGRATE_URL` is set. The audit table is append-only (DB trigger) and hash-chained (`0015`); the registry outbox (`0006`) is written inside the publish transaction and drained with backoff; evidence dossiers are append-only (`0021`).

---

## What Makes This Node Different (the trust layer, shipped)

**Honesty is enforced, not promised.** Every trust-critical port reports its tier (`ghost` / `sandbox` / `live`) in `/health`; under `NODE_PROFILE=production` the node **refuses to start** while any required port resolves to a placeholder — a node cannot claim trust services it doesn't have. **History is tamper-evident:** every audit entry is hash-chained; a superuser edit is detected at the exact index. **Registration is never lost:** EU-registry intent is committed to a durable outbox in the same transaction as publish, then drained with retry/backoff — kill the node mid-publish and nothing is lost (tested). **Regulation ships as signed data:** compliance rulesets arrive as Ed25519-signed bundles, verified fail-closed and hot-swapped atomically; the active version is visible in `/health`. **Anyone can verify, offline:** a signed evidence dossier (passport, JWS, DID document, audit chain, transfer chain) exports in one call and verifies with zero network via [`dpp-evidence`](https://github.com/odal-node/dpp-core/tree/main/crates/dpp-evidence).
**Honesty is enforced, not promised.** Every trust-critical port reports its tier (`ghost` / `sandbox` / `live`) in `/health`; under `NODE_PROFILE=production` the node **refuses to start** while any required port resolves to a placeholder — a node cannot claim trust services it doesn't have. **History is tamper-evident:** every audit entry is hash-chained; a superuser edit is detected at the exact index. **Registration is never lost:** EU-registry intent is committed to a durable outbox in the same transaction as publish, then drained with retry/backoff — kill the node mid-publish and nothing is lost (tested). **Regulation ships as signed data:** compliance rulesets arrive as Ed25519-signed bundles, verified fail-closed and hot-swapped atomically; the active version is visible in `/health`. **Evidence is generated and verified, not just claimed:** a signed dossier (passport, JWS, DID document, audit chain, transfer chain) is generated and stored in one call, then checked against its own signatures and hash chains via `odal verify` or the evidence API — see [docs/architecture/EVIDENCE-DOSSIER.md](docs/architecture/EVIDENCE-DOSSIER.md).

---

Expand Down
Loading
Loading