linter

package
v0.1.1 Latest Latest
Warning

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

Go to latest
Published: Jul 16, 2026 License: MIT Imports: 12 Imported by: 0

Documentation

Overview

Package linter implements the decolint engine: it determines what kind of devcontainer directory a path is (a dev container definition, a Feature, or a Template), locates the configuration files it contains, parses them as HuJSON (JSONC), runs lint rules against the syntax tree, and filters findings suppressed by ignore comments.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Category added in v0.1.0

type Category int

Category classifies a rule by the kind of problem it reports. Every rule belongs to exactly one category, so users can adjust the severity of a whole class of rules at once.

const (

	// CategoryCorrectness marks a rule that reports configuration that is invalid or does not
	// behave as written.
	CategoryCorrectness Category = iota + 1
	// CategorySecurity marks a rule that reports container runtime privilege and hardening issues.
	CategorySecurity
	// CategoryReproducibility marks a rule that reports unpinned versions or digests that make the
	// resulting environment change over time.
	CategoryReproducibility
	// CategoryStyle marks a rule that reports discouraged or legacy configuration that still works.
	CategoryStyle
)

func ParseCategory added in v0.1.0

func ParseCategory(name string) (Category, error)

ParseCategory parses a category name, matched case-insensitively, into a Category. It returns an error if name does not name a known category.

func (Category) String added in v0.1.0

func (c Category) String() string

String returns the category's name, as used in configuration files and output.

type Context

type Context struct {
	// Path is the path of the file being linted.
	Path string
	// Type is the kind of configuration file being linted.
	Type FileType
	// Src is the raw content of the file.
	Src []byte
	// Root is the HuJSON syntax tree parsed from Src. It preserves comments and byte offsets into Src.
	Root *hujson.Value
}

Context carries everything a rule needs to inspect a single configuration file.

type FileType

type FileType string

FileType identifies the kind of configuration file being linted.

const (
	// Devcontainer is a devcontainer.json file.
	Devcontainer FileType = "devcontainer"
	// Feature is a devcontainer-feature.json file.
	Feature FileType = "feature"
	// Template is a devcontainer-template.json file.
	Template FileType = "template"
)

type Finding

type Finding struct {
	// Message describes the problem in a human-readable way.
	Message string
	// Offset is the byte offset into Context.Src where the problem is located, typically the
	// StartOffset of the offending value.
	Offset int
}

Finding is a single problem reported by a rule.

type Issue

type Issue struct {
	Path     string   `json:"path"`
	Line     int      `json:"line"` // 1-based
	Col      int      `json:"col"`  // 1-based, in bytes
	RuleID   string   `json:"ruleId"`
	Message  string   `json:"message"`
	Severity Severity `json:"severity"`
}

Issue is a rule finding resolved to a file position.

func (Issue) String

func (i Issue) String() string

type Linter

type Linter struct {
	// contains filtered or unexported fields
}

Linter runs a set of rules against devcontainer configuration files.

func New

func New() *Linter

New returns an empty Linter. Use RegisterRule to add rules to it.

func (*Linter) Lint

func (l *Linter) Lint(ctx context.Context, path string, src []byte, fileType FileType) ([]Issue, error)

Lint lints src, which is the content of a configuration file of the given type. path is used only for reporting.

func (*Linter) LintDir

func (l *Linter) LintDir(ctx context.Context, root *os.Root) ([]Issue, error)

LintDir determines the kind of devcontainer directory root is opened on (a dev container definition, a Feature, or a Template), and lints every configuration file it contains. It is an error if the directory contains no configuration. All file access happens through root, so it is confined to that directory; configuration files under its .devcontainer directory are only accessed within that directory. Symbolic links are followed only while they resolve inside that boundary, and a link escaping it is treated as nonexistent. Issue paths are the files' locations joined onto root's name.

func (*Linter) RegisterRule

func (l *Linter) RegisterRule(r *Rule, severity Severity)

RegisterRule adds r to the linter, to run at the given severity.

type Node

type Node struct {
	// Pointer is the JSON Pointer (RFC 6901) of the value, e.g. "/image" or "/mounts/0". It is "" for
	// the document root.
	Pointer string
	// Value is the HuJSON value at Pointer.
	Value *hujson.Value
}

Node is a single value reached by the engine's traversal.

type Platform

type Platform int

Platform identifies a target platform a rule is scoped to.

const (
	// PlatformVSCode marks a rule specific to Visual Studio Code's Dev Containers extension.
	PlatformVSCode Platform = iota
	// PlatformCodespaces marks a rule specific to GitHub Codespaces.
	PlatformCodespaces
)

func ParsePlatform

func ParsePlatform(name string) (Platform, error)

ParsePlatform parses a platform name, matched case-insensitively, into a Platform. It returns an error if name does not name a known platform.

func (Platform) MarshalJSONTo added in v0.1.0

func (p Platform) MarshalJSONTo(enc *jsontext.Encoder) error

MarshalJSONTo encodes the platform as its name (see String), for use with encoding/json/v2.

func (Platform) String

func (p Platform) String() string

String returns the platform's name, as used in the -platform flag and in output.

func (*Platform) UnmarshalJSONFrom added in v0.1.0

func (p *Platform) UnmarshalJSONFrom(dec *jsontext.Decoder) error

UnmarshalJSONFrom decodes a platform from its name (see ParsePlatform), for use with encoding/json/v2.

type Rule

type Rule struct {
	// ID is the unique identifier of the rule, used in output and in ignore directives (e.g.
	// "no-image-latest").
	ID string
	// Description is a short human-readable description of what the rule checks.
	Description string
	// Category classifies the kind of problem this rule reports. Every rule must declare exactly
	// one category; the severity of all rules in a category can be adjusted at once.
	Category Category
	// FileTypes are the kinds of configuration files this rule applies to. The rule is only run
	// against files of these types.
	FileTypes []FileType
	// Platforms are the target platforms this rule applies to. A nil or empty value means the rule
	// applies to every platform and always runs, regardless of which platforms are selected when the
	// linter is configured.
	Platforms []Platform
	// Paths are the JSON Pointer patterns of the values this rule wants to inspect. A "*" segment
	// matches any object member name or array index (e.g. "/mounts/*"); the empty string matches the
	// document root.
	Paths []string
	// Check inspects one value matching Paths and returns any findings. It is called at most once per
	// rule for a given value, even if several patterns match it. Check must be safe for concurrent
	// use, since it may be called for multiple files.
	Check func(ctx *Context, node *Node) []Finding
}

Rule is a single lint rule.

A rule declares the kinds of configuration files it applies to via FileTypes and the JSON Pointer paths it is interested in via Paths. The lint engine traverses the HuJSON syntax tree of each matching file exactly once and calls Check for every value matching one of its paths. The syntax tree preserves comments and byte offsets, so findings can point at the exact location of the offending value.

type Severity

type Severity int

Severity indicates how a finding should be treated: whether it's reported as an error or a warning, or not reported at all. It is specified when a rule is registered on a Linter. Severities are ordered from least to most severe, so they can be compared directly (e.g. to rank findings or apply a fail threshold).

const (
	// SeverityOff disables a rule; it produces no findings.
	SeverityOff Severity = iota
	// SeverityWarn marks a finding as a warning.
	SeverityWarn
	// SeverityError marks a finding as an error.
	SeverityError
)

func ParseSeverity

func ParseSeverity(name string) (Severity, error)

ParseSeverity parses a severity name, matched case-insensitively, into a Severity. It returns an error if name does not name a known severity.

func (Severity) MarshalJSONTo

func (s Severity) MarshalJSONTo(enc *jsontext.Encoder) error

MarshalJSONTo encodes the severity as its name (see String), for use with encoding/json/v2.

func (Severity) String

func (s Severity) String() string

String returns the severity's name, as used in output and configuration files.

func (*Severity) UnmarshalJSONFrom

func (s *Severity) UnmarshalJSONFrom(dec *jsontext.Decoder) error

UnmarshalJSONFrom decodes a severity from its name (see ParseSeverity), for use with encoding/json/v2.

Jump to

Keyboard shortcuts

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