From 772c06c205365a7220752b5833e991ae6472ee19 Mon Sep 17 00:00:00 2001 From: linmeng <819991304@qq.com> Date: Thu, 30 Jul 2026 11:11:58 +0800 Subject: [PATCH] fix: use deploy-owned staging temp paths Create staging mutation payloads in randomized deploy-owned temporary directories so migration and deployment do not require writes under the protected application root. --- .gitea/workflows/deploy-staging.yml | 3 ++- .gitea/workflows/migrate-staging-database.yml | 3 ++- deploy/run-staging-deploy.sh | 2 +- deploy/run-staging-migration.sh | 2 +- frontend/tests/staging-backend-workflows.test.ts | 8 ++++++-- 5 files changed, 12 insertions(+), 6 deletions(-) diff --git a/.gitea/workflows/deploy-staging.yml b/.gitea/workflows/deploy-staging.yml index c2e66d02..a2ccf161 100644 --- a/.gitea/workflows/deploy-staging.yml +++ b/.gitea/workflows/deploy-staging.yml @@ -83,13 +83,14 @@ jobs: ssh_root="${RUNNER_TEMP}/staging-ssh" key_path="$ssh_root/id_ed25519" known_hosts_path="$ssh_root/known_hosts" - incoming="$DEPLOY_PATH/.incoming/${GITEA_RUN_ID:?}-${GITEA_RUN_ATTEMPT:-1}" install -m 700 -d "$ssh_root" printf '%s\n' "$SSH_PRIVATE_KEY" | tr -d '\r' > "$key_path" printf '%s\n' "$STAGING_KNOWN_HOSTS" | tr -d '\r' > "$known_hosts_path" chmod 600 "$key_path" "$known_hosts_path" ssh_options=(-i "$key_path" -p "$DEPLOY_PORT" -o BatchMode=yes -o IdentitiesOnly=yes -o StrictHostKeyChecking=yes -o "UserKnownHostsFile=$known_hosts_path") remote="$DEPLOY_USER@$DEPLOY_HOST" + incoming="$(ssh "${ssh_options[@]}" "$remote" "mktemp -d /tmp/jyotisha-staging.XXXXXXXXXX")" + [[ "$incoming" == /tmp/jyotisha-staging.* ]] cleanup() { ssh "${ssh_options[@]}" "$remote" "DOCKER_CONFIG='$incoming/.docker' docker logout '$REGISTRY_HOST' >/dev/null 2>&1 || true; rm -rf -- '$incoming'" >/dev/null 2>&1 || true; docker logout "$REGISTRY_HOST" >/dev/null 2>&1 || true; rm -rf -- "$ssh_root"; } trap cleanup EXIT ssh "${ssh_options[@]}" "$remote" "install -d -m 700 '$incoming/.docker'" diff --git a/.gitea/workflows/migrate-staging-database.yml b/.gitea/workflows/migrate-staging-database.yml index c9188dfb..1be31b1a 100644 --- a/.gitea/workflows/migrate-staging-database.yml +++ b/.gitea/workflows/migrate-staging-database.yml @@ -69,13 +69,14 @@ jobs: ssh_root="${RUNNER_TEMP}/staging-migration-ssh" key_path="$ssh_root/id_ed25519" known_hosts_path="$ssh_root/known_hosts" - incoming="$DEPLOY_PATH/.incoming/${GITEA_RUN_ID:?}-${GITEA_RUN_ATTEMPT:-1}" install -m 700 -d "$ssh_root" printf '%s\n' "$SSH_PRIVATE_KEY" | tr -d '\r' > "$key_path" printf '%s\n' "$STAGING_KNOWN_HOSTS" | tr -d '\r' > "$known_hosts_path" chmod 600 "$key_path" "$known_hosts_path" ssh_options=(-i "$key_path" -p "$DEPLOY_PORT" -o BatchMode=yes -o IdentitiesOnly=yes -o StrictHostKeyChecking=yes -o "UserKnownHostsFile=$known_hosts_path") remote="$DEPLOY_USER@$DEPLOY_HOST" + incoming="$(ssh "${ssh_options[@]}" "$remote" "mktemp -d /tmp/jyotisha-staging.XXXXXXXXXX")" + [[ "$incoming" == /tmp/jyotisha-staging.* ]] cleanup() { ssh "${ssh_options[@]}" "$remote" "DOCKER_CONFIG='$incoming/.docker' docker logout '$REGISTRY_HOST' >/dev/null 2>&1 || true; rm -rf -- '$incoming'" >/dev/null 2>&1 || true; docker logout "$REGISTRY_HOST" >/dev/null 2>&1 || true; rm -rf -- "$ssh_root"; } trap cleanup EXIT ssh "${ssh_options[@]}" "$remote" "install -d -m 700 '$incoming/.docker'" diff --git a/deploy/run-staging-deploy.sh b/deploy/run-staging-deploy.sh index 3b95cb54..f361fabc 100755 --- a/deploy/run-staging-deploy.sh +++ b/deploy/run-staging-deploy.sh @@ -29,7 +29,7 @@ if [ "$ALLOW_ROLLBACK" != "true" ] && [ "$ALLOW_ROLLBACK" != "false" ]; then exit 1 fi case "$INCOMING_PATH" in - "$DEPLOY_PATH"/.incoming/*) ;; + /tmp/jyotisha-staging.*) ;; *) echo "unsafe incoming staging path" >&2; exit 1 ;; esac diff --git a/deploy/run-staging-migration.sh b/deploy/run-staging-migration.sh index 9b342251..0501d3a5 100755 --- a/deploy/run-staging-migration.sh +++ b/deploy/run-staging-migration.sh @@ -23,7 +23,7 @@ image_pattern='^crpi-d1feco6itet73spp\.cn-hongkong\.personal\.cr\.aliyuncs\.com/ exit 1 } case "$INCOMING_PATH" in - "$DEPLOY_PATH"/.incoming/*) ;; + /tmp/jyotisha-staging.*) ;; *) echo "unsafe incoming staging path" >&2; exit 1 ;; esac diff --git a/frontend/tests/staging-backend-workflows.test.ts b/frontend/tests/staging-backend-workflows.test.ts index 4eab8e3b..423e4db3 100644 --- a/frontend/tests/staging-backend-workflows.test.ts +++ b/frontend/tests/staging-backend-workflows.test.ts @@ -220,11 +220,15 @@ test("Gitea staging digest resolution selects linux amd64 from manifest arrays", } }); -test("Gitea staging mutations use available run identifiers", () => { +test("Gitea staging mutations use deploy-owned temporary paths", () => { for (const workflow of [read(giteaDeployWorkflow), read(giteaMigrationWorkflow)]) { - assert.match(workflow, /\$\{GITEA_RUN_ID:\?\}-\$\{GITEA_RUN_ATTEMPT:-1\}/); + assert.match(workflow, /mktemp -d \/tmp\/jyotisha-staging\.XXXXXXXXXX/); + assert.match(workflow, /\[\[ "\$incoming" == \/tmp\/jyotisha-staging\.\* \]\]/); assert.doesNotMatch(workflow, /GITEA_RUN_NUMBER/); } + for (const script of [read(deployScript), read(migrationScript)]) { + assert.match(script, /\/tmp\/jyotisha-staging\.\*\) ;;/); + } }); test("staging mutations retain every pending deployment and migration", () => {