Skip to content

Commit

Permalink
feat(RELEASE-1403): rework embargo-check task for issues
Browse files Browse the repository at this point in the history
This commit reworks the managed embargo-check task for how it handles
issues in issues.redhat.com. First, it adds authentication for searching
for these issues. If the issue is found and is not of type
Vulnerability, it will pass.

If the issue is of type Vulnerability, the task will now ensure that the
component from the issue matches a component in the
releaseNotes.content.images section and that the CVE from the issue is
present in said component section.

Signed-off-by: Johnny Bieren <[email protected]>
  • Loading branch information
johnbieren committed Feb 6, 2025
1 parent 26c0979 commit f11dc89
Show file tree
Hide file tree
Showing 10 changed files with 487 additions and 14 deletions.
12 changes: 11 additions & 1 deletion tasks/managed/embargo-check/README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
# embargo-check

Tekton task to check if any issues or CVEs in the releaseNotes key of the data.json are embargoed. It checks the issues
by server using curl and checks the CVEs via an InternalRequest. If any issue or CVE is embargoed, the task will fail.
by server using curl and checks the CVEs via an InternalRequest. If any issue does not exist or any CVE is embargoed,
the task will fail. The task will also fail if a Jira issue listed is for a component that does not exist in the
releaseNotes.content.images section or if said component does not list the CVE from the issue.

## Parameters

Expand All @@ -13,6 +15,14 @@ by server using curl and checks the CVEs via an InternalRequest. If any issue or
| taskGitUrl | The url to the git repo where the release-service-catalog tasks to be used are stored | No | - |
| taskGitRevision | The revision in the taskGitUrl repo to be used | No | - |

## Changes in 1.0.0
* Authentication is added to checking issues in issues.redhat.com
* If the issue exists and is not of type `Vulnerability`, the task will pass on that issue
* If the issue is of type `Vulnerability`
* If the `Downstream Component Name` from the issue is not listed in the `releaseNotes.content.images`
section, the task will fail
* If the `CVE ID` from the issue is not present in its component's fixed cves section, the task will fail

## Changes in 0.5.0
* Added taskGiturl and taskGitRevision parameters to be passed to the internalRequest
* The pipeline is called via git resolver now instead of cluster resolver
Expand Down
58 changes: 53 additions & 5 deletions tasks/managed/embargo-check/embargo-check.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,18 @@ kind: Task
metadata:
name: embargo-check
labels:
app.kubernetes.io/version: "0.5.0"
app.kubernetes.io/version: "1.0.0"
annotations:
tekton.dev/pipelines.minVersion: "0.12.1"
tekton.dev/tags: release
spec:
description: >
Tekton task to check if any issues or CVEs in the releaseNotes key of the data.json
are embargoed. It checks the issues by server using curl and checks the CVEs via an
InternalRequest. If any issue or CVE is embargoed, the task will fail.
InternalRequest. If any issue does not exist or any CVE is embargoed, the task will
fail. The task will also fail if a Jira issue listed is for a component that does
not exist in the releaseNotes.content.images section or if said component does not
list the CVE from the issue.
params:
- name: dataPath
description: Path to the JSON string of the merged data to use in the data workspace
Expand All @@ -36,6 +39,12 @@ spec:
steps:
- name: check-issues
image: quay.io/konflux-ci/release-service-utils:0f82be4be43294b6a96846d87ef7f7c0b9e34267
env:
- name: ACCESS_TOKEN
valueFrom:
secretKeyRef:
name: todo
key: TODO
script: |
#!/usr/bin/env bash
set -x
Expand All @@ -62,19 +71,58 @@ spec:
exit 1
fi
set +x # There are a lot of custom fields, don't want to pollute the logs or leak the ACCESS_TOKEN
CUSTOM_RH_FIELDS="$(curl -H "Authorization: Bearer $ACCESS_TOKEN" https://issues.redhat.com/rest/api/2/field)"
set -x
CVE_FIELD="$(jq -r '.[] | select(.name=="CVE ID") | .id' <<< "$CUSTOM_RH_FIELDS")"
COMPONENT_FIELD="$(jq -r '.[] | select(.name=="Downstream Component Name") | .id' <<< "$CUSTOM_RH_FIELDS")"
RC=0
NUM_ISSUES=$(jq -cr '.releaseNotes.issues.fixed | length' "${DATA_FILE}")
for ((i = 0; i < NUM_ISSUES; i++)); do
issue=$(jq -c --argjson i "$i" '.releaseNotes.issues.fixed[$i]' "${DATA_FILE}")
server=$(jq -r '.source' <<< "$issue")
API=$(jq -r '.[] | select(.servers[] | contains("'"$server"'")) | .api' <<< "$SUPPORTED_ISSUE_TRACKERS")
API_URL="https://$(jq -r '.source' <<< "$issue")/${API}/$(jq -r '.id' <<< "$issue")"
curl --fail --output /dev/null "${API_URL}"
API_URL="https://"
# Add authentication for issues.redhat.com
if [ "$server" = "issues.redhat.com" ] ; then
API_URL="-H \"Authorization: Bearer $ACCESS_TOKEN\" ${API_URL}"
fi
API_URL="${API_URL}$(jq -r '.source' <<< "$issue")/${API}/$(jq -r '.id' <<< "$issue")"
OUTPUT=$(curl --retry 3 --fail "${API_URL}")
if [ $? -ne 0 ] ; then
echo "${issue} is not publicly visible. Assuming it is embargoed and stopping pipelineRun execution."
echo "${issue} is not visible. Assuming it is embargoed and stopping pipelineRun execution."
RC=1
continue
fi
# Perform additional checks only for Vulnerability issues for issues.redhat.com
if [ "$server" != "issues.redhat.com" ] ; then
continue
fi
ISSUE_TYPE=$(jq -r '.fields.issuetype.name' <<< "$OUTPUT")
if [ "$ISSUE_TYPE" != "Vulnerability" ] ; then
continue
fi
CVE_ID=$(jq -r --arg field "$CVE_FIELD" '.fields[$field]' <<< "$OUTPUT")
COMPONENT_NAME=$(jq -r --arg field "$COMPONENT_FIELD" '.fields[$field]' <<< "$OUTPUT")
if ! COMPONENT_IN_RELEASE_NOTES="$(jq -ec --arg name "$COMPONENT_NAME" \
'.releaseNotes.content.images[] | select(.component==$name)' "$DATA_FILE")"; then
echo -n "Issue $issue lists 'Downstream Component Name' $COMPONENT_NAME but that component does"
echo " not appear in releaseNotes.content.images. Failing"
RC=2
fi
if [ "$(jq --arg CVE "$CVE_ID" '.cves.fixed | has($CVE)' <<< "$COMPONENT_IN_RELEASE_NOTES")" != "true" ]
then
echo -n "Issue $issue lists 'Downstream Component Name' $COMPONENT_NAME and 'CVE ID' $CVE_ID"
echo " but that CVE is not present in the releaseNotes.content.images section for that component."
echo "Failing"
RC=3
continue
fi
done
exit $RC
Expand Down
18 changes: 15 additions & 3 deletions tasks/managed/embargo-check/tests/mocks.sh
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,27 @@ function curl() {
echo Mock curl called with: $* >&2
echo $* >> $(workspaces.data.path)/mock_curl.txt

if [[ "$*" == "--fail --output /dev/null https://jira.atlassian.com/rest/api/2/issue/ISSUE-123" ]]
if [[ "$*" == "--fail https://jira.atlassian.com/rest/api/2/issue/ISSUE-123" ]]
then
:
elif [[ "$*" == "--fail --output /dev/null https://bugzilla.redhat.com/rest/bug/12345" ]]
elif [[ "$*" == "--fail https://bugzilla.redhat.com/rest/bug/12345" ]]
then
:
elif [[ "$*" == "--fail --output /dev/null https://jira.atlassian.com/rest/api/2/issue/EMBARGOED-987" ]]
elif [[ "$*" == "--fail https://jira.atlassian.com/rest/api/2/issue/EMBARGOED-987" ]]
then
exit 1
elif [[ "$*" == *"Authorization: Bearer"*"https://issues.redhat.com/rest/api/2/issue/MISSINGRH-123" ]]
then
exit 1
elif [[ "$*" == *"Authorization: Bearer"*"https://issues.redhat.com/rest/api/2/issue/FEATURE-123" ]] # Not a Vulnerability
then
echo '{"fields":{"issuetype":{"name":"Feature"}}}'
elif [[ "$*" == *"Authorization: Bearer"*"https://issues.redhat.com/rest/api/2/issue/CVE-123" ]] # Vulnerability
then
echo '{"fields":{"issuetype":{"name":"Vulnerability"},"customfield_123":"CVE-123","customfield_456":"my-component"}}'
elif [[ "$*" == *"issues.redhat.com/rest/api/2/field" ]]
then
echo '[{"id":"customfield_123","name":"CVE ID","custom":true},{"id":"customfield_456","name":"Downstream Component Name","custom":true},{"id":"customfield_555","name":"Some other one","custom":true}]'
else
echo Error: Unexpected call
exit 1
Expand Down
4 changes: 4 additions & 0 deletions tasks/managed/embargo-check/tests/pre-apply-task-hook.sh
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,7 @@ TASK_PATH="$1"
SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
yq -i '.spec.steps[0].script = load_str("'$SCRIPT_DIR'/mocks.sh") + .spec.steps[0].script' "$TASK_PATH"
yq -i '.spec.steps[1].script = load_str("'$SCRIPT_DIR'/mocks.sh") + .spec.steps[1].script' "$TASK_PATH"

# Create a dummy access token secret (and delete it first if it exists)
kubectl delete secret todo --ignore-not-found
kubectl create secret generic todo --from-literal=TODO=abcdefg
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
---
apiVersion: tekton.dev/v1
kind: Pipeline
metadata:
name: test-embargo-check-non-vuln-rh-issue
spec:
description: Test for embargo-check with a issues.redhat.com issue that is not of type Vulnerability
workspaces:
- name: tests-workspace
tasks:
- name: setup
workspaces:
- name: data
workspace: tests-workspace
taskSpec:
workspaces:
- name: data
steps:
- name: setup-values
image: quay.io/konflux-ci/release-service-utils:0f82be4be43294b6a96846d87ef7f7c0b9e34267
script: |
#!/usr/bin/env sh
set -eux
cat > "$(workspaces.data.path)"/data.json << EOF
{
"releaseNotes": {
"issues": {
"fixed": [
{
"id": "ISSUE-123",
"source": "jira.atlassian.com"
},
{
"id": "FEATURE-123",
"source": "issues.redhat.com"
}
]
}
}
}
EOF
- name: run-task
taskRef:
name: embargo-check
params:
- name: dataPath
value: data.json
- name: pipelineRunUid
value: $(context.pipelineRun.uid)
- name: taskGitUrl
value: "http://localhost"
- name: taskGitRevision
value: "main"
workspaces:
- name: data
workspace: tests-workspace
runAfter:
- setup
- name: check-result
workspaces:
- name: data
workspace: tests-workspace
taskSpec:
steps:
- name: check-result
image: quay.io/konflux-ci/release-service-utils:0f82be4be43294b6a96846d87ef7f7c0b9e34267
script: |
#!/usr/bin/env bash
set -eux
if [ "$(wc -l < "$(workspaces.data.path)"/mock_curl.txt)" != 3 ]; then
echo Error: curl was expected to be called 3 times. Actual calls:
cat "$(workspaces.data.path)"/mock_curl.txt
exit 1
fi
[[ $(head -n 1 "$(workspaces.data.path)/mock_curl.txt") == *"issues.redhat.com/rest/api/2/field" ]]
[[ $(head -n 2 "$(workspaces.data.path)/mock_curl.txt" | tail -n 1) \
== *"ISSUE-123"* ]]
[[ $(tail -n 1 "$(workspaces.data.path)/mock_curl.txt") == *"FEATURE-123"* ]]
runAfter:
- run-task
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
---
apiVersion: tekton.dev/v1
kind: Pipeline
metadata:
name: test-embargo-check-nonexistent-rh-issue
annotations:
test/assert-task-failure: "run-task"
spec:
description: Test for embargo-check where a issues.redhat.com issue cannot be found
workspaces:
- name: tests-workspace
tasks:
- name: setup
workspaces:
- name: data
workspace: tests-workspace
taskSpec:
workspaces:
- name: data
steps:
- name: setup-values
image: quay.io/konflux-ci/release-service-utils:0f82be4be43294b6a96846d87ef7f7c0b9e34267
script: |
#!/usr/bin/env sh
set -eux
cat > "$(workspaces.data.path)/data.json" << EOF
{
"releaseNotes": {
"issues": {
"fixed": [
{
"id": "MISSINGRH-123",
"source": "issues.redhat.com"
},
{
"id": "12345",
"source": "bugzilla.redhat.com"
}
]
}
}
}
EOF
- name: run-task
taskRef:
name: embargo-check
params:
- name: dataPath
value: data.json
- name: pipelineRunUid
value: $(context.pipelineRun.uid)
- name: taskGitUrl
value: "http://localhost"
- name: taskGitRevision
value: "main"
workspaces:
- name: data
workspace: tests-workspace
runAfter:
- setup
Original file line number Diff line number Diff line change
Expand Up @@ -69,15 +69,15 @@ spec:
#!/usr/bin/env bash
set -eux
if [ "$(wc -l < "$(workspaces.data.path)"/mock_curl.txt)" != 2 ]; then
echo Error: curl was expected to be called 2 times. Actual calls:
if [ "$(wc -l < "$(workspaces.data.path)"/mock_curl.txt)" != 3 ]; then
echo Error: curl was expected to be called 3 times. Actual calls:
cat "$(workspaces.data.path)"/mock_curl.txt
exit 1
fi
[[ $(cat $(workspaces.data.path)/mock_curl.txt | head -n 1) \
[[ $(head -n 1 "$(workspaces.data.path)/mock_curl.txt") == *"issues.redhat.com/rest/api/2/field" ]]
[[ $(head -n 2 "$(workspaces.data.path)/mock_curl.txt" | tail -n 1) \
== *"ISSUE-123"* ]]
[[ $(cat $(workspaces.data.path)/mock_curl.txt | head -n 2 | tail -n 1) \
== *"12345"* ]]
[[ $(tail -n 1 "$(workspaces.data.path)/mock_curl.txt") == *"12345"* ]]
runAfter:
- run-task
Loading

0 comments on commit f11dc89

Please sign in to comment.