@deeeed/metamask-harness 0.17.4 → 0.18.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +775 -0
- package/README.md +65 -71
- package/adapters/extension/ensure-browser.sh +12 -1
- package/adapters/extension/inject.mjs +7 -0
- package/adapters/extension/launch-browser.cjs +10 -3
- package/adapters/extension/lib/chrome-args.cjs +31 -0
- package/adapters/extension/lib/macos-focus.cjs +32 -0
- package/adapters/extension/live.sh +10 -20
- package/adapters/manifest.json +8 -0
- package/adapters/mobile/open-device.sh +45 -7
- package/adapters/mobile/verify.sh +15 -3
- package/adapters/shared/harness-source-fingerprint.mjs +49 -0
- package/adapters/shared/install-repo-deps.sh +1 -5
- package/adapters/shared/open-debug.mjs +184 -103
- package/adapters/shared/resolve-slot-ports-core.mjs +23 -6
- package/adapters/shared/resolve-slot-ports.sh +22 -5
- package/bin/mm-harness +15 -3
- package/dist/adapters/core/surface.js +4 -1
- package/dist/adapters/extension/console-capture.js +3 -1
- package/dist/adapters/extension/harness-freshness.js +39 -0
- package/dist/adapters/extension/product-config.js +110 -0
- package/dist/adapters/extension/runtime-decision.js +20 -71
- package/dist/adapters/extension/surface.js +19 -1
- package/dist/adapters/mobile/prepare.js +17 -0
- package/dist/adapters/mobile/source-freshness.js +26 -41
- package/dist/adapters/mobile/surface.js +4 -1
- package/dist/adapters/resolve-slot-ports.js +2 -0
- package/dist/adapters/slot-ports.js +13 -32
- package/dist/adapters.js +50 -17
- package/dist/checkout-lock.js +27 -2
- package/dist/cli-color.js +19 -0
- package/dist/cli-commands.js +1 -1
- package/dist/cli.js +2 -3
- package/dist/command-contract.js +13 -3
- package/dist/commands/call.js +115 -29
- package/dist/commands/checklist.js +4 -1
- package/dist/commands/completion-candidates.js +20 -13
- package/dist/commands/debug.js +31 -38
- package/dist/commands/doctor.js +33 -6
- package/dist/commands/fixtures.js +65 -17
- package/dist/commands/flows.js +39 -10
- package/dist/commands/launch/extension.js +40 -15
- package/dist/commands/launch/index.js +41 -5
- package/dist/commands/list-executables.js +151 -29
- package/dist/commands/manifest.js +127 -18
- package/dist/commands/parse-args.js +11 -1
- package/dist/commands/run-engine.js +384 -56
- package/dist/commands/run.js +112 -17
- package/dist/commands/shared.js +22 -2
- package/dist/commands/status-probe.js +3 -0
- package/dist/commands/status.js +1 -0
- package/dist/completions-cache.js +1 -1
- package/dist/doctor.js +56 -6
- package/dist/harness.js +6 -5
- package/dist/heal-bounds.js +1 -1
- package/dist/live-adapter-contract.js +132 -12
- package/dist/manifest.js +161 -1
- package/dist/mm-harness-cli.js +13 -7
- package/dist/recipe-security.js +178 -0
- package/dist/runner.js +87 -13
- package/dist/runtime-context.js +8 -26
- package/docs/CONTRIBUTING.md +137 -0
- package/docs/QA.md +185 -0
- package/docs/RECIPES.md +161 -0
- package/docs/SECURITY.md +88 -0
- package/library/actions/core/perps/read_account.mjs +2 -2
- package/library/actions/core/perps/read_orders.mjs +2 -1
- package/library/actions/core/perps/read_positions.mjs +2 -1
- package/library/actions/core/wallet/list_accounts.mjs +95 -0
- package/library/actions/extension/platform/cdp.mjs +1 -0
- package/library/actions/extension/wallet/list_accounts.mjs +41 -0
- package/library/actions/mobile/platform/bridge.mjs +1 -5
- package/library/actions/mobile/wallet/list_accounts.mjs +37 -0
- package/library/manifests/core.action-manifest.json +61 -0
- package/library/manifests/extension.action-manifest.json +53 -0
- package/library/manifests/mobile.action-manifest.json +53 -0
- package/library/recipes/runner/action-validation.extension.recipe.json +8 -1
- package/library/recipes/runner/action-validation.mobile.recipe.json +8 -1
- package/package.json +10 -6
- package/scripts/completions.sh +7 -7
- package/docs/ADAPTER-SURFACE.md +0 -26
- package/docs/CHEATSHEET.md +0 -48
- package/docs/CLI-ERGONOMICS-AUDIT.md +0 -32
- package/docs/CLI-ERGONOMICS-HUMAN-QA.md +0 -64
- package/docs/CODE-MAP.md +0 -62
- package/docs/UX-PRINCIPLES.md +0 -66
- package/docs/VIDEO-DEMO-VALIDATION.md +0 -74
- package/docs/architecture.md +0 -88
- package/docs/live-adapter-contract.md +0 -190
- package/docs/package-boundaries.md +0 -47
- package/docs/perps-flow-catalog.md +0 -235
- package/docs/recipe-libraries.md +0 -71
- package/docs/runtime-file-conventions.md +0 -36
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
# Contributing
|
|
2
|
+
|
|
3
|
+
Keep `mm-harness` thin: put each change in the layer that owns it and validate
|
|
4
|
+
both the machine contract and the visible human result.
|
|
5
|
+
|
|
6
|
+
## Ownership
|
|
7
|
+
|
|
8
|
+
```text
|
|
9
|
+
bin/mm-harness
|
|
10
|
+
-> src/ typed CLI and product decisions
|
|
11
|
+
-> @farmslot/recipe-harness generic execution, UI transports, evidence
|
|
12
|
+
-> @farmslot/protocol schemas
|
|
13
|
+
-> adapters/ focused host/browser/device leaves
|
|
14
|
+
-> library/ MetaMask actions, flows, recipes
|
|
15
|
+
-> MetaMask checkout product under test
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
| Layer | Owns |
|
|
19
|
+
|---|---|
|
|
20
|
+
| `@farmslot/protocol` | recipe and evidence schemas |
|
|
21
|
+
| `@farmslot/recipe-harness` | generic execution, recovery, traces, artifacts, `ui.*` |
|
|
22
|
+
| `mm-harness` | MetaMask runtime control, diagnostics, durable domain actions |
|
|
23
|
+
| skills/checklists | task workflow and proof expectations |
|
|
24
|
+
| product checkout | app behavior and explicit debug hooks |
|
|
25
|
+
|
|
26
|
+
Generic bootstrap, trust, receipts, and recovery belong upstream. MetaMask
|
|
27
|
+
platform behavior and risk classification belong here. Ticket assertions stay
|
|
28
|
+
task-local.
|
|
29
|
+
|
|
30
|
+
## Repository map
|
|
31
|
+
|
|
32
|
+
| Path | Responsibility |
|
|
33
|
+
|---|---|
|
|
34
|
+
| `bin/mm-harness` | only public executable |
|
|
35
|
+
| `src/commands/` | command behavior |
|
|
36
|
+
| `src/adapters/` | typed platform decisions and `AdapterSurface` |
|
|
37
|
+
| `adapters/<platform>/` | focused shell/Node host operations |
|
|
38
|
+
| `adapters/<platform>/inject*` | assemble the checkout overlay from shipped adapter/library files |
|
|
39
|
+
| `library/actions/` | executable MetaMask action adapters |
|
|
40
|
+
| `library/flows/` | reusable parameterized behavior |
|
|
41
|
+
| `library/recipes/` | reusable proofs |
|
|
42
|
+
| `library/manifests/` | declared capability surface |
|
|
43
|
+
| `scripts/` | build/validation tooling and shipped completion/human-QA helpers |
|
|
44
|
+
|
|
45
|
+
All TypeScript lives under `src/`. Use `.mjs` for direct no-build Node leaves,
|
|
46
|
+
`.cjs` only for required CommonJS contexts, and shell only for host/device
|
|
47
|
+
commands. Decisions belong in TypeScript; a leaf performs one operation and
|
|
48
|
+
exits.
|
|
49
|
+
|
|
50
|
+
## Adapter surface
|
|
51
|
+
|
|
52
|
+
Commands resolve shared platform behavior through
|
|
53
|
+
`src/adapters/surface.ts`. Extend `AdapterSurface` only when all platforms need
|
|
54
|
+
the concept, implement all three adapters, and let Core report headless/N/A
|
|
55
|
+
explicitly. Do not add command-local platform ladders for surface-owned behavior.
|
|
56
|
+
|
|
57
|
+
Each checkout owns:
|
|
58
|
+
|
|
59
|
+
```text
|
|
60
|
+
temp/recipe/runtime/ ports, processes, fixture, logs, runtime identity
|
|
61
|
+
temp/recipe/harness/ installed runtime overlay
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Profiles, devices, ports, watchers, and evidence paths must resolve from that
|
|
65
|
+
checkout so slots remain isolated.
|
|
66
|
+
|
|
67
|
+
## Actions and adapters
|
|
68
|
+
|
|
69
|
+
Official `ui.*` behavior comes from the generic runtime. MetaMask-specific
|
|
70
|
+
actions are manifest-declared modules under:
|
|
71
|
+
|
|
72
|
+
```text
|
|
73
|
+
library/actions/<platform>/<domain>/<name>.mjs
|
|
74
|
+
library/actions/shared/<domain>/<name>.mjs
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Configured libraries use the same structure. An adapter receives a JSON input
|
|
78
|
+
path, writes JSON to its `outputPath` or stdout, returns redacted trace-safe
|
|
79
|
+
output, and performs only the declared operation. It must not execute another
|
|
80
|
+
recipe graph.
|
|
81
|
+
|
|
82
|
+
The input path is argv 1 and `METAMASK_RECIPE_ADAPTER_INPUT`. Its document is:
|
|
83
|
+
|
|
84
|
+
```json
|
|
85
|
+
{
|
|
86
|
+
"schemaVersion": 1,
|
|
87
|
+
"platform": "mobile|extension|core",
|
|
88
|
+
"action": "metamask.example.action",
|
|
89
|
+
"node": {},
|
|
90
|
+
"context": {
|
|
91
|
+
"nodeId": "step-id",
|
|
92
|
+
"projectRoot": "/path/to/checkout",
|
|
93
|
+
"artifactsDir": "/path/to/run/artifacts"
|
|
94
|
+
},
|
|
95
|
+
"outputPath": "/temporary/output.json"
|
|
96
|
+
}
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
Write JSON to `outputPath` (also `METAMASK_RECIPE_ADAPTER_OUTPUT`) or stdout.
|
|
100
|
+
Write evidence under `context.artifactsDir` and return relative artifact paths.
|
|
101
|
+
`METAMASK_RECIPE_LIVE_ADAPTER_DIR` is the explicit task-local implementation
|
|
102
|
+
root; configured libraries are the durable sharing mechanism.
|
|
103
|
+
|
|
104
|
+
Add a bundled action only when it is reusable, typed, stable, reduces inference
|
|
105
|
+
or risk, and has a real postcondition. Otherwise use a team library or task-local
|
|
106
|
+
recipe. Follow [Recipes](RECIPES.md) and [Security](SECURITY.md).
|
|
107
|
+
|
|
108
|
+
## CLI contract
|
|
109
|
+
|
|
110
|
+
- Human mode is contextual, colored only in a TTY, and teaches one exact next
|
|
111
|
+
action on failure.
|
|
112
|
+
- `--json` stdout is one stable document with no decoration.
|
|
113
|
+
- Long work acknowledges intent before blocking and streams child output.
|
|
114
|
+
- Lifecycle commands are checkout-scoped and idempotent.
|
|
115
|
+
- `doctor` is read-only; `doctor --fix` repairs without launching.
|
|
116
|
+
- No command may fabricate platform support or readiness.
|
|
117
|
+
|
|
118
|
+
When adding a command, register its behavior and human metadata, then add a
|
|
119
|
+
contract test. When a flag reaches a host leaf, both the typed composer and leaf
|
|
120
|
+
parser must accept it. Before renaming or removing a public flag, injected file,
|
|
121
|
+
or wrapper, verify real callers and retain compatibility only when one exists.
|
|
122
|
+
|
|
123
|
+
## Change gates
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
yarn test:unit
|
|
127
|
+
yarn test:coverage
|
|
128
|
+
yarn check
|
|
129
|
+
bash tests/contract/run.sh
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
Runtime changes also require real affected-platform QA and a packed installation
|
|
133
|
+
test. Update `CHANGELOG.md` under `Unreleased` for user-visible behavior.
|
|
134
|
+
|
|
135
|
+
Docs describe only current behavior. History belongs in the changelog and Git;
|
|
136
|
+
do not add handovers, audits, speculative roadmaps, or duplicate command guides
|
|
137
|
+
under `docs/`.
|
package/docs/QA.md
ADDED
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
# QA
|
|
2
|
+
|
|
3
|
+
Validate the installed candidate as a human would use it. Use disposable
|
|
4
|
+
profiles and an unfunded fixture; preserve existing product source and active
|
|
5
|
+
processes.
|
|
6
|
+
|
|
7
|
+
## Candidate and provenance
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
export CANDIDATE=/path/to/mm-harness-candidate.tgz
|
|
11
|
+
export QA_HOME="$(mktemp -d "$HOME/mmh-qa.XXXXXX")"
|
|
12
|
+
export QA_PREFIX="$QA_HOME/npm"
|
|
13
|
+
HOME="$QA_HOME" npm install -g --prefix "$QA_PREFIX" "$CANDIDATE"
|
|
14
|
+
export PATH="$QA_PREFIX/bin:$PATH"
|
|
15
|
+
mm-harness --version
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
- [ ] The executable and dependencies resolve inside the isolated prefix.
|
|
19
|
+
- [ ] No dependency is a symlink or resolves through a local Farmslot checkout.
|
|
20
|
+
- [ ] Record the tarball SHA-256 and product SHAs.
|
|
21
|
+
- [ ] Product trees start and finish without tracked changes.
|
|
22
|
+
|
|
23
|
+
## Common
|
|
24
|
+
|
|
25
|
+
Run inside each Extension, Mobile, and Core checkout:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
mm-harness doctor
|
|
29
|
+
mm-harness doctor --json
|
|
30
|
+
mm-harness status
|
|
31
|
+
mm-harness actions
|
|
32
|
+
mm-harness flows
|
|
33
|
+
mm-harness run --list
|
|
34
|
+
mm-harness run runner.smoke --describe
|
|
35
|
+
mm-harness run runner.smoke --plan
|
|
36
|
+
mm-harness run runner.smoke
|
|
37
|
+
mm-harness last --json
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
- [ ] Product, checkout, slot, ports, and next action are correct.
|
|
41
|
+
- [ ] Human output is concise and evidence paths are absolute.
|
|
42
|
+
- [ ] JSON output is one parseable document without color or prose on stdout.
|
|
43
|
+
- [ ] `run` chooses a checkout-local artifact directory; an explicit
|
|
44
|
+
`--artifacts-dir` still wins.
|
|
45
|
+
- [ ] Reports, trace, diagnostics, executed recipe, and manifest exist and agree.
|
|
46
|
+
- [ ] `last --json` reconstructs the run without re-executing it.
|
|
47
|
+
|
|
48
|
+
Recovery checks:
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
mm-harness actions --wat
|
|
52
|
+
mm-harness run missing.recipe --describe
|
|
53
|
+
mm-harness doctor --fix
|
|
54
|
+
mm-harness verify
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
- [ ] Bad input fails before runtime work with a stable code and one exact next
|
|
58
|
+
action.
|
|
59
|
+
- [ ] `doctor --fix` is idempotent and does not choose a fixture or launch.
|
|
60
|
+
- [ ] With `capture-helper` absent, Extension reports CDP screenshots and Mobile
|
|
61
|
+
reports `simctl`/ADB screenshots; video is honestly unavailable.
|
|
62
|
+
|
|
63
|
+
Run the bounded multi-platform preflight when all three checkouts are available:
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
yarn qa:human \
|
|
67
|
+
--extension /path/to/metamask-extension \
|
|
68
|
+
--mobile /path/to/metamask-mobile \
|
|
69
|
+
--core /path/to/metamask-core \
|
|
70
|
+
--artifacts-dir temp/human-qa
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
It supplements the visible checks below; it does not replace them.
|
|
74
|
+
|
|
75
|
+
## Extension
|
|
76
|
+
|
|
77
|
+
Fresh MetaMask Extension needs its normal product configuration and
|
|
78
|
+
checkout-pinned Chromium. Follow the product files; do not invent values:
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
cd /path/to/metamask-extension
|
|
82
|
+
cp .metamaskrc.dist .metamaskrc
|
|
83
|
+
${EDITOR:-vi} .metamaskrc
|
|
84
|
+
yarn playwright install chromium
|
|
85
|
+
mm-harness launch --verify
|
|
86
|
+
mm-harness fixtures set
|
|
87
|
+
mm-harness run wallet.smoke
|
|
88
|
+
mm-harness logs --source extension
|
|
89
|
+
mm-harness logs --source dapp
|
|
90
|
+
mm-harness logs --source webpack
|
|
91
|
+
mm-harness debug
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
- [ ] Missing/placeholder Infura configuration returns
|
|
95
|
+
`EXTENSION_PRODUCT_CONFIG_REQUIRED` before build or browser startup.
|
|
96
|
+
- [ ] Missing Chromium returns `EXTENSION_BROWSER_REQUIRED` without using system
|
|
97
|
+
Chrome.
|
|
98
|
+
- [ ] Launch uses the checkout-owned profile, opens one MetaMask surface, avoids
|
|
99
|
+
keychain prompts, and preserves keyboard focus by default.
|
|
100
|
+
- [ ] A second launch reuses the watcher/profile without duplicate tabs.
|
|
101
|
+
- [ ] Two source edits rebuild incrementally; refresh shows each change; revert
|
|
102
|
+
restores a clean tree.
|
|
103
|
+
- [ ] Log sources are distinct.
|
|
104
|
+
- [ ] `debug` opens connected DevTools for the active Extension surface;
|
|
105
|
+
`location.href` returns its `chrome-extension://` URL and remains connected.
|
|
106
|
+
|
|
107
|
+
## Mobile
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
cd /path/to/metamask-mobile
|
|
111
|
+
mm-harness provision runway ios
|
|
112
|
+
mm-harness launch ios --verify
|
|
113
|
+
mm-harness fixtures set
|
|
114
|
+
mm-harness call metamask.wallet.ensure_unlocked
|
|
115
|
+
mm-harness run wallet.smoke
|
|
116
|
+
mm-harness logs --source app
|
|
117
|
+
mm-harness logs --source metro
|
|
118
|
+
mm-harness debug
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
- [ ] Simulator opens only when absent and does not steal focus by default.
|
|
122
|
+
- [ ] A second launch reuses the running simulator and Metro.
|
|
123
|
+
- [ ] Fixture setup and unlock show the intended redacted account without
|
|
124
|
+
mnemonic/private-key output.
|
|
125
|
+
- [ ] Status matches verified product routes: `Login`/`LockScreen` are locked;
|
|
126
|
+
`WalletView` is unlocked.
|
|
127
|
+
- [ ] App and Metro logs are separate.
|
|
128
|
+
- [ ] A JS edit rebuilds through Metro and appears after reload without a native
|
|
129
|
+
rebuild; revert restores a clean tree.
|
|
130
|
+
|
|
131
|
+
When Android/ADB is available, repeat with:
|
|
132
|
+
|
|
133
|
+
```bash
|
|
134
|
+
mm-harness launch android --device <serial> --verify
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
## Core
|
|
138
|
+
|
|
139
|
+
```bash
|
|
140
|
+
cd /path/to/metamask-core
|
|
141
|
+
mm-harness doctor
|
|
142
|
+
mm-harness call metamask.wallet.list_accounts scope=selected
|
|
143
|
+
mm-harness run runner.smoke
|
|
144
|
+
mm-harness logs
|
|
145
|
+
mm-harness debug
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
- [ ] Doctor reports a headless controller surface and no capture requirement.
|
|
149
|
+
- [ ] Account output is fixture-backed and redacted.
|
|
150
|
+
- [ ] Smoke writes the complete evidence package without launching an app.
|
|
151
|
+
- [ ] Logs/debug fail with truthful headless teaching errors.
|
|
152
|
+
|
|
153
|
+
## Trust and evidence
|
|
154
|
+
|
|
155
|
+
- [ ] An untrusted restricted plan fails with `RECIPE_TRUST_REQUIRED` and no
|
|
156
|
+
side effect.
|
|
157
|
+
- [ ] A wrong/stale digest fails with `RECIPE_APPROVAL_MISMATCH`.
|
|
158
|
+
- [ ] Only the unchanged, reviewed plan executes with its exact approval digest.
|
|
159
|
+
- [ ] Human output, JSON, reports, traces, diagnostics, and screenshots contain
|
|
160
|
+
no mnemonic, private key, seed, bearer token, or API credential.
|
|
161
|
+
- [ ] Diagnostics contain only events observed in the proof window.
|
|
162
|
+
- [ ] Screenshot provenance identifies capture-helper, CDP, simctl, or ADB
|
|
163
|
+
accurately.
|
|
164
|
+
|
|
165
|
+
## Automated and release gates
|
|
166
|
+
|
|
167
|
+
```bash
|
|
168
|
+
yarn check
|
|
169
|
+
bash tests/contract/run.sh
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
Before release:
|
|
173
|
+
|
|
174
|
+
- [ ] Focused unit tests and full contract suite pass.
|
|
175
|
+
- [ ] Packed isolated installation passes the critical Extension, Mobile, and
|
|
176
|
+
Core scenarios.
|
|
177
|
+
- [ ] Independent review approves the exact final diff.
|
|
178
|
+
- [ ] Known limits are explicit: Extension requires product Infura setup;
|
|
179
|
+
Mobile requires its normal dev-client/device setup; video requires optional
|
|
180
|
+
`capture-helper`; the harness never invents funded fixtures.
|
|
181
|
+
- [ ] Existing Farmslot slots remain compatible.
|
|
182
|
+
|
|
183
|
+
When a slot manager is available, repeat `runner.smoke` in one existing managed
|
|
184
|
+
checkout per product and verify its profile/device, ports, processes, and fixture
|
|
185
|
+
remain isolated.
|
package/docs/RECIPES.md
ADDED
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
# Recipes
|
|
2
|
+
|
|
3
|
+
Use the smallest durable layer that proves the task:
|
|
4
|
+
|
|
5
|
+
1. bundled actions;
|
|
6
|
+
2. a bundled or team flow;
|
|
7
|
+
3. a task-local recipe;
|
|
8
|
+
4. a trusted task-local action or direct controller/CDP operation when no
|
|
9
|
+
stable action exists.
|
|
10
|
+
|
|
11
|
+
Search before writing code:
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
mm-harness actions <intent>
|
|
15
|
+
mm-harness actions --action <name>
|
|
16
|
+
mm-harness flows
|
|
17
|
+
mm-harness flows describe <ref> --json
|
|
18
|
+
mm-harness run --list
|
|
19
|
+
mm-harness run <name> --describe
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Discovery reports the winning source, fields, examples, and shadowed sources.
|
|
23
|
+
Use `--json` when an agent needs exact metadata.
|
|
24
|
+
|
|
25
|
+
## Compose a proof
|
|
26
|
+
|
|
27
|
+
An action performs one operation. A flow packages reusable product setup or
|
|
28
|
+
behavior. A recipe owns the task's acceptance criteria and evidence.
|
|
29
|
+
|
|
30
|
+
Minimal recipe:
|
|
31
|
+
|
|
32
|
+
```json
|
|
33
|
+
{
|
|
34
|
+
"schema_version": 1,
|
|
35
|
+
"title": "Wallet readiness proof",
|
|
36
|
+
"description": "Proves the running wallet is reachable and unlocked.",
|
|
37
|
+
"validate": {
|
|
38
|
+
"workflow": {
|
|
39
|
+
"entry": "unlock",
|
|
40
|
+
"nodes": {
|
|
41
|
+
"unlock": {
|
|
42
|
+
"action": "metamask.wallet.ensure_unlocked",
|
|
43
|
+
"intent": "Ensure the fixture-backed wallet is unlocked",
|
|
44
|
+
"next": "done"
|
|
45
|
+
},
|
|
46
|
+
"done": { "action": "end", "status": "pass" }
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Validate without side effects, then run:
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
mm-harness run recipe.json --plan
|
|
57
|
+
mm-harness run recipe.json
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
To reuse an existing Extension build on a specific CDP runtime:
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
mm-harness run recipe.json --cdp-port 9500 --launch-existing-dist
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Rules:
|
|
67
|
+
|
|
68
|
+
- Use real product paths; never mutate DOM, Redux, controller, or persisted
|
|
69
|
+
state to fabricate proof.
|
|
70
|
+
- Setup may use supported APIs, but a read/assert or visible UI postcondition
|
|
71
|
+
must prove the result.
|
|
72
|
+
- Use `ui.*` for human-visible behavior. Keep ticket copy, styling, and layout
|
|
73
|
+
claims in the task recipe and screenshots.
|
|
74
|
+
- Parameterize repeated behavior instead of multiplying action names.
|
|
75
|
+
- Every `ensure_*` flow must prove a postcondition.
|
|
76
|
+
- Keep secrets out of recipes, libraries, and evidence.
|
|
77
|
+
|
|
78
|
+
The Recipe Protocol v1 schema is authoritative:
|
|
79
|
+
<https://farmslot.io/docs/reference/recipe-protocol-v1>.
|
|
80
|
+
|
|
81
|
+
## Share reusable behavior
|
|
82
|
+
|
|
83
|
+
A library may contain manifests, action implementations, flows, and complete
|
|
84
|
+
recipes:
|
|
85
|
+
|
|
86
|
+
```text
|
|
87
|
+
team-recipes/
|
|
88
|
+
library.json
|
|
89
|
+
manifests/extension.action-manifest.json
|
|
90
|
+
actions/extension/wallet/ensure_ready.mjs
|
|
91
|
+
flows/wallet.flows.json
|
|
92
|
+
recipes/onboarding/smoke.extension.recipe.json
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
Minimal `library.json`:
|
|
96
|
+
|
|
97
|
+
```json
|
|
98
|
+
{
|
|
99
|
+
"kind": "recipe-library",
|
|
100
|
+
"schema_version": 1,
|
|
101
|
+
"name": "wallet-team",
|
|
102
|
+
"owner": "wallet-team"
|
|
103
|
+
}
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
Enable it:
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
export RECIPE_LIBRARY_PATH="wallet=$HOME/shared-library/wallet-team"
|
|
110
|
+
mm-harness flows
|
|
111
|
+
mm-harness run --list
|
|
112
|
+
mm-harness run onboarding.smoke --describe
|
|
113
|
+
mm-harness run onboarding.smoke --plan
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
Use `--library wallet=/path/to/library` for one command. Without an explicit
|
|
117
|
+
library, the personal library is `$FARMSLOT_HOME/recipe-library` (default
|
|
118
|
+
`~/.farmslot/recipe-library`). Resolution is task/local configuration first,
|
|
119
|
+
then bundled MetaMask; runs snapshot resolved definitions so shadowing is
|
|
120
|
+
reviewable.
|
|
121
|
+
|
|
122
|
+
Promote a repeated flow only after it has a useful description, typed params,
|
|
123
|
+
and successful proof:
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
mm-harness flows promote --from recipe.json --flow wallet.ensure_ready --run artifacts
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
## Direct product access
|
|
130
|
+
|
|
131
|
+
The bundled catalog is intentionally small. A task may use a real controller or
|
|
132
|
+
CDP path when that is clearer than adding a permanent wrapper.
|
|
133
|
+
|
|
134
|
+
Before doing so, validate the path in current product source and record:
|
|
135
|
+
|
|
136
|
+
- the controller/API and supported parameters;
|
|
137
|
+
- whether it reads or mutates state;
|
|
138
|
+
- required preconditions;
|
|
139
|
+
- the independent postcondition;
|
|
140
|
+
- trace redaction.
|
|
141
|
+
|
|
142
|
+
Do not infer route or controller names from memory. A direct mutation still
|
|
143
|
+
requires a separate read/assert or visible UI proof. If the operation repeats
|
|
144
|
+
across tasks, move it to a reviewed team library; promote it into the bundled
|
|
145
|
+
catalog only when it is broadly reusable and stable across supported products.
|
|
146
|
+
|
|
147
|
+
## Cross-platform expectations
|
|
148
|
+
|
|
149
|
+
Mobile and Extension use the same wallet and Perps vocabulary where both expose
|
|
150
|
+
the behavior. Core is headless: it reports fixture-backed controller inputs and
|
|
151
|
+
does not pretend to have a selected UI account or app route.
|
|
152
|
+
|
|
153
|
+
Inspect the current capability instead of assuming parity:
|
|
154
|
+
|
|
155
|
+
```bash
|
|
156
|
+
mm-harness actions --category wallet --json
|
|
157
|
+
mm-harness actions --category perps --json
|
|
158
|
+
mm-harness actions --action metamask.wallet.list_accounts --json
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
See [Security](SECURITY.md) before enabling custom executable actions.
|
package/docs/SECURITY.md
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# Security
|
|
2
|
+
|
|
3
|
+
`mm-harness` executes product code, recipes, and optional custom adapters with
|
|
4
|
+
the current user's authority. It is a proof tool, not an OS sandbox.
|
|
5
|
+
|
|
6
|
+
## Trust boundary
|
|
7
|
+
|
|
8
|
+
- Bundled actions and recipes are trusted package content.
|
|
9
|
+
- A configured library cannot declare itself trusted.
|
|
10
|
+
- Untrusted plans that request restricted capabilities stop before runtime
|
|
11
|
+
preparation or side effects with `RECIPE_TRUST_REQUIRED`.
|
|
12
|
+
- The failure reports blocked nodes, capabilities, source provenance, and one
|
|
13
|
+
exact approval command.
|
|
14
|
+
- Approval is bound to the resolved plan, implementation bundle, project root,
|
|
15
|
+
artifact directory, and execution environment.
|
|
16
|
+
- Changed code or inputs produce `RECIPE_APPROVAL_MISMATCH`; an old digest does
|
|
17
|
+
not authorize a new plan.
|
|
18
|
+
|
|
19
|
+
Never construct an approval from memory. Inspect the plan and use the exact
|
|
20
|
+
`userAction` emitted by the failed run. Review custom libraries like application
|
|
21
|
+
code because approved code retains the user's filesystem, process, and network
|
|
22
|
+
permissions.
|
|
23
|
+
|
|
24
|
+
## Product-state integrity
|
|
25
|
+
|
|
26
|
+
Proof must come from supported UI, controller, or API paths. Never write DOM,
|
|
27
|
+
React/Redux/MobX state, controller internals, or storage merely to manufacture
|
|
28
|
+
the claimed result.
|
|
29
|
+
|
|
30
|
+
Fixture setup is allowed before the proof window when it is explicit in the
|
|
31
|
+
trace. Mutating setup must finish with a real read/assert or visible UI
|
|
32
|
+
postcondition.
|
|
33
|
+
|
|
34
|
+
## Wallet fixtures
|
|
35
|
+
|
|
36
|
+
Each checkout has one canonical fixture:
|
|
37
|
+
|
|
38
|
+
```text
|
|
39
|
+
temp/recipe/runtime/wallet-fixture.json
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Initialize it explicitly from an approved fixture or choose the disposable
|
|
43
|
+
`--dev` option shown in the [README](../README.md). Never fund a dev fixture.
|
|
44
|
+
|
|
45
|
+
- Never commit a fixture containing a mnemonic or private key.
|
|
46
|
+
- Never print, paste, or record mnemonic/private-key material.
|
|
47
|
+
- Use funded fixtures only in the intended isolated environment.
|
|
48
|
+
- `fixtures set` reads the password from the fixture; do not put it on the
|
|
49
|
+
command line.
|
|
50
|
+
- Human and JSON outputs may identify redacted accounts but must not expose
|
|
51
|
+
secret material.
|
|
52
|
+
|
|
53
|
+
## Evidence and journals
|
|
54
|
+
|
|
55
|
+
Recipe output may include application logs, screenshots, traces, and custom
|
|
56
|
+
action results. Before sharing it:
|
|
57
|
+
|
|
58
|
+
- verify the artifact manifest contains only intended files;
|
|
59
|
+
- search human output, JSON, traces, diagnostics, and reports for credentials;
|
|
60
|
+
- confirm screenshots use the declared provider and show no sensitive UI;
|
|
61
|
+
- keep task-local artifacts out of source control unless intentionally reviewed.
|
|
62
|
+
|
|
63
|
+
`mm-harness last --json` stores a redacted resumability record. It is not a
|
|
64
|
+
secret store.
|
|
65
|
+
|
|
66
|
+
## Runtime isolation
|
|
67
|
+
|
|
68
|
+
Extension uses a checkout-owned Chrome profile and CDP port. Mobile resolves a
|
|
69
|
+
checkout-owned simulator/device and Metro port. Core is headless. Parallel
|
|
70
|
+
checkouts must not share profiles, runtime directories, process markers, or
|
|
71
|
+
evidence directories.
|
|
72
|
+
|
|
73
|
+
On macOS, Extension Chromium uses a mock keychain so an isolated test profile
|
|
74
|
+
does not touch the operator's login keychain. Product configuration and wallet
|
|
75
|
+
fixtures remain user-owned; the harness detects missing prerequisites but never
|
|
76
|
+
invents them.
|
|
77
|
+
|
|
78
|
+
## Release checks
|
|
79
|
+
|
|
80
|
+
Security-sensitive changes require:
|
|
81
|
+
|
|
82
|
+
1. trust-boundary tests proving rejection occurs before side effects;
|
|
83
|
+
2. exact-digest success and stale-digest rejection;
|
|
84
|
+
3. redaction tests for arguments, results, journals, and evidence;
|
|
85
|
+
4. packed-install provenance with no local links;
|
|
86
|
+
5. independent review of the exact diff.
|
|
87
|
+
|
|
88
|
+
Use [QA](QA.md) for the runnable checklist.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { getCoreController, runAdapter } from './_controller.mjs';
|
|
1
|
+
import { getCoreController, isDirectRun, runAdapter } from './_controller.mjs';
|
|
2
2
|
|
|
3
3
|
function redactAccount(account) {
|
|
4
4
|
return {
|
|
@@ -27,4 +27,4 @@ export async function readAccount(input) {
|
|
|
27
27
|
};
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
-
runAdapter(readAccount);
|
|
30
|
+
if (isDirectRun(import.meta.url)) runAdapter(readAccount);
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
getCoreController,
|
|
3
|
+
isDirectRun,
|
|
3
4
|
redactPosition,
|
|
4
5
|
runAdapter,
|
|
5
6
|
selectedItems,
|
|
@@ -24,4 +25,4 @@ export async function readPositions(input) {
|
|
|
24
25
|
};
|
|
25
26
|
}
|
|
26
27
|
|
|
27
|
-
runAdapter(readPositions);
|
|
28
|
+
if (isDirectRun(import.meta.url)) runAdapter(readPositions);
|