Files
cozystack/hack/retention-delete_test.bats
Aleksei Sviridkin da1f1cc387 ci(retention): delete with the workflow token
The app installation token lists package versions but its DELETE of a
listed version is answered with 404, while the repository's
GITHUB_TOKEN with packages: write deleted the same version without any
change to package settings. Deletes therefore go through GITHUB_TOKEN;
listing keeps the app token.

That deletion was shown on a package linked to this repository. A
package linked elsewhere is not attempted: it is skipped before its
versions are read and named in a warning, so it cannot turn every
apply run red. A failed read of the link still fails the run, and so
does a sweep in which no resolved package is linked, since that sweep
prunes nothing.

Assisted-by: LLM
Signed-off-by: Aleksei Sviridkin <f@lex.la>
2026-10-10 21:15:48 +03:00

83 lines
2.5 KiB
Bash

#!/usr/bin/env bats
# Tests for hack/retention-delete.sh — the delete half of the GHCR retention
# workflow. A refused DELETE must fail the run: a sweep that only warns stays
# green while deleting nothing, which is how retention went unnoticed before.
#
# Run with: bats hack/retention-delete_test.bats
load test_helper
SCRIPT="${BATS_TEST_DIRNAME}/retention-delete.sh"
# gh stub: records every call, refuses version 2 the way the API does.
_stub_gh() {
mkdir -p "$1"
cat > "$1/gh" <<'EOF'
#!/bin/sh
printf '%s token=%s\n' "$*" "${GH_TOKEN:-}" >> "$GH_CALLS"
case "$*" in
*/versions/2*) echo 'gh: Forbidden (HTTP 403)' >&2; exit 1 ;;
esac
EOF
chmod +x "$1/gh"
}
setup() {
strict_setup
_stub_gh "${BATS_TEST_TMPDIR}/bin"
export PATH="${BATS_TEST_TMPDIR}/bin:$PATH"
export GH_CALLS="${BATS_TEST_TMPDIR}/calls"
export ORG=cozystack
export GH_TOKEN=app-token
export DELETE_TOKEN=workflow-token
: > "$GH_CALLS"
}
@test "apply: a refused delete is an error naming the HTTP status, the rest still run, exit is non-zero" {
run env APPLY=true "$SCRIPT" cozystack/foo version 1 2 3
[ "$status" -ne 0 ]
[ "$(wc -l < "$GH_CALLS" | tr -d ' ')" -eq 3 ]
grep -q 'cozystack%2Ffoo/versions/3' "$GH_CALLS"
case "$output" in
*"::error::"*"version 2"*"HTTP 403"*) ;;
*) echo "FAIL: no error with the HTTP status: $output"; false ;;
esac
}
@test "apply: all deletes succeeding exits zero" {
run env APPLY=true "$SCRIPT" cozystack/foo version 1 3
[ "$status" -eq 0 ]
[ "$(wc -l < "$GH_CALLS" | tr -d ' ')" -eq 2 ]
}
@test "dry-run calls nothing and exits zero" {
run env APPLY=false "$SCRIPT" cozystack/foo version 1 2 3
[ "$status" -eq 0 ]
[ ! -s "$GH_CALLS" ]
case "$output" in
*"would delete cozystack/foo version 2"*) ;;
*) echo "FAIL: dry-run did not report: $output"; false ;;
esac
}
@test "apply: deletes with DELETE_TOKEN, not the token that listed the versions" {
run env APPLY=true "$SCRIPT" cozystack/foo version 1
[ "$status" -eq 0 ]
grep -q 'versions/1 token=workflow-token$' "$GH_CALLS"
}
@test "apply: no DELETE_TOKEN is refused before any call" {
run env -u DELETE_TOKEN APPLY=true "$SCRIPT" cozystack/foo version 1
[ "$status" -ne 0 ]
[ ! -s "$GH_CALLS" ]
case "$output" in
*"DELETE_TOKEN is required"*) ;;
*) echo "FAIL: refusal does not name DELETE_TOKEN: $output"; false ;;
esac
}
@test "dry-run needs no DELETE_TOKEN" {
run env -u DELETE_TOKEN APPLY=false "$SCRIPT" cozystack/foo version 1
[ "$status" -eq 0 ]
}