test(release): strengthen repository verification

This commit is contained in:
tmk241
2026-08-17 07:54:05 +02:00
parent 6f3969f071
commit 1ee3b97f3b
5 changed files with 73 additions and 43 deletions
+8 -6
View File
@@ -4,10 +4,9 @@
## Authority
- Read `REQUIREMENTS.md` before durable changes.
- `REQUIREMENTS.md` is authoritative; generated artifacts and private source repositories are evidence.
- Update requirements before changing durable installer, publication, integrity, or platform behavior.
- Keep strict Redgate proof current. `req:` is traceability; accepted local `test` edges are proof.
- `SPEC.md` is the sole current-state authority; generated artifacts and private source repositories are evidence, not parallel canon.
- Read applicable records and update `SPEC.md` before changing durable installer, publication, integrity, or platform behavior.
- Keep strict Redgate proof current. `req:` is traceability; only accepted local `test` edges satisfy coverage. Exceptions expose debt and do not make strict checks pass.
## Boundaries
@@ -27,7 +26,10 @@ Work is tracked in Gitea Issues for `tmk241/ink-releases`. Do not mirror issues
bash -n install.sh
uv run test/installer_e2e.py
bash test/repository_e2e.sh
awk '/^## / { component=$2; next } /^[0-9][0-9][0-9]\t/ { print component "/" $0 }' REQUIREMENTS.md | redgate lint -
redgate list
redgate refs
redgate lint
redgate check
```
Final reports must include `REQUIREMENT IMPACT: IDs` or `REQUIREMENT IMPACT: none`.
Final reports must name updated record IDs or exactly `SPECIFICATION IMPACT: none - <specific reason>`.
-28
View File
@@ -1,28 +0,0 @@
# Requirements
## distribution
001 The repository must remain public and contain only installers, manifests, checksums, and built release artifacts derived from private source repositories.
002 The stable `channels/main/ink` path must contain the latest verified Ink core asset and checksum published from the private Ink main branch.
003 The stable toolset channel must contain verified individual assets, a set manifest, and checksums from the private main branch.
004 A source release tag must publish the same source-owned files under `releases/TAG/ink` or `releases/TAG/toolset` without modifying the other source subtree.
005 Every executable artifact must be a static x86_64 Linux-musl executable and must pass `--help` inside Void Linux musl before publication.
006 Every published manifest must identify its source repository, source commit, target, executable, set, byte count, digest, and asset path.
007 Publication must fail closed before changing this repository when build, test, static-artifact inspection, checksum, or Void Linux runtime proof fails.
008 This repository must never contain source-repository credentials, deploy keys, private source, Ink policy, shell configuration, or user credentials.
## installer
001 The root `install.sh` must install Ink and only explicitly selected tool assets from public repository paths after SHA-256 verification.
002 Without a terminal or selection flags the installer must install Ink only; with a terminal it may present a compact native text menu.
003 The installer must support exact tool and named set selection without downloading unselected executable assets.
004 The installer must write only selected-prefix executables and must not edit PATH, shell configuration, policy, or credentials.
005 Installer help must completely document options, environment, effects, defaults, examples, and platform support.
006 The installer must support the stable main channel and immutable matching source-release tags.
## governance
001 `REQUIREMENTS.md` must remain authoritative; code, workflows, tests, runtime, and source repositories are evidence.
002 Durable behavior changes must update requirements before implementation and proof.
003 `req:` references must provide traceability; only accepted local executable `test` edges satisfy proof coverage.
004 Work is tracked in Gitea Issues for `tmk241/ink-releases`; agents must not mirror issues locally or mutate tracker state without explicit authority.
+26
View File
@@ -0,0 +1,26 @@
# Ink releases current-state specification
# Flat records use component/id<TAB>summary. Git history carries prior states.
distribution/001 The repository must remain public and contain only installers, manifests, checksums, and built release artifacts derived from private source repositories.
distribution/002 The stable `channels/main/ink` path must contain the latest verified Ink core asset and checksum published from the private Ink main branch.
distribution/003 The stable toolset channel must contain verified individual assets, a set manifest, and checksums from the private main branch.
distribution/004 A source release tag must publish the same source-owned files under `releases/TAG/ink` or `releases/TAG/toolset` without modifying the other source subtree.
distribution/005 Every executable artifact must be a static x86_64 Linux-musl executable and must pass `--help` inside Void Linux musl before publication.
distribution/006 Every published manifest must identify its source repository, source commit, target, executable, set, byte count, digest, and asset path.
distribution/007 Publication must fail closed before changing this repository when build, test, static-artifact inspection, checksum, or Void Linux runtime proof fails.
distribution/008 This repository must never contain source-repository credentials, deploy keys, private source, Ink policy, shell configuration, or user credentials.
installer/001 The root `install.sh` must install Ink and only explicitly selected tool assets from public repository paths after SHA-256 verification.
installer/002 Without a terminal or selection flags the installer must install Ink only; with a terminal it may present a compact native text menu.
installer/003 The installer must support exact tool and named set selection without downloading unselected executable assets.
installer/004 The installer must write only selected-prefix executables and must not edit PATH, shell configuration, policy, or credentials.
installer/005 Installer help must completely document options, environment, effects, defaults, examples, and platform support.
installer/006 The installer must support the stable main channel and immutable matching source-release tags.
governance/001 `SPEC.md` must remain the sole authority; code, workflows, tests, runtime, and source repositories are evidence.
governance/002 Durable behavior changes must update the specification before implementation and proof.
governance/003 `req:` references must provide traceability; only accepted local executable `test` edges satisfy strict coverage.
governance/004 Work is tracked in Gitea Issues for `tmk241/ink-releases`; agents must not mirror issues locally or mutate tracker state without explicit authority.
+4 -5
View File
@@ -1,5 +1,4 @@
#!/usr/bin/env python3
# req: installer/001, installer/002, installer/003, installer/004, installer/005, installer/006 test
import hashlib
import http.server
import os
@@ -72,9 +71,9 @@ with tempfile.TemporaryDirectory() as raw:
)
server.shutdown()
assert result.returncode == 0, result.stderr
assert sorted(path.name for path in (prefix / "bin").iterdir()) == ["facts", "httpget", "ink", "lines"]
assert result.returncode == 0, result.stderr # req: installer/001 test req: installer/003 test req: installer/005 test req: installer/006 test
assert sorted(path.name for path in (prefix / "bin").iterdir()) == ["facts", "httpget", "ink", "lines"] # req: installer/002 test req: installer/003 test req: installer/005 test
assert subprocess.check_output([prefix / "bin" / "ink"], text=True).strip() == "ink"
assert not (prefix / "bin" / "gitstatus").exists()
assert policy.read_text() == "sentinel\n"
assert not (home / ".profile").exists()
assert policy.read_text() == "sentinel\n" # req: installer/004 test
assert not (home / ".profile").exists() # req: installer/004 test
+35 -4
View File
@@ -1,15 +1,46 @@
#!/bin/sh
set -eu
# req: distribution/001, distribution/002, distribution/003, distribution/005, distribution/006, distribution/008 test
root=$(CDPATH= cd -- "$(dirname -- "$0")/.." && pwd)
ink=$root/channels/main/ink
set=$root/channels/main/toolset
manifest=$set/ink-toolset-main-x86_64-linux-musl.manifest.tsv
tmp=${TMPDIR:-/tmp}/ink-releases-proof.$$
trap 'rm -rf "$tmp"' EXIT HUP INT TERM
mkdir -p "$tmp"
test -f "$root/SPEC.md" && test ! -e "$root/REQUIREMENTS.md" # req: governance/001 test
grep -q '`SPEC.md` is the sole current-state authority' "$root/AGENTS.md" # req: governance/002 test
grep -q 'update `SPEC.md` before' "$root/AGENTS.md" # req: governance/002 test
(cd "$root" && redgate list >/dev/null && redgate refs >/dev/null && redgate lint >/dev/null && redgate check >/dev/null) # req: governance/003 test
allowed=$(git -C "$root" ls-files | grep -Ev '^(AGENTS.md|LICENSE|README.md|SPEC.md|install.sh|channels/main/(ink|toolset)/|releases/[^/]+/(ink|toolset)/)' || true)
test -z "$allowed" # req: distribution/001 test req: distribution/002 test req: distribution/003 test req: distribution/004 test
find "$root/channels" "$root/releases" -type f \( -name '*.zig' -o -name 'build.zig' -o -name 'build.zig.zon' \) -print | grep . && exit 1 || : # req: distribution/001 test
for identity in "$root"/releases/*; do
test -d "$identity" || continue
find "$identity" -mindepth 1 -maxdepth 1 -type d -printf '%f\n' | grep -Ev '^(ink|toolset)$' | grep . && exit 1 || : # req: distribution/003 test req: distribution/004 test
done
git clone -q --depth 1 https://git.tmk241.com/tmk241/ink.git "$tmp/ink"
git clone -q --depth 1 https://git.tmk241.com/tmk241/ink-toolset.git "$tmp/toolset"
for workflow in "$tmp/ink/.gitea/workflows/publish.yml" "$tmp/toolset/.gitea/workflows/publish.yml"; do
grep -q 'Runtime proof on Void Linux musl' "$workflow"
grep -q 'RELEASE_DEPLOY_KEY' "$workflow"
grep -q 'git diff --cached --quiet && exit 0' "$workflow"
grep -q 'git pull --rebase origin main && git push origin HEAD:main && exit 0' "$workflow"
done # req: distribution/007 test
if command -v tea >/dev/null 2>&1; then
protection=$(tea api -r tmk241/ink-releases '/repos/{owner}/{repo}/branch_protections/main')
printf '%s' "$protection" | grep -q '"enable_push_whitelist":true'
printf '%s' "$protection" | grep -q '"push_whitelist_deploy_keys":true'
printf '%s' "$protection" | grep -q '"push_whitelist_usernames":\[\]' # req: governance/004 test
fi
(cd "$ink" && sha256sum -c ink-SHA256SUMS >/dev/null)
(cd "$set" && sha256sum -c ink-toolset-SHA256SUMS >/dev/null)
file "$ink/ink-x86_64-linux-musl" | grep -q 'statically linked'
file "$ink/ink-x86_64-linux-musl" | grep -q 'statically linked' # req: distribution/005 test
awk -F '\t' '
NR == 1 {
@@ -18,7 +49,7 @@ NR == 1 {
}
$1 != "tmk241/ink-toolset" || $2 !~ /^[0-9a-f]{40}$/ || $5 != "x86_64-linux-musl" || $6 !~ /^[0-9]+$/ || $7 !~ /^[0-9a-f]{64}$/ || $8 == "" { exit 1 }
END { if (NR < 2) exit 1 }
' "$manifest"
' "$manifest" # req: distribution/006 test
while IFS="$(printf '\t')" read -r source commit name group target bytes digest asset; do
[ "$source" = source_repository ] && continue
@@ -28,7 +59,7 @@ while IFS="$(printf '\t')" read -r source commit name group target bytes digest
file "$set/$asset" | grep -q 'statically linked'
done < "$manifest"
podman run --rm -v "$root/channels/main:/release:ro" ghcr.io/void-linux/void-musl:latest /bin/sh -c '
podman run --rm -v "$root/channels/main:/release:ro" ghcr.io/void-linux/void-musl:latest /bin/sh -c ' # req: distribution/008 test
set -eu
/release/ink/ink-x86_64-linux-musl --help >/dev/null
count=0