licence_audit/notice

Types

Injected HTTP clients for every network operation the notices flow performs. Bundling them keeps call signatures stable as the fallback grows and lets tests substitute deterministic fakes without touching the network.

pub type Clients {
  Clients(
    fetch_hex_tarball: fn(String, String) -> Result(
      BitArray,
      FetchError,
    ),
    fetch_git_archive: fn(repository.Repository, String) -> Result(
      BitArray,
      FetchError,
    ),
    resolve_commit: fn(repository.Repository, String) -> Result(
      option.Option(String),
      FetchError,
    ),
    fetch_repo_archive: fn(repository.Repository, String) -> Result(
      BitArray,
      FetchError,
    ),
    fetch_spdx_index: fn(spdx.IndexKind) -> Result(
      List(String),
      FetchError,
    ),
    fetch_spdx: fn(spdx.Requirement) -> Result(
      option.Option(String),
      FetchError,
    ),
  )
}

Constructors

  • Clients(
      fetch_hex_tarball: fn(String, String) -> Result(
        BitArray,
        FetchError,
      ),
      fetch_git_archive: fn(repository.Repository, String) -> Result(
        BitArray,
        FetchError,
      ),
      resolve_commit: fn(repository.Repository, String) -> Result(
        option.Option(String),
        FetchError,
      ),
      fetch_repo_archive: fn(repository.Repository, String) -> Result(
        BitArray,
        FetchError,
      ),
      fetch_spdx_index: fn(spdx.IndexKind) -> Result(
        List(String),
        FetchError,
      ),
      fetch_spdx: fn(spdx.Requirement) -> Result(
        option.Option(String),
        FetchError,
      ),
    )

    Arguments

    fetch_git_archive

    Fetch a git package’s source archive at its immutable manifest commit. Provider-agnostic: the repository.Repository contains the parsed provider (GitHub, GitLab, or Codeberg) so the correct archive endpoint is used. Never resolves tags or HEAD — the commit is fixed.

    resolve_commit

    Resolve a repository tag to an immutable commit SHA. Ok(Some(sha)) resolved, Ok(None) tag not found (try the next candidate), Error transient network/API failure (surface a warning and fall through).

    fetch_spdx

    Fetch canonical SPDX text for a requirement. Ok(Some(text)) resolved, Ok(None) unknown identifier, Error transient network failure.

pub type Error {
  UnknownPackages(packages: List(String))
  MissingLicenceText(packages: List(String))
  MetadataFailed(package: String, reason: String)
  UnsupportedSource(
    package: String,
    source: String,
    detail: String,
  )
  FetchFailed(package: String, reason: String)
  ArchiveFailed(package: String, reason: String)
  ChecksumMismatch(
    package: String,
    expected: String,
    actual: String,
  )
  PathReadFailed(package: String, path: String, reason: String)
  SpdxFetchFailed(package: String, id: String, reason: String)
  OutputWriteFailed(path: String, reason: String)
}

Constructors

  • UnknownPackages(packages: List(String))
  • MissingLicenceText(packages: List(String))
  • MetadataFailed(package: String, reason: String)
  • UnsupportedSource(
      package: String,
      source: String,
      detail: String,
    )
  • FetchFailed(package: String, reason: String)
  • ArchiveFailed(package: String, reason: String)
  • ChecksumMismatch(
      package: String,
      expected: String,
      actual: String,
    )
  • PathReadFailed(package: String, path: String, reason: String)
  • SpdxFetchFailed(package: String, id: String, reason: String)
  • OutputWriteFailed(path: String, reason: String)
pub type FetchError {
  FetchNetworkFailure
  FetchTimeout
  FetchTimeoutAfter(seconds: Int)
  FetchUnexpectedResponse(status: Int)
  FetchDownloadTooLarge(limit: Int)
}

Constructors

  • FetchNetworkFailure
  • FetchTimeout

    A request timed out at the 30s source-archive default. Kept as a nullary variant for source compatibility with existing callers/tests that construct or match on FetchTimeout directly.

  • FetchTimeoutAfter(seconds: Int)

    A request timed out at a duration other than the 30s source-archive default (e.g. the 10s metadata fetches used by the repository/SPDX fallback). Includes the timeout in seconds so describe_fetch_error reports the actual configured duration rather than assuming 30s.

  • FetchUnexpectedResponse(status: Int)
  • FetchDownloadTooLarge(limit: Int)
pub type NoticeEntry {
  NoticeEntry(package: NoticePackage, files: List(NoticeFile))
}

Constructors

pub type NoticeFile {
  NoticeFile(path: String, contents: String)
}

Constructors

  • NoticeFile(path: String, contents: String)
pub type NoticePackage {
  NoticePackage(
    name: String,
    version: String,
    declared_licences: List(String),
    repo_links: List(String),
    source: PackageSource,
    scope: manifest.Scope,
  )
}

Constructors

  • NoticePackage(
      name: String,
      version: String,
      declared_licences: List(String),
      repo_links: List(String),
      source: PackageSource,
      scope: manifest.Scope,
    )

    Arguments

    repo_links

    Candidate source-repository URLs (from Hex meta.links or a local gleam.toml), consulted by the repository fallback when the package’s own source archive ships no licence text.

pub type PackageSource {
  HexPackage(outer_checksum: String)
  GitPackage(
    repository: repository.Repository,
    url: String,
    commit: String,
    path: option.Option(String),
  )
  PathPackage(path: String)
}

Constructors

  • HexPackage(outer_checksum: String)
  • GitPackage(
      repository: repository.Repository,
      url: String,
      commit: String,
      path: option.Option(String),
    )

    A dependency fetched directly from a git host at an immutable manifest commit. repository is the normalized provider identity used to build the archive request; url is the original manifest-recorded source URL, preserved verbatim for rendering.

  • PathPackage(path: String)

Values

pub fn commit_response(
  repo: repository.Repository,
  status: Int,
  body: String,
) -> Result(option.Option(String), FetchError)

Pure mapping of a repository commit-resolution HTTP #(status, body) to an outcome, split out from the network call so status handling is testable without live traffic: 404 → tag not found, 2xx → decode the SHA (a missing field is also “not found”), any other status → transient failure.

pub fn decode_notice_files(
  encoded: String,
) -> Result(List(NoticeFile), Nil)

Parse notice files written by encode_notice_files. Returns Error(Nil) on any malformed or blank entry so old blank results become cache misses.

pub fn default_clients() -> Clients

The default clients, wired to the real Hex, provider, and SPDX endpoints.

pub fn describe_error(error: Error) -> String
pub fn describe_fetch_error(error: FetchError) -> String
pub fn encode_notice_files(files: List(NoticeFile)) -> String

Serialise notice files for the on-disk cache as a JSON array of {path, contents} objects.

pub fn fetch_json(
  request: request.Request(String),
) -> Result(#(Int, String), FetchError)

Dispatch a small JSON GET, returning #(status, body) or a transport error mapped onto FetchError.

pub fn fetch_tarball(
  request: request.Request(BitArray),
) -> Result(BitArray, FetchError)
pub fn fetch_verified_hex_tarball(
  name: String,
  version: String,
  expected_checksum: String,
  fetch_hex_tarball: fn(String, String) -> Result(
    BitArray,
    FetchError,
  ),
) -> Result(BitArray, Error)

Fetch a Hex package tarball and verify it against the lockfile checksum.

pub fn filter_entries(
  selected: List(manifest.SbomEntry),
  locked: List(manifest.SbomEntry),
  configuration: config.Notices,
) -> Result(List(manifest.SbomEntry), Error)
pub fn has_licence_file(files: List(NoticeFile)) -> Bool

Whether files already contain an actual licence-text file (LICENSE, LICENCE, or COPYING). A package whose source ships only a NOTICE file — or nothing, or blank licence files — returns False and must use the fallback.

pub fn has_text(contents: String) -> Bool

Check Unicode whitespace too: string.trim leaves spaces such as NBSP.

pub fn licence_files(
  files: List(source_archive.ArchiveFile),
) -> Result(List(NoticeFile), source_archive.ArchiveError)
pub fn licence_files_only(
  files: List(NoticeFile),
) -> List(NoticeFile)

Keep only the licence-text files from a list, dropping ancillary NOTICE files. Used to lift a licence out of a fallback repository archive without pulling in that repo’s own NOTICE.

pub fn package_source(
  entry: manifest.SbomEntry,
) -> Result(PackageSource, Error)
pub fn packages_from_entries(
  entries: List(manifest.SbomEntry),
  scopes: dict.Dict(String, manifest.Scope),
  metadata_for: fn(manifest.SbomEntry) -> #(
    Result(hex.PackageMetadata, Error),
    option.Option(String),
  ),
) -> #(Result(List(NoticePackage), Error), option.Option(String))
pub fn read_remote_source(
  package: NoticePackage,
  fetch_hex_tarball: fn(String, String) -> Result(
    BitArray,
    FetchError,
  ),
  fetch_git_archive: fn(repository.Repository, String) -> Result(
    BitArray,
    FetchError,
  ),
) -> Result(List(source_archive.ArchiveFile), Error)
pub fn read_source_notices(
  package: NoticePackage,
  clients: Clients,
) -> Result(List(NoticeFile), Error)

Read only the selected notice files, preserving selection against the full source inventory rather than inferring an archive root from a subset.

pub fn render(
  entries: List(NoticeEntry),
  manifest_path manifest_path: String,
) -> String
pub fn repo_licence_files(
  package_name: String,
  bytes: BitArray,
) -> Result(List(NoticeFile), Error)

Extract the licence-text files from a fallback repository’s gzip tar archive. Ancillary NOTICE files from the repository are dropped; only the actual licence text is lifted. Extraction failures are tagged to package_name.

pub fn selected_entries(
  manifest_value: manifest.SbomManifest,
  scopes: dict.Dict(String, manifest.Scope),
  include_dev include_dev: Bool,
) -> List(manifest.SbomEntry)
pub fn selected_notice_paths(
  paths: List(String),
) -> List(#(String, String))
pub fn spdx_file(
  requirement: spdx.Requirement,
  text: String,
) -> NoticeFile

Build the synthetic notice file for a resolved SPDX record, labelling its origin via a SPDX-License-List/<id>.txt path. The canonical text is stored verbatim.

pub fn spdx_response(
  requirement: spdx.Requirement,
  status: Int,
  body: String,
) -> Result(option.Option(String), FetchError)

Pure mapping of an SPDX detail-record HTTP #(status, body) to an outcome, split out from the network call so status handling is testable without live traffic: 404 → unknown identifier, 2xx → decode the canonical text (a missing field is also “unknown”), any other status → transient failure.

✨ Search Document