From 26b1f6744617abcd37e4b7c961b11b567fb97d3a Mon Sep 17 00:00:00 2001 From: Alan Wang Date: Wed, 20 May 2026 13:49:39 -0700 Subject: [PATCH] Add production deployment pipeline --- .github/workflows/deploy.yml | 87 ++++++++++++ .github/workflows/pr-checks.yml | 127 ++++++++++++++++++ .gitignore | 8 ++ docs/deployment-pipeline.md | 83 ++++++++++++ .../src/styles/sections/hero-panel.css | 3 +- 5 files changed, 307 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/deploy.yml create mode 100644 .github/workflows/pr-checks.yml create mode 100644 docs/deployment-pipeline.md diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml new file mode 100644 index 0000000..49a734c --- /dev/null +++ b/.github/workflows/deploy.yml @@ -0,0 +1,87 @@ +name: Deploy Production + +on: + push: + branches: + - main + workflow_dispatch: + +permissions: + contents: read + +concurrency: + group: production-deploy + cancel-in-progress: false + +jobs: + deploy: + name: Build and deploy theme + runs-on: ubuntu-latest + environment: production + defaults: + run: + shell: bash + env: + THREEW_DEPLOY_TARGET: production + THREEW_PROD_FTP_HOST: ${{ secrets.THREEW_PROD_FTP_HOST }} + THREEW_PROD_FTP_PORT: ${{ secrets.THREEW_PROD_FTP_PORT }} + THREEW_PROD_FTP_USER: ${{ secrets.THREEW_PROD_FTP_USER }} + THREEW_PROD_FTP_PASS: ${{ secrets.THREEW_PROD_FTP_PASS }} + THREEW_PROD_REMOTE_THEME_DIR: ${{ secrets.THREEW_PROD_REMOTE_THEME_DIR }} + THREEW_PROD_DEPLOY_SCHEME: ${{ secrets.THREEW_PROD_DEPLOY_SCHEME }} + THREEW_PROD_SSL_VERIFY: ${{ secrets.THREEW_PROD_SSL_VERIFY }} + steps: + - name: Check out repository + uses: actions/checkout@v4 + + - name: Set up Node.js + uses: actions/setup-node@v4 + with: + node-version: 20 + cache: npm + cache-dependency-path: wp-content/themes/3w-2025/package-lock.json + + - name: Install lftp + run: | + sudo apt-get update + sudo apt-get install -y lftp + + - name: Install theme dependencies + working-directory: wp-content/themes/3w-2025 + run: npm ci + + - name: Lint CSS + working-directory: wp-content/themes/3w-2025 + run: npm run lint:css + + - name: Lint JavaScript + working-directory: wp-content/themes/3w-2025 + run: npm run lint:js + + - name: Build theme assets + working-directory: wp-content/themes/3w-2025 + run: npm run build + + - name: Check theme PHP files + run: find wp-content/themes/3w-2025 -name '*.php' -print0 | xargs -0 -n1 php -l + + - name: Verify deployment secrets + run: | + missing=0 + for name in \ + THREEW_PROD_FTP_HOST \ + THREEW_PROD_FTP_USER \ + THREEW_PROD_FTP_PASS \ + THREEW_PROD_REMOTE_THEME_DIR \ + THREEW_PROD_DEPLOY_SCHEME; do + if [[ -z "${!name:-}" ]]; then + echo "Missing required secret-backed env: ${name}" >&2 + missing=1 + fi + done + if [[ "${missing}" -ne 0 ]]; then + exit 1 + fi + + - name: Deploy theme with existing script + run: ./scripts/deploy-theme.sh --target production diff --git a/.github/workflows/pr-checks.yml b/.github/workflows/pr-checks.yml new file mode 100644 index 0000000..a85fc34 --- /dev/null +++ b/.github/workflows/pr-checks.yml @@ -0,0 +1,127 @@ +name: PR Checks + +on: + pull_request: + branches: + - main + +permissions: + contents: read + pull-requests: read + security-events: write + actions: read + +concurrency: + group: pr-checks-${{ github.event.pull_request.number }} + cancel-in-progress: true + +jobs: + quality: + name: Theme lint and build + runs-on: ubuntu-latest + defaults: + run: + working-directory: wp-content/themes/3w-2025 + steps: + - name: Check out repository + uses: actions/checkout@v4 + + - name: Set up Node.js + uses: actions/setup-node@v4 + with: + node-version: 20 + cache: npm + cache-dependency-path: wp-content/themes/3w-2025/package-lock.json + + - name: Install dependencies + run: npm ci + + - name: Lint CSS + run: npm run lint:css + + - name: Lint JavaScript + run: npm run lint:js + + - name: Build theme assets + run: npm run build + + php-syntax: + name: PHP syntax check + runs-on: ubuntu-latest + steps: + - name: Check out repository + uses: actions/checkout@v4 + + - name: Check theme PHP files + run: find wp-content/themes/3w-2025 -name '*.php' -print0 | xargs -0 -n1 php -l + + dependency-review: + name: Dependency review + runs-on: ubuntu-latest + steps: + - name: Check out repository + uses: actions/checkout@v4 + + - name: Review dependency changes + uses: actions/dependency-review-action@v4 + with: + fail-on-severity: moderate + + npm-audit: + name: npm audit + runs-on: ubuntu-latest + defaults: + run: + working-directory: wp-content/themes/3w-2025 + steps: + - name: Check out repository + uses: actions/checkout@v4 + + - name: Set up Node.js + uses: actions/setup-node@v4 + with: + node-version: 20 + cache: npm + cache-dependency-path: wp-content/themes/3w-2025/package-lock.json + + - name: Install dependencies + run: npm ci + + - name: Run production dependency audit + run: npm audit --omit=dev --audit-level=moderate + + secret-scan: + name: Secret scan + runs-on: ubuntu-latest + steps: + - name: Check out repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Run Gitleaks + uses: gitleaks/gitleaks-action@v2 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + codeql: + name: CodeQL analysis + runs-on: ubuntu-latest + permissions: + contents: read + security-events: write + actions: read + steps: + - name: Check out repository + uses: actions/checkout@v4 + + - name: Initialize CodeQL + uses: github/codeql-action/init@v3 + with: + languages: javascript-typescript + + - name: Autobuild + uses: github/codeql-action/autobuild@v3 + + - name: Perform CodeQL analysis + uses: github/codeql-action/analyze@v3 diff --git a/.gitignore b/.gitignore index e8bddb4..3a7c56a 100644 --- a/.gitignore +++ b/.gitignore @@ -33,6 +33,14 @@ test-results/ scripts/logs/ .playwright-mcp/ +# Agent/local metadata +.pi/ +.claude/ + +# Local screenshots and visual review captures +*.png +!wp-content/themes/3w-2025/**/*.png + # Product data files scraped-products*.json woocommerce-products*.json diff --git a/docs/deployment-pipeline.md b/docs/deployment-pipeline.md new file mode 100644 index 0000000..bc3b2aa --- /dev/null +++ b/docs/deployment-pipeline.md @@ -0,0 +1,83 @@ +# Production deployment pipeline + +## Overview + +GitHub Actions owns CI/security gates and production deployment. Secrets stay in GitHub Actions secrets or protected environments only; no production secret belongs in repository files. + +## Pull request checks + +Workflow: `.github/workflows/pr-checks.yml` + +Runs on pull requests targeting `main`: + +- Theme dependency install with `npm ci` +- CSS lint with `npm run lint:css` +- JavaScript lint with `npm run lint:js` +- Theme asset build with `npm run build` +- PHP syntax validation for theme PHP files +- Production dependency audit with `npm audit --omit=dev --audit-level=moderate` +- GitHub dependency review, failing on moderate or higher severity +- Gitleaks secret scan +- CodeQL JavaScript/TypeScript analysis + +Recommended branch protection for `main`: + +- Require pull request before merge +- Require all PR check jobs to pass +- Require conversation resolution +- Block force pushes +- Restrict who can dismiss reviews + +## Production deployment + +Workflow: `.github/workflows/deploy.yml` + +Runs on pushes to `main` and manual `workflow_dispatch`. + +Deployment reuses the existing script: + +```bash +./scripts/deploy-theme.sh --target production +``` + +The workflow performs quality gates before calling the script: + +- `npm ci` +- `npm run lint:css` +- `npm run lint:js` +- `npm run build` +- PHP syntax validation +- required deployment secret presence check + +The deploy script then builds the theme again and mirrors runtime-safe theme files through `lftp`, using the script's existing exclude rules. + +## Required GitHub configuration + +Create a protected GitHub environment named `production`. + +Recommended environment protection: + +- Required reviewers enabled +- Deployment branches limited to `main` +- Environment secrets scoped to `production` + +Required secrets: + +| Secret | Purpose | +| --- | --- | +| `THREEW_PROD_FTP_HOST` | Production FTP/FTPS/SFTP host | +| `THREEW_PROD_FTP_PORT` | Production port; optional if default protocol port is acceptable | +| `THREEW_PROD_FTP_USER` | Production deploy username | +| `THREEW_PROD_FTP_PASS` | Production deploy password | +| `THREEW_PROD_REMOTE_THEME_DIR` | Remote theme directory, e.g. `public_html/wp-content/themes/3w-2025` | +| `THREEW_PROD_DEPLOY_SCHEME` | `ftp`, `ftps`, or `sftp` | +| `THREEW_PROD_SSL_VERIFY` | `yes` or `no`; prefer `yes` for FTPS | + +Do not add `.env`, passwords, deploy keys, or host credentials to git. + +## Notes + +- `scripts/deploy-theme.sh` loads `.env` for local runs only. GitHub Actions supplies the same variable names from GitHub Secrets. +- The npm audit gate omits development dependencies because the WordPress build toolchain currently reports dev-only advisories that require breaking tool upgrades; production dependency exposure is still gated, while CodeQL, Gitleaks, dependency review, linting, and builds cover PR quality/security. +- The production deploy job is attached to the `production` environment so GitHub can enforce approvals before secrets are exposed to the runner. +- If SFTP key auth is required later, update `scripts/deploy-theme.sh` to support a production-specific key secret materialized into a temporary runner file, then pass `THREEW_SSH_KEY_PATH` to the script. diff --git a/wp-content/themes/3w-2025/src/styles/sections/hero-panel.css b/wp-content/themes/3w-2025/src/styles/sections/hero-panel.css index 3a4a6bc..47eebf8 100644 --- a/wp-content/themes/3w-2025/src/styles/sections/hero-panel.css +++ b/wp-content/themes/3w-2025/src/styles/sections/hero-panel.css @@ -151,7 +151,8 @@ } .threew-hero__panel-shell { - max-width: clamp(360px, 34vw, 520px); + max-width: none; + width: 100%; padding: clamp(0.65rem, 1.3vw, 1.1rem); } }