Write a retention/PI policy
A policy is the declarative YAML that decides, for every PI-marked field, what
ScaiLog does with it — and how long entries are kept. Developers mark a field as
PI with pi(value, pi_type); the policy is where you, as an operator, turn that
pi_type into a concrete action per service and environment. Each tenant has one
active policy, versioned. Editing it needs the admin capability.
The four actions#
For each PI field the policy resolves to exactly one action:
| Action | Effect |
|---|---|
encrypt |
Store the value encrypted under the subject's per-subject DEK. Decryptable via DSAR; destroyed on erasure. This is what makes cryptographic erasure work. |
redact |
Replace the value with [REDACTED:<pi_type>] before storage. No plaintext, no ciphertext. |
drop |
Discard the field entirely; only its category is recorded. |
keep |
Store the value in plaintext. Lawful only for genuinely non-identifying types (pseudonymous); the validator warns otherwise. |
Author the YAML#
A policy is a policy name, a version, an optional match block, a list of
rules, and two retention settings. This is the built-in default:
1 2 3 4 5 6 7 | |
entry_retention_days is how long ordinary entries are kept; entries carrying PI
use the (typically shorter) pi_entry_retention_days. A rule targets a
pi_type and sets an action, optionally narrowed by service and
environment, and may set a per-rule retention_days. A richer example:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | |
Action default and the taxonomy#
A rule with action: default (and any field with no matching rule) falls through
to the built-in taxonomy default for that pi_type. The defaults are:
pi_type |
Default action |
|---|---|
direct_identifier |
encrypt |
online_identifier |
encrypt |
location |
encrypt |
financial |
encrypt |
freeform_user_content |
encrypt |
credentials |
drop |
special_category |
drop |
pseudonymous |
keep |
An unknown custom pi_type with no matching rule defaults to drop — the safe
choice is to never store PI you have not classified.
Most-specific resolution#
When several rules match a field, ScaiLog picks the most specific one. Each
condition adds to a specificity score: a concrete pi_type (not *) is worth 4,
a service match 2, an environment match 1; ties break toward the
later-declared rule. So in the example above, a direct_identifier field emitted
in dev resolves to drop (pi_type + environment = 5) while the same field in
prod resolves to encrypt (pi_type only = 4). Resolution runs across
(service, environment, pi_type); the match block scopes the whole policy to a
tenant/environment.
Whichever version resolved a given entry is frozen into that entry, so historical entries stay explainable even after you change the policy.
Validate and version it#
Validation runs server-side when you store a policy — the server checks the YAML,
rejects bad actions or malformed rules with a 400, and returns non-fatal
warnings (for example, using keep on an identifying pi_type). Store a new
version with the CLI:
1 2 3 | |
scailog policy edit surfaces any validation warnings after storing. The
underlying API is a GET/PUT pair:
1 | |
1 2 3 4 5 | |
A successful PUT stores a new version and returns { "version": N, "warnings": [...] }. Each store is a new version; the previous ones remain in
scailog policy history.