Skip to content

feat(ci): add GitHub Actions workflow for sequential CMS and Web deployment#8

Open
jhb-dev wants to merge 19 commits intomainfrom
test/preview-deployment
Open

feat(ci): add GitHub Actions workflow for sequential CMS and Web deployment#8
jhb-dev wants to merge 19 commits intomainfrom
test/preview-deployment

Conversation

@jhb-dev
Copy link
Copy Markdown
Contributor

@jhb-dev jhb-dev commented Dec 22, 2025

Testing the preview deployment workflow. This adds a banner showing the CMS URL used for the build.


Note

Conditionally deploy CMS/Web with skip tags and CMS-first ordering, add CMS preview auth bypass support to Web fetches, and document the deployment process.

  • CI/CD (deploy.yml): Introduces detect-changes to deploy CMS/Web only when their folders or workflow change; supports [skip-cms]/[skip-web]; adds manual inputs; ensures CMS deploy runs before Web; passes CMS_URL and optional CMS_VERCEL_AUTOMATION_BYPASS_SECRET to Web preview builds; updates summary output and PR comment to handle skipped CMS.
  • Web (Astro): Adds CMS_VERCEL_AUTOMATION_BYPASS_SECRET to env schema; new sdk/bypassHeader and integrates it in getRedirects and sdk/cachedFetch so preview builds can access protected CMS via Vercel automation bypass header.
  • Docs: README expanded with deployment flow, Vercel setup, skip tags, secrets, and preview authentication instructions.

Written by Cursor Bugbot for commit 2d1465e. This will update automatically on new commits. Configure here.

@vercel
Copy link
Copy Markdown

vercel bot commented Dec 22, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

2 Skipped Deployments
Project Deployment Review Updated (UTC)
website Ignored Ignored Preview Dec 22, 2025 9:43pm
website-cms Ignored Ignored Preview Dec 22, 2025 9:43pm

Copy link
Copy Markdown

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the final PR Bugbot will review for you during this billing cycle

Your free Bugbot reviews will reset on January 9

Details

You are on the Bugbot Free tier. On this plan, Bugbot will review limited PRs each billing cycle.

To receive Bugbot reviews on all of your PRs, visit the Cursor dashboard to activate Pro and start your 14-day free trial.

const isPreviewDeployment = VERCEL_ENV === 'preview'

console.log('[Preview Test] CMS_URL:', CMS_URL)
console.log('[Preview Test] VERCEL_ENV:', VERCEL_ENV)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Debug console.log statements will run in production

The console.log statements labeled [Preview Test] are unconditional and will execute on every page render in all environments, including production. Unlike the isPreviewDeployment banner which is conditional, these logs always run. This appears to be temporary debugging code that was included for testing purposes but will pollute server logs with CMS_URL and VERCEL_ENV values on every page load.

Fix in Cursor Fix in Web

@claude
Copy link
Copy Markdown

claude bot commented Dec 22, 2025

Pull Request Review

Summary

This PR adds a preview deployment banner to display the CMS URL and updates the deployment workflow to pass CMS_URL as both a build-time and runtime environment variable.

Issues Found

🔴 Critical: Security Concern - Exposing Internal URLs

Location: web/src/layout/Layout.astro:29-30, web/src/layout/Layout.astro:67-71

The banner exposes the internal CMS preview URL to all users visiting the preview deployment. This could be a security risk:

<div class="bg-amber-500 text-black text-center py-2 text-sm font-medium">
  Preview Deployment - CMS: {CMS_URL}
</div>

Recommendation: If this banner is for debugging purposes, consider:

  1. Only showing it to authenticated users/admins
  2. Showing a generic message like "Preview Deployment" without the URL
  3. Removing the banner entirely once testing is complete

🟡 Medium: Client-Side Environment Variable Misconfiguration

Location: astro.config.mjs:22-25, web/src/layout/Layout.astro:6

CMS_URL is defined as a client-side environment variable (context: 'client') in the Astro config. However, it's imported from astro:env/client and exposed directly in the HTML output and console logs.

Issues:

  • Client-side env vars are bundled into the JavaScript and exposed to users
  • The CMS URL is already being logged to the browser console (console.log at line 30-31)
  • This may not be necessary since the CMS URL should primarily be used at build time

Recommendation:

  • If the CMS URL only needs to be available during build, consider making it a server-side variable
  • Remove the console.log statements before merging (lines 30-31)

🟡 Medium: Deployment Workflow - Redundant Environment Variable

Location: .github/workflows/deploy.yml:135

The workflow now passes CMS_URL twice:

--build-env CMS_URL=${{ needs.deploy-cms.outputs.deployment_url }} -e CMS_URL=${{ needs.deploy-cms.outputs.deployment_url }}

Issue:

  • --build-env makes it available during build time
  • -e makes it available at runtime
  • Since this is a static site (pnpm build generates static files), runtime environment variables (-e) won't affect the static output
  • However, if CMS_URL is a client-side variable, it needs to be set at build time to be bundled

Clarification needed: Is the runtime -e flag intentional? If the site is fully static, only --build-env is needed.

🟢 Minor: Debug Code Left in Production Path

Location: web/src/layout/Layout.astro:30-31

Console logs are present in the component:

console.log('[Preview Test] CMS_URL:', CMS_URL)
console.log('[Preview Test] VERCEL_ENV:', VERCEL_ENV)

Recommendation: Remove these before merging or wrap them in a development-only check.

