ssube / salty-dog Goto Github PK
View Code? Open in Web Editor NEWRule-based JSON/YAML validator using JSON schemas
Home Page: https://ssube.github.io/salty-dog/
License: MIT License
Rule-based JSON/YAML validator using JSON schemas
Home Page: https://ssube.github.io/salty-dog/
License: MIT License
Add a fragments
or definitions
block to the rules files, defining schema fragments that will be added before the rules are run.
This will allow shared object definitions and DRY up the rule bodies.
Something is broken!
Error loading schema to validate config since v0.9 image was published.
uncaught error during main: Error: ENOENT: no such file or directory, open '/build/src/git.company.com/sKSMtss1/1/x/y/z/rules/salty-dog.yml'
at Object.openSync (node:fs:585:3)
at readFileSync (node:fs:453:35)
at loadSchema (/usr/local/share/.config/yarn/global/node_modules/salty-dog/out/bundle/index.cjs:33664:44)
at validateConfig (/usr/local/share/.config/yarn/global/node_modules/salty-dog/out/bundle/index.cjs:33687:33)
at main (/usr/local/share/.config/yarn/global/node_modules/salty-dog/out/bundle/index.cjs:33775:8) {
errno: -2,
syscall: 'open',
code: 'ENOENT',
path: '/build/src/git.company.com/sKSMtss1/1/x/y/z/rules/salty-dog.yml'
}
Should load the config from /salty-dog/rules/salty-dog.yml
(or ../../rules
, relative to the entrypoint script), whether that is /salty-dog/out/bundle/index.cjs
or /salty-dog/out/src/index.js
.
Add hooks to the visitor context so callers can be notified at various important times, including:
Along the way:
Adding chai to the test
chunk via manualChunks
(id.includes('/chai/')
) causes the test run to throw an error:
created out/ in 5s
/home/ssube/code/ssube/salty-dog//node_modules/.bin/mocha /home/ssube/code/ssube/salty-dog//out/test.js
/home/ssube/code/ssube/salty-dog/node_modules/mocha/node_modules/yargs/yargs.js:1163
else throw err
^
TypeError: __chunk_1.createCommonjsModule is not a function
at Object.<anonymous> (/home/ssube/code/ssube/salty-dog/out/vendor.js:3899:29)
at Module._compile (internal/modules/cjs/loader.js:816:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:827:10)
at Module.load (internal/modules/cjs/loader.js:685:32)
at Function.Module._load (internal/modules/cjs/loader.js:620:12)
at Module.require (internal/modules/cjs/loader.js:723:19)
at require (internal/modules/cjs/helpers.js:14:16)
at Object.<anonymous> (/home/ssube/code/ssube/salty-dog/out/test.js:6:17)
at Module._compile (internal/modules/cjs/loader.js:816:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:827:10)
at Module.load (internal/modules/cjs/loader.js:685:32)
at Function.Module._load (internal/modules/cjs/loader.js:620:12)
at Module.require (internal/modules/cjs/loader.js:723:19)
at require (internal/modules/cjs/helpers.js:14:16)
at /home/ssube/code/ssube/salty-dog/node_modules/mocha/lib/mocha.js:330:36
at Array.forEach (<anonymous>)
at Mocha.loadFiles (/home/ssube/code/ssube/salty-dog/node_modules/mocha/lib/mocha.js:327:14)
at Mocha.run (/home/ssube/code/ssube/salty-dog/node_modules/mocha/lib/mocha.js:804:10)
at Object.exports.singleRun (/home/ssube/code/ssube/salty-dog/node_modules/mocha/lib/cli/run-helpers.js:207:16)
at exports.runMocha (/home/ssube/code/ssube/salty-dog/node_modules/mocha/lib/cli/run-helpers.js:300:13)
at Object.exports.handler.argv [as handler] (/home/ssube/code/ssube/salty-dog/node_modules/mocha/lib/cli/run.js:296:3)
at Object.runCommand (/home/ssube/code/ssube/salty-dog/node_modules/mocha/node_modules/yargs/lib/command.js:242:26)
at Object.parseArgs [as _parseArgs] (/home/ssube/code/ssube/salty-dog/node_modules/mocha/node_modules/yargs/yargs.js:1087:28)
at Object.parse (/home/ssube/code/ssube/salty-dog/node_modules/mocha/node_modules/yargs/yargs.js:566:25)
at Object.exports.main (/home/ssube/code/ssube/salty-dog/node_modules/mocha/lib/cli/cli.js:63:6)
at Object.<anonymous> (/home/ssube/code/ssube/salty-dog/node_modules/mocha/bin/_mocha:10:23)
at Module._compile (internal/modules/cjs/loader.js:816:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:827:10)
at Module.load (internal/modules/cjs/loader.js:685:32)
at Function.Module._load (internal/modules/cjs/loader.js:620:12)
at Function.Module.runMain (internal/modules/cjs/loader.js:877:12)
at internal/main/run_main_module.js:21:11
Makefile:83: recipe for target 'test' failed
make: *** [test] Error 1
Fix that and get test deps out of the vendor
chunk.
While the base SchemaRule
can do a lot, future rules may need more logic or use a different kind of schema. This will be especially important with #6 and external rules.
Wire up DI through https://github.com/ssube/noicejs and await container.create(rule.type)
should solve that neatly. Rule modules can provide DI modules if they have additional Parser
or Rule
classes.
Yargs offers bash/zsh completion, as an option or command. Set that up and look into whether the --mode
option should, in fact, be the command.
As a convenience, allow --rules
to take a directory, and load rules from each .yml
file within that directory. Optionally recurse.
The context data used to pass selected item index and rule name down is untyped and not particularly flexible.
Passing arbitrary data down will never be possible to type well, but using context hooks (#21) to pass errors and diffs up as they are encountered will allow the friendly messaging to happen in a more appropriate place. Since that place will know what rule produced the messages, it could even call some sort of Rule.format
method.
The mutate
option, used to apply deep-diffs to the target object, is currently being inferred based on mode === MODE.fix
, with no way to turn it off.
mutate
option under fix
commandTo validate a pipe between commands, the CLI should have options to set input to stdin
and output to stdout
. For example: jinja foo.tpl | salty-dog --mode fail --source - --dest - | kubectl apply -f -
Not all rules need a filter
: some should apply to every selected node.
Make the field optional.
Rather than loading all rules from files, add a way to require
modules that export rules: Array<RuleData>
.
The YAML parser supports multiple documents per file, which is fairly common among k8s resources. While cleaning up the walker/visitor, add a top-level loop for multiple documents.
This didn't make #112, but to complete #20 for errors, the selected item's index (out of all selected items, before filtering) should be included in the error message and data.
This will require moving the map(friendlyError)
call up into the visitor to some extent, although schema rules should not leak raw Ajv errors.
Load rule files from subdirectories of the given --rule-path
s.
With #3 implemented, offer a way to accept or roll back changes.
For each rule, if the working copy differs from the original data:
The salty-dog-meta
rules should be able to validate --rules
source files and the config after they have been loaded and parsed.
The examples use bunyan
and/or jq
to filter logs, but neither is present in the containers. Both are available from standard package repositories.
Filtering and formatting logs is pretty useful.
jq
bunyan
globallyyarn global bin
to pathFully adopt the project structure and makefile from https://github.com/ssube/rollup-template
This issue lists Renovate updates and detected dependencies. Read the Dependency Dashboard docs to learn more.
Warning
Renovate failed to look up the following dependencies: Failed to look up npm package @apextoaster/js-utils
, Failed to look up npm package @apextoaster/js-yaml-schema
, Failed to look up npm package @istanbuljs/nyc-config-typescript
, Failed to look up npm package @istanbuljs/schema
, Failed to look up npm package @microsoft/api-documenter
, Failed to look up npm package @microsoft/api-extractor
, Failed to look up npm package @types/bunyan
, Failed to look up npm package @types/chai
, Failed to look up npm package @types/chai-as-promised
, Failed to look up npm package @types/deep-diff
, Failed to look up npm package @types/js-yaml
, Failed to look up npm package @types/lodash
, Failed to look up npm package @types/minimatch
, Failed to look up npm package @types/mocha
, Failed to look up npm package @types/node
, Failed to look up npm package @types/sinon
, Failed to look up npm package @types/sinon-chai
, Failed to look up npm package @types/source-map-support
, Failed to look up npm package @types/yargs
, Failed to look up npm package @typescript-eslint/eslint-plugin
, Failed to look up npm package @typescript-eslint/parser
, Failed to look up npm package ajv
, Failed to look up npm package bunyan
, Failed to look up npm package c8
, Failed to look up npm package chai
, Failed to look up npm package chai-as-promised
, Failed to look up npm package deep-diff
, Failed to look up npm package esbuild
, Failed to look up npm package eslint
, Failed to look up npm package eslint-plugin-chai
, Failed to look up npm package eslint-plugin-chai-expect
, Failed to look up npm package eslint-plugin-chai-expect-keywords
, Failed to look up npm package eslint-plugin-import
, Failed to look up npm package eslint-plugin-mocha
, Failed to look up npm package eslint-plugin-no-null
, Failed to look up npm package eslint-plugin-sonarjs
, Failed to look up npm package js-yaml
, Failed to look up npm package jsonpath-plus
, Failed to look up npm package lodash
, Failed to look up npm package memfs
, Failed to look up npm package minimatch
, Failed to look up npm package mocha
, Failed to look up npm package noicejs
, Failed to look up npm package nyc
, Failed to look up npm package sinon
, Failed to look up npm package sinon-chai
, Failed to look up npm package source-map-support
, Failed to look up npm package standard-version
, Failed to look up npm package typescript
, Failed to look up npm package yargs
.
Files affected: package.json
These updates have all been created already. Click a checkbox below to force a retry/rebase of any.
Dockerfile.alpine
docker.artifacts.apextoaster.com/library/node 19-alpine
Dockerfile.stretch
docker.artifacts.apextoaster.com/library/node 17-stretch
.gitlab/ci-tools.yml
docker.artifacts.apextoaster.com/apextoaster/base 1.5
docker.artifacts.apextoaster.com/apextoaster/code-climate 0.6
docker.artifacts.apextoaster.com/apextoaster/docker 20.10
docker.artifacts.apextoaster.com/apextoaster/docker-dind 20.10
docker.artifacts.apextoaster.com/apextoaster/node 16.19
docker.artifacts.apextoaster.com/apextoaster/sonar-scanner 4.4
package.json
@apextoaster/js-utils 0.5.0
@apextoaster/js-yaml-schema 0.5.0
@istanbuljs/nyc-config-typescript 1.0.2
@istanbuljs/schema 0.1.3
@microsoft/api-documenter 7.22.8
@microsoft/api-extractor 7.35.1
@types/bunyan 1.8.8
@types/chai 4.3.5
@types/chai-as-promised 7.1.5
@types/deep-diff 1.0.2
@types/js-yaml 4.0.5
@types/lodash 4.14.195
@types/minimatch 5.1.2
@types/mocha 10.0.1
@types/node 18.15.3
@types/sinon 10.0.15
@types/sinon-chai 3.2.9
@types/source-map-support 0.5.6
@types/yargs 17.0.24
@typescript-eslint/eslint-plugin 5.59.8
@typescript-eslint/parser 5.59.8
ajv 8.12.0
bunyan 1.8.15
c8 7.14.0
chai 4.3.7
chai-as-promised 7.1.1
deep-diff 1.0.2
esbuild 0.18.5
eslint 8.41.0
eslint-plugin-chai 0.0.1
eslint-plugin-chai-expect 3.0.0
eslint-plugin-chai-expect-keywords 2.1.0
eslint-plugin-import 2.27.5
eslint-plugin-mocha 10.1.0
eslint-plugin-no-null 1.0.2
eslint-plugin-sonarjs 0.19.0
js-yaml 4.1.0
jsonpath-plus 7.2.0
lodash 4.17.21
memfs 3.5.1
minimatch 5.1.6
mocha 10.2.0
noicejs 4.0.0
nyc 15.1.0
sinon 15.1.0
sinon-chai 3.7.0
source-map-support 0.5.21
standard-version 9.5.0
typescript 4.9.5
yargs 17.7.2
lodash 4.17.21
Set up a pipeline, publish packages and images, and run all manner of quality assurance bots.
There is an error with this repository's Renovate configuration that needs to be fixed. As a precaution, Renovate will stop PRs until it is resolved.
Error type: undefined. Note: this is a nested preset so please contact the preset author if you are unable to fix it yourself.
Document the project workflow (or copy it from isolex), make issue labels, add issue templates, etc.
Ajv supports modifying data during validation, including:
These will form the basis of --mode=fix
.
Since rules use selectors and schemas are run against selected nodes, if jsonpath-plus makes a copy of the data while selecting, then the nodes will need to be replaced in the original data.
The CLI has a number of options, but they are hidden and useless without --help
. Switching to the full version of yargs should sort that out: https://github.com/yargs/yargs/blob/HEAD/docs/examples.md#yargs-is-here-to-help-you
The tsconfig/target-lib
rule has a very convoluted schema, using a series of partial objects in oneOf
to ensure that lib
contains the value of target
.
It looks like ajv $data
references would sort that out neatly and allow the value of target
to be used directly with something like { $data: "./target" }
.
Passing rule errors through ctx.error(err)
as they occur causes them to be added directly to the context's error buffer without going through the end-of-rule result.errors.length > 0
check, causing the rule to appear as though it passed. The program as a whole still exits with the correct status and error count, since the errors are added to the context, but not attributed to the correct rule.
The raw error messages from Ajv and diffs from deep-diff are not the most readable, but are wonderfully detailed:
{"name":"salty-dog","hostname":"cerberus","pid":23892,"level":20,"item":{"metadata":{"name":"example"},"spec":{"template":{"spec":{"containers":[{"name":"test"}]}}}},"msg":"checking item","time":"2019-07-01T14:09:15.175Z","v":0}
{"name":"kubernetes-labels","hostname":"cerberus","pid":23892,"level":40,"errors":[{"keyword":"required","dataPath":".metadata","schemaPath":"#/properties/metadata/required","params":{"missingProperty":"labels"},"message":"should have required property 'labels
'"}],"item":{"metadata":{"name":"example"},"spec":{"template":{"spec":{"containers":[{"name":"test"}]}}}},"rule":{"desc":"all resources should have labels","level":"info","name":"kubernetes-labels","select":"$","tags":["kubernetes","labels"],"check":{"type":"o
bject","required":["metadata"],"properties":{"metadata":{"type":"object","required":["labels"],"properties":{"labels":{"type":"object","additionalProperties":false,"patternProperties":{"^[-.a-z0-9]{1,63}$":{"type":"string"}}}}}}}},"msg":"rule failed on item","
time":"2019-07-01T14:09:15.175Z","v":0}
{"name":"salty-dog","hostname":"cerberus","pid":23892,"level":40,"count":1,"rule":{"desc":"all resources should have labels","level":"info","name":"kubernetes-labels","select":"$","tags":["kubernetes","labels"],"check":{"type":"object","required":["metadata"],
"properties":{"metadata":{"type":"object","required":["labels"],"properties":{"labels":{"type":"object","additionalProperties":false,"patternProperties":{"^[-.a-z0-9]{1,63}$":{"type":"string"}}}}}}}},"msg":"rule failed","time":"2019-07-01T14:09:15.175Z","v":0}
{"name":"salty-dog","hostname":"cerberus","pid":23892,"level":50,"count":2,"errors":[{"keyword":"required","dataPath":"","schemaPath":"#/required","params":{"missingProperty":"resources"},"message":"should have required property 'resources'"},{"keyword":"requi
red","dataPath":".metadata","schemaPath":"#/properties/metadata/required","params":{"missingProperty":"labels"},"message":"should have required property 'labels'"}],"msg":"some rules failed","time":"2019-07-01T14:09:15.175Z","v":0}
Parts:
Is it possible to access the yaml frontmatter? I'd like to be able to set some details and tags up there
Add short aliases for help and the other include options, to match -v
for --version
and -t
for --include-tag
.
--help
: -h
--include-level
: -l
, --level
--include-name
: -n
, --name
The most common options should have single-letter aliases.
The --include-*
options are the "default" way to filter rules (exclusion is more complicated and less useful), and --include-tag
is already aliased to --tag
and -t
.
Hello,
Here is my Dockerfile to use Alpine Linux instead of Debian and build in a container. I ended up with an ~83MB image.
FROM node:11-alpine AS build
RUN apk add -U --no-cache build-base # Add git to run git commands in make
COPY . /salty-dog
WORKDIR /salty-dog
RUN make
FROM node:11-alpine
# copy config, which changes rarely
COPY docs/config-docker.yml /root/.salty-dog.yml
# copy package first, to invalidate other layers when version changes
COPY package.json /salty-dog/package.json
# copy chunks, largest to smallest (entrypoint)
COPY --from=build /salty-dog/out/vendor.js /salty-dog/out/vendor.js
COPY --from=build /salty-dog/out/main.js /salty-dog/out/main.js
COPY --from=build /salty-dog/out/index.js /salty-dog/out/index.js
# set up as global cli tool
WORKDIR /salty-dog
RUN yarn global add file:$(pwd)
ENV PATH="${PATH}:$(yarn global bin)"
COPY rules /salty-dog/rules
ENTRYPOINT [ "node", "/salty-dog/out/index.js" ]
CMD [ "--help" ]
It also implies minor changes to test-examples.sh to make it shell compliant.
Do you see any problem moving to Alpine ? If any, we may simply add a new image with a specific tag alpine.
I can make a PR if you want.
Write more rules: useful examples are better than arbitrary ones, and tons of existing tools store their config in JSON or YAML.
Requirements:
Tools:
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.