Skip to content

feat(image): support pinning qdrant image by digest - #457

Open
unique-jakub wants to merge 1 commit into
qdrant:mainfrom
unique-jakub:feat/image-digest-support
Open

feat(image): support pinning qdrant image by digest#457
unique-jakub wants to merge 1 commit into
qdrant:mainfrom
unique-jakub:feat/image-digest-support

Conversation

@unique-jakub

@unique-jakub unique-jakub commented Apr 27, 2026

Copy link
Copy Markdown

Closes #388.

What

Add support for pinning the qdrant container image by SHA256 digest, so that the chart can render repository@sha256:<digest> and provide immutable, content-addressed pulls.

Why

Tag-based image references are mutable: anyone with push access to the registry can replace the image behind a tag without changing the tag itself. Digest pinning is a standard supply-chain mitigation but is currently impossible with this chart because:

  1. The chart assembles the image as "{{ repo }}:{{ tag }}", so the only way for a user to pass a digest is to stuff tag@sha256:... into image.tag.
  2. templates/statefulset.yaml then passes image.tag directly to semverCompare ">=1.7.3" to pick the readiness probe path, which fails with error calling semverCompare: invalid semantic version once the tag contains @sha256:.

This PR makes the chart digest-aware on both fronts.

Changes

values.yaml

A new optional field:

image:
  repository: docker.io/qdrant/qdrant
  tag: ""
  digest: ""              # e.g. sha256:abc123…
  useUnprivilegedImage: false

templates/_helpers.tpl

Two new helpers:

  • qdrant.image — renders repository@digest when image.digest is set, otherwise repository:tag[-unprivileged]. Used for both the main container and the ensure-dir-ownership initContainer.
  • qdrant.image.semver — extracts the semver portion of image.tag for semverCompare. It strips any @sha256:… suffix (the form Renovate emits when it digest-pins a Helm value) and falls back to Chart.AppVersion when the tag is empty.

templates/statefulset.yaml

Three call sites updated to use the new helpers:

  • Main container image:{{ include "qdrant.image" . }}
  • ensure-dir-ownership initContainer image:{{ include "qdrant.image" . }}
  • Readiness probe path semverCompare → uses include "qdrant.image.semver" $

Behaviour matrix

image.tag image.digest useUnprivilegedImage Rendered image semverCompare input
"" (default) "" false repo:<Chart.AppVersion> <Chart.AppVersion>
v1.6.0 "" true repo:v1.6.0-unprivileged v1.6.0
"" sha256:abc false repo@sha256:abc <Chart.AppVersion>
v1.17.1 sha256:abc false repo@sha256:abc v1.17.1
v1.17.1@sha256:abc "" false repo:v1.17.1@sha256:abc (valid OCI) v1.17.1

Default behaviour is unchanged — with digest empty the chart still renders repository:tag[-unprivileged] exactly as before.

When both digest and useUnprivilegedImage are set, the digest takes precedence; users wanting the unprivileged variant must supply the digest of that variant. This is documented inline in values.yaml.

Tests

helm lint charts/qdrant passes.

go test ./test/ passes the entire existing suite plus a new TestImageDigestPinning that covers:

  • digest-only renders repository@digest
  • digest with tag still renders repository@digest
  • digest takes precedence over useUnprivilegedImage
  • tag@sha256: notation strips the digest from semverCompare (>=1.7.3 path)
  • tag@sha256: notation respects pre-1.7.3 readiness path
--- PASS: TestImageDigestPinning (0.40s)
    --- PASS: TestImageDigestPinning/digest_only_renders_repository@digest
    --- PASS: TestImageDigestPinning/digest_with_tag_still_renders_repository@digest
    --- PASS: TestImageDigestPinning/digest_takes_precedence_over_useUnprivilegedImage_suffix
    --- PASS: TestImageDigestPinning/tag@sha256_notation_strips_digest_from_semverCompare
    --- PASS: TestImageDigestPinning/tag@sha256_notation_respects_pre-1.7.3_readiness_path

I left Chart.yaml / CHANGELOG.md untouched since per CONTRIBUTING.md those are bumped during release. Happy to add the changelog entry if you'd like it in this PR.

Adds a new `image.digest` value and two helper templates so that users can
reference the qdrant container image by SHA256 digest for immutable,
content-addressed pulls (closing the gap reported in qdrant#388).

Behaviour:

* When `image.digest` is set, the container is rendered as
  `repository@digest` and the digest takes precedence over `image.tag` and
  the `-unprivileged` suffix. Users wanting the unprivileged variant must
  supply the digest of that variant.
* The new `qdrant.image.semver` helper strips an optional `@sha256:...`
  suffix from `image.tag` (this is the form Renovate emits when it
  digest-pins a Helm value) before the readiness-probe path's
  `semverCompare ">=1.7.3"` check, so chart logic that depends on the
  qdrant version keeps working when callers use the combined notation.
* Default behaviour is unchanged: with `digest` empty the chart still
  renders `repository:tag[-unprivileged]`.

Tests: extends the unit suite with `TestImageDigestPinning` covering
digest-only, digest+tag, digest+useUnprivilegedImage, and the
`tag@sha256:` notation for both >=1.7.3 and <1.7.3 readiness paths.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support pinning container image by digest (repo@sha256) in values

1 participant