Merge pull request #80 from living-ip/codex/gcp-iap-failure-receipt
Some checks are pending
CI / lint-and-test (push) Waiting to run
Some checks are pending
CI / lint-and-test (push) Waiting to run
Retain sanitized GCP operator failure receipts
This commit is contained in:
commit
206ea51951
2 changed files with 64 additions and 0 deletions
47
.github/workflows/gcp-iap-operator.yml
vendored
47
.github/workflows/gcp-iap-operator.yml
vendored
|
|
@ -179,11 +179,13 @@ jobs:
|
||||||
export_environment_variables: true
|
export_environment_variables: true
|
||||||
|
|
||||||
- name: Install Google Cloud CLI
|
- name: Install Google Cloud CLI
|
||||||
|
id: setup_gcloud
|
||||||
uses: google-github-actions/setup-gcloud@v3
|
uses: google-github-actions/setup-gcloud@v3
|
||||||
with:
|
with:
|
||||||
project_id: ${{ env.PROJECT_ID }}
|
project_id: ${{ env.PROJECT_ID }}
|
||||||
|
|
||||||
- name: Run fixed IAP operation
|
- name: Run fixed IAP operation
|
||||||
|
id: operate
|
||||||
shell: bash
|
shell: bash
|
||||||
env:
|
env:
|
||||||
OPERATION: ${{ inputs.operation }}
|
OPERATION: ${{ inputs.operation }}
|
||||||
|
|
@ -193,6 +195,51 @@ jobs:
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
scripts/gcp_iap_operator.sh "${OPERATION}" "${REQUEST_ID}" "${TARGET_DB}"
|
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
|
- name: Upload sanitized result
|
||||||
if: always()
|
if: always()
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v4
|
||||||
|
|
|
||||||
|
|
@ -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")
|
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:
|
def test_workflow_builds_exact_main_bundle_from_tracked_files_and_hashes() -> None:
|
||||||
source = WORKFLOW.read_text(encoding="utf-8")
|
source = WORKFLOW.read_text(encoding="utf-8")
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue