mirror of
https://github.com/obra/superpowers.git
synced 2026-07-17 23:44:04 +08:00
fix(codex): make package script and its test portable beyond macOS/bsdtar
The packaging pipeline only worked on a Mac with default umask, for
three stacked reasons:
- The deterministic-metadata tar flags (--uid/--gid/--uname/--gname)
are bsdtar spellings; GNU tar rejects them, so the tar.gz archive
step died on Linux. Detect the tar flavor and use --owner=:0
--group=:0 --numeric-owner on GNU tar, which writes byte-identical
ustar headers (uid/gid 0, empty uname/gname).
- Staged file modes depended on two umasks canceling out: git archive
masks entry modes with tar.umask (git default 0002 -> 775), and the
unflagged tar extraction re-masked with the process umask (022 on
macOS -> 755, but 002 elsewhere -> 775). Pin tar.umask=0022 on the
archive call and extract with -p so staged modes are canonical
755/644 on every machine.
- The test's timestamp assertion parsed bsdtar's -tv column layout and
expected epoch 0 rendered in a US timezone ("Dec 31 1969"); GNU tar
uses different columns and UTC hosts render "1970-01-01". Assert
mtime == 0 via python3 tarfile instead, matching how the test
already checks zip timestamps.
tests/codex/test-package-codex-plugin.sh now passes on Linux/GNU tar;
the bsdtar branch preserves the exact flags that passed on macOS.
This commit is contained in:
@@ -230,14 +230,16 @@ prepare_metadata_root() {
|
|||||||
|
|
||||||
METADATA_ROOT="$(prepare_metadata_root "$METADATA_SOURCE")"
|
METADATA_ROOT="$(prepare_metadata_root "$METADATA_SOURCE")"
|
||||||
|
|
||||||
git -C "$REPO_ROOT" archive --format=tar "$REF" -- \
|
# Pin tar.umask and extract with -p so staged modes are canonical 755/644
|
||||||
|
# regardless of the builder's git config or process umask.
|
||||||
|
git -C "$REPO_ROOT" -c tar.umask=0022 archive --format=tar "$REF" -- \
|
||||||
.codex-plugin \
|
.codex-plugin \
|
||||||
CODE_OF_CONDUCT.md \
|
CODE_OF_CONDUCT.md \
|
||||||
LICENSE \
|
LICENSE \
|
||||||
README.md \
|
README.md \
|
||||||
assets \
|
assets \
|
||||||
skills \
|
skills \
|
||||||
| tar -xf - -C "$STAGE"
|
| tar -xpf - -C "$STAGE"
|
||||||
|
|
||||||
VERSION="$(jq -r '.version // empty' "$STAGE/.codex-plugin/plugin.json")"
|
VERSION="$(jq -r '.version // empty' "$STAGE/.codex-plugin/plugin.json")"
|
||||||
[[ -n "$VERSION" ]] || die "could not read version from .codex-plugin/plugin.json"
|
[[ -n "$VERSION" ]] || die "could not read version from .codex-plugin/plugin.json"
|
||||||
@@ -298,12 +300,19 @@ case "$FORMAT" in
|
|||||||
)
|
)
|
||||||
;;
|
;;
|
||||||
tar.gz)
|
tar.gz)
|
||||||
# Match the prior official archive's deterministic tar entry metadata.
|
# Match the prior official archive's deterministic tar entry metadata:
|
||||||
|
# ustar entries with uid/gid 0 and empty uname/gname. GNU tar and bsdtar
|
||||||
|
# (macOS) spell those flags differently.
|
||||||
|
if tar --version 2>/dev/null | grep -q 'GNU tar'; then
|
||||||
|
TAR_METADATA_FLAGS=(--owner=:0 --group=:0 --numeric-owner)
|
||||||
|
else
|
||||||
|
TAR_METADATA_FLAGS=(--uid 0 --gid 0 --uname '' --gname '')
|
||||||
|
fi
|
||||||
TZ=UTC find "$STAGE" -exec touch -t 197001010000 {} +
|
TZ=UTC find "$STAGE" -exec touch -t 197001010000 {} +
|
||||||
(
|
(
|
||||||
cd "$STAGE"
|
cd "$STAGE"
|
||||||
rm -f "$OUTPUT"
|
rm -f "$OUTPUT"
|
||||||
COPYFILE_DISABLE=1 tar -cf - --no-recursion --format ustar --uid 0 --gid 0 --uname '' --gname '' -T "$ARCHIVE_LIST" |
|
COPYFILE_DISABLE=1 tar -cf - --no-recursion --format ustar "${TAR_METADATA_FLAGS[@]}" -T "$ARCHIVE_LIST" |
|
||||||
gzip -9n >"$OUTPUT"
|
gzip -9n >"$OUTPUT"
|
||||||
)
|
)
|
||||||
;;
|
;;
|
||||||
|
|||||||
@@ -210,8 +210,13 @@ assert_equals "$tar_archive_paths" "$archive_paths" "zip and tar.gz archives con
|
|||||||
tar_task_brief_mode="$(tar -tzvf "$tar_archive" skills/subagent-driven-development/scripts/task-brief | awk '{print $1}')"
|
tar_task_brief_mode="$(tar -tzvf "$tar_archive" skills/subagent-driven-development/scripts/task-brief | awk '{print $1}')"
|
||||||
assert_equals "$tar_task_brief_mode" "-rwxr-xr-x" "tar.gz archive preserves executable script mode"
|
assert_equals "$tar_task_brief_mode" "-rwxr-xr-x" "tar.gz archive preserves executable script mode"
|
||||||
|
|
||||||
tar_metadata_times="$(tar -tzvf "$tar_archive" | awk '{print $6, $7, $8}' | sort -u)"
|
tar_metadata_times="$(python3 - "$tar_archive" <<'PY'
|
||||||
assert_equals "$tar_metadata_times" "Dec 31 1969" "tar.gz archive normalizes entry timestamps"
|
import sys, tarfile
|
||||||
|
with tarfile.open(sys.argv[1]) as archive:
|
||||||
|
print(sorted({member.mtime for member in archive.getmembers()}))
|
||||||
|
PY
|
||||||
|
)"
|
||||||
|
assert_equals "$tar_metadata_times" "[0]" "tar.gz archive normalizes entry timestamps"
|
||||||
|
|
||||||
metadata_archive="$TEST_ROOT/metadata-source.tar.gz"
|
metadata_archive="$TEST_ROOT/metadata-source.tar.gz"
|
||||||
metadata_zip="$TEST_ROOT/metadata-source.zip"
|
metadata_zip="$TEST_ROOT/metadata-source.zip"
|
||||||
|
|||||||
Reference in New Issue
Block a user