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.
This commit is contained in:
2026-07-12 00:47:18 +09:00
parent 6e9a9aa41b
commit cc94d5aeae
+46 -93
View File
@@ -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"