mirror of
https://github.com/we-promise/sure.git
synced 2026-06-04 10:19:03 +00:00
ci(preview): fix Cloudflare registry image deployment (#2124)
* ci(preview): fix Cloudflare registry image deployment Keep the preview workflow's secret-bearing deploy path on trusted tooling while rewriting Wrangler config through registry-shaped image refs for push and deploy. Centralize preview log redaction and extend resolver/security guard coverage for artifact identity conflicts. * ci(preview): keep failure diagnostics resilient * ci(preview): redact private key diagnostics
This commit is contained in:
141
.github/workflows/preview-deploy.yml
vendored
141
.github/workflows/preview-deploy.yml
vendored
@@ -25,6 +25,7 @@ jobs:
|
||||
head_sha: ${{ steps.preview.outputs.head_sha }}
|
||||
is_fork: ${{ steps.preview.outputs.is_fork }}
|
||||
pr_number: ${{ steps.preview.outputs.pr_number }}
|
||||
resolution_source: ${{ steps.preview.outputs.resolution_source }}
|
||||
should_deploy: ${{ steps.preview.outputs.should_deploy }}
|
||||
|
||||
steps:
|
||||
@@ -105,6 +106,7 @@ jobs:
|
||||
HEAD_SHA: ${{ needs.preview-gate.outputs.head_sha }}
|
||||
IS_FORK: ${{ needs.preview-gate.outputs.is_fork }}
|
||||
PR_NUMBER: ${{ needs.preview-gate.outputs.pr_number }}
|
||||
RESOLUTION_SOURCE: ${{ needs.preview-gate.outputs.resolution_source }}
|
||||
|
||||
steps:
|
||||
- name: Checkout trusted preview tooling
|
||||
@@ -202,6 +204,9 @@ jobs:
|
||||
cp trusted/workers/preview/tsconfig.json "$preview_dir/tsconfig.json"
|
||||
cp trusted/workers/preview/wrangler.toml "$preview_dir/wrangler.toml"
|
||||
cp -R trusted/workers/preview/src "$preview_dir/src"
|
||||
mkdir -p "$preview_dir/deploy"
|
||||
cp trusted/workers/preview/deploy/redact_preview_log.sh "$preview_dir/deploy/redact_preview_log.sh"
|
||||
chmod 0755 "$preview_dir/deploy/redact_preview_log.sh"
|
||||
|
||||
diagnostics_nonce="$(openssl rand -hex 32)"
|
||||
sed -i "s/\${PR_NUMBER}/${PR_NUMBER}/g" "$preview_dir/wrangler.toml"
|
||||
@@ -245,32 +250,54 @@ jobs:
|
||||
cd "$RUNNER_TEMP/sure-preview-worker"
|
||||
config_path="$RUNNER_TEMP/sure-preview-worker/wrangler.toml"
|
||||
image_tag="sure-preview-pr-${PR_NUMBER}:${HEAD_SHA}"
|
||||
temporary_image_ref="registry.cloudflare.com/${CLOUDFLARE_ACCOUNT_ID}/${image_tag}"
|
||||
push_log="$RUNNER_TEMP/wrangler-containers-push.log"
|
||||
clean_log="$RUNNER_TEMP/wrangler-containers-push.clean.log"
|
||||
push_status=0
|
||||
|
||||
# wrangler containers push validates wrangler.toml, so point the trusted
|
||||
# config at the loaded CI image before replacing it with the registry ref.
|
||||
LOCAL_IMAGE_TAG="$image_tag" node - "$config_path" <<'NODE'
|
||||
# config at a registry-shaped ref while it pushes the verified local image.
|
||||
TEMPORARY_IMAGE_REF="$temporary_image_ref" node - "$config_path" <<'NODE'
|
||||
const fs = require('node:fs');
|
||||
|
||||
const configPath = process.argv[2];
|
||||
const imageTag = process.env.LOCAL_IMAGE_TAG;
|
||||
const imageRef = process.env.TEMPORARY_IMAGE_REF;
|
||||
|
||||
if (!/^sure-preview-pr-[1-9][0-9]*:[a-f0-9]{40}$/.test(imageTag || '')) {
|
||||
throw new Error('Expected local preview image tag for wrangler containers push');
|
||||
if (!/^registry\.cloudflare\.com\/[A-Za-z0-9_-]+\/sure-preview-pr-[1-9][0-9]*:[a-f0-9]{40}$/.test(imageRef || '')) {
|
||||
throw new Error('Expected registry-shaped preview image ref before wrangler containers push');
|
||||
}
|
||||
|
||||
const original = fs.readFileSync(configPath, 'utf8');
|
||||
const updated = original.replace(/image = "[^"]+"/, `image = ${JSON.stringify(imageTag)}`);
|
||||
const updated = original.replace(/image = "[^"]+"/, `image = ${JSON.stringify(imageRef)}`);
|
||||
if (updated === original) {
|
||||
throw new Error('Expected wrangler.toml to contain an image entry to rewrite before push');
|
||||
}
|
||||
fs.writeFileSync(configPath, updated);
|
||||
NODE
|
||||
|
||||
./node_modules/.bin/wrangler containers push "$image_tag" 2>&1 | tee "$push_log"
|
||||
set +e
|
||||
./node_modules/.bin/wrangler containers push "$image_tag" 2>&1 | tee "$push_log" | ./deploy/redact_preview_log.sh
|
||||
push_status=${PIPESTATUS[0]}
|
||||
set -e
|
||||
perl -pe 's/\e\[[0-9;]*[A-Za-z]//g' "$push_log" > "$clean_log"
|
||||
image_ref=$(grep -Eo 'registry\.cloudflare\.com/[^[:space:]]+' "$clean_log" | tail -n 1 | tr -d '\r')
|
||||
|
||||
if [ "$push_status" -ne 0 ]; then
|
||||
exit "$push_status"
|
||||
fi
|
||||
|
||||
image_ref="$(node - "$clean_log" <<'NODE'
|
||||
const fs = require('node:fs');
|
||||
|
||||
const logPath = process.argv[2];
|
||||
const log = fs.readFileSync(logPath, 'utf8');
|
||||
const expectedSuffix = `sure-preview-pr-${process.env.PR_NUMBER}:${process.env.HEAD_SHA}`;
|
||||
const pattern = /registry\.cloudflare\.com\/[A-Za-z0-9_-]+\/sure-preview-pr-[1-9][0-9]*:[a-f0-9]{40}/g;
|
||||
const matches = [...log.matchAll(pattern)].map((match) => match[0]);
|
||||
const imageRef = matches.findLast((candidate) => candidate.endsWith(`/${expectedSuffix}`));
|
||||
|
||||
if (imageRef) process.stdout.write(imageRef);
|
||||
NODE
|
||||
)"
|
||||
|
||||
if [ -z "$image_ref" ]; then
|
||||
echo "Could not find Cloudflare registry image reference in wrangler output" >&2
|
||||
@@ -292,11 +319,16 @@ jobs:
|
||||
|
||||
const configPath = process.argv[2];
|
||||
const imageRef = process.env.IMAGE_REF;
|
||||
const expectedSuffix = `sure-preview-pr-${process.env.PR_NUMBER}:${process.env.HEAD_SHA}`;
|
||||
|
||||
if (!imageRef || !imageRef.startsWith('registry.cloudflare.com/')) {
|
||||
if (!/^registry\.cloudflare\.com\/[A-Za-z0-9_-]+\/sure-preview-pr-[1-9][0-9]*:[a-f0-9]{40}$/.test(imageRef || '')) {
|
||||
throw new Error('Expected a Cloudflare registry image reference');
|
||||
}
|
||||
|
||||
if (!imageRef.endsWith(`/${expectedSuffix}`)) {
|
||||
throw new Error('Cloudflare registry image reference does not match this preview artifact');
|
||||
}
|
||||
|
||||
const original = fs.readFileSync(configPath, 'utf8');
|
||||
const updated = original.replace(/image = "[^"]+"/, `image = ${JSON.stringify(imageRef)}`);
|
||||
if (updated === original) {
|
||||
@@ -305,7 +337,10 @@ jobs:
|
||||
fs.writeFileSync(configPath, updated);
|
||||
NODE
|
||||
|
||||
cat "$config_path"
|
||||
# Print a redacted copy for logs without mutating the config used by deploy.
|
||||
redacted_config="$RUNNER_TEMP/wrangler-redacted.toml"
|
||||
"$RUNNER_TEMP/sure-preview-worker/deploy/redact_preview_log.sh" < "$config_path" > "$redacted_config"
|
||||
cat "$redacted_config"
|
||||
|
||||
- name: Deploy to Cloudflare Containers
|
||||
id: deploy
|
||||
@@ -321,7 +356,11 @@ jobs:
|
||||
clean_deploy_log="$RUNNER_TEMP/wrangler-deploy.clean.log"
|
||||
|
||||
deploy_once() {
|
||||
./node_modules/.bin/wrangler deploy --config wrangler.toml --var "PR_NUMBER:${PR_NUMBER}" 2>&1 | tee "$deploy_log"
|
||||
set +e
|
||||
./node_modules/.bin/wrangler deploy --config wrangler.toml --var "PR_NUMBER:${PR_NUMBER}" 2>&1 | tee "$deploy_log" | ./deploy/redact_preview_log.sh
|
||||
local deploy_status=${PIPESTATUS[0]}
|
||||
set -e
|
||||
return "$deploy_status"
|
||||
}
|
||||
|
||||
if ! deploy_once; then
|
||||
@@ -406,12 +445,90 @@ jobs:
|
||||
if-no-files-found: error
|
||||
retention-days: 3
|
||||
|
||||
- name: Collect preview failure diagnostics
|
||||
if: failure()
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
diagnostics_dir="$RUNNER_TEMP/preview-failure-diagnostics"
|
||||
manifest_file="$RUNNER_TEMP/preview-image/sure-preview-image.manifest.json"
|
||||
redaction_helper="$RUNNER_TEMP/sure-preview-worker/deploy/redact_preview_log.sh"
|
||||
mkdir -p "$diagnostics_dir"
|
||||
|
||||
jq -n \
|
||||
--arg artifactName "$ARTIFACT_NAME" \
|
||||
--arg headSha "$HEAD_SHA" \
|
||||
--arg isFork "$IS_FORK" \
|
||||
--arg prNumber "$PR_NUMBER" \
|
||||
--arg resolutionSource "$RESOLUTION_SOURCE" \
|
||||
'{
|
||||
artifactName: $artifactName,
|
||||
headSha: $headSha,
|
||||
isFork: $isFork,
|
||||
prNumber: $prNumber,
|
||||
resolutionSource: $resolutionSource
|
||||
}' > "$diagnostics_dir/preview-request.json"
|
||||
|
||||
sanitize_copy() {
|
||||
local source="$1"
|
||||
local destination="$2"
|
||||
if [ -f "$source" ]; then
|
||||
if [ -x "$redaction_helper" ]; then
|
||||
"$redaction_helper" < "$source" > "$destination"
|
||||
else
|
||||
cp "$source" "$destination"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
if [ -f "$manifest_file" ]; then
|
||||
jq '{
|
||||
artifactVersion,
|
||||
archivePath,
|
||||
archiveSha256,
|
||||
headSha,
|
||||
imageId,
|
||||
imageTag,
|
||||
prNumber
|
||||
}' "$manifest_file" > "$diagnostics_dir/preview-image-manifest.json"
|
||||
fi
|
||||
|
||||
sanitize_copy "$RUNNER_TEMP/sure-preview-worker/wrangler.toml" "$diagnostics_dir/wrangler.toml"
|
||||
sanitize_copy "$RUNNER_TEMP/wrangler-containers-push.clean.log" "$diagnostics_dir/wrangler-containers-push.log"
|
||||
if [ -f "$RUNNER_TEMP/wrangler-deploy.clean.log" ]; then
|
||||
sanitize_copy "$RUNNER_TEMP/wrangler-deploy.clean.log" "$diagnostics_dir/wrangler-deploy.log"
|
||||
else
|
||||
sanitize_copy "$RUNNER_TEMP/wrangler-deploy.log" "$diagnostics_dir/wrangler-deploy.log"
|
||||
fi
|
||||
|
||||
find "$diagnostics_dir" -maxdepth 1 -type f -print
|
||||
|
||||
- name: Upload preview failure diagnostics
|
||||
if: failure()
|
||||
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6
|
||||
with:
|
||||
name: preview-failure-diagnostics-pr-${{ env.PR_NUMBER }}-${{ env.HEAD_SHA }}
|
||||
path: ${{ runner.temp }}/preview-failure-diagnostics
|
||||
if-no-files-found: error
|
||||
retention-days: 3
|
||||
|
||||
- name: Prepare cleanup metadata
|
||||
if: success()
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
metadata_dir="$RUNNER_TEMP/preview-cleanup-metadata"
|
||||
mkdir -p "$metadata_dir"
|
||||
"$RUNNER_TEMP/sure-preview-worker/deploy/redact_preview_log.sh" \
|
||||
< "$RUNNER_TEMP/sure-preview-worker/wrangler.toml" \
|
||||
> "$metadata_dir/wrangler.toml"
|
||||
|
||||
- name: Store cleanup metadata
|
||||
if: success()
|
||||
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6
|
||||
with:
|
||||
name: preview-cleanup-pr-${{ env.PR_NUMBER }}
|
||||
path: ${{ runner.temp }}/sure-preview-worker/wrangler.toml
|
||||
path: ${{ runner.temp }}/preview-cleanup-metadata/wrangler.toml
|
||||
retention-days: 2
|
||||
|
||||
deployment_status:
|
||||
|
||||
Reference in New Issue
Block a user