Add fail-closed ACME authority helper injection

This commit is contained in:
2026-09-18 23:23:20 -04:00
parent 5e766cf51a
commit 0809cc740a
+135 -6
View File
@@ -11,6 +11,21 @@ import os
AUTHORITY_FILE = "/acme_authority/state/acme-authority" AUTHORITY_FILE = "/acme_authority/state/acme-authority"
HELPER_MARKER = "const acmeAuthorityFile ="
AUTHORITY_HELPER = f"""const acmeAuthorityFile = "{AUTHORITY_FILE}";
const requireAcmeAuthority = () => {{
try {{
fs.accessSync(acmeAuthorityFile, fs.constants.R_OK);
}} catch {{
throw new error.ValidationError(
"ACME operations are disabled on this cluster node",
);
}}
}};
"""
@dataclass(frozen=True) @dataclass(frozen=True)
class GateConfig: class GateConfig:
@@ -65,19 +80,133 @@ def write_source(path: Path, source: str) -> None:
path.write_text(source) path.write_text(source)
def replace_exactly_once(
source: str,
old: str,
new: str,
*,
description: str,
) -> str:
count = source.count(old)
if count != 1:
raise RuntimeError(
f"{description}: expected anchor exactly once, found {count}"
)
return source.replace(old, new, 1)
def require_fragment(
source: str,
fragment: str,
*,
description: str,
) -> None:
if fragment not in source:
raise RuntimeError(
f"{description}: required fragment not found"
)
def apply_authority_helper(source: str) -> str: def apply_authority_helper(source: str) -> str:
""" """
Install the common requireAcmeAuthority() helper. Install the shared requireAcmeAuthority() helper.
Implemented in the next development step. The helper is inserted immediately after the top-level fs import so the
patch remains close to the dependency it requires.
""" """
raise NotImplementedError("authority helper mutation not implemented yet")
expected_declaration = (
f'const acmeAuthorityFile = "{AUTHORITY_FILE}";'
)
if expected_declaration in source:
require_fragment(
source,
"const requireAcmeAuthority = () => {",
description="existing authority helper",
)
require_fragment(
source,
"fs.accessSync(acmeAuthorityFile, fs.constants.R_OK);",
description="existing authority helper",
)
log("authority_helper=already-present")
return source
if HELPER_MARKER in source:
raise RuntimeError(
"authority helper already exists but does not match "
f"configured authority file {AUTHORITY_FILE}"
)
# Prefer the end of the known ESM import block used by current NPM.
# Older CommonJS releases fall back to their fs import.
supported_anchors = (
'import internalNginx from "./nginx.js";\n',
'const fs = require("fs");\n',
'const fs = require("node:fs");\n',
)
matches = [
anchor
for anchor in supported_anchors
if anchor in source
]
if len(matches) != 1:
raise RuntimeError(
"authority helper: expected exactly one supported insertion "
f"anchor, found {len(matches)}"
)
anchor = matches[0]
replacement = anchor + "\n" + AUTHORITY_HELPER
source = replace_exactly_once(
source,
anchor,
replacement,
description="authority helper",
)
log(f"authority_helper=added anchor={anchor.strip()!r}")
return source
def verify(source: str, config: GateConfig) -> None: def verify(source: str, config: GateConfig) -> None:
""" """
Verify every requested mutation before certificate.js is written. Verify shared patch state.
Implemented after the individual mutation modules. Individual mutation modules will add their own verification markers as
they are implemented.
""" """
raise NotImplementedError("patch verification not implemented yet")
if config.any_enabled:
require_fragment(
source,
f'const acmeAuthorityFile = "{AUTHORITY_FILE}";',
description="authority helper verification",
)
require_fragment(
source,
"const requireAcmeAuthority = () => {",
description="authority helper verification",
)
require_fragment(
source,
"fs.accessSync(acmeAuthorityFile, fs.constants.R_OK);",
description="authority helper verification",
)
require_fragment(
source,
"ACME operations are disabled on this cluster node",
description="authority helper verification",
)
log("verification=passed")