Skip to content
Merged
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
23 changes: 18 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
[![](https://img.shields.io/crates/v/darkbio-ark.svg)](https://crates.io/crates/darkbio-ark)
[![](https://github.com/dark-bio/cli/workflows/tests/badge.svg)](https://github.com/dark-bio/cli/actions/workflows/ci.yml)

`ark` is the command line interface to [Ark](https://dark.bio) enclaves. An Ark holds one person's data. It is plugged into your computer over USB, or emulated on it. Its owner approves access from their phone in Ark Companion, available on the [App Store](https://apps.apple.com/app/id6751324700) and [Google Play](https://play.google.com/store/apps/details?id=bio.dark.companion). This tool talks to the Ark, the Dark Bio cloud and the phone on the owner's behalf, but it can never approve anything itself.
`ark` is the command line interface to [Ark](https://dark.bio) enclaves. An Ark holds one person's data. It is plugged into your computer over USB, or emulated on it by [Ark Emulator](https://github.com/dark-bio/emulator). Its owner approves access from their phone in Ark Companion, available on the [App Store](https://apps.apple.com/app/id6751324700) and [Google Play](https://play.google.com/store/apps/details?id=bio.dark.companion). This tool talks to the Ark, the Dark Bio cloud and the phone on the owner's behalf, but it can never approve anything itself.

What this tool does:

Expand Down Expand Up @@ -50,6 +50,8 @@ sudo udevadm control --reload-rules

## First session

Plug in your Ark, or [start an emulated one](#emulated-arks), and run:

```sh
ark devices # find the Ark
ark status # trust, firmware, paired, unlocked
Expand All @@ -61,6 +63,17 @@ ark app run my.wasm > report.md # approve on the phone; report on stdout

Pairing happens once. Unlocking lasts until the Ark loses power. Check `ark status` before a data command or app run; these need an unlocked Ark. If it reports locked, `--unlock` lets the command unlock first, with phone approval. Nothing bypasses the phone. Deleting the pairing in Ark Companion discards the unlock key, and the reset button on the Ark erases all data.

## Emulated Arks

[Ark Emulator](https://github.com/dark-bio/emulator) boots the real Ark firmware on your computer, for development and demos, and `ark` talks to it as it does to hardware. It keeps its data in a plain file, so keep real data on hardware. A fresh emulator is enrolled once, in a browser at [Ark Hub](https://hub.dark.bio), before it pairs:

```sh
ark-emulator start # boot one; prints its locator once it is ready
ark enroll # prints where to enroll it at Ark Hub
```

After that, the first session above applies. The enrollment lasts 30 days; then `ark-emulator stop`, `ark-emulator wipe` and `ark-emulator start` give a fresh device to enroll again. `ark-emulator --help` covers the rest.

## Datasets

The Ark keeps data in named slots. `ark data list` shows the inventory, `ark data show <slot>` adds a slot's description and upload format, and `ark data paths` maps the data apps can read, with `--json` giving each path's description, exact format and examples. These commands do not transfer datasets.
Expand All @@ -81,13 +94,13 @@ An app is one WebAssembly file that reads the paths it declares and prints a rep

`ark firmware list` shows the installed build and published candidates; `ark firmware update` installs the newest candidate and waits for the Ark to return running it. Who approves depends on the Ark's state: nobody while unpaired, the device button while paired and locked, the phone while unlocked. The installation itself is confirmed on this computer, with `--yes` when there is no one to ask.

This release needs Ark firmware 0.11.5 or later; `ark --version` prints the minimum. An older Ark is still served by `status`, `doctor`, the `firmware` commands and `enroll --cwt`, enough to bring it up to date.
This release needs Ark firmware 0.11.5 or later; `ark --version` prints the minimum. An older Ark is still served by `status`, `doctor`, the `firmware` commands and `enroll --cwt`, enough to bring it up to date. An emulator runs the firmware bundled with Ark Emulator, so a newer emulator release is its update.

## Devices and diagnostics

One Ark is picked automatically. With several, select one with `-d` by locator, serial, name or emulator image, or with the bare words `hardware` and `emulator`. Run commands one at a time, including reads. `device-busy` means another `ark` command or an Ark Hub browser tab holds the USB session. Emulators come from the [Ark Emulator](https://github.com/dark-bio/emulator) desktop app, which boots the real firmware on your computer for development and demos.
One Ark is picked automatically. With several, select one with `-d` by locator, serial, name or emulator image, or with the bare words `hardware` and `emulator`. Run commands one at a time, including reads. `device-busy` means another `ark` command or an Ark Hub browser tab holds the USB session.

`ark status` shows the Ark's attested identity and works offline; `ark genuine` checks that identity against Dark Bio's device registry; `ark enroll` gives a fresh emulator its identity. When something is off, `ark doctor` checks your computer, the Ark and the cloud, and suggests fixes without applying them. `-v` adds step narration; `--log debug` or `--log trace` enables diagnostic logs.
`ark status` shows the Ark's attested identity and works offline, and `ark genuine` checks that identity against Dark Bio's device registry. When something is off, `ark doctor` checks your computer, the Ark and the cloud, and suggests fixes without applying them. `-v` adds step narration; `--log debug` or `--log trace` enables diagnostic logs.

## Output and automation

Expand All @@ -104,7 +117,7 @@ Scripts and AI agents should read `ark help agents` first. Nothing prompts witho
| `agents` | Driving the tool from a script or an AI agent |
| `states` | Pairing, locking, trust and firmware compatibility |
| `output` | Reading output, JSON, streams and error codes |
| `devices` | Locators, selection and cloud environments |
| `devices` | Locators, selection, emulators and cloud environments |
| `datasets` | Slots, uploads, reference downloads and the cache |
| `apps` | The manifest, the sandbox and its limits |

Expand Down
2 changes: 1 addition & 1 deletion src/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ pub(crate) enum Command {
Pair,
/// Unlock the Ark, approved on your phone
Unlock,
/// Give the Ark its attested identity
/// Enroll the Ark at Ark Hub, or install an attestation
Enroll(Enroll),
/// Read and change the datasets on the Ark
#[command(subcommand)]
Expand Down
22 changes: 15 additions & 7 deletions src/device.rs
Original file line number Diff line number Diff line change
Expand Up @@ -224,18 +224,19 @@ pub(crate) fn genuine(context: &Context) -> Result<(), Error> {
if !registration.active() {
return Err(
Error::new(4, "registry-inactive", "the Ark registration is inactive").hint(
if registration.disabled {
if registration.disabled || connection.device.kind() != DeviceKind::Emulator {
"contact Dark Bio"
} else {
"enroll the emulator again to obtain a fresh identity"
"run `ark-emulator stop`, `ark-emulator wipe` and `ark-emulator start` \
for a fresh device, then `ark enroll`"
},
),
);
}
Ok(())
}

/// Installs a supplied attestation or directs online enrollment to the Ark Hub.
/// Installs a supplied attestation or directs online enrollment to Ark Hub.
/// After installation, reconnects without recovery pinning to verify the new identity;
/// a reconnect failure still reports that enrollment was acknowledged.
pub(crate) fn enroll(context: &Context, args: args::Enroll) -> Result<(), Error> {
Expand All @@ -256,12 +257,19 @@ pub(crate) fn enroll(context: &Context, args: args::Enroll) -> Result<(), Error>
};
let Some(certificate) = certificate else {
if matches!(connection.identity, Identity::Attested { .. }) {
return Err(Error::new(
let mut error = Error::new(
5,
"already-enrolled",
"the Ark already has an attested identity",
)
.hint("a fresh emulator identity requires a fresh emulator disk"));
);
if connection.device.kind() == DeviceKind::Emulator {
error.hints.push(
"a new identity needs a fresh device, from `ark-emulator stop`, \
`ark-emulator wipe` and `ark-emulator start`"
.into(),
);
}
return Err(error);
}
let env = connection.env.ok_or_else(|| {
Error::new(4, "environment-unknown", "cloud environment unknown")
Expand All @@ -277,7 +285,7 @@ pub(crate) fn enroll(context: &Context, args: args::Enroll) -> Result<(), Error>
return Err(Error::new(
1,
"enrollment-required",
"online enrollment is performed at the Ark Hub",
"online enrollment happens at Ark Hub",
));
};
connection.client.call(
Expand Down
4 changes: 3 additions & 1 deletion src/help.rs
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,9 @@ fn decorate(command: &mut clap::Command, parent: &str, theme: &Theme) {
"status" => {
"0 done; 1 local; 2 usage; 3 device; 5 Ark (including outdated firmware, not pairing or lock state); 7 timeout"
}
"enroll" => "0 done; 1 local; 2 usage; 3 device; 5 Ark; 7 timeout",
"enroll" => {
"0 installed with --cwt; 1 local or enrollment-required; 2 usage; 3 device; 5 Ark; 7 timeout"
}
"genuine" | "app cancel" | "firmware list" | "doctor" => {
"0 done; 1 local; 2 usage; 3 device; 4 cloud; 5 Ark; 7 timeout"
}
Expand Down
24 changes: 18 additions & 6 deletions src/help/agents.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# Driving ark from a script or an AI agent

An Ark holds one person's health data. It is plugged into this computer over
USB, or emulated on it. The owner approves access to their data on their phone,
in Ark Companion. You cannot approve for them.
USB, or emulated on it by Ark Emulator. The owner approves access to their data
on their phone, in Ark Companion. You cannot approve for them.

## Running

Expand Down Expand Up @@ -58,7 +58,9 @@ timeout, 8 app failure, 130 Ctrl-C, 143 SIGTERM.
## Checking state

Start with `ark devices` and `ark status`. Status works offline and shows
paired and unlocked state. If unpaired, `ark pair` needs the owner's phone.
trust, paired and unlocked state. A fresh emulator reports self-signed trust
and is enrolled before pairing; `ark enroll` prints the Ark Hub address where
that happens, in a browser. If unpaired, `ark pair` needs the owner's phone.
If locked, `ark unlock` needs phone approval and lasts until power is cut.
Data commands and app run need an unlocked Ark. Pass --unlock only when status
reports locked and unlocking is authorized. A dry run never unlocks; unlock
Expand All @@ -77,16 +79,26 @@ Read `ark help datasets` for build, version, dependency and cache meanings, and
Unpaired Arks can receive firmware updates without phone or button approval.
The CLI still requires installation confirmation; use --yes noninteractively.

## Emulated Arks

Without hardware, Ark Emulator from https://github.com/dark-bio/emulator boots
the real firmware on this computer, for development and demos. Read
`ark-emulator help agents` before starting, stopping or wiping one.
`ark-emulator start` returns once the emulator accepts clients and prints its
locator, which --device takes. From there ark drives it like hardware, and the
owner approves on their phone. `ark help devices` covers how long an
emulator's identity lasts and where its firmware comes from.

## Writing an app

An app is one WebAssembly file using WASI preview 1. Run with no arguments it
prints a TOML manifest naming itself and the data paths it wants; run with a
data directory it reads those paths and prints a report. `ark data paths --json`
describes every path an app can read, with each file's exact contents and
examples, and `ark help apps` covers the manifest, grants and sandbox. Apps are
checked and executed on the Ark; the CLI has no separate WASM runtime.
checked and executed on the Ark, hardware or emulated; the CLI has no separate
WASM runtime.

Worked apps in Rust, Go, C and Python live at
https://github.com/dark-bio/examples, with fixtures that run them on this
computer. Without hardware, the desktop emulator at
https://github.com/dark-bio/emulator boots the real firmware for development.
computer.
5 changes: 3 additions & 2 deletions src/help/apps.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@
An app is one WASI preview 1 WebAssembly file. With no arguments it prints a
TOML manifest; when the Ark runs it with a data directory it reads its declared
paths and prints a report. The Ark owns manifest validation, sandboxing and
permission enforcement. Use a hardware Ark or the desktop emulator from
https://github.com/dark-bio/emulator; the CLI has no local execution sandbox.
permission enforcement, and the CLI has no local execution sandbox. Apps run on
a hardware Ark or on one emulated by Ark Emulator, from
https://github.com/dark-bio/emulator.

Worked apps in Rust, Go, C and Python, with fixtures that run them on this
computer, are at https://github.com/dark-bio/examples.
Expand Down
45 changes: 32 additions & 13 deletions src/help/devices.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,6 @@ registry is normal when no emulator is running. A registry whose listing
version this tool does not know is a failed source, reported as a warning. A
failed discovery source does not hide devices found through another source.

Emulators come from the desktop app at https://github.com/dark-bio/emulator,
which boots the real firmware on this computer. It exists for development and
demos and keeps its data in a plain file, so keep real data on hardware.

The reading view shows locator, name, serial, kind, environment and ready.
JSON devices entries contain locator, kind, name, serial, image, environment
and ready. environment and ready are launcher metadata for
Expand All @@ -27,20 +23,43 @@ USB addresses may change across reboot. Firmware verification searches by the
reported serial, then authenticates the same identity key and checks the build.
A discovery serial alone never proves which Ark returned.

## Emulators

Ark Emulator, from https://github.com/dark-bio/emulator, boots the real
firmware on this computer for development and demos. It keeps its data in a
plain file, so keep real data on hardware. `ark-emulator start` boots one and
prints its locator once the firmware accepts clients, and `ark devices` lists
it from then on. `ark-emulator help agents` covers starting, stopping and
wiping emulators from a script.

`ark` talks to an emulator exactly as to hardware, except for its identity and
its firmware. A fresh emulator has a self-signed identity, which `ark status`
reports, and it is enrolled before it pairs. `ark enroll` prints the Ark Hub
address where it gets an attested identity, in a browser. That identity lasts
30 days. Then the cloud refuses the device and `ark genuine` reports it
expired. `ark-emulator stop`, `ark-emulator wipe` and `ark-emulator start`
give a fresh device to enroll again.

The firmware is the build bundled with the emulator app, so
`ark firmware update` does not apply. A newer Ark Emulator release carries
newer firmware, and `ark-emulator --version` names the bundled build.

## Cloud environments

The environment order is --env, trusted attestation, emulator launcher report,
then release. The CLI trusts release, staging and develop roots. An explicit
--env that contradicts the attestation warns; it changes routing, not trust.
Develop and staging routes produce one note per command, hidden by --quiet.
The offline attested label identifies the signer. Use genuine to check the
Ark's current cloud registration.
then release. An emulator image is bound to one environment when it first
boots, and `ark-emulator start --env` chooses it for a new image. The CLI
trusts release, staging and develop roots. An explicit --env that contradicts
the attestation warns; it changes routing, not trust. Develop and staging
routes produce one note per command, hidden by --quiet. The offline attested
label identifies the signer. Use genuine to check the Ark's current cloud
registration.

Develop and staging cloud and package hosts may require Cloudflare Access login.
Install cloudflared when prompted. Interactive commands open a browser when login
is needed and reuse the session afterward. Without a terminal, under --no-input,
or with --json, login-required includes the manual login command. API and
package hosts have separate credentials. Status remains usable offline.
Install cloudflared when prompted. Interactive commands open a browser when
login is needed and reuse the session afterward. Without a terminal, under
--no-input, or with --json, login-required includes the manual login command.
API and package hosts have separate credentials. Status remains usable offline.

Firmware checks cloud access before preparation. If login expires after the Ark
has prepared the update, the CLI signs in and asks you to rerun the command;
Expand Down
6 changes: 4 additions & 2 deletions src/help/output.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,8 @@ Exit 1, local input or confirmation:
published for the environment
- `confirmation-required`: firmware installation needs confirmation; use
--yes when running noninteractively
- `enrollment-required`: online enrollment happens at the Ark Hub
- `enrollment-required`: enrollment happens in a browser at Ark Hub, at the
address the hint gives
- `io`: a local read or write failed

Exit 2, `usage`: invalid arguments or an unknown help topic. A zero, negative or
Expand All @@ -105,7 +106,8 @@ Exit 4, cloud:
has the cloudflared command
- `proof-rejected`: the cloud refused the device proof; run `ark doctor`
- `pairing-failed`: the rendezvous or the companion side failed
- `registry-inactive`: the registration is disabled, expired or superseded
- `registry-inactive`: the registration is disabled, expired or superseded;
contact Dark Bio, or wipe an expired or superseded emulator and enroll again

Exit 5, Ark state or refusal:
- `not-paired`: run `ark pair`
Expand Down
5 changes: 3 additions & 2 deletions src/help/states.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
# Ark states

Discovery reports labels; the handshake establishes identity. Trust is attested,
self-signed, or pinned by --pubkey on status and enroll. A cloud environment
controls routing and never changes the handshake's trust result.
self-signed, or pinned by --pubkey on status and enroll. A fresh emulator is
self-signed until it is enrolled, as `ark help devices` describes. A cloud
environment controls routing and never changes the handshake's trust result.

Status works offline, including while unpaired or locked. It reads pairing,
lock and cloud sync state without synchronizing. Commands that need cloud
Expand Down
3 changes: 3 additions & 0 deletions tests/palette.rs
Original file line number Diff line number Diff line change
Expand Up @@ -344,10 +344,13 @@ fn help_matches_the_supported_palette() {
/// of the loop a reader arrives in, and the root page lists the shared options.
#[test]
fn manual_carries_the_cross_references() {
// Wrapped, so a phrase is looked for across line breaks.
let manual = String::from_utf8(ark(&["help", "--all"]).stdout).unwrap();
let manual = manual.split_whitespace().collect::<Vec<_>>().join(" ");
for link in [
"https://github.com/dark-bio/examples",
"https://github.com/dark-bio/emulator",
"ark-emulator help agents",
] {
assert!(manual.contains(link), "{link}");
}
Expand Down
Loading