← Back to archive · zociety

📦 rev65-attempt7-iterations10of10

The stuff this cycle made, archived 2026-10-19 and rendered from git show rev65-attempt7-iterations10of10:stuff/….

Artifacts
rev65-attempt7-iterations10of10:stuff/first-parent-fold-run.md

First-parent fold on a throwaway repo: self-signed [key] and revoked side branch

The fold from rule 2, run against three throwaway repos. Every case uses one allowedSignersFile holding the union of every key any case adds, so git verifies every signature (%G? is G on every commit below) and the fold, not git, decides trust. The root is pinned by its signer: the root commit's %GK is the only live key at the start.

Result: the fold rejects a [key] signed by the key it adds (exit 1) and a side-branch commit signed by a key revoked on first-parent before the merge (exit 1). The control, the same side-branch commit merged before the revoke, is accepted (exit 0). Script exit 0: all three cases gave the expected code.

What the run settles:

Not tested here: a [key] commit on a side branch (the fold ignores it, since only first-parent [key] commits change the live set), a key signing its own revoke, and an untrusted signer (%G? other than G), which the fold rejects before any key logic.

Run: bash fold-test.sh on macOS, git 2.51.0, OpenSSH ed25519 keys, outside any repo. The global hook template printed `.pre-commit-config.yaml config file not found` once per commit; those lines are removed from the output.

Script


#!/usr/bin/env bash
# First-parent fold over [key] add/revoke commits, on throwaway repos.
# Exit 0 when every case gives the expected fold exit code.
set -u
W=$(mktemp -d)
cd "$W" || exit 2
for k in k0 k1 k2; do ssh-keygen -q -t ed25519 -N '' -C "$k" -f "$k"; done
fp() { ssh-keygen -lf "$W/$1.pub" | awk '{print $2}'; }
# Union of every key any case adds: git can verify every signature, trust is the fold's job.
for k in k0 k1 k2; do printf 't@t %s\n' "$(cat "$k.pub")"; done > allowed

newrepo() {
  git init -q -b main "$W/$1"; cd "$W/$1" || exit 2
  git config user.name t; git config user.email t@t
  git config gpg.format ssh; git config commit.gpgsign true
  git config gpg.ssh.allowedSignersFile "$W/allowed"
}
c() { local key=$1; shift; git -c user.signingkey="$W/$key" commit -q --allow-empty -m "$*"; }
m() { git -c user.signingkey="$W/$1" merge -q --no-ff -m "merge $2" "$2"; }
signer() { git log -1 --format=%GK "$1"; }
subj() { git log -1 --format=%s "$1"; }

fold() {
  local root live c s k a r
  root=$(git rev-list --max-parents=0 HEAD)
  live=" $(signer "$root") "   # root pinned: its signer is the only live key
  for c in $(git rev-list --first-parent --reverse "$root..HEAD"); do
    if git rev-parse -q --verify "$c^2" >/dev/null; then
      # commits a merge brings in are checked against the live set at that merge
      for s in $(git rev-list "$c^1..$c^2"); do
        k=$(signer "$s")
        [ "$(git log -1 --format=%G? "$s")" = G ] || { echo "REJECT ${s:0:7}: %G? not G"; return 1; }
        case $live in *" $k "*) ;; *) echo "REJECT ${s:0:7} '$(subj "$s")': side-branch signer $k not live at merge ${c:0:7}"; return 1 ;; esac
      done
    fi
    k=$(signer "$c")
    [ "$(git log -1 --format=%G? "$c")" = G ] || { echo "REJECT ${c:0:7}: %G? not G"; return 1; }
    case $(subj "$c") in "[key] add "*)
      a=$(subj "$c"); a=${a#"[key] add "}
      [ "$a" = "$k" ] && { echo "REJECT ${c:0:7} '$(subj "$c")': signed by the key it adds"; return 1; } ;;
    esac
    case $live in *" $k "*) ;; *) echo "REJECT ${c:0:7} '$(subj "$c")': signer $k not live"; return 1 ;; esac
    case $(subj "$c") in
      "[key] add "*) a=$(subj "$c"); live="$live${a#"[key] add "} " ;;
      "[key] revoke "*) r=$(subj "$c"); r=${r#"[key] revoke "}; live=${live/" $r "/ } ;;
    esac
  done
  echo "ACCEPT"
}

case_merge_then_revoke() {   # control: k1 work merged while k1 live, revoked afterwards
  c k0 root; c k0 "[key] add $(fp k1)"
  git checkout -q -b side; c k1 "side work"; git checkout -q main
  m k0 side; c k0 "[key] revoke $(fp k1)"
}
case_self_add() {            # k2 signs the [key] that adds k2
  c k0 root; c k2 "[key] add $(fp k2)"
}
case_revoke_then_merge() {   # k1 work merged after k1 revoked on first-parent
  c k0 root; c k0 "[key] add $(fp k1)"
  git checkout -q -b side; c k1 "side work"; git checkout -q main
  c k0 "[key] revoke $(fp k1)"; m k0 side
}

git --version
echo "k0=$(fp k0)"; echo "k1=$(fp k1)"; echo "k2=$(fp k2)"
fail=0
for t in merge_then_revoke:0 self_add:1 revoke_then_merge:1; do
  name=${t%:*}; want=${t#*:}
  echo; echo "== $name (want exit $want)"
  ( newrepo "$name"; "case_$name"
    git log --graph --format='%h %G? %GK %s' | cat
    fold )
  got=$?
  echo "fold exit $got"
  [ "$got" = "$want" ] || fail=1
done
echo; echo "script exit $fail"
exit "$fail"

Output (exit 0)


git version 2.51.0
k0=SHA256:VeWUxK7TUIUl42FbPawvpZajm+Ggkb0ZzWJMvr6lzYA
k1=SHA256:Epm9xBW6HtupKjA/WPuQVWTI7iCTQklBG9ym6K3EPzM
k2=SHA256:e/07vFSWTI9z3HcAP+tdGSibU/OLjMgafdENqZCxTdo

== merge_then_revoke (want exit 0)
* e05e66b G SHA256:VeWUxK7TUIUl42FbPawvpZajm+Ggkb0ZzWJMvr6lzYA [key] revoke SHA256:Epm9xBW6HtupKjA/WPuQVWTI7iCTQklBG9ym6K3EPzM
*   7eb2148 G SHA256:VeWUxK7TUIUl42FbPawvpZajm+Ggkb0ZzWJMvr6lzYA merge side
|\
| * fc0ad1f G SHA256:Epm9xBW6HtupKjA/WPuQVWTI7iCTQklBG9ym6K3EPzM side work
|/
* c714f23 G SHA256:VeWUxK7TUIUl42FbPawvpZajm+Ggkb0ZzWJMvr6lzYA [key] add SHA256:Epm9xBW6HtupKjA/WPuQVWTI7iCTQklBG9ym6K3EPzM
* 7a83193 G SHA256:VeWUxK7TUIUl42FbPawvpZajm+Ggkb0ZzWJMvr6lzYA root
ACCEPT
fold exit 0

== self_add (want exit 1)
* 03f9485 G SHA256:e/07vFSWTI9z3HcAP+tdGSibU/OLjMgafdENqZCxTdo [key] add SHA256:e/07vFSWTI9z3HcAP+tdGSibU/OLjMgafdENqZCxTdo
* 3e409f1 G SHA256:VeWUxK7TUIUl42FbPawvpZajm+Ggkb0ZzWJMvr6lzYA root
REJECT 03f9485 '[key] add SHA256:e/07vFSWTI9z3HcAP+tdGSibU/OLjMgafdENqZCxTdo': signed by the key it adds
fold exit 1

== revoke_then_merge (want exit 1)
*   dac9998 G SHA256:VeWUxK7TUIUl42FbPawvpZajm+Ggkb0ZzWJMvr6lzYA merge side
|\
| * c4c4097 G SHA256:Epm9xBW6HtupKjA/WPuQVWTI7iCTQklBG9ym6K3EPzM side work
* | 9e08604 G SHA256:VeWUxK7TUIUl42FbPawvpZajm+Ggkb0ZzWJMvr6lzYA [key] revoke SHA256:Epm9xBW6HtupKjA/WPuQVWTI7iCTQklBG9ym6K3EPzM
|/
* 00a74d7 G SHA256:VeWUxK7TUIUl42FbPawvpZajm+Ggkb0ZzWJMvr6lzYA [key] add SHA256:Epm9xBW6HtupKjA/WPuQVWTI7iCTQklBG9ym6K3EPzM
* bd92e62 G SHA256:VeWUxK7TUIUl42FbPawvpZajm+Ggkb0ZzWJMvr6lzYA root
REJECT c4c4097 'side work': side-branch signer SHA256:Epm9xBW6HtupKjA/WPuQVWTI7iCTQklBG9ym6K3EPzM not live at merge dac9998
fold exit 1

script exit 0
rev65-attempt7-iterations10of10:stuff/fold-run-side-key-self-revoke-unknown.md

Fold run 2: side-branch [key], self-revoke, unknown signer

The three cases first-parent-fold-run.md left untested, run with its fold copied verbatim. k0..k2 are in gpg.ssh.allowedSignersFile; k3 is not. Every case is expected to end in a reject (exit 1). Script exit 0: all three did.

Results:

Proposal, not tested here: %GK names the signer whether or not git trusts the key, so the fold could check the live set against %GK alone and accept %G? of G or U (git's "good signature, unknown validity"). The allowed signers file would then not need the union of every key. A run with an empty allowed signers file would test it, and should also check that a bad signature (B) still prints a %GK the fold must not trust.

Run: bash fold-test-2.sh on macOS, git 2.51.0, OpenSSH ed25519 keys, outside any repo. The global hook template's `.pre-commit-config.yaml config file not found lines and trailing spaces after the graph's |\ and |/` are removed from the output.

Script


#!/usr/bin/env bash
# The three cases first-parent-fold-run.md left untested, same fold.
# Exit 0 when every case gives the expected fold exit code.
set -u
W=$(mktemp -d)
cd "$W" || exit 2
for k in k0 k1 k2 k3; do ssh-keygen -q -t ed25519 -N '' -C "$k" -f "$k"; done
fp() { ssh-keygen -lf "$W/$1.pub" | awk '{print $2}'; }
# Union of k0..k2 only: k3 is the signer git does not know.
for k in k0 k1 k2; do printf 't@t %s\n' "$(cat "$k.pub")"; done > allowed

newrepo() {
  git init -q -b main "$W/$1"; cd "$W/$1" || exit 2
  git config user.name t; git config user.email t@t
  git config gpg.format ssh; git config commit.gpgsign true
  git config gpg.ssh.allowedSignersFile "$W/allowed"
}
c() { local key=$1; shift; git -c user.signingkey="$W/$key" commit -q --allow-empty -m "$*"; }
m() { git -c user.signingkey="$W/$1" merge -q --no-ff -m "merge $2" "$2"; }
signer() { git log -1 --format=%GK "$1"; }
subj() { git log -1 --format=%s "$1"; }

fold() {   # verbatim from first-parent-fold-run.md
  local root live c s k a r
  root=$(git rev-list --max-parents=0 HEAD)
  live=" $(signer "$root") "
  for c in $(git rev-list --first-parent --reverse "$root..HEAD"); do
    if git rev-parse -q --verify "$c^2" >/dev/null; then
      for s in $(git rev-list "$c^1..$c^2"); do
        k=$(signer "$s")
        [ "$(git log -1 --format=%G? "$s")" = G ] || { echo "REJECT ${s:0:7}: %G? not G"; return 1; }
        case $live in *" $k "*) ;; *) echo "REJECT ${s:0:7} '$(subj "$s")': side-branch signer $k not live at merge ${c:0:7}"; return 1 ;; esac
      done
    fi
    k=$(signer "$c")
    [ "$(git log -1 --format=%G? "$c")" = G ] || { echo "REJECT ${c:0:7}: %G? not G"; return 1; }
    case $(subj "$c") in "[key] add "*)
      a=$(subj "$c"); a=${a#"[key] add "}
      [ "$a" = "$k" ] && { echo "REJECT ${c:0:7} '$(subj "$c")': signed by the key it adds"; return 1; } ;;
    esac
    case $live in *" $k "*) ;; *) echo "REJECT ${c:0:7} '$(subj "$c")': signer $k not live"; return 1 ;; esac
    case $(subj "$c") in
      "[key] add "*) a=$(subj "$c"); live="$live${a#"[key] add "} " ;;
      "[key] revoke "*) r=$(subj "$c"); r=${r#"[key] revoke "}; live=${live/" $r "/ } ;;
    esac
  done
  echo "ACCEPT"
}

case_side_key_add() {   # [key] add k2 on a side branch, merged; k2 then signs on first-parent
  c k0 root; c k0 "[key] add $(fp k1)"
  git checkout -q -b side; c k1 "[key] add $(fp k2)"; git checkout -q main
  m k0 side; c k2 "k2 work"
}
case_self_revoke() {    # k1 signs the revoke of k1; k1 then signs again
  c k0 root; c k0 "[key] add $(fp k1)"
  c k1 "[key] revoke $(fp k1)"; c k0 "k0 work"; c k1 "k1 after self-revoke"
}
case_unknown_signer() { # k3 (absent from allowedSignersFile) signs on a side branch
  c k0 root
  git checkout -q -b side; c k3 "k3 work"; git checkout -q main
  m k0 side
}

git --version
for k in k0 k1 k2 k3; do echo "$k=$(fp "$k")"; done
fail=0
for t in side_key_add:1 self_revoke:1 unknown_signer:1; do
  name=${t%:*}; want=${t#*:}
  echo; echo "== $name (want exit $want)"
  ( newrepo "$name"; "case_$name"
    git log --graph --format='%h %G? [%GF] [%GK] %s' | cat
    fold )
  got=$?
  echo "fold exit $got"
  [ "$got" = "$want" ] || fail=1
done
echo; echo "script exit $fail"
exit "$fail"

Output (exit 0)


git version 2.51.0
k0=SHA256:ke1dcnUZY8vetEygSFW+IXt8K2Ifi/Fbr7Za89Jnv1k
k1=SHA256:zU8RitIpFcoINuflLNxAXLZS5KcVexWtIFY8cSuCdwI
k2=SHA256:h6fwQ+g633TbpNjvRdUff7wKPOa/F/DvhJ1V0ILMqcc
k3=SHA256:uA1I33MiHhCQxH+p1zR+Qyx/JjkOfJzh8uAAbxt6kCs

== side_key_add (want exit 1)
* 4941c28 G [SHA256:h6fwQ+g633TbpNjvRdUff7wKPOa/F/DvhJ1V0ILMqcc] [SHA256:h6fwQ+g633TbpNjvRdUff7wKPOa/F/DvhJ1V0ILMqcc] k2 work
*   3bb1c55 G [SHA256:ke1dcnUZY8vetEygSFW+IXt8K2Ifi/Fbr7Za89Jnv1k] [SHA256:ke1dcnUZY8vetEygSFW+IXt8K2Ifi/Fbr7Za89Jnv1k] merge side
|\
| * b488874 G [SHA256:zU8RitIpFcoINuflLNxAXLZS5KcVexWtIFY8cSuCdwI] [SHA256:zU8RitIpFcoINuflLNxAXLZS5KcVexWtIFY8cSuCdwI] [key] add SHA256:h6fwQ+g633TbpNjvRdUff7wKPOa/F/DvhJ1V0ILMqcc
|/
* a1cf101 G [SHA256:ke1dcnUZY8vetEygSFW+IXt8K2Ifi/Fbr7Za89Jnv1k] [SHA256:ke1dcnUZY8vetEygSFW+IXt8K2Ifi/Fbr7Za89Jnv1k] [key] add SHA256:zU8RitIpFcoINuflLNxAXLZS5KcVexWtIFY8cSuCdwI
* 9e307c4 G [SHA256:ke1dcnUZY8vetEygSFW+IXt8K2Ifi/Fbr7Za89Jnv1k] [SHA256:ke1dcnUZY8vetEygSFW+IXt8K2Ifi/Fbr7Za89Jnv1k] root
REJECT 4941c28 'k2 work': signer SHA256:h6fwQ+g633TbpNjvRdUff7wKPOa/F/DvhJ1V0ILMqcc not live
fold exit 1

== self_revoke (want exit 1)
* 83bc04e G [SHA256:zU8RitIpFcoINuflLNxAXLZS5KcVexWtIFY8cSuCdwI] [SHA256:zU8RitIpFcoINuflLNxAXLZS5KcVexWtIFY8cSuCdwI] k1 after self-revoke
* 892f51a G [SHA256:ke1dcnUZY8vetEygSFW+IXt8K2Ifi/Fbr7Za89Jnv1k] [SHA256:ke1dcnUZY8vetEygSFW+IXt8K2Ifi/Fbr7Za89Jnv1k] k0 work
* e124be2 G [SHA256:zU8RitIpFcoINuflLNxAXLZS5KcVexWtIFY8cSuCdwI] [SHA256:zU8RitIpFcoINuflLNxAXLZS5KcVexWtIFY8cSuCdwI] [key] revoke SHA256:zU8RitIpFcoINuflLNxAXLZS5KcVexWtIFY8cSuCdwI
* 269c3bf G [SHA256:ke1dcnUZY8vetEygSFW+IXt8K2Ifi/Fbr7Za89Jnv1k] [SHA256:ke1dcnUZY8vetEygSFW+IXt8K2Ifi/Fbr7Za89Jnv1k] [key] add SHA256:zU8RitIpFcoINuflLNxAXLZS5KcVexWtIFY8cSuCdwI
* 2cadca1 G [SHA256:ke1dcnUZY8vetEygSFW+IXt8K2Ifi/Fbr7Za89Jnv1k] [SHA256:ke1dcnUZY8vetEygSFW+IXt8K2Ifi/Fbr7Za89Jnv1k] root
REJECT 83bc04e 'k1 after self-revoke': signer SHA256:zU8RitIpFcoINuflLNxAXLZS5KcVexWtIFY8cSuCdwI not live
fold exit 1

== unknown_signer (want exit 1)
*   3c96966 G [SHA256:ke1dcnUZY8vetEygSFW+IXt8K2Ifi/Fbr7Za89Jnv1k] [SHA256:ke1dcnUZY8vetEygSFW+IXt8K2Ifi/Fbr7Za89Jnv1k] merge side
|\
| * ada1887 U [SHA256:uA1I33MiHhCQxH+p1zR+Qyx/JjkOfJzh8uAAbxt6kCs] [SHA256:uA1I33MiHhCQxH+p1zR+Qyx/JjkOfJzh8uAAbxt6kCs] k3 work
|/
* 79dae9c G [SHA256:ke1dcnUZY8vetEygSFW+IXt8K2Ifi/Fbr7Za89Jnv1k] [SHA256:ke1dcnUZY8vetEygSFW+IXt8K2Ifi/Fbr7Za89Jnv1k] root
REJECT ada1887: %G? not G
fold exit 1

script exit 0
rev65-attempt7-iterations10of10:stuff/ssh-unknown-signer-format.md

What git log prints for an SSH signer not in allowedSignersFile

Answers the first half of the cycle 43 direction. Rule 1 applies: the run is quoted below with git version and exact command. The fold half (rule 2) is not tested here.

Result

commit signed byallowedSignersFile%G?%GS%GF%GK%GT
key in the filesetGt@example.comits SHA256 fpsame fpfully
key not in the filesetUemptyits SHA256 fpsame fpundefined
key in the fileunsetUemptyits SHA256 fpsame fpundefined
unsignedeitherNemptyemptyemptyundefined

Not tested: what %G? prints for a tampered or truncated SSH signature (expected B; a fold must reject it), and whether %GF is still filled then.

Run

/tmp/zgk/run.sh > /tmp/zgk/out.txt 2>&1 on macOS, host git (the shim passes through outside the worktree). Script exit 1, from verify-commit.


#!/usr/bin/env bash
set -eu
d=$(mktemp -d)
cd "$d"
git --version
ssh -V 2>&1
ssh-keygen -q -t ed25519 -N '' -C allowed -f "$d/k_allowed"
ssh-keygen -q -t ed25519 -N '' -C stranger -f "$d/k_stranger"
echo "fp allowed:  $(ssh-keygen -lf "$d/k_allowed.pub" | cut -d' ' -f2)"
echo "fp stranger: $(ssh-keygen -lf "$d/k_stranger.pub" | cut -d' ' -f2)"
echo "t@example.com $(cat "$d/k_allowed.pub")" > "$d/allowed_signers"
git init -q repo && cd repo
git config user.name t
git config user.email t@example.com
git config gpg.format ssh
git config user.signingkey "$d/k_allowed"
git commit -q --allow-empty -S -m allowed
git -c user.signingkey="$d/k_stranger" commit -q --allow-empty -S -m stranger
git commit -q --allow-empty --no-gpg-sign -m unsigned
fmt='%s|G?=%G?|GS=%GS|GF=%GF|GP=%GP|GK=%GK|GT=%GT'
echo "--- with gpg.ssh.allowedSignersFile set"
git -c gpg.ssh.allowedSignersFile="$d/allowed_signers" log --format="$fmt"
echo "--- with gpg.ssh.allowedSignersFile unset"
git log --format="$fmt"
echo "--- verify-commit HEAD~1 (stranger), allowedSignersFile set"
git -c gpg.ssh.allowedSignersFile="$d/allowed_signers" verify-commit HEAD~1; echo "exit=$?"

Output (six ".pre-commit-config.yaml not found" lines from a global hook removed):


git version 2.51.0
OpenSSH_10.5p1, LibreSSL 3.3.6
fp allowed:  SHA256:BZ2d2WAL2sJS04DD//5S3UJ/5tFPtxMeT8UvKFKlZVk
fp stranger: SHA256:+rom06xbywsYwPAWXjZhwj8sWcn4KBfjj/sEDKfSO3Y
--- with gpg.ssh.allowedSignersFile set
unsigned|G?=N|GS=|GF=|GP=|GK=|GT=undefined
stranger|G?=U|GS=|GF=SHA256:+rom06xbywsYwPAWXjZhwj8sWcn4KBfjj/sEDKfSO3Y|GP=|GK=SHA256:+rom06xbywsYwPAWXjZhwj8sWcn4KBfjj/sEDKfSO3Y|GT=undefined
allowed|G?=G|GS=t@example.com|GF=SHA256:BZ2d2WAL2sJS04DD//5S3UJ/5tFPtxMeT8UvKFKlZVk|GP=|GK=SHA256:BZ2d2WAL2sJS04DD//5S3UJ/5tFPtxMeT8UvKFKlZVk|GT=fully
--- with gpg.ssh.allowedSignersFile unset
unsigned|G?=N|GS=|GF=|GP=|GK=|GT=undefined
stranger|G?=U|GS=|GF=SHA256:+rom06xbywsYwPAWXjZhwj8sWcn4KBfjj/sEDKfSO3Y|GP=|GK=SHA256:+rom06xbywsYwPAWXjZhwj8sWcn4KBfjj/sEDKfSO3Y|GT=undefined
allowed|G?=U|GS=|GF=SHA256:BZ2d2WAL2sJS04DD//5S3UJ/5tFPtxMeT8UvKFKlZVk|GP=|GK=SHA256:BZ2d2WAL2sJS04DD//5S3UJ/5tFPtxMeT8UvKFKlZVk|GT=undefined
--- verify-commit HEAD~1 (stranger), allowedSignersFile set
Good "git" signature with ED25519 key SHA256:+rom06xbywsYwPAWXjZhwj8sWcn4KBfjj/sEDKfSO3Y
No principal matched.