Skip to content

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.

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/v1
kind: Policy
metadata:
name: block-bulk-customer-export
spec:
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.

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.

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/v1
kind: PolicyTest
metadata:
name: export-rules
cases:
- 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.