11#! /bin/bash
22set -eo pipefail
33
4+ # Prevent git from prompting for passwords interactively (no TTY in containers)
5+ export GIT_TERMINAL_PROMPT=0
6+
47# Track error context for the cleanup trap
58ERROR_MESSAGE=" "
69ARTIFACTS=()
10+ PUSH_FAILED=" "
711
812# Report job result back to the backend.
913# TODO: Incorporate CALLBACK_TOKEN for request signing (HMAC-SHA256).
@@ -33,6 +37,31 @@ report_result() {
3337 cd /app && " ${cmd[@]} " || echo " WARNING: Failed to report result to backend"
3438}
3539
40+ # Strip git tokens from files before committing to prevent secret leaks.
41+ # The x2a tool may embed SOURCE_REPO_TOKEN in generated files (e.g., Policyfile.lock.json)
42+ # when Chef resolves cookbook sources using authenticated URLs.
43+ sanitize_secrets () {
44+ local dir=" $1 "
45+ echo " === Sanitizing secrets from output files ==="
46+
47+ # Match GitHub PATs (ghp_, gho_, github_pat_) and generic token@host patterns in URLs
48+ local count=0
49+ while IFS= read -r -d ' ' file; do
50+ if grep -qE ' https?://[^@/:[:space:]]+@' " $file " 2> /dev/null; then
51+ # Strip token from URLs: https://ghp_xxx@github.com/... → https://github.com/...
52+ sed -i ' s|https\?://[^@/:[:space:]]*@|https://|g' " $file "
53+ echo " Sanitized: ${file#/ workspace/ target/ } "
54+ count=$(( count + 1 ))
55+ fi
56+ done < <( find " $dir " -type f \( -name ' *.json' -o -name ' *.yaml' -o -name ' *.yml' -o -name ' *.lock' \) -print0 2> /dev/null)
57+
58+ if [ " $count " -eq 0 ]; then
59+ echo " No secrets found in output files"
60+ else
61+ echo " Sanitized ${count} file(s)"
62+ fi
63+ }
64+
3665# Cleanup trap: fires on every exit (success or failure).
3766# Guarantees exactly one report_result call regardless of how the script ends.
3867cleanup () {
@@ -42,6 +71,10 @@ cleanup() {
4271 # Always try to commit and push whatever is in the working directory
4372 if [ -d /workspace/target/.git ]; then
4473 cd /workspace/target
74+
75+ # Sanitize secrets from output files before committing
76+ sanitize_secrets " ${PROJECT_PATH:-/ workspace/ target} "
77+
4578 git add " ${PROJECT_DIR:- ${PROJECT_ID} .${PROJECT_ABBREV} } " 2> /dev/null || git add -A || true
4679 git commit -m " x2a: ${PHASE} phase for ${MODULE_NAME:- project}
4780
@@ -53,11 +86,16 @@ Job: ${JOB_ID}
5386Co-Authored-By: ${GIT_AUTHOR_NAME} <${GIT_AUTHOR_EMAIL} >
5487" || true
5588 git pull --rebase origin " ${TARGET_REPO_BRANCH} " 2> /dev/null || true
56- git push origin " ${TARGET_REPO_BRANCH} " || true
89+ if ! git push origin " ${TARGET_REPO_BRANCH} " ; then
90+ PUSH_FAILED=" Failed to push to ${TARGET_REPO_URL} branch ${TARGET_REPO_BRANCH} "
91+ echo " ERROR: ${PUSH_FAILED} "
92+ fi
5793 fi
5894
5995 if [ ${exit_code} -ne 0 ]; then
6096 report_result " error" " ${ERROR_MESSAGE:- Script failed with exit code ${exit_code} } "
97+ elif [ -n " ${PUSH_FAILED} " ]; then
98+ report_result " error" " ${PUSH_FAILED} "
6199 else
62100 report_result " success" " "
63101 fi
@@ -73,21 +111,18 @@ git_clone_repos() {
73111 echo " === Cloning target repository ==="
74112 local target_auth_url=" https://${TARGET_REPO_TOKEN} @${TARGET_REPO_URL# https:// } "
75113
76- if git ls-remote " ${target_auth_url} " & > /dev/null; then
77- if git ls-remote --exit-code --heads " ${target_auth_url} " " ${TARGET_REPO_BRANCH} " & > /dev/null; then
78- # Repo exists, branch exists — clone normally
79- ERROR_MESSAGE=" Failed to clone target repository from ${TARGET_REPO_URL} "
80- git clone --depth=1 --single-branch --branch=" ${TARGET_REPO_BRANCH} " \
81- " ${target_auth_url} " /workspace/target
82- else
83- # Repo exists, branch doesn't — clone default branch, create target branch locally
84- echo " Branch '${TARGET_REPO_BRANCH} ' not found on remote, creating it"
85- ERROR_MESSAGE=" Failed to clone target repository from ${TARGET_REPO_URL} "
86- git clone --depth=1 " ${target_auth_url} " /workspace/target
87- cd /workspace/target
88- git checkout -b " ${TARGET_REPO_BRANCH} "
89- fi
114+ ERROR_MESSAGE=" Failed to clone target repository from ${TARGET_REPO_URL} "
115+ if git clone --depth=1 --single-branch --branch=" ${TARGET_REPO_BRANCH} " \
116+ " ${target_auth_url} " /workspace/target 2> /dev/null; then
117+ # Repo and branch exist — cloned successfully
118+ :
119+ elif git clone --depth=1 " ${target_auth_url} " /workspace/target 2> /dev/null; then
120+ # Repo exists but branch doesn't — create target branch locally
121+ echo " Branch '${TARGET_REPO_BRANCH} ' not found on remote, creating it"
122+ cd /workspace/target
123+ git checkout -b " ${TARGET_REPO_BRANCH} "
90124 else
125+ # Repo doesn't exist or can't be accessed — init empty
91126 echo " Target repo doesn't exist, initializing empty repo"
92127 mkdir -p /workspace/target
93128 cd /workspace/target
@@ -216,13 +251,13 @@ case "${PHASE}" in
216251
217252 # Copy migration-plan.md from target repo to source dir
218253 # The x2a tool does os.chdir(source_dir) and reads migration-plan.md from there
219- if [ ! -f " ${SOURCE_BASE} / ${PROJECT_DIR } /migration-plan.md" ]; then
220- ERROR_MESSAGE=" migration-plan.md not found in ${SOURCE_BASE} / ${PROJECT_DIR } / - init phase must be run first"
254+ if [ ! -f " ${PROJECT_PATH } /migration-plan.md" ]; then
255+ ERROR_MESSAGE=" migration-plan.md not found in ${PROJECT_PATH } / - init phase must be run first"
221256 exit 1
222257 fi
223258
224- echo " Copying migration-plan.md from source project directory to source root..."
225- cp -v " ${SOURCE_BASE} / ${PROJECT_DIR } /migration-plan.md" " ${SOURCE_BASE} /migration-plan.md"
259+ echo " Copying migration-plan.md from target project directory to source root..."
260+ cp -v " ${PROJECT_PATH } /migration-plan.md" " ${SOURCE_BASE} /migration-plan.md"
226261
227262 # Check if x2a tool is available (required)
228263 if [ ! -d /app ] || [ ! -f /app/app.py ]; then
0 commit comments