Skip to content

fix: restrict membership management to org publishers#2285

Open
vyctorbrzezowski wants to merge 6 commits into
openclaw:mainfrom
vyctorbrzezowski:contrib/personal-publisher-membership-guard
Open

fix: restrict membership management to org publishers#2285
vyctorbrzezowski wants to merge 6 commits into
openclaw:mainfrom
vyctorbrzezowski:contrib/personal-publisher-membership-guard

Conversation

@vyctorbrzezowski
Copy link
Copy Markdown
Contributor

@vyctorbrzezowski vyctorbrzezowski commented May 16, 2026

Summary

Makes personal publishers behave like account aliases, not shared teams. Old membership rows on someone else's personal publisher no longer let another user publish, transfer, or manage their resources.

What changed

  • Member add/update flows remain restricted to org publishers.
  • Personal publisher authority now comes only from linkedUserId === actorUserId.
  • Stale personal-publisher membership rows no longer authorize publish target resolution.
  • Skill transfer destinations no longer accept stale personal-publisher membership rows.
  • Package owner read/manage gates now treat user publishers as linked-user only.
  • Org publisher membership still authorizes org publishing normally.
  • Existing stale personal membership rows can remain for cleanup; they no longer grant authority.

Public behavior

Publishing, transferring, or managing through a personal publisher now requires that the personal publisher is linked to the acting user. A stale membership row cannot authorize a different user's personal publisher.

Org publisher membership remains valid for org-owned publishing.

Behavior proof

Live Convex runtime proof for the remaining stale personal-membership paths ClawSweeper called out:

$ bunx convex run --push --typecheck=disable --codegen disable proof2285:run
- Preparing Convex functions...

✔ Convex functions ready!
{
  "directTransfer": {
    "error": "You do not have admin access for \"@proof2285-...-owner\". Ask an owner or admin to add you before transferring this skill.",
    "ok": false
  },
  "packageAppeal": {
    "error": "Unauthorized",
    "ok": false
  },
  "packageModerationStatus": {
    "error": "Unauthorized",
    "ok": false
  },
  "fixture": {
    "actorUserId": "<redacted>",
    "ownerHandle": "proof2285-...-owner",
    "packageName": "@proof2285-.../demo",
    "skillSlug": "proof2285-...-skill"
  }
}

This proof creates a stale personal-publisher membership for a non-linked actor and verifies that it cannot authorize direct skill transfer, package appeal submission, or owner-only package moderation status access.

Focused regression suite:

$ bun run test convex/publishers.test.ts convex/packages.public.test.ts convex/skills.ownership.test.ts
Test Files  3 passed (3)
Tests       167 passed (167)

Validation

$ bun run ci:unit
Test Files  204 passed (204)
Tests       1994 passed (1994)
Statements  85.98%
Branches    75.17%
Functions   86.37%
Lines        89.48%
$ bun run ci:types-build
tsc, package typechecks, clawhub-mod typecheck, Vite build, and Nitro build passed.

Current GitHub CI for this head also has unit, packages, types-build, e2e-http, playwright-smoke, and playwright-local-auth passing. The static job currently stops at bun audit on the existing transitive ws advisory GHSA-58qx-3vcg-4xpx.

@vyctorbrzezowski vyctorbrzezowski requested review from a team and Patrick-Erichsen as code owners May 16, 2026 04:00
@vercel
Copy link
Copy Markdown
Contributor

vercel Bot commented May 16, 2026

@vyctorbrzezowski is attempting to deploy a commit to the Amantus Machina Team on Vercel.

A member of the Team first needs to authorize it.

@openclaw-barnacle openclaw-barnacle Bot added the triage: refactor-only Candidate: refactor/cleanup-only PR without maintainer context. label May 16, 2026
@clawsweeper
Copy link
Copy Markdown

clawsweeper Bot commented May 16, 2026

Codex review: needs changes before merge.

Latest ClawSweeper review: 2026-05-24 03:27 UTC / May 23, 2026, 11:27 PM ET.

Workflow note: Future ClawSweeper reviews update this same comment in place.

How this review workflow works
  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.

Summary
This PR makes personal publishers linked-user-only for membership management and owner-scope authorization while preserving org publisher membership.

