# Build artifacts tagged with commit SHA, git tag, or semantic version; Docker images use SHA not latest

- **Pattern:** `ab-000973` (`deployment-readiness.ci-cd-pipeline.artifact-versioning`)
- **Severity:** high
- **Lifecycle:** active
- **Last modified:** 2026-04-18
- **Canonical URL:** https://auditbuffet.com/patterns/ab-000973
- **License:** CC-BY-4.0 — attribute to AuditBuffet Pattern Catalog (https://auditbuffet.com/patterns/ab-000973)

## Why it matters

Docker images tagged exclusively as `latest` make it impossible to pinpoint which code version is running in production, roll back to a known-good build, or audit what changed between deployments. SLSA Build-L2 requires traceable artifact provenance; SSDF DS.1 requires unique build identifiers. Without SHA or semantic version tagging, a failed deployment becomes a debugging exercise because `latest` is overwritten with each push — the previous good build is gone.

## Severity rationale

High because mutable `latest` tags eliminate the ability to pin or roll back to a specific artifact, making incident recovery slower and deployment audits impossible.

## Remediation

Tag Docker images with the commit SHA or semantic version in your CI/CD workflow. Never push `latest` as the only tag.

```yaml
# .github/workflows/deploy.yml
- name: Build and push image
  run: |
    COMMIT_SHA=${{ github.sha }}
    docker build -t myregistry/myapp:${COMMIT_SHA:0:7} .
    docker push myregistry/myapp:${COMMIT_SHA:0:7}
```

For semver-based projects:

```yaml
- run: |
    VERSION=$(npm pkg get version | tr -d '"')
    docker build -t myregistry/myapp:${VERSION} .
    docker push myregistry/myapp:${VERSION}
```

Update your deployment manifests or Helm values to reference the specific tag, not `latest`. Store the mapping of version → commit in release notes or GitHub Releases.

## Detection

- **ID:** `artifact-versioning`
- **Severity:** `high`
- **What to look for:** Enumerate every relevant item. Check CI/CD pipeline configuration for artifact versioning strategy. For Docker images, look for Dockerfile and CI/CD workflow to see if images are tagged with SHA, semantic version, or tag rather than `latest`. Check for package.json version field and whether builds use version numbers.
- **Pass criteria:** At least 1 of the following conditions is met. Build artifacts (Docker images, compiled packages, deployables) are tagged with commit SHA, git tag, or semantic version. Docker images are not tagged with `latest` as the primary tag.
- **Fail criteria:** Build artifacts use `latest` tag exclusively (in Docker), or no versioning scheme is evident in the build process.
- **Do NOT pass when:** The item exists only as a placeholder, stub, or TODO comment — partial implementation does not count as passing.
- **Skip (N/A) when:** The project does not build artifacts or uses a platform that handles versioning automatically (e.g., Vercel auto-generates deployment IDs).
- **Cross-reference:** For broader data handling practices, the Data Protection audit covers data lifecycle management.
- **Detail on fail:** `"Docker images in Dockerfile are tagged only as 'latest'. No commit SHA or semantic version in build process."` or `"Build artifacts have no version identifier; CI/CD workflow does not tag deployments."`
- **Remediation:** Add versioning to your build process. For Docker in GitHub Actions:

  ```yaml
  - name: Build and push Docker image
    run: |
      COMMIT_SHA=${{ github.sha }}
      docker build -t myregistry/myapp:${COMMIT_SHA:0:7} .
      docker push myregistry/myapp:${COMMIT_SHA:0:7}
  ```

  Or use semantic versioning:

  ```yaml
  - run: npm version patch  # or minor, major
  - run: docker build -t myregistry/myapp:$(npm pkg get version | tr -d '"') .
  ```

## External references

- iso-25010 reliability.maturity
- slsa Build-L2
- ssdf DS.1

Taxons: operational-readiness

HTML version: https://auditbuffet.com/patterns/ab-000973
