# Dependency Source Integrity Rules
# Category: dependency-source
# Evaluates package manager data for non-registry, local, or mutable sources
- id: PKG-001
  name: "Install script from direct manifest source"
  description: "npm packages with install scripts declared from git, URL, or local path sources in the manifest increase supply chain attack surface"
  severity: high
  category: dependency-source
  dry-run-support: full
  condition: |
    components[
      $prop($, 'cdx:npm:hasInstallScript') = 'true'
      and $hasProp($, 'cdx:npm:manifestSourceType')
    ]
  location: |
    { "bomRef": $."bom-ref", "purl": purl }
  message: "npm package '{{ name }}@{{ version }}' executes install script from manifest-declared source type(s): {{ $prop($, 'cdx:npm:manifestSourceType') }}"
  mitigation: "Avoid git, URL, or local-path dependencies with lifecycle hooks; use registry-published dependencies or vendor explicitly"
  evidence: |
    {
      "manifestSourceType": $prop($, 'cdx:npm:manifestSourceType'),
      "manifestSource": $prop($, 'cdx:npm:manifestSource'),
      "riskyScripts": $prop($, 'cdx:npm:risky_scripts'),
      "resolvedPath": $prop($, 'cdx:npm:resolvedPath'),
      "isLink": $prop($, 'cdx:npm:isLink')
    }
- id: PKG-002
  name: "Go module uses local replacement"
  description: "Go modules with local_dir replacements are non-hermetic and may not be reproducible"
  severity: high
  category: dependency-source
  dry-run-support: full
  condition: |
    components[
      $hasProp($, 'cdx:go:local_dir')
    ]
  location: |
    { "bomRef": $."bom-ref", "purl": purl }
  message: "Go module '{{ name }}' uses local replacement: {{ $prop($, 'cdx:go:local_dir') }}"
  mitigation: "Use published module versions or vendor dependencies explicitly for reproducible builds"
  evidence: |
    {
      "localDir": $prop($, 'cdx:go:local_dir'),
      "toolchain": $prop($, 'cdx:go:toolchain')
    }
- id: PKG-003
  name: "Swift local checkout in build"
  description: "Swift packages with localCheckoutPath indicate developer-only dependencies not suitable for release"
  severity: high
  category: dependency-source
  dry-run-support: full
  condition: |
    components[
      $hasProp($, 'cdx:swift:localCheckoutPath')
    ]
  location: |
    { "bomRef": $."bom-ref", "purl": purl }
  message: "Swift package '{{ name }}' uses local checkout: {{ $prop($, 'cdx:swift:localCheckoutPath') }}"
  mitigation: "Use remote package references (URL or registry) for release artifacts"
  evidence: |
    {
      "checkoutPath": $prop($, 'cdx:swift:localCheckoutPath'),
      "packageName": $prop($, 'cdx:swift:packageName')
    }
- id: PKG-004
  name: "Nix flake missing reproducibility metadata"
  description: "Nix dependencies without revision or nar_hash cannot be verified for content integrity"
  severity: high
  category: dependency-source
  dry-run-support: full
  condition: |
    components[
      $startsWith(purl, 'pkg:nix/')
      and (
        $prop($, 'cdx:nix:revision') = null
        or $prop($, 'cdx:nix:nar_hash') = null
      )
    ]
  location: |
    { "bomRef": $."bom-ref", "purl": purl }
  message: "Nix package '{{ name }}' missing reproducibility metadata (revision or nar_hash)"
  mitigation: "Ensure flake.lock includes both revision and nar_hash for content-addressed reproducibility"
  evidence: |
    {
      "inputUrl": $prop($, 'cdx:nix:input_url'),
      "ref": $prop($, 'cdx:nix:ref'),
      "hasRevision": $hasProp($, 'cdx:nix:revision'),
      "hasNarHash": $hasProp($, 'cdx:nix:nar_hash')
    }
- id: PKG-005
  name: "Ruby gem tracks mutable branch"
  description: "Ruby gems sourced from git branches (without revision pin) can change unexpectedly"
  severity: medium
  category: dependency-source
  dry-run-support: full
  condition: |
    components[
      $hasProp($, 'cdx:gem:remoteBranch')
      and $hasProp($, 'cdx:gem:remoteRevision')
    ]
  location: |
    { "bomRef": $."bom-ref", "purl": purl }
  message: "Ruby gem '{{ name }}' tracks mutable branch '{{ $prop($, 'cdx:gem:remoteBranch') }}' without commit pin"
  mitigation: "Pin to specific revision: gem 'foo', git: '...', ref: '<commit-sha>'"
  evidence: |
    {
      "remote": $prop($, 'cdx:gem:remote'),
      "branch": $prop($, 'cdx:gem:remoteBranch'),
      "tag": $prop($, 'cdx:gem:remoteTag')
    }
- id: PKG-006
  name: "Python dependency from non-approved registry"
  description: "PyPI packages from unapproved registries may introduce unvetted code"
  severity: low
  category: dependency-source
  dry-run-support: full
  condition: |
    components[
      $hasProp($, 'cdx:pypi:registry')
      and $prop($, 'cdx:pypi:registry') != 'https://pypi.org/simple'
      and $prop($, 'cdx:pypi:registry') != 'https://pypi.org'
    ]
  location: |
    { "bomRef": $."bom-ref", "purl": purl }
  message: "Python package '{{ name }}' sourced from non-default registry: {{ $prop($, 'cdx:pypi:registry') }}"
  mitigation: "Verify registry trustworthiness"
  evidence: |
    {
      "registry": $prop($, 'cdx:pypi:registry'),
      "resolvedFrom": $prop($, 'cdx:pypi:resolved_from')
    }
- id: PKG-007
  name: "Cargo dependency from mutable git source"
  description: "Cargo git dependencies without revision or tag pinning can change unexpectedly and reduce build reproducibility"
  severity: high
  category: dependency-source
  dry-run-support: full
  condition: |
    components[
      $hasProp($, 'cdx:cargo:git')
      and $prop($, 'cdx:cargo:gitRev') = null
      and $prop($, 'cdx:cargo:gitTag') = null
    ]
  location: |
    { "bomRef": $."bom-ref", "purl": purl }
  message: "Cargo dependency '{{ name }}@{{ version }}' tracks git source '{{ $prop($, 'cdx:cargo:git') }}' without an immutable revision pin"
  mitigation: "Prefer crates.io releases or pin git dependencies with `rev = \"<commit-sha>\"` or a signed, reviewed tag"
  evidence: |
    {
      "git": $prop($, 'cdx:cargo:git'),
      "branch": $prop($, 'cdx:cargo:gitBranch'),
      "tag": $prop($, 'cdx:cargo:gitTag'),
      "dependencyKind": $prop($, 'cdx:cargo:dependencyKind')
    }
- id: PKG-008
  name: "Cargo dependency from local path"
  description: "Cargo path dependencies are local source references that reduce release reproducibility and may bypass registry review controls"
  severity: high
  category: dependency-source
  dry-run-support: full
  condition: |
    components[
      $hasProp($, 'cdx:cargo:path')
    ]
  location: |
    { "bomRef": $."bom-ref", "purl": purl }
  message: "Cargo dependency '{{ name }}@{{ version }}' uses local path source '{{ $prop($, 'cdx:cargo:path') }}'"
  mitigation: "Use published crate versions for release builds or vendor the dependency explicitly with clear provenance review"
  evidence: |
    {
      "path": $prop($, 'cdx:cargo:path'),
      "dependencyKind": $prop($, 'cdx:cargo:dependencyKind'),
      "target": $prop($, 'cdx:cargo:target')
    }
- id: PKG-009
  name: "Collider package resolved from insecure HTTP origin"
  description: "Collider lock entries that resolve from HTTP origins can be observed or modified in transit before wrap-hash verification occurs"
  severity: medium
  category: dependency-source
  dry-run-support: full
  condition: |
    components[
      $prop($, 'cdx:collider:originScheme') = 'http'
    ]
  location: |
    { "bomRef": $."bom-ref", "purl": purl }
  message: "Collider package '{{ name }}@{{ version }}' resolves from insecure origin '{{ $prop($, 'cdx:collider:origin') }}'"
  mitigation: "Prefer HTTPS, trusted file:// repositories, or an authenticated internal mirror for Collider package origins"
  evidence: |
    {
      "origin": $prop($, 'cdx:collider:origin'),
      "originHost": $prop($, 'cdx:collider:originHost'),
      "dependencyKind": $prop($, 'cdx:collider:dependencyKind')
    }
- id: PKG-010
  name: "Collider origin required sanitization before BOM emission"
  description: "Collider lock origin URLs should not carry credentials, query strings, or fragments because those values may embed secrets or unstable signed URLs"
  severity: low
  category: dependency-source
  dry-run-support: full
  condition: |
    components[
      $prop($, 'cdx:collider:originSanitized') = 'true'
    ]
  location: |
    { "bomRef": $."bom-ref", "purl": purl }
  message: "Collider package '{{ name }}@{{ version }}' had sensitive origin fields stripped before BOM emission"
  mitigation: "Avoid embedding credentials or signed query parameters in Collider repository origin URLs; prefer stable repository base URLs"
  evidence: |
    {
      "origin": $prop($, 'cdx:collider:origin'),
      "originHost": $prop($, 'cdx:collider:originHost'),
      "dependencyKind": $prop($, 'cdx:collider:dependencyKind')
    }
- id: PKG-011
  name: "Python dependency uses direct manifest source"
  description: "Python dependencies declared via git, direct URL, or local path in requirements or pyproject files bypass normal registry version mediation"
  severity: high
  category: dependency-source
  dry-run-support: full
  condition: |
    components[
      $hasProp($, 'cdx:pypi:manifestSourceType')
    ]
  location: |
    { "bomRef": $."bom-ref", "purl": purl }
  message: "Python package '{{ name }}@{{ version }}' is declared from manifest {{ $prop($, 'cdx:pypi:manifestSourceType') }} source '{{ $prop($, 'cdx:pypi:manifestSource') }}'"
  mitigation: "Prefer registry-published releases for production builds, or pin and review direct git/URL/path sources explicitly"
  evidence: |
    {
      "manifestSourceType": $prop($, 'cdx:pypi:manifestSourceType'),
      "manifestSource": $prop($, 'cdx:pypi:manifestSource'),
      "registry": $prop($, 'cdx:pypi:registry'),
      "resolvedFrom": $prop($, 'cdx:pypi:resolved_from')
    }