Reproducibility: yes. Source inspection shows current main and the PR head can grant skill version file reads from any getMemberRoleInternal result, while that internal query returns raw publisherMembers roles without checking whether the publisher is a linked personal publisher.

PR rating
Overall: 🧂 unranked krab
Proof: 🦞 diamond lobster
Patch quality: 🧂 unranked krab
Summary: Strong proof supports the covered paths, but the remaining action-side file-read authorization gap is a serious merge blocker.

Rank-up moves:

  • Fix getReadme/getFileText authorization for personal publishers.
  • Add focused regression coverage for stale personal member denial and org member allowance on skill version file reads.
What the crustacean ranks mean
  • 🦀 challenger crab: rare, exceptional readiness with strong proof, clean implementation, and convincing validation.
  • 🦞 diamond lobster: very strong readiness with only minor maintainer review expected.
  • 🐚 platinum hermit: good normal PR, likely mergeable with ordinary maintainer review.
  • 🦐 gold shrimp: useful signal, but proof or patch confidence is still limited.
  • 🦪 silver shellfish: thin signal; proof, validation, or implementation needs work.
  • 🧂 unranked krab: not merge-ready because proof is missing/unusable or there are serious correctness or safety concerns.
  • 🌊 off-meta tidepool: rating does not apply to this item.

Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics.

Real behavior proof
Sufficient (live_output): The PR body includes redacted live Convex output proving stale personal memberships are denied for representative transfer, package appeal, and package moderation status paths; the uncovered file-read path remains a code finding.

Risk before merge

  • Merging intentionally makes personal publishers linked-user-only, so stale or extra personal-publisher membership rows will fail closed instead of granting publish/manage access.
  • Any workflow that relied on collaborative membership on a personal publisher needs to move to org publisher membership.
  • The action-side skill version file reader still appears to honor raw publisherMembers roles, so a stale personal-publisher member can retain nonpublic getReadme/getFileText access unless this branch covers that path too.

Maintainer options:

  1. Fix action-side file access first (recommended)
    Update getReadme/getFileText authorization so stale personal-publisher memberships cannot read nonpublic skill version files while org members remain authorized.
  2. Accept linked-user-only personal publishers
    After the file-read gap is fixed, maintainers can intentionally accept that personal publishers are identity aliases and existing collaborative personal-publisher rows fail closed.
  3. Pause for collaboration policy
    Pause or close the PR if maintainers want personal publishers to retain team-like collaboration semantics instead of requiring org publishers.
Copy recommended automerge instruction
@clawsweeper automerge

Special instructions:
Patch the action-side skill version file access path so stale personal publisher membership rows do not authorize getReadme/getFileText. Add an internal query or helper that returns linked-user-only access for user publishers and preserves org membership access, then add focused regression tests for stale personal member denial and org member allowance.

Next step before merge
A narrow automated repair can cover the missed action-side file reader; maintainers still need to own the broader compatibility decision before merge.

Security
Needs attention: The diff tightens backend authorization overall, but one action-side skill file access gate still appears to honor stale personal-publisher membership rows.

Review findings

  • [P1] Guard skill version files with linked-user publisher access — convex/skills.ts:7712-7716
Review details

Best possible solution:

Route every owner-scope access path, including skill version file actions, through linked-user-only personal publisher logic and org membership logic, then merge only after maintainers accept the compatibility tradeoff.

Do we have a high-confidence way to reproduce the issue?

Yes. Source inspection shows current main and the PR head can grant skill version file reads from any getMemberRoleInternal result, while that internal query returns raw publisherMembers roles without checking whether the publisher is a linked personal publisher.

Is this the best way to solve the issue?

No, not yet. The linkedUserId-centered approach is the right maintainable direction, but it needs to cover action-side skill version file access before merge.

Label justifications:

  • P1: The PR changes active authorization checks for publisher-owned package and skill management/read paths and has a remaining security-boundary gap.
  • merge-risk: 🚨 compatibility: Existing stale or extra personal-publisher membership rows will stop authorizing access after merge.
  • merge-risk: 🚨 security-boundary: The diff changes which records authorize personal versus org publisher resources and still needs the action-side file-read path covered.
  • rating: 🧂 unranked krab: Current PR rating is 🧂 unranked krab because proof is 🦞 diamond lobster, patch quality is 🧂 unranked krab, and Strong proof supports the covered paths, but the remaining action-side file-read authorization gap is a serious merge blocker.
  • status: ⏳ waiting on author: ClawSweeper has contributor-facing work open and is waiting for author action. Sufficient (live_output): The PR body includes redacted live Convex output proving stale personal memberships are denied for representative transfer, package appeal, and package moderation status paths; the uncovered file-read path remains a code finding.
  • proof: sufficient: Contributor real behavior proof is sufficient. The PR body includes redacted live Convex output proving stale personal memberships are denied for representative transfer, package appeal, and package moderation status paths; the uncovered file-read path remains a code finding.

Full review comments:

  • [P1] Guard skill version files with linked-user publisher access — convex/skills.ts:7712-7716
    This branch updates many owner gates to ignore stale personal memberships, but canReadSkillVersionFiles still treats any getMemberRoleInternal result as access. Since getMemberRoleInternal returns raw publisherMembers roles without checking whether the publisher is kind: "user", a stale personal-publisher member can still read nonpublic getReadme/getFileText content. Route this action-side gate through the same linked-user-only personal publisher logic while preserving org membership access.
    Confidence: 0.86

Overall correctness: patch is incorrect
Overall confidence: 0.86

Security concerns:

  • [high] Stale personal member can still read skill version files — convex/skills.ts:7712
    canReadSkillVersionFiles calls getMemberRoleInternal, and the PR head still returns raw publisher membership roles there; this can preserve nonpublic skill file access for a stale member of a personal publisher.
    Confidence: 0.84

Acceptance criteria:

  • bun run test convex/versionFileAccess.test.ts convex/skills.public.test.ts convex/skills.ownership.test.ts convex/publishers.test.ts
  • bun run ci:unit
  • bun run ci:types-build

What I checked:

  • Live PR state and proof: The live PR is open at head 6fd4de1; its body includes redacted Convex runtime output for stale personal-membership denial on transfer, package appeal, and package moderation status paths, plus focused tests and CI. (6fd4de113e93)
  • Current-main vulnerable owner gate: Current main falls through from a non-linked personal publisher to getPublisherMembership in assertCanManageOwnedResource, which is the stale-membership authority pattern this PR is trying to close. (convex/lib/publishers.ts:129, 963b0a571943)
  • Candidate shared helper: The PR adds canAccessPublisherOwnerScope so user publishers authorize only linkedUserId equality, while org publishers still use membership roles. (convex/lib/publishers.ts:481, 6fd4de113e93)
  • Remaining action-side file-read gap: On the PR head, canReadSkillVersionFiles still grants access when getMemberRoleInternal returns any role for the skill owner publisher, so it does not distinguish stale personal-publisher rows from valid org membership. (convex/skills.ts:7712, 6fd4de113e93)
  • Raw membership internal query: The PR head keeps getMemberRoleInternal as a direct publisherMembers role lookup, which is fine for org callers but unsafe as the sole action-side gate for personal publishers. (convex/publishers.ts:890, 6fd4de113e93)
  • Existing file-access tests lack the stale-personal case: versionFileAccess.test.ts covers hidden skill file denial and org collaborator allowance, but the current test harness only supplies a raw publisherMemberRole and does not cover stale personal-publisher member denial. (convex/versionFileAccess.test.ts:112, 963b0a571943)

Likely related people:

  • Patrick-Erichsen: Git blame and merged PR metadata tie the current publisher membership helpers, package owner gates, skill owner gates, and action-side file access gate to the org/publisher release and adjacent org repair work. (role: feature-history owner and recent area contributor; confidence: high; commits: b753b1f7ab0e, b07196f336ae; files: convex/lib/publishers.ts, convex/publishers.ts, convex/packages.ts)
  • vyctorbrzezowski: Beyond authoring this PR, current-main history shows recent merged work on the skill listing surface that overlaps the dashboard/read paths changed here. (role: recent adjacent contributor; confidence: medium; commits: 07bf41e1091e; files: convex/skills.ts)

