Integrate BIMP with your image ingestion and approval pipeline so that every newly approved image becomes an image mapping automatically.
You can update internal mappings with the BIMP API or manage an external
bimp-mappings.json file in source control. Choose one source of truth for each
policy phase. BIMP does not allow API edits to mappings managed by an external
source.
For guidance on structuring Policy Groups and phases, see Policy Management.
Contents
Section titled “Contents”- Before you begin
- Update mappings with the BIMP API
- Integrate API updates into CI/CD
- Continuously update an external mapping file
Before you begin
Section titled “Before you begin”Define the information your ingestion pipeline will provide for every approved image:
- the existing image reference used as the From image;
- the newly approved, exact Target image reference;
- the reason for the update;
- any operating system and architecture scope; and
- the Policy Groups and phases that should receive the mapping.
Targets must be exact image references. Validate the image, tag, digest, and platform compatibility before updating BIMP.
Update mappings with the BIMP API
Section titled “Update mappings with the BIMP API”Use this approach when BIMP owns the mappings and your ingestion pipeline should publish each update without a separate BIMP review.
Prepare API access
Section titled “Prepare API access”Create an API key with permission to read Policy Groups and phases, write image mappings, and publish policy. See Access the BIMP API for setup and secret-handling guidance.
Set the values used by the examples:
export BIMP_API_URL="https://<your-bimp-host>"export BIMP_ORGANIZATION_ID="<organization-id>"export BIMP_FROM_IMAGE="registry.example.com/python:3.12.1"export BIMP_TARGET_IMAGE="registry.example.com/python:3.12.2"export BIMP_MAPPING_REASON="Approved by the image ingestion pipeline"# Load BIMP_API_KEY from your secret manager.Do not store the API key in the pipeline definition, source repository, or build log.
Identify the impacted Policy Groups
Section titled “Identify the impacted Policy Groups”List the organization’s Policy Groups:
curl --fail-with-body --silent --show-error \ --header "x-api-key: $BIMP_API_KEY" \ --header "accept: application/json" \ "$BIMP_API_URL/api/v1/org/$BIMP_ORGANIZATION_ID/policy-groups" \ | jq '.items[] | {id, name, applyToAllRepos}'Inspect a Policy Group to find its phases, source types, and published mappings:
export BIMP_POLICY_GROUP_ID="<policy-group-id>"
curl --fail-with-body --silent --show-error \ --header "x-api-key: $BIMP_API_KEY" \ --header "accept: application/json" \ "$BIMP_API_URL/api/v1/org/$BIMP_ORGANIZATION_ID/policy-groups/"\"$BIMP_POLICY_GROUP_ID/details" \ | jq '{phases, publishedMappings}'Select every Policy Group whose published policy uses the previous approved image and record the internal phase that owns incremental updates. Keep this destination list in pipeline configuration so an image is not added to an unrelated Policy Group. External phases cannot be edited with the mappings API.
The examples below use a JSON destination list:
export BIMP_POLICY_DESTINATIONS='[ {"groupId":"<first-policy-group-id>","phaseId":"<first-phase-id>"}, {"groupId":"<second-policy-group-id>","phaseId":"<second-phase-id>"}]'Integrate API updates into CI/CD
Section titled “Integrate API updates into CI/CD”Update one Policy Group
Section titled “Update one Policy Group”Use the following request to add the mapping to one internal policy phase. The
same command can run in GitHub Actions or another CI/CD system after its secret
manager exposes BIMP_API_KEY to the job:
export BIMP_POLICY_GROUP_ID="<policy-group-id>"export BIMP_POLICY_PHASE_ID="<policy-phase-id>"
curl --fail-with-body --silent --show-error \ --request POST \ --header "x-api-key: $BIMP_API_KEY" \ --header "accept: application/json" \ --header "content-type: application/json" \ --data "$( jq -n \ --arg fromImage "$BIMP_FROM_IMAGE" \ --arg toImage "$BIMP_TARGET_IMAGE" \ --arg reason "$BIMP_MAPPING_REASON" \ '{fromImage: $fromImage, toImage: $toImage, reason: $reason}' )" \ "$BIMP_API_URL/api/v1/org/$BIMP_ORGANIZATION_ID/policy-groups/"\"$BIMP_POLICY_GROUP_ID/phases/$BIMP_POLICY_PHASE_ID/mappings"The request creates a draft mapping. Publish the updated Policy Group with a second request:
curl --fail-with-body --silent --show-error \ --request POST \ --header "x-api-key: $BIMP_API_KEY" \ --header "accept: application/json" \ "$BIMP_API_URL/api/v1/org/$BIMP_ORGANIZATION_ID/policy-groups/"\"$BIMP_POLICY_GROUP_ID/publish"Configure the GitHub Actions job to fail when either command exits with an
error. The --fail-with-body option returns a failing exit code while retaining
the BIMP error response for troubleshooting.
Update every impacted Policy Group
Section titled “Update every impacted Policy Group”For each destination, post the mapping to the phase and then publish its Policy Group:
printf '%s' "$BIMP_POLICY_DESTINATIONS" | jq -c '.[]' |while IFS= read -r destination; do group_id="$(printf '%s' "$destination" | jq -r '.groupId')" phase_id="$(printf '%s' "$destination" | jq -r '.phaseId')"
jq -n \ --arg fromImage "$BIMP_FROM_IMAGE" \ --arg toImage "$BIMP_TARGET_IMAGE" \ --arg reason "$BIMP_MAPPING_REASON" \ '{fromImage: $fromImage, toImage: $toImage, reason: $reason}' | curl --fail-with-body --silent --show-error \ --request POST \ --header "x-api-key: $BIMP_API_KEY" \ --header "accept: application/json" \ --header "content-type: application/json" \ --data-binary @- \ "$BIMP_API_URL/api/v1/org/$BIMP_ORGANIZATION_ID/policy-groups/"\"$group_id/phases/$phase_id/mappings"
curl --fail-with-body --silent --show-error \ --request POST \ --header "x-api-key: $BIMP_API_KEY" \ --header "accept: application/json" \ "$BIMP_API_URL/api/v1/org/$BIMP_ORGANIZATION_ID/policy-groups/"\"$group_id/publish"donePublishing makes the complete Policy Group draft live, not only the mapping created by this run. Ensure the group has no unrelated draft changes before the pipeline publishes it.
The API updates one Policy Group at a time. A failure can leave earlier groups published and later groups unchanged. Make the pipeline safe to retry by checking the phase’s draft mappings before creating a mapping. If the same From image and platform already exist, verify or update that mapping instead of creating a duplicate.
The publish endpoint does not immediately open remediation pull or merge requests. Repositories follow their normal remediation routines.
Continuously update an external mapping file
Section titled “Continuously update an external mapping file”Use this approach when source control and your existing approval workflow should own the mapping set.
Create an external policy phase and connect it to a bimp-mappings.json file
on a branch that BIMP can access. Once the external source is active, changes
merged into the configured branch are synchronized into published policy
automatically. The pipeline does not need to call the BIMP publish API for each
file update.
The file must contain an object with a mappings array:
{ "mappings": [ { "fromImage": "registry.example.com/python:3.12.1", "toImage": "registry.example.com/python:3.12.2", "reason": "Approved by the image ingestion pipeline" }, { "fromImage": "registry.example.com/node:22.1.0", "toImage": "registry.example.com/node:22.2.0", "platformScope": "linux/amd64", "reason": "Approved Node.js image" } ]}Each mapping requires fromImage and toImage. reason, platformScope,
mappingContext, applicableDateTime, bypassCooldown, and order are
optional. Targets must be exact; From image values can use supported
wildcards.
BIMP treats the file as the complete source for that phase. Every pipeline run must preserve existing mappings and add or update the relevant entry. Do not replace the file with only the newest mapping, because mappings omitted from a subsequent version are removed from that phase.
Upsert a mapping safely
Section titled “Upsert a mapping safely”After approving an image, check out the branch that contains
bimp-mappings.json. Pass the previous image, approved image, reason, and
optional platform scope to the job as environment variables:
export BIMP_FROM_IMAGE="registry.example.com/python:3.12.1"export BIMP_TARGET_IMAGE="registry.example.com/python:3.12.2"export BIMP_MAPPING_REASON="Approved by the image ingestion pipeline"export BIMP_PLATFORM_SCOPE=""Use jq to update the matching entry or append it when it does not exist. A
mapping is identified by its From image and platform scope:
mapping_file="bimp-mappings.json"updated_file="$(mktemp)"
jq \ --arg fromImage "$BIMP_FROM_IMAGE" \ --arg toImage "$BIMP_TARGET_IMAGE" \ --arg reason "$BIMP_MAPPING_REASON" \ --arg platformScope "${BIMP_PLATFORM_SCOPE:-}" \ ' .mappings = ( if any( .mappings[]; .fromImage == $fromImage and (.platformScope // "") == $platformScope ) then [ .mappings[] | if .fromImage == $fromImage and (.platformScope // "") == $platformScope then . + {toImage: $toImage, reason: $reason} else . end ] else .mappings + [ {fromImage: $fromImage, toImage: $toImage, reason: $reason} + if $platformScope == "" then {} else {platformScope: $platformScope} end ] end ) ' "$mapping_file" > "$updated_file"
jq -e '.mappings | type == "array"' "$updated_file" > /dev/nullmv "$updated_file" "$mapping_file"This preserves unrelated mappings and makes repeated runs with the same source
and platform update the existing entry instead of adding a duplicate. Run the
commands with set -euo pipefail so the job stops before committing when the
file is missing, invalid, or cannot be updated.
Example GitHub Actions workflow
Section titled “Example GitHub Actions workflow”The following workflow accepts an approved image update, modifies
bimp-mappings.json, and opens a pull request against main. Adapt the trigger
and branch name to match your ingestion pipeline:
name: Update BIMP image mappings
on: workflow_dispatch: inputs: from_image: description: Current approved image reference required: true type: string target_image: description: New approved image reference required: true type: string reason: description: Reason for the update required: true type: string platform_scope: description: Optional platform, such as linux/amd64 required: false type: string
permissions: contents: write pull-requests: write
jobs: update-policy: runs-on: ubuntu-latest env: BIMP_FROM_IMAGE: ${{ inputs.from_image }} BIMP_TARGET_IMAGE: ${{ inputs.target_image }} BIMP_MAPPING_REASON: ${{ inputs.reason }} BIMP_PLATFORM_SCOPE: ${{ inputs.platform_scope }} steps: - name: Check out the policy repository uses: actions/checkout@v6 with: ref: main
- name: Update the mapping file shell: bash run: | set -euo pipefail mapping_file="bimp-mappings.json" updated_file="$(mktemp)"
jq \ --arg fromImage "$BIMP_FROM_IMAGE" \ --arg toImage "$BIMP_TARGET_IMAGE" \ --arg reason "$BIMP_MAPPING_REASON" \ --arg platformScope "${BIMP_PLATFORM_SCOPE:-}" \ ' .mappings = ( if any( .mappings[]; .fromImage == $fromImage and (.platformScope // "") == $platformScope ) then [ .mappings[] | if .fromImage == $fromImage and (.platformScope // "") == $platformScope then . + {toImage: $toImage, reason: $reason} else . end ] else .mappings + [ { fromImage: $fromImage, toImage: $toImage, reason: $reason } + if $platformScope == "" then {} else {platformScope: $platformScope} end ] end ) ' "$mapping_file" > "$updated_file"
jq -e '.mappings | type == "array"' "$updated_file" > /dev/null mv "$updated_file" "$mapping_file"
- name: Open a pull request shell: bash env: GH_TOKEN: ${{ github.token }} run: | set -euo pipefail branch="bimp/image-update-${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}"
git config user.name "github-actions[bot]" git config user.email \ "41898282+github-actions[bot]@users.noreply.github.com" git switch -c "$branch" git add bimp-mappings.json
if git diff --cached --quiet; then echo "The mapping is already current." exit 0 fi
git commit -m "Update approved image mapping" git push --set-upstream origin "$branch" gh pr create \ --base main \ --head "$branch" \ --title "Update approved image mapping" \ --body "Updates bimp-mappings.json from the image ingestion pipeline."GitHub documents the GITHUB_TOKEN permission
model, the
official actions/checkout action, and
the gh pr create command.
The repository or organization must allow GitHub Actions to create pull
requests. If the workflow updates a different private repository, the built-in
GITHUB_TOKEN is not sufficient because it is scoped to the repository that
contains the workflow. Use a narrowly scoped GitHub App installation token or
another organization-approved credential in that case. See GitHub’s guidance
for authenticating workflows.
Merge and synchronize the update
Section titled “Merge and synchronize the update”The complete automation flow is:
- validate and approve the new image;
- read the current
bimp-mappings.jsonfrom the configured branch; - add or update the mapping without removing unrelated entries;
- validate the resulting JSON and ensure each target is exact;
- commit the change directly or open a pull or merge request; and
- merge the change into the branch monitored by BIMP.
Use a pull or merge request when policy changes require human approval. Commit directly only when the ingestion pipeline already provides the required approval controls.
After the change is merged, check the external phase in BIMP to confirm the latest synchronization succeeded. Organization or Policy Group cooldown settings may delay when an automatically synchronized update becomes active.