settld 0.2.0 → 0.2.2
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/README.md +21 -0
- package/SETTLD_VERSION +1 -1
- package/bin/settld.js +18 -0
- package/docs/QUICKSTART_MCP_HOSTS.md +78 -4
- package/docs/gitbook/quickstart.md +47 -4
- package/docs/integrations/openclaw/PUBLIC_QUICKSTART.md +13 -0
- package/docs/ops/VERCEL_MONOREPO_DEPLOY.md +42 -0
- package/package.json +2 -1
- package/scripts/ci/run-mcp-host-smoke.mjs +6 -0
- package/scripts/ci/run-production-cutover-gate.mjs +6 -0
- package/scripts/demo/mcp-paid-exa.mjs +18 -1
- package/scripts/setup/login.mjs +299 -0
- package/scripts/setup/onboard.mjs +281 -26
- package/scripts/setup/session-store.mjs +65 -0
- package/scripts/vercel/build-mkdocs.sh +3 -3
- package/scripts/vercel/ignore-dashboard.sh +26 -0
- package/scripts/vercel/ignore-mkdocs.sh +2 -0
- package/scripts/vercel/install-mkdocs.sh +2 -3
- package/scripts/wallet/cli.mjs +871 -0
- package/src/core/wallet-funding-coinbase.js +197 -0
- package/src/core/wallet-funding-hosted.js +155 -0
- package/src/core/wallet-provider-bootstrap.js +95 -0
package/README.md
CHANGED
|
@@ -86,6 +86,27 @@ npm install -g settld
|
|
|
86
86
|
settld setup
|
|
87
87
|
```
|
|
88
88
|
|
|
89
|
+
Check wallet wiring and funding path:
|
|
90
|
+
|
|
91
|
+
```sh
|
|
92
|
+
settld wallet status
|
|
93
|
+
settld wallet fund --open
|
|
94
|
+
settld wallet fund --method transfer
|
|
95
|
+
settld wallet balance --watch --min-usdc 1
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Hosted top-up (recommended): configure Coinbase Hosted Onramp on the backend so `settld wallet fund --open` launches funding directly:
|
|
99
|
+
|
|
100
|
+
```sh
|
|
101
|
+
export MAGIC_LINK_WALLET_FUND_PROVIDER='coinbase'
|
|
102
|
+
export MAGIC_LINK_COINBASE_API_KEY_VALUE='organizations/<org_id>/apiKeys/<key_id>'
|
|
103
|
+
export MAGIC_LINK_COINBASE_API_SECRET_KEY='-----BEGIN EC PRIVATE KEY-----\n...\n-----END EC PRIVATE KEY-----'
|
|
104
|
+
export MAGIC_LINK_COINBASE_PROJECT_ID='<project_id>'
|
|
105
|
+
export MAGIC_LINK_COINBASE_DESTINATION_NETWORK='base'
|
|
106
|
+
export MAGIC_LINK_COINBASE_ASSET='USDC'
|
|
107
|
+
export MAGIC_LINK_COINBASE_FIAT_CURRENCY='USD'
|
|
108
|
+
```
|
|
109
|
+
|
|
89
110
|
Legacy setup wizard (advanced / old flags):
|
|
90
111
|
|
|
91
112
|
```sh
|
package/SETTLD_VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
0.2.
|
|
1
|
+
0.2.1
|
package/bin/settld.js
CHANGED
|
@@ -9,6 +9,7 @@ function usage() {
|
|
|
9
9
|
console.error("usage:");
|
|
10
10
|
console.error(" settld --version");
|
|
11
11
|
console.error(" settld onboard [--help]");
|
|
12
|
+
console.error(" settld login [--help]");
|
|
12
13
|
console.error(" settld setup [--help]");
|
|
13
14
|
console.error(" settld setup legacy [--help]");
|
|
14
15
|
console.error(" settld setup circle [--help]");
|
|
@@ -21,6 +22,15 @@ function usage() {
|
|
|
21
22
|
console.error(" settld closepack export --agreement-hash <sha256> --out <path.zip> [--ops-token tok_ops] [--base-url http://127.0.0.1:3000] [--tenant-id tenant_default] [--protocol 1.0]");
|
|
22
23
|
console.error(" settld closepack verify <path.zip> [--json-out <path.json>]");
|
|
23
24
|
console.error(" settld x402 receipt verify <receipt.json|-> [--strict] [--format json|text] [--json-out <path>]");
|
|
25
|
+
console.error(
|
|
26
|
+
" settld wallet status [--base-url <url>] [--tenant-id <id>] [--session-file <path>] [--cookie <cookie>] [--magic-link-api-key <key>] [--format text|json] [--json-out <path>]"
|
|
27
|
+
);
|
|
28
|
+
console.error(
|
|
29
|
+
" settld wallet fund [--method card|bank|transfer|faucet] [--open] [--hosted-url <url>] [--non-interactive] [--base-url <url>] [--tenant-id <id>] [--session-file <path>] [--cookie <cookie>] [--magic-link-api-key <key>] [--format text|json] [--json-out <path>]"
|
|
30
|
+
);
|
|
31
|
+
console.error(
|
|
32
|
+
" settld wallet balance [--watch] [--min-usdc <amount>] [--interval-seconds <n>] [--timeout-seconds <n>] [--base-url <url>] [--tenant-id <id>] [--session-file <path>] [--cookie <cookie>] [--magic-link-api-key <key>] [--format text|json] [--json-out <path>]"
|
|
33
|
+
);
|
|
24
34
|
console.error(" settld profile list [--format json|text] [--json-out <path>]");
|
|
25
35
|
console.error(" settld profile init <profile-id> [--out <path>] [--force] [--format json|text] [--json-out <path>]");
|
|
26
36
|
console.error(
|
|
@@ -138,6 +148,10 @@ function main() {
|
|
|
138
148
|
return runNodeScript("scripts/setup/onboard.mjs", argv.slice(1));
|
|
139
149
|
}
|
|
140
150
|
|
|
151
|
+
if (cmd === "login") {
|
|
152
|
+
return runNodeScript("scripts/setup/login.mjs", argv.slice(1));
|
|
153
|
+
}
|
|
154
|
+
|
|
141
155
|
if (cmd === "doctor") {
|
|
142
156
|
return runNodeScript("scripts/doctor/mcp-host.mjs", argv.slice(1));
|
|
143
157
|
}
|
|
@@ -266,6 +280,10 @@ function main() {
|
|
|
266
280
|
process.exit(1);
|
|
267
281
|
}
|
|
268
282
|
|
|
283
|
+
if (cmd === "wallet") {
|
|
284
|
+
return runNodeScript("scripts/wallet/cli.mjs", argv.slice(1));
|
|
285
|
+
}
|
|
286
|
+
|
|
269
287
|
if (cmd === "profile") {
|
|
270
288
|
return runNodeScript("scripts/profile/cli.mjs", argv.slice(1));
|
|
271
289
|
}
|
|
@@ -17,7 +17,9 @@ Required inputs:
|
|
|
17
17
|
|
|
18
18
|
- `SETTLD_BASE_URL` (local or hosted API URL)
|
|
19
19
|
- `SETTLD_TENANT_ID`
|
|
20
|
-
-
|
|
20
|
+
- one of:
|
|
21
|
+
- `SETTLD_API_KEY` (`keyId.secret`), or
|
|
22
|
+
- `SETTLD_BOOTSTRAP_API_KEY` (onboarding bootstrap key that mints `SETTLD_API_KEY` during setup)
|
|
21
23
|
- Node.js 20+
|
|
22
24
|
|
|
23
25
|
Recommended non-interactive pattern:
|
|
@@ -35,6 +37,20 @@ settld setup --non-interactive \
|
|
|
35
37
|
--out-env ./.tmp/settld-openclaw.env
|
|
36
38
|
```
|
|
37
39
|
|
|
40
|
+
If you want setup to generate the tenant API key for you:
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
settld setup --non-interactive \
|
|
44
|
+
--host openclaw \
|
|
45
|
+
--base-url https://api.settld.work \
|
|
46
|
+
--tenant-id tenant_default \
|
|
47
|
+
--bootstrap-api-key 'ml_admin_xxx' \
|
|
48
|
+
--wallet-mode managed \
|
|
49
|
+
--wallet-bootstrap remote \
|
|
50
|
+
--profile-id engineering-spend \
|
|
51
|
+
--smoke
|
|
52
|
+
```
|
|
53
|
+
|
|
38
54
|
If you want validation only (no config writes):
|
|
39
55
|
|
|
40
56
|
```bash
|
|
@@ -153,7 +169,60 @@ Then activate host-side:
|
|
|
153
169
|
- `cursor`: restart Cursor.
|
|
154
170
|
- `openclaw`: run `openclaw doctor`, ensure OpenClaw onboarding is complete (`openclaw onboard --install-daemon`), then run `openclaw tui`.
|
|
155
171
|
|
|
156
|
-
## 5)
|
|
172
|
+
## 5) Fund and verify wallet state
|
|
173
|
+
|
|
174
|
+
Check wallet assignment after setup:
|
|
175
|
+
|
|
176
|
+
```bash
|
|
177
|
+
settld wallet status
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
Funding paths:
|
|
181
|
+
|
|
182
|
+
```bash
|
|
183
|
+
# Guided selector (recommended)
|
|
184
|
+
settld wallet fund --open
|
|
185
|
+
|
|
186
|
+
# Hosted flow (card/bank) - provider-hosted URL, add --open to launch browser
|
|
187
|
+
settld wallet fund --method card --open
|
|
188
|
+
settld wallet fund --method bank --open
|
|
189
|
+
|
|
190
|
+
# Direct transfer path (prints chain + destination address)
|
|
191
|
+
settld wallet fund --method transfer
|
|
192
|
+
|
|
193
|
+
# Sandbox only: request faucet top-up
|
|
194
|
+
settld wallet fund --method faucet
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
Provider-hosted card/bank links are configured on the control-plane backend.
|
|
198
|
+
|
|
199
|
+
Option A (recommended): Coinbase Hosted Onramp:
|
|
200
|
+
|
|
201
|
+
```bash
|
|
202
|
+
export MAGIC_LINK_WALLET_FUND_PROVIDER='coinbase'
|
|
203
|
+
export MAGIC_LINK_COINBASE_API_KEY_VALUE='organizations/<org_id>/apiKeys/<key_id>'
|
|
204
|
+
export MAGIC_LINK_COINBASE_API_SECRET_KEY='-----BEGIN EC PRIVATE KEY-----\n...\n-----END EC PRIVATE KEY-----'
|
|
205
|
+
export MAGIC_LINK_COINBASE_PROJECT_ID='<project_id>'
|
|
206
|
+
export MAGIC_LINK_COINBASE_DESTINATION_NETWORK='base'
|
|
207
|
+
export MAGIC_LINK_COINBASE_ASSET='USDC'
|
|
208
|
+
export MAGIC_LINK_COINBASE_FIAT_CURRENCY='USD'
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
Option B: explicit card/bank URLs:
|
|
212
|
+
|
|
213
|
+
```bash
|
|
214
|
+
# backend env (magic-link service)
|
|
215
|
+
export MAGIC_LINK_WALLET_FUND_CARD_URL='https://pay.example.com/topup?tenant={tenantId}&method=card&address={walletAddress}'
|
|
216
|
+
export MAGIC_LINK_WALLET_FUND_BANK_URL='https://pay.example.com/topup?tenant={tenantId}&method=bank&address={walletAddress}'
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
After funding, wait until spend wallet has balance:
|
|
220
|
+
|
|
221
|
+
```bash
|
|
222
|
+
settld wallet balance --watch --min-usdc 1
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
## 6) How the agent uses Settld after activation
|
|
157
226
|
|
|
158
227
|
After host activation, the agent interacts with Settld through MCP `settld.*` tools.
|
|
159
228
|
|
|
@@ -184,7 +253,7 @@ Verify first receipt from artifacts:
|
|
|
184
253
|
settld x402 receipt verify <artifactDir>/x402-receipt.json --json-out /tmp/settld-first-receipt.json
|
|
185
254
|
```
|
|
186
255
|
|
|
187
|
-
##
|
|
256
|
+
## 7) Host config helper customization
|
|
188
257
|
|
|
189
258
|
Default host configuration logic is in:
|
|
190
259
|
|
|
@@ -198,10 +267,15 @@ settld setup --host-config ./path/to/custom-host-config.mjs
|
|
|
198
267
|
|
|
199
268
|
Your helper should provide resolver/setup exports compatible with `scripts/setup/wizard.mjs`.
|
|
200
269
|
|
|
201
|
-
##
|
|
270
|
+
## 8) Troubleshooting
|
|
202
271
|
|
|
203
272
|
- `BYO wallet mode missing required env keys`
|
|
204
273
|
- Provide all required Circle keys in section 3.
|
|
274
|
+
- `auth required: pass --cookie/--magic-link-api-key or run settld login first`
|
|
275
|
+
- Run `settld login`, then retry `settld wallet status` / `settld wallet fund`.
|
|
276
|
+
- `no hosted funding URL configured for card/bank`
|
|
277
|
+
- set backend Coinbase env (`MAGIC_LINK_WALLET_FUND_PROVIDER=coinbase`, `MAGIC_LINK_COINBASE_API_KEY_VALUE`, `MAGIC_LINK_COINBASE_API_SECRET_KEY`) or set explicit `MAGIC_LINK_WALLET_FUND_CARD_URL` / `MAGIC_LINK_WALLET_FUND_BANK_URL`.
|
|
278
|
+
- pass `--hosted-url` for an ad-hoc override.
|
|
205
279
|
- `host config helper missing`
|
|
206
280
|
- Add `scripts/setup/host-config.mjs` or pass `--host-config`.
|
|
207
281
|
- `SETTLD_API_KEY must be a non-empty string`
|
|
@@ -51,7 +51,45 @@ source ./.tmp/settld.env
|
|
|
51
51
|
|
|
52
52
|
Then restart your host app (Codex/Claude/Cursor/OpenClaw) so it reloads MCP config.
|
|
53
53
|
|
|
54
|
-
## 2)
|
|
54
|
+
## 2) Check wallet and fund it
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
settld wallet status
|
|
58
|
+
settld wallet fund --method transfer
|
|
59
|
+
settld wallet balance --watch --min-usdc 1
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Optional methods:
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
settld wallet fund --open
|
|
66
|
+
settld wallet fund --method card --open
|
|
67
|
+
settld wallet fund --method bank --open
|
|
68
|
+
settld wallet fund --method faucet
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
For card/bank, configure one hosted provider URL strategy on the control-plane backend.
|
|
72
|
+
|
|
73
|
+
Option A (recommended): Coinbase Hosted Onramp:
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
export MAGIC_LINK_WALLET_FUND_PROVIDER='coinbase'
|
|
77
|
+
export MAGIC_LINK_COINBASE_API_KEY_VALUE='organizations/<org_id>/apiKeys/<key_id>'
|
|
78
|
+
export MAGIC_LINK_COINBASE_API_SECRET_KEY='-----BEGIN EC PRIVATE KEY-----\n...\n-----END EC PRIVATE KEY-----'
|
|
79
|
+
export MAGIC_LINK_COINBASE_PROJECT_ID='<project_id>'
|
|
80
|
+
export MAGIC_LINK_COINBASE_DESTINATION_NETWORK='base'
|
|
81
|
+
export MAGIC_LINK_COINBASE_ASSET='USDC'
|
|
82
|
+
export MAGIC_LINK_COINBASE_FIAT_CURRENCY='USD'
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
Option B: explicit card/bank hosted templates:
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
export MAGIC_LINK_WALLET_FUND_CARD_URL='https://pay.example.com/topup?tenant={tenantId}&method=card&address={walletAddress}'
|
|
89
|
+
export MAGIC_LINK_WALLET_FUND_BANK_URL='https://pay.example.com/topup?tenant={tenantId}&method=bank&address={walletAddress}'
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
## 3) Verify MCP connectivity
|
|
55
93
|
|
|
56
94
|
```bash
|
|
57
95
|
npm run mcp:probe -- --call settld.about '{}'
|
|
@@ -62,7 +100,7 @@ Expected outcome:
|
|
|
62
100
|
- `settld.about` succeeds
|
|
63
101
|
- host can discover `settld.*` tools
|
|
64
102
|
|
|
65
|
-
##
|
|
103
|
+
## 4) Run first paid call
|
|
66
104
|
|
|
67
105
|
```bash
|
|
68
106
|
npm run demo:mcp-paid-exa
|
|
@@ -75,7 +113,7 @@ Expected output includes:
|
|
|
75
113
|
- `decisionId=...`
|
|
76
114
|
- `settlementReceiptId=...`
|
|
77
115
|
|
|
78
|
-
##
|
|
116
|
+
## 5) Verify first receipt (proof packet)
|
|
79
117
|
|
|
80
118
|
```bash
|
|
81
119
|
jq -c 'first' <artifactDir>/x402-receipts.export.jsonl > /tmp/settld-first-receipt.json
|
|
@@ -84,7 +122,7 @@ settld x402 receipt verify /tmp/settld-first-receipt.json --format json --json-o
|
|
|
84
122
|
|
|
85
123
|
`/tmp/settld-first-receipt.verify.json` is your deterministic verification artifact for audit/compliance.
|
|
86
124
|
|
|
87
|
-
##
|
|
125
|
+
## 6) Optional: policy profile workflows
|
|
88
126
|
|
|
89
127
|
```bash
|
|
90
128
|
settld profile list
|
|
@@ -99,5 +137,10 @@ settld profile simulate ./profiles/engineering-spend.profile.json --format json
|
|
|
99
137
|
- ensure key is present in setup flags or shell env.
|
|
100
138
|
- `BYO wallet mode missing required env keys`
|
|
101
139
|
- provide all required Circle keys in `docs/QUICKSTART_MCP_HOSTS.md`.
|
|
140
|
+
- `auth required: pass --cookie/--magic-link-api-key or run settld login first`
|
|
141
|
+
- run `settld login`, then retry wallet commands.
|
|
142
|
+
- `no hosted funding URL configured for card/bank`
|
|
143
|
+
- set backend Coinbase env (`MAGIC_LINK_WALLET_FUND_PROVIDER=coinbase`, `MAGIC_LINK_COINBASE_API_KEY_VALUE`, `MAGIC_LINK_COINBASE_API_SECRET_KEY`) or set explicit `MAGIC_LINK_WALLET_FUND_CARD_URL` / `MAGIC_LINK_WALLET_FUND_BANK_URL`.
|
|
144
|
+
- pass `--hosted-url` for an ad-hoc override.
|
|
102
145
|
- Host cannot find MCP tools
|
|
103
146
|
- rerun setup, restart host, then rerun `npm run mcp:probe`.
|
|
@@ -53,6 +53,19 @@ npx -y settld@latest setup \
|
|
|
53
53
|
--smoke
|
|
54
54
|
```
|
|
55
55
|
|
|
56
|
+
If you do not have a tenant `sk_*` yet, let setup mint one:
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
npx -y settld@latest setup \
|
|
60
|
+
--non-interactive \
|
|
61
|
+
--host openclaw \
|
|
62
|
+
--base-url https://api.settld.work \
|
|
63
|
+
--tenant-id tenant_default \
|
|
64
|
+
--bootstrap-api-key 'ml_admin_xxx' \
|
|
65
|
+
--wallet-mode managed \
|
|
66
|
+
--wallet-bootstrap remote
|
|
67
|
+
```
|
|
68
|
+
|
|
56
69
|
## 3) Verify OpenClaw + Settld are wired
|
|
57
70
|
|
|
58
71
|
Run:
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# Vercel Monorepo Deploy (Docs + Website)
|
|
2
|
+
|
|
3
|
+
Use **two separate Vercel projects** pointing at the same GitHub repo:
|
|
4
|
+
|
|
5
|
+
1. `settld-docs` (MkDocs)
|
|
6
|
+
2. `settld-site` (Dashboard website)
|
|
7
|
+
|
|
8
|
+
## Project 1: `settld-docs` (MkDocs)
|
|
9
|
+
|
|
10
|
+
- Root Directory: repo root (`.`)
|
|
11
|
+
- Production Branch: `main`
|
|
12
|
+
- Build/Output config comes from `/vercel.json`:
|
|
13
|
+
- `installCommand`: `bash scripts/vercel/install-mkdocs.sh`
|
|
14
|
+
- `buildCommand`: `bash scripts/vercel/build-mkdocs.sh`
|
|
15
|
+
- `ignoreCommand`: `bash scripts/vercel/ignore-mkdocs.sh`
|
|
16
|
+
- `outputDirectory`: `mkdocs/site`
|
|
17
|
+
|
|
18
|
+
Deploy will run when docs-relevant files change (including `mkdocs/docs/**`).
|
|
19
|
+
|
|
20
|
+
## Project 2: `settld-site` (Website)
|
|
21
|
+
|
|
22
|
+
- Root Directory: `dashboard`
|
|
23
|
+
- Production Branch: `main`
|
|
24
|
+
- Build/Output config comes from `/dashboard/vercel.json`:
|
|
25
|
+
- `installCommand`: `npm install`
|
|
26
|
+
- `buildCommand`: `npm run build`
|
|
27
|
+
- `ignoreCommand`: `bash ../scripts/vercel/ignore-dashboard.sh`
|
|
28
|
+
- `outputDirectory`: `dist`
|
|
29
|
+
|
|
30
|
+
Deploy will run when website-relevant files change (`dashboard/**` + deploy scripts/workflows).
|
|
31
|
+
|
|
32
|
+
## Push Flow
|
|
33
|
+
|
|
34
|
+
1. Commit and push changes to `main`.
|
|
35
|
+
2. Verify both Vercel projects are connected to this repo and track `main`.
|
|
36
|
+
3. Check the commit SHA in each Vercel deployment detail page matches the pushed commit.
|
|
37
|
+
|
|
38
|
+
## Quick Troubleshooting
|
|
39
|
+
|
|
40
|
+
- Docs didn’t deploy: confirm changes touched `mkdocs/docs/**` or another path matched by `scripts/vercel/ignore-mkdocs.sh`.
|
|
41
|
+
- Website didn’t deploy: confirm changes touched `dashboard/**` or another path matched by `scripts/vercel/ignore-dashboard.sh`.
|
|
42
|
+
- Wrong commit deployed: confirm Vercel project production branch is `main`, not a feature branch.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "settld",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.2",
|
|
4
4
|
"description": "Settld kernel CLI and local control-plane tooling",
|
|
5
5
|
"private": false,
|
|
6
6
|
"type": "module",
|
|
@@ -136,6 +136,7 @@
|
|
|
136
136
|
},
|
|
137
137
|
"dependencies": {
|
|
138
138
|
"@circle-fin/developer-controlled-wallets": "^10.1.0",
|
|
139
|
+
"@coinbase/cdp-sdk": "^1.44.1",
|
|
139
140
|
"pg": "^8.11.5",
|
|
140
141
|
"snarkjs": "^0.7.6"
|
|
141
142
|
},
|
|
@@ -11,6 +11,10 @@ function randomId(prefix) {
|
|
|
11
11
|
return `${prefix}_${crypto.randomBytes(6).toString("hex")}`;
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
+
function buildScopedOpsToken(token) {
|
|
15
|
+
return `${String(token ?? "").trim()}:ops_read,ops_write,finance_read,finance_write,audit_read`;
|
|
16
|
+
}
|
|
17
|
+
|
|
14
18
|
function pickPort() {
|
|
15
19
|
return new Promise((resolve, reject) => {
|
|
16
20
|
const server = net.createServer();
|
|
@@ -243,6 +247,7 @@ function stopServer(server) {
|
|
|
243
247
|
async function main() {
|
|
244
248
|
const reportPath = path.resolve(process.cwd(), process.env.MCP_HOST_SMOKE_REPORT_PATH || "artifacts/ops/mcp-host-smoke.json");
|
|
245
249
|
const opsToken = randomId("ops");
|
|
250
|
+
const scopedOpsToken = buildScopedOpsToken(opsToken);
|
|
246
251
|
const magicLinkApiKey = randomId("ml_admin");
|
|
247
252
|
const tenantId = randomId("tenant");
|
|
248
253
|
|
|
@@ -259,6 +264,7 @@ async function main() {
|
|
|
259
264
|
env: {
|
|
260
265
|
PORT: String(apiPort),
|
|
261
266
|
PROXY_BIND_HOST: "127.0.0.1",
|
|
267
|
+
PROXY_OPS_TOKENS: scopedOpsToken,
|
|
262
268
|
PROXY_OPS_TOKEN: opsToken,
|
|
263
269
|
PROXY_AUTOTICK_INTERVAL_MS: "200"
|
|
264
270
|
}
|
|
@@ -141,6 +141,10 @@ function randomId(prefix) {
|
|
|
141
141
|
return `${prefix}_${crypto.randomBytes(6).toString("hex")}`;
|
|
142
142
|
}
|
|
143
143
|
|
|
144
|
+
function buildScopedOpsToken(token) {
|
|
145
|
+
return `${String(token ?? "").trim()}:ops_read,ops_write,finance_read,finance_write,audit_read`;
|
|
146
|
+
}
|
|
147
|
+
|
|
144
148
|
function pickPort() {
|
|
145
149
|
return new Promise((resolve, reject) => {
|
|
146
150
|
const server = net.createServer();
|
|
@@ -239,6 +243,7 @@ function startNodeProc({ name, scriptPath, env }) {
|
|
|
239
243
|
async function startEphemeralApi(env = process.env) {
|
|
240
244
|
const port = await pickPort();
|
|
241
245
|
const opsToken = randomId("ops");
|
|
246
|
+
const scopedOpsToken = buildScopedOpsToken(opsToken);
|
|
242
247
|
const baseUrl = `http://127.0.0.1:${port}`;
|
|
243
248
|
const api = startNodeProc({
|
|
244
249
|
name: "cutover-api",
|
|
@@ -247,6 +252,7 @@ async function startEphemeralApi(env = process.env) {
|
|
|
247
252
|
...env,
|
|
248
253
|
PORT: String(port),
|
|
249
254
|
PROXY_BIND_HOST: "127.0.0.1",
|
|
255
|
+
PROXY_OPS_TOKENS: scopedOpsToken,
|
|
250
256
|
PROXY_OPS_TOKEN: opsToken,
|
|
251
257
|
PROXY_AUTOTICK_INTERVAL_MS: "200"
|
|
252
258
|
}
|
|
@@ -192,6 +192,18 @@ function readEnvString(name, fallback = null) {
|
|
|
192
192
|
return String(raw).trim();
|
|
193
193
|
}
|
|
194
194
|
|
|
195
|
+
function readFirstOpsTokenFromScopedList(raw) {
|
|
196
|
+
const text = String(raw ?? "").trim();
|
|
197
|
+
if (!text) return null;
|
|
198
|
+
const firstEntry = text
|
|
199
|
+
.split(";")
|
|
200
|
+
.map((entry) => String(entry ?? "").trim())
|
|
201
|
+
.find(Boolean);
|
|
202
|
+
if (!firstEntry) return null;
|
|
203
|
+
const token = firstEntry.split(":")[0]?.trim() ?? "";
|
|
204
|
+
return token || null;
|
|
205
|
+
}
|
|
206
|
+
|
|
195
207
|
function assertCircleModeInputs({ mode }) {
|
|
196
208
|
if (mode === "stub") return;
|
|
197
209
|
const required = ["CIRCLE_API_KEY", "CIRCLE_WALLET_ID_SPEND", "CIRCLE_WALLET_ID_ESCROW", "CIRCLE_TOKEN_ID_USDC"];
|
|
@@ -646,7 +658,10 @@ async function main() {
|
|
|
646
658
|
const workload = normalizeWorkload(cli.workload ?? readEnvString("SETTLD_DEMO_WORKLOAD", "exa"));
|
|
647
659
|
const externalReserveRequired = circleMode !== "stub";
|
|
648
660
|
assertCircleModeInputs({ mode: circleMode });
|
|
649
|
-
const
|
|
661
|
+
const inheritedOpsTokenList = readEnvString("PROXY_OPS_TOKENS", null);
|
|
662
|
+
const derivedOpsToken = readFirstOpsTokenFromScopedList(inheritedOpsTokenList);
|
|
663
|
+
const opsToken = String(process.env.SETTLD_DEMO_OPS_TOKEN ?? derivedOpsToken ?? "tok_ops").trim() || "tok_ops";
|
|
664
|
+
const scopedOpsToken = `${opsToken}:ops_read,ops_write,finance_read,finance_write,audit_read`;
|
|
650
665
|
const tenantId = String(process.env.SETTLD_TENANT_ID ?? "tenant_default").trim() || "tenant_default";
|
|
651
666
|
|
|
652
667
|
const workloadConfig = (() => {
|
|
@@ -733,6 +748,8 @@ async function main() {
|
|
|
733
748
|
cmd: "node",
|
|
734
749
|
args: ["src/api/server.js"],
|
|
735
750
|
env: {
|
|
751
|
+
// Pin ops auth for this demo process so inherited deployment env can't cause token mismatch.
|
|
752
|
+
PROXY_OPS_TOKENS: scopedOpsToken,
|
|
736
753
|
PROXY_OPS_TOKEN: opsToken,
|
|
737
754
|
BIND_HOST: "127.0.0.1",
|
|
738
755
|
PORT: String(apiPort),
|