Codex review notes: model gpt-5.5, reasoning high; reviewed against 963b0a571943.

@vyctorbrzezowski vyctorbrzezowski force-pushed the contrib/personal-publisher-membership-guard branch from 7d3ffa9 to 33ffa7f Compare May 16, 2026 22:44
@clawsweeper clawsweeper Bot added P1 High-priority user-facing bug, regression, or broken workflow. impact:security Security boundary, credential, authz, sandbox, or sensitive-data risk. rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. merge-risk: 🚨 security-boundary 🚨 Merging this PR could weaken sandboxing, authorization, credentials, or sensitive data. and removed impact:security Security boundary, credential, authz, sandbox, or sensitive-data risk. labels May 16, 2026
@vyctorbrzezowski vyctorbrzezowski force-pushed the contrib/personal-publisher-membership-guard branch from 33ffa7f to 5f97962 Compare May 18, 2026 15:01
@vyctorbrzezowski
Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

@clawsweeper
Copy link
Copy Markdown

clawsweeper Bot commented May 18, 2026

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: the existing ClawSweeper review comment will be edited in place when the review finishes.

Re-review progress:

@vyctorbrzezowski vyctorbrzezowski force-pushed the contrib/personal-publisher-membership-guard branch from 5f97962 to 8f08815 Compare May 18, 2026 20:13
@vyctorbrzezowski
Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

@clawsweeper clawsweeper Bot added proof: sufficient Contributor real behavior proof is sufficient. status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action. and removed status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. labels May 18, 2026
@clawsweeper
Copy link
Copy Markdown

clawsweeper Bot commented May 18, 2026

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: the existing ClawSweeper review comment will be edited in place when the review finishes.

Re-review progress:

@clawsweeper
Copy link
Copy Markdown

clawsweeper Bot commented May 20, 2026

ClawSweeper PR egg

🔥 Warming up: real-behavior proof passed; findings, security review, or rank-up moves are still in progress.

Hatch command

Comment @clawsweeper hatch when this PR is hatchable.

Hatchability rules:

  • Merged PRs are hatchable.
  • Open PRs are hatchable when they are status: 👀 ready for maintainer look, status: 🚀 automerge armed, or labeled clawsweeper:automerge.
  • Closed unmerged PRs are hatchable only when one of those hatchable labels is still present in the durable record.
What is this egg doing here?
  • Eggs appear after the PR passes real-behavior proof. It is here for vibes, not verdicts: it does not change labels, ratings, merge decisions, or automation.
  • The shell reacts to review momentum: open follow-up work warms it up, re-review makes it wobble, and a clean final review lets it hatch.
  • Hatchability usually comes from sufficient real-behavior proof, no blocking P0/P1/P2 findings, no security attention needed, and clean correctness. A merged PR is already final, so merge makes the egg hatchable independently.
  • The hatch is seeded from this repository and PR number, so the same PR keeps the same creature; the reviewed head SHA can only change safe visual details.
  • Rarity is just collectible sparkle: 🥚 common, 🌱 uncommon, 💎 rare, ✨ glimmer, and 🌈 legendary.

@vyctorbrzezowski vyctorbrzezowski force-pushed the contrib/personal-publisher-membership-guard branch from 16ece38 to 6fd4de1 Compare May 21, 2026 16:06
@clawsweeper clawsweeper Bot removed the rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. label May 21, 2026
@clawsweeper clawsweeper Bot added rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. merge-risk: 🚨 compatibility 🚨 Merging this PR could break existing users, config, migrations, defaults, or upgrades. and removed status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action. labels May 21, 2026
@clawsweeper clawsweeper Bot added rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action. and removed rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. labels May 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

merge-risk: 🚨 compatibility 🚨 Merging this PR could break existing users, config, migrations, defaults, or upgrades. merge-risk: 🚨 security-boundary 🚨 Merging this PR could weaken sandboxing, authorization, credentials, or sensitive data. P1 High-priority user-facing bug, regression, or broken workflow. proof: sufficient Contributor real behavior proof is sufficient. rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action. triage: refactor-only Candidate: refactor/cleanup-only PR without maintainer context.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant