docs(commonly): correct attachment-read authorization - #11
Conversation
lilyshen0722
left a comment
There was a problem hiding this comment.
Approve — this is strictly better than what it replaces, and I verified all three claims against origin/main rather than taking them from the thread. One refinement below, non-blocking.
What I checked
The old text — "the uploads route uses the same pod-membership ACL as agent writes" — is false in both directions, which is why this PR exists. The replacement:
"Un-scoped files (avatars) are public" — exact. backend/routes/uploads.ts:313:
if (!meta?.podId) return true; // un-scoped: public (avatars etc.)"a different predicate from the write path, which requires an active AgentInstallation" — confirmed, and this is the load-bearing half. The two paths genuinely don't share a predicate:
// WRITE — routes/agentsRuntime.ts
router.post('/pods/:podId/uploads', agentRuntimeAuth, uploadSingle('file'), ...
if (!ensurePodMatch(req.agentInstallations || req.agentInstallation, podId, req.agentAuthorizedPodIds))
return res.status(403)
// READ — routes/uploads.ts:318
const agentUserId = req.agentUser?._id?.toString();
if (agentUserId && await canReadAttachment(fileName, agentUserId)) return true;canReadAttachment never consults AgentInstallation at all. So an agent can hold read access to a file in a pod it has no active installation for. That asymmetry is exactly what the old docstring flattened, and naming it is the main value here.
Refinement — canReadAttachment is wider than "pod membership"
The new text summarizes it as "authorize the runtime token via pod membership (canReadAttachment)". Naming the function is the right call — a reader can go look. But the one-line gloss covers one of five grant surfaces (backend/services/attachmentAccess.ts:96-160):
:108 fileDoc.uploadedBy === userId → owner. no pod involved at all
:115 File.podId + Pod.members → pod membership ← the one named
:129 any User.profilePicture references it → ANY authenticated caller
:140 a referencing post with no podId → ANY authenticated caller
:91 a referencing PG message → membership of that message's pod
Two of these matter for an agent specifically:
- The owner path is the common agent case. An agent uploads a deliverable, then reads it back. The grant comes from
uploadedBy, not membership — so the docstring names the wrong reason for the read most agents will actually do. - The public-post path widens it past the pod. A pod-scoped file also referenced by a global post is readable by any authenticated caller. Someone reasoning "pod-scoped ⇒ pod members only" from this docstring would get that wrong.
This isn't the old defect — that one overclaimed a guarantee. This one under-describes a permissive predicate, which fails safe for a caller reasoning about their own access and unsafe for one reasoning about who else can read. Suggested one-line change:
* Fetch an attachment. Pod-scoped files authorize the runtime token via
* `canReadAttachment` — owner, pod membership, or a public post/profile
* reference — note this is a different predicate from the write path,
* which requires an active AgentInstallation. Un-scoped files (avatars)
* are public.
Same length, and it stops the summary from being narrower than the function it names.
Notes
mergeStateStatusreadsUNSTABLE— that's non-required checks pending, not a failure. Doesn't block.- Doc-only, no runtime change;
git diff --checkclean, confirmed. - Method note against my own read: my first pass at
authorizePodFilecame from the working tree and showed no agent-token path at all — which would have been a serious finding. The tree predates openclaw#830.git merge-base --is-ancestor 7692a766 HEAD→ false; everything above is read fromorigin/main.
Not verified
- That
agentRuntimeAuthfiltersAgentInstallationonstatus: 'active'specifically — I confirmed the write path routes through installations and the read path doesn't, which is what the docstring claims. The word "active" I took from the repo's own documented behavior, not from reading the middleware. - Nothing about the
?t=signed-token path, which this docstring doesn't mention and doesn't need to.
79ac6ee to
3fca77a
Compare
Summary
readAttachmentdocstring to distinguish pod-membership reads from AgentInstallation-gated writes.Verification
git diff --checkcanReadAttachment, while agent writes require an activeAgentInstallation.No runtime behavior changes.