Repository navigation
feat(auth): make artifacts private to their owner with three sharing levels - #18
Merged
Merged
Conversation
Every artifact gets an owner (the version 1 publisher) and one of three levels: private (default), organization (account_required) and public (public_link). Only the owner lists an artifact. Adds AUTH-032 to AUTH-037 and DSP-014 as specified, records decision 0032, and rewords SCP-008, AUTH-008, CMT-006, CMT-007 and ADM-005. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Qwpo6f39DCmJkJwz5ahK1p
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Qwpo6f39DCmJkJwz5ahK1p
Every artifact stores owner_principal_id, backfilled from the version 1 publisher on SQLite, Postgres and D1, and the access CHECK accepts private. Repository lists return the viewer's own artifacts, plus service-owned ones for human administrators. Mailbox bundles resolve dispatched threads by id, so a service-key agent no longer depends on listing a member's artifacts. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Qwpo6f39DCmJkJwz5ahK1p
A principal sees an artifact it controls, or one shared beyond Private when it holds read authority; otherwise the artifact reads as missing. Only the owner, or a human administrator for a service-owned artifact, controls it. The owner or any human administrator may lower its level. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Qwpo6f39DCmJkJwz5ahK1p
Every artifact-scoped read checks visibility after loading the artifact: get, versions, files, archive, media, comparisons, actions, comments, content bootstrap, preview leases, linked live origins and the Git clone token, over HTTP and MCP. A principal that cannot read receives the same 404 as for a missing artifact. HTTP and MCP inputs accept the private level. The spec exempts dispatch records and agent presence, which carry no artifact data, and gives anonymous requests the same sign-in requirement for Private as for Organization. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Qwpo6f39DCmJkJwz5ahK1p
HTTP and MCP lists, search, tag filters and comment sort return the reader's artifacts only; an administrator's list adds service-owned ones. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Qwpo6f39DCmJkJwz5ahK1p
…elete Publishing, capture, relink, restore, tags, review mode and raising the level require control of the artifact on top of the existing capability gates. Lowering is also open to any human administrator, who may delete any artifact, Private ones included. Comment writes need visibility; deleting others' comments with manage:any, and bulk clearing, need control or a human administrator. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Qwpo6f39DCmJkJwz5ahK1p
HTTP, MCP, linked artifacts and the CLI create Private artifacts by default; the CLI gains --organization beside --public, and the two conflict. MCP capabilities list three levels. The local API token counts as a service principal, so the local administrator reads and lists what it publishes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Qwpo6f39DCmJkJwz5ahK1p
Agents connect with service keys and cannot read a Private artifact, so creating a dispatch for its threads fails with 409 ARTIFACT_PRIVATE and creates nothing. A sender that cannot read the artifact receives the usual not-found response. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Qwpo6f39DCmJkJwz5ahK1p
ARTIFACT_SERVER_ORGANIZATION_NAME, at most 64 characters without control characters, reaches the session response as installation.organizationName. Helm exposes it as configuration.organizationName, and Compose passes it through. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Qwpo6f39DCmJkJwz5ahK1p
A General access selector replaces Manage access and saves on change, confirming in place before Public and returning to the saved level on failure. Non-owners see it disabled; administrators may only lower. At Public a Public link row comes first. Management controls follow the artifact's owner, and the admin bulk action reads Stop public access. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Qwpo6f39DCmJkJwz5ahK1p
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Qwpo6f39DCmJkJwz5ahK1p
AUTH-032 to AUTH-037 and DSP-014 move to behavior_verified with the local, browser and external-storage runs. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Qwpo6f39DCmJkJwz5ahK1p
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Qwpo6f39DCmJkJwz5ahK1p
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Qwpo6f39DCmJkJwz5ahK1p
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Artifacts are private to their owner unless shared. Each artifact has an owner, the principal that published version 1, and one of three sharing levels:
privateaccount_requiredpublic_linkOnly the owner sees an artifact in lists. Human administrators also list service-owned artifacts, lower any level and delete any artifact, but cannot read a member's Private one.
Spec:
project/spec/artifact-sharing-levels-spec.md. Decision:project/spec/decisions/0032-owner-private-artifacts.md.Changes
owner_principal_idon SQLite (schema 15), Postgres (migration 0014) and D1 (v12), backfilled from the version 1 publisher. The access CHECK allowsprivate. List queries filter by owner.manage:anyrequire control.--organization, which conflicts with--public. The local API token counts as a service principal.ARTIFACT_PRIVATE. Mailbox bundles resolve threads by id instead of by listing artifacts.ARTIFACT_SERVER_ORGANIZATION_NAME/ Helmconfiguration.organizationNameappears in the session response asinstallation.organizationName.behavior_verified. SCP-008, AUTH-002, AUTH-008, AUTH-030, CMT-006/007/008, PRS-005 and ADM-005 are reworded.Behaviour change for existing installations
@plannotator/agent-bridgepackage finds dispatched threads by listing artifacts, so service-key agents using it will see empty bundles until it is updated.Test Plan
pnpm verify:iteration: everything passes except:--maxWorkers=8run (438/438).test:compact-compose,test:external-storage-composeandtest:helm. The local Docker driver has no buildx attestation or arm64 emulation, so CI proves them.pnpm verify:external-storage-runtime: 23/23 against Postgres and MinIO.🤖 Generated with Claude Code
https://claude.ai/code/session_01Qwpo6f39DCmJkJwz5ahK1p