#!/usr/bin/env bash # # TST-25: Linux side of the Windows/x86 Worker CI tier. # # Runs in the `windows-x86` / nightly Gitea jobs on a Linux runner (which always schedules, # unlike a broken Windows act_runner). SSHes to windev (10.100.0.48), where it fetches + # checks out the SHA under test in the isolated CI clone C:\build\mxaccessgw-ci and runs # scripts/ci/windev-worker-ci.ps1 there. The remote exit code propagates through # ssh -> this script -> the CI step, so a Worker regression turns the job red. # # Usage: run-windev-ci.sh # # Environment: # CI_SHA commit to test (default: `git rev-parse HEAD` in this checkout) # WINDEV_SSH_KEY private key (Gitea secret). Store it BASE64-ENCODED (one line): # Gitea's secret masker is line-oriented, so a raw multiline PEM in # the step `env:` echo is NOT redacted and leaks in cleartext, whereas # the single-line base64 is masked to *** (TST-25 acceptance: no key # material in logs). A raw PEM is still accepted for local hand-testing # (auto-detected). If empty, falls back to the runner's default identity. # WINDEV_SSH_KNOWN_HOSTS pinned host keys (Gitea secret). If empty, uses the committed # scripts/ci/windev.known_hosts. # WINDEV_SSH_USER ssh user on windev (default: ci) # WINDEV_SSH_HOST windev host/IP (default: 10.100.0.48) # # The private key is never echoed (written 0600 to a temp file, removed on exit). git on # windev writes progress to stderr, so the remote bootstrap does NOT use -ErrorActionPreference # Stop around git — it checks $LASTEXITCODE instead (known windev gotcha). set -euo pipefail MODE="${1:-}" case "$MODE" in build|test|live) ;; *) echo "usage: $0 " >&2; exit 2 ;; esac SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" CI_SHA="${CI_SHA:-$(git -C "$SCRIPT_DIR" rev-parse HEAD)}" WINDEV_SSH_USER="${WINDEV_SSH_USER:-ci}" WINDEV_SSH_HOST="${WINDEV_SSH_HOST:-10.100.0.48}" REMOTE_CLONE='C:\build\mxaccessgw-ci' REMOTE_SCRIPT='scripts\ci\windev-worker-ci.ps1' # Validate the SHA shape before it reaches a remote shell command. if ! printf '%s' "$CI_SHA" | grep -Eq '^[0-9a-fA-F]{7,40}$'; then echo "run-windev-ci: refusing to run — CI_SHA '$CI_SHA' is not a hex commit id" >&2 exit 2 fi WORK="$(mktemp -d)" cleanup() { rm -rf "$WORK"; } trap cleanup EXIT SSH_OPTS=(-o BatchMode=yes -o StrictHostKeyChecking=yes -o ConnectTimeout=15) # known_hosts: secret if provided, else the committed pins. KNOWN_HOSTS="$WORK/known_hosts" if [ -n "${WINDEV_SSH_KNOWN_HOSTS:-}" ]; then printf '%s\n' "$WINDEV_SSH_KNOWN_HOSTS" > "$KNOWN_HOSTS" else cp "$SCRIPT_DIR/windev.known_hosts" "$KNOWN_HOSTS" fi SSH_OPTS+=(-o "UserKnownHostsFile=$KNOWN_HOSTS") # Private key: secret if provided, else fall back to the default identity/agent. # CI stores it base64-encoded (single line) so Gitea's line-oriented secret masker redacts it # in the step env echo — a raw multiline PEM leaks in cleartext. Decode when it is valid base64 # wrapping a PEM; otherwise treat the value as a raw PEM (local hand-testing convenience). if [ -n "${WINDEV_SSH_KEY:-}" ]; then KEY="$WORK/id_ci" if printf '%s' "$WINDEV_SSH_KEY" | base64 -d 2>/dev/null | grep -q 'PRIVATE KEY'; then ( umask 077; printf '%s' "$WINDEV_SSH_KEY" | base64 -d > "$KEY" ) else ( umask 077; printf '%s\n' "$WINDEV_SSH_KEY" > "$KEY" ) fi SSH_OPTS+=(-o IdentitiesOnly=yes -i "$KEY") fi echo "run-windev-ci: mode=$MODE sha=$CI_SHA target=${WINDEV_SSH_USER}@${WINDEV_SSH_HOST}" # Remote PowerShell bootstrap: fetch + checkout enough to load the versioned CI script, then # hand off to it. Not Stop around git (stderr progress). # # The bootstrap fetch/checkout mutates the shared clone's git index, so it MUST hold the # worktree lock — otherwise two concurrent runs collide on .git/index.lock before either # reaches windev-worker-ci.ps1's lock (the exact race the lock exists to prevent). We take the # same mkdir lock here (atomic; retry to a 20-min deadline) and export MXGW_CI_LOCK_HELD so the # handed-off script re-uses this lock instead of re-acquiring/releasing it. A standalone/manual # run of windev-worker-ci.ps1 (degraded mode) has no such env and self-locks as before. read -r -d '' BOOTSTRAP <