2026-07-19 05:58:17 +09:00
|
|
|
#!/usr/bin/env bash
|
|
|
|
|
set -euo pipefail
|
|
|
|
|
|
|
|
|
|
cd "$(dirname "$0")/.."
|
|
|
|
|
|
|
|
|
|
document=docs/spec/contracts.md
|
|
|
|
|
test -f "$document"
|
|
|
|
|
|
|
|
|
|
for heading in \
|
|
|
|
|
"## HTTP contract" \
|
|
|
|
|
"## SQL contract" \
|
|
|
|
|
"## Identity encoding contract" \
|
|
|
|
|
"## Content identity contract" \
|
|
|
|
|
"## Environment contract" \
|
|
|
|
|
"## Supported-store contract" \
|
|
|
|
|
"## Deployment authority contract"; do
|
|
|
|
|
grep -Fx "$heading" "$document" >/dev/null
|
|
|
|
|
done
|
|
|
|
|
|
|
|
|
|
for ownership in \
|
|
|
|
|
'| HTTP | `src/Nuthatch/Api.hs`, `src/Nuthatch/App.hs` | `make check-product` |' \
|
|
|
|
|
'| SQL | `sql/`, `src/Nuthatch/Db.hs`, `src/Nuthatch/Protocol.hs` | `make check-storage-foundation` |' \
|
|
|
|
|
'| Identity encoding | `src/Nuthatch/Paths.hs` | `make test` |' \
|
|
|
|
|
'| Content identity | `src/Nuthatch/Streaming.hs`, `src/Nuthatch/S3.hs` | `make check-streaming` |' \
|
|
|
|
|
'| Environment | `src/Nuthatch/Config.hs` | `make check-runtime` |' \
|
|
|
|
|
'| Supported store | `src/Nuthatch/S3.hs` | `make check-protocol` |' \
|
|
|
|
|
'| Deployment authority | Deployment object-store IAM/policy; secret injection in `deploy/kubernetes/nuthatch.yaml.in` | `make check-auth` |'; do
|
|
|
|
|
grep -Fx "$ownership" "$document" >/dev/null
|
|
|
|
|
done
|
|
|
|
|
|
|
|
|
|
for path in \
|
|
|
|
|
src/Nuthatch/Api.hs \
|
|
|
|
|
src/Nuthatch/App.hs \
|
|
|
|
|
src/Nuthatch/Config.hs \
|
|
|
|
|
src/Nuthatch/Db.hs \
|
|
|
|
|
src/Nuthatch/Paths.hs \
|
|
|
|
|
src/Nuthatch/Protocol.hs \
|
|
|
|
|
src/Nuthatch/S3.hs \
|
|
|
|
|
src/Nuthatch/Streaming.hs \
|
2026-07-19 15:21:24 +09:00
|
|
|
sql/001_initial_schema.sql \
|
2026-07-19 05:58:17 +09:00
|
|
|
deploy/kubernetes/nuthatch.yaml.in \
|
|
|
|
|
tests/kind/lib.sh \
|
2026-07-19 15:21:24 +09:00
|
|
|
tests/kind/product-matrix-job.yaml.in; do
|
2026-07-19 05:58:17 +09:00
|
|
|
test -e "$path"
|
|
|
|
|
grep -F "$path" "$document" >/dev/null
|
|
|
|
|
done
|
|
|
|
|
|
|
|
|
|
if grep -Eiq '\b(TODO|TBD|unresolved|open question)\b' "$document"; then
|
|
|
|
|
printf '%s\n' "Durable contracts contain an unresolved marker" >&2
|
|
|
|
|
exit 1
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
grep -F 'e0240ab33521a1882fb647a79f7fd3c74c9b6348b29bdb14e572204517882859' "$document" >/dev/null
|
|
|
|
|
grep -F 'Public `GET /nuthatch.js`' "$document" >/dev/null
|
|
|
|
|
grep -F '`nuthatch-sha256`' "$document" >/dev/null
|
|
|
|
|
grep -F '`x-amz-meta-nuthatch-sha256`' "$document" >/dev/null
|
|
|
|
|
grep -F 'always streams the full body and computes its digest' "$document" >/dev/null
|
|
|
|
|
grep -F '`NUTHATCH_JWT_SECRET` contains at least 32 UTF-8 bytes.' "$document" >/dev/null
|
|
|
|
|
grep -F '`NUTHATCH_COOKIE_NAME`, `NUTHATCH_CSRF_COOKIE_NAME`, and' "$document" >/dev/null
|
|
|
|
|
grep -F '`NUTHATCH_OIDC_ADDITIONAL_AUDIENCES`' "$document" >/dev/null
|
|
|
|
|
grep -F '`users/` and `shared/`' "$document" >/dev/null
|
|
|
|
|
grep -F 'only for' "$document" >/dev/null
|
|
|
|
|
grep -F '`NUTHATCH_S3_BUCKET`' "$document" >/dev/null
|
|
|
|
|
grep -F 'authority over other buckets' "$document" >/dev/null
|
|
|
|
|
grep -F 'exclusive writer' "$document" >/dev/null
|
|
|
|
|
grep -F "object-store IAM or policy system enforces that scope" "$document" >/dev/null
|
2026-07-19 15:21:24 +09:00
|
|
|
grep -F "verifies denial against a different" "$document" >/dev/null
|
2026-07-19 05:58:17 +09:00
|
|
|
grep -F 'They are not product requirements' "$document" >/dev/null
|
|
|
|
|
|
|
|
|
|
printf '%s\n' "Durable implementation contracts passed"
|