cooldown

package module
v0.3.1 Latest Latest
Warning

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

Go to latest
Published: Nov 2, 2026 License: MIT Imports: 7 Imported by: 0

README

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.

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func ParseDuration

func ParseDuration(s string) (time.Duration, error)

ParseDuration parses a duration string supporting days (e.g., "3d"), in addition to Go's standard time.ParseDuration formats ("48h", "30m"). "0" means disabled (returns 0).

Types

type Config

type Config struct {
	// Default is the global default cooldown duration (e.g., "3d", "48h").
	Default string `json:"default" yaml:"default"`

	// Ecosystems overrides the default for specific ecosystems.
	// Keys are ecosystem names (e.g., "npm", "pypi").
	Ecosystems map[string]string `json:"ecosystems" yaml:"ecosystems"`

	// Packages overrides the cooldown for specific packages.
	// Keys are PURLs (e.g., "pkg:npm/lodash", "pkg:npm/@babel/core").
	Packages map[string]string `json:"packages" yaml:"packages"`
	// contains filtered or unexported fields
}

Config holds cooldown settings for version filtering. Cooldown hides package versions published too recently, giving the community time to spot malicious releases before they're pulled into projects.

func (*Config) Enabled

func (c *Config) Enabled() bool

Enabled returns true if any cooldown is configured.

func (*Config) Evaluate added in v0.2.0

func (c *Config) Evaluate(ecosystem, packagePURL string, publishedAt, evaluatedAt time.Time) Decision

Evaluate returns the cooldown decision for a version at evaluatedAt. AvailableAt is zero when the publication time is unknown. Otherwise, it is the publication time plus the selected cooldown, including when the cooldown is disabled.

func (*Config) For

func (c *Config) For(ecosystem, packagePURL string) time.Duration

For returns the effective cooldown duration for a given ecosystem and package PURL. Resolution order: package override > ecosystem override > global default.

func (*Config) IsAllowed

func (c *Config) IsAllowed(ecosystem, packagePURL string, publishedAt time.Time) bool

IsAllowed returns true if a version with the given publish time has passed the cooldown period for this ecosystem/package.

type Decision added in v0.2.0

type Decision struct {
	Allowed     bool
	Cooldown    time.Duration
	AvailableAt time.Time
	Reason      Reason
}

Decision describes the result of evaluating a package version.

type Policy added in v0.3.0

type Policy struct {
	// contains filtered or unexported fields
}

Policy applies exact PURL overrides before package-pattern overrides.

func NewPolicy added in v0.3.0

func NewPolicy(base *Config, packagePatterns map[string]string) (*Policy, error)

NewPolicy creates a Policy using the supplied exact and pattern overrides. Exact keys and lookup PURLs must use the same canonical encoding. Do not modify base after constructing the policy.

func (*Policy) Enabled added in v0.3.0

func (p *Policy) Enabled() bool

Enabled reports whether any configured cooldown can filter a package version.

func (*Policy) Evaluate added in v0.3.0

func (p *Policy) Evaluate(ecosystem, packagePURL string, publishedAt, evaluatedAt time.Time) Decision

Evaluate returns the cooldown decision at the supplied evaluation time.

func (*Policy) For added in v0.3.0

func (p *Policy) For(ecosystem, packagePURL string) time.Duration

For returns the duration, with exact overrides taking precedence over patterns.

func (*Policy) IsAllowed added in v0.3.0

func (p *Policy) IsAllowed(ecosystem, packagePURL string, publishedAt time.Time) bool

IsAllowed reports whether the package version has completed its cooldown.

type Reason added in v0.2.0

type Reason string

Reason explains why a package version is allowed or blocked.

const (
	// ReasonDisabled means the selected cooldown duration is zero.
	ReasonDisabled Reason = "disabled"
	// ReasonElapsed means the package version has passed its cooldown period.
	ReasonElapsed Reason = "elapsed"
	// ReasonWaiting means the package version is still in its cooldown period.
	ReasonWaiting Reason = "waiting"
	// ReasonUnknownPublicationTime means the package version has no publication
	// time and is allowed by the default permissive policy.
	ReasonUnknownPublicationTime Reason = "unknown-publication-time"
)

Jump to

Keyboard shortcuts

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