Files
glint/FEATURES.md
T
k3nny b8e640de03 docs(docs): extract features to FEATURES.md, trim README
The README features block grew to 38 bullets plus a full lint-rules
table, making the document hard to scan. This commit:

- Creates FEATURES.md with a structured reference covering lint rules
  (GL001–GL043 tables), include resolution, context simulation, output
  formats, configuration, graph visualization, and developer tools.
- Replaces the flat bullet list in README with a 6-line "What it does"
  category summary that links to FEATURES.md and ROADMAP.md.
- Removes the redundant ## Lint rules section from README (now in
  FEATURES.md).
- Adds 'explain' to the commands block in the README Usage section.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-14 11:07:51 +02:00

11 KiB
Raw Permalink Blame History

glint — feature reference

This document describes every capability in the current release. For planned work see ROADMAP.md.


Lint rules

Every finding carries a stable rule ID (GL001 GL043) that can be used to suppress, filter, or look up the check. Run glint explain <ID> for a description, bad-YAML example, and fix.

Pipeline-level

ID Sev Rule
GL001 WARN No stages: block — GitLab falls back to its built-in default stages
GL002 ERR workflow.rules[*].when must be always or never
GL036 ERR default.timeout is not a valid GitLab CI duration string
GL040 WARN A stage name appears more than once in stages:

Job structure

ID Sev Rule
GL003 ERR Job missing required script: (or run:)
GL004 ERR Job stage: references a stage not declared in stages:
GL005 ERR only: and rules: used together
GL006 ERR except: and rules: used together
GL007 WARN only: / except: used (deprecated; prefer rules:)

Keyword constraints

ID Sev Rule
GL008 ERR when: has an invalid value
GL009 ERR when: delayed without start_in:
GL010 ERR start_in: set but when: is not delayed
GL011 ERR parallel: integer not in range 2200, or map form missing matrix:
GL012 ERR retry: integer not in range 02, or retry.max out of range
GL013 ERR retry.when: contains an unrecognised failure type
GL014 ERR allow_failure: is not a boolean or a map with exit_codes:
GL015 ERR interruptible: is not a boolean
GL016 ERR Trigger job also defines script:
GL017 ERR trigger: map missing project: or include:
GL018 ERR coverage: is not a regex wrapped in /…/
GL019 ERR release: missing required tag_name:, or is not a map
GL020 ERR environment.url set without environment.name, or invalid action:
GL021 ERR artifacts.when invalid, or expose_as set without paths
GL022 WARN pages job artifacts.paths does not include public/
GL023 ERR cache.when or cache.policy has an invalid value
GL024 ERR rules[*].when has an invalid value
GL025 ERR image: map form missing name:
GL026 ERR inherit.default / inherit.variables is not a boolean or list
GL034 ERR services: map form missing name:, or alias: is not a valid DNS label
GL036 ERR timeout: is not a valid GitLab CI duration string
GL037 ERR id_tokens: entry missing required aud:
GL038 ERR secrets: entry missing a provider key (vault, gcp_secret_manager, azure_key_vault)
GL039 WARN Job uses pages: keyword but artifacts.paths doesn't include the publish directory
GL041 WARN cache.key.files entry looks like a glob; must be an exact file path

Cross-job graph

ID Sev Rule
GL027 ERR/WARN needs: references a job that doesn't exist (WARN when optional: true)
GL028 ERR needs: references a job in a later stage
GL029 ERR Circular dependency in needs: graph
GL030 ERR dependencies: references a job that doesn't exist
GL031 ERR dependencies: references a job in the same or a later stage

Expression & reachability

ID Sev Rule
GL032 WARN rules:if: references $VAR not declared in any variables: block (may be false-positive for project-setting variables)
GL033 WARN Every rule in rules: has when: never — job permanently excluded (provable without evaluating if: expressions)
GL035 WARN rules:changes / rules:exists path is absolute — absolute paths never match in GitLab CI
GL042 WARN Every rules:if: condition evaluates to false given the declared variable values — job statically unreachable (only fires when all referenced variables are declared in YAML)

Inheritance

ID Sev Rule
GL043 WARN inherit: default: declared but the pipeline has no default: block (dead declaration), or the list form names fields not set in default:

Hidden jobs

Jobs whose name starts with . are reusable templates; most rules are skipped for them. This matches GitLab CI's own behaviour.


Include resolution

Capability Notes
include: local: Read from disk, recursively merged before linting
include: remote: HTTPS URL fetched unauthenticated; unreachable URLs produce a warning, linting continues
include: project: Fetched from the GitLab REST API using the configured token; skipped with a warning when no token is available
include: component: Fetched from the GitLab CI/CD Catalog; public components work without a token
include: inputs: $[[ inputs.KEY ]] and $[[ inputs.KEY | default(…) ]] placeholders substituted from the with: block before parsing
Depth limit Include chains capped at 100 levels (matches GitLab); circular cross-file references detected via visited-set tracking
Offline mode --offline serves all remote includes from the cache; missing entries produce a warning
Include cache --cache-dir DIR (or ~/.cache/glint by default with --offline) persists fetched templates; keyed by SHA-256 of the request coordinates

Token resolution order (first non-empty wins):

Source Header
--token flag / GITLAB_TOKEN env PRIVATE-TOKEN
CI_JOB_TOKEN env JOB-TOKEN
GITLAB_PRIVATE_TOKEN env PRIVATE-TOKEN

URL resolution order: --gitlab-url flag → CI_SERVER_URL env → GITLAB_URL env → https://gitlab.com


Context simulation

Pass --branch, --tag, --source, or --var to evaluate rules:if: and only/except filters against a specific pipeline event. When no context flag is given glint defaults to --branch main --source push so that rules:if: expressions are always evaluated.

Evaluated at lint time:

  • rules:if: — full expression language: ==, !=, =~, !~, &&, ||, !, (…), $VAR/${VAR}, string literals, null, regex flags (/pat/i)
  • only: / except: — ref keywords, branch-name globs, and /regex/ patterns
  • workflow:rules: — evaluated to determine whether the pipeline would run; matching rule's variables: are injected before job evaluation
  • Variable expansion — $VAR / ${VAR} references in variable values expanded after all sources merge; transitive chains resolved (up to 10 passes)

Not evaluated (no git tree at lint time): rules:changes:, rules:exists:.

Predefined variables set by shortcut flags:

Flag Variables populated
--branch NAME CI_COMMIT_BRANCH, CI_COMMIT_REF_NAME, CI_COMMIT_REF_SLUG, CI_PIPELINE_SOURCE=push
--tag NAME CI_COMMIT_TAG, CI_COMMIT_REF_NAME, CI_COMMIT_REF_SLUG, CI_PIPELINE_SOURCE=push; clears CI_COMMIT_BRANCH
--source EVENT CI_PIPELINE_SOURCE
--var KEY=VALUE any variable; overrides shortcuts; repeatable

Use --list-vars to print the resolved variable table to stderr.


Output formats

Pass --format to glint check. In structured formats the summary line is written to stderr so stdout contains only the machine-readable payload.

Format Flag Description
Text (default) --format text Ruff-style file:line: RULE [sev] message
JSON --format json Stable schema (version 1); findings array + summary block
SARIF 2.1.0 --format sarif Consumed by GitHub Code Scanning and GitLab SAST
JUnit XML --format junit CI test-report artifact (artifacts:reports:junit)
GitHub annotations --format github ::error file=…,line=…,title=RULE::message inline PR comments

JSON schema (schema_version: 1):

{
  "schema_version": 1,
  "glint_version": "v0.2.20",
  "pipeline": ".gitlab-ci.yml",
  "findings": [
    {"rule":"GL004","severity":"error","file":".gitlab-ci.yml","line":14,
     "job":"deploy","message":"stage \"production\" is not defined in 'stages'"}
  ],
  "summary": {"total": 1, "errors": 1, "warnings": 0}
}

Configuration

.glint.yml project config file

Searched from the pipeline file's directory upward to the first .git boundary.

# Suppress rules globally for this project.
ignore:
  - GL007   # migrating from only:/except:
  - GL032   # dynamic variables injected by CI

# Override rule severity (error | warning | ignore).
# 'ignore' is equivalent to listing the rule in ignore:.
severity:
  GL004: warning   # demote during a stage migration
  GL035: error     # promote to hard error for this project

# Extra stage names valid beyond those in the pipeline's own stages: block.
stages:
  - quality
  - security

# Default GitLab token (lower priority than --token and GITLAB_TOKEN).
token: glpat-xxxx

# Default GitLab instance URL.
url: https://gitlab.example.com

# Default cache directory.
cache_dir: ~/.cache/glint

Priority chain: --token/--gitlab-url flags > .glint.yml > environment variables.

Inline suppression (# glint: ignore)

Suppress a finding for a specific job by placing a comment immediately before it:

# glint: ignore GL007
legacy-job:
  only: [main]
  script: echo ok

# Multiple rules (comma- or space-separated):
# glint: ignore GL007, GL032
other-job:
  script: echo ok

# Suppress every rule for this job:
# glint: ignore all
noisy-job:
  script: echo ok

Suppressions are scoped to the single job they precede and do not affect other jobs or pipeline-level findings.


Graph visualization (glint graph)

Mode Output
tree (default) Terminal job tree: stages as branches, jobs as leaves; annotated with [manual], [delayed], [trigger] where applicable
includes Mermaid flowchart to stdout; colour-coded nodes by include type (local, remote, project, component, template)
pipeline GitLab CI-style SVG/PNG written to --out directory (default: glint-out/); converted to PNG when rsvg-convert, inkscape, or magick is available
all includes to stdout + pipeline file path to stderr

In DAG pipelines (any job has needs:) the pipeline graph uses job-to-job Bézier connectors instead of stage-to-stage lines.


Developer tools

Tool Description
glint explain <RULE> Print description, rationale, bad-YAML example, and fix for a rule. Case-insensitive (gl007 = GL007).
glint explain List all rules with ID, severity, and title.
--list-vars Print all resolved pipeline variables (pipeline + workflow rules + context) to stderr before linting.
--version / -v Print the compiled version string.