From 313063aa8a48d2408023f2614c157629f38dd4ae Mon Sep 17 00:00:00 2001 From: Christopher Hiller Date: Tue, 29 Aug 2023 17:03:57 -0700 Subject: [PATCH] chore(core): add schema validation tests I pulled in [ajv](https://npm.im/ajv) for this. I had tried to use [z-schema](https://npm.im/z-schema) but I couldn't get it working quickly (apparently you need to supply the metaschema??) so abandoned it. If there's a more lightweight, _maintained_ solution, I'm happy to try it. --- package-lock.json | 17 +++++ packages/core/package.json | 1 + .../core/test/policy/invalid-bad-path.json | 7 ++ .../test/policy/invalid-bad-pkg-name.json | 9 +++ packages/core/test/policy/invalid-empty.json | 1 + packages/core/test/policy/valid.json | 63 ++++++++++++++++ packages/core/test/policySchema.spec.js | 29 ++++++++ .../test/snapshots/policySchema.spec.js.md | 69 ++++++++++++++++++ .../test/snapshots/policySchema.spec.js.snap | Bin 0 -> 854 bytes 9 files changed, 196 insertions(+) create mode 100644 packages/core/test/policy/invalid-bad-path.json create mode 100644 packages/core/test/policy/invalid-bad-pkg-name.json create mode 100644 packages/core/test/policy/invalid-empty.json create mode 100644 packages/core/test/policy/valid.json create mode 100644 packages/core/test/policySchema.spec.js create mode 100644 packages/core/test/snapshots/policySchema.spec.js.md create mode 100644 packages/core/test/snapshots/policySchema.spec.js.snap diff --git a/package-lock.json b/package-lock.json index cf4abd9e85..28e06c6ff1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17324,6 +17324,7 @@ }, "devDependencies": { "@types/json-stable-stringify": "^1.0.34", + "ajv": "^8.12.0", "ses": "^0.18.8", "tmp-promise": "^3.0.3" }, @@ -17331,6 +17332,22 @@ "node": "^16.20.0 || ^18.0.0 || ^20.0.0" } }, + "packages/core/node_modules/ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, "packages/core/node_modules/type-fest": { "version": "4.3.3", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.3.3.tgz", diff --git a/packages/core/package.json b/packages/core/package.json index 100a2f3a4d..352696f6b4 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -17,6 +17,7 @@ }, "devDependencies": { "@types/json-stable-stringify": "^1.0.34", + "ajv": "^8.12.0", "ses": "^0.18.8", "tmp-promise": "^3.0.3" }, diff --git a/packages/core/test/policy/invalid-bad-path.json b/packages/core/test/policy/invalid-bad-path.json new file mode 100644 index 0000000000..c5420e87ad --- /dev/null +++ b/packages/core/test/policy/invalid-bad-path.json @@ -0,0 +1,7 @@ +{ + "resolutions": { + "some>package": { + "some>other>package": "/etc/passwd" + } + } +} diff --git a/packages/core/test/policy/invalid-bad-pkg-name.json b/packages/core/test/policy/invalid-bad-pkg-name.json new file mode 100644 index 0000000000..8b47d86c37 --- /dev/null +++ b/packages/core/test/policy/invalid-bad-pkg-name.json @@ -0,0 +1,9 @@ +{ + "resources": { + "bad>!!packagename": { + "globals": { + "console": true + } + } + } +} diff --git a/packages/core/test/policy/invalid-empty.json b/packages/core/test/policy/invalid-empty.json new file mode 100644 index 0000000000..0967ef424b --- /dev/null +++ b/packages/core/test/policy/invalid-empty.json @@ -0,0 +1 @@ +{} diff --git a/packages/core/test/policy/valid.json b/packages/core/test/policy/valid.json new file mode 100644 index 0000000000..617d43575d --- /dev/null +++ b/packages/core/test/policy/valid.json @@ -0,0 +1,63 @@ +{ + "resources": { + "browserify>buffer": { + "globals": { + "console": true + }, + "packages": { + "browserify>buffer>base64-js": true, + "browserify>buffer>ieee754": true + } + }, + "browserify>events": { + "globals": { + "console": true + } + }, + "browserify>process": { + "globals": { + "clearTimeout": true, + "setTimeout": true + } + }, + "browserify>string_decoder": { + "packages": { + "browserify>util>safe-buffer": true + } + }, + "browserify>util>safe-buffer": { + "packages": { + "browserify>buffer": true + } + }, + "keccak": { + "packages": { + "browserify>buffer": true, + "keccak>readable-stream": true + } + }, + "keccak>readable-stream": { + "packages": { + "browserify>browser-resolve": true, + "browserify>buffer": true, + "browserify>events": true, + "browserify>inherits": true, + "browserify>process": true, + "browserify>string_decoder": true, + "keccak>readable-stream>util-deprecate": true + } + }, + "keccak>readable-stream>util-deprecate": { + "globals": { + "console.trace": true, + "console.warn": true, + "localStorage": true + } + } + }, + "resolutions": { + "some>package": { + "some>other>package": "./here" + } + } +} diff --git a/packages/core/test/policySchema.spec.js b/packages/core/test/policySchema.spec.js new file mode 100644 index 0000000000..4cd4ec78a5 --- /dev/null +++ b/packages/core/test/policySchema.spec.js @@ -0,0 +1,29 @@ +const test = require('ava') +const Ajv = require('ajv') + +const schema = require('../schema/lavamoat-policy.v0-0-1.schema.json') +const validPolicy = require('./policy/valid.json') +const invalidPolicyEmpty = require('./policy/invalid-empty.json') +const invalidBadPkgName = require('./policy/invalid-bad-pkg-name.json') +const invalidBadPath = require('./policy/invalid-bad-path.json') + +const ajv = new Ajv({ allErrors: true }) +const validate = ajv.compile(schema) +test('policy schema - known good policy', (t) => { + t.truthy(validate(validPolicy)) +}) + +test('policy schema - invalid policy - empty', (t) => { + t.falsy(validate(invalidPolicyEmpty)) + t.snapshot(validate.errors) +}) + +test('policy schema - invalid policy - bad pkg name', (t) => { + t.falsy(validate(invalidBadPkgName)) + t.snapshot(validate.errors) +}) + +test('policy schema - invalid policy - bad resolution path', (t) => { + t.falsy(validate(invalidBadPath)) + t.snapshot(validate.errors) +}) diff --git a/packages/core/test/snapshots/policySchema.spec.js.md b/packages/core/test/snapshots/policySchema.spec.js.md new file mode 100644 index 0000000000..f21ae84e23 --- /dev/null +++ b/packages/core/test/snapshots/policySchema.spec.js.md @@ -0,0 +1,69 @@ +# Snapshot report for `test/policySchema.spec.js` + +The actual snapshot is saved in `policySchema.spec.js.snap`. + +Generated by [AVA](https://avajs.dev). + +## policy schema - invalid policy - empty + +> Snapshot 1 + + [ + { + instancePath: '', + keyword: 'required', + message: 'must have required property \'resources\'', + params: { + missingProperty: 'resources', + }, + schemaPath: '#/anyOf/0/required', + }, + { + instancePath: '', + keyword: 'required', + message: 'must have required property \'resolutions\'', + params: { + missingProperty: 'resolutions', + }, + schemaPath: '#/anyOf/1/required', + }, + { + instancePath: '', + keyword: 'anyOf', + message: 'must match a schema in anyOf', + params: {}, + schemaPath: '#/anyOf', + }, + ] + +## policy schema - invalid policy - bad pkg name + +> Snapshot 1 + + [ + { + instancePath: '/resources', + keyword: 'additionalProperties', + message: 'must NOT have additional properties', + params: { + additionalProperty: 'bad>!!packagename', + }, + schemaPath: '#/properties/resources/additionalProperties', + }, + ] + +## policy schema - invalid policy - bad resolution path + +> Snapshot 1 + + [ + { + instancePath: '/resolutions/some>package/some>other>package', + keyword: 'pattern', + message: 'must match pattern "^(\\.{1,2})(/(?=[^/\\0])[^/\\0]+)*/?$"', + params: { + pattern: '^(\\.{1,2})(/(?=[^/\\0])[^/\\0]+)*/?$', + }, + schemaPath: '#/properties/resolutions/patternProperties/%5E(%40%5Ba-z0-9-~0%5D%5Ba-z0-9-._~0%5D*~1)%3F%5Ba-z0-9-~0%5D%5Ba-z0-9-._~0%5D*(%3E(%40%5Ba-z0-9-~0%5D%5Ba-z0-9-._~0%5D*~1)%3F%5Ba-z0-9-~0%5D%5Ba-z0-9-._~0%5D*)*%24/patternProperties/%5E(%40%5Ba-z0-9-~0%5D%5Ba-z0-9-._~0%5D*~1)%3F%5Ba-z0-9-~0%5D%5Ba-z0-9-._~0%5D*(%3E(%40%5Ba-z0-9-~0%5D%5Ba-z0-9-._~0%5D*~1)%3F%5Ba-z0-9-~0%5D%5Ba-z0-9-._~0%5D*)*%24/pattern', + }, + ] diff --git a/packages/core/test/snapshots/policySchema.spec.js.snap b/packages/core/test/snapshots/policySchema.spec.js.snap new file mode 100644 index 0000000000000000000000000000000000000000..468f95f0131042ce2113625dd55df47124292c6f GIT binary patch literal 854 zcmV-c1F8H$RzVY>nexLQ1|ZF2o1SiVf0g>xw; zbopgAXdjCR00000000BkR?klpK@^_Zwp#?WfE-C&z)BY=TcCts1frtxWHI634@8IU zK-YGExU)s8kw}bJ6K}*Do;-Lk{s-QSi6^gKO-xKoJbBc&+a0!Sjf>cr*yPK+nZEZr z-<$8fbZ2d~Vyb2K=s9&Xr$XeM5cFnG?E-&m8xO@Sm1casm4*}ak zC@kI-_8we50KNnIVhCLZSg}x;xHs%D!U=>^;3M?9q!Qh@Q!|)D43#btr{o`^kWaEq zYj;e$$oFkFyRGDj+r4Jz>n$+At0+D=UxvMDpGwo2I$!bdQE z26yLyqD5??vrzi>`jaC-1dH(Y-$4> zx?4)u7}JdPMgQUW`Jr8v{!v&*!?W|jm5m%+s{}UXb;%$)ZJuBFYs35!Mq!hs#7>u3ihzYe%mEm@!p;W&WTrVjWHMcaR;@3@UjtS{+(9_?=!cx7_ zf(*RXyc8hA$M^s;92r!CGyxCg*B6EAzl2|T9WGofQe{0&33nCK4Ua$9-)|AM476PZ zaNXqhrJF!-k_F6~z5y;k1#Y%TKBG!Q%P7p$>6~AS`o?rh)aFMK0!u;# z9BLa8nwoByX?}z>u##CGyFWfU@j%WfnfcjkE6Q^2x?EpIUgjd>`+X?qC#0Jh2+Rrq0E=drbN~PV literal 0 HcmV?d00001