Performance Considerations

  • ✅ No significant performance impact
  • The banner is conditionally rendered only in preview environments
  • Client-side bundle size increase is minimal

Positive Aspects

  • ✅ Good documentation in the workflow file (prerequisites and TODO notes)
  • ✅ Proper conditional rendering using isPreviewDeployment
  • ✅ Sequential deployment ensures CMS is available before Web build

Recommendations

  1. Remove or restrict the CMS URL banner to prevent exposing internal infrastructure
  2. Remove console.log debug statements
  3. Review the necessity of -e CMS_URL in the deployment workflow
  4. Consider making CMS_URL server-only if it's primarily used at build time
  5. If this is temporary testing code, add a comment indicating it should be removed before production

Review conducted per repository's CLAUDE.md guidelines

@github-actions
Copy link
Copy Markdown

github-actions bot commented Dec 22, 2025

Preview Deployment

Project URL
CMS https://website-7q4ulfe13-jhb-software.vercel.app
Web https://website-meixwazgn-jhb-software.vercel.app

The Web preview uses the CMS preview URL for content fetching.

@claude
Copy link
Copy Markdown

claude bot commented Dec 22, 2025

Code Review for PR #8

Summary

This PR adds preview deployment diagnostics by displaying the CMS URL in a banner on preview deployments and enhancing the CI workflow to capture and expose Vercel inspect URLs.


Potential Bugs & Issues

1. Fragile Shell Parsing in GitHub Actions

Location: .github/workflows/deploy.yml:78-80, 92-94, 136-138, 149-151

The workflow uses grep and awk to parse Vercel CLI output. This parsing is fragile and can break if Vercel changes their output format. If grep/awk don't find matches, variables will be empty, causing downstream issues with no validation.

Recommendation: Add validation after extraction to ensure URLs were successfully extracted, or use Vercel's JSON output if available.

2. Missing Error Handling for Empty Inspect URLs

Location: .github/workflows/deploy.yml:204-205

The PR comment table includes inspect URLs without checking if they exist. If inspect_url extraction fails, this creates broken markdown links.

Recommendation: Use conditional formatting or fallback text.

3. CMS_URL Exposed to Client

Location: web/src/layout/Layout.astro:6, 70

CMS_URL is imported from astro:env/client and rendered in HTML, exposing internal preview URLs in the client-side bundle. Combined with the TODO about authentication concerns in deploy.yml, this could be a security issue.

Recommendation: Verify if preview CMS URLs should be publicly visible. If not, consider using server-side rendering only for this banner.


Performance Considerations

1. Runtime Environment Variable Access

Location: web/src/layout/Layout.astro:30-31

The layout logs CMS_URL on every page render, creating unnecessary noise in server logs. Performance impact is minimal but adds overhead.

Recommendation: Remove debug logs before merging or gate them behind a debug flag.

2. Banner HTML Injected on Every Page

Location: web/src/layout/Layout.astro:67-73

Impact is minimal - the banner is small and conditionally rendered. No significant performance concern.


Security Concerns

1. Vercel Token Exposure Risk

Location: .github/workflows/deploy.yml:78, 91, 135, 148

The workflow captures full Vercel CLI output including stderr. If Vercel CLI ever logs the token or sensitive info to stderr, it could be captured.

Recommendation: Be cautious with captured output.

2. Preview Deployment Authentication

Location: .github/workflows/deploy.yml:12

The workflow requires disabling authentication on preview deployments. Anyone with the URL can access the CMS. Combined with exposing CMS_URL in the frontend banner, this creates an attack vector.

Recommendation:

  • Implement VERCEL_AUTOMATION_BYPASS_SECRET as noted in the TODO
  • Ensure preview CMS deployments have proper access controls
  • Consider IP allowlisting or basic auth for preview environments

3. Command Injection Risk

Location: .github/workflows/deploy.yml:148

The workflow passes deployment URL directly to shell without proper quoting. While unlikely with Vercel URLs, it's not properly quoted.

Recommendation: Add quotes around the variable.


Additional Notes

  1. Debug Console Logs: Lines 30-31 in Layout.astro appear to be temporary debug statements. Remove before production merge.

  2. Workflow Prerequisites: Good documentation added about authentication requirements.

  3. PR Comment Enhancement: The new Inspect column in the PR comment table is a nice UX improvement.


Recommendations Summary

High Priority:

  • Add validation for extracted URLs in GitHub Actions
  • Address authentication concerns for preview deployments
  • Review if CMS_URL should be client-accessible

Medium Priority:

  • Remove debug console.log statements
  • Add proper quoting in shell scripts
  • Handle empty inspect URLs gracefully

Low Priority:

  • Consider using Vercel JSON output for more reliable parsing
  • Add error handling for failed URL extractions

@claude
Copy link
Copy Markdown

claude bot commented Dec 22, 2025

Pull Request Review

Overview

This PR refactors the deployment workflow and adds preview deployment visibility features. The changes simplify the GitHub Actions workflow and add a banner to preview deployments showing the CMS URL being used.


Potential Bugs and Issues

1. Critical: Bash boolean expression syntax error

Location: .github/workflows/deploy.yml:68

The GitHub expression syntax is invalid. The && operator in GitHub expressions has higher precedence than ||, and this expression doesn't properly evaluate to a bash string.

Fix: Use proper boolean evaluation with extra parentheses.

2. Fragile URL parsing with grep/awk

Location: .github/workflows/deploy.yml:71-72, 100-101

Issues:

  • Relies on Vercel CLI output format which could change
  • No error handling if patterns don't match
  • Could capture incorrect URLs if output format varies

Recommendation: Add validation to check if URLs were successfully extracted before proceeding.

3. Console.log in production code

Location: web/src/layout/Layout.astro:30-31

Debug logs left in production code. These will run on every page load in all environments.

Fix: Remove before merging or guard with development check using import.meta.env.DEV

4. Potential environment variable undefined issue

Location: web/src/layout/Layout.astro:70

The CMS_URL is accessed in the client-side template but might be undefined if the env variable isn't set during build.

Recommendation: Add safety check with fallback value.


Performance Considerations

Workflow simplification improves CI speed - Removing Node.js setup and Vercel CLI installation steps is a good optimization.

Banner adds minimal overhead - The preview banner only renders when VERCEL_ENV === 'preview'.


Security Concerns

⚠️ CMS_URL exposure in client code - The CMS URL is exposed in client-side HTML and JavaScript bundle. While acceptable for preview deployments, ensure the CMS URL doesn't contain sensitive information.

🔴 Authentication disabled for CMS previews - Preview CMS deployments are publicly accessible without authentication. Implement VERCEL_AUTOMATION_BYPASS_SECRET as noted in the TODO.


Summary

Must fix before merge:

  1. Fix the boolean expression syntax error in line 68
  2. Remove or guard the debug console.log statements

Should fix soon:

  1. Add error handling for URL extraction
  2. Add fallback for undefined CMS_URL in the banner
  3. Implement VERCEL_AUTOMATION_BYPASS_SECRET per the TODO

Overall: The workflow simplification is well-designed, but there are critical syntax and logging issues that need addressing before merge.

@claude
Copy link
Copy Markdown

claude bot commented Dec 22, 2025

Code Review

Critical Issue

Shell Expression Syntax Error (.github/workflows/deploy.yml:68) - The PROD_FLAG assignment has incorrect bash syntax and will cause deployment failures. It should use proper conditional logic like the deploy-web job does (lines 93-100).

Other Issues

  • Unsafe URL Extraction (lines 71-72, 102-103) - Using regex to extract URLs from CLI output is fragile. Add validation to ensure URLs were extracted successfully.
  • Client-Side Environment Variable Exposure (Layout.astro:6) - CMS_URL is exposed in the client bundle. Ensure this is acceptable for preview deployments.
  • Debug Console Logs (Layout.astro:30-31) - Debug console logs should be removed or wrapped in development-only conditions before merging.

Security Concerns

  • CMS_URL is publicly exposed in client bundle - ensure no sensitive tokens
  • Verify echo OUTPUT does not log sensitive information

Performance

  • Using npx vercel adds 2-5s vs pre-installing, but acceptable trade-off for simpler workflow

Positive Changes

  • Consolidated deployment logic reduces duplication
  • Better PR comments with inspect URLs
  • Cleaner workflow structure

@claude
Copy link
Copy Markdown

claude bot commented Dec 22, 2025

Code Review - PR #8: Preview Deployment Workflow

Summary

This PR streamlines the deployment workflow by simplifying the GitHub Actions configuration and adding a preview banner to show the CMS URL being used. Overall the changes are well-structured, but there are several issues that need attention.


🐛 Critical Issues

1. Incorrect Bash Syntax in Workflow (.github/workflows/deploy.yml:67)

PROD_FLAG=${{ (github.event_name == 'push' && github.ref == 'refs/heads/main') || github.event.inputs.environment == 'production' && '--prod' || '' }}

Problem: This syntax is incorrect. GitHub Actions expressions don't support shell-style ternary operators with && and || chaining like this. The PROD_FLAG will not evaluate correctly.

Fix: Use proper conditional syntax:

PROD_FLAG=${{ ((github.event_name == 'push' && github.ref == 'refs/heads/main') || github.event.inputs.environment == 'production') && '--prod' || '' }}

Note: The entire first condition needs to be wrapped in parentheses.

2. Security: Sensitive Information Exposure (web/src/layout/Layout.astro:70)

The preview banner exposes the internal CMS URL to all users visiting preview deployments. This could reveal:

  • Internal infrastructure details
  • Deployment patterns
  • Vercel subdomain structures

Recommendation: Consider whether this information should be publicly visible. If it's only needed for debugging, use server-side logging or restrict display to authenticated users.

3. Environment Variable Context Mismatch (web/src/layout/Layout.astro:6)

import { CMS_URL } from 'astro:env/client'

CMS_URL is defined as a client context variable with public access, meaning it will be exposed in the client-side JavaScript bundle. This is likely intentional for the preview banner, but:

  • It increases bundle size slightly
  • Exposes the CMS URL to anyone inspecting the page source
  • May not be necessary if the banner is the only use case

Consider: If the banner is only for preview environments, you might want to use a server-only variable and render the banner server-side.


⚠️ Code Quality Issues

4. Debug Console Logs Left in Production Code (web/src/layout/Layout.astro:30-31)

console.log('[Preview Test] CMS_URL:', CMS_URL)
console.log('[Preview Test] VERCEL_ENV:', VERCEL_ENV)

Problem: These console logs will execute on every page load in all environments, including production (though they won't output anything meaningful in production since CMS_URL might be the production URL).

Fix: Remove these debug logs or wrap them in a conditional:

if (import.meta.env.DEV || isPreviewDeployment) {
  console.log('[Preview Test] CMS_URL:', CMS_URL)
  console.log('[Preview Test] VERCEL_ENV:', VERCEL_ENV)
}

5. Missing Error Handling in Workflow

The workflow doesn't handle cases where:

  • The CMS deployment URL is empty or invalid
  • Vercel CLI fails to return a URL
  • The deployment fails silently

Recommendation: Add validation:

if [ -z "$DEPLOYMENT_URL" ]; then
  echo "Error: Deployment URL is empty"
  exit 1
fi

📊 Performance Considerations

6. Unnecessary npx Overhead

Using npx vercel deploy instead of pre-installing the Vercel CLI means every deployment downloads and executes the CLI fresh. This:

  • Adds ~5-10 seconds per deployment
  • Increases network usage
  • Could fail if npm registry is slow

Trade-off: The old approach with npm install -g vercel@latest ensured a consistent version and faster execution. The new approach is simpler but slower.

Recommendation: If deployment speed is important, consider caching the Vercel CLI or pre-installing it.


Positive Changes

  1. Simplified workflow logic: Consolidating deploy-prod and deploy-preview steps reduces duplication
  2. Better deployment summary: The table format is cleaner and more readable
  3. Environment variable injection: Properly passing CMS URL to the Web build via --build-env and --env
  4. Clear documentation: The TODO comment about VERCEL_AUTOMATION_BYPASS_SECRET is helpful

🔍 Questions

  1. Is the CMS URL supposed to be publicly visible in preview deployments?
  2. Are the console logs intentional for debugging this PR, or were they left in by mistake?
  3. Have you tested the workflow with the new PROD_FLAG syntax? It may not work as expected.

📝 Recommendations

Before merging:

  1. Fix the PROD_FLAG syntax in line 67
  2. Remove or conditionalize the debug console logs
  3. Consider security implications of exposing CMS URL
  4. Add error handling for empty deployment URLs
  5. Test the workflow in a preview environment to ensure it works correctly

Nice to have:

  • Add validation for deployment URLs
  • Consider caching Vercel CLI for faster deployments
  • Make CMS URL exposure configurable or authenticated

@claude
Copy link
Copy Markdown

claude bot commented Dec 22, 2025

PR Review: Preview Deployment Workflow

I've reviewed the changes in this PR. Here's my analysis:

Potential Bugs & Issues

Critical: Shell Operator Precedence Bug (Line 128)

The PROD_FLAG assignment has incorrect operator precedence that will cause unexpected behavior.

Issue: The && operator has higher precedence than ||, so the expression evaluates incorrectly.

Fix needed: Add parentheses to group the OR conditions before the AND.

Medium: Shell Pattern Matching Logic (Lines 102-103)

Similar operator precedence issue in the change detection logic.

Fix needed: Use if-then-else blocks instead of chained operators for clarity and correctness.

Medium: Missing CMS URL Handling in Web Deploy

Line 161-162 passes CMS_URL to Vercel, but when CMS deployment is skipped, needs.deploy-cms.outputs.deployment_url will be empty. This could cause the Web build to use an undefined/empty CMS_URL.

Recommendation: Add validation or use a fallback URL when CMS is skipped.

Minor: Console Logs Left in Production Code

Lines 30-31 in Layout.astro contain debug console logs that will execute on every page render.

Recommendation: Remove before merging or wrap in a debug flag check.

Security Concerns

Medium: Exposure of Internal CMS URL

The preview banner (lines 68-72 in Layout.astro) displays the CMS URL publicly. While this is a preview environment, it could expose internal infrastructure details and potential attack surface for the CMS.

Recommendation: Consider whether this information should be visible to all preview visitors, or restrict to authenticated users only.

Info: TODO Acknowledged

Line 21 correctly identifies the need to use VERCEL_AUTOMATION_BYPASS_SECRET instead of disabling authentication entirely. This is a good security practice to track.

Performance Considerations

Positive: Conditional Deployment

The new detect-changes job prevents unnecessary deployments, which is excellent for reducing CI/CD costs, faster feedback loops, and lower Vercel bandwidth usage.

Positive: Parallel Job Structure

The workflow correctly uses job dependencies instead of sequential steps, allowing GitHub Actions to optimize scheduling.

Additional Observations

  1. Missing Error Handling: The git diff command (line 99) uses || echo "" which silently swallows errors. Consider logging when the diff fails.

  2. Fetch Depth: Using fetch-depth: 2 (line 73) assumes only comparing adjacent commits. For PRs with multiple commits or force-pushes, this might not capture all changes.

  3. String Comparison: Line 156 compares IS_PROD as a string which is correct for shell, but be aware this differs from GitHub Actions boolean expressions.

Summary

Must Fix Before Merge:

  • Shell operator precedence issues (lines 102-103, 128)
  • CMS URL handling when deployment is skipped

Should Fix:

  • Remove debug console.log statements
  • Consider security implications of exposing CMS URLs

Nice to Have:

  • Better error handling for git operations
  • More robust change detection for complex PR scenarios

Overall, this is a well-structured improvement to the deployment workflow with smart optimizations. The conditional deployment logic is solid, but needs the operator precedence fixes to work correctly.

@claude
Copy link
Copy Markdown

claude bot commented Dec 22, 2025

PR Review: Preview Deployment Workflow

I've reviewed the changes and here's my feedback:

Potential Bugs/Issues

  1. ⚠️ Bash operator precedence bug (Line 102-103) - Critical logic error:

    CMS_CHANGED=$([[ "$CHANGED_FILES" == *"cms/"* ]] || [[ "$CHANGED_FILES" == *".github/workflows/deploy.yml"* ]] && echo 'true' || echo 'false')

    The && has higher precedence than ||, so this will return 'false' if only cms/ changed. Should be:

    CMS_CHANGED=$(([[ "$CHANGED_FILES" == *"cms/"* ]] || [[ "$CHANGED_FILES" == *".github/workflows/deploy.yml"* ]]) && echo 'true' || echo 'false')

    Same issue on line 103 for WEB_CHANGED.

  2. 🔒 Sensitive data exposure (Line 70) - The preview banner displays the full CMS URL in production HTML, which could expose internal deployment URLs to end users. Consider:

    • Only showing this to authenticated users
    • Truncating/obfuscating the URL
    • Using a data attribute instead of visible text
  3. 📝 Console logs in production (Lines 30-31) - Debug logs will run on every page load in preview deployments. Consider wrapping in import.meta.env.DEV or removing before merge.

Performance Considerations

  1. ⚡ Unnecessary workflow runs - The workflow will run on ALL PRs/pushes even if no relevant files changed. The detect-changes job still runs and consumes CI minutes. Consider adding a path filter at the workflow level:

    on:
      push:
        branches: [main]
        paths: ['cms/**', 'web/**', '.github/workflows/deploy.yml']
      pull_request:
        paths: ['cms/**', 'web/**', '.github/workflows/deploy.yml']
  2. 💰 npx overhead - Using npx vercel instead of pre-installing will download Vercel CLI on every job run (~5-10s overhead). Consider adding a setup step:

    - name: Setup Node.js
      uses: actions/setup-node@v4
      with:
        node-version: 22
    - name: Install Vercel CLI
      run: npm install -g vercel@latest

Security Concerns

  1. 🔓 Authentication disabled requirement - The README instructs users to disable Vercel Authentication for CMS previews (line 19, 62-63), which creates a security gap. The TODO on line 21 is important - VERCEL_AUTOMATION_BYPASS_SECRET should be prioritized.

  2. 🔑 Secrets in bash variables - Lines 128, 160, 161 use secrets in unquoted bash variables. While GitHub masks these in logs, consider using environment variables directly when possible.

Additional Observations

Good practices:

  • Proper job dependencies with needs
  • Conditional deployment logic is well-structured
  • PR comment automation is helpful
  • Skip tags are a nice UX improvement

📋 Recommendations:

  • Add error handling for failed deployments
  • Consider adding deployment timeout limits
  • Test the skip tag logic with various commit message formats (body vs title)

Testing Checklist

Before merging, verify:

  • Test with [skip-cms] in commit message
  • Test with [skip-web] in commit message
  • Verify preview banner appears only on preview deployments
  • Confirm CMS URL is correctly passed to web build
  • Test manual workflow_dispatch with different combinations

Priority Fixes: Item #1 (operator precedence) is critical and will cause incorrect change detection.

HEAD_SHA=${{ github.sha }}
fi

CHANGED_FILES=$(git diff --name-only $BASE_SHA $HEAD_SHA 2>/dev/null || echo "")
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shallow clone breaks PR change detection silently

For pull requests, fetch-depth: 2 is insufficient to ensure github.event.pull_request.base.sha and head.sha exist in the shallow clone. When the base branch has diverged or the PR has multiple commits, the git diff command at line 99 fails silently (error suppressed with 2>/dev/null || echo ""), resulting in empty CHANGED_FILES. This causes both cms_changed and web_changed to be 'false', and no preview deployments will occur for the PR.

Fix in Cursor Fix in Web

@claude
Copy link
Copy Markdown

claude bot commented Dec 22, 2025

PR Review - Preview Deployment Workflow

This PR implements a smart deployment workflow with change detection, skip tags, and preview deployments. The implementation is solid but has critical issues that must be addressed before merging.


Critical Bugs

1. Bash Operator Precedence Issue (.github/workflows/deploy.yml:102-103)
The boolean expressions have incorrect operator precedence. The && binds tighter than ||, causing incorrect evaluation. Use explicit grouping or if-statements.

2. Test Code Left in Production

  • cms/src/endpoints/sitemap.ts:62-66 - Remove dummy sitemap entry
  • web/src/layout/Layout.astro:30-31 - Remove debug console logs

Security Concerns

1. VERCEL_TOKEN Exposure - Consider using env vars instead of command args
2. Disabled Vercel Authentication - Implement VERCEL_AUTOMATION_BYPASS_SECRET as noted in TODO
3. No Deployment URL Validation - Add validation to ensure valid HTTPS URLs


Performance

1. Redundant Checkout - Consider using dorny/paths-filter for change detection
2. npx vercel - Install Vercel CLI globally to avoid downloading on every run


Recommendations

Before merging:

  1. Fix bash operator precedence bug
  2. Remove all test code (dummy sitemap, console logs)
  3. Add deployment URL validation
  4. Use Vercel CLI env var for token

Future improvements:

  1. Implement VERCEL_AUTOMATION_BYPASS_SECRET
  2. Optimize with dorny/paths-filter
  3. Cache Vercel CLI installation

Overall: Solid architecture with good separation of concerns. Critical issues are the operator precedence bug and test code cleanup.

pages.push({
path: '/dummy-test-entry',
updatedAt: new Date().toISOString(),
})
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Test dummy entry added to production sitemap

A dummy test entry with path /dummy-test-entry is being added to the sitemap endpoint. The TODO comment explicitly states "Remove this dummy entry - testing CMS-only deployment", indicating this is temporary test code. This will cause a fake non-existent page to appear in the production sitemap, potentially affecting SEO and confusing search engines.

Fix in Cursor Fix in Web

@claude
Copy link
Copy Markdown

claude bot commented Dec 22, 2025

PR Review: Preview Deployment Workflow

Summary

This PR enhances the deployment workflow with intelligent change detection, skip tags, and preview visibility. Overall good improvements, but there are some issues that need attention before merging.


Critical Issues

1. Potential Security Risk: CMS_URL Exposure

Location: web/src/layout/Layout.astro:30

The PR adds console logging of CMS_URL which could expose internal infrastructure details:

console.log('[Preview Test] CMS_URL:', CMS_URL)
console.log('[Preview Test] VERCEL_ENV:', VERCEL_ENV)

Issue: These console logs will be visible in browser dev tools on preview deployments, potentially exposing internal URLs to anyone with access to the preview.

Recommendation: Remove these debug logs before merging, or wrap them in a more restrictive condition if they're needed for troubleshooting.


2. Test Code Left in Production Path

Location: cms/src/endpoints/sitemap.ts:62-66

// TODO: Remove this dummy entry - testing CMS-only deployment
pages.push({
  path: '/dummy-test-entry',
  updatedAt: new Date().toISOString(),
})

Issue: This dummy sitemap entry will be included in production builds and could affect SEO or cause confusion.

Recommendation: Remove this test code before merging. If needed for testing, use environment checks to only include in preview/development.


Bugs & Issues

3. Workflow Change Detection Logic

Location: .github/workflows/deploy.yml:88-89

CMS_CHANGED=$([[ "$CHANGED_FILES" == *"cms/"* ]] || [[ "$CHANGED_FILES" == *".github/workflows/deploy.yml"* ]] && echo 'true' || echo 'false')
WEB_CHANGED=$([[ "$CHANGED_FILES" == *"web/"* ]] || [[ "$CHANGED_FILES" == *".github/workflows/deploy.yml"* ]] && echo 'true' || echo 'false')

Issue: Bash operator precedence may cause unexpected behavior. The && has higher precedence than ||, which could lead to incorrect results.

Current behavior: (A || B) && C || D evaluates as ((A || B) && C) || D

Recommendation: Add explicit parentheses or restructure:

CMS_CHANGED=$(if [[ "$CHANGED_FILES" == *"cms/"* ]] || [[ "$CHANGED_FILES" == *".github/workflows/deploy.yml"* ]]; then echo 'true'; else echo 'false'; fi)
WEB_CHANGED=$(if [[ "$CHANGED_FILES" == *"web/"* ]] || [[ "$CHANGED_FILES" == *".github/workflows/deploy.yml"* ]]; then echo 'true'; else echo 'false'; fi)

4. Missing Error Handling for Git Diff

Location: .github/workflows/deploy.yml:79

CHANGED_FILES=$(git diff --name-only $BASE_SHA $HEAD_SHA 2>/dev/null || echo "")

Issue: If git diff fails silently, CHANGED_FILES will be empty, causing both cms_changed and web_changed to be false, potentially skipping necessary deployments.

Recommendation: Add explicit error handling or fail the job if git commands fail:

CHANGED_FILES=$(git diff --name-only $BASE_SHA $HEAD_SHA) || {
  echo "Error: Failed to detect changes"
  exit 1
}

Performance Considerations

5. Unnecessary Workflow Complexity

Location: .github/workflows/deploy.yml

Observation: The workflow now has three jobs (detect-changes → deploy-cms → deploy-web) with conditional logic spread across multiple places.

Minor Concern: While functional, this adds complexity. Consider if the change detection could be simplified or if skip tags alone would suffice for most use cases.

Benefit: The change detection does prevent unnecessary deployments, saving build minutes and costs.


Security Concerns

6. Vercel Authentication Disabled in Documentation

Location: README.md:57-58

The README recommends disabling Vercel Authentication:

Disable Vercel Authentication for CMS preview deployments to allow the Web build to fetch data

Concern: This creates a security gap where preview CMS deployments are publicly accessible without authentication.

Note: The TODO comment in the workflow acknowledges this:

# TODO: Migrate to using VERCEL_AUTOMATION_BYPASS_SECRET instead of disabling authentication.

Recommendation: Prioritize implementing VERCEL_AUTOMATION_BYPASS_SECRET to avoid leaving preview CMS deployments unprotected.


Code Quality Issues

7. Inconsistent Environment Variable Access

Location: web/src/layout/Layout.astro:6, 30

import { CMS_URL } from 'astro:env/client'
import { VERCEL_ENV } from 'astro:env/server'

Observation: Mixing client and server environment imports in the same component.

Question: Is CMS_URL intentionally exposed to the client? If not, consider importing from astro:env/server instead for better security.


8. Typo in Layout.astro

Location: web/src/layout/Layout.astro:74

<slot /></output>

Issue: There's a stray </output> closing tag that should be </main>.

Impact: This will cause HTML validation errors and may break the page layout.

Fix Required: Change to </main>


Positive Aspects

  • Well-documented deployment workflow in README
  • Smart change detection to reduce unnecessary builds
  • Skip tags provide flexible deployment control
  • Preview URL visibility banner helps with debugging
  • Proper use of job dependencies and conditional execution
  • Comprehensive PR comment with deployment URLs

Recommendations Summary

Before Merging:

  1. Remove console.log statements from Layout.astro
  2. Remove dummy sitemap entry from cms/src/endpoints/sitemap.ts
  3. Fix the </output></main> typo in Layout.astro
  4. Improve change detection bash logic with explicit conditionals
  5. Add proper error handling for git diff failures

Post-Merge:

  1. Implement VERCEL_AUTOMATION_BYPASS_SECRET for CMS preview security
  2. Review if CMS_URL should be server-side only

Optional:

  • Consider simplifying workflow if change detection proves overly complex
  • Add integration tests for the deployment workflow logic

Let me know if you'd like help addressing any of these issues!

echo "CMS preview deployed to: $DEPLOYMENT_URL"
env:
VERCEL_PROJECT_ID: ${{ secrets.VERCEL_CMS_PROJECT_ID }}
COMMIT_MSG="${{ github.event.head_commit.message || github.event.pull_request.title || '' }}"
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Skip tags won't work in PR commit messages

The skip tag detection uses github.event.head_commit.message which is null for pull request events, falling back to github.event.pull_request.title. This means for PRs, [skip-cms] or [skip-web] tags must be added to the PR title, not the commit message as documented in the README. Users following the documentation ("Add these tags to your commit message...") will find the feature doesn't work on pull requests.

Fix in Cursor Fix in Web

@claude
Copy link
Copy Markdown

claude bot commented Dec 22, 2025

Code Review - PR #8

I've reviewed this PR and found several issues that should be addressed:

🐛 Potential Bugs

  1. Shell operator precedence issue (.github/workflows/deploy.yml:99-100)

    • The bash && operator has higher precedence than ||, which may cause incorrect logic when checking for changed files
    • Current: [[ "$CHANGED_FILES" == *"cms/"* ]] || [[ "$CHANGED_FILES" == *".github/workflows/deploy.yml"* ]] && echo 'true' || echo 'false'
    • This evaluates as: (A || B && C) || D, not (A || B) && C || D
    • Fix: Add parentheses or restructure the logic to ensure both conditions are checked before the echo
  2. Closing tag typo (web/src/layout/Layout.astro:76)

    • Line has </output> instead of </main>
    • This will cause a build error
  3. Missing error handling (web/src/cms/getRedirects.ts:14)

    • If the redirects fetch fails, there's no error handling which could cause the build to crash
    • Consider wrapping in try/catch with fallback to empty object

🔒 Security Concerns

  1. Bypass secret exposure (web/src/layout/Layout.astro:30-31, web/astro.config.mjs:31-35)

    • While CMS_VERCEL_AUTOMATION_BYPASS_SECRET is correctly marked as access: 'secret' in the config, ensure it's never logged in production
    • The console.log statements on lines 30-31 of Layout.astro should be removed before merging as they may inadvertently log sensitive data in build logs
    • Fix: Remove debug console.log statements
  2. Client-side CMS_URL exposure (web/src/layout/Layout.astro:70)

    • CMS_URL is marked as context: 'client' which means it's included in the client bundle
    • The preview banner displays this URL publicly, which is acceptable for testing but consider if this exposes internal infrastructure
    • Recommendation: This is fine for preview deployments, but ensure the banner is never shown in production

⚡ Performance Considerations

  1. Headers object recreation (web/src/cms/sdk/bypassHeader.ts:13)

    • Creating a new Headers object on every fetch may have minor performance impact
    • Consider only creating Headers when bypassSecret is present:
    if (!bypassSecret) {
      return init ?? {}
    }
    const headers = new Headers(init?.headers)
    headers.set('x-vercel-protection-bypass', bypassSecret)
    return { ...init, headers }
  2. Unnecessary workflow runs (.github/workflows/deploy.yml:99-100)

    • The change detection logic will trigger both CMS and Web deploys if only the workflow file changes
    • Consider separating workflow-only changes from actual code changes to avoid unnecessary deployments

🧹 Code Quality

  1. Temporary test code (cms/src/endpoints/sitemap.ts:62-66)

    • The TODO comment indicates this is test code that should be removed
    • Action required: Remove before merging or clarify if it's needed for testing this PR
  2. Console.log statements (web/src/layout/Layout.astro:30-31)

    • Debug logging should be removed before merging to production
    • Action required: Remove debug statements

✅ Positive Observations

  • Good separation of concerns with the bypassHeader utility
  • Clear documentation in README.md for deployment workflow
  • Proper use of environment variables with correct access levels
  • Smart use of conditional deployment based on changed files

📋 Summary

Must fix before merge:

  • Fix the closing tag typo in Layout.astro:76
  • Remove console.log debug statements
  • Remove or address the dummy sitemap entry
  • Fix shell operator precedence in workflow file

Recommended improvements:

  • Add error handling for redirects fetch
  • Consider edge cases in change detection logic

Let me know if you need clarification on any of these points!

@jhb-dev jhb-dev force-pushed the test/preview-deployment branch from 2f88cf4 to 3ff8c22 Compare December 22, 2025 21:40
@claude
Copy link
Copy Markdown

claude bot commented Dec 22, 2025

PR Review: Preview Deployment Workflow

I've reviewed this PR and found several issues that need attention before merging.


Potential Bugs

1. Bash Logic Error in Workflow (Critical)

Location: .github/workflows/deploy.yml:98-99

The bash operator precedence in the change detection logic is incorrect. The && binds tighter than ||, which means when neither cms/ nor workflow file changes, it still outputs true instead of false.

Fix: Use proper if-else structure instead of chained operators.

2. Test Code Left in Production

Location: cms/src/endpoints/sitemap.ts:62-66

Dummy sitemap entry with TODO comment should be removed before merge.


Performance Considerations

1. Git Fetch Depth Limitation

fetch-depth: 2 may cause git diff failures for PRs with many commits. Consider using fetch-depth: 0 or add error handling.

2. Client-Side CMS_URL Exposure

CMS_URL is exposed in browser bundle. Consider if preview URLs should be visible to all users.


Security Concerns

1. Bypass Secret Exposure (High Severity)

Location: .github/workflows/deploy.yml:166-167

The bypass secret is passed as runtime environment variable (--env) in addition to build-time. This exposes the secret in the deployed environment where it could be extracted.

Fix: Remove --env flags for the bypass secret, only use --build-env.

2. Sensitive Data in Console Logs

Location: web/src/layout/Layout.astro:30-31

Debug console.log statements expose deployment info. Remove before production.

3. Preview Banner Information Disclosure

Banner displays CMS URL publicly on all preview deployments. Evaluate if this is acceptable.


Summary

  • Critical: Fix bash logic error in change detection
  • Critical: Remove bypass secret from runtime environment variables
  • Required: Remove dummy sitemap test entry
  • Recommended: Clean up debug console logs
  • Consider: Security implications of exposing CMS URLs publicly

The core approach is sound, but these issues should be addressed before merging to production.

@claude
Copy link
Copy Markdown

claude bot commented Dec 22, 2025

Code Review

I have reviewed PR #8 and identified several areas for feedback:

Potential Bugs/Issues

  1. Workflow file change detection logic (lines 99-100) - The bash logic has operator precedence issues. Due to operator precedence, && binds tighter than ||, which means this will only output true if the workflow file changed AND will output false if CMS files changed but the workflow file did not. This should be rewritten with explicit if-else statements.

  2. Missing error handling for empty CMS_URL - In getRedirects.ts:14, the code uses process.env.CMS_URL! with a non-null assertion. If this variable is missing, the error will only surface at runtime. Consider adding explicit validation.

  3. Cache key collision risk - In cachedFetch.ts:12, the cache key includes headers as JSON.stringify(headers). The cache key function does not account for header order differences in JSON.stringify.

Performance Considerations

  1. Redundant environment variable passing - Lines 171-174 pass CMS_VERCEL_AUTOMATION_BYPASS_SECRET as both --build-env and --env. The --build-env should be sufficient for build-time access. The --env flag is for runtime, which is not needed since this is used only during the build phase.

  2. Vercel CLI installation - Installing Vercel CLI globally on every workflow run (lines 123, 158) could be cached using GitHub Actions cache to speed up deployments.

Security Concerns

  1. Bypass secret exposure risk - The CMS_VERCEL_AUTOMATION_BYPASS_SECRET is being passed to both build and runtime environments. While Vercel encrypts these, minimize the secret exposure surface by only passing it where needed (--build-env only).

  2. Bypass header on all requests - In cachedFetch.ts:26 and getRedirects.ts:15, the bypass header is added to ALL requests, even those not targeting the CMS. Consider adding validation to only add the bypass header when the request URL starts with the CMS URL.

  3. Headers mutation - The addBypassHeader function creates a new Headers object but then spreads the original init. If init.headers was already a Headers object, this could lead to unexpected behavior.

Recommendations Priority

High Priority:

  • Fix the bash operator precedence bug in change detection

Medium Priority:

  • Limit bypass header to CMS-only requests
  • Remove redundant --env flag for bypass secret

Low Priority:

  • Add explicit CMS_URL validation in getRedirects
  • Consider caching Vercel CLI installation

Overall, this is a well-structured PR that adds important functionality for preview deployments. The main concern is the bash logic bug that could cause incorrect change detection.

@jhb-dev jhb-dev changed the title test: preview deployment workflow feat(ci): add GitHub Actions workflow for sequential CMS and Web deployment Dec 22, 2025
echo "| Project | URL |" >> $GITHUB_STEP_SUMMARY
echo "|---------|-----|" >> $GITHUB_STEP_SUMMARY
echo "| CMS | ${{ needs.deploy-cms.outputs.deployment_url || 'Skipped' }} |" >> $GITHUB_STEP_SUMMARY
echo "| Web | ${{ steps.deploy.outputs.deployment_url }} |" >> $GITHUB_STEP_SUMMARY
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR comment job skipped when CMS deployment is skipped

The comment-preview job has needs: [deploy-cms, deploy-web] but its if condition lacks always(). In GitHub Actions, when any job in needs is skipped, dependent jobs are also skipped by default. With the new change detection logic, deploy-cms can now be skipped for PRs with only web changes, causing comment-preview to be skipped even when deploy-web succeeds. The deploy-web job correctly uses always() at line 143 to handle this, but comment-preview doesn't follow the same pattern.

Fix in Cursor Fix in Web

- name: Check for skip tags
id: skip
run: |
COMMIT_MSG="${{ github.event.head_commit.message || github.event.pull_request.title || '' }}"
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Script injection via untrusted commit message or PR title

The commit message and PR title are directly interpolated into a bash script using ${{ github.event.head_commit.message || github.event.pull_request.title }}. This is a well-documented GitHub Actions script injection vulnerability. An attacker can craft a PR title like Fix $(malicious_command) or use backticks, and the shell will execute the embedded command on the runner. For PRs from forks, anyone can control the PR title. The safe pattern is to pass untrusted values via the env: context instead of direct interpolation.

Fix in Cursor Fix in Web

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant