From 4c3166a8471c5db50ccf889bfeaf045e02384893 Mon Sep 17 00:00:00 2001 From: mignot Date: Mon, 2 Nov 2026 10:59:04 +0100 Subject: [PATCH] chore: clarify SSH target terminology --- .../actions/run-coolify-oneshot/action.yml | 8 ++-- .../actions/trigger-coolify-deploy/action.yml | 12 +++--- .../workflows/set-image-tags-on-server.yml | 4 +- CHANGELOG.md | 10 ++--- README.md | 41 ------------------- 5 files changed, 17 insertions(+), 58 deletions(-) diff --git a/.github/actions/run-coolify-oneshot/action.yml b/.github/actions/run-coolify-oneshot/action.yml index 2040ebf..887a3f6 100644 --- a/.github/actions/run-coolify-oneshot/action.yml +++ b/.github/actions/run-coolify-oneshot/action.yml @@ -61,7 +61,7 @@ runs: COOLIFY_API_TOKEN: ${{ inputs.coolify_api_token }} IMAGE: ${{ inputs.image }} COMMAND: ${{ inputs.command }} - SERVER_HOST: ${{ inputs.server_host }} + SSH_TARGET_HOST: ${{ inputs.server_host }} SERVER_DEPLOY_USERNAME: ${{ inputs.server_deploy_username }} SERVER_DEPLOY_SSH_PRIVATE_KEY: ${{ inputs.server_deploy_ssh_private_key }} TIMEOUT_MINUTES: ${{ inputs.timeout_minutes }} @@ -74,7 +74,7 @@ runs: [ -z "$COOLIFY_API_TOKEN" ] && missing+=(coolify_api_token) [ -z "$IMAGE" ] && missing+=(image) [ -z "$COMMAND" ] && missing+=(command) - [ -z "$SERVER_HOST" ] && missing+=(server_host) + [ -z "$SSH_TARGET_HOST" ] && missing+=(server_host) [ -z "$SERVER_DEPLOY_USERNAME" ] && missing+=(server_deploy_username) [ -z "$SERVER_DEPLOY_SSH_PRIVATE_KEY" ] && missing+=(server_deploy_ssh_private_key) if [ "${#missing[@]}" -gt 0 ]; then @@ -143,13 +143,13 @@ runs: COOLIFY_ENVIRONMENT: ${{ inputs.coolify_environment }} IMAGE: ${{ inputs.image }} COMMAND: ${{ inputs.command }} - SERVER_HOST: ${{ inputs.server_host }} + SSH_TARGET_HOST: ${{ inputs.server_host }} SERVER_DEPLOY_USERNAME: ${{ inputs.server_deploy_username }} TIMEOUT_MINUTES: ${{ inputs.timeout_minutes }} RUN_ID: ${{ github.run_id }}-${{ github.run_attempt }} LOCAL_ENV_FILE: ${{ steps.env.outputs.file }} run: | - target="${SERVER_DEPLOY_USERNAME}@${SERVER_HOST}" + target="${SERVER_DEPLOY_USERNAME}@${SSH_TARGET_HOST}" env_file=$(ssh "$target" 'umask 077; mktemp') trap 'rm -f "$LOCAL_ENV_FILE"; ssh "$target" "rm -f $env_file" || true' EXIT scp -q "$LOCAL_ENV_FILE" "${target}:${env_file}" diff --git a/.github/actions/trigger-coolify-deploy/action.yml b/.github/actions/trigger-coolify-deploy/action.yml index 1010b10..f1b2273 100644 --- a/.github/actions/trigger-coolify-deploy/action.yml +++ b/.github/actions/trigger-coolify-deploy/action.yml @@ -128,12 +128,12 @@ runs: || inputs.server_deploy_username != '' || inputs.server_deploy_ssh_private_key != '' shell: bash env: - SERVER_HOST: ${{ inputs.server_host }} + SSH_TARGET_HOST: ${{ inputs.server_host }} SERVER_DEPLOY_USERNAME: ${{ inputs.server_deploy_username }} SERVER_DEPLOY_SSH_PRIVATE_KEY: ${{ inputs.server_deploy_ssh_private_key }} run: | missing=() - [ -z "$SERVER_HOST" ] && missing+=(server_host) + [ -z "$SSH_TARGET_HOST" ] && missing+=(server_host) [ -z "$SERVER_DEPLOY_USERNAME" ] && missing+=(server_deploy_username) [ -z "$SERVER_DEPLOY_SSH_PRIVATE_KEY" ] && missing+=(server_deploy_ssh_private_key) if [ "${#missing[@]}" -gt 0 ]; then @@ -172,7 +172,7 @@ runs: HEALTH_CHECK_PATH: ${{ inputs.health_check_path }} HEALTH_CHECK_BASE_URL_OVERRIDE: ${{ inputs.health_check_base_url_override }} HEALTH_CHECK_ORIGIN_IP: ${{ inputs.health_check_origin_ip }} - SERVER_HOST: ${{ inputs.server_host }} + SSH_TARGET_HOST: ${{ inputs.server_host }} SERVER_DEPLOY_USERNAME: ${{ inputs.server_deploy_username }} CANCEL_NATIVE_ONLY: ${{ inputs.cancel_native_only }} run: | @@ -192,7 +192,7 @@ runs: # deployment_uuid (see ApplicationDeploymentJob::graceful_shutdown_container). force_stop_build() { echo " Force-stopping in-progress build container $1 via SSH..." - ssh -o StrictHostKeyChecking=accept-new "${SERVER_DEPLOY_USERNAME}@${SERVER_HOST}" \ + ssh -o StrictHostKeyChecking=accept-new "${SERVER_DEPLOY_USERNAME}@${SSH_TARGET_HOST}" \ "docker stop --time 5 $1" \ || echo " WARNING: failed to stop $1 (may have already finished)" } @@ -234,7 +234,7 @@ runs: curl -s -o /dev/null -X POST -H "Authorization: Bearer ${COOLIFY_API_TOKEN}" \ "${COOLIFY_API_URL}/api/v1/deployments/${phantom_uuid}/cancel" || true - # SERVER_HOST/SERVER_DEPLOY_USERNAME presence is already enforced by the + # SSH_TARGET_HOST/SERVER_DEPLOY_USERNAME presence is already enforced by the # "Check required build-kill inputs" step — no fallback here. if [ "$phantom_status" = "in_progress" ]; then force_stop_build "$phantom_uuid" @@ -310,7 +310,7 @@ runs: "${COOLIFY_API_URL}/api/v1/deployments/${stale_uuid}/cancel" \ || echo " WARNING: failed to cancel stale deployment ${stale_uuid}" >&2 if [ "$stale_status" = "in_progress" ]; then - if [ -n "$SERVER_HOST" ]; then + if [ -n "$SSH_TARGET_HOST" ]; then force_stop_build "$stale_uuid" else echo "::warning::Stale build ${stale_uuid} was only marked cancelled — without server_host its build container may still be running (coollabsio/coolify#5850)." diff --git a/.github/workflows/set-image-tags-on-server.yml b/.github/workflows/set-image-tags-on-server.yml index c9586a9..0a11f1d 100644 --- a/.github/workflows/set-image-tags-on-server.yml +++ b/.github/workflows/set-image-tags-on-server.yml @@ -37,12 +37,12 @@ jobs: steps: - name: Check required vars and secrets env: - SERVER_HOST: ${{ vars.DEPLOY_SSH_HOST }} + SSH_TARGET_HOST: ${{ vars.DEPLOY_SSH_HOST }} IMAGE_TAGS_POOL_DIR: ${{ vars.IMAGE_TAGS_POOL_DIR }} SERVER_DEPLOY_USERNAME: ${{ secrets.SERVER_DEPLOY_USERNAME }} SERVER_DEPLOY_SSH_PRIVATE_KEY: ${{ secrets.SERVER_DEPLOY_SSH_PRIVATE_KEY }} run: | - required=(SERVER_HOST IMAGE_TAGS_POOL_DIR SERVER_DEPLOY_USERNAME SERVER_DEPLOY_SSH_PRIVATE_KEY) + required=(SSH_TARGET_HOST IMAGE_TAGS_POOL_DIR SERVER_DEPLOY_USERNAME SERVER_DEPLOY_SSH_PRIVATE_KEY) missing=() for v in "${required[@]}"; do [ -z "${!v}" ] && missing+=("$v") diff --git a/CHANGELOG.md b/CHANGELOG.md index 84f1209..0724f35 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -52,6 +52,11 @@ All contributors (including maintainers) should update `CHANGELOG.md` when creat ## [Unreleased] +### Changed + +- Clarify SSH target naming in deployment actions and remove obsolete workflow documentation. + + ## [5.0.0] - 2026-11-01 @@ -367,7 +372,6 @@ All contributors (including maintainers) should update `CHANGELOG.md` when creat ### Added -- **call-redeployment-webhook** (`workflow_call` / `workflow_dispatch`): Optional input **`hook_id_base`** and optional secret **`redeployment_webhook_secret`**. When **`hook_id_base`** is non-empty after trim, the workflow validates **`SERVER_HOST`**, **`REDEPLOYMENT_WEBHOOK_PORT`**, **`hook_id_base`**, and **`redeployment_webhook_secret`**, then POSTs **`/hooks/-`** with **`X-Secret`** from **`redeployment_webhook_secret`** (same **`Redeployment accepted`** body check). **BehindTheMusicTree/infrastructure** uses this for **The Music Deck admin** staging after **`provision`**, passing **`hook_id_base`** from **`TMD_ADMIN_API_REDEPLOYMENT_HOOK_ID_BASE`**. BTMT callers stay unchanged: omit **`hook_id_base`** (or pass empty) and use **`secrets: inherit`** with **`REDEPLOYMENT_HOOK_ID_BASE`** / **`REDEPLOYMENT_WEBHOOK_SECRET_*`**. Declared **`workflow_call`** secrets: **`REDEPLOYMENT_WEBHOOK_PORT`**, **`REDEPLOYMENT_WEBHOOK_SECRET_PROD`**, **`REDEPLOYMENT_WEBHOOK_SECRET_STAGING`**, **`redeployment_webhook_secret`** (all optional for **`inherit`**; TMD-only callers pass **`REDEPLOYMENT_WEBHOOK_PORT`** + **`redeployment_webhook_secret`** explicitly). ## [0.1.5] - 2026-04-28 @@ -379,13 +383,11 @@ All contributors (including maintainers) should update `CHANGELOG.md` when creat ### Documentation -- **Variable naming**: Replaced the last `VPS_IP` reference in docs/changelog with `SERVER_HOST` for consistent terminology ## [0.1.3] - 2026-04-18 ### Changed -- **call-redeployment-webhook**: Standardized on `SERVER_HOST` variable naming for consistency across workflows ## [0.1.2] - 2026-04-18 @@ -395,9 +397,7 @@ All contributors (including maintainers) should update `CHANGELOG.md` when creat ### Changed -- **Webhook URL construction**: Host IP variable is now named `SERVER_HOST` instead of `VPS_IP`. -- **Webhook and SSH use SERVER_HOST**: call-redeployment-webhook and set-image-tag-on-server now use variable **SERVER_HOST** (instead of DOMAIN_NAME) for the webhook URL host and SSH destination. Use when the main domain points elsewhere (e.g. Vercel). Callers must set **SERVER_HOST** in the environment (repo or org variables). - **Webhook ID**: REDEPLOYMENT_HOOK_ID is no longer a secret but now a var diff --git a/README.md b/README.md index c4e35b7..b7ce8bf 100644 --- a/README.md +++ b/README.md @@ -95,20 +95,6 @@ Writes one pooled stack/env image-tags manifest on the server (atomic `*.new` th Required caller config: `vars.DEPLOY_SSH_HOST`, `vars.IMAGE_TAGS_POOL_DIR` (e.g. `/srv/btmt/image-tags`), `secrets.SERVER_DEPLOY_USERNAME`, `secrets.SERVER_DEPLOY_SSH_PRIVATE_KEY`. -### Sync env to server - -App-agnostic reusable: upload an env fragment into **`ENV_POOL_DIR`** on the server (atomic write). Redeploy (**BehindTheMusicTree/infrastructure**) promotes pool → **`scripts/sync-env/`** via **`promote-sync-env-to-canonical.sh`**; compose generators read canonical sync-env files, not merged keys in **`scripts/.env`**. - -**Workflow file:** `.github/workflows/sync-env-to-server.yml` - -| Input | Required | Description | -| ------------------- | -------- | --------------------------------------------------------------------------------------- | -| `sync_env` | Yes | `prod` or `staging` (lowercase) | -| `app_name` | Yes | App name for fragment path (e.g. `htmt-api`) | -| `fragment_artifact` | Yes | Artifact name and path to fragment file (e.g. `sync-env-fragment-staging/fragment.env`) | - -**Caller must:** (1) Build the fragment in a job (app-specific keys), write it to a file (e.g. `fragment.env`), and upload it with `actions/upload-artifact` using the same artifact name. (2) Have a job that calls this workflow with `needs: build-fragment`, `secrets: inherit`, and inputs `sync_env`, `app_name`, `fragment_artifact`. Required **vars** (repo or environment): `SERVER_HOST`, `ENV_POOL_DIR`, `SYNC_ENV_REMOTE_FILENAME_PREFIX_BASE`, and either `HTMT_API_APP_NAME` or `APP_NAME` (app name for fragment path). Required **secrets**: `SERVER_DEPLOY_USERNAME`, `SERVER_DEPLOY_SSH_PRIVATE_KEY`, plus any vars/secrets for the keys included in the fragment (see workflow: `FRAGMENT_KEYS` and the “Build env fragment” step). Trigger **redeploy** after sync so promoted **`sync-env`** files reach **`compose/*.env`** / compose generation. To support a new app or new keys, add the key to `FRAGMENT_KEYS` and to the Build env fragment step env in this repo. - ### Trigger Coolify Deploy App-agnostic composite action: trigger a Coolify application deploy via API, poll it to a terminal status (`finished`/`failed`/`cancelled-by-user`), and optionally HTTP health-check it before returning. Use this to enforce cross-application deploy ordering (e.g. deploy an API before its dependent web app) instead of relying on Coolify's native, unordered git-push auto-deploy — most useful on single-build-slot Coolify instances where two order-dependent builds triggered independently can otherwise deadlock or race. @@ -310,33 +296,6 @@ This repo only contains workflow definitions. Each repository that **calls** the When **`hook_id_base`** equals **`TMD_ADMIN_API_REDEPLOYMENT_HOOK_ID_BASE`** (repository variable, trimmed), **`X-Secret`** uses **`TMD_ADMIN_API_WEBHOOK_SECRET_PROD`** / **`TMD_ADMIN_API_WEBHOOK_SECRET_STAGING`**. When **`hook_id_base`** equals **`TMD_ADMIN_WEB_REDEPLOYMENT_HOOK_ID_BASE`**, **`X-Secret`** uses **`TMD_ADMIN_WEB_WEBHOOK_SECRET_PROD`** / **`TMD_ADMIN_WEB_WEBHOOK_SECRET_STAGING`**. Any other `hook_id_base` fails fast (no fallback). **`REDEPLOYMENT_WEBHOOK_PORT`** is always required. -### Sync env to server - -Required by **sync-env-to-server** (caller’s environment): - -| Type | Name | Description | -| -------- | -------------------------------------- | -------------------------------------------------------------------------------- | -| Variable | `SERVER_HOST` | VPS IP or hostname for SSH | -| Variable | `ENV_POOL_DIR` | Server pool directory where env fragments are stored (e.g. `/srv/btmt/env-pool`) | -| Variable | `SYNC_ENV_REMOTE_FILENAME_PREFIX_BASE` | Fragment filename prefix (e.g. `sync-env-`) | -| Variable | `HTMT_API_APP_NAME` or `APP_NAME` | App name for fragment path (e.g. `htmt-api`) | -| Secret | `SERVER_DEPLOY_USERNAME` | SSH user | -| Secret | `SERVER_DEPLOY_SSH_PRIVATE_KEY` | SSH private key | - -Plus any vars/secrets for the fragment keys (see workflow; add new keys in the reusable when needed). - -### Deploy workflows - -Required by **deploy-app-env-file**, **deploy-nginx-env-fragment**, and **deploy-docker-compose-part** (caller’s environment must have these): - -| Type | Name | Description | -| -------- | ------------------------------- | -------------------------------------------------------------------------------------------------------------- | -| Variable | `REDEPLOYMENT_ROOT` | Redeployment tree root (e.g. `/var/webhook/redeployment`); pool/compose paths use `{REDEPLOYMENT_ROOT}-{env}/` | -| Variable | `DOCKER_COMPOSE_DIR_NAME` | Compose dir name under redeploy dir | -| Variable | `SERVER_HOST` | VPS IP or hostname for SSH | -| Secret | `SERVER_DEPLOY_USERNAME` | SSH user for deploy | -| Secret | `SERVER_DEPLOY_SSH_PRIVATE_KEY` | SSH private key for deploy | - ## Setup Instructions 1. **Configure secrets and variables** in the repo (or org) that calls the workflows: **Settings** → **Environments** → create or select `staging` / `prod` and add the required entries from [Required Configuration](#required-configuration).