Documentation
¶
Overview ¶
Package rules provides the core rule system for the Dockerfile linter.
Index ¶
- Constants
- Variables
- func BuildKitDocURL(ruleName string) string
- func CheckEpilogueOrder(commands []instructions.Command) bool
- func HadolintDocURL(ruleCode string) string
- func HasDuplicateEpilogueNames(names []string) bool
- func IsEpilogueInstruction(name string) bool
- func Register(rule Rule)
- func TallyDocURL(ruleCode string) string
- type AsyncRule
- type BuildContext
- type ConfigurableRule
- type EpilogueOrderResolveData
- type FixSafety
- type HeredocFixType
- type HeredocResolveData
- type LintInput
- type Location
- func NewFileLocation(file string) Location
- func NewLineLocation(file string, line int) Location
- func NewLocationFromRange(file string, r parser.Range) Location
- func NewLocationFromRanges(file string, ranges []parser.Range) Location
- func NewRangeLocation(file string, startLine, startCol, endLine, endCol int) Location
- type NewlineResolveData
- type Position
- type Registry
- func (r *Registry) All() []Rule
- func (r *Registry) ByCategory(category string) []Rule
- func (r *Registry) BySeverity(severity Severity) []Rule
- func (r *Registry) Codes() []string
- func (r *Registry) Experimental() []Rule
- func (r *Registry) Get(code string) Rule
- func (r *Registry) Has(code string) bool
- func (r *Registry) Register(rule Rule)
- type Rule
- type RuleMetadata
- type Severity
- type SuggestedFix
- type TextEdit
- type Violation
Constants ¶
const BuildKitRulePrefix = "buildkit/"
BuildKitRulePrefix is the namespace prefix for rules from BuildKit's linter.
const EpilogueOrderResolverID = "epilogue-order"
EpilogueOrderResolverID is the unique identifier for the epilogue-order fix resolver.
const HadolintRulePrefix = "hadolint/"
HadolintRulePrefix is the namespace prefix for Hadolint-compatible rules.
const HeredocDefaultMinCommands = 3
HeredocDefaultMinCommands is the default minimum number of commands required to suggest heredoc conversion. Heredocs add 2 lines overhead (<<EOF and EOF), so converting 2 commands saves no lines.
const HeredocResolverID = "prefer-run-heredoc"
HeredocResolverID is the unique identifier for the heredoc fix resolver.
const HeredocRuleCode = TallyRulePrefix + "prefer-run-heredoc"
HeredocRuleCode is the full rule code for the prefer-run-heredoc rule. Used by other rules (like DL3003) to check if heredoc conversion is enabled.
const NewlineResolverID = "newline-between-instructions"
NewlineResolverID is the unique identifier for the newline-between-instructions fix resolver.
const PipefailRuleCode = HadolintRulePrefix + "DL4006"
PipefailRuleCode is the full rule code for the DL4006 pipefail rule. Used by the heredoc formatter to determine whether to add set -o pipefail.
const TallyRulePrefix = "tally/"
TallyRulePrefix is the namespace prefix for tally's own rules.
Variables ¶
var EpilogueOrderRank = map[string]int{ command.StopSignal: 0, command.Healthcheck: 1, command.Entrypoint: 2, command.Cmd: 3, }
EpilogueOrderRank maps lowercase epilogue instruction names to their canonical position. This is the single source of truth for epilogue ordering, shared by the rule and resolver.
Functions ¶
func BuildKitDocURL ¶ added in v0.13.0
BuildKitDocURL returns the documentation URL for a BuildKit rule. The ruleName should be the PascalCase name without prefix (e.g. "StageNameCasing").
func CheckEpilogueOrder ¶ added in v0.11.0
func CheckEpilogueOrder(commands []instructions.Command) bool
CheckEpilogueOrder reports whether epilogue instructions in the given commands are correctly positioned at the end and in canonical order. ONBUILD commands are ignored.
func HadolintDocURL ¶ added in v0.13.0
HadolintDocURL returns the documentation URL for a Hadolint rule. The ruleCode should be the DL/SC code without prefix (e.g. "DL3001").
func HasDuplicateEpilogueNames ¶ added in v0.11.0
HasDuplicateEpilogueNames reports whether any name in the slice appears more than once.
func IsEpilogueInstruction ¶ added in v0.11.0
IsEpilogueInstruction reports whether the lowercase instruction name is an epilogue instruction.
func TallyDocURL ¶ added in v0.9.6
TallyDocURL returns the documentation URL for a tally rule code. The ruleCode should include the "tally/" prefix (e.g. "tally/max-lines").
Types ¶
type AsyncRule ¶
type AsyncRule interface {
Rule
PlanAsync(input LintInput) []async.CheckRequest
}
AsyncRule is an optional interface for rules that require slow I/O (registry, network, filesystem). Rules implementing this interface participate in the async checks pipeline.
PlanAsync is called during the planning phase (no I/O). It returns check requests that the async runtime will execute under budget control.
The handler's OnSuccess returns []any where each element is a rules.Violation. This avoids an import cycle between the async and rules packages.
type BuildContext ¶
type BuildContext interface {
// IsIgnored checks if a path would be ignored by .dockerignore.
IsIgnored(path string) (bool, error)
// FileExists checks if a file exists in the build context.
FileExists(path string) bool
// IsHeredocFile checks if a path is a virtual heredoc file.
IsHeredocFile(path string) bool
// HasIgnoreFile returns true if a .dockerignore file exists.
HasIgnoreFile() bool
}
BuildContext is an interface for build-time context awareness. Rules can type-assert this to *context.BuildContext if they need context-aware features like .dockerignore checking.
type ConfigurableRule ¶
type ConfigurableRule interface {
Rule
// Schema returns the JSON Schema for this rule's configuration options.
// This follows ESLint's meta.schema pattern where rules define their own schema.
// The schema is used for:
// - Config validation
// - Documentation generation
// - IDE autocompletion
//
// Example return value:
//
// map[string]any{
// "type": "object",
// "properties": map[string]any{
// "max": map[string]any{"type": "integer", "minimum": 0, "default": 50},
// },
// "additionalProperties": false,
// }
Schema() map[string]any
// DefaultConfig returns the default configuration for this rule.
// Used when no user config is provided.
DefaultConfig() any
// ValidateConfig checks if a configuration is valid for this rule.
ValidateConfig(config any) error
}
ConfigurableRule is an optional interface for rules that accept configuration.
type EpilogueOrderResolveData ¶ added in v0.11.0
type EpilogueOrderResolveData struct {
// StageIndex is the 0-based index of the stage that triggered the violation.
StageIndex int
}
EpilogueOrderResolveData carries resolver context. The resolver is self-contained (re-parses and re-analyzes the file), so StageIndex is informational — it identifies the stage that triggered the violation. The resolver processes all applicable stages in one pass.
type FixSafety ¶
type FixSafety int
FixSafety categorizes how reliable a fix is.
const ( // FixSafe means the fix is always correct and won't change behavior. // These fixes can be applied automatically without review. FixSafe FixSafety = iota // FixSuggestion means the fix is likely correct but may need review. // Examples: apt search → apt-cache search (different output format). FixSuggestion // FixUnsafe means the fix might change behavior significantly. // These require explicit --fix-unsafe flag to apply. FixUnsafe )
type HeredocFixType ¶
type HeredocFixType int
HeredocFixType indicates the type of heredoc fix.
const ( // HeredocFixConsecutive is for consecutive RUN instructions. HeredocFixConsecutive HeredocFixType = iota // HeredocFixChained is for a single RUN with chained commands. HeredocFixChained )
type HeredocResolveData ¶
type HeredocResolveData struct {
// Type indicates whether this is for consecutive RUNs or chained commands.
Type HeredocFixType
// StageIndex is the 0-based index of the stage containing the RUN(s).
StageIndex int
// ShellVariant is the shell variant for parsing.
ShellVariant shell.Variant
// MinCommands is the minimum number of commands to trigger heredoc conversion.
MinCommands int
// PipefailEnabled indicates whether DL4006 (pipefail) is enabled.
// When true, the heredoc formatter will add "set -o pipefail" inside the
// heredoc body if any command contains a pipe, avoiding the need for a
// separate SHELL instruction.
PipefailEnabled bool
}
HeredocResolveData contains the data needed to resolve a heredoc fix. This is stored in SuggestedFix.ResolverData.
The resolver uses re-parsing to find fixes rather than fingerprint matching. This approach is more robust because content may have changed due to sync fixes (apt → apt-get, cd → WORKDIR, etc.) applied before the heredoc resolver runs.
type LintInput ¶
type LintInput struct {
// File is the path to the Dockerfile being linted.
File string
// AST is the parsed Dockerfile AST from BuildKit (guaranteed non-nil).
// Use AST nodes for line information, not raw source counting.
AST *parser.Result
// Stages contains the parsed build stages with typed instructions.
// This is populated by BuildKit's instructions.Parse().
Stages []instructions.Stage
// MetaArgs contains ARG instructions that appear before the first FROM.
// These are global build arguments that affect base image selection.
MetaArgs []instructions.ArgCommand
// Source is the raw source content of the Dockerfile.
// Used for snippet extraction and directive parsing.
Source []byte
// Context is optional build context for context-aware rules.
// Rules should check for nil before using.
Context BuildContext
// Semantic is the semantic model for cross-instruction analysis.
// Provides stage resolution, variable scoping, and COPY --from validation.
// May be nil for backward compatibility with rules that don't need it.
// Type is *semantic.Model but declared as any to avoid import cycle.
Semantic any
// Config is the rule-specific configuration (type depends on rule).
Config any
// EnabledRules contains the codes of all rules that are enabled in this run.
// Rules can check this to coordinate behavior, e.g., DL3003 can skip its fix
// if prefer-run-heredoc is enabled and would handle the command better.
// May be nil if not computed (for backward compatibility in tests).
EnabledRules []string
// HeredocMinCommands is the configured min-commands for the prefer-run-heredoc rule.
// Rules that coordinate with heredoc (like DL3003) should use this value.
// Zero means use the default (HeredocDefaultMinCommands).
HeredocMinCommands int
}
LintInput contains all the information a rule needs to check a Dockerfile. Rules should work with the AST and typed instructions, not raw source text.
The linter guarantees that AST and Source are always valid (non-nil) when Check is called. If parsing fails, the linter reports parse errors and exits without invoking any rules (following ESLint's approach).
IMPORTANT: LintInput is read-only. Rules must not mutate any fields (File, AST, Stages, MetaArgs, Source, Context, Config). If a rule needs to modify data, it must copy it first. This prevents hidden coupling between rules.
func (LintInput) GetHeredocMinCommands ¶
GetHeredocMinCommands returns the configured min-commands for heredoc conversion. Returns the configured value if set, otherwise returns HeredocDefaultMinCommands. Used by rules coordinating with prefer-run-heredoc (e.g., DL3003).
func (LintInput) IsRuleEnabled ¶
IsRuleEnabled checks if a specific rule is enabled in the current run. Returns false if EnabledRules is nil (for backward compatibility in tests).
func (LintInput) Snippet ¶
Snippet extracts a range of lines from the source (0-based, inclusive). This is a convenience wrapper around SourceMap().Snippet().
func (LintInput) SnippetForLocation ¶
SnippetForLocation extracts the source code at a location. If the location is file-level (no specific line), returns empty string. If the location is a point, returns just that line. If the location is a range, returns all lines in the range.
Note: Location uses 1-based line numbers, SourceMap uses 0-based.
type Location ¶
type Location struct {
// File is the path to the source file (not in parser.Range).
File string `json:"file"`
// Start is the starting position (inclusive, 1-based line numbers).
Start Position `json:"start"`
// End is the ending position (exclusive, LSP semantics).
// Points to the first position after the range.
// A point location has End.Line < 0 (unset) or End equals Start.
End Position `json:"end"`
}
Location represents a range in a source file. This extends parser.Range by adding the File path. BuildKit's Range only contains Start/End positions without file context.
Following LSP conventions, Start is inclusive and End is exclusive. This means End points to the first position AFTER the covered text.
See: github.com/moby/buildkit/frontend/dockerfile/parser.Range
func NewFileLocation ¶
NewFileLocation creates a location for file-level issues (no specific line). Uses -1 as sentinel since 0 would be invalid (lines are 1-based).
func NewLineLocation ¶
NewLineLocation creates a location for a specific line (1-based). Creates a point location (no range) at the start of the line.
func NewLocationFromRange ¶
NewLocationFromRange converts a BuildKit parser.Range to our Location type. This bridges BuildKit's internal types with our output schema. BuildKit uses 1-based line numbers. The mapping is direct—no adjustment needed.
func NewLocationFromRanges ¶
NewLocationFromRanges creates a Location from a slice of BuildKit Ranges. Uses the first range if multiple exist, or returns file-level if empty.
func NewRangeLocation ¶
NewRangeLocation creates a location spanning multiple lines/columns. Lines are 1-based, columns are 0-based.
func (Location) IsFileLevel ¶
IsFileLevel returns true if this is a file-level location (no specific line).
func (Location) IsPointLocation ¶
IsPointLocation returns true if this is a single-point location (no range). A point location has End.Line < 0 (unset) or End equals Start.
type NewlineResolveData ¶ added in v0.11.0
type NewlineResolveData struct {
Mode string
}
NewlineResolveData carries the configuration mode for the resolver. This is stored in SuggestedFix.ResolverData.
type Position ¶
type Position struct {
// Line is the 1-based line number (first line is 1, same as BuildKit).
Line int `json:"line"`
// Column is the 0-based column number (same as BuildKit's Character field).
Column int `json:"column"`
}
Position represents a single point in a source file. This is our JSON-serializable equivalent of parser.Position, which uses "Character" instead of "Column" and lacks JSON tags.
We use 1-based line numbers to align with BuildKit's internal representation. Note: BuildKit's AST uses 1-based lines (first line is 1), not 0-based.
See: github.com/moby/buildkit/frontend/dockerfile/parser.Position
type Registry ¶
type Registry struct {
// contains filtered or unexported fields
}
Registry manages rule registration and lookup.
func DefaultRegistry ¶
func DefaultRegistry() *Registry
DefaultRegistry returns the global default registry.
func (*Registry) ByCategory ¶
ByCategory returns rules filtered by category.
func (*Registry) BySeverity ¶
BySeverity returns rules filtered by default severity.
func (*Registry) Experimental ¶
Experimental returns rules marked as experimental.
type Rule ¶
type Rule interface {
// Metadata returns static information about the rule.
Metadata() RuleMetadata
// Check runs the rule against the given input and returns any violations.
// The AST and Source fields are guaranteed non-nil. The Context field
// may be nil in v1.0 (context-aware linting is optional).
Check(input LintInput) []Violation
}
Rule is the interface that all linting rules must implement.
type RuleMetadata ¶
type RuleMetadata struct {
// Code is the unique identifier (e.g., "DL3006", "max-lines").
Code string
// Name is the human-readable rule name.
Name string
// Description explains what the rule checks.
Description string
// DocURL links to detailed documentation.
DocURL string
// DefaultSeverity is the severity when not overridden.
DefaultSeverity Severity
// Category groups related rules (e.g., "security", "performance", "style").
Category string
// IsExperimental marks rules that may change or be removed.
IsExperimental bool
// FixPriority determines the order in which fixes are applied.
// Lower values = earlier application (content fixes like DL3027: apt → apt-get).
// Higher values = later application (structural transforms like prefer-run-heredoc).
// Default 0 is for content fixes. Use 100+ for structural transformations.
FixPriority int
}
RuleMetadata contains static information about a rule.
type Severity ¶
type Severity int
Severity represents the severity level of a rule violation.
const ( // SeverityError indicates a critical issue that should fail the build. SeverityError Severity = iota // SeverityWarning indicates a significant issue that may cause problems. SeverityWarning // SeverityInfo indicates a suggestion or best practice recommendation. SeverityInfo // SeverityStyle indicates a style/formatting preference. SeverityStyle // SeverityOff disables the rule completely. // Placed after other severities to avoid zero-value confusion. SeverityOff )
func ParseSeverity ¶
ParseSeverity parses a severity string into a Severity value.
func (Severity) IsMoreSevereThan ¶
IsMoreSevereThan returns true if s is more severe than other.
func (Severity) MarshalJSON ¶
MarshalJSON implements json.Marshaler.
func (*Severity) UnmarshalJSON ¶
UnmarshalJSON implements json.Unmarshaler. Pointer receiver required by json.Unmarshaler interface.
type SuggestedFix ¶
type SuggestedFix struct {
// Description explains what this fix does.
Description string `json:"description"`
// Edits contains the actual text replacements to apply.
// May be empty if NeedsResolve is true (populated by resolver).
Edits []TextEdit `json:"edits,omitempty"`
// Safety indicates how reliable this fix is.
// Default (zero value) is FixSafe.
Safety FixSafety `json:"safety,omitzero"`
// IsPreferred marks this as the recommended fix when alternatives exist.
IsPreferred bool `json:"isPreferred,omitzero"`
// NeedsResolve indicates this fix requires async resolution.
// When true, Edits is empty and ResolverID specifies which resolver to use.
// Examples: fetching image digests, computing file checksums.
NeedsResolve bool `json:"needsResolve,omitzero"`
// ResolverID identifies which FixResolver should compute the edits.
// Only used when NeedsResolve is true.
ResolverID string `json:"resolverId,omitempty"`
// ResolverData contains opaque data for the resolver.
// Not serialized to JSON; used internally during fix application.
ResolverData any `json:"-"`
// ResolveErr captures resolver failures during fix application.
// Not serialized to JSON; used internally for diagnostics.
ResolveErr error `json:"-"`
// Priority determines application order when multiple fixes exist.
// Copied from rule's FixPriority. Lower = applied first.
// Content fixes (priority 0) run before structural transforms (priority 100+).
Priority int `json:"priority,omitzero"`
}
SuggestedFix represents a structured edit hint for auto-fix suggestions. It describes what text to replace and what to replace it with.
Fixes can be synchronous (Edits populated immediately) or asynchronous (NeedsResolve=true, edits computed later by a FixResolver).
type TextEdit ¶
type TextEdit struct {
// Location specifies where to apply the edit.
Location Location `json:"location"`
// NewText is the text to insert/replace with. Empty string means delete.
NewText string `json:"newText"`
}
TextEdit represents a single text replacement in a file.
type Violation ¶
type Violation struct {
// Location specifies where the violation occurred.
Location Location `json:"location"`
// RuleCode is the unique identifier for the rule (e.g., "DL3006", "max-lines").
RuleCode string `json:"rule"`
// Message is a human-readable description of the issue.
Message string `json:"message"`
// Detail provides additional context (optional).
Detail string `json:"detail,omitempty"`
// Severity indicates how critical this violation is.
Severity Severity `json:"severity"`
// DocURL links to documentation about this rule (optional).
DocURL string `json:"docUrl,omitempty"`
// SourceCode is the source snippet where the violation occurred (optional).
// Populated by post-processing; rules don't need to set this.
SourceCode string `json:"sourceCode,omitempty"`
// SuggestedFix provides a structured fix hint (optional).
// Supports "auto-fix suggestion" without auto-applying.
SuggestedFix *SuggestedFix `json:"suggestedFix,omitempty"`
// StageIndex tracks which Dockerfile stage this violation belongs to.
// Used internally for merging async results; not serialized.
StageIndex int `json:"-"`
}
Violation represents a single linting violation. This extends BuildKit's subrequests/lint.Warning with:
- Severity levels (BuildKit treats all as warnings)
- Inline file path (BuildKit uses SourceIndex into separate Sources array)
- SuggestedFix for auto-fix hints
- SourceCode snippet
See: github.com/moby/buildkit/frontend/subrequests/lint.Warning
func NewViolation ¶
NewViolation creates a new violation with the minimum required fields.
func NewViolationFromBuildKitWarning ¶
func NewViolationFromBuildKitWarning( file string, ruleName string, description string, url string, message string, location []parser.Range, ) Violation
NewViolationFromBuildKitWarning converts BuildKit linter callback parameters to our Violation type. This bridges BuildKit's linter.LintWarnFunc with our output schema.
Parameters match linter.LintWarnFunc: (rulename, description, url, fmtmsg, location) The rule code is automatically namespaced with "buildkit/" prefix.
func (Violation) WithDetail ¶
WithDetail adds a detail message to the violation.
func (Violation) WithDocURL ¶
WithDocURL adds a documentation URL to the violation.
func (Violation) WithSourceCode ¶
WithSourceCode adds source code snippet to the violation.
func (Violation) WithSuggestedFix ¶
func (v Violation) WithSuggestedFix(fix *SuggestedFix) Violation
WithSuggestedFix adds a fix suggestion to the violation.
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
Package all imports all rule packages to register them.
|
Package all imports all rule packages to register them. |
|
Package asyncutil provides shared helpers for async rule implementations.
|
Package asyncutil provides shared helpers for async rule implementations. |
|
Package buildkit provides metadata for BuildKit's built-in linter rules.
|
Package buildkit provides metadata for BuildKit's built-in linter rules. |
|
fixes
Package fixes provides auto-fix enrichment for BuildKit linter rules.
|
Package fixes provides auto-fix enrichment for BuildKit linter rules. |
|
Package configutil provides utilities for rule configuration resolution.
|
Package configutil provides utilities for rule configuration resolution. |
|
Package hadolint implements hadolint-compatible linting rules for Dockerfiles.
|
Package hadolint implements hadolint-compatible linting rules for Dockerfiles. |
|
Package tally implements tally-specific linting rules for Dockerfiles.
|
Package tally implements tally-specific linting rules for Dockerfiles. |