Changeset 0261730 in Klonkt
- Timestamp:
- 08/08/2026 04:18:37 PM (4 weeks ago)
- Branches:
- main
- Children:
- abcf51a
- Parents:
- 66d97b8
- Files:
-
- 2 edited
-
src/services/guardianship/handshake.js (modified) (1 diff)
-
test/guardianship.test.js (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
src/services/guardianship/handshake.js
r66d97b8 r0261730 341 341 notify(site.slug, { kind: 'offer_rejected', offer: offerId }); 342 342 return { status: 202, id: offerId, url: offerId }; 343 } 344 345 // §1 is flat in BOTH directions. The Offer path above bars a ward from 346 // offering to guard; this is the mirror: an actor that already guards wards 347 // must not become a ward itself. Only the ward's own accept can create that 348 // state, so the candidate and the existing guardians pass through untouched. 349 // 350 // Without it the inconsistency would also be invisible. actorProps() picks 351 // one role with an if/else and would publish shaer:guardians while dropping 352 // shaer:isGuardian, so this account keeps routing its wards' escalations 353 // locally while every remote §4 check reads it as malformed and drops it — 354 // a ward believing it is watched over when it is not, silent on both sides. 355 if (me === offer.ward_uri && relations.listWards(site.slug).length) { 356 return { status: 403, error: 'a_guardian_cannot_be_guarded' }; 343 357 } 344 358 -
test/guardianship.test.js
r66d97b8 r0261730 119 119 assert.equal(r.status, 403); 120 120 assert.equal(r.error, 'a_ward_cannot_guard'); 121 }); 122 123 test('a guardian cannot be guarded either: §1 is flat in both directions', async () => { 124 // parent guards kid by now, and gran (a guardian, so free to offer) offers 125 // to guard parent. The offer itself is fine; only parent's accept would 126 // make one actor ward and guardian at once. 127 assert.ok(G.listWards('parent').length, 'parent already guards someone'); 128 const off = await G.handleGuardianshipOutbox(gran, { 129 type: 'Offer', object: { type: 'Relationship', subject: ME, relationship: 'shaer:Guardian', object: GRAN }, 130 }); 131 assert.equal(off.status, 202, 'a guardian may still offer to guard'); 132 const id = offerIdFrom(off); 133 134 const r = await G.handleGuardianshipOutbox(parent, { type: 'Accept', object: id }); 135 assert.equal(r.status, 403); 136 assert.equal(r.error, 'a_guardian_cannot_be_guarded'); 137 138 // Nothing recorded, and the actor document still reads as a pure guardian. 139 // Without the check actorProps() would have flipped it to a ward silently. 140 assert.deepEqual(G.listGuardians('parent'), []); 141 const doc = AP.buildActor('https://test.example', parent); 142 assert.equal(doc['shaer:isGuardian'], true); 143 assert.equal(doc['shaer:guardians'], undefined); 144 145 // The candidate and the existing guardians are untouched by the check, so 146 // the offer is refusable in the ordinary way rather than stuck. 147 await G.handleGuardianshipOutbox(parent, { type: 'Reject', object: id }); 121 148 }); 122 149
Note:
See TracChangeset
for help on using the changeset viewer.
![(please configure the [header_logo] section in trac.ini)](/chrome/site/your_project_logo.png)