|
| 1 | +--- |
| 2 | +phase: 05.1-github-actions-ci-cd |
| 3 | +plan: "01" |
| 4 | +subsystem: infra |
| 5 | +tags: [cd, image-tag, pulumi-config, test-scaffold, static-analysis] |
| 6 | +dependency_graph: |
| 7 | + requires: [] |
| 8 | + provides: [IMAGE_TAG config key, CD static test scaffold] |
| 9 | + affects: [infra/config.py, infra/components/app.py, tests/infra/] |
| 10 | +tech_stack: |
| 11 | + added: [] |
| 12 | + patterns: [AST-based static test, YAML-based workflow test, Pulumi config fallback] |
| 13 | +key_files: |
| 14 | + created: |
| 15 | + - tests/infra/test_cd_workflows_static.py |
| 16 | + - tests/infra/test_cd_static.py |
| 17 | + modified: |
| 18 | + - infra/config.py |
| 19 | + - infra/components/app.py |
| 20 | +decisions: |
| 21 | + - IMAGE_TAG uses cfg.get() (optional) not cfg.require() so local dev works without the flag |
| 22 | + - ENV fallback preserves existing behavior for manual pulumi up without --config imageTag |
| 23 | + - Test scaffold created before workflow files (Wave 0 pattern) so Plan 02 has concrete assertions to satisfy |
| 24 | +metrics: |
| 25 | + duration: "~5 minutes" |
| 26 | + completed_date: "2026-04-11" |
| 27 | + tasks_completed: 2 |
| 28 | + files_modified: 4 |
| 29 | +--- |
| 30 | + |
| 31 | +# Phase 05.1 Plan 01: IMAGE_TAG Config and CD Test Scaffold Summary |
| 32 | + |
| 33 | +**One-liner:** IMAGE_TAG config key with ENV fallback added to Pulumi; static test scaffold validates all CD-01 through CD-05 contracts via YAML and AST parsing. |
| 34 | + |
| 35 | +## Tasks Completed |
| 36 | + |
| 37 | +| Task | Name | Commit | Files | |
| 38 | +|------|------|--------|-------| |
| 39 | +| 1 | Create static test scaffold for CD workflows and imageTag config | 50914d5 | tests/infra/test_cd_workflows_static.py, tests/infra/test_cd_static.py | |
| 40 | +| 2 | Add IMAGE_TAG config key to config.py and update app.py | 450e6cf | infra/config.py, infra/components/app.py | |
| 41 | + |
| 42 | +## What Was Built |
| 43 | + |
| 44 | +### IMAGE_TAG Pulumi Config Key (Task 2) |
| 45 | + |
| 46 | +Added `IMAGE_TAG: str = cfg.get("imageTag") or ENV` to `infra/config.py`. When CI runs `pulumi up --config vici-infra:imageTag=a1b2c3d`, the deployed container image tag is the 7-char git SHA (e.g., `us-central1-docker.pkg.dev/PROJECT/vici/app:a1b2c3d`). When running locally without the flag, `IMAGE_TAG` falls back to `ENV` (e.g., "dev"), preserving existing behavior. |
| 47 | + |
| 48 | +Updated `infra/components/app.py` to import `IMAGE_TAG` alongside `ENV` and use it in the `pulumi.Output.concat(registry_url, "/vici:", IMAGE_TAG)` call. |
| 49 | + |
| 50 | +### CD Static Test Scaffold (Task 1) |
| 51 | + |
| 52 | +Two test files establish the RED → GREEN contract for Plan 02: |
| 53 | + |
| 54 | +**`tests/infra/test_cd_workflows_static.py`** — Six test classes using `yaml.safe_load`: |
| 55 | +- `TestCD01DevAutoDeployOnMain` — cd-dev.yml push-to-main trigger and cd-base.yml call with `command: up, stack: dev` |
| 56 | +- `TestCD02StagingManualDispatchOnly` — cd-staging.yml has `workflow_dispatch` only (no `pull_request`) |
| 57 | +- `TestCD03ProdEnvironmentApproval` — cd-prod.yml passes `with.environment: prod` |
| 58 | +- `TestCD04WIFAuth` — cd-base.yml build+deploy jobs use `google-github-actions/auth@v3`, no static keys, `id-token: write` |
| 59 | +- `TestCD05CIUnchanged` — ci.yml has no `google-github-actions` steps and no `gcloud` run commands |
| 60 | +- `TestCDBaseStructure` — cd-base.yml has exactly `{build, deploy}` jobs, deploy needs build, build outputs sha, Docker GHA cache, conditional push on `command == up`, `gcp_project` input required, health check on dev up, pulumi config-map with imageTag |
| 61 | + |
| 62 | +**`tests/infra/test_cd_static.py`** — Two test classes using `ast` module: |
| 63 | +- `TestImageTagConfig` — config.py has module-level `IMAGE_TAG` assignment and `cfg.get("imageTag") or ENV` pattern |
| 64 | +- `TestAppUsesImageTag` — app.py imports `IMAGE_TAG` on the `from config import` line and uses it (not `ENV`) in the registry_url concat |
| 65 | + |
| 66 | +## Test State After This Plan |
| 67 | + |
| 68 | +| Test Class | Status | Reason | |
| 69 | +|------------|--------|--------| |
| 70 | +| TestCD05CIUnchanged | PASS | ci.yml already has no GCP steps | |
| 71 | +| TestCD01DevAutoDeployOnMain::test_cd_dev_calls_cd_base_with_up | PASS | Existing cd-dev.yml happens to call cd-base.yml | |
| 72 | +| TestCD03ProdEnvironmentApproval::test_cd_prod_passes_environment_prod | PASS | Existing cd-prod.yml passes environment | |
| 73 | +| TestCD04WIFAuth::test_cd_base_deploy_job_uses_wif_auth | PASS | Existing cd-base.yml has WIF in single deploy job | |
| 74 | +| TestCD04WIFAuth::test_cd_base_no_static_key_steps | PASS | No static keys in existing workflow | |
| 75 | +| TestImageTagConfig (both) | PASS | Task 2 GREEN | |
| 76 | +| TestAppUsesImageTag (both) | PASS | Task 2 GREEN | |
| 77 | +| All remaining | FAIL | Expected RED — workflow files not yet rewritten (Plan 02) | |
| 78 | + |
| 79 | +## Deviations from Plan |
| 80 | + |
| 81 | +None — plan executed exactly as written. |
| 82 | + |
| 83 | +## Known Stubs |
| 84 | + |
| 85 | +None — IMAGE_TAG is fully wired from config.py to app.py. No placeholder values. |
| 86 | + |
| 87 | +## Threat Flags |
| 88 | + |
| 89 | +None — no new network endpoints, auth paths, or trust boundary crossings introduced. IMAGE_TAG is a non-secret Pulumi config value (git SHA string); T-5.1-01 disposition is `accept` per plan threat model. |
| 90 | + |
| 91 | +## Self-Check: PASSED |
| 92 | + |
| 93 | +- `tests/infra/test_cd_workflows_static.py` exists and contains all 6 required test classes |
| 94 | +- `tests/infra/test_cd_static.py` exists and contains both required test classes |
| 95 | +- Commit 50914d5 exists (test scaffold) |
| 96 | +- Commit 450e6cf exists (IMAGE_TAG config) |
| 97 | +- `grep "IMAGE_TAG" infra/config.py` returns the assignment line |
| 98 | +- `grep "IMAGE_TAG" infra/components/app.py` returns import and usage lines |
| 99 | +- `uv run pytest tests/infra/test_cd_static.py` — 4 passed |
| 100 | +- `uv run pytest tests/infra/test_cd_workflows_static.py::TestCD05CIUnchanged` — 1 passed |
0 commit comments