Skip to content

feat: emit relative acl:agent in pod creation (#430)#431

Merged
melvincarvalho merged 2 commits into
gh-pagesfrom
issue-430-relative-acl-agent
May 14, 2026
Merged

feat: emit relative acl:agent in pod creation (#430)#431
melvincarvalho merged 2 commits into
gh-pagesfrom
issue-430-relative-acl-agent

Conversation

@melvincarvalho
Copy link
Copy Markdown
Contributor

Summary

  • Make the on-disk pod portable for the owner half too: every .acl now emits acl:agent as 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).
  • Builds on feat: emit relative acl:accessTo / acl:default in pod creation (#428) #429 (which made accessTo/default relative). Together: an operator can mv a pod directory to a different domain without rewriting any ACL files.
  • The webId parameter on createPodStructure / createRootPodStructure is 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 webid claim is fixed at auth time. That's Phase 4 of #427 and needs its own design (likely --canonical-host + auth-layer normalization).

Tests

  • 4 new unit tests (one per affected generator: generateOwnerAcl, generatePrivateAcl, generateInboxAcl, generatePublicFolderAcl) verify a relative agent string is preserved verbatim.
  • 2 new round-trip tests parse the same on-wire ACL document under different host URLs and assert the agent resolves to the requesting host — including the parent-relative '../profile/card.jsonld#me' from a /alice/private/.acl (resolves correctly to /alice/profile/card.jsonld#me, doesn't escape the pod).
  • 793/793 existing tests pass — same-host owner read/write is exercised throughout the existing pod creation / ACL access tests, so they double as regression coverage.

Test plan

  • npm test — 793/793 passing locally
  • New unit tests for relative agent emission
  • New round-trip parser tests for ./ and ../ agents

Closes #430. Phase 2 of #427.

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.
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 ownerWebId verbatim, plus round-trip parse tests asserting relative agents resolve against the .acl URL.
  • Update WAC generator JSDoc to document that ownerWebId may be relative and is resolved against the ACL URL.
  • Update pod creation (single-user and multi-user) to write relative acl:agent values 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.

Comment thread src/server.js Outdated
Comment on lines +973 to +976
const ownerFromRoot = './profile/card.jsonld#me';
const ownerFromChild = '../profile/card.jsonld#me';
const ownerFromProfile = './card.jsonld#me';

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment thread src/handlers/container.js Outdated
Comment on lines +206 to +209
const ownerFromRoot = './profile/card.jsonld#me';
const ownerFromChild = '../profile/card.jsonld#me';
const ownerFromProfile = './card.jsonld#me';

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 4 out of 4 changed files in this pull request and generated no new comments.

@melvincarvalho melvincarvalho merged commit 0f202a2 into gh-pages May 14, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Phase 2: emit relative acl:agent in ACL generators (#427) ACL relative URI resolution: ./#me not matching authenticated WebID

2 participants