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
8 changes: 8 additions & 0 deletions .github/workflows/check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,19 @@ jobs:
run: cargo install cargo-deny --version 0.20.2 --locked
- name: Install frontend dependencies
run: npm ci --ignore-scripts
# CI only, so a new advisory doesn't block local checks. Production packages only.
- name: Audit frontend dependencies
run: npm audit --omit=dev --audit-level=high
# The helper exists only on Mac, so check.sh runs the companion's tests only there.
- name: Install companion dependencies
if: runner.os == 'macOS'
working-directory: companion
run: npm ci --ignore-scripts
# These packages ship inside the helper, the one process that holds the Agent Key.
- name: Audit companion dependencies
if: runner.os == 'macOS'
working-directory: companion
run: npm audit --omit=dev --audit-level=high
# Automated checks do not establish physical native UI, capture or biometric acceptance.
- name: Run unified checks
run: bash scripts/check.sh
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,12 @@ node_modules/
# local vault data must never be committed
/src-tauri/target

# key files, at any depth (an example file stays tracked)
.env
.env.*
*.env
!.env.example

# local AI-tooling databases (Ruflo), not project files
ruvector.db
ruvector.db.*
Expand Down
9 changes: 6 additions & 3 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ A personal app for storing secrets, encrypted and saved only on this computer.
## Rules

- Never put real secrets (passwords, keys, seed phrases) in code, tests, docs, `.scratch/` issues, or commits. Use obviously fake placeholders.
- Never open, list, copy or decrypt a real Vault, Backup or Safety Copy, never run the Emergency Reader on one, and never ask for or accept its Master Password, Recovery Key or Hidden Fields, even if the owner asks (ADR-0007). Say no, say why, and offer a fictional Vault.
- Never open, list, copy, decrypt, delete, move, overwrite or clean a real Vault, Backup or Safety Copy, or the app's data folders (`com.encryptednote.app*`), never run the Emergency Reader on one, and never ask for or accept its Master Password, Recovery Key or Hidden Fields, even if the owner asks (ADR-0007). Say no, say why, and offer a fictional Vault.
- Ask the owner before any `git clean -x` or `-X`: it deletes ignored files, such as `*.enote` Backups.
- Launch a release build only with a test identifier: `scripts/package-companion.sh --app --identifier com.encryptednote.companiontest`. With the default identifier it opens the owner's real Vault folder, so `--app` refuses it; `--owner-build` is for the owner only.
- Never add network access to the Vault core or WebView: no HTTP clients, updaters, telemetry, crash reporters or analytics (ADR-0001). The only approved exception is the optional Agent Companion helper (ADR-0009): a separately sandboxed XPC service that makes only the companion's fixed OpenAI request. Never widen it, give it Vault access, or add networking anywhere else. Its source is in `companion/`: never import that folder from `src/`, `src-tauri/src/` or `crates/` (ADR-0010).
- Keys and decrypted Notes live only in the Rust core; the WebView receives one Hidden Field at a time (ADR-0003). The Agent Companion helper may hold one separately created Agent Key, never a Vault value (ADR-0009).
- Never pass Vault content, Note metadata, Note keys, Wallet Kinds, the Master Password or the Recovery Key to the Agent Companion, and never forward helper output, provider errors, keys or tokens to the WebView (ADR-0009).
Expand All @@ -14,14 +16,15 @@ A personal app for storing secrets, encrypted and saved only on this computer.
## Verify

- In a fresh clone or worktree, first: `npm ci --ignore-scripts` (never `npm install`, ADR-0003), and on Mac also `npm --prefix companion ci --ignore-scripts`
- Before a pull request: `./scripts/check.sh`
- Before a pull request: `./scripts/check.sh` (several minutes: run it in the background). It also runs the secret scan, `node scripts/scan-secrets.mjs`, and fails if an entitlement file differs from `scripts/pinned-hashes.txt`.
- One crate: `cargo test --locked -p <store|notes|session|policy|guard|vault-format|enote-reader>` (slow: run it in the background)
- App crate: `cargo test --locked -p encrypted-note-app --tests` (slow, can take many minutes: run it in the background)
- WebView: `npm run typecheck`
- Network rule, and no Vault imports of `companion/`: `node scripts/check-network-source.mjs`
- Companion (Mac): `npm --prefix companion test`. It runs one file at a time because the tests share port 8789, so don't run it alongside `scripts/verify-companion.sh`.
- App with a fictional Vault: `ENOTE_DEV_DATA_DIR="$(mktemp -d)" npm run tauri dev` (add `ENOTE_DEV_ALLOW_CAPTURE=1` for screenshots)
- Screens without Rust: `npm run dev` (port 1420 must be free), then open `http://127.0.0.1:1420/fixture.html?phase=unlocked&companion=running`. Replies are fictional; this proves nothing about native panels, locks or the helper.
- Owner scripts: `scripts/build-reader.sh` and `scripts/companion-setup.sh`. Run the setup script only with `--dry-run` and an account name that doesn't exist.
- Screens without Rust: `npm run dev` (port 1420 must be free), then open `http://127.0.0.1:1420/fixture.html?phase=unlocked&companion=running`. Other switches, listed in `src/dev-fixture.ts`: `companion=ended_by_lock`, `&older`, `&touchid_changed`, and `phase=no_vault&missing`. Replies are fictional; this proves nothing about native panels, locks or the helper.

