Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions docs/sbom-dependency-scope.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,8 +87,9 @@ When the same name and version is declared in more than one section, one mark is
| `mix.exs` `only:` an atom or a list that includes an environment other than `:dev` and `:test`, such as `only: [:dev, :prod]` | Stays section `dependencies`, or `optionalDependencies` when `optional: true`. Exported. | Same CycloneDX fields as that section. | Same SPDX relationship as that section. |
| `mix.exs` `git:`, `github:`, `path:`, or `in_umbrella:` | Not a Hex row. A `path:` value or `in_umbrella: true` that points at another Mix project in the same scan is a project reference relative to the scan root. `git:` and `github:` stay absent. | Absent. `mix.lock` is not expanded, so a package that appears only there is absent. | Absent. |
| .NET `<PackageReference>` in a `.csproj`, `.vbproj`, or `.sqlproj` | `PrivateAssets` whose trimmed value is `all`, in any letter case, on the attribute or the child element, is section `devDependencies`. Any other value, including `compile`, and a missing `PrivateAssets`, is section `dependencies`. The same package referenced again in that project without `PrivateAssets=all` stays section `dependencies`, and that production reference supplies the version. A `packages.config` entry is section `dependencies`. A `<PackageReference>` with no `Version` takes the version from the nearest `Directory.Packages.props` `<PackageVersion>` between the project directory and the scan root. Package ids match without regard to case. `VersionOverride` on the reference wins over that central version and over a `Version` on the same reference. A reference whose version cannot be resolved stays in the scan with version `unknown`. Exported. | `vibgrate:scope` = `direct`. Component `scope` = `excluded` on a development row. Omitted on a production row. `dependencies` omitted. The export list has no NuGet lockfile. | Annotation `scope=direct`. `DEV_DEPENDENCY_OF` from a development row to `SPDXRef-DOCUMENT`. A production row has no document relationship. |
| `pubspec.yaml` `dependencies` | Section `dependencies`. Exported. An SDK entry (`flutter: { sdk: flutter }`, a nested `sdk: flutter`, or `sdk: flutter` on the same line) is skipped. A name also listed under `dev_dependencies` is stored once, as this section, and this declaration supplies the spec. | `vibgrate:scope` = `direct`. Component `scope` omitted. `dependencies` omitted. The export list has no `pubspec.lock`. | Annotation `scope=direct`. No document relationship. |
| `pubspec.yaml` `dependencies` | Section `dependencies`. Exported. An SDK entry (`flutter: { sdk: flutter }`, a nested `sdk: flutter`, or `sdk: flutter` on the same line) is skipped. A name also listed under `dev_dependencies` is stored once, as this section. This declaration supplies the spec unless `dependency_overrides` replaces it. | `vibgrate:scope` = `direct`. Component `scope` omitted. `dependencies` omitted. The export list has no `pubspec.lock`. | Annotation `scope=direct`. No document relationship. |
| `pubspec.yaml` `dev_dependencies` | Section `devDependencies`. Exported. An SDK entry (`flutter_test: { sdk: flutter }`, a nested `sdk: flutter`, or `sdk: flutter` on the same line) is skipped, the same as an SDK entry under `dependencies`. A name also listed under `dependencies` is stored once, as `dependencies`. pub.dev lookups and drift age buckets use production rows only. | `vibgrate:scope` = `direct`. Component `scope` = `excluded`. Omitted when the kept row is production. `dependencies` omitted. | Annotation `scope=direct`. `DEV_DEPENDENCY_OF` from a development row to `SPDXRef-DOCUMENT`. A production row has no document relationship. |
| `pubspec.yaml` `dependency_overrides` | Same entry forms as `dependencies` (one-line version, `{ version: … }`, nested `version:`, `path:`, and `git:`). An SDK entry is skipped and does not replace a declared spec. A package also declared under `dependencies` or `dev_dependencies` keeps that section, and the override supplies the spec. A package listed only here is section `dependencies`. A `pubspec.lock` version still supplies `resolvedVersion`. | Same CycloneDX fields as the section the row lands in. | Same SPDX relationship as that section. |
| `packages.lock.json` | `Direct` and `Transitive` entries under `dependencies.<framework>.<id>`. `Project` entries are skipped. The version is `resolved`. The same package id and version under more than one target framework is one component. Package ids match without regard to case. The kept spelling is the code-unit minimum of the spellings in the file. | `direct` when a parsed manifest row has that name and version, otherwise `transitive`. `contentHash` is a SHA-512 digest on that component. `dependencies` follow each entry's `dependencies` map when the named package is resolved in this file. A `Direct` entry is a root dependency. | Annotation `scope=direct` or `scope=transitive`. `DEPENDS_ON` follows that map. Manifest `DEV_DEPENDENCY_OF` is still written from `PrivateAssets`. |

