Open
Description
Discussed in https://github.com/orgs/open-policy-agent/discussions/666
Originally posted by zscott March 1, 2025
❗ When this makes it into a CHANGELOG, let's ensure to attribute it to @zscott, not me!
Problem
I build and push OCI bundles to ghcr.io using github actions but when I try to pull the bundle into opa I get "Bundle load failed: no layers in manifest". I'm probably doing something silly, but I've been banging my head on this for a while now.
❯ opa run --server --config-file=opa-config.yaml
{"addrs":["localhost:8181"],"diagnostic-addrs":[],"level":"info","msg":"Initializing server.","time":"2025-03-01T05:52:24-06:00"}
{"level":"info","msg":"Starting bundle loader.","name":"trust-framework","plugin":"bundle","time":"2025-03-01T05:52:24-06:00"}
{"level":"error","msg":"Bundle load failed: no layers in manifest","name":"trust-framework","plugin":"bundle","time":"2025-03-01T05:52:24-06:00"}
{"level":"error","msg":"Bundle load failed: no layers in manifest","name":"trust-framework","plugin":"bundle","time":"2025-03-01T05:52:25-06:00"}
{"level":"error","msg":"Bundle load failed: no layers in manifest","name":"trust-framework","plugin":"bundle","time":"2025-03-01T05:52:25-06:00"}
{"level":"error","msg":"Bundle load failed: no layers in manifest","name":"trust-framework","plugin":"bundle","time":"2025-03-01T05:52:26-06:00"}
{"level":"error","msg":"Bundle load failed: no layers in manifest","name":"trust-framework","plugin":"bundle","time":"2025-03-01T05:52:27-06:00"}
^C{"level":"info","msg":"Shutting down...","time":"2025-03-01T05:52:27-06:00"}
opa-config.yaml
services:
ghcr:
url: https://ghcr.io
type: oci
credentials:
bearer:
token: "${GHCR_TOKEN}"
bundles:
trust-framework:
service: ghcr
resource: ghcr.io/<org>/<image>:sha-1ebe12f
persist: false
polling:
min_delay_seconds: 60
max_delay_seconds: 120
When I examine the image with dive it only has a single layer.
Build steps (full github workflow below):
make bundle
echo '{}' > config.json
oras push ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ env.VERSION }} \
--config config.json:application/vnd.oci.image.config.v1+json \
bundle/bundle.tar.gz:application/vnd.oci.image.layer.v1.tar+gzip
Versions
❯ opa version
Version: 1.2.0
Build Commit: d537788
Build Timestamp: 2025-02-28T14:17:35Z
Build Hostname:
Go Version: go1.24.0
Platform: darwin/arm64
Rego Version: v1
WebAssembly: unavailable
❯ oras version
Version: 1.2.2+Homebrew
Go version: go1.23.4
Makefile
.PHONY: build test run clean
# Variables
BUNDLE_DIR := bundle
BUNDLE_FILE := bundle.tar.gz
BUILD_HASH := $(shell git rev-parse HEAD)
bundle:
@mkdir -p $(BUNDLE_DIR)
@opa build --bundle --revision $(BUILD_HASH) -o $(BUNDLE_DIR)/$(BUNDLE_FILE) ./src
test:
@opa test ./src
run: build
@./scripts/run-server.sh
clean:
@rm -rf $(BUNDLE_DIR)
github workflow
name: Build and Deploy
on:
push:
branches: [ "main" ]
tags: [ 'v*' ]
pull_request:
branches: [ "main" ]
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
jobs:
build:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- name: Checkout repository
uses: actions/checkout@v3
- name: Install OPA
run: |
curl -L -o opa https://openpolicyagent.org/downloads/v1.2.0/opa_linux_amd64_static
chmod +x opa
sudo mv opa /usr/local/bin/
- name: Install ORAS
run: |
VERSION="1.2.0"
curl -LO "https://github.com/oras-project/oras/releases/download/v${VERSION}/oras_${VERSION}_linux_amd64.tar.gz"
mkdir -p oras-install/
tar -zxf oras_${VERSION}_*.tar.gz -C oras-install/
sudo mv oras-install/oras /usr/local/bin/
rm -rf oras_${VERSION}_*.tar.gz oras-install/
- name: Log in to the Container registry
if: github.event_name != 'pull_request'
uses: docker/login-action@v2
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build bundle
run: make bundle
- name: Push bundle to container registry
if: github.event_name != 'pull_request'
run: |
# Create a simple config file for the OCI image
echo '{}' > config.json
# Push the bundle to the container registry with proper media types that OPA expects
oras push ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ env.VERSION }} \
--config config.json:application/vnd.oci.image.config.v1+json \
bundle/bundle.tar.gz:application/vnd.oci.image.layer.v1.tar+gzip
- name: Extract metadata
id: meta
uses: docker/metadata-action@v4
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=semver,pattern={{version}}
type=ref,event=branch
type=sha,format=short
- name: Create artifact version from git
id: version
run: |
if [[ $GITHUB_REF == refs/tags/v* ]]; then
VERSION=${GITHUB_REF#refs/tags/v}
else
VERSION="latest"
fi
echo "VERSION=$VERSION" >> $GITHUB_ENV
- name: Set up QEMU
uses: docker/setup-qemu-action@v2
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Build and push Docker image
if: github.event_name != 'pull_request'
uses: docker/build-push-action@v4
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
file: .github/workflows/Dockerfile
platforms: linux/amd64,linux/arm64
```</div>