Watch
1
0
Fork
You've already forked souveraine
0

publish: the public projection begins here

This is a projection, not a development branch. The tree above was constructed
from the internal source named below under a manifest that decides which paths
may leave, then scanned as a whole tree rather than as a series of patches, and
only then published.

Public history starts here because the history before it was not admissible,
and neither was the tree. What used to stand in this repository included a
rescue copy of another machine, a directory of phone handoffs, deployment
wired to one house, and a submodule pointing at a forge no stranger can reach.
None of that was ever the product. It stays in the private forge, which is
allowed to hold the whole working organism, and this is what was deliberately
sent out instead.

Three mechanisms produced this tree, in decreasing order of trust. A top-level
path the manifest does not name never arrives at all, which is the one that
catches directories nobody has thought of yet. Named internal files inside
admitted roots are dropped. A short, reviewed table replaces deployment
defaults that a public build must not carry -- an endpoint aimed at one LAN, a
VPN profile belonging to one phone, packaging built from one checkout path.

Everything after this commit is an ordinary publication with the same three
trailers, so a force push stops being routine and starts meaning that
something deliberate happened. The trailers bind the projection to its source
without pretending the public SHA is the private one: same lineage, different
tree, and the record says so.

Source-Sha: 8f27b1e76a8fef560a336aba18e6990713ff1047
Policy-Sha: 6b261d2f3e6e1fb19874846ba4bb1dfe15565d25b8618c1c1afba0419c101d27
Tree-Digest: 18ec3563c5e5ef9a414993a9f6734b251ff9ed3cd56eebdd6cac01e45c6e3067
This commit is contained in:
Fimeg 2026-09-04 15:55:48 -04:00
commit 8f42fc953d
1476 changed files with 238455 additions and 0 deletions

13
.publication/EPOCH Normal file
View file

@ -0,0 +1,13 @@
# Break glass.
#
# Ordinary publication is fast-forward only. This file authorises the
# publication job to replace the public branch exactly once, and only when the
# public ref it finds is the one named below. After the epoch lands, the named
# SHA is no longer what any remote holds, so this authorisation is spent and
# force push goes dark again without anyone remembering to close it.
#
# Development history is never rewritten. It is preserved internally at
# archive/public-pre-epoch-2026-09-04.
replaces b68bcebf6c390ec6e2a361aff3f17ea0736c7da2
reason sanitized projection epoch; public history begins at the cut

View file

@ -0,0 +1,478 @@
#!/usr/bin/env python3
"""Editorial authority over a public tree.
The existing `.publication` mechanism answers a transport question: was this
SHA produced by the right gates, on the right repository, under a policy that
authorizes projection to this destination. It is a good answer to that
question and this file does not replace it.
This file answers the question nobody was asking:
Does this tree belong outside at all?
Six gates, in the order a reviewer would actually apply them:
1. tree-shape every top-level entry is classified by the manifest
2. new-surface what the public diff P1 -> P2 newly admits
3. file-class forbidden classes anywhere in the tree
4. content the whole candidate tree, not the changed lines
5. history subjects, bodies, and author identities
6. presentation what a stranger sees in the root listing
Gate 4 is the one that matters most and is the one an incremental scanner
structurally cannot provide. A patch scanner sees a file the day it lands. It
never sees it again. A tree that was clean when every one of its commits was
scanned can still be a tree that should not be public, because publication is
a property of the tree, not of the diffs that built it.
The severity model is deliberately harsher than the incremental scanner's.
There, a home path or a LAN address is a WARN: one line in one patch, and a
human is reading the patch anyway. Here the same finding is a DENY, because
nobody reads a whole tree, and because the finding means the path is standing
in the public product right now, not that it passed through once.
Absence of known-secret content is not authorization to publish.
Exceptions are narrow and auditable: path, rule, reason, review date. A rule
turned off globally is not an exception, it is a retreat, so this file has no
syntax for one.
"""
import argparse
import fnmatch
import json
import os
import re
import subprocess
import sys
from datetime import date
SCHEMA_VERSION = 1
DENY = "deny"
REVIEW = "review"
NOTE = "note"
SEVERITY_ORDER = {DENY: 0, REVIEW: 1, NOTE: 2}
# Anything a forge will not render as source. Reviewed by eye, not by rule.
BINARY_HINT = re.compile(
r"\.(png|jpe?g|gif|webp|ico|pdf|zip|gz|xz|zst|bz2|tar|so|a|o|dll|dylib"
r"|exe|bin|wav|mp3|mp4|ogg|woff2?|ttf|otf|jar|whl|deb|rpm|img|iso)$",
re.IGNORECASE,
)
# Host suffixes a stranger can actually resolve. A submodule pointed anywhere
# else is both a leak and a repository that does not clone.
PUBLIC_FORGE_HOSTS = (
"forge.caseytunturi.com",
"codeberg.org",
"github.com",
"gitlab.com",
"git.sr.ht",
)
class Rule:
__slots__ = ("rule_id", "description", "pattern", "severity")
def __init__(self, rule_id, description, pattern, severity):
self.rule_id = rule_id
self.description = description
self.pattern = re.compile(pattern, re.IGNORECASE)
self.severity = severity
# Capabilities deny because publishing one hands control to whoever reads it
# and no later cleanup takes it back. Topology denies here — see the module
# docstring — because in a tree it is a standing disclosure, not a transit.
CONTENT_RULES = (
Rule("private-key", "private key material",
r"-----BEGIN (?:RSA|DSA|EC|OPENSSH|PGP) PRIVATE KEY", DENY),
# The value must be quoted. An unquoted run of letters after `authorization:`
# is a type name in every language that has types, and matching it made the
# gate cry wolf over `authorization: MutationAuthorization` on first run.
Rule("bearer-token", "embedded token or bearer credential",
r"(?:ghp|gho|ghs|ghu|github_pat)_[A-Za-z0-9_]{20,}"
r"|(?:authorization|private[-_]?token|api[-_]?key|client[-_]?secret)"
r"\s*[:=]\s*['\"][A-Za-z0-9._~+/=-]{16,}['\"]", DENY),
Rule("rfc1918", "private LAN address",
r"\b(?:10\.\d{1,3}\.\d{1,3}\.\d{1,3}"
r"|192\.168\.\d{1,3}\.\d{1,3}"
r"|172\.(?:1[6-9]|2\d|3[01])\.\d{1,3}\.\d{1,3})\b", DENY),
# Case-sensitive on purpose. Every rule here is otherwise IGNORECASE, and
# a case-blind `/Users/` matched the phrase "sessions/users/seats" in a
# comment about loginctl. A macOS home is capitalised; a POSIX path segment
# spelled `users` is not a home directory.
Rule("home-path", "developer home directory",
r"/home/[a-z][a-z0-9_-]*|(?-i:/Users/[A-Za-z])|(?-i:C:\\\\Users\\\\)", DENY),
Rule("internal-host", "internal hostname or forge",
r"\bwiuf|\barchdev\b|\bwiufph\b", DENY),
# The internal domain only. An author's own public contact address is not a
# leak — it is on the security page on purpose, and matching it made the
# gate refuse commits for being signed by the person who wrote them.
Rule("internal-email", "internal service identity or internal domain",
r"@wiuf\.net", DENY),
Rule("ai-attribution", "model attribution",
r"co-authored-by:\s*(?:claude|gpt|copilot|codex)"
r"|generated with \[?claude", REVIEW),
)
MESSAGE_RULES = CONTENT_RULES
def run(repo, args, ok=(0,)):
p = subprocess.run(["git", "-C", repo] + args,
capture_output=True, text=True, errors="replace")
if p.returncode not in ok:
raise RuntimeError(f"git {' '.join(args)}: {p.stderr.strip()}")
return p.stdout
class Finding:
__slots__ = ("gate", "severity", "rule", "path", "detail", "excerpt")
def __init__(self, gate, severity, rule, path, detail, excerpt=""):
self.gate = gate
self.severity = severity
self.rule = rule
self.path = path
self.detail = detail
self.excerpt = excerpt
def redact(text, match):
"""Keep the shape, drop the value. A report is itself a publishable object."""
s, e = match.span()
line = text[max(0, s - 40):e + 40].replace("\n", " ").strip()
hit = match.group(0)
keep = 2 if len(hit) > 6 else 1
masked = hit[:keep] + "*" * max(1, len(hit) - keep * 2) + (hit[-keep:] if len(hit) > 6 else "")
return line.replace(hit, masked)[:150]
class Manifest:
"""The authority for what may cross. Changing it is the consequential act."""
def __init__(self, raw, path):
self.path = path
self.schema_version = raw.get("schema_version")
if self.schema_version != SCHEMA_VERSION:
raise ValueError(f"{path}: schema_version must be {SCHEMA_VERSION}")
self.repository = raw.get("repository", "?")
self.public_roots = list(raw.get("public_roots", []))
self.public_root_files = list(raw.get("public_root_files", []))
self.review_required = list(raw.get("review_required", []))
self.forbidden = list(raw.get("forbidden", []))
self.forbidden_classes = list(raw.get("forbidden_classes", []))
self.max_blob_bytes = int(raw.get("max_blob_bytes", 2 * 1024 * 1024))
self.exceptions = list(raw.get("exceptions", []))
def classify_root(self, name):
if name in self.forbidden:
return "forbidden"
if name in self.public_roots or name in self.public_root_files:
return "allowed"
if name in self.review_required:
return "review"
return "unclassified"
def excepted(self, path, rule_id):
"""An exception names one path and one rule, and says why, and when."""
for exc in self.exceptions:
if exc.get("rule") != rule_id:
continue
if not fnmatch.fnmatch(path, exc.get("path", "")):
continue
if not exc.get("reason") or not exc.get("reviewed"):
continue
return exc
return None
def tree_entries(repo, sha):
"""(mode, type, oid, path) for every entry, recursively."""
out = run(repo, ["ls-tree", "-r", "-l", sha])
entries = []
for line in out.splitlines():
if not line.strip():
continue
meta, path = line.split("\t", 1)
parts = meta.split()
mode, otype, oid = parts[0], parts[1], parts[2]
size = parts[3] if len(parts) > 3 else "-"
entries.append((mode, otype, oid, size, path))
return entries
def top_level(repo, sha):
return [l for l in run(repo, ["ls-tree", "--name-only", sha]).splitlines() if l.strip()]
# ---------------------------------------------------------------- gate 1
def gate_tree_shape(repo, sha, manifest, findings):
for name in top_level(repo, sha):
verdict = manifest.classify_root(name)
if verdict == "forbidden":
findings.append(Finding(
"tree-shape", DENY, "forbidden-root", name,
"top-level path is forbidden by the public-surface manifest"))
elif verdict == "unclassified":
findings.append(Finding(
"tree-shape", DENY, "unclassified-root", name,
"no manifest entry admits this top-level path to the public product"))
elif verdict == "review":
findings.append(Finding(
"tree-shape", REVIEW, "review-root", name,
"manifest marks this root review-required"))
# ---------------------------------------------------------------- gate 2
def gate_new_surface(repo, sha, previous, manifest, findings):
if not previous:
findings.append(Finding(
"new-surface", NOTE, "no-baseline", "-",
"no previous public SHA given; the diff gate did not run"))
return
out = run(repo, ["diff", "--name-status", "--diff-filter=ACR", previous, sha])
added = []
for line in out.splitlines():
parts = line.split("\t")
if len(parts) >= 2:
added.append(parts[-1])
old_roots = set(top_level(repo, previous))
# One finding per newly admitted root, not one per file underneath it: the
# decision being reviewed is the root, and a hundred rows for one directory
# buries the other gates' output.
reported = set()
for path in added:
root = path.split("/", 1)[0]
if root not in old_roots and root not in reported:
reported.add(root)
sev = REVIEW if manifest.classify_root(root) == "allowed" else DENY
findings.append(Finding(
"new-surface", sev, "new-top-level", root,
"publication newly admits a top-level path; "
"this is a public-surface change, not a code change"))
if os.path.basename(path).startswith("."):
findings.append(Finding(
"new-surface", REVIEW, "new-dotfile", path,
"new dotfile or dotdirectory entering the public tree"))
# Symlinks and submodules are surface changes disguised as files.
for mode, otype, _oid, _size, path in tree_entries(repo, sha):
if mode == "120000":
target = run(repo, ["show", f"{sha}:{path}"]).strip()
escapes = target.startswith("/") or ".." in target.split("/")
findings.append(Finding(
"new-surface", DENY if escapes else NOTE, "symlink", path,
"symlink target leaves the public tree" if escapes
else "symlink stays inside the public tree"))
if otype == "commit":
findings.append(Finding(
"new-surface", REVIEW, "submodule", path,
"submodule gitlink; its URL must resolve publicly"))
def gate_submodule_urls(repo, sha, findings):
try:
text = run(repo, ["show", f"{sha}:.gitmodules"])
except RuntimeError:
return
name = None
for line in text.splitlines():
line = line.strip()
if line.startswith("[submodule"):
name = line
if line.startswith("url"):
url = line.split("=", 1)[1].strip()
host = re.sub(r"^[a-z+]+://", "", url).split("/")[0].split("@")[-1].split(":")[0]
if not any(host == h or host.endswith("." + h) for h in PUBLIC_FORGE_HOSTS):
findings.append(Finding(
"new-surface", DENY, "submodule-private-url", ".gitmodules",
f"submodule url host is not publicly resolvable ({host}); "
"the public repository cannot clone and the host leaks",
excerpt=name or ""))
# ---------------------------------------------------------------- gate 3
def gate_file_class(repo, sha, manifest, findings):
for _mode, _otype, _oid, size, path in tree_entries(repo, sha):
for pat in manifest.forbidden_classes:
if fnmatch.fnmatch(path, pat) or fnmatch.fnmatch(os.path.basename(path), pat):
findings.append(Finding(
"file-class", DENY, "forbidden-class", path,
f"matches forbidden class {pat!r}"))
break
if size not in ("-", None) and size.isdigit() and int(size) > manifest.max_blob_bytes:
findings.append(Finding(
"file-class", REVIEW, "oversized-blob", path,
f"{int(size):,} bytes exceeds the reviewed maximum "
f"({manifest.max_blob_bytes:,})"))
# ---------------------------------------------------------------- gate 4
def gate_content(repo, sha, manifest, findings, limit_per_rule=40):
counts = {}
for _mode, otype, _oid, _size, path in tree_entries(repo, sha):
if otype != "blob" or BINARY_HINT.search(path):
continue
try:
text = run(repo, ["show", f"{sha}:{path}"])
except RuntimeError:
continue
if "\0" in text[:8000]:
continue
for rule in CONTENT_RULES:
m = rule.pattern.search(text)
if not m:
continue
exc = manifest.excepted(path, rule.rule_id)
if exc:
findings.append(Finding(
"content", NOTE, rule.rule_id, path,
f"excepted: {exc['reason']} (reviewed {exc['reviewed']})"))
continue
counts[rule.rule_id] = counts.get(rule.rule_id, 0) + 1
if counts[rule.rule_id] > limit_per_rule:
continue
findings.append(Finding(
"content", rule.severity, rule.rule_id, path,
rule.description, excerpt=redact(text, m)))
# ---------------------------------------------------------------- gate 5
def gate_history(repo, sha, manifest, findings, limit_per_rule=25):
sep = "\x1e"
out = run(repo, ["log", f"--format=%H{sep}%an <%ae>{sep}%s{sep}%b\x1d", sha])
counts = {}
total = 0
for record in out.split("\x1d"):
record = record.strip("\n")
if not record.strip():
continue
parts = record.split(sep)
if len(parts) < 4:
continue
h, ident, subject, body = parts[0], parts[1], parts[2], parts[3]
total += 1
blob = f"{ident}\n{subject}\n{body}"
for rule in MESSAGE_RULES:
m = rule.pattern.search(blob)
if not m:
continue
counts[rule.rule_id] = counts.get(rule.rule_id, 0) + 1
if counts[rule.rule_id] > limit_per_rule:
continue
findings.append(Finding(
"history", rule.severity, rule.rule_id, h[:12],
f"{rule.description} in commit metadata: {subject[:60]}",
excerpt=redact(blob, m)))
findings.append(Finding("history", NOTE, "reachable", "-",
f"{total} commits reachable from {sha[:12]}"))
# ---------------------------------------------------------------- gate 6
def gate_presentation(repo, sha, manifest, findings):
roots = top_level(repo, sha)
product = [r for r in roots
if manifest.classify_root(r) == "allowed" and not r.startswith(".")]
other = [r for r in roots if manifest.classify_root(r) != "allowed"]
findings.append(Finding(
"presentation", NOTE, "root-listing", "-",
f"{len(roots)} top-level entries; {len(product)} read as product, "
f"{len(other)} do not"))
if other:
findings.append(Finding(
"presentation", REVIEW, "mixed-listing", "-",
"a stranger cannot distinguish product from working material: "
+ ", ".join(sorted(other))))
# ---------------------------------------------------------------- report
GATES = ("tree-shape", "new-surface", "file-class", "content", "history", "presentation")
def report(findings, repo, sha, previous, manifest):
lines = []
w = lines.append
w(f"# Public-surface audit — {manifest.repository}")
w("")
w(f"- candidate SHA: `{sha[:12]}`")
w(f"- previous public SHA: `{previous[:12] if previous else '(none given)'}`")
w(f"- manifest: `{os.path.basename(manifest.path)}`")
w(f"- generated: {date.today().isoformat()}")
w("")
deny = [f for f in findings if f.severity == DENY]
review = [f for f in findings if f.severity == REVIEW]
verdict = "DENY" if deny else ("REVIEW" if review else "PASS")
w(f"**Verdict: {verdict}** — {len(deny)} deny, {len(review)} review, "
f"{len([f for f in findings if f.severity == NOTE])} note.")
w("")
for gate in GATES:
rows = [f for f in findings if f.gate == gate]
if not rows:
continue
w(f"## {gate}")
w("")
rows.sort(key=lambda f: (SEVERITY_ORDER[f.severity], f.rule, f.path))
w("| sev | rule | path | detail |")
w("| --- | --- | --- | --- |")
for f in rows:
detail = f.detail
if f.excerpt:
detail += f" — `{f.excerpt}`"
detail = detail.replace("|", "\\|")
w(f"| {f.severity} | {f.rule} | `{f.path}` | {detail} |")
w("")
return "\n".join(lines)
def main():
ap = argparse.ArgumentParser(description=__doc__.splitlines()[0])
ap.add_argument("--repo", required=True)
ap.add_argument("--sha", required=True)
ap.add_argument("--manifest", required=True)
ap.add_argument("--previous", default="")
ap.add_argument("--out", default="")
ap.add_argument("--skip-history", action="store_true")
args = ap.parse_args()
with open(args.manifest) as fh:
manifest = Manifest(json.load(fh), args.manifest)
sha = run(args.repo, ["rev-parse", args.sha]).strip()
previous = run(args.repo, ["rev-parse", args.previous]).strip() if args.previous else ""
findings = []
gate_tree_shape(args.repo, sha, manifest, findings)
gate_new_surface(args.repo, sha, previous, manifest, findings)
gate_submodule_urls(args.repo, sha, findings)
gate_file_class(args.repo, sha, manifest, findings)
gate_content(args.repo, sha, manifest, findings)
if not args.skip_history:
gate_history(args.repo, sha, manifest, findings)
gate_presentation(args.repo, sha, manifest, findings)
text = report(findings, args.repo, sha, previous, manifest)
if args.out:
with open(args.out, "w") as fh:
fh.write(text + "\n")
print(f"wrote {args.out}")
else:
print(text)
return 1 if any(f.severity == DENY for f in findings) else 0
if __name__ == "__main__":
sys.exit(main())