--- title: "Understand job and cache SBOM completeness" description: "Know when job dependencies, including packages restored from GitHub Actions caches, are fully represented in CRACI" source: "https://docs.craci.com/guides/cache-sbom-completeness/" --- Use CRACI SBOM completeness to decide whether a job's dependency view accounts for every package that could have entered the build. CRACI evaluates the job's own package evidence and the evidence attached to every GitHub Actions cache it restores. CRACI carries known dependencies forward when a later job restores a cache. This keeps the later job's dependency view accurate even when a package comes from the cache instead of being downloaded again. If a cache SBOM is incomplete, packages missing from that cache may also be missing from the restoring job's SBOM. ## When a job SBOM is complete A job has a complete CRACI SBOM only when: - CRACI observed complete dependency evidence for the job itself; - the job did not allow unmatched, unmonitored traffic; and - every cache restored by the job has a complete CRACI SBOM. These requirements make completeness transitive. If a job restores an incomplete cache, its SBOM is incomplete too. If that job produces another cache, the new cache carries the incomplete status forward. CRACI displays one of these results: | Result | Meaning | Complete | | ----------------------------- | --------------------------------------------------------------------------------- | -------- | | **Complete** | CRACI observed complete job evidence, and every restored cache was complete. | Yes | | **Complete with connections** | The requirements passed, but the job used one or more custom network connections. | Yes | | **Incomplete** | CRACI identified a condition that could leave dependencies out of the SBOM. | No | | **Unavailable** | CRACI could not finish evaluating the evidence. | No | | **Not recorded** | The job predates completeness reporting. | No | :::caution[Custom connections can carry unobserved packages] CRACI considers **Complete with connections** a complete SBOM result. However, traffic allowed through `network.connections` bypasses CRACI's package-aware proxy and is not monitored for package downloads. You are responsible for ensuring that custom connections do not supply packages or other build dependencies. If a destination is a package registry, configure it as a supported built-in preset or custom `source` instead of a connection so CRACI can observe its packages. ::: ## When a cache SBOM is complete A cache has a complete CRACI SBOM only when all of these conditions are true: - **One cache per producing job** When a job creates multiple caches, CRACI cannot reliably determine which cache contains each observed package. - **Complete producing-job evidence** The producing job must have a complete SBOM, including complete evidence from caches that it restored. CRACI follows the producing job's known dependencies, including dependencies from caches that job restored. It does not inspect package manifests inside the cache archive. A legacy cache created before this information was recorded therefore has unavailable evidence, even if its producing job used monitored traffic. ## Best practices - **Derive cache keys from dependency lockfiles.** Include a lockfile hash, such as `${{ hashFiles('package-lock.json') }}`, in the cache key. A dependency change then produces a new cache instead of restoring stale packages selected by an older lockfile. - **Use custom connections only when you understand the trust boundary.** CRACI does not monitor connections for package downloads. Prefer a built-in preset or custom `source` for package registries. If you need a connection, restrict its destinations and ports, and verify that it cannot supply packages or build tools. ## Produce a cache with complete dependency information Create a runner template under **Settings → Runner templates** and select **Monitored** for its network policy. Select that template in each job that produces a cache: ```yaml - uses: cracicorp/setup@v1 with: template: monitored-build ``` Alternatively, configure the job's network policy directly. Set `default: deny` to block traffic that matches no preset, source, or connection: ```yaml - uses: cracicorp/setup@v1 with: network: | default: deny ``` In both cases, have the producing job create only one cache. See [Control network access from jobs](./setup-action-network/) for package sources, custom connections, and network policy examples.