app
KiCad - the KiCad Bridge
Public Made by Adomby adom
Drive your own KiCad from an AI, in the background: open every editor, read the whole board as data (the EDA Bridge Standard board model), stack-up, part heights, netlists, place, route, pour, DRC and exports.
← Commit history
sign_azure: sign locally when this is the signing machine; redact private values in every message
1 file changed
+79−9
tools/sign_azure.py+79−9@@ -10,7 +10,8 @@ Nothing from it is ever written to this repo, a reply, a log line or an issue. python3 tools/sign_azure.py <exe> <version> # sign one exe in place; exits non-zero unless verified -The flow, each step a gate:+On the signing machine itself (this WSL runs on the config's host) it signs locally through powershell.exe,+staging under the host's %LOCALAPPDATA%; elsewhere it goes through Adom Bridge. The flow, each step a gate: 1. stage the exe and sign-verify.ps1 on the host (send_files; the folder name has no dots); 2. one run_script signs and verifies there: Get-AuthenticodeSignature Valid, the expected subject, a Microsoft timestamp, signtool verify /pa;@@ -85,8 +86,79 @@ def ab_json(*args, timeout=600): return d +POWERSHELL = "/mnt/c/Windows/System32/WindowsPowerShell/v1.0/powershell.exe"+++def redact(text, cfg):+ """A message with every private config value blanked: the signing script's hints name the tenant."""+ text = str(text)+ for k in ("endpoint", "account", "profile", "tenant", "timestampUrl", "stageDir"):+ v = str(cfg.get(k) or "")+ if len(v) > 3:+ text = text.replace(v, f"<{k}>")+ return text+++def local_windows_host():+ """This machine's Windows name when we run in WSL on it (the signing machine itself), else None."""+ if not os.path.exists(POWERSHELL):+ return None+ r = subprocess.run(["/mnt/c/Windows/System32/cmd.exe", "/c", "hostname"], capture_output=True, text=True, cwd="/mnt/c")+ return r.stdout.strip() or None+++def checks_of(v, cfg):+ return {+ "Status Valid": v.get("status") == "Valid",+ "signer subject": cfg["expectSubject"] in (v.get("subject") or ""),+ "timestamped": "Microsoft" in (v.get("timestamper") or ""),+ "signtool verify /pa": "Successfully verified" in (v.get("signtoolVerify") or ""),+ }+++def sign_locally(exe, ver, cfg, ps1):+ """On the signing machine itself (WSL on it): stage under its own %LOCALAPPDATA%, run sign-verify.ps1+ with powershell.exe, no Adom Bridge round trip."""+ win = lambda p: subprocess.run(["wslpath", "-w", str(p)], capture_output=True, text=True).stdout.strip()+ lad = subprocess.run(["/mnt/c/Windows/System32/cmd.exe", "/c", "echo %LOCALAPPDATA%"], capture_output=True, text=True, cwd="/mnt/c").stdout.strip()+ stage_win = cfg["stageDir"].replace("%LOCALAPPDATA%", lad) + "\\kicad-build-" + ver.replace(".", "_")+ stage = Path(subprocess.run(["wslpath", "-u", stage_win], capture_output=True, text=True).stdout.strip())+ shutil.rmtree(stage, ignore_errors=True)+ stage.mkdir(parents=True)+ unsigned_sha = hashlib.sha256(exe.read_bytes()).hexdigest()+ shutil.copy2(exe, stage / "kicad-bridge.exe")+ shutil.copy2(ps1, stage / "sign-verify.ps1")+ print(f"== sign kicad-bridge.exe {ver} here (the signing machine) ==")+ r = subprocess.run([POWERSHELL, "-NoProfile", "-NonInteractive", "-ExecutionPolicy", "Bypass", "-File", win(stage / "sign-verify.ps1"),+ "-Exe", win(stage / "kicad-bridge.exe"), "-Endpoint", cfg["endpoint"], "-Account", cfg["account"],+ "-Profile", cfg["profile"], "-Tenant", cfg["tenant"], "-Timestamp", cfg["timestampUrl"]],+ capture_output=True, text=True, cwd="/mnt/c", timeout=540)+ out = r.stdout+ try:+ v = json.loads(out[out.find("{"):out.rfind("}") + 1])+ except ValueError:+ raise SystemExit(f"REFUSED: the signing script gave no verdict (exit {r.returncode}): {redact((out + r.stderr)[-600:], cfg)}")+ if v.get("error"):+ raise SystemExit(f"REFUSED: cannot sign ({v['error']}): {redact(v.get('detail', ''), cfg)}\n fix: {redact(v.get('fix', ''), cfg)}")+ checks = checks_of(v, cfg)+ if not all(checks.values()):+ raise SystemExit(f"REFUSED: signature checks failed: {checks}")+ signed = stage / "kicad-bridge.exe"+ signed_sha = hashlib.sha256(signed.read_bytes()).hexdigest()+ if signed_sha == unsigned_sha:+ raise SystemExit("REFUSED: the exe is byte-identical after signing")+ subs = assert_signed(signed)+ shutil.copy2(signed, exe)+ shutil.rmtree(stage, ignore_errors=True)+ print(" " + ", ".join(f"{k} {'ok' if ok else 'FAIL'}" for k, ok in checks.items()) + f"; verified again here, sha256 {signed_sha[:12]}")+ return {"file": "kicad-bridge.exe", "version": ver, "status": v["status"], "subject": SIGNER_ORG, "timestamper": v["timestamper"],+ "signtoolVerify": "Successfully verified", "sha256Unsigned": unsigned_sha, "sha256": signed_sha,+ "localSubjects": [x for x in subs if SIGNER_ORG in x], "where": "signing machine (local)"}++ def sign(exe, ver):- """Sign `exe` in place on the signing host; returns the signing report (no private values in it)."""+ """Sign `exe` in place: here when this is the signing machine (WSL on it), else on the signing host+ through Adom Bridge. Returns the signing report (no private values in it).""" exe = Path(exe) sd = signing_dir() cfg_p, ps1 = sd / "config.json", sd / "sign-verify.ps1"@@ -95,6 +167,9 @@ def sign(exe, ver): f"deliberately not in this public repo; ask Colby to copy it over privately.") cfg = json.loads(cfg_p.read_text()) host = cfg["host"]+ here = local_windows_host()+ if here and here.lower() == host.lower():+ return sign_locally(exe, ver, cfg, ps1) stage = cfg["stageDir"].replace("%LOCALAPPDATA%", cfg.get("localAppData", r"C:\Users\cknox\AppData\Local")) \ + "\\kicad-build-" + ver.replace(".", "_") # a dotted folder name reads as a file path to send_files unsigned_sha = hashlib.sha256(exe.read_bytes()).hexdigest()@@ -123,13 +198,8 @@ def sign(exe, ver): raise SystemExit(f"REFUSED: the signing script gave no verdict (stdout {len(so)} chars, stderr {len(r.get('stderr') or '')} chars, error {r.get('errorCode') or r.get('error') or '-'})") if v.get("error"): shutil.rmtree(work, ignore_errors=True)- raise SystemExit(f"REFUSED: the signing host cannot sign ({v['error']}): {v.get('detail', '')}\n fix: {v.get('fix', '')}")- checks = {- "Status Valid": v.get("status") == "Valid",- "signer subject": cfg["expectSubject"] in (v.get("subject") or ""),- "timestamped": "Microsoft" in (v.get("timestamper") or ""),- "signtool verify /pa": "Successfully verified" in (v.get("signtoolVerify") or ""),- }+ raise SystemExit(f"REFUSED: the signing host cannot sign ({v['error']}): {redact(v.get('detail', ''), cfg)}\n fix: {redact(v.get('fix', ''), cfg)}")+ checks = checks_of(v, cfg) if not all(checks.values()): shutil.rmtree(work, ignore_errors=True) raise SystemExit(f"REFUSED: signature checks failed on the host: {checks}")