Prepare Sandwich Hime v1 release candidate source
This commit is contained in:
@@ -0,0 +1,69 @@
|
||||
<!-- SPDX-License-Identifier: AGPL-3.0-only -->
|
||||
|
||||
# Sanitized public source snapshots
|
||||
|
||||
`export-public-snapshot.sh` creates a host-neutral filesystem snapshot from a
|
||||
committed Git tree. It does not initialize a repository, copy `.git`, configure
|
||||
a remote, commit, tag, push, or publish anything.
|
||||
|
||||
Release use requires a clean worktree, a ref resolving exactly to `HEAD`, and
|
||||
the exact-file policy committed at `scripts/public-snapshot.allow` in that
|
||||
ref:
|
||||
|
||||
```sh
|
||||
scripts/export-public-snapshot.sh \
|
||||
--mode release \
|
||||
--ref HEAD \
|
||||
--destination ../sandwich-hime-public-review
|
||||
```
|
||||
|
||||
The destination must not exist and its canonical parent must be outside the
|
||||
source worktree, its worktree-specific Git directory, and its shared Git common
|
||||
directory. This includes ordinary `.git` directories and linked-worktree
|
||||
metadata stored elsewhere. The exporter creates a private sibling staging
|
||||
directory and renames it into place only after all checks pass. It never clears
|
||||
or replaces an existing destination; failure cleanup is limited to a staging
|
||||
directory carrying the exporter's ownership marker.
|
||||
|
||||
Review mode may use an externally reviewed exact-file policy while changes to
|
||||
the exporter itself await a commit. Its provenance is conspicuously marked
|
||||
`review` and is not a release artifact:
|
||||
|
||||
```sh
|
||||
scripts/export-public-snapshot.sh \
|
||||
--mode review \
|
||||
--allowlist /path/to/reviewed-exact-files.allow \
|
||||
--destination ../snapshot-for-review
|
||||
```
|
||||
|
||||
The policy accepts individual files only—never directories or globs. The
|
||||
export fails for missing/duplicate/forbidden entries, non-regular Git objects,
|
||||
symlinks, binary or oversized content, aggregate size limits, private developer
|
||||
filesystem indicators, common private-key/token indicators, database or build
|
||||
artifacts, and explicitly private integration material. Host workflow folders,
|
||||
private trees, prototype/history trees, and application-specific integrations
|
||||
are not in the reviewed policy.
|
||||
|
||||
`PUBLIC-SNAPSHOT.sha256` records every exported source file. The deterministic
|
||||
`PUBLIC-SNAPSHOT.json` records only the project identifier, export policy and
|
||||
mode, file count, and policy/manifest digests. Private commit and tree IDs,
|
||||
commit timestamps, author or committer identity, email, hostname, branch name,
|
||||
remote URL, and checkout path stay outside the exported tree. Filesystem
|
||||
timestamps are normalized to the Unix epoch. A separate private release ledger
|
||||
may map the private source commit to the resulting public commit and signed
|
||||
tags.
|
||||
|
||||
When an exported tree is reviewed into an existing public checkout, compare and
|
||||
copy files by content (for example, checksum-aware synchronization or a fresh
|
||||
tree replacement). Size-and-modification-time shortcuts are unsafe here because
|
||||
the exporter deliberately gives every snapshot the same normalized timestamp;
|
||||
the manifest and provenance records must be verified again before publication.
|
||||
|
||||
Run the focused checks with:
|
||||
|
||||
```sh
|
||||
bash scripts/test-public-snapshot.sh
|
||||
```
|
||||
|
||||
The implementation expects Bash, Git, tar, GNU-compatible core utilities, and
|
||||
a filesystem supporting an atomic rename within the destination parent.
|
||||
+25
-7
@@ -3,23 +3,41 @@
|
||||
# Repository verification tools
|
||||
|
||||
These scripts are intentionally understandable shell rather than a release
|
||||
framework with hidden defaults. The maintained verification and release path
|
||||
is Linux.
|
||||
framework with hidden defaults. The maintained native verification paths are
|
||||
Linux/amd64 and macOS/arm64.
|
||||
|
||||
- `verify.sh` runs root and nested-module tests and vet, builds `himesan`, checks the compiler-owned golden output, and proves two generation passes leave the same bytes and unchanged modification times. Set `HIMESAN_RACE=1` for race tests.
|
||||
- `check-licenses.sh` enforces the AGPL compiler / Apache runtime boundary and prevents generated application Go from inheriting an AGPL identifier.
|
||||
- `release-check.sh --version vX.Y.Z` is a clean-checkout technical preflight, including exact candidate-version and generated-provenance checks. Beta publication follows the narrower prerelease gates in `RELEASE.md`; release candidates and final v1 additionally use `--public` with a human-reviewed `HIMESAN_RELEASE_EVIDENCE_DIR`. The script never tags, pushes, publishes, or deploys.
|
||||
- `test-public-snapshot.sh` proves the exact allowlist, secret/path scanner, legal boundary, deterministic manifest, and no-overwrite export behavior on both maintained native hosts.
|
||||
- Contract tests bind the exported runtime API, CLI help, JSON/configuration schemas, diagnostic-code inventory, generic component signature, and generated provenance to the reviewed files under `contracts/` and `sando/testdata/`.
|
||||
- `release-check.sh --version vX.Y.Z` is a clean-checkout technical preflight, including exact candidate-version and generated-provenance checks. Beta publication follows the narrower prerelease gates in `RELEASE.md`; release candidates and final v1 additionally use `--public` with a human-reviewed `HIMESAN_RELEASE_EVIDENCE_DIR` and the four-lane `HIMESAN_NATIVE_EVIDENCE_DIR`. Seal the review directory with `go run ./cmd/himesan-release evidence-manifest`; `verify-native` independently checks every native receipt sidecar, source identity, gate, freshness bound, and generated-output digest. The script never tags, pushes, publishes, or deploys.
|
||||
- `verify-public-install.sh --version vX.Y.Z` is a post-tag/publication check. It verifies exact `go-get=1` package routes, adds the nested runtime before installing the parent compiler, and exercises fresh direct-fetch and public-proxy caches without interactive Git credentials.
|
||||
- `package-native.sh` performs two native builds and uses the repository-owned Go packager for a deterministic archive, manifest, SBOM, and checksums. `package-macos.sh` is the explicit Apple Silicon entrypoint used by the release operator.
|
||||
- `sign-notarize-macos.sh` is a deliberately manual boundary. It requires the explicitly approved unsigned archive digest, uses Cole's Developer ID and Keychain-held notary profile, regenerates provenance and checksums for the changed signed Mach-O bytes, and produces a signed, notarized, and stapled DMG. The native runner receives neither credential.
|
||||
- `verify-real-browser.sh` is opt-in release evidence. It runs the development client in an actual reviewed Chrome/Chromium binary, exercising CSP-restricted execution, SSE diagnostics, reload, and fragment/API exclusions, then reruns the process cleanup integration cases. Chrome is not a normal build or consumer dependency.
|
||||
|
||||
The canonical Linux CI and release preflight also run bounded fuzz sessions for the parser/context compiler and Go-aware delimiter scanner. Seed-corpus execution remains part of ordinary `go test`; the bounded sessions are extra evidence, not a substitute for longer scheduled fuzzing before v1.
|
||||
The canonical Linux and macOS CI gates run the contract and public-snapshot
|
||||
checks plus bounded fuzz sessions for the parser/context compiler, Go-aware
|
||||
delimiter scanner, URL policy, and LSP boundaries. The compiler target also
|
||||
asserts deterministic diagnostics and generated Go, source-digest binding, and
|
||||
safe source-map directives. Seed-corpus execution remains part of ordinary
|
||||
`go test`; the bounded sessions are extra evidence, not a substitute for the
|
||||
long exact-candidate campaign before v1.
|
||||
|
||||
The release preflight invokes `govulncheck` from the official Go vulnerability project at the exact module version `golang.org/x/vuln@v1.6.0`. Updating that pin requires reviewing the upstream tag and rerunning the supported Go lines.
|
||||
|
||||
## Preview automation status
|
||||
|
||||
Forge workflows are intentionally excluded from the sanitized pre-1.0 public
|
||||
snapshot. The private development repository uses pinned Linux runners; the
|
||||
public source remains independently verifiable with `verify.sh`, the license
|
||||
check, and the Linux release preflight.
|
||||
snapshot. The private development repository uses pinned Linux/amd64 and
|
||||
repository-scoped native macOS/arm64 runners; the public source remains
|
||||
independently verifiable with the repository scripts and both native release
|
||||
preflights.
|
||||
|
||||
The private `public-candidate-verification` workflow is a release controller,
|
||||
not public-source evidence by association. It accepts only the exact lowercase
|
||||
commit currently at canonical public `main`, clones only that fixed Gitea origin without credentials,
|
||||
and produces receipts naming `gamertan/sandwich-hime`. Development-repository
|
||||
receipts cannot satisfy the public release preflight.
|
||||
|
||||
If Gitea automation is later added to the public repository, pin every external action to a reviewed immutable commit, document its provenance, grant minimum permissions, and keep a local verification path. A secondary forge may host a sanitized, read-only discovery snapshot, but hosted workflows stay disabled there and it does not become a release or contribution authority.
|
||||
|
||||
@@ -54,7 +54,7 @@ check_sha256() {
|
||||
|
||||
is_comment_capable_project_file() {
|
||||
case "$1" in
|
||||
COPYRIGHT | */COPYRIGHT | .editorconfig | .gitattributes | .gitignore | *.go | *.mod | *.md | *.sh | *.ps1 | *.yml | *.yaml | *.html | *.css | *.js | *.toml | *.allow)
|
||||
COPYRIGHT | */COPYRIGHT | .editorconfig | .gitattributes | .gitignore | *.go | *.mod | *.md | *.txt | *.sh | *.ps1 | *.yml | *.yaml | *.html | *.css | *.js | *.toml | *.plist | *.allow)
|
||||
return 0
|
||||
;;
|
||||
*)
|
||||
@@ -67,8 +67,10 @@ list_project_files() {
|
||||
if git rev-parse --is-inside-work-tree >/dev/null 2>&1; then
|
||||
git ls-files --cached --others --exclude-standard -z
|
||||
else
|
||||
find . -type d \( -name .git -o -name vendor -o -name bin -o -name dist -o -name coverage \) -prune -o \
|
||||
-type f -print0 | sed -z 's#^\./##'
|
||||
while IFS= read -r -d '' path; do
|
||||
printf '%s\0' "${path#./}"
|
||||
done < <(find . -type d \( -name .git -o -name vendor -o -name bin -o -name dist -o -name coverage \) -prune -o \
|
||||
-type f -print0)
|
||||
fi
|
||||
}
|
||||
|
||||
@@ -152,7 +154,8 @@ while IFS= read -r -d '' path; do
|
||||
continue
|
||||
;;
|
||||
*.json)
|
||||
fail "$path cannot carry a comment and needs an explicit license-map entry"
|
||||
grep -Fq "\`$path\`" LICENSES.md || \
|
||||
fail "$path cannot carry a comment and needs an exact license-map entry"
|
||||
continue
|
||||
;;
|
||||
esac
|
||||
|
||||
Executable
+258
@@ -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"
|
||||
Executable
+71
@@ -0,0 +1,71 @@
|
||||
#!/usr/bin/env bash
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
repo_root=$(CDPATH= cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd)
|
||||
cd "$repo_root"
|
||||
|
||||
usage() {
|
||||
printf 'Usage: scripts/native-gate.sh --repository OWNER/REPOSITORY --go-version goX.Y.Z --runner-version VERSION --runner-name NAME --output DIR\n' >&2
|
||||
}
|
||||
|
||||
repository=''
|
||||
expected_go=''
|
||||
runner_version=''
|
||||
runner_name=''
|
||||
output=''
|
||||
while (( $# > 0 )); do
|
||||
case "$1" in
|
||||
--repository) repository=$2; shift 2 ;;
|
||||
--go-version) expected_go=$2; shift 2 ;;
|
||||
--runner-version) runner_version=$2; shift 2 ;;
|
||||
--runner-name) runner_name=$2; shift 2 ;;
|
||||
--output) output=$2; shift 2 ;;
|
||||
*) usage; exit 2 ;;
|
||||
esac
|
||||
done
|
||||
if [[ ! "$repository" =~ ^[a-z0-9][a-z0-9._-]*/[a-z0-9][a-z0-9._-]*$ || -z "$expected_go" || -z "$runner_version" || -z "$runner_name" || -z "$output" ]]; then
|
||||
usage
|
||||
exit 2
|
||||
fi
|
||||
if [[ "$(go env GOVERSION)" != "$expected_go" ]]; then
|
||||
printf 'error: expected %s, found %s\n' "$expected_go" "$(go env GOVERSION)" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
mkdir -p -- "$output"
|
||||
./scripts/check-licenses.sh
|
||||
./scripts/test-public-snapshot.sh
|
||||
HIMESAN_RACE=1 ./scripts/verify.sh
|
||||
go test ./internal/compiler -run '^$' -fuzz '^FuzzCompileNeverPanics$' -fuzztime=15s
|
||||
go test ./internal/compiler -run '^$' -fuzz '^FuzzGoDelimiterNeverPanics$' -fuzztime=15s
|
||||
go test ./internal/lsp -run '^$' -fuzz '^FuzzFrameReaderNeverPanics$' -fuzztime=15s
|
||||
go test ./internal/lsp -run '^$' -fuzz '^FuzzDocumentPositionNeverPanics$' -fuzztime=15s
|
||||
(
|
||||
cd sando
|
||||
go test -run '^$' -fuzz '^FuzzWriteURLPolicy$' -fuzztime=15s
|
||||
)
|
||||
go run golang.org/x/vuln/cmd/govulncheck@v1.6.0 ./...
|
||||
(
|
||||
cd sando
|
||||
go run golang.org/x/vuln/cmd/govulncheck@v1.6.0 ./...
|
||||
)
|
||||
./scripts/verify-consumer.sh
|
||||
|
||||
./scripts/package-native.sh --version v0.0.0-verification.1 --output "$output"
|
||||
artifact=$(find "$output" -maxdepth 1 -type f -name '*.tar.gz' -print -quit)
|
||||
artifact_sha=$(awk '{print $1}' "$artifact.sha256")
|
||||
completed_at=$(date -u '+%Y-%m-%dT%H:%M:%SZ')
|
||||
go run ./cmd/himesan-release receipt \
|
||||
--output "$output/TEND-CI-VERIFICATION.json" \
|
||||
--repository "$repository" \
|
||||
--commit "$(git rev-parse HEAD)" \
|
||||
--tree "$(git rev-parse 'HEAD^{tree}')" \
|
||||
--goos "$(go env GOOS)" --goarch "$(go env GOARCH)" \
|
||||
--go-version "$expected_go" --runner-version "$runner_version" \
|
||||
--runner-name "$runner_name" --artifact-sha256 "$artifact_sha" \
|
||||
--completed-at "$completed_at" \
|
||||
--gates test,vet,build,race,generation,contracts,public-snapshot,fuzz,vulnerability,consumer,package \
|
||||
--generated-files internal/compiler/testdata/golden/basic.sando.go
|
||||
printf 'Native verification evidence: %s\n' "$output"
|
||||
Executable
+8
@@ -0,0 +1,8 @@
|
||||
#!/usr/bin/env bash
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
if [[ "$(uname -s)/$(uname -m)" != Darwin/arm64 ]]; then
|
||||
printf 'error: the maintained macOS artifact must be built natively on darwin/arm64\n' >&2
|
||||
exit 1
|
||||
fi
|
||||
exec "$(dirname -- "${BASH_SOURCE[0]}")/package-native.sh" "$@"
|
||||
Executable
+81
@@ -0,0 +1,81 @@
|
||||
#!/usr/bin/env bash
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
repo_root=$(CDPATH= cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd)
|
||||
cd "$repo_root"
|
||||
|
||||
usage() { printf 'Usage: scripts/package-native.sh --version vX.Y.Z --output DIR\n' >&2; }
|
||||
version=''
|
||||
output=''
|
||||
while (( $# > 0 )); do
|
||||
case "$1" in
|
||||
--version) [[ $# -ge 2 ]] || { usage; exit 2; }; version=$2; shift 2 ;;
|
||||
--output) [[ $# -ge 2 ]] || { usage; exit 2; }; output=$2; shift 2 ;;
|
||||
*) usage; exit 2 ;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [[ ! "$version" =~ ^v[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.-]+)?$ ]]; then
|
||||
printf 'error: a canonical v-prefixed release version is required\n' >&2
|
||||
exit 2
|
||||
fi
|
||||
[[ -n "$output" ]] || { usage; exit 2; }
|
||||
if ! git diff --quiet -- || ! git diff --cached --quiet --; then
|
||||
printf 'error: native release packaging requires a clean tracked worktree\n' >&2
|
||||
exit 1
|
||||
fi
|
||||
untracked_sources=$(git ls-files --others --exclude-standard -- \
|
||||
'*.go' '*.sando' 'go.mod' 'go.sum' 'vendor/**' || true)
|
||||
if [[ -n "$untracked_sources" ]]; then
|
||||
printf 'error: untracked build inputs prevent trustworthy release provenance:\n%s\n' "$untracked_sources" >&2
|
||||
exit 1
|
||||
fi
|
||||
target="$(go env GOOS)/$(go env GOARCH)"
|
||||
case "$target" in
|
||||
darwin/arm64 | linux/amd64) ;;
|
||||
*) printf 'error: unsupported maintained native target: %s\n' "$target" >&2; exit 1 ;;
|
||||
esac
|
||||
if [[ "$(go env GOVERSION)" != go1.26.7 && "$(go env GOVERSION)" != go1.27.0 ]]; then
|
||||
printf 'error: unsupported release toolchain: %s\n' "$(go env GOVERSION)" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
temporary=$(mktemp -d "${TMPDIR:-/tmp}/himesan-native-package.XXXXXXXX")
|
||||
temporary=$(CDPATH= cd -- "$temporary" && pwd -P)
|
||||
cleanup() { rm -rf -- "$temporary"; }
|
||||
trap cleanup EXIT HUP INT TERM
|
||||
|
||||
commit=$(git rev-parse HEAD)
|
||||
tree=$(git rev-parse 'HEAD^{tree}')
|
||||
source_date_epoch=$(git show -s --format=%ct HEAD)
|
||||
go_version=$(go env GOVERSION)
|
||||
target_os=${target%/*}
|
||||
target_arch=${target#*/}
|
||||
linker_flags="-buildid= -X gamertan.com/sandwich-hime/internal/version.Compiler=$version"
|
||||
for pass in one two; do
|
||||
CGO_ENABLED=0 GOTOOLCHAIN=local go build -buildvcs=false -trimpath \
|
||||
-ldflags "$linker_flags" -o "$temporary/himesan-$pass" ./cmd/himesan
|
||||
done
|
||||
if ! cmp -s "$temporary/himesan-one" "$temporary/himesan-two"; then
|
||||
printf 'error: repeated native builds were not byte-identical\n' >&2
|
||||
exit 1
|
||||
fi
|
||||
case "$target" in
|
||||
darwin/arm64) expected='Mach-O 64-bit executable arm64' ;;
|
||||
linux/amd64) expected='ELF 64-bit LSB executable, x86-64' ;;
|
||||
esac
|
||||
if ! file "$temporary/himesan-one" | grep -Fq "$expected"; then
|
||||
printf 'error: candidate has the wrong native executable format\n' >&2
|
||||
file "$temporary/himesan-one" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
mkdir -p -- "$output"
|
||||
go run ./cmd/himesan-release package \
|
||||
--version "$version" --commit "$commit" --tree "$tree" \
|
||||
--go-version "$go_version" --goos "$target_os" --goarch "$target_arch" \
|
||||
--binary "$temporary/himesan-one" --output "$output" \
|
||||
--source-date-epoch "$source_date_epoch"
|
||||
printf 'Unsigned native package created. Signing and notarization were not performed.\n'
|
||||
Executable
+121
@@ -0,0 +1,121 @@
|
||||
#!/usr/bin/env bash
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
# Sourced validation helpers for export-public-snapshot.sh and its focused
|
||||
# tests. This file deliberately leaves the caller's shell options unchanged.
|
||||
|
||||
snapshot_status_is_clean() {
|
||||
[[ -z $1 ]]
|
||||
}
|
||||
|
||||
snapshot_path_is_at_or_below() {
|
||||
local candidate=$1
|
||||
local boundary=$2
|
||||
|
||||
[[ $boundary == / || $candidate == "$boundary" || $candidate == "$boundary/"* ]]
|
||||
}
|
||||
|
||||
snapshot_realpath_existing() {
|
||||
local path=$1
|
||||
local directory base
|
||||
if [[ -d $path ]]; then
|
||||
(CDPATH= cd -- "$path" && pwd -P)
|
||||
return
|
||||
fi
|
||||
if [[ -f $path ]]; then
|
||||
directory=$(dirname -- "$path")
|
||||
base=$(basename -- "$path")
|
||||
directory=$(CDPATH= cd -- "$directory" && pwd -P) || return 1
|
||||
printf '%s/%s\n' "$directory" "$base"
|
||||
return
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
snapshot_forbidden_path() {
|
||||
local path=$1
|
||||
local lower
|
||||
lower=$(printf '%s' "$path" | LC_ALL=C tr '[:upper:]' '[:lower:]')
|
||||
|
||||
[[ $path != /* && $path != *\\* && $path != *//* ]] || return 0
|
||||
[[ $path != . && $path != .. && $path != ../* && $path != */../* && $path != */.. ]] || return 0
|
||||
[[ $path != *$'\n'* && $path != *$'\r'* && $path != *$'\t'* ]] || return 0
|
||||
|
||||
case "/$lower/" in
|
||||
*/.git/* | */.gitea/* | */.github/* | */private/* | */prototype/* | */prototypes/* | */history/* | */legacy/* | */vendor/* | */bin/* | */dist/* | */coverage/* | */cmd/himetest/* | */cmd/himework/* | */internal/himesan/* | */internal/integration/* | */templates/*)
|
||||
return 0
|
||||
;;
|
||||
esac
|
||||
case $lower in
|
||||
go.work | go.work.sum | .env | .env.* | */.env | */.env.* | *.db | *.db-* | *.sqlite | *.sqlite3 | *.pem | *.key | *.p12 | *.pfx | */id_rsa | */id_ed25519 | *credentials* | *.exe | *.dll | *.dylib | *.so | *.a | *.o | *.test | *.prof | *.cover | *.zip | *.tar | *.tar.gz | *.tgz)
|
||||
return 0
|
||||
;;
|
||||
esac
|
||||
return 1
|
||||
}
|
||||
|
||||
snapshot_validate_export_tree() {
|
||||
local root=$1
|
||||
local marker=${2:-}
|
||||
local max_file_bytes=${SNAPSHOT_MAX_FILE_BYTES:-1048576}
|
||||
local max_total_bytes=${SNAPSHOT_MAX_TOTAL_BYTES:-16777216}
|
||||
local max_files=${SNAPSHOT_MAX_FILES:-2000}
|
||||
local total=0
|
||||
local count=0
|
||||
local file rel size
|
||||
local users_word=Users
|
||||
local private_unix="/(home|${users_word})/[^/[:space:]]+"
|
||||
local private_windows='[A-Za-z]:[\\/]+Users[\\/]'
|
||||
local private_wsl="/mnt/[a-zA-Z]/${users_word}/"
|
||||
local pem_begin='-----BEGIN '
|
||||
local private_key="${pem_begin}([A-Z0-9]+ )?PRIVATE KEY-----|${pem_begin}PGP PRIVATE KEY BLOCK-----"
|
||||
local provider_token='AKIA[0-9A-Z]{16}|(ghp|gho|ghu|ghs|ghr)_[A-Za-z0-9]{20,}|glpat-[A-Za-z0-9_-]{20,}|xox[baprs]-[A-Za-z0-9-]{20,}'
|
||||
local private_commit_id='(private development (source|baseline)|private (development )?(commit|source))[^[:cntrl:]]*[0-9a-f]{12,64}'
|
||||
local private_repository='sandwich-hime-''dev'
|
||||
|
||||
if find "$root" -type l -print -quit | grep -q .; then
|
||||
echo "public snapshot: symbolic links are forbidden" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
while IFS= read -r -d '' file; do
|
||||
rel=${file#"$root"/}
|
||||
[[ -z $marker || $rel != "$marker" ]] || continue
|
||||
if snapshot_forbidden_path "$rel"; then
|
||||
echo "public snapshot: forbidden path: $rel" >&2
|
||||
return 1
|
||||
fi
|
||||
size=$(wc -c <"$file")
|
||||
size=${size//[[:space:]]/}
|
||||
if ((size > max_file_bytes)); then
|
||||
echo "public snapshot: oversized file: $rel ($size bytes)" >&2
|
||||
return 1
|
||||
fi
|
||||
total=$((total + size))
|
||||
count=$((count + 1))
|
||||
if ((total > max_total_bytes || count > max_files)); then
|
||||
echo "public snapshot: export exceeds aggregate size/count limits" >&2
|
||||
return 1
|
||||
fi
|
||||
if [[ -s $file ]] && ! LC_ALL=C grep -Iq . "$file"; then
|
||||
echo "public snapshot: binary file rejected: $rel" >&2
|
||||
return 1
|
||||
fi
|
||||
if LC_ALL=C grep -Eq "$private_unix|$private_windows|$private_wsl" "$file"; then
|
||||
echo "public snapshot: private filesystem path indicator in $rel" >&2
|
||||
return 1
|
||||
fi
|
||||
if LC_ALL=C grep -Eq -- "$private_key|$provider_token" "$file"; then
|
||||
echo "public snapshot: key or credential indicator in $rel" >&2
|
||||
return 1
|
||||
fi
|
||||
if LC_ALL=C grep -Eiq -- "$private_commit_id" "$file"; then
|
||||
echo "public snapshot: private commit identifier in $rel" >&2
|
||||
return 1
|
||||
fi
|
||||
if LC_ALL=C grep -Fq -- "$private_repository" "$file"; then
|
||||
echo "public snapshot: private repository indicator in $rel" >&2
|
||||
return 1
|
||||
fi
|
||||
done < <(find "$root" -type f -print0 | LC_ALL=C sort -z)
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
# Exact reviewed file allowlist for a host-neutral public source snapshot.
|
||||
# Directories, globs, and implicit descendants are intentionally unsupported.
|
||||
|
||||
.editorconfig
|
||||
.gitattributes
|
||||
.gitignore
|
||||
AI_CONTRIBUTIONS.md
|
||||
CHANGELOG.md
|
||||
CLA.md
|
||||
CONTRIBUTING.md
|
||||
COPYRIGHT
|
||||
DCO.txt
|
||||
GENERATED_CODE.md
|
||||
GOVERNANCE.md
|
||||
LICENSE
|
||||
LICENSES.md
|
||||
MAINTAINERS.md
|
||||
OUTPUT_EXCEPTION.md
|
||||
README.md
|
||||
RELEASE.md
|
||||
ROADMAP.md
|
||||
SECURITY.md
|
||||
SPEC.md
|
||||
TRADEMARKS.md
|
||||
cmd/himesan/contract_test.go
|
||||
cmd/himesan/main.go
|
||||
cmd/himesan/main_test.go
|
||||
cmd/himesan-release/main.go
|
||||
contracts/diagnostic-codes-v1.txt
|
||||
contracts/generated-provenance-v1.txt
|
||||
contracts/himesan-cli-help-v1.txt
|
||||
contracts/himesan-config-v1.schema.json
|
||||
contracts/himesan-operation-output-v1.schema.json
|
||||
contracts/himesan-version-output-v1.schema.json
|
||||
docs/ARCHITECTURE.md
|
||||
docs/BENCHMARKS.md
|
||||
docs/BRAND.md
|
||||
docs/COMPATIBILITY.md
|
||||
docs/DEVELOPMENT_SERVER.md
|
||||
docs/DIAGNOSTICS.md
|
||||
docs/LANGUAGE_SERVER.md
|
||||
docs/SECURITY_EVIDENCE.md
|
||||
docs/THREAT_MODEL.md
|
||||
docs/V1_RELEASE_PLAN.md
|
||||
go.mod
|
||||
internal/compiler/abi_test.go
|
||||
internal/compiler/analysis.go
|
||||
internal/compiler/analysis_test.go
|
||||
internal/compiler/backend.go
|
||||
internal/compiler/compiler_test.go
|
||||
internal/compiler/contract_test.go
|
||||
internal/compiler/context.go
|
||||
internal/compiler/diagnostic.go
|
||||
internal/compiler/discover.go
|
||||
internal/compiler/e2e_test.go
|
||||
internal/compiler/fuzz_test.go
|
||||
internal/compiler/model.go
|
||||
internal/compiler/operation.go
|
||||
internal/compiler/parse.go
|
||||
internal/compiler/replace_unix.go
|
||||
internal/compiler/replace_windows.go
|
||||
internal/compiler/testdata/golden/basic.sando
|
||||
internal/compiler/testdata/golden/basic.sando.go
|
||||
internal/devserver/browser_evidence_test.go
|
||||
internal/devserver/config.go
|
||||
internal/devserver/config_test.go
|
||||
internal/devserver/contract_test.go
|
||||
internal/devserver/events.go
|
||||
internal/devserver/process.go
|
||||
internal/devserver/process_test.go
|
||||
internal/devserver/process_unix.go
|
||||
internal/devserver/process_windows.go
|
||||
internal/devserver/process_windows_32.go
|
||||
internal/devserver/process_windows_64.go
|
||||
internal/devserver/proxy.go
|
||||
internal/devserver/proxy_test.go
|
||||
internal/devserver/supervisor.go
|
||||
internal/devserver/supervisor_test.go
|
||||
internal/devserver/watch.go
|
||||
internal/devserver/watch_test.go
|
||||
internal/lsp/features.go
|
||||
internal/lsp/protocol.go
|
||||
internal/lsp/protocol_test.go
|
||||
internal/lsp/security_test.go
|
||||
internal/lsp/server.go
|
||||
internal/lsp/server_test.go
|
||||
internal/lsp/workspace.go
|
||||
internal/releaseartifact/artifact.go
|
||||
internal/releaseartifact/artifact_test.go
|
||||
internal/releaseartifact/evidence.go
|
||||
internal/releaseartifact/evidence_test.go
|
||||
internal/releaseartifact/macos.go
|
||||
internal/releaseartifact/macos_test.go
|
||||
internal/releaseartifact/native.go
|
||||
internal/releaseartifact/native_test.go
|
||||
internal/testpath/tempdir.go
|
||||
internal/testpath/tempdir_test.go
|
||||
internal/version/version.go
|
||||
internal/version/version_test.go
|
||||
sando/COPYRIGHT
|
||||
sando/LICENSE
|
||||
sando/README.md
|
||||
sando/api_contract_test.go
|
||||
sando/benchmark_test.go
|
||||
sando/component.go
|
||||
sando/component_test.go
|
||||
sando/differential_test.go
|
||||
sando/go.mod
|
||||
sando/trust.go
|
||||
sando/write.go
|
||||
sando/write_test.go
|
||||
sando/testdata/public-api-v1.txt
|
||||
scripts/README.md
|
||||
scripts/PUBLIC_SNAPSHOT.md
|
||||
scripts/check-licenses.sh
|
||||
scripts/export-public-snapshot.sh
|
||||
scripts/native-gate.sh
|
||||
scripts/package-macos.sh
|
||||
scripts/package-native.sh
|
||||
scripts/public-snapshot-lib.sh
|
||||
scripts/public-snapshot.allow
|
||||
scripts/release-check.sh
|
||||
scripts/sign-notarize-macos.sh
|
||||
scripts/test-public-snapshot.sh
|
||||
scripts/verify-consumer.sh
|
||||
scripts/verify-public-install.sh
|
||||
scripts/verify-real-browser.sh
|
||||
scripts/verify.sh
|
||||
+37
-25
@@ -16,9 +16,11 @@ artifacts in the repository, pushes, or deploys.
|
||||
--version Candidate compiler version.
|
||||
--runtime-tag Existing runtime tag retained by a compiler-only release.
|
||||
Omit only when publishing a matching new runtime tag.
|
||||
--public Require the human-reviewed RC/final launch evidence bundle named
|
||||
by HIMESAN_RELEASE_EVIDENCE_DIR. Canonical beta prereleases may
|
||||
run their narrower publication preflight without this flag.
|
||||
--public Require the human-reviewed RC/final launch evidence bundle
|
||||
named by HIMESAN_RELEASE_EVIDENCE_DIR and the four native
|
||||
runner receipts named by HIMESAN_NATIVE_EVIDENCE_DIR.
|
||||
Canonical beta prereleases may run their narrower publication
|
||||
preflight without this flag.
|
||||
EOF
|
||||
}
|
||||
|
||||
@@ -171,6 +173,7 @@ if (( compiler_only == 1 )); then
|
||||
fi
|
||||
|
||||
artifact_dir=$(mktemp -d "${TMPDIR:-/tmp}/himesan-release-check.XXXXXXXX")
|
||||
artifact_dir=$(CDPATH= cd -- "$artifact_dir" && pwd -P)
|
||||
cleanup() {
|
||||
if [[ -n "${artifact_dir:-}" && -d "$artifact_dir" ]]; then
|
||||
rm -rf -- "$artifact_dir"
|
||||
@@ -238,6 +241,7 @@ for pass in 1 2; do
|
||||
done
|
||||
|
||||
./scripts/check-licenses.sh
|
||||
./scripts/test-public-snapshot.sh
|
||||
HIMESAN_RACE=1 ./scripts/verify.sh
|
||||
|
||||
printf '\n==> bounded compiler fuzz gates\n'
|
||||
@@ -245,6 +249,10 @@ go test ./internal/compiler -run '^$' -fuzz '^FuzzCompileNeverPanics$' -fuzztime
|
||||
go test ./internal/compiler -run '^$' -fuzz '^FuzzGoDelimiterNeverPanics$' -fuzztime=20s
|
||||
go test ./internal/lsp -run '^$' -fuzz '^FuzzFrameReaderNeverPanics$' -fuzztime=20s
|
||||
go test ./internal/lsp -run '^$' -fuzz '^FuzzDocumentPositionNeverPanics$' -fuzztime=20s
|
||||
(
|
||||
cd sando
|
||||
go test -run '^$' -fuzz '^FuzzWriteURLPolicy$' -fuzztime=20s
|
||||
)
|
||||
|
||||
printf '\n==> vulnerability scan (pinned golang.org/x/vuln v1.6.0)\n'
|
||||
go run golang.org/x/vuln/cmd/govulncheck@v1.6.0 ./...
|
||||
@@ -253,15 +261,16 @@ go run golang.org/x/vuln/cmd/govulncheck@v1.6.0 ./...
|
||||
go run golang.org/x/vuln/cmd/govulncheck@v1.6.0 ./...
|
||||
)
|
||||
|
||||
printf '\n==> building supported Linux release binary\n'
|
||||
for target in \
|
||||
linux/amd64; do
|
||||
target_os=${target%/*}
|
||||
target_arch=${target#*/}
|
||||
CGO_ENABLED=0 GOOS="$target_os" GOARCH="$target_arch" \
|
||||
go build -trimpath -ldflags "$compiler_linker_flags" \
|
||||
-o "$artifact_dir/himesan-$target_os-$target_arch" ./cmd/himesan
|
||||
done
|
||||
target="$(go env GOOS)/$(go env GOARCH)"
|
||||
case "$target" in
|
||||
linux/amd64 | darwin/arm64) ;;
|
||||
*) printf 'error: release preflight requires a maintained native target, found %s\n' "$target" >&2; exit 1 ;;
|
||||
esac
|
||||
target_os=${target%/*}
|
||||
target_arch=${target#*/}
|
||||
printf '\n==> building supported native %s release binary\n' "$target"
|
||||
CGO_ENABLED=0 go build -trimpath -ldflags "$compiler_linker_flags" \
|
||||
-o "$artifact_dir/himesan-$target_os-$target_arch" ./cmd/himesan
|
||||
|
||||
for required in \
|
||||
scripts/verify-public-install.sh \
|
||||
@@ -274,23 +283,26 @@ done
|
||||
|
||||
if (( public_release == 1 )); then
|
||||
evidence_dir=${HIMESAN_RELEASE_EVIDENCE_DIR:-}
|
||||
native_evidence_dir=${HIMESAN_NATIVE_EVIDENCE_DIR:-}
|
||||
if [[ -z "$evidence_dir" || ! -d "$evidence_dir" ]]; then
|
||||
printf 'error: --public requires HIMESAN_RELEASE_EVIDENCE_DIR\n' >&2
|
||||
exit 1
|
||||
fi
|
||||
for evidence in \
|
||||
legal-review.md \
|
||||
linux-platform.md \
|
||||
security.md \
|
||||
development-supervisor.md \
|
||||
benchmark-methodology.md \
|
||||
vanity-imports.md \
|
||||
signing-and-recovery.md; do
|
||||
if [[ ! -s "$evidence_dir/$evidence" ]]; then
|
||||
printf 'error: public release evidence is missing or empty: %s\n' "$evidence_dir/$evidence" >&2
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
if [[ -z "$native_evidence_dir" || ! -d "$native_evidence_dir" ]]; then
|
||||
printf 'error: --public requires HIMESAN_NATIVE_EVIDENCE_DIR\n' >&2
|
||||
exit 1
|
||||
fi
|
||||
go run ./cmd/himesan-release verify-native \
|
||||
--directory "$native_evidence_dir" \
|
||||
--repository gamertan/sandwich-hime \
|
||||
--commit "$(git rev-parse HEAD)" \
|
||||
--tree "$(git rev-parse 'HEAD^{tree}')"
|
||||
go run ./cmd/himesan-release verify-evidence \
|
||||
--directory "$evidence_dir" \
|
||||
--repository gamertan/sandwich-hime \
|
||||
--version "$version" \
|
||||
--commit "$(git rev-parse HEAD)" \
|
||||
--tree "$(git rev-parse 'HEAD^{tree}')"
|
||||
fi
|
||||
|
||||
if [[ -n "$(git status --porcelain=v1 --untracked-files=all)" ]]; then
|
||||
|
||||
Executable
+80
@@ -0,0 +1,80 @@
|
||||
#!/usr/bin/env bash
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
usage() {
|
||||
cat >&2 <<'EOF'
|
||||
Usage: scripts/sign-notarize-macos.sh --archive FILE --sha256 DIGEST --output DIR --keychain-profile NAME
|
||||
|
||||
Run this manually from Cole's signed-in macOS account. It never runs in CI.
|
||||
It signs the native CLI, creates and signs a DMG, submits that DMG to Apple's
|
||||
notary service, staples its ticket, and validates the distribution.
|
||||
EOF
|
||||
}
|
||||
|
||||
archive=''
|
||||
archive_sha256=''
|
||||
output=''
|
||||
profile=''
|
||||
identity='Developer ID Application: Cole Speelman (5BXR9JCUBL)'
|
||||
identifier='com.gamertan.sandwich-hime.himesan'
|
||||
while (( $# > 0 )); do
|
||||
case "$1" in
|
||||
--archive) archive=$2; shift 2 ;;
|
||||
--sha256) archive_sha256=$2; shift 2 ;;
|
||||
--output) output=$2; shift 2 ;;
|
||||
--keychain-profile) profile=$2; shift 2 ;;
|
||||
*) usage; exit 2 ;;
|
||||
esac
|
||||
done
|
||||
if [[ -z "$archive" || -z "$archive_sha256" || -z "$output" || -z "$profile" ]]; then usage; exit 2; fi
|
||||
if [[ ! "$archive_sha256" =~ ^[0-9a-f]{64}$ ]]; then
|
||||
printf 'error: --sha256 must be the approved lowercase archive digest\n' >&2
|
||||
exit 2
|
||||
fi
|
||||
if [[ "$(uname -s)/$(uname -m)" != Darwin/arm64 ]]; then
|
||||
printf 'error: signing must run natively on Apple Silicon macOS\n' >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
temporary=$(mktemp -d "${TMPDIR:-/tmp}/himesan-notarize.XXXXXXXX")
|
||||
temporary=$(CDPATH= cd -- "$temporary" && pwd -P)
|
||||
cleanup() { rm -rf -- "$temporary"; }
|
||||
trap cleanup EXIT HUP INT TERM
|
||||
|
||||
go run ./cmd/himesan-release extract-macos \
|
||||
--archive "$archive" --sha256 "$archive_sha256" --output "$temporary"
|
||||
root=$(find "$temporary" -mindepth 1 -maxdepth 1 -type d -print -quit)
|
||||
binary="$root/himesan"
|
||||
[[ -x "$binary" ]] || { printf 'error: archive does not contain executable himesan\n' >&2; exit 1; }
|
||||
|
||||
codesign --force --options runtime --timestamp \
|
||||
--identifier "$identifier" --sign "$identity" "$binary"
|
||||
codesign --verify --strict --verbose=2 "$binary"
|
||||
go run ./cmd/himesan-release finalize-macos \
|
||||
--directory "$root" \
|
||||
--unsigned-archive-sha256 "$archive_sha256" \
|
||||
--identity "$identity" --identifier "$identifier" \
|
||||
--finalized-at "$(date -u '+%Y-%m-%dT%H:%M:%SZ')"
|
||||
codesign --verify --strict --verbose=2 "$binary"
|
||||
|
||||
mkdir -p -- "$output"
|
||||
version=$(basename "$root")
|
||||
dmg="$output/$version.dmg"
|
||||
if [[ -e "$dmg" || -e "$dmg.sha256" ]]; then
|
||||
printf 'error: signed distribution output already exists: %s\n' "$dmg" >&2
|
||||
exit 1
|
||||
fi
|
||||
hdiutil create -quiet -fs HFS+ -format UDZO -volname "$version" -srcfolder "$root" "$dmg"
|
||||
codesign --force --timestamp --sign "$identity" "$dmg"
|
||||
codesign --verify --strict --verbose=2 "$dmg"
|
||||
xcrun notarytool submit "$dmg" --keychain-profile "$profile" --wait
|
||||
xcrun stapler staple "$dmg"
|
||||
xcrun stapler validate "$dmg"
|
||||
codesign --verify --strict --verbose=2 "$dmg"
|
||||
spctl --assess --type open --context context:primary-signature --verbose=2 "$dmg"
|
||||
dmg_sha256=$(shasum -a 256 "$dmg" | awk '{print $1}')
|
||||
printf '%s %s\n' "$dmg_sha256" "$(basename "$dmg")" >"$dmg.sha256"
|
||||
chmod 0444 "$dmg" "$dmg.sha256"
|
||||
printf 'Signed, notarized, and stapled distribution: %s\n' "$dmg"
|
||||
Executable
+278
@@ -0,0 +1,278 @@
|
||||
#!/usr/bin/env bash
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
project_root=$(CDPATH= cd -- "$(dirname -- "$0")/.." && pwd)
|
||||
# shellcheck source=public-snapshot-lib.sh
|
||||
source "$project_root/scripts/public-snapshot-lib.sh"
|
||||
exporter=$project_root/scripts/export-public-snapshot.sh
|
||||
temporary=$(mktemp -d)
|
||||
cleanup() {
|
||||
rm -rf -- "$temporary"
|
||||
}
|
||||
trap cleanup EXIT
|
||||
|
||||
bash -n "$project_root/scripts/public-snapshot-lib.sh" "$exporter"
|
||||
if grep -Eq 'git[[:space:]]+(init|commit|tag|push|remote)([[:space:]]|$)' "$exporter"; then
|
||||
echo "exporter contains a forbidden Git mutation command" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
for required in COPYRIGHT OUTPUT_EXCEPTION.md sando/COPYRIGHT; do
|
||||
grep -Fxq "$required" "$project_root/scripts/public-snapshot.allow" || {
|
||||
echo "required legal boundary is absent from public allowlist: $required" >&2
|
||||
exit 1
|
||||
}
|
||||
done
|
||||
|
||||
snapshot_status_is_clean ""
|
||||
if snapshot_status_is_clean " M reviewed.go"; then
|
||||
echo "dirty status was accepted" >&2
|
||||
exit 1
|
||||
fi
|
||||
snapshot_path_is_at_or_below /var/tmp / || {
|
||||
echo "filesystem-root boundary did not contain an absolute path" >&2
|
||||
exit 1
|
||||
}
|
||||
if snapshot_path_is_at_or_below /safe-ish /safe; then
|
||||
echo "path boundary accepted a sibling prefix" >&2
|
||||
exit 1
|
||||
fi
|
||||
for path in .gitea/workflows/verify.yml .github/workflows/verify.yml private/notes.md \
|
||||
internal/integration/product/test.go go.work build/output.exe data/private.db history/prototype.go; do
|
||||
if ! snapshot_forbidden_path "$path"; then
|
||||
echo "private/build path was not rejected: $path" >&2
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
snapshot_forbidden_path README.md && { echo "safe path was rejected" >&2; exit 1; }
|
||||
|
||||
# Exercise the scanner against the complete proposed policy, including these
|
||||
# uncommitted exporter files, so the next clean commit cannot reveal a
|
||||
# self-triggering detector or a missing reviewed path.
|
||||
proposed_tree=$temporary/proposed
|
||||
mkdir -p "$proposed_tree"
|
||||
while IFS= read -r line || [[ -n $line ]]; do
|
||||
[[ -n $line && ${line:0:1} != '#' ]] || continue
|
||||
[[ -f $project_root/$line && ! -L $project_root/$line ]] || {
|
||||
echo "reviewed allowlist path is missing or not regular: $line" >&2
|
||||
exit 1
|
||||
}
|
||||
mkdir -p "$proposed_tree/$(dirname -- "$line")"
|
||||
cp -p -- "$project_root/$line" "$proposed_tree/$line"
|
||||
done <"$project_root/scripts/public-snapshot.allow"
|
||||
snapshot_validate_export_tree "$proposed_tree"
|
||||
(cd "$proposed_tree" && bash scripts/check-licenses.sh)
|
||||
private_home_pattern='/'home'/'cole
|
||||
private_commit_pattern='80bed136''75e8'
|
||||
private_tag_pattern='prototype-''2025'
|
||||
if LC_ALL=C grep -IRq -e "$private_home_pattern" -e "$private_commit_pattern" -e "$private_tag_pattern" "$proposed_tree"; then
|
||||
echo "public allowlist contains a private path or history identifier" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
safe_tree=$temporary/safe
|
||||
mkdir -p "$safe_tree"
|
||||
printf 'ordinary reviewed source\n' >"$safe_tree/source.go"
|
||||
snapshot_validate_export_tree "$safe_tree"
|
||||
|
||||
empty_tree=$temporary/empty
|
||||
mkdir -p "$empty_tree"
|
||||
: >"$empty_tree/empty.txt"
|
||||
snapshot_validate_export_tree "$empty_tree"
|
||||
|
||||
symlink_tree=$temporary/symlink
|
||||
mkdir -p "$symlink_tree"
|
||||
printf 'target\n' >"$symlink_tree/target"
|
||||
ln -s target "$symlink_tree/link"
|
||||
if snapshot_validate_export_tree "$symlink_tree" >/dev/null 2>&1; then
|
||||
echo "symlink tree was accepted" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
oversized_tree=$temporary/oversized
|
||||
mkdir -p "$oversized_tree"
|
||||
printf '123456789\n' >"$oversized_tree/large.txt"
|
||||
if SNAPSHOT_MAX_FILE_BYTES=8 snapshot_validate_export_tree "$oversized_tree" >/dev/null 2>&1; then
|
||||
echo "oversized file was accepted" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
binary_tree=$temporary/binary
|
||||
mkdir -p "$binary_tree"
|
||||
printf 'text\000binary\n' >"$binary_tree/blob.dat"
|
||||
if snapshot_validate_export_tree "$binary_tree" >/dev/null 2>&1; then
|
||||
echo "binary file was accepted" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
private_tree=$temporary/private
|
||||
mkdir -p "$private_tree"
|
||||
printf '/%s/%s/project/private.db\n' home developer >"$private_tree/path.txt"
|
||||
if snapshot_validate_export_tree "$private_tree" >/dev/null 2>&1; then
|
||||
echo "private filesystem path was accepted" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
private_commit_tree=$temporary/private-commit
|
||||
mkdir -p "$private_commit_tree"
|
||||
printf 'Private development source: %040d\n' 0 >"$private_commit_tree/ledger.txt"
|
||||
if snapshot_validate_export_tree "$private_commit_tree" >/dev/null 2>&1; then
|
||||
echo "private commit identifier was accepted" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
private_repository_tree=$temporary/private-repository
|
||||
mkdir -p "$private_repository_tree"
|
||||
printf 'gamertan/%s%s\n' 'sandwich-hime-' 'dev' >"$private_repository_tree/source.txt"
|
||||
if snapshot_validate_export_tree "$private_repository_tree" >/dev/null 2>&1; then
|
||||
echo "private repository identifier was accepted" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
credential_tree=$temporary/credential
|
||||
mkdir -p "$credential_tree"
|
||||
printf '%s%s\n' '-----BEGIN ' 'PRIVATE KEY-----' >"$credential_tree/secret.txt"
|
||||
if snapshot_validate_export_tree "$credential_tree" >/dev/null 2>&1; then
|
||||
echo "private key indicator was accepted" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Until these new exporter files themselves are committed, construct a
|
||||
# review-only policy containing the intersection of the reviewed policy and
|
||||
# the selected committed source ref. No repository or Git object is mutated.
|
||||
review_policy=$temporary/review.allow
|
||||
while IFS= read -r line || [[ -n $line ]]; do
|
||||
[[ -n $line && ${line:0:1} != '#' ]] || continue
|
||||
if git -C "$project_root" cat-file -e "HEAD:$line" 2>/dev/null &&
|
||||
git -C "$project_root" diff --quiet HEAD -- "$line"; then
|
||||
printf '%s\n' "$line" >>"$review_policy"
|
||||
fi
|
||||
done <"$project_root/scripts/public-snapshot.allow"
|
||||
|
||||
# A destination beneath the source worktree (including .git) must fail before
|
||||
# staging creation. This test never removes anything from the source tree.
|
||||
inside_name=himesan-export-must-not-exist-$$
|
||||
inside_destination=$project_root/.git/$inside_name
|
||||
[[ ! -e $inside_destination && ! -L $inside_destination ]] || {
|
||||
echo "in-worktree destination unexpectedly exists before test" >&2
|
||||
exit 1
|
||||
}
|
||||
if "$exporter" --source "$project_root" --ref HEAD --mode review \
|
||||
--allowlist "$review_policy" --destination "$inside_destination" >/dev/null 2>&1; then
|
||||
echo "exporter accepted a destination inside the source worktree" >&2
|
||||
exit 1
|
||||
fi
|
||||
[[ ! -e $inside_destination && ! -L $inside_destination ]] || {
|
||||
echo "failed in-worktree export created its destination" >&2
|
||||
exit 1
|
||||
}
|
||||
if find "$project_root/.git" -maxdepth 1 -name ".${inside_name}.himesan-public-export.*" -print -quit | grep -q .; then
|
||||
echo "failed in-worktree export created a staging directory" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# A linked worktree stores its private Git directory and shared common Git
|
||||
# directory outside that worktree root. Neither metadata location may become
|
||||
# an export destination. The isolated repositories live entirely in $temporary.
|
||||
linked_main=$temporary/linked-main
|
||||
linked_worktree=$temporary/linked-worktree
|
||||
git init -q "$linked_main"
|
||||
printf 'reviewed linked-worktree source\n' >"$linked_main/source.go"
|
||||
git -C "$linked_main" add source.go
|
||||
git -C "$linked_main" -c user.name='Snapshot Test' -c user.email='snapshot@example.invalid' \
|
||||
commit -qm 'seed isolated exporter test'
|
||||
git -C "$linked_main" worktree add -q --detach "$linked_worktree" HEAD
|
||||
linked_policy=$temporary/linked.allow
|
||||
printf 'source.go\n' >"$linked_policy"
|
||||
linked_git_dir=$(git -C "$linked_worktree" rev-parse --absolute-git-dir)
|
||||
linked_common_dir=$(git -C "$linked_worktree" rev-parse --git-common-dir)
|
||||
if [[ $linked_common_dir != /* ]]; then
|
||||
linked_common_dir=$linked_worktree/$linked_common_dir
|
||||
fi
|
||||
linked_common_dir=$(snapshot_realpath_existing "$linked_common_dir")
|
||||
|
||||
assert_metadata_destination_rejected() {
|
||||
local label=$1
|
||||
local parent=$2
|
||||
local name=$3
|
||||
local rejected_destination=$parent/$name
|
||||
[[ ! -e $rejected_destination && ! -L $rejected_destination ]] || {
|
||||
echo "$label destination unexpectedly exists before test" >&2
|
||||
exit 1
|
||||
}
|
||||
if "$exporter" --source "$linked_worktree" --ref HEAD --mode review \
|
||||
--allowlist "$linked_policy" --destination "$rejected_destination" >/dev/null 2>&1; then
|
||||
echo "exporter accepted destination inside $label" >&2
|
||||
exit 1
|
||||
fi
|
||||
[[ ! -e $rejected_destination && ! -L $rejected_destination ]] || {
|
||||
echo "failed $label export created its destination" >&2
|
||||
exit 1
|
||||
}
|
||||
if find "$parent" -maxdepth 1 -name ".${name}.himesan-public-export.*" -print -quit | grep -q .; then
|
||||
echo "failed $label export created a staging directory" >&2
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
assert_metadata_destination_rejected 'linked-worktree Git directory' "$linked_git_dir" linked-private-destination
|
||||
assert_metadata_destination_rejected 'shared Git common directory' "$linked_common_dir" linked-common-destination
|
||||
|
||||
first=$temporary/public-one
|
||||
second=$temporary/public-two
|
||||
"$exporter" --source "$project_root" --ref HEAD --mode review \
|
||||
--allowlist "$review_policy" --destination "$first" >/dev/null
|
||||
"$exporter" --source "$project_root" --ref HEAD --mode review \
|
||||
--allowlist "$review_policy" --destination "$second" >/dev/null
|
||||
diff -r --no-dereference "$first" "$second" >/dev/null
|
||||
(cd "$first" && sha256sum -c PUBLIC-SNAPSHOT.sha256 >/dev/null)
|
||||
|
||||
for excluded in .git .gitea .github private history internal/integration go.work; do
|
||||
[[ ! -e $first/$excluded && ! -L $first/$excluded ]] || {
|
||||
echo "excluded path reached snapshot: $excluded" >&2
|
||||
exit 1
|
||||
}
|
||||
done
|
||||
[[ -f $first/sando/component.go ]] || { echo "reviewed runtime source was not exported" >&2; exit 1; }
|
||||
[[ -f $first/PUBLIC-SNAPSHOT.json && -f $first/PUBLIC-SNAPSHOT.sha256 ]] || {
|
||||
echo "public provenance files are missing" >&2
|
||||
exit 1
|
||||
}
|
||||
grep -q '"schema_version":2' "$first/PUBLIC-SNAPSHOT.json"
|
||||
grep -q '"export_mode":"review"' "$first/PUBLIC-SNAPSHOT.json"
|
||||
if grep -Fq "$project_root" "$first/PUBLIC-SNAPSHOT.json" \
|
||||
|| grep -Fq "$project_root" "$first/PUBLIC-SNAPSHOT.sha256" \
|
||||
|| grep -q '@' "$first/PUBLIC-SNAPSHOT.json" \
|
||||
|| grep -Eq '"(commit|tree|source_date_epoch)"' "$first/PUBLIC-SNAPSHOT.json"; then
|
||||
echo "public provenance exposed a checkout path or email" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
occupied=$temporary/occupied
|
||||
mkdir -p "$occupied"
|
||||
printf 'do not delete\n' >"$occupied/owner-marker"
|
||||
if "$exporter" --source "$project_root" --ref HEAD --mode review \
|
||||
--allowlist "$review_policy" --destination "$occupied" >/dev/null 2>&1; then
|
||||
echo "exporter accepted an existing destination" >&2
|
||||
exit 1
|
||||
fi
|
||||
grep -q 'do not delete' "$occupied/owner-marker"
|
||||
|
||||
status=$(git -C "$project_root" status --porcelain=v1 --untracked-files=all)
|
||||
release_destination=$temporary/release
|
||||
if snapshot_status_is_clean "$status"; then
|
||||
"$exporter" --source "$project_root" --ref HEAD --mode release \
|
||||
--destination "$release_destination" >/dev/null
|
||||
else
|
||||
if "$exporter" --source "$project_root" --ref HEAD --mode release \
|
||||
--destination "$release_destination" >"$temporary/release.log" 2>&1; then
|
||||
echo "release export accepted a dirty source" >&2
|
||||
exit 1
|
||||
fi
|
||||
grep -q 'release source worktree is dirty' "$temporary/release.log"
|
||||
[[ ! -e $release_destination ]] || { echo "failed release created a destination" >&2; exit 1; }
|
||||
fi
|
||||
|
||||
echo "public snapshot export checks passed"
|
||||
Executable
+25
@@ -0,0 +1,25 @@
|
||||
#!/usr/bin/env bash
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
repo_root=$(CDPATH= cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd)
|
||||
temporary=$(mktemp -d "${TMPDIR:-/tmp}/himesan-consumer.XXXXXXXX")
|
||||
temporary=$(CDPATH= cd -- "$temporary" && pwd -P)
|
||||
cleanup() { rm -rf -- "$temporary"; }
|
||||
trap cleanup EXIT HUP INT TERM
|
||||
|
||||
mkdir -p "$temporary/golden"
|
||||
cp "$repo_root/internal/compiler/testdata/golden/basic.sando" "$temporary/golden/page.sando"
|
||||
GOTOOLCHAIN=local go build -trimpath -o "$temporary/himesan" "$repo_root/cmd/himesan"
|
||||
"$temporary/himesan" generate "$temporary/golden/page.sando"
|
||||
(
|
||||
cd "$temporary"
|
||||
GOTOOLCHAIN=local go mod init example.test/himesan-consumer
|
||||
GOTOOLCHAIN=local go mod edit -go=1.25
|
||||
GOTOOLCHAIN=local go mod edit -replace=gamertan.com/sandwich-hime/sando="$repo_root/sando"
|
||||
GOTOOLCHAIN=local go mod tidy
|
||||
GOTOOLCHAIN=local go test ./...
|
||||
)
|
||||
|
||||
printf 'Temporary Go 1.25 consumer compiled generated output successfully.\n'
|
||||
@@ -101,6 +101,7 @@ if [[ "$browser_status" != 404 ]]; then
|
||||
fi
|
||||
|
||||
scratch_dir=$(mktemp -d "${TMPDIR:-/tmp}/himesan-public-install.XXXXXXXX")
|
||||
scratch_dir=$(CDPATH= cd -- "$scratch_dir" && pwd -P)
|
||||
cleanup() {
|
||||
if [[ -n "${scratch_dir:-}" && -d "$scratch_dir" ]]; then
|
||||
chmod -R u+w -- "$scratch_dir" 2>/dev/null || true
|
||||
|
||||
Executable
+35
@@ -0,0 +1,35 @@
|
||||
#!/usr/bin/env bash
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
repo_root=$(CDPATH= cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd)
|
||||
cd "$repo_root"
|
||||
|
||||
chrome=${HIMESAN_CHROME:-}
|
||||
if [[ -z "$chrome" ]]; then
|
||||
case "$(uname -s)" in
|
||||
Darwin) chrome='/Applications/Google Chrome.app/Contents/MacOS/Google Chrome' ;;
|
||||
Linux)
|
||||
for candidate in google-chrome-stable google-chrome chromium chromium-browser; do
|
||||
if command -v "$candidate" >/dev/null 2>&1; then
|
||||
chrome=$(command -v "$candidate")
|
||||
break
|
||||
fi
|
||||
done
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
if [[ -z "$chrome" || ! -f "$chrome" || ! -x "$chrome" ]]; then
|
||||
printf 'error: set HIMESAN_CHROME to a reviewed Chrome or Chromium executable\n' >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
printf 'Real-browser executable: '
|
||||
"$chrome" --version
|
||||
printf 'Go toolchain: '
|
||||
go version
|
||||
HIMESAN_CHROME="$chrome" go test -count=1 -tags=himesan_browser_evidence \
|
||||
./internal/devserver -run '^TestRealBrowserDevelopmentClient$' -v
|
||||
go test -count=1 ./internal/devserver \
|
||||
-run '^(TestSupervisorBuildsSwapsAndCleansUp|TestSupervisorClearsTargetWhenCurrentApplicationExits)$' -v
|
||||
@@ -65,6 +65,7 @@ run_module_checks . "compiler module"
|
||||
|
||||
log "compiler module: go build"
|
||||
build_dir=$(mktemp -d "${TMPDIR:-/tmp}/himesan-verify.XXXXXXXX")
|
||||
build_dir=$(CDPATH= cd -- "$build_dir" && pwd -P)
|
||||
cleanup() {
|
||||
if [[ -n "${build_dir:-}" && -d "$build_dir" ]]; then
|
||||
rm -rf -- "$build_dir"
|
||||
|
||||
Reference in New Issue
Block a user