Initial commit: SFP server deployment template
- 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 <noreply@anthropic.com>
This commit is contained in:
65
.github/instructions/codacy.instructions.md
vendored
Normal file
65
.github/instructions/codacy.instructions.md
vendored
Normal file
@@ -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)
|
||||
---
|
186
.github/workflows/deploy-server.yml
vendored
Normal file
186
.github/workflows/deploy-server.yml
vendored
Normal file
@@ -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
|
134
README.md
Normal file
134
README.md
Normal file
@@ -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/)
|
Reference in New Issue
Block a user