-
Notifications
You must be signed in to change notification settings - Fork 65
Plugin Catalog Index Generation
The plugin catalog index is the collection of community and supported plugins of this repository. It contains all the metadata, OCI image references, and default configuration needed for RHDH to discover and load dynamic plugins. This page explains how the catalog index is built, what it contains, and where it is published.
The catalog index generation pipeline reads workspace metadata, queries container registries, and produces a self-contained directory of catalog entities and an index.json file. This directory is then packaged as an OCI image and pushed to a container registry, where RHDH consumes it.
flowchart LR
subgraph Inputs
META["workspaces/{name}/metadata/{plugin}.yaml<br/>(Package entities)"]
CATS["catalog-entities/extensions/<br/>(Plugin entities, Collections)"]
PKGS["Package list files<br/>(default.packages.yaml,<br/>rhdh-supported-packages.txt,<br/>rhdh-community-packages.txt)"]
VERS["versions.json"]
end
subgraph Pipeline
GEN["generate-catalog-index<br/>workflow"]
end
subgraph Outputs
IDX["catalog-index/<br/>(index.json, entities, DPDY)"]
OCI["OCI images<br/>(quay.io, ghcr.io)"]
BRANCH["catalog-index-{branch}<br/>git branch"]
WIKI["Wiki status page"]
end
META --> GEN
CATS --> GEN
PKGS --> GEN
VERS --> GEN
GEN --> IDX
IDX --> OCI
IDX --> BRANCH
GEN --> WIKI
The pipeline runs via the [generate-catalog-index.yaml](../.github/workflows/generate-catalog-index.yaml) workflow, triggered on pushes to main and release-* branches when relevant files change, or manually via workflow_dispatch.
The core orchestrator script is [scripts/update-index.sh](../scripts/update-index.sh), which runs four steps in sequence:
flowchart TB
subgraph "Step 1: Plugin Builds Bootstrap"
S1_IN["workspaces/{name}/metadata/{plugin}.yaml<br/>plugins-list.yaml<br/>versions.json<br/>Package list files"]
S1["bootstrapPluginBuilds.py"]
S1_OUT["plugin_builds/{ws}/{plugin}.json<br/>(workspace path, OCI ref, support level)"]
S1_IN --> S1 --> S1_OUT
end
subgraph "Step 2: Image Metadata Fetch"
S2["generatePluginBuildInfo.py"]
S2_OUT["plugin_builds/{ws}/{plugin}.json<br/>(+ digest, build-date, vcs-ref)"]
S1_OUT --> S2
REG["Container registries<br/>(quay.io, ghcr.io)"] --> S2
S2 --> S2_OUT
end
subgraph "Step 3: DPDY Generation"
S3_IN["default.packages.yaml<br/>metadata appConfigExamples"]
S3["generateDynamicPluginsDefaultYaml.sh<br/>+ injectDpdyTagComments.py"]
S3_OUT["dynamic-plugins.default.yaml"]
S3_IN --> S3
S2_OUT -- "tag & build-date<br/>for comments" --> S3
S3 --> S3_OUT
end
subgraph "Step 4: Catalog Index Generation"
S4["generateCatalogIndex.py"]
S4_OUT["index.json<br/>catalog-entities/<br/>build-report.json"]
S2_OUT --> S4
S3_OUT -- "OCI ref updates &<br/>tag comments" --> S4
CATS2["catalog-entities/extensions/"] --> S4
S4 --> S4_OUT
end
Reads each workspaces/*/metadata/*.yaml file and constructs initial plugin_builds/<workspace>/<image-name>.json entries. Each entry includes the workspace path, support level, and a constructed OCI tag reference based on the registry type:
-
ghcr.io:
bs_{backstage_version}__{plugin_version}(e.g.,bs_1.49.4__0.8.2) -
quay.io/rhdh:
{rhdh_version}--{plugin_version}(e.g.,1.10--0.8.2)
Plugins are filtered to only those matching the provided --packages-file list(s).
Queries the container registry for each plugin's OCI image to retrieve:
-
Digest (
sha256:...) for immutable references - Build date and VCS ref from container labels
- Upstream/midstream repo refs from container env vars
Then updates plugin_builds with the relevant metadata.
Images that don't exist in the registry are logged as warnings.
For each plugin, the image metadata fetch follows a three-tier resolution:
-
Exact tag match: The constructed tag (e.g.,
1.10.0--1.5.4) is queried directly. If the image exists, its metadata is used as-is. -
RHDH version alias (quay.io/rhdh only): If the exact tag is not found and the RHDH version prefix has three parts (x.y.z), the patch version is stripped to try the minor-version alias (e.g.,
1.10.2--β1.10--). This is because downstream builds are not repeated for each RHDH patch release if the plugin hasn't changed β a build done during1.10.0produces both1.10.0--1.5.4and1.10--1.5.4tags, and the1.10--alias remains valid for1.10.1,1.10.2, etc. If the exact plugin version is found under the alias, the resolved reference is used without marking it as a fallback. If the alias has tags but not the exact plugin version, the plugin is reported as not found β a new downstream build is needed. -
Fallback to latest version: If the exact plugin version is not found under the original prefix, the latest published plugin version within that prefix is used. This is flagged as a fallback in the output, and the metadata YAML's
version:field is updated to match. Fallback only applies within the original prefix β the alias (minor-version) prefix is only used for exact matches.
Alias resolution does not apply to ghcr.io (community) builds, which use Backstage version prefixes (bs_x.y.z__).
Generates dynamic-plugins.default.yaml β the default plugin configuration shipped with RHDH. This step only runs for the supported tier (requires a YAML-format packages file with enabled/disabled structure).
After generating the DPDY, the script calls injectDpdyTagComments.py to insert # Tag: <tag>, Build date: <date> comments from plugin_builds/*.json (produced by Steps 1-2). Each plugin's registryReference tag and build-date label are extracted from the enriched JSON files and placed as comments above the corresponding - package: lines. This provides traceability from each plugin entry back to the specific OCI image tag and build date, without requiring live registry API calls (which previously caused Quay API timeouts).
Inputs:
-
default.packages.yamlβ lists which plugins are enabled vs disabled by default -
workspaces/*/metadata/*.yamlβspec.appConfigExamples[0].contentprovides thepluginConfigfor each plugin -
plugin_builds/*.jsonβ provides tag and build-date metadata for comment injection
Output structure (truncated):
plugins:
# Tag: 1.10--0.8.2, Build date: 2026-05-20T13:45:25Z
- package: oci://quay.io/rhdh/red-hat-developer-hub-backstage-plugin-adoption-insights:1.10--0.8.2
enabled: true
pluginConfig:
dynamicPlugins:
frontend:
red-hat-developer-hub.backstage-plugin-adoption-insights:
# ... frontend wiring config
# Tag: 1.10--1.2.0, Build date: 2026-05-19T09:12:00Z
- package: oci://quay.io/rhdh/backstage-community-plugin-acr:1.10--1.2.0
enabled: falseThe final step that produces the catalog index:
- Copies
catalog-entities/extensions/(Plugin entities, collections) to the output directory - Copies
workspaces/*/metadata/*.yaml(Package entities) to thepackagesdirectory of the catalog index output directory - Scrubs entities to only include packages matching the package list filter
- Verifies each plugin's OCI image exists in the registry
- Generates
index.jsonwith digest-based references - Updates Package entity files and DPDY with OCI references and Tag/Build date comments
- Regenerates
all.yamllocation files
The generated catalog-index/<tier>/ directory contains:
| File | Purpose |
|---|---|
index.json |
Main index mapping plugin image names to OCI refs with digests |
catalog-entities/extensions/packages/*.yaml |
Package entity definitions with resolved OCI references |
catalog-entities/extensions/plugins/*.yaml |
Plugin entity definitions (descriptions, icons, categories) |
catalog-entities/extensions/collections/*.yaml |
Collection groupings (featured, recommended, etc.) |
dynamic-plugins.default.yaml |
Default plugin configuration (supported tier only) |
build-info.json |
Build metadata (date, versions, source commit) |
build-report.json |
Detailed per-plugin build status with stage tracking (not included in final OCI artifact) |
The pipeline runs twice per build β once for each tier:
Plugins with Red Hat support (GA or Tech Preview heading to GA).
-
Filter: Union of
default.packages.yaml+rhdh-supported-packages.txt -
Registry:
quay.io/rhdh(plugins registry) /quay.io/rhdh-community(catalog index image registry) -
Published to:
quay.io/rhdh-community/plugin-catalog-index -
Tags:
bs_{backstage_version}-{short_sha},bs_{backstage_version},latest - Includes DPDY: Yes
Community-supported plugins.
-
Filter:
rhdh-community-packages.txt -
Registry:
ghcr.io/redhat-developer/rhdh-plugin-export-overlays -
Published to:
ghcr.io/redhat-developer/rhdh-plugin-export-overlays/plugin-catalog-index -
Tags:
bs_{backstage_version}-{short_sha},bs_{backstage_version},latest - Includes DPDY: No
After each build, a status page is automatically pushed to the GitHub Wiki:
- Index page: Plugin Catalog Index Status β links to all branch status pages
-
Per-branch pages:
Plugin-Catalog-Status-{branch}β shows which plugins passed/failed and why
The status page includes:
- Build metadata (date, commit, versions)
- Summary counts per tier (total, passed, failed)
- Per-plugin tables with links to metadata files, OCI references, and failure reasons
- Links to the workflow run for debugging failures
The raw build-report.json files are also available on the catalog-index-{branch} git branch in catalog-index/supported/build-report.json and catalog-index/community/build-report.json.
Pushes to main or release-* branches that modify any of these paths trigger the workflow:
workspaces/*/metadata/*.yamlcatalog-entities/extensions/**-
default.packages.yaml,rhdh-supported-packages.txt,rhdh-community-packages.txt scripts/**versions.json
# Build from main, push to catalog-index-main
gh workflow run generate-catalog-index.yaml
# Build from a specific branch
gh workflow run generate-catalog-index.yaml -f source-branch=release-1.9
# Build from one branch, push catalog to a custom target branch
gh workflow run generate-catalog-index.yaml \
-f source-branch=main \
-f target-branch=catalog-index-customTo extract the contents from a catalog index image, run this script:
unpack () {
if [[ ! $1 ]]; then
echo "Usage: unpack reg/org/container:tagorsha"
else
local IMAGE="$1"
DIR="${IMAGE//:/_}"
DIR="/tmp/${DIR//\//-}"
rm -fr "$DIR"; mkdir -p "$DIR"; container_id=$(podman create "${IMAGE}")
podman export $container_id -o /tmp/image.tar && tar xf /tmp/image.tar -C "${DIR}/"; podman rm $container_id; rm -f /tmp/image.tar
echo "Unpacked $IMAGE into $DIR"
cd $DIR; tree -d -L 3 -I "usr|root|buildinfo"
fi
}
unpack ghcr.io/redhat-developer/rhdh-plugin-export-overlays/plugin-catalog-index:1.11-bs_1.49.4
unpack quay.io/rhdh-community/plugin-catalog-index:<some tag>
Once unpacked, you should see a tree of metadata files to browse, as well as index.json and build-info.json.
.
βββ catalog-entities
βββ extensions
βββ collections
βββ packages
βββ plugins
- 64 workspaces
- 11 with patches