@@ -41,45 +41,58 @@ FORBIDDEN = {
4141}
4242
4343
44- def entitlements_from_workflow(path, job, marker, terminator):
45- """The verbatim copy the signing job writes, lifted out of its heredoc."""
46- import yaml
47- d = yaml.safe_load(open(path))
48- for step in d["jobs"][job]["steps"]:
49- run = step.get("run") or ""
50- if marker not in run:
51- continue
52- after = run.split(marker, 1)[1]
53- lines = []
54- for line in after.split("\n"):
55- if line.strip() == terminator:
56- break
57- lines.append(line[10:] if line.startswith(" " * 10) else line)
58- return plistlib.loads("\n".join(lines).encode())
59- return None
44+ def entitlements_from_workflow(path, marker, terminator):
45+ """The verbatim copy the signing job writes, lifted out of its heredoc.
46+
47+ Read as TEXT, not through a YAML parser. A heredoc body is a textual
48+ construct -- the workflow's own shell finds it exactly this way -- and
49+ reaching for PyYAML to locate it added a dependency the macOS runner's
50+ python3 does not have. This runs on stdlib alone, which is the only thing
51+ a check that gates a build should need.
52+ """
53+ text = open(path, encoding="utf-8").read()
54+ if text.count(marker) != 1:
55+ return None, f"expected exactly one {marker.strip()} heredoc"
56+
57+ after = text.split(marker, 1)[1]
58+ body = []
59+ for line in after.split("\n"):
60+ if line.strip() == terminator:
61+ # De-indent by whatever the terminator is indented by: a heredoc
62+ # closed with <<- or written at a different depth still works.
63+ pad = len(line) - len(line.lstrip())
64+ return "\n".join(
65+ l[pad:] if l.startswith(" " * pad) else l for l in body
66+ ), None
67+ body.append(line)
68+ return None, f"heredoc opened with {marker.strip()} is never closed"
6069
6170
6271pairs = [
6372 (
6473 "Developer ID",
6574 f"{repo}/resource/entitlements/Normal.entitlements",
6675 f"{repo}/.github/workflows/build.yml",
67- "sign-macos",
6876 "<<'PLIST'\n",
6977 "PLIST",
7078 ),
7179]
7280
73- for name, repo_file, workflow, job, marker, terminator in pairs:
81+ for name, repo_file, workflow, marker, terminator in pairs:
7482 try:
7583 committed = plistlib.load(open(repo_file, "rb"))
7684 except Exception as exc: # noqa: BLE001
7785 failures.append(f"{name}: {repo_file} does not parse: {exc}")
7886 continue
7987
80- applied = entitlements_from_workflow(workflow, job, marker, terminator)
81- if applied is None:
82- failures.append(f"{name}: no entitlements heredoc found in {job}")
88+ body, why = entitlements_from_workflow(workflow, marker, terminator)
89+ if body is None:
90+ failures.append(f"{name}: {why} in {workflow}")
91+ continue
92+ try:
93+ applied = plistlib.loads(body.encode())
94+ except Exception as exc: # noqa: BLE001
95+ failures.append(f"{name}: the copy in {workflow} does not parse: {exc}")
8396 continue
8497
8598 if committed != applied:
0 commit comments