Watch
1
0
Fork
You've already forked souveraine-viewtop
0

add the cross libc the aarch64 link needs

gcc-aarch64-linux-gnu ships the compiler, not the target startup files;
without libc6-dev-arm64-cross ld cannot find Scrt1.o.
This commit is contained in:
Fimeg 2026-08-23 21:07:14 -04:00
commit 8ec3aa5fb6
6 changed files with 73 additions and 18 deletions

View file

@ -35,7 +35,8 @@ jobs:
sudo apt-get install -y --no-install-recommends \
libdrm-dev libudev-dev libgbm-dev libxkbcommon-dev libegl1-mesa-dev \
libwayland-dev libinput-dev libdbus-1-dev libsystemd-dev libseat-dev \
libdisplay-info-dev gcc-aarch64-linux-gnu binutils python3 file
libdisplay-info-dev gcc-aarch64-linux-gnu libc6-dev-arm64-cross \
binutils python3 file
- name: fmt
run: cargo fmt --all -- --check

View file

@ -1,4 +1,4 @@
{
"manifest_sha256": "7541bd805a211cfad05ab27687c4540d3edb7684cd463bf3808b4f466a1a1e29",
"manifest_sha256": "3e99da2194b599d29cf0a9a3814740b0e45628dac17fcc39e1ce831977500bc7",
"mechanism_version": 1
}

View file

@ -1,13 +1,13 @@
{
"files": {
".publication/bin/verify-publication": "ead82d864fe76131755bd04292fad19a5f034ecb664d512164bfa9e63324aabe",
".publication/bin/verify-publication": "686947723311e864196eae1ea8151b678aa4814456d97b34070b8ef39516a453",
".publication/lib/__init__.py": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
".publication/lib/gates.py": "ee542bbb7a7277aaae1129ea3cbc2f9d45e64c7c2f09b5041c88fa62725c8caa",
".publication/lib/giteaapi.py": "74402d43081cd3fbe35058d83cd3e0fef4fcc6777efd85c45c8a72f12ec94cd5",
".publication/lib/history.py": "34576127365d71a8e9143f7525329304ebdd10adfabb289d8cd512b8fd3b7759",
".publication/lib/history.py": "c1f64124d47324593e69f4dac0d4cd7654e121fc3e56ee5b13092f17ac76f24e",
".publication/lib/mechanism.py": "22f07e1e45be9d84c8dda40b186d67ba31a39918350b8f4eb7aee7c48773a43c",
".publication/lib/policy.py": "f6fa0dff1eedbe5d5451c96eb7fb7d91a52784de7acbef69c9df0e9c9976891c",
".publication/lib/scanner.py": "261e8dbb2e5bcf119c5117ca31773fcfce08308e6cc2a6eefe67594ac805f70b"
".publication/lib/scanner.py": "c57bba77ffbb4827d83e97c749350f39ea19ba6e5d27cd6ff5222114c48871e3"
},
"mechanism_version": 1
}

View file

