--- name: image-repo-mapping description: Use when resolving which GitHub repository to clone for CVE analysis from a container image name in a Jira ticket summary, pscomponent label, or Downstream Component Name field. --- # Image to Repository Mapping Translates a container image name into the GitHub repository URL to clone for analysis. Image names appear in the ticket summary, `pscomponent:` labels, and the `Downstream Component Name` custom field. ## When to Use This Skill Use this skill when: - An image name has been extracted from a Jira ticket (summary, label, or custom field) - The user passes `--repo=` using a short image name rather than a full GitHub URL - Phase 0.7 needs to determine which repository to clone --- ## Resolution Order Apply these in order and stop at the first match: 1. **Full GitHub URL supplied** (`--repo=https://github.com/...`) → use directly, skip this skill. 2. **Exact image name match** — look the image name up in the table below. 3. **Prefix match** — strip version suffixes (e.g. `-1-0`, `-1-12-4`, `-rhel9`, `-rhel8`) and re-match. 4. **Keyword match** — check the per-section keyword rules at the bottom of each group. 5. **NOT FOUND → Exit immediately** with the error message below. Do not guess. Do not proceed with analysis. > **Tip:** Strip `pkg:oci/` prefix before matching (e.g. `pkg:oci/ose-ansible-operator` → `ose-ansible-operator`). ### Not-Found Exit If no match is found after all steps above, **stop immediately** and output: ``` ❌ Repository mapping not found for image: The image "" is not in the known mapping table and could not be resolved automatically. To proceed, re-run with an explicit repository URL: --repo=https://github.com/org/repo Or add the mapping to: plugins/compliance/skills/image-repo-mapping/SKILL.md Do NOT continue analysis without a confirmed source repository. ``` Do NOT fall back to guessing, fuzzy matching, or prompting the user inline. Exit the command at this point. --- ## Two Repository Patterns Components fall into one of two patterns. The resolution output is different for each. ### Pattern A — Direct repo Clone the mapped repo directly at the mapped branch. Used by: Operator SDK, Ansible Operator, must-gather, Secrets Store CSI. ``` image → repo URL + branch ``` ### Pattern B — Release repo with git submodules Some components use a dedicated `-release` repo that aggregates all component repos as git submodules. The release repo branch pins each submodule to the exact commit/tag used for that release. Used by: cert-manager, ZTWIM, ESO. **Resolution steps for Pattern B:** 1. Clone the **release repo** at the mapped release branch 2. Read `.gitmodules` from that branch to find the submodule entry matching the target image 3. Read the **pinned commit** from the release repo tree (`git ls-tree HEAD `) — do not clone from the `.gitmodules` branch field alone 4. Clone the **component repo** and check out that pinned commit for analysis ```bash # Step 1: Clone release repo at correct branch (per-run path under REPOS_BASE) RELEASE_CLONE_DIR="${REPOS_BASE}/.release-clones/$(echo "${RELEASE_REPO_URL}" | sed -E 's#^[a-zA-Z]+://github\.com/##; s#\.git$##; s#/$##' | tr '/' '-')-${RELEASE_BRANCH}" rm -rf "${RELEASE_CLONE_DIR}" mkdir -p "$(dirname "${RELEASE_CLONE_DIR}")" git clone --depth=1 -b "${RELEASE_BRANCH}" "${RELEASE_REPO_URL}" "${RELEASE_CLONE_DIR}" # Step 2: Read .gitmodules cat "${RELEASE_CLONE_DIR}/.gitmodules" # Step 3: Extract submodule path + url from .gitmodules # Step 4: Read pinned commit from release repo tree PINNED_COMMIT=$(git -C "${RELEASE_CLONE_DIR}" ls-tree HEAD "${SUBMODULE_PATH}" | awk '{print $3}') if [ -z "${PINNED_COMMIT}" ]; then echo "ERROR: no pinned commit found for ${SUBMODULE_PATH}" exit 1 fi # Step 5: Clone component repo and checkout pinned commit (fetch SHA explicitly — shallow clone alone may miss it) git clone "${COMPONENT_URL}" "${REPO_DIR}" git -C "${REPO_DIR}" fetch origin "${PINNED_COMMIT}" git -C "${REPO_DIR}" checkout "${PINNED_COMMIT}" ``` **Jira branch → release branch naming for Pattern B:** | Jira `BRANCH` value | Release branch | |---|---| | `cert-manager-X-Y` | `release-X.Y` in `cert-manager-operator-release` | | `external-secrets-X-Y` | `release-X.Y` in `external-secrets-operator-release` | | `ztwim-1.0` | **`release-1.0.0`** in `zero-trust-workload-identity-manager-release` _(one-time exception — team confirmed this was a branching mistake; future releases use `release-X.Y`)_ | | `ztwim-X.Y` (any other) | `release-X.Y` in `zero-trust-workload-identity-manager-release` | > **Note:** Jira branch values use hyphens for separators (e.g. `external-secrets-1-0`) while release branches use dots (e.g. `release-1.0`). Strip the component prefix and convert the remaining hyphen-separated version to dot notation. --- ## Image → Repository Map > Every image name here has appeared in real ticket summaries or labels. This table is intentionally scoped to the components this command has been validated against — extend it as new components come up (see the not-found exit message above). ### cert-manager / jetstack — Pattern B (release repo + submodules) **Release repo:** `https://github.com/openshift/cert-manager-operator-release` **Submodules:** `cert-manager-operator`, `cert-manager`, `cert-manager-istio-csr` **Branch mapping:** Jira `cert-manager-X-Y` → `release-X.Y` in the release repo Clone the release repo at the correct branch, read `.gitmodules` to find the submodule URL and pinned ref for the target image, then clone that component at the pinned ref. | Image Name / Prefix | Submodule in `.gitmodules` | |---|---| | `cert-manager/cert-manager-operator-rhel9`, `cert-manager/cert-manager-operator-bundle`, `cert-manager-operator-*` | `cert-manager-operator` | | `cert-manager/cert-manager-istio-csr-rhel9` | `cert-manager-istio-csr` | | `cert-manager/jetstack-cert-manager-*`, `jetstack-cert-manager-*`, `redhat-user-workloads/jetstack-cert-manager-*` | `cert-manager` | #### cert-manager-operator (operator + bundle only) | Image Name / Prefix | GitHub Repository | |---|---| | `cert-manager-operator-container` | `https://github.com/openshift/cert-manager-operator` | | `cert-manager-operator-rhel9` | `https://github.com/openshift/cert-manager-operator` | | `cert-manager/cert-manager-operator-rhel9` | `https://github.com/openshift/cert-manager-operator` | | `cert-manager/cert-manager-operator-bundle` | `https://github.com/openshift/cert-manager-operator` | #### cert-manager-istio-csr | Image Name / Prefix | GitHub Repository | |---|---| | `cert-manager/cert-manager-istio-csr-rhel9` | `https://github.com/openshift/cert-manager-istio-csr` | #### jetstack-cert-manager | Image Name / Prefix | GitHub Repository | |---|---| | `cert-manager/jetstack-cert-manager-rhel9` | `https://github.com/openshift/jetstack-cert-manager` | | `cert-manager/jetstack-cert-manager-acmesolver-rhel9` | `https://github.com/openshift/jetstack-cert-manager` | | `jetstack-cert-manager-rhel9` | `https://github.com/openshift/jetstack-cert-manager` | | `jetstack-cert-manager-container` | `https://github.com/openshift/jetstack-cert-manager` | | `jetstack-cert-manager-acmesolver-rhel9` | `https://github.com/openshift/jetstack-cert-manager` | | `jetstack-cert-manager-acmesolver-container` | `https://github.com/openshift/jetstack-cert-manager` | | `redhat-user-workloads/jetstack-cert-manager-*` | `https://github.com/openshift/jetstack-cert-manager` | **Namespace prefix match:** `cert-manager` → requires full image name lookup above (multiple repos in this namespace). **Keyword match:** `cert-manager-operator` / `cert-manager-operator-bundle` → `cert-manager-operator`; `cert-manager-istio-csr` → `cert-manager-istio-csr`; `jetstack-cert-manager` → `jetstack-cert-manager`. --- ### Operator SDK / Helm Operator (non-ansible images) | Image Name / Prefix | GitHub Repository | |---|---| | `operator-sdk` | `https://github.com/openshift/ocp-release-operator-sdk` | | `openshift4/ose-operator-sdk-rhel8` | `https://github.com/openshift/ocp-release-operator-sdk` | | `openshift4/ose-operator-sdk-rhel9` | `https://github.com/openshift/ocp-release-operator-sdk` | | `openshift-enterprise-operator-sdk-container` | `https://github.com/openshift/ocp-release-operator-sdk` | | `openshift4/ose-helm-operator` | `https://github.com/openshift/ocp-release-operator-sdk` | | `openshift4/ose-helm-rhel9-operator` | `https://github.com/openshift/ocp-release-operator-sdk` | | `openshift-enterprise-helm-operator-container` | `https://github.com/openshift/ocp-release-operator-sdk` | | `pkg:oci/ose-operator-sdk-rhel8` | `https://github.com/openshift/ocp-release-operator-sdk` | | `pkg:oci/ose-operator-sdk-rhel9` | `https://github.com/openshift/ocp-release-operator-sdk` | | `pkg:oci/ose-helm-operator` | `https://github.com/openshift/ocp-release-operator-sdk` | | `pkg:oci/openshift-enterprise-helm-operator` | `https://github.com/openshift/ocp-release-operator-sdk` | --- ### Ansible Operator | Image Name / Prefix | GitHub Repository | |---|---| | `ansible-operator-plugins` | `https://github.com/openshift/ansible-operator-plugins` | | `openshift4/ose-ansible-operator` | `https://github.com/openshift/ansible-operator-plugins` | | `openshift4/ose-ansible-rhel9-operator` | `https://github.com/openshift/ansible-operator-plugins` | | `openshift-enterprise-ansible-operator-container` | `https://github.com/openshift/ansible-operator-plugins` | | `pkg:oci/ose-ansible-operator` | `https://github.com/openshift/ansible-operator-plugins` | | `pkg:oci/ose-ansible-rhel9-operator` | `https://github.com/openshift/ansible-operator-plugins` | **Keyword match:** any image containing `ansible-operator` → `https://github.com/openshift/ansible-operator-plugins` --- ### External Secrets Operator — Pattern B (release repo + submodules) **Release repo:** `https://github.com/openshift/external-secrets-operator-release` **Submodules:** `external-secrets-operator`, `external-secrets`, `bitwarden-sdk-server` **Branch mapping:** Jira `external-secrets-X-Y` → `release-X.Y` in the release repo Clone the release repo at the correct branch, read `.gitmodules` to find the submodule URL and pinned ref for the target image, then clone that component at the pinned ref. | Image Name / Prefix | Submodule in `.gitmodules` | |---|---| | `external-secrets-operator/external-secrets-operator-rhel9`, `external-secrets-operator/external-secrets-operator-bundle`, `redhat-user-workloads/external-secrets-operator-*` | `external-secrets-operator` | | `external-secrets-operator/external-secrets-rhel9`, `redhat-user-workloads/external-secrets-1-0` | `external-secrets` | | `external-secrets-operator/bitwarden-sdk-server-rhel9`, `redhat-user-workloads/bitwarden-sdk-server-*` | `bitwarden-sdk-server` | **Keyword match:** `external-secrets-operator` / `external-secrets-operator-bundle` → submodule `external-secrets-operator`; `bitwarden-sdk-server` → submodule `bitwarden-sdk-server`; `external-secrets-rhel9` / `external-secrets-1-0` → submodule `external-secrets`. --- ### Zero Trust / SPIFFE / SPIRE — Pattern B (release repo + submodules) **Release repo:** `https://github.com/openshift/zero-trust-workload-identity-manager-release` **Submodules:** `zero-trust-workload-identity-manager` (spire-operator), `spiffe-spire`, `spiffe-spire-controller-manager`, `spiffe-spiffe-csi` **Branch mapping:** Jira `ztwim-X.Y` → `release-X.Y` in the release repo Clone the release repo at the correct branch (`--recurse-submodules` is NOT needed — read `.gitmodules` manually and clone only the relevant submodule), then clone that component at the pinned ref. | Image Name / Prefix | Submodule in `.gitmodules` | |---|---| | `zero-trust-workload-identity-manager/zero-trust-workload-identity-manager-rhel9`, `*-operator-bundle` | `zero-trust-workload-identity-manager` | | `zero-trust-workload-identity-manager/spiffe-spire-agent-rhel9`, `*spiffe-spire-server*`, `*spire-oidc*`, `redhat-user-workloads/spiffe-spire-*` | `spiffe-spire` | | `zero-trust-workload-identity-manager/spiffe-spire-controller-manager-rhel9` | `spiffe-spire-controller-manager` | | `zero-trust-workload-identity-manager/spiffe-csi-driver-rhel9`, `redhat-user-workloads/spiffe-csi-driver-*` | `spiffe-spiffe-csi` | | `zero-trust-workload-identity-manager/spiffe-helper-rhel9` | `spiffe-spiffe-helper` | The `zero-trust-workload-identity-manager` namespace spans **four** repositories — match on the full image name, not just the namespace prefix. #### spire-operator (operator + bundle only) | Image Name / Prefix | GitHub Repository | |---|---| | `zero-trust-workload-identity-manager/zero-trust-workload-identity-manager-rhel9` | `https://github.com/openshift/spire-operator` | | `zero-trust-workload-identity-manager/zero-trust-workload-identity-manager-operator-bundle` | `https://github.com/openshift/spire-operator` | #### spiffe-spire (agent, server, OIDC discovery provider) | Image Name / Prefix | GitHub Repository | |---|---| | `zero-trust-workload-identity-manager/spiffe-spire-agent-rhel9` | `https://github.com/openshift/spiffe-spire` | | `zero-trust-workload-identity-manager/spiffe-spire-server-rhel9` | `https://github.com/openshift/spiffe-spire` | | `zero-trust-workload-identity-manager/spiffe-spire-oidc-discovery-provider-rhel9` | `https://github.com/openshift/spiffe-spire` | | `redhat-user-workloads/spiffe-spire-agent-*` | `https://github.com/openshift/spiffe-spire` | | `redhat-user-workloads/spiffe-spire-server-*` | `https://github.com/openshift/spiffe-spire` | | `redhat-user-workloads/spiffe-spire-oidc-discovery-provider-*` | `https://github.com/openshift/spiffe-spire` | #### spiffe-spire-controller-manager | Image Name / Prefix | GitHub Repository | |---|---| | `zero-trust-workload-identity-manager/spiffe-spire-controller-manager-rhel9` | `https://github.com/openshift/spiffe-spire-controller-manager` | #### spiffe-spiffe-csi (CSI driver) | Image Name / Prefix | GitHub Repository | |---|---| | `zero-trust-workload-identity-manager/spiffe-csi-driver-rhel9` | `https://github.com/openshift/spiffe-spiffe-csi` | | `redhat-user-workloads/spiffe-csi-driver-*` | `https://github.com/openshift/spiffe-spiffe-csi` | #### spiffe-spiffe-helper | Image Name / Prefix | GitHub Repository | |---|---| | `zero-trust-workload-identity-manager/spiffe-helper-rhel9` | `https://github.com/openshift/spiffe-spiffe-helper` | **Namespace prefix match:** `zero-trust-workload-identity-manager` → requires full image name lookup above (multiple repos in this namespace). **Keyword match:** `spire-agent` / `spire-server` / `spire-oidc` → `https://github.com/openshift/spiffe-spire`; `spire-controller-manager` → `https://github.com/openshift/spiffe-spire-controller-manager`; `spiffe-csi-driver` → `https://github.com/openshift/spiffe-spiffe-csi`; `spiffe-helper` → `https://github.com/openshift/spiffe-spiffe-helper`; `zero-trust-workload-identity-manager` (manager/bundle) → `https://github.com/openshift/spire-operator`. --- ### must-gather | Image Name / Prefix | GitHub Repository | |---|---| | `openshift4/ose-must-gather-rhel9` | `https://github.com/openshift/must-gather` | | `openshift4/ose-support-log-gather-rhel9-operator` | `https://github.com/openshift/must-gather-operator` | --- ### Secrets Store CSI The namespace spans **two** repositories. The mustgather image is built from the operator repo. #### secrets-store-csi-driver-operator (operator, bundle, mustgather) | Image Name / Prefix | GitHub Repository | |---|---| | `openshift4/ose-secrets-store-csi-driver-rhel9-operator` | `https://github.com/openshift/secrets-store-csi-driver-operator` | | `openshift4/ose-secrets-store-csi-driver-operator-bundle` | `https://github.com/openshift/secrets-store-csi-driver-operator` | | `ose-secrets-store-csi-driver-operator-container` | `https://github.com/openshift/secrets-store-csi-driver-operator` | | `openshift4/ose-secrets-store-csi-mustgather-rhel9` | `https://github.com/openshift/secrets-store-csi-driver-operator` | | `ose-secrets-store-csi-mustgather-container` | `https://github.com/openshift/secrets-store-csi-driver-operator` | #### secrets-store-csi-driver (driver only) | Image Name / Prefix | GitHub Repository | |---|---| | `openshift4/ose-secrets-store-csi-driver-rhel9` | `https://github.com/openshift/secrets-store-csi-driver` | | `ose-secrets-store-csi-driver-container` | `https://github.com/openshift/secrets-store-csi-driver` | **Keyword match:** `secrets-store-csi-mustgather` / `secrets-store-csi-driver-operator` / `secrets-store-csi-driver-operator-bundle` → `secrets-store-csi-driver-operator`; `secrets-store-csi-driver-rhel9` (driver image, not operator) → `secrets-store-csi-driver`. --- ## Return Value **Success:** ```json { "skill": "image-repo-mapping", "status": "success", "resolved_repos": [ { "image_name": "openshift4/ose-ansible-rhel9-operator", "repo_url": "https://github.com/openshift/ansible-operator-plugins", "clone_path": ".work/compliance/analyze-cve/repos/ansible-operator-plugins", "confidence": "exact_match", "match_method": "exact" } ], "unresolved": [], "resolution_method": "summary_image_name" } ``` **Not found (exit):** ```json { "skill": "image-repo-mapping", "status": "not_found", "image_name": "", "error": "No repository mapping found. Re-run with --repo=https://github.com/org/repo or add the mapping to image-repo-mapping/SKILL.md." } ``` `confidence`: `exact_match`, `prefix_match`, `keyword_match`, `user_provided` --- ## Integration with analyze-cve Called from **Phase 0.7** of the [analyze-cve](../analyze-cve/SKILL.md) skill. **Input:** image name extracted by `jira-cve-extraction` skill (from summary, `pscomponent:` label, or `Downstream Component Name` field), or the short name passed via `--repo=` **Output:** `(image_name, repo_url, clone_path)` tuple passed to Phase 0.7 for cloning