Gate legacy artifact publication to manual main dispatch
This commit is contained in:
parent
832f0c3f47
commit
74cff4b048
3 changed files with 52 additions and 6 deletions
10
.github/workflows/gcp-artifact.yml
vendored
10
.github/workflows/gcp-artifact.yml
vendored
|
|
@ -1,9 +1,6 @@
|
|||
name: gcp-artifact
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
|
|
@ -28,6 +25,13 @@ jobs:
|
|||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 20
|
||||
steps:
|
||||
- name: Require manual main dispatch
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
test "${GITHUB_EVENT_NAME}" = "workflow_dispatch"
|
||||
test "${GITHUB_REF}" = "refs/heads/main"
|
||||
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- id: auth
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ the current readiness run passes.
|
|||
- `roles/storage.objectViewer`
|
||||
- GitHub Actions can publish Artifact Registry images through Workload Identity Federation:
|
||||
- workflow: `.github/workflows/gcp-artifact.yml`
|
||||
- trigger: explicit `workflow_dispatch` only; ordinary branch pushes never publish
|
||||
- provider: `projects/785938879453/locations/global/workloadIdentityPools/github-actions/providers/living-ip-github`
|
||||
- service account: `sa-artifact-builder@teleo-501523.iam.gserviceaccount.com`
|
||||
- repository scope: `living-ip/teleo-infrastructure`
|
||||
|
|
@ -53,13 +54,31 @@ the current readiness run passes.
|
|||
|
||||
## How To Build
|
||||
|
||||
Automatic Artifact Registry publishing runs on pushes to `main` through GitHub Actions. To run the same lane manually from GitHub:
|
||||
The legacy `teleo-pipeline-gcp-staging` image is never published by an ordinary
|
||||
push to `main`. Publishing it is a live Artifact Registry mutation and requires
|
||||
an explicit manual dispatch from the reviewed `main` revision:
|
||||
|
||||
```bash
|
||||
gh workflow run gcp-artifact.yml --repo living-ip/teleo-infrastructure --ref main
|
||||
```
|
||||
|
||||
The workflow authenticates to GCP with Workload Identity Federation, builds `Dockerfile.gcp-staging`, runs the image smoke test, pushes the image, and uploads `gcp-artifact-image.txt` as a run artifact.
|
||||
The workflow authenticates to GCP with Workload Identity Federation, builds
|
||||
`Dockerfile.gcp-staging`, runs the image smoke test, pushes the image, and
|
||||
uploads `gcp-artifact-image.txt` as a run artifact. This is the legacy Teleo
|
||||
pipeline image path; it does not publish the separately reviewed
|
||||
`leoclean-nosend-staging` artifact.
|
||||
|
||||
The first job step fails before checkout or cloud authentication unless the
|
||||
event is `workflow_dispatch` and the selected ref is `refs/heads/main`. This is
|
||||
a repository-owned execution guard. The current Workload Identity Federation
|
||||
condition remains repository-scoped rather than IAM ref-scoped; binding the
|
||||
principal to `main` in IAM is a separate reviewed live-GCP hardening decision.
|
||||
|
||||
The manual-only governance change does not attest or repair that legacy image.
|
||||
The last run that reached a runner (`29810180369`) failed before publication
|
||||
because `Dockerfile.gcp-staging` did not copy the packaged
|
||||
`observatory_read_adapter` directory. Do not dispatch the legacy publisher
|
||||
until a separate reviewed repair or retirement decision closes that defect.
|
||||
|
||||
For a read-only GCP posture probe through the same Workload Identity path:
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,31 @@
|
|||
from pathlib import Path
|
||||
|
||||
import yaml
|
||||
|
||||
WORKFLOW = Path(".github/workflows/gcp-artifact.yml")
|
||||
|
||||
|
||||
def test_gcp_artifact_workflow_is_manual_only() -> None:
|
||||
workflow = yaml.load(WORKFLOW.read_text(), Loader=yaml.BaseLoader)
|
||||
|
||||
assert set(workflow["on"]) == {"workflow_dispatch"}
|
||||
assert "push" not in workflow["on"]
|
||||
|
||||
|
||||
def test_gcp_artifact_workflow_requires_main_before_authentication() -> None:
|
||||
workflow = WORKFLOW.read_text()
|
||||
|
||||
guard = workflow.index("Require manual main dispatch")
|
||||
checkout = workflow.index("actions/checkout@v4")
|
||||
auth = workflow.index("google-github-actions/auth@v2")
|
||||
|
||||
assert 'test "${GITHUB_EVENT_NAME}" = "workflow_dispatch"' in workflow
|
||||
assert 'test "${GITHUB_REF}" = "refs/heads/main"' in workflow
|
||||
assert guard < checkout < auth
|
||||
|
||||
|
||||
def test_gcp_artifact_workflow_retains_immutable_image_digest() -> None:
|
||||
workflow = Path(".github/workflows/gcp-artifact.yml").read_text()
|
||||
workflow = WORKFLOW.read_text()
|
||||
|
||||
assert "gcloud artifacts docker images describe" in workflow
|
||||
assert "Image tag already exists; reusing immutable Artifact Registry image." in workflow
|
||||
|
|
|
|||
Loading…
Reference in a new issue