Skip to content

feat(ci): Add deployment workflow for staging and production - #95

Merged
frankbria merged 10 commits into
mainfrom
feature/deploy-workflow
Dec 16, 2025
Merged

feat(ci): Add deployment workflow for staging and production#95
frankbria merged 10 commits into
mainfrom
feature/deploy-workflow

Conversation

@frankbria

@frankbria frankbria commented Dec 16, 2025

Copy link
Copy Markdown
Owner

Summary

  • Add GitHub Actions deployment workflow with SSH-based deployment to staging and production environments
  • Integrates with existing test workflow as quality gate (tests must pass before deployment)
  • Uses existing GitHub secrets: HOST, USER, SSH_KEY, PROJECT_PATH

Deployment Triggers

Trigger Environment Condition
Push to main Staging Automatic after tests pass
GitHub Release Production Automatic after tests pass
Manual dispatch Either Select environment in Actions UI

Changes

  • .github/workflows/deploy.yml - New deployment workflow
  • .github/workflows/test.yml - Added workflow_call trigger for reusability
  • claudedocs/SESSION.md - Implementation documentation

Security Features

  • Uses webfactory/ssh-agent for secure SSH key handling
  • No secrets echoed in logs
  • Known hosts verification to prevent MITM attacks
  • Pre-deployment backup for production deployments

Test plan

  • Verify YAML syntax is valid (automated)
  • Push to main triggers staging deployment
  • Manual dispatch works for staging
  • Production deployment works on release (when production env is created)

Summary by CodeRabbit

  • New Features

    • Automated staging and production deployment pipeline with environment selection, environment-specific builds, post-deploy health checks, deployment summaries, and optional tag-based releases plus pre-deployment backups.
  • Documentation

    • Expanded CI/CD guide covering execution plan, required secrets, server requirements, security and rollback/backup guidance, and manual deployment steps.
  • Chores

    • Made the test workflow callable for reuse by other workflows.

✏️ Tip: You can customize this high-level summary in your review settings.

- Add deploy.yml workflow with SSH-based deployment
- Staging: Auto-deploys on push to main (after tests pass)
- Production: Deploys on GitHub releases or manual trigger
- Quality gates: Requires test.yml to pass before deployment
- Security: Uses ssh-agent for secure key handling
- Add workflow_call trigger to test.yml for reusability
- Include pre-deployment backups for production
- Add health check verification post-deployment

Triggers:
- Push to main → staging
- GitHub Release → production
- Manual workflow_dispatch → either

Required secrets: HOST, USER, SSH_KEY, PROJECT_PATH
@coderabbitai

coderabbitai Bot commented Dec 16, 2025

Copy link
Copy Markdown
Contributor

Caution

Review failed

The pull request is closed.

Walkthrough

Adds a GitHub Actions "Deploy" workflow for staging and production SSH-based deployments (build, PM2/service restart, health checks, backups for production). Makes the test workflow callable by other workflows. Replaces SESSION.md with a CI/CD deployment session guide and required secrets/instructions.

Changes

Cohort / File(s) Change Summary
Deployment workflow
\.github/workflows/deploy.yml
New "Deploy" workflow (triggers: push to main, release, workflow_dispatch with env choice). Jobs: test (calls existing test workflow), deploy-staging (push/main or manual, SSH setup, create .env.staging, backend/frontend build, PM2 with staging config, health check, summary), deploy-production (release or manual, create .env.production, pre-deploy backup, tag-or-main checkout, production builds, optional migrations, PM2 production config, health check, summary).
Test workflow callable
\.github/workflows/test.yml
Added workflow_call to expose the test workflow for invocation by other workflows; original triggers preserved.
Documentation / Session guide
claudedocs/SESSION.md
Replaced previous E2E CI troubleshooting content with a CI/CD deployment session guide: goals, required GitHub Secrets, eight-phase execution plan, deployment triggers, server requirements, manual fallback steps, and risk/mitigation notes.

Sequence Diagram(s)

