sdk

package
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 4, 2022 License: MIT Imports: 6 Imported by: 0

README

Creating new rules and rulesets

HCL vet uses a logical grouping of rules called a ruleset to manage what the linter checks for.

An example ruleset can be found here.

A ruleset is just a simple directory and can be either local or hosted on most remote filestores/repositories. This is extremely powerful as it means you can host your own rulesets or download other's.

How to create a ruleset

1) Use the create command

To create your own custom ruleset, create the directory the ruleset will exist within and run:

$ hclvet ruleset create <name>

This will create the required folders and files needed.

2) Customize your ruleset

Ruleset settings and information is kept in the ruleset.hcl file in the root of the directory.

Within it you will find two attributes: version and name.

  • Version should be changed in the same fashion as most semver applications. Anytime you change, add, or remove a rule bump the version to convey that there is a newer version.
  • Name is the 20 character maximum, alphanumeric name for your ruleset and should not be changed once set.

How to create a rule

1) Creating a new rule

Rules are written in Golang and kept in the rules folder found in the root of a ruleset directory.

Within this folder, each rule is just a miniature golang program and kept in a folder on its own. The directory name of the rule determines which ID it gets mapped to within HCLvet.

You can run the hclvet rule create <rule_name> command to create a new rule from the root of the ruleset directory.

2) Customizing your new rule

Created rules are just simple, testable golang programs with only a few pieces that you need to finish implementing. These parts are highlighted and explained with comments in the main.go file within the rule directory upon using the generator to create a new rule.

The Check function

The check function is where the logic for the lint rule is stored. It receives the file to be linted as an argument and then returns a list of linting errors pertaining to that file.

The implementation of the linting logic should be simple as the sdk offers hcl file parsers that return an easy to walk list of all blocks and attributes within the given file.

The Main function

The main function simply contains details about the linting rule and registers the rule with the NewRule function located in the SDK.

Documentation

Overview

package sdk is a convenience package enabling the easy downstream development around hclvet. It provides the primitives to allow for ruleset/rule creation and structs to help in parsing hclvet output.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func NewRule

func NewRule(rule *Rule)

NewRule registers a new linting rule. This function must be included inside a rule.

func ParseHCL

func ParseHCL(content []byte) *hclsyntax.Body

ParseHCL parses the HCL file content and returns a simple data structure representing the file. It's safe to ignore the error from ParseHCL as it should have already been handled by the main process.

Types

type Check

type Check interface {
	Check(content []byte) ([]RuleError, error)
}

Check provides an interface for the user to define their own check/lint method. This is the core of the pluggable interface pattern and allows the user to simply consume the hcl file and return linting errors.

content is the full hclfile in byte format.

type LintError

type LintError struct {
	Filepath string    `json:"filepath"`
	Line     string    `json:"line"`
	RuleErr  RuleError `json:"rule_error"`
	Rule     Rule      `json:"rule"`
	Ruleset  string    `json:"ruleset"`
}

LintError is a harness for all the details that go into a lint error

type LintErrorWrapper

type LintErrorWrapper struct {
	Label string `json:"label"`
	Data  struct {
		LintError *LintError `json:"lint_error"`
	} `json:"data"`
}

LintErrorWrapper is a convenience struct so that json output is easier to programmatically read. Nesting the output of LintError as a pointer allows downstream programs to check if the line parses cleanly into the wrapper by simply checking if the resulting object is nil Example:

A line that is not a LintError err := json.Unmarshal(logLine, &newError)

if err != nil {
	t.Fatal(err)
}

if newError.Data.LintError == nil { We know this is not a LintError because this is nil }

type Position

type Position struct {
	// These are uint32 because that is what the protobuf requires
	Line   uint32 `json:"line"`
	Column uint32 `json:"column"`
}

Position represents location within a document.

type Range

type Range struct {
	Start Position `json:"start"`
	End   Position `json:"end"`
}

Range represents the starting and ending points on a specific line within a document.

type Rule

type Rule struct {
	// ID is used by the main hclvet program to uniquely identify rules. Should not be set if creating a rule.
	ID string `hcl:"id,label" json:"id"`
	// The name of the rule, it should be short and to the point of what the rule is for.
	Name string `hcl:"name" json:"name"`
	// A short description about the rule. This should be one line at most and will be shown
	// to the user when the rule finds errors.
	Short string `hcl:"short" json:"short"`
	// A longer description about the rule. This can be looked up by the user via command line.
	Long string `hcl:"long" json:"long"`
	// A link that pertains to the rule; usually additional documentation.
	Link string `hcl:"link" json:"link"`
	// Enabled controls whether the rule will be enabled by default on addition of a ruleset.
	// If enabled is set to false, the user will have to manually turn on the rule.
	Enabled bool `hcl:"enabled" json:"enabled"`
	// Check is a function which runs when the rule is called. This should contain the logic around
	// what the rule is checking.
	Check `json:"-"`
}

Rule is the representation of a single rule within hclvet. This just combines the rule with the check interface. This should be kept in lockstep with the Rule model from the hclvet package.

func (*Rule) ExecuteRule

func (rule *Rule) ExecuteRule(request *proto.ExecuteRuleRequest) (*proto.ExecuteRuleResponse, error)

ExecuteRule runs the linting rule given a single file and returns any linting errors.

func (*Rule) GetRuleInfo

func (rule *Rule) GetRuleInfo(request *proto.GetRuleInfoRequest) (*proto.GetRuleInfoResponse, error)

GetRuleInfo returns information about the rule itself.

type RuleError

type RuleError struct {
	// Suggestion is a short text description on how to fix the error.
	Suggestion string `json:"suggestion"`
	// Remediation is a short snippet of code that can be used to fix the error.
	Remediation string `json:"remediation"`
	// The location of the error in the file.
	Location Range `json:"location"`
	// metadata is a key value store that allows the rule to include extra data,
	// that can be used by any tooling consuming said rule. For example "severity"
	// might be something included in metadata.
	Metadata map[string]string `json:"metadata"`
}

RuleError represents a single lint error's details

func ProtoToRuleError

func ProtoToRuleError(proto *proto.RuleError) *RuleError

type Ruleset

type Ruleset struct {
	Name       string `hcl:"name,label" json:"name"`
	Version    string `hcl:"version" json:"version"`
	Repository string `hcl:"repository" json:"repository"`
	Enabled    bool   `hcl:"enabled" json:"enabled"`
	Rules      []Rule `hcl:"rule,block" json:"rules"`
}

Ruleset represents a packaged set of rules that govern what hclvet checks for.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL