Policy files
A policy file is YAML. apiVersion is vulnify.io/v1. kind is Policy or PolicyTest. Several documents may share one file. Separate them with ---.
The JSON Schema is https://docs.vulnify.io/schemas/policies.v1.json. It is a byte copy of schema/policies.v1.json from the Node.js SDK. vulnify policies validate checks kind: Policy documents against that schema and prints file:line errors. The Python package vendors the same bytes.
vulnify init writes the two examples below.
kind: Policy
Section titled “kind: Policy”metadata.name is the policy name. It is 1 to 120 characters and unique per organization. spec is the policy without that name.
spec.action is the action family: ANY, READ, WRITE, DELETE, or EXPORT. A specific event action such as EXPORT_DATA belongs in condition.action, and in a test input.action.
spec.resource is a resource type, not the resource name an event sends. The types are ANY, PUBLIC, INTERNAL, SENSITIVE, CUSTOMER_PII, FINANCIAL, and EMPLOYEE. ANY and null match every type. The resource name (customers-db in the test below) is only on the test input.
apiVersion: vulnify.io/v1kind: Policymetadata: name: block-bulk-customer-exportspec: description: Block exports of more than 1000 customer records enabled: true action: EXPORT resource: CUSTOMER_PII condition: minRecords: 1001 decision: BLOCK mode: ENFORCE approverRoles: - OWNER - ADMIN| Field | Required | Meaning |
|---|---|---|
description |
no | Up to 500 characters. |
enabled |
no | Defaults to true. |
action |
yes | Action family. |
resource |
no | Resource type. Null and ANY match every type. |
condition |
no | See below. Every field that is set must match. |
decision |
yes | ALLOW, REVIEW, or BLOCK. |
mode |
no | ENFORCE (default) or MONITOR. |
approverRoles |
no | OWNER, ADMIN, MEMBER. Empty means owners and admins. Used when decision is REVIEW. |
policies pull may also write metadata.id and metadata.updatedAt. policies apply ignores them.
Conditions
Section titled “Conditions”A condition is the policy-engine object. It is not a comparison object. recordsAffected: { gt: 1000 } does not validate. More than 1000 records is minRecords: 1001, because minRecords means recordsAffected is greater than or equal to that integer.
| Field | Meaning |
|---|---|
action |
Event action: READ_DATA, WRITE_DATA, DELETE_DATA, EXPORT_DATA, or SEND_EMAIL. |
destination |
EXTERNAL matches EXTERNAL_EMAIL and EXTERNAL_API. INTERNAL matches INTERNAL. |
destinationContains |
Substring of the destination, 1 to 100 characters. |
containsSensitiveData |
The resource holds sensitive data. |
minRecords |
recordsAffected is greater than or equal to this integer. |
maxRecords |
recordsAffected is less than or equal to this integer. |
minRiskScore |
Integer from 0 through 100. |
outsideBusinessHours |
Outside Monday–Friday 09:00–18:00 in the organization time zone. |
agentIds |
Agent ids. Each id is a UUID. |
allOf |
Every nested condition matches. An empty allOf matches. |
anyOf |
At least one nested condition matches. An empty anyOf does not. |
Groups may nest. The API also accepts dlpTypes and lgpdCategories on a dashboard condition. Those two fields are not in the YAML schema. vulnify policies validate rejects them.
ALLOW on a policy overrides the risk engine. REVIEW and BLOCK tighten it. MONITOR records what would have happened. Organization monitor mode is separate. See Policies.
kind: PolicyTest
Section titled “kind: PolicyTest”input.action is the event action. input.resource is the resource name registered in Vulnify, not the policy resource type. expect.policy is metadata.name of a Policy document. expect may be omitted. The result then has pass: null and the CLI prints SKIP.
apiVersion: vulnify.io/v1kind: PolicyTestmetadata: name: export-rulescases: - name: bulk export is blocked input: agent: support-bot action: EXPORT_DATA resource: customers-db recordsAffected: 5000 expect: decision: BLOCK policy: block-bulk-customer-export| Input field | Required | Meaning |
|---|---|---|
agent |
yes | Agent name, 1 to 100 characters. |
action |
yes | READ_DATA, WRITE_DATA, DELETE_DATA, EXPORT_DATA, or SEND_EMAIL. |
resource |
yes | Resource name, 1 to 100 characters. |
destination |
no | INTERNAL, EXTERNAL_EMAIL, or EXTERNAL_API. |
recordsAffected |
no | Integer from 0 through 100000000. |
containsSensitiveData |
no | Boolean. |
metadata |
no | Object. The API accepts it and does not use it. |
expect.decision is required when expect is present. expect.policy is the expected matched policy name.
vulnify test posts these cases to POST /v1/policies/test. One file, or the whole vulnify/tests directory, may hold up to 200 cases in one request. See CLI and policies as code.

