From cc94d5aeae65eb316760bf8b6b50c4c3913a0240 Mon Sep 17 00:00:00 2001 From: kjh2064 Date: Sun, 12 Jul 2026 00:47:18 +0900 Subject: [PATCH] fix: Eliminate cross-job artifact passing and fix download URL Found via SSH log analysis (actions_log/.../2332.log, Run #2002): 1. This Gitea Actions instance's runner explicitly rejects the actions/upload-artifact@v4 / download-artifact@v4 protocol: "GHESNotSupportedError: @actions/artifact v2.0.0+, upload-artifact@v4+ and download-artifact@v4+ are not currently supported on GHES." The old 3-job split (fetch-release -> pre-deploy-check -> deploy) relied on upload-artifact/download-artifact to hand the .tar.gz from the fetch job to the deploy job, so it could never succeed on this server regardless of any other fix. 2. Independently, the guessed download URL pattern /releases/download/{tag}/{filename} doesn't exist on this Gitea instance -- it silently downloaded a 19-byte "404 page not found" body as if it were the artifact (curl exited 0, file "existed"). Fixes: - Merge fetch-release + pre-deploy-check + deploy into a single `deploy` job so the downloaded artifact never needs to cross a job boundary -- it's downloaded and scp'd from the same runner filesystem in one shot. - Fetch the real `browser_download_url` from the release JSON instead of constructing the URL by convention. - Add a `file "$ARTIFACT" | grep -q "gzip compressed"` guard right after download so a wrong-URL / error-page download fails loudly instead of silently proceeding with garbage bytes. - Update post-deploy-check / post-deploy-report to read from `needs.deploy.outputs.*` now that fetch-release no longer exists as a separate job. --- .gitea/workflows/deploy-prod.yml | 139 ++++++++++--------------------- 1 file changed, 46 insertions(+), 93 deletions(-) diff --git a/.gitea/workflows/deploy-prod.yml b/.gitea/workflows/deploy-prod.yml index 9928c55f..927baca4 100644 --- a/.gitea/workflows/deploy-prod.yml +++ b/.gitea/workflows/deploy-prod.yml @@ -20,17 +20,27 @@ env: REPO: kjh2064/QuantEngineByItz jobs: - fetch-release: - name: Fetch Release Artifact + deploy: + name: Deploy to Production runs-on: ubuntu-latest - timeout-minutes: 10 + timeout-minutes: 30 outputs: release-tag: ${{ steps.fetch.outputs.tag }} artifact-name: ${{ steps.fetch.outputs.artifact }} - artifact-size: ${{ steps.fetch.outputs.size }} commit-hash: ${{ steps.fetch.outputs.commit }} steps: + - name: Verify SSH Key and Secrets + run: | + SSH_KEY_B64="${{ secrets.DEPLOY_SSH_KEY_B64 }}" + SSH_KEY_RAW="${{ secrets.DEPLOY_SSH_KEY }}" + if [ -z "$SSH_KEY_B64" ] && [ -z "$SSH_KEY_RAW" ]; then + echo "ERROR: DEPLOY_SSH_KEY_B64 or DEPLOY_SSH_KEY not configured" + exit 1 + fi + [ -z "${{ secrets.GITEA_TOKEN }}" ] && { echo "ERROR: GITEA_TOKEN not configured"; exit 1; } + echo "✓ SSH key and GITEA_TOKEN configured" + - name: Fetch Release Info id: fetch run: | @@ -39,113 +49,58 @@ jobs: REPO="${{ env.REPO }}" if [ -z "$RELEASE_INPUT" ]; then - # Fetch latest release RELEASE_URL="https://gitea.taxbaik.com/api/v1/repos/$REPO/releases/latest" else - # Fetch specific release RELEASE_URL="https://gitea.taxbaik.com/api/v1/repos/$REPO/releases/tags/$RELEASE_INPUT" fi - RELEASE=$(curl -s -H "Authorization: token $TOKEN" "$RELEASE_URL") + RELEASE=$(curl -sf -H "Authorization: token $TOKEN" "$RELEASE_URL") TAG=$(echo "$RELEASE" | jq -r '.tag_name') COMMIT=$(echo "$RELEASE" | jq -r '.target_commitish' | cut -c1-7) + ARTIFACT=$(echo "$RELEASE" | jq -r '.assets[0].name') + DOWNLOAD_URL=$(echo "$RELEASE" | jq -r '.assets[0].browser_download_url') if [ "$TAG" = "null" ] || [ -z "$TAG" ]; then - echo "ERROR: Release not found" - exit 1 + echo "ERROR: Release not found"; exit 1 fi - - # Find artifact in assets - ARTIFACT=$(echo "$RELEASE" | jq -r '.assets[0].name') - SIZE=$(echo "$RELEASE" | jq -r '.assets[0].size') - if [ "$ARTIFACT" = "null" ] || [ -z "$ARTIFACT" ]; then - echo "ERROR: No artifacts found in release $TAG" - exit 1 + echo "ERROR: No artifacts found in release $TAG"; exit 1 + fi + if [ "$DOWNLOAD_URL" = "null" ] || [ -z "$DOWNLOAD_URL" ]; then + echo "ERROR: No browser_download_url found for asset"; exit 1 fi echo "tag=${TAG}" >> $GITHUB_OUTPUT echo "artifact=${ARTIFACT}" >> $GITHUB_OUTPUT - echo "size=${SIZE}" >> $GITHUB_OUTPUT + echo "download_url=${DOWNLOAD_URL}" >> $GITHUB_OUTPUT echo "commit=${COMMIT}" >> $GITHUB_OUTPUT echo "✓ Release: $TAG" echo "✓ Artifact: $ARTIFACT" - echo "✓ Size: $SIZE bytes" + echo "✓ Download URL: $DOWNLOAD_URL" - name: Download Release Artifact run: | - TAG="${{ steps.fetch.outputs.tag }}" ARTIFACT="${{ steps.fetch.outputs.artifact }}" TOKEN="${{ secrets.GITEA_TOKEN }}" - REPO="${{ env.REPO }}" - - DOWNLOAD_URL="https://gitea.taxbaik.com/api/v1/repos/$REPO/releases/download/$TAG/$ARTIFACT" + DOWNLOAD_URL="${{ steps.fetch.outputs.download_url }}" echo "Downloading: $DOWNLOAD_URL" - curl -L -H "Authorization: token $TOKEN" \ - -o "$ARTIFACT" \ - "$DOWNLOAD_URL" + curl -sfL -H "Authorization: token $TOKEN" -o "$ARTIFACT" "$DOWNLOAD_URL" - if [ ! -f "$ARTIFACT" ]; then - echo "ERROR: Failed to download artifact" + # A 404/error page would still create a small file -- verify it's a + # real gzip archive, not an HTML/JSON error body (this is exactly + # how the old /releases/download/{tag}/{file} guessed URL failed + # silently: curl exited 0 but wrote a 19-byte "404 page not found"). + file "$ARTIFACT" | grep -q "gzip compressed" || { + echo "ERROR: Downloaded file is not a valid gzip archive:" + file "$ARTIFACT" + cat "$ARTIFACT" exit 1 - fi + } echo "✓ Downloaded: $(du -sh $ARTIFACT)" - - name: Upload to Actions - uses: actions/upload-artifact@v4 - with: - name: release-artifact - path: quantengine_*.tar.gz - retention-days: 1 - - pre-deploy-check: - name: Pre-Deployment Verification - runs-on: ubuntu-latest - needs: fetch-release - timeout-minutes: 5 - - steps: - - name: Verify SSH Key - run: | - SSH_KEY_B64="${{ secrets.DEPLOY_SSH_KEY_B64 }}" - SSH_KEY_RAW="${{ secrets.DEPLOY_SSH_KEY }}" - if [ -z "$SSH_KEY_B64" ] && [ -z "$SSH_KEY_RAW" ]; then - echo "ERROR: DEPLOY_SSH_KEY_B64 or DEPLOY_SSH_KEY not configured" - exit 1 - fi - echo "✓ SSH key configured" - - - name: Verify Secrets - run: | - [ -z "${{ secrets.DEPLOY_HOST }}" ] && { echo "ERROR: DEPLOY_HOST not configured"; exit 1; } - [ -z "${{ secrets.DEPLOY_USER }}" ] && { echo "ERROR: DEPLOY_USER not configured"; exit 1; } - echo "✓ All secrets configured" - - - name: Verify Release Artifact - run: | - if [ "${{ needs.fetch-release.outputs.artifact-name }}" = "" ]; then - echo "ERROR: Release artifact not found" - exit 1 - fi - echo "✓ Release: ${{ needs.fetch-release.outputs.release-tag }}" - echo "✓ Artifact: ${{ needs.fetch-release.outputs.artifact-name }}" - echo "✓ Commit: ${{ needs.fetch-release.outputs.commit-hash }}" - - deploy: - name: Deploy to Production - runs-on: ubuntu-latest - needs: [ fetch-release, pre-deploy-check ] - timeout-minutes: 30 - - steps: - - name: Download Release Artifact - uses: actions/download-artifact@v4 - with: - name: release-artifact - - name: Setup SSH run: | mkdir -p ~/.ssh @@ -172,7 +127,7 @@ jobs: - name: Upload Release Artifact run: | - ARTIFACT="${{ needs.fetch-release.outputs.artifact-name }}" + ARTIFACT="${{ steps.fetch.outputs.artifact }}" echo "Uploading: $ARTIFACT" ls -lh "$ARTIFACT" @@ -184,9 +139,9 @@ jobs: - name: Deploy & Verify run: | - ARTIFACT="${{ needs.fetch-release.outputs.artifact-name }}" - RELEASE_TAG="${{ needs.fetch-release.outputs.release-tag }}" - COMMIT="${{ needs.fetch-release.outputs.commit-hash }}" + ARTIFACT="${{ steps.fetch.outputs.artifact }}" + RELEASE_TAG="${{ steps.fetch.outputs.tag }}" + COMMIT="${{ steps.fetch.outputs.commit }}" ssh -i ~/.ssh/deploy_key \ -p ${{ env.DEPLOY_PORT }} \ @@ -245,7 +200,7 @@ jobs: post-deploy-check: name: Health Check & Verification runs-on: ubuntu-latest - needs: [ fetch-release, deploy ] + needs: deploy timeout-minutes: 10 steps: @@ -307,7 +262,7 @@ jobs: fi # Check 5: Release verified - echo "✓ [5/5] Deployment release: ${{ needs.fetch-release.outputs.release-tag }} (commit: ${{ needs.fetch-release.outputs.commit-hash }})" + echo "✓ [5/5] Deployment release: ${{ needs.deploy.outputs.release-tag }} (commit: ${{ needs.deploy.outputs.commit-hash }})" # Check 6: DB connectivity (GET /Account/Login returns 200 even when # the DB password is stale -- the page itself has no DB dependency. @@ -349,15 +304,14 @@ jobs: name: Deployment Report runs-on: ubuntu-latest if: always() - needs: [ fetch-release, deploy, post-deploy-check ] + needs: [ deploy, post-deploy-check ] steps: - name: Report Status run: | - RELEASE="${{ needs.fetch-release.outputs.release-tag }}" - COMMIT="${{ needs.fetch-release.outputs.commit-hash }}" - ARTIFACT="${{ needs.fetch-release.outputs.artifact-name }}" - FETCH_STATUS="${{ needs.fetch-release.result }}" + RELEASE="${{ needs.deploy.outputs.release-tag }}" + COMMIT="${{ needs.deploy.outputs.commit-hash }}" + ARTIFACT="${{ needs.deploy.outputs.artifact-name }}" DEPLOY_STATUS="${{ needs.deploy.result }}" CHECK_STATUS="${{ needs.post-deploy-check.result }}" @@ -370,12 +324,11 @@ jobs: echo "Artifact: $ARTIFACT" echo "" echo "【 Status 】" - echo "Fetch: $([ "$FETCH_STATUS" = "success" ] && echo "✓" || echo "✗") $FETCH_STATUS" echo "Deploy: $([ "$DEPLOY_STATUS" = "success" ] && echo "✓" || echo "✗") $DEPLOY_STATUS" echo "Health: $([ "$CHECK_STATUS" = "success" ] && echo "✓" || echo "✗") $CHECK_STATUS" echo "" - if [ "$FETCH_STATUS" = "success" ] && [ "$DEPLOY_STATUS" = "success" ] && [ "$CHECK_STATUS" = "success" ]; then + if [ "$DEPLOY_STATUS" = "success" ] && [ "$CHECK_STATUS" = "success" ]; then echo "✅ Deployment Successful" echo "Server: 178.104.200.7" echo "Release: $RELEASE"