Administer

Release policies

On this page

What a policy does

Governance skills guide the coding agent while it builds, and Valet doesn't check that the agent followed them. A release policy is a check Valet runs itself. Valet evaluates every new release of an artifact, app or agent against your organization's policies before the release goes live, whoever published it and however they did.

A policy is a checker configured for your organization. Each policy has an enforcement:

  • Monitor reports findings and never stops a release. New policies start in Monitor.
  • Block at a severity refuses a release that has a finding at or above that severity: info, low, medium, high or critical. It also refuses a release the checker couldn't evaluate.

A refused release never goes live, and the current release stays live.

Each release gets a release evaluation, made of one policy evaluation per policy. Each policy evaluation reports its findings: the severity, the rule, the file and line or the package, and how to fix it.

When every policy is Monitor, a release goes live at once, and its policies finish evaluating it after it is live.

The checkers

Valet ships two checkers:

catalog:osv

Name
Dependencies (OSV)
Finds
Packages with known vulnerabilities

catalog:secrets

Name
Secrets (gitleaks)
Finds
Credentials committed to the source

list_policies and valet policies checkers list both, with their settings.

Dependencies (OSV)

catalog:osv reads the packages a release pins and looks each one up in OSV.dev, a public vulnerability database run by Google. It reads:

  • npm: package-lock.json.
  • Python: the metadata of installed packages, and name==version lines in requirements.txt.
  • Go: the modules compiled into a Go program, or go.sum.

An app's build holds the exact versions it installed, so the checker reads the build as well as the source. It doesn't check operating-system packages, packages in the runtime image, or whether the vulnerable code is ever called.

The checker sends each package's ecosystem, name and version to api.osv.dev, and nothing else from the release. If your organization can't share its package list that way, don't add this policy.

Each finding takes its severity from the advisory, names the lowest version that fixes it, and links to the advisory on OSV.dev. The checker never passes a release it couldn't read in full. It errors when it can't reach OSV.dev, when a dependency file doesn't parse, or when the release has more than 20,000 packages.

The setting ignore takes comma-separated advisory IDs to skip. An ID matches the advisory's own ID or any of its aliases, such as a CVE- or GHSA- ID.

Secrets (gitleaks)

catalog:secrets scans a release's source with the default rules of gitleaks, about 220 rules that each match one vendor's credential format. The scan runs inside Valet and sends nothing out.

  • Every finding is high, except a generic API key, which the rule guesses from a name and randomness. That finding is medium.
  • A finding names the file and line, never the value it matched.
  • The scan skips lockfiles, node_modules/ and vendor/, images, fonts, binaries, files over 1 MiB, and lines that carry a gitleaks:allow comment. It does scan .env files.
  • It reads the source only, not the build.

