Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions content/manuals/dhi/_index.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ params:
description: Guides, blog posts, Docker Hub catalog, GitHub repositories, and more.
icon: link
link: /dhi/resources/
- title: Release notes
description: New features, improvements, and changes in Docker Hardened Images.
icon: newspaper
link: /dhi/release-notes/platform/
---

Docker Hardened Images (DHI) provide minimal, secure, and production-ready
Expand Down
6 changes: 6 additions & 0 deletions content/manuals/dhi/release-notes/_index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
build:
render: never
title: Release notes
weight: 999
---
82 changes: 82 additions & 0 deletions content/manuals/dhi/release-notes/cli.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
---
title: DHI CLI release notes
linkTitle: CLI release notes
description: New features, bug fixes, and changes in the DHI CLI
keywords: docker hardened images, dhi, dhictl, cli, release notes, changelog
toc_min: 1
toc_max: 2
tags:
- Release notes
---

This page lists changes in recent stable releases of the DHI CLI (`docker dhi`). For
the full release history, including pre-releases and downloads, see the
[dhictl releases on GitHub](https://github.com/docker-hardened-images/dhictl/releases).

<!-- BEGIN GENERATED RELEASES -->

## 0.0.4

{{< release-date date="2026-05-25" >}}

[GitHub release](https://github.com/docker-hardened-images/dhictl/releases/tag/v0.0.4)

### What's New
Comment thread
craig-osterhout marked this conversation as resolved.

- Adds `deb` subcommand for DHI DEB repositories that emits netrc-style credentials for authenticating against DHI DEB repositories

## 0.0.3

{{< release-date date="2026-04-22" >}}

[GitHub release](https://github.com/docker-hardened-images/dhictl/releases/tag/v0.0.3)

### What's New

- Adds attestation list and get commands for managing attestations
- Adds SBOM subcommand for software bill of materials attestation
- Adds bulk support to prepare command for customizations
- Adds compression field support for customizations
- Adds tag-definition-id column to catalog get output

### Breaking change

We removed the `--output` flags from the few commands that had it (`customization prepare` and `customization get`) in favor of stdout redirections.
Comment thread
craig-osterhout marked this conversation as resolved.
```console
# before
dhictl customization prepare --org my-org golang 1.25 --output my-customization.yaml

# after
dhictl customization prepare --org my-org golang 1.25 > my-customization.yaml
```

## 0.0.2

{{< release-date date="2026-03-19" >}}

[GitHub release](https://github.com/docker-hardened-images/dhictl/releases/tag/v0.0.2)

This is a maintenance release focused on build system improvements.

### Technical Changes

- Disables CGO globally to fix macOS 16 dyld crash and simplify build process

## 0.0.1

{{< release-date date="2026-03-12" >}}

[GitHub release](https://github.com/docker-hardened-images/dhictl/releases/tag/v0.0.1)

This release improves the mirroring functionality in dhictl by allowing command arguments.

### Improvements

- Mirror start command now accepts arguments for more flexible mirroring operations

<!-- END GENERATED RELEASES -->

## Earlier releases

For older versions, see the
[dhictl releases on GitHub](https://github.com/docker-hardened-images/dhictl/releases).
95 changes: 95 additions & 0 deletions content/manuals/dhi/release-notes/platform.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
---
title: Docker Hardened Images release notes
linkTitle: Platform release notes
description: Learn about the latest features and changes in Docker Hardened Images
keywords: docker hardened images, dhi, release notes, changelog, features, changes, new, releases
tags: [Release notes]
---


This page contains information about the new features, improvements, and changes
in the Docker Hardened Images (DHI) platform. Release notes are aggregated by
quarter and include only notable product changes.

## Q2 2026

New features and enhancements released in the second quarter of 2026.

- Debian Hardened System Packages: Added support for Debian-based Docker
Hardened System Packages (HSP), including new CLI workflows for authenticating
to the Debian HSP repository.
- Mend.io scanner integration: Mend.io is now a supported scanner for consuming
DHI VEX data.
- Black Duck scanner integration: Black Duck is now a supported scanner for
consuming DHI VEX data.
- DHI Select self-serve purchase: DHI Select is now available for self-serve
purchase directly through the Docker website.
- Bulk customization: Apply customizations to multiple images in a single
operation through the Docker Hub UI and the CLI.
- Terraform provider: Manage DHI resources, including customizations and
mirrors, using the official Terraform provider.

## Q1 2026

New features and enhancements released in the first quarter of 2026.

- Docker Hardened System Packages (HSP): Announced Docker Hardened System
Packages, a new offering that provides individually hardened packages for use
in your own base images. For more information, see the [announcement blog
post](https://www.docker.com/blog/announcing-docker-hardened-system-packages/).
- Wiz scanner integration: Wiz is now a supported scanner for consuming DHI VEX
data.

## Q4 2025

New features and enhancements released in the fourth quarter of 2025.

- Docker Hardened Images Community (Free): Docker Hardened Images are now
available for every developer through a Community subscription tier. The
subscription tiers are now Community, Select, and Enterprise. For more
information, see the [announcement blog
post](https://www.docker.com/blog/docker-hardened-images-for-every-developer/).
- Independent security validation by SRLabs: SRLabs published an independent
security validation of Docker Hardened Images. See the
[validation announcement](https://www.docker.com/blog/docker-hardened-images-security-independently-validated-by-srlabs/).
- Docker Scout scoring for DHI: Docker Scout image scoring now accounts for the
security improvements provided by DHI.
- Trivy VEX repository: VEX data for DHI is published in a Trivy-compatible OCI
VEX repository, making it easier for Trivy and other scanners to consume.
- Docker Scout DHI policy: New Docker Scout policy that evaluates whether images
use Docker Hardened Images.
- Hardened Helm charts (Beta): Beta release of Docker Hardened Helm Charts. For
more information, see the [announcement blog
post](https://www.docker.com/blog/docker-hardened-images-helm-charts-beta/).
- Mirroring UX: Updated the mirroring experience in Docker Hub with a refreshed
UI and clearer flows.

## Q3 2025

New features and enhancements released in the third quarter of 2025.

- Next evolution release: A major release that introduced customizations,
FedRAMP-ready images, the AI Migration Agent, and deeper scanner integrations.
See the [announcement blog
post](https://www.docker.com/blog/the-next-evolution-of-docker-hardened-images/)
and the [FedRAMP compliance blog
post](https://www.docker.com/blog/fedramp-compliance-with-hardened-images/).
- DHI customizations: Customize DHI images directly from the Docker Hub UI,
with options for adding packages, files, and configuration on top of a base
hardened image.
- AI Migration Agent: AI-assisted Dockerfile migration to help convert existing
Dockerfiles to use Docker Hardened Images.
- CIS compliance attestations: CIS benchmark compliance attestations are now
included with DHI images.
- STIG variants: STIG-hardened image variants for U.S. Department of Defense
compliance use cases.

## Q2 2025

New features and enhancements released in the second quarter of 2025.

- Docker Hardened Images launch: Docker announced Docker Hardened Images, a new
family of secure, minimal, and production-ready container images maintained by
Docker. For more information, see the [launch blog
post](https://www.docker.com/blog/introducing-docker-hardened-images/).
- FIPS variants: FIPS-validated image variants for Docker Hardened Images.
78 changes: 67 additions & 11 deletions hack/sbx-release-notes.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,13 @@
# dependencies = ["jinja2"]
# ///
"""
Fetch recent stable releases from docker/sbx-releases and splice them into
content/manuals/ai/sandboxes/release-notes.md between the BEGIN/END markers.
Fetch recent stable releases from a GitHub releases page and splice them into
a docs markdown file between the BEGIN/END markers.

Usage (from repo root):

./hack/sbx-release-notes.py
./hack/sbx-release-notes.py --preset dhi
GITHUB_TOKEN=$(gh auth token) ./hack/sbx-release-notes.py
./hack/sbx-release-notes.py --minor-releases 3
"""
Expand All @@ -29,8 +30,18 @@

from jinja2 import Template

DEFAULT_REPO = "docker/sbx-releases"
DEFAULT_FILE = Path("content/manuals/ai/sandboxes/release-notes.md")
PRESETS: dict[str, dict] = {
"sbx": {
"repo": "docker/sbx-releases",
"file": Path("content/manuals/ai/sandboxes/release-notes.md"),
},
"dhi": {
"repo": "docker-hardened-images/dhictl",
"file": Path("content/manuals/dhi/release-notes/cli.md"),
},
}

DEFAULT_PRESET = "sbx"
DEFAULT_MINOR_RELEASES = 3

BEGIN = "<!-- BEGIN GENERATED RELEASES -->"
Expand Down Expand Up @@ -89,7 +100,7 @@ def parse_stable(raw: list[dict]) -> list[dict]:
"version": f"{major}.{minor}.{patch}",
"date": r["published_at"][:10],
"url": r["html_url"],
"body": shift_headings(body),
"body": normalize_body(shift_headings(body)),
}
)
out.sort(key=lambda r: (r["major"], r["minor"], r["patch"]), reverse=True)
Expand Down Expand Up @@ -123,6 +134,41 @@ def shift_headings(body: str) -> str:
return "\n".join(lines)


def normalize_body(body: str) -> str:
"""Fix markdownlint issues in release body content:
- Ensure a blank line follows each heading (MD022).
- Add 'console' language tag to fenced code blocks that have none (MD040).
Safe to run on content that already complies — no double blank lines are added."""
lines = body.splitlines()
result: list[str] = []
in_fence = False

for i, line in enumerate(lines):
stripped = line.lstrip(" \t")

if stripped.startswith(("```", "~~~")):
if not in_fence:
# Opening fence: add language tag if missing
fence_marker = "```" if stripped.startswith("```") else "~~~"
lang = stripped[len(fence_marker):].strip()
if not lang:
indent = line[: len(line) - len(stripped)]
line = f"{indent}{fence_marker}console"
in_fence = not in_fence
result.append(line)
continue

result.append(line)

# Outside fences: insert blank line after a heading if the next line is non-empty
if not in_fence and stripped.startswith("#"):
next_line = lines[i + 1] if i + 1 < len(lines) else ""
if next_line.strip():
result.append("")

return "\n".join(result)


def splice(path: Path, generated: str) -> None:
src = path.read_text()
try:
Expand All @@ -135,20 +181,30 @@ def splice(path: Path, generated: str) -> None:

def main() -> None:
p = argparse.ArgumentParser(description=__doc__)
p.add_argument("--repo", default=DEFAULT_REPO)
p.add_argument("--file", type=Path, default=DEFAULT_FILE)
p.add_argument(
"--preset",
choices=list(PRESETS),
default=DEFAULT_PRESET,
help="Named preset that sets --repo and --file defaults (default: %(default)s)",
)
p.add_argument("--repo", default=None, help="GitHub repo (owner/name), overrides preset")
p.add_argument("--file", type=Path, default=None, help="Target markdown file, overrides preset")
p.add_argument("--minor-releases", type=int, default=DEFAULT_MINOR_RELEASES)
args = p.parse_args()

releases = pick_minor_releases(parse_stable(fetch(args.repo)), args.minor_releases)
preset = PRESETS[args.preset]
repo = args.repo or preset["repo"]
file = args.file or preset["file"]

releases = pick_minor_releases(parse_stable(fetch(repo)), args.minor_releases)
if not releases:
sys.exit("no stable releases found")

generated = TEMPLATE.render(releases=releases)
splice(args.file, generated)
splice(file, generated)
if shutil.which("npx"):
subprocess.run(["npx", "--no-install", "prettier", "--write", str(args.file)], check=False)
print(f"Wrote {len(releases)} releases (latest {args.minor_releases} minor releases) to {args.file}")
subprocess.run(["npx", "--no-install", "prettier", "--write", str(file)], check=False)
print(f"Wrote {len(releases)} releases (latest {args.minor_releases} minor releases) to {file}")


if __name__ == "__main__":
Expand Down