`--no-transitive` keeps the manifest rows (development, optional, and peer included) and omits lockfile-only rows. It omits CycloneDX `dependencies`. SPDX still writes `DEV_DEPENDENCY_OF` and `OPTIONAL_DEPENDENCY_OF` for those manifest rows, and it omits `DEPENDS_ON` because the lockfile graph is not read.
Expand Down Expand Up @@ -148,7 +149,7 @@ A Maven `pom.xml` exports `<scope>test</scope>` as `direct` with component `scop

A `mix.exs` dependency written `{:jason, "~> 1.4", optional: true}` is `direct` with component `scope` `optional` and SPDX `OPTIONAL_DEPENDENCY_OF`. `{:credo, "~> 1.7", only: [:dev, :test], runtime: false}` and `{:dialyxir, "~> 1.4", only: :dev, runtime: false}` are `direct` with component `scope` `excluded` and SPDX `DEV_DEPENDENCY_OF`. The same marks are written when the tuple is split across lines. A development `only:` wins when that tuple also sets `optional: true`. `only: [:dev, :prod]` stays a production row. `optional: false`, a missing `optional`, and `runtime: false` by itself omit component `scope`. A `git:`, `github:`, `path:`, or `in_umbrella:` dependency is absent from the export. A `path:` value or `in_umbrella: true` that points at another Mix project in the same scan is a project reference relative to the scan root and is not a Hex row, so it does not change drift age buckets. The export list has no `mix.lock`, so CycloneDX `dependencies` and SPDX `DEPENDS_ON` are omitted. Drift age buckets count production rows, including optional rows, and leave development rows out.

A `pubspec.yaml` that declares `http` under `dependencies` and `flutter_lints` under `dev_dependencies` exports both as `direct`. `flutter_lints` has component `scope` `excluded` and SPDX `DEV_DEPENDENCY_OF`. `http` omits component `scope`. `flutter: { sdk: flutter }` and `flutter_test: { sdk: flutter }` are absent. A name listed in both sections stays a production row, and the `dependencies` declaration supplies the spec. The export list has no `pubspec.lock`, so CycloneDX `dependencies` and SPDX `DEPENDS_ON` are omitted. Drift age buckets and pub.dev lookups use production rows and leave development rows out.
A `pubspec.yaml` that declares `http` under `dependencies` and `flutter_lints` under `dev_dependencies` exports both as `direct`. `flutter_lints` has component `scope` `excluded` and SPDX `DEV_DEPENDENCY_OF`. `http` omits component `scope`. `flutter: { sdk: flutter }` and `flutter_test: { sdk: flutter }` are absent. A name listed in both sections stays a production row, and the `dependencies` declaration supplies the spec unless `dependency_overrides` replaces it. A package listed only in `dependency_overrides` is a production row. An SDK override is absent and does not replace a declared spec. The export list has no `pubspec.lock`, so CycloneDX `dependencies` and SPDX `DEPENDS_ON` are omitted. Drift age buckets and pub.dev lookups use production rows and leave development rows out.

A `composer.json` that declares `monolog/monolog` under `require` and `phpunit/phpunit` under `require-dev` exports both as `direct`. `phpunit/phpunit` has component `scope` `excluded` and SPDX `DEV_DEPENDENCY_OF`. `monolog/monolog` omits component `scope`. A name listed in both tables stays a production row, and the `require` declaration supplies the spec. `php` and `ext-*` platform requirements are not components. CycloneDX `dependencies` and SPDX `DEPENDS_ON` are omitted, including when `composer.lock` is present. Packagist lookups and drift age buckets use production rows and leave development rows out. An unresolved development row is also left out of DriftScore.

Expand All @@ -171,5 +172,5 @@ A `Gemfile.lock` exports every gem under `GEM` `specs:`, plus a `PATH` or `GIT`
13. A `mix.exs` tuple with a keyword list of any length is a direct row, including a tuple written on more than one line. `only: :dev`, `only: :test`, and a list whose every environment is `:dev` or `:test` are section `devDependencies`. That wins over `optional: true`. `optional: true` otherwise is section `optionalDependencies`. `optional: false`, a missing `optional`, and `runtime: false` stay section `dependencies`. `only: [:dev, :prod]` stays production. A `git:`, `github:`, `path:`, or `in_umbrella:` dependency is absent as a Hex row. A `path:` value or `in_umbrella: true` that points at another Mix project in the same scan is a project reference relative to the scan root. `mix.lock` is not expanded, so a package that appears only there is absent. Drift age buckets and Hex lookups use production rows, including optional rows, and leave development rows out.
14. A .NET `<PackageReference>` whose `PrivateAssets` value is `all` (attribute or child element, trimmed, any letter case) is section `devDependencies`. Any other value, and a missing `PrivateAssets`, stays section `dependencies`. The same package referenced again in that project without `PrivateAssets=all` stays section `dependencies`, and the production reference supplies the version. `packages.config` entries stay section `dependencies`. A `<PackageReference>` with no `Version` takes the version from the nearest `Directory.Packages.props` `<PackageVersion>` between the project directory and the scan root. Package ids match without regard to case. The first `<PackageVersion>` for an id wins. `VersionOverride` wins over that central version and over an inline `Version`. A reference whose version cannot be resolved stays a row with version `unknown`. `packages.lock.json` is expanded: `Direct` and `Transitive` entries are components, and `Project` entries are skipped. The component version is `resolved`. `contentHash` is copied as a SHA-512 digest. The same package id and version under more than one target framework is one component, and package ids are matched without regard to case. The kept spelling is the code-unit minimum of the spellings in the file. A package that appears only in the lockfile is `transitive`. CycloneDX `dependencies` and SPDX `DEPENDS_ON` follow that entry's `dependencies` map when the named package is resolved in the same lockfile. A dependency version that does not match a resolved package is omitted. `Direct` entries are the root dependency list.
15. `Pipfile` `[dev-packages]` is section `devDependencies`. `[packages]` stays section `dependencies`. A name in both tables is stored once, as `dependencies`, and the `[packages]` declaration supplies the spec. A requirements file is section `devDependencies` when its base name has a `dev` or `test` segment split on `-`, `_`, or `.` (`requirements-dev.txt`, `requirements_dev.txt`, `requirements-test.txt`, `dev-requirements.txt`). `requirements.txt` and any other requirements file without that segment stay section `dependencies`. A name declared in one of those development files and in a production manifest row is stored once, as `dependencies`, and the production declaration supplies the spec. Which file is read first does not change that section. `Pipfile.lock` is expanded after `uv.lock`. `default` and `develop` entries that have a `version` are components. A leading `==` is removed before the purl is built (`==2.31.0` is `pkg:pypi/requests@2.31.0`). `hashes` values of the form `sha256:<hex>` are digests; any other value is omitted. An `editable` entry and a `path` entry are skipped, including when they also carry a `version`. A git entry with no `version` is skipped. A name that appears only in `develop` is a development row. When the manifest did not declare that version, `vibgrate:scope` stays `transitive`, CycloneDX component `scope` is `excluded`, and SPDX writes `DEV_DEPENDENCY_OF`. A name in both `default` and `develop` stays production, including when the two versions differ and including a PEP 503 spelling difference (`Some_Pkg` and `some-pkg`), so component `scope` is omitted. A name the manifest declared keeps that section: a `[packages]` row stays production even when the lockfile lists that version only under `develop`. The file records no edges, so CycloneDX `dependencies` and SPDX `DEPENDS_ON` are omitted. A truncated or invalid `Pipfile.lock` fails the export. `--no-transitive` omits these lockfile-only rows, including a develop-only package the manifest did not declare.
16. `pubspec.yaml` `dev_dependencies` is section `devDependencies`. `dependencies` stays section `dependencies`. A name in both sections is stored once, as `dependencies`, and the `dependencies` declaration supplies the spec. An SDK entry in either section (`name: { sdk: flutter }`, a nested `sdk:` key, or `sdk: flutter` on the same line) is absent. pub.dev lookups and drift age buckets use production rows and leave development rows out. `pubspec.lock` is not expanded, so CycloneDX `dependencies` and SPDX `DEPENDS_ON` are omitted. A development package declared in the manifest and missing from the lockfile is still a direct row.
16. `pubspec.yaml` `dev_dependencies` is section `devDependencies`. `dependencies` stays section `dependencies`. A name in both sections is stored once, as `dependencies`, and the `dependencies` declaration supplies the spec unless `dependency_overrides` replaces it. `dependency_overrides` is read in the same forms. The override supplies the spec and the row keeps the section of the declaration. A package listed only there is section `dependencies`. An SDK entry in any of the three sections (`name: { sdk: flutter }`, a nested `sdk:` key, or `sdk: flutter` on the same line) is absent, and an SDK override does not replace a declared spec. pub.dev lookups and drift age buckets use production rows and leave development rows out. `pubspec.lock` is not expanded, so CycloneDX `dependencies` and SPDX `DEPENDS_ON` are omitted. When `pubspec.lock` is present its version still supplies `resolvedVersion`. A development package declared in the manifest and missing from the lockfile is still a direct row.
17. `Gemfile.lock` dependency lines under a spec are not edges. A `PATH` or `GIT` gem with `remote: .` is omitted. A platform suffix is not part of the version. A gem that appears only in the lockfile is `transitive`, with purl `pkg:gem/<name>@<version>`. CycloneDX `dependencies` and SPDX `DEPENDS_ON` are omitted.
Loading
Loading