Fixes #553. The PyPI and npm validators fetch the version-specific metadata endpoint (`/pypi/{name}/{version}/json` and the npm equivalent) and report any non-200 as `<pkg> not found`. That endpoint 404s for two different reasons though: the package doesn't exist, or it exists and only the *version* is missing (e.g. a release that hasn't propagated yet). So a valid package reads as gone: ```diff - PyPI package 'requests' not found (status: 404) + PyPI package 'requests' exists, but version '99.99.99' was not found (status: 404). A newly published release can take a moment to appear on PyPI. Wait and retry, or publish version '99.99.99' before registering it ``` On a version 404 it probes the package-level endpoint (`/pypi/{name}/json`, `/{name}`) with a `HEAD` to tell the two apart, and reports 429/5xx as transient rather than "not found". `HEAD` so it reads a status without pulling the whole packument. The probe carries its own 3s deadline: it only refines the error message, so a hung probe must not stretch the validator past the ~10s-per-registry budget the publish path assumes. Same probe-and-classify shape as the existing cargo validator. The fetch is split into `validatePyPIPackage` / `validateNPMPackage` behind `export_test.go` so the branches are testable with `httptest`, the same seam cargo uses. ### Testing - [x] hermetic `httptest` for the status matrix (version-missing, package-missing, 5xx, 429, inconclusive probe, positive path, scoped npm); the mocks pin the expected method per endpoint (`GET` fetch, `HEAD` probe) - [x] hermetic deadline test: a hung probe is cut off at ~3s and reported as inconclusive, not "not found" - [x] existing live package tests still pass, now also hitting the HEAD probe; on a live 429/5xx they now `t.Skip` as inconclusive instead of flaking (deliberate: CI runs these against the real registries with no short-mode gating) - [x] `gofmt` / `go vet` / `golangci-lint` clean Out of scope: auto-retry for the propagation race, and SSRF redirect-pinning parity for the pypi/npm clients (pre-existing, shared with nuget).
20 lines
969 B
Go
20 lines
969 B
Go
package registries
|
|
|
|
// ValidateCargoREADME exposes the package-private validateCargoREADME to the
|
|
// external _test package so httptest-driven tests can exercise the README-fetch
|
|
// and mcp-name token-match pipeline against a mock server, bypassing the
|
|
// exact-baseURL guard that the public ValidateCargo enforces.
|
|
//
|
|
// Intended for cargo_test.go's positive-path and transient-error tests only.
|
|
var ValidateCargoREADME = validateCargoREADME
|
|
|
|
// ValidatePyPIPackage and ValidateNPMPackage expose the package-private
|
|
// validatePyPIPackage / validateNPMPackage to the external _test package so
|
|
// httptest-driven tests can exercise the metadata fetch and status-disambiguation
|
|
// pipeline (missing package vs missing/unpropagated version vs transient upstream)
|
|
// against a mock server, bypassing the exact-baseURL guard that the public
|
|
// ValidatePyPI / ValidateNPM enforce.
|
|
var (
|
|
ValidatePyPIPackage = validatePyPIPackage
|
|
ValidateNPMPackage = validateNPMPackage
|
|
)
|