SBOM Scope Property Registry v1

ID: CONTRACT-SBOM-SCOPE-PROPERTIES-V1 Status: Published Last Updated: 2026-06-21 Source of truth: src/Scanner/__Libraries/StellaOps.Scanner.Core/Contracts/DependencyScope.cs, src/Scanner/__Libraries/StellaOps.Scanner.Analyzers.Lang/Core/LanguageComponentMapper.cs, src/Scanner/__Libraries/StellaOps.Scanner.Emit/.../CycloneDxComposer.cs (MapScope).

Registers the stellaops.scope.* CycloneDX properties namespace that Stella analyzers emit on every language component, encoding the declared → deployed scope axis (the layer between “found/declared in an SBOM” and “deployed/reachable at runtime”). These properties are additive and back-compatible: an analyzer that does not resolve scope emits none of them, and consumers that do not understand them ignore them.

See also: Canonical SBOM Identifier v1, Scanner architecture §3.1 (component model), and the stella sbom checkreference (the primary consumer of these properties).

Why a property namespace (not just CycloneDX scope)

CycloneDX component.scope has only three values — required / optional / excluded — which is too coarse to carry the nine canonical Stella scopes and cannot distinguish “proven dev” from “no information.” Stella therefore emits both:

The mapping from canonical scope to CycloneDX scope (CycloneDxComposer.MapScope):

Canonical (stellaops.scope.effective)CycloneDX component.scope
runtime, bundled, providedrequired
optional, peeroptional
dev, test, buildexcluded
unknown (or absent)(no scope claim — the consumer’s fail-safe re-applies)

A proven non-deployed scope is never silently re-promoted to required; only a genuine unknown produces a null CycloneDX scope.

Registered properties

Property nameValue domainCardinalityMeaning
stellaops.scope.effectiveruntime | bundled | provided | optional | peer | build | test | dev | unknown0…1 per componentThe graph-wide effective scope: the most-deployed scope under which the component is reachable from any project root, after transitive propagation. This is the emitted/filtered value.
stellaops.scope.declaredsame domain as effective0…1 per componentThe declared scope of the direct edge from a project root, if the component is a direct dependency; absent for transitive-only components. Retained for auditability and to explain how the effective scope was computed.
stellaops.scope.deployedtrue | false0…1 per componentThe single gate bit: = effective.IsDeployed(). true for {runtime, bundled, provided, optional, peer, unknown}; false for {dev, test, build}. Downstream gates key off this bit so the partition is stable regardless of how many canonical scopes exist.
stellaops.scope.resolutionsee resolution-marker table0…1 per componentHow the scope was determined (graph quality / provenance). An honest precision marker — derived / partial-graph / *-no-graph / *-degraded mean the deployed bit is a prediction or fail-safe, not a lockfile-authoritative fact.

Deployed-set (the deployed=true cut)

deployed-set     = { runtime, bundled, provided, optional, peer, unknown }
non-deployed-set = { dev, test, build }

unknown is deployed-side by the fail-safe rule (R2): any edge/component that cannot be resolved defaults to a deployed-equivalent treatment so a vulnerability is never hidden on missing data. unknown never lowers a concrete deployed scope.

stellaops.scope.resolution markers

MarkerEmitted byMeaning
lockfile-authoritativenpm v2/v3, composer, pnpm, nuget, etc. with full graph + per-pkg flagsScope is read directly from authoritative lockfile data.
derivedyarn/pnpm/ruby/rust graph-derivationScope computed from the lockfile dependency graph (no per-node flag) — accurate but inferred.
lockfile-v1-degradednpm package-lock v1Degraded lockfile (no packages map); direct deps back-filled from package.json.
yarn-classic-derivedyarn classic (v1)Section scope derived from package.json + workspaces; entries with no root scope floor at unknown.
partial-graphany ecosystem with a severed edgeComponent reachable only through an unresolvable link: / workspace: / peer path; floored at unknown (deployed, fail-safe).
no-graph / requirements-no-graphpython requirements.txt, roots-only inputsNo usable transitive edge graph; scope is roots-only or unknown (deployed).

Determinism

These properties are deterministic: the canonical token is fixed per scope, stellaops.scope.deployed is a pure function of effective, and the accumulator/composer emit properties in stable ordinal order. A re-run on identical inputs is byte-identical.

Consumers