Skip to content

Commit 68ae69c

Browse files
feat(RELEASE-1993): convert update-fbc-catalog-task to Python entrypoint
Replace the two inline bash steps with a call to the standalone Python script in the release-service-utils image. Tekton test mocks are converted to the declarative mocks.yaml pattern compatible with the Python entrypoint, and scenario-specific tests now covered by pytest in the utils repo are removed. Fix TASK_ENTRYPOINT quoting in test_tekton_tasks.sh: args with Tekton placeholders were wrapped in double quotes, which breaks when the substituted value has embedded double quotes (e.g. JSON arrays). Switched to single quotes so the value is preserved literally after Tekton substitution. Signed-off-by: Filip Nikolovski <fnikolov@redhat.com>
1 parent 1354585 commit 68ae69c

15 files changed

Lines changed: 140 additions & 1463 deletions

.github/scripts/mock_http_json.py

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -41,26 +41,28 @@ def log_message(self, *_args: object) -> None:
4141
# Keep Tekton step logs readable; every GET would otherwise print a line.
4242
return
4343

44-
def do_GET(self) -> None:
44+
def _route_body(self) -> bytes | None:
4545
parsed = urlparse(self.path)
4646
path = parsed.path.rstrip("/") or "/"
47-
body = None
4847
# Order in mocks.yaml matters: first matching rule wins (not most specific).
4948
for rule in self.routes:
5049
suf = rule.get("path_suffix")
5150
if suf is not None:
5251
# Match both "/auth/token" and "/auth/token/" style paths.
53-
if path.endswith(suf) or path.endswith(suf.rstrip("/")):
52+
suf_stripped = suf.rstrip("/")
53+
if path.endswith(suf) or (suf_stripped and path.endswith(suf_stripped)):
5454
# mocks.yaml body values are strings, not pre-serialized bytes.
55-
body = rule["body"].encode("utf-8")
56-
break
55+
return rule["body"].encode("utf-8")
5756
# path_suffix and path_contains are mutually exclusive per rule.
5857
continue
5958
sub = rule.get("path_contains")
6059
if sub is not None and sub in parsed.path:
6160
# Query string is ignored; only the path is checked.
62-
body = rule["body"].encode("utf-8")
63-
break
61+
return rule["body"].encode("utf-8")
62+
return None
63+
64+
def _send_routed_json(self) -> None:
65+
body = self._route_body()
6466
if body is None:
6567
# Unmatched paths look like "service down" to callers, not empty JSON.
6668
self.send_response(404)
@@ -72,6 +74,8 @@ def do_GET(self) -> None:
7274
self.end_headers()
7375
self.wfile.write(body)
7476

77+
do_GET = do_POST = _send_routed_json
78+
7579

7680
class _ReuseHTTPServer(HTTPServer):
7781
# Lets the test step restart the mock without "Address already in use".

