ecluse:ecluse-core
Safe HaskellNone
LanguageGHC2021

Ecluse.Core.Package

Description

The ecosystem-neutral package model used by admission and rules. Artifact entry keys retain source coordinates while adapters keep ownership of wire formats.

Synopsis

Scopes

data Scope Source #

An npm scope, stored without its leading '@' (the scope of @myorg/pkg is "myorg"). mkScope normalises away a leading '@', so equality does not depend on how the scope was written.

Instances

Instances details
Show Scope Source # 
Instance details

Defined in Ecluse.Core.Package

Methods

showsPrec :: Int -> Scope -> ShowS #

show :: Scope -> String #

showList :: [Scope] -> ShowS #

Eq Scope Source # 
Instance details

Defined in Ecluse.Core.Package

Methods

(==) :: Scope -> Scope -> Bool #

(/=) :: Scope -> Scope -> Bool #

Ord Scope Source # 
Instance details

Defined in Ecluse.Core.Package

Methods

compare :: Scope -> Scope -> Ordering #

(<) :: Scope -> Scope -> Bool #

(<=) :: Scope -> Scope -> Bool #

(>) :: Scope -> Scope -> Bool #

(>=) :: Scope -> Scope -> Bool #

max :: Scope -> Scope -> Scope #

min :: Scope -> Scope -> Scope #

mkScope :: Text -> Scope Source #

Build a Scope, tolerating an optional leading '@'.

unScope :: Scope -> Text Source #

The bare scope text, without the leading '@'.

renderScope :: Scope -> Text Source #

Render a scope in npm wire form, with the leading '@'.

Package identity

data PackageName Source #

A package identity, decoupled from any registry's wire format and built with mkPackageName. Equality and ordering read (pkgEcosystem, pkgNamespace, pkgCanonical) only, so Flask and flask are one PyPI package and two npm ones.

mkPackageName :: Ecosystem -> Maybe Scope -> Text -> PackageName Source #

Build a PackageName, normalising the canonical key for the ecosystem: PEP 503 for PyPI, verbatim for npm and RubyGems.

pkgEcosystem :: PackageName -> Ecosystem Source #

The ecosystem this name belongs to.

pkgNamespace :: PackageName -> Maybe Scope Source #

The scope, if scoped (npm @scope/name). Nothing for PyPI/RubyGems.

pkgCanonical :: PackageName -> ShortText Source #

The normalised matching key: PEP 503 for PyPI, verbatim for npm and RubyGems.

pkgBaseName :: PackageName -> ShortText Source #

The base name with any @scope/ prefix dropped. It is not part of identity. Read it back through unscopedName.

renderPackageName :: PackageName -> Text Source #

Render a package name in its native wire form (the display name).

unscopedName :: PackageName -> Text Source #

The unscoped (base) name as Text: @babel/code-frame reads back as code-frame.

The name charset boundary

isAsciiNameComponent :: Text -> Bool Source #

Whether one component of a package name is ASCII with no control character: the boundary every ecosystem's grammar rests on, because an invisible codepoint renders two names as one.

Canonical keys

canonicalise :: Ecosystem -> Text -> Text Source #

Normalise a display name into its canonical matching key for an ecosystem. An ecosystem with a normalisation grammar keeps it in its own module.

Normalised signals

data CodeExecSignal Source #

Whether installing a version executes code (the cross-ecosystem unification of npm install scripts, PyPI sdist builds, and RubyGems native extensions).

Constructors

NoCodeOnInstall

Determined: installation runs no code.

RunsCodeOnInstall Text

Determined: installation runs code. The text says how, for the audit trail.

CodeExecUnknown

Not yet determined (e.g. nothing has fetched the RubyGems gemspec yet). Pure rules abstain, and the effectful tier may resolve it.

Instances

Instances details
Show CodeExecSignal Source # 
Instance details

Defined in Ecluse.Core.Package

Eq CodeExecSignal Source # 
Instance details

Defined in Ecluse.Core.Package

data Availability Source #

Whether a version is offered, advisory-deprecated, or withdrawn.

Constructors

Available

Offered normally.

Deprecated Text

Advisory deprecation (npm), still resolvable. Carries the message.

Yanked (Maybe Text)

Withdrawn from resolution (PyPI yank keeps the file, RubyGems yank removes it). Carries the reason, if given.

Instances

Instances details
Show Availability Source # 
Instance details

Defined in Ecluse.Core.Package

Eq Availability Source # 
Instance details

Defined in Ecluse.Core.Package

Artifacts

data Artifact Source #

One distribution file for a version. A version owns a NonEmpty list of these: npm has exactly one, PyPI has an sdist plus many wheels, RubyGems has one per platform.

Constructors

Artifact 

Fields

  • artEntryKey :: EntryKey

    The coordinate in its source snapshot. Admission preserves it unchanged.

  • artFilename :: Text
     
  • artUrl :: Text
     
  • artHashes :: [Hash]

    Integrity digests. The client verifies the download against these.

  • artSize :: Maybe Int

    The registry-declared size, if reported. Not always the tarball byte count: npm populates it from dist.unpackedSize, the size of the unpacked tree.

Instances

Instances details
Show Artifact Source # 
Instance details

Defined in Ecluse.Core.Package

Eq Artifact Source # 
Instance details

Defined in Ecluse.Core.Package

data Hash Source #

An artifact digest validated by mkHash. Record updates must preserve its encoding and length.

Instances

Instances details
Show Hash Source # 
Instance details

Defined in Ecluse.Core.Package.Hash

Methods

showsPrec :: Int -> Hash -> ShowS #

show :: Hash -> String #

showList :: [Hash] -> ShowS #

Eq Hash Source # 
Instance details

Defined in Ecluse.Core.Package.Hash

Methods

(==) :: Hash -> Hash -> Bool #

(/=) :: Hash -> Hash -> Bool #

hashAlg :: Hash -> HashAlg Source #

The algorithm the digest was computed with.

hashValue :: Hash -> Text Source #

The digest itself, in the algorithm's wire encoding (e.g. hex, or the single sha512-… component for SRI).

mkHash :: HashAlg -> Text -> Either Text Hash Source #

Validate encoding and digest length, preserving the wire spelling. Strength is a separate admission decision.

mkSriHashes :: Text -> Either Text (NonEmpty Hash) Source #

Split SRI components, rejecting the whole string when empty or when any component is malformed.

data HashAlg Source #

A hash algorithm an integrity digest is computed with. The Ord instance is integrity authority, not constructor order: SRI < MD5 < SHA1 < SHA256 < SHA384 < Blake2b < SHA512.

Constructors

SHA1 
SHA256 
SHA384 
SHA512 
MD5 
Blake2b 
SRI

One Subresource-Integrity component. mkSriHashes splits whitespace-separated components.

Instances

Instances details
Generic HashAlg Source # 
Instance details

Defined in Ecluse.Core.Package.Hash

Associated Types

type Rep HashAlg 
Instance details

Defined in Ecluse.Core.Package.Hash

type Rep HashAlg = D1 ('MetaData "HashAlg" "Ecluse.Core.Package.Hash" "ecluse-0.4.0-inplace-ecluse-core" 'False) ((C1 ('MetaCons "SHA1" 'PrefixI 'False) (U1 :: Type -> Type) :+: (C1 ('MetaCons "SHA256" 'PrefixI 'False) (U1 :: Type -> Type) :+: C1 ('MetaCons "SHA384" 'PrefixI 'False) (U1 :: Type -> Type))) :+: ((C1 ('MetaCons "SHA512" 'PrefixI 'False) (U1 :: Type -> Type) :+: C1 ('MetaCons "MD5" 'PrefixI 'False) (U1 :: Type -> Type)) :+: (C1 ('MetaCons "Blake2b" 'PrefixI 'False) (U1 :: Type -> Type) :+: C1 ('MetaCons "SRI" 'PrefixI 'False) (U1 :: Type -> Type))))

Methods

from :: HashAlg -> Rep HashAlg x #

to :: Rep HashAlg x -> HashAlg #

Show HashAlg Source # 
Instance details

Defined in Ecluse.Core.Package.Hash

Eq HashAlg Source # 
Instance details

Defined in Ecluse.Core.Package.Hash

Methods

(==) :: HashAlg -> HashAlg -> Bool #

(/=) :: HashAlg -> HashAlg -> Bool #

Ord HashAlg Source # 
Instance details

Defined in Ecluse.Core.Package.Hash

Universe HashAlg Source # 
Instance details

Defined in Ecluse.Core.Package.Hash

Methods

universe :: [HashAlg] #

type Rep HashAlg Source # 
Instance details

Defined in Ecluse.Core.Package.Hash

type Rep HashAlg = D1 ('MetaData "HashAlg" "Ecluse.Core.Package.Hash" "ecluse-0.4.0-inplace-ecluse-core" 'False) ((C1 ('MetaCons "SHA1" 'PrefixI 'False) (U1 :: Type -> Type) :+: (C1 ('MetaCons "SHA256" 'PrefixI 'False) (U1 :: Type -> Type) :+: C1 ('MetaCons "SHA384" 'PrefixI 'False) (U1 :: Type -> Type))) :+: ((C1 ('MetaCons "SHA512" 'PrefixI 'False) (U1 :: Type -> Type) :+: C1 ('MetaCons "MD5" 'PrefixI 'False) (U1 :: Type -> Type)) :+: (C1 ('MetaCons "Blake2b" 'PrefixI 'False) (U1 :: Type -> Type) :+: C1 ('MetaCons "SRI" 'PrefixI 'False) (U1 :: Type -> Type))))

Algorithm vocabulary

renderHashAlg :: HashAlg -> Text Source #

The canonical lowercase name, also used in configuration and error text.

parseHashAlg :: Text -> Either Text HashAlg Source #

Parse canonical names and single-dash aliases, ignoring case and surrounding whitespace. SRI is not selectable.

sriPrefix :: Text -> Text Source #

The token before the first dash. Without a dash, the entire string is the prefix.

sriBody :: Text -> Text Source #

The body after the first dash, or empty text when there is no dash.

sriAlgorithm :: Text -> Maybe HashAlg Source #

Resolve an SRI prefix. An unsupported prefix asserts no algorithm and clears no integrity floor.

Digest computation

computeDigest :: HashAlg -> Maybe (LByteString -> ByteString) Source #

Digest computation for verifiable algorithms. MD5 cannot prove integrity, and SRI must first resolve its algorithm.

isComputable :: HashAlg -> Bool Source #

Whether the worker can compute and verify the algorithm.

Per-version details

data PackageDetails Source #

The ecosystem-agnostic snapshot of one package version: the signals a rule sees and the artifact facts that merge, admission, serving and the mirror read. Adapters project into it.

Constructors

PackageDetails 

Fields

Instances

Instances details
Show PackageDetails Source # 
Instance details

Defined in Ecluse.Core.Package

Eq PackageDetails Source # 
Instance details

Defined in Ecluse.Core.Package

Packument-level view

data PackageInfo Source #

The packument-level view of a package (PackageDetails is the per-version snapshot embedded within it). A registry adapter projects its packument into this type, so the proxy core never sees the wire format.

Constructors

PackageInfo 

Fields

Instances

Instances details
Show PackageInfo Source # 
Instance details

Defined in Ecluse.Core.Package

Eq PackageInfo Source # 
Instance details

Defined in Ecluse.Core.Package

Dropped entries

data InvalidEntry Source #

A single registry-document entry a projection dropped as malformed rather than failing the whole document, kept so an operator can see that an upstream served one, and which.

mkInvalidEntry :: InvalidEntryKind -> Text -> Value -> Text -> InvalidEntry Source #

Record a dropped entry, reducing every URL in the key and the value to its authority: an upstream-supplied artifact location can carry a credential, and this record reaches a log line.

data InvalidEntryKind Source #

Which kind of registry-document entry a dropped InvalidEntry came from. A dropped manifest or index file loses a serve candidate, a dropped tag, time or listing only its own datum.

Constructors

InvalidVersionManifest

A versions entry whose manifest did not project (no dist/tarball, an unusable version).

InvalidDistTag

A dist-tags entry whose target was not a usable version string.

InvalidPublishTime

A time entry, keyed by a present version, that was not a decodable instant.

InvalidIndexFile

A Simple-index file entry that did not project (no name or location, an unusable digest).

InvalidVersionListing

A versions-listing entry that was not a usable version string.

renderInvalidEntryKind :: InvalidEntryKind -> Text Source #

The operator-facing label for a drop kind. It is the bucket key an operator filters on, so it is held stable as this text rather than the constructor name.

dropCountsByKind :: [InvalidEntry] -> Map Text Int Source #

How many entries dropped under each kind's label. Only the kinds actually seen appear, so a document's drop profile carries no bucket its ecosystem has no entries for.