@ -58,9 +58,10 @@ def main(argv=None):
except (json.JSONDecodeError, KeyError) as exc:
reasons.append(f"MECHANISM MANIFEST.json is unusable ({exc})")
cleanup = []
try:
reasons.extend("HISTORY " + r for r in history.verify(
args.ref, repo_root, pol, pinned_paths=pinned_paths))
args.ref, repo_root, pol, pinned_paths=pinned_paths, warnings=cleanup))
except history.GitError as exc:
reasons.append(f"HISTORY {exc}")
@ -88,11 +89,11 @@ def main(argv=None):
reasons.extend("GATES " + d for d in report.denials)
unproven = report.unproven
_emit(reasons, allowed=not reasons, unproven=unproven, policy=pol)
_emit(reasons, allowed=not reasons, unproven=unproven, policy=pol, cleanup=cleanup)
return 1 if reasons else 0
def _emit(reasons, allowed, unproven=(), policy=None):
def _emit(reasons, allowed, unproven=(), policy=None, cleanup=()):
if policy is not None:
print(f"[publication] {policy.internal_repository} -> "
f"{policy.destination_host}/{policy.destination_repository} "
@ -102,6 +103,12 @@ def _emit(reasons, allowed, unproven=(), policy=None):
print(f"[publication] DENY {r}")
for u in unproven:
print(f"[publication] unproven: {u}")
if cleanup:
print(f"[publication] {len(cleanup)} cleanup finding(s) -- recorded, not blocking:")
for c in cleanup[:40]:
print(f"[publication] {c}")
if len(cleanup) > 40:
print(f"[publication] ... and {len(cleanup) - 40} more")
if __name__ == "__main__":

View file

@ -99,7 +99,7 @@ def scan_tree(ref, cwd, rules=scanner.HOUSE_RULES, pinned_paths=()):
if scanner.CONTENT not in rule.surfaces:
continue
proc = subprocess.run(
["git", "grep", "-I", "-i", "-n", "-E", rule.pattern.pattern, ref],
["git", "grep", "-I", "-i", "-n", "-E", "-e", rule.pattern.pattern, ref],
cwd=cwd, capture_output=True, text=True, errors="replace")
if proc.returncode not in (0, 1):
raise GitError("git grep failed: " + proc.stderr.strip())
@ -136,9 +136,15 @@ def load_allowlist(repo_root):
return shas, digest, path
def verify(ref, repo_root, policy, pinned_paths=()):
"""Return failure reasons. Empty means this history may be published."""
def verify(ref, repo_root, policy, pinned_paths=(), warnings=None):
"""Return failure reasons. Empty means this history may be published.
`warnings` collects nonsecret findings -- topology, home paths, ugly
defaults. They are recorded in the publication report and do not deny.
Secrets deny. Publication is not certification.
"""
reasons = []
warnings = [] if warnings is None else warnings
try:
require_full_history(repo_root)
_git(["rev-parse", "--verify", f"{ref}^{{commit}}"], repo_root)
@ -163,17 +169,27 @@ def verify(ref, repo_root, policy, pinned_paths=()):
except GitError:
reasons.append(f"history: allowlist commit {sha} is stale or unreachable from {ref}")
severity = {r.rule_id: r.severity for r in scanner.HOUSE_RULES}
findings = scan_history(ref, repo_root)
unreviewed = sorted(set(findings) - set(allowed))
for sha in unreviewed:
rules = sorted({f.rule_id for f in findings[sha]})
reasons.append(f"history: unreviewed private infrastructure in {sha} ({', '.join(rules)})")
fatal = [r for r in rules if severity.get(r) == scanner.FATAL]
if fatal:
reasons.append(f"history: secret material in {sha} ({', '.join(fatal)})")
rest = [r for r in rules if severity.get(r) != scanner.FATAL]
if rest:
warnings.append(f"history {sha[:12]}: {', '.join(rest)}")
# Unallowlistable by construction: the allowlist is not consulted here.
for rule_id, path, line_no in scan_tree(ref, repo_root, pinned_paths=pinned_paths):
reasons.append(
f"candidate-tree: {rule_id} at {path}:{line_no} -- the tree at {ref} must be "
"clean; a reviewed history entry cannot excuse it")
if severity.get(rule_id) == scanner.FATAL:
reasons.append(
f"candidate-tree: {rule_id} at {path}:{line_no} -- a secret in the tree "
f"at {ref} is a capability handed to whoever reads it")
else:
warnings.append(f"candidate-tree {path}:{line_no}: {rule_id}")
reasons.extend(scanner.check_repo_assertions(repo_root, policy.repo_assertions))
reasons.extend(_oversized(ref, repo_root, policy.repo_assertions["max_blob_bytes"]))

View file

@ -18,21 +18,52 @@ METADATA = "metadata"
ALL_SURFACES = frozenset({CONTENT, MESSAGE, METADATA})
class Rule:
__slots__ = ("rule_id", "description", "pattern", "surfaces")
FATAL = "fatal"
WARN = "warn"
def __init__(self, rule_id, description, pattern, surfaces):
class Rule:
__slots__ = ("rule_id", "description", "pattern", "surfaces", "severity")
def __init__(self, rule_id, description, pattern, surfaces, severity=WARN):
self.rule_id = rule_id
self.description = description
self.pattern = re.compile(pattern, re.IGNORECASE)
self.surfaces = frozenset(surfaces)
self.severity = severity
# wiuf is matched as a bare token rather than as wiuf\.net so that one rule
# covers the domain, every depth of subdomain, every case, URLs, addresses,
# config values, and the host spellings wiufph and WIUF-Docker. Over-matching
# costs one review; under-matching publishes the house.
HOUSE_RULES = (
# Two severities, and the difference is what a finding costs someone.
#
# A private key or an embedded token is a capability: publishing it hands
# control to whoever reads it, and no amount of later cleanup takes it back.
# Those deny.
#
# A home path, a LAN address, a hostname or an ugly default is topology. It is
# worth removing and it is not worth withholding working software over. Those
# are recorded in the publication report and fixed afterwards.
#
# Publication is not certification.
SECRET_RULES = (
Rule("private-key", "PEM or OpenSSH private key block",
r"BEGIN (RSA |DSA |EC |OPENSSH |PGP )?PRIVATE KEY( BLOCK)?-",
ALL_SURFACES, FATAL),
Rule("url-credential", "credential in a URL's userinfo",
r"://[A-Za-z0-9._%-]+:[A-Za-z0-9._%+/=-]{8,}@", ALL_SURFACES, FATAL),
Rule("oauth2-clone", "authenticated clone URL",
r"://oauth2:[^@\s\"']+@", ALL_SURFACES, FATAL),
Rule("forge-pat", "forge personal access token",
r"\b(gh[pousr]_[A-Za-z0-9]{36}|glpat-[A-Za-z0-9_-]{20,})\b",
ALL_SURFACES, FATAL),
Rule("aws-key", "AWS access key id",
r"\bAKIA[0-9A-Z]{16}\b", ALL_SURFACES, FATAL),
)
HOUSE_RULES = SECRET_RULES + (
Rule("wiuf", "canonical internal domain and host family (wiuf.net, any subdomain, wiufph, WIUF-Docker)",
r"wiuf", ALL_SURFACES),
Rule("net-10-10", "internal LAN 10.10.0.0/16",