Skip to content
git-pkgsPublic

About

Ecosystem-agnostic version-age filter for package-manager tools

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

1 star

Watchers

1 watching

Forks

Latest commit

 

History

30 Commits

Folders and files

Repository files navigation

cooldown

A small, ecosystem-agnostic version-age filter for package-manager tools. Hides versions published too recently so the community has time to spot malicious releases before they're pulled into projects.

Cross-ecosystem by construction: the same Config shape covers npm, PyPI, Cargo, RubyGems, Composer, Conda, Hex, NuGet, Pub, and any future ecosystem. Resolution order is package-PURL > ecosystem-name > global default, so a single config can express a strict default with targeted opt-outs.

Install

go get github.com/git-pkgs/cooldown

Usage

cfg := &cooldown.Config{
    Default:    "48h",                              // global window
    Ecosystems: map[string]string{"npm": "72h"},    // npm gets longer
    Packages:   map[string]string{                  // per-PURL override
        "pkg:npm/htmx.org": "0",                    // 0 = disabled
    },
}

if cfg.IsAllowed("npm", "pkg:npm/lodash", publishedAt) {
    // version cleared the window; use it
}

decision := cfg.Evaluate("npm", "pkg:npm/lodash", publishedAt, evaluatedAt)
if !decision.Allowed {
    fmt.Printf("available at %s (%s)\n", decision.AvailableAt, decision.Reason)
}

Config.Evaluate accepts an explicit evaluation time and returns the selected cooldown, availability time, and a typed reason. Versions without a publication time remain allowed and return ReasonUnknownPublicationTime. Config.IsAllowed is the current-time shorthand. Config.For(ecosystem, purl) returns the effective duration; useful when surfacing the policy to a UI. Config.Enabled() reports whether any cooldown is configured (cheap check before walking a large version set).

Duration strings accept Go's standard formats (48h, 30m, 1h30m) plus a d suffix for days (3d). 0 disables the window.

For package-pattern overrides, construct a Policy before serving requests:

policy, err := cooldown.NewPolicy(cfg, map[string]string{
    "pkg:npm/@example/*": "0",
    "pkg:nuget/example.*": "7d",
})
if err != nil {
    return err
}
decision := policy.Evaluate("npm", "pkg:npm/%40example/widget", publishedAt, evaluatedAt)

Policy provides the same For, Evaluate, IsAllowed, and Enabled methods as Config. Exact package overrides take precedence over patterns, followed by ecosystem overrides and the global default. The matching pattern with the most literal characters wins, with lexical order breaking ties. * and ? do not match /; character classes and escapes are rejected.

Patterns accept either @ or %40 for npm scopes. Exact keys and lookup PURLs must already use the same canonical encoding. The constructor rejects invalid pattern durations and conflicting normalized patterns; equivalent durations such as 1d and 24h are accepted. A nil base config supplies a zero default. Construct the policy once and leave the base config unchanged while using it concurrently.

Why standalone

Originally lived inside an HTTP proxy that filtered registry responses; spotted as a reusable shape and lifted out. The same predicate is useful for package-manager CLIs, dependency-update bots, security scanners, and anything else that walks a version set with an age constraint.

License

MIT.

About

Ecosystem-agnostic version-age filter for package-manager tools

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

1 star

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages