2026-05-15 15:08:20 +02:00
|
|
|
# Roadmap
|
|
|
|
|
|
2026-05-16 00:32:38 +02:00
|
|
|
This roadmap is intended to be checkable. Each item should either be completed
|
|
|
|
|
with tests/docs or split into smaller items before implementation.
|
|
|
|
|
|
|
|
|
|
Status markers:
|
|
|
|
|
|
|
|
|
|
- `[ ]` Not started
|
|
|
|
|
- `[~]` In progress
|
|
|
|
|
- `[x]` Done
|
|
|
|
|
|
2026-05-15 15:08:20 +02:00
|
|
|
## Phase 0: Bootstrap
|
|
|
|
|
|
2026-05-16 00:32:38 +02:00
|
|
|
Goal: establish a compiling single-binary local runtime with local state, local
|
|
|
|
|
control, local CAS, service installation, and written architecture decisions.
|
|
|
|
|
|
|
|
|
|
- `[x]` Single `geth` binary with daemon and control modes.
|
|
|
|
|
Acceptance criteria:
|
|
|
|
|
- `cargo run -p geth -- init` initializes a temp `GETH_HOME`.
|
|
|
|
|
- `cargo run -p geth -- daemon run` starts one local daemon.
|
|
|
|
|
- No `gethd` or `gethctl` binaries exist in the workspace.
|
|
|
|
|
|
|
|
|
|
- `[x]` Local daemon control socket.
|
|
|
|
|
Acceptance criteria:
|
|
|
|
|
- Control request/response types roundtrip through JSONL serialization.
|
|
|
|
|
- `geth status` and `geth node id` talk to a running daemon.
|
|
|
|
|
- Control decoding treats input as untrusted and returns structured errors.
|
|
|
|
|
|
|
|
|
|
- `[x]` Local metadata store and identity.
|
|
|
|
|
Acceptance criteria:
|
|
|
|
|
- SQLite migrations are idempotent.
|
|
|
|
|
- Agent identity persists across repeated opens of the same `GETH_HOME`.
|
|
|
|
|
- Store schema includes resources, auth/keychain logs, CAS, peers, modules,
|
|
|
|
|
SSH cert requests, certificates, and revocations.
|
|
|
|
|
|
|
|
|
|
- `[x]` Local filesystem CAS.
|
|
|
|
|
Acceptance criteria:
|
|
|
|
|
- `geth cas add/hash/has/get/list` work through the daemon.
|
|
|
|
|
- Blob paths use BLAKE3 hashes under `cas/blobs/<aa>/<bb>/<hash>`.
|
|
|
|
|
- Unit or integration tests verify bytes roundtrip unchanged.
|
|
|
|
|
|
|
|
|
|
- `[x]` User service installer.
|
|
|
|
|
Acceptance criteria:
|
|
|
|
|
- `geth daemon service print --manager systemd|launchd|windows-task` prints
|
|
|
|
|
the expected user-level service definition or command.
|
|
|
|
|
- Linux install targets a systemd user unit, not a system service.
|
|
|
|
|
- macOS install targets a launchd user agent.
|
|
|
|
|
- Windows install targets a per-user scheduled task.
|
|
|
|
|
- Tests verify generated definitions do not target privileged system services.
|
|
|
|
|
|
|
|
|
|
- `[x]` Bootstrap docs and ADRs.
|
|
|
|
|
Acceptance criteria:
|
|
|
|
|
- README explains what geth is and what it is not.
|
|
|
|
|
- Architecture docs state Iroh-only remote communication and SSH trust role.
|
|
|
|
|
- ADRs cover single binary, Iroh-only transport, resources, auth, SSH, CAS,
|
|
|
|
|
synchronized structures, service installation, and SSH certificate flows.
|
2026-05-15 15:08:20 +02:00
|
|
|
|
|
|
|
|
## Phase 1: Iroh Foundation
|
|
|
|
|
|
2026-05-16 00:32:38 +02:00
|
|
|
Goal: make the daemon own a real Iroh endpoint and establish authenticated
|
|
|
|
|
geth-to-geth connections without granting trust from discovery alone.
|
|
|
|
|
|
2026-05-16 01:54:00 +02:00
|
|
|
- `[x]` Pin and compile Iroh dependencies.
|
2026-05-16 00:32:38 +02:00
|
|
|
Acceptance criteria:
|
|
|
|
|
- `iroh` is added only after APIs are pinned and `cargo check --workspace`
|
|
|
|
|
passes.
|
|
|
|
|
- `geth-iroh` exposes endpoint startup/shutdown wrappers.
|
|
|
|
|
- Docs note exact crate versions and any API assumptions.
|
|
|
|
|
|
2026-05-16 01:54:00 +02:00
|
|
|
- `[x]` Daemon-owned Iroh endpoint.
|
2026-05-16 00:32:38 +02:00
|
|
|
Acceptance criteria:
|
|
|
|
|
- The daemon creates one shared Iroh endpoint on startup.
|
|
|
|
|
- `geth status --json` reports endpoint status and EndpointID.
|
|
|
|
|
- Endpoint identity is bound to agent/node identity in local metadata.
|
|
|
|
|
- Restarting the daemon preserves higher-level node identity.
|
|
|
|
|
|
2026-05-16 03:17:45 +02:00
|
|
|
- `[x]` Built-in relay policy and configuration.
|
2026-05-16 02:06:28 +02:00
|
|
|
Acceptance criteria:
|
2026-05-16 03:17:45 +02:00
|
|
|
- Config can select disabled, default Iroh relays, and staging relays.
|
2026-05-16 02:06:28 +02:00
|
|
|
- The intended product default uses relays unless explicitly disabled.
|
|
|
|
|
- `geth status --json` reports the selected relay mode.
|
|
|
|
|
- Tests cover config parsing and endpoint builder relay-mode selection.
|
|
|
|
|
|
2026-05-16 14:28:38 +02:00
|
|
|
- `[x]` Custom relay maps.
|
2026-05-16 03:17:45 +02:00
|
|
|
Acceptance criteria:
|
|
|
|
|
- Config can define and select named custom relay maps.
|
|
|
|
|
- Invalid relay URLs fail config validation with clear errors.
|
|
|
|
|
- Status output identifies the selected custom relay map without exposing
|
|
|
|
|
unrelated config.
|
|
|
|
|
|
2026-05-16 14:33:45 +02:00
|
|
|
- `[x]` Iroh LAN address discovery.
|
2026-05-16 02:06:28 +02:00
|
|
|
Acceptance criteria:
|
2026-05-16 14:33:45 +02:00
|
|
|
- Config can enable or disable Iroh local-network discovery.
|
|
|
|
|
- The daemon registers Iroh's local mDNS-like discovery service when enabled.
|
|
|
|
|
- `geth status --json` reports whether local-network discovery is enabled.
|
|
|
|
|
|
2026-05-18 17:05:43 +02:00
|
|
|
- `[x]` Signed peer-card LAN discovery payloads.
|
2026-05-16 14:33:45 +02:00
|
|
|
Acceptance criteria:
|
2026-05-18 04:03:52 +02:00
|
|
|
- `[x]` Manual `geth peer export/import/list` can exchange signed peer cards
|
|
|
|
|
and store them as untrusted candidates.
|
2026-05-18 12:09:50 +02:00
|
|
|
- `[x]` Exported daemon peer cards include Iroh EndpointID plus available
|
|
|
|
|
relay/direct address candidates.
|
2026-05-18 17:05:43 +02:00
|
|
|
- `[x]` The daemon can advertise and discover signed geth peer cards over LAN
|
2026-05-16 14:33:45 +02:00
|
|
|
discovery.
|
2026-05-18 04:03:52 +02:00
|
|
|
- `[x]` Imported peer cards are stored only as untrusted peer candidates.
|
|
|
|
|
- `[x]` Discovered EndpointIDs do not grant module access without keychain/auth
|
2026-05-16 02:06:28 +02:00
|
|
|
validation.
|
|
|
|
|
|
2026-05-16 03:37:51 +02:00
|
|
|
- `[x]` Protocol/router scaffold.
|
2026-05-16 00:32:38 +02:00
|
|
|
Acceptance criteria:
|
|
|
|
|
- ALPN constants are registered through one module router.
|
|
|
|
|
- Unknown ALPNs are rejected explicitly.
|
|
|
|
|
- Tests cover registration collisions and unknown protocol handling.
|
|
|
|
|
|
2026-05-16 14:24:21 +02:00
|
|
|
- `[x]` Peer cards.
|
2026-05-16 00:32:38 +02:00
|
|
|
Acceptance criteria:
|
|
|
|
|
- A peer card contains node ID, agent ID, endpoint candidates, timestamp, and
|
|
|
|
|
signature metadata.
|
2026-05-18 04:03:52 +02:00
|
|
|
- Peer-card signatures cover deterministic canonical payloads and reject
|
|
|
|
|
tampered endpoint candidates.
|
2026-05-16 00:32:38 +02:00
|
|
|
- Peer cards are stored in `peer_cards`.
|
|
|
|
|
- Invalid or unsigned peer cards do not update trust state.
|
|
|
|
|
|
2026-05-16 14:24:21 +02:00
|
|
|
- `[x]` Untrusted discovery backend trait.
|
2026-05-16 00:32:38 +02:00
|
|
|
Acceptance criteria:
|
|
|
|
|
- Discovery returns candidate peer cards only.
|
|
|
|
|
- No discovery result grants capabilities or trust.
|
|
|
|
|
- `auth explain` can distinguish "discovered" from "trusted".
|
|
|
|
|
|
2026-05-18 17:01:50 +02:00
|
|
|
- `[x]` Basic authenticated peer connection.
|
2026-05-18 12:09:50 +02:00
|
|
|
Acceptance criteria:
|
|
|
|
|
- `[x]` `geth peer ping <node-id>` dials another node over Iroh using an
|
|
|
|
|
imported signed peer card.
|
|
|
|
|
- `[x]` The remote side validates the caller's signed peer card and stores it
|
|
|
|
|
as a candidate only.
|
|
|
|
|
- `[x]` The ping response records negotiated ALPN and remote endpoint
|
|
|
|
|
identity.
|
2026-05-18 17:01:50 +02:00
|
|
|
- `[x]` The remote side proves an agent/node binding before protected module
|
2026-05-18 12:09:50 +02:00
|
|
|
access.
|
2026-05-18 17:01:50 +02:00
|
|
|
- `[x]` Protected module handlers reject requests that only know an
|
2026-05-18 12:09:50 +02:00
|
|
|
EndpointID and lack resource capabilities.
|
2026-05-15 15:08:20 +02:00
|
|
|
|
2026-05-18 22:17:27 +02:00
|
|
|
- `[x]` Authorized sync status summary.
|
|
|
|
|
Acceptance criteria:
|
|
|
|
|
- `[x]` The daemon can ask an imported peer for sync stream watermarks over
|
|
|
|
|
the protected Iroh control ALPN.
|
|
|
|
|
- `[x]` The serving peer validates the caller's signed peer card against the
|
|
|
|
|
observed Iroh EndpointID before returning watermarks.
|
|
|
|
|
- `[x]` The serving peer only includes streams where the caller already has
|
|
|
|
|
the relevant resource capability.
|
|
|
|
|
- `[x]` Background live-sync skips per-module pulls when the authorized remote
|
|
|
|
|
watermark has not advanced.
|
|
|
|
|
- `[x]` Tests verify unauthorized streams are omitted from summary output.
|
|
|
|
|
|
2026-05-15 15:08:20 +02:00
|
|
|
## Phase 2: Trust And Authorization
|
|
|
|
|
|
2026-05-16 00:32:38 +02:00
|
|
|
Goal: replace stubs with signed, reducible keychain/auth operation logs and
|
|
|
|
|
resource-scoped capability decisions.
|
|
|
|
|
|
2026-05-16 14:37:16 +02:00
|
|
|
- `[x]` Canonical signed operation envelope.
|
2026-05-16 00:32:38 +02:00
|
|
|
Acceptance criteria:
|
|
|
|
|
- Keychain and auth ops use deterministic canonical encoding for signatures.
|
|
|
|
|
- JSON is not used as the signed representation.
|
|
|
|
|
- Tests verify equivalent operations hash/sign identically across runs.
|
|
|
|
|
|
2026-05-16 16:34:20 +02:00
|
|
|
- `[~]` SSH-admin-rooted keychain initialization.
|
|
|
|
|
Acceptance criteria:
|
|
|
|
|
- `[x]` `geth keychain init` records a local `KeychainInit`.
|
|
|
|
|
- `[x]` `geth keychain init --admin-key <path>` records an admin SSH public
|
|
|
|
|
key fingerprint.
|
|
|
|
|
- `[x]` `geth keychain status` reports the reduced local keychain view.
|
2026-05-19 16:04:20 +02:00
|
|
|
- `[x]` `geth keychain init --signing-key <path>` signs recorded keychain ops
|
|
|
|
|
with `ssh-keygen -Y sign`.
|
|
|
|
|
- `[x]` OpenSSH keychain signatures use the explicit
|
|
|
|
|
`geth.keychain.v1@geth.local` namespace.
|
|
|
|
|
- `[x]` Keychain OpenSSH signatures are stored in local SQLite.
|
2026-05-19 16:05:57 +02:00
|
|
|
- `[x]` `geth keychain status` reports the stored keychain signature count.
|
2026-05-19 18:58:07 +02:00
|
|
|
- `[x]` `geth keychain status` verifies stored keychain signatures against
|
|
|
|
|
canonical payloads with OpenSSH when public key material is available.
|
2026-05-19 16:04:20 +02:00
|
|
|
- `[x]` Missing `ssh-keygen` or unavailable hardware keys produce clear
|
2026-05-16 16:34:20 +02:00
|
|
|
errors during signing.
|
2026-05-19 16:04:20 +02:00
|
|
|
- `[x]` Tests cover signed keychain init with a generated local OpenSSH key
|
|
|
|
|
when `ssh-keygen` is available.
|
2026-05-19 18:58:07 +02:00
|
|
|
- `[x]` Tests cover local OpenSSH verification of stored keychain signatures.
|
2026-05-19 16:04:20 +02:00
|
|
|
- `[ ]` Future completion verifies signatures before accepting replicated
|
|
|
|
|
keychain ops.
|
2026-05-16 00:32:38 +02:00
|
|
|
|
2026-05-16 14:39:18 +02:00
|
|
|
- `[x]` Keychain operation reducer.
|
2026-05-16 00:32:38 +02:00
|
|
|
Acceptance criteria:
|
|
|
|
|
- Admin keys, users, devices, nodes, agents, and endpoint bindings reduce into
|
|
|
|
|
a current keychain view.
|
|
|
|
|
- Revoked keys/devices/nodes are excluded from active views.
|
|
|
|
|
- Tests cover add, rename, revoke, and endpoint rotation.
|
|
|
|
|
|
2026-05-16 14:41:23 +02:00
|
|
|
- `[x]` Resource auth operation reducer.
|
2026-05-16 00:32:38 +02:00
|
|
|
Acceptance criteria:
|
|
|
|
|
- Resource create, authority set, grants, revocations, and groups reduce into
|
|
|
|
|
a current permission view.
|
|
|
|
|
- Capabilities are strings, including scoped forms such as
|
|
|
|
|
`kv.write_prefix:apps/foo/`.
|
|
|
|
|
- Tests cover grant, revoke, group membership, and denied access.
|
|
|
|
|
|
2026-05-16 16:32:03 +02:00
|
|
|
- `[~]` `auth explain` real decision path.
|
|
|
|
|
Acceptance criteria:
|
|
|
|
|
- `[x]` `geth auth grant` and `geth auth revoke` persist local auth ops.
|
|
|
|
|
- `[x]` `geth auth explain <subject> <resource> <capability>` reports
|
|
|
|
|
allowed/denied from the local auth-op reducer when local ops exist.
|
|
|
|
|
- `[x]` Output includes the grant ID or missing grant that caused the result.
|
|
|
|
|
- `[x]` JSON output is stable enough for tests and scripts.
|
|
|
|
|
- `[ ]` Future completion requires signed-op validation before accepting
|
|
|
|
|
replicated auth ops.
|
2026-05-16 00:32:38 +02:00
|
|
|
|
2026-05-16 22:18:49 +02:00
|
|
|
- `[~]` Resource secrets and bearer invites.
|
|
|
|
|
Acceptance criteria:
|
|
|
|
|
- `[x]` `geth secret create <resource>` records resource secret epoch 1
|
|
|
|
|
metadata.
|
|
|
|
|
- `[x]` `geth secret rotate <resource>` records the next resource secret
|
|
|
|
|
epoch.
|
|
|
|
|
- `[x]` Secret epoch rotation is represented in durable metadata.
|
2026-05-17 02:58:58 +02:00
|
|
|
- `[x]` Bearer secrets grant only resource-scoped capabilities.
|
|
|
|
|
- `[x]` Bearer principals cannot mutate trust graph state by default.
|
|
|
|
|
- `[x]` Tests verify bearer access does not imply node identity.
|
2026-05-19 19:08:08 +02:00
|
|
|
- `[x]` `geth secret bearer challenge/prove/verify` exercises
|
|
|
|
|
resource-scoped bearer challenge-response proofs.
|
|
|
|
|
- `[x]` Tests verify valid bearer proofs and capability-scoped proof denial.
|
2026-05-19 19:16:30 +02:00
|
|
|
- `[x]` Remote module authorization paths accept optional bearer proofs for
|
|
|
|
|
the requested resource capability without granting node identity.
|
|
|
|
|
- `[x]` Tests verify remote CAS fetch succeeds through a bearer proof before
|
|
|
|
|
the caller has a node grant.
|
2026-05-20 13:10:34 +02:00
|
|
|
- `[x]` Bearer creation separates the persisted public bearer id from the
|
|
|
|
|
private bearer token returned to the caller.
|
|
|
|
|
- `[x]` Bearer list/revoke operate on public bearer ids while proof and remote
|
|
|
|
|
authorization use the private token.
|
|
|
|
|
- `[x]` Tests verify the public bearer id differs from the private token and
|
|
|
|
|
remote bearer auth uses the token.
|
2026-05-16 00:32:38 +02:00
|
|
|
|
|
|
|
|
- `[~]` SSH certificate and revocation lifecycle.
|
|
|
|
|
Acceptance criteria:
|
2026-05-17 18:29:47 +02:00
|
|
|
- `[x]` `geth ssh cert request/requests/approve/import/list` persist local
|
|
|
|
|
metadata.
|
|
|
|
|
- `[x]` Approval emits an explicit `ssh-keygen -s ...` command for
|
|
|
|
|
CA/YubiKey use.
|
2026-05-19 15:56:47 +02:00
|
|
|
- `[x]` `geth ssh cert approve --sign` can run `ssh-keygen`, import the
|
|
|
|
|
resulting OpenSSH certificate, and mark the request signed.
|
|
|
|
|
- `[x]` Tests cover signing with a generated local OpenSSH CA key when
|
|
|
|
|
`ssh-keygen` is available.
|
2026-05-17 18:29:47 +02:00
|
|
|
- `[x]` `geth ssh revocation add/list/export` persists and exports
|
|
|
|
|
revocations.
|
|
|
|
|
- `[x]` Revocations can be exported as JSONL and OpenSSH KRL specification
|
2026-05-18 11:51:12 +02:00
|
|
|
text or as a binary OpenSSH KRL through `ssh-keygen`.
|
2026-05-18 17:24:10 +02:00
|
|
|
- `[x]` Authorized peers can pull SSH cert-flow metadata with
|
|
|
|
|
`geth ssh cert sync <node-id>`.
|
|
|
|
|
- `[x]` Authorized peers can pull SSH revocation metadata with
|
|
|
|
|
`geth ssh revocation sync <node-id>`.
|
2026-05-18 18:29:45 +02:00
|
|
|
- `[x]` The daemon background live-sync loop refreshes known peers without a
|
|
|
|
|
manual command.
|
|
|
|
|
- `[x]` SSH metadata live-sync stores per-peer high-water cursors in
|
|
|
|
|
`module_state` and requests only records at or beyond the cursor.
|
2026-05-19 15:44:13 +02:00
|
|
|
- `[x]` Local SSH cert request/read/approve/import commands can enforce
|
|
|
|
|
`ssh_cert.request`, `ssh_cert.read`, `ssh_cert.approve`, and
|
|
|
|
|
`ssh_cert.import` for explicit non-owner `--subject` principals.
|
|
|
|
|
- `[x]` Local SSH revocation publish/read/import commands can enforce
|
|
|
|
|
`ssh_revocation.publish`, `ssh_revocation.read`, and
|
|
|
|
|
`ssh_revocation.import` for explicit non-owner `--subject` principals.
|
|
|
|
|
- `[x]` Tests cover denied and granted non-owner local SSH cert request and
|
|
|
|
|
revocation publish flows.
|
2026-05-20 13:13:44 +02:00
|
|
|
- `[x]` Sync import rejects conflicting certificate request, certificate, and
|
|
|
|
|
revocation records with ids that already exist locally.
|
|
|
|
|
- `[x]` Tests verify conflicting SSH cert request and revocation records do
|
|
|
|
|
not overwrite local metadata.
|
2026-05-19 15:44:13 +02:00
|
|
|
- `[ ]` Future completion requires all accepted SSH cert/revocation records
|
2026-05-20 13:13:44 +02:00
|
|
|
to carry signed provenance and reduce cleanly before replication.
|
2026-05-16 00:32:38 +02:00
|
|
|
|
|
|
|
|
## Phase 3: CAS, KV, And Pubsub
|
|
|
|
|
|
|
|
|
|
Goal: turn local CAS and stubs into Iroh-backed replicated modules while keeping
|
|
|
|
|
authorization and durable-state boundaries clear.
|
|
|
|
|
|
2026-05-18 17:18:25 +02:00
|
|
|
- `[~]` Iroh-blobs CAS integration.
|
|
|
|
|
Acceptance criteria:
|
|
|
|
|
- `[x]` `geth cas fetch <node-id> <hash>` can fetch a blob from an imported
|
|
|
|
|
peer over the daemon-owned Iroh control ALPN.
|
|
|
|
|
- `[x]` The serving peer validates the caller's signed peer card against the
|
|
|
|
|
observed Iroh EndpointID before considering authorization.
|
|
|
|
|
- `[x]` Remote CAS fetch requires `cas.fetch` on `resource:cas:local`.
|
|
|
|
|
- `[x]` The requester verifies returned bytes against the requested BLAKE3
|
|
|
|
|
CAS hash before storing them locally.
|
|
|
|
|
- `[x]` Local add/get/hash/has/list behavior remains backward compatible.
|
2026-05-19 15:37:02 +02:00
|
|
|
- `[x]` Successful fetches record the serving peer as a local provider for
|
|
|
|
|
the CAS hash.
|
|
|
|
|
- `[x]` `geth cas providers <hash>` lists locally known providers.
|
|
|
|
|
- `[x]` Tests cover local provider metadata storage.
|
2026-05-18 17:18:25 +02:00
|
|
|
- `[ ]` Replace the bootstrap control-ALPN transfer with `iroh-blobs`
|
|
|
|
|
provider/fetch behavior.
|
2026-05-16 00:32:38 +02:00
|
|
|
|
2026-05-16 21:10:25 +02:00
|
|
|
- `[x]` CAS pin and cache policy.
|
2026-05-16 16:36:35 +02:00
|
|
|
Acceptance criteria:
|
|
|
|
|
- `[x]` `geth cas pin <hash>` persists local pin metadata.
|
|
|
|
|
- `[x]` `geth cas unpin <hash>` removes local pin metadata.
|
|
|
|
|
- `[x]` `geth cas list` reports pinned versus unpinned blobs.
|
2026-05-16 21:10:25 +02:00
|
|
|
- `[x]` Pinned blobs are retained across cache cleanup.
|
|
|
|
|
- `[x]` Unpinned cached blobs can be evicted by policy.
|
|
|
|
|
- `[x]` Tests cover attempted eviction of pinned data.
|
2026-05-16 00:32:38 +02:00
|
|
|
|
|
|
|
|
- `[ ]` Encrypted private blobs.
|
|
|
|
|
Acceptance criteria:
|
|
|
|
|
- Private blob payloads are encrypted before network distribution.
|
|
|
|
|
- Access is gated by resource secret epoch material.
|
|
|
|
|
- Docs explicitly avoid claiming forward secrecy or PCS.
|
|
|
|
|
|
2026-05-16 21:52:35 +02:00
|
|
|
- `[~]` Iroh-docs KV integration.
|
2026-05-16 00:32:38 +02:00
|
|
|
Acceptance criteria:
|
2026-05-16 21:52:35 +02:00
|
|
|
- `[x]` `geth kv create/set/get` works against a named local KV resource.
|
|
|
|
|
- `[x]` KV metadata and entries are durable in the local SQLite store.
|
2026-05-17 18:26:30 +02:00
|
|
|
- `[x]` The auth evaluator allows `kv.write_prefix:<prefix>` grants to
|
|
|
|
|
satisfy matching `kv.write_key:<key>` requests.
|
|
|
|
|
- `[x]` Tests cover allowed and denied prefix-scoped KV write explanations.
|
2026-05-18 04:06:41 +02:00
|
|
|
- `[x]` `geth kv set --subject <principal>` enforces local capability
|
|
|
|
|
decisions for non-local test callers.
|
2026-05-18 18:36:03 +02:00
|
|
|
- `[x]` `geth kv sync <node-id> <name>` pulls authorized updates from an
|
|
|
|
|
imported peer over Iroh.
|
|
|
|
|
- `[x]` Remote KV sync requires `kv.read` on `resource:kv:<name>`.
|
|
|
|
|
- `[x]` Background live-sync refreshes local KV stores from known peers using
|
|
|
|
|
per-peer/per-KV high-water cursors.
|
2026-05-16 21:52:35 +02:00
|
|
|
- `[ ]` KV metadata is replicated through Iroh Documents.
|
2026-05-16 00:32:38 +02:00
|
|
|
|
2026-05-17 18:23:51 +02:00
|
|
|
- `[~]` Iroh-gossip pubsub integration.
|
|
|
|
|
Acceptance criteria:
|
|
|
|
|
- `[x]` `geth pubsub pub/sub` works against the local daemon.
|
|
|
|
|
- `[x]` Local pubsub messages are kept in a bounded daemon-lifetime ring
|
|
|
|
|
buffer.
|
|
|
|
|
- `[x]` Pubsub messages are documented and tested as lossy notifications, not
|
|
|
|
|
durable facts.
|
2026-05-18 18:41:04 +02:00
|
|
|
- `[x]` `geth pubsub pub <topic> <message> --node <node-id>` publishes to an
|
|
|
|
|
imported peer over Iroh.
|
|
|
|
|
- `[x]` Remote pubsub publish requires `pubsub.publish` on
|
|
|
|
|
`resource:pubsub:<topic>`.
|
2026-05-19 15:28:48 +02:00
|
|
|
- `[x]` `geth pubsub sub <topic> --node <node-id>` reads an authorized peer
|
|
|
|
|
snapshot over Iroh.
|
|
|
|
|
- `[x]` Remote pubsub subscribe requires `pubsub.subscribe` on
|
|
|
|
|
`resource:pubsub:<topic>`.
|
|
|
|
|
- `[x]` Tests cover denied and allowed remote pubsub subscribe.
|
2026-05-18 18:41:04 +02:00
|
|
|
- `[ ]` Replace bootstrap remote publish with iroh-gossip topics.
|
2026-05-17 18:23:51 +02:00
|
|
|
- `[ ]` Docs and tests keep durable state in CAS/KV/document/db instead.
|
2026-05-16 00:32:38 +02:00
|
|
|
|
|
|
|
|
## Phase 4: Pipes, SSH Proxy, And SSH Distribution
|
|
|
|
|
|
|
|
|
|
Goal: add authorized stream-oriented management workflows over Iroh.
|
|
|
|
|
|
2026-05-17 20:17:26 +02:00
|
|
|
- `[~]` Dumbpipe-style Iroh streams.
|
|
|
|
|
Acceptance criteria:
|
|
|
|
|
- `[x]` `geth pipe listen/connect` works against a local daemon-lifetime
|
|
|
|
|
registry.
|
|
|
|
|
- `[x]` Tests cover local listener registration, local connect matching, and
|
|
|
|
|
daemon restart behavior.
|
2026-05-18 18:45:10 +02:00
|
|
|
- `[x]` `geth pipe connect <name> --node <node-id>` can connect to an
|
|
|
|
|
imported peer over Iroh at the control-plane level.
|
|
|
|
|
- `[x]` Remote pipe connect requires `pipe.connect` on
|
|
|
|
|
`resource:pipe:<name>`.
|
2026-05-19 19:21:42 +02:00
|
|
|
- `[x]` `geth pipe listen <name> --node <node-id>` can register an authorized
|
|
|
|
|
daemon-lifetime listener on an imported peer.
|
|
|
|
|
- `[x]` Remote pipe listen requires `pipe.listen` on
|
|
|
|
|
`resource:pipe:<name>`.
|
|
|
|
|
- `[x]` Tests cover denied and allowed remote listener registration.
|
2026-05-18 18:45:10 +02:00
|
|
|
- `[ ]` Pipe connect carries bidirectional byte streams over Iroh.
|
2026-05-17 20:17:26 +02:00
|
|
|
- `[ ]` Streams close cleanly and propagate errors.
|
2026-05-16 00:32:38 +02:00
|
|
|
|
|
|
|
|
- `[ ]` TCP forwarding.
|
|
|
|
|
Acceptance criteria:
|
|
|
|
|
- A local TCP listener can forward over an authorized Iroh pipe.
|
|
|
|
|
- Tests cover basic request/response forwarding.
|
|
|
|
|
- Forwarding is resource-scoped and can be disabled by auth.
|
|
|
|
|
|
|
|
|
|
- `[ ]` Unix socket forwarding where supported.
|
|
|
|
|
Acceptance criteria:
|
|
|
|
|
- Unix socket forwarding is available on Unix platforms.
|
|
|
|
|
- Unsupported platforms return clear errors.
|
|
|
|
|
- Tests skip or use cfg guards where sockets are unavailable.
|
|
|
|
|
|
2026-05-19 15:51:11 +02:00
|
|
|
- `[~]` SSH proxy over Iroh.
|
|
|
|
|
Acceptance criteria:
|
|
|
|
|
- `[x]` `geth ssh proxy <node>` contacts an imported peer over the protected
|
|
|
|
|
Iroh control ALPN.
|
|
|
|
|
- `[x]` Remote daemon checks `ssh_proxy.connect` on
|
|
|
|
|
`resource:ssh-proxy:local` before returning proxy connection metadata.
|
|
|
|
|
- `[x]` Tests cover denied and granted SSH proxy control-plane attempts.
|
|
|
|
|
- `[x]` Knowing an EndpointID alone cannot reach sshd.
|
|
|
|
|
- `[ ]` Future completion opens a dedicated authorized Iroh byte stream.
|
|
|
|
|
- `[ ]` Remote daemon connects that stream to local sshd or a restricted
|
|
|
|
|
built-in geth admin shell only after authorization.
|
2026-05-16 00:32:38 +02:00
|
|
|
|
2026-05-18 17:24:10 +02:00
|
|
|
- `[~]` SSH certificate and revocation distribution.
|
2026-05-16 00:32:38 +02:00
|
|
|
Acceptance criteria:
|
2026-05-18 17:24:10 +02:00
|
|
|
- `[x]` Cert request and imported certificate records can be pulled from an
|
|
|
|
|
imported peer over Iroh.
|
|
|
|
|
- `[x]` Revocation records can be pulled from an imported peer over Iroh.
|
|
|
|
|
- `[x]` Remote sync validates the caller's signed peer card against the
|
|
|
|
|
observed Iroh EndpointID before considering authorization.
|
|
|
|
|
- `[x]` Cert metadata sync requires `ssh_cert.sync` on `resource:ssh:certs`.
|
|
|
|
|
- `[x]` Revocation metadata sync requires `ssh_revocation.sync` on
|
|
|
|
|
`resource:ssh:revocations`.
|
|
|
|
|
- `[x]` Consumers can list current certs/revocations from local state while
|
|
|
|
|
offline after sync.
|
2026-05-18 18:29:45 +02:00
|
|
|
- `[x]` Background live-sync uses the same protected Iroh path and cursor
|
|
|
|
|
state as manual sync.
|
2026-05-18 17:24:10 +02:00
|
|
|
- `[ ]` Replace pull-only metadata sync with a resource log or CRDT model.
|
2026-05-20 13:13:44 +02:00
|
|
|
- `[x]` Conflicting records with already-known ids are rejected during import
|
|
|
|
|
rather than replacing local metadata.
|
|
|
|
|
- `[ ]` Unsigned records are rejected or quarantined once signed provenance is
|
|
|
|
|
part of the metadata format.
|
2026-05-16 00:32:38 +02:00
|
|
|
|
2026-05-18 11:58:39 +02:00
|
|
|
- `[x]` OpenSSH KRL import/export.
|
2026-05-16 00:32:38 +02:00
|
|
|
Acceptance criteria:
|
2026-05-17 18:29:47 +02:00
|
|
|
- `[x]` Revocation records can produce an OpenSSH KRL specification file.
|
|
|
|
|
- `[x]` Tests cover serial, key ID, and public key revocation spec lines.
|
2026-05-18 11:51:12 +02:00
|
|
|
- `[x]` Revocation records can produce an OpenSSH binary KRL file.
|
|
|
|
|
- `[x]` Tests cover binary KRL export for public-key revocations when
|
|
|
|
|
`ssh-keygen` is available.
|
2026-05-18 11:56:42 +02:00
|
|
|
- `[x]` JSONL exports and OpenSSH KRL specification source files can be
|
|
|
|
|
imported into revocation metadata.
|
|
|
|
|
- `[x]` Binary OpenSSH KRL import returns a clear unsupported message because
|
|
|
|
|
KRL files are not enumerable through OpenSSH tooling.
|
|
|
|
|
- `[x]` Tests cover JSONL and KRL-spec import.
|
2026-05-18 11:58:39 +02:00
|
|
|
- `[x]` Tests cover certificate revocations.
|
2026-05-15 15:08:20 +02:00
|
|
|
|
|
|
|
|
## Phase 5: DB And Documents
|
|
|
|
|
|
2026-05-16 00:32:38 +02:00
|
|
|
Goal: add durable synchronized data structures for SQLite/cr-sqlite and
|
|
|
|
|
Automerge documents.
|
|
|
|
|
|
2026-05-16 21:13:33 +02:00
|
|
|
- `[x]` DB resource registration.
|
2026-05-16 00:32:38 +02:00
|
|
|
Acceptance criteria:
|
|
|
|
|
- `geth db add <name> <path>` records DB metadata.
|
|
|
|
|
- `geth db status <name>` reports local path, schema metadata, and sync state.
|
|
|
|
|
- Nonexistent paths and invalid names produce clear errors.
|
|
|
|
|
|
2026-05-17 20:32:36 +02:00
|
|
|
- `[x]` cr-sqlite change extraction.
|
2026-05-16 00:32:38 +02:00
|
|
|
Acceptance criteria:
|
2026-05-17 20:01:36 +02:00
|
|
|
- `[x]` DB status detects whether `crsql_changes` exists.
|
|
|
|
|
- `[x]` DB status reports `crsql_changes` row count, columns, and max
|
|
|
|
|
`db_version` when available.
|
|
|
|
|
- `[x]` Tests use a temp SQLite DB and deterministic fixture changes.
|
2026-05-17 20:22:50 +02:00
|
|
|
- `[x]` The module can extract typed change batches from `crsql_changes`.
|
|
|
|
|
- `[x]` Schema hash/version metadata is included in extracted change batches.
|
2026-05-17 20:32:36 +02:00
|
|
|
- `[x]` Extracted batches are exposed through `geth db changes`.
|
2026-05-16 00:32:38 +02:00
|
|
|
|
2026-05-18 22:11:57 +02:00
|
|
|
- `[~]` DB sync over Iroh.
|
2026-05-16 00:32:38 +02:00
|
|
|
Acceptance criteria:
|
2026-05-18 22:11:57 +02:00
|
|
|
- `[x]` `geth db sync <node-id> <name>` exists and talks to the daemon.
|
|
|
|
|
- `[x]` Remote DB sync uses the protected Iroh control ALPN.
|
|
|
|
|
- `[x]` The serving peer validates the caller's signed peer card against the
|
|
|
|
|
observed Iroh EndpointID before considering authorization.
|
|
|
|
|
- `[x]` Remote DB sync requires `db.sync` on the remote
|
|
|
|
|
`resource:db:<name>`.
|
|
|
|
|
- `[x]` The response carries typed `crsql_changes` batches plus schema
|
|
|
|
|
metadata.
|
|
|
|
|
- `[x]` The requester detects schema mismatch before advancing the sync
|
|
|
|
|
cursor.
|
|
|
|
|
- `[x]` Background live-sync runs DB sync for local DB resources and known
|
|
|
|
|
peers.
|
|
|
|
|
- `[x]` Per-peer/per-DB high-water cursors are stored in `module_state`.
|
2026-05-19 19:02:39 +02:00
|
|
|
- `[x]` Extracted batches are exposed through `geth db changes`.
|
|
|
|
|
- `[x]` Compatible remote batches are inserted into the local
|
|
|
|
|
`crsql_changes` table or view before advancing the cursor.
|
|
|
|
|
- `[x]` Tests cover typed batch application into deterministic fixture
|
|
|
|
|
`crsql_changes` tables.
|
2026-05-18 22:11:57 +02:00
|
|
|
- `[ ]` Add an integration test with a real cr-sqlite-enabled SQLite DB that
|
|
|
|
|
proves two local test nodes exchange and apply changes.
|
|
|
|
|
- `[ ]` Optional CAS-backed snapshots or batches are documented if used.
|
2026-05-16 00:32:38 +02:00
|
|
|
|
2026-05-16 22:15:18 +02:00
|
|
|
- `[~]` Automerge document resource.
|
2026-05-16 00:32:38 +02:00
|
|
|
Acceptance criteria:
|
2026-05-16 22:15:18 +02:00
|
|
|
- `[x]` `geth document create/status` works for local documents.
|
|
|
|
|
- `[x]` Document metadata and empty JSON state are stored durably.
|
2026-05-17 19:59:03 +02:00
|
|
|
- `[x]` `geth document set/get` stores and returns validated local JSON
|
|
|
|
|
state.
|
|
|
|
|
- `[x]` Tests cover create, update, save, and reload of local JSON document
|
|
|
|
|
state.
|
2026-05-18 18:49:34 +02:00
|
|
|
- `[x]` `geth document sync <node-id> <name>` pulls authorized JSON state
|
|
|
|
|
from an imported peer over Iroh.
|
|
|
|
|
- `[x]` Background live-sync refreshes local JSON documents from known peers
|
|
|
|
|
using per-peer/per-document cursors.
|
2026-05-16 22:15:18 +02:00
|
|
|
- `[ ]` Automerge document state is stored durably.
|
2026-05-17 19:59:03 +02:00
|
|
|
- `[ ]` Tests cover Automerge create, update, save, and reload.
|
2026-05-16 00:32:38 +02:00
|
|
|
|
|
|
|
|
- `[ ]` Automerge sync over Iroh.
|
|
|
|
|
Acceptance criteria:
|
2026-05-18 18:49:34 +02:00
|
|
|
- `[x]` Bootstrap JSON last-writer-wins sync works across two local test
|
|
|
|
|
nodes over Iroh.
|
2026-05-16 00:32:38 +02:00
|
|
|
- Resource authorization gates read/write sync.
|
|
|
|
|
- Conflicts converge according to Automerge semantics.
|
2026-05-15 15:08:20 +02:00
|
|
|
|
|
|
|
|
## Phase 6: File Sync And Advanced Local-First Auth
|
|
|
|
|
|
2026-05-16 00:32:38 +02:00
|
|
|
Goal: build higher-level local-first collaboration on CAS trees, resource auth,
|
|
|
|
|
and future group key evolution.
|
|
|
|
|
|
2026-05-17 21:20:24 +02:00
|
|
|
- `[x]` CAS tree objects.
|
2026-05-16 00:32:38 +02:00
|
|
|
Acceptance criteria:
|
2026-05-17 21:20:24 +02:00
|
|
|
- `[x]` Tree objects describe directories, files, executable bits, and blob
|
|
|
|
|
hashes.
|
|
|
|
|
- `[x]` Tree objects are content-addressed and stored in CAS.
|
|
|
|
|
- `[x]` Tests cover deterministic tree hashing.
|
2026-05-16 00:32:38 +02:00
|
|
|
|
2026-05-18 03:50:09 +02:00
|
|
|
- `[~]` File roots.
|
|
|
|
|
Acceptance criteria:
|
|
|
|
|
- `[x]` A file root maps a local path to a CAS tree resource.
|
|
|
|
|
- `[x]` `geth cas root add/list/scan` persists local root metadata and latest
|
|
|
|
|
tree state.
|
|
|
|
|
- `[x]` Scan detects create/update/delete/rename changes.
|
|
|
|
|
- `[x]` Scan output documents that geth never overwrites file roots without a
|
|
|
|
|
recorded future sync decision.
|
|
|
|
|
- `[ ]` File roots can be synced across nodes.
|
2026-05-16 00:32:38 +02:00
|
|
|
|
2026-05-18 03:57:26 +02:00
|
|
|
- `[~]` Conflict handling.
|
|
|
|
|
Acceptance criteria:
|
|
|
|
|
- `[x]` Conflicts are represented as durable metadata.
|
|
|
|
|
- `[x]` CLI/control can record, list, and choose a resolution for local
|
|
|
|
|
conflict metadata.
|
|
|
|
|
- `[x]` Tests cover local concurrent edit conflict record/list/resolve.
|
|
|
|
|
- `[ ]` Future sync records conflicts automatically from base/local/remote
|
|
|
|
|
tree comparisons.
|
|
|
|
|
- `[ ]` Tests cover automatic concurrent edit, delete/edit, and rename
|
|
|
|
|
conflict detection.
|
2026-05-16 00:32:38 +02:00
|
|
|
|
|
|
|
|
- `[ ]` Keyhive-like convergent capabilities.
|
|
|
|
|
Acceptance criteria:
|
|
|
|
|
- Capability state is represented as local-first replicated auth data.
|
|
|
|
|
- Convergent grant/revoke semantics are documented and tested.
|
|
|
|
|
- Migration from current auth ops is documented.
|
|
|
|
|
|
|
|
|
|
- `[ ]` BeeKEM/CGKA-inspired group key evolution.
|
|
|
|
|
Acceptance criteria:
|
|
|
|
|
- Design doc states exact security properties and non-properties.
|
|
|
|
|
- Prototype is behind explicit experimental module boundaries.
|
|
|
|
|
- Current resource secret epoch model remains compatible or has a migration.
|