Overview
If you manage a Harbor registry with dozens of projects and hundreds of repositories, answering a simple question like "what Helm charts do we have?" can be surprisingly difficult. Harbor's UI lets you browse one project at a time, but there is no built-in way to get a consolidated inventory across every project.
This post walks through a Bash script that uses the Harbor v2.0 REST API to enumerate every OCI Helm chart version across all projects and outputs a clean CSV. It is completely read-only — no charts are pulled or modified.
Prerequisites
bash4+ (macOS ships with 3.x — usebrew install bashif needed)curljq- A Harbor user account with read access to the target projects
Step 1 — Clone the tool
git clone https://github.com/karankiruba09/platform-infra-automation.git
cd platform-infra-automation/kubernetes/harbor-helm-discoveryThe tool is a single self-contained script: list-harbor-helm-charts.sh.
Step 2 — Set environment variables
The script accepts configuration through environment variables or positional arguments. Environment variables are the recommended approach:
export HARBOR_URL=https://harbor.example.com
export HARBOR_USER=admin
export HARBOR_PASSWORD='your-password-here'If your Harbor instance uses a self-signed certificate, also set:
export HARBOR_INSECURE=trueOptional tuning
The following environment variables can be used to tune performance:
PAGE_SIZE(default: 100) — Number of items per API pagePARALLELISM(default: 32) — Concurrent artifact lookups per projectOUTPUT_CSV(default:./output/harbor-helm-charts.csv) — Path for the output CSV file
Step 3 — Run the script
./list-harbor-helm-charts.shYou will see per-project progress printed to stderr as it scans:
Listing OCI Helm charts from https://harbor.example.com
Using parallelism: 32
Scanning project: platform-charts (42 repositories)
Found 87 OCI Helm chart version entries in platform-charts
Scanning project: infra (18 repositories)
Found 34 OCI Helm chart version entries in infra
...Step 4 — Review the output
The script produces two files:
CSV file
Located at output/harbor-helm-charts.csv by default:
project,repository,version
"platform-charts","platform-charts/nginx-ingress","4.10.1"
"platform-charts","platform-charts/nginx-ingress","4.9.0"
"infra","infra/cert-manager","1.14.5"
...Each row represents a single tagged chart version. If a chart artifact has no tags, it appears as <untagged>.
Totals file
Located at output/harbor-helm-charts.total.txt:
total_oci_helm_chart_versions,515This gives you a quick count without needing to parse the CSV.
How it works
The script follows a three-level pagination pattern through the Harbor v2.0 API:
- Projects —
GET /api/v2.0/projectswith page/page_size parameters. Each project includes arepo_countfield; projects with zero repositories are skipped. - Repositories — For each project,
GET /api/v2.0/projects/{project}/repositoriesretrieves all repository names. - Artifacts — For each repository,
GET /api/v2.0/projects/{project}/repositories/{repo}/artifacts?with_tag=truereturns artifacts with their tags. The script filters for OCI Helm charts by checking three fields:type == "CHART", orartifact_type/media_typematchingapplication/vnd.cncf.helm.config.v1+json.
Artifact lookups are parallelized within each project using xargs -P (default: 32 concurrent workers), which keeps the scan fast even against registries with thousands of repositories.
Use cases
- Audit and compliance — generate a full inventory of Helm charts stored in your registry for change management or security review
- Migration planning — when moving to a new registry or upgrading Harbor, know exactly what needs to be migrated
- Cleanup — identify stale or untagged chart versions that can be garbage-collected
- Reporting — feed the CSV into a dashboard or spreadsheet to track chart sprawl over time
Tips
- The script is read-only — it only issues GET requests against the Harbor API. It does not pull, push, or delete anything.
- If you have a large registry (1000+ repositories), consider increasing
PAGE_SIZEto reduce the number of API round-trips. - For very large scans, you can redirect stdout to a file separately from the progress output on stderr:
./list-harbor-helm-charts.sh > full-output.csv 2>progress.logThe CSV output is also printed to stdout, so you can pipe it directly into other tools:
./list-harbor-helm-charts.sh 2>/dev/null | sort -t, -k1,1
