DEV Community

Matheus
Matheus

Posted on • Originally published at releaserun.com

How I Track EOL Dates and CVEs in My README With One Badge

Every README has badges. Build passing. Coverage 94%. License MIT.

None of them answer the question that actually matters: is this project running on supported versions?

You can have 100% test coverage on a project pinned to Node 16 (EOL since September 2025). The CI badge says "healthy." The runtime says otherwise.

I wanted a badge that shows version health — not build status, not coverage, but whether the thing you're depending on is still alive. So I built one.

One line of markdown

![Python Health](https://img.releaserun.com/badge/health/python.svg)
Enter fullscreen mode Exit fullscreen mode

That renders a live badge showing the current Python health grade:

Python Health

It auto-updates. No tokens, no config, no API keys. Just an image URL.

Four badge types

What you need Badge Markdown
Overall health grade ![](https://img.releaserun.com/badge/health/kubernetes.svg)
EOL countdown ![](https://img.releaserun.com/badge/eol/nodejs/20.svg)
Known CVEs ![](https://img.releaserun.com/badge/cve/kubernetes/1.34.svg)
Latest version ![](https://img.releaserun.com/badge/v/go.svg)

Health grades run A through F. The scoring: 35% freshness (how current is the version), 35% security (known CVEs), 30% EOL status (support timeline). A critical unfixed CVE caps you at D. Anything past EOL for 1+ year forces an F.

URL pattern: https://img.releaserun.com/badge/{type}/{product}[/{version}].svg

300+ products supported — everything on endoflife.date: Python, Node.js, Go, Rust, Kubernetes, Docker, PostgreSQL, React, TypeScript, Ruby, PHP, .NET, and basically every runtime and infrastructure tool in a production stack.

The "why should I care" section

Here's the scenario that prompted this.

I was reviewing a PR on a project that had a green CI, 87% coverage, active contributors — looked great. Then I checked the Dockerfile: FROM node:16-alpine. Node 16 hit EOL in September 2025. No CVE scanning was going to flag that because the image itself wasn't vulnerable — the runtime lifecycle was the problem.

If the README had shown ![Node.js 16 EOL](https://img.releaserun.com/badge/eol/nodejs/16.svg), anyone opening that repo would've seen the red badge immediately.

Version currency is a signal. Badges make signals visible.

Set it up in 30 seconds

Option 1: Copy-paste (simplest)

Add markers to your README:

## Version Health

<!-- releaserun-badges-start -->
[![Python](https://img.releaserun.com/badge/health/python/3.12.svg)](https://releaserun.com/badges/python/)
[![Node.js](https://img.releaserun.com/badge/eol/nodejs/20.svg)](https://releaserun.com/badges/nodejs/)
[![K8s](https://img.releaserun.com/badge/cve/kubernetes/1.34.svg)](https://releaserun.com/badges/kubernetes/)
<!-- releaserun-badges-end -->
Enter fullscreen mode Exit fullscreen mode

Wrapping in a link is optional but useful — it takes people to a landing page with full version timelines, embed snippets, and context on what the grades mean.

Option 2: GitHub Action (auto-updating)

name: Update Badges
on:
  schedule:
    - cron: '0 6 * * 1'  # Weekly Monday
  workflow_dispatch:

permissions:
  contents: write
  pull-requests: write

jobs:
  badges:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: Matheus-RR/badges@v1
        with:
          products: |
            python:3.12
            node:20
            kubernetes:1.34
          badge-types: health,eol,cve
          github-token: ${{ secrets.GITHUB_TOKEN }}
Enter fullscreen mode Exit fullscreen mode

The Action finds the <!-- releaserun-badges-start --> / <!-- releaserun-badges-end --> markers in your README and opens a PR with updated badges. You review and merge.

Why a PR instead of direct commit? Because badge content changes (a version goes EOL, a CVE is published), and you should see what changed before it's in your main branch.

Option 3: Interactive Builder

Don't want to type URLs? The Badge Builder lets you search 300+ products, pick badge types, preview them live, and copy the embed code in Markdown, HTML, reStructuredText, or AsciiDoc.

Not shields.io

People ask this, so: shields.io does static labels and CI metrics (build status, coverage, npm version). Great tool, different job.

ReleaseRun badges show live version intelligence: health grades that update as versions age, EOL countdowns that tick down in real-time, CVE counts that reflect the current threat landscape. The data source is different, the use case is different.

Use both. shields.io for your CI pipeline status. ReleaseRun for your dependency health.

Customize it

Every badge accepts query params:

https://img.releaserun.com/badge/health/python.svg?style=flat-square&label=runtime
Enter fullscreen mode Exit fullscreen mode
Param What it does
style flat (default) or flat-square
label Custom left-side text
color Override right-side color
labelColor Override left-side color

How it works under the hood

The service queries endoflife.date for version lifecycle data, enriches it with CVE data from NVD, computes health grades, and renders SVG badges on the fly via pybadges.

Four cache layers keep it fast:

  • In-memory SVG cache (2 min) → sub-50ms for repeat requests
  • Data cache (5 min) → limits upstream API calls
  • HTTP cache headers → browser + CDN caching
  • Cloudflare CDN → global edge

Badges are never more than 5 minutes stale.

Get started

Pick any product. Copy one line. Push.

![](https://img.releaserun.com/badge/health/python.svg)
![](https://img.releaserun.com/badge/eol/nodejs/20.svg)
![](https://img.releaserun.com/badge/cve/kubernetes/1.34.svg)
![](https://img.releaserun.com/badge/v/docker-engine.svg)
Enter fullscreen mode Exit fullscreen mode

Full docs and every supported product: releaserun.com/badges/

GitHub Action: Matheus-RR/badges

Badge Builder: releaserun.com/badges/builder/


ReleaseRun tracks software releases across 300+ technologies. The badge service is free.

Top comments (0)