| name | endor-sca-findings |
| description | Use when tracing vulnerability and dependency lineage across Findings,
PackageVersions, and SBOM artifacts to verify resolved vs present state at
branch/commit scope—customer "is this fixed" asks, orphaned related-resource
errors, patched-vs-upstream coordinate confusion, or UI export vs API mismatches.
|
SCA findings provenance
Playbook for customer-facing dependency/finding investigations.
Inputs
- Tenant namespace (for example
endorlabs)
- Project identifier (UUID or repo URL)
- Vulnerability identifier(s) (CVE, GHSA)
- Branch/ref and commit SHA of interest
- Optional artifacts: CSV export, SBOM export
Separate scope / evidence / conclusion in customer writeups (portable-examples). If both API key and ENDOR_TOKEN exist, pass auth_method="browser-auth". Package-lineage semantics: endor-dependency-provenance.
Project-scoped namespace (required)
Do this before Flow B/C. Client(tenant=<estate_root>) with default
traverse=False lists only the estate root path — not child namespaces
where projects usually live. Filters like spec.project_uuid or
spec.importer_data.project_uuid do not substitute for the correct namespace;
you often get zero rows with no error.
- Discover the project (when namespace unknown):
Project.search_by_name(query, traverse=True, max_pages=…) and pick the intended row.
- Pin namespace for all project-scoped lists:
namespace=project.namespace on Finding, ScanResult, PackageVersion,
and DependencyMetadata.
- Do not rely on implicit client namespace for project RCA after step 1.
project_ns = project.namespace
client.Finding.list(namespace=project_ns, filter=..., traverse=False)
client.DependencyMetadata.list(
namespace=project_ns,
filter=F("spec.importer_data.project_uuid") == project.uuid,
traverse=False,
)
Use traverse=True on dependency lists only when deliberately searching
tenant-wide (costly). For single-project provenance, always pin
project.namespace.
OSS namespace (OSS-scoped facades vs tenant-scoped DependencyMetadata)
Some resources use the literal top-level namespace oss on the wire (facade
scope="oss"), parallel to customer tenants — for example Vulnerability
catalog queries. Do not derive <tenant>.oss or child paths under the
customer root for those facades.
DependencyMetadata list/get/group is tenant-scoped (customer namespace
segment, same as Project / PackageVersion). Use the project's
tenant_meta.namespace (or an explicit child namespace) for Flow C — not
literal oss. Row payloads may still set spec.dependency_data.namespace to
"oss" for catalog coordinates; that is field semantics, not the API path.
Verified pattern (matches endorlabs.workflows.estate.analyze.project_map.map and estate analytics
workflows). Requires project resolved first — see
Project-scoped namespace:
client.DependencyMetadata.list(
namespace=project.namespace,
traverse=False,
filter=F("spec.importer_data.project_uuid") == project.uuid,
)
Flow B — Finding Provenance
- Resolve
Project and set project_ns = project.namespace (see above).
- Query findings scoped to
namespace=project_ns.
- Filter by CVE/GHSA and dependency package match terms.
- Group by full
spec.target_dependency_package_name string (exact coordinate), not substring family.
- Record:
- finding UUID
spec.target_dependency_package_name
spec.target_uuid
spec.dependency_file_paths
spec.source_code_version.ref and .sha
Flow C — Dependency Provenance
- Same
project / project.namespace as Flow B.
- Pull
PackageVersion rows for project + branch/ref scope (namespace=project.namespace).
- Inspect
spec.resolved_dependencies when present:
- dependency graph nodes
- component names/versions
- Pull
DependencyMetadata on the project's tenant namespace (not literal
oss); match spec.importer_data.project_uuid and optional
package_version_ref/sha. See
OSS namespace vs DependencyMetadata.
- Validate referenced UUIDs from findings (
spec.target_uuid) and flag non-resolving resources.
- When function-level provenance/reachability is required, hand off to:
uv run endor-reachability-context --tenant <tenant> --namespace <namespace> --finding-uuid <finding_uuid> (default: workspace/projects/<finding-uuid>/reachability_context.json)
- Use generated
reachability_context.json for cross-plane (customer + oss) stitching evidence.
Flow D — Artifact Reconciliation
Compare API truth vs exported artifacts:
- Findings CSV
- missing commit SHA
- missing package/dependency UUIDs
- coordinate coverage gaps
- SBOM export
- determine format (CycloneDX vs SPDX)
- reconcile component purl/version with finding coordinate
- inspect pedigree/ancestor/patch metadata where available
Always separate:
- upstream coordinate (for example
...@9.4.18.v20190429)
- Endor-patched coordinate (for example
...@9.4.18.v20190429-endor-YYYY-MM-DD)
Flow E — Commit-Level Disposition
For the exact commit SHA:
- Confirm findings exist at SHA in general (sanity check).
- Re-run with vulnerability/dependency filters at same SHA.
- Conclude one of:
- present at SHA
- not present at SHA
- inconclusive (data gaps)
- Include confidence and why.
Output Template
Use this structure in investigation notes:
# Dependency/Finding Provenance Summary
- Tenant/project:
- Branch/commit scope:
- Vulnerability scope:
## High-confidence facts
- ...
## Data quality caveats
- ...
## Resolved vs present at commit
- Status:
- Evidence:
- Confidence:
## Open hypotheses
- ...
## Next verification steps
- ...
Common Pitfalls
- Implicit estate-root namespace on project-scoped lists (
traverse=False) —
silent empty results; always use namespace=project.namespace after resolving
the project (see Project-scoped namespace).
- Wrong namespace for
DependencyMetadata (using literal oss instead of
customer namespace) or for true OSS-scoped facades (see
OSS namespace vs DependencyMetadata).
- Counting grouped findings by substring instead of exact coordinate.
- Treating findings labels and BOM coordinates as the same without lineage evidence.
- Relying on CSV export alone for commit-level conclusions.
Related skills