Version Freshness Linter¶
AI Agent Context (click to expand)
Purpose: Complete guide to using the version-freshness linter for detecting EOL and outdated runtime versions
Scope: Configuration, usage, supported file types, data source, and CI/CD integration
Overview: Comprehensive documentation for the version-freshness linter that checks infrastructure and runtime versions against endoflife.date lifecycle data. Covers supported file types (Dockerfiles, GitHub Actions, version-pinning files, Terraform), configuration options, CLI usage, caching behavior, and CI/CD integration. Helps teams avoid deploying on end-of-life runtimes that AI code generators frequently suggest.
Dependencies: endoflife.date API (MIT-licensed, CDN-cached), requests library, packaging library
Exports: Usage documentation, configuration examples, supported file types reference
Related: cli-reference.md for CLI commands, configuration.md for config format, how-to-ignore-violations.md for ignore patterns
Implementation: File-type-specific extractors with endoflife.date API caching and configurable detection levels
This follows the AI-Optimized Documentation Standard.
Try It Now¶
Example output:
Dockerfile:1
[ERROR] version-freshness.eol-version: python 3.8 has reached end of life (EOL: 2024-10-14)
Suggestion: Upgrade to 3.13
Fix it: Upgrade to a supported version of the runtime.
Overview¶
The version-freshness linter checks infrastructure and runtime versions in your project against endoflife.date lifecycle data. It detects end-of-life (EOL) versions and optionally flags outdated versions that are supported but not the latest.
The AI Version Problem¶
AI code generators frequently suggest outdated runtime versions because their training data skews old. Developers accept these without checking because they look plausible:
# AI-generated - Node 16 reached EOL September 2023
- uses: actions/setup-node@v4
with:
node-version: '16'
No existing tool catches this at lint time. Vulnerability scanners check CVEs, update bots create PRs, but nothing says "this version is EOL" during code review.
What It Checks¶
This linter targets infrastructure/runtime versions, not library versions:
- Docker base images (
FROM python:3.9) - GitHub Actions setup steps (
python-version: '3.8') - Version-pinning files (
.python-version,.nvmrc) - Terraform version constraints (
required_version)
Supported File Types¶
| File Type | Pattern | What It Extracts |
|---|---|---|
| Dockerfile | Dockerfile* |
FROM image:tag lines |
| GitHub Actions | .github/workflows/*.yml |
Version keys in with: blocks |
| Python version | .python-version |
Single version string |
| Node version | .nvmrc, .node-version |
Single version string |
| Tool versions | .tool-versions |
tool version per line (asdf) |
| Mise config | mise.toml |
[tools] section |
| Terraform | *.tf |
required_version = "..." |
| pyproject.toml | pyproject.toml |
Python version constraint |
Supported Products¶
Any product tracked by endoflife.date (450+ products), including: Python, Node.js, Go, Java, Ruby, PHP, Rust, Elixir, PostgreSQL, MySQL, Redis, Nginx, Alpine, Ubuntu, Debian, and more.
Rules¶
version-freshness.eol-version (default: enabled)¶
Flags versions that have reached end of life. These versions no longer receive security patches.
version-freshness.outdated-runtime (default: disabled)¶
Flags versions that are supported but not the latest cycle. This is a stricter check, useful for teams that want to stay on the latest.
# Violation (with check_outdated: true): python 3.11 is not the latest supported version (latest: 3.13)
FROM python:3.11-slim
Configuration¶
Add to .thailint.yaml:
version-freshness:
enabled: true
# Flag end-of-life versions (default: true)
check_eol: true
# Flag non-latest supported versions (default: false, stricter)
check_outdated: false
# Cache refresh interval in hours (default: 24)
cache_ttl_hours: 24
# Files/patterns to ignore
ignore:
- "Dockerfile.legacy"
- "tests/**"
- ".github/workflows/compat-test.yml"
Configuration Options¶
| Option | Type | Default | Description |
|---|---|---|---|
enabled |
bool | true |
Enable/disable the linter |
check_eol |
bool | true |
Flag end-of-life versions |
check_outdated |
bool | false |
Flag non-latest supported versions |
cache_ttl_hours |
int | 24 |
Hours before refreshing API data |
ignore |
list | [] |
File patterns to skip |
Data Source¶
Version lifecycle data comes from endoflife.date:
- MIT licensed, open source, 450+ products
- Static JSON on CDN, updated daily by automated bots
- 3,250+ GitHub stars, actively maintained for 7+ years
- No API key required, no rate limiting
Caching¶
Data is cached locally at ~/.cache/thailint/endoflife/ with one JSON file per product. Cache behavior:
- Fresh cache (within TTL): Use cached data, no network request
- Stale cache (past TTL): Fetch from API, update cache
- Offline fallback: If API unreachable, use stale cache
- No cache: If no cache and API unreachable, skip product (no false positives)
Ignoring Violations¶
Line-level (inline comment)¶
Block-level¶
# thailint: ignore-start version-freshness
- uses: actions/setup-python@v5
with:
python-version: '3.9' # intentionally pinned for legacy compat
# thailint: ignore-end
File-level¶
Repository-level¶
Comment-less files¶
Files like .python-version and .nvmrc have no comment syntax. Use repository-level ignore patterns to suppress violations in these files.
CI/CD Integration¶
GitHub Actions¶
- name: Check version freshness
run: |
pip install thailint
thailint version-freshness --format sarif . > version-freshness.sarif
- name: Upload SARIF
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: version-freshness.sarif
Pre-commit¶
- repo: local
hooks:
- id: version-freshness
name: Check version freshness
entry: thailint version-freshness
language: system
pass_filenames: false