Skip to content

Commit d7d1182

Browse files
Merge pull request #204 from Fieldnote-Echo/codex/crates-recovery-metadata-check
Fix crates.io recovery version detection
2 parents 9eff62f + f7d209e commit d7d1182

2 files changed

Lines changed: 213 additions & 133 deletions

File tree

.github/workflows/release.yml

Lines changed: 126 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -1085,66 +1085,95 @@ jobs:
10851085
ATTESTED="${RUNNER_TEMP}/attested/ordvec-${VERSION}.crate"
10861086
[ -f "$ATTESTED" ] || { echo "::error::attested .crate missing at $ATTESTED"; exit 1; }
10871087
A_SHA=$(sha256sum "$ATTESTED" | cut -d' ' -f1)
1088+
METADATA_URL="https://crates.io/api/v1/crates/ordvec/${VERSION}"
10881089
API_URL="https://crates.io/api/v1/crates/ordvec/${VERSION}/download"
10891090
STATIC_URL="https://static.crates.io/crates/ordvec/ordvec-${VERSION}.crate"
10901091
CRATES_IO_USER_AGENT="ordvec-release-verify/${VERSION} (https://github.com/Fieldnote-Echo/ordvec)"
10911092
EXISTING="${RUNNER_TEMP}/existing-ordvec.crate"
1093+
METADATA="${RUNNER_TEMP}/existing-ordvec-metadata.json"
1094+
METADATA_STATUS_FILE="${RUNNER_TEMP}/existing-ordvec-metadata-status.txt"
10921095
API_STATUS_FILE="${RUNNER_TEMP}/existing-ordvec-api-status.txt"
10931096
STATIC_STATUS_FILE="${RUNNER_TEMP}/existing-ordvec-static-status.txt"
1094-
already_present=false
1097+
version_present=false
10951098
1096-
rm -f "$EXISTING" "$API_STATUS_FILE" "$STATIC_STATUS_FILE"
1097-
API_CURL_EXIT=0
1099+
rm -f "$EXISTING" "$METADATA" "$METADATA_STATUS_FILE" "$API_STATUS_FILE" "$STATIC_STATUS_FILE"
1100+
METADATA_CURL_EXIT=0
10981101
curl -sSL --retry 3 --retry-delay 2 --retry-all-errors --connect-timeout 10 --max-time 60 \
10991102
--user-agent "$CRATES_IO_USER_AGENT" \
1103+
--header "Accept: application/json" \
11001104
--write-out "%{http_code}" \
1101-
--output "$EXISTING" \
1102-
"$API_URL" > "$API_STATUS_FILE" || API_CURL_EXIT=$?
1103-
API_STATUS="$(cat "$API_STATUS_FILE")"
1104-
if [ "$API_CURL_EXIT" -ne 0 ]; then
1105-
echo "::error::could not determine crates.io status while checking ordvec ${VERSION} at $API_URL (curl exit ${API_CURL_EXIT}). Refusing recovery."
1105+
--output "$METADATA" \
1106+
"$METADATA_URL" > "$METADATA_STATUS_FILE" || METADATA_CURL_EXIT=$?
1107+
METADATA_STATUS="$(cat "$METADATA_STATUS_FILE")"
1108+
if [ "$METADATA_CURL_EXIT" -ne 0 ]; then
1109+
echo "::error::could not determine crates.io metadata while checking ordvec ${VERSION} at $METADATA_URL (curl exit ${METADATA_CURL_EXIT}). Refusing recovery."
11061110
exit 1
11071111
fi
1108-
case "$API_STATUS" in
1112+
case "$METADATA_STATUS" in
11091113
200)
1110-
already_present=true
1114+
version_present=true
11111115
;;
11121116
404)
1113-
rm -f "$EXISTING"
1117+
rm -f "$METADATA"
11141118
;;
11151119
*)
1116-
echo "::error::unexpected crates.io status ${API_STATUS} while checking ordvec ${VERSION} at $API_URL. Refusing recovery."
1120+
echo "::error::unexpected crates.io metadata status ${METADATA_STATUS} while checking ordvec ${VERSION} at $METADATA_URL. Refusing recovery."
11171121
exit 1
11181122
;;
11191123
esac
11201124
1121-
if [ "$already_present" != true ]; then
1125+
if [ "$version_present" != true ]; then
1126+
echo "already_published=false" >> "$GITHUB_OUTPUT"
1127+
echo "crates.io metadata does not list ordvec ${VERSION}; proceeding with publish."
1128+
else
1129+
downloaded=false
1130+
API_STATUS="unset"
1131+
STATIC_STATUS="unset"
1132+
API_CURL_EXIT=0
11221133
STATIC_CURL_EXIT=0
1123-
curl -sSL --retry 3 --retry-delay 2 --retry-all-errors --connect-timeout 10 --max-time 60 \
1124-
--user-agent "$CRATES_IO_USER_AGENT" \
1125-
--write-out "%{http_code}" \
1126-
--output "$EXISTING" \
1127-
"$STATIC_URL" > "$STATIC_STATUS_FILE" || STATIC_CURL_EXIT=$?
1128-
STATIC_STATUS="$(cat "$STATIC_STATUS_FILE")"
1129-
if [ "$STATIC_CURL_EXIT" -ne 0 ]; then
1130-
echo "::error::could not determine crates.io status while checking ordvec ${VERSION} at $STATIC_URL (curl exit ${STATIC_CURL_EXIT}). Refusing recovery."
1134+
for i in 1 2 3 4 5 6 7 8 9 10 11 12; do
1135+
rm -f "$EXISTING"
1136+
API_CURL_EXIT=0
1137+
curl -sSL --retry 0 --retry-all-errors --connect-timeout 5 --max-time 10 \
1138+
--user-agent "$CRATES_IO_USER_AGENT" \
1139+
--write-out "%{http_code}" \
1140+
--output "$EXISTING" \
1141+
"$API_URL" > "$API_STATUS_FILE" || API_CURL_EXIT=$?
1142+
API_STATUS="$(cat "$API_STATUS_FILE")"
1143+
if [ "$API_CURL_EXIT" -eq 0 ] && [ "$API_STATUS" = 200 ]; then
1144+
downloaded=true
1145+
break
1146+
fi
1147+
1148+
rm -f "$EXISTING"
1149+
STATIC_CURL_EXIT=0
1150+
curl -sSL --retry 0 --retry-all-errors --connect-timeout 5 --max-time 10 \
1151+
--user-agent "$CRATES_IO_USER_AGENT" \
1152+
--write-out "%{http_code}" \
1153+
--output "$EXISTING" \
1154+
"$STATIC_URL" > "$STATIC_STATUS_FILE" || STATIC_CURL_EXIT=$?
1155+
STATIC_STATUS="$(cat "$STATIC_STATUS_FILE")"
1156+
if [ "$STATIC_CURL_EXIT" -eq 0 ] && [ "$STATIC_STATUS" = 200 ]; then
1157+
downloaded=true
1158+
break
1159+
fi
1160+
1161+
rm -f "$EXISTING"
1162+
echo " waiting for crates.io to serve ordvec ${VERSION} for recovery (${i}/12)..."
1163+
if [ "$i" != 12 ]; then sleep 5; fi
1164+
done
1165+
1166+
if [ "$downloaded" != true ]; then
1167+
API_DETAIL="status ${API_STATUS:-unset}"
1168+
STATIC_DETAIL="status ${STATIC_STATUS:-unset}"
1169+
if [ "${API_CURL_EXIT:-0}" -ne 0 ]; then API_DETAIL="curl exit ${API_CURL_EXIT}"; fi
1170+
if [ "${STATIC_CURL_EXIT:-0}" -ne 0 ]; then STATIC_DETAIL="curl exit ${STATIC_CURL_EXIT}"; fi
1171+
echo "::error::crates.io metadata lists ordvec ${VERSION}, but recovery endpoints did not serve the .crate after retries (API ${API_DETAIL}, static ${STATIC_DETAIL}). Refusing recovery."
11311172
exit 1
11321173
fi
1133-
case "$STATIC_STATUS" in
1134-
200)
1135-
already_present=true
1136-
;;
1137-
404)
1138-
rm -f "$EXISTING"
1139-
;;
1140-
*)
1141-
echo "::error::unexpected crates.io status ${STATIC_STATUS} while checking ordvec ${VERSION} at $STATIC_URL. Refusing recovery."
1142-
exit 1
1143-
;;
1144-
esac
11451174
fi
11461175
1147-
if [ "$already_present" = true ]; then
1176+
if [ "${downloaded:-false}" = true ]; then
11481177
E_SHA=$(sha256sum "$EXISTING" | cut -d' ' -f1)
11491178
echo "attested: $A_SHA"
11501179
echo "crates.io-served: $E_SHA"
@@ -1154,9 +1183,6 @@ jobs:
11541183
fi
11551184
echo "already_published=true" >> "$GITHUB_OUTPUT"
11561185
echo "::notice::crates.io already serves byte-identical ordvec ${VERSION}; skipping upload and verifying served bytes."
1157-
else
1158-
echo "already_published=false" >> "$GITHUB_OUTPUT"
1159-
echo "Both crates.io recovery endpoints returned 404 for ordvec ${VERSION}; proceeding with publish."
11601186
fi
11611187
# Mint the short-lived crates.io credential immediately before publish so
11621188
# the ephemeral token's exposure window is minimal. No stored secret.
@@ -1436,66 +1462,95 @@ jobs:
14361462
ATTESTED="${RUNNER_TEMP}/attested/ordvec-manifest-${VERSION}.crate"
14371463
[ -f "$ATTESTED" ] || { echo "::error::attested .crate missing at $ATTESTED"; exit 1; }
14381464
A_SHA=$(sha256sum "$ATTESTED" | cut -d' ' -f1)
1465+
METADATA_URL="https://crates.io/api/v1/crates/ordvec-manifest/${VERSION}"
14391466
API_URL="https://crates.io/api/v1/crates/ordvec-manifest/${VERSION}/download"
14401467
STATIC_URL="https://static.crates.io/crates/ordvec-manifest/ordvec-manifest-${VERSION}.crate"
14411468
CRATES_IO_USER_AGENT="ordvec-release-verify/${VERSION} (https://github.com/Fieldnote-Echo/ordvec)"
14421469
EXISTING="${RUNNER_TEMP}/existing-ordvec-manifest.crate"
1470+
METADATA="${RUNNER_TEMP}/existing-ordvec-manifest-metadata.json"
1471+
METADATA_STATUS_FILE="${RUNNER_TEMP}/existing-ordvec-manifest-metadata-status.txt"
14431472
API_STATUS_FILE="${RUNNER_TEMP}/existing-ordvec-manifest-api-status.txt"
14441473
STATIC_STATUS_FILE="${RUNNER_TEMP}/existing-ordvec-manifest-static-status.txt"
1445-
already_present=false
1474+
version_present=false
14461475
1447-
rm -f "$EXISTING" "$API_STATUS_FILE" "$STATIC_STATUS_FILE"
1448-
API_CURL_EXIT=0
1476+
rm -f "$EXISTING" "$METADATA" "$METADATA_STATUS_FILE" "$API_STATUS_FILE" "$STATIC_STATUS_FILE"
1477+
METADATA_CURL_EXIT=0
14491478
curl -sSL --retry 3 --retry-delay 2 --retry-all-errors --connect-timeout 10 --max-time 60 \
14501479
--user-agent "$CRATES_IO_USER_AGENT" \
1480+
--header "Accept: application/json" \
14511481
--write-out "%{http_code}" \
1452-
--output "$EXISTING" \
1453-
"$API_URL" > "$API_STATUS_FILE" || API_CURL_EXIT=$?
1454-
API_STATUS="$(cat "$API_STATUS_FILE")"
1455-
if [ "$API_CURL_EXIT" -ne 0 ]; then
1456-
echo "::error::could not determine crates.io status while checking ordvec-manifest ${VERSION} at $API_URL (curl exit ${API_CURL_EXIT}). Refusing recovery."
1482+
--output "$METADATA" \
1483+
"$METADATA_URL" > "$METADATA_STATUS_FILE" || METADATA_CURL_EXIT=$?
1484+
METADATA_STATUS="$(cat "$METADATA_STATUS_FILE")"
1485+
if [ "$METADATA_CURL_EXIT" -ne 0 ]; then
1486+
echo "::error::could not determine crates.io metadata while checking ordvec-manifest ${VERSION} at $METADATA_URL (curl exit ${METADATA_CURL_EXIT}). Refusing recovery."
14571487
exit 1
14581488
fi
1459-
case "$API_STATUS" in
1489+
case "$METADATA_STATUS" in
14601490
200)
1461-
already_present=true
1491+
version_present=true
14621492
;;
14631493
404)
1464-
rm -f "$EXISTING"
1494+
rm -f "$METADATA"
14651495
;;
14661496
*)
1467-
echo "::error::unexpected crates.io status ${API_STATUS} while checking ordvec-manifest ${VERSION} at $API_URL. Refusing recovery."
1497+
echo "::error::unexpected crates.io metadata status ${METADATA_STATUS} while checking ordvec-manifest ${VERSION} at $METADATA_URL. Refusing recovery."
14681498
exit 1
14691499
;;
14701500
esac
14711501
1472-
if [ "$already_present" != true ]; then
1502+
if [ "$version_present" != true ]; then
1503+
echo "already_published=false" >> "$GITHUB_OUTPUT"
1504+
echo "crates.io metadata does not list ordvec-manifest ${VERSION}; proceeding with publish."
1505+
else
1506+
downloaded=false
1507+
API_STATUS="unset"
1508+
STATIC_STATUS="unset"
1509+
API_CURL_EXIT=0
14731510
STATIC_CURL_EXIT=0
1474-
curl -sSL --retry 3 --retry-delay 2 --retry-all-errors --connect-timeout 10 --max-time 60 \
1475-
--user-agent "$CRATES_IO_USER_AGENT" \
1476-
--write-out "%{http_code}" \
1477-
--output "$EXISTING" \
1478-
"$STATIC_URL" > "$STATIC_STATUS_FILE" || STATIC_CURL_EXIT=$?
1479-
STATIC_STATUS="$(cat "$STATIC_STATUS_FILE")"
1480-
if [ "$STATIC_CURL_EXIT" -ne 0 ]; then
1481-
echo "::error::could not determine crates.io status while checking ordvec-manifest ${VERSION} at $STATIC_URL (curl exit ${STATIC_CURL_EXIT}). Refusing recovery."
1511+
for i in 1 2 3 4 5 6 7 8 9 10 11 12; do
1512+
rm -f "$EXISTING"
1513+
API_CURL_EXIT=0
1514+
curl -sSL --retry 0 --retry-all-errors --connect-timeout 5 --max-time 10 \
1515+
--user-agent "$CRATES_IO_USER_AGENT" \
1516+
--write-out "%{http_code}" \
1517+
--output "$EXISTING" \
1518+
"$API_URL" > "$API_STATUS_FILE" || API_CURL_EXIT=$?
1519+
API_STATUS="$(cat "$API_STATUS_FILE")"
1520+
if [ "$API_CURL_EXIT" -eq 0 ] && [ "$API_STATUS" = 200 ]; then
1521+
downloaded=true
1522+
break
1523+
fi
1524+
1525+
rm -f "$EXISTING"
1526+
STATIC_CURL_EXIT=0
1527+
curl -sSL --retry 0 --retry-all-errors --connect-timeout 5 --max-time 10 \
1528+
--user-agent "$CRATES_IO_USER_AGENT" \
1529+
--write-out "%{http_code}" \
1530+
--output "$EXISTING" \
1531+
"$STATIC_URL" > "$STATIC_STATUS_FILE" || STATIC_CURL_EXIT=$?
1532+
STATIC_STATUS="$(cat "$STATIC_STATUS_FILE")"
1533+
if [ "$STATIC_CURL_EXIT" -eq 0 ] && [ "$STATIC_STATUS" = 200 ]; then
1534+
downloaded=true
1535+
break
1536+
fi
1537+
1538+
rm -f "$EXISTING"
1539+
echo " waiting for crates.io to serve ordvec-manifest ${VERSION} for recovery (${i}/12)..."
1540+
if [ "$i" != 12 ]; then sleep 5; fi
1541+
done
1542+
1543+
if [ "$downloaded" != true ]; then
1544+
API_DETAIL="status ${API_STATUS:-unset}"
1545+
STATIC_DETAIL="status ${STATIC_STATUS:-unset}"
1546+
if [ "${API_CURL_EXIT:-0}" -ne 0 ]; then API_DETAIL="curl exit ${API_CURL_EXIT}"; fi
1547+
if [ "${STATIC_CURL_EXIT:-0}" -ne 0 ]; then STATIC_DETAIL="curl exit ${STATIC_CURL_EXIT}"; fi
1548+
echo "::error::crates.io metadata lists ordvec-manifest ${VERSION}, but recovery endpoints did not serve the .crate after retries (API ${API_DETAIL}, static ${STATIC_DETAIL}). Refusing recovery."
14821549
exit 1
14831550
fi
1484-
case "$STATIC_STATUS" in
1485-
200)
1486-
already_present=true
1487-
;;
1488-
404)
1489-
rm -f "$EXISTING"
1490-
;;
1491-
*)
1492-
echo "::error::unexpected crates.io status ${STATIC_STATUS} while checking ordvec-manifest ${VERSION} at $STATIC_URL. Refusing recovery."
1493-
exit 1
1494-
;;
1495-
esac
14961551
fi
14971552
1498-
if [ "$already_present" = true ]; then
1553+
if [ "${downloaded:-false}" = true ]; then
14991554
E_SHA=$(sha256sum "$EXISTING" | cut -d' ' -f1)
15001555
echo "attested: $A_SHA"
15011556
echo "crates.io-served: $E_SHA"
@@ -1505,9 +1560,6 @@ jobs:
15051560
fi
15061561
echo "already_published=true" >> "$GITHUB_OUTPUT"
15071562
echo "::notice::crates.io already serves byte-identical ordvec-manifest ${VERSION}; skipping upload and verifying served bytes."
1508-
else
1509-
echo "already_published=false" >> "$GITHUB_OUTPUT"
1510-
echo "Both crates.io recovery endpoints returned 404 for ordvec-manifest ${VERSION}; proceeding with publish."
15111563
fi
15121564
- name: Validate manifest publish dry-run
15131565
if: steps.manifest_crate_recovery.outputs.already_published != 'true'

0 commit comments

Comments
 (0)