feat: production GCP Cloud Run foundation + hardened, optimized front end (keyless IaC, WCAG 2.2 AA, GEO/structured-data, CWV-budgeted CI)#713
Open
adammerrill wants to merge 33 commits into
Conversation
Implementation of AstroWind v3 architecture: - Transition CI/CD from Cloud Build to native GitHub Actions. - Add feature-gated multi-project Terraform foundation. - Integrate SCC, CAI, Audit Logs, and IAM Analyzer. - Establish SLIs, SLOs, error budgets, and synthetic monitoring. - Enforce cost governance via Terraform and strengthen DR capabilities.
Convert to Reusable GCP Starter Template
The attribute_condition was scoped to the GitHub owner (any repo under adammerrill/ could federate). The SA binding used the same owner-wide principalSet. Both are now scoped to attribute.repository == 'adammerrill/astro-gcp-cloudrun-starter', so no other repository under the same account can assume the deploy identity. Adds github_repo variable wired through shared env → iam module. Template users must set github_repo in their tfvars; the .example file is updated with the new placeholder. https://claude.ai/code/session_019m7zNSare8J2meL24HDW5K
security(wif): scope WIF identity to this repo only, not entire owner
SA impersonation (used by all downstream environment providers) requires iamcredentials.googleapis.com to generate access tokens. Without it the shared/providers.tf data source fails with 400 badRequest on first plan. https://claude.ai/code/session_019m7zNSare8J2meL24HDW5K
The google_service_account_access_token data source passes scopes directly to the generateAccessToken API, which requires full URIs. Short-form names like 'cloud-platform' are invalid arguments and cause a 400 error. Changed all four environment providers.tf files to use full URIs, matching the format already used in the impersonation provider block above. https://claude.ai/code/session_019m7zNSare8J2meL24HDW5K
fix: use full OAuth2 URIs for SA impersonation scopes + add iamcredentials API to bootstrap
…s, drop duplicate state bucket (#4) * fix(bootstrap): add missing seed APIs needed by downstream environments Previously only 4 APIs were enabled on seed projects. Downstream Terraform environments were failing with 403/disabled errors as each missing API was encountered. Added the full set needed before any environment apply can succeed: - cloudbilling.googleapis.com (project_factory billing config) - iamcredentials.googleapis.com (SA impersonation token generation) - artifactregistry.googleapis.com (shared AR repo creation) - run.googleapis.com (Cloud Run service creation) - secretmanager.googleapis.com (Secret Manager resources) https://claude.ai/code/session_019m7zNSare8J2meL24HDW5K * fix: grant admin SA WIF+SA-admin roles; drop redundant state bucket in shared Two issues surfaced applying the shared environment: 1. The admin SA (editor + projectIamAdmin) cannot create Workload Identity Pools or set IAM policy on service accounts. Added roles/iam.workloadIdentityPoolAdmin and roles/iam.serviceAccountAdmin to the bootstrap admin_roles so downstream WIF/SA-binding resources can be created. 2. The shared environment's storage module created a bucket with the same name as the bootstrap-managed TF state bucket, causing a 409 conflict and dual-ownership across two state files. Removed the storage module from the shared environment; bootstrap owns the state bucket and shared referenced none of the storage outputs. https://claude.ai/code/session_019m7zNSare8J2meL24HDW5K --------- Co-authored-by: Claude <noreply@anthropic.com>
Validated by a full local terraform apply of the dev environment. - deploy-dev.yml: pass TF_VAR_* env vars and -backend-config so CI uses correct values and a gitignored backend - bootstrap admin_roles: add run.admin, logging.configWriter, monitoring.admin, secretmanager.admin (needed by env modules) - storage module: create_state_bucket flag + count-indexed state buckets and outputs so env layers don't duplicate the bootstrap state bucket - dev/main.tf: create_state_bucket = false https://claude.ai/code/session_019m7zNSare8J2meL24HDW5K Co-authored-by: Claude <noreply@anthropic.com>
The deploy pipeline ran a full terraform apply, which broke under keyless WIF in two ways: - The env providers.tf impersonate sa-terraform-admin and require var.terraform_service_account, which CI never set, so apply hung at an interactive prompt until timeout. - backend.tf is gitignored, so -backend-config fell back to local state and would have tried to recreate all already-provisioned resources. Infrastructure is owned by Terraform run deliberately from a controlled environment. CI should only build the app image and deploy a new Cloud Run revision to the existing service. Removed the Setup Terraform and Terraform Apply steps; kept build/push -> deploy-cloudrun -> smoke test. Requires the deploy SA to have roles/run.developer on the env project and roles/iam.serviceAccountUser on the Cloud Run runtime SA. https://claude.ai/code/session_019m7zNSare8J2meL24HDW5K Co-authored-by: Claude <noreply@anthropic.com>
When the container image lives in the shared project's Artifact Registry but the service runs in an env project, the puller is the env project's Cloud Run Service Agent (service-PROJECTNUMBER@serverless-robot-prod), not the runtime SA. Added a data.google_project lookup to construct that agent identity and grant it artifactregistry.reader on the shared project. Without this, deploys fail with a 403 downloadArtifacts denied. https://claude.ai/code/session_019m7zNSare8J2meL24HDW5K Co-authored-by: Claude <noreply@anthropic.com>
… + fix docs) (#9) * docs(audit): gap register — repo vs. actual deploy reality https://claude.ai/code/session_019m7zNSare8J2meL24HDW5K * feat(terraform): codify deploy-SA roles; default create_project=false; service_name=website - iam module grants the GitHub deploy SA run.developer + serviceAccountUser on the runtime SA (was a manual gcloud step) when deploy_service_account_email is set; dev wires it deterministically from shared_project_id. - create_project now defaults to false in env layers (bootstrap owns projects); true caused a billing precondition error. - dev service_name default is now 'website' to match the SERVICE_NAME CI var. https://claude.ai/code/session_019m7zNSare8J2meL24HDW5K * feat(template): complete .example files for required config - shared tfvars.example: add project_id, project_name, create_project - dev tfvars.example: add project_name, create_project, service_name (+ coupling note) - add bootstrap/backend.tf.example so state migration is a copy, not a hand-edit https://claude.ai/code/session_019m7zNSare8J2meL24HDW5K * fix(ci,template): remove unused /app scaffold; staging/prod app-deploy-only - /app placeholder server is unused by the build (root Dockerfile builds the Astro site and serves via nginx:8080); removed to stop misleading users. - staging/prod workflows drop terraform-apply-in-CI to match the validated dev pipeline (keyless, least-privilege, no impersonation hang). https://claude.ai/code/session_019m7zNSare8J2meL24HDW5K * docs(setup): corrected ordered setup + fresh-user walkthrough - FRESH_USER_WALKTHROUGH.md: single authoritative zero-to-deployed path incl. GitHub Variables and verify-URL steps. - SETUP_PLAYBOOK: copy backend.tf.example (not hand-edit main.tf); apply shared before dev; create_project note; project-quota callout. - TEMPLATE_SETUP: correct build path (Astro + nginx:8080, no /app); add CI step. - README: fix 9-vs-8 governance rule count. https://claude.ai/code/session_019m7zNSare8J2meL24HDW5K --------- Co-authored-by: Claude <noreply@anthropic.com>
Adds a 'Run workflow' button to the dev/staging/prod deploy workflows so the current main (or a chosen ref) can be rebuilt and redeployed on demand without an empty commit — useful for forcing a clean rebuild or after rotating GCP-side config. https://claude.ai/code/session_019m7zNSare8J2meL24HDW5K Co-authored-by: Claude <noreply@anthropic.com>
…og, URLs) (#11) * fix(content): repoint stale arthelokyo/astrowind URLs to the new repo Replaces github.com/arthelokyo/astrowind (and the arthelokyo profile + stars badge + astrowind.vercel.app canonical hosts) with github.com/adammerrill/astro-gcp-cloudrun-starter across pages, layouts, landing variants, and legal pages. https://claude.ai/code/session_019m7zNSare8J2meL24HDW5K * feat(content): rebrand homepage, nav, config, and blog to the GCP Cloud Run story - Homepage rewritten around the real value: keyless WIF, Terraform layers, scale-to-zero cost, hardening, app-deploy-only CI, and what ships in the box. - config.yaml metadata/description/handle updated; stale Google verification + vercel site URL replaced. - Footer/nav: 'Use this template' CTA, GCP-themed links, new footnote. - Blog: two lorem-ipsum posts replaced with real guides (deploy-to-Cloud-Run, template-in-depth); customization post retitled. https://claude.ai/code/session_019m7zNSare8J2meL24HDW5K * content: rebrand secondary pages (homes demos, legal, alt text) Removes remaining AstroWind/Astrowind brand references across the alternate-homepage demos (saas, startup, mobile-app), legal pages, the blog list page, and image alt text. Awkward grammar from the brand swap was cleaned up; the startup hero now leads with the Astro + Cloud Run story. Legal-entity placeholder de-branded. https://claude.ai/code/session_019m7zNSare8J2meL24HDW5K * content: clear final brand mentions (announcement, landing post, Image comment, slug) Removes the remaining user-visible AstroWind references from the announcement star-bar and the landing blog post, de-brands an internal component comment, and renames the customization post file so the old brand no longer appears in its URL slug. https://claude.ai/code/session_019m7zNSare8J2meL24HDW5K * style: apply prettier formatting to rebranded files Fixes the check:prettier CI step — formats the homepage, navigation, the two new docs, and the saas/startup demo pages to Prettier style. https://claude.ai/code/session_019m7zNSare8J2meL24HDW5K --------- Co-authored-by: Claude <noreply@anthropic.com>
…ess (#12) * feat(crawler-access): explicit AI-crawler allow policy in robots.txt Explicitly welcomes GPTBot/OAI-SearchBot, ClaudeBot/Claude-User, PerplexityBot, Google-Extended, and Applebot-Extended so the site can be found and cited by AI search engines. They were already allowed via 'User-agent: *'; this makes the stance intentional with a per-bot opt-out. The sitemap reference is still auto-appended at build time. Source: web.dev/articles/vitals; vendor robots.txt integration. https://claude.ai/code/session_019m7zNSare8J2meL24HDW5K * ci(lighthouse): add Core Web Vitals performance budget Runs Lighthouse CI on every PR and fails on CWV regressions: LCP>2.5s, CLS>0.1, TBT>300ms (TBT = lab proxy for INP, which is field-only). Performance/a11y/SEO category scores warn at <0.9 until stable real numbers are observed, then tighten to error. Lab is diagnostic; CrUX field data is the true scoreboard once live. Source: web.dev/articles/vitals, web.dev/articles/inp, Google Search Central. https://claude.ai/code/session_019m7zNSare8J2meL24HDW5K * docs: phase 1 performance & crawler-access guide (plain-language + sources) https://claude.ai/code/session_019m7zNSare8J2meL24HDW5K * ci(lighthouse): median of 3 runs; hard-gate LCP/CLS, advisory TBT A single Lighthouse run on a shared CI runner reported an inflated 1183ms TBT despite the page shipping only ~16KB JS. Switched to 3 runs + median aggregation to de-noise. Hard-fail on lab-stable LCP/CLS at the official thresholds; treat TBT as advisory (warn) because INP is field-only and lab TBT is noisy — true INP is monitored via CrUX. Source: web.dev/articles/inp, web.dev/articles/lab-and-field-data-differences. https://claude.ai/code/session_019m7zNSare8J2meL24HDW5K --------- Co-authored-by: Claude <noreply@anthropic.com>
…#13) Adds config-driven structured data so AI/search engines can extract and cite the site: - src/utils/schema.ts: central, config-driven schema.org builders - StructuredData.astro: renders JSON-LD; Layout injects Organization + WebSite sitewide, pages append their own - Homepage: SoftwareApplication + FAQPage (single source of truth shared with the on-page FAQ) + BreadcrumbList - Blog posts: BlogPosting + BreadcrumbList - public/llms.txt: curated LLM index (llmstxt.org spec) - docs/GEO_STRUCTURED_DATA.md: plain-language guide + sources Only real, verifiable facts (no fabricated ratings). Locally validated: homepage 5 JSON-LD blocks, blog post 4, all valid JSON. Verify with Google Rich Results Test post-deploy. Sources: schema.org, Google structured-data docs, CMU GEO (KDD 2024), llmstxt.org. https://claude.ai/code/session_019m7zNSare8J2meL24HDW5K Co-authored-by: Claude <noreply@anthropic.com>
…14) - Adds a global prefers-reduced-motion fallback (WCAG 2.2 SC 2.3.3) that neutralizes animations/transitions/smooth-scroll for users who request reduced motion; functional state changes still work. - Computed exact WCAG contrast for every color token in BOTH themes. Light passes everywhere; the only normal-text dark failure was the Button link-hover (primary on dark = 3.8:1). Fixed with dark:hover:text-blue-300 (11.1:1, verified). accent is never used as dark text; icon/large uses of primary meet the 3.0 UI threshold. - Tokenized an introduced hardcoded text-blue-600 -> text-primary (+ dark). - docs/STYLING_ACCESSIBILITY.md: contrast table, sources, and the browser-only manual checklist (responsive overflow, full tokenization). Sources: w3.org/WAI/WCAG22, web.dev/prefers-reduced-motion. https://claude.ai/code/session_019m7zNSare8J2meL24HDW5K Co-authored-by: Claude <noreply@anthropic.com>
…it (#15) - Adds a 'Skip to main content' link as the first focusable element, targeting <main id="main">, so keyboard/screen-reader users can bypass the nav (WCAG 2.2 SC 2.4.1 Bypass Blocks). - Audited and verified already-correct: landmarks (header/nav/main/footer), heading order (one h1), button-vs-link semantics, associated form labels, focus visibility (focus:ring replacements), required alt text, html lang. - Confirmed minimal hydration: ZERO client:* islands; only the ~16KB View Transitions module ships site-wide (optimal for INP). - docs/COMPONENT_ACCESSIBILITY.md: audit results + manual keyboard/SR checklist. Source: w3.org WCAG 2.2 Bypass Blocks / Focus Visible. https://claude.ai/code/session_019m7zNSare8J2meL24HDW5K Co-authored-by: Claude <noreply@anthropic.com>
…ents (#16) - Analytics.astro upgraded to a privacy-first GA4 setup: Consent Mode v2 defaults all storage to denied (cookieless until a CMP/banner grants), IP anonymization on, OFF unless a Measurement ID is configured. - Tracks key conversion events with no PII: cta_use_template, outbound_click, form_submit, scroll_depth (25/50/75/100%). - docs/CONVERSION_MEASUREMENT.md: what is measured + how to read GA4, how to isolate AI-referral traffic (the GEO payoff), how to enable it, where REAL trust signals come from (no fabrication), and a no-dark-patterns commitment. Build-verified: GA OFF by default → inert guarded script, no gtag loaded. Sources: developers.google.com/tag-platform/security/guides/consent. https://claude.ai/code/session_019m7zNSare8J2meL24HDW5K Co-authored-by: Claude <noreply@anthropic.com>
#17) * docs: refresh README and AGENTS for the GCP starter + 5-phase features - README rewritten as a GCP Cloud Run starter front door: definition-first intro, 'why this template' pillars, quickstart pointing to the walkthrough, a complete docs index (deploy/infra + the 5 optimization guides), accurate project structure, and config notes. Removed stale AstroWind marketing and Netlify/Vercel/PandaStack/CodeSandbox/StackBlitz deploy buttons. - AGENTS.md: overview now reflects the GCP/keyless/Terraform reality; added SEO/GEO/Analytics layer, Infrastructure & CI/CD, and Documentation sections; expanded the verification checklist with the CI gate and optimization invariants (JSON-LD, WCAG AA, skip link, CWV budget). https://claude.ai/code/session_019m7zNSare8J2meL24HDW5K * docs(readme): restore all original sections, updated (additive, nothing removed) Audited the prior rewrite and restored every section it had dropped, with corrected/current details: - Table of Contents, Demo, TL;DR, Getting started, full Project structure tree (updated to include terraform/, docs/, .github/workflows/, Dockerfile, schema.ts, Analytics/StructuredData, lighthouserc.json, navigation.ts). - Configuration (config.yaml example refreshed to current values), Customize Design, and the full Deploy section: production-manual, Netlify, Vercel (link fixed to this repo), PandaStack, and GCP (primary). - CodeSandbox/StackBlitz buttons, front-end feature bullets, badges, FAQ (filled in real Q&A), Acknowledgements (credits AstroWind/Arthelokyo). Kept the new GCP/optimization intro, pillars, and the full docs index. Principle: documentation is only updated to reflect current state, never removed. https://claude.ai/code/session_019m7zNSare8J2meL24HDW5K * docs(playbook): restore the inline GCS backend HCL block (additive) The audit replaced the inline backend{} snippet with a 'copy backend.tf.example' instruction; this restores the actual HCL block as a reference alongside the cp step, so no useful content is lost. Other modified docs (AGENTS, TEMPLATE_SETUP, IAC_RULES) were verified additive — their changes only updated content to the current state. https://claude.ai/code/session_019m7zNSare8J2meL24HDW5K --------- Co-authored-by: Claude <noreply@anthropic.com>
…I + push-protection docs) (#18) Layered secret scanning for this public repo: Gitleaks pre-commit hook, TruffleHog CI verification, and GitHub Advanced Security backstop, plus Dependabot version-updates config. - .gitleaks.toml allowlist (public GA4 ID, .example placeholders, keyless-WIF SA emails/provider path, dist/node_modules/CDN hosts) - .pre-commit-config.yaml + .githooks/pre-commit (native) gate the staged diff - .github/workflows/secret-scan.yml: Gitleaks SARIF + TruffleHog --only-verified (PR diff + weekly full-history sweep) - .github/dependabot.yml: weekly grouped updates (npm, github-actions, docker) - .gitignore hardened with SA/OAuth JSON key patterns, broader .env.*/secrets.*/PEM - SECURITY.md: three-layer runbook, allowlist rationale, rotate-first response Baseline scan: 0 verified / 0 unverified secrets in full history. No rotation or history rewrite required; CI gate ships fail-closed.
Bumps the npm-minor-patch group with 13 updates: | Package | From | To | | --- | --- | --- | | [astro](https://github.com/withastro/astro/tree/HEAD/packages/astro) | `6.4.2` | `6.4.7` | | [@astrojs/mdx](https://github.com/withastro/astro/tree/HEAD/packages/integrations/mdx) | `6.0.1` | `6.0.3` | | [@tailwindcss/typography](https://github.com/tailwindlabs/tailwindcss-typography) | `0.5.19` | `0.5.20` | | [@tailwindcss/vite](https://github.com/tailwindlabs/tailwindcss/tree/HEAD/packages/@tailwindcss-vite) | `4.3.0` | `4.3.1` | | [@types/mdx](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/mdx) | `2.0.13` | `2.0.14` | | [@typescript-eslint/eslint-plugin](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/eslint-plugin) | `8.60.0` | `8.61.1` | | [@typescript-eslint/parser](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/parser) | `8.60.0` | `8.61.1` | | [eslint](https://github.com/eslint/eslint) | `10.4.0` | `10.5.0` | | [js-yaml](https://github.com/nodeca/js-yaml) | `4.1.1` | `4.2.0` | | [prettier](https://github.com/prettier/prettier) | `3.8.3` | `3.8.4` | | [sharp](https://github.com/lovell/sharp) | `0.34.5` | `0.35.1` | | [tailwindcss](https://github.com/tailwindlabs/tailwindcss/tree/HEAD/packages/tailwindcss) | `4.3.0` | `4.3.1` | | [typescript-eslint](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/typescript-eslint) | `8.60.0` | `8.61.1` | Updates `astro` from 6.4.2 to 6.4.7 - [Release notes](https://github.com/withastro/astro/releases) - [Changelog](https://github.com/withastro/astro/blob/main/packages/astro/CHANGELOG.md) - [Commits](https://github.com/withastro/astro/commits/astro@6.4.7/packages/astro) Updates `@astrojs/mdx` from 6.0.1 to 6.0.3 - [Release notes](https://github.com/withastro/astro/releases) - [Changelog](https://github.com/withastro/astro/blob/main/packages/integrations/mdx/CHANGELOG.md) - [Commits](https://github.com/withastro/astro/commits/@astrojs/mdx@6.0.3/packages/integrations/mdx) Updates `@tailwindcss/typography` from 0.5.19 to 0.5.20 - [Release notes](https://github.com/tailwindlabs/tailwindcss-typography/releases) - [Changelog](https://github.com/tailwindlabs/tailwindcss-typography/blob/main/CHANGELOG.md) - [Commits](tailwindlabs/tailwindcss-typography@v0.5.19...v0.5.20) Updates `@tailwindcss/vite` from 4.3.0 to 4.3.1 - [Release notes](https://github.com/tailwindlabs/tailwindcss/releases) - [Changelog](https://github.com/tailwindlabs/tailwindcss/blob/main/CHANGELOG.md) - [Commits](https://github.com/tailwindlabs/tailwindcss/commits/v4.3.1/packages/@tailwindcss-vite) Updates `@types/mdx` from 2.0.13 to 2.0.14 - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases) - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/mdx) Updates `@typescript-eslint/eslint-plugin` from 8.60.0 to 8.61.1 - [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases) - [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/CHANGELOG.md) - [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.61.1/packages/eslint-plugin) Updates `@typescript-eslint/parser` from 8.60.0 to 8.61.1 - [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases) - [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/parser/CHANGELOG.md) - [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.61.1/packages/parser) Updates `eslint` from 10.4.0 to 10.5.0 - [Release notes](https://github.com/eslint/eslint/releases) - [Commits](eslint/eslint@v10.4.0...v10.5.0) Updates `js-yaml` from 4.1.1 to 4.2.0 - [Changelog](https://github.com/nodeca/js-yaml/blob/master/CHANGELOG.md) - [Commits](https://github.com/nodeca/js-yaml/commits) Updates `prettier` from 3.8.3 to 3.8.4 - [Release notes](https://github.com/prettier/prettier/releases) - [Changelog](https://github.com/prettier/prettier/blob/main/CHANGELOG.md) - [Commits](prettier/prettier@3.8.3...3.8.4) Updates `sharp` from 0.34.5 to 0.35.1 - [Release notes](https://github.com/lovell/sharp/releases) - [Commits](lovell/sharp@v0.34.5...v0.35.1) Updates `tailwindcss` from 4.3.0 to 4.3.1 - [Release notes](https://github.com/tailwindlabs/tailwindcss/releases) - [Changelog](https://github.com/tailwindlabs/tailwindcss/blob/main/CHANGELOG.md) - [Commits](https://github.com/tailwindlabs/tailwindcss/commits/v4.3.1/packages/tailwindcss) Updates `typescript-eslint` from 8.60.0 to 8.61.1 - [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases) - [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/typescript-eslint/CHANGELOG.md) - [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.61.1/packages/typescript-eslint) --- updated-dependencies: - dependency-name: astro dependency-version: 6.4.7 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: npm-minor-patch - dependency-name: "@astrojs/mdx" dependency-version: 6.0.3 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: npm-minor-patch - dependency-name: "@tailwindcss/typography" dependency-version: 0.5.20 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: npm-minor-patch - dependency-name: "@tailwindcss/vite" dependency-version: 4.3.1 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: npm-minor-patch - dependency-name: "@types/mdx" dependency-version: 2.0.14 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: npm-minor-patch - dependency-name: "@typescript-eslint/eslint-plugin" dependency-version: 8.61.1 dependency-type: direct:development update-type: version-update:semver-minor dependency-group: npm-minor-patch - dependency-name: "@typescript-eslint/parser" dependency-version: 8.61.1 dependency-type: direct:development update-type: version-update:semver-minor dependency-group: npm-minor-patch - dependency-name: eslint dependency-version: 10.5.0 dependency-type: direct:development update-type: version-update:semver-minor dependency-group: npm-minor-patch - dependency-name: js-yaml dependency-version: 4.2.0 dependency-type: direct:development update-type: version-update:semver-minor dependency-group: npm-minor-patch - dependency-name: prettier dependency-version: 3.8.4 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: npm-minor-patch - dependency-name: sharp dependency-version: 0.35.1 dependency-type: direct:development update-type: version-update:semver-minor dependency-group: npm-minor-patch - dependency-name: tailwindcss dependency-version: 4.3.1 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: npm-minor-patch - dependency-name: typescript-eslint dependency-version: 8.61.1 dependency-type: direct:development update-type: version-update:semver-minor dependency-group: npm-minor-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps the docker group with 2 updates: node and nginx. Updates `node` from 22-alpine to 26-alpine Updates `nginx` from 1.27-alpine to 1.31-alpine --- updated-dependencies: - dependency-name: node dependency-version: 26-alpine dependency-type: direct:production dependency-group: docker - dependency-name: nginx dependency-version: 1.31-alpine dependency-type: direct:production dependency-group: docker ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps the github-actions group with 9 updates: | Package | From | To | | --- | --- | --- | | [actions/checkout](https://github.com/actions/checkout) | `4` | `6` | | [actions/setup-node](https://github.com/actions/setup-node) | `4` | `6` | | [docker/setup-buildx-action](https://github.com/docker/setup-buildx-action) | `3` | `4` | | [docker/build-push-action](https://github.com/docker/build-push-action) | `5` | `7` | | [hashicorp/setup-terraform](https://github.com/hashicorp/setup-terraform) | `3` | `4` | | [google-github-actions/auth](https://github.com/google-github-actions/auth) | `2` | `3` | | [google-github-actions/setup-gcloud](https://github.com/google-github-actions/setup-gcloud) | `2` | `3` | | [google-github-actions/deploy-cloudrun](https://github.com/google-github-actions/deploy-cloudrun) | `2` | `3` | | [gitleaks/gitleaks-action](https://github.com/gitleaks/gitleaks-action) | `2` | `3` | Updates `actions/checkout` from 4 to 6 - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](actions/checkout@v4...v6) Updates `actions/setup-node` from 4 to 6 - [Release notes](https://github.com/actions/setup-node/releases) - [Commits](actions/setup-node@v4...v6) Updates `docker/setup-buildx-action` from 3 to 4 - [Release notes](https://github.com/docker/setup-buildx-action/releases) - [Commits](docker/setup-buildx-action@v3...v4) Updates `docker/build-push-action` from 5 to 7 - [Release notes](https://github.com/docker/build-push-action/releases) - [Commits](docker/build-push-action@v5...v7) Updates `hashicorp/setup-terraform` from 3 to 4 - [Release notes](https://github.com/hashicorp/setup-terraform/releases) - [Changelog](https://github.com/hashicorp/setup-terraform/blob/main/CHANGELOG.md) - [Commits](hashicorp/setup-terraform@v3...v4) Updates `google-github-actions/auth` from 2 to 3 - [Release notes](https://github.com/google-github-actions/auth/releases) - [Changelog](https://github.com/google-github-actions/auth/blob/main/CHANGELOG.md) - [Commits](google-github-actions/auth@v2...v3) Updates `google-github-actions/setup-gcloud` from 2 to 3 - [Release notes](https://github.com/google-github-actions/setup-gcloud/releases) - [Changelog](https://github.com/google-github-actions/setup-gcloud/blob/main/CHANGELOG.md) - [Commits](google-github-actions/setup-gcloud@v2...v3) Updates `google-github-actions/deploy-cloudrun` from 2 to 3 - [Release notes](https://github.com/google-github-actions/deploy-cloudrun/releases) - [Changelog](https://github.com/google-github-actions/deploy-cloudrun/blob/main/CHANGELOG.md) - [Commits](google-github-actions/deploy-cloudrun@v2...v3) Updates `gitleaks/gitleaks-action` from 2 to 3 - [Release notes](https://github.com/gitleaks/gitleaks-action/releases) - [Commits](gitleaks/gitleaks-action@v2...v3) --- updated-dependencies: - dependency-name: actions/checkout dependency-version: '6' dependency-type: direct:production update-type: version-update:semver-major dependency-group: github-actions - dependency-name: actions/setup-node dependency-version: '6' dependency-type: direct:production update-type: version-update:semver-major dependency-group: github-actions - dependency-name: docker/setup-buildx-action dependency-version: '4' dependency-type: direct:production update-type: version-update:semver-major dependency-group: github-actions - dependency-name: docker/build-push-action dependency-version: '7' dependency-type: direct:production update-type: version-update:semver-major dependency-group: github-actions - dependency-name: hashicorp/setup-terraform dependency-version: '4' dependency-type: direct:production update-type: version-update:semver-major dependency-group: github-actions - dependency-name: google-github-actions/auth dependency-version: '3' dependency-type: direct:production update-type: version-update:semver-major dependency-group: github-actions - dependency-name: google-github-actions/setup-gcloud dependency-version: '3' dependency-type: direct:production update-type: version-update:semver-major dependency-group: github-actions - dependency-name: google-github-actions/deploy-cloudrun dependency-version: '3' dependency-type: direct:production update-type: version-update:semver-major dependency-group: github-actions - dependency-name: gitleaks/gitleaks-action dependency-version: '3' dependency-type: direct:production update-type: version-update:semver-major dependency-group: github-actions ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps [tar](https://github.com/isaacs/node-tar) from 7.5.15 to 7.5.16. - [Release notes](https://github.com/isaacs/node-tar/releases) - [Changelog](https://github.com/isaacs/node-tar/blob/main/CHANGELOG.md) - [Commits](isaacs/node-tar@v7.5.15...v7.5.16) --- updated-dependencies: - dependency-name: tar dependency-version: 7.5.16 dependency-type: indirect ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bump typescript 5.9.3 -> 6.0.3 (major). Verified: astro check (0/0/0 across 95 files), eslint, prettier, and the production build all pass. tsconfig extends astro/tsconfigs/base; TS 6.0 strict-by-default surfaced no new errors. No source changes required.
…eme check (#26) Resolve 5 CodeQL code-scanning alerts on main: - ci.yml: add least-privilege top-level `permissions: contents: read` (4x "Workflow does not contain permissions"). Jobs only read the repo. - permalinks.ts: make getPermalink's absolute/special-link detection case-insensitive and cover all script-capable pseudo-schemes (javascript:/data:/vbscript:) so the URL scheme check is complete and non-bypassable (High: "Incomplete URL scheme check"). Behavior unchanged. Verified: astro check 0/0/0, eslint, prettier, docker build, lighthouse, CodeQL all green.
Resolves Dependabot alert "vite: server.fs.deny bypass on Windows alternate paths" (CVE-2026-53571), patched in vite 7.3.5 for the 7.x line. Within the existing ^7 override; lockfile-only, esbuild unchanged. astro check / eslint / prettier / docker build / lighthouse / CodeQL all green.
… triage (#28) Additive docs for this session's security work: AGENTS.md stack TS 5.9->6.0 + Security automation subsection; SECURITY.md least-privilege workflow permissions note + new "Dependency security & vulnerability triage" policy (in-range fixes, execution-path triage, dismiss "not used"). No content removed.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This contribution extends AstroWind into a production-ready, zero-secrets GCP Cloud Run starter: a complete keyless Terraform/CI foundation, plus a hardened, accessibility- and discoverability-optimized front end, and a fully refreshed documentation set.
🔗 Live preview (deployed to Google Cloud Run from this branch):
https://website-kah2tr5ppq-uc.a.run.app/
What's included
☁️ GCP Cloud Run deployment foundation (new)
bootstrap(projects, GCS state bucket, automation SA) →shared(Workload Identity Federation, deploy SA, Artifact Registry) → per-environment (dev/staging/prod). Reusablemodules/foriam,cloud_run,artifact_registry,monitoring,logging,secret_manager, andcost_governance.min-instances = 0, capped autoscaling, smallest sensible CPU/memory, and a billing budget with alerts (≈ $0/month within the free tier).Dockerfilebuilding the static site and serving it with nginx on port 8080 as a non-root user (~25 MB image).ci.yml(astro check + ESLint + Prettier, Docker build,terraform validateacross all envs, Lighthouse Core Web Vitals budget) and app-deploy-onlydeploy-*.ymlworkflows (build → Artifact Registry → Cloud Run revision → smoke test).🎨 Design-system hardening
prefers-reduced-motionfallback (WCAG SC 2.3.3) and a skip-to-content link (SC 2.4.1).alt, and minimal hydration confirmed.⚡ Performance & 🔎 discoverability (GEO/SEO)
src/utils/schema.ts+StructuredData.astro):Organization,WebSite,BlogPosting,BreadcrumbList,FAQPage.public/llms.txt(llmstxt.org) and an explicit AI-crawler policy inrobots.txt(GPTBot, ClaudeBot, PerplexityBot, Google-Extended, Applebot-Extended).📈 Conversion & measurement (privacy-first)
cta_*,outbound_click,form_submit,scroll_depth).📚 Documentation (refreshed + new)
README.mdandAGENTS.md, plus a fulldocs/set: Fresh User Walkthrough (zero → live URL), Setup Playbook, IaC Governance Rules, a repo-vs-reality Gap Register, and five plain-language optimization guides (performance/crawler, GEO/structured-data, styling/accessibility, component accessibility, conversion/measurement) — each with authoritative sources.Security posture
.exampleplaceholders committed; real tfvars/backend/state gitignored; keyless identity (WIF). Verified clean across files, history, and CI logs.Compatibility & adoption
terraform/, theDockerfile, and thedeploy-*workflows.Testing / validation
npm run checkgreen; CI green (check + Docker +terraform validate+ Lighthouse).Notes for maintainers
This is a large, opinionated addition (a deployment + hardening foundation, not just a theme tweak). If a single PR is too broad, it can be split into focused PRs — (1) front-end a11y, (2) GEO/structured-data, (3) privacy analytics, (4) the GCP/Terraform/CI foundation — or adopted as a companion "AstroWind + GCP Cloud Run" template variant. Happy to reshape to fit the project's direction.