ci: publish exact no-send candidate through WIF
This commit is contained in:
parent
fda8ab1e6d
commit
d36a6d8cc1
3 changed files with 431 additions and 0 deletions
1
.github/workflows/ci.yml
vendored
1
.github/workflows/ci.yml
vendored
|
|
@ -100,6 +100,7 @@ jobs:
|
|||
tests/test_decision_engine_replay.py \
|
||||
tests/test_evaluate_agent_routing.py \
|
||||
tests/test_gcp_artifact_workflow.py \
|
||||
tests/test_gcp_leoclean_nosend_release_workflow.py \
|
||||
tests/test_capture_vps_canonical_postgres_snapshot.py \
|
||||
tests/test_gcp_infra_execute_canary.py \
|
||||
tests/test_gcp_infra_readiness_checker.py \
|
||||
|
|
|
|||
284
.github/workflows/gcp-leoclean-nosend-release.yml
vendored
Normal file
284
.github/workflows/gcp-leoclean-nosend-release.yml
vendored
Normal file
|
|
@ -0,0 +1,284 @@
|
|||
name: gcp-leoclean-nosend-release
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
id-token: write
|
||||
|
||||
concurrency:
|
||||
group: gcp-leoclean-nosend-release-main
|
||||
cancel-in-progress: false
|
||||
|
||||
env:
|
||||
PROJECT_ID: teleo-501523
|
||||
REGION: europe-west6
|
||||
ARTIFACT_REPOSITORY: teleo
|
||||
IMAGE_REPOSITORY: europe-west6-docker.pkg.dev/teleo-501523/teleo/leoclean-nosend-staging
|
||||
WORKLOAD_IDENTITY_PROVIDER: projects/785938879453/locations/global/workloadIdentityPools/github-actions/providers/living-ip-github
|
||||
ARTIFACT_SERVICE_ACCOUNT: sa-artifact-builder@teleo-501523.iam.gserviceaccount.com
|
||||
|
||||
jobs:
|
||||
publish:
|
||||
name: Build, smoke, and publish exact no-send release
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 90
|
||||
env:
|
||||
RELEASE_ROOT: ${{ runner.temp }}/leoclean-nosend-release
|
||||
RUNTIME_ARTIFACT: ${{ runner.temp }}/leoclean-nosend-release/runtime-artifact
|
||||
RUNTIME_RECEIPT: ${{ runner.temp }}/leoclean-nosend-release/evidence/runtime-receipt.json
|
||||
OCI_SMOKE_RECEIPT: ${{ runner.temp }}/leoclean-nosend-release/evidence/oci-smoke.json
|
||||
IMAGE_CONTEXT: ${{ runner.temp }}/leoclean-nosend-release/image-context
|
||||
BUILD_PUSH_RECEIPT: ${{ runner.temp }}/leoclean-nosend-release/receipts/build-push-receipt.json
|
||||
RELEASE_BUNDLE: ${{ runner.temp }}/leoclean-nosend-release/final/release-v3
|
||||
DOCKER_CONFIG: ${{ runner.temp }}/leoclean-nosend-release/docker-config
|
||||
steps:
|
||||
- name: Require manual main dispatch
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
test "${GITHUB_EVENT_NAME}" = "workflow_dispatch"
|
||||
test "${GITHUB_REF}" = "refs/heads/main"
|
||||
test "${GITHUB_REF_TYPE}" = "branch"
|
||||
|
||||
- name: Check out exact dispatched revision
|
||||
uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262
|
||||
with:
|
||||
fetch-depth: 0
|
||||
persist-credentials: false
|
||||
ref: ${{ github.sha }}
|
||||
|
||||
- name: Verify exact clean main revision
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
test "$(git rev-parse --verify HEAD)" = "${GITHUB_SHA}"
|
||||
test "$(git rev-parse --verify refs/remotes/origin/main^{commit})" = "${GITHUB_SHA}"
|
||||
test -z "$(git status --porcelain=v1 --untracked-files=all)"
|
||||
|
||||
- name: Set up exact Python
|
||||
uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065
|
||||
with:
|
||||
python-version: "3.11.9"
|
||||
|
||||
- name: Install exact no-send build tools
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
python -m pip install --disable-pip-version-check 'uv==0.9.30' 'PyYAML==6.0.3'
|
||||
test "$(uv --version | awk '{print $2}')" = "0.9.30"
|
||||
test "$(command -v docker)" = "/usr/bin/docker"
|
||||
|
||||
- name: Verify fixed staging package target
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
python - <<'PY'
|
||||
import os
|
||||
|
||||
from ops import gcp_leoclean_nosend_package as package
|
||||
|
||||
assert package.PROJECT == "teleo-501523"
|
||||
assert package.PLATFORM == "linux/amd64"
|
||||
assert os.environ["IMAGE_REPOSITORY"] == package.IMAGE_REPOSITORY
|
||||
assert package.IMAGE_REPOSITORY == "europe-west6-docker.pkg.dev/teleo-501523/teleo/leoclean-nosend-staging"
|
||||
PY
|
||||
|
||||
- name: Pull digest-pinned OCI bases
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
docker pull --platform=linux/amd64 \
|
||||
"ghcr.io/astral-sh/uv:0.9.30@sha256:538e0b39736e7feae937a65983e49d2ab75e1559d35041f9878b7b7e51de91e4"
|
||||
docker pull --platform=linux/amd64 \
|
||||
"docker.io/library/python:3.11.9-slim-bookworm@sha256:8fb099199b9f2d70342674bd9dbccd3ed03a258f26bbd1d556822c6dfc60c317"
|
||||
docker pull --platform=linux/amd64 \
|
||||
"docker.io/library/postgres:16.14-bookworm@sha256:92620daddcd947f8d5ab5ba66e848702fe443d87fed30c4cea8e389fd78dfc55"
|
||||
|
||||
- name: Compile and release-verify exact runtime artifact
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
install -d -m 0700 "${RELEASE_ROOT}" "${RELEASE_ROOT}/evidence"
|
||||
LEOCLEAN_NOSEND_RESULTS_DIR="${RELEASE_ROOT}/evidence" \
|
||||
LEOCLEAN_NOSEND_RECEIPT="${RUNTIME_RECEIPT}" \
|
||||
LEOCLEAN_NOSEND_ARTIFACT_OUTPUT="${RUNTIME_ARTIFACT}" \
|
||||
scripts/run_leoclean_nosend_runtime_canary.sh
|
||||
|
||||
- name: Smoke exact no-send OCI surface
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
python scripts/run_gcp_leoclean_nosend_oci_smoke.py \
|
||||
--repo-root "${GITHUB_WORKSPACE}" \
|
||||
--artifact "${RUNTIME_ARTIFACT}" \
|
||||
--runtime-receipt "${RUNTIME_RECEIPT}" \
|
||||
--output "${OCI_SMOKE_RECEIPT}"
|
||||
|
||||
- name: Prepare exact candidate context
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
identity_contract="${RELEASE_ROOT}/identity-runtime-contract.json"
|
||||
identity_manifest="${RELEASE_ROOT}/identity-manifest.json"
|
||||
identity_bundle="${RELEASE_ROOT}/identity"
|
||||
|
||||
python ops/gcp_leoclean_nosend_package.py identity-contract \
|
||||
--repo-root "${GITHUB_WORKSPACE}" \
|
||||
--artifact "${RUNTIME_ARTIFACT}" \
|
||||
--receipt "${RUNTIME_RECEIPT}" \
|
||||
--output "${identity_contract}"
|
||||
python ops/gcp_leoclean_nosend_package.py generate-identity-manifest \
|
||||
--repo-root "${GITHUB_WORKSPACE}" \
|
||||
--artifact "${RUNTIME_ARTIFACT}" \
|
||||
--receipt "${RUNTIME_RECEIPT}" \
|
||||
--database-fingerprint fixtures/working-leo/leo-identity-v1/leo-database-fingerprint-v1.json \
|
||||
--constitution fixtures/working-leo/leo-identity-v1/leo-constitution-v1.json \
|
||||
--database-identity fixtures/working-leo/leo-identity-v1/leo-database-identity-v1.json \
|
||||
--identity-source-root "${GITHUB_WORKSPACE}" \
|
||||
--output "${identity_manifest}"
|
||||
python ops/gcp_leoclean_nosend_package.py compile-identity \
|
||||
--repo-root "${GITHUB_WORKSPACE}" \
|
||||
--artifact "${RUNTIME_ARTIFACT}" \
|
||||
--receipt "${RUNTIME_RECEIPT}" \
|
||||
--identity-manifest "${identity_manifest}" \
|
||||
--identity-source-root "${GITHUB_WORKSPACE}" \
|
||||
--output "${identity_bundle}"
|
||||
python ops/gcp_leoclean_nosend_package.py prepare \
|
||||
--repo-root "${GITHUB_WORKSPACE}" \
|
||||
--artifact "${RUNTIME_ARTIFACT}" \
|
||||
--receipt "${RUNTIME_RECEIPT}" \
|
||||
--identity "${identity_bundle}" \
|
||||
--identity-source-root "${GITHUB_WORKSPACE}" \
|
||||
--output "${IMAGE_CONTEXT}"
|
||||
|
||||
python - "${OCI_SMOKE_RECEIPT}" "${IMAGE_CONTEXT}/image-input.json" "${GITHUB_SHA}" <<'PY'
|
||||
import json
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
smoke = json.loads(Path(sys.argv[1]).read_text(encoding="utf-8"))
|
||||
image_input = json.loads(Path(sys.argv[2]).read_text(encoding="utf-8"))
|
||||
revision = sys.argv[3]
|
||||
assert smoke["status"] == "pass"
|
||||
assert smoke["cleanup"]["status"] == "pass"
|
||||
assert smoke["teleo_git_head"] == revision
|
||||
assert image_input["runtime"]["teleo_git_head"] == revision
|
||||
assert smoke["input_sha256"] == image_input["input_sha256"]
|
||||
assert smoke["identity_sha256"] == image_input["identity"]["bundle_sha256"]
|
||||
PY
|
||||
|
||||
- name: Authenticate to Google Cloud through WIF
|
||||
id: auth
|
||||
uses: google-github-actions/auth@c200f3691d83b41bf9bbd8638997a462592937ed
|
||||
with:
|
||||
workload_identity_provider: ${{ env.WORKLOAD_IDENTITY_PROVIDER }}
|
||||
service_account: ${{ env.ARTIFACT_SERVICE_ACCOUNT }}
|
||||
create_credentials_file: true
|
||||
export_environment_variables: true
|
||||
|
||||
- name: Set up exact gcloud
|
||||
uses: google-github-actions/setup-gcloud@e427ad8a34f8676edf47cf7d7925499adf3eb74f
|
||||
with:
|
||||
version: "550.0.0"
|
||||
|
||||
- name: Require immutable fixed Artifact Registry repository
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
repository_readback="${RUNNER_TEMP}/leoclean-nosend-repository.json"
|
||||
umask 077
|
||||
gcloud artifacts repositories describe "${ARTIFACT_REPOSITORY}" \
|
||||
--project "${PROJECT_ID}" \
|
||||
--location "${REGION}" \
|
||||
--format json >"${repository_readback}"
|
||||
python - "${repository_readback}" <<'PY'
|
||||
import json
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
repository = json.loads(Path(sys.argv[1]).read_text(encoding="utf-8"))
|
||||
assert repository["name"] == (
|
||||
"projects/teleo-501523/locations/europe-west6/repositories/teleo"
|
||||
)
|
||||
assert repository["format"] == "DOCKER"
|
||||
assert repository["dockerConfig"]["immutableTags"] is True
|
||||
PY
|
||||
rm -f -- "${repository_readback}"
|
||||
|
||||
- name: Configure private Artifact Registry Docker auth
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
install -d -m 0700 "${DOCKER_CONFIG}"
|
||||
gcloud auth configure-docker "${REGION}-docker.pkg.dev" --quiet
|
||||
test -f "${DOCKER_CONFIG}/config.json"
|
||||
test ! -L "${DOCKER_CONFIG}/config.json"
|
||||
chmod 0600 "${DOCKER_CONFIG}/config.json"
|
||||
|
||||
- name: Build and push one immutable candidate
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
install -d -m 0700 "$(dirname "${BUILD_PUSH_RECEIPT}")"
|
||||
python ops/gcp_leoclean_nosend_package.py build-push \
|
||||
--repo-root "${GITHUB_WORKSPACE}" \
|
||||
--image-context "${IMAGE_CONTEXT}" \
|
||||
--docker-binary /usr/bin/docker \
|
||||
--docker-host unix:///var/run/docker.sock \
|
||||
--docker-config "${DOCKER_CONFIG}" \
|
||||
--output-receipt "${BUILD_PUSH_RECEIPT}" \
|
||||
--execute-staging-push
|
||||
|
||||
- name: Finalize and validate release v3 bundle
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
install -d -m 0700 "$(dirname "${RELEASE_BUNDLE}")"
|
||||
python ops/gcp_leoclean_nosend_package.py finalize \
|
||||
--image-input "${IMAGE_CONTEXT}/image-input.json" \
|
||||
--build-push-receipt "${BUILD_PUSH_RECEIPT}" \
|
||||
--docker-binary /usr/bin/docker \
|
||||
--docker-host unix:///var/run/docker.sock \
|
||||
--docker-config "${DOCKER_CONFIG}" \
|
||||
--output-bundle "${RELEASE_BUNDLE}"
|
||||
python ops/gcp_leoclean_nosend_package.py validate \
|
||||
--release "${RELEASE_BUNDLE}/release.json"
|
||||
|
||||
python - "${BUILD_PUSH_RECEIPT}" "${RELEASE_BUNDLE}/release.json" "${OCI_SMOKE_RECEIPT}" "${GITHUB_SHA}" <<'PY'
|
||||
import json
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
receipt = json.loads(Path(sys.argv[1]).read_text(encoding="utf-8"))
|
||||
release = json.loads(Path(sys.argv[2]).read_text(encoding="utf-8"))
|
||||
smoke = json.loads(Path(sys.argv[3]).read_text(encoding="utf-8"))
|
||||
revision = sys.argv[4]
|
||||
assert receipt["schema"] == "livingip.leocleanNoSendBuildPushReceipt.v1"
|
||||
assert release["schema"] == "livingip.leocleanNoSendRelease.v3"
|
||||
assert release["build_push_receipt"] == receipt
|
||||
assert release["image_input"]["runtime"]["teleo_git_head"] == revision
|
||||
assert release["image_input"]["input_sha256"] == smoke["input_sha256"]
|
||||
assert release["image"]["reference"].startswith(
|
||||
"europe-west6-docker.pkg.dev/teleo-501523/teleo/leoclean-nosend-staging@sha256:"
|
||||
)
|
||||
PY
|
||||
|
||||
- name: Upload exact build and release evidence
|
||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02
|
||||
with:
|
||||
name: leoclean-nosend-release-${{ github.sha }}
|
||||
path: |
|
||||
${{ env.RUNTIME_RECEIPT }}
|
||||
${{ env.OCI_SMOKE_RECEIPT }}
|
||||
${{ env.BUILD_PUSH_RECEIPT }}
|
||||
${{ env.RELEASE_BUNDLE }}/release.json
|
||||
${{ env.RELEASE_BUNDLE }}/leoclean-gcp-nosend.service
|
||||
if-no-files-found: error
|
||||
retention-days: 30
|
||||
|
||||
- name: Remove ephemeral Docker authentication
|
||||
if: always()
|
||||
shell: bash
|
||||
run: rm -rf -- "${DOCKER_CONFIG}"
|
||||
146
tests/test_gcp_leoclean_nosend_release_workflow.py
Normal file
146
tests/test_gcp_leoclean_nosend_release_workflow.py
Normal file
|
|
@ -0,0 +1,146 @@
|
|||
from pathlib import Path
|
||||
|
||||
import yaml
|
||||
|
||||
from ops import gcp_leoclean_nosend_package as package
|
||||
|
||||
WORKFLOW = Path(".github/workflows/gcp-leoclean-nosend-release.yml")
|
||||
|
||||
|
||||
def load_workflow() -> dict[str, object]:
|
||||
return yaml.load(WORKFLOW.read_text(encoding="utf-8"), Loader=yaml.BaseLoader)
|
||||
|
||||
|
||||
def workflow_step(name: str) -> dict[str, object]:
|
||||
workflow = load_workflow()
|
||||
jobs = workflow["jobs"]
|
||||
assert isinstance(jobs, dict)
|
||||
publish = jobs["publish"]
|
||||
assert isinstance(publish, dict)
|
||||
steps = publish["steps"]
|
||||
assert isinstance(steps, list)
|
||||
return next(step for step in steps if step.get("name") == name)
|
||||
|
||||
|
||||
def test_release_workflow_is_manual_main_only_and_serialized() -> None:
|
||||
workflow = load_workflow()
|
||||
|
||||
assert set(workflow["on"]) == {"workflow_dispatch"}
|
||||
assert workflow["permissions"] == {"contents": "read", "id-token": "write"}
|
||||
assert workflow["concurrency"] == {
|
||||
"group": "gcp-leoclean-nosend-release-main",
|
||||
"cancel-in-progress": "false",
|
||||
}
|
||||
guard = workflow_step("Require manual main dispatch")["run"]
|
||||
assert 'test "${GITHUB_EVENT_NAME}" = "workflow_dispatch"' in guard
|
||||
assert 'test "${GITHUB_REF}" = "refs/heads/main"' in guard
|
||||
assert 'test "${GITHUB_REF_TYPE}" = "branch"' in guard
|
||||
|
||||
|
||||
def test_release_workflow_checks_out_exact_clean_revision_without_persisted_token() -> None:
|
||||
step = workflow_step("Check out exact dispatched revision")
|
||||
|
||||
assert step["uses"] == "actions/checkout@11d5960a326750d5838078e36cf38b85af677262"
|
||||
assert step["with"] == {
|
||||
"fetch-depth": "0",
|
||||
"persist-credentials": "false",
|
||||
"ref": "${{ github.sha }}",
|
||||
}
|
||||
revision_check = workflow_step("Verify exact clean main revision")["run"]
|
||||
assert 'test "$(git rev-parse --verify HEAD)" = "${GITHUB_SHA}"' in revision_check
|
||||
assert 'test "$(git rev-parse --verify refs/remotes/origin/main^{commit})" = "${GITHUB_SHA}"' in revision_check
|
||||
assert "git status --porcelain=v1 --untracked-files=all" in revision_check
|
||||
|
||||
|
||||
def test_release_workflow_smokes_before_requesting_cloud_identity() -> None:
|
||||
workflow = WORKFLOW.read_text(encoding="utf-8")
|
||||
|
||||
smoke = workflow.index("Smoke exact no-send OCI surface")
|
||||
auth = workflow.index("Authenticate to Google Cloud through WIF")
|
||||
push = workflow.index("Build and push one immutable candidate")
|
||||
finalize = workflow.index("Finalize and validate release v3 bundle")
|
||||
upload = workflow.index("Upload exact build and release evidence")
|
||||
assert smoke < auth < push < finalize < upload
|
||||
assert "scripts/run_leoclean_nosend_runtime_canary.sh" in workflow
|
||||
assert "scripts/run_gcp_leoclean_nosend_oci_smoke.py" in workflow
|
||||
assert 'assert smoke["input_sha256"] == image_input["input_sha256"]' in workflow
|
||||
assert 'assert smoke["cleanup"]["status"] == "pass"' in workflow
|
||||
|
||||
|
||||
def test_release_workflow_uses_exact_wif_artifact_builder_without_repository_secrets() -> None:
|
||||
workflow = load_workflow()
|
||||
text = WORKFLOW.read_text(encoding="utf-8")
|
||||
env = workflow["env"]
|
||||
|
||||
assert env["PROJECT_ID"] == "teleo-501523"
|
||||
assert env["REGION"] == "europe-west6"
|
||||
assert env["ARTIFACT_REPOSITORY"] == "teleo"
|
||||
assert env["IMAGE_REPOSITORY"] == package.IMAGE_REPOSITORY
|
||||
assert env["WORKLOAD_IDENTITY_PROVIDER"] == (
|
||||
"projects/785938879453/locations/global/workloadIdentityPools/github-actions/providers/living-ip-github"
|
||||
)
|
||||
assert env["ARTIFACT_SERVICE_ACCOUNT"] == "sa-artifact-builder@teleo-501523.iam.gserviceaccount.com"
|
||||
assert "${{ secrets." not in text
|
||||
assert "password" not in text.casefold()
|
||||
|
||||
auth = workflow_step("Authenticate to Google Cloud through WIF")
|
||||
assert auth["uses"] == "google-github-actions/auth@c200f3691d83b41bf9bbd8638997a462592937ed"
|
||||
assert auth["with"] == {
|
||||
"workload_identity_provider": "${{ env.WORKLOAD_IDENTITY_PROVIDER }}",
|
||||
"service_account": "${{ env.ARTIFACT_SERVICE_ACCOUNT }}",
|
||||
"create_credentials_file": "true",
|
||||
"export_environment_variables": "true",
|
||||
}
|
||||
|
||||
|
||||
def test_release_workflow_requires_immutable_repository_and_package_owned_candidate_push() -> None:
|
||||
workflow = WORKFLOW.read_text(encoding="utf-8")
|
||||
immutable = workflow_step("Require immutable fixed Artifact Registry repository")["run"]
|
||||
push = workflow_step("Build and push one immutable candidate")["run"]
|
||||
|
||||
assert "gcloud artifacts repositories describe" in immutable
|
||||
assert 'repository["dockerConfig"]["immutableTags"] is True' in immutable
|
||||
assert "ops/gcp_leoclean_nosend_package.py build-push" in push
|
||||
assert "--execute-staging-push" in push
|
||||
assert "--docker-binary /usr/bin/docker" in push
|
||||
assert "--docker-host unix:///var/run/docker.sock" in push
|
||||
assert "docker push" not in workflow
|
||||
assert "docker tag" not in workflow
|
||||
assert "candidate-" not in workflow
|
||||
|
||||
|
||||
def test_release_workflow_finalizes_v3_and_uploads_only_allowlisted_evidence() -> None:
|
||||
finalize = workflow_step("Finalize and validate release v3 bundle")["run"]
|
||||
upload = workflow_step("Upload exact build and release evidence")
|
||||
paths = upload["with"]["path"].splitlines()
|
||||
|
||||
assert "ops/gcp_leoclean_nosend_package.py finalize" in finalize
|
||||
assert "ops/gcp_leoclean_nosend_package.py validate" in finalize
|
||||
assert 'assert release["schema"] == "livingip.leocleanNoSendRelease.v3"' in finalize
|
||||
assert paths == [
|
||||
"${{ env.RUNTIME_RECEIPT }}",
|
||||
"${{ env.OCI_SMOKE_RECEIPT }}",
|
||||
"${{ env.BUILD_PUSH_RECEIPT }}",
|
||||
"${{ env.RELEASE_BUNDLE }}/release.json",
|
||||
"${{ env.RELEASE_BUNDLE }}/leoclean-gcp-nosend.service",
|
||||
]
|
||||
assert upload["with"]["if-no-files-found"] == "error"
|
||||
assert upload["with"]["retention-days"] == "30"
|
||||
assert "*" not in upload["with"]["path"]
|
||||
assert "google-github-actions" not in upload["with"]["path"]
|
||||
|
||||
|
||||
def test_release_workflow_has_no_deployment_or_runtime_mutation_surface() -> None:
|
||||
workflow = WORKFLOW.read_text(encoding="utf-8").casefold()
|
||||
forbidden = (
|
||||
"--execute-restart",
|
||||
"install_gcp_leoclean_nosend_release.py",
|
||||
"gcloud compute",
|
||||
"gcloud sql",
|
||||
"gcloud secrets",
|
||||
"kubectl",
|
||||
"systemctl",
|
||||
"terraform apply",
|
||||
)
|
||||
|
||||
assert all(marker not in workflow for marker in forbidden)
|
||||
Loading…
Reference in a new issue