Skip to content

fix: restrict membership management to org publishers#2285

Merged
Patrick-Erichsen merged 21 commits into
openclaw:mainfrom
vyctorbrzezowski:contrib/personal-publisher-membership-guard
May 27, 2026
Merged

fix: restrict membership management to org publishers#2285
Patrick-Erichsen merged 21 commits into
openclaw:mainfrom
vyctorbrzezowski:contrib/personal-publisher-membership-guard

Conversation

@vyctorbrzezowski

@vyctorbrzezowski vyctorbrzezowski commented May 16, 2026

Copy link
Copy Markdown
Contributor

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

vercel Bot commented May 16, 2026

Copy link
Copy Markdown
Contributor

@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

clawsweeper Bot commented May 16, 2026

Copy link
Copy Markdown
Contributor

Codex review: found issues before merge. Reviewed May 27, 2026, 4:49 PM ET / 20:49 UTC.

Summary
The PR changes publisher, skill, and package authorization so personal publishers authorize by linked user rather than extra membership rows, with regression tests and an orgs spec note.

Reproducibility: yes. from source inspection: current main still checks publisherMembers for personal-publisher owner scopes in helpers such as assertCanManageOwnedResource and package owner access. I did not run a live exploit locally because this is a read-only review, but the PR body includes live Convex denial proof for representative stale-membership paths.

Review metrics: 2 noteworthy metrics.

  • Diff size: 13 files, +2825/-128 vs merge base. The PR touches multiple authorization paths and a large regression-test surface, so maintainers should review it as a security-boundary change rather than a small refactor.
  • Merge refresh: 4 changed-in-both sections. The branch needs conflict resolution against current main before CI or mergeability can settle the final patch.

Merge readiness
Overall: 🐚 platinum hermit
Proof: 🦞 diamond lobster
Patch quality: 🐚 platinum hermit
Result: ready for maintainer review.

Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch.

Rank-up moves:

  • Resolve the current merge conflicts against main while preserving the moderated skill file/tag guard changes from the newer main branch.
  • Remove the CHANGELOG.md entry and keep release-note context in the PR body/spec.

Risk before merge

  • The branch is currently dirty against main; conflict resolution must preserve the current-main moderated skill file/tag guards from fix(api): guard moderated skill files and tags #2287 while applying this PR's personal-publisher checks.
  • This intentionally removes stale personal-publisher membership as an authorization path, so any user relying on accidental personal-publisher collaboration will lose that access and must use org publishers instead.
  • The PR changes security-sensitive owner-scope gates for publishing, transfers, private/package moderation reads, appeals, and skill file reads; a missed path would either preserve stale access or break legitimate linked-user/org access.

Maintainer options:

  1. Refresh And Preserve Main Guards (recommended)
    Resolve the current changed-in-both sections against main while preserving the moderated skill file/tag fixes that landed after this branch diverged.
  2. Accept Linked-User-Only Personal Publishers
    Maintainers can intentionally accept that stale personal-publisher membership rows stop granting access, with org publishers as the supported collaboration path.
  3. Pause For Migration Policy
    If stale personal-publisher collaboration needs a user-facing migration or cleanup flow first, pause this PR until that policy is explicit.

Next step before merge
Maintainers should have the author refresh the dirty branch, remove the changelog edit, and explicitly own the compatibility/security-boundary decision before merge.

Security
Cleared: No supply-chain concern was found; the diff tightens authorization boundaries but needs the merge-refresh and compatibility decision called out above.

Review findings

  • [P3] Remove the release-owned changelog edit — CHANGELOG.md:19
Review details

Best possible solution:

Refresh the branch against current main, remove release-owned changelog churn, keep the linked-user-only personal publisher boundary, and land it with the existing live proof plus targeted regression coverage.

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

Yes, from source inspection: current main still checks publisherMembers for personal-publisher owner scopes in helpers such as assertCanManageOwnedResource and package owner access. I did not run a live exploit locally because this is a read-only review, but the PR body includes live Convex denial proof for representative stale-membership paths.

Is this the best way to solve the issue?

Yes, the linked-user-only helper is the right security shape for personal publishers, with org publishers retaining membership roles. The merge-safe version should drop the changelog edit and be rebased so it composes with the current moderated file/tag guards.

Full review comments:

  • [P3] Remove the release-owned changelog edit — CHANGELOG.md:19
    CHANGELOG.md is release-owned for normal PRs in this review lane, and this PR already carries the needed release-note context in its body. Please drop this line so release owners can compose the final changelog entry when shipping.
    Confidence: 0.91

Overall correctness: patch is correct
Overall confidence: 0.78

AGENTS.md: found and applied where relevant.

Codex review notes: model gpt-5.5, reasoning high; reviewed against 97023d3123f4.

Label changes

Label changes:

  • add rating: 🐚 platinum hermit: Overall readiness is 🐚 platinum hermit; proof is 🦞 diamond lobster and patch quality is 🐚 platinum hermit.
  • add status: 👀 ready for maintainer look: ClawSweeper has no concrete contributor-facing blocker left for this PR. Sufficient (live_output): The PR body includes redacted live Convex output demonstrating after-fix denial of stale personal-membership access for transfer, package appeal, and package moderation status paths.
  • remove rating: 🧂 unranked krab: Current PR rating is rating: 🐚 platinum hermit, so this older rating label is no longer current.
  • remove status: ⏳ waiting on author: Current PR status label is status: 👀 ready for maintainer look.

Label justifications:

  • P1: This is a security-sensitive authorization fix for publisher ownership and package/skill management paths.
  • merge-risk: 🚨 compatibility: Existing stale personal-publisher memberships will no longer authorize workflows that may have accidentally worked before.
  • merge-risk: 🚨 security-boundary: The PR changes who can publish, transfer, appeal, and read owner-only resources through publisher ownership gates.
  • rating: 🐚 platinum hermit: Overall readiness is 🐚 platinum hermit; proof is 🦞 diamond lobster and patch quality is 🐚 platinum hermit.
  • status: 👀 ready for maintainer look: ClawSweeper has no concrete contributor-facing blocker left for this PR. Sufficient (live_output): The PR body includes redacted live Convex output demonstrating after-fix denial of stale personal-membership access for transfer, package appeal, and package moderation status paths.
  • proof: sufficient: Contributor real behavior proof is sufficient. The PR body includes redacted live Convex output demonstrating after-fix denial of stale personal-membership access for transfer, package appeal, and package moderation status paths.
Evidence reviewed

Acceptance criteria:

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

What I checked:

  • AGENTS.md policy read: Read the full repository AGENTS.md; its Convex guidance, security-sensitive spec guidance, and PR/release hygiene informed this review. (AGENTS.md:1, 97023d3123f4)
  • Current main still needs the fix: Current main's owned-resource helper returns for a linked personal publisher but then falls through to publisher membership checks, so a stale personal membership row can still authorize some owner-scope paths. (convex/lib/publishers.ts:130, 97023d3123f4)
  • Package owner reads still use membership on main: Current main's package owner read/manage helpers accept publisherMembers rows before verifying a user publisher's linked user, leaving the central package-access issue unsolved on main. (convex/packages.ts:697, 97023d3123f4)
  • PR central implementation: The PR adds canAccessPublisherOwnerScope so user publishers authorize only the linked user, with legacy unlinked personal publishers falling back to ownerUserId; org publishers keep role-based membership checks. (convex/lib/publishers.ts:487, bc60c281dff4)
  • Spec intent added: The PR records the intended invariant that personal publishers are identity aliases and authorization must key off linkedUserId rather than extra membership rows. (specs/orgs.md:255, bc60c281dff4)
  • Real behavior proof: The PR body includes redacted live Convex output showing stale personal memberships are denied for direct skill transfer, package appeal submission, and package moderation status access, plus focused and full validation summaries. (bc60c281dff4)

Likely related people:

  • vyctorbrzezowski: Authz hardening around package publish owners and moderated skill file access landed recently on current main, directly adjacent to this PR's package/skill ownership paths. (role: recent adjacent contributor; confidence: high; commits: 707d39092391, 97023d3123f4; files: convex/packages.ts, convex/skills.ts, convex/versionFileAccess.test.ts)
  • Patrick-Erichsen: Recent publisher/org tooling and release commits touch the publisher ownership area and the current PR branch also contains follow-up commits by this author. (role: recent area contributor; confidence: medium; commits: 30bf8f252a7c, 5ed0ddd06675; files: convex/publishers.ts, convex/lib/publishers.ts, CHANGELOG.md)
  • Peter Steinberger: The org publisher ownership feature and lifecycle permission alignment appear in the history of the publisher membership model this PR is tightening. (role: feature introducer; confidence: medium; commits: f6ce8f9e1efa, 8287c494b20c; files: convex/publishers.ts, convex/lib/publishers.ts, specs/orgs.md)
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.

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.

@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

clawsweeper Bot commented May 18, 2026

Copy link
Copy Markdown
Contributor

🦞🧹
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

clawsweeper Bot commented May 18, 2026

Copy link
Copy Markdown
Contributor

🦞🧹
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

clawsweeper Bot commented May 20, 2026

Copy link
Copy Markdown
Contributor

ClawSweeper PR egg

✨ Hatched: 🥚 common Velvet Lint Imp

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.

Rarity: 🥚 common.
Trait: sparkles near resolved comments.
Image traits: location CI tidepool; accessory review stamp; palette plum, gold, and soft gray; mood mischievous; pose stepping out of a freshly hatched shell; shell smooth pearl shell; lighting bright celebratory glints; background subtle branch markers.
Share on X: post this hatch
Copy: My PR egg hatched a 🥚 common Velvet Lint Imp in ClawSweeper.

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
@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. and removed 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. labels May 27, 2026
@Patrick-Erichsen Patrick-Erichsen merged commit d854449 into openclaw:main May 27, 2026
19 of 20 checks passed
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: 🐚 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. triage: refactor-only Candidate: refactor/cleanup-only PR without maintainer context.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants