Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -300,7 +300,15 @@ jobs:
go-version-file: src/go.mod
- name: Dependency sync check
run: python3 tests/contract/check-deps-sync.py

- name: Gonuts pin identity (one version, every carrier)
run: |
# Offline leg only: every go.mod that references the wallet fork
# must pin the manifest's version exactly (#791). The --latest
# staleness leg (pin must be the fork's newest stable tag) is a
# release-time verdict — scripts/release-check.sh — because
# failing every open PR the moment the fork tags would be noise.
bash tests/contract/gonuts-pin_test.sh
python3 tests/contract/check-gonuts-pin.py
- name: Toolchain parity (manifest is the single source of truth)
run: python3 tests/contract/check-toolchain-parity.py
- name: Stale import path check
Expand Down
6 changes: 6 additions & 0 deletions .ngit/act/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,12 @@ jobs:
go-version-file: src/go.mod
- name: Dependency sync check
run: python3 tests/contract/check-deps-sync.py
- name: Gonuts pin identity (one version, every carrier)
run: |
# Offline leg only (the ngit lane has no GitHub token for the
# fork-tag query; --latest is scripts/release-check.sh's verdict).
bash tests/contract/gonuts-pin_test.sh
python3 tests/contract/check-gonuts-pin.py
- name: Mirror and relay sync check
run: python3 tests/contract/check-mirror-sync.py
- name: Stale import path check
Expand Down
16 changes: 12 additions & 4 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -118,10 +118,18 @@ than inventing new harnesses.
- **gonuts-tollgate is our fork to maintain.** Upstream `elnosh/gonuts`
is dead (last release v0.4.2, 2025); we carry ~40 patches. Every
wallet-level fix lands in `OpenTollGate/gonuts-tollgate` first, is
tagged, then bumped here via the `replace` directive — the require lands
in every nested module that carries it: `src/`, `src/cli`, `src/merchant`
and `src/tollwallet`, four `go.mod` files today. Never fix a wallet bug
by patching around the fork locally.
tagged, then bumped here. Never fix a wallet bug by patching around
the fork locally. **The pin is ONE version, identical in every `go.mod`
that references the fork** — `tests/contract/check-gonuts-pin.py`
discovers carriers by glob and names
`packaging/build-inputs.json`'s `.gonuts.version` as the single
truth; never update a carrier count or list anywhere by hand (that is
exactly how #791 drifted). Bumps go through
`scripts/bump-gonuts.sh <tag>`, which rewrites the manifest and every
carrier together; `release-check` refuses to cut a release while the
fork has a newer stable tag than the one pinned. Pseudo-version
integration pins are for branches awaiting their tag and must not
outlive that tag on `main`.
- **bbolt persistence.** Keyset records (which own derivation counters)
are nested under mint-URL-named buckets; the DB has no transactions
spanning "fetch keysets + swap + save proofs". This is why counter
Expand Down
14 changes: 14 additions & 0 deletions changelog.d/791-gonuts-pin-fence.internal.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
- **The gonuts-tollgate pin is one version, everywhere, by fence.** The
+ wallet fork's pin drifted three ways in one release week (#791): a
+ carrier outside the documented four (scripts/token-recovery, pinned three
+ minors behind at v0.10.0) was missed by a hand bump, two open PRs pinned
+ the same lines to a tag and a pseudo-version, and a newer fork tag
+ carrying an open-P2 fix went unnoticed. `packaging/build-inputs.json` now
+ names the pin as `.gonuts.version`; `tests/contract/check-gonuts-pin.py`
+ discovers carriers by glob and refuses any disagreement (pre-commit,
+ offline), `scripts/bump-gonuts.sh` rewrites manifest and every carrier
+ together so a half-update cannot happen, and `release-check` refuses to
+ cut a release while the fork has a newer stable tag than the one pinned.
+ The stale token-recovery pin is raised to the current v0.13.0 in the same
+ change
+ ([#791](https://github.com/OpenTollGate/tollgate-module-basic-go/issues/791)).
11 changes: 11 additions & 0 deletions hooks/pre-commit
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,17 @@ if git diff --cached --name-only | grep -qE 'build-inputs\.json|tests/cloud-lab/
python3 tests/contract/check-toolchain-parity.py
fi

# The gonuts-tollgate pin is ONE version in every carrier (#791): the manifest
# names it, check-gonuts-pin.py discovers carriers by glob and refuses any
# disagreement — offline and fast, so it belongs here. go.sum is a trigger too:
# a tidy can move a pin without a go.mod hunk. The --latest staleness leg is
# deliberately NOT here — network in a hook means flaky commits; release-check
# owns that verdict.
if git diff --cached --name-only | grep -qE '(^|/)go\.mod$|(^|/)go\.sum$|^packaging/build-inputs\.json$'; then
echo "🔍 Checking the gonuts-tollgate pin (one version, everywhere)..."
python3 tests/contract/check-gonuts-pin.py
fi

# Single source of truth for the release version (VERSION at the repo root).
# Only runs when a file that carries the version is staged.
if git diff --cached --name-only \
Expand Down
5 changes: 5 additions & 0 deletions packaging/build-inputs.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@
"sha256": "d0f743b33e8d8945e6b1f432edd15785c70507121d6e2a723b21285eddf8b57b"
}
},
"gonuts": {
"repo": "https://github.com/OpenTollGate/gonuts-tollgate",
"version": "v0.13.0",
"comment": "The wallet fork every Go module pins IDENTICALLY. tests/contract/check-gonuts-pin.py enumerates carriers by glob (never a hand list) and fails on any disagreement with this value; scripts/bump-gonuts.sh rewrites manifest and every carrier together. Before a release is cut, release-check verifies this is the fork's latest stable tag. Pseudo-version integration pins are for branches only and must not outlive their tag on main."
},
"node": {
"version": "22.17.0",
"tarball_linux_x64": {
Expand Down
79 changes: 79 additions & 0 deletions scripts/bump-gonuts.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
#!/usr/bin/env bash
#
# bump-gonuts.sh — the ONLY supported way to move the gonuts-tollgate pin.
#
# Rewrites the single source of truth (packaging/build-inputs.json .gonuts.
# version) and EVERY go.mod carrier the fence discovers by glob, in one run,
# so a half-update cannot happen (#791: the hand-bumped PR #780 moved four
# carriers and left a fifth at v0.10.0).
#
# Usage:
# scripts/bump-gonuts.sh <tag> # e.g. scripts/bump-gonuts.sh v0.13.2
#
# Requires: go on PATH (each carrier gets `go get` + `go mod tidy` so its
# go.sum is recomputed honestly). Refuses anything that is not vMAJOR.MINOR.
# PATCH — pseudo-version integration pins (#771 pattern) are edited by hand
# on their branch, never through this script, and must not outlive their tag
# on main.
set -euo pipefail

ROOT="$(cd "$(dirname "$0")/.." && pwd)"
MANIFEST="$ROOT/packaging/build-inputs.json"
FENCE="tests/contract/check-gonuts-pin.py"

if [ $# -ne 1 ] || ! printf '%s' "$1" | grep -qE '^v[0-9]+\.[0-9]+\.[0-9]+$'; then
echo "usage: scripts/bump-gonuts.sh <tag> (e.g. v0.13.2 — a real tag of OpenTollGate/gonuts-tollgate)" >&2
exit 1
fi
NEW_VERSION="$1"

command -v go >/dev/null 2>&1 || {
echo "FATAL: go is not on PATH — every carrier's go.sum must be recomputed by the toolchain, not hand-edited" >&2
exit 1
}

OLD_VERSION="$(python3 -c "import json; print(json.load(open('$MANIFEST'))['gonuts']['version'])")"
if [ "$OLD_VERSION" = "$NEW_VERSION" ]; then
echo "manifest already pins $NEW_VERSION — nothing to do"
exit 0
fi
echo "gonuts-tollgate: $OLD_VERSION -> $NEW_VERSION"

# 1. The truth moves first; the fence below judges everything against it.
python3 - "$MANIFEST" "$NEW_VERSION" <<'PY'
import collections, json, sys
path, version = sys.argv[1], sys.argv[2]
with open(path) as fh:
data = json.load(fh, object_pairs_hook=collections.OrderedDict)
if "gonuts" not in data:
raise SystemExit(f"FATAL: {path} has no gonuts key — see #791 for the block to add")
data["gonuts"]["version"] = version
with open(path, "w") as fh:
json.dump(data, fh, indent=2)
fh.write("\n")
PY

# 2. Every discovered carrier moves, via the toolchain (never hand-edited sums).
carriers="$(python3 - <<'PY'
import sys
from pathlib import Path
sys.path.insert(0, "tests/contract")
import importlib.util
spec = importlib.util.spec_from_file_location("cgp", "tests/contract/check-gonuts-pin.py")
cgp = importlib.util.module_from_spec(spec)
spec.loader.exec_module(cgp)
for mod in cgp.carriers(Path(".")):
print(mod.parent)
PY
)"
for module_dir in $carriers; do
echo " bumping $module_dir"
(cd "$module_dir" && go get "github.com/OpenTollGate/gonuts-tollgate@$NEW_VERSION" && go mod tidy)
done

# 3. The verdict: identity must hold everywhere, and the pin must be a real,
# newest stable tag of the fork (network; this script is a maintainer
# action, not a hook).
python3 "$ROOT/$FENCE" --latest

echo "done: gonuts-tollgate $NEW_VERSION everywhere. Commit manifest + carriers together."
5 changes: 5 additions & 0 deletions scripts/release-check.sh
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,11 @@ run_deps_imports() {
python3 tests/contract/check-deps-sync.py >"$tmpdir/deps.log" 2>&1 || ok=1
python3 tests/contract/check-mirror-sync.py >>"$tmpdir/deps.log" 2>&1 || ok=1
python3 tests/contract/check-import-paths.py >>"$tmpdir/deps.log" 2>&1 || ok=1
# The gonuts pin: identity offline, plus the --latest release-time verdict
# (#791) — a release is not cut while the wallet fork has a newer stable
# tag than the one every carrier pins (the #705-in-v0.13.2 near-miss).
python3 tests/contract/check-gonuts-pin.py >>"$tmpdir/deps.log" 2>&1 || ok=1
python3 tests/contract/check-gonuts-pin.py --latest >>"$tmpdir/deps.log" 2>&1 || ok=1
if [ "$ok" = 0 ]; then
record "Dependency/import consistency" PASS
else
Expand Down
2 changes: 1 addition & 1 deletion scripts/token-recovery/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ module token-recovery

go 1.26.0

require github.com/OpenTollGate/gonuts-tollgate v0.10.0
require github.com/OpenTollGate/gonuts-tollgate v0.13.0

require (
github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da // indirect
Expand Down
4 changes: 2 additions & 2 deletions scripts/token-recovery/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERo
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 h1:TngWCqHvy9oXAN6lEVMRuU21PR1EtLVZJmdB18Gu3Rw=
github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk=
github.com/OpenTollGate/gonuts-tollgate v0.10.0 h1:vxxwGE0U5w3s53odXPmtGyHQ01yZJEKv/oqmhOdVz2k=
github.com/OpenTollGate/gonuts-tollgate v0.10.0/go.mod h1:4er8keqQ4yg3Zuz0w1BuXclKSeKOk3SGqsEl4b0oI7M=
github.com/OpenTollGate/gonuts-tollgate v0.13.0 h1:BtxPOSzbSED8ZytVzhEVBXrYgHRlSHqcgoWdhG5evds=
github.com/OpenTollGate/gonuts-tollgate v0.13.0/go.mod h1:4er8keqQ4yg3Zuz0w1BuXclKSeKOk3SGqsEl4b0oI7M=
github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da h1:KjTM2ks9d14ZYCvmHS9iAKVt9AyzRSqNU1qabPih5BY=
github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da/go.mod h1:eHEWzANqSiWQsof+nXEI9bUVUyV6F53Fp89EuCh2EAA=
github.com/aead/siphash v1.0.1 h1:FwHfE/T45KPKYuuSAKyyvE+oPWcaQ+CUmFW0bPlM+kg=
Expand Down
Loading