Coming soon. Depotex is in active development, so features and these docs may still change.

Policies

Control what users can do with rules that block, warn or adjust actions

Policies let administrators control how Depotex behaves in their organization. A policy watches one kind of action (an event, such as a repository being created), checks a condition, and then blocks the action, lets it through with a warning, or adjusts one of its values.

License: Pro or higher. Permissions: policies:read to view, policies:write to create and change, policies:admin to exempt users or roles. Organization admins can view and write policies; exemptions need a super admin.

1. Create a policy

This example limits sign-ins to your office and VPN networks. Every policy is made the same way: pick a template (or write a condition), test it, start it in dry run, then enforce it once its decisions look right.

Creating a policy: New policy, a template, its networks, Try it, then Create policy
Creating a policy: New policy, a template, its networks, Try it, then Create policy
  1. Open the policies — Go to Settings → Policies and select New policy. You need the policies:write permission (organization admins and super admins have it).
  2. Pick a template — Templates are grouped by area: Sign-in, API tokens, Profiles, Repositories and Other. The badge on each says what it does when it matches: Block, Warn or Adjust. Choose Sign in only from these networks. For a rule no template covers, choose Custom condition under Your own at the end of the list (see Conditions).
  3. Fill in the form — Give the policy a Name and an optional Description. Under Allowed IP ranges, enter one range per line, for example 10.0.0.0/8 and 192.168.0.0/16. Leave Message shown to the user empty to show the standard message in each person's language, or write your own (for example where to find the VPN).
  4. Set the priority — Priority decides the order when several policies watch the same event: lower numbers run first and the first policy that blocks wins (default 100). See Order and conflicts.
  5. Choose how it starts — Under Start in, keep Dry run (Recommended): the policy records what it would do without stopping anyone. Enforced applies it at once; Off saves it without running it.
  6. Test it — In Try it, edit the Sample payload (for example set ip to an address outside your ranges), set Actor roles if the condition uses them, and select Run test. The result says whether the condition matches and what the policy would do. Nothing is saved.
  7. Create it — Select Create policy. The policy opens on its own page with the tabs Settings, Decisions, Compliance, History and Exemptions, and the mode switch (Off, Dry run, Enforced) at the top.
  8. Watch, then enforce — Leave it in dry run for a few days and check Decisions for sign-ins it would have blocked. Add exemptions for accounts that must keep working (for example a break-glass admin), then select Enforced. Depotex asks first and says how many actions it would have affected in the last 7 days.
New policy: templates grouped by area, each with the effect it has
New policy: templates grouped by area, each with the effect it has
Try it: a sample sign-in from outside the ranges matches, so the policy would block it
Try it: a sample sign-in from outside the ranges matches, so the policy would block it
The new policy in dry run, with its Settings, Decisions, Compliance, History and Exemptions tabs
The new policy in dry run, with its Settings, Decisions, Compliance, History and Exemptions tabs

Test a sign-in policy before enforcing it. A Sign in only from these networks or Sign in only with these roles policy that matches your own address or role locks you out too. Keep a super admin exempted, or keep the policy in dry run until its decisions show only the sign-ins you meant to stop.

2. Managing policies

Go to Settings → Policies. The list shows each policy's event, effect, mode and priority, and what it did in the last 7 days (for example "3 blocked" or "4 would warn"); filter it by mode with All, Enforced, Dry run and Off. Open a policy to edit it, see its decisions, restore an earlier version, or manage exemptions.

Settings → Policies: each policy's event, effect, mode, priority and decisions in the last 7 days
Settings → Policies: each policy's event, effect, mode, priority and decisions in the last 7 days
  • New policy: templates are grouped by area (Sign-in, API tokens, Profiles, Repositories); pick one and fill in its form, or choose Custom condition under Your own to write your own: choose the event, write the condition (the fields you can use are listed under the event), choose what happens, and write the message people see. Start in sets the first mode; dry run is recommended.
  • Mode: switch an existing policy between Off, Dry run and Enforced at the top of its page. Enforcing asks first and says how many actions it would have affected in the last 7 days.
  • Try it: in the policy's settings, run the condition against sample data to see whether it would match, without saving. Changes wait in a bar at the bottom until you save or discard them.
  • Decisions: what the policy blocked, warned about, adjusted, or would have in dry run.
  • History: every saved version with what it changed (for example "Added 192.168.12.0/24 to Allowed IP ranges"), who saved it and when; Restore saves an older one as the newest version.
  • Exemptions: users or roles the policy skips (super admins only).

When a warn policy matches, people see its message as a notice in the corner of the screen; when a block policy matches, they see its message instead of the action happening.

3. Templates

