Update release_pipeline.yml
This commit is contained in:
148
.github/workflows/release_pipeline.yml
vendored
148
.github/workflows/release_pipeline.yml
vendored
@@ -56,7 +56,6 @@ defaults:
|
||||
run:
|
||||
shell: bash
|
||||
|
||||
# Default permissions are minimized; jobs elevate as needed.
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
@@ -79,7 +78,6 @@ jobs:
|
||||
permissions:
|
||||
contents: read
|
||||
actions: read
|
||||
# Required for permissions check via REST API
|
||||
pull-requests: read
|
||||
|
||||
steps:
|
||||
@@ -203,28 +201,28 @@ jobs:
|
||||
{
|
||||
echo "### Guard report"
|
||||
echo "```json"
|
||||
echo "{"
|
||||
echo " \"repository\": \"${GITHUB_REPOSITORY}\","
|
||||
echo " \"workflow\": \"${GITHUB_WORKFLOW}\","
|
||||
echo " \"job\": \"${GITHUB_JOB}\","
|
||||
echo " \"run_id\": ${GITHUB_RUN_ID},"
|
||||
echo " \"run_number\": ${GITHUB_RUN_NUMBER},"
|
||||
echo " \"run_attempt\": ${GITHUB_RUN_ATTEMPT},"
|
||||
echo " \"run_url\": \"${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}\","
|
||||
echo " \"actor\": \"${GITHUB_ACTOR}\","
|
||||
echo " \"actor_permission\": \"${{ steps.auth.outputs.permission }}\","
|
||||
echo " \"sha\": \"${GITHUB_SHA}\","
|
||||
echo " \"event\": \"${EVENT_NAME}\","
|
||||
echo " \"ref\": \"${REF_NAME}\","
|
||||
echo " \"version\": \"${VERSION}\","
|
||||
echo " \"source_branch\": \"${SOURCE_BRANCH}\","
|
||||
echo " \"target_branch\": \"${TARGET_BRANCH}\","
|
||||
echo " \"promoted_branch\": \"${PROMOTED_BRANCH}\","
|
||||
echo " \"channel\": \"${CHANNEL}\","
|
||||
echo " \"release_mode\": \"${RELEASE_MODE}\","
|
||||
echo " \"override\": \"${OVERRIDE}\","
|
||||
echo " \"today_utc\": \"${TODAY_UTC}\""
|
||||
echo "}"
|
||||
echo "{"
|
||||
echo " \"repository\": \"${GITHUB_REPOSITORY}\","
|
||||
echo " \"workflow\": \"${GITHUB_WORKFLOW}\","
|
||||
echo " \"job\": \"${GITHUB_JOB}\","
|
||||
echo " \"run_id\": ${GITHUB_RUN_ID},"
|
||||
echo " \"run_number\": ${GITHUB_RUN_NUMBER},"
|
||||
echo " \"run_attempt\": ${GITHUB_RUN_ATTEMPT},"
|
||||
echo " \"run_url\": \"${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}\","
|
||||
echo " \"actor\": \"${GITHUB_ACTOR}\","
|
||||
echo " \"actor_permission\": \"${{ steps.auth.outputs.permission }}\","
|
||||
echo " \"sha\": \"${GITHUB_SHA}\","
|
||||
echo " \"event\": \"${EVENT_NAME}\","
|
||||
echo " \"ref\": \"${REF_NAME}\","
|
||||
echo " \"version\": \"${VERSION}\","
|
||||
echo " \"source_branch\": \"${SOURCE_BRANCH}\","
|
||||
echo " \"target_branch\": \"${TARGET_BRANCH}\","
|
||||
echo " \"promoted_branch\": \"${PROMOTED_BRANCH}\","
|
||||
echo " \"channel\": \"${CHANNEL}\","
|
||||
echo " \"release_mode\": \"${RELEASE_MODE}\","
|
||||
echo " \"override\": \"${OVERRIDE}\","
|
||||
echo " \"today_utc\": \"${TODAY_UTC}\""
|
||||
echo "}"
|
||||
echo "```"
|
||||
} >> "${GITHUB_STEP_SUMMARY}"
|
||||
|
||||
@@ -250,7 +248,8 @@ jobs:
|
||||
printf '"sha":"%s",' "${GITHUB_SHA}"
|
||||
printf '"runner_os":"%s",' "${RUNNER_OS}"
|
||||
printf '"runner_name":"%s"' "${RUNNER_NAME}"
|
||||
printf '}\n'
|
||||
printf '}
|
||||
'
|
||||
echo "```"
|
||||
} >> "${GITHUB_STEP_SUMMARY}"
|
||||
|
||||
@@ -348,7 +347,8 @@ jobs:
|
||||
printf '"event":"%s",' "${GITHUB_EVENT_NAME}"
|
||||
printf '"ref_name":"%s",' "${GITHUB_REF_NAME}"
|
||||
printf '"sha":"%s"' "${GITHUB_SHA}"
|
||||
printf '}\n'
|
||||
printf '}
|
||||
'
|
||||
echo "```"
|
||||
} >> "${GITHUB_STEP_SUMMARY}"
|
||||
|
||||
@@ -424,7 +424,8 @@ jobs:
|
||||
{
|
||||
echo "ERROR: Date normalization script not found in approved locations."
|
||||
echo "Approved locations:"
|
||||
printf '%s\n' "${CANDIDATES[@]}"
|
||||
printf '%s
|
||||
' "${CANDIDATES[@]}"
|
||||
echo "Discovered candidates (first 5):"
|
||||
echo "${FOUND:-<none>}"
|
||||
echo "Required action: add scripts/release/update_dates.sh (preferred) to the repo."
|
||||
@@ -506,6 +507,7 @@ jobs:
|
||||
FTP_PORT: ${{ secrets.FTP_PORT }}
|
||||
FTP_PATH_SUFFIX: ${{ vars.FTP_PATH_SUFFIX }}
|
||||
CHANNEL: ${{ needs.guard.outputs.channel }}
|
||||
DEPLOY_DRY_RUN: ${{ vars.DEPLOY_DRY_RUN }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
@@ -513,7 +515,6 @@ jobs:
|
||||
|
||||
[ -n "${FTP_HOST:-}" ] || missing+=("FTP_HOST")
|
||||
[ -n "${FTP_USER:-}" ] || missing+=("FTP_USER")
|
||||
[ -n "${FTP_KEY:-}" ] || missing+=("FTP_KEY")
|
||||
[ -n "${FTP_PATH:-}" ] || missing+=("FTP_PATH")
|
||||
|
||||
proto="${FTP_PROTOCOL:-sftp}"
|
||||
@@ -521,18 +522,23 @@ jobs:
|
||||
missing+=("FTP_PROTOCOL_INVALID")
|
||||
fi
|
||||
|
||||
first_line="$(printf '%s' "${FTP_KEY:-}" | head -n 1 || true)"
|
||||
key_present=false
|
||||
if [ -n "${FTP_KEY:-}" ]; then
|
||||
if printf '%s' "${first_line}" | grep -q '^PuTTY-User-Key-File-'; then
|
||||
key_format="ppk"
|
||||
elif printf '%s' "${first_line}" | grep -q '^-----BEGIN '; then
|
||||
key_format="openssh"
|
||||
else
|
||||
key_format="unknown"
|
||||
missing+=("FTP_KEY_FORMAT")
|
||||
fi
|
||||
else
|
||||
key_format="missing"
|
||||
key_present=true
|
||||
fi
|
||||
|
||||
pw_present=false
|
||||
if [ -n "${FTP_PASSWORD:-}" ]; then
|
||||
pw_present=true
|
||||
fi
|
||||
|
||||
auth_mode="password"
|
||||
if [ "${key_present}" = "true" ]; then
|
||||
auth_mode="key"
|
||||
fi
|
||||
|
||||
if [ "${auth_mode}" = "password" ] && [ "${pw_present}" != "true" ]; then
|
||||
missing+=("FTP_PASSWORD_REQUIRED")
|
||||
fi
|
||||
|
||||
{
|
||||
@@ -542,9 +548,13 @@ jobs:
|
||||
sep=""
|
||||
for m in "${missing[@]}"; do
|
||||
printf '%s"%s"' "${sep}" "${m}"
|
||||
sep=","
|
||||
sep=",";
|
||||
done
|
||||
printf '],"key_format":"%s","channel":"%s"}\n' "${key_format}" "${CHANNEL}"
|
||||
printf '],"channel":"%s","deploy_dry_run":"%s","credential_presence":{"FTP_KEY":"%s","FTP_PASSWORD":"%s"}}
|
||||
' \
|
||||
"${CHANNEL}" "${DEPLOY_DRY_RUN:-false}" \
|
||||
"$( [ "${key_present}" = "true" ] && echo present || echo missing )" \
|
||||
"$( [ "${pw_present}" = "true" ] && echo present || echo missing )"
|
||||
echo "```"
|
||||
} >> "${GITHUB_STEP_SUMMARY}"
|
||||
|
||||
@@ -587,9 +597,10 @@ jobs:
|
||||
sep=""
|
||||
for m in "${missing[@]}"; do
|
||||
printf '%s"%s"' "${sep}" "${m}"
|
||||
sep=","
|
||||
sep=",";
|
||||
done
|
||||
printf ']}\n'
|
||||
printf ']}
|
||||
'
|
||||
echo "```"
|
||||
} >> "${GITHUB_STEP_SUMMARY}"
|
||||
exit 1
|
||||
@@ -621,31 +632,32 @@ jobs:
|
||||
sep=""
|
||||
for s in "${required_scripts[@]}"; do
|
||||
printf '%s"%s"' "${sep}" "${s}"
|
||||
sep=","
|
||||
sep=",";
|
||||
done
|
||||
|
||||
printf '],"optional":['
|
||||
sep=""
|
||||
for s in "${optional_scripts[@]}"; do
|
||||
printf '%s"%s"' "${sep}" "${s}"
|
||||
sep=","
|
||||
sep=",";
|
||||
done
|
||||
|
||||
printf '],"ran":['
|
||||
sep=""
|
||||
for s in "${ran[@]}"; do
|
||||
printf '%s"%s"' "${sep}" "${s}"
|
||||
sep=","
|
||||
sep=",";
|
||||
done
|
||||
|
||||
printf '],"skipped_optional":['
|
||||
sep=""
|
||||
for s in "${skipped[@]}"; do
|
||||
printf '%s"%s"' "${sep}" "${s}"
|
||||
sep=","
|
||||
sep=",";
|
||||
done
|
||||
|
||||
printf ']}\n'
|
||||
printf ']}
|
||||
'
|
||||
echo "```"
|
||||
} >> "${GITHUB_STEP_SUMMARY}"
|
||||
|
||||
@@ -663,7 +675,6 @@ jobs:
|
||||
DIST_DIR="${GITHUB_WORKSPACE}/dist"
|
||||
mkdir -p "${DIST_DIR}"
|
||||
|
||||
# Detect manifest inside src for type naming only.
|
||||
MANIFEST=""
|
||||
if [ -f "src/templateDetails.xml" ]; then
|
||||
MANIFEST="src/templateDetails.xml"
|
||||
@@ -691,7 +702,6 @@ jobs:
|
||||
EXT_TYPE="unknown"
|
||||
fi
|
||||
|
||||
# Policy: archive must include ONLY the src directory tree (no repo root files).
|
||||
ZIP="${REPO_NAME}-${VERSION}-${CHANNEL}-${EXT_TYPE}.zip"
|
||||
|
||||
zip -r -X "${DIST_DIR}/${ZIP}" src \
|
||||
@@ -775,7 +785,6 @@ jobs:
|
||||
REMOTE_PATH="${FTP_PATH%/}/${CHANNEL}"
|
||||
fi
|
||||
|
||||
# Guardrails: remote path safety.
|
||||
if [ -z "${REMOTE_PATH}" ] || [ "${REMOTE_PATH}" = "/" ]; then
|
||||
echo "ERROR: Unsafe REMOTE_PATH resolved (${REMOTE_PATH:-<empty>})" >> "${GITHUB_STEP_SUMMARY}"
|
||||
exit 1
|
||||
@@ -785,18 +794,15 @@ jobs:
|
||||
exit 1
|
||||
fi
|
||||
|
||||
AUTH_MODE=""
|
||||
AUTH_MODE="password"
|
||||
if [ -n "${FTP_KEY:-}" ]; then
|
||||
AUTH_MODE="key"
|
||||
else
|
||||
AUTH_MODE="password"
|
||||
fi
|
||||
|
||||
# Credential precedence: key wins when both are present.
|
||||
PASSWORD_PRESENT="$( [ -n "${FTP_PASSWORD:-}" ] && echo true || echo false )"
|
||||
KEY_PRESENT="$( [ -n "${FTP_KEY:-}" ] && echo true || echo false )"
|
||||
|
||||
if [ "${AUTH_MODE}" = "password" ] && [ -z "${FTP_PASSWORD:-}" ]; then
|
||||
if [ "${AUTH_MODE}" = "password" ] && [ "${PASSWORD_PRESENT}" != "true" ]; then
|
||||
echo "ERROR: FTP_PASSWORD required when FTP_KEY is not provided" >> "${GITHUB_STEP_SUMMARY}"
|
||||
exit 1
|
||||
fi
|
||||
@@ -879,7 +885,6 @@ jobs:
|
||||
|
||||
ZIP_BYTES_LOCAL="$(stat -c%s "${DIST_DIR}/${ZIP}")"
|
||||
|
||||
# Preflight: remote collision detection and directory validation.
|
||||
set +e
|
||||
preflight_log="$(mktemp)"
|
||||
lftp -d -e "\
|
||||
@@ -898,7 +903,12 @@ jobs:
|
||||
set -e
|
||||
|
||||
if [ "${preflight_rc}" -ne 0 ]; then
|
||||
cat "${preflight_log}" >> "${GITHUB_STEP_SUMMARY}" || true
|
||||
{
|
||||
echo "### SFTP preflight log"
|
||||
echo "```"
|
||||
tail -n 400 "${preflight_log}" || true
|
||||
echo "```"
|
||||
} >> "${GITHUB_STEP_SUMMARY}" || true
|
||||
exit "${preflight_rc}"
|
||||
fi
|
||||
|
||||
@@ -920,7 +930,6 @@ jobs:
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Upload + verify with failure classification.
|
||||
set +e
|
||||
upload_log="$(mktemp)"
|
||||
lftp -d -e "\
|
||||
@@ -955,7 +964,6 @@ jobs:
|
||||
fi
|
||||
fi
|
||||
|
||||
# Always attach upload log to summary (bounded by job log limits, but critical for audit).
|
||||
{
|
||||
echo "### SFTP session log"
|
||||
echo "```"
|
||||
@@ -973,14 +981,12 @@ jobs:
|
||||
exit "${rc}"
|
||||
fi
|
||||
|
||||
# Verification: ensure ZIP appears in directory listing.
|
||||
if ! grep -F " ${ZIP}" "${upload_log}" >/dev/null 2>&1; then
|
||||
echo "ERROR: Upload completed but verification failed. ZIP not visible in remote listing." >> "${GITHUB_STEP_SUMMARY}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
ZIP_BYTES_REMOTE="unknown"
|
||||
# Best-effort size extraction from ls -l output (platform dependent).
|
||||
ZIP_BYTES_REMOTE="$(awk -v z="${ZIP}" '$NF==z {print $(NF-4)}' "${upload_log}" | tail -n 1 || true)"
|
||||
if [ -z "${ZIP_BYTES_REMOTE}" ]; then
|
||||
ZIP_BYTES_REMOTE="unknown"
|
||||
@@ -1171,15 +1177,15 @@ jobs:
|
||||
{
|
||||
echo "### Release event telemetry"
|
||||
echo "```json"
|
||||
echo "{"
|
||||
echo " \"repository\": \"${GITHUB_REPOSITORY}\","
|
||||
echo " \"event\": \"${GITHUB_EVENT_NAME}\","
|
||||
echo " \"ref_name\": \"${GITHUB_REF_NAME}\","
|
||||
echo " \"sha\": \"${GITHUB_SHA}\","
|
||||
echo " \"channel\": \"${{ needs.guard.outputs.channel }}\","
|
||||
echo " \"release_mode\": \"${{ needs.guard.outputs.release_mode }}\","
|
||||
echo " \"version\": \"${{ needs.guard.outputs.version }}\""
|
||||
echo "}"
|
||||
echo "{"
|
||||
echo " \"repository\": \"${GITHUB_REPOSITORY}\","
|
||||
echo " \"event\": \"${GITHUB_EVENT_NAME}\","
|
||||
echo " \"ref_name\": \"${GITHUB_REF_NAME}\","
|
||||
echo " \"sha\": \"${GITHUB_SHA}\","
|
||||
echo " \"channel\": \"${{ needs.guard.outputs.channel }}\","
|
||||
echo " \"release_mode\": \"${{ needs.guard.outputs.release_mode }}\","
|
||||
echo " \"version\": \"${{ needs.guard.outputs.version }}\""
|
||||
echo "}"
|
||||
echo "```"
|
||||
} >> "${GITHUB_STEP_SUMMARY}"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user