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==versionlines inrequirements.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/andvendor/, images, fonts, binaries, files over 1 MiB, and lines that carry agitleaks:allowcomment. It does scan.envfiles. - 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 ascould 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.