The setting exclude takes comma-separated path globs of source files to skip, such as testdata/*,*.pem. A glob with no / also matches a file's name in any folder, so *.pem skips keys/dev.pem.

Add a policy

Start in Monitor to see what a policy finds before it blocks anything. A policy's name uses lowercase letters, digits and hyphens. Ask your agent:

Add a Valet release policy called dependencies that checks our packages with OSV. Start it in Monitor.
set_policy
{ "policy": "dependencies", "checker": "catalog:osv", "enforcement": "monitor" }

list_policies and valet policies show how each policy's evaluations came out over the last 30 days. For a Monitor policy, they count the releases it would have blocked at critical, high and medium.

Once the findings look right, make the policy block. Ask your agent:

Make the dependencies policy block releases at high.
set_policy
{ "policy": "dependencies", "checker": "catalog:osv", "enforcement": "block", "block_at": "high" }

Adding a policy with a name that exists replaces it, settings included, so pass every setting again. To pass one:

set_policy
{
  "policy": "secrets",
  "checker": "catalog:secrets",
  "settings": { "exclude": "testdata/*,*.pem" },
  "enforcement": "block",
  "block_at": "high"
}

What a change does

A change to a policy applies to releases not yet decided. Changing a policy's enforcement or settings never changes a decided evaluation, and a running policy evaluation keeps the checker and enforcement it started with. A running policy evaluation whose checker hasn't started yet uses the current settings. Removing a policy, or changing its checker, cancels its running policy evaluations, so releases that waited only on it go ahead.

So making a Block policy Monitor doesn't release a deploy it's already holding. Publish again, and the new release is evaluated under Monitor.

Publish with policies

A publish runs as before until the release is built. Then each blocking policy evaluates the release while Valet holds it, and nothing new is live yet. valet deploy prints Waiting for policies…, then each policy's status as it changes. A blocked deploy ends like this:

Waiting for policies (dependencies, secrets)…
  dependencies  pending (block at high)
  secrets       pending (block at high)
  secrets       passed (block at high)
  dependencies  blocked (block at high)
    high  build/workspace/package-lock.json  Command Injection in lodash (lodash@4.17.15) (osv/GHSA-35jh-r3h4-6jhm) [blocks]
      Fix: Upgrade lodash to 4.17.21
      More: https://osv.dev/vulnerability/GHSA-35jh-r3h4-6jhm
Error: deploy.policy_blocked: acme's policies blocked shop's changes: dependencies found 1 finding at high or above. Nothing was deployed; the current release is still live. Fix it and deploy again.

Over MCP, publish_site and publish_agent answer that the release waits for its policies, with the release evaluation's ID. publish_app answers before the build finishes, so the agent follows the build with get_build. Its deploy_state reads checking while policies hold the release and refused once they refuse it.

When every blocking policy passes, the release goes live. When one doesn't, the publish ends with one of two errors:

  • deploy.policy_blocked: a finding is at or above the policy's severity. The message names the policy and counts its findings.
  • deploy.policy_errored: the checker couldn't evaluate the release. The message names the policy and quotes the checker's error, such as could not reach OSV.dev.

Either way, nothing was deployed, and the current release is still live. See Error codes.

Fix it and publish again

For a blocked release, fix what the findings name, then publish again. Ask your agent:

Policies blocked the last release of shop. Read the findings, fix them, and publish again.

For an errored policy, publish again. A brief failure, such as OSV.dev not answering, clears on its own. If the policy keeps erroring, a member can change or remove it.

A new publish replaces a release that is still waiting. The replaced release never goes live, and Valet stops its evaluation.

While an agent's release waits, Valet refuses changes that would redeploy the agent, such as attaching a skill, with deploy.checking. Wait for the policies, or publish again.

Follow an evaluation

valet deploy waits up to 5 minutes for the policies. --wait-timeout changes the wait, and --no-wait skips it. When the wait ends first, the evaluation goes on. Ask your agent:

Check whether shop's release passed its policies.
get_evaluation
{ "name": "shop", "wait_seconds": 20 }

Both read the service's latest release evaluation: each policy's status, every finding with its file or package and its fix, and what Valet did with the release. wait_seconds waits up to 20 seconds for the evaluation or the deploy to change. To read an older evaluation, pass its ID, as evaluation_id or as the argument to valet policies show.

Remove a policy

Ask your agent:

Remove the dependencies release policy.
destroy_policy
{ "policy": "dependencies" }

New releases no longer evaluate the policy. Its running policy evaluations are canceled, so releases that waited only on it go ahead. See What a change does. Past evaluations stay on the releases they evaluated.

In the dashboard

  • Governance › Policies. Governance has two tabs: Standards, the skills, and Policies. Policies lists each policy with its checker, its enforcement, and whether it errored recently. Below the list, Blocked in the last 30 days shows each refused release with its service, commit, policy and first finding. Add policy picks a checker, then asks for a name, an enforcement and the checker's settings. Select a policy to change or remove it.
  • Releases. Every artifact, app and agent has a Releases tab. It lists each release, including those that never went live, with its author, when it was published, and its state: live, previous, checking, blocked, errored, superseded or building. Open a release to see each policy's findings: blocking policies first, then Monitor policies, marked Never blocks.
  • Attention. When an artifact, app or agent has a refused release newer than any release that went live or passed, the sidebar badge for its kind counts it. Its listing names the problem, with a Review release link to the release. A banner on its page lists the blocking findings and how to clear them. All three clear when a newer release goes live or passes. They also clear when you publish source that matches the live release exactly, such as by undoing the change the policy refused. That publish makes no new release, and the refused release still shows as blocked or errored.

Limits

  • Policies evaluate every release in the organization. A policy can't be limited to some services, and no service can be exempted.
  • An organization skill's releases are evaluated too, but the dashboard shows no Releases tab or attention for a skill. Follow a skill's evaluation with valet policies show.
  • Only the two catalog checkers exist. You can't add a checker of your own.