#!/usr/bin/env python3 """Replay the reviewed Hermes Dockerfile heredocs for pinned Kaniko v1.23.2. Kaniko v1.23.2 parses shell heredoc bodies into ``RunCommand.Files`` but its RUN implementation executes only ``CmdLine``. The interpreters therefore receive empty stdin and exit successfully. Docker and BuildKit execute these blocks normally, so this compatibility runner is enabled only by the Kaniko pipeline. """ from __future__ import annotations import argparse import re import subprocess from pathlib import Path MAX_DOCKERFILE_BYTES = 2_000_000 BLOCKS = ( ("RUN node <<'NODE'", "NODE", ("node",)), ("RUN python - <<'PY'", "PY", ("python", "-")), ) EXPECTED_COMMANDS = ("node", *("python",) * 7, "node") PARSER_DIRECTIVE = re.compile( r"^\s*#\s*([a-z]+)\s*=\s*(.*?)\s*$", re.IGNORECASE ) def _escape_character(lines: list[str]) -> str: """Return the one Dockerfile parser escape directive, or its default.""" escape = "\\" directives: set[str] = set() for line in lines: if not line.strip(): break match = PARSER_DIRECTIVE.fullmatch(line) if not match: break name, value = match.group(1).lower(), match.group(2) if name in directives: raise ValueError(f"multiple Dockerfile {name} directives") directives.add(name) if name == "escape": if value not in {"\\", "`"}: raise ValueError("unsupported Dockerfile escape directive") escape = value return escape def _continued(line: str, escape: str) -> bool: """Match Docker's unescaped continuation marker at physical line end.""" stripped = line.rstrip() count = len(stripped) - len(stripped.rstrip(escape)) return count % 2 == 1 def _logical_instruction( lines: list[str], index: int, escape: str ) -> tuple[str, int]: """Normalize escape-newline pairs, including split opcodes/operators.""" logical = lines[index] while _continued(logical.split("\n")[-1], escape): logical = logical.rstrip() logical = logical[:-1] index += 1 while index < len(lines) and lines[index].lstrip().startswith("#"): index += 1 if index >= len(lines) or not lines[index].strip(): raise ValueError("unterminated Dockerfile line continuation") logical += lines[index].lstrip() return logical, index def extract_blocks(source: str) -> list[tuple[tuple[str, ...], str]]: """Inventory every RUN heredoc, then return only the reviewed contract.""" markers = {start: (end, command) for start, end, command in BLOCKS} lines = source.splitlines() escape = _escape_character(lines) blocks: list[tuple[tuple[str, ...], str]] = [] index = 0 while index < len(lines): marker = markers.get(lines[index]) if marker is None: if not lines[index].strip() or lines[index].lstrip().startswith("#"): index += 1 continue logical, index = _logical_instruction(lines, index, escape) stripped = logical.lstrip() if ( stripped[:3].upper() == "RUN" and (len(stripped) == 3 or stripped[3].isspace()) and "<<" in stripped ): raise ValueError( "unsupported RUN heredoc outside the exact reviewed contract" ) index += 1 continue end, command = marker body_start = index + 1 index = body_start while index < len(lines) and lines[index] != end: index += 1 if index == len(lines): raise ValueError(f"unterminated {command[0]} heredoc") body = "\n".join(lines[body_start:index]) + "\n" if not body.strip(): raise ValueError(f"empty {command[0]} heredoc") blocks.append((command, body)) index += 1 commands = tuple(command[0] for command, _body in blocks) if commands != EXPECTED_COMMANDS: raise ValueError( "Hermes Dockerfile heredoc contract changed: " f"expected {EXPECTED_COMMANDS!r}, received {commands!r}" ) return blocks def replay(dockerfile: Path, block_index: int) -> None: """Execute one exact heredoc after inventorying the complete Dockerfile.""" size = dockerfile.stat().st_size if size < 1 or size > MAX_DOCKERFILE_BYTES: raise ValueError("Hermes Dockerfile size is outside the reviewed boundary") source = dockerfile.read_text(encoding="utf-8") blocks = extract_blocks(source) if block_index < 1 or block_index > len(blocks): raise ValueError("heredoc block index is outside the reviewed contract") command, body = blocks[block_index - 1] print(f"replaying reviewed Dockerfile heredoc {block_index}/{len(blocks)}") subprocess.run(command, input=body, text=True, check=True) def main() -> int: """Parse the one explicit Dockerfile path and replay its reviewed patches.""" parser = argparse.ArgumentParser() parser.add_argument("--dockerfile", required=True, type=Path) parser.add_argument("--block-index", required=True, type=int) args = parser.parse_args() replay(args.dockerfile, args.block_index) return 0 if __name__ == "__main__": raise SystemExit(main())