| Safe Haskell | None |
|---|---|
| Language | GHC2021 |
Ecluse.Core.Server.Pipeline.Origin
Description
Resolving a packument's upstream origins: the per-origin fetch with its credential posture, the read-handle construction over the mount's dependencies, and the typed outcome the merge consumes.
The credential-authority invariant lives here (see
docs/architecture/access-model.md): the private (trusted) origin is fetched
uncached with the client's own forwarded credential, so the upstream
re-authorises every client itself, while the public origin is fetched anonymous
(the client's credential is stripped before any public-upstream fetch) and resolved
through the shared metadata cache, one shared document serving every client. A fetch
that fails degrades to no contribution rather than an error; a self-reported
different package name is kept distinct (OriginNameMismatch) so the
no-valid-origin terminal can render a 502 apart from a transient outage.
Ecluse.Core.Server.Pipeline.Packument gates, merges, and serves what resolves
here; Ecluse.Core.Server.Pipeline.Tarball shares the public read handle
(withPublicMetadataClient) so its single-version gate and the packument fetch
collapse onto one cache entry.
Synopsis
- data Contribution = Contribution {}
- fingerprintPiece :: Contribution -> (Provenance, ContentDigest, [Text])
- data OriginResult
- originManifest :: OriginResult -> Maybe Manifest
- fetchPrivateOrigin :: PackumentDeps -> ServeRuntime -> Maybe Secret -> PackageName -> Handler OriginResult
- fetchPublicOrigin :: PackumentDeps -> ServeRuntime -> PackageName -> Handler OriginResult
- withPublicMetadataClient :: ServeRuntime -> PackumentDeps -> Text -> (MetadataClient -> IO a) -> Handler a
A resolved contribution
data Contribution Source #
A successfully resolved upstream contribution: the parsed packument used to
decide, alongside the raw document (CachedDoc) the served body is rebuilt from, and the
origin body's ContentDigest for the derived validator. Pairing the views is
the decision-surface/served-surface contract -- every stage carries the raw
document next to the typed view so losslessness survives the pipeline. The raw document
is threaded opaquely: the pipeline hands it to the injected adapter capabilities and
never reads it.
Constructors
| Contribution | |
Fields | |
fingerprintPiece :: Contribution -> (Provenance, ContentDigest, [Text]) Source #
One source's slice of the derived validator: its provenance, its origin body's digest, and the version keys that actually survived its gate -- together with the mount base URL and package name, exactly the inputs the assembled document is a deterministic function of (the plan itself derives from these).
The per-origin outcome
data OriginResult Source #
The outcome of resolving one upstream origin for a packument, beyond the
plain "resolved or not" the merge consumes: a name mismatch is kept distinct from a
plain non-resolution so the no-valid-origin terminal status can render a 502 (a
responding upstream returned a packument for a different package) apart from a
transient outage or a genuine absence.
Constructors
| OriginResolved Manifest | A packument that decoded and whose self-reported name matched the request. |
| OriginNameMismatch | The origin answered, but its packument self-reported a name for a different
package -- dropped as untrusted for this request, and a |
| OriginUnresolved | The origin did not yield a usable packument -- unreachable, undecodable, or a genuine absence -- the existing degrade (no contribution). |
| OriginAbsent | The origin is not configured on this mount (a serve-only mount with no
private upstream): structurally absent, kept distinct from |
originManifest :: OriginResult -> Maybe Manifest Source #
The resolved manifest an origin contributed, if any. A name mismatch, a plain non-resolution, and an absent origin alike contribute no document to the merge.
Fetching the two origins
fetchPrivateOrigin :: PackumentDeps -> ServeRuntime -> Maybe Secret -> PackageName -> Handler OriginResult Source #
Resolve the private (trusted) upstream origin, uncached, forwarding the client's
own credential (the default passthrough posture). Returns its coherent (parsed
packument, raw Value) pair -- or Nothing when the origin is unavailable or its body
does not parse. A failed fetch is a degraded contribution, not an error: the merge
serves the best-effort union of whatever resolved (partial-upstream availability).
Under passthrough the private upstream is the per-client authority for who may read
what, so its metadata is not shared across clients: it is fetched and parsed on
every request with that client's own forwarded token, so the upstream re-authorises
each client itself. Caching it would key on the base URL alone (no credential
dimension), so within the TTL one client's cache hit would skip the fetch and serve
another client's private document -- bypassing the upstream's authorisation. The private
origin is therefore deliberately kept out of the metadata cache; only the anonymous
public origin is cached. (How a non-passthrough strategy can instead share the private
origin safely is the serve-time authorisation it adds -- see
docs/architecture/access-model.md.)
fetchPublicOrigin :: PackumentDeps -> ServeRuntime -> PackageName -> Handler OriginResult Source #
Resolve the public (gated, anonymous) upstream origin through the metadata cache,
keyed by the origin's base URL as its Source, returning its coherent (parsed
packument, raw Value) pair -- or Nothing when the origin is unavailable or its body
does not parse. A failed fetch is a degraded contribution, not an error.
The public origin is anonymous (no client credential), so a single cached entry serves
every client without crossing any trust boundary -- there is no per-client authority
to preserve, only one shared anonymous document. A hit returns the cached pair
(typed view and the exact bytes it was decoded from), so the served document and the
decision over it stay coherent across the TTL, and concurrent resolutions of a
popular package collapse to one upstream call -- as does the tarball gate's
single-version read, which shares this very cache entry (fetchVersionMetadata).
withPublicMetadataClient :: ServeRuntime -> PackumentDeps -> Text -> (MetadataClient -> IO a) -> Handler a Source #
The public origin's read handle: anonymous (no token), resolved through the shared
metadata cache under the base URL's Source. Both the packument fetch (fetchFullManifest)
and the tarball gate's single-version read (fetchVersionMetadata) go through this handle,
so they share one cache entry.