diff --git a/.github/workflows/_probe-empty-stack-command.yml b/.github/workflows/_probe-empty-stack-command.yml new file mode 100644 index 0000000..9be7232 --- /dev/null +++ b/.github/workflows/_probe-empty-stack-command.yml @@ -0,0 +1,11 @@ +name: _probe-empty-stack-command +on: + pull_request: + branches: [main] +jobs: + probe: + uses: ./.github/workflows/stack-tests.yml + with: + gate-name: probe + compose-file: probe-compose.yaml + stack-command: "" diff --git a/.github/workflows/stack-tests.yml b/.github/workflows/stack-tests.yml index 7658114..c9737f8 100644 --- a/.github/workflows/stack-tests.yml +++ b/.github/workflows/stack-tests.yml @@ -79,6 +79,17 @@ jobs: shell: bash run: ${{ inputs.ready-command }} + - name: Reject an empty stack-command + shell: bash + env: + STACK_COMMAND: ${{ inputs.stack-command }} + run: | + set -euo pipefail + if [[ -z "${STACK_COMMAND// /}" ]]; then + echo "::error::stack-command must not be empty or blank -- an empty run: step succeeds having run no ${{ inputs.gate-name }} gate (FR-017: a gate must fail visibly, never pass silently)" + exit 1 + fi + - name: Run ${{ inputs.gate-name }} gate shell: bash run: ${{ inputs.stack-command }} diff --git a/probe-compose.yaml b/probe-compose.yaml new file mode 100644 index 0000000..48bbb83 --- /dev/null +++ b/probe-compose.yaml @@ -0,0 +1,3 @@ +services: + redis: + image: redis:7-alpine diff --git a/tests/workflows/stack-tests-contract.bats b/tests/workflows/stack-tests-contract.bats new file mode 100644 index 0000000..712b8d8 --- /dev/null +++ b/tests/workflows/stack-tests-contract.bats @@ -0,0 +1,22 @@ +#!/usr/bin/env bash +# Contract test for the reusable stack-tests workflow (gitops spec 007 T027). +# Same grep-the-contract style as tests/workflows/reusable-workflow-contract.bats. +# stack-command is required: true with no default, exactly like ci.yml's +# test-command was before gitops spec 003 T024 found it could be silently +# satisfied by an empty string -- this guards the same failure mode here. +set -euo pipefail + +root="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" +stack_tests="$root/.github/workflows/stack-tests.yml" + +fail() { echo "stack-tests-contract: $*" >&2; exit 1; } +have() { grep -Fq -- "$2" "$1" || fail "$3"; } + +[[ -f "$stack_tests" ]] || fail "missing required file: $stack_tests" + +have "$stack_tests" "workflow_call" "stack-tests.yml must be a reusable workflow" +have "$stack_tests" "stack-command:" "stack-tests.yml must take a required stack-command gate" +have "$stack_tests" "stack-command must not be empty or blank" \ + "stack-tests.yml must fail visibly on an empty stack-command, never pass having run no gate (FR-017, gitops spec 007 T027)" + +echo "stack-tests-contract: OK -- stack-tests.yml is a reusable workflow that fails visibly on an empty stack-command."