Browse docs
Docs / Admin & IT / Permissions
View as Markdown

Permissions

Swarmfile's permission model is built from access control lists (ACLs) applied to folders and files, layered on top of a per-project mode that decides what happens when no grant exists at all.

Read, comment, comment + upload, write, admin#

Every grant is one of five levels, and each level can be either an allow or a deny:

LevelLets you
readSee and download the contents of the folder or file
commentEverything read does, plus leave comments and @-mentions on files in the folder
comment_uploadEverything comment does, plus upload new files through the server-side upload route - a guest-reviewer tier, deliberately still below write: it does not grant overwrite, delete, rename, rollback, or restore on existing files
writeModify contents - create, edit, delete within the folder tree
adminManage grants on the folder or file itself, in addition to read/write

Each level implies everything below it, and the levels are ordered exactly as listed above. comment and comment_upload exist for guest reviewers and external collaborators - see External Collaborators & Sharing - who need to leave feedback (and, for comment_upload, drop off new files) without the ability to touch what's already there.

A grant is set on a specific folder or file and is inheritable down the tree beneath it. You don't have to re-grant access at every nesting level - set it once on a parent folder and everything under it inherits the grant. Depth isn't a tiebreaker: a grant closer to the file doesn't override one set higher up the tree. See below for exactly how multiple grants combine.

A grant applies to the item you name, not to its surroundings. Access is resolved per entry, so granting someone read or write on a single file lets them open that file (for example, by path or link) without granting the rest of the folder it sits in. The way to it stays walkable, though: a folder on the path to something a person holds a grant on still appears in listings and can be opened, and opening it returns only entries they can read and folders on the path to a grant - everything else stays filtered out. Grant the containing folder when the recipient needs the folder itself - to browse its other contents, or to create entries in it. Inheritance only means something for folders: a file has nothing beneath it to inherit, so a file grant's inheritance flag has no effect, and grants store it off whenever they are written or changed.

How resolution works#

When Swarmfile decides whether you can do something to a file, it walks up the ancestor chain from that file to the project root, collecting every grant that applies to you along the way.

Allow grants add up - they don't override each other. If more than one allow grant applies along that chain (say, read on the project root and write on a specific subfolder beneath it), the highest level wins, regardless of which grant is closer to the file. A grant lower in the tree can raise your access above what a parent folder gives you; nothing lower in the tree can reduce it. Only a deny restricts access below what an allow elsewhere in the chain provides.

Deny always wins. If a deny shows up anywhere in that ancestor chain, it overrides any allow found elsewhere in the chain - no matter which one is "closer" to the file. This is a deliberate, conservative default: a broad deny placed high up in a folder tree is a reliable way to lock something down, and nobody can accidentally punch a hole in it with a more specific allow lower down.

Where a deny doesn't reach today. Two known limits, so you can plan around them:

  • Read-deny during an identity-service outage. Grant checks depend on resolving who someone is; during a rare outage of the org's identity/membership service, open-mode reads are served best-effort so a whole project can't lock out, and publishing a public release fails closed in that state. Put folders that must stay restricted in a protected-mode project.
  • Changes reach a mounted drive in two stages. Granting or revoking access updates the hub immediately (the web dashboard, the CLI, and new mounts see it at once), and a mounted drive is pushed the change, so its cached permission answers refresh on the spot instead of waiting for a remount. A revoke goes further: the revoked folder is removed from that drive's listing and its cached file data is deleted, then confirmed back to the organization as a purge receipt. A newly granted folder is the remaining lag: it can still be missing from that drive's file listing - and writing into it may still need a reopen - until the mount is reopened.

Org owners bypass ACLs entirely. An owner can always get into any project, folder, or file in their org, regardless of what grants exist. ACLs govern members; they don't govern the owner.

Open vs. protected projects#

Each project runs in one of two modes, set at the project level:

  • Open mode - the default for new projects on every plan. Access is permissive: ACLs function as additive grants layered on top of general access, useful for restricting specific sensitive folders without having to explicitly grant everything else.
  • Protected mode - access is default-deny. Nothing in the project is accessible without an explicit grant. Use this for projects where you want to enumerate exactly who can see what, rather than opt specific things out. Protected is always an explicit choice: the web app and Desktop App offer it next to Open (both default Open), and an API or CLI create that omits the ACL mode gets Open - on every plan, including Pro and Enterprise. Protected mode itself needs Pro or above: creating a project as protected, or switching an existing one into protected mode, is refused server-side on Starter. Switching back to open is always allowed.

Switching a project's mode doesn't rewrite existing grants - it changes what happens when no grant matches at all. See Organizations, Projects & Members for project lifecycle and mode selection.

Access comes from grants, not membership. Joining an org through an invite adds the org role only, so a member with no grant on a protected project sees an empty project - the web files view says so explicitly ("you don't have access to any files here; ask an org admin") rather than pretending the project is empty. On a plan with ACLs (Pro and above), the Team tab's invite form can pre-grant whole-project Read or Write access alongside the invite, and the Team tab lists every member's whole-project grants next to their name; expanding a member's project there loads that project's folder- and file-level grants on demand, so an admin can inspect the full per-project picture without opening each project (a note appears when a page was capped). Folder- and file-level access is also managed under each project's Permissions tab.

Creating at the project root. A protected project's top level has no parent folder for a grant to inherit from, so a new file or folder created directly at the root - or an existing entry moved there - is allowed to an org owner, the project's creator, or a member holding a project-wide write (or higher) grant. A folder-scoped grant - even admin - does not authorize a root create; work inside an existing folder, or ask an owner to create the top-level folder. Overwriting an existing root file is ordinary write access to that file and does not need root authority - it adds no new top-level name. In an open project this is moot: any member who can write creates at the root like anywhere else. The web's Upload / New Folder controls, the desktop drive's root writes, and a git push whose commit adds or moves a name at the root follow the same rule.

Publishing a release on a protected project requires project-wide admin access. Org owners and the project's creator always pass, and a project API key passes with a project-wide write grant. A release publishes the tagged commit's entire tree to an anonymous URL, and the manifest walk doesn't filter per-entry ACLs, so a member holding only a folder-scoped grant could otherwise publish a tree containing folders they can't read. On an open-mode project, any member who can still write the project as a whole may publish. Deleting (unpublishing) a release requires the same access as publishing one. A member made read-only by a deny grant can do neither, and external collaborators can do neither.

You can't publish a release that contains anything you're denied read on. In either mode, if you hold a read deny on any file in the tagged tree, or on a folder along its path, the publish is refused with 403. The deny can be granted to you directly or to one of your groups, and it counts even when it doesn't inherit, because the release's paths would reveal the folder. A deny on a folder the tag doesn't include doesn't block the publish, and neither does a deny below read (a write deny, say). Ask an org owner or the project's creator to publish instead: a deny never limits what they can read. Unpublishing isn't subject to this check.

A publish fails safe when your permissions can't be checked. If Swarmfile can't look up your organization permissions at that moment, it can't tell whether you hold a deny, so the publish is refused with 503 and the error code org_unavailable. It's a temporary refusal, so retry shortly. If your read restrictions cover a very large part of the project, the publish is refused with 403 rather than checked file by file. Neither refusal applies to org owners or the project's creator, and unpublishing is never refused this way.

Creating or deleting a tag requires project-wide write. A tag names the whole tree at a commit, and it's what a release is published from. On an open-mode project that's every member by default. On a protected project you need a project-wide write (or higher) grant, since a folder-scoped grant isn't enough; org owners and the project's creator always pass. A project API key needs its own project-wide write grant in either mode.

Windows DACL projection#

On Windows, Swarmfile projects the effective ACL permissions it's enforcing down onto the actual NTFS-style DACL that Windows and Explorer see on the mounted drive. Permissions aren't just an app-level restriction invisible to the rest of the OS; they show up as real Windows ACL entries on the mount - what you see depends on your own role, by design:

  • Org admins and owners, and anyone with an explicit admin grant on a folder, see the full list of every principal with access to it - exactly what Explorer's Properties → Security tab is built to show.
  • Everyone else sees just their own effective access level on that folder - read, write, or none - not who else has access. The full roster is deliberately not browsable by ordinary members, the same way it isn't exposed anywhere else in the product: seeing it would let anyone map out an org's whole access structure just by opening folder properties.

Either way, the DACL Windows shows is never stale or invented - it's a live read of what Swarmfile is actually enforcing for the account looking at it.

Branch protection#

Folder ACLs govern who can touch content; branch protection is a separate governance control over how changes land. The day-to-day mechanics - protecting a branch, opening a merge request, the approval flow - are in Branches & Merging. What matters here is that protection is an org-admin control, not a project ACL: creating, editing, and removing protection requires an org admin (or owner) role, and it's enforced server-side regardless of any grant a member holds inside the project.

There are two ways to protect a branch, and they stack:

  • A per-branch flag - mark one named branch (say main) protected, with its own required-approval count.
  • Glob protection rules - a pattern like release/* protects every branch that matches it, now and in the future, with the rule's own required-approval count.

When both apply to the same branch, the effective required-approval count is the maximum of the per-branch flag's count and every matching rule's count (each configurable from 1 to 10). A rule can raise a branch's floor but never lower it below what the branch's own flag already requires.

Protection rules can also require CI checks to pass (--require-checks-to-pass), independently of the approval count; the per-branch flag has no checks toggle, so to gate one exact branch on CI use a no-wildcard rule (swarmfile protection-rule create main --require-checks-to-pass) - the CLI reference says the same. A branch counts as checks-gated if any matching rule says so - the same OR-based resolution the approval count uses. A CI check that's never reported for the exact commit being merged counts as failing, not skipped, so the gate can't be satisfied by a check nobody's configured to run yet.

A protection rule can additionally carry a list of auto-reviewers - a CODEOWNERS-style reviewer list scoped to whichever branches the rule matches. Every merge request opened against a matching branch automatically requests a review from each configured principal, on top of anyone requested by hand. This is bookkeeping, not enforcement: naming someone an auto-reviewer never makes their approval individually required - the required-approval count above is still the only lever for that.

On a protected branch, a direct merge is refused, and so is every direct write - saving, editing, renaming, moving, deleting, creating, uploading from the web, staging/committing, rolling back, resolving a conflict, auto-resolving one, or reflecting LFS content - with 409 protected_branch; the change has to go through a merge request that collects the required number of approvals before it can land. This is how protection forces review: there's no admin-only "just merge it" bypass on the protected branch itself, and a non-admin also can't archive a protected branch out from under the rule. Folder ACLs still govern who may attempt a write, but a grant cannot override protection.

Limitation. Self-review is blocked per user - the person who opened a merge request cannot approve it. That raises the cost of a unilateral change and creates an audit trail, but it is an identity check, not a cryptographic proof that two different humans reviewed the work: a second credential controlled by the same person can still approve. Treat the approval count as a control that raises that cost, not as a guarantee of independent review. Every protection change and every quarantine/ACL action lands in the activity feed - see the audit-log list in Operations.

Plan requirements and downgrades#

Folder ACLs and Windows DACL projection are Pro plan and above. They're enforced server-side - the server validates the org's plan entitlement before honoring an ACL operation, so plan gating can't be worked around from the client.

If an org is later downgraded below the tier that supports ACLs, existing grants keep working and nothing is silently opened up. The only thing that changes is:

  • Revoking or narrowing a grant - always available, on any plan. You can never be stranded unable to fix an over-broad permission just because the org downgraded.
  • Adding a new grant - blocked on a downgraded plan, until the org upgrades again.

This mirrors the downgrade behavior for identity features - see Identity - and is intentional: a downgrade should never leave you less secure, only less able to add new access.

For the broader security model - org isolation and storage separation - see Security.

Public access requests#

A public project accepts access requests from its public page by default (Project settings → Public access requests turns them off and on). Any registered Swarmfile user with a verified email - no organization membership - can then ask for one of three levels:

  • Comment access grants comment on the project's root Contributions folder - the same external collaborator tier, without a seat.
  • Contributor access grants comment_upload on that folder: new files only, no overwrite or delete. It is not write, and it never grants access outside the folder.
  • Membership mints the ordinary organization invitation (role member), which uses a seat; on a protected project the invitation also carries a whole-project write grant so the new member can see it.

Approvals run on the same checks as an owner-minted guest invitation: the external-collaborator ceiling and the spend cap. A refusal on either leaves the request pending with the reason, so buying seats or collaborators and approving again works. Free organizations can grant membership but not comment/contributor access - their public page offers membership only.

The project's owners and admins decide each request from the Project settings tab; the queue there and a badge on the Project settings tab show pending work. Guests and contributors an approval creates appear in External Collaborators & Sharing like any other external collaborator, and revoking them there removes the grant. Approving a guest or contributor request after the project stops being public (or is archived) is refused - use the sharing flow or restore the project instead.

The requester sees the status on the project page and in My requests, can withdraw a pending request, and gets an email on the decision. A declined requester can ask again, with a short message explaining what changed. Requests one person may have pending in an organization at once are capped; when a project is deleted, its requests are removed with it, and old requests age out after 180 days.