Skip to content

Releases: nlink-jp/cve-lookup

v0.1.3

Choose a tag to compare

@magifd2 magifd2 released this 21 Sep 20:32

get --raw is now described as upstream's own document rather than its bytes: terminal-obeyed characters are escaped, a carriage return between tokens becomes a newline, and a cached copy is compacted with <, > and & escaped. Output is unchanged. See CHANGELOG.md.

v0.1.2

Choose a tag to compare

@magifd2 magifd2 released this 21 Sep 01:36

Fixed

  • get --raw could let an upstream document overwrite the lines already
    printed.
    A carriage return is legal whitespace between JSON tokens and an
    instruction to a terminal — it returns the cursor to the start of the line.
    It cannot be escaped there (between tokens an escape is not valid JSON), so a
    CRLF now loses the carriage return and a lone one becomes a newline. The
    document a parser sees is unchanged.

v0.1.1

Choose a tag to compare

@magifd2 magifd2 released this 20 Sep 16:43

Fixed

  • search --min-cvss NaN was accepted and sent upstream as min_cvss=NaN,
    where an ignored filter comes back looking like a filtered list. The range
    check was written as "below 0 or above 10", which NaN passes; the config
    parser already stated its ranges from the inside, the flags did not.
    --timeout NaN, Inf and 1e300 were accepted too, and the config file's
    one-hour ceiling did not apply to the flag. Both now take the same rule.
  • A numeric flag given as 0 was read as the flag's absence. --limit 0
    printed the default page, --year 0 every year, and --timeout 0 the
    configured timeout, without a word — 0.1.0 said this was fixed and had fixed
    it for --min-cvss only. They are refused, at the MCP surface too
    (search_cves with year: 0). match --limit -1 was the last of them — -1
    was that flag's own "not given" — and is refused as well.
  • A timeout or TTL so small that it rounds to no time at all (1e-10 seconds)
    was accepted and became a zero duration, which means "not set" to the config
    loader and "no timeout" to the HTTP client: the smallest value one could
    write behaved as the largest. It is refused, from the flag, the environment
    and the config file alike.
  • Upstream's error text reached stderr with bidirectional controls intact.
    The three places that neutralise third-party text each kept their own list of
    what a terminal obeys, and the one for error messages had no bidi controls, so
    an error body could reorder the line it was printed on — against what this
    README says. There is one list now (internal/termsafe).

v0.1.0

Choose a tag to compare

@magifd2 magifd2 released this 20 Sep 14:10

First release.

Added

  • get <CVE-ID>...: CVSS by version with who rated it, CISA KEV, EPSS, SSVC,
    exploitation evidence, patch availability and EchelonGraph's fused score —
    as this tool's own projection, every block naming its source. A block
    upstream holds nothing for is omitted and named in absent; a score of 0 is
    never passed on as a rating. --section opens cpe / references /
    score-factors in full; --raw prints upstream's body as it arrived.
  • search [<text>]: free-text search over descriptions with --severity,
    --basis, --min-cvss, --kev, --year, --sort, --limit, --offset.
    Enums are validated before the request, because upstream silently ignores an
    invalid sort.
  • match --product P [--vendor V]: CVEs that apply to a product at the CPE
    layer, paged locally. An unknown product is product_known: false, not an
    empty list. No version is sent upstream. Upstream does not filter by vendor:
    rows whose vendor it could not confirm carry vendor_unverified, the result
    counts them, and the headline says VENDOR NOT CONFIRMED when the vendor
    matched nothing.
  • exposure <CVE-ID>: internet-exposure footprint. A CVE the radar does not
    follow is tracked: false, never "0 hosts"; a key upstream leaves out stays
    absent instead of becoming a zero.
  • related <CVE-ID>: CVEs sharing a product, a vendor advisory or a CWE, up to
    ten per relation, each with what ties it. A CVE upstream does not index is
    reported as such, never as three empty lists; when that cannot be checked
    the answer is incomplete and the run exits 1.
  • advisories [--vendor V] [--has-cve | --no-cve]: vendor advisories from
    Microsoft, Red Hat, GitHub, Cisco, AWS, Google Cloud and GitLab, newest
    first — --no-cve lists what vendors disclosed before a CVE ID existed.
    The vendor is a closed set, because upstream answers an unknown one with an
    empty list.
  • advisory <vendor> <id>: one advisory in full, by the vendor's own
    identifier.
  • status: feed freshness and counts by severity, always live.
  • cache status|clear, and a fixed-TTL result cache holding upstream's body
    with three freshness windows. Errors, not_found and an unverified empty
    answer are never cached; --refresh bypasses it.
  • mcp: a local stdio MCP server with ten tools — get_cve, search_cves,
    match_product, get_exposure, get_related, search_advisories,
    get_advisory, feed_status, cache_status, get_usage. Results are sized
    for a model's context: compact by default, every cap counted, and everything
    left out reachable through section, paged (text by characters). Behind the
    caps, any other string over 1000 characters is shortened and named, and no
    result leaves the server over 128 KB (response_too_large). get_usage
    carries the tool reference, the result schemas and how to read the "upstream
    has no data" shapes.
  • Stable error codes end to end: not_found (worded "not in EchelonGraph's
    index", and only for the API's own 404 on a single resource),
    endpoint_unavailable (a path outside the public API — a wrong base_url —
    or a listing that answers 404), rate_limited, bad_request,
    upstream_error, network_error, timeout, decode_error,
    invalid_argument, unknown_tool, response_too_large, internal_error.
  • Input that is not understood is refused rather than ignored: unknown config
    sections and keys, a key set to "", a number outside its range, a
    --config path that does not exist, a flag value that used to double as
    "not given", stray arguments, and MCP arguments a tool does not declare are
    each an error naming the offender.
  • Text output makes every string from upstream inert before it is printed —
    control characters, escape sequences and the Unicode bidirectional controls
    are shown as escapes — and prints third-party text behind a gutter. --json
    and --raw write the same characters as the \u escapes they equal.
  • Sectioned-TOML configuration with CVE_LOOKUP_* overrides and a validated
    base_url. The file is searched in $XDG_CONFIG_HOME/cve-lookup/,
    ~/.config/cve-lookup/ and, on macOS, ~/Library/Application Support/;
    cache status prints the file that was read.
  • Per-process request pacing with a short burst, 30 requests per minute by
    default — half the 60 per minute upstream allows per IP address. A 429 is
    reported, not retried.
  • A live end-to-end suite (make e2e) that pins the upstream behaviours the
    design rests on, and a drift check against the CISA KEV catalogue and FIRST
    EPSS with tolerances — a release gate that fails, rather than skips, when it
    could not compare.