# Container images and the supply chain

Trace which contents were released by which builder and tests instead of trusting a label. Assess image, registry and runtime separately.

Original AI-assisted SecNet educational content. Fictional local examples; not a standards provider publication, endorsement or compliance evidence. Page exercises do not create account progress.

Sources checked: 2026-10-21

## Tag, digest and origin

A release or latest tag can change; a digest identifies specific bytes. A digest alone does not guarantee harmless content. Trusted registry, expected signer and verified build provenance are separate questions. registry.example is fictional here; nothing is downloaded or pushed. Bind identity, build origin and approved use to the same image digest.

## Scope of a scan result

An image scan relies on package/version inventory; it does not fully cover business logic or runtime authority. Review OS and application dependencies together. Record scanner/database date, digest and suppressed findings. An expired exception must not inherit automatic acceptance from an old green result. A skipped scan returning nothing differs from a completed scan finding nothing; preserve that distinction in pipeline evidence.

## Reducing and running the image

Removing unnecessary tools and packages can reduce exposure; provide debugging and response through a separate controlled workflow. Test non-root file permissions, required writable areas under a read-only root and health behavior. A distroless or small-image label is not approval. A small image running with host privileges still presents risk: image and Pod policy are separate layers.

## Worked example: the rebuilt package

After digest A is tested and signed, the pipeline rebuilds digest B from the same source. Prior tests apply to A; do not assume identical evidence for B. testsOnDigest=false exposes that distinction in the model. The local JSON inspector checks digest-reference syntax only, not registry access, signatures or vulnerabilities. Add those external evidence records and owners to the actual release record. Do not silently close findings without an exception rationale, affected service, expiry and remediation plan.

## Working sequence

1. Pin image digest and registry origin.
2. Record scan scope and database date.
3. Verify signer and build provenance.
4. Test non-root and read-only runtime behavior.
5. Decide release using evidence for the same digest.

## 1. From label to contents

A release label does not identify verified contents. Require digest match, allowed registry and signature-verification evidence together; the model does not produce those proofs.

This code is a local policy model; it does not replace target/cluster testing.

### Weak implementation
```js
s=>s.tag==='release'
```

### Corrected implementation
```js
s=>s.digestMatched&&s.registryAllowed&&s.signatureVerified
```

### Synthetic input and actual model output
```json
{
  "before": [
    {
      "name": "verified-content",
      "input": {
        "tag": "release",
        "digestMatched": true,
        "registryAllowed": true,
        "signatureVerified": true
      },
      "expected": true,
      "observed": true,
      "matched": true
    },
    {
      "name": "mutable-label",
      "input": {
        "tag": "release",
        "digestMatched": false,
        "registryAllowed": true,
        "signatureVerified": false
      },
      "expected": false,
      "observed": true,
      "matched": false
    },
    {
      "name": "wrong-registry",
      "input": {
        "tag": "release",
        "digestMatched": true,
        "registryAllowed": false,
        "signatureVerified": true
      },
      "expected": false,
      "observed": true,
      "matched": false
    }
  ],
  "after": [
    {
      "name": "verified-content",
      "input": {
        "tag": "release",
        "digestMatched": true,
        "registryAllowed": true,
        "signatureVerified": true
      },
      "expected": true,
      "observed": true,
      "matched": true
    },
    {
      "name": "mutable-label",
      "input": {
        "tag": "release",
        "digestMatched": false,
        "registryAllowed": true,
        "signatureVerified": false
      },
      "expected": false,
      "observed": false,
      "matched": true
    },
    {
      "name": "wrong-registry",
      "input": {
        "tag": "release",
        "digestMatched": true,
        "registryAllowed": false,
        "signatureVerified": true
      },
      "expected": false,
      "observed": false,
      "matched": true
    }
  ]
}
```

## 2. A stale scan result

A green scan cannot approve another digest or an expired exception. A direct-package list is insufficient when transitive review is missing.

This code is a local policy model; it does not replace target/cluster testing.

### Weak implementation
```js
s=>s.scanGreen
```

### Corrected implementation
```js
s=>s.scanGreen&&s.digestMatched&&s.transitiveReviewed&&s.exceptionCurrent
```

### Synthetic input and actual model output
```json
{
  "before": [
    {
      "name": "same-artifact",
      "input": {
        "scanGreen": true,
        "digestMatched": true,
        "transitiveReviewed": true,
        "exceptionCurrent": true
      },
      "expected": true,
      "observed": true,
      "matched": true
    },
    {
      "name": "stale-scan",
      "input": {
        "scanGreen": true,
        "digestMatched": false,
        "transitiveReviewed": true,
        "exceptionCurrent": true
      },
      "expected": false,
      "observed": true,
      "matched": false
    },
    {
      "name": "expired-exception",
      "input": {
        "scanGreen": true,
        "digestMatched": true,
        "transitiveReviewed": true,
        "exceptionCurrent": false
      },
      "expected": false,
      "observed": true,
      "matched": false
    }
  ],
  "after": [
    {
      "name": "same-artifact",
      "input": {
        "scanGreen": true,
        "digestMatched": true,
        "transitiveReviewed": true,
        "exceptionCurrent": true
      },
      "expected": true,
      "observed": true,
      "matched": true
    },
    {
      "name": "stale-scan",
      "input": {
        "scanGreen": true,
        "digestMatched": false,
        "transitiveReviewed": true,
        "exceptionCurrent": true
      },
      "expected": false,
      "observed": false,
      "matched": true
    },
    {
      "name": "expired-exception",
      "input": {
        "scanGreen": true,
        "digestMatched": true,
        "transitiveReviewed": true,
        "exceptionCurrent": false
      },
      "expected": false,
      "observed": false,
      "matched": true
    }
  ]
}
```

## 3. Who signed it?

Being signed is not the same as originating from the expected builder. Require allowed signer, verified provenance and same-digest tests; no actual signature is verified here.

This code is a local policy model; it does not replace target/cluster testing.

### Weak implementation
```js
s=>s.signed
```

### Corrected implementation
```js
s=>s.signed&&s.signerAllowed&&s.provenanceVerified&&s.testsOnDigest
```

### Synthetic input and actual model output
```json
{
  "before": [
    {
      "name": "trusted-builder",
      "input": {
        "signed": true,
        "signerAllowed": true,
        "provenanceVerified": true,
        "testsOnDigest": true
      },
      "expected": true,
      "observed": true,
      "matched": true
    },
    {
      "name": "unknown-signer",
      "input": {
        "signed": true,
        "signerAllowed": false,
        "provenanceVerified": true,
        "testsOnDigest": true
      },
      "expected": false,
      "observed": true,
      "matched": false
    },
    {
      "name": "rebuilt-after-test",
      "input": {
        "signed": true,
        "signerAllowed": true,
        "provenanceVerified": true,
        "testsOnDigest": false
      },
      "expected": false,
      "observed": true,
      "matched": false
    }
  ],
  "after": [
    {
      "name": "trusted-builder",
      "input": {
        "signed": true,
        "signerAllowed": true,
        "provenanceVerified": true,
        "testsOnDigest": true
      },
      "expected": true,
      "observed": true,
      "matched": true
    },
    {
      "name": "unknown-signer",
      "input": {
        "signed": true,
        "signerAllowed": false,
        "provenanceVerified": true,
        "testsOnDigest": true
      },
      "expected": false,
      "observed": false,
      "matched": true
    },
    {
      "name": "rebuilt-after-test",
      "input": {
        "signed": true,
        "signerAllowed": true,
        "provenanceVerified": true,
        "testsOnDigest": false
      },
      "expected": false,
      "observed": false,
      "matched": true
    }
  ]
}
```

## Exit evidence

- Signature, provenance and scan records for one digest
- Expiring exception and runtime test evidence

## References

- [NIST SP 800-190 · Container security](https://csrc.nist.gov/pubs/sp/800/190/final)
- [Kubernetes · Security context](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/)
