[grade=B urn:ump:bbfbsfru4nizg75wcxum7mwzhie6txhr22hw6jvz36wiihmgzmlq] P7 people store: dedupe upsert by providerUserId
CI / Test & Lint (pull_request) Canceled after 0s
CI / Security audit (pull_request) Canceled after 0s

Dogfood finding #3: upsertPerson resolved existing records by id only.
The wizard upserts a bootstrap admin AFTER a provider sync has already
created a person for the same Tailscale user (no id passed), so the same
providerUserId was duplicated into two records. Resolve existing by
providerUserId when no id is given; bootstrap Admin group + protectedAt are
preserved on the merge. New regression test; full suite 3414/3414.
This commit is contained in:
Hermes Agent committed 2026-10-04 03:12:23 -07:00
1 parent 776cf3c4ca
commit c430e02117
2 files changed
+31 -1

No files matched your search

@@ -82,6 +82,26 @@ describe('network-people-store: CRUD', () => {
expect(list).toHaveLength(1); // merged, not duplicated expect(list).toHaveLength(1); // merged, not duplicated
}); });
test('upsertPerson merges by providerUserId when id is omitted (wizard after provider sync)', async () => {
const synced = await store.upsertPerson({
displayName: 'SamiAhmed7777',
providerUserId: 'ughVnuLDu621CNTRL',
});
expect(synced.groups).toEqual(['Admin']); // bootstrap identity
const fromWizard = await store.upsertPerson({
displayName: 'Sami Ahmed',
providerUserId: 'ughVnuLDu621CNTRL',
});
expect(fromWizard.id).toBe(synced.id);
expect(fromWizard.displayName).toBe('Sami Ahmed');
expect(fromWizard.groups).toEqual(['Admin']);
expect(fromWizard.protectedAt).toBe(synced.protectedAt);
const list = await store.listPeople();
expect(list).toHaveLength(1);
});
test('updatePerson patches only provided fields', async () => { test('updatePerson patches only provided fields', async () => {
const p = await store.upsertPerson({ displayName: 'Bob', providerUserId: 'ts-2', groups: ['G'] }); const p = await store.upsertPerson({ displayName: 'Bob', providerUserId: 'ts-2', groups: ['G'] });
const u = await store.updatePerson(p.id, { displayName: 'Bobby' }); const u = await store.updatePerson(p.id, { displayName: 'Bobby' });
@@ -180,7 +180,17 @@ function createPeopleStore(opts = {}) {
function upsertPerson(input = {}) { function upsertPerson(input = {}) {
return _enqueue(() => { return _enqueue(() => {
const data = _load(); const data = _load();
const existing = input.id ? data.people[input.id] : null; // Resolve the existing record by id when given, else by providerUserId
// (dogfood finding 2026-10-04: the wizard upserts a person AFTER a
// provider sync already created one for the same Tailscale user with no
// id — without this lookup the same providerUserId was duplicated).
const existing = input.id
? data.people[input.id]
: (input.providerUserId
? Object.values(data.people).find(
(p) => p.providerUserId && p.providerUserId === input.providerUserId
) || null
: null);
const isFirst = Object.keys(data.people).length === 0; const isFirst = Object.keys(data.people).length === 0;
const id = existing ? existing.id : (input.id || crypto.randomUUID()); const id = existing ? existing.id : (input.id || crypto.randomUUID());