WIP: Paused over-hardening fix wave (boot checkout verification, double-read package manifest)
This commit is contained in:
@@ -123,7 +123,7 @@ grep -q '/etc/profile.d/nvm.sh' "$stage" \
|
||||
|| note 'the extension build never sources nvm, so npm is missing on any machine without a system node'
|
||||
|
||||
# node_modules is a dependency tree, not configuration.
|
||||
git -C "$repo_dir" check-ignore -q "$extension/node_modules" 2>/dev/null \
|
||||
git -C "$repo_dir" check-ignore -q "$extension/node_modules/" 2>/dev/null \
|
||||
|| note 'the extension node_modules is not gitignored'
|
||||
|
||||
# npm must honour the committed dependency graph. This disposable fixture
|
||||
@@ -167,6 +167,131 @@ stage_output="$(PATH="$fixture_root/bin:$PATH" PANAMA_PATH="$fixture_root" \
|
||||
cmp -s -- "$lock_before" "$lockfile" \
|
||||
|| note 'a rejected Vicinae lockfile mismatch changed package-lock.json'
|
||||
|
||||
# Successful builds carry a digest receipt over both manifests and every
|
||||
# source file. Directory mtimes do not change when an existing file is edited,
|
||||
# so each byte class must independently invalidate the build.
|
||||
digest_root="$fixture_root/digest"
|
||||
digest_extension="$digest_root/config/local/share/vicinae/extensions/panama-search"
|
||||
digest_data="$digest_root/vicinae-data"
|
||||
mkdir -p "$digest_root/config/local/share/vicinae/scripts" \
|
||||
"$digest_extension/src" "$digest_extension/assets" "$digest_root/bin"
|
||||
cp -- "$manifest" "$digest_extension/package.json"
|
||||
cp -- "$repo_dir/config/local/share/vicinae/extensions/panama-search/package-lock.json" \
|
||||
"$digest_extension/package-lock.json"
|
||||
cp -- "$repo_dir/config/local/share/vicinae/extensions/panama-search/src/search.tsx" \
|
||||
"$digest_extension/src/search.tsx"
|
||||
cp -- "$repo_dir/config/local/share/vicinae/extensions/panama-search/tsconfig.json" \
|
||||
"$digest_extension/tsconfig.json"
|
||||
cp -- "$repo_dir/config/local/share/vicinae/extensions/panama-search/assets/extension_icon.svg" \
|
||||
"$digest_extension/assets/extension_icon.svg"
|
||||
cat >"$digest_root/bin/npm" <<'EOF'
|
||||
#!/usr/bin/env bash
|
||||
printf '%s\n' "$*" >>"${NPM_LOG:?}"
|
||||
case "${1:-}:${2:-}" in
|
||||
ci:--silent) exit 0 ;;
|
||||
run:build)
|
||||
mkdir -p "$VICINAE_DATA_DIR/extensions/$(basename "$PWD")"
|
||||
printf 'built\n' >"$VICINAE_DATA_DIR/extensions/$(basename "$PWD")/bundle"
|
||||
;;
|
||||
*) exit 64 ;;
|
||||
esac
|
||||
EOF
|
||||
cat >"$digest_root/bin/find" <<'EOF'
|
||||
#!/usr/bin/env bash
|
||||
set -uo pipefail
|
||||
status=0
|
||||
/usr/bin/find "$@" || status=$?
|
||||
[[ "${STUB_FIND_FAIL:-0}" != 1 ]] || exit 74
|
||||
exit "$status"
|
||||
EOF
|
||||
chmod +x "$digest_root/bin/npm" "$digest_root/bin/find"
|
||||
|
||||
run_digest_stage() {
|
||||
: >"$digest_root/npm.log"
|
||||
PATH="$digest_root/bin:$PATH" PANAMA_PATH="$digest_root" \
|
||||
VICINAE_DATA_DIR="$digest_data" NPM_LOG="$digest_root/npm.log" \
|
||||
STUB_FIND_FAIL="${STUB_FIND_FAIL:-0}" \
|
||||
bash "$stage" >"$digest_root/stage.out" 2>&1
|
||||
}
|
||||
|
||||
run_digest_stage || note 'the Vicinae digest fixture initial build failed'
|
||||
cmp -s <(printf 'ci --silent\nrun build\n') "$digest_root/npm.log" \
|
||||
|| note 'the Vicinae digest fixture did not perform its initial locked build'
|
||||
run_digest_stage || note 'the unchanged Vicinae digest fixture failed'
|
||||
[[ ! -s "$digest_root/npm.log" ]] \
|
||||
|| note 'an unchanged Vicinae extension rebuilt despite its matching receipt'
|
||||
|
||||
for digest_input in src/search.tsx package.json package-lock.json tsconfig.json \
|
||||
assets/extension_icon.svg; do
|
||||
printf '\n// digest mutation: %s\n' "$digest_input" >>"$digest_extension/$digest_input"
|
||||
run_digest_stage || note "the Vicinae digest fixture failed after changing $digest_input"
|
||||
cmp -s <(printf 'ci --silent\nrun build\n') "$digest_root/npm.log" \
|
||||
|| note "changing existing $digest_input bytes did not rebuild the Vicinae extension"
|
||||
done
|
||||
|
||||
# A traversal can emit valid-looking partial output and still fail. Sorting
|
||||
# that output must not hide find's producer status or replace the successful
|
||||
# build receipt with a digest over an incomplete source tree.
|
||||
digest_receipt="$digest_data/extensions/panama-search/.panama-source-sha256"
|
||||
cp -- "$digest_receipt" "$digest_root/receipt.before-find-failure"
|
||||
STUB_FIND_FAIL=1 run_digest_stage \
|
||||
|| note 'the Vicinae stage made a digest traversal failure fatal'
|
||||
[[ ! -s "$digest_root/npm.log" ]] \
|
||||
|| note 'a failed Vicinae digest traversal still rebuilt the extension'
|
||||
grep -q 'inputs could not be verified; skipping' "$digest_root/stage.out" \
|
||||
|| note 'a failed Vicinae digest traversal was accepted as verified input'
|
||||
cmp -s -- "$digest_root/receipt.before-find-failure" "$digest_receipt" \
|
||||
|| note 'a failed Vicinae digest traversal replaced the successful receipt'
|
||||
|
||||
# Helper writes run in conditional contexts in production, where Bash disables
|
||||
# implicit errexit inside the whole function. Each producer therefore has to
|
||||
# return its own write/publication failure and remove its temporary receipt.
|
||||
vicinae_helpers="$digest_root/vicinae-helpers"
|
||||
sed '/^panama_path=/,$d' "$stage" >"$vicinae_helpers"
|
||||
: >"$digest_root/empty-inputs"
|
||||
mkdir "$digest_root/manifest-output-directory"
|
||||
manifest_status=0
|
||||
bash -c 'source "$1"; set +e; _write_vicinae_manifest "$2" "$3" "$4"' bash \
|
||||
"$vicinae_helpers" "$digest_extension" "$digest_root/empty-inputs" \
|
||||
"$digest_root/manifest-output-directory" >/dev/null 2>&1 \
|
||||
|| manifest_status=$?
|
||||
[[ "$manifest_status" -ne 0 ]] \
|
||||
|| note 'a failed Vicinae manifest initialization returned success'
|
||||
|
||||
receipt_failure_root="$digest_root/receipt-publication-failure"
|
||||
mkdir -p "$receipt_failure_root/built" "$receipt_failure_root/bin"
|
||||
printf 'prior receipt\n' >"$receipt_failure_root/built/.panama-source-sha256"
|
||||
cat >"$receipt_failure_root/bin/mv" <<'EOF'
|
||||
#!/usr/bin/env bash
|
||||
destination="${!#}"
|
||||
[[ "$destination" != */.panama-source-sha256 ]] || exit 75
|
||||
exec /usr/bin/mv "$@"
|
||||
EOF
|
||||
chmod +x "$receipt_failure_root/bin/mv"
|
||||
receipt_status=0
|
||||
PATH="$receipt_failure_root/bin:$PATH" bash -c \
|
||||
'source "$1"; set +e; _record_vicinae_digest "$2" "$3"' bash \
|
||||
"$vicinae_helpers" "$receipt_failure_root/built" "$(printf 'a%.0s' {1..64})" \
|
||||
>/dev/null 2>&1 || receipt_status=$?
|
||||
[[ "$receipt_status" -ne 0 ]] \
|
||||
|| note 'a failed Vicinae receipt publication returned success'
|
||||
cmp -s <(printf 'prior receipt\n') \
|
||||
"$receipt_failure_root/built/.panama-source-sha256" \
|
||||
|| note 'a failed Vicinae receipt publication replaced the prior receipt'
|
||||
[[ -z "$(find "$receipt_failure_root/built" \
|
||||
-name '.panama-source-sha256.*' -print -quit)" ]] \
|
||||
|| note 'a failed Vicinae receipt publication left a temporary receipt'
|
||||
|
||||
# Prove the directory-only ignore rule in a repository where node_modules does
|
||||
# not already exist. The trailing slash is part of the query contract.
|
||||
ignore_root="$fixture_root/ignore-repository"
|
||||
mkdir -p "$ignore_root/config/local/share/vicinae/extensions/panama-search"
|
||||
cp -- "$repo_dir/.gitignore" "$ignore_root/.gitignore"
|
||||
git -C "$ignore_root" init -q
|
||||
git -C "$ignore_root" check-ignore -q \
|
||||
'config/local/share/vicinae/extensions/panama-search/node_modules/' \
|
||||
|| note 'a fresh clone with no node_modules directory does not match the ignore rule'
|
||||
|
||||
# ── Report ───────────────────────────────────────────────────────────────────
|
||||
|
||||
if (( ${#findings[@]} > 0 )); then
|
||||
|
||||
Reference in New Issue
Block a user