sequenceDiagram
    participant GH as GitHub Actions
    participant Test as Test Workflow
    participant SSH as Remote Server
    participant Health as Health Endpoint

    GH->>Test: workflow_call -> run tests
    Test-->>GH: tests pass

    alt Deploy → Staging (push main or manual env=staging)
        GH->>SSH: open SSH, copy env (.env.staging)
        GH->>SSH: checkout code (main)
        SSH->>SSH: backend install & build (dev)
        SSH->>SSH: frontend npm ci & build (staging)
        SSH->>SSH: pm2 start/reload (ecosystem.staging.config.js)
        SSH->>Health: GET /health
        Health-->>SSH: 200 OK
        SSH-->>GH: deployment summary
    end

    alt Deploy → Production (release or manual env=production)
        GH->>SSH: open SSH, create backups (state.db, commits, logs)
        GH->>SSH: checkout tag or origin/main
        SSH->>SSH: backend install & production build
        SSH->>SSH: frontend npm ci & production build
        SSH->>SSH: optional migrations
        SSH->>SSH: pm2 start/reload (ecosystem.production.config.js)
        SSH->>Health: GET /health
        Health-->>SSH: 200 OK
        SSH-->>GH: deployment summary
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

  • Inspect .github/workflows/deploy.yml for secrets usage, SSH/known_hosts handling, and exposed environment variables in .env.* steps.
  • Verify conditional checkout logic for release.tag_name vs origin/main and manual dispatch behavior.
  • Review pre-deploy backup steps and any placeholders for migrations/DB operations.
  • Confirm PM2/service management commands and order relative to migrations and health checks.

Possibly related PRs

Poem

🐰 I nudged the YAML, twitched my nose,
Keys whispered, servers in neat rows,
Staging danced, production glowed,
Health checks sang, the traffic flowed,
Hop, build, deploy — a bunny's prose. 🥕

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat(ci): Add deployment workflow for staging and production' directly and clearly describes the main change: introducing a new CI/CD deployment workflow with staging and production environment support.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c9e956e and 3c62076.

📒 Files selected for processing (2)
  • .github/workflows/deploy.yml (1 hunks)
  • claudedocs/SESSION.md (1 hunks)

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (6)
.github/workflows/deploy.yml (5)

54-57: Consider pre-configuring known hosts for stronger MITM protection.

Using ssh-keyscan at runtime trusts whatever host key is returned at that moment. For stronger security, you could store the server's host key fingerprint as a secret and verify it, or commit a known_hosts file with pre-verified keys.

That said, this approach is common and acceptable for most use cases.


110-114: Health check failure should fail the workflow.

Currently, if the health check fails, the workflow still succeeds due to || echo. For staging, consider failing the workflow when health checks fail to catch broken deployments early.

      - name: Verify deployment
        run: |
          echo "🔍 Verifying deployment..."
          sleep 10
-          ssh ${{ secrets.USER }}@${{ secrets.HOST }} "curl -sf http://localhost:8080/health" || echo "⚠️  Health check failed or endpoint not available"
+          ssh ${{ secrets.USER }}@${{ secrets.HOST }} "curl -sf http://localhost:8080/health" || { echo "❌ Health check failed"; exit 1; }

160-172: Consider a persistent backup location instead of /tmp.

Backups stored in /tmp may be cleared by the OS before you need them for rollback (e.g., after a reboot). Consider storing backups in a dedicated persistent directory like ~/codeframe-backups or $PROJECT_PATH/backups.

-            BACKUP_DIR="/tmp/codeframe-backup-\$(date +%Y%m%d-%H%M%S)"
+            BACKUP_DIR="\$HOME/codeframe-backups/\$(date +%Y%m%d-%H%M%S)"
             mkdir -p \$BACKUP_DIR

238-242: Health check failure should fail the production deployment workflow.

Same issue as staging—the || echo pattern masks deployment failures. For production, it's especially important to fail the workflow if the health check fails so you're alerted to broken deployments.

      - name: Verify deployment
        run: |
          echo "🔍 Verifying production deployment..."
          sleep 15
-          ssh ${{ secrets.USER }}@${{ secrets.HOST }} "curl -sf http://localhost:8080/health" || echo "⚠️  Health check failed or endpoint not available"
+          ssh ${{ secrets.USER }}@${{ secrets.HOST }} "curl -sf http://localhost:8080/health" || { echo "❌ Production health check failed"; exit 1; }

215-217: Migrations placeholder should be addressed before production use.

The placeholder comment for database migrations should be either implemented or documented as a known limitation. If migrations are needed later, forgetting to add them here could cause production issues.

Would you like me to open an issue to track implementing database migration support?

claudedocs/SESSION.md (1)

60-65: Add blank lines around the table for proper Markdown rendering.

Per markdownlint MD058, tables should be surrounded by blank lines.

 ### Deployment Triggers
+
 | Trigger | Environment | Condition |
 |---------|-------------|-----------|
 | Push to `main` | Staging | Automatic after tests pass |
 | GitHub Release | Production | Automatic after tests pass |
 | Manual dispatch | Either | Select environment in UI |
+
 ### Required GitHub Setup
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6274e97 and f194a34.

📒 Files selected for processing (3)
  • .github/workflows/deploy.yml (1 hunks)
  • .github/workflows/test.yml (1 hunks)
  • claudedocs/SESSION.md (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.md

📄 CodeRabbit inference engine (AGENTS.md)

Documentation files must be sized to fit in a single agent context window (spec.md ~200-400 lines, plan.md ~300-600 lines, tasks.md ~400-800 lines)

Files:

  • claudedocs/SESSION.md
🧠 Learnings (1)
📚 Learning: 2025-12-11T17:15:19.102Z
Learnt from: CR
Repo: frankbria/codeframe PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-11T17:15:19.102Z
Learning: Applies to codeframe/agents/worker_agent.py : Implement quality gates with 4 stages (tests → type checking → coverage → review) before task completion

Applied to files:

  • .github/workflows/deploy.yml
🪛 markdownlint-cli2 (0.18.1)
claudedocs/SESSION.md

61-61: Tables should be surrounded by blank lines

(MD058, blanks-around-tables)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: Backend Unit Tests
  • GitHub Check: Frontend Unit Tests
  • GitHub Check: E2E Smoke Tests (Chromium)
🔇 Additional comments (4)
.github/workflows/test.yml (1)

8-8: LGTM!

Adding workflow_call enables this workflow to be used as a reusable workflow, which is the correct approach for implementing a quality gate in the deployment workflow.

.github/workflows/deploy.yml (3)

1-22: LGTM!

The trigger configuration appropriately maps deployment scenarios: automatic staging on main push, automatic production on release, and manual dispatch for flexibility.


23-29: LGTM!

Using the test workflow as a quality gate via uses: is a clean approach that avoids code duplication.


59-108: LGTM!

The staging deployment script is well-structured with:

  • set -e for fail-fast behavior
  • Conditional venv creation
  • Conditional service restarts with warnings

One consideration: long-running operations like npm ci could cause SSH timeouts on slow networks. If you encounter issues, consider adding ServerAliveInterval to the SSH config.

- Replace systemctl commands with PM2 restart/start
- Update health check port from 8080 to 14200 (staging backend port)
- Add logs directory creation before PM2 start
- Support optional ecosystem.production.config.js for production
- Add PM2 save after restart to persist process list
- Add environment file creation step for staging and production
- Create .env.staging/.env.production from GitHub secrets
- Set proper file permissions (600) for security
- Document new required secrets: ANTHROPIC_API_KEY, OPENAI_API_KEY,
  CORS_ORIGINS, API_URL, WS_URL

New secrets needed in staging environment:
- ANTHROPIC_API_KEY
- OPENAI_API_KEY (optional)
- CORS_ORIGINS
- API_URL
- WS_URL

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 8

🧹 Nitpick comments (2)
.github/workflows/deploy.yml (2)

19-21: Unused environment variables.

The PYTHON_VERSION and NODE_VERSION environment variables are defined but never referenced in the workflow. Either use them in the deployment scripts (e.g., python${{ env.PYTHON_VERSION }}) or remove them to avoid confusion.


219-221: Database migrations are commented out.

The placeholder comment suggests migrations may be needed, but there's no actual migration command. If your application requires database schema migrations, this step must be implemented before production deployment.

Do you need database migrations for this project? If yes, I can help you implement the appropriate migration command (e.g., using Alembic for Python).

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f194a34 and c9e956e.

📒 Files selected for processing (1)
  • .github/workflows/deploy.yml (1 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-12-11T17:15:19.102Z
Learnt from: CR
Repo: frankbria/codeframe PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-11T17:15:19.102Z
Learning: Applies to codeframe/agents/worker_agent.py : Implement quality gates with 4 stages (tests → type checking → coverage → review) before task completion

Applied to files:

  • .github/workflows/deploy.yml
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: Frontend Unit Tests
  • GitHub Check: Backend Unit Tests
  • GitHub Check: E2E Smoke Tests (Chromium)
🔇 Additional comments (1)
.github/workflows/deploy.yml (1)

27-29: LGTM! Clean quality gate implementation.

Delegating to the reusable test workflow is the right approach for enforcing quality gates before deployment.

Comment thread .github/workflows/deploy.yml
Comment on lines +70 to +71
git fetch origin main
git reset --hard origin/main

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Ensure git reset works from any branch state.

The git reset --hard origin/main assumes the working directory is already on the main branch. If the server is on a different branch or in a detached HEAD state, this might not work as expected.

Apply this approach for more robust git operations:

 echo "📥 Pulling latest code..."
+git fetch origin main
+git checkout main
-git fetch origin main
 git reset --hard origin/main
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
git fetch origin main
git reset --hard origin/main
git fetch origin main
git checkout main
git reset --hard origin/main
🤖 Prompt for AI Agents
.github/workflows/deploy.yml around lines 70 to 71: the current sequence uses
"git reset --hard origin/main" which can fail if the repo is on a different
branch or in detached HEAD; instead fetch and then force-create/replace the
local main branch from origin so the command works from any state—use "git fetch
origin main" followed by "git checkout -B main origin/main" (or similar) to
ensure you are on a local main that exactly matches origin/main before any
resets or deployments.

Comment thread .github/workflows/deploy.yml Outdated
Comment thread .github/workflows/deploy.yml Outdated
Comment thread .github/workflows/deploy.yml
Comment on lines +188 to +199
# Pull the release tag or main
echo "📥 Pulling latest code..."
git fetch origin --tags
TAG_NAME="${{ github.event.release.tag_name }}"
if [ -n "\$TAG_NAME" ]; then
git checkout \$TAG_NAME
echo "✅ Checked out tag: \$TAG_NAME"
else
git fetch origin main
git reset --hard origin/main
echo "✅ Reset to origin/main"
fi

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Git checkout logic unsafe with empty tag name.

When triggered via workflow_dispatch for production, github.event.release.tag_name will be empty, causing TAG_NAME to be an empty string. The condition on line 192 checks if [ -n "\$TAG_NAME" ], which correctly handles this, but the logic could be clearer.

However, there's a potential issue: if someone triggers a manual production deployment without a release, they get origin/main, which may not be what they intended for production.

Consider one of these approaches:

Option 1: Require a tag for production deployments:

 TAG_NAME="${{ github.event.release.tag_name }}"
 if [ -n "\$TAG_NAME" ]; then
   git checkout \$TAG_NAME
   echo "✅ Checked out tag: \$TAG_NAME"
 else
-  git fetch origin main
-  git reset --hard origin/main
-  echo "✅ Reset to origin/main"
+  echo "❌ Production deployments require a release tag"
+  exit 1
 fi

Option 2: Add tag input to workflow_dispatch:

 workflow_dispatch:
   inputs:
     environment:
       description: 'Environment to deploy to'
       required: true
       default: 'staging'
       type: choice
       options:
         - staging
         - production
+    tag:
+      description: 'Tag to deploy (required for production)'
+      required: false
+      type: string
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
# Pull the release tag or main
echo "📥 Pulling latest code..."
git fetch origin --tags
TAG_NAME="${{ github.event.release.tag_name }}"
if [ -n "\$TAG_NAME" ]; then
git checkout \$TAG_NAME
echo "✅ Checked out tag: \$TAG_NAME"
else
git fetch origin main
git reset --hard origin/main
echo "✅ Reset to origin/main"
fi
# Pull the release tag or main
echo "📥 Pulling latest code..."
git fetch origin --tags
TAG_NAME="${{ github.event.release.tag_name }}"
if [ -n "\$TAG_NAME" ]; then
git checkout \$TAG_NAME
echo "✅ Checked out tag: \$TAG_NAME"
else
echo "❌ Production deployments require a release tag"
exit 1
fi
🤖 Prompt for AI Agents
.github/workflows/deploy.yml lines 188-199: the current checkout logic uses
github.event.release.tag_name which can be empty for workflow_dispatch and may
unintentionally deploy origin/main to production; update the workflow to require
an explicit tag for production deployments or add a workflow_dispatch input for
a tag and validate it: add a required 'tag' input to the production dispatch (or
check github.event.inputs.tag), set TAG_NAME from that input (falling back to
release.tag_name only if present), and if TAG_NAME is empty fail the job with a
clear error and non-zero exit instead of defaulting to origin/main, logging the
missing tag and expected usage.

Comment thread .github/workflows/deploy.yml Outdated
Comment thread .github/workflows/deploy.yml Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 7

♻️ Duplicate comments (2)
.github/workflows/deploy.yml (2)

200-241: Critical: Same command injection vulnerability as staging.

This step has the same security issue as the staging environment file creation (lines 59-101). The heredoc with unsanitized environment variables could allow command injection.

Apply the same fix as suggested for staging - create the file locally and use SCP to transfer it securely.


338-342: Critical: Health check always succeeds (same issue as staging).

Line 342 has the same problem as the staging health check - the || echo makes it always succeed even if the health check fails. This is especially critical for production deployments.

Apply the same fix as suggested for staging, with the retry loop being even more important for production to ensure the service is truly healthy before marking deployment as successful.

🧹 Nitpick comments (2)
.github/workflows/deploy.yml (2)

102-155: Consider adding rollback mechanism for failed deployments.

If any deployment step fails after pulling code (line 113), the server will be left in a potentially broken state. Consider implementing a rollback mechanism that reverts to the previous commit if deployment fails.

You could add a pre-deployment commit capture and post-deployment verification with rollback:

# Before deployment (after line 109)
PREVIOUS_COMMIT=$(git rev-parse HEAD)

# After all deployment steps, if any fail, add a trap:
trap 'echo "❌ Deployment failed, rolling back..."; git reset --hard $PREVIOUS_COMMIT; exit 1' ERR

305-307: Database migrations are not implemented.

The placeholder comment indicates that database migrations should be run, but there's no actual implementation. This could lead to schema mismatches after deployment if the codebase expects database changes.

Do you want me to generate a database migration implementation based on the project structure, or would you prefer to open an issue to track this task?

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f194a34 and b73e4cb.

📒 Files selected for processing (2)
  • .github/workflows/deploy.yml (1 hunks)
  • claudedocs/SESSION.md (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.md

📄 CodeRabbit inference engine (AGENTS.md)

Documentation files must be sized to fit in a single agent context window (spec.md ~200-400 lines, plan.md ~300-600 lines, tasks.md ~400-800 lines)

Files:

  • claudedocs/SESSION.md
🧠 Learnings (1)
📚 Learning: 2025-12-11T17:15:19.102Z
Learnt from: CR
Repo: frankbria/codeframe PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-11T17:15:19.102Z
Learning: Applies to codeframe/agents/worker_agent.py : Implement quality gates with 4 stages (tests → type checking → coverage → review) before task completion

Applied to files:

  • .github/workflows/deploy.yml
🪛 markdownlint-cli2 (0.18.1)
claudedocs/SESSION.md

70-70: Tables should be surrounded by blank lines

(MD058, blanks-around-tables)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Backend Unit Tests
  • GitHub Check: E2E Smoke Tests (Chromium)
🔇 Additional comments (8)
.github/workflows/deploy.yml (8)

27-29: LGTM! Quality gate properly configured.

Reusing the existing test workflow as a quality gate before deployment follows best practices and prevents deploying broken code.


46-57: LGTM! SSH setup follows security best practices.

Using webfactory/ssh-agent ensures the SSH key is never exposed in logs, and ssh-keyscan adds the host to known_hosts to prevent MITM attacks.


163-171: LGTM! Deployment summary provides good visibility.

The deployment summary includes relevant information (branch, commit, actor, timestamp) that will help track deployments in the Actions UI.


182-184: Verify production environment URL.

The production URL https://codeframe.example.com appears to be a placeholder. Ensure this is updated to the actual production domain before deploying to production.


274-285: LGTM! Tag-based deployment logic is well-implemented.

The logic correctly handles both release-triggered deployments (using the tag) and manual dispatches (falling back to main). This provides flexibility for production deployments.


287-296: Good: Production-optimized dependency installation.

Using uv sync --no-dev (line 296) appropriately excludes development dependencies from the production environment, reducing the attack surface and deployment size.


344-351: LGTM! Production summary appropriately shows version information.

Using github.event.release.tag_name || github.ref_name ensures the summary shows the tag for release deployments or branch for manual deployments.


19-21: Python 3.11 matches the project requirement (requires-python = ">=3.11" in pyproject.toml). Node 20 is acceptable; the project does not specify a Node engine version requirement in package.json or version files.

Comment thread .github/workflows/deploy.yml
Comment thread .github/workflows/deploy.yml
Comment thread .github/workflows/deploy.yml
Comment thread .github/workflows/deploy.yml Outdated
Comment thread .github/workflows/deploy.yml
Comment thread .github/workflows/deploy.yml
Comment thread claudedocs/SESSION.md
All environment variables now come from GitHub secrets so they can be
configured per-environment (staging vs production) in GitHub settings.

Secrets required per environment:
- ANTHROPIC_API_KEY, OPENAI_API_KEY
- DATABASE_PATH, API_HOST, API_PORT
- CORS_ORIGINS, API_URL, WS_URL
- LOG_LEVEL, LOG_FILE
- ENVIRONMENT, DEBUG, HOT_RELOAD
- Staging: ecosystem.staging.config.js, check for codeframe-staging-backend
- Production: ecosystem.production.config.js, check for codeframe-production-backend
- Use pm2 describe instead of grep for reliable process detection
- Move backups from /tmp to PROJECT_PATH/backups for persistence
- Create timestamped compressed tar.gz archives
- Include: database, .codeframe configs, .env files, ecosystem configs, logs
- Record git commit info in archive
- Implement retention policy (keep last 10 backups)
- Use atomic operations (create in /tmp, mv to final location)
- Set proper permissions (700 dir, 600 archives)
- Abort deployment if backup fails
- Report backup size and count after completion
- Replace one-liner health check with retry loop (12 attempts, 5s apart)
- Exit 0 immediately on success
- Exit 1 after all attempts fail (fails the workflow)
- Show progress on each attempt
- Applied to both staging and production deployments
- Use pm2 jlist with grep for robust process existence check
- Restart individual processes by name when they exist
- Start with --only flag when processes don't exist
- Handle backend and frontend processes separately
- Applied to both staging and production deployments
- Use printf with %s to build env content (no shell interpretation)
- Base64 encode content before transfer to prevent injection
- Decode safely on remote server
- Write to .tmp file first, then atomic mv to final location
- Verify file was created and is non-empty before proceeding
- Exit with error if creation fails

This prevents command injection if secrets contain shell metacharacters
like backticks, $(), or other special characters.
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