Templates cover common rules without writing a condition. Pick one under New policy, fill in its form, and Depotex builds the condition for you. The message people see is a standard one, translated into each person's language; write your own message to replace it.

A policy made from a template: its rule, effect, message and priority
A policy made from a template: its rule, effect, message and priority
TemplateWhat it doesYou set
Sign in only from these networksBlocks sign-ins from IP addresses outside your rangesIP ranges, such as 10.0.0.0/8 or 2001:db8::/32
Sign in only with these rolesBlocks sign-ins by users whose role isn't listedRoles
Turn off “Remember me”Sessions end when the browser closesNothing
Maximum API token lifetimeBlocks API tokens that never expire or last too longDays (1 to 3650)
API tokens need an IP allowlistBlocks API tokens created without an IP allowlistNothing
Keep permissions out of API tokensBlocks API tokens that include listed permissionsPermissions, such as users:delete
Preset avatars onlyBlocks uploaded profile picturesNothing
Allowed repository formatsBlocks new repositories in formats you haven't selectedFormats
Refuse components under some licensesQuarantines artifact versions, and refuses application SBOMs, that list a component under one of your licensesLicense identifiers, such as AGPL-3.0-only
Refuse SBOMs with severe vulnerabilitiesQuarantines versions, and refuses application SBOMs, whose components have a known vulnerability of the severities you pick (VEX assessments applied); checked again when new advisories arriveSeverities
Refuse SBOMs with fixable severe vulnerabilitiesThe same, but only vulnerabilities that already have a fixed version countSeverities
Refuse SBOMs with low coverageQuarantines versions, and refuses application SBOMs, whose SBOM coverage is in the bands you pick (too little is known to tell whether they are safe)Coverage bands
Require complete SBOMs with package URLsQuarantines versions, and refuses application SBOMs, whose components lack package URLs or that were cut at the component limitNothing
Require an SBOMQuarantines versions that have no SBOM, published with them or made by Depotex from their metadataNothing (add a repository condition to leave proxies alone)
Refuse vibe check-ins with some findingsRefuses a push to a vibe project when its scan finds one of the findings you pickFindings
Refuse vibe check-ins with severe findingsRefuses a push to a vibe project when its scan finds something of the severities you pickSeverities

The SBOM and vibe templates are listed under Other; see SBOMs & vulnerabilities and Quarantine for what a quarantined version means. Turn off “Remember me” adjusts the sign-in instead of blocking it; every other template blocks.

A policy made from a template opens in the same form when you edit it. Switch to custom condition turns it into a custom policy, starting from the condition the template built.

Sign-in templates run on every sign-in, and each sign-in is checked against every range or role you list (up to 100). That stays well under a millisecond, but a dry-run sign-in template writes a decision for every sign-in it would block, which on a busy system adds up; review it and switch it to enforce or off.

4. What a policy can do

EffectWhat happens when the condition is true
Block (deny)The action doesn't happen. The user sees the policy's message.
Warn (warn)The action happens, and the user sees the policy's message as a warning.
Adjust (set)The action happens with the values you set, for the fields the event allows (for example a repository's description).

Policies only restrict: they never let anyone do something their role doesn't already allow.

5. Modes

ModeMeaning
dry_runRecords what the policy would have done, without doing it. New policies start here.
enforceThe policy takes effect.
offThe policy is ignored.

Start every policy in dry run, check its decisions for a few days, then switch it to enforce.

6. Conditions

Conditions are short expressions in CEL (Common Expression Language). They can use:

NameContains
payloadThe action's details, e.g. payload.format for a new repository. Passwords and secrets are never included.
actorWho is acting: actor.id (e.g. user:42), actor.roles, actor.org
nowThe current time
!(payload.format in ["raw", "npm"])                 // anything other than raw or npm
!payload.name.startsWith("team-")                   // names must start with team-
!("org_admin" in actor.roles) && payload.format == "docker"

Sign-on policies use auth.login, checked after the password is verified and before the session starts:

!payload.ip.startsWith("10.20.")                    // only from the office network
payload.remember_me                                   // with effect "set" {"remember_me": false}: no long sessions
payload.expires_at == null                            // on apitoken.create: tokens must expire

A sign-on policy only refuses a sign-in after the password was correct, so its message tells the person their password worked. Keep sign-on messages general if that matters to you.

A condition must be true or false, may only use the fields the event provides (checked when you save), and has a size limit so it always runs quickly. GET /api/policies/events lists the events that accept policies and their fields.

7. Order and conflicts

  • Policies run in order of priority (lower first).
  • The first enforced block stops the action; warnings from all matching policies are shown.
  • If two policies adjust the same field, the one with the lower priority wins.
  • If a policy's condition fails to run, the action goes ahead, except on security-sensitive actions, where it is blocked.

8. Events that accept policies

auth.login, apitoken.create, apitoken.update, apitoken.rotate, apitoken.org_policy.update, avatar.update, alert.create and, in the sample app, depot.repository.create. See the Events reference.

9. Exemptions

Exempt a user (user:42) or a role (role:org_admin) from a policy, with a reason and an optional expiry date. Exemptions are logged, like every policy change.

10. Compliance: checking what already exists

A policy only checks actions when they happen, so things created before it existed never meet it — for example API tokens created before a 90-day limit. The policy's Compliance tab lists existing items that the policy would block or warn about if they were created today.

  • Depotex checks every block and warn policy that is on each night; Check now runs it immediately (needs policies:write).
  • It only reports. Nothing is changed, revoked or deleted: decide what to do with each item yourself.
  • Each item is checked with its owner as the actor, and exemptions apply.
  • Available for API tokens and repositories. Sign-in policies can't be checked this way (there's nothing lasting to check).
  • A check reads at most POLICY_SCAN_MAX_ITEMS items (10,000 by default) and is marked as incomplete beyond that.

11. Decisions and history

  • Every time a policy blocks, warns, adjusts, would have done so in dry run, is skipped by an exemption or fails, a decision is recorded (kept 30 days, POLICY_DECISION_RETENTION_DAYS).
  • Every change creates a new version; you can roll back to any earlier version.

12. Performance

  • An action with no policies for your organization isn't slowed down.
  • Each policy on an event is checked while the user waits, in well under a millisecond for typical conditions; the total is capped by POLICY_EVAL_BUDGET (50 ms by default).
  • Every time a policy matches, a decision is written to the database. A policy that matches almost everything on a busy event — for example a dry-run policy with condition true on auth.login — writes a decision for every sign-in. Keep conditions specific and don't leave broad dry runs running.
  • Changes to policies take effect immediately on all servers with Redis, and within POLICY_CACHE_TTL (10 s) without it.

Very complex conditions (large lists, nested loops) take longer and can hit the size limit (POLICY_COST_LIMIT), in which case they count as a failed check. Prefer several simple policies to one complex one.

13. API

MethodEndpointPermissionDescription
GET/api/policies/eventspolicies:readEvents that accept policies, with their fields
GET/api/policies/templatespolicies:readTemplates and their parameters
GET / POST/api/policiesread / writeList / create
GET / PUT / DELETE/api/policies/{id}read / write / writeView / change (send the version you edited) / delete
GET/api/policies/{id}/versionsreadHistory, with changedBy and changedByName
POST/api/policies/{id}/rollbackwrite{"version": 2}
GET / POST/api/policies/{id}/exemptionsread / policies:adminList / add {subject, reason, expiresAt}
DELETE/api/policies/{id}/exemptions/{exemptionId}policies:adminRemove an exemption
POST/api/policies/testwriteTry a draft policy on sample data without saving it
GET/api/policies/impactreadDecisions of the last 7 days per policy, counted by outcome: {data: [{policyId, counts: {deny: 3, would_warn: 4}}], since, days}
GET/api/policies/decisions?policyId=readDecisions, newest first (paginated)
GET/api/policies/{id}/compliancereadLatest compliance check and the items it found (paginated)
POST/api/policies/{id}/compliance/scanwriteCheck existing items now
curl -X POST /api/policies -H "Content-Type: application/json" -d '{
  "name": "Only raw and npm repositories",
  "event": "depot.repository.create",
  "mode": "dry_run",
  "condition": "!(payload.format in [\"raw\", \"npm\"])",
  "effect": "deny",
  "messageText": "Only raw and npm repositories are allowed."
}'

From a template: send template and templateParams instead of event, condition and effect. Parameter errors come back as fields named templateParams.<name>.

curl -X POST /api/policies -H "Content-Type: application/json" -d '{
  "name": "Tokens expire within 90 days",
  "template": "token_max_lifetime",
  "templateParams": {"days": 90}
}'

A blocked action returns 403 with "reason": "policy_denied". Warnings come back in the Depotex-Policy-Warnings response header (base64url-encoded JSON).

14. Settings

VariableDefaultDescription
POLICY_CACHE_TTL10sHow quickly a server picks up policy changes when Redis isn't available
POLICY_EVAL_BUDGET50msTime limit for checking an action's policies
POLICY_COST_LIMIT10000Maximum size of a condition's work
POLICY_DECISION_RETENTION_DAYS30How long decisions are kept
POLICY_SCAN_SCHEDULE30 3 * * *When the nightly compliance check runs (UTC)
POLICY_SCAN_MAX_ITEMS10000Most items one compliance check reads