End-of-Life Runtime Guardrails
Enforce that runtime versions are still maintained upstream. Two checks: not past end-of-life, and still in active support (not just security-only maintenance). Reads the `endoflife` collector's `.lang.<language>.eol` data.
endoflife to your lunar-config.yml:uses: github://earthly/lunar-lib/policies/endoflife@v1.0.5
Included Guardrails
This policy includes 2 guardrails that enforce standards for your security and compliance.
runtime-not-eol
Fails if any detected runtime under .lang.<language>.eol is past
its end-of-life date (is_eol == true). Skips cleanly when no
runtime EOL data is present (e.g. component has no detectable
runtime pin, or the endoflife collector did not run). All detected
runtimes must be non-EOL — multi-runtime components fail if any one
is EOL.
runtime-supported
Fails if any detected runtime is outside the active support window
(is_supported == false). For products that distinguish active
support from security-only maintenance (e.g. Node.js, Python,
.NET), this catches services running on a runtime that's still
patched for security but no longer receiving non-security fixes.
For products without a separate active-support window (e.g. Go),
this check is equivalent to runtime-not-eol. Skips cleanly when
no EOL data is present.
How Guardrails Fit into Lunar
Lunar guardrails define your engineering standards as code. They evaluate data collected by integrations and produce pass/fail checks with actionable feedback.
Policies support gradual enforcement—from silent scoring to blocking PRs or deployments—letting you roll out standards at your own pace without disrupting existing workflows.
Learn How Lunar Works →Example Evaluated Data
This policy evaluates structured metadata from the Component JSON. Here's an example of the data it checks:
{
"lang": {
"go": {
"eol": {
"source": {
"tool": "endoflife.date",
"integration": "api",
"collected_at": "2026-04-27T12:00:00Z"
},
"product": "go",
"cycle": "1.21",
"detected_version": "1.21",
"is_eol": true,
"is_supported": false,
"eol_date": "2024-08-13",
"support_until": null,
"lts": false,
"latest_in_cycle": "1.21.13"
}
},
"nodejs": {
"eol": {
"source": {
"tool": "endoflife.date",
"integration": "api",
"collected_at": "2026-04-27T12:00:00Z"
},
"product": "nodejs",
"cycle": "20",
"detected_version": "20.11.1",
"is_eol": false,
"is_supported": false,
"eol_date": "2026-04-30",
"support_until": "2024-10-22",
"lts": true,
"latest_in_cycle": "20.19.0"
}
}
}
}
Required Integrations
This policy evaluates data gathered by one or more of the following integration(s).
Make sure to enable them in your lunar-config.yml.
Configuration
Configure this policy in your lunar-config.yml.
Inputs
| Input | Required | Default | Description |
|---|
Documentation
View on GitHubEnd-of-Life Runtime Guardrails
Enforce that components are pinned to runtime versions that upstream still maintains — catches the "neglected legacy service" smell of services running on EOL or out-of-support runtimes.
Overview
This policy operates on data produced by the endoflife collector, which detects pinned runtime versions across Node.js, Python, Ruby, Go, Java, .NET, and PHP, then resolves their EOL/support status against endoflife.date. Two checks: runtime-not-eol (no detected runtime is past its end-of-life date) and runtime-supported (no detected runtime is outside its active-support window). Both checks skip cleanly when no .lang.<language>.eol data is present (e.g. component has no detectable runtime pin, or the endoflife collector hasn't run).
Policies
This plugin provides the following policies (use include to select a subset):
| Policy | Description |
|---|---|
runtime-not-eol |
Fails when any .lang.<language>.eol.is_eol is true — runtime is past eol_date, no upstream fixes (security or otherwise) |
runtime-supported |
Fails when any .lang.<language>.eol.is_supported is false — runtime is past active support (may still receive security-only patches) |
runtime-supported is strictly stricter than runtime-not-eol (an EOL runtime is also unsupported). The two coexist so you can pick the strictness for your enforcement: runtime-not-eol for the worst-case hard-block; runtime-supported to catch drift early before a runtime hits security-only maintenance. For runtimes where endoflife.date doesn't expose a separate support phase (most notably Go), is_supported is equivalent to not is_eol, so the two checks behave identically for those.
If multiple runtimes are detected on the same component (rare — e.g. a service shipping a Python sidecar plus a Java app), all must pass; failures list every offending runtime. The policy currently has no tunable inputs — pass/fail thresholds are absolute (a runtime is EOL or it isn't, in active support or not). For thresholds like "fail if EOL is within N days", file a follow-up issue.
Required Data
This policy reads from the following Component JSON paths:
| Path | Type | Provided By |
|---|---|---|
.lang.<language>.eol.is_eol |
boolean | endoflife |
.lang.<language>.eol.is_supported |
boolean | endoflife |
.lang.<language>.eol.cycle |
string | endoflife |
.lang.<language>.eol.detected_version |
string | endoflife |
.lang.<language>.eol.eol_date |
string | null | endoflife |
.lang.<language>.eol.support_until |
string | null | endoflife |
.lang.<language>.eol.product |
string | endoflife |
<language> is one of go, nodejs, python, ruby, java, dotnet, php. Both checks skip when no .lang.<language>.eol data is present for any language.
Installation
Add to your lunar-config.yml:
collectors:
- uses: github://earthly/lunar-lib/collectors/endoflife@v1.0.0
on: ["domain:your-domain"]
policies:
- uses: github://earthly/lunar-lib/policies/endoflife@v1.0.0
enforcement: report-pr
# include: [runtime-not-eol] # Only run the hard-EOL check
The collector and policy are paired — the policy reads .lang.<language>.eol data, which only the endoflife collector writes today. Make sure the collector is enabled wherever the policy runs.
Examples
Passing Example
{
"lang": {
"nodejs": {
"version": "20.11.1",
"eol": {
"source": { "tool": "endoflife.date", "integration": "api" },
"product": "nodejs",
"cycle": "20",
"detected_version": "20.11.1",
"is_eol": false,
"is_supported": true,
"eol_date": "2026-04-30",
"support_until": "2025-04-30",
"lts": true,
"latest_in_cycle": "20.19.0"
}
}
}
}
Failing Example
{
"lang": {
"go": {
"version": "1.21",
"eol": {
"source": { "tool": "endoflife.date", "integration": "api" },
"product": "go",
"cycle": "1.21",
"detected_version": "1.21",
"is_eol": true,
"is_supported": false,
"eol_date": "2024-08-13",
"support_until": null,
"lts": false,
"latest_in_cycle": "1.21.13"
}
}
}
}
Failure message (runtime-not-eol): go cycle 1.21 (detected 1.21) reached end-of-life on 2024-08-13. Move to a supported cycle (current latest: see https://endoflife.date/go).
Failure message (runtime-supported): go cycle 1.21 (detected 1.21) is out of active support and reached end-of-life on 2024-08-13 (Go has no separate active-support phase). Bump to a still-supported cycle (see https://endoflife.date/go).
Remediation
When this policy fails, you can resolve it by:
runtime-not-eol: Bump the pinned runtime to a cycle whoseeol_dateis in the future. Update the relevant version file (.go-version,.nvmrc,.python-version,package.jsonengines, etc.) and rebuild. Reference the matching endoflife.date page (linked in the failure message) for the current latest cycle and any LTS recommendations.runtime-supported: Bump the pinned runtime to a cycle that's still in active support (i.e. beforesupport_until). This is the recommended fix even when the runtime isn't yet EOL — security-only maintenance is a holding pattern, not a destination.- If the bump is blocked (incompatible dependencies, planned re-platform, etc.) and you need to silence the check temporarily, configure the policy with
enforcement: report-prrather thanblock-pruntil the upgrade lands. Don't suppress the data — leaving the EOL signal visible in the component JSON keeps the issue surfaced.
The policy does not check whether the detected version is the latest patch in its cycle (use .lang.<language>.eol.latest_in_cycle vs detected_version for a custom patch-hygiene check) and does not enforce LTS-only usage (use .lang.<language>.eol.lts for a custom LTS check). Example Component JSON is defined in lunar-policy.yml under example_component_json.
Open Source
This policy is open source and available on GitHub. Contribute improvements, report issues, or fork it for your own use.
Common Use Cases
Explore how individual guardrails work with specific integrations.
Ready to Automate Your Standards?
See how Lunar can turn your AGENTS.md, engineering wiki, compliance docs, or postmortem action items into automated guardrails with our 200+ built-in guardrails.