dhi: add release notes (#25245)

<!--Delete sections as needed -->

## Description

- Added CLI and platform release notes for DHI.
- Modified sbx release note script to also fetch dhictl and fix some
formatting issues introduced by the DHI CLI release notes.


https://deploy-preview-25245--docsdocker.netlify.app/dhi/release-notes/platform/

https://deploy-preview-25245--docsdocker.netlify.app/dhi/release-notes/cli/

## Related issues or tickets


## Reviews

<!-- Notes for reviewers here -->
<!-- List applicable reviews (optionally @tag reviewers) -->

- [ ] Editorial review
- [ ] Product review

Signed-off-by: Craig Osterhout <craig.osterhout@docker.com>
This commit is contained in:
Craig Osterhout
2026-06-10 08:36:47 -07:00
committed by GitHub
parent c5fea43c1f
commit 140b37a933
5 changed files with 254 additions and 11 deletions
+4
View File
@@ -34,6 +34,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
@@ -0,0 +1,6 @@
---
build:
render: never
title: Release notes
weight: 999
---
+82
View File
@@ -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
- 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.
```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).
@@ -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.
+67 -11
View File
@@ -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
"""
@@ -29,8 +30,18 @@ from pathlib import Path
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 -->"
@@ -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)
@@ -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:
@@ -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__":