.github/scripts/test_tekton_tasks.sh

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -62,10 +62,13 @@ apply_python_command_mocks_merge() {
6262
echo '#!/usr/bin/env bash'
6363
echo "TASK_ENTRYPOINT=("
6464
for w in "${entrypoint_argv[@]}"; do
65-
# Do not use printf %q for Tekton placeholders: single-quoted %q output
66-
# prevents Tekton from rewriting $(params.*) inside spec.steps[].script.
65+
# Tekton placeholders must stay unescaped so Tekton can substitute them
66+
# (printf %q would escape the '$'). Use single quotes so that JSON
67+
# values with embedded double quotes survive bash array construction.
68+
# Tekton does raw text replacement on the whole script string before
69+
# bash sees it, so single quotes do not prevent substitution.
6770
if [[ "$w" == *'$('* ]]; then
68-
printf ' "%s"\n' "$w"
71+
printf " '%s'\n" "$w"
6972
else
7073
printf ' %q\n' "$w"
7174
fi

tasks/internal/update-fbc-catalog-task/tests/mocks.sh

Lines changed: 0 additions & 379 deletions
This file was deleted.
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
---
2+
# Declarative mocks for Tekton tests of this task (Python entrypoint). Rendered
3+
# by .github/scripts/render_python_task_mocks_from_yaml.py when
4+
# test_tekton_tasks.sh runs.
5+
version: 1
6+
services:
7+
- type: http_json
8+
bind: 127.0.0.1
9+
routes:
10+
- path_suffix: /fbc-operations
11+
body: >-
12+
{"id":1,"state":"in_progress","state_reason":"The request was initiated",
13+
"from_index":"quay.io/scoheb/fbc-index-testing:latest",
14+
"index_image":"quay.io/scoheb/fbc-index-testing:latest",
15+
"fbc_fragments":["registry.io/image0@sha256:0000"],
16+
"distribution_scope":"stage",
17+
"logs":{"url":"http://127.0.0.1:8080/api/v1/builds/1/logs"}}
18+
- path_contains: /builds/1/logs
19+
body: "Mock IIB build log"
20+
- path_suffix: /builds/1
21+
body: >-
22+
{"id":1,"state":"complete",
23+
"state_reason":"The FBC fragment was successfully added in the index image",
24+
"from_index":"quay.io/scoheb/fbc-index-testing:latest",
25+
"index_image":"quay.io/scoheb/fbc-index-testing:latest",
26+
"index_image_resolved":"registry-proxy-stage.engineering.redhat.com/rh-osbs-stage/iib@sha256:0000",
27+
"internal_index_image_copy":"registry-proxy-stage.engineering.redhat.com/rh-osbs-stage/iib:1",
28+
"fbc_fragments":["registry.io/image0@sha256:0000"],
29+
"build_tags":[],"distribution_scope":"stage",
30+
"updated":"2025-01-01T00:00:00+00:00","created":"2025-01-01T00:00:00+00:00",
31+
"logs":{"url":"http://127.0.0.1:8080/api/v1/builds/1/logs"},
32+
"request_type":"fbc-operations"}
33+
- path_suffix: /builds
34+
body: '{"items":[]}'
35+
rewrite_secret_mount:
36+
source: /mnt/iib-services-config
37+
env_var: IIB_SERVICES_CONFIG_MOUNT
38+
url_file: url
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
#!/usr/bin/env bash
2+
# Tekton test mock: subprocess kinit in the task image succeeds without Kerberos.
3+
exit 0
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
#!/usr/bin/env bash
2+
# Tekton test mock: wrap python3 to inject a stub requests_kerberos module.
3+
# The real requests_kerberos needs a live Kerberos credential cache that
4+
# does not exist in test pods (kinit is mocked). This stub provides the
5+
# HTTPKerberosAuth class as a no-op auth handler so requests.Session.post()
6+
# proceeds without Negotiate headers.
7+
set -eu
8+
9+
MOCK_PYPATH="$(mktemp -d)"
10+
cat > "${MOCK_PYPATH}/requests_kerberos.py" << 'PYEOF'
11+
OPTIONAL = 1
12+
REQUIRED = 2
13+
DISABLED = 3
14+
15+
class HTTPKerberosAuth:
16+
def __init__(self, **kwargs):
17+
pass
18+
def __call__(self, r):
19+
return r
20+
PYEOF
21+
22+
export PYTHONPATH="${MOCK_PYPATH}:${PYTHONPATH:-}"
23+
exec /usr/bin/python3 "$@"
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
#!/usr/bin/env bash
2+
# Tekton test mock for skopeo inspect (called by helpers/skopeo.py via subprocess).
3+
set -eu
4+
5+
for arg in "$@"; do
6+
case "${arg}" in
7+
--config) CONFIG=true ;;
8+
--raw) RAW=true ;;
9+
esac
10+
done
11+
12+
if [[ "${RAW:-}" == "true" ]]; then
13+
cat <<'EOF'
14+
{"manifests":[
15+
{"mediaType":"application/vnd.docker.distribution.manifest.v2+json","digest":"sha256:000"},
16+
{"mediaType":"application/vnd.docker.distribution.manifest.v2+json","digest":"sha256:001"}
17+
]}
18+
EOF
19+
exit 0
20+
fi
21+
22+
if [[ "${CONFIG:-}" == "true" ]]; then
23+
echo "{\"created\":\"$(date --iso-8601=seconds)\"}"
24+
exit 0
25+
fi
26+
27+
echo "mock skopeo: unhandled args: $*" >&2
28+
exit 1

tasks/internal/update-fbc-catalog-task/tests/pre-apply-task-hook.sh

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,11 @@ kubectl apply -f .github/resources/crd_rbac.yaml
99
# create required secrets
1010
kubectl create secret generic iib-service-account-secret \
1111
--from-literal=principal="iib@kerberos" \
12-
--from-literal=keytab="something"
12+
--from-literal=keytab="c29tZXRoaW5n"
1313
kubectl create secret generic iib-services-config \
1414
--from-literal=krb5.conf="" \
1515
--from-literal=url="https://fakeiib.host"
1616

1717
kubectl create secret generic iib-overwrite-fromimage-credentials \
1818
--from-literal=username="bot+user" \
1919
--from-literal=token="token"
20-
21-
# Add mocks to the beginning of task step script
22-
TASK_PATH="$1"
23-
SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
24-
yq -i '.spec.steps[0].script = load_str("'$SCRIPT_DIR'/mocks.sh") + .spec.steps[0].script' "$TASK_PATH"
25-
yq -i '.spec.steps[1].script = load_str("'$SCRIPT_DIR'/mocks.sh") + .spec.steps[1].script' "$TASK_PATH"

tasks/internal/update-fbc-catalog-task/tests/test-update-fbc-catalog-auth-failure.yaml

Lines changed: 0 additions & 105 deletions
This file was deleted.

tasks/internal/update-fbc-catalog-task/tests/test-update-fbc-catalog-error.yaml

Lines changed: 0 additions & 90 deletions
This file was deleted.

0 commit comments

Comments
 (0)