feat: emit relative acl:agent in pod creation (#430)#431
Conversation
Phase 2 of #427 (#430). Builds on #429 (relative accessTo/default). The owner WebID lives at <pod>/profile/card.jsonld#me. Each .acl now references it relative to that .acl's container — './profile/card.jsonld#me' from the pod root, '../profile/card.jsonld#me' from an immediate child folder, './card.jsonld#me' from /profile/.acl. The parser already resolves relative agent URIs against the .acl URL (PR #65 / #64), so this is a writer-side change only. Existing absolute-agent ACLs on disk continue to authorize correctly. Together with #429 the on-disk pod is now host-portable: an operator can `mv` a pod directory to a different domain without rewriting any ACL files. Same-host owner read/write keeps working — covered by existing pod creation / ACL access tests. The `webId` parameter on createPodStructure / createRootPodStructure remains the absolute WebID URI: it is still the global identifier published in the profile document and consumed by OIDC, federation, typeIndex generation, etc. Only the in-ACL references become relative. Cross-host *owner write* (token issued by host A, request to host B) still mismatches because the token's `webid` claim is fixed at auth time; that's Phase 4 and needs its own design. Tests: - 4 unit tests (one per affected generator) verify a relative agent string is preserved verbatim. - 2 round-trip tests parse the same on-wire ACL under different host URLs and assert the agent resolves to the requesting host, including the parent-relative '../profile/card.jsonld#me' from a child folder. 793/793 tests pass.
There was a problem hiding this comment.
Pull request overview
This PR extends the pod-portability work from #429 by making ACL generators and pod-creation code emit relative acl:agent WebIDs (in addition to already-relative acl:accessTo/acl:default). This keeps newly created on-disk pods portable across hostnames/interfaces without rewriting .acl files.
Changes:
- Add unit tests ensuring ACL generators preserve relative
ownerWebIdverbatim, plus round-trip parse tests asserting relative agents resolve against the.aclURL. - Update WAC generator JSDoc to document that
ownerWebIdmay be relative and is resolved against the ACL URL. - Update pod creation (single-user and multi-user) to write relative
acl:agentvalues in seeded ACL files.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| test/wac.test.js | Adds unit + round-trip tests for relative acl:agent emission/resolution (#430). |
| src/wac/parser.js | Updates documentation to reflect relative ownerWebId support in generators. |
| src/server.js | Seeds single-user root pod ACLs with relative acl:agent paths. |
| src/handlers/container.js | Seeds multi-user pod ACLs with relative acl:agent paths. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| const ownerFromRoot = './profile/card.jsonld#me'; | ||
| const ownerFromChild = '../profile/card.jsonld#me'; | ||
| const ownerFromProfile = './card.jsonld#me'; | ||
|
|
There was a problem hiding this comment.
Addressed in b424397: introduced relativizeOwnerWebId(webId, podUri, aclBase) in src/wac/parser.js and replaced the hardcoded relative paths at this call site with owner(aclBase) lookups. Now derives directly from the absolute webId, so legacy profile/card#me, custom shapes, and foreign owners all produce correct output (foreign owners fall through unchanged). 6 unit tests cover the layouts plus a round-trip through the parser.
| const ownerFromRoot = './profile/card.jsonld#me'; | ||
| const ownerFromChild = '../profile/card.jsonld#me'; | ||
| const ownerFromProfile = './card.jsonld#me'; | ||
|
|
There was a problem hiding this comment.
Addressed in b424397: introduced relativizeOwnerWebId(webId, podUri, aclBase) in src/wac/parser.js and replaced the hardcoded relative paths at this call site with owner(aclBase) lookups. Now derives directly from the absolute webId, so legacy profile/card#me, custom shapes, and foreign owners all produce correct output (foreign owners fall through unchanged). 6 unit tests cover the layouts plus a round-trip through the parser.
Address Copilot review on #431. The previous commit hardcoded the relative agent IRI as './profile/card.jsonld#me' / '../profile/card.jsonld#me' in both createPodStructure and createRootPodStructure, which would silently diverge from the profile document if a pod ever uses a different layout (legacy 'profile/card#me', custom shapes, future refactors). Replace with a new helper `relativizeOwnerWebId(webId, podUri, aclBase)` exported from src/wac/parser.js. Callers pass the .acl's container relative to the pod root ('', 'private/', 'profile/', 'settings/', 'inbox/', 'public/'); the helper slices the WebID's tail and prepends the right number of '../' hops. Foreign owner WebIDs (not under podUri) fall through unchanged as absolute IRIs. Tests: 6 new unit tests in test/wac.test.js cover the modern, legacy, and custom-shape WebIDs, foreign owners, and a round-trip through the parser confirming the relative form resolves back to the original absolute WebID under each .acl location. 799/799 tests pass.
Summary
.aclnow emitsacl:agentas a path relative to the .acl's container (e.g.'./profile/card.jsonld#me'from the pod root,'../profile/card.jsonld#me'from a child folder,'./card.jsonld#me'from/profile/.acl).accessTo/defaultrelative). Together: an operator canmva pod directory to a different domain without rewriting any ACL files.webIdparameter oncreatePodStructure/createRootPodStructureis unchanged — still the absolute global identifier published in the profile document and consumed by OIDC, federation, typeIndex generation, etc. Only the in-ACL references become relative.Why
Phase 2 of #427. Phase 1 (#429) made public-read work cross-host. The owner half was still locked to whichever host the pod-creation request came in on. The parser already resolves relative agent URIs against the .acl URL — proven by PR #65 (
bdbbbb7) which closed #64 — so this is a writer-side change only.What this doesn't fix
Cross-host owner write (token issued by host A, request to host B) still mismatches because the token's
webidclaim is fixed at auth time. That's Phase 4 of #427 and needs its own design (likely--canonical-host+ auth-layer normalization).Tests
generateOwnerAcl,generatePrivateAcl,generateInboxAcl,generatePublicFolderAcl) verify a relative agent string is preserved verbatim.'../profile/card.jsonld#me'from a/alice/private/.acl(resolves correctly to/alice/profile/card.jsonld#me, doesn't escape the pod).Test plan
npm test— 793/793 passing locally./and../agentsCloses #430. Phase 2 of #427.