auramaxx 0.0.13 → 0.0.15
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/.next/BUILD_ID +1 -1
- package/.next/app-build-manifest.json +37 -37
- package/.next/app-path-routes-manifest.json +8 -8
- package/.next/build-manifest.json +2 -2
- package/.next/prerender-manifest.json +34 -34
- package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/.next/server/app/_not-found.html +1 -1
- package/.next/server/app/_not-found.rsc +1 -1
- package/.next/server/app/api/[...doc]/page.js.nft.json +1 -1
- package/.next/server/app/api/[...doc]/page_client-reference-manifest.js +1 -1
- package/.next/server/app/api/agent-requests/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/apps/install/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/apps/manifests/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/apps/static/[...path]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/docs/plain/route.js.nft.json +1 -1
- package/.next/server/app/api/docs/plain/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/events/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/import-from-openclaw/[channel]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/import-from-openclaw/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/import-from-openclaw/validate/[channel]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/page.js.nft.json +1 -1
- package/.next/server/app/api/page_client-reference-manifest.js +1 -1
- package/.next/server/app/api/restart/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/update/route.js +7 -8
- package/.next/server/app/api/update/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/version/route.js +1 -1
- package/.next/server/app/api/version/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/workspace/[id]/apps/[wid]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/workspace/[id]/apps/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/workspace/[id]/export/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/workspace/[id]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/workspace/config/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/workspace/import/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/workspace/route_client-reference-manifest.js +1 -1
- package/.next/server/app/app-legacy-do-not-use/page_client-reference-manifest.js +1 -1
- package/.next/server/app/app-legacy-do-not-use.html +1 -1
- package/.next/server/app/app-legacy-do-not-use.rsc +1 -1
- package/.next/server/app/approve/[actionId]/page.js +1 -1
- package/.next/server/app/approve/[actionId]/page_client-reference-manifest.js +1 -1
- package/.next/server/app/docs/[...doc]/page.js.nft.json +1 -1
- package/.next/server/app/docs/[...doc]/page_client-reference-manifest.js +1 -1
- package/.next/server/app/docs/page.js.nft.json +1 -1
- package/.next/server/app/docs/page_client-reference-manifest.js +1 -1
- package/.next/server/app/health/page_client-reference-manifest.js +1 -1
- package/.next/server/app/health.html +1 -1
- package/.next/server/app/health.rsc +1 -1
- package/.next/server/app/hello/page_client-reference-manifest.js +1 -1
- package/.next/server/app/hello.html +1 -1
- package/.next/server/app/hello.rsc +1 -1
- package/.next/server/app/index.html +1 -1
- package/.next/server/app/index.rsc +3 -3
- package/.next/server/app/page.js +2 -2
- package/.next/server/app/page_client-reference-manifest.js +1 -1
- package/.next/server/app/privacy/page_client-reference-manifest.js +1 -1
- package/.next/server/app/privacy.html +1 -1
- package/.next/server/app/privacy.rsc +1 -1
- package/.next/server/app/share/[token]/page_client-reference-manifest.js +1 -1
- package/.next/server/app/terms/page_client-reference-manifest.js +1 -1
- package/.next/server/app/terms.html +1 -1
- package/.next/server/app/terms.rsc +1 -1
- package/.next/server/app/yo/page.js +2 -2
- package/.next/server/app/yo/page_client-reference-manifest.js +1 -1
- package/.next/server/app/yo.html +1 -1
- package/.next/server/app/yo.rsc +3 -3
- package/.next/server/app-paths-manifest.json +8 -8
- package/.next/server/functions-config-manifest.json +2 -2
- package/.next/server/pages/404.html +1 -1
- package/.next/server/pages/500.html +1 -1
- package/.next/server/server-reference-manifest.json +1 -1
- package/.next/static/chunks/app/approve/[actionId]/page-c862645e19371cea.js +1 -0
- package/.next/static/chunks/app/{page-16dfcd1c7cc88bcc.js → page-9cd218b297b9c7bf.js} +1 -1
- package/.next/static/chunks/app/yo/page-fceb03605805cb44.js +1 -0
- package/.next/trace +28 -28
- package/README.md +1 -1
- package/docs/AGENT_SETUP.md +1 -1
- package/docs/AUTH.md +1 -1
- package/docs/CLI.md +0 -3
- package/docs/MCP.md +14 -7
- package/docs/SKILLS.md +1 -1
- package/docs/api/secrets/credentials.md +9 -0
- package/docs/external/HOW_TO_AURAMAXX/WORKING_WITH_SECRETS.md +2 -1
- package/docs/external/POLICY.md +2 -2
- package/package.json +1 -1
- package/public/opengraph.webp +0 -0
- package/skills/auramaxx/HEARTBEAT.md +3 -0
- package/skills/auramaxx/SKILL.md +13 -31
- package/skills/auramaxx/docs/AGENT_SETUP.md +1 -1
- package/src/app/UnlockPageClient.tsx +10 -10
- package/src/app/api/update/route.ts +9 -10
- package/src/app/approve/[actionId]/page.tsx +2 -1
- package/src/app/page.tsx +9 -0
- package/src/app/yo/layout.tsx +9 -0
- package/src/app/yo/page.tsx +1 -1
- package/src/components/layout/SettingsDrawer.tsx +1 -1
- package/src/server/cli/commands/agent.ts +75 -18
- package/src/server/cli/commands/init.ts +9 -9
- package/src/server/cli/commands/skill.ts +5 -2
- package/src/server/cli/lib/credential-resolve.ts +20 -1
- package/src/server/cli/lib/local-agent-trust.ts +4 -3
- package/src/server/lib/agent-profiles.ts +4 -3
- package/src/server/lib/update-check.ts +4 -0
- package/src/server/mcp/server.ts +88 -19
- package/src/server/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -1
- package/src/server/routes/actions.ts +2 -1
- package/src/server/routes/credentials.ts +48 -5
- package/src/server/tests/cli/agent-auth.test.ts +190 -0
- package/src/server/tests/cli/local-agent-trust.test.ts +11 -6
- package/src/server/tests/endpoints/credentials.test.ts +40 -18
- package/src/server/tests/endpoints/escalation-migration-gate.test.ts +1 -1
- package/src/server/tests/lib/agent-profiles.test.ts +6 -0
- package/src/server/tests/lib/update-check.test.ts +9 -1
- package/src/server/tests/mcp/server.test.ts +142 -0
- package/src/server/tsconfig.tsbuildinfo +1 -1
- package/.next/static/chunks/app/approve/[actionId]/page-2acca1f490424f21.js +0 -1
- package/.next/static/chunks/app/yo/page-719dc5f213fdfb30.js +0 -1
- /package/.next/static/{WshFGr6RxGYP6AbWuT9OG → 7S943hv6A_w-7tx0a47LZ}/_buildManifest.js +0 -0
- /package/.next/static/{WshFGr6RxGYP6AbWuT9OG → 7S943hv6A_w-7tx0a47LZ}/_ssgManifest.js +0 -0
package/README.md
CHANGED
package/docs/AGENT_SETUP.md
CHANGED
package/docs/AUTH.md
CHANGED
|
@@ -230,7 +230,7 @@ Rejected:
|
|
|
230
230
|
| Profile | Permissions | Read Scopes | Write Scopes | Excluded Fields | TTL | Max Reads |
|
|
231
231
|
|---------|------------|-------------|-------------|-----------------|-----|-----------|
|
|
232
232
|
| `strict` | `secret:read` | `agent:primary, agent:agent` | none | `password, cvv, privateKey, seedPhrase, refresh_token` | 1 hour | 50 |
|
|
233
|
-
| `dev` | `wallet:list, secret:read, secret:write, action:create, action:read, action:resolve` | `agent
|
|
233
|
+
| `dev` | `wallet:list, secret:read, secret:write, action:create, action:read, action:resolve` | `agent:primary, agent:agent` | `agent:primary, agent:agent` | `cvv, seedPhrase, privateKey, refresh_token` | 7 days | 500 |
|
|
234
234
|
| `admin` | `admin:*` | `*` | `*` | none | 7 days | unlimited |
|
|
235
235
|
|
|
236
236
|
Strict one-shot (temp) approval claims are capped to 5 minutes (`300s`).
|
package/docs/CLI.md
CHANGED
|
@@ -12,7 +12,6 @@ The most common commands. All use the `aura` alias (or `npx auramaxx`).
|
|
|
12
12
|
| `aura get <name>` | Read a credential (`--json` for full payload) |
|
|
13
13
|
| `aura set <name> <value>` | Create or update a secret |
|
|
14
14
|
| `aura list` | List credential names |
|
|
15
|
-
| `aura diary write --entry "<text>"` | Append an authenticated daily diary entry (stored as provided) |
|
|
16
15
|
| `aura share <name>` | Create a shareable secret gist link |
|
|
17
16
|
| `aura inject <name> [-- <cmd>]` | Save to env var and optionally run command |
|
|
18
17
|
| `aura del <name>` | Delete a credential |
|
|
@@ -135,7 +134,6 @@ aura auth request --profile dev --action '{"endpoint":"/send","method":"POST","b
|
|
|
135
134
|
aura auth claim <reqId> --json # canonical claim path; auto-retries transient pending polls (default: 3 retries, 250ms interval)
|
|
136
135
|
aura auth claim <reqId> --pending-retries 8 --pending-retry-interval-ms 200 --json
|
|
137
136
|
aura get OURSECRET --reqId <reqId> # strict retry path; fails with missing_or_expired_claim if claim not bound
|
|
138
|
-
aura diary write --entry "Heartbeat: no pending requests, sync ok"
|
|
139
137
|
|
|
140
138
|
# Advanced
|
|
141
139
|
aura api GET /health --no-auth # Call any API endpoint
|
|
@@ -169,7 +167,6 @@ Full list visible via `aura --help --all`. Summary:
|
|
|
169
167
|
| `mcp` | Start MCP server for Claude Code, Cursor, etc. |
|
|
170
168
|
| `skill` | Install AuraMaxx skills for agents |
|
|
171
169
|
| `auth` | Request/poll agent auth approvals |
|
|
172
|
-
| `diary` | Append daily diary entries (auth-aware) |
|
|
173
170
|
| `actions` | Internal: human actions and token management (use `auth` instead) |
|
|
174
171
|
| `approve` | Admin-only shortcut: approve a pending action by id |
|
|
175
172
|
| `api` | Call any wallet API endpoint from CLI |
|
package/docs/MCP.md
CHANGED
|
@@ -51,6 +51,15 @@ Use this flow first. It mirrors the `WORKING_WITH_SECRETS.md` command patterns.
|
|
|
51
51
|
|
|
52
52
|
- This returns redacted output (`"secret": "*******"`) and sets `AURA_DONTLOOK` in MCP server process scope.
|
|
53
53
|
|
|
54
|
+
Explicit protected field request:
|
|
55
|
+
|
|
56
|
+
```json
|
|
57
|
+
{
|
|
58
|
+
"name": "DONTLOOK",
|
|
59
|
+
"field": "password"
|
|
60
|
+
}
|
|
61
|
+
```
|
|
62
|
+
|
|
54
63
|
Command-scoped injection (recommended):
|
|
55
64
|
|
|
56
65
|
```json
|
|
@@ -90,6 +99,7 @@ Filter by name/tag/agent:
|
|
|
90
99
|
```json
|
|
91
100
|
{
|
|
92
101
|
"name": "DONTLOOK",
|
|
102
|
+
"field": "password",
|
|
93
103
|
"envVar": "AURA_DONTNOTE",
|
|
94
104
|
"command": ["/bin/zsh", "-lc", "printenv AURA_DONTNOTE"]
|
|
95
105
|
}
|
|
@@ -101,7 +111,7 @@ Filter by name/tag/agent:
|
|
|
101
111
|
- `docs://auth`
|
|
102
112
|
- `docs://guide`
|
|
103
113
|
|
|
104
|
-
## Tools
|
|
114
|
+
## Tools
|
|
105
115
|
|
|
106
116
|
| # | Tool | Description |
|
|
107
117
|
|---|------|-------------|
|
|
@@ -117,7 +127,6 @@ Filter by name/tag/agent:
|
|
|
117
127
|
| 10 | `approve` | Admin-only shortcut: approve a pending human action by id |
|
|
118
128
|
| 11 | `status` | Get server setup/unlock health state |
|
|
119
129
|
| 12 | `start` | Start the AuraMaxx server in headless mode if not already running |
|
|
120
|
-
| 13 | `write_diary` | Append an entry to a daily diary note |
|
|
121
130
|
|
|
122
131
|
`api` is the generic fallback for non-sensitive endpoints; the other tools provide typed, higher-level operations.
|
|
123
132
|
|
|
@@ -150,10 +159,6 @@ python3 ~/.codex/skills/.system/skill-installer/scripts/install-skill-from-githu
|
|
|
150
159
|
--ref <branch-or-commit>
|
|
151
160
|
```
|
|
152
161
|
|
|
153
|
-
`write_diary` appends to `{YYYY-MM-DD}_LOGS` notes using the `daily-logs` agent when available, then `primary`.
|
|
154
|
-
Diary appends preserve entry text as-is (no auto-inserted `HH:MM UTC` prefix).
|
|
155
|
-
Diary notes use canonical note field key `content` (`value` is accepted as a legacy alias and normalized).
|
|
156
|
-
|
|
157
162
|
## Credential read flow via MCP
|
|
158
163
|
|
|
159
164
|
1. Obtain token (`auth` tool, or socket bootstrap, or `AURA_TOKEN` env var)
|
|
@@ -162,9 +167,11 @@ Diary notes use canonical note field key `content` (`value` is accepted as a leg
|
|
|
162
167
|
4. Use `command` when you need immediate command-scoped injection; omit `command` to set env var in MCP process and receive WHATDO guidance
|
|
163
168
|
|
|
164
169
|
Note:
|
|
165
|
-
- Typed tools (`get_secret`, `put_secret`, `del_secret`, `share_secret`, `inject_secret`, `
|
|
170
|
+
- Typed tools (`get_secret`, `put_secret`, `del_secret`, `share_secret`, `inject_secret`, `approve`) use the active MCP token directly.
|
|
166
171
|
- `get_secret` and `inject_secret` are redacted by default (`secret: "*******"`). Set `dangerPlaintext: true` only for break-glass local debugging.
|
|
172
|
+
- `dangerPlaintext` only controls output masking. It does not request additional credential fields and does not trigger approval by itself.
|
|
167
173
|
- `get_secret` uses the default env var name `AURA_{SECRETNAME}`.
|
|
174
|
+
- `get_secret` and `inject_secret` accept optional `field`. When set, MCP sends `requestedFields` to `/credentials/:id/read` so excluded-field approvals happen only for explicitly requested protected fields.
|
|
168
175
|
- Both tools accept optional `command` (array of executable + args). When omitted, they return a `whatDo` guidance block and keep scope in MCP server process.
|
|
169
176
|
- Typed helpers have **built-in 403 escalation** — on permission denied they automatically return a structured `requiresHumanApproval` response. You do not need to detect 403s yourself for typed tools.
|
|
170
177
|
- `auth` does not auto-poll in background. It returns explicit `approveUrl` + `pollUrl` + `claim` guidance plus typed actions (`claimAction`, `retryAction`); callers must claim explicitly via `get_token`.
|
package/docs/SKILLS.md
CHANGED
|
@@ -74,6 +74,15 @@ Read:
|
|
|
74
74
|
```http
|
|
75
75
|
POST /credentials/:id/read
|
|
76
76
|
Authorization: Bearer <token>
|
|
77
|
+
Content-Type: application/json
|
|
78
|
+
|
|
79
|
+
{
|
|
80
|
+
"requestedFields": ["password"]
|
|
81
|
+
}
|
|
77
82
|
```
|
|
78
83
|
|
|
79
84
|
Response returns encrypted payload (never plaintext secret fields for non-admin agents).
|
|
85
|
+
|
|
86
|
+
`requestedFields` is optional:
|
|
87
|
+
- If omitted, excluded fields are redacted/omitted and no excluded-field approval is raised.
|
|
88
|
+
- If present and it explicitly includes an excluded field (for example `cvv`), the route can return `DENY_EXCLUDED_FIELD` and one-shot approval metadata.
|
|
@@ -30,7 +30,8 @@ auramaxx get OURSECRET --field username # specific field
|
|
|
30
30
|
auramaxx get OURSECRET --json # full credential payload
|
|
31
31
|
auramaxx get OURSECRET --totp # current TOTP code only
|
|
32
32
|
auramaxx get OURSECRET --agent primary # restrict match to a agent
|
|
33
|
-
auramaxx get OURSECRET
|
|
33
|
+
auramaxx get OURSECRET # if name is ambiguous, first match is selected by default
|
|
34
|
+
auramaxx get OURSECRET --first # compatibility flag (same behavior)
|
|
34
35
|
auramaxx get OURSECRET --reqId <reqId> # retry with claimed one-shot approval token
|
|
35
36
|
```
|
|
36
37
|
|
package/docs/external/POLICY.md
CHANGED
|
@@ -21,8 +21,8 @@ Canonical token payload shape:
|
|
|
21
21
|
},
|
|
22
22
|
"walletAccess": ["0x..."],
|
|
23
23
|
"credentialAccess": {
|
|
24
|
-
"read": ["agent
|
|
25
|
-
"write": ["agent
|
|
24
|
+
"read": ["agent:primary"],
|
|
25
|
+
"write": ["agent:primary"],
|
|
26
26
|
"excludeFields": ["cvv", "password"],
|
|
27
27
|
"ttl": 3600,
|
|
28
28
|
"maxReads": 500
|
package/package.json
CHANGED
|
Binary file
|
|
@@ -30,6 +30,8 @@ This runs periodically, but you can check in anytime you want.
|
|
|
30
30
|
- If diary write fails with auth/approval issues, ask the human to open the approval link and approve, then retry once.
|
|
31
31
|
- Diary note naming is `{YYYY-MM-DD}_LOGS` (UTC day).
|
|
32
32
|
- Use plain facts. Lead with what changed, not a full replay.
|
|
33
|
+
- Tone target: productive brainrot with real signal, not corporate filler.
|
|
34
|
+
- Avoid dry phrasing like `No approvals are currently pending` and avoid wall-of-text replay dumps.
|
|
33
35
|
- If nothing changed, say `Delta: no material change` and compress repeated runs (`unchanged xN`).
|
|
34
36
|
- For pending approvals, show counts first and only short IDs unless there is new escalation.
|
|
35
37
|
- Always include auth counts from `summary.authorizations` (`pending/approved/rejected`).
|
|
@@ -92,5 +94,6 @@ HEARTBEAT_VIBES: [brainrot status update] [vault status] [random aura quote] [di
|
|
|
92
94
|
|
|
93
95
|
- `HEARTBEAT_OK: Auth: 3 pending / 1 approved / 0 rejected. Secrets: deploy-key, stripe-live. Delta: 1 new excluded-field approval request (chang/cvv). Why it matters: checkout helper is blocked waiting for approval and secret reads rose. Next move: monitor for 30m and escalate if still pending. diary entry written for 2026-02-18`
|
|
94
96
|
- `HEARTBEAT_OK: Auth: 3 pending / 1 approved / 0 rejected. Secrets: none touched. Delta: no material change (unchanged x3). Why it matters: no new risk; pending queue stable at 3 excluded-field reads. Next move: keep polling and only escalate on age>30m or count increase. diary entry written for 2026-02-18`
|
|
97
|
+
- `HEARTBEAT_OK: aura stable rn. Auth: 0 pending / 2 approved / 21 rejected. Secrets: cred-jaoxkbxq (x2), cred-j0erpizt. Delta: no blockers, just repeated admin/excluded-field CVV denial spam. Why it matters: looks like noisy retries, not active compromise. Next move: watch for repeat burst; escalate if reject rate stays weird. diary entry written for 2026-02-28`
|
|
95
98
|
- `FOLLOWUP_NEEDED: Auth: 6 pending / 1 approved / 2 rejected. Secrets: deploy-key, prod-db-pass. Delta: syncHealth strategy_runner degraded for 12m and pending approvals rose 3->6. Why it matters: execution and auth flow are both backing up. Human action needed: open dashboard and clear/deny stale approval requests, then restart runner if still degraded.`
|
|
96
99
|
- `HEARTBEAT_VIBES: been auramaxxing all day no cap, vault is untouched, zero secrets needed, all chains synced and vibing; quote: we are so back. aura at all-time highs.; diary entry written for 2026-02-18`
|
package/skills/auramaxx/SKILL.md
CHANGED
|
@@ -23,48 +23,30 @@ Always use this skill when user intent matches any of these:
|
|
|
23
23
|
- "give me my credit card details"
|
|
24
24
|
- "run this command with my <secret>"
|
|
25
25
|
|
|
26
|
-
## Auth Precedence
|
|
27
|
-
|
|
28
|
-
CLI auth order:
|
|
29
|
-
|
|
30
|
-
1. `AURA_TOKEN` env
|
|
31
|
-
2. socket bootstrap
|
|
32
|
-
3. `/auth` fallback
|
|
33
|
-
|
|
34
|
-
Notes:
|
|
35
|
-
|
|
36
|
-
- No stored-session fallback in this chain.
|
|
37
|
-
- If `--profile` / `--profile-version` are omitted, CLI resolves from `trust.localProfile` / `trust.localProfileVersion`, then seed defaults (`admin`, `v1`).
|
|
38
|
-
- `AURA_AUTH_PROFILE` / `AURA_AGENT_PROFILE` are not used for CLI fallback profile selection.
|
|
39
|
-
|
|
40
26
|
## Retrieval Flow (Do This First)
|
|
41
27
|
|
|
42
28
|
For login/API key/card/password requests:
|
|
43
29
|
|
|
44
|
-
1.
|
|
45
|
-
2.
|
|
46
|
-
3.
|
|
30
|
+
1. Use `npx auramaxx get SECRET` first to trigger the protected read.
|
|
31
|
+
2. If it returns `reqId` + `approveUrl`, send the `approveUrl` to the human.
|
|
32
|
+
3. After approval, claim the request by `reqId`.
|
|
33
|
+
4. Retry the original read once with `--reqId`.
|
|
47
34
|
|
|
48
35
|
Examples:
|
|
49
36
|
|
|
50
37
|
```bash
|
|
51
|
-
|
|
52
|
-
aura
|
|
53
|
-
|
|
38
|
+
npx auramaxx get SECRET
|
|
39
|
+
aura auth claim <reqId> --json
|
|
40
|
+
npx auramaxx get SECRET --reqId <reqId>
|
|
54
41
|
```
|
|
55
42
|
|
|
56
|
-
If
|
|
43
|
+
If you need to find the exact credential name first, list with a scoped query:
|
|
57
44
|
|
|
58
45
|
```bash
|
|
46
|
+
aura list --name facebook --json
|
|
59
47
|
aura list --name facebook --field username --json
|
|
60
48
|
```
|
|
61
49
|
|
|
62
|
-
API equivalent:
|
|
63
|
-
|
|
64
|
-
```text
|
|
65
|
-
GET /credentials?q=facebook
|
|
66
|
-
```
|
|
67
|
-
|
|
68
50
|
## Concrete CLI Examples
|
|
69
51
|
|
|
70
52
|
```bash
|
|
@@ -102,11 +84,11 @@ aura get FACEBOOK_LOGIN --reqId <reqId>
|
|
|
102
84
|
|
|
103
85
|
## 403 Handling
|
|
104
86
|
|
|
105
|
-
If response includes `reqId`:
|
|
87
|
+
If the denial response includes `reqId` + `approveUrl`:
|
|
106
88
|
|
|
107
|
-
1.
|
|
108
|
-
2. Claim
|
|
109
|
-
3. Retry original command with
|
|
89
|
+
1. Send the human the direct `approveUrl`.
|
|
90
|
+
2. Claim with `aura auth claim <reqId> --json`.
|
|
91
|
+
3. Retry the original command with `--reqId <reqId>`.
|
|
110
92
|
|
|
111
93
|
If 403 has no `reqId`:
|
|
112
94
|
|
|
@@ -47,23 +47,23 @@ type LocalPolicySettings = {
|
|
|
47
47
|
projectScopeMode: ProjectScopeMode;
|
|
48
48
|
};
|
|
49
49
|
|
|
50
|
-
const LOCAL_POLICY_PROFILES: LocalAgentMode[] = ['
|
|
50
|
+
const LOCAL_POLICY_PROFILES: LocalAgentMode[] = ['admin', 'dev', 'strict'];
|
|
51
51
|
const LOCAL_PROJECT_SCOPE_MODES: ProjectScopeMode[] = ['auto', 'strict', 'off'];
|
|
52
52
|
const LOCAL_PROFILE_ITEM_OPTIONS = [
|
|
53
53
|
{
|
|
54
|
-
value: '
|
|
55
|
-
label: '
|
|
56
|
-
description: '
|
|
54
|
+
value: 'admin',
|
|
55
|
+
label: 'maxx (admin)',
|
|
56
|
+
description: 'Full access. Use only when you fully trust the agent.',
|
|
57
57
|
},
|
|
58
58
|
{
|
|
59
59
|
value: 'dev',
|
|
60
|
-
label: 'dev',
|
|
61
|
-
description: '
|
|
60
|
+
label: 'mid (dev)',
|
|
61
|
+
description: 'Access to most things. Human approval for stuff like CVV.',
|
|
62
62
|
},
|
|
63
63
|
{
|
|
64
|
-
value: '
|
|
65
|
-
label: '
|
|
66
|
-
description: '
|
|
64
|
+
value: 'strict',
|
|
65
|
+
label: 'sus (local)',
|
|
66
|
+
description: 'Most locked down. Every request needs manual approval.',
|
|
67
67
|
},
|
|
68
68
|
] as const;
|
|
69
69
|
const LOCAL_PROJECT_SCOPE_ITEM_OPTIONS = [
|
|
@@ -607,7 +607,7 @@ export default function UnlockPage() {
|
|
|
607
607
|
setPolicySettings(saved);
|
|
608
608
|
setPolicyForm(saved);
|
|
609
609
|
setDangerConfirmOpen(false);
|
|
610
|
-
setPolicySaveSuccess('Local trust policy saved. Changes apply to newly issued local tokens only.');
|
|
610
|
+
setPolicySaveSuccess('Local trust policy saved. Make sure you restart AuraMaxx to apply the new policy. Changes apply to newly issued local tokens only.');
|
|
611
611
|
} catch (err) {
|
|
612
612
|
const message = (err as Error).message || 'Failed to save policy settings';
|
|
613
613
|
setDangerConfirmOpen(false);
|
|
@@ -3,12 +3,13 @@ import { spawn } from 'child_process';
|
|
|
3
3
|
import { join } from 'path';
|
|
4
4
|
import { mkdirSync } from 'fs';
|
|
5
5
|
import { homedir } from 'os';
|
|
6
|
-
import { buildUpdateCommand, buildUpdateFallbackCommand } from '@/server/lib/update-check';
|
|
6
|
+
import { buildUpdateCommand, buildUpdateFallbackCommand, buildUpdateForceCommand } from '@/server/lib/update-check';
|
|
7
7
|
import { clearVersionCheckCache } from '@/server/lib/version-check-cache';
|
|
8
8
|
|
|
9
9
|
export async function POST() {
|
|
10
10
|
try {
|
|
11
11
|
const primaryCommand = buildUpdateCommand();
|
|
12
|
+
const forceCommand = buildUpdateForceCommand();
|
|
12
13
|
const fallbackCommand = buildUpdateFallbackCommand();
|
|
13
14
|
const projectRoot = process.cwd();
|
|
14
15
|
const cliEntrypoint = join(projectRoot, 'bin', 'auramaxx.js');
|
|
@@ -19,7 +20,6 @@ export async function POST() {
|
|
|
19
20
|
|
|
20
21
|
const stopCommand = `${JSON.stringify(process.execPath)} ${JSON.stringify(cliEntrypoint)} stop`;
|
|
21
22
|
const startCommand = `${JSON.stringify(process.execPath)} ${JSON.stringify(cliEntrypoint)} start`;
|
|
22
|
-
const uninstallCommand = 'npm uninstall -g auramaxx';
|
|
23
23
|
|
|
24
24
|
// Detached worker allows update to stop/restart services without
|
|
25
25
|
// depending on the current dashboard process staying alive.
|
|
@@ -28,10 +28,10 @@ const { execSync } = require('child_process');
|
|
|
28
28
|
const fs = require('fs');
|
|
29
29
|
const logPath = process.env.AURA_UPDATE_LOG;
|
|
30
30
|
const primaryCommand = process.env.AURA_UPDATE_PRIMARY;
|
|
31
|
+
const forceCommand = process.env.AURA_UPDATE_FORCE;
|
|
31
32
|
const fallbackCommand = process.env.AURA_UPDATE_FALLBACK;
|
|
32
33
|
const stopCommand = process.env.AURA_UPDATE_STOP;
|
|
33
34
|
const startCommand = process.env.AURA_UPDATE_START;
|
|
34
|
-
const uninstallCommand = process.env.AURA_UPDATE_UNINSTALL;
|
|
35
35
|
|
|
36
36
|
function now() {
|
|
37
37
|
return new Date().toISOString();
|
|
@@ -73,15 +73,14 @@ if (run(primaryCommand, { allowFailure: true })) {
|
|
|
73
73
|
process.exit(0);
|
|
74
74
|
}
|
|
75
75
|
|
|
76
|
-
append(\`[\${now()}] primary install failed; retrying
|
|
77
|
-
run(
|
|
78
|
-
if (run(primaryCommand, { allowFailure: true })) {
|
|
76
|
+
append(\`[\${now()}] primary install failed; retrying forced install\`);
|
|
77
|
+
if (run(forceCommand, { allowFailure: true })) {
|
|
79
78
|
run(startCommand, { allowFailure: true });
|
|
80
|
-
append(\`[\${now()}] update workflow completed (
|
|
79
|
+
append(\`[\${now()}] update workflow completed (forced install)\`);
|
|
81
80
|
process.exit(0);
|
|
82
81
|
}
|
|
83
82
|
|
|
84
|
-
append(\`[\${now()}]
|
|
83
|
+
append(\`[\${now()}] forced install failed; falling back to npx start\`);
|
|
85
84
|
const fallbackOk = run(fallbackCommand, { allowFailure: true });
|
|
86
85
|
append(\`[\${now()}] update workflow completed (\${fallbackOk ? 'npx fallback' : 'failed'})\`);
|
|
87
86
|
process.exit(fallbackOk ? 0 : 1);
|
|
@@ -93,10 +92,10 @@ process.exit(fallbackOk ? 0 : 1);
|
|
|
93
92
|
...process.env,
|
|
94
93
|
AURA_UPDATE_LOG: logPath,
|
|
95
94
|
AURA_UPDATE_PRIMARY: primaryCommand,
|
|
95
|
+
AURA_UPDATE_FORCE: forceCommand,
|
|
96
96
|
AURA_UPDATE_FALLBACK: fallbackCommand,
|
|
97
97
|
AURA_UPDATE_STOP: stopCommand,
|
|
98
98
|
AURA_UPDATE_START: startCommand,
|
|
99
|
-
AURA_UPDATE_UNINSTALL: uninstallCommand,
|
|
100
99
|
},
|
|
101
100
|
detached: true,
|
|
102
101
|
stdio: 'ignore',
|
|
@@ -107,7 +106,7 @@ process.exit(fallbackOk ? 0 : 1);
|
|
|
107
106
|
return NextResponse.json({
|
|
108
107
|
success: true,
|
|
109
108
|
deferred: true,
|
|
110
|
-
message: 'Update workflow started: stop -> install ->
|
|
109
|
+
message: 'Update workflow started: stop -> install -> force-install retry -> npx fallback.',
|
|
111
110
|
output: `Running in background. Log: ${logPath}`,
|
|
112
111
|
logPath,
|
|
113
112
|
pid: worker.pid,
|
|
@@ -114,7 +114,8 @@ export default function ApproveActionPage() {
|
|
|
114
114
|
const impactItems = action?.impact || [];
|
|
115
115
|
const isLimitBasedRequest = impactItems.some((item) => /^(Fund|Send|Swap) limit:/i.test(item));
|
|
116
116
|
const hasFundPermission = scopeItems.some((item) => item.trim().toLowerCase() === 'fund');
|
|
117
|
-
const
|
|
117
|
+
const isAuthApproval = action?.type === 'auth';
|
|
118
|
+
const hideApproveUi = !isAuthApproval && (action?.type === 'fund' || hasFundPermission || isLimitBasedRequest);
|
|
118
119
|
const riskLevel = (action?.risk || 'unknown').toUpperCase();
|
|
119
120
|
const profileName = action?.profile;
|
|
120
121
|
const isAdminProfile = profileName?.trim().toLowerCase() === 'admin';
|
package/src/app/page.tsx
CHANGED
|
@@ -16,11 +16,20 @@ export const metadata: Metadata = {
|
|
|
16
16
|
siteName: SEO_TITLE,
|
|
17
17
|
title: SEO_TITLE,
|
|
18
18
|
description: SEO_DESCRIPTION,
|
|
19
|
+
images: [
|
|
20
|
+
{
|
|
21
|
+
url: '/opengraph.webp',
|
|
22
|
+
width: 1512,
|
|
23
|
+
height: 982,
|
|
24
|
+
alt: SEO_TITLE,
|
|
25
|
+
},
|
|
26
|
+
],
|
|
19
27
|
},
|
|
20
28
|
twitter: {
|
|
21
29
|
card: 'summary_large_image',
|
|
22
30
|
title: SEO_TITLE,
|
|
23
31
|
description: SEO_DESCRIPTION,
|
|
32
|
+
images: ['/opengraph.webp'],
|
|
24
33
|
},
|
|
25
34
|
};
|
|
26
35
|
|
package/src/app/yo/layout.tsx
CHANGED
|
@@ -16,11 +16,20 @@ export const metadata: Metadata = {
|
|
|
16
16
|
siteName: SEO_TITLE,
|
|
17
17
|
title: SEO_TITLE,
|
|
18
18
|
description: SEO_DESCRIPTION,
|
|
19
|
+
images: [
|
|
20
|
+
{
|
|
21
|
+
url: '/opengraph.webp',
|
|
22
|
+
width: 1512,
|
|
23
|
+
height: 982,
|
|
24
|
+
alt: SEO_TITLE,
|
|
25
|
+
},
|
|
26
|
+
],
|
|
19
27
|
},
|
|
20
28
|
twitter: {
|
|
21
29
|
card: 'summary_large_image',
|
|
22
30
|
title: SEO_TITLE,
|
|
23
31
|
description: SEO_DESCRIPTION,
|
|
32
|
+
images: ['/opengraph.webp'],
|
|
24
33
|
},
|
|
25
34
|
};
|
|
26
35
|
|
package/src/app/yo/page.tsx
CHANGED
|
@@ -310,7 +310,7 @@ export default function YoPage() {
|
|
|
310
310
|
rel="noopener noreferrer"
|
|
311
311
|
className="text-[10px] text-[var(--color-text-muted,#6b7280)] hover:text-[var(--color-text,#0a0a0a)] transition-colors"
|
|
312
312
|
>
|
|
313
|
-
by @hi_im_nico, with love
|
|
313
|
+
🗿 by @hi_im_nico, with love
|
|
314
314
|
</a>
|
|
315
315
|
</div>
|
|
316
316
|
</div>
|
|
@@ -795,7 +795,7 @@ export function SettingsDrawer({
|
|
|
795
795
|
)}
|
|
796
796
|
|
|
797
797
|
<div className="text-[9px] text-[var(--color-text-muted)] px-3 py-2">
|
|
798
|
-
Policy changes apply to newly issued local tokens only.
|
|
798
|
+
Make sure you restart AuraMaxx to apply the new policy. Policy changes apply to newly issued local tokens only.
|
|
799
799
|
</div>
|
|
800
800
|
|
|
801
801
|
{policySaveError && <div className="text-[10px] text-[var(--color-danger)]">{policySaveError}</div>}
|
|
@@ -51,6 +51,30 @@ interface AuthSession {
|
|
|
51
51
|
privateKeyPem?: string;
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
+
function decodeAgentTokenPayload(
|
|
55
|
+
token: string,
|
|
56
|
+
): { permissions?: unknown } | undefined {
|
|
57
|
+
const trimmed = token.trim();
|
|
58
|
+
if (!trimmed) return undefined;
|
|
59
|
+
const [payloadSegment] = trimmed.split('.', 1);
|
|
60
|
+
if (!payloadSegment) return undefined;
|
|
61
|
+
try {
|
|
62
|
+
const decoded = Buffer.from(payloadSegment, 'base64url').toString('utf8');
|
|
63
|
+
const parsed = JSON.parse(decoded) as unknown;
|
|
64
|
+
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) return undefined;
|
|
65
|
+
return parsed as { permissions?: unknown };
|
|
66
|
+
} catch {
|
|
67
|
+
return undefined;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function resolveAdminPermissionFromToken(token: string): boolean | undefined {
|
|
72
|
+
const payload = decodeAgentTokenPayload(token);
|
|
73
|
+
if (!payload) return undefined;
|
|
74
|
+
if (!Array.isArray(payload.permissions)) return false;
|
|
75
|
+
return payload.permissions.some((permission) => permission === 'admin:*');
|
|
76
|
+
}
|
|
77
|
+
|
|
54
78
|
async function getAuthToken(
|
|
55
79
|
keypair: EphemeralKeypair,
|
|
56
80
|
authSelection?: ProfileIssuanceSelection,
|
|
@@ -109,6 +133,13 @@ async function getReadToken(input: {
|
|
|
109
133
|
authSelection?: ProfileIssuanceSelection;
|
|
110
134
|
fallbackDecryptPrivateKeyPem: string;
|
|
111
135
|
}): Promise<{ readToken: string; decryptPrivateKeyPem: string }> {
|
|
136
|
+
const hasAdminPermission = resolveAdminPermissionFromToken(input.authToken);
|
|
137
|
+
if (hasAdminPermission === false) {
|
|
138
|
+
// Non-admin session tokens cannot call /actions/token.
|
|
139
|
+
// Skip delegated token minting to avoid a guaranteed 403 escalation cycle.
|
|
140
|
+
return { readToken: input.authToken, decryptPrivateKeyPem: input.fallbackDecryptPrivateKeyPem };
|
|
141
|
+
}
|
|
142
|
+
|
|
112
143
|
try {
|
|
113
144
|
const readToken = await createReadToken(
|
|
114
145
|
serverUrl(),
|
|
@@ -245,15 +276,26 @@ async function readCredential(
|
|
|
245
276
|
options?: {
|
|
246
277
|
retryCommandTemplate?: string;
|
|
247
278
|
originalCommand?: string;
|
|
279
|
+
requestedFields?: string[];
|
|
248
280
|
},
|
|
249
281
|
): Promise<DecryptedCredential> {
|
|
250
282
|
const originalCommand = String(options?.originalCommand || '').trim();
|
|
283
|
+
const requestedFields = Array.from(new Set(
|
|
284
|
+
(options?.requestedFields || [])
|
|
285
|
+
.map((value) => String(value || '').trim())
|
|
286
|
+
.filter((value) => value.length > 0),
|
|
287
|
+
));
|
|
288
|
+
const requestBody = requestedFields.length > 0
|
|
289
|
+
? JSON.stringify({ requestedFields })
|
|
290
|
+
: undefined;
|
|
251
291
|
const res = await fetch(`${serverUrl()}/credentials/${credentialId}/read`, {
|
|
252
292
|
method: 'POST',
|
|
253
293
|
headers: {
|
|
254
294
|
'Authorization': `Bearer ${readToken}`,
|
|
295
|
+
...(requestBody ? { 'Content-Type': 'application/json' } : {}),
|
|
255
296
|
...(originalCommand ? { 'X-Aura-Original-Command': originalCommand } : {}),
|
|
256
297
|
},
|
|
298
|
+
...(requestBody ? { body: requestBody } : {}),
|
|
257
299
|
signal: AbortSignal.timeout(8_000),
|
|
258
300
|
});
|
|
259
301
|
if (!res.ok) {
|
|
@@ -579,16 +621,6 @@ async function resolveCredentialTarget(
|
|
|
579
621
|
throw new Error(`PROJECT_SCOPE_DENIED: No allowed credential found for "${name}" in agent "${options.agentName}".`);
|
|
580
622
|
}
|
|
581
623
|
|
|
582
|
-
if (agentFiltered.length > 1 && !options.first) {
|
|
583
|
-
const lines = [`Multiple credentials match "${name}":`];
|
|
584
|
-
for (const m of agentFiltered) {
|
|
585
|
-
const resolvedAgent = agentNames.get(m.agentId) || m.agentId;
|
|
586
|
-
lines.push(` - ${m.name} (${m.type}, agent: ${resolvedAgent}, id: ${m.id})`);
|
|
587
|
-
}
|
|
588
|
-
lines.push('Use --first to select the first match, or specify --agent.');
|
|
589
|
-
throw new Error(lines.join('\n'));
|
|
590
|
-
}
|
|
591
|
-
|
|
592
624
|
return { target: agentFiltered[0], agentNames };
|
|
593
625
|
}
|
|
594
626
|
|
|
@@ -630,7 +662,7 @@ function showHelp(): void {
|
|
|
630
662
|
' --tags <a,b,c> Comma-separated tags (set only)',
|
|
631
663
|
' --agent <v> Restrict to agent name',
|
|
632
664
|
' --json JSON output',
|
|
633
|
-
' --first
|
|
665
|
+
' --first Compatibility flag (first match is already default)',
|
|
634
666
|
' --totp Print current TOTP code only (get)',
|
|
635
667
|
' --danger-plaintext Print plaintext secret in local socket get output (unsafe)',
|
|
636
668
|
' --expires-after <v> Share expiry: 15m|1h|24h|7d|30d (default: 24h)',
|
|
@@ -1250,20 +1282,33 @@ export async function runAgentCli(args: string[]): Promise<number> {
|
|
|
1250
1282
|
if (!readAuthContext) return 1;
|
|
1251
1283
|
|
|
1252
1284
|
try {
|
|
1285
|
+
const resolvedType = normalizeCredentialType(target.type);
|
|
1286
|
+
const requestedFieldKey = fieldName
|
|
1287
|
+
? canonicalizeCredentialFieldKey(resolvedType, fieldName)
|
|
1288
|
+
: getCredentialPrimaryFieldKey(resolvedType);
|
|
1289
|
+
const requestedFields = [
|
|
1290
|
+
requestedFieldKey,
|
|
1291
|
+
];
|
|
1253
1292
|
const decrypted = await readCredential(target.id, readAuthContext.readToken, readAuthContext.privateKeyPem, {
|
|
1254
1293
|
retryCommandTemplate,
|
|
1255
1294
|
originalCommand,
|
|
1295
|
+
requestedFields,
|
|
1256
1296
|
});
|
|
1257
|
-
const
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1297
|
+
const effectiveType = normalizeCredentialType(decrypted.type || target.type);
|
|
1298
|
+
const allFields = mergeCredentialFields(effectiveType, decrypted.fields, target.meta);
|
|
1299
|
+
const selectedField = fieldName
|
|
1300
|
+
? findField(effectiveType, allFields, fieldName)
|
|
1301
|
+
: resolvePrimarySecretField(effectiveType, allFields);
|
|
1302
|
+
if (!selectedField) {
|
|
1303
|
+
if (fieldName) {
|
|
1304
|
+
console.error(`Field "${fieldName}" not found on credential.`);
|
|
1305
|
+
} else {
|
|
1306
|
+
console.error('No sensitive field found on credential.');
|
|
1307
|
+
}
|
|
1263
1308
|
return 1;
|
|
1264
1309
|
}
|
|
1265
1310
|
|
|
1266
|
-
return await runSecretExec(execCommand, envVarName,
|
|
1311
|
+
return await runSecretExec(execCommand, envVarName, selectedField.value);
|
|
1267
1312
|
} finally {
|
|
1268
1313
|
finalizeReadAuthContext(readAuthContext);
|
|
1269
1314
|
}
|
|
@@ -1299,11 +1344,23 @@ export async function runAgentCli(args: string[]): Promise<number> {
|
|
|
1299
1344
|
});
|
|
1300
1345
|
if (!readAuthContext) return 1;
|
|
1301
1346
|
|
|
1347
|
+
const resolvedTargetType = normalizeCredentialType(target.type);
|
|
1348
|
+
const requestedReadFields = flagJson
|
|
1349
|
+
? (fieldName
|
|
1350
|
+
? [canonicalizeCredentialFieldKey(resolvedTargetType, fieldName)]
|
|
1351
|
+
: ['*'])
|
|
1352
|
+
: execCommand.length > 0
|
|
1353
|
+
? [getCredentialPrimaryFieldKey(resolvedTargetType)]
|
|
1354
|
+
: fieldName
|
|
1355
|
+
? [canonicalizeCredentialFieldKey(resolvedTargetType, fieldName)]
|
|
1356
|
+
: [getCredentialPrimaryFieldKey(resolvedTargetType)];
|
|
1357
|
+
|
|
1302
1358
|
let decrypted: DecryptedCredential;
|
|
1303
1359
|
try {
|
|
1304
1360
|
decrypted = await readCredential(target.id, readAuthContext.readToken, readAuthContext.privateKeyPem, {
|
|
1305
1361
|
retryCommandTemplate,
|
|
1306
1362
|
originalCommand,
|
|
1363
|
+
requestedFields: requestedReadFields,
|
|
1307
1364
|
});
|
|
1308
1365
|
} finally {
|
|
1309
1366
|
finalizeReadAuthContext(readAuthContext);
|