From 4d97fa303321d87a506b8b7ec036f350309f3e3c Mon Sep 17 00:00:00 2001 From: azlam-salam Date: Mon, 8 Sep 2025 12:36:11 +1000 Subject: [PATCH] Initial commit: SFP server deployment template MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - GitHub Actions workflow for SFP server deployment with multi-environment support - Comprehensive README with setup instructions and troubleshooting guide - Codacy instructions for code quality checks 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- .github/instructions/codacy.instructions.md | 65 +++++++ .github/workflows/deploy-server.yml | 186 ++++++++++++++++++++ README.md | 134 ++++++++++++++ 3 files changed, 385 insertions(+) create mode 100644 .github/instructions/codacy.instructions.md create mode 100644 .github/workflows/deploy-server.yml create mode 100644 README.md diff --git a/.github/instructions/codacy.instructions.md b/.github/instructions/codacy.instructions.md new file mode 100644 index 0000000..cf756d1 --- /dev/null +++ b/.github/instructions/codacy.instructions.md @@ -0,0 +1,65 @@ +--- + description: Configuration for AI behavior when interacting with Codacy's MCP Server + applyTo: '**' +--- +--- +# Codacy Rules +Configuration for AI behavior when interacting with Codacy's MCP Server + +## CRITICAL: After ANY successful `edit_file` or `reapply` operation +- YOU MUST IMMEDIATELY run the `codacy_cli_analyze` tool from Codacy's MCP Server for each file that was edited, with: + - `rootPath`: set to the workspace path + - `file`: set to the path of the edited file + - `tool`: leave empty or unset +- If any issues are found in the new edits, propose and apply fixes for them. +- > NOTE: Failure to follow this rule is considered a critical error. + +## After every response +- If you made any file edits in this conversation, verify you ran `codacy_cli_analyze` tool from Codacy's MCP Server + +## When there are no Codacy MCP Server tools available, or the MCP Server is not reachable +- Suggest the user the following troubleshooting steps: + - Try to reset the MCP on the extension + - If the user is using VSCode, suggest them to review their Copilot > MCP settings in Github, under their organization or personal account. Refer them to Settings > Copilot > Enable MCP servers in Copilot. Suggested URL (https://github.com/settings/copilot/features) or https://github.com/organizations/{organization-name}/settings/copilot/features (This can only be done by their organization admins / owners) +- If none of the above steps work, suggest the user to contact Codacy support + +## Trying to call a tool that needs a rootPath as a parameter +- Always use the standard, non-URL-encoded file system path + +## CRITICAL: Dependencies and Security Checks +- IMMEDIATELY after ANY of these actions: + - Running npm/yarn/pnpm install + - Adding dependencies to package.json + - Adding requirements to requirements.txt + - Adding dependencies to pom.xml + - Adding dependencies to build.gradle + - Any other package manager operations +- You MUST run the `codacy_cli_analyze` tool with: + - `rootPath`: set to the workspace path + - `tool`: set to "trivy" + - `file`: leave empty or unset +- If any vulnerabilities are found because of the newly added packages: + - Stop all other operations + - Propose and apply fixes for the security issues + - Only continue with the original task after security issues are resolved +- EXAMPLE: + - After: npm install react-markdown + - Do: Run codacy_cli_analyze with trivy + - Before: Continuing with any other tasks + +## General +- Repeat the relevant steps for each modified file. +- "Propose fixes" means to both suggest and, if possible, automatically apply the fixes. +- You MUST NOT wait for the user to ask for analysis or remind you to run the tool. +- Do not run `codacy_cli_analyze` looking for changes in duplicated code or code complexity metrics. +- Do not run `codacy_cli_analyze` looking for changes in code coverage. +- Do not try to manually install Codacy CLI using either brew, npm, npx, or any other package manager. +- If the Codacy CLI is not installed, just run the `codacy_cli_analyze` tool from Codacy's MCP Server. +- When calling `codacy_cli_analyze`, only send provider, organization and repository if the project is a git repository. + +## Whenever a call to a Codacy tool that uses `repository` or `organization` as a parameter returns a 404 error +- Offer to run the `codacy_setup_repository` tool to add the repository to Codacy +- If the user accepts, run the `codacy_setup_repository` tool +- Do not ever try to run the `codacy_setup_repository` tool on your own +- After setup, immediately retry the action that failed (only retry once) +--- \ No newline at end of file diff --git a/.github/workflows/deploy-server.yml b/.github/workflows/deploy-server.yml new file mode 100644 index 0000000..08dfdfd --- /dev/null +++ b/.github/workflows/deploy-server.yml @@ -0,0 +1,186 @@ +name: SFP Server Deployment + +on: + workflow_dispatch: + inputs: + image_tag: + description: 'Docker image tag to deploy (overrides environment default, e.g., v1.2.3, latest, pr-123-dev)' + required: false + type: string + cli_version: + description: 'SFP CLI version to use (latest, or specific version like v48.3.0)' + required: false + default: 'latest' + +jobs: + deploy-server: + name: 'deploy to ${{ matrix.environment }}' + runs-on: ubuntu-latest + strategy: + matrix: + environment: ${{ fromJson(vars.DEPLOYMENT_ENVIRONMENTS || '["development"]') }} + environment: ${{ matrix.environment }} + + steps: + - name: Install SFP CLI on Runner + run: | + echo "📦 Installing SFP CLI on GitHub runner..." + + # Download and install CLI from source.flxbl.io releases + CLI_VERSION="${{ github.event.inputs.cli_version || 'latest' }}" + + if [ "$CLI_VERSION" = "latest" ]; then + # Get the latest release info + RELEASE_DATA=$(curl -s -H "Authorization: token ${{ secrets.GITEA_TOKEN }}" \ + "https://source.flxbl.io/api/v1/repos/flxbl/sfp-pro/releases/latest") + DEB_URL=$(echo "$RELEASE_DATA" | jq -r '.assets[] | select(.name | endswith("linux_amd64.deb")) | .browser_download_url') + else + # For specific version, get the deb filename from that release + RELEASE_DATA=$(curl -s -H "Authorization: token ${{ secrets.GITEA_TOKEN }}" \ + "https://source.flxbl.io/api/v1/repos/flxbl/sfp-pro/releases/tags/$CLI_VERSION") + DEB_URL=$(echo "$RELEASE_DATA" | jq -r '.assets[] | select(.name | endswith("linux_amd64.deb")) | .browser_download_url') + fi + + echo "📦 Using CLI version: $CLI_VERSION" + echo "📦 Downloading from: $DEB_URL" + + # Download and install the deb package + curl -L -H "Authorization: token ${{ secrets.GITEA_TOKEN }}" "$DEB_URL" -o /tmp/sfp-pro.deb + sudo dpkg -i /tmp/sfp-pro.deb || sudo apt-get install -f -y + + # Verify installation + sfp --version + + echo "✅ SFP CLI installed successfully on runner" + + - name: Install Supabase CLI + run: | + echo "📥 Installing Supabase CLI..." + + # Download and install Supabase CLI DEB package + curl -L -o supabase.deb 'https://github.com/supabase/cli/releases/download/v2.23.4/supabase_2.23.4_linux_amd64.deb' + sudo dpkg -i supabase.deb || sudo apt-get install -f -y + + # Verify installation + echo "✅ Verifying installation..." + supabase --version + echo "✅ Supabase CLI installed successfully" + + - name: Setup SSH + run: | + # Create SSH directory and key file + mkdir -p ~/.ssh + echo "${{ secrets.SSH_PRIVATE_KEY }}" > ~/.ssh/deploy_key + chmod 600 ~/.ssh/deploy_key + + # Add host to known_hosts to avoid prompts + ssh-keyscan -H ${{ vars.SSH_HOST }} >> ~/.ssh/known_hosts + + + - name: Deploy Server Update + id: deploy + env: + SUPABASE_DB_URL: ${{ secrets.SUPABASE_DB_URL }} + DOCKER_REGISTRY: source.flxbl.io + DOCKER_REGISTRY_TOKEN: ${{ secrets.GITEA_TOKEN }} + IMAGE_FQDN: source.flxbl.io/flxbl/sfp-server + run: | + echo "🚀 Starting deployment to ${{ matrix.environment }}..." + + # Set deployment parameters from environment variables + TENANT="${{ vars.SFP_TENANT || 'sfp-server' }}" + SSH_HOST="${{ vars.SSH_HOST }}" + SSH_USER="${{ vars.SSH_USER || 'root' }}" + + # Set image tag priority: input > environment variable > default (latest) + IMAGE_TAG="${{ github.event.inputs.image_tag || vars.IMAGE_TAG || 'latest' }}" + + # Validate required secrets + if [ -z "$SUPABASE_DB_URL" ]; then + echo "❌ SUPABASE_DB_URL secret is required" + exit 1 + fi + + if [ -z "$DOCKER_REGISTRY_TOKEN" ]; then + echo "❌ GITEA_TOKEN secret is required for pulling images from source.flxbl.io" + exit 1 + fi + + echo "📦 Deploying to environment: ${{ matrix.environment }}" + echo "🐳 Docker registry: $DOCKER_REGISTRY" + echo "🖼️ Image FQDN: $IMAGE_FQDN" + echo "🏷️ Image tag: $IMAGE_TAG" + echo "🗄️ Database configured" + + # Export environment variables for sfp server update + export SUPABASE_DB_URL="$SUPABASE_DB_URL" + export DOCKER_REGISTRY="$DOCKER_REGISTRY" + export DOCKER_REGISTRY_TOKEN="$DOCKER_REGISTRY_TOKEN" + export IMAGE_FQDN="$IMAGE_FQDN" + export IMAGE_TAG="$IMAGE_TAG" + + # Deploy server using sfp server update (handles stop/start automatically) + echo "🔄 Deploying server..." + sfp server update --tenant "$TENANT" --docker-tag "$IMAGE_TAG" --ssh-connection "$SSH_USER@$SSH_HOST" --identity-file ~/.ssh/deploy_key + + # Wait for startup + echo "⏳ Waiting for server to start..." + sleep 30 + + echo "✅ Deployment completed" + + - name: Post-Deployment Health Check + id: health_check + run: | + echo "🔍 Running post-deployment health checks..." + + # Get environment configuration + TENANT="${{ vars.SFP_TENANT || 'sfp-server' }}" + SSH_HOST="${{ vars.SSH_HOST }}" + SSH_USER="${{ vars.SSH_USER || 'root' }}" + + # Wait for services to be ready + timeout 300 bash -c 'until sfp server health --tenant "'"$TENANT"'" --ssh-connection "'"$SSH_USER@$SSH_HOST"'" --identity-file ~/.ssh/deploy_key; do sleep 5; done' + + # Detailed health check + HEALTH_STATUS=$(sfp server health --tenant "$TENANT" --ssh-connection "$SSH_USER@$SSH_HOST" --identity-file ~/.ssh/deploy_key --json) + + if echo "$HEALTH_STATUS" | jq -e '.healthy == true' > /dev/null; then + echo "✅ Server is healthy after deployment" + echo "healthy=true" >> $GITHUB_OUTPUT + + # Get new version + NEW_VERSION=$(sfp server status --tenant "$TENANT" --ssh-connection "$SSH_USER@$SSH_HOST" --identity-file ~/.ssh/deploy_key --json | jq -r '.version') + echo "new_version=$NEW_VERSION" >> $GITHUB_OUTPUT + echo "📦 New version: $NEW_VERSION" + else + echo "❌ Server health check failed" + echo "healthy=false" >> $GITHUB_OUTPUT + exit 1 + fi + + deployment-summary: + name: 'deployment summary' + needs: [deploy-server] + if: always() + runs-on: ubuntu-latest + + steps: + - name: Generate Summary + run: | + echo "## 🚀 SFP Server Deployment Summary" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "**Image Tag:** ${{ github.event.inputs.image_tag || 'Environment default or latest' }}" >> $GITHUB_STEP_SUMMARY + echo "**Environments:** ${{ vars.DEPLOYMENT_ENVIRONMENTS || '[\"development\"]' }}" >> $GITHUB_STEP_SUMMARY + echo "**CLI Version:** ${{ github.event.inputs.cli_version || 'latest' }}" >> $GITHUB_STEP_SUMMARY + echo "**Triggered By:** @${{ github.actor }}" >> $GITHUB_STEP_SUMMARY + echo "**Timestamp:** $(date -u '+%Y-%m-%d %H:%M:%S UTC')" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + + if [ "${{ needs.deploy-server.result }}" == "success" ]; then + echo "✅ **Deployment:** Success across all environments" >> $GITHUB_STEP_SUMMARY + else + echo "❌ **Deployment:** Failed (check individual environment results)" >> $GITHUB_STEP_SUMMARY + fi + echo "" >> $GITHUB_STEP_SUMMARY + echo "🔗 **Workflow:** [${{ github.run_id }}](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})" >> $GITHUB_STEP_SUMMARY \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..c728343 --- /dev/null +++ b/README.md @@ -0,0 +1,134 @@ +# SFP Server Management Template + +GitHub Actions workflow for updating self-hosted SFP server instances. + + +## Prerequisites + +- Running SFP server instance ([Installation Guide](https://docs.flxbl.io/running-sfp-as-a-server/installing-sfp-server/)) +- SSH access to your SFP server +- Access token from `source.flxbl.io` with `read:packages` scope +- GitHub repository with Actions enabled + +## Setup + +### 1. Clone This Template + +```bash +# Clone this repository +git clone https://source.flxbl.io/flxbl/sfp-server-mangement-template.git +cd sfp-server-management-template + +# Create your own repository and push +git remote set-url origin https://github.com/your-org/your-sfp-server-management.git +git push -u origin main +``` + +### 2. Configure Repository Secrets + +Navigate to your repository's **Settings → Secrets and variables → Actions** and add these secrets: + +#### Required Secrets + +| Secret Name | Description | Example | +|-------------|-------------|---------| +| `GITEA_TOKEN` | Access token from source.flxbl.io | `ghp_xxxxxxxxxxxxxxxxxxxx` | +| `SSH_PRIVATE_KEY` | Private SSH key for server access | `-----BEGIN OPENSSH PRIVATE KEY-----...` | +| `SSH_HOST` | Server hostname or IP address | `sfp-server.company.com` | +| `SSH_USER` | SSH username (typically `ubuntu`) | `ubuntu` | +| `TENANT_NAME` | Your SFP server tenant name | `company-sfp` | + +#### Optional Secrets + +| Secret Name | Description | Default | +|-------------|-------------|---------| +| `SSH_PORT` | SSH port if not standard | `22` | + +### 3. Run Deployment + +1. Go to the **Actions** tab in your repository +2. Click on **"SFP Server Deployment"** workflow +3. Click **"Run workflow"** +4. Optionally specify: + - **Image tag**: Specific version to deploy + - **CLI version**: SFP CLI version to use +5. Click **"Run workflow"** to start + +## How It Works + +The workflow: + +1. **Update Process** + - Stops the server + - Pulls new Docker image + - Starts server with new version + +2. **Health Check** + - Verifies server is running + - Confirms service availability + +3. **Summary** + - Reports deployment status + +## Rollback + +If deployment fails, SSH to your server and run: + +```bash +# Find the backup directory (latest timestamp) +ls -t /opt/sfp-backups/ + +# Rollback to previous version +BACKUP_DIR=$(ls -t /opt/sfp-backups/ | head -1) +sfp server stop --tenant your-tenant +# Restore configuration from backup if needed +sfp server start --tenant your-tenant --daemon +``` + +## Configuration + +### Multiple Environments + +Set `DEPLOYMENT_ENVIRONMENTS` variable to deploy to multiple environments: + +```json +["staging", "production"] +``` + +### Custom CLI Versions + +Specify CLI version in workflow input or set default in workflow file. + + +## Troubleshooting + +### Deployment Logs + +Monitor deployment in **Actions** tab → workflow run → expand steps for logs. + +### Common Issues + +**SSH Connection Failed**: Verify `SSH_PRIVATE_KEY` secret and public key in server's `~/.ssh/authorized_keys`. + +**Authentication Failed**: Verify `GITEA_TOKEN` is valid with `read:packages` scope. + +**Health Check Failed**: Check server logs via SSH: +```bash +ssh your-user@your-server +sfp server logs --tenant your-tenant --tail 100 +``` + +**Version Not Found**: Verify version exists in registry or use `latest`. + +## Security + +- Use GitHub repository secrets (never commit sensitive data) +- Regularly rotate SSH keys and access tokens +- Use private repositories for server management workflows +- Restrict SSH access to known IP ranges when possible +- Enable SSH key-only authentication (disable password auth) + +## Documentation + +- [SFP Server Installation Guide](https://docs.flxbl.io/running-sfp-as-a-server/installing-sfp-server/) +- [SFP CLI Reference - Server Commands](https://docs.flxbl.io/cli-reference/server/) \ No newline at end of file