fix(provenance): address #143 review — page-stamp tests, confine is_agent, doc fixes

Resolves the open items from the latest PR #143 code review:

- test(page): cover the four agentSourceFields stamp sites (create, update,
  movePage, movePageToSpace) with agent + normal-user payload assertions;
  add findById({ includeIsAgent: true }) wiring guards to the JWT and collab
  auth-seam specs so a future drop of the option is caught.
- fix(privacy): drop `isAgent` from UserRepo.baseFields and gate it behind a
  new opt-in `findById({ includeIsAgent })`, requested only by the two auth
  seams that derive provenance — stops the flag leaking via the workspace
  member list and generic user payloads.
- docs: correct the agentSourceFields JSDoc and the two UPDATE-site comments
  to distinguish INSERT (omitted column → DB default 'user') from UPDATE
  (omitted column → existing value kept, Kysely writes only present keys).
- style(page): collapse three stray double blank lines left by an earlier edit.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
claude_code
2026-06-24 02:04:23 +03:00
parent 7705d44fc6
commit 683b9d5de2
8 changed files with 282 additions and 16 deletions

View File

@@ -207,6 +207,14 @@ describe('AuthenticationExtension.onAuthenticate', () => {
expect(ctx.actor).toBe('user');
expect(ctx.aiChatId).toBeNull();
// Wiring guard (#143): the collab seam MUST opt into the isAgent flag —
// it is not in baseFields, so without this option findById omits it and a
// flagged service account's collab edits would silently persist as 'user'.
expect(userRepo.findById).toHaveBeenCalledWith(
USER_ID,
WORKSPACE_ID,
expect.objectContaining({ includeIsAgent: true }),
);
});
it('is_agent user with NO claim → actor=agent (collab seam consults the signed identity)', async () => {

View File

@@ -44,7 +44,9 @@ export class AuthenticationExtension implements Extension {
const userId = jwtPayload.sub;
const workspaceId = jwtPayload.workspaceId;
const user = await this.userRepo.findById(userId, workspaceId);
const user = await this.userRepo.findById(userId, workspaceId, {
includeIsAgent: true,
});
if (!user) {
throw new UnauthorizedException();