@1aboveio/skills 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +3 -0
- package/README.md +90 -0
- package/bin/1aboveio-skills.mjs +18 -0
- package/package.json +28 -0
- package/runtime/skills/distribution/generated/recipes.json +1189 -0
- package/runtime/skills/distribution/scripts/bundles.mjs +280 -0
- package/runtime/skills/engineering/engineering-runtime/scripts/main-module.mjs +80 -0
- package/skills/backend/airflow-dag-develop/LICENSE +3 -0
- package/skills/backend/airflow-dag-develop/SKILL.md +111 -0
- package/skills/backend/app-debug/LICENSE +3 -0
- package/skills/backend/app-debug/SKILL.md +109 -0
- package/skills/backend/app-debug/references/common-errors.md +128 -0
- package/skills/backend/python-backend/LICENSE +3 -0
- package/skills/backend/python-backend/SKILL.md +326 -0
- package/skills/cicd-pipeline/cloud-build/LICENSE +3 -0
- package/skills/cicd-pipeline/cloud-build/SKILL.md +707 -0
- package/skills/cicd-pipeline/cloud-debug/LICENSE +3 -0
- package/skills/cicd-pipeline/cloud-debug/SKILL.md +316 -0
- package/skills/cicd-pipeline/cloud-debug/references/build-failures.md +238 -0
- package/skills/cicd-pipeline/cloud-debug/references/deploy-failures.md +376 -0
- package/skills/cicd-pipeline/cloud-debug/references/pipeline-failures.md +378 -0
- package/skills/cicd-pipeline/cloud-deploy/LICENSE +3 -0
- package/skills/cicd-pipeline/cloud-deploy/SKILL.md +229 -0
- package/skills/cicd-pipeline/cloud-deploy/references/config-templates.md +257 -0
- package/skills/cicd-pipeline/docker/LICENSE +3 -0
- package/skills/cicd-pipeline/docker/SKILL.md +126 -0
- package/skills/cicd-pipeline/google-cloud/LICENSE +3 -0
- package/skills/cicd-pipeline/google-cloud/SKILL.md +118 -0
- package/skills/cicd-pipeline/google-cloud/references/gcs.md +469 -0
- package/skills/cicd-pipeline/google-cloud/references/iam.md +451 -0
- package/skills/cicd-pipeline/google-cloud/references/project.md +349 -0
- package/skills/cicd-pipeline/google-cloud/references/secrets.md +336 -0
- package/skills/cicd-pipeline/google-cloud/references/vpc.md +312 -0
- package/skills/cicd-pipeline/google-cloud/scripts/create-sa.sh +36 -0
- package/skills/cicd-pipeline/google-cloud/scripts/gcp-config.sh +31 -0
- package/skills/cicd-pipeline/google-cloud/scripts/grant-iap.sh +41 -0
- package/skills/cicd-pipeline/google-cloud/scripts/setup-secrets.sh +48 -0
- package/skills/cicd-pipeline/mergify/LICENSE +3 -0
- package/skills/cicd-pipeline/mergify/SKILL.md +138 -0
- package/skills/cicd-pipeline/mergify/assets/templates/mergify.yml +237 -0
- package/skills/cicd-pipeline/mergify/assets/templates/ruleset.json +46 -0
- package/skills/cicd-pipeline/mergify/references/branch-protection.md +277 -0
- package/skills/cicd-pipeline/mergify/references/configuration.md +183 -0
- package/skills/cicd-pipeline/mergify/references/diagnosis.md +73 -0
- package/skills/cicd-pipeline/mergify/references/traps.md +78 -0
- package/skills/cicd-pipeline/mergify/references/watch-contract.md +218 -0
- package/skills/cicd-pipeline/mergify/scripts/audit-core.mjs +131 -0
- package/skills/cicd-pipeline/mergify/scripts/audit.mjs +4 -0
- package/skills/cicd-pipeline/mergify/scripts/watch-pr-delivery-core.mjs +663 -0
- package/skills/cicd-pipeline/mergify/scripts/watch-pr-delivery.mjs +4 -0
- package/skills/cicd-pipeline/podman/LICENSE +3 -0
- package/skills/cicd-pipeline/podman/SKILL.md +70 -0
- package/skills/cicd-pipeline/podman/agents/openai.yaml +4 -0
- package/skills/cicd-pipeline/podman/assets/templates/podman-compose-socket-directory.yml +6 -0
- package/skills/cicd-pipeline/podman/assets/templates/podman-service-override.conf +3 -0
- package/skills/cicd-pipeline/podman/references/compose-compatibility.md +70 -0
- package/skills/cicd-pipeline/podman/references/networking-and-ports.md +74 -0
- package/skills/cicd-pipeline/podman/references/rootless-services-and-sockets.md +156 -0
- package/skills/cicd-pipeline/podman/references/troubleshooting.md +98 -0
- package/skills/engineering/e2e-test/LICENSE +3 -0
- package/skills/engineering/e2e-test/SKILL.md +156 -0
- package/skills/engineering/e2e-test/assets/ci-gates.cloudbuild.yaml +272 -0
- package/skills/engineering/e2e-test/assets/ci-gates.github.yml +451 -0
- package/skills/engineering/e2e-test/assets/e2e-workflow.yml +282 -0
- package/skills/engineering/e2e-test/references/authoring/auth-flows.md +159 -0
- package/skills/engineering/e2e-test/references/authoring/playwright-config.md +71 -0
- package/skills/engineering/e2e-test/references/authoring/playwright-patterns.md +219 -0
- package/skills/engineering/e2e-test/references/authoring/test-skipping.md +44 -0
- package/skills/engineering/e2e-test/references/ci-integration.md +121 -0
- package/skills/engineering/e2e-test/references/ci-playwright-container.md +280 -0
- package/skills/engineering/e2e-test/references/debugging.md +36 -0
- package/skills/engineering/e2e-test/references/presentation-sweep.md +131 -0
- package/skills/engineering/e2e-test/references/reviewing.md +39 -0
- package/skills/engineering/e2e-test/references/route-discovery.md +50 -0
- package/skills/engineering/e2e-test/references/route-manifest.md +44 -0
- package/skills/engineering/e2e-test/scripts/detect-routes-fastapi.py +290 -0
- package/skills/engineering/e2e-test/scripts/detect-routes-nextjs.mjs +200 -0
- package/skills/engineering/e2e-test/scripts/post-visual-evidence.mjs +158 -0
- package/skills/engineering/e2e-test/scripts/presentation-checks.mjs +171 -0
- package/skills/engineering/e2e-test/scripts/presentation-perceivability.mjs +179 -0
- package/skills/engineering/e2e-test/scripts/presentation-reachability.mjs +154 -0
- package/skills/engineering/e2e-test/scripts/presentation-render-health.mjs +141 -0
- package/skills/engineering/e2e-test/scripts/presentation-sweep.mjs +148 -0
- package/skills/engineering/e2e-test/scripts/presentation-temporal.mjs +127 -0
- package/skills/engineering/e2e-test/scripts/presentation-visual.mjs +84 -0
- package/skills/engineering/e2e-test/scripts/project-route-manifest.mjs +75 -0
- package/skills/engineering/e2e-test/scripts/validate-manifest.mjs +106 -0
- package/skills/engineering/engineering-runtime/LICENSE +3 -0
- package/skills/engineering/engineering-runtime/SKILL.md +10 -0
- package/skills/engineering/engineering-runtime/agents/openai.yaml +6 -0
- package/skills/engineering/engineering-runtime/coherence/workflow.json +553 -0
- package/skills/engineering/engineering-runtime/scripts/exact-head-artifact.mjs +131 -0
- package/skills/engineering/engineering-runtime/scripts/head-check-set.mjs +398 -0
- package/skills/engineering/engineering-runtime/scripts/main-module.mjs +80 -0
- package/skills/engineering/engineering-runtime/scripts/mergify-yaml.mjs +11 -0
- package/skills/engineering/engineering-runtime/scripts/package-lock.json +43 -0
- package/skills/engineering/engineering-runtime/scripts/package.json +10 -0
- package/skills/engineering/engineering-runtime/scripts/required-check-plan.mjs +223 -0
- package/skills/engineering/engineering-runtime/scripts/workflow-coherence.mjs +576 -0
- package/skills/engineering/engineering-runtime/scripts/workflow-policy.mjs +166 -0
- package/skills/engineering/ensure-coverage/LICENSE +3 -0
- package/skills/engineering/ensure-coverage/SKILL.md +136 -0
- package/skills/engineering/ensure-coverage/evals/evals.json +125 -0
- package/skills/engineering/ensure-coverage/references/breadth/coverage-ledger.md +91 -0
- package/skills/engineering/ensure-coverage/references/breadth/inventory-contract.md +83 -0
- package/skills/engineering/ensure-coverage/references/breadth/surface-baseline.md +44 -0
- package/skills/engineering/ensure-coverage/references/breadth/surface-discovery.md +16 -0
- package/skills/engineering/ensure-coverage/references/depth/characterization.md +68 -0
- package/skills/engineering/ensure-coverage/references/depth/coverage.config.example.json +25 -0
- package/skills/engineering/ensure-coverage/references/depth/grading.md +35 -0
- package/skills/engineering/ensure-coverage/references/depth/mock-policy.md +87 -0
- package/skills/engineering/ensure-coverage/references/depth/test-smells.md +23 -0
- package/skills/engineering/ensure-coverage/references/enforcement/ci-contract.md +164 -0
- package/skills/engineering/ensure-coverage/references/enforcement/hooks.md +85 -0
- package/skills/engineering/ensure-coverage/references/examples/coverage-ledger.md +109 -0
- package/skills/engineering/ensure-coverage/references/examples/refund-flow.md +33 -0
- package/skills/engineering/ensure-coverage/references/presentation/axis.md +78 -0
- package/skills/engineering/ensure-coverage/references/presentation/runner-contract.md +74 -0
- package/skills/engineering/ensure-coverage/references/process/audit-mode.md +33 -0
- package/skills/engineering/ensure-coverage/references/process/output-template.md +139 -0
- package/skills/engineering/ensure-coverage/references/process/review-contract-template.md +119 -0
- package/skills/engineering/ensure-coverage/references/process/scope-class.md +178 -0
- package/skills/engineering/ensure-coverage/references/process/test-strategy.md +55 -0
- package/skills/engineering/ensure-coverage/schemas/coverage-config.schema.json +45 -0
- package/skills/engineering/ensure-coverage/schemas/coverage-file.schema.json +93 -0
- package/skills/engineering/ensure-coverage/scripts/adapters/nextjs-inventory.mjs +178 -0
- package/skills/engineering/ensure-coverage/scripts/check-quarantine-expiry.mjs +101 -0
- package/skills/engineering/ensure-coverage/scripts/ci-audit.mjs +358 -0
- package/skills/engineering/ensure-coverage/scripts/coverage-checklist.mjs +494 -0
- package/skills/engineering/ensure-coverage/scripts/coverage-ledger.mjs +663 -0
- package/skills/engineering/ensure-coverage/scripts/design-parity.mjs +591 -0
- package/skills/engineering/ensure-coverage/scripts/evidence-block.mjs +367 -0
- package/skills/engineering/ensure-coverage/scripts/lint-tests.mjs +269 -0
- package/skills/engineering/ensure-coverage/scripts/mock-policy-config.mjs +176 -0
- package/skills/engineering/ensure-coverage/scripts/package-lock.json +76 -0
- package/skills/engineering/ensure-coverage/scripts/package.json +19 -0
- package/skills/engineering/ensure-coverage/scripts/scope-class.mjs +554 -0
- package/skills/engineering/harness-runtime/LICENSE +3 -0
- package/skills/engineering/harness-runtime/SKILL.md +18 -0
- package/skills/engineering/harness-runtime/agents/openai.yaml +6 -0
- package/skills/engineering/harness-runtime/bin/discover-models.mjs +4 -0
- package/skills/engineering/harness-runtime/bin/model-catalog.mjs +4 -0
- package/skills/engineering/harness-runtime/contracts.md +15 -0
- package/skills/engineering/harness-runtime/discover-models.mjs +392 -0
- package/skills/engineering/harness-runtime/fixtures/native-question-schemas.json +33 -0
- package/skills/engineering/harness-runtime/fixtures/question-responses.json +54 -0
- package/skills/engineering/harness-runtime/index.mjs +767 -0
- package/skills/engineering/harness-runtime/model-catalog.mjs +787 -0
- package/skills/engineering/harness-runtime/native-question-contracts.md +37 -0
- package/skills/engineering/harness-runtime/references/model-catalog-seed.json +159 -0
- package/skills/engineering/harness-runtime/references/model-catalog.md +57 -0
- package/skills/engineering/implement-and-pr/LICENSE +3 -0
- package/skills/engineering/implement-and-pr/SKILL.md +176 -0
- package/skills/engineering/implement-and-pr/references/ci-iteration.md +10 -0
- package/skills/engineering/implement-and-pr/references/closeout.md +27 -0
- package/skills/engineering/implement-and-pr/references/contract-complete-fix-rounds.md +34 -0
- package/skills/engineering/implement-and-pr/references/evidence-rules.md +39 -0
- package/skills/engineering/implement-and-pr/references/incremental-plan.md +16 -0
- package/skills/engineering/implement-and-pr/references/self-review.md +23 -0
- package/skills/engineering/implement-and-pr/references/tdd-mode.md +18 -0
- package/skills/engineering/resolve-issues/LICENSE +3 -0
- package/skills/engineering/resolve-issues/SKILL.md +167 -0
- package/skills/engineering/resolve-issues/generated/workflow-repair-policy.json +448 -0
- package/skills/engineering/resolve-issues/references/breaker.md +82 -0
- package/skills/engineering/resolve-issues/references/deliverables.md +27 -0
- package/skills/engineering/resolve-issues/references/delivery.md +108 -0
- package/skills/engineering/resolve-issues/references/evidence-lane.md +21 -0
- package/skills/engineering/resolve-issues/references/exact-head-ci.md +287 -0
- package/skills/engineering/resolve-issues/references/fan-out.md +33 -0
- package/skills/engineering/resolve-issues/references/finalization.md +68 -0
- package/skills/engineering/resolve-issues/references/guarantees.md +10 -0
- package/skills/engineering/resolve-issues/references/high-risk.md +29 -0
- package/skills/engineering/resolve-issues/references/incidents/848/README.md +156 -0
- package/skills/engineering/resolve-issues/references/intake.md +86 -0
- package/skills/engineering/resolve-issues/references/integration-gate.md +53 -0
- package/skills/engineering/resolve-issues/references/interference.md +87 -0
- package/skills/engineering/resolve-issues/references/loop.md +134 -0
- package/skills/engineering/resolve-issues/references/model-catalog.md +9 -0
- package/skills/engineering/resolve-issues/references/postmortem.md +27 -0
- package/skills/engineering/resolve-issues/references/pre-flight-model-slots.md +41 -0
- package/skills/engineering/resolve-issues/references/pre-flight-recording-and-checkout.md +48 -0
- package/skills/engineering/resolve-issues/references/pre-flight.md +41 -0
- package/skills/engineering/resolve-issues/references/regression-checklist.md +26 -0
- package/skills/engineering/resolve-issues/references/run-state.md +288 -0
- package/skills/engineering/resolve-issues/references/sandboxed-testing.md +48 -0
- package/skills/engineering/resolve-issues/references/spawn-contract.md +96 -0
- package/skills/engineering/resolve-issues/references/terminal-evidence-journal.md +40 -0
- package/skills/engineering/resolve-issues/references/why.md +653 -0
- package/skills/engineering/resolve-issues/schemas/fix-round.schema.json +49 -0
- package/skills/engineering/resolve-issues/scripts/combine-and-verify.mjs +721 -0
- package/skills/engineering/resolve-issues/scripts/component-candidate.mjs +962 -0
- package/skills/engineering/resolve-issues/scripts/contract-revision.mjs +220 -0
- package/skills/engineering/resolve-issues/scripts/detect-delivery-mode.mjs +420 -0
- package/skills/engineering/resolve-issues/scripts/detect-target-branch.mjs +256 -0
- package/skills/engineering/resolve-issues/scripts/detect-workspace-mode.mjs +168 -0
- package/skills/engineering/resolve-issues/scripts/discover-models.mjs +9 -0
- package/skills/engineering/resolve-issues/scripts/doctrine.mjs +62 -0
- package/skills/engineering/resolve-issues/scripts/evidence-lifecycle-contract.mjs +191 -0
- package/skills/engineering/resolve-issues/scripts/exact-head-ci.mjs +413 -0
- package/skills/engineering/resolve-issues/scripts/exact-head-github-provider.mjs +332 -0
- package/skills/engineering/resolve-issues/scripts/finalize.mjs +488 -0
- package/skills/engineering/resolve-issues/scripts/fix-rounds.mjs +3307 -0
- package/skills/engineering/resolve-issues/scripts/fixtures/evidence-lifecycle-circular-1001.json +16 -0
- package/skills/engineering/resolve-issues/scripts/fixtures/evidence-lifecycle-valid-sequencing.json +51 -0
- package/skills/engineering/resolve-issues/scripts/fixtures/fmm-express-830-component-candidate.json +17 -0
- package/skills/engineering/resolve-issues/scripts/fixtures/head-check-set-1081.json +166 -0
- package/skills/engineering/resolve-issues/scripts/gate-value-series.mjs +92 -0
- package/skills/engineering/resolve-issues/scripts/guide-index.mjs +73 -0
- package/skills/engineering/resolve-issues/scripts/head-check-set.mjs +159 -0
- package/skills/engineering/resolve-issues/scripts/interference.mjs +427 -0
- package/skills/engineering/resolve-issues/scripts/model-catalog.mjs +9 -0
- package/skills/engineering/resolve-issues/scripts/next-operations.mjs +419 -0
- package/skills/engineering/resolve-issues/scripts/postmortem.mjs +909 -0
- package/skills/engineering/resolve-issues/scripts/preflight-questions.mjs +322 -0
- package/skills/engineering/resolve-issues/scripts/reconcile-contained-unit-prs.mjs +415 -0
- package/skills/engineering/resolve-issues/scripts/release-state-contract.mjs +697 -0
- package/skills/engineering/resolve-issues/scripts/report.mjs +494 -0
- package/skills/engineering/resolve-issues/scripts/required-check-plan.mjs +172 -0
- package/skills/engineering/resolve-issues/scripts/round-metadata.mjs +79 -0
- package/skills/engineering/resolve-issues/scripts/run-state-review6-cases.mjs +334 -0
- package/skills/engineering/resolve-issues/scripts/run-state.mjs +4784 -0
- package/skills/engineering/resolve-issues/scripts/sandbox-selftest.mjs +395 -0
- package/skills/engineering/resolve-issues/scripts/spawn-contract.mjs +290 -0
- package/skills/engineering/resolve-issues/scripts/terminal-dispositions.mjs +170 -0
- package/skills/engineering/resolve-issues/scripts/terminal-evidence-journal.mjs +293 -0
- package/skills/engineering/resolve-issues/scripts/unit-kind.mjs +197 -0
- package/skills/engineering/resolve-issues/scripts/unit-lifecycle.mjs +127 -0
- package/skills/engineering/resolve-issues/scripts/watch-delivery.mjs +893 -0
- package/skills/engineering/resolve-issues/scripts/workspaces.mjs +829 -0
- package/skills/engineering/resolve-issues/workflows/independent-review.workflow.js +290 -0
- package/skills/engineering/resolve-issues/workflows/prior-art-scan.workflow.js +80 -0
- package/skills/engineering/resolve-issues/workflows/workflow-smoke.mjs +102 -0
- package/skills/engineering/resolve-release/LICENSE +3 -0
- package/skills/engineering/resolve-release/SKILL.md +112 -0
- package/skills/engineering/resolve-release/references/assembly.md +137 -0
- package/skills/engineering/resolve-release/references/auto-when-green.md +56 -0
- package/skills/engineering/resolve-release/references/candidate.md +167 -0
- package/skills/engineering/resolve-release/references/exposure.md +178 -0
- package/skills/engineering/resolve-release/references/handoff.md +24 -0
- package/skills/engineering/resolve-release/references/postmortem.md +230 -0
- package/skills/engineering/resolve-release/references/preflight.md +207 -0
- package/skills/engineering/resolve-release/references/principles.md +94 -0
- package/skills/engineering/resolve-release/references/regression-checklist.md +36 -0
- package/skills/engineering/resolve-release/references/related-skills.md +12 -0
- package/skills/engineering/resolve-release/references/routing.md +149 -0
- package/skills/engineering/resolve-release/references/verified-sha-github-flow.md +285 -0
- package/skills/engineering/resolve-release/references/versioning.md +202 -0
- package/skills/engineering/resolve-release/references/why.md +53 -0
- package/skills/engineering/resolve-release/scripts/adapter-completion-artifact.mjs +389 -0
- package/skills/engineering/resolve-release/scripts/build-changes.mjs +209 -0
- package/skills/engineering/resolve-release/scripts/candidate-hygiene.mjs +407 -0
- package/skills/engineering/resolve-release/scripts/candidate-identity.mjs +904 -0
- package/skills/engineering/resolve-release/scripts/candidate-traffic.mjs +81 -0
- package/skills/engineering/resolve-release/scripts/checked-adapter-loader.mjs +612 -0
- package/skills/engineering/resolve-release/scripts/close-attempt.mjs +135 -0
- package/skills/engineering/resolve-release/scripts/closeout-release.mjs +161 -0
- package/skills/engineering/resolve-release/scripts/doctrine.mjs +106 -0
- package/skills/engineering/resolve-release/scripts/durable-processing.mjs +522 -0
- package/skills/engineering/resolve-release/scripts/ensure-target-green.mjs +659 -0
- package/skills/engineering/resolve-release/scripts/evidence-bundle.mjs +1014 -0
- package/skills/engineering/resolve-release/scripts/finalize-release.mjs +526 -0
- package/skills/engineering/resolve-release/scripts/fixtures/durable-processing-adapter.mjs +169 -0
- package/skills/engineering/resolve-release/scripts/green-gate.mjs +599 -0
- package/skills/engineering/resolve-release/scripts/isolated-adapter-evaluator.mjs +752 -0
- package/skills/engineering/resolve-release/scripts/metadata-pr-status.mjs +56 -0
- package/skills/engineering/resolve-release/scripts/metadata-sync.mjs +1538 -0
- package/skills/engineering/resolve-release/scripts/postmortem.mjs +381 -0
- package/skills/engineering/resolve-release/scripts/preflight-probes.mjs +498 -0
- package/skills/engineering/resolve-release/scripts/production-endpoints.mjs +326 -0
- package/skills/engineering/resolve-release/scripts/rc-circuit-breaker.mjs +272 -0
- package/skills/engineering/resolve-release/scripts/report.mjs +417 -0
- package/skills/engineering/resolve-release/scripts/reprobe-credentials.mjs +114 -0
- package/skills/engineering/resolve-release/scripts/revalidate-candidate.mjs +238 -0
- package/skills/engineering/resolve-release/scripts/review-packet.mjs +503 -0
- package/skills/engineering/resolve-release/scripts/rollback-floor.mjs +263 -0
- package/skills/engineering/resolve-release/scripts/version-assert.mjs +339 -0
- package/skills/engineering/resolve-release/scripts/version-postmortem.mjs +485 -0
- package/skills/engineering/resolve-release/scripts/version.mjs +1199 -0
- package/skills/engineering/resolve-release/scripts/watch-candidate-delivery.mjs +449 -0
- package/skills/engineering/resolve-release/vendor/ACORN-LICENSE +21 -0
- package/skills/engineering/resolve-release/vendor/README.md +60 -0
- package/skills/engineering/resolve-release/vendor/acorn.mjs +6233 -0
- package/skills/engineering/resolve-release/vendor/quickjs/core/LICENSE +21 -0
- package/skills/engineering/resolve-release/vendor/quickjs/core/README.md +341 -0
- package/skills/engineering/resolve-release/vendor/quickjs/core/README.template.md +70 -0
- package/skills/engineering/resolve-release/vendor/quickjs/core/dist/chunk-TAV5CUKK.mjs +2 -0
- package/skills/engineering/resolve-release/vendor/quickjs/core/dist/chunk-TAV5CUKK.mjs.map +1 -0
- package/skills/engineering/resolve-release/vendor/quickjs/core/dist/chunk-V2S4ZYJR.mjs +7 -0
- package/skills/engineering/resolve-release/vendor/quickjs/core/dist/chunk-V2S4ZYJR.mjs.map +1 -0
- package/skills/engineering/resolve-release/vendor/quickjs/core/dist/index.d.mts +2033 -0
- package/skills/engineering/resolve-release/vendor/quickjs/core/dist/index.d.ts +2033 -0
- package/skills/engineering/resolve-release/vendor/quickjs/core/dist/index.js +7 -0
- package/skills/engineering/resolve-release/vendor/quickjs/core/dist/index.js.map +1 -0
- package/skills/engineering/resolve-release/vendor/quickjs/core/dist/index.mjs +2 -0
- package/skills/engineering/resolve-release/vendor/quickjs/core/dist/index.mjs.map +1 -0
- package/skills/engineering/resolve-release/vendor/quickjs/core/dist/module-ES6BEMUI.mjs +2 -0
- package/skills/engineering/resolve-release/vendor/quickjs/core/dist/module-ES6BEMUI.mjs.map +1 -0
- package/skills/engineering/resolve-release/vendor/quickjs/core/dist/module-asyncify-2EFITU5U.mjs +2 -0
- package/skills/engineering/resolve-release/vendor/quickjs/core/dist/module-asyncify-2EFITU5U.mjs.map +1 -0
- package/skills/engineering/resolve-release/vendor/quickjs/core/package.json +49 -0
- package/skills/engineering/resolve-release/vendor/quickjs/ffi-types/LICENSE +21 -0
- package/skills/engineering/resolve-release/vendor/quickjs/ffi-types/README.md +5 -0
- package/skills/engineering/resolve-release/vendor/quickjs/ffi-types/dist/index.d.mts +549 -0
- package/skills/engineering/resolve-release/vendor/quickjs/ffi-types/dist/index.d.ts +549 -0
- package/skills/engineering/resolve-release/vendor/quickjs/ffi-types/dist/index.js +2 -0
- package/skills/engineering/resolve-release/vendor/quickjs/ffi-types/dist/index.js.map +1 -0
- package/skills/engineering/resolve-release/vendor/quickjs/ffi-types/dist/index.mjs +2 -0
- package/skills/engineering/resolve-release/vendor/quickjs/ffi-types/dist/index.mjs.map +1 -0
- package/skills/engineering/resolve-release/vendor/quickjs/ffi-types/package.json +36 -0
- package/skills/engineering/resolve-release/vendor/quickjs/release-sync/LICENSE +47 -0
- package/skills/engineering/resolve-release/vendor/quickjs/release-sync/README.md +82 -0
- package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/emscripten-module.browser.d.ts +11 -0
- package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/emscripten-module.browser.mjs +22 -0
- package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/emscripten-module.cjs +21 -0
- package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/emscripten-module.cloudflare.cjs +21 -0
- package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/emscripten-module.cloudflare.d.ts +11 -0
- package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/emscripten-module.d.ts +11 -0
- package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/emscripten-module.mjs +25 -0
- package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/emscripten-module.wasm +0 -0
- package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/ffi.d.mts +85 -0
- package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/ffi.d.ts +85 -0
- package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/ffi.js +2 -0
- package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/ffi.js.map +1 -0
- package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/ffi.mjs +2 -0
- package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/ffi.mjs.map +1 -0
- package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/index.d.mts +20 -0
- package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/index.d.ts +20 -0
- package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/index.js +2 -0
- package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/index.js.map +1 -0
- package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/index.mjs +2 -0
- package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/index.mjs.map +1 -0
- package/skills/engineering/resolve-release/vendor/quickjs/release-sync/package.json +61 -0
- package/skills/engineering/review-pr/LICENSE +3 -0
- package/skills/engineering/review-pr/SKILL.md +123 -0
- package/skills/engineering/review-pr/references/adversarial-reviewer-prompt.md +42 -0
- package/skills/engineering/review-pr/references/code-correctness.md +5 -0
- package/skills/engineering/review-pr/references/contract-freshness.md +9 -0
- package/skills/engineering/review-pr/references/coordination.md +18 -0
- package/skills/engineering/review-pr/references/domain-hazards.md +123 -0
- package/skills/engineering/review-pr/references/finding-themes.md +7 -0
- package/skills/engineering/review-pr/references/github-posting.md +98 -0
- package/skills/engineering/review-pr/references/golden-path-smoke.md +5 -0
- package/skills/engineering/review-pr/references/incremental-output.md +16 -0
- package/skills/engineering/review-pr/references/inputs-and-discovery.md +31 -0
- package/skills/engineering/review-pr/references/output-format.md +99 -0
- package/skills/engineering/review-pr/references/over-mock-screen.md +7 -0
- package/skills/engineering/review-pr/references/promotion-prs.md +16 -0
- package/skills/engineering/review-pr/references/re-review.md +18 -0
- package/skills/engineering/review-pr/references/review-method.md +199 -0
- package/skills/engineering/review-pr/references/review-mode.md +30 -0
- package/skills/engineering/review-pr/references/review-posture.md +53 -0
- package/skills/engineering/review-pr/references/round1-depth.md +62 -0
- package/skills/engineering/review-pr/references/scripts.md +17 -0
- package/skills/engineering/review-pr/references/workflow.md +16 -0
- package/skills/engineering/review-pr/schemas/findings.schema.json +282 -0
- package/skills/engineering/review-pr/scripts/finding-contract.mjs +285 -0
- package/skills/engineering/review-pr/scripts/post-review.mjs +405 -0
- package/skills/engineering/review-pr/scripts/pr-context.mjs +207 -0
- package/skills/engineering/review-pr/scripts/scan-diff.mjs +365 -0
- package/skills/engineering/review-pr/scripts/theme-contract.mjs +57 -0
- package/skills/engineering/smoke/LICENSE +3 -0
- package/skills/engineering/smoke/SKILL.md +131 -0
- package/skills/engineering/smoke/assets/smoke.manifest.example.json +53 -0
- package/skills/engineering/smoke/references/manifest.md +192 -0
- package/skills/engineering/smoke/scripts/smoke.mjs +713 -0
- package/skills/fullstack/better-auth/LICENSE +3 -0
- package/skills/fullstack/better-auth/SKILL.md +601 -0
- package/skills/fullstack/better-auth/references/feishu-api.md +270 -0
- package/skills/fullstack/monorepo/LICENSE +3 -0
- package/skills/fullstack/monorepo/SKILL.md +465 -0
- package/skills/fullstack/nextjs-fullstack/LICENSE +3 -0
- package/skills/fullstack/nextjs-fullstack/SKILL.md +210 -0
- package/skills/fullstack/nextjs-fullstack/conventions.md +318 -0
- package/skills/fullstack/nextjs-fullstack/frontend-conventions.md +61 -0
- package/skills/fullstack/nextjs-fullstack/nextjs16.md +287 -0
- package/skills/fullstack/nextjs-fullstack/server-actions.md +409 -0
- package/skills/fullstack/prisma-setup/LICENSE +3 -0
- package/skills/fullstack/prisma-setup/SKILL.md +180 -0
- package/skills/fullstack/prisma-setup/nextjs.md +258 -0
- package/skills/fullstack/prisma-setup/turborepo.md +301 -0
- package/skills/fullstack/shadcn/LICENSE +3 -0
- package/skills/fullstack/shadcn/SKILL.md +119 -0
- package/skills/fullstack/shadcn/assets/shadcn-small.png +0 -0
- package/skills/fullstack/shadcn/assets/shadcn.png +0 -0
- package/skills/fullstack/shadcn/cli.md +411 -0
- package/skills/fullstack/shadcn/customization.md +224 -0
- package/skills/fullstack/shadcn/evals/evals.json +90 -0
- package/skills/fullstack/shadcn/mcp.md +101 -0
- package/skills/fullstack/shadcn/rules/base-vs-radix.md +323 -0
- package/skills/fullstack/shadcn/rules/component-selection.md +67 -0
- package/skills/fullstack/shadcn/rules/composition.md +195 -0
- package/skills/fullstack/shadcn/rules/data-table.md +201 -0
- package/skills/fullstack/shadcn/rules/forms.md +255 -0
- package/skills/fullstack/shadcn/rules/icons.md +103 -0
- package/skills/fullstack/shadcn/rules/styling.md +167 -0
- package/skills/fullstack/zod-v4/LICENSE +3 -0
- package/skills/fullstack/zod-v4/SKILL.md +287 -0
|
@@ -0,0 +1,707 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: cloud-build
|
|
3
|
+
description: "Build or debug Cloud Build pipelines for Cloud Run: cloudbuild.yaml, triggers, Artifact Registry, Docker builds, migration jobs, deploy steps, secrets, VPC, notifications. Not for staged multi-environment promotion (cloud-deploy)."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Cloud Build Direct Deploy to Cloud Run
|
|
7
|
+
|
|
8
|
+
Simpler alternative to Cloud Deploy for single-container services without staged promotion or verification gates.
|
|
9
|
+
|
|
10
|
+
## Related Skills
|
|
11
|
+
|
|
12
|
+
- [google-cloud](../google-cloud/SKILL.md) - Centralized GCP operations
|
|
13
|
+
- [IAM patterns](../google-cloud/references/iam.md) - Service accounts, roles, IAP, token minting
|
|
14
|
+
- [VPC configuration](../google-cloud/references/vpc.md) - Networks, subnets, Cloud Run with VPC
|
|
15
|
+
- [Secrets Manager](../google-cloud/references/secrets.md) - Secret setup, access, Cloud Run integration
|
|
16
|
+
- [cloud-deploy](../cloud-deploy/SKILL.md) - Complex deployments with Cloud Deploy + Skaffold
|
|
17
|
+
- [cloud-debug](../cloud-debug/SKILL.md) - Debugging Cloud Build/Deploy failures
|
|
18
|
+
|
|
19
|
+
## When to Use
|
|
20
|
+
|
|
21
|
+
- Single container deployments
|
|
22
|
+
- Services handling own migrations (e.g., Airflow standalone)
|
|
23
|
+
- No need for staged promotion with verification
|
|
24
|
+
|
|
25
|
+
For complex deployments with migrations and verification, use `cloud-deploy` skill.
|
|
26
|
+
|
|
27
|
+
## Architecture
|
|
28
|
+
|
|
29
|
+
**GitFlow (default)** — a long-lived integration branch plus a production branch:
|
|
30
|
+
|
|
31
|
+
```
|
|
32
|
+
dev push ────→ Cloud Build ────→ Cloud Run (dev)
|
|
33
|
+
PR to master ─→ Cloud Build ────→ Cloud Run (staging)
|
|
34
|
+
v*-rc.* tag ──→ Cloud Build ────→ Cloud Run (prod, 0% traffic candidate)
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
**GitHub Flow** — one long-lived branch; see [GitHub Flow variant](#github-flow-variant) for the trigger set and what changes:
|
|
38
|
+
|
|
39
|
+
```
|
|
40
|
+
PR opened ─────→ Cloud Build ────→ build + test only, no deploy
|
|
41
|
+
merge to main ─→ Cloud Build ────→ Cloud Run (staging, 100% traffic)
|
|
42
|
+
v*-rc.* tag ───→ Cloud Build ────→ Cloud Run (prod, 0% traffic candidate)
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
**The prod fork is identical in both.** It keys off the rc tag, not off a branch — which is the practical payoff of triggering production on a tag: the release path stops caring what the branching model is.
|
|
46
|
+
|
|
47
|
+
## Environment Configuration
|
|
48
|
+
|
|
49
|
+
### Triggers
|
|
50
|
+
|
|
51
|
+
- **Dev**: `dev` branch push — active development
|
|
52
|
+
- **Staging**: PR to `master` — PR validation
|
|
53
|
+
- **Prod**: `v*-rc.*` tag push — builds a candidate revision at 0% traffic; the release lane verifies it and shifts traffic
|
|
54
|
+
|
|
55
|
+
### Database
|
|
56
|
+
|
|
57
|
+
- **Dev**: Dedicated dev DB — migrations skipped for faster iteration
|
|
58
|
+
- **Staging**: Dedicated staging DB — runs migrations + test seeds
|
|
59
|
+
- **Prod**: Production DB — runs migrations + prod seeds
|
|
60
|
+
|
|
61
|
+
Dev skips migrations/seeds during build for speed. Cloud Run Jobs are still configured so they can be triggered manually when needed.
|
|
62
|
+
|
|
63
|
+
**For Cloud SQL connection patterns, see [google-cloud skill VPC reference](../google-cloud/references/vpc.md) — Cloud SQL Connection Standard.**
|
|
64
|
+
|
|
65
|
+
### Build Steps
|
|
66
|
+
|
|
67
|
+
All environments run: **setup env → build → update job → deploy → test**
|
|
68
|
+
|
|
69
|
+
Staging + Prod additionally run: **migrate → seed**
|
|
70
|
+
|
|
71
|
+
Step descriptions:
|
|
72
|
+
- **setup env**: Initialize environment-specific variables (VPC, secrets)
|
|
73
|
+
- **build**: Build and push Docker image to Artifact Registry
|
|
74
|
+
- **update job**: Configure Cloud Run Jobs (for migrate/seed) — does not execute them
|
|
75
|
+
- **migrate**: Execute database migration job
|
|
76
|
+
- **deploy**: Deploy to Cloud Run service
|
|
77
|
+
- **seed**: Execute database seed job
|
|
78
|
+
- **test**: Run integration tests against deployed service
|
|
79
|
+
|
|
80
|
+
### Migration Best Practice: Skip When Schema Inputs Are Unchanged
|
|
81
|
+
|
|
82
|
+
If migrations run through Cloud Build, prefer a single combined **migrate-if-needed** step rather than separate "check", "update job", and "execute job" steps. The step should:
|
|
83
|
+
|
|
84
|
+
1. Hash only the files that define database shape
|
|
85
|
+
2. Compare that hash to the last applied hash stored outside the build workspace
|
|
86
|
+
3. Skip migration image build, job update, and job execution when the hash is unchanged
|
|
87
|
+
|
|
88
|
+
Use a persistent marker such as a GCS object:
|
|
89
|
+
|
|
90
|
+
```text
|
|
91
|
+
gs://$PROJECT_ID_cloudbuild/migrate-markers/{service}-${_ENV}.digest
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Why:
|
|
95
|
+
- Avoids slow no-op migration runs on every deploy
|
|
96
|
+
- Works with Cloud Build's shallow clone and source mirror limitations
|
|
97
|
+
- Keeps migration execution tied to actual schema changes rather than every app change
|
|
98
|
+
|
|
99
|
+
Do not hash the whole repo. Hash only migration-relevant inputs for the ORM in use.
|
|
100
|
+
|
|
101
|
+
Practical rules:
|
|
102
|
+
- Do **not** gate migrations with `git diff HEAD^ HEAD`. Merge commits, shallow clones, and repository-event checkouts can compare against the wrong parent and produce false positives.
|
|
103
|
+
- The **first** build after adopting digest-based gating should usually run migrations once, because there is no previous marker yet. That is expected marker seeding, not a failure of the gate.
|
|
104
|
+
- After a successful migration job, write the new digest marker even if the job only reports "database schema is up to date". Otherwise every later build will look like a first run.
|
|
105
|
+
- Prefer `gcr.io/google.com/cloudsdktool/cloud-sdk:slim` and keep the skip path to a single always-started SDK step. A split "decide" + "maybe-run" pattern is usually slower for the common unchanged-schema case.
|
|
106
|
+
- If Cloud Build UI still shows a migration step, check whether it truly executed a Cloud Run Job or only started a step that exited early. Those are different.
|
|
107
|
+
|
|
108
|
+
### Prisma Example
|
|
109
|
+
|
|
110
|
+
For Prisma, prefer hashing:
|
|
111
|
+
- `prisma/schema.prisma`
|
|
112
|
+
- `prisma/migrations/**`
|
|
113
|
+
|
|
114
|
+
If the digest is unchanged, skip all migration job work. A pragmatic pattern is a single slim SDK step that:
|
|
115
|
+
- computes the digest
|
|
116
|
+
- compares it with the stored marker
|
|
117
|
+
- exits immediately when unchanged
|
|
118
|
+
- otherwise deploys and executes the migration job
|
|
119
|
+
- writes the new digest back to GCS after success
|
|
120
|
+
|
|
121
|
+
Example:
|
|
122
|
+
|
|
123
|
+
```yaml
|
|
124
|
+
- name: gcr.io/google.com/cloudsdktool/cloud-sdk:slim
|
|
125
|
+
id: migrate-if-needed
|
|
126
|
+
entrypoint: bash
|
|
127
|
+
args:
|
|
128
|
+
- -ceu
|
|
129
|
+
- |
|
|
130
|
+
digest_file="/workspace/migration-digest.txt"
|
|
131
|
+
marker="gs://${PROJECT_ID}_cloudbuild/migrate-markers/{service}-${_ENV}.digest"
|
|
132
|
+
current_digest="$$( \
|
|
133
|
+
{ \
|
|
134
|
+
printf '%s\0' prisma/schema.prisma; \
|
|
135
|
+
find prisma/migrations -type f -print0; \
|
|
136
|
+
} | sort -z | xargs -0 sha256sum | sha256sum | cut -d' ' -f1 \
|
|
137
|
+
)"
|
|
138
|
+
previous_digest="$$(gcloud storage cat "$${marker}" 2>/dev/null || true)"
|
|
139
|
+
|
|
140
|
+
if [[ -n "$${previous_digest}" && "$${previous_digest}" == "$${current_digest}" ]]; then
|
|
141
|
+
echo "Prisma schema unchanged; skipping migrate job."
|
|
142
|
+
exit 0
|
|
143
|
+
fi
|
|
144
|
+
|
|
145
|
+
printf '%s' "$${current_digest}" > "$${digest_file}"
|
|
146
|
+
|
|
147
|
+
migration_script="$$(cat <<'EOF'
|
|
148
|
+
status_output=$$(pnpm prisma migrate status 2>&1 || true)
|
|
149
|
+
echo "$${status_output}"
|
|
150
|
+
if grep -qi "Database schema is up to date" <<<"$${status_output}"; then
|
|
151
|
+
echo "Database already up to date"
|
|
152
|
+
exit 0
|
|
153
|
+
fi
|
|
154
|
+
if grep -qi "Following migration" <<<"$${status_output}" || grep -qi "have not yet been applied" <<<"$${status_output}"; then
|
|
155
|
+
pnpm prisma migrate deploy
|
|
156
|
+
exit 0
|
|
157
|
+
fi
|
|
158
|
+
echo "Unexpected prisma migrate status output"
|
|
159
|
+
exit 1
|
|
160
|
+
EOF
|
|
161
|
+
)"
|
|
162
|
+
|
|
163
|
+
gcloud run jobs deploy {service}-${_ENV}-migrate \
|
|
164
|
+
--image=$LOCATION-docker.pkg.dev/$PROJECT_ID/{repo}/{service}:$COMMIT_SHA \
|
|
165
|
+
--region=$LOCATION \
|
|
166
|
+
--command=bash \
|
|
167
|
+
--args=-ceu \
|
|
168
|
+
--args="$${migration_script}"
|
|
169
|
+
|
|
170
|
+
gcloud run jobs execute {service}-${_ENV}-migrate --region=$LOCATION --wait --format=none
|
|
171
|
+
gcloud storage cp "$${digest_file}" "$${marker}"
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
### Tortoise ORM + Aerich Example
|
|
175
|
+
|
|
176
|
+
For Tortoise ORM, there is no single canonical schema file like Prisma. Hash:
|
|
177
|
+
- `aerich.ini` or equivalent Aerich config
|
|
178
|
+
- `migrations/**` or `aerich/**` migration files
|
|
179
|
+
- the model packages that define Tortoise tables
|
|
180
|
+
|
|
181
|
+
The same preference applies here: a combined digest-check + migrate-if-needed step is usually better than separate decision and execution steps unless the pipeline has a strong reason to split them.
|
|
182
|
+
|
|
183
|
+
Example:
|
|
184
|
+
|
|
185
|
+
```yaml
|
|
186
|
+
- name: gcr.io/google.com/cloudsdktool/cloud-sdk:slim
|
|
187
|
+
id: check-migrations
|
|
188
|
+
entrypoint: bash
|
|
189
|
+
args:
|
|
190
|
+
- -ceu
|
|
191
|
+
- |
|
|
192
|
+
marker="gs://${PROJECT_ID}_cloudbuild/migrate-markers/{service}-${_ENV}.digest"
|
|
193
|
+
current_digest="$$( \
|
|
194
|
+
{ \
|
|
195
|
+
printf '%s\0' aerich.ini; \
|
|
196
|
+
find migrations -type f -print0 2>/dev/null || true; \
|
|
197
|
+
find app/models -type f \\( -name '*.py' -o -name '*.sql' \\) -print0; \
|
|
198
|
+
} \
|
|
199
|
+
| sort -z \
|
|
200
|
+
| xargs -0 sha256sum \
|
|
201
|
+
| sha256sum \
|
|
202
|
+
| cut -d' ' -f1)"
|
|
203
|
+
previous_digest="$$(gcloud storage cat "$${marker}" 2>/dev/null || true)"
|
|
204
|
+
|
|
205
|
+
if [[ -n "$${previous_digest}" && "$${previous_digest}" == "$${current_digest}" ]]; then
|
|
206
|
+
echo "Aerich inputs unchanged; skipping migrate job."
|
|
207
|
+
exit 0
|
|
208
|
+
fi
|
|
209
|
+
|
|
210
|
+
touch /workspace/.migrate-needed
|
|
211
|
+
printf '%s' "$${current_digest}" > /workspace/.new-migration-digest
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
For Aerich, keep the migration command deterministic inside the Cloud Run Job:
|
|
215
|
+
|
|
216
|
+
```bash
|
|
217
|
+
aerich upgrade
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
If you generate migrations in CI, treat that as a separate workflow with tighter review controls. For normal deploys, prefer committing generated migration files and only applying them in Cloud Build.
|
|
221
|
+
|
|
222
|
+
## cloudbuild.yaml
|
|
223
|
+
|
|
224
|
+
```yaml
|
|
225
|
+
substitutions:
|
|
226
|
+
_ENV: dev
|
|
227
|
+
_MIN_INSTANCES: '0'
|
|
228
|
+
_DATABASE_URL_SECRET: {service}-database-url-${_ENV}
|
|
229
|
+
_SECRET_KEY: {service}-secret-key
|
|
230
|
+
# VPC configuration per environment
|
|
231
|
+
_VPC_NETWORK_DEV: 'default'
|
|
232
|
+
_VPC_SUBNET_DEV: 'default'
|
|
233
|
+
_VPC_NETWORK_STAGING: 'default'
|
|
234
|
+
_VPC_SUBNET_STAGING: 'default'
|
|
235
|
+
_VPC_NETWORK_PROD: 'prod'
|
|
236
|
+
_VPC_SUBNET_PROD: 'prod'
|
|
237
|
+
|
|
238
|
+
steps:
|
|
239
|
+
# Initialize environment-specific variables
|
|
240
|
+
- name: 'bash'
|
|
241
|
+
env:
|
|
242
|
+
- '_ENV=${_ENV}'
|
|
243
|
+
- '_VPC_NETWORK_DEV=${_VPC_NETWORK_DEV}'
|
|
244
|
+
- '_VPC_NETWORK_STAGING=${_VPC_NETWORK_STAGING}'
|
|
245
|
+
- '_VPC_NETWORK_PROD=${_VPC_NETWORK_PROD}'
|
|
246
|
+
- '_VPC_SUBNET_DEV=${_VPC_SUBNET_DEV}'
|
|
247
|
+
- '_VPC_SUBNET_STAGING=${_VPC_SUBNET_STAGING}'
|
|
248
|
+
- '_VPC_SUBNET_PROD=${_VPC_SUBNET_PROD}'
|
|
249
|
+
args:
|
|
250
|
+
- '-c'
|
|
251
|
+
- |
|
|
252
|
+
ENV_UPPER=$$(echo "$$_ENV" | tr '[:lower:]' '[:upper:]')
|
|
253
|
+
NETWORK_VAR="_VPC_NETWORK_$$ENV_UPPER"
|
|
254
|
+
SUBNET_VAR="_VPC_SUBNET_$$ENV_UPPER"
|
|
255
|
+
VPC_NETWORK="$${!NETWORK_VAR}"
|
|
256
|
+
VPC_SUBNET="$${!SUBNET_VAR}"
|
|
257
|
+
echo "VPC_NETWORK=$$VPC_NETWORK" > /workspace/env.sh
|
|
258
|
+
echo "VPC_SUBNET=$$VPC_SUBNET" >> /workspace/env.sh
|
|
259
|
+
echo "Initialized: VPC network=$$VPC_NETWORK, subnet=$$VPC_SUBNET"
|
|
260
|
+
|
|
261
|
+
# Build the Docker image
|
|
262
|
+
- name: 'gcr.io/cloud-builders/docker'
|
|
263
|
+
args:
|
|
264
|
+
- 'build'
|
|
265
|
+
- '-t'
|
|
266
|
+
- '$LOCATION-docker.pkg.dev/$PROJECT_ID/{repo}/{service}:$COMMIT_SHA'
|
|
267
|
+
- '-t'
|
|
268
|
+
- '$LOCATION-docker.pkg.dev/$PROJECT_ID/{repo}/{service}:latest'
|
|
269
|
+
- '.'
|
|
270
|
+
|
|
271
|
+
# Push to Artifact Registry
|
|
272
|
+
- name: 'gcr.io/cloud-builders/docker'
|
|
273
|
+
args:
|
|
274
|
+
- 'push'
|
|
275
|
+
- '--all-tags'
|
|
276
|
+
- '$LOCATION-docker.pkg.dev/$PROJECT_ID/{repo}/{service}'
|
|
277
|
+
|
|
278
|
+
# Deploy to Cloud Run
|
|
279
|
+
- name: 'gcr.io/google.com/cloudsdktool/cloud-sdk'
|
|
280
|
+
entrypoint: bash
|
|
281
|
+
args:
|
|
282
|
+
- '-c'
|
|
283
|
+
- |
|
|
284
|
+
source /workspace/env.sh
|
|
285
|
+
gcloud run deploy {service}-${_ENV} \
|
|
286
|
+
--image=$LOCATION-docker.pkg.dev/$PROJECT_ID/{repo}/{service}:$COMMIT_SHA \
|
|
287
|
+
--region=$LOCATION \
|
|
288
|
+
--platform=managed \
|
|
289
|
+
--min-instances=${_MIN_INSTANCES} \
|
|
290
|
+
--max-instances=1 \
|
|
291
|
+
--memory=2Gi \
|
|
292
|
+
--cpu=1 \
|
|
293
|
+
--port=8080 \
|
|
294
|
+
--cpu-boost \
|
|
295
|
+
--no-cpu-throttling \
|
|
296
|
+
--timeout=300 \
|
|
297
|
+
--set-secrets=DATABASE_URL=${_DATABASE_URL_SECRET}:latest,SECRET_KEY=${_SECRET_KEY}:latest \
|
|
298
|
+
--network=$${VPC_NETWORK} \
|
|
299
|
+
--subnet=$${VPC_SUBNET}
|
|
300
|
+
|
|
301
|
+
options:
|
|
302
|
+
logging: CLOUD_LOGGING_ONLY
|
|
303
|
+
machineType: E2_HIGHCPU_8
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
## Infrastructure Configuration
|
|
307
|
+
|
|
308
|
+
For IAM, VPC, Secrets, and IAP patterns, see the [google-cloud](../google-cloud/SKILL.md) skill:
|
|
309
|
+
|
|
310
|
+
- **VPC**: [google-cloud/vpc.md](../google-cloud/references/vpc.md) - Network/subnet setup for Cloud Run
|
|
311
|
+
- **Secrets**: [google-cloud/secrets.md](../google-cloud/references/secrets.md) - Secret Manager setup and Cloud Run integration
|
|
312
|
+
- **IAM/IAP**: [google-cloud/iam.md](../google-cloud/references/iam.md) - Service accounts, roles, IAP access, token minting
|
|
313
|
+
|
|
314
|
+
### Build Triggers
|
|
315
|
+
|
|
316
|
+
```bash
|
|
317
|
+
# Dev
|
|
318
|
+
gcloud builds triggers create github --name="{service}-dev" \
|
|
319
|
+
--repo-name="REPO" --repo-owner="OWNER" --branch-pattern="^dev$" \
|
|
320
|
+
--build-config="cloudbuild.yaml" --substitutions="_ENV=dev,_MIN_INSTANCES=0"
|
|
321
|
+
|
|
322
|
+
# Staging
|
|
323
|
+
gcloud builds triggers create github --name="{service}-staging" \
|
|
324
|
+
--repo-name="REPO" --repo-owner="OWNER" --pull-request-pattern="^master$" \
|
|
325
|
+
--build-config="cloudbuild.yaml" --substitutions="_ENV=staging,_MIN_INSTANCES=0"
|
|
326
|
+
|
|
327
|
+
# Prod — fires on release-candidate tags minted by the release lane, not on branch push
|
|
328
|
+
gcloud builds triggers create github --name="{service}-prod" \
|
|
329
|
+
--repo-name="REPO" --repo-owner="OWNER" --tag-pattern="^v[0-9]+\.[0-9]+\.[0-9]+-rc\.[0-9]+$" \
|
|
330
|
+
--build-config="cloudbuild.yaml" --substitutions="_ENV=prod,_MIN_INSTANCES=1"
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
**Footgun: the prod tag pattern must not match the final `v<version>` tag.** The release lane mints `v1.4.0-rc.1` to produce a candidate, and then — after the candidate verifies ALIVE and traffic is at 100% — mints `v1.4.0`. A loose pattern like `^v.*$` matches both, so the final tag fires a second production build that rebuilds and redeploys an already-live release at 0% traffic for no reason. Anchor the `-rc.<n>` suffix, as above, and check the pattern against both tag shapes before creating the trigger.
|
|
334
|
+
|
|
335
|
+
Dev and staging triggers are unchanged: `dev` still builds on branch push, staging still builds on PRs to `master`.
|
|
336
|
+
|
|
337
|
+
### GitHub Flow variant
|
|
338
|
+
|
|
339
|
+
One long-lived branch (`main`), short-lived feature branches, no `dev`. Three triggers, the same `cloudbuild.yaml`:
|
|
340
|
+
|
|
341
|
+
```bash
|
|
342
|
+
# PR — build and test only. No deploy: a PR is not an environment.
|
|
343
|
+
gcloud builds triggers create github --name="{service}-pr" \
|
|
344
|
+
--repo-name="REPO" --repo-owner="OWNER" --pull-request-pattern="^main$" \
|
|
345
|
+
--build-config="cloudbuild.yaml" --substitutions="_ENV=ci"
|
|
346
|
+
|
|
347
|
+
# Staging — every merge to main deploys at 100% and records the SHA-keyed verdict
|
|
348
|
+
gcloud builds triggers create github --name="{service}-staging" \
|
|
349
|
+
--repo-name="REPO" --repo-owner="OWNER" --branch-pattern="^main$" \
|
|
350
|
+
--build-config="cloudbuild.yaml" --substitutions="_ENV=staging,_MIN_INSTANCES=0"
|
|
351
|
+
|
|
352
|
+
# Prod — byte-identical to the GitFlow prod trigger
|
|
353
|
+
gcloud builds triggers create github --name="{service}-prod" \
|
|
354
|
+
--repo-name="REPO" --repo-owner="OWNER" --tag-pattern="^v[0-9]+\.[0-9]+\.[0-9]+-rc\.[0-9]+$" \
|
|
355
|
+
--build-config="cloudbuild.yaml" --substitutions="_ENV=prod,_MIN_INSTANCES=1"
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
**`_ENV=staging` takes the dev fork's behavior, not the GitFlow staging behavior.** It deploys at 100% and runs the smoke as a **non-blocking recorder** publishing a `dev-smoke`-style commit status — because under GitHub Flow this environment *is* the integration environment. Reuse the [dev fork step](#integration-dev-deploy-100-record-the-verdict-never-fail-the-build) verbatim, matching on `staging` instead of `dev`. Everything else — build, migrations, seeds, the prod fork — is unchanged.
|
|
359
|
+
|
|
360
|
+
**What the recorded verdict means here is weaker, and that is the one thing to understand.** In GitFlow, the promoted SHA and the validated SHA are the same commit: `dev` is validated, and the promotion fast-forwards it into `main`. Under GitHub Flow there is only one branch, so the release lane cuts `release/<version>` at a validated SHA, merges it back into `main`, and the **shipped SHA is that merge commit** — which also carries anything else that landed on `main` meanwhile. Those commits never earned a verdict.
|
|
361
|
+
|
|
362
|
+
So under GitHub Flow the SHA-keyed staging verdict is a **pre-filter, not the release gate**. The gate is the prod candidate at 0% traffic, which validates the *exact shipped SHA* on real infrastructure before any user reaches it. That is sound precisely because of the 0%-candidate design — under a deploy-then-smoke pipeline the same topology would ship unvalidated commits straight to users.
|
|
363
|
+
|
|
364
|
+
**Order is forced: merge first, then tag.** `version.mjs tag` refuses a SHA that is not an ancestor of the production branch, so the release branch cannot be rc-tagged before it lands on `main`. Merge the release PR, then mint the rc on the merge commit. Release-lane sequencing: `resolve-release` step 1.
|
|
365
|
+
|
|
366
|
+
## Build Notifications
|
|
367
|
+
|
|
368
|
+
Build notifications can be routed via Cloud Build Pub/Sub topic to external services (Slack, Discord, webhooks). Configure the notification sink at the project level.
|
|
369
|
+
|
|
370
|
+
**Critical:** Do NOT set `options.pubsubTopic` in `cloudbuild.yaml` — it overrides the built-in topic and can break your notification pipeline.
|
|
371
|
+
|
|
372
|
+
## Post-deploy smoke gate (Cloud Run)
|
|
373
|
+
|
|
374
|
+
A "deploy SUCCESS" only proves the revision is `Ready` — not that the real built image, with real secrets/env, actually works. The bug class this catches lives *only* in the deployed artifact (a secret with a trailing newline, an env substitution like `_ENV` stripped at deploy, a file not `COPY`ed into the image, a `redirect_uri` from the container bind origin, traffic pinned to a stale revision). No PR-lane or `next dev` test sees it. Run a curated **smoke gate** against the deployed revision — the canonical doctrine, the manifest format, and the `--target` semantics live in the **`smoke` skill** (`skills/engineering/smoke`); this section is only the Cloud Run/Cloud Build *placement*.
|
|
375
|
+
|
|
376
|
+
**The pipeline owns artifacts. The release lane owns exposure.** That seam decides what each fork of the build is allowed to do. The build's job ends at producing something verifiable — an image, a revision, a verdict. Deciding that users should see it is the release lane's job, not a build step's.
|
|
377
|
+
|
|
378
|
+
**Where it blocks depends on who the environment serves.** The blocking placement protects *users*, so it belongs on the **production** path. An integration environment (`dev`) has no users to protect — there, a blocking smoke only converts small bugs and infra flakes into failed builds and full rebuild cycles. So the same seam cuts differently per fork, and each fork's contract output is different:
|
|
379
|
+
|
|
380
|
+
- **`dev` output: a SHA-keyed verdict.** Deploy at 100%, smoke as a non-blocking recorder, publish the verdict as a commit status. Nothing is gated here; the verdict blocks later, at the dev→main promotion, where the release lane pins its candidate to a validated SHA (`resolve-release` principle 11).
|
|
381
|
+
- **prod output: a 0%-traffic candidate revision.** Deploy with `--no-traffic`, surface the revision name and candidate URL, and **stop**. The build does not smoke it and does not shift traffic — `resolve-release` does both.
|
|
382
|
+
|
|
383
|
+
**Why the prod gate moved out of the build.** The gate did not disappear; it moved to where it can be operated:
|
|
384
|
+
|
|
385
|
+
- **Validation becomes retryable without a rebuild.** A red smoke inside the build means re-triggering the whole build to retry a config or secret fix. Against an already-deployed candidate URL it is a re-run measured in seconds.
|
|
386
|
+
- **The traffic shift sits behind a human authorization point.** A build step promoting traffic is an automatic decision made by whoever pushed a tag. In the release lane it is an explicit act with a person and a version behind it.
|
|
387
|
+
- **The pipeline can change without the release doctrine changing.** `cloudbuild.yaml` is free to change builders, regions, or step order; the release contract is still "give me a candidate at 0%."
|
|
388
|
+
|
|
389
|
+
### Production: build a candidate, stop before traffic
|
|
390
|
+
|
|
391
|
+
The prod fork's entire contract is three facts:
|
|
392
|
+
|
|
393
|
+
- **In:** a tag push matching `v*-rc.*` — release-candidate tags, minted by the release lane.
|
|
394
|
+
- **Out:** a candidate revision deployed at **0% traffic**, with its revision name and candidate URL discoverable by the caller.
|
|
395
|
+
- **Never:** it does not validate, and it does not shift traffic.
|
|
396
|
+
|
|
397
|
+
```
|
|
398
|
+
tag v*-rc.* → build → deploy --no-traffic --tag candidate → publish {revision, url} → END
|
|
399
|
+
│
|
|
400
|
+
resolve-release: smoke --profile prod-preview (read-only) ──┤
|
|
401
|
+
ALIVE → update-traffic 100%, tag v<version>
|
|
402
|
+
DEAD → delete the 0% revision (traffic never moved)
|
|
403
|
+
```
|
|
404
|
+
|
|
405
|
+
Because traffic never moved, a DEAD verdict is not a rollback and has no user impact — the candidate revision is simply deleted.
|
|
406
|
+
|
|
407
|
+
```yaml
|
|
408
|
+
# Prod fork: deploy the candidate at 0% traffic, then stop.
|
|
409
|
+
- name: 'gcr.io/google.com/cloudsdktool/cloud-sdk'
|
|
410
|
+
id: deploy-candidate
|
|
411
|
+
entrypoint: bash
|
|
412
|
+
args:
|
|
413
|
+
- '-c'
|
|
414
|
+
- |
|
|
415
|
+
[[ "${_ENV}" == "prod" ]] || exit 0
|
|
416
|
+
source /workspace/env.sh
|
|
417
|
+
gcloud run deploy {service}-${_ENV} \
|
|
418
|
+
--image=$LOCATION-docker.pkg.dev/$PROJECT_ID/{repo}/{service}:$COMMIT_SHA \
|
|
419
|
+
--region=$LOCATION \
|
|
420
|
+
--platform=managed \
|
|
421
|
+
--min-instances=${_MIN_INSTANCES} \
|
|
422
|
+
--max-instances=1 \
|
|
423
|
+
--memory=2Gi \
|
|
424
|
+
--cpu=1 \
|
|
425
|
+
--port=8080 \
|
|
426
|
+
--cpu-boost \
|
|
427
|
+
--no-cpu-throttling \
|
|
428
|
+
--timeout=300 \
|
|
429
|
+
--set-secrets=DATABASE_URL=${_DATABASE_URL_SECRET}:latest,SECRET_KEY=${_SECRET_KEY}:latest \
|
|
430
|
+
--network=$${VPC_NETWORK} \
|
|
431
|
+
--subnet=$${VPC_SUBNET} \
|
|
432
|
+
--no-traffic \
|
|
433
|
+
--tag=candidate
|
|
434
|
+
|
|
435
|
+
# Publish the candidate coordinates for the release lane. Build ends here.
|
|
436
|
+
- name: 'gcr.io/google.com/cloudsdktool/cloud-sdk'
|
|
437
|
+
id: publish-candidate
|
|
438
|
+
entrypoint: bash
|
|
439
|
+
args:
|
|
440
|
+
- '-c'
|
|
441
|
+
- |
|
|
442
|
+
[[ "${_ENV}" == "prod" ]] || exit 0
|
|
443
|
+
svc="$$(gcloud run services describe {service}-${_ENV} --region=$LOCATION --format=json)"
|
|
444
|
+
|
|
445
|
+
# Read BOTH coordinates off the same `candidate` traffic entry. Do not reach for
|
|
446
|
+
# .status.latestCreatedRevisionName: "latest" and "the one I just tagged" are the
|
|
447
|
+
# same thing only when nothing else is deploying, and the case where they diverge
|
|
448
|
+
# is exactly the case you need this to be right — a concurrent build would hand the
|
|
449
|
+
# release lane one revision's name beside another revision's URL.
|
|
450
|
+
revision="$$(jq -r '.status.traffic[] | select(.tag=="candidate") | .revisionName' <<<"$${svc}")"
|
|
451
|
+
url="$$(jq -r '.status.traffic[] | select(.tag=="candidate") | .url' <<<"$${svc}")"
|
|
452
|
+
[[ -n "$${url}" && "$${url}" != "null" ]] || { echo "no candidate tag URL"; exit 1; }
|
|
453
|
+
[[ -n "$${revision}" && "$${revision}" != "null" ]] || { echo "no candidate revision"; exit 1; }
|
|
454
|
+
|
|
455
|
+
# Prove the tagged revision runs THIS build's image before publishing it as the
|
|
456
|
+
# candidate. Without this, a failed deploy that left the previous candidate in place
|
|
457
|
+
# publishes stale coordinates the release lane would validate and promote.
|
|
458
|
+
running="$$(gcloud run revisions describe "$${revision}" --region=$LOCATION \
|
|
459
|
+
--format='value(spec.containers[0].image)')"
|
|
460
|
+
[[ "$${running}" == *":$COMMIT_SHA" ]] || {
|
|
461
|
+
echo "candidate $${revision} runs $${running}, not $COMMIT_SHA"; exit 1; }
|
|
462
|
+
|
|
463
|
+
jq -n --arg r "$${revision}" --arg u "$${url}" --arg s "$COMMIT_SHA" --arg t "$TAG_NAME" \
|
|
464
|
+
'{revision:$$r, candidate_url:$$u, commit_sha:$$s, rc_tag:$$t}' \
|
|
465
|
+
> /workspace/candidate.json
|
|
466
|
+
gcloud storage cp /workspace/candidate.json \
|
|
467
|
+
"gs://$${PROJECT_ID}_cloudbuild/candidates/{service}-$TAG_NAME.json"
|
|
468
|
+
cat /workspace/candidate.json
|
|
469
|
+
```
|
|
470
|
+
|
|
471
|
+
**The `candidate` tag moves; the revision name does not.** Each prod build re-points `--tag=candidate` at its own new revision, so the tag URL always means "the newest candidate," not "the candidate I built." That is why the published JSON carries the **revision name** and why the release lane deletes a failed candidate **by name** — and it is a second reason `resolve-release` principle 7 serializes releases: two candidates in flight would leave the earlier one addressable only by revision, its URL silently repointed at the later build.
|
|
472
|
+
|
|
473
|
+
**Surface the coordinates as a GCS object keyed by the RC tag, not as log output.** The release lane already knows the tag it pushed, so it can fetch `candidates/{service}-<rc-tag>.json` without knowing the build ID — no build lookup, no log scraping, and the object outlives log retention. The `cat` at the end is a convenience for humans reading the build, not the interface. Derive the URL from `gcloud run services describe` rather than from `gcloud run deploy` output: the tag URL lives in `status.traffic[]`, and describing the service after the deploy also proves the tag actually landed (the guard above fails the build if it did not).
|
|
474
|
+
|
|
475
|
+
**Verification-time policy belongs to the release lane.** Against production, the release lane runs smoke under a **read-only production Validation Profile** (`prod-preview`/`prod-active`); the profile's semantics are the `smoke` skill's to document, not this file's.
|
|
476
|
+
|
|
477
|
+
**Notification.** A prod build that fails now means the *candidate was never produced* — it flows into the **existing Cloud Build → Pub/Sub notification** above, no new sink. The smoke verdict is no longer a build event at all; it belongs to the release lane.
|
|
478
|
+
|
|
479
|
+
**Debug-loop tip.** Moving validation out of the build is exactly what makes retrying it cheap — this used to be an optional "split it into a second trigger" refinement, and it is now the default. Re-running smoke against the already-deployed candidate URL costs seconds and needs no rebuild. (For staged multi-environment promotion, prefer `cloud-deploy`'s verify phase, which gates promotion and is likewise retryable without a rebuild.)
|
|
480
|
+
|
|
481
|
+
### Integration (`dev`): deploy 100%, record the verdict, never fail the build
|
|
482
|
+
|
|
483
|
+
`dev` deploys straight to **100% traffic** on build success — no `--no-traffic` staging, no smoke step that can fail the build. Smoke still runs, as a **recorder**:
|
|
484
|
+
|
|
485
|
+
```
|
|
486
|
+
build → deploy (100% traffic) → smoke → publish SHA-keyed verdict (never fails the build)
|
|
487
|
+
```
|
|
488
|
+
|
|
489
|
+
```yaml
|
|
490
|
+
# Dev fork: deploy at 100% traffic (the standard deploy step above), then record a verdict.
|
|
491
|
+
- name: 'gcr.io/google.com/cloudsdktool/cloud-sdk'
|
|
492
|
+
id: record-smoke-verdict
|
|
493
|
+
entrypoint: bash
|
|
494
|
+
secretEnv: ['GITHUB_TOKEN']
|
|
495
|
+
args:
|
|
496
|
+
- '-c'
|
|
497
|
+
- |
|
|
498
|
+
[[ "${_ENV}" == "dev" ]] || exit 0
|
|
499
|
+
post_status() { # $1=state $2=description
|
|
500
|
+
curl -sS -X POST \
|
|
501
|
+
-H "Authorization: Bearer $${GITHUB_TOKEN}" \
|
|
502
|
+
-H "Accept: application/vnd.github+json" \
|
|
503
|
+
"https://api.github.com/repos/OWNER/REPO/statuses/$COMMIT_SHA" \
|
|
504
|
+
-d "$$(jq -n --arg s "$$1" --arg d "$$2" \
|
|
505
|
+
'{state:$$s, context:"dev-smoke", description:$$d}')"
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
svc="$$(gcloud run services describe {service}-${_ENV} --region=$LOCATION --format=json)"
|
|
509
|
+
serving="$$(jq -r '.status.traffic[] | select(.percent==100) | .revisionName' <<<"$${svc}")"
|
|
510
|
+
url="$$(jq -r '.status.url' <<<"$${svc}")"
|
|
511
|
+
|
|
512
|
+
# Identify the serving revision by the IMAGE it runs, not by its name: revision
|
|
513
|
+
# names are Cloud Run's own counter (`{service}-dev-00042-abc`) and carry no SHA.
|
|
514
|
+
# The image tag is the only thing that ties the running code to this commit.
|
|
515
|
+
running="$$(gcloud run revisions describe "$${serving}" --region=$LOCATION \
|
|
516
|
+
--format='value(spec.containers[0].image)')"
|
|
517
|
+
if [[ "$${running}" != *":$COMMIT_SHA" ]]; then
|
|
518
|
+
# Traffic is pinned to a stale revision. Smoking now would test OLD code and
|
|
519
|
+
# publish a green verdict against THIS SHA — a false ALIVE that the release lane
|
|
520
|
+
# would later read as authorization to promote. Fail the status, run nothing.
|
|
521
|
+
post_status failure "traffic on $${serving} running $${running##*:} — not this SHA; no verdict earned"
|
|
522
|
+
exit 0
|
|
523
|
+
fi
|
|
524
|
+
|
|
525
|
+
node <smoke>/scripts/smoke.mjs verdict --target "$${url}" --out /workspace/smoke-verdict.json \
|
|
526
|
+
&& state=success || state=failure
|
|
527
|
+
post_status "$${state}" "$$(jq -r '.summary // "smoke verdict unavailable"' /workspace/smoke-verdict.json)"
|
|
528
|
+
|
|
529
|
+
exit 0 # never fail the dev build on a DEAD verdict
|
|
530
|
+
|
|
531
|
+
availableSecrets:
|
|
532
|
+
secretManager:
|
|
533
|
+
- versionName: projects/$PROJECT_ID/secrets/github-status-token/versions/latest
|
|
534
|
+
env: GITHUB_TOKEN
|
|
535
|
+
```
|
|
536
|
+
|
|
537
|
+
- After traffic shifts, **confirm the serving revision is running this commit's image**, then run smoke against the live service URL. Capture the exit code instead of letting it fail the step. Compare **images, not revision names** — Cloud Run names revisions from its own counter, so a name-based check silently never matches and degrades to no check at all. On a mismatch, publish `failure` and **run no smoke**: traffic is on older code, so any verdict it produced would be a green light keyed to a SHA that never served.
|
|
538
|
+
- **Publish the verdict as a commit status on the SHA** (context `dev-smoke`, state `success`/`failure`, description naming the broken path on DEAD). This is the artifact the release lane reads: `resolve-release` pins its release candidate to a SHA with green CI **and** `dev-smoke` ALIVE. The image for a SHA is immutable, so the recorded verdict stays valid after `dev` moves on — no re-run at release time.
|
|
539
|
+
- The step then **exits 0 regardless of verdict**: a DEAD verdict marks the SHA unpromotable; it must not block the next dev iteration.
|
|
540
|
+
- **Non-blocking must not mean silent.** On DEAD, still notify (a Pub/Sub message from the step, or a webhook on the `dev-smoke` status change) so a broken dev is known in minutes, not discovered at release time.
|
|
541
|
+
|
|
542
|
+
## Rules
|
|
543
|
+
|
|
544
|
+
### Entrypoint Fail-Fast
|
|
545
|
+
|
|
546
|
+
All `entrypoint.sh` scripts that use case statements MUST fail on unknown or missing commands. Never silently default to starting a server or executing arbitrary commands.
|
|
547
|
+
|
|
548
|
+
```bash
|
|
549
|
+
# WRONG - silently starts server on unknown command
|
|
550
|
+
*)
|
|
551
|
+
exec python -m app.main
|
|
552
|
+
;;
|
|
553
|
+
|
|
554
|
+
# WRONG - executes arbitrary commands
|
|
555
|
+
*)
|
|
556
|
+
exec "$@"
|
|
557
|
+
;;
|
|
558
|
+
|
|
559
|
+
# CORRECT - fail fast with clear error
|
|
560
|
+
"")
|
|
561
|
+
echo "Error: No command specified."
|
|
562
|
+
echo "Usage: entrypoint.sh {migrate|seed|test|serve}"
|
|
563
|
+
exit 1
|
|
564
|
+
;;
|
|
565
|
+
*)
|
|
566
|
+
echo "Error: Unknown command '$1'"
|
|
567
|
+
echo "Usage: entrypoint.sh {migrate|seed|test|serve}"
|
|
568
|
+
exit 1
|
|
569
|
+
;;
|
|
570
|
+
```
|
|
571
|
+
|
|
572
|
+
**Why:** Silent defaults cause Cloud Run Jobs to hang indefinitely when passed unrecognized commands (e.g., a `seed` command that doesn't exist). The job appears stuck because it started a server instead of failing immediately.
|
|
573
|
+
|
|
574
|
+
### Debug Master Branch Issues by Comparing to Dev
|
|
575
|
+
|
|
576
|
+
When debugging and fixing issues on the master branch, always ask: **"Why didn't this occur on the dev branch?"**
|
|
577
|
+
|
|
578
|
+
This question helps identify:
|
|
579
|
+
- **Environment differences**: VPC, secrets, min instances, database configuration
|
|
580
|
+
- **Missing build steps**: Dev skips migrations/seeds - did this mask an issue?
|
|
581
|
+
- **Trigger differences**: Dev triggers on branch push, staging on PR, prod on a `v*-rc.*` tag push
|
|
582
|
+
- **Data differences**: Dev may have different seed data or database state
|
|
583
|
+
|
|
584
|
+
If the issue only manifests on master/prod:
|
|
585
|
+
1. Compare the cloudbuild.yaml substitutions between environments
|
|
586
|
+
2. Check if migrations ran correctly (dev skips them)
|
|
587
|
+
3. Verify secrets are correctly configured for the environment
|
|
588
|
+
4. Confirm VPC/network settings match expectations
|
|
589
|
+
|
|
590
|
+
**Why:** Issues that appear only in production often stem from environment-specific configuration that was never tested because dev has different settings. Systematically comparing environments catches configuration drift early.
|
|
591
|
+
|
|
592
|
+
## Key Patterns
|
|
593
|
+
|
|
594
|
+
- **Substitutions**: `${_ENV}` for Cloud Build substitutions
|
|
595
|
+
- **Bash escaping**: `$$VAR` for bash variables (becomes `$VAR`)
|
|
596
|
+
- **Env file**: `/workspace/env.sh` persists variables across steps
|
|
597
|
+
- **Min instances**: 0 dev/staging, 1 prod
|
|
598
|
+
- **Machine type**: `E2_HIGHCPU_8` for faster builds
|
|
599
|
+
- **Startup flags**: `--cpu-boost --no-cpu-throttling --timeout=300` for slow-starting containers
|
|
600
|
+
- **Entrypoint**: Always fail fast on unknown commands (see Rules)
|
|
601
|
+
|
|
602
|
+
For VPC, Secrets, and IAM patterns, see [google-cloud](../google-cloud/SKILL.md) and its reference files.
|
|
603
|
+
|
|
604
|
+
## Debug
|
|
605
|
+
|
|
606
|
+
```bash
|
|
607
|
+
# List recent builds
|
|
608
|
+
gcloud builds list --region=$LOCATION --limit=5
|
|
609
|
+
|
|
610
|
+
# Find builds for a specific branch
|
|
611
|
+
gcloud builds list --filter="trigger.branchName=YOUR_BRANCH" --region=$LOCATION
|
|
612
|
+
|
|
613
|
+
# Builds on main branch that failed
|
|
614
|
+
gcloud builds list --filter="trigger.branchName=main AND status=FAILURE" --region=$LOCATION
|
|
615
|
+
|
|
616
|
+
# Detailed output with branch and commit info
|
|
617
|
+
gcloud builds list --filter="trigger.branchName=dev" --region=$LOCATION --limit=10 \
|
|
618
|
+
--format="table(id,startTime,status,trigger.branchName,substitutions.SHORT_SHA)"
|
|
619
|
+
|
|
620
|
+
# View logs for a specific build
|
|
621
|
+
gcloud builds log BUILD_ID --region=$LOCATION
|
|
622
|
+
|
|
623
|
+
# Describe build status
|
|
624
|
+
gcloud builds describe BUILD_ID --region=$LOCATION
|
|
625
|
+
|
|
626
|
+
# Check Cloud Run service status
|
|
627
|
+
gcloud run services describe {svc}-{env} --region=$LOCATION
|
|
628
|
+
```
|
|
629
|
+
|
|
630
|
+
## Best Practices
|
|
631
|
+
|
|
632
|
+
### Enable IAP Protection on Cloud Run
|
|
633
|
+
|
|
634
|
+
See [google-cloud/iam.md](../google-cloud/references/iam.md#cloud-run-native-iap) for:
|
|
635
|
+
- Enabling IAP on Cloud Run with `--no-allow-unauthenticated` and `--iap`
|
|
636
|
+
- Granting access to domain users, individual users, and service accounts
|
|
637
|
+
- IAP in Cloud Build pipelines
|
|
638
|
+
|
|
639
|
+
For programmatic access to IAP-protected resources, see [google-cloud/iam.md#service-account-authentication-jwt-pattern](../google-cloud/references/iam.md#service-account-authentication-jwt-pattern) for:
|
|
640
|
+
- Service account JWT authentication pattern for E2E tests, CI/CD runners, and inter-service calls
|
|
641
|
+
|
|
642
|
+
## Closed-Loop Execution (Monitor → Debug → Fix → Monitor)
|
|
643
|
+
|
|
644
|
+
**Goal:** Never stop after `gcloud builds log --stream`. Always declare the next step and continue until DONE criteria are met or escalated.
|
|
645
|
+
|
|
646
|
+
### DONE / Exit Criteria
|
|
647
|
+
- **Cloud Build:** Build status is `SUCCESS` and all steps complete without errors.
|
|
648
|
+
- **Cloud Run Deploy:** Service revision is updated and `Ready` with desired traffic.
|
|
649
|
+
- **Verification:** Basic smoke check passes (health endpoint or minimal request) and no new errors in service logs for a short window.
|
|
650
|
+
|
|
651
|
+
### Timeboxed Monitoring
|
|
652
|
+
1. **Stream build logs** for 5-10 minutes:
|
|
653
|
+
```bash
|
|
654
|
+
gcloud builds log BUILD_ID --region=$LOCATION --stream
|
|
655
|
+
```
|
|
656
|
+
2. **If still running**, describe build to pinpoint the current step:
|
|
657
|
+
```bash
|
|
658
|
+
gcloud builds describe BUILD_ID --region=$LOCATION
|
|
659
|
+
```
|
|
660
|
+
3. **If failing**, identify the failing step (by step name/ID), then drill into its logs or related service/job logs.
|
|
661
|
+
|
|
662
|
+
### FAILURE vs SUCCESS (Next Commands)
|
|
663
|
+
|
|
664
|
+
**On FAILURE:**
|
|
665
|
+
- Declare next step: "Next step: inspect failing step `<step-name>` logs and related Cloud Run/Job logs."
|
|
666
|
+
- Run:
|
|
667
|
+
```bash
|
|
668
|
+
gcloud builds describe BUILD_ID --region=$LOCATION
|
|
669
|
+
gcloud builds log BUILD_ID --region=$LOCATION
|
|
670
|
+
gcloud run services describe {svc}-{env} --region=$LOCATION
|
|
671
|
+
```
|
|
672
|
+
- Apply fix (config/code), then **re-run build**, and loop back to monitoring.
|
|
673
|
+
|
|
674
|
+
**On SUCCESS:**
|
|
675
|
+
- Declare next step: "Next step: verify deployment and check service logs."
|
|
676
|
+
- Run:
|
|
677
|
+
```bash
|
|
678
|
+
gcloud run services describe {svc}-{env} --region=$LOCATION
|
|
679
|
+
gcloud run services logs read {svc}-{env} --region=$LOCATION --limit=50
|
|
680
|
+
```
|
|
681
|
+
- Perform a minimal verification (health endpoint or basic request). If clean, declare DONE.
|
|
682
|
+
|
|
683
|
+
### Next Step Declaration Rule
|
|
684
|
+
After any log stream or describe command, **explicitly state the next step** before taking it. This prevents stalls after log streaming.
|
|
685
|
+
|
|
686
|
+
### Escalation / Ask-Confirmation Boundary (Risky Ops)
|
|
687
|
+
Ask for confirmation **before** any of the following:
|
|
688
|
+
- Database migrations or seeds in prod
|
|
689
|
+
- Rolling back to a prior revision
|
|
690
|
+
- Changing IAM, VPC, or secrets
|
|
691
|
+
- Deleting resources or data
|
|
692
|
+
|
|
693
|
+
### Incident Checklist (Copy/Paste)
|
|
694
|
+
|
|
695
|
+
```
|
|
696
|
+
[ ] Identify build ID and region
|
|
697
|
+
[ ] Stream build logs (5-10 min)
|
|
698
|
+
[ ] Describe build to find current/failing step
|
|
699
|
+
[ ] If failing: capture step name and error
|
|
700
|
+
[ ] Inspect related Cloud Run service/job logs
|
|
701
|
+
[ ] Declare next step explicitly
|
|
702
|
+
[ ] Apply fix and re-run build
|
|
703
|
+
[ ] Verify Cloud Run revision is Ready + traffic
|
|
704
|
+
[ ] Smoke check endpoint
|
|
705
|
+
[ ] Confirm no new errors in logs (short window)
|
|
706
|
+
[ ] Declare DONE or escalate with reason
|
|
707
|
+
```
|