First real run of provisionSandbox.ts against the seeded sandbox surfaced three bugs in userSetup.ts (verified live: ai_agent_sandbox rowid 4 had api_key NULL and was missing only facture/creer of the 11 intended rights):
generateApiKey never saved. It generated the key client-side and read it into .ai_agent_sandbox.key, but never submitted the edit form, so Dolibarr never persisted api_key (DB stayed NULL → the key can't authenticate). → now clicks Save after generating.
assignRights selector was a substring match.[href*="rights=12"] also matched rights=121 / rights=1232, so .first() clicked the wrong link and facture creer (12) was skipped. → anchored with the trailing & (rights=12&) for an exact match.
createUser wasn't idempotent. A re-run hit the existing login and couldn't parse a new id. → added findUserId (look up by login in the user list) and return the existing id instead of creating a duplicate.
deno check passes. The fixes make a re-run complete the provisioning: it finds the existing user, grants the missing facture creer, and generates + persists the API key.
First real run of `provisionSandbox.ts` against the seeded sandbox surfaced three bugs in `userSetup.ts` (verified live: `ai_agent_sandbox` rowid 4 had `api_key` NULL and was missing only `facture/creer` of the 11 intended rights):
1. **`generateApiKey` never saved.** It generated the key client-side and read it into `.ai_agent_sandbox.key`, but never submitted the edit form, so Dolibarr never persisted `api_key` (DB stayed NULL → the key can't authenticate). → now clicks **Save** after generating.
2. **`assignRights` selector was a substring match.** `[href*="rights=12"]` also matched `rights=121` / `rights=1232`, so `.first()` clicked the wrong link and `facture creer` (12) was skipped. → anchored with the trailing `&` (`rights=12&`) for an exact match.
3. **`createUser` wasn't idempotent.** A re-run hit the existing login and couldn't parse a new id. → added `findUserId` (look up by login in the user list) and return the existing id instead of creating a duplicate.
`deno check` passes. The fixes make a re-run complete the provisioning: it finds the existing user, grants the missing `facture creer`, and generates + **persists** the API key.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
First real run against the sandbox revealed three issues in userSetup.ts:
1. generateApiKey generated the key client-side and read it into the file but
never submitted the edit form, so Dolibarr never persisted api_key (DB stayed
NULL → the key could not authenticate). Now it clicks Save after generating.
2. assignRights matched `rights=<id>` as an href substring, so a short id like
12 (facture creer) also matched rights=121 / rights=1232 and .first() clicked
the wrong link — facture creer was never granted. Anchored with a trailing
"&" (rights=<id>&) for an exact match.
3. createUser was not idempotent: a re-run hit the existing login and failed to
parse a new id. Added findUserId (look up by login via the user list) and
return the existing id instead of creating a duplicate.
Verified the symptoms live: ai_agent_sandbox (rowid 4) had api_key NULL and was
missing only facture/creer among the 11 intended rights.
Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
First real run of
provisionSandbox.tsagainst the seeded sandbox surfaced three bugs inuserSetup.ts(verified live:ai_agent_sandboxrowid 4 hadapi_keyNULL and was missing onlyfacture/creerof the 11 intended rights):generateApiKeynever saved. It generated the key client-side and read it into.ai_agent_sandbox.key, but never submitted the edit form, so Dolibarr never persistedapi_key(DB stayed NULL → the key can't authenticate). → now clicks Save after generating.assignRightsselector was a substring match.[href*="rights=12"]also matchedrights=121/rights=1232, so.first()clicked the wrong link andfacture creer(12) was skipped. → anchored with the trailing&(rights=12&) for an exact match.createUserwasn't idempotent. A re-run hit the existing login and couldn't parse a new id. → addedfindUserId(look up by login in the user list) and return the existing id instead of creating a duplicate.deno checkpasses. The fixes make a re-run complete the provisioning: it finds the existing user, grants the missingfacture creer, and generates + persists the API key.🤖 Generated with Claude Code