Steelman
steelman is a reporting CLI for Flux-managed Helm releases.
It scans Flux resources from:
- live Kubernetes clusters
- Git repositories containing Flux manifests
- or both
It compares those releases against Docker Hardened Images catalog data and reports one of:
- already using a DHI chart
- a DHI chart replacement is available
- DHI image replacements are available inside the chart values
- no DHI replacement was found
Scope
Current scope:
- Flux
HelmRelease - Flux
HelmRepository - Flux
OCIRepository
Not currently supported:
- plain Helm releases that are not represented as Flux resources
- Argo CD applications
- direct workload or pod inspection
valuesFromresolution
What It Checks
For each Flux release, the tool:
- identifies the current chart source
- checks whether a DHI chart exists
- if not, tries to resolve chart defaults with
helm show values - merges inline
HelmRelease.spec.values - extracts image references from the effective values
- checks whether matching DHI images exist
Chart replacement takes precedence over image replacement.
Requirements
- Python 3.12+
uvhelmif you want image replacement analysis- kubeconfig access if you want live cluster scanning
Usage
Using the published package:
uvx steelman
Common variants:
uvx steelman --mode cluster
uvx steelman --mode git --repo /path/to/gitops-repo
uvx steelman --contexts prod-eu,prod-us
uvx steelman --output-dir reports
uvx steelman --offline
uvx steelman --skip-image-analysis
uvx steelman --include-already-migrated
uvx steelman --helm-bin helm
uvx steelman --image-match-threshold 0.75
uvx steelman --aliases ./aliases.yaml
uvx steelman --verbose
uvx steelman --issue
Use the ci subcommand to run with CI defaults (generates steelman-issue.md by default):
uvx steelman ci
uvx steelman ci --mode git --repo . --output-dir reports
uvx steelman ci --no-issue
Defaults
If run without flags:
--mode both- scans
.recursively for Flux manifests - reads kubeconfig from the default location
- uses all contexts if kubeconfig contains 10 or fewer contexts
- otherwise uses the current context only
- omits the
already_dhi_chartsection from the Markdown report - writes:
./steelman.md./steelman.json
The ci subcommand uses the same defaults with one difference:
- writes
./steelman-issue.mdin addition to the above (use--no-issueto suppress)
Output
The Markdown report contains:
- summary
- hardened chart available
- hardened images available
- no DHI replacement
- scan notes
Use --include-already-migrated if you want the Markdown report to include releases that are already using DHI charts.
The JSON report contains:
- catalog metadata
- inventory summary
- recommendation counts
- per-release results
- recorded errors
The issue report contains:
- a CI-managed
DHI implementation statusissue body - pending chart and image migrations as checklist items
- already-migrated DHI releases as checked items
- scan errors and a compact summary for a single long-lived issue
CI Examples
These examples assume:
- the repository is a Flux v2 GitOps repository
- the scan should use Git manifests, not live cluster access
- the generated report should be kept as an artifact or posted into an issue
For Git-only scans, use:
uvx steelman ci --mode git --repo . --output-dir reports
GitHub Actions
This example runs on a schedule and on manual dispatch, scans the current Flux repo, uploads the report artifacts, and creates or updates a single issue named DHI implementation status.
name: Steelman Report
on:
schedule:
- cron: "0 6 * * 1"
workflow_dispatch:
permissions:
contents: read
issues: write
jobs:
steelman:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v6
- name: Set up uv
uses: astral-sh/setup-uv@v7
- name: Run steelman
run: uvx steelman ci --mode git --repo . --output-dir reports
- name: Upload reports
uses: actions/upload-artifact@v6
with:
name: steelman-report
path: reports/*
if-no-files-found: error
- name: Create or update issue
env:
GH_TOKEN: ${{ github.token }}
run: |
issue_number="$(gh issue list --state open --label steelman --search 'DHI implementation status in:title' --json number --jq '.[0].number')"
if [ -n "$issue_number" ]; then
gh issue edit "$issue_number" --title "DHI implementation status" --body-file reports/steelman-issue.md
else
gh issue create --title "DHI implementation status" --label steelman --body-file reports/steelman-issue.md
fi
Notes:
- this scans desired state from Git only
reports/steelman.md,reports/steelman.json, andreports/steelman-issue.mdare uploaded as artifactssteelman cigeneratessteelman-issue.mdby default; usesteelman ci --no-issueto skip it- the issue update step requires
issues: write
Woodpecker CI
This example runs the same Git-only scan and stores the generated files in the workspace. If your Woodpecker setup exposes a GitHub token, you can also open or update the same long-lived issue with gh.
steps:
steelman:
image: ghcr.io/astral-sh/uv:python3.13-bookworm
commands:
- uvx steelman ci --mode git --repo . --output-dir reports
steelman-report:
image: ghcr.io/astral-sh/uv:python3.13-bookworm
environment:
GITHUB_TOKEN:
from_secret: github_token
commands:
- apt-get update
- apt-get install -y gh
- issue_number="$(gh issue list --repo "$CI_REPO" --state open --label steelman --search 'DHI implementation status in:title' --json number --jq '.[0].number')"
- |
if [ -n "$issue_number" ]; then
gh issue edit "$issue_number" --repo "$CI_REPO" --title "DHI implementation status" --body-file reports/steelman-issue.md
else
gh issue create --repo "$CI_REPO" --title "DHI implementation status" --label steelman --body-file reports/steelman-issue.md
fi
Notes:
- the second step is optional
- if you do not want issue creation, keep only the
steelmanstep - artifact handling in Woodpecker depends on your runner and storage configuration, so this example leaves the report in
reports/
GitLab CI
This example runs the same Git-only scan in a Flux repository, stores the generated reports as job artifacts, and optionally opens or updates a single GitLab issue for DHI implementation tracking.
stages:
- report
steelman:
stage: report
image: ghcr.io/astral-sh/uv:python3.13-bookworm
script:
- uvx steelman ci --mode git --repo . --output-dir reports
artifacts:
when: always
paths:
- reports/steelman.md
- reports/steelman.json
- reports/steelman-issue.md
expire_in: 7 days
steelman_issue:
stage: report
image: debian:bookworm-slim
needs:
- job: steelman
artifacts: true
rules:
- if: $GITLAB_TOKEN
script:
- apt-get update
- apt-get install -y curl jq
- |
issue_iid="$(curl --silent --header "PRIVATE-TOKEN: $GITLAB_TOKEN" \
"$CI_API_V4_URL/projects/$CI_PROJECT_ID/issues?state=opened&labels=steelman&search=DHI%20implementation%20status" | jq -r '.[0].iid // empty')"
- |
report_body="$(jq -Rs . < reports/steelman-issue.md)"
if [ -n "$issue_iid" ]; then
curl --silent --request PUT \
--header "PRIVATE-TOKEN: $GITLAB_TOKEN" \
--header "Content-Type: application/json" \
--data "{\"title\":\"DHI implementation status\",\"description\":$report_body}" \
"$CI_API_V4_URL/projects/$CI_PROJECT_ID/issues/$issue_iid"
else
curl --silent --request POST \
--header "PRIVATE-TOKEN: $GITLAB_TOKEN" \
--header "Content-Type: application/json" \
--data "{\"title\":\"DHI implementation status\",\"description\":$report_body,\"labels\":\"steelman\"}" \
"$CI_API_V4_URL/projects/$CI_PROJECT_ID/issues"
fi
Notes:
- the
steelman_issuejob is optional - set
GITLAB_TOKENas a masked CI variable if you want issue creation - if you only want artifacts, keep just the
steelmanjob
Cluster Mode In CI
If you want to scan live clusters instead of Git manifests, switch to:
uvx steelman ci --mode cluster --contexts prod-eu,prod-us --output-dir reports
That requires kubeconfig access in the CI environment. For a Flux repository, Git mode is usually the simpler starting point because it only scans desired state from the repo.
Current Limitations
valuesFromis detected but not resolved- image analysis depends on
helm show values - some OCI chart sources may fail
helm show valuesdepending on how the chart is published - matching is heuristic and may still need alias tuning for edge cases
Development
uv sync --group dev
uv run ruff check .
uv run ruff format --check .
uv run ty check
uv run pytest
Metadata
Release files for steelman 0.4.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| steelman-0.4.1.tar.gz | 20.9 kB | Without provenance | Details for steelman-0.4.1.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| steelman-0.4.1-py3-none-any.whl | Python 3 | none | any | Details for steelman-0.4.1-py3-none-any.whl |
Total release size: 48.1 kB
Release files / steelman-0.4.1.tar.gz
| Download URL | steelman-0.4.1.tar.gz |
|---|---|
| Size | 20.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
612dbef5f521e605cdb5377ad069decdfa4d713542e8515ea7a9b064e6e5a2a5
|
|
BLAKE2b-256 checksum How to use checksums |
b6b08b6601243179fb526020003429a06a353130beed31a334641217a6cfc7dd
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.10.11 {"installer":{"name":"uv","version":"0.10.11","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / steelman-0.4.1-py3-none-any.whl
| Download URL | steelman-0.4.1-py3-none-any.whl |
|---|---|
| Size | 27.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
39ec5f54429a9f89d08d0d362f0ba5a84443b1816d0fe0aa30fb877c51f0a1ee
|
|
BLAKE2b-256 checksum How to use checksums |
4811431043a8bfcb18342b9e13ddde465c607551b953a1edd1a3aba32a27aea8
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.10.11 {"installer":{"name":"uv","version":"0.10.11","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Security for steelman 0.4.1
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.