Skip to content

Commit cc73756

Browse files
committed
fix(RELEASE-12379): use completion_time instead of buildTimestamp
Replace the buildTimestamp parameter/result with completion_time extracted directly from the IIB build info JSON response. This ensures timestamp consistency with the actual build completion time and adds support for conditional timestamped tags in FBC releases. Changes: - add-fbc-contribution: Extract completion_time from IIB build response (updated_by field), validate it's a 10-digit epoch timestamp, and create target_index_with_timestamp field that avoids duplicate timestamps for hotfix/pre-GA releases - collect-index-images: Use target_index_with_timestamp to conditionally include timestamped tags (2 tags for regular releases, 1 for hotfix/pre-GA) - publish-index-image: Publish both target_index and target_index_with_timestamp tags only when they differ - extract-index-image: Remove unused buildTimestamp parameter - prepare-fbc-snapshot: Update comment to clarify timestamp is arbitrary until build completion - fbc-release pipeline: Remove buildTimestamp parameter passing For regular releases, both v4.14 and v4.14-<timestamp> tags are published. For hotfix/pre-GA releases (which already include timestamps in target_index), only a single tag is published to avoid duplication. This change also fixes RELEASE-2666 by ensuring the timestamped image is properly created and available for signing. All integration tests updated to reflect the new behavior. Assisted-By: Claude Code Signed-off-by: Leandro Mendes <lmendes@redhat.com>
1 parent 761dca0 commit cc73756

20 files changed

Lines changed: 388 additions & 231 deletions

pipelines/managed/fbc-release/fbc-release.yaml

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -494,8 +494,6 @@ spec:
494494
- name: pathInRepo
495495
value: tasks/managed/extract-index-image/extract-index-image.yaml
496496
params:
497-
- name: inputDataFile
498-
value: $(tasks.add-fbc-contribution-to-index-image.results.requestResultsFile)
499497
- name: resultsDirPath
500498
value: "$(tasks.collect-data.results.resultsDir)"
501499
- name: ociStorage
@@ -529,8 +527,6 @@ spec:
529527
value: "$(tasks.collect-data.results.data)"
530528
- name: internalRequestResultsFile
531529
value: $(tasks.add-fbc-contribution-to-index-image.results.internalRequestResultsFile)
532-
- name: buildTimestamp
533-
value: $(tasks.add-fbc-contribution-to-index-image.results.buildTimestamp)
534530
- name: retries
535531
value: "3"
536532
- name: pipelineRunUid
@@ -565,8 +561,6 @@ spec:
565561
- name: pathInRepo
566562
value: tasks/managed/collect-index-images/collect-index-images.yaml
567563
params:
568-
- name: buildTimestamp
569-
value: $(tasks.add-fbc-contribution-to-index-image.results.buildTimestamp)
570564
- name: internalRequestResultsFile
571565
value: $(tasks.add-fbc-contribution-to-index-image.results.internalRequestResultsFile)
572566
- name: ociStorage

tasks/managed/add-fbc-contribution/add-fbc-contribution.yaml

Lines changed: 33 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -100,8 +100,6 @@ spec:
100100
description: The name of the key in the ConfigMap that contains the CA bundle data
101101
default: ca-bundle.crt
102102
results:
103-
- name: buildTimestamp
104-
description: Build timestamp used in the tag
105103
- name: requestResultsFile
106104
description: Internal Request results file
107105
- name: internalRequestResultsFile
@@ -211,9 +209,6 @@ spec:
211209
mustPublishIndexImage="$(params.mustPublishIndexImage)"
212210
mustOverwriteFromIndexImage="$(params.mustOverwriteFromIndexImage)"
213211
214-
timestamp_format=$(jq -r '.fbc.timestampFormat // "%s"' "${DATA_FILE}")
215-
timestamp=$(date "+${timestamp_format}")
216-
217212
# Extract OCP versions from snapshot
218213
ocp_versions=$(jq -r '.components[].ocpVersion' "$SNAPSHOT_PATH" | sort -u)
219214
echo "INFO: Found OCP versions: $(echo "$ocp_versions" | tr '\n' ' ')"
@@ -223,8 +218,6 @@ spec:
223218
echo " - mustOverwriteFromIndexImage: ${mustOverwriteFromIndexImage}"
224219
echo " - iibServiceAccountSecret: ${iib_service_account_secret}"
225220
226-
# Initialize results file for multi-OCP processing
227-
echo -n "$timestamp" > "$(results.buildTimestamp.path)"
228221
jq -n '{"components": []}' | tee "$RESULTS_FILE"
229222
230223
# Snapshot validation for multi-OCP processing
@@ -472,10 +465,40 @@ spec:
472465
# Process results for each fragment in this batch
473466
local decompressed_json_build_info
474467
decompressed_json_build_info="$(jq -r '.jsonBuildInfo' <<< "${results}" | base64 -d | gunzip)"
468+
469+
# Extract and validate completion_time from IIB build info
475470
local completion_time_raw
476471
completion_time_raw="$(jq -r '.updated' <<< "${decompressed_json_build_info}")"
472+
473+
if [[ -z "${completion_time_raw}" || "${completion_time_raw}" == "null" ]]; then
474+
echo "ERROR: completion_time not found in IIB build info"
475+
return 1
476+
fi
477+
478+
echo "INFO: Extracting completion_time from IIB build info"
479+
echo " Raw value: ${completion_time_raw}"
480+
477481
local completion_time
478-
completion_time=$(date +"${timestamp_format}" -d "${completion_time_raw}")
482+
if ! completion_time=$(date +"%s" -d "${completion_time_raw}"); then
483+
echo "ERROR: Failed to parse completion_time: ${completion_time_raw}"
484+
echo "Date conversion error: ${completion_time}"
485+
return 1
486+
fi
487+
echo " Epoch timestamp: ${completion_time}"
488+
489+
# Ensure completion_time contains ten digits
490+
if [[ ! "${completion_time}" =~ ^[0-9]{10}$ ]]; then
491+
echo "ERROR: Invalid completion_time format (expected 10 digits): ${completion_time}"
492+
return 1
493+
fi
494+
495+
# timestamped_target_index is the target_index with completion_time, unless
496+
# for hotfix or pre-ga which already has it and can be the same.
497+
if [[ "$group_target_index" =~ .*[0-9]{10}$ ]]; then
498+
target_index_with_timestamp="$group_target_index"
499+
else
500+
target_index_with_timestamp="$group_target_index-${completion_time}"
501+
fi
479502
480503
# Process fragments in batch
481504
local fragment_index=0
@@ -488,12 +511,14 @@ spec:
488511
build_results=$(jq \
489512
--arg fragment "$fragment" \
490513
--arg target_index "$group_target_index" \
514+
--arg target_index_with_timestamp "$target_index_with_timestamp" \
491515
--arg ocp_version "$group_ocp_version" \
492516
--arg completion_time "$completion_time" \
493517
--argjson decompressed_json "${decompressed_json_build_info}" \
494518
'{
495519
"fbc_fragment": $fragment,
496520
"target_index": $target_index,
521+
"target_index_with_timestamp": $target_index_with_timestamp,
497522
"ocp_version": $ocp_version,
498523
"image_digests": (.indexImageDigests | split(" ") | del(.[] | select(. == ""))),
499524
"index_image": $decompressed_json.index_image,

tasks/managed/add-fbc-contribution/tests/mocks.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ function date() {
133133
"+%Y-%m-%dT%H:%M:%SZ")
134134
echo "2023-10-10T15:00:00Z" |tee $(params.dataDir)/mock_date_iso_format.txt
135135
;;
136-
"+%s")
136+
"+%s"*)
137137
echo "1696946200" | tee $(params.dataDir)/mock_date_epoch.txt
138138
;;
139139
"-u +%Hh%Mm%Ss -d @"*)
Lines changed: 248 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,248 @@
1+
---
2+
apiVersion: tekton.dev/v1
3+
kind: Pipeline
4+
metadata:
5+
name: test-add-fbc-contribution-hotfix
6+
spec:
7+
description: Test add-fbc-contribution task for hotfix releases
8+
params:
9+
- name: ociStorage
10+
description: The OCI repository where the Trusted Artifacts are stored.
11+
type: string
12+
- name: ociArtifactExpiresAfter
13+
description: Expiration date for the trusted artifacts created in the
14+
OCI repository. An empty string means the artifacts do not expire.
15+
type: string
16+
default: "1d"
17+
- name: orasOptions
18+
description: oras options to pass to Trusted Artifacts calls
19+
type: string
20+
default: "--insecure"
21+
- name: trustedArtifactsDebug
22+
description: Flag to enable debug logging in trusted artifacts. Set to a non-empty string to enable.
23+
type: string
24+
default: ""
25+
- name: dataDir
26+
description: The location where data will be stored
27+
type: string
28+
- name: sourceDataArtifact
29+
description: Location of trusted artifacts to be used to populate data directory
30+
type: string
31+
default: ""
32+
tasks:
33+
- name: setup
34+
params:
35+
- name: sourceDataArtifact
36+
value: $(params.sourceDataArtifact)
37+
- name: dataDir
38+
value: $(params.dataDir)
39+
taskSpec:
40+
params:
41+
- name: sourceDataArtifact
42+
type: string
43+
description: Location of trusted artifacts to be used to populate data directory
44+
- name: dataDir
45+
type: string
46+
description: The location where data will be stored
47+
results:
48+
- name: sourceDataArtifact
49+
type: string
50+
volumes:
51+
- name: workdir
52+
emptyDir: {}
53+
stepTemplate:
54+
volumeMounts:
55+
- mountPath: /var/workdir
56+
name: workdir
57+
env:
58+
- name: IMAGE_EXPIRES_AFTER
59+
value: $(params.ociArtifactExpiresAfter)
60+
- name: "ORAS_OPTIONS"
61+
value: "$(params.orasOptions)"
62+
- name: "DEBUG"
63+
value: "$(params.trustedArtifactsDebug)"
64+
steps:
65+
- name: setup-test-data
66+
image: quay.io/konflux-ci/release-service-utils@sha256:5546fa78d3c88d7b6a2e8cff8902f7757f00541d0bbaf113b9f293133894afa3
67+
script: |
68+
#!/usr/bin/env bash
69+
set -eux
70+
71+
# Ensure data directory exists
72+
mkdir -p "$(params.dataDir)"
73+
74+
# Create snapshot with prepared FBC components (already processed by prepare-fbc-snapshot)
75+
# Note: In hotfix mode, prepare-fbc-snapshot would have already replaced {{timestamp}}
76+
# with an actual timestamp. We use a fixed timestamp for test reproducibility.
77+
cat > "$(params.dataDir)/snapshot.json" << 'EOF'
78+
{
79+
"components": [
80+
{
81+
"name": "fbc-target-index-testing",
82+
"containerImage": "quay.io/hacbs-release-tests/test-ocp-version/test-fbc-component@sha256:f6e744662e342c1321deddb92469b55197002717a15f8c0b1bb2d9440aac2297",
83+
"repository": "quay.io/scoheb/fbc-target-index-testing",
84+
"ocpVersion": "v4.12",
85+
"updatedFromIndex": "quay.io/redhat/redhat-operator-index:v4.12",
86+
"targetIndex": "quay.io/scoheb/fbc-target-index-testing:v4.12-KONFLUX-123-1234567890"
87+
}
88+
]
89+
}
90+
EOF
91+
92+
# Create FBC data configuration for staged release
93+
cat > "$(params.dataDir)/data.json" << 'EOF'
94+
{
95+
"fbc": {
96+
"fromIndex": "quay.io/redhat/redhat-operator-index:{{ OCP_VERSION }}",
97+
"targetIndex": "quay.io/scoheb/fbc-target-index-testing:v4.12-KONFLUX-123-1234567890",
98+
"hotfix": true,
99+
"issueId": "KONFLUX-123"
100+
}
101+
}
102+
EOF
103+
104+
# Create mock results directory structure
105+
mkdir -p "$(params.dataDir)/results"
106+
107+
echo "Staged test data created for add-fbc-contribution"
108+
- name: create-trusted-artifact
109+
ref:
110+
name: create-trusted-artifact
111+
params:
112+
- name: ociStorage
113+
value: $(params.ociStorage)
114+
- name: workDir
115+
value: $(params.dataDir)
116+
- name: sourceDataArtifact
117+
value: $(results.sourceDataArtifact.path)
118+
119+
- name: run-task
120+
taskRef:
121+
name: add-fbc-contribution
122+
params:
123+
- name: snapshotPath
124+
value: snapshot.json
125+
- name: dataPath
126+
value: data.json
127+
- name: pipelineRunUid
128+
value: $(context.pipelineRun.uid)
129+
- name: resultsDirPath
130+
value: results
131+
- name: ociStorage
132+
value: $(params.ociStorage)
133+
- name: sourceDataArtifact
134+
value: "$(tasks.setup.results.sourceDataArtifact)=$(params.dataDir)"
135+
- name: dataDir
136+
value: $(params.dataDir)
137+
- name: trustedArtifactsDebug
138+
value: $(params.trustedArtifactsDebug)
139+
- name: orasOptions
140+
value: $(params.orasOptions)
141+
- name: taskGitUrl
142+
value: "https://github.com/konflux-ci/release-service-catalog.git"
143+
- name: taskGitRevision
144+
value: "development"
145+
- name: maxBatchSize
146+
value: "5"
147+
- name: mustPublishIndexImage
148+
value: "false"
149+
- name: mustOverwriteFromIndexImage
150+
value: "false"
151+
- name: iibServiceAccountSecret
152+
value: "iib-services-config"
153+
runAfter:
154+
- setup
155+
156+
- name: verify-results
157+
params:
158+
- name: sourceDataArtifact
159+
value: "$(tasks.run-task.results.sourceDataArtifact)=$(params.dataDir)"
160+
- name: dataDir
161+
value: $(params.dataDir)
162+
taskSpec:
163+
params:
164+
- name: sourceDataArtifact
165+
type: string
166+
description: Location of trusted artifacts to be used to populate data directory
167+
- name: dataDir
168+
type: string
169+
description: The location where data will be stored
170+
results:
171+
- name: sourceDataArtifact
172+
type: string
173+
volumes:
174+
- name: workdir
175+
emptyDir: {}
176+
stepTemplate:
177+
volumeMounts:
178+
- mountPath: /var/workdir
179+
name: workdir
180+
env:
181+
- name: IMAGE_EXPIRES_AFTER
182+
value: $(params.ociArtifactExpiresAfter)
183+
- name: "ORAS_OPTIONS"
184+
value: "$(params.orasOptions)"
185+
- name: "DEBUG"
186+
value: "$(params.trustedArtifactsDebug)"
187+
steps:
188+
- name: use-trusted-artifact
189+
ref:
190+
name: use-trusted-artifact
191+
params:
192+
- name: workDir
193+
value: $(params.dataDir)
194+
- name: sourceDataArtifact
195+
value: $(params.sourceDataArtifact)
196+
- name: orasOptions
197+
value: $(params.orasOptions)
198+
- name: verify-hotfix-processing
199+
image: quay.io/konflux-ci/release-service-utils@sha256:5546fa78d3c88d7b6a2e8cff8902f7757f00541d0bbaf113b9f293133894afa3
200+
script: |
201+
#!/usr/bin/env bash
202+
set -eux
203+
204+
echo "=== HOTFIX RELEASE VERIFICATION ==="
205+
206+
# Verify results file was created
207+
RESULTS_FILE="$(params.dataDir)/results/internal-requests-results.json"
208+
if [[ -f "$RESULTS_FILE" ]]; then
209+
echo "✅ Results file exists"
210+
echo "Results contents:"
211+
jq . "$RESULTS_FILE"
212+
else
213+
echo "❌ Results file missing at $RESULTS_FILE"
214+
exit 1
215+
fi
216+
217+
# Verify components were processed despite empty targetIndex
218+
COMPONENTS_COUNT=$(jq '.components | length' "$RESULTS_FILE")
219+
if [[ "$COMPONENTS_COUNT" -gt 0 ]]; then
220+
echo "✅ Components were processed successfully: $COMPONENTS_COUNT"
221+
else
222+
echo "❌ No components processed"
223+
exit 1
224+
fi
225+
226+
# Verify hotfix release specific behavior
227+
FIRST_COMPONENT_TARGET=$(jq -r '.components[0].target_index' "$RESULTS_FILE")
228+
FIRST_COMPONENT_TARGET_TS=$(jq -r '.components[0].target_index_with_timestamp' "$RESULTS_FILE")
229+
if [[ "$FIRST_COMPONENT_TARGET" =~ v4\.12-KONFLUX-123-[0-9]{10}$ ]]; then
230+
echo "✅ Target index matches hotfix pattern with 10-digit timestamp"
231+
else
232+
echo "❌ Unexpected target index format, got: $FIRST_COMPONENT_TARGET"
233+
exit 1
234+
fi
235+
236+
# Verify that for hotfix, target_index and target_index_with_timestamp are the same
237+
if [[ "$FIRST_COMPONENT_TARGET" == "$FIRST_COMPONENT_TARGET_TS" ]]; then
238+
echo "✅ Hotfix: target_index equals target_index_with_timestamp (no duplication)"
239+
else
240+
echo "❌ Hotfix should have same target_index and target_index_with_timestamp"
241+
echo " target_index: $FIRST_COMPONENT_TARGET"
242+
echo " target_index_with_timestamp: $FIRST_COMPONENT_TARGET_TS"
243+
exit 1
244+
fi
245+
246+
echo "=== HOTFIX RELEASE TEST PASSED ==="
247+
runAfter:
248+
- run-task

tasks/managed/collect-index-images/README.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ Tekton task that generates a JSON file to be used to create pyxis image for inde
66

77
| Name | Description | Optional | Default value |
88
|----------------------------|----------------------------------------------------------------------------------------------------------------------------|----------|----------------------|
9-
| buildTimestamp | Build timestamp for the index image | No | - |
109
| internalRequestResultsFile | Path to the results file of the InternalRequest build result | No | - |
1110
| ociStorage | The OCI repository where the Trusted Artifacts are stored | Yes | empty |
1211
| ociArtifactExpiresAfter | Expiration date for the trusted artifacts created in the OCI repository. An empty string means the artifacts do not expire | Yes | 1d |

0 commit comments

Comments
 (0)