Skip to content

upstream: fix: Prevent 500 on invalid query input for robot accounts (goharbor/harbor#23670) #1099

upstream: fix: Prevent 500 on invalid query input for robot accounts (goharbor/harbor#23670)

upstream: fix: Prevent 500 on invalid query input for robot accounts (goharbor/harbor#23670) #1099

Workflow file for this run

name: PR Preview Images
on:
pull_request:
branches: [main, "release-[0-9]*.[0-9]*"]
# Allowlist: only build preview images when an input that actually reaches
# one of the images changes. Each entry below is consumed by a dockerfile
# COPY/build-arg or by the task build steps (gen-apis / build:binary).
# Anything not listed (docs, tests, 8gcr-ee patches, lint config, dev
# taskfiles, other workflows) cannot change an image, so it is skipped.
paths:
- "src/**" # Go components + portal sources
- "api/v2.0/swagger.yaml" # gen-apis (core) + portal API client
- "tools/swagger/templates/**" # gen-apis output templates
- "make/migrations/**" # baked into harbor-core
- "icons/**" # baked into harbor-core
- "config/portal/**" # portal nginx.conf
- "LICENSE" # baked into harbor-portal
- "VERSION" # ReleaseVersion ldflag baked into the Go binaries
- "dockerfile/**" # every image
- "versions.env" # build-args + registry/trivy/distribution pins
- "Taskfile.yml" # build orchestration root
- "taskfile/build.yml" # gen-apis + build:binary recipes
- ".github/workflows/pr-ci.yml" # this workflow
- ".github/actions/setup-go-cached/**" # Go build env used by the build jobs
- ".github/actions/setup-task/**" # Task install action used by the build jobs
permissions:
contents: read
concurrency:
group: pr-preview-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
env:
REGISTRY_ADDRESS: ${{ vars.REGISTRY_ADDRESS || '8gears.container-registry.com' }}
PR_REGISTRY_PROJECT: ${{ vars.PR_REGISTRY_PROJECT }}
PREVIEW_TAG: pr-${{ github.event.pull_request.number }}
jobs:
build:
name: "${{ matrix.component }} (${{ matrix.platform }})"
if: ${{ github.event.pull_request.head.repo.full_name == github.repository && github.actor != 'renovate[bot]' }}
strategy:
fail-fast: false
matrix:
component: [core, jobservice, registryctl, exporter, portal, registry, trivy-adapter]
platform:
- linux/amd64
- linux/arm64
runs-on: ${{ vars.RUNNER || 'ubuntu-latest' }}
permissions:
contents: read
steps:
- name: Prepare
id: prepare
run: |
platform=${{ matrix.platform }}
echo "PLATFORM_PAIR=${platform//\//-}" >> "$GITHUB_ENV"
if [ "${{ matrix.component }}" = "trivy-adapter" ]; then
echo "image_name=trivy-adapter" >> "$GITHUB_OUTPUT"
else
echo "image_name=harbor-${{ matrix.component }}" >> "$GITHUB_OUTPUT"
fi
# Surface pod env var for GitHub Actions expressions
if [ -n "$BUILDX_HOST" ]; then
echo "BUILDX_HOST=$BUILDX_HOST" >> "$GITHUB_ENV"
fi
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Load versions
run: grep -E '^[A-Z_]+=' versions.env >> "$GITHUB_ENV"
- name: Setup Go
uses: ./.github/actions/setup-go-cached
with:
go-version-file: src/go.mod
go-sum-path: src/go.sum
- name: Install Task
uses: ./.github/actions/setup-task
with:
version: 3.49.1
- name: Generate API code
if: ${{ contains(fromJSON('["core","jobservice","registryctl","exporter","registry","trivy-adapter"]'), matrix.component) }}
run: task build:gen-apis
- name: Compile Go binary
if: ${{ contains(fromJSON('["core","jobservice","registryctl","exporter","registry","trivy-adapter"]'), matrix.component) }}
env:
COMPONENT: ${{ matrix.component }}
PLATFORM_PAIR: ${{ env.PLATFORM_PAIR }}
run: task build:binary:${COMPONENT}:${PLATFORM_PAIR} GIT_COMMIT="${GITHUB_SHA:0:8}"
- name: Compile image helper binaries
env:
COMPONENT: ${{ matrix.component }}
PLATFORM_PAIR: ${{ env.PLATFORM_PAIR }}
run: |
task build:binary:lprobe:${PLATFORM_PAIR}
if [ "${COMPONENT}" = "trivy-adapter" ]; then
task build:binary:trivy:${PLATFORM_PAIR}
fi
- uses: docker/setup-qemu-action@96fe6ef7f33517b61c61be40b68a1882f3264fb8 # v4.2.0
if: env.BUILDX_HOST == ''
- uses: docker/setup-buildx-action@bb05f3f5519dd87d3ba754cc423b652a5edd6d2c # v4.2.0
with:
driver: ${{ env.BUILDX_HOST && 'remote' || '' }}
endpoint: ${{ env.BUILDX_HOST }}
- name: Log in to registry
uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4.6.0
with:
registry: ${{ env.REGISTRY_ADDRESS }}
username: ${{ vars.PR_REGISTRY_USERNAME }}
password: ${{ secrets.PR_REGISTRY_PASSWORD }}
- name: Build and push by digest
id: build
uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # v7.3.0
with:
context: .
file: dockerfile/${{ matrix.component }}.dockerfile
platforms: ${{ matrix.platform }}
build-args: |
ALPINE_VERSION=${{ env.ALPINE_VERSION }}
NGINX_VERSION=${{ env.NGINX_VERSION }}
BUN_VERSION=${{ env.BUN_VERSION }}
GO_VERSION=${{ env.GO_VERSION }}
DISTRIBUTION_VERSION=${{ env.DISTRIBUTION_VERSION }}
LPROBE_VERSION=${{ env.LPROBE_VERSION }}
TRIVY_BASE_IMAGE_VERSION=${{ env.TRIVY_BASE_IMAGE_VERSION }}
HARBOR_SCANNER_TRIVY_VERSION=${{ env.HARBOR_SCANNER_TRIVY_VERSION }}
tags: ${{ env.REGISTRY_ADDRESS }}/${{ env.PR_REGISTRY_PROJECT }}/${{ steps.prepare.outputs.image_name }}
outputs: type=image,push-by-digest=true,name-canonical=true,push=true
- name: Export digest
run: |
mkdir -p "${{ runner.temp }}/digests"
digest="${{ steps.build.outputs.digest }}"
touch "${{ runner.temp }}/digests/${digest#sha256:}"
- name: Upload digest
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: preview-digest-${{ matrix.component }}-${{ env.PLATFORM_PAIR }}
path: ${{ runner.temp }}/digests/*
if-no-files-found: error
retention-days: 1
merge:
name: "Merge ${{ matrix.component }}"
if: ${{ github.event.pull_request.head.repo.full_name == github.repository && github.actor != 'renovate[bot]' }}
needs: [build]
strategy:
fail-fast: false
matrix:
component: [core, jobservice, registryctl, exporter, portal, registry, trivy-adapter]
runs-on: ${{ vars.RUNNER || 'ubuntu-latest' }}
permissions:
contents: read
steps:
- name: Prepare BuildKit
id: prepare
run: |
if [ "${{ matrix.component }}" = "trivy-adapter" ]; then
echo "image_name=trivy-adapter" >> "$GITHUB_OUTPUT"
else
echo "image_name=harbor-${{ matrix.component }}" >> "$GITHUB_OUTPUT"
fi
if [ -n "$BUILDX_HOST" ]; then
echo "BUILDX_HOST=$BUILDX_HOST" >> "$GITHUB_ENV"
fi
- name: Download digests
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
path: ${{ runner.temp }}/digests
pattern: preview-digest-${{ matrix.component }}-*
merge-multiple: true
- name: Log in to registry
uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4.6.0
with:
registry: ${{ env.REGISTRY_ADDRESS }}
username: ${{ vars.PR_REGISTRY_USERNAME }}
password: ${{ secrets.PR_REGISTRY_PASSWORD }}
- uses: docker/setup-buildx-action@bb05f3f5519dd87d3ba754cc423b652a5edd6d2c # v4.2.0
with:
driver: ${{ env.BUILDX_HOST && 'remote' || '' }}
endpoint: ${{ env.BUILDX_HOST }}
- name: Create manifest list and push
working-directory: ${{ runner.temp }}/digests
env:
IMAGE: ${{ env.REGISTRY_ADDRESS }}/${{ env.PR_REGISTRY_PROJECT }}/${{ steps.prepare.outputs.image_name }}
run: |
# shellcheck disable=SC2046
docker buildx imagetools create \
-t "${IMAGE}:${PREVIEW_TAG}" \
$(printf "${IMAGE}@sha256:%s " *)
sign:
name: Sign preview images
if: ${{ github.event.pull_request.head.repo.full_name == github.repository && github.actor != 'renovate[bot]' }}
needs: [merge]
runs-on: ${{ vars.RUNNER || 'ubuntu-latest' }}
permissions:
contents: read
id-token: write
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Setup Go
uses: ./.github/actions/setup-go-cached
with:
go-version-file: src/go.mod
go-sum-path: src/go.sum
- name: Install crane
run: go install github.com/google/go-containerregistry/cmd/crane@v0.20.3
- name: Install envsubst
run: command -v envsubst || (sudo apt-get update && sudo apt-get install -y gettext-base)
- name: Install cosign
uses: sigstore/cosign-installer@6f9f17788090df1f26f669e9d70d6ae9567deba6 # v4.1.2
- name: Install syft
uses: anchore/sbom-action/download-syft@e22c389904149dbc22b58101806040fa8d37a610 # v0.24.0
- name: Log in to registry
uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4.6.0
with:
registry: ${{ env.REGISTRY_ADDRESS }}
username: ${{ vars.PR_REGISTRY_USERNAME }}
password: ${{ secrets.PR_REGISTRY_PASSWORD }}
- name: Sign images, generate SBOMs, and attest
run: |
for image in core jobservice registryctl exporter portal registry trivy-adapter; do
image_name="harbor-${image}"
if [ "${image}" = "trivy-adapter" ]; then
image_name="trivy-adapter"
fi
ref="${REGISTRY_ADDRESS}/${PR_REGISTRY_PROJECT}/${image_name}:${PREVIEW_TAG}"
digest="$(crane digest "${ref}")"
image_ref="${REGISTRY_ADDRESS}/${PR_REGISTRY_PROJECT}/${image_name}@${digest}"
cosign sign --yes "${image_ref}"
syft "${image_ref}" -o spdx-json > "sbom-${image}.spdx.json"
cosign attest --yes --predicate "sbom-${image}.spdx.json" --type spdxjson "${image_ref}"
done
pr-comment:
name: Comment preview image refs
if: ${{ github.event.pull_request.head.repo.full_name == github.repository && github.actor != 'renovate[bot]' }}
needs: [sign]
runs-on: ${{ vars.RUNNER || 'ubuntu-latest' }}
permissions:
issues: write
pull-requests: write
steps:
- name: Install gh CLI
run: |
if ! command -v gh &>/dev/null; then
curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg \
| sudo dd of=/usr/share/keyrings/githubcli-archive-keyring.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" \
| sudo tee /etc/apt/sources.list.d/github-cli.list > /dev/null
sudo apt-get update && sudo apt-get install -y gh
fi
- name: Create or update PR comment
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
env:
MARKER: "<!-- harbor-next-pr-preview -->"
with:
script: |
const marker = process.env.MARKER;
const registryAddress = process.env.REGISTRY_ADDRESS;
const registryProject = process.env.PR_REGISTRY_PROJECT;
const previewTag = process.env.PREVIEW_TAG;
const repository = process.env.GITHUB_REPOSITORY;
const issueNumber = context.payload.pull_request.number;
const owner = context.repo.owner;
const repo = context.repo.repo;
const body = `${marker}
Preview images for this PR are available in \`${registryAddress}/${registryProject}\` with tag \`${previewTag}\`.
- \`${registryAddress}/${registryProject}/harbor-core:${previewTag}\`
- \`${registryAddress}/${registryProject}/harbor-jobservice:${previewTag}\`
- \`${registryAddress}/${registryProject}/harbor-registryctl:${previewTag}\`
- \`${registryAddress}/${registryProject}/harbor-exporter:${previewTag}\`
- \`${registryAddress}/${registryProject}/harbor-portal:${previewTag}\`
- \`${registryAddress}/${registryProject}/harbor-registry:${previewTag}\`
- \`${registryAddress}/${registryProject}/trivy-adapter:${previewTag}\`
Verify a preview image:
\`\`\`
cosign verify \\
--certificate-identity-regexp="https://github.com/${repository}/.github/workflows/pr-ci.yml@.*" \\
--certificate-oidc-issuer="https://token.actions.githubusercontent.com" \\
${registryAddress}/${registryProject}/harbor-core:${previewTag}
\`\`\`
Verify SBOM attestation:
\`\`\`
cosign verify-attestation \\
--certificate-identity-regexp="https://github.com/${repository}/.github/workflows/pr-ci.yml@.*" \\
--certificate-oidc-issuer="https://token.actions.githubusercontent.com" \\
--type spdxjson \\
${registryAddress}/${registryProject}/harbor-core:${previewTag}
\`\`\``;
const comments = await github.paginate(github.rest.issues.listComments, {
owner,
repo,
issue_number: issueNumber,
per_page: 100,
});
const existingComment = comments.find(comment =>
comment.user?.login === 'github-actions[bot]' &&
comment.body?.startsWith(marker)
);
if (existingComment) {
await github.rest.issues.updateComment({
owner,
repo,
comment_id: existingComment.id,
body,
});
return;
}
await github.rest.issues.createComment({
owner,
repo,
issue_number: issueNumber,
body,
});