README
snyk-policy
Loads Snyk policy files, typically name .snyk
, parses them and returns a structure policy object.
From there, the policy object can filter
vulnerabilities based on vuln.id
and path (vuln.from
) matching.
Policies can also load from multiple locations, and optionally support trusting deep policies, or ignoring all policies entirely.
How it works
The policy module is written to support future versions of policy formats, so you shouldn't need to worry about what version you're dealing with.
The policy is loaded, typically this will be a YAML file named .snyk
(but can be loaded from another filename).
This returns an object that has the following public keys:
ignore
Objectpatch
Objectsuggest
Object (optionally depending on the policy config)version
String
The ignore
, patch
and suggest
all have similar top level structures. For example:
ignore: {
'<snyk-vuln-id>': [
{
'<module path>': { <metadata> }
}
]
}
The metadata for ignore and suggest are the same:
{
reason: '<string>',
expires: '<JSON date format>'
}
The metadata for patch is:
{
patched: '<JSON date format>';
}
For a full example of a fully parsed policy file, see this fixture example.
The vulnerability report is passed in to the instance .filter
function and the vulns are filtered out based on the ignore rules and the patch rules.
If there is any suggest keys on the policy a note
property is added to the individual vulnerability it matches.
How filtering works
The filtering works on two levels:
- matches on
vuln.id
- matches the
vuln.from
against the module path
If first (1) is satisfied, then (2) is checked. If ignoring, the vulnerability is stripped from the report.
If the rule is listed in the patches, the Snyk patch file is also checked to ensure it exists (this is a way to validate the patch has actually taken place - but note that this can be circumvented when the file system isn't available, see skipping patch verification.
A module path is constructed by the name and then optionally the version or version range. A star rule (*
) is also supported.
Module path rules
Given the following dependency tree, and assuming we have a known vulnerability in semver@2.3.2:
.
└─┬ @remy/protect-test@1.0.7
├── semver@2.3.2
└─┬ snyk@0.5.0
├─┬ os-name@1.0.3
│ └─┬ win-release@1.1.1
│ └── semver@5.1.0
├── semver@5.1.0
└─┬ update-notifier@0.5.0
└─┬ semver-diff@2.1.0
└── semver@5.1.0
The following are examples of module paths that could target the semver vulnerability (note that the root module name is not part of the path, represented as .
in the tree above):
@remy/protect-test > semver
@remy/protect-test@1.0.7 > semver@2.3.2
* > semver
* > semver@2.x
The first example rule (above) is how the policy is stored by default. However, policy files can be manually edited if desired.
Usage
Installed via npm: npm install -S snyk-policy
. Typically loaded and applied to vulnerabilities:
const policy = require('snyk-policy');
const vulns = snyk.test('snyk-demo-app@1.0.0'); // assumes snyk is loaded
policy.load(process.cwd()).then((rules) => {
console.log(rules.filter(vulns));
});
Skipping patch verification
Before the policy runs the filter, if the policy return object includes the property skipVerifyPatch: true
then the check for the patch file will not be performed.
This is in use in the registry (private repo) and is useful when the policy loading doesn't have local access to the file system that the packages live on.
API
policy.load(root[, options])
Parses and loads a given directory or directories. Returns a promise
.
: String | Array root
This can be a string pointing to a directory (if so, must include a .snyk
file inside) or you can define the specific filename to load, i.e. ./my-policy
.
If an array is given, the first policy is the primary, and the subsequent policies will inherit the module path from the primary policy.
Important: All secondary policy ignore
rules are ignored and treated as suggestions, adding a note
property on the vulnerability.
: Object options
ignore-policy: true
ignores all the policy rules and returns an empty policy (use insnyk test --ignore-policy
)trust-policies: true
appliesignore
rules in secondary policies (and doesn't offer them as suggestions)loose: true
do not throw an exception if the policy can't be loaded from disk- `skipPatchValidation
policy.loadFromText(string)
Parses the string and returns the policy. Returns a promise
.
: String string
A raw YAML string.
policy.save(config[, root, progress]) & .save([root, progress])
Save the policy to disk in the latest format, so if the original policy version was v1
and the newest is v2
, the policy will be upgraded.
Note that this method is also available on the response object from .load
, so can be called as res.save()
(where res
is the loaded config).
Returns a promise
.
: Object config
The structure policy object.
: String root
The directory to save the policy file (.snyk
). Defaults to CWD via process.cwd()
.
: Promise progress
A progress indicator, as used in snyk cli.
policy.filter(config, vulns) & .filter(vulns)
Applies the policy to the vulnerabilities object. The vulns
object is expected as:
{
ok: Boolean,
vulnerabilities: Array
}
If all the vulns are stripped because of the policy, then the ok
bool is set to true
.
Note that this method is also available on the response object from .load
, so can be called as res.filter()
(where res
is the loaded config).
Returns an object
in the same structure as vulns
.
policy.getByVuln(config, vuln)
Returns any matching rule given a specific vulnerability object. The vuln
object must contain id
and from
to match correctly.
Returns an object
structured as:
{
type: String, // ignore | patch
id: String, // vuln.id
rule: Array, // array of package@version
reason: String, // included in ignore rules
expires: String, // JSON time included in ignore rules
}
: Object config
The loaded policy object (from .load
).
: Object vuln
Single vulnerability object.
Sample policies
Note that <path to package>
below is the dependency chain of package names and valid versions separated by a >
symbol.
By default, the policy file does not add versions to these packages, so a path would look like: 'jade > transformers > uglify-js'
, but it can include versions. More details and examples can be seen in the module path rules section.
Ignore
ignore:
'<snyk-vuln-id>':
- '<path to package>':
reason: String
expires: String(format: Date().toJSON())
patch: {}
version: v1.0.0
Patch
patch:
'<snyk-vuln-id>':
- '<path to package>':
patched: String(format: Date().toJSON())
version: v1