Repository navigation
Rule Based Policy
Rule-based policy lets you declare data-only rules for deciding which already-detected variables should be masked or ignored.
Policy can be configured in setup() or .camouflage.yaml. It never executes project code and it cannot make unsupported files parseable. A mask rule can only affect values that a parser or custom pattern already found.
Policy decisions are deterministic:
-
terminal_path_ignoresignore matching root-relative paths first. - A matching
action = 'mask'rule withallow_force = truecan override a terminal path ignore. - For normal ordered rules, the first matching rule wins.
- A later
allow_force = truemask rule can override an earlier broad ignore rule. - If nothing matches,
default_actionis used. The default ismask.
When policy is disabled, variables are masked normally and policy reports policy_disabled.
require('camouflage').setup({
policy = {
enabled = true,
default_action = 'mask', -- 'mask' | 'ignore'
terminal_path_ignores = { '.git/**', 'node_modules/**' },
rules = {
{
id = 'ignore-debug-flags',
action = 'ignore',
key = { '^DEBUG$', '^PORT$' },
parser = { 'env', 'json', 'yaml' },
},
{
id = 'force-client-secrets',
action = 'mask',
allow_force = true,
ignore_case = true,
key = { 'client[_%.%-]?secret', 'private[_%.%-]?key' },
},
},
},
})Key patterns are case-sensitive, like any Lua pattern: password matches db_password but not DB_PASSWORD. Environment files use upper case, JSON and YAML usually don't, so a rule that should cover both sets ignore_case = true and writes its patterns in lower case. See ignore_case.
The same policy can live in .camouflage.yaml:
version: 1
policy:
enabled: true
default_action: mask
terminal_path_ignores:
- .git/**
- node_modules/**
rules:
- id: ignore-debug-flags
action: ignore
key: ['^DEBUG$', '^PORT$']
parser: [env, json, yaml]
- id: force-client-secrets
action: mask
allow_force: true
ignore_case: true
key:
- client[_%.%-]?secret
- private[_%.%-]?key| Field | Type | Description |
|---|---|---|
id |
string |
Stable identifier shown in redacted metadata |
action |
'mask' | 'ignore' |
Decision when the rule matches |
allow_force |
boolean |
Lets a mask rule override path ignores or broad ignore rules |
path |
string|string[] |
Project-root-relative glob |
basename |
string|string[] |
Basename glob |
parser |
string|string[] |
Parser name such as env, json, yaml, toml, hcl
|
key |
string|string[] |
Lua pattern matched against parsed variable keys, case-sensitive |
ignore_case |
boolean |
Also match key against the lower-cased key, default false
|
nested |
boolean |
Match nested-key metadata |
commented |
boolean |
Match commented-line metadata |
value_length |
{ min?: number, max?: number } |
Match plaintext length without exposing the value |
value_shape |
string|string[] |
Safe shape predicate, listed below |
value_prefix |
string|string[] |
Literal prefix predicate |
value_suffix |
string|string[] |
Literal suffix predicate |
Supported value_shape values:
| Shape | Matches |
|---|---|
empty |
Empty string |
non_empty |
Any non-empty string |
numeric |
Numeric-looking values |
boolean |
true or false
|
quoted |
Single- or double-quoted values |
jwt_like |
Three base64url-ish JWT segments |
token_like |
Non-space token-like values with at least 8 characters |
Value predicates inspect the value only to make the decision. Warnings, status output, audit findings, and policy stats do not include plaintext values.
Ignore safe operational toggles:
version: 1
policy:
rules:
- id: ignore-non-secret-flags
action: ignore
key: ['^DEBUG$', '^LOG_LEVEL$', '^PORT$']
value_shape: [boolean, numeric, non_empty]Ignore fixture directories but force real-looking secrets back on:
version: 1
policy:
terminal_path_ignores:
- tests/fixtures/**
rules:
- id: force-private-keys
action: mask
allow_force: true
key: ['private[_%.%-]?key']Mask only specific keys by default. Everything the rules don't match stays readable, so let the rule match every case:
version: 1
policy:
default_action: ignore
rules:
- id: mask-sensitive-keys
action: mask
ignore_case: true
key:
- password
- secret
- token
- api[_%-]*keyThis masks DB_PASSWORD, api_token and ApiKey alike, and leaves LOG_LEVEL readable. Without ignore_case the lower-case patterns would miss the upper-case keys of a .env, and those would be left unmasked. default_action: ignore also makes camouflage warn about the file, since it can leave values unmasked.
:CamouflageStatus reports whether policy is enabled and how many variables were ignored in the current buffer.
Workspace Audit applies the same policy and includes redacted policy metadata in each finding.
Key patterns are case-sensitive by default. With ignore_case: true a rule's key patterns are tried against the key as written and against the lower-cased key, the way the Weak Secret Check patterns are, so a pattern written in lower case covers every case:
| Pattern | ignore_case |
Matches |
|---|---|---|
password |
false (default) |
db_password |
password |
true |
db_password, DB_PASSWORD, DbPassword
|
^DB_PASSWORD$ |
true |
DB_PASSWORD, db_password, Db_Password
|
^%u+_TOKEN$ |
true |
API_TOKEN only |
An exact key, a pattern wrapped in ^ and $ with no other pattern characters in it, is compared in any case. A pattern itself isn't lower-cased, so a class like %u still means upper case, and a pattern written in upper case (PASSWORD) still only matches upper case.
A rule can also say how its values are masked, not only whether they are:
| Field | Type | Description |
|---|---|---|
style |
string |
text, dotted, stars, scramble or partial
|
mask_char |
string |
Single character used for the mask |
mask_length |
integer |
Fixed mask width, which hides the value's length |
show_start |
integer |
With partial: characters kept at the start |
show_end |
integer |
With partial: characters kept at the end |
version: 1
policy:
rules:
- id: aws-key-id
action: mask
key: ['^AWS_ACCESS_KEY_ID$']
style: partial
show_end: 4
- id: fixed-width
action: mask
ignore_case: true
key: ['password']
mask_char: '#'
mask_length: 10AWS_ACCESS_KEY_ID=****************MPLE
AWS_SECRET_ACCESS_KEY=*************
DB_PASSWORD=##########
These fields are data, a name and a few numbers, so a .camouflage.yaml can
carry them with nothing executable in it. A rule with an invalid style or a
fractional number is dropped with a warning, and its values are masked the usual
way.
partial reveals what it is asked to reveal. Use it on identifiers, not on
passwords.
-
Project Config: using policy in
.camouflage.yaml - Workspace Audit: policy-aware audit output
- Configuration: full configuration reference