Prepare Sandwich Hime v1 release candidate source

This commit is contained in:
2026-08-23 16:25:02 -04:00
parent c11552b87a
commit efd5b997ed
64 changed files with 5276 additions and 156 deletions
+258
View File
@@ -0,0 +1,258 @@
#!/usr/bin/env bash
# SPDX-License-Identifier: AGPL-3.0-only
set -euo pipefail
script_root=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
project_root=$(CDPATH= cd -- "$script_root/.." && pwd)
# shellcheck source=public-snapshot-lib.sh
source "$script_root/public-snapshot-lib.sh"
# Release safety limits are policy, not caller-tunable settings.
SNAPSHOT_MAX_FILE_BYTES=1048576
SNAPSHOT_MAX_TOTAL_BYTES=16777216
SNAPSHOT_MAX_FILES=2000
usage() {
cat >&2 <<'USAGE'
Usage: export-public-snapshot.sh --destination PATH [options]
Options:
--source PATH Git worktree root (default: repository containing script)
--ref REF Committed source ref (default: HEAD)
--mode MODE release (default) or review
--allowlist PATH Review mode only: audited external exact-file policy
The destination must not exist and must be outside the source worktree. The
exporter creates it atomically and never initializes Git, configures a remote,
commits, tags, pushes, or copies .git.
USAGE
}
source_path=$project_root
source_ref=HEAD
destination=""
mode=release
allowlist_override=""
while [[ $# -gt 0 ]]; do
case $1 in
--source)
[[ $# -ge 2 ]] || { usage; exit 2; }
source_path=$2
shift 2
;;
--ref)
[[ $# -ge 2 ]] || { usage; exit 2; }
source_ref=$2
shift 2
;;
--destination)
[[ $# -ge 2 ]] || { usage; exit 2; }
destination=$2
shift 2
;;
--mode)
[[ $# -ge 2 ]] || { usage; exit 2; }
mode=$2
shift 2
;;
--allowlist)
[[ $# -ge 2 ]] || { usage; exit 2; }
allowlist_override=$2
shift 2
;;
-h | --help)
usage
exit 0
;;
*)
echo "public snapshot: unknown argument: $1" >&2
usage
exit 2
;;
esac
done
[[ -n $destination ]] || { usage; exit 2; }
[[ $mode == release || $mode == review ]] || { echo "public snapshot: mode must be release or review" >&2; exit 2; }
[[ $source_ref != -* && $source_ref != *$'\n'* && $source_ref != *$'\r'* ]] || {
echo "public snapshot: invalid source ref" >&2
exit 2
}
if [[ $mode == release && -n $allowlist_override ]]; then
echo "public snapshot: release mode requires the allowlist committed in the source ref" >&2
exit 2
fi
source_path=$(snapshot_realpath_existing "$source_path")
git_root=$(git -C "$source_path" rev-parse --show-toplevel 2>/dev/null) || {
echo "public snapshot: source is not a Git worktree" >&2
exit 1
}
git_root=$(snapshot_realpath_existing "$git_root")
[[ $source_path == "$git_root" ]] || { echo "public snapshot: --source must name the worktree root" >&2; exit 1; }
git_dir=$(git -C "$git_root" rev-parse --absolute-git-dir 2>/dev/null) || {
echo "public snapshot: cannot resolve source Git metadata directory" >&2
exit 1
}
git_common_dir=$(git -C "$git_root" rev-parse --git-common-dir 2>/dev/null) || {
echo "public snapshot: cannot resolve source Git common directory" >&2
exit 1
}
git_dir=$(snapshot_realpath_existing "$git_dir")
if [[ $git_common_dir != /* ]]; then
git_common_dir=$git_root/$git_common_dir
fi
git_common_dir=$(snapshot_realpath_existing "$git_common_dir")
commit=$(git -C "$git_root" rev-parse --verify "${source_ref}^{commit}" 2>/dev/null) || {
echo "public snapshot: source ref does not resolve to a commit" >&2
exit 1
}
[[ $commit =~ ^[0-9a-f]{40}$ || $commit =~ ^[0-9a-f]{64}$ ]] || {
echo "public snapshot: source commit is not a full object ID" >&2
exit 1
}
if [[ $mode == release ]]; then
head_commit=$(git -C "$git_root" rev-parse --verify HEAD^{commit})
[[ $commit == "$head_commit" ]] || { echo "public snapshot: release ref must resolve to HEAD" >&2; exit 1; }
status=$(git -C "$git_root" status --porcelain=v1 --untracked-files=all)
snapshot_status_is_clean "$status" || {
echo "public snapshot: release source worktree is dirty" >&2
exit 1
}
fi
destination_parent=$(dirname -- "$destination")
destination_name=$(basename -- "$destination")
[[ $destination_name != . && $destination_name != .. && -n $destination_name ]] || {
echo "public snapshot: invalid destination name" >&2
exit 2
}
destination_parent=$(snapshot_realpath_existing "$destination_parent")
[[ -d $destination_parent && ! -L $destination_parent ]] || {
echo "public snapshot: destination parent must be an existing non-symlink directory" >&2
exit 1
}
for protected_root in "$git_root" "$git_dir" "$git_common_dir"; do
if snapshot_path_is_at_or_below "$destination_parent" "$protected_root"; then
echo "public snapshot: destination must be outside the source worktree and Git metadata" >&2
exit 1
fi
done
destination=$destination_parent/$destination_name
[[ ! -e $destination && ! -L $destination ]] || {
echo "public snapshot: destination already exists; refusing to alter it" >&2
exit 1
}
staging=$(mktemp -d "$destination_parent/.${destination_name}.himesan-public-export.XXXXXX")
marker_name=.himesan-public-export-owned
marker=$staging/$marker_name
printf 'owned temporary public snapshot staging directory\n' >"$marker"
cleanup() {
local status=$?
if [[ -n ${staging:-} && -d $staging && -f $marker ]]; then
case $staging in
"$destination_parent"/."$destination_name".himesan-public-export.*)
rm -rf -- "$staging"
;;
esac
fi
exit "$status"
}
trap cleanup EXIT
policy_file=$staging/.himesan-policy-input
if [[ -n $allowlist_override ]]; then
[[ $mode == review ]] || { echo "public snapshot: external policy is review-only" >&2; exit 2; }
[[ -f $allowlist_override && ! -L $allowlist_override ]] || {
echo "public snapshot: external allowlist must be a regular non-symlink file" >&2
exit 1
}
cp -- "$allowlist_override" "$policy_file"
else
policy_path=scripts/public-snapshot.allow
git -C "$git_root" cat-file -e "$commit:$policy_path" 2>/dev/null || {
echo "public snapshot: committed ref lacks $policy_path" >&2
exit 1
}
git -C "$git_root" show "$commit:$policy_path" >"$policy_file"
fi
policy_sha256=$(sha256sum "$policy_file" | awk '{print $1}')
seen_lines=$'\n'
paths=()
while IFS= read -r line || [[ -n $line ]]; do
[[ -n $line && ${line:0:1} != '#' ]] || continue
if [[ $line == *[[:space:]]* ]] || snapshot_forbidden_path "$line"; then
echo "public snapshot: invalid or forbidden allowlist entry: $line" >&2
exit 1
fi
case $seen_lines in
*$'\n'"$line"$'\n'*)
echo "public snapshot: duplicate allowlist entry: $line" >&2
exit 1
;;
esac
seen_lines=$seen_lines$line$'\n'
record=$(git -C "$git_root" ls-tree "$commit" -- "$line")
[[ -n $record && ${record#*$'\t'} == "$line" && $record != *$'\n'* ]] || {
echo "public snapshot: allowlisted path is absent or ambiguous in source ref: $line" >&2
exit 1
}
read -r object_mode object_type object_id <<<"${record%%$'\t'*}"
[[ $object_type == blob && ($object_mode == 100644 || $object_mode == 100755) ]] || {
echo "public snapshot: allowlisted path is not a regular file: $line" >&2
exit 1
}
blob_size=$(git -C "$git_root" cat-file -s "$object_id")
((blob_size <= SNAPSHOT_MAX_FILE_BYTES)) || {
echo "public snapshot: allowlisted blob is oversized: $line" >&2
exit 1
}
paths+=("$line")
done <"$policy_file"
[[ ${#paths[@]} -gt 0 ]] || { echo "public snapshot: allowlist selected no files" >&2; exit 1; }
sorted_paths=()
while IFS= read -r -d '' path; do
sorted_paths[${#sorted_paths[@]}]=$path
done < <(printf '%s\0' "${paths[@]}" | LC_ALL=C sort -z)
git -C "$git_root" archive --format=tar "$commit" -- "${sorted_paths[@]}" | tar -xf - -C "$staging"
unlink "$policy_file"
exported_count=$(find "$staging" -type f ! -name "$marker_name" | wc -l)
exported_count=${exported_count//[[:space:]]/}
[[ $exported_count -eq ${#sorted_paths[@]} ]] || {
echo "public snapshot: extracted file count does not match allowlist" >&2
exit 1
}
snapshot_validate_export_tree "$staging" "$marker_name"
manifest=$staging/PUBLIC-SNAPSHOT.sha256
manifest_input=$staging/.himesan-manifest-input
(cd "$staging" && find . -type f ! -name "$marker_name" ! -name .himesan-manifest-input -print0 | LC_ALL=C sort -z | xargs -0 sha256sum) >"$manifest_input"
mv "$manifest_input" "$manifest"
manifest_sha256=$(sha256sum "$manifest" | awk '{print $1}')
provenance=$staging/PUBLIC-SNAPSHOT.json
printf '{"schema_version":2,"project":"sandwich-hime","export_policy":"exact-allowlist-v1","export_mode":"%s","file_count":%s,"allowlist_sha256":"%s","manifest_sha256":"%s"}\n' \
"$mode" "$exported_count" "$policy_sha256" "$manifest_sha256" >"$provenance"
# Normalize filesystem metadata to a public constant as well as normalizing
# content. Private commit IDs, tree IDs, timestamps, identities, refs, remote
# URLs, and checkout paths do not enter the exported tree.
TZ=UTC find "$staging" -exec touch -t 197001010000 {} +
unlink "$marker"
if mv --help 2>&1 | grep -q -- '-T'; then
mv -nT -- "$staging" "$destination"
else
# BSD mv has no -T. The existing-destination preflight above preserves the
# same no-overwrite policy for the local macOS review lane.
mv -n "$staging" "$destination"
fi
if [[ -e $staging || ! -d $destination ]]; then
echo "public snapshot: destination appeared during activation; staging was not published" >&2
exit 1
fi
staging=""
printf 'public_snapshot=%s\ncommit=%s\nfiles=%s\n' "$destination" "$commit" "$exported_count"