Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,31 @@ build_root:
from_repository: true
images:
items:
- dockerfile_literal: |-
FROM registry.access.redhat.com/ubi9/go-toolset
USER 0
RUN dnf install -y git make jq && \
dnf install -y 'dnf-command(config-manager)' && \
dnf config-manager --add-repo https://cli.github.com/packages/rpm/gh-cli.repo && \
dnf install -y gh && \
dnf clean all
RUN dnf module enable -y nodejs:20 && \
dnf install -y nodejs npm && \
npm install -g @anthropic-ai/claude-code && \
dnf clean all
WORKDIR /app
RUN git clone --depth 1 -b main https://github.com/openshift-eng/oape-ai-e2e.git /tmp/oape && \
cp -r /tmp/oape/scripts /app/scripts && \
cp -r /tmp/oape/plugins /plugins && \
mkdir -p /config && cp -r /tmp/oape/deploy/config/* /config/ && \
rm -rf /tmp/oape
RUN go install golang.org/x/tools/cmd/goimports@v0.33.0 && \
curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/v2.1.6/install.sh | sh -s -- -b /usr/local/bin v2.1.6

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

FILE='ci-operator/config/openshift/must-gather-operator/openshift-must-gather-operator-master.yaml'

echo "== file exists =="
git ls-files "$FILE"

echo
echo "== size =="
wc -l "$FILE"

echo
echo "== relevant excerpt =="
sed -n '1,120p' "$FILE"

Repository: openshift/release

Length of output: 3977


Pin the agent image’s external inputs
ci-operator/config/openshift/must-gather-operator/openshift-must-gather-operator-master.yaml:23-34 still pulls executable code from mutable network locations: @anthropic-ai/claude-code without a version, oape-ai-e2e from main, and the golangci-lint installer script via curl. Since this image later runs with GitHub/GCP credentials, lock these to immutable versions/SHAs and avoid piping the installer straight from the network.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@ci-operator/config/openshift/must-gather-operator/openshift-must-gather-operator-master.yaml`
around lines 23 - 34, The image build is still consuming mutable external
inputs, so update the RUN steps that install `@anthropic-ai/claude-code`, clone
oape-ai-e2e, and fetch golangci-lint to use immutable pinned versions or commit
SHAs instead of latest/main. Replace the network-piped golangci-lint installer
flow with a safer, pinned install method, and keep the build reproducible by
locking every remote dependency referenced in the Dockerfile snippet.

RUN git config --global user.name "openshift-app-platform-shift-bot" && \
git config --global user.email "267347085+openshift-app-platform-shift-bot@users.noreply.github.com"
RUN chmod -R g=u /opt/app-root/src
USER 1001
to: review-handler-agent
- dockerfile_path: Dockerfile.openshift
from: base-rhel9
to: must-gather-operator
Expand All @@ -28,7 +53,9 @@ operator:
with: stable:must-gather
promotion:
to:
- name: "5.0"
- excluded_images:
- review-handler-agent
name: "5.0"
namespace: ocp
releases:
initial:
Expand Down Expand Up @@ -197,6 +224,99 @@ tests:
requests:
cpu: 100m
workflow: optional-operators-ci-operator-sdk-gcp
- always_run: false
as: oape-review-handler
optional: true
steps:
test:
- as: review
commands: |
set -euo pipefail

echo "[setup] Starting oape-review-handler for ${REPO_OWNER}/${REPO_NAME} PR#${PULL_NUMBER}"

# --- Rehearsal detection ---
if [[ "${REPO_NAME}" == "release" && "${REPO_OWNER}" == "openshift" ]]; then
echo "[setup] Detected openshift/release context — switching to test target"
export REPO_OWNER="openshift"
export REPO_NAME="must-gather-operator"
TEST_PR=$(curl -s "https://api.github.com/repos/${REPO_OWNER}/${REPO_NAME}/pulls?state=open&per_page=1" \
| python3 -c "import sys,json; data=json.load(sys.stdin); print(data[0]['number'] if data else '')" 2>/dev/null || echo "")
if [[ -z "$TEST_PR" ]]; then
echo "[setup] No open PRs found — skipping"
exit 0
fi
export PULL_NUMBER="$TEST_PR"
echo "[setup] Testing against ${REPO_OWNER}/${REPO_NAME}#${PULL_NUMBER}"
fi

# --- GitHub auth: App token with GITHUB_TOKEN fallback ---
USE_APP_TOKEN="false"
if [[ -f /var/run/github-app/app-id && -f /var/run/github-app/private-key.pem ]]; then
echo "[auth] Attempting GitHub App token..."
APP_ID=$(cat /var/run/github-app/app-id)
PEM_PATH="/var/run/github-app/private-key.pem"
HEADER=$(printf '{"alg":"RS256","typ":"JWT"}' | openssl base64 -e -A | tr '+/' '-_' | tr -d '=')
NOW=$(date +%s); EXP=$((NOW + 300))
PAYLOAD=$(printf '{"iat":%d,"exp":%d,"iss":"%s"}' "$NOW" "$EXP" "$APP_ID" | openssl base64 -e -A | tr '+/' '-_' | tr -d '=')
SIGNATURE=$(printf '%s' "${HEADER}.${PAYLOAD}" | openssl dgst -sha256 -sign "$PEM_PATH" -binary | openssl base64 -e -A | tr '+/' '-_' | tr -d '=')
JWT="${HEADER}.${PAYLOAD}.${SIGNATURE}"
INSTALL_RESPONSE=$(curl -s -w "\n%{http_code}" -H "Authorization: Bearer ${JWT}" -H "Accept: application/vnd.github+json" \
"https://api.github.com/repos/${REPO_OWNER}/${REPO_NAME}/installation")
HTTP_CODE=$(echo "$INSTALL_RESPONSE" | tail -1)
INSTALL_BODY=$(echo "$INSTALL_RESPONSE" | sed '$d')
if [[ "$HTTP_CODE" -eq 200 ]]; then
INST_ID=$(echo "$INSTALL_BODY" | python3 -c "import sys,json; print(json.load(sys.stdin)['id'])")
TOKEN_RESPONSE=$(curl -s -w "\n%{http_code}" -X POST -H "Authorization: Bearer ${JWT}" -H "Accept: application/vnd.github+json" \
"https://api.github.com/app/installations/${INST_ID}/access_tokens")
T_CODE=$(echo "$TOKEN_RESPONSE" | tail -1)
T_BODY=$(echo "$TOKEN_RESPONSE" | sed '$d')
if [[ "$T_CODE" -eq 201 ]]; then
export GH_TOKEN=$(echo "$T_BODY" | python3 -c "import sys,json; print(json.load(sys.stdin)['token'])")
USE_APP_TOKEN="true"
echo "[auth] GitHub App token generated successfully"
else
echo "[auth] WARN: App token creation failed (HTTP ${T_CODE}), falling back to GITHUB_TOKEN"
fi
else
echo "[auth] WARN: App not installed on ${REPO_OWNER}/${REPO_NAME} (HTTP ${HTTP_CODE}), falling back to GITHUB_TOKEN"
fi
else
echo "[auth] GitHub App credentials not mounted, using GITHUB_TOKEN"
fi
if [[ "$USE_APP_TOKEN" != "true" ]]; then
if [[ -z "${GH_TOKEN:-}" && -z "${GITHUB_TOKEN:-}" ]]; then
echo "[auth] ERROR: No GitHub token available" >&2
exit 1
fi
export GH_TOKEN="${GH_TOKEN:-${GITHUB_TOKEN}}"
fi

# --- GCP auth for Claude (Vertex AI) ---
export GOOGLE_APPLICATION_CREDENTIALS="/var/run/gcloud-adc/application_default_credentials.json"
export CLAUDE_CODE_USE_VERTEX="1"
export CLOUD_ML_REGION="global"
export ANTHROPIC_VERTEX_PROJECT_ID="itpc-gcp-hcm-pe-eng-claude"

# --- Run review handler ---
export PR_URL="https://github.com/${REPO_OWNER}/${REPO_NAME}/pull/${PULL_NUMBER}"
export PLUGINS_DIR="/plugins/oape/skills"

gh auth setup-git
/app/scripts/pr-agent/review-handler.sh --pr-url "$PR_URL"
credentials:
- mount_path: /var/run/gcloud-adc
name: oap-lts-claude-gcp-vertex-sa
namespace: test-credentials
- mount_path: /var/run/github-app
name: openshift-app-platform-shift-github-bot
namespace: test-credentials
from: review-handler-agent
resources:
requests:
cpu: "1"
memory: 500Mi
timeout: 1h0m0s
zz_generated_metadata:
branch: master
org: openshift
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -508,6 +508,89 @@ presubmits:
secret:
secretName: result-aggregator
trigger: (?m)^/test( | .* )lint,?($|\s.*)
- agent: kubernetes
always_run: false
branches:
- ^master$
- ^master-
cluster: build12
context: ci/prow/oape-review-handler
decorate: true
decoration_config:
sparse_checkout_files:
- .ci-operator.yaml
- Dockerfile.openshift
labels:
ci.openshift.io/generator: prowgen
pj-rehearse.openshift.io/can-be-rehearsed: "true"
name: pull-ci-openshift-must-gather-operator-master-oape-review-handler
optional: true
rerun_command: /test oape-review-handler
spec:
containers:
- args:
- --gcs-upload-secret=/secrets/gcs/service-account.json
- --image-import-pull-secret=/etc/pull-secret/.dockerconfigjson
- --lease-server-credentials-file=/etc/boskos/credentials
- --report-credentials-file=/etc/report/credentials
- --secret-dir=/secrets/ci-pull-credentials
- --target=oape-review-handler
command:
- ci-operator
env:
- name: HTTP_SERVER_IP
valueFrom:
fieldRef:
fieldPath: status.podIP
image: quay-proxy.ci.openshift.org/openshift/ci:ci_ci-operator_latest
imagePullPolicy: Always
name: ""
ports:
- containerPort: 8080
name: http
resources:
requests:
cpu: 10m
volumeMounts:
- mountPath: /etc/boskos
name: boskos
readOnly: true
- mountPath: /secrets/ci-pull-credentials
name: ci-pull-credentials
readOnly: true
- mountPath: /secrets/gcs
name: gcs-credentials
readOnly: true
- mountPath: /secrets/manifest-tool
name: manifest-tool-local-pusher
readOnly: true
- mountPath: /etc/pull-secret
name: pull-secret
readOnly: true
- mountPath: /etc/report
name: result-aggregator
readOnly: true
serviceAccountName: ci-operator
volumes:
- name: boskos
secret:
items:
- key: credentials
path: credentials
secretName: boskos-credentials
- name: ci-pull-credentials
secret:
secretName: ci-pull-credentials
- name: manifest-tool-local-pusher
secret:
secretName: manifest-tool-local-pusher
- name: pull-secret
secret:
secretName: registry-pull-credentials
- name: result-aggregator
secret:
secretName: result-aggregator
trigger: (?m)^/test( | .* )oape-review-handler,?($|\s.*)
- agent: kubernetes
always_run: false
branches:
Expand Down