Help us shape the future of Go! Take the 2026 Go Developer Survey

support

package
v0.46.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 1, 2026 License: BSD-3-Clause Imports: 4 Imported by: 0

Documentation

Overview

Package support answers a question a vulnerability database cannot: is the version we publish on an upstream release line that is still supported?

⛔ END-OF-LIFE IS NOT A CVE, AND THAT IS THE WHOLE REASON THIS EXISTS. OSV answers "what is known to be wrong with this version". A line that upstream has stopped supporting has, by definition, nothing known about it yet — and never will, because nobody is looking and no fix is coming. `bk vulnfetch` and the daily sweep are structurally blind to it: they can return a clean zero for a package whose upstream stopped issuing fixes years ago.

Measured 2026-10-29 against the registry: it publishes openssl 3.2, 3.3, 3.4, 3.5, 3.6 and 4.0. Of those, 3.2 and 3.3 were already out of support, 3.4 went out on 2026-10-22 — a week earlier — and 3.6 goes out on 2026-11-01. A `^3` constraint takes the newest 3.x, which is 3.6: so the default resolution was three days from an unsupported line while 3.5, the LTS supported to 2030, sat in the registry unused. Nothing in the CVE lane could say so.

The source, and the field that lies

endoflife.date's v1 API (schema 1.2.1) returns, per product, a list of release cycles. The fields that matter are `isEol` and `eolFrom`.

⛔ `isMaintained` IS NOT THE ANSWER, and reading it would invert the verdict on the worst case. From the live response for openssl:

{"name":"1.1.1","isEol":true,"eolFrom":"2023-09-11","isMaintained":true}
{"name":"3.0",  "isEol":true,"eolFrom":"2026-09-07","isMaintained":true}

Both lines have been out of support for a while, and both say `isMaintained: true` — it reflects the PAID extended support openssl sells (the product's own labels call it "Premium support"). A check reading that field would report 1.1.1 as healthy, which is exactly the bottle this fleet has 32 of.

⛔ AN ABSENT DATE IS NOT A DISTANT ONE. A cycle may carry `eolFrom: null`, which means nobody has published a date — not that the line is supported forever. It is reported as UNKNOWN and never as healthy, because the alternative is a silence that reads like an answer.

How the others do it

Yocto has no equivalent: its CVE handling is identity plus a database, which is the half this complements. Wolfi gets closest with the `fix-not-planned` event, which its own documentation reserves for end-of-life packages and says "should never be used on supported software" — but that is a decision recorded per advisory, after somebody noticed. This asks the question before there is an advisory to decide about.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Product

type Product struct {
	Name     string
	Label    string
	Policy   string
	Releases []Release
}

Product is one product's release lines.

func ParseProduct

func ParseProduct(data []byte) (*Product, error)

ParseProduct reads an endoflife.date v1 product response.

type Release

type Release struct {
	Name    string `json:"name"`
	Label   string `json:"label"`
	IsLTS   bool   `json:"isLts"`
	IsEOL   bool   `json:"isEol"`
	EOLFrom string `json:"eolFrom"`
	// ⛔ Deliberately NOT decoded: `isMaintained`. It is true for lines that
	// have been end-of-life for years, because it reflects paid extended
	// support. Leaving it out of the type means no later reader can reach for
	// it by accident.
	Latest struct {
		Name string `json:"name"`
	} `json:"latest"`
}

Release is one upstream release line, as endoflife.date reports it.

func BestLine

func BestLine(p *Product, now time.Time) (Release, bool)

BestLine is the line a reader should move to: the longest-supported one, preferring an LTS when two end on the same day.

It exists so a finding can name a destination. "openssl 3.6 ends on Sunday" is a problem; "and 3.5 is supported to 2030" is the next step, and leaving the reader to find it is how a report becomes a chore.

func CycleFor

func CycleFor(version string, releases []Release) (Release, bool)

CycleFor is the release line a version belongs to: the LONGEST cycle name that prefixes it on a component boundary.

⛔ THE BOUNDARY IS THE POINT. A plain string prefix puts `3.60` in line `3.6`, and the longest-match rule is what keeps openssl's `1.1.1w` out of line `1.1.0`'s neighbour `1.1`: it belongs to `1.1.1`. The character after the match may be a separator or a patch letter — openssl spells its patch releases `1.1.1w` — but it may never be another digit, which would mean a different line entirely.

type State

type State int

State is what a version's line is worth.

const (
	// StateUnknown: no line claims this version, or the line publishes no
	// date. Never reported as healthy.
	StateUnknown State = iota
	// StateSupported: the line is current and no end date is near.
	StateSupported
	// StateExpiring: the line has an end date inside the window asked for.
	StateExpiring
	// StateEOL: the line is past its end date.
	StateEOL
)

func (State) String

func (s State) String() string

type Verdict

type Verdict struct {
	Version string
	Cycle   Release
	State   State
	// EOL is the line's end date, zero when it publishes none.
	EOL time.Time
	// Why says, in one line, what was read and what it means.
	Why string
}

Verdict is one version judged against its release line.

func Judge

func Judge(version string, p *Product, now time.Time, within time.Duration) Verdict

Judge places a version on its line and says what that line is worth as of `now`, treating an end date within `within` as expiring.

⛔ IT READS `isEol` AND THE DATE, NOT ONE OR THE OTHER. The flag is how upstream states a decision and the date is when it takes effect, and they disagree for a day or two around a transition — openssl 3.6 carried `isEol:false` with `eolFrom:2026-11-01` three days before that date. Either one alone answers late.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL