Retain sanitized GCP operator failure receipts

This commit is contained in:
twentyOne2x 2026-07-12 05:25:21 +02:00
parent fe8e3bd9a4
commit eb7abc045d
2 changed files with 64 additions and 0 deletions

View file

@ -179,11 +179,13 @@ jobs:
export_environment_variables: true
- name: Install Google Cloud CLI
id: setup_gcloud
uses: google-github-actions/setup-gcloud@v3
with:
project_id: ${{ env.PROJECT_ID }}
- name: Run fixed IAP operation
id: operate
shell: bash
env:
OPERATION: ${{ inputs.operation }}
@ -193,6 +195,51 @@ jobs:
set -euo pipefail
scripts/gcp_iap_operator.sh "${OPERATION}" "${REQUEST_ID}" "${TARGET_DB}"
- name: Ensure sanitized result receipt
if: always()
shell: bash
env:
OPERATION: ${{ inputs.operation }}
REQUEST_ID: ${{ inputs.request_id }}
TARGET_DB: ${{ inputs.target_db }}
VALIDATE_OUTCOME: ${{ steps.validate.outcome }}
AUTH_OUTCOME: ${{ steps.auth.outcome }}
SETUP_GCLOUD_OUTCOME: ${{ steps.setup_gcloud.outcome }}
OPERATE_OUTCOME: ${{ steps.operate.outcome }}
run: |
set -euo pipefail
install -d -m 0700 "${RESULT_DIR}"
result_path="${RESULT_DIR}/result.json"
if [[ -s "${result_path}" ]] && python3 -c 'import json,sys; json.load(open(sys.argv[1]))' "${result_path}"; then
exit 0
fi
RESULT_PATH="${result_path}" python3 - <<'PY'
import json
import os
from pathlib import Path
result = {
"schema": "livingip.gcpIapOperatorResult.v1",
"operation": os.environ["OPERATION"],
"request_id": os.environ["REQUEST_ID"],
"target_db": os.environ["TARGET_DB"],
"status": "fail",
"failure_class": "workflow_stopped_before_valid_operator_result",
"step_outcomes": {
"validate": os.environ["VALIDATE_OUTCOME"],
"auth": os.environ["AUTH_OUTCOME"],
"setup_gcloud": os.environ["SETUP_GCLOUD_OUTCOME"],
"operate": os.environ["OPERATE_OUTCOME"],
},
"credential_values_logged": False,
"raw_stdout_retained": False,
"raw_stderr_retained": False,
}
path = Path(os.environ["RESULT_PATH"])
path.write_text(json.dumps(result, indent=2, sort_keys=True) + "\n", encoding="utf-8")
path.chmod(0o600)
PY
- name: Upload sanitized result
if: always()
uses: actions/upload-artifact@v4

View file

@ -153,6 +153,23 @@ def test_workflow_initializes_runner_paths_at_step_runtime() -> None:
assert "runner.temp" not in WORKFLOW.read_text(encoding="utf-8")
def test_workflow_retains_sanitized_failure_receipt_before_upload() -> None:
workflow = load_workflow()
steps = workflow["jobs"]["operate"]["steps"]
receipt_index = next(i for i, step in enumerate(steps) if step.get("name") == "Ensure sanitized result receipt")
upload_index = next(i for i, step in enumerate(steps) if step.get("uses") == "actions/upload-artifact@v4")
receipt = steps[receipt_index]
source = receipt["run"]
assert receipt_index < upload_index
assert receipt["if"] == "always()"
assert receipt["env"]["AUTH_OUTCOME"] == "${{ steps.auth.outcome }}"
assert receipt["env"]["OPERATE_OUTCOME"] == "${{ steps.operate.outcome }}"
assert "workflow_stopped_before_valid_operator_result" in source
assert '"credential_values_logged": False' in source
assert '"raw_stdout_retained": False' in source
assert '"raw_stderr_retained": False' in source
def test_workflow_builds_exact_main_bundle_from_tracked_files_and_hashes() -> None:
source = WORKFLOW.read_text(encoding="utf-8")