Several sessions may share this checkout: check `git status` and stage named paths only. On an exFAT drive, macOS writes `._*` files that break the Tauri build: set `CARGO_TARGET_DIR` and `TMPDIR` to an APFS disk, pass `--out` and `--cache` on that disk to `scripts/package-companion.sh`, and first run `find src-tauri/capabilities src-tauri/permissions -name '._*' -delete 2>/dev/null || true`.

Expand Down
6 changes: 3 additions & 3 deletions CONTEXT.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ A separate credential the owner creates at a service only for AI agent work, wit
_Avoid_: sharing an owner key, agent access to the Vault

**Agent Companion**:
The optional helper inside the app, with its own macOS sandbox, that lets one approved agent use one fixed OpenAI text operation with an **Agent Key**. It can't open the **Vault**, is off unless the owner starts it, and stops at the end of its one-hour grant, on Stop, whenever the app is **Locked**, on sleep and when the app quits ([ADR-0009](docs/adr/0009-optional-agent-companion-helper.md)).
The optional helper inside the app, with its own macOS sandbox, that lets the agent tools in one separate Mac account use one fixed OpenAI text operation with an **Agent Key**. It can't open the **Vault**, is off unless the owner starts it, and stops at the end of its one-hour grant, on Stop, whenever the app is **Locked**, on sleep and when the app quits ([ADR-0009](docs/adr/0009-optional-agent-companion-helper.md)).
_Avoid_: agent bridge (that's the agent account's side), Vault connector, plugin

### Screen privacy
Expand Down Expand Up @@ -128,7 +128,7 @@ _Avoid_: pinned, bookmarked, starred item
## Relationships

- The owner has one **Vault**; it moves between computers only when the owner copies the file by hand.
- AI agents have no access to the **Vault**, its **Notes**, their metadata, **Backups**, **Safety Copies**, or the **Emergency Reader**. The **Master Password**, **Recovery Key** and **Wallet Kinds** never take part in agent work.
- The app gives AI agents no interface to the **Vault**, its **Notes**, their metadata, **Backups**, **Safety Copies** or the **Emergency Reader**, and agents are told never to use them. That limits the app, not the computer: what keeps an agent running in the owner's own Mac account away from these files is the owner's setup. The **Master Password**, **Recovery Key** and **Wallet Kinds** never take part in agent work.
- The **Agent Companion** is the only **Agent Key** integration inside the app; it runs apart from the **Vault** in its own sandbox and never receives Vault content. Any other **Agent Key** integration is separate from this app. Hiding the key still lets an agent perform every operation its provider scope permits, within its enforced limits; only the owner can independently approve scope or limit changes ([ADR-0007](docs/adr/0007-agents-use-separate-restricted-keys.md)).
- Results from an external agent's allowed service actions may leave this computer, including for a cloud model provider; no Vault content or metadata may enter that route.
- Moving a **Vault** to the other computer means opening a **Backup** there. There is no separate "export" or "sync" concept.
Expand All @@ -146,7 +146,7 @@ _Avoid_: pinned, bookmarked, starred item
- The **Vault** file has only **Master Password** and **Recovery Key** credential slots. Enabled **Quick Unlock** opens this computer's current Vault with a separately protected **Vault Key**, without adding a credential slot or releasing the **Wallet Key**.
- A **Vault** has exactly one **Recovery Key**, shown to the owner once, at setup, to write onto their **Recovery Kit**.
- **Safety Copies** stay on this computer; a **Backup** is the owner's copy somewhere else. Both are complete **Vaults**.
- The **Emergency Reader** never writes **Notes** to disk; it only shows them.
- The **Emergency Reader** never writes **Notes** to disk; it only shows them, and only in a terminal unless the owner adds `--allow-non-terminal`.
- A **Vault** that uses any of the newer optional parts of a **Note** (the address or derivation path of a **Seed Phrase**; the purpose of a **Login**; the key ID, secret, purpose, where it is managed, expiry date or variable name of an **API Key**), even on a **Note** in **Trash**, opens only in a current app and a current **Emergency Reader**. Older ones refuse the whole file, and some of them call it damaged, so the app on the other computer and any saved **Emergency Reader** must be updated first, before such a **Vault** is moved there.
- A **Note** in **Trash** is still inside the **Vault** (still encrypted); "Delete forever" removes it from this copy only; older copies still contain it.
- Removing a **Wallet Kind** needs the **Master Password**, like every other change to one: moving it to **Trash**, "Delete forever", and emptying a **Trash** that holds one.
Expand Down
Loading
Loading