Sovra — Concepts & Methodology
The canonical reference for every term, score and formula the engine produces. If a number appears in a report, its meaning and its limits are defined here.
1 · The component model
Every scanned thing is a component with these fields:
| Field | Meaning |
|---|---|
ecosystem | npm (package-lock, pnpm-lock, bare package.json) · PyPI · Maven/Gradle (incl. Android) · Cargo (Rust) · NuGet (.NET) · Go · OCI (container images) · GitHub Actions · AI Model |
relation | direct (you chose it) · transitive (a dependency of a dependency) · declared (listed in a bare requirements.txt — the transitive tree is invisible) |
introduced_via | for transitive components: the direct dependencies through which it enters. The actionable fact — you fix transitive risk at the entry point. |
depth | distance from your project in the dependency graph (informational only — risk is never discounted by depth; xz-utils was deep) |
scope | runtime (ships in your product — the CRA's concern) · build (runs in your pipeline: Actions, base images, AI coding tools — a compromised one injects anything into what ships) |
2 · The jurisdiction vector
"Jurisdiction" is four different questions. The engine answers each separately:
| Dimension | Field | Question | Source |
|---|---|---|---|
| Legal control | jurisdiction | Whose law can compel the entity holding the project? | KB: curated org map, GLEIF legal-entity records, owner profile location |
| Distribution | distribution_jurisdiction | Whose law controls the registry the artifact transits? | Constant per ecosystem — npm (Microsoft), PyPI (PSF), Go proxy (Google) are all US. 100% coverage, zero inference. |
| Hosting | hosting | Where does the source of truth live? | Host domain (github.com → US; codeberg.org → DE e.V.) |
| OS packaging (C/C++ only) | distro_vendor_jurisdiction | Whose law reaches the vendor that builds/patches/signs the OS package a project actually links? | Curated per --reference-distro target (see DESIGN-CXX-DISTRO-REFERENCE.md) — the distro/ports vendor, not the library author. Only populated when a reference distro is set at scan time. |
| Maintainer geography | (feeds jurisdiction) | Where do the humans sit? | Owner profile locations, bucketed to country groups |
They routinely diverge — EU-authored code is still US-distributed. Sovereignty scoring uses legal control; distribution is reported alongside so the headline stays truthful.
Buckets: US · EU (the 27) · UK/adequacy (UK plus GDPR-adequacy jurisdictions: CH, NO, CA, JP, KR, IL, NZ…) · CN · Unknown.
Why legal control matters: CLOUD Act & FISA §702
Legal control isn't an abstract label — it determines who can be compelled. Two distinct US authorities, two distinct exposure classes, both already computed from signals above (no new scoring, just named citation):
| Authority | Reaches | Sovra's proxy |
|---|---|---|
| CLOUD Act (18 U.S.C. §2713) | Any US-controlled provider — extraterritorially, regardless of hosting | jurisdiction == "US" (the legal-control signal, this section) |
| FISA §702 (50 U.S.C. §1881a) | Specifically US "electronic communication service" / "remote computing service" providers — a narrower class | Declared AI-toolchain providers (§5) and their jurisdiction |
This is a risk lens, not a compliance obligation — there is no "CLOUD Act compliance" a vendor achieves, unlike CRA/NIS2/DORA/AI Act above. It's exported as its own ontology framework (USEXPOSURE, two provisions: USEXPOSURE-CLOUDACT served by the jurisdiction check, USEXPOSURE-FISA702 served by AI-toolchain provenance) via sovra export --framework usexposure or the UI's Regulatory mapping panel. Provider "covered" status, government process and privilege determinations require counsel — this surfaces the exposure signal, not a legal opinion.
Confidence on jurisdiction
Every legal-control value carries a confidence (0–1). It is inferred intelligence, never asserted fact:
| Signal | Weight | Note |
|---|---|---|
| Curated org map (Microsoft, Eclipse AISBL…) | 0.80–0.95 | legal seats, hand-maintained |
| GLEIF legal-entity record | 0.85 | open LEI database; conservative name matching |
| Owner profile location | 0.50–0.55 | free-text, bucketed; people move |
| Nothing | 0.20–0.25 | reported Unknown — never guessed |
Agreeing signals add +0.05 each (cap 0.95). Conflicting strong signals (e.g. US entity, EU maintainer base) produce disputed: true and confidence ×0.75 — a conflict is a *finding*, not something to average away.
Known limit: commit-timezone analysis is impossible via the GitHub API (dates are normalized to UTC); it would require cloning. Not implemented rather than implemented badly.
3 · Risk flags
| Flag | Trigger | Why it matters |
|---|---|---|
single | active maintainers ≤ 1 | one person is the supply chain — the xz-utils pattern (compromise or abandonment of one individual) |
stale | no maintainer activity ≥ 18 months | security fixes unlikely to arrive |
relicense | license family with restrictive-relicensing history (Elastic-2.0, BUSL, SSPL) | redistribution terms can change under you; CRA-relevant |
handoff | documented maintainer-handoff / compromise history (curated) | the tj-actions/changed-files compromise |
unpinned | GitHub Action not pinned to a 40-char commit SHA, or image tagged :latest | mutable refs are rewritable by an attacker — the tj-actions/changed-files compromise (March 2025) |
us-distribution | scan-level finding: ≥50% of runtime artifacts transit US-controlled registries | the registries are a choke point regardless of authorship. Flagged once at scan level (per-component flagging would be 100% noise); the mitigation is an EU-controlled pull-through mirror — a configuration change, not a code change |
centralized-distribution | component is distributed exclusively through a vendor-controlled mobile platform (Google/Apple/Huawei/Xiaomi/Samsung) | the vendor acts as a gatekeeper and can retroactively block app installation (e.g., Google's Sept 2026 Android developer verification); creates single-point-of-failure and lock-in risk |
Active maintainers — the approximate number of people actively maintaining the component, derived from committer distribution (DDS < 0.15 or a single committer ⇒ 1). This is the term used everywhere in the product and the reports; the machine-readable field is named bus_factor (kept for API stability). n/a means *no data*, which never silently becomes a flag.
4 · Scores (all 0–100, higher better)
Sovereignty — runtime components only. 100 − mean(jurisdiction penalty) with penalties EU 0 · UK/adequacy 12 · Unknown 40 · US 60 · CN 85.
Resilience — runtime components only. 100 − Σ flag penalties (single 8 · stale 5 · handoff 12 · unpinned 4).
Build hygiene — build components only. 100 − Σ build penalties (unpinned 10 · single 10 · stale 5 · handoff 25). 100 when there is no build chain.
Analysis confidence — how much to trust the three scores above. Weighted sum of four data signals:
| Signal | Weight | Meaning |
|---|---|---|
| Provenance coverage | 0.40 | share of components with KB/pipeline data |
| Mean jurisdiction confidence | 0.25 | average of §2 confidences |
| Maintainer-data availability | 0.20 | share with active-maintainer counts (bus_factor) |
| Tree visibility | 0.15 | share *not* from declared-only manifests |
Low confidence means the scores are floors/estimates, not verdicts — run sovra kb warm to raise coverage. An empty scan (0 components) has confidence 0 and an explicit warning — nothing-measured must never present as all-clear. Unpinned requirements appear with version ?: visible beats invisible.
Floor vs ceiling. The US share is reported as a range: the confirmed floor, and the ceiling if every Unknown resolved to US (us_share_ceiling_pct). Bounds instead of false precision.
5 · AI-generation provenance (declared tier)
LLM coding tools are build-chain suppliers: they shape the code and see the prompt context (your code goes *into* the model). The engine models a detected provider as a scope: build component of ecosystem AI Model, with the provider entity's legal seat as its jurisdiction (Anthropic/OpenAI/ Google = US, Mistral = EU…).
What jurisdiction does generated code itself have? Almost none — purely AI-generated output is most likely not copyrightable (human-authorship requirement, US and EU); ownership rests on the provider's contract, under the provider's governing law. Those are the facts the engine reports.
Detection tiers — only the first is implemented, by design:
| Tier | Evidence | Status |
|---|---|---|
| declared | agent config files (CLAUDE.md, AGENTS.md, GEMINI.md, .github/copilot-instructions.md, .cursorrules, .windsurfrules, .aider.conf.yml) · AI co-author commit trailers (last ≤200 local / 50 remote commits) | ✅ implemented |
| inferred | statistical style detection | ❌ not implemented — unreliable arms race; violates "reported, never guessed" |
| attested | CycloneDX ML-BOM / AI provenance attestations | future — coverage will arrive with AI-Act transparency obligations |
Declared evidence proves the *tool is used*, not which lines it wrote. ai_commit_pct = share of sampled commits carrying an AI co-author trailer.
6 · The knowledge base (KB)
Three tiers, consulted in order:
1. Curated seed (knowledge.py) — hand-verified entries, the foundation/ org/provider tables. Highest trust. 2. Pipeline cache (~/.cache/sovra/kb.json, filled by sovra kb warm or inline with sovra scan --warm / the UI's "build the KB during the scan" checkbox). The scanner follows every referenced package — direct and transitive alike (lockfiles enumerate the full tree) and fetches each one's license + jurisdiction provenance individually from deps.dev (licenses, source repo, Scorecard-"Maintained" as activity proxy), ecosyste.ms (owner kind/location, committers/DDS), GLEIF (legal entities). Every source optional; missing sources lower confidence, never fail. 3. Heuristic tier (Maven only): groupId reverse-domains carry a built-in jurisdiction signal (org.eclipse → Eclipse EU 0.85; de.* ccTLD → EU 0.45). Jurisdiction-only — deliberately NOT counted as provenance coverage; warming still fetches the full record. 4. Nothing → Unknown at 0.2–0.25 confidence. Counted against coverage.
Activity proxy: Scorecard "Maintained" score maps to last-activity months (≥8 → 0; ≥5 → 6; ≥3 → 12; else 20). A proxy, labeled as such.
7 · Outputs
- SBOM — CycloneDX 1.6 JSON:
bom-refs, a specdependenciesgraph,sovra:*properties carrying everything above (jurisdiction + confidence, relation, scope, distribution, hosting…), AI providers asmachine-learning-modelcomponents. SHA-256 integrity digest always; signed via two backends: Ed25519 local key (auto on every scan when thecryptographyextra is installed; key at ~/.config/sovra/, fingerprinted, 0600) and Sigstore/cosign (sovra sign --backend cosign— explicit, because keyless signing needs an OIDC identity; adds the public transparency log). Detached.sig.jsonsidecars over the canonical JSON bytes;sovra verifydetects any post-signing modification. - Board report (markdown) and executive deck (pptx) — same data, C-level framing, CRA/DORA context (reporting obligations 11 Sep 2026; full SBOM obligations 11 Dec 2027).
- Replacement plan — for each flagged component: blast radius (dependents, unique transitive subtree, fix point), curated alternatives/mitigations, coarse S/M/L effort with assumptions attached (no call-site analysis yet), and simulated score gains (re-scoring without the component + its unique subtree). Mitigations only clear the flags they actually fix — pinning clears
unpinned, notsingle. - Regulatory mapping — every check is linked to the legal clause it satisfies (CRA, NIS2, DORA, EU AI Act, OpenChain/ISO-5230, US CLOUD Act/FISA §702, and the data-jurisdiction/cross-border-transfer lens), filtered to your plan tier. Each clause is labelled with the strongest relation among its covering checks: performs — Sovra computes or produces the control itself (the SBOM is the CRA component inventory) — or evidences — Sovra supplies input toward a control the organisation still owns and runs (the board report evidences a risk assessment; it isn't one). A clause with neither is customer-owned — entirely out of Sovra's scope, shown so the map never overclaims coverage.
sovra complianceprints the map;sovra export --framework <name>renders the full pack for one framework.
8 · Continuous monitoring (snapshots, diff, gate)
Each scan snapshot is stored per repo-slug; diff compares the latest two and marks changes material when a new flag appears, a flagged component enters, a component disappears, or jurisdiction moves. The gate evaluates a JSON policy: static rules (min scores, forbidden flags/jurisdictions, US-distribution cap) plus the baseline rule (forbid_new_flags) that fails only on NEW risk — accepted debt stays accepted. Exit codes: 0 pass, 1 violations, 2 usage error.
9 · Multi-tenancy (v3.0)
Tenant API keys are generated once and stored only as SHA-256 hashes. Data boundaries: private per tenant — scans, snapshots, diffs, dashboards (history/tenants/<id>/); shared — the KB cache (public package intelligence only; no customer data ever enters it). An empty tenant registry means personal mode: no auth, the implicit default tenant. The platform dashboard (owner keys only) is anonymized by construction: distributions, prevalence and public package names — never tenant or repo identifiers.
10 · Privacy & honesty rules (design invariants)
- Jurisdiction about *people* is stored only as derived country buckets with confidence and source labels — no personal-data dossiers (GDPR legitimate-interest posture).
- Unknown is reported as Unknown. No signal → no score movement.
- Conflicts surface as
disputed, never silent averaging. - Every coarse estimate states its assumptions inline.
- Anything not implemented (inferred AI detection, commit-TZ analysis) is documented here as not implemented — the tool never claims capabilities it lacks.
11 · Glossary, acronyms & reference incidents
Every acronym Sovra uses, in plain language, with a link to the authoritative source. Knowing exactly what a term means — and being able to check it — is itself part of the confidence the tool is meant to give you.
Regulations & legal frameworks
| Acronym | Full name | What it requires (in one line) | Source |
|---|---|---|---|
| CRA | EU Cyber Resilience Act — Regulation (EU) 2024/2847 | A machine-readable SBOM (at least top-level dependencies), secure-by-design, and vulnerability reporting for any product with digital elements. Reporting obligations apply 11 Sep 2026; full obligations 11 Dec 2027. | EUR-Lex 2024/2847 · EC overview |
| NIS2 | Network & Information Security Directive 2 — Directive (EU) 2022/2555 | Baseline cybersecurity risk-management and incident-reporting duties across essential/important sectors, explicitly including supply-chain security. Unlike every other framework in this table, it's a Directive: it binds only through each Member State's own transposing law, which varies in entity thresholds, sector scope and sanctions. sovra compliance --country <cc> cites the curated national delta where one exists (ontology.NIS2_TRANSPOSITION) or an explicit not-yet-curated warning — never the Directive text presented as if it were the national law. | EUR-Lex 2022/2555 |
| DORA | Digital Operational Resilience Act — Regulation (EU) 2022/2554 | ICT risk management for EU financial entities; Article 28 requires a continuously maintained register of ICT third-party providers — the "what's in our stack, always" view. | EUR-Lex 2022/2554 |
| EU AI Act | Artificial Intelligence Act — Regulation (EU) 2024/1689 | Risk-based rules for AI systems. Relevant here because Annex IV technical documentation for high-risk systems must describe third-party software, pre-trained models/tools used (2(a)), software versions (1(c)) and component architecture (2(c)); Art 25 assigns value-chain responsibilities and Art 53 covers integrated general-purpose AI models. Sovra populates that component/AI-toolchain slice — not risk classification, data governance, human oversight or conformity assessment. Phased application: GPAI 2 Aug 2025, high-risk (Annex III) 2 Aug 2026, high-risk (Annex I) 2 Aug 2027. | EUR-Lex 2024/1689 · Annex IV |
| GDPR | General Data Protection Regulation — Regulation (EU) 2016/679 | EU personal-data law. Relevant here because maintainer geography touches personal data — Sovra stores only derived country buckets, never dossiers. | EUR-Lex 2016/679 |
| CLOUD Act | US Clarifying Lawful Overseas Use of Data Act (2018), codified at 18 U.S.C. §2713 | Lets US authorities compel US-controlled providers to produce data regardless of where it is hosted — why US legal control matters even for EU-hosted artifacts. Formalized as the USEXPOSURE-CLOUDACT provision (§2 below, exportable via sovra export --framework usexposure). | US DOJ |
| FISA §702 | US Foreign Intelligence Surveillance Act, Section 702 — 50 U.S.C. §1881a; last reauthorized by the Reforming Intelligence and Securing America Act (RISAA), 20 Apr 2024 | Compels US "electronic communication service" / "remote computing service" providers to assist with foreign-intelligence targeting — a narrower provider class than the CLOUD Act's general reach. Formalized as the USEXPOSURE-FISA702 provision, evidenced by declared AI-toolchain providers (§5). Sovra cannot determine whether a given provider is actually "covered" under a §702 certification — that needs counsel. | Cornell LII, 50 U.S.C. §1881a |
Standards, formats & data sources
| Term | What it is | Source |
|---|---|---|
| SBOM | Software Bill of Materials — a machine-readable inventory of every component in your software. | CISA |
| CycloneDX | The OWASP SBOM standard Sovra emits (v1.6). | cyclonedx.org |
| SPDX | An alternative ISO/IEC 5962 SBOM format (not yet emitted; on the roadmap). | spdx.dev |
| purl | Package URL — the pkg:npm/lodash@4.17.21 coordinate scheme used in the SBOM. | purl-spec |
| GLEIF / LEI | Global Legal Entity Identifier Foundation and its open Legal Entity Identifier database — used to resolve who legally controls a project. | gleif.org |
| OIDC / Sigstore | OpenID Connect — the identity protocol behind Sigstore/cosign keyless signing (a short-lived identity instead of a long-lived key). | Sigstore · OpenID Connect |
| Ed25519 | The fast elliptic-curve signature scheme used for Sovra's local-key SBOM signing. | ed25519.cr.yp.to |
| PEP 621 | The Python standard for project metadata in pyproject.toml ([project] dependencies). | peps.python.org/pep-0621 |
| Scorecard | OpenSSF Scorecard — its "Maintained" check is Sovra's activity proxy. | OpenSSF Scorecard |
| DDS | Development Distribution Score — from ecosyste.ms, the fraction of commits made by the top contributor; a high concentration (DDS < 0.15) signals an effective single maintainer. | ecosyste.ms |
Reference supply-chain incidents
These two real incidents are the patterns the resilience and build-hygiene scores are designed to catch. The flags reference them by name; here is the context.
The xz-utils backdoor — CVE-2024-3094
In March 2024 a backdoor was discovered in xz-utils (the liblzma compression library shipped on virtually every Linux distribution). It was not a coding bug: over roughly two years a contributor operating as "Jia Tan" earned the trust of the project, was granted commit and then release-manager rights, and shipped malicious code in versions 5.6.0 and 5.6.1 that targeted the sshd daemon for pre-authentication remote code execution. It was caught almost by accident by a Microsoft engineer (Andres Freund) investigating a ~500 ms SSH slowdown. This is the canonical case for three Sovra flags at once: a deep dependency, a single maintainer, and a maintainer handoff. Sources: Wikipedia · NVD CVE-2024-3094.
The tj-actions/changed-files compromise — CVE-2025-30066
In March 2025 the widely used GitHub Action tj-actions/changed-files was compromised. Attackers retroactively repointed many existing version tags (e.g. @v44, @v45) to a single malicious commit that dumped CI/CD secrets — access keys, tokens, private keys — into public workflow logs. Over 23,000 repositories referenced the action; anything using it between 12–15 March 2025 was at risk. It was patched in v46.0.1. This is exactly why Sovra raises the unpinned flag: a mutable tag is rewritable by whoever controls the upstream, so actions must be pinned to a full 40-character commit SHA. Sources: CISA alert · GitHub Advisory GHSA-mrrh-fwg8-r2c3.
12 · Open-source license compliance
A separate legal axis from sovereignty and security. Sovereignty asks *who controls this dependency*; license compliance asks *what does using and distributing this code obligate us to do, and do any obligations conflict*. The reference standard is OpenChain ISO/IEC 5230:2020 — a process standard for an organisation's OSS compliance programme. Sovra performs the technical steps (identify the OSS, resolve obligations, prepare notices) and evidences the programme; it cannot make an organisation "5230 conformant" — that is a programme attestation, not a tool output.
License identification
Each component's raw license string is normalised to a canonical SPDX id (or SPDX expression like MIT OR Apache-2.0). Aliases ("Apache 2.0") and deprecated ids (GPL-2.0 → GPL-2.0-only) are mapped; anything unresolved is reported as unknown with the original string kept — never silently dropped. For a dual OR license the choice is surfaced, defaulting to the most restrictive option until a choice is recorded (fail-safe, not fail-permissive).
Obligation class
Every license carries an obligation class and tags:
| Class | Examples | Core obligation |
|---|---|---|
| permissive | MIT, BSD, Apache-2.0 | Attribution / notice on distribution |
| weak-copyleft | MPL-2.0, LGPL, EPL | Disclose source of the (modified) library |
| strong-copyleft | GPL-2.0, GPL-3.0 | Offer complete corresponding source, same license |
| network-copyleft | AGPL-3.0, SSPL | Source obligation triggers on network use |
| source-available | BUSL, Elastic-2.0, SSPL | Field-of-use / commercial restrictions |
| public-domain | CC0, Unlicense, 0BSD | None |
Reach
An obligation only matters if it actually attaches to how you ship. Reach combines the class with the project's distribution mode and the component's scope:
- distributed-binary / -source / library — conveyed: full distribution + network triggers (the default; strictest common case).
- saas — not conveyed, so distribution triggers stay dormant (the GPL "SaaS loophole"), but network-copyleft (AGPL/SSPL) still triggers.
- internal — neither distribution nor network triggers.
- build scope — toolchain isn't shipped with the product, so its obligations have reach
n/a.
This is why a GPL build tool, or GPL under SaaS, costs nothing, while distributed strong-copyleft and network-exposed AGPL are weighted heavily. Static vs dynamic linking (which narrows some LGPL obligations) cannot be detected from a manifest — it is a property of the build/link step, so Sovra models at scope granularity and flags the limitation rather than guessing.
C/C++: declared direct deps + curated transitive
C/C++ has no central registry or lockfile, so a build manifest (ffmpeg-style configure, vcpkg, Conan) lists the libraries the project links directly, without versions and without each library's own dependencies. Sovra treats those as direct deps, fills their license/jurisdiction from a curated knowledge base (the verifiable signal is the license — e.g. x264/x265 are GPL), and expands a curated transitive map of well-established sub-dependencies (e.g. librsvg → cairo, gnutls → nettle, gmp). That transitive layer is best-effort "typically links" knowledge, not resolved from a lockfile — build flags can prune it — so it is presented like jurisdiction: curated intelligence, not a guaranteed resolved tree. Versions stay ?; the confidence score reflects the declared, registry-less nature of the ecosystem.
License-risk score & flags
The license score (0–100) is the mean reach penalty over runtime components, with a flat hit for any unresolved incompatibility. Flags: copyleft (live source-disclosure obligation), license-conflict (incompatible with another component — a distribution blocker), license-unknown (unresolved license). Conflicts use a curated set of well-established incompatible pairs (e.g. GPL-2.0-only with Apache-2.0) and are only raised among components whose obligations are actually live under the chosen mode. The OpenChain export pack (sovra export --framework openchain) renders the BOM, the obligation register, the conflict report and a generated NOTICE file; copyright lines absent from the knowledge base are marked [VERIFY], never fabricated.