Skip to content
Open
Changes from all commits
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
208 changes: 208 additions & 0 deletions .tekton/integration-tests/pipelines/bundle-update-pipeline.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,208 @@
---
apiVersion: tekton.dev/v1beta1
kind: Pipeline
metadata:
name: bundle-update-integration-test
spec:
description: |
Integration test pipeline that updates the bundle related images from a Konflux snapshot.
Parses the SNAPSHOT JSON to extract component images, updates related_images.json,
regenerates the bundle, and creates a pull request against the source repository.
params:
- name: SNAPSHOT
type: string
description: 'The JSON string representing the snapshot of the application under test.'
default: '{"components": [{"name":"test-app", "containerImage": "quay.io/example/repo:latest"}]}'
- name: forkGitUrl
type: string
description: The git repository URL where the updated code is committed to.
default: "https://github.com/raptorsun/lightspeed-operator.git"
- name: forkBranch
type: string
description: The branch of the git repository where the updated code is committed to.
default: "bundle-update"
- name: forkUser
type: string
description: The Github user of the fork git repository.
default: "raptorsun"
- name: sourceGitUrl
type: string
description: The source git repository URL to clone as starting point for the bundle update.
default: "https://github.com/openshift/lightspeed-operator.git"
- name: sourceBranch
type: string
description: The branch of the source git repository to clone as starting point for the bundle update.
default: "main"
tasks:
- name: update-related-images
params:
- name: SNAPSHOT
value: $(params.SNAPSHOT)
- name: forkGitUrl
value: $(params.forkGitUrl)
- name: forkBranch
value: $(params.forkBranch)
- name: forkUser
value: $(params.forkUser)
- name: sourceGitUrl
value: $(params.sourceGitUrl)
- name: sourceBranch
value: $(params.sourceBranch)
taskSpec:
params:
- name: SNAPSHOT
type: string
- name: forkGitUrl
type: string
default: "https://github.com/raptorsun/lightspeed-operator.git"
- name: forkBranch
type: string
default: "bundle-update"
- name: forkUser
type: string
default: "raptorsun"
- name: sourceGitUrl
type: string
default: "https://github.com/openshift/lightspeed-operator.git"
- name: sourceBranch
type: string
default: "main"
results:
- name: commit-id
description: The commit ID where bundle is updated
- name: pull-request-url
description: The URL of the created pull request
steps:
- name: git-clone
image: quay.io/openshift-lightspeed/release-automation:bundle-update-0.0.4
workingDir: /workspace
script: |
git clone --single-branch --branch $(params.sourceBranch) $(params.sourceGitUrl) repo
cd repo
git checkout -b $(params.forkBranch)
- name: update-file
image: quay.io/openshift-lightspeed/release-automation:bundle-update-0.0.4
workingDir: /workspace
env:
- name: SNAPSHOT
value: $(params.SNAPSHOT)
- name: HOME
value: /workspace
- name: GOTOOLCHAIN
value: auto
script: |
set -euo pipefail
cd repo

echo "Snapshot content:"
echo "${SNAPSHOT}" | jq .

# Update related_images.json from SNAPSHOT JSON.
# Preserve entries not present in the application snapshot (bundle, dataverse-exporter, postgresql).
# Map snapshot component names to related_images.json names:
# lightspeed-service -> lightspeed-service-api
# lightspeed-console -> lightspeed-console-plugin
# lightspeed-operator -> lightspeed-operator (unchanged)
# openshift-mcp-server -> openshift-mcp-server (unchanged)
# lightspeed-ocp-rag -> lightspeed-ocp-rag (unchanged)
jq --argjson snapshot "${SNAPSHOT}" '
[.[] | select(
.name == "lightspeed-operator-bundle" or
.name == "lightspeed-to-dataverse-exporter" or
.name == "lightspeed-postgresql"
)] +
[$snapshot.components[] | select(.name == "lightspeed-service") |
{name: "lightspeed-service-api", image: .containerImage, revision: .source.git.revision}] +
[$snapshot.components[] | select(.name == "lightspeed-console") |
{name: "lightspeed-console-plugin", image: .containerImage, revision: .source.git.revision}] +
[$snapshot.components[] | select(.name == "lightspeed-operator") |
{name: "lightspeed-operator", image: .containerImage, revision: .source.git.revision}] +
[$snapshot.components[] | select(.name == "openshift-mcp-server") |
{name: "openshift-mcp-server", image: .containerImage, revision: .source.git.revision}] +
[$snapshot.components[] | select(.name == "lightspeed-ocp-rag") |
{name: "lightspeed-ocp-rag", image: .containerImage, revision: .source.git.revision}]
' related_images.json > tmp.json && mv tmp.json related_images.json
Comment on lines +108 to +124

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Inspect current related_images.json to enumerate expected entries and cross-check names used by the jq mapping.
fd -t f 'related_images.json' --exec cat {}

Repository: openshift/lightspeed-operator

Length of output: 2134


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the pipeline context around the jq transformation.
file=".tekton/integration-tests/pipelines/bundle-update-pipeline.yaml"
wc -l "$file"
sed -n '1,220p' "$file"

# Find where SNAPSHOT comes from and where related_images.json is used.
rg -n --no-heading 'SNAPSHOT|related_images\.json|lightspeed-service-api|lightspeed-console-plugin|lightspeed-operator|openshift-mcp-server|lightspeed-ocp-rag' .tekton . -g '!**/.git/**'

Repository: openshift/lightspeed-operator

Length of output: 50386


🏁 Script executed:

#!/bin/bash
set -euo pipefail

file=".tekton/integration-tests/pipelines/bundle-update-pipeline.yaml"

echo "== file length =="
wc -l "$file"

echo "== relevant lines =="
sed -n '1,220p' "$file"

echo "== where this pipeline is referenced =="
rg -n --no-heading 'bundle-update-pipeline\.yaml|bundle-update' .tekton -g '!**/.git/**'

echo "== snapshot/component usage in this pipeline =="
rg -n --no-heading 'SNAPSHOT|related_images\.json|lightspeed-service-api|lightspeed-console-plugin|lightspeed-operator|openshift-mcp-server|lightspeed-ocp-rag' "$file"

Repository: openshift/lightspeed-operator

Length of output: 13976


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== bundle-update scenario references =="
rg -n --no-heading 'bundle-update-integration-test|bundle-update-pipeline|update-related-images|related_images\.json|SNAPSHOT' .tekton -g '!**/.git/**'

echo "== bundle-update related scenario file if any =="
fd -a 'bundle-update' .tekton

echo "== integration-test scenario excerpts =="
sed -n '1,220p' .tekton/integration-tests/integration-test-scenarios/konflux-integration-test-scenarios.yaml

echo "== release bundle-update pipeline excerpt =="
sed -n '1,220p' .tekton/release/bundle-update/pipeline.yaml

Repository: openshift/lightspeed-operator

Length of output: 50385


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== snapshot_to_image_list.sh =="
fd -a 'snapshot_to_image_list.sh' .
script="$(fd -a 'snapshot_to_image_list.sh' . | head -n 1)"
wc -l "$script"
cat -n "$script"

echo "== bundle-update release pipeline jq logic around related images =="
sed -n '96,116p' .tekton/release/bundle-update/pipeline.yaml

Repository: openshift/lightspeed-operator

Length of output: 14848


🏁 Script executed:

#!/bin/bash
set -euo pipefail

script="$(fd -a 'snapshot_to_image_list.sh' . | head -n 1)"
echo "== $script =="
wc -l "$script"
cat -n "$script"

echo "== related image handling in .tekton/release/bundle-update/pipeline.yaml =="
sed -n '96,116p' .tekton/release/bundle-update/pipeline.yaml

Repository: openshift/lightspeed-operator

Length of output: 14830


🌐 Web query:

Konflux AppStudio snapshot spec components always include all components application under test documentation

💡 Result:

In Konflux AppStudio, a Snapshot does not necessarily include all components of an application under test in every instance. A Snapshot represents an immutable collection of container images for the components of an application at a specific point in time [1]. When the Integration Service creates a snapshot following a successful component build, it includes the newly built component and the component references from the application's Global Candidate List (GCL) [2][3]. The GCL tracks the most recently promoted image and commit for each component [3]. While the snapshot is intended to represent the state of the application components to be tested together [1][4], users can also create manual snapshots or override snapshots [5][6]. An override snapshot allows users to explicitly define the state of specific components, effectively resetting the GCL for those components [5][3]. Therefore, the components listed in the snapshot spec are the specific collection that the Integration Service will test as a whole [2][4]. Top Results: [1][2][3]

Citations:


Preserve existing entries when a snapshot component is absent Konflux snapshots can be partial, so each select(.name == …) here can drop lightspeed-service-api, lightspeed-console-plugin, lightspeed-operator, openshift-mcp-server, or lightspeed-ocp-rag from related_images.json instead of keeping the previous value. That leaves the generated bundle incomplete.

🤖 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 @.tekton/integration-tests/pipelines/bundle-update-pipeline.yaml around lines
106 - 122, The jq update in the related_images.json generation step is dropping
existing entries whenever a snapshot component is missing. Update the
transformation around the lightspeed-service, lightspeed-console,
lightspeed-operator, openshift-mcp-server, and lightspeed-ocp-rag selects so
each target entry is only replaced when a matching snapshot component exists,
otherwise the prior related_images.json value is preserved. Keep the existing
lightspeed-operator-bundle, lightspeed-to-dataverse-exporter, and
lightspeed-postgresql entries intact while merging in any available
snapshot-derived images.


echo "Updated related_images.json:"
cat related_images.json

# Extract the current bundle version from the CSV before make bundle overwrites it.
# The Makefile defaults BUNDLE_TAG to 1.1.1; we must pass the actual version.
BUNDLE_TAG=$(grep '^ version:' bundle/manifests/lightspeed-operator.clusterserviceversion.yaml | awk '{print $2}')
echo "Using BUNDLE_TAG=${BUNDLE_TAG}"

PATH=./bin:$PATH make bundle BUNDLE_TAG="${BUNDLE_TAG}"
- name: git-config
image: quay.io/openshift-lightspeed/release-automation:bundle-update-0.0.4
workingDir: /workspace
env:
- name: HOME
value: /workspace
script: |
set -euo pipefail
cd repo
git config user.email "hasun@redhat.com"
git config user.name "Haoyu Sun's Bot"
git remote add fork $(params.forkGitUrl)
- name: git-commit-push
image: quay.io/openshift-lightspeed/release-automation:bundle-update-0.0.4
workingDir: /workspace
env:
- name: GITHUB_TOKEN
valueFrom:
secretKeyRef:
name: release-bot-github-token
key: github-token
script: |
set -euo pipefail
cd repo
git add related_images.json bundle

if git diff --cached --quiet; then
echo "No changes to commit - related_images and bundle are already up to date"
echo -n "no-change" | tee $(results.commit-id.path)
echo -n "no-pr-needed" | tee $(results.pull-request-url.path)
exit 0
fi

git commit -m "Update related_images and bundle from snapshot"
git rev-parse HEAD | tee $(results.commit-id.path)
git config credential.helper '!f() { sleep 1; echo "username=git"; echo "password=$GITHUB_TOKEN"; }; f'
git push --force fork $(params.forkBranch)
RESPONSE=$(curl -L \
-X POST \
-H "Accept: application/vnd.github+json" \
-H "Authorization: Bearer ${GITHUB_TOKEN}" \
-H "X-GitHub-Api-Version: 2022-11-28" \
https://api.github.com/repos/openshift/lightspeed-operator/pulls \
-d '{"title":"Bundle Update from Integration Test Snapshot","body":"This PR updates the related_images and bundle based on the latest snapshot from Konflux integration test.","head":"$(params.forkUser):$(params.forkBranch)","base":"$(params.sourceBranch)"}')
echo "Github response:"
echo "$RESPONSE"
jq -r '.html_url' <<< "$RESPONSE" | tee $(results.pull-request-url.path)
Comment on lines +172 to +181

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

PR creation failures are silently swallowed; the pipeline still reports success.

curl -L without -f/--fail-with-body exits 0 on HTTP 4xx/5xx (e.g., a 422 when the PR already exists, or auth failure). With set -euo pipefail the step still succeeds, RESPONSE holds an error body, and jq -r '.html_url' writes the literal null into the pull-request-url result. The task then reports success with no usable PR URL.

Fail fast and validate the response before publishing the result:

🛡️ Proposed hardening for the GitHub call
-              RESPONSE=$(curl -L \
-                -X POST \
+              HTTP_CODE=$(curl -sS -L \
+                -o response.json -w '%{http_code}' \
+                -X POST \
                 -H "Accept: application/vnd.github+json" \
                 -H "Authorization: Bearer ${GITHUB_TOKEN}" \
                 -H "X-GitHub-Api-Version: 2022-11-28" \
                 https://api.github.com/repos/openshift/lightspeed-operator/pulls \
                 -d '{"title":"Bundle Update from Integration Test Snapshot","body":"This PR updates the related_images and bundle based on the latest snapshot from Konflux integration test.","head":"$(params.forkUser):$(params.forkBranch)","base":"$(params.sourceBranch)"}')
               echo "Github response:"
-              echo "$RESPONSE"
-              jq -r '.html_url' <<< "$RESPONSE" | tee $(results.pull-request-url.path)
+              cat response.json
+              if [ "$HTTP_CODE" -lt 200 ] || [ "$HTTP_CODE" -ge 300 ]; then
+                echo "GitHub PR creation failed with HTTP $HTTP_CODE" >&2
+                exit 1
+              fi
+              jq -r '.html_url' response.json | tee $(results.pull-request-url.path)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
RESPONSE=$(curl -L \
-X POST \
-H "Accept: application/vnd.github+json" \
-H "Authorization: Bearer ${GITHUB_TOKEN}" \
-H "X-GitHub-Api-Version: 2022-11-28" \
https://api.github.com/repos/openshift/lightspeed-operator/pulls \
-d '{"title":"Bundle Update from Integration Test Snapshot","body":"This PR updates the related_images and bundle based on the latest snapshot from Konflux integration test.","head":"$(params.forkUser):$(params.forkBranch)","base":"$(params.sourceBranch)"}')
echo "Github response:"
echo "$RESPONSE"
jq -r '.html_url' <<< "$RESPONSE" | tee $(results.pull-request-url.path)
HTTP_CODE=$(curl -sS -L \
-o response.json -w '%{http_code}' \
-X POST \
-H "Accept: application/vnd.github+json" \
-H "Authorization: Bearer ${GITHUB_TOKEN}" \
-H "X-GitHub-Api-Version: 2022-11-28" \
https://api.github.com/repos/openshift/lightspeed-operator/pulls \
-d '{"title":"Bundle Update from Integration Test Snapshot","body":"This PR updates the related_images and bundle based on the latest snapshot from Konflux integration test.","head":"$(params.forkUser):$(params.forkBranch)","base":"$(params.sourceBranch)"}')
echo "Github response:"
cat response.json
if [ "$HTTP_CODE" -lt 200 ] || [ "$HTTP_CODE" -ge 300 ]; then
echo "GitHub PR creation failed with HTTP $HTTP_CODE" >&2
exit 1
fi
jq -r '.html_url' response.json | tee $(results.pull-request-url.path)
🤖 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 @.tekton/integration-tests/pipelines/bundle-update-pipeline.yaml around lines
165 - 174, The GitHub PR creation step in the bundle update pipeline is
swallowing HTTP failures and still writing a bogus result. Update the curl-based
request that assigns RESPONSE to fail on non-2xx responses and only emit
pull-request-url after verifying the response contains a valid html_url; if the
API call fails or returns an error payload, stop the step instead of piping null
into the result. Use the RESPONSE handling and jq extraction in this step as the
main places to harden.

results:
- name: commit-id
description: The commit ID where bundle is updated.
value: "$(tasks.update-related-images.results.commit-id)"
- name: pull-request-url
description: The URL of the created pull request.
value: "$(tasks.update-related-images.results.pull-request-url)"
finally:
- name: export-logs-for-retention
taskRef:
resolver: git
params:
- name: url
value: https://github.com/konflux-ci/tekton-integration-catalog.git
- name: revision
value: main
- name: pathInRepo
value: tasks/export-logs/0.1/export-logs-to-quay.yaml
params:
- name: pipeline-run-name
value: $(context.pipelineRun.name)
- name: namespace
value: $(context.pipelineRun.namespace)
- name: quay-repo
value: "quay.io/openshift-lightspeed/ols-operator-artifacts"
- name: artifact-credentials-secret
value: ols-konflux-artifacts-bot