YAML linting tools for Replicated applications
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Failed to load latest commit information.
.circleci
.github
bin
docs
projects
src
.codeclimate.yml
.gitattributes
.gitignore
.npmignore
CHANGELOG
LICENSE
Makefile
README.md
package.json
tdd
tsconfig.json
tsfmt.json
tslint.json
yarn.lock

README.md

replicated-lint

CircleCI Code Climate Test Coverage

YAML linting tools for Replicated applications.

Usage

Install the CLI executable with

npm install -g replicated-lint

Lint with replicated-lint validate

replicated-lint validate -f my-app.yml

or pipe from stdin:

cat my-app.yml | replicated-lint validate -f -

Results that have issues will look something like:

{ type: 'info',
  rule: 'prop-configitem-testproc-run-on-save',
  message: 'If a config item\'s test_proc.run_on_save is not set to \'true\', test_proc\'s will not be checked automatically. Consider setting your test_proc\'s run_on_save to automatically validate inputs',
  positions: 
   [ { path: 'config.1.items.2.test_proc',
       start: { position: 8130, line: 325, column: 4 },
       end: { position: 8322, line: 331, column: 0 } },
     { path: 'config.3.test_proc',
       start: { position: 8692, line: 346, column: 2 },
       end: { position: 9141, line: 365, column: 2 } } ],
  links: [ 'https://www.replicated.com/docs/packaging-an-application/test-procs/' ] }

# prop-configitem-testproc-run-on-save continued from line 321
322  
323    - name: phone_number
324      type: text
325      test_proc:
326        display_name: Is this a Phone Number?
327        command: regex_match
328        args:
329        - "([0-9]{3})[-]([0-9]{3})[-]([0-9]{4})$"
330        - "That doesn't seem to be a phone number!"
331  - name: auth
332    title: Authentication
333    description: Where will user accounts be provisioned
334    items:

Extending the CLI with custom rules

replicated-lint rules can be expressed as JSON, so it is easy to add your own custom rules.

If you have a custom rule set in no-latest.json, you can pass it to replicated-lint using

cat my-app.yml | replicated-lint validate -f - --extraRules no-latest.yaml

--extraRules can be specified multiple times. An example YAML rule set might look something like

---
- name: custom-no-latest
  type: error
  message: "Don't use `latest` for container versions."
  test:
    AnyOf:
      path: components
      pred:
        AnyOf: containers
        pred:
          Eq:
            path: version
            value: latest

replicated-lint validate supports the following options:

Options:
  --version         Show version number                                [boolean]
  --help            Show help                                          [boolean]
  --infile, -f      Input file to validate. Use "-" for stdin
                                                         [string] [default: "-"]
  --threshold, -t   Threshold of of issues to report
                  [string] [choices: "info", "warn", "error"] [default: "error"]
  --extraRules, -e  Path to file containing JSON definitions for additional yaml
                    rules. Can be specified multiple times.[array] [default: []]
  --reporter, -r    Output Format to use
                     [string] [choices: "console", "junit"] [default: "console"]
  --outputDir, -o   junit reporter only -- path to directory to output junit xml
                    reports                   [string] [default: "test-results"]

Developing

Installing Dependencies

We compile to ES5 and test on nodejs 7.8.0, but earlier versions of node should work as well.

npm install -g yarn
yarn

Running the tests

To run the tests once

yarn test

To watch files and re-run tests on changes, use the tdd script

./tdd

Regenerating the documentation

replicated-lint docs gen will print reference documentation stdout as markdown. yarn docs will write it to docs/gen.md.

To update the docs in help center, grab everything in replicated-lint/docs/gen.md and paste it into help-center/.../yaml.md, replacing everything below <!-- the rest of this document is autogenerated-->.

Library Usage

replicated-lint is designed with extensibility in mind, making it suitable for general purpose YAML and JSON linting and policy definition

  • Flexible, modular rule sets
  • CLI
  • Autogenerate unit tests and documentation from rule definitions
npm install --save replicated-lint
import * as linter from "replicated-lint";

const yaml = `
---
replicated_api_version: 2.8.0
components: 
  - name: ELK
    containers: 
      - image: getelk/search`;


const ruleViolations = linter.defaultLint(yaml);
console.log(ruleViolations); // []

Custom Rule Sets

linter.rules.all can be substituted or extended with custom rule definitions. A rule's test field should return { matched: true } when the rule is triggered by invalid JSON.

import * as linter from "replicated-lint"; 

const yaml = `
---
foo:
  bar: baz`;

const testSpec: any = {
  Or: {
    preds: [
      {Eq: { path: "foo.bar", value: "baz"}},
      {Eq: { path: "foo.bar", value: "boz"}},
    ],
  }
}

const rules: linter.YAMLRule[] = [
  {
    name: "foo-bar-neq-baz",
    message: "foo.bar can't be baz!",
    test: testSpec,
    type: "error",
  }
];

const ruleViolations = linter.lint(yaml, { rules });
console.log(ruleViolations);  /*
[{
        type: "error",
        positions: [{
          path: "foo.bar",
          start: {
            position: 12,
            line: 3,
            column: 2,
          },
          end: {
            position: 20,
            line: 3,
            column: 10,
          },
        }],
        message: "foo.bar can't be baz!",
}]
*/

Register new rules with linter.enginer.register. Rules should implement JSONReadable<Predicate<any>>, usually as a static method

import * as linter from "replicated-lint";


// rule MyRule checks if root object has property "spam" equal to "eggs"
class MyRule implements linter.Predicate<any> {
  test(obj: any) {
    const matched = obj.spam !== "eggs"; // fail when spam != eggs
    const paths = ["spam"];              // if matched == true, optionally include a path where a rule was violated
    return { matched, paths };
  }

  public static fromJson(obj: any, registry: linter.engine.Registry) {
    return new MyRule();
  }
}

linter.engine.register(MyRule);

const testSpec: linter.Test = { MyRule: {}};

const rules: linter.YAMLRule[] = [
  {
    name: "spam-eq-eggs",
    message: "spam must be equal to eggs!",
    test: testSpec,
    type: "error",
  }
];

const yaml = `
---
spam: eggs`;

const ruleViolations = linter.lint(yaml, { rules }); 
console.log(ruleViolations); // []

Custom implementations of engine.Registry can also be passed as a third argument to linter.lint, otherwise a default registry will be used.