From ee2551b7b60be0558bde673f4b9789a2427a10f6 Mon Sep 17 00:00:00 2001 From: Pieter Viljoen Date: Thu, 22 Oct 2026 20:54:28 -0700 Subject: [PATCH 1/2] End Allexport at a set +a and Name the Character-Set Tier System The write guard kept allexport on after a later set +a or set +o allexport, so a plain assignment it no longer exported still read as exported and a git command after it was denied. Apply each set flag in order. The Character Set pointer called an enumeration that now holds emoji callout markers an ASCII tier system, so it names the character-set tier system. Co-Authored-By: Claude Sonnet 5.5 --- GOVERNANCE.md | 2 +- .../agent-safety/claude/gh-write-guard.py | 35 +++++++++++++++++-- 2 files changed, 34 insertions(+), 3 deletions(-) diff --git a/GOVERNANCE.md b/GOVERNANCE.md index 14e4cc562..a34d710ad 100644 --- a/GOVERNANCE.md +++ b/GOVERNANCE.md @@ -171,7 +171,7 @@ No comment, no docstring, and no instruction document names an issue, a pull req ### Character Set -The full ASCII tier system (never legitimate, legitimate next to a number, always legitimate, a fixed set of emoji callout markers, developer-typed Unicode), the letters of a recorded name keeping their actual spelling, and the semicolon and spaced-hyphen rules are in the `comment-and-doc-style` Skill referenced above. +The full character-set tier system (never legitimate, legitimate next to a number, always legitimate, a fixed set of emoji callout markers, developer-typed Unicode), the letters of a recorded name keeping their actual spelling, and the semicolon and spaced-hyphen rules are in the `comment-and-doc-style` Skill referenced above. ### Line Endings diff --git a/host-setup/agent-safety/claude/gh-write-guard.py b/host-setup/agent-safety/claude/gh-write-guard.py index 6990ca264..ded466111 100755 --- a/host-setup/agent-safety/claude/gh-write-guard.py +++ b/host-setup/agent-safety/claude/gh-write-guard.py @@ -1864,6 +1864,22 @@ def _git_invocations_at(cmd): _EXPORTING_BUILTINS = {"export": None, "declare": "-x", "typeset": "-x", "local": "-x"} +def _set_allexport(options, allexport): + """Whether `allexport` holds after a `set` given `options`, each flag applied in order. + + `-a` and `-o allexport` turn it on, `+a` and `+o allexport` turn it off, so a `set +a` after a + `set -a` ends the export of later plain assignments. A cluster such as `-ea` turns it on. + """ + for i, w in enumerate(options): + if w[:1] in ("-", "+") and w[1:2] not in ("", "-") and "a" in w[1:] and "o" not in w[1:]: + allexport = w[0] == "-" + elif w in ("-o", "+o") and options[i + 1 : i + 2] == ["allexport"]: + allexport = w == "-o" + elif w in ("-oallexport", "+oallexport"): + allexport = w[0] == "-" + return allexport + + def _export_events(toks): """Each place in `toks` where the shell exports variables, as (index, the (name, value) pairs it exports). @@ -1899,8 +1915,7 @@ def remember(pairs): break options.append(w) if t == "set": - flags = [w for w in options if w[:1] == "-" and w[1:2] not in ("", "-")] - allexport = allexport or any("a" in w for w in flags) or "allexport" in options + allexport = _set_allexport(options, allexport) continue if t not in _EXPORTING_BUILTINS and t != "readonly": continue @@ -13896,6 +13911,22 @@ def _nested_wrapper(body, depth): "deny", "a set -o allexport exports a plain GIT_DIR assignment", ), + ( + "cd /worktree && set -a; set +a; GIT_DIR=/primary/.git; git reset --hard", + "/somewhere-else", + {"/primary/.git": True, "/worktree": False}, + None, + "allow", + "a set +a ends the export of a later plain GIT_DIR assignment", + ), + ( + "cd /worktree && set -o allexport; set +o allexport; GIT_DIR=/primary/.git; git reset --hard", + "/somewhere-else", + {"/primary/.git": True, "/worktree": False}, + None, + "allow", + "a set +o allexport ends the export of a later plain GIT_DIR assignment", + ), ( "cd /worktree && set -e && GIT_DIR=/primary/.git && git reset --hard", "/somewhere-else", From af7b25eba1429b01c3804ac22d53f9b96689946d Mon Sep 17 00:00:00 2001 From: Pieter Viljoen Date: Thu, 22 Oct 2026 20:56:52 -0700 Subject: [PATCH 2/2] Keep the Write Guard's Allexport Reading One-Way Ending allexport at a set +a read the off switch regardless of control flow (a function never called, a subshell, a pipeline, a loop rerun), which allowed what develop denied. Restore the one-way reading, which fails closed. Co-Authored-By: Claude Sonnet 5.5 --- .../agent-safety/claude/gh-write-guard.py | 35 ++----------------- 1 file changed, 2 insertions(+), 33 deletions(-) diff --git a/host-setup/agent-safety/claude/gh-write-guard.py b/host-setup/agent-safety/claude/gh-write-guard.py index ded466111..6990ca264 100755 --- a/host-setup/agent-safety/claude/gh-write-guard.py +++ b/host-setup/agent-safety/claude/gh-write-guard.py @@ -1864,22 +1864,6 @@ def _git_invocations_at(cmd): _EXPORTING_BUILTINS = {"export": None, "declare": "-x", "typeset": "-x", "local": "-x"} -def _set_allexport(options, allexport): - """Whether `allexport` holds after a `set` given `options`, each flag applied in order. - - `-a` and `-o allexport` turn it on, `+a` and `+o allexport` turn it off, so a `set +a` after a - `set -a` ends the export of later plain assignments. A cluster such as `-ea` turns it on. - """ - for i, w in enumerate(options): - if w[:1] in ("-", "+") and w[1:2] not in ("", "-") and "a" in w[1:] and "o" not in w[1:]: - allexport = w[0] == "-" - elif w in ("-o", "+o") and options[i + 1 : i + 2] == ["allexport"]: - allexport = w == "-o" - elif w in ("-oallexport", "+oallexport"): - allexport = w[0] == "-" - return allexport - - def _export_events(toks): """Each place in `toks` where the shell exports variables, as (index, the (name, value) pairs it exports). @@ -1915,7 +1899,8 @@ def remember(pairs): break options.append(w) if t == "set": - allexport = _set_allexport(options, allexport) + flags = [w for w in options if w[:1] == "-" and w[1:2] not in ("", "-")] + allexport = allexport or any("a" in w for w in flags) or "allexport" in options continue if t not in _EXPORTING_BUILTINS and t != "readonly": continue @@ -13911,22 +13896,6 @@ def _nested_wrapper(body, depth): "deny", "a set -o allexport exports a plain GIT_DIR assignment", ), - ( - "cd /worktree && set -a; set +a; GIT_DIR=/primary/.git; git reset --hard", - "/somewhere-else", - {"/primary/.git": True, "/worktree": False}, - None, - "allow", - "a set +a ends the export of a later plain GIT_DIR assignment", - ), - ( - "cd /worktree && set -o allexport; set +o allexport; GIT_DIR=/primary/.git; git reset --hard", - "/somewhere-else", - {"/primary/.git": True, "/worktree": False}, - None, - "allow", - "a set +o allexport ends the export of a later plain GIT_DIR assignment", - ), ( "cd /worktree && set -e && GIT_DIR=/primary/.git && git reset --hard", "/somewhere-else",