ugly-app 0.1.987 → 0.1.988

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.
@@ -40,5 +40,18 @@ export interface ProbeAuthResult {
40
40
  * since some service tokens are intentionally non-expiring
41
41
  */
42
42
  export declare function inspectJwt(token: string): 'valid' | 'expired' | 'unknown';
43
+ /**
44
+ * The account a token acts as, read from its `sub` claim without verifying the
45
+ * signature (it's our own token — we only need to know whose it is).
46
+ *
47
+ * This is the check that would have caught the worst auth failure this tool has
48
+ * had: a project token minted while a FAKE login was in place carries a phantom
49
+ * subject (`e2e-auth-user`, `e2e-user`, …) that is not a ugly.bot account at
50
+ * all. The token verifies, `dev` works, tests appear to sign in — and then every
51
+ * billable call for that project 402s, or worse, test accounts get created
52
+ * pointing at an account that cannot pay. Nothing in the failure names the
53
+ * token, so it has cost hours more than once.
54
+ */
55
+ export declare function jwtSubject(token: string): string | null;
43
56
  export declare function probeAuth(input: ProbeAuthInput): ProbeAuthResult;
44
57
  //# sourceMappingURL=probeAuth.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"probeAuth.d.ts","sourceRoot":"","sources":["../../src/cli/probeAuth.ts"],"names":[],"mappings":"AAoBA,MAAM,MAAM,UAAU,GAAG,IAAI,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,CAAC;AAE1D,MAAM,WAAW,QAAQ;IACvB,MAAM,EAAE,UAAU,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,uEAAuE;IACvE,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,eAAe;IAC9B,iEAAiE;IACjE,KAAK,EAAE,QAAQ,EAAE,CAAC;IAClB,yCAAyC;IACzC,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB;;;;;;OAMG;IACH,UAAU,EAAE,OAAO,CAAC;IACpB,mDAAmD;IACnD,kBAAkB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACxC;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACjC;AAyBD;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,GAAG,SAAS,GAAG,SAAS,CAazE;AAyCD,wBAAgB,SAAS,CAAC,KAAK,EAAE,cAAc,GAAG,eAAe,CAqLhE"}
1
+ {"version":3,"file":"probeAuth.d.ts","sourceRoot":"","sources":["../../src/cli/probeAuth.ts"],"names":[],"mappings":"AAoBA,MAAM,MAAM,UAAU,GAAG,IAAI,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,CAAC;AAE1D,MAAM,WAAW,QAAQ;IACvB,MAAM,EAAE,UAAU,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,uEAAuE;IACvE,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,eAAe;IAC9B,iEAAiE;IACjE,KAAK,EAAE,QAAQ,EAAE,CAAC;IAClB,yCAAyC;IACzC,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB;;;;;;OAMG;IACH,UAAU,EAAE,OAAO,CAAC;IACpB,mDAAmD;IACnD,kBAAkB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACxC;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACjC;AAyBD;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,GAAG,SAAS,GAAG,SAAS,CAazE;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAWvD;AAyCD,wBAAgB,SAAS,CAAC,KAAK,EAAE,cAAc,GAAG,eAAe,CA+MhE"}
@@ -57,6 +57,30 @@ export function inspectJwt(token) {
57
57
  return 'unknown';
58
58
  }
59
59
  }
60
+ /**
61
+ * The account a token acts as, read from its `sub` claim without verifying the
62
+ * signature (it's our own token — we only need to know whose it is).
63
+ *
64
+ * This is the check that would have caught the worst auth failure this tool has
65
+ * had: a project token minted while a FAKE login was in place carries a phantom
66
+ * subject (`e2e-auth-user`, `e2e-user`, …) that is not a ugly.bot account at
67
+ * all. The token verifies, `dev` works, tests appear to sign in — and then every
68
+ * billable call for that project 402s, or worse, test accounts get created
69
+ * pointing at an account that cannot pay. Nothing in the failure names the
70
+ * token, so it has cost hours more than once.
71
+ */
72
+ export function jwtSubject(token) {
73
+ const parts = token.split('.');
74
+ if (parts.length !== 3)
75
+ return null;
76
+ try {
77
+ const payload = JSON.parse(Buffer.from(parts[1], 'base64url').toString('utf-8'));
78
+ return typeof payload.sub === 'string' && payload.sub ? payload.sub : null;
79
+ }
80
+ catch {
81
+ return null;
82
+ }
83
+ }
60
84
  function readGlobalAuth(homeDir) {
61
85
  const file = path.join(homeDir, '.ugly-bot', 'auth.json');
62
86
  const { data, malformed } = readJson(file);
@@ -219,6 +243,31 @@ export function probeAuth(input) {
219
243
  });
220
244
  }
221
245
  }
246
+ // 2b. Does each project token actually act as YOU?
247
+ //
248
+ // A project token whose `sub` isn't your account is not a smaller problem
249
+ // than a missing one — it is a token that works everywhere except where it
250
+ // matters. `auth:create-bot` bills test accounts to that subject, so a
251
+ // phantom one produces exactly the symptom that started all this: accounts
252
+ // that look fine and can't spend.
253
+ if (projectId && globalAuth) {
254
+ for (const [label, token, file] of [
255
+ ['auth (cloud)', cloudToken, `${projectId}.json`],
256
+ ['auth (local)', localToken, `${projectId}.local.json`],
257
+ ]) {
258
+ if (!token)
259
+ continue;
260
+ const sub = jwtSubject(token);
261
+ if (!sub || sub === globalAuth.userId)
262
+ continue;
263
+ lines.push({
264
+ status: 'error',
265
+ label,
266
+ detail: `token acts as "${sub}", not you (${globalAuth.userId}) — test accounts made with it bill an account you don't own`,
267
+ });
268
+ nextSteps.push(`Delete ~/.ugly-bot/${file} and re-run \`npx ugly-app dev\` (or \`login\`) to re-mint it as ${globalAuth.userId}`);
269
+ }
270
+ }
222
271
  // 3. Agent-ready summary.
223
272
  // For headless tooling, the global user token is what unblocks
224
273
  // everything: project tokens are derived. If we're in local mode we
@@ -1 +1 @@
1
- {"version":3,"file":"probeAuth.js","sourceRoot":"","sources":["../../src/cli/probeAuth.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"probeAuth.js","sourceRoot":"","sources":["../../src/cli/probeAuth.ts"],"names":[],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- export declare const CLI_VERSION = "0.1.987";
1
+ export declare const CLI_VERSION = "0.1.988";
2
2
  //# sourceMappingURL=version.d.ts.map
@@ -1,3 +1,3 @@
1
1
  // Auto-generated by prebuild — do not edit manually
2
- export const CLI_VERSION = "0.1.987";
2
+ export const CLI_VERSION = "0.1.988";
3
3
  //# sourceMappingURL=version.js.map
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "ugly-app",
3
3
  "packageManager": "pnpm@10.34.5",
4
- "version": "0.1.987",
4
+ "version": "0.1.988",
5
5
  "type": "module",
6
6
  "comment:files": "Allowlist what ships to npm. dist = runtime; src = sourcemap targets (dist/*.js.map reference ../../src/); templates = CLI scaffold. Everything else at repo root (.pgdata local Postgres, coverage, assets/icons sources, test/, test-results/) is excluded by omission. The !negations strip the scaffold's installed deps + cruft (templates/node_modules is 200MB+ and must never ship). package.json/README/LICENSE ship automatically.",
7
7
  "files": [
@@ -101,6 +101,31 @@ export function inspectJwt(token: string): 'valid' | 'expired' | 'unknown' {
101
101
  }
102
102
  }
103
103
 
104
+ /**
105
+ * The account a token acts as, read from its `sub` claim without verifying the
106
+ * signature (it's our own token — we only need to know whose it is).
107
+ *
108
+ * This is the check that would have caught the worst auth failure this tool has
109
+ * had: a project token minted while a FAKE login was in place carries a phantom
110
+ * subject (`e2e-auth-user`, `e2e-user`, …) that is not a ugly.bot account at
111
+ * all. The token verifies, `dev` works, tests appear to sign in — and then every
112
+ * billable call for that project 402s, or worse, test accounts get created
113
+ * pointing at an account that cannot pay. Nothing in the failure names the
114
+ * token, so it has cost hours more than once.
115
+ */
116
+ export function jwtSubject(token: string): string | null {
117
+ const parts = token.split('.');
118
+ if (parts.length !== 3) return null;
119
+ try {
120
+ const payload = JSON.parse(
121
+ Buffer.from(parts[1]!, 'base64url').toString('utf-8'),
122
+ ) as { sub?: unknown };
123
+ return typeof payload.sub === 'string' && payload.sub ? payload.sub : null;
124
+ } catch {
125
+ return null;
126
+ }
127
+ }
128
+
104
129
  interface GlobalAuth {
105
130
  token: string;
106
131
  userId: string;
@@ -288,6 +313,32 @@ export function probeAuth(input: ProbeAuthInput): ProbeAuthResult {
288
313
  }
289
314
  }
290
315
 
316
+ // 2b. Does each project token actually act as YOU?
317
+ //
318
+ // A project token whose `sub` isn't your account is not a smaller problem
319
+ // than a missing one — it is a token that works everywhere except where it
320
+ // matters. `auth:create-bot` bills test accounts to that subject, so a
321
+ // phantom one produces exactly the symptom that started all this: accounts
322
+ // that look fine and can't spend.
323
+ if (projectId && globalAuth) {
324
+ for (const [label, token, file] of [
325
+ ['auth (cloud)', cloudToken, `${projectId}.json`],
326
+ ['auth (local)', localToken, `${projectId}.local.json`],
327
+ ] as const) {
328
+ if (!token) continue;
329
+ const sub = jwtSubject(token);
330
+ if (!sub || sub === globalAuth.userId) continue;
331
+ lines.push({
332
+ status: 'error',
333
+ label,
334
+ detail: `token acts as "${sub}", not you (${globalAuth.userId}) — test accounts made with it bill an account you don't own`,
335
+ });
336
+ nextSteps.push(
337
+ `Delete ~/.ugly-bot/${file} and re-run \`npx ugly-app dev\` (or \`login\`) to re-mint it as ${globalAuth.userId}`,
338
+ );
339
+ }
340
+ }
341
+
291
342
  // 3. Agent-ready summary.
292
343
  // For headless tooling, the global user token is what unblocks
293
344
  // everything: project tokens are derived. If we're in local mode we
@@ -1,2 +1,2 @@
1
1
  // Auto-generated by prebuild — do not edit manually
2
- export const CLI_VERSION = "0.1.987";
2
+ export const CLI_VERSION = "0.1.988";
@@ -4,37 +4,72 @@ description: Create test users and seed data
4
4
  user-invocable: true
5
5
  ---
6
6
 
7
- # Creating Test Users
7
+ # Creating test users
8
8
 
9
- ## Register a test user
10
- ```bash
11
- curl -X POST http://localhost:3000/auth/register \
12
- -H "Content-Type: application/json" \
13
- -d '{"email":"test1@test.com","password":"testpass123"}'
14
- # Returns: {"token":"..."}
15
- ```
9
+ **There is exactly one supported way, and it is the same one everywhere.** Everything
10
+ else that has ever been used here — `POST /auth/register` with a password, hand-signed
11
+ JWTs, reusing the project token from `~/.ugly-bot/<projectId>.json`, `mongosh` cleanup —
12
+ either no longer exists or produces an account that looks signed in and cannot spend.
16
13
 
17
- ## Save token for use in tests
18
- ```bash
19
- TOKEN=$(curl -s -X POST http://localhost:3000/auth/login \
20
- -H "Content-Type: application/json" \
21
- -d '{"email":"test1@test.com","password":"testpass123"}' | jq -r .token)
22
- echo $TOKEN
14
+ ## In a Playwright test
15
+
16
+ ```ts
17
+ import { testAccount, authenticateAs } from 'ugly-app/playwright';
18
+
19
+ const acct = await testAccount('checkout-flow'); // idempotent per project+slug
20
+ await authenticateAs(page, acct); // or a domain: 'myapp.ugly.bot'
21
+ await page.goto('/');
23
22
  ```
24
23
 
25
- ## Seed multiple users
24
+ - `acct` is `{ userId, token, email, payerUserId?, canSpend? }`.
25
+ - Add `{ requireSpend: true }` when the spec's point is a real AI response — it fails up
26
+ front with a readable message instead of a 402 three layers deep.
27
+ - `testAccountPage(browser, slug, domain?)` does both steps in one call.
28
+
29
+ ## From the CLI (bots, swarms, manual poking)
30
+
26
31
  ```bash
27
- for i in 1 2 3 4 5; do
28
- curl -s -X POST http://localhost:3000/auth/register \
29
- -H "Content-Type: application/json" \
30
- -d "{\"email\":\"bot${i}@test.com\",\"password\":\"botpass123\"}"
31
- done
32
+ npx ugly-app auth:create-bot --slug <slug> --name "<Name>"
33
+ # → { userId, token, email, billing: { payerUserId, canSpend, subscribed } }
32
34
  ```
33
35
 
34
- ## Delete all test users
35
- ```bash
36
- mongosh "$MONGODB_URI" --eval "db.user.deleteMany({email:/test\.com$/})"
36
+ Use `token` as the `auth_token` cookie. Any deployed app accepts it, including default
37
+ Mode-A apps.
38
+
39
+ ## What this guarantees
40
+
41
+ - **A real ugly.bot account**, so `/verify` accepts it everywhere.
42
+ - **Billed to you.** The account holds no credit of its own; a `billToUserId` pointer
43
+ routes its AI spend to the app owner. It never shows an "out of credit" banner just for
44
+ being a test account.
45
+ - **Not creatable broken.** ugly.bot refuses to mint one when the calling identity isn't a
46
+ real account — the stale/fake-login case — with a message naming the fix
47
+ (`npx ugly-app login`). That failure used to surface hours later as an unexplained 402.
48
+ - **Idempotent.** Same project + slug ⇒ same account, run after run. No litter.
49
+
50
+ ## Cleanup
51
+
52
+ Don't. Accounts are reused across runs, an idle one bills nothing, and a ugly.bot cron
53
+ reaps synthetic ones after ~7 days. Never delete users with raw SQL — that orphans rows
54
+ in every collection keyed on the userId.
55
+
56
+ ## Seeding data for a test user
57
+
58
+ Call the app's own API as that account, so the data goes through the same validation real
59
+ users do:
60
+
61
+ ```ts
62
+ await request.post('/api/<endpoint>', {
63
+ headers: { 'Cookie': `auth_token=${acct.token}`, 'Content-Type': 'application/json' },
64
+ data: { input: { /* ... */ } },
65
+ });
37
66
  ```
38
67
 
68
+ ## Local, hermetic alternative (no ugly.bot, no money)
69
+
70
+ For tests that don't need real AI or prod data, use test mode instead — it's free and
71
+ offline. See `TESTING.md` §1: `UGLY_APP_TEST_MODE=1` plus the `impersonate(userId)`
72
+ fixture from `ugly-app/testing`.
73
+
39
74
  # Notes
40
75
  <!-- Claude: append observations here — record which test users exist -->