Project Copacetic

repository·main·Indexed 23 days ago

https://github.com/project-copacetic/copacetic

A CLI tool (copa) designed to directly patch container image vulnerabilities without full image rebuilds. It uses vulnerability scanner reports (such as Trivy) and buildkit to apply updates as new layers, reducing storage and transmission costs. The tool supports OS-level patching and experimental library patching for .NET, Node.js, and Python.

Tokens
33.4K
Snippets
75
Records
143
Agent score
81%

What's inside Copacetic

  1. Overview of Project Copacetic (copa)

    main

    Project Copacetic provides a CLI tool named copa that allows you to directly patch container image vulnerabilities without performing a full image rebuild.

    Key features include:

    • Direct Patching: Uses buildkit to apply updates as new layers, avoiding the need to wait for upstream base image updates or full rebuild pipelines.
    • Scanner Integration: Can ingest vulnerability scanning results from popular tools like Trivy to identify which packages need updating.
    • Extensible Engine: Uses adapters to parse different vulnerability report formats and support various package managers (e.g., apt, apk).
    • Low Overhead: Reduces storage and transmission costs by creating only an additional patch layer rather than a completely new image with different layer hashes.
  2. Available Copacetic patching demos

    main

    The demo directory contains several scripts demonstrating different patching workflows using demo-magic.

    ScriptDescription
    copa-demo.shOS-level patching of nginx:1.21.6
    copa-demo-dotnet.shOS + .NET library patching of Azure Relay Bridge
    copa-demo-nodejs.shOS + Node.js library patching of node:18-alpine
    copa-demo-python.shOS + Python library patching of python:3.11-alpine

    Note: Language-specific patching demos (dotnet, nodejs, python) require the COPA_EXPERIMENTAL=1 environment variable. This variable is automatically set within the individual scripts.

  3. Use Copa as a BuildKit frontend

    main

    Copa can be used as a BuildKit frontend to patch container images directly within BuildKit builds. This allows for containerized patching without installing the Copa CLI on build machines, provides direct access to vulnerability reports via build contexts, and integrates seamlessly with CI/CD tools like Docker Buildx and GitHub Actions.

    Prerequisites

    • BuildKit Instance: Access via buildctl, Docker Buildx (docker buildx build), or a local BuildKit daemon.
    • Copa Frontend Image: ghcr.io/project-copacetic/copacetic-frontend (use :latest or a specific version like :v0.13.0).
    • Vulnerability Scanner: Trivy or another supported scanner (e.g., Grype) to generate reports.
    • Container Runtime: Docker or Podman.
  4. How Copacetic uses BuildKit for patching

    main

    Copacetic functions as a pseudo-frontend to BuildKit. Instead of using a Dockerfile, it generates and executes LLB (Low-Level Builder) graphs to perform the following steps:

    1. Probing: It probes the target image as a filesystem bundle to retrieve package manager status (e.g., checking the dpkg status file).
    2. Tooling Injection: It fetches and deploys necessary tools (like package managers or busybox) into the target image. If the target image is minimal (like a distroless image), Copacetic uses a standard OS container to stage the tooling and process updates before copying them to the target.
    3. Patch Deployment: It uses BuildKit's diff and merge graph operations to stage the patches. This results in an image that contains the original image content plus a new layer containing only the deployed patches.
  5. How multi-platform patching strategies work

    main

    Copa handles multi-platform images (Docker manifest lists or OCI Indexes) using three distinct strategies depending on the flags provided:

    1. Report-Based (--report <dir>): Copa uses the reports in the directory to identify which platforms to patch. Platforms with reports are patched; platforms without reports are copied over as a passthrough (unchanged).
    2. Platform-Selective (--platform <list>): Only the specified platforms are patched. All other platforms in the original manifest are preserved unchanged.
    3. Comprehensive (Default): If neither flag is provided, Copa attempts to patch all available platforms in the manifest.

    Important Constraints:

    • --platform and --report are mutually exclusive.
    • --push and --oci-dir are mutually exclusive.
    • If --push is not used, patched images are saved locally, but preserved (unpatched) platforms will only exist in the registry.
    • Build attestations, signatures, and OCI referrers from the original image are not preserved.
  6. The architecture of the `copa patch` command

    main

    The copa patch command acts as an engine that bridges two extensible components: a ScanReportParser and a PackageManager. This allows Copacetic to support various vulnerability scanner formats and different methods for applying patches via different package managers.

    To extend Copacetic, implementations must satisfy these interfaces:

    • ScanReportParser: Responsible for taking a vulnerability report file and producing an UpdateManifest.
    • PackageManager: Responsible for taking the target image and the UpdateManifest to apply the patches.

    Core data structures used in this process include:

    • UpdatePackage: Represents a specific package name and version.
    • UpdateManifest: Contains metadata about the target environment (OSType, OSVersion, Arch) and the list of required Updates.
    type UpdatePackage struct {
        Name    string
        Version string
    }
    
    type UpdateManifest struct {
        OSType    string
        OSVersion string
        Arch      string
        Updates   []UpdatePackage
    }
    
    type ScanReportParser interface {
        Parse(reportPath string) (*UpdateManifest, error)
    }
    
    type PackageManager interface {
        Apply(imagePath string, report *UpdateManifest) error
    }
  7. Preventing layer buildup during patching

    main
    Copa prevents the accumulation of multiple patch layers by discarding the previous patch layer with each new patch operation. Instead of stacking layers, Copa creates a new layer that squashes all previous updates and the new updates into a single layer based on the original base image. This approach keeps the resulting patched image size optimized.
  8. How bulk patching versioning and skipping works

    main

    Versioned Tags

    When using bulk patching with --push, Copa creates version-suffixed tags to avoid overwriting immutable registry tags. Each re-patch is created from the original source image, not the previous patched image, to prevent layer buildup.

    Example sequence:

    • nginx:1.25.3 (Original)
    • nginx:1.25.3-patched (Initial patch)
    • nginx:1.25.3-patched-1 (First re-patch from original)
    • nginx:1.25.3-patched-2 (Second re-patch from original)

    Skipping Images

    Copa uses vulnerability reports to decide if re-patching is necessary. Reports are matched via the ArtifactName field in the JSON report.

    • If -r (report) is NOT provided: Copa always proceeds with patching.
    • If -r IS provided:
      • If the report shows no fixable vulnerabilities $\rightarrow$ Skip.
      • If the report shows fixable vulnerabilities $\rightarrow$ Re-patch with a version-bumped tag.
      • If no matching ArtifactName is found $\rightarrow$ Proceed (fail-open).

    Copa is scanner-agnostic; it works with any supported scanner (Trivy, native formats, or custom plugins) as long as you provide the reports.

  9. Scanner Plugin Interface (v1alpha1 and v1alpha2)

    main

    Scanner plugins must output a JSON object to standard output representing an UpdateManifest. There are two supported API versions:

    v1alpha1

    Designed for OS-level package updates only. It uses a single updates field.

    v1alpha2

    Supports application-level patching by separating updates into osupdates and langupdates. This version includes additional fields like type and class for packages, and an optional variant in the architecture configuration.

    Note: alpha versions are not guaranteed to be backwards compatible.

  10. How Copacetic patches container images

    main

    Unlike traditional rebasing (e.g., crane rebase), which switches out entire layers and can break image consistency or mask package updates, Copacetic patches the filesystem bundle as a whole.

    This approach ensures:

    • Consistency: The resulting image state is consistent because it treats the filesystem as a single unit rather than a collection of layers.
    • Broad Coverage: It can patch vulnerabilities introduced at any layer, including OS packages added in application layers.
    • Independence: It does not require coordination with base image publishers or knowledge of the image's exact lineage/transitive dependencies.

    Copacetic works by reframing the problem from "updating the base image" to "updating specific packages identified in a scan report."

  11. Compare `copa patch` vs `copa generate`

    main
    Featurecopa patchcopa generate
    OutputPatched image in registry/daemonBuild context tar stream
    Registry AccessRequired for pushNot required
    Use CaseDirect patchingPipeline integration
    FlexibilityLess flexibleHighly flexible
    PerformanceSingle operationCan be parallelized
    VEX OutputYes (with image digest)Yes (with image tag only)
    Docker Build FeaturesLimited (no buildx flags)Full (all docker build flags)