#!/usr/bin/env python3 """Stempler de udgivne indlæg om efter flytningen fra src/content/blog/.md til content/blog//index.md. Stien og frontmatter indgår i stemplet, så de gamle er ugyldige. Kør på zola-branchen, med master stadig på Astro-versionen: PUBLISH_KEY= python3 scripts/omstempl.py [--fra master] PUBLISH_KEY= python3 scripts/verify-approvals.py git commit -am "blog: stempl indlæg om efter flytning til Zola" Scriptet underskriver kun det der allerede var godkendt. For hvert indlæg tjekker det at det gamle stempel er gyldigt, og at den nye fil er præcis den gamle i nyt format. Fejler ét indlæg, skrives der intet. """ import argparse import hashlib import hmac import os import re import subprocess import sys sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) from godkendelse import BLOG, assets_for, read_text, sign, stamp_of # noqa: E402 OLD = "src/content/blog" def git(*args, binary=False): return subprocess.run(["git", *args], check=True, capture_output=True, text=not binary).stdout def old_sign(key, rel, text, assets): """Det gamle format: stemplet stod som topniveau-linje og er det eneste der skæres fra.""" lines = text.replace("\r\n", "\n").split("\n") end = lines.index("---", 1) lines = [l for i, l in enumerate(lines) if not (0 < i < end and l.startswith("godkendt:"))] tail = "".join(f"\n@asset {p} {h}" for p, h in assets) body = f"{rel}\n" + "\n".join(lines) + tail return "v1:" + hmac.new(key, body.encode(), hashlib.sha256).hexdigest() def migrated(text, stamp): """Den gamle fil i det nye format: tags under taxonomies, stemplet under extra.""" lines = text.split("\n") end = lines.index("---", 1) head = [] for l in lines[1:end]: if l.startswith("godkendt:"): continue head += ["taxonomies:", " " + l] if l.startswith("tags:") else [l] return "\n".join(["---", *head, "extra:", f' godkendt: "{stamp}"', *lines[end:]]) def old_assets(ref, slug): out = git("ls-tree", "--name-only", ref, f"{OLD}/{slug}/").split() return sorted((p, hashlib.sha256(git("show", f"{ref}:{p}", binary=True)).hexdigest()) for p in out) def main(): ap = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter) ap.add_argument("--fra", default="master", help="ref med de gamle, godkendte indlæg") args = ap.parse_args() if not os.environ.get("PUBLISH_KEY"): sys.exit("PUBLISH_KEY mangler.") key = bytes.fromhex(os.environ["PUBLISH_KEY"]) slugs = sorted(n for n in os.listdir(BLOG) if os.path.isdir(f"{BLOG}/{n}")) new, errors = {}, [] for slug in slugs: rel = f"{BLOG}/{slug}/index.md" old_rel = f"{OLD}/{slug}.md" try: old = git("show", f"{args.fra}:{old_rel}") except subprocess.CalledProcessError: errors.append(f"{rel}: findes ikke i {args.fra} som {old_rel}; kun godkendelsesflowet må stemple nyt") continue text = read_text(rel) stamp_gl, draft = stamp_of(old) o_assets = old_assets(args.fra, slug) n_assets = assets_for(slug) if draft or not stamp_gl or not hmac.compare_digest(stamp_gl, old_sign(key, old_rel, old, o_assets)): errors.append(f"{old_rel}: det gamle stempel er ikke gyldigt med denne nøgle") continue if text != migrated(old, stamp_of(text)[0]): errors.append(f"{rel}: indholdet er ændret i forhold til {args.fra}") continue if [h for _, h in o_assets] != [h for _, h in n_assets]: errors.append(f"{rel}: billederne er ændret i forhold til {args.fra}") continue new[rel] = migrated(old, sign(key, rel, text, n_assets)) if errors: print("\n".join(f"✗ {e}" for e in errors), file=sys.stderr) sys.exit(f"\n{len(errors)} fejl. Intet er skrevet.") for rel, text in new.items(): with open(rel, "w", encoding="utf-8", newline="") as f: f.write(text) print(f"✓ {rel}") print(f"\n{len(new)} indlæg stemplet om. Kør scripts/verify-approvals.py og commit.") if __name__ == "__main__": main()