Harden staging preflight receipt publication

This commit is contained in:
fwazb 2026-07-20 23:30:14 -07:00
parent 7bafcb4314
commit 16b32193f7
4 changed files with 361 additions and 25 deletions

View file

@ -33,15 +33,25 @@ Run from the exact clean, tracked source revision with an already authenticated
Cloud account that has the reviewed IAP/OS Login read path:
```bash
receipt_dir="$(mktemp -d "${TMPDIR:-/tmp}/livingip-leoclean-preflight.XXXXXX")"
chmod 0700 "$receipt_dir"
python3 ops/check_gcp_leoclean_nosend_preflight.py \
--output /tmp/leoclean-nosend-gcp-preflight.json
--output "$receipt_dir/preflight.json"
```
The output file is created with mode `0600`. Authentication, permission, and
connection failures emit only a bounded category; command stderr is not copied
into the receipt. The checker rejects an alternate repository root, an output
path inside the source tree, untracked critical inputs, and source drift during
the live observation.
The output parent must already exist, be owned by the operator, and have no
group/other write permission. The output name must not exist. The checker
creates it once with no-clobber/no-symlink semantics, keeps the same file and
directory identity open through publication, writes mode `0600`, and fsyncs
the file and directory. It never removes or overwrites the output pathname;
an ambiguous publication failure can therefore leave a private residue for
operator inspection.
Authentication, permission, connection, and receipt-publication failures emit
only a bounded category; command stderr and filesystem exception details are
not copied into the receipt or stdout. The checker rejects an alternate
repository root, an output path inside the source tree, untracked critical
inputs, and source drift during the live observation.
## Claim ceiling and rollback
@ -52,7 +62,8 @@ secret access, database authentication, scoped PostgreSQL permissions, image
publication, deployment, restart, rollback, model behavior, parity, traffic,
or production readiness.
This slice changes no repository-independent service state. Its local rollback
boundary is deletion of the branch/worktree and any generated receipt. Any
time-bounded SSH key created by the access path expires after at most five
minutes.
This slice changes no repository-independent service state beyond the stated
possibility of a time-bounded SSH key. Its local rollback boundary is deletion
of the branch/worktree; generated receipts and ambiguous private residues are
operator-owned evidence and are not deleted automatically. Any time-bounded
SSH key created by the access path expires after at most five minutes.

View file

@ -71,7 +71,22 @@ cut over safely and retire the VPS after soak.
#210 head. It checks exact control-plane and host prerequisites without
reading secrets, logging into PostgreSQL, deploying, or restarting. Its
bounded IAP/SSH path uses a fixed remote command and a maximum five-minute
key lifetime, but no live run is currently authorized.
key lifetime. Receipt publication now requires a pre-existing private
operator-owned directory, creates one mode-`0600` no-clobber/no-symlink
file through a held directory descriptor, verifies stable identity, fsyncs
both file and directory, and preserves ambiguous residues. No live run is
currently authorized.
- Artifact Registry cleanup policy is not an additional hard gate for the
package: immutable tags prevent deletion of the retained tagged candidate.
The post-push/finalization path must still re-prove the exact retained
candidate tag-to-digest binding immediately before deployment.
- Current offline evidence for the preflight extraction: 243 focused
preflight/package/OCI tests pass; Ruff, Python compilation, formatting, and
diff checks pass. The repository suite produced 2,497 passes and 5 expected
skips inside the desktop sandbox; all 18 sandbox-denied Docker, loopback, and
Swift-cache cases passed in a separately authorized 59-test local rerun,
reconciling the suite to 2,515 passes and 5 skips. No cloud or registry
endpoint was contacted.
- Historical only: the superseded preflight branch records an earlier live
observation of `e2-standard-4` on `teleo-staging-europe-west6`
(`10.60.0.0/20`) with an external IPv4 attachment. That observation is not

View file

@ -11,6 +11,7 @@ import json
import os
import re
import shlex
import stat
import subprocess
import sys
from collections.abc import Callable
@ -467,7 +468,10 @@ def _host_readback(runner: Runner, private_ip: str) -> dict[str, Any]:
_require(value["project"] == package.PROJECT, "host metadata project drifted")
_require(value["instance"] == package.INSTANCE, "host metadata instance drifted")
_require(value["service_account"] == package.SERVICE_ACCOUNT, "host metadata service account drifted")
_require(version is not None and int(version.group(1)) >= MINIMUM_DOCKER_MAJOR, "Docker server is below the reviewed minimum")
_require(
version is not None and int(version.group(1)) >= MINIMUM_DOCKER_MAJOR,
"Docker server is below the reviewed minimum",
)
_require(value["docker_server_os"] == "linux", "Docker server OS is not Linux")
_require(value["docker_server_arch"] == "amd64", "Docker server architecture is not amd64")
try:
@ -553,6 +557,151 @@ def _validated_repo_root(repo_root: Path) -> Path:
return resolved
def _normalized_output_path(path: Path) -> Path:
expanded = path.expanduser()
if not expanded.is_absolute():
expanded = Path.cwd() / expanded
if expanded.name in {"", ".", ".."}:
raise PreflightError("invalid_output_path", "preflight receipt output path is invalid")
try:
parent = expanded.parent.resolve(strict=True)
except OSError as exc:
raise PreflightError(
"invalid_output_path",
"preflight receipt parent must already exist",
) from exc
return parent / expanded.name
def _assert_private_output_parent(parent_descriptor: int, parent: Path) -> os.stat_result:
try:
observed = os.fstat(parent_descriptor)
named = os.stat(parent, follow_symlinks=False)
except OSError as exc:
raise PreflightError(
"invalid_output_path",
"preflight receipt parent cannot be identified safely",
) from exc
if not (
stat.S_ISDIR(observed.st_mode)
and (observed.st_dev, observed.st_ino) == (named.st_dev, named.st_ino)
and observed.st_uid == os.geteuid()
and observed.st_mode & 0o022 == 0
):
raise PreflightError(
"invalid_output_path",
"preflight receipt parent must be operator-owned and not group/world writable",
)
return observed
def _output_entry_stat(parent_descriptor: int, name: str) -> os.stat_result | None:
try:
return os.stat(name, dir_fd=parent_descriptor, follow_symlinks=False)
except FileNotFoundError:
return None
except OSError as exc:
raise PreflightError(
"invalid_output_path",
"preflight receipt output cannot be identified safely",
) from exc
def _open_private_output_parent(output_path: Path) -> int:
flags = os.O_RDONLY
if hasattr(os, "O_DIRECTORY"):
flags |= os.O_DIRECTORY
if hasattr(os, "O_NOFOLLOW"):
flags |= os.O_NOFOLLOW
try:
descriptor = os.open(output_path.parent, flags)
except OSError as exc:
raise PreflightError(
"invalid_output_path",
"preflight receipt parent is missing or unsafe",
) from exc
try:
_assert_private_output_parent(descriptor, output_path.parent)
if _output_entry_stat(descriptor, output_path.name) is not None:
raise PreflightError(
"invalid_output_path",
"preflight receipt output already exists",
)
except (OSError, PreflightError):
os.close(descriptor)
raise
return descriptor
def _write_all(descriptor: int, payload: bytes) -> None:
offset = 0
while offset < len(payload):
written = os.write(descriptor, payload[offset:])
if written <= 0:
raise OSError("preflight receipt write made no progress")
offset += written
def _publish_private_receipt(
output_path: Path,
parent_descriptor: int,
payload: dict[str, Any],
) -> None:
try:
encoded = (json.dumps(payload, allow_nan=False, indent=2, sort_keys=True) + "\n").encode("utf-8")
except (TypeError, ValueError) as exc:
raise PreflightError(
"receipt_publication_failed",
"preflight receipt could not be encoded",
) from exc
descriptor: int | None = None
try:
_assert_private_output_parent(parent_descriptor, output_path.parent)
if _output_entry_stat(parent_descriptor, output_path.name) is not None:
raise PreflightError(
"receipt_publication_failed",
"preflight receipt output was created before publication",
)
flags = os.O_WRONLY | os.O_CREAT | os.O_EXCL
if hasattr(os, "O_NOFOLLOW"):
flags |= os.O_NOFOLLOW
descriptor = os.open(output_path.name, flags, 0o600, dir_fd=parent_descriptor)
os.fchmod(descriptor, 0o600)
before = os.fstat(descriptor)
_write_all(descriptor, encoded)
os.fsync(descriptor)
after = os.fstat(descriptor)
named = os.stat(output_path.name, dir_fd=parent_descriptor, follow_symlinks=False)
through_path = os.stat(output_path, follow_symlinks=False)
if not (
stat.S_ISREG(after.st_mode)
and (before.st_dev, before.st_ino) == (after.st_dev, after.st_ino)
and (after.st_dev, after.st_ino) == (named.st_dev, named.st_ino)
and (after.st_dev, after.st_ino) == (through_path.st_dev, through_path.st_ino)
and after.st_uid == os.geteuid()
and stat.S_IMODE(after.st_mode) == 0o600
and after.st_nlink == 1
and after.st_size == len(encoded)
):
raise PreflightError(
"receipt_publication_failed",
"published preflight receipt identity or posture drifted",
)
_assert_private_output_parent(parent_descriptor, output_path.parent)
os.fsync(parent_descriptor)
except PreflightError:
raise
except OSError as exc:
raise PreflightError(
"receipt_publication_failed",
"preflight receipt publication failed",
) from exc
finally:
if descriptor is not None:
os.close(descriptor)
def _source_revision(
repo_root: Path,
*,
@ -591,34 +740,38 @@ def _source_revision(
return source_revision
def main() -> int:
def main(argv: list[str] | None = None) -> int:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--repo-root", type=Path, default=Path(__file__).resolve().parents[1])
parser.add_argument("--output", type=Path)
args = parser.parse_args()
args = parser.parse_args(argv)
output_path: Path | None = None
output_parent_descriptor: int | None = None
try:
repo_root = _validated_repo_root(args.repo_root)
if args.output:
output_path = args.output.expanduser().resolve()
output_path = _normalized_output_path(args.output)
try:
output_path.relative_to(repo_root)
except ValueError:
pass
else:
raise PreflightError("invalid_output_path", "preflight receipt must be written outside the source tree")
output_parent_descriptor = _open_private_output_parent(output_path)
source_revision = _source_revision(repo_root)
payload = build_preflight(source_revision=source_revision)
if _source_revision(repo_root) != source_revision:
raise PreflightError("source_revision_changed", "source revision changed during preflight")
if output_path is not None and output_parent_descriptor is not None:
_publish_private_receipt(output_path, output_parent_descriptor, payload)
except (PreflightError, subprocess.SubprocessError, OSError) as exc:
category = exc.category if isinstance(exc, PreflightError) else "local_preflight_unavailable"
payload = {"schema": SCHEMA, "status": "blocked", "category": category}
print(json.dumps(payload, separators=(",", ":"), sort_keys=True))
return 69 if category in {"authentication_required", "permission_denied", "connection_unavailable"} else 1
if output_path:
output_path.parent.mkdir(parents=True, exist_ok=True)
package.write_json(output_path, payload, mode=0o600)
finally:
if output_parent_descriptor is not None:
os.close(output_parent_descriptor)
print(json.dumps(payload, indent=2, sort_keys=True))
return 0

View file

@ -5,6 +5,8 @@ from __future__ import annotations
import copy
import hashlib
import json
import os
import stat
import subprocess
import sys
from collections.abc import Callable
@ -30,9 +32,7 @@ def live_fixtures() -> dict[str, object]:
"machineTypes/e2-standard-4"
),
"cpuPlatform": "Intel Broadwell",
"serviceAccounts": [
{"email": "sa-teleo-staging-vm@teleo-501523.iam.gserviceaccount.com"}
],
"serviceAccounts": [{"email": "sa-teleo-staging-vm@teleo-501523.iam.gserviceaccount.com"}],
"disks": [
{
"boot": True,
@ -169,9 +169,10 @@ def test_exact_read_only_preflight_passes_without_exposing_private_ip() -> None:
"ssh_key_maximum_lifetime": "5m",
}
assert payload["host"]["cloudsql_private_tcp_5432"] == "reachable"
assert payload["control_plane"]["cloudsql"]["private_ip_sha256"] == hashlib.sha256(
PRIVATE_IP.encode("ascii")
).hexdigest()
assert (
payload["control_plane"]["cloudsql"]["private_ip_sha256"]
== hashlib.sha256(PRIVATE_IP.encode("ascii")).hexdigest()
)
assert PRIVATE_IP not in json.dumps(payload)
assert len(calls) == 7
assert calls[:-1] == [
@ -446,7 +447,12 @@ def test_preflight_rejects_an_unrelated_clean_repository(tmp_path: Path) -> None
def test_direct_cli_imports_then_rejects_an_unrelated_repository(tmp_path: Path) -> None:
completed = subprocess.run(
[sys.executable, str(preflight.SOURCE_ROOT / "ops" / "check_gcp_leoclean_nosend_preflight.py"), "--repo-root", str(tmp_path)],
[
sys.executable,
str(preflight.SOURCE_ROOT / "ops" / "check_gcp_leoclean_nosend_preflight.py"),
"--repo-root",
str(tmp_path),
],
text=True,
capture_output=True,
check=False,
@ -457,3 +463,154 @@ def test_direct_cli_imports_then_rejects_an_unrelated_repository(tmp_path: Path)
"schema": "livingip.leocleanNoSendGcpPreflight.v1",
"status": "blocked",
}
def _private_output_directory(tmp_path: Path) -> Path:
directory = tmp_path / "private-receipts"
directory.mkdir(mode=0o700)
directory.chmod(0o700)
return directory
def _stub_successful_cli(monkeypatch: pytest.MonkeyPatch) -> dict[str, object]:
payload: dict[str, object] = {
"schema": preflight.SCHEMA,
"status": "pass",
"source_revision": REVISION,
}
monkeypatch.setattr(preflight, "_source_revision", lambda *_args, **_kwargs: REVISION)
monkeypatch.setattr(preflight, "build_preflight", lambda **_kwargs: payload)
return payload
def test_cli_publishes_one_private_no_clobber_receipt(
tmp_path: Path,
capsys: pytest.CaptureFixture[str],
monkeypatch: pytest.MonkeyPatch,
) -> None:
payload = _stub_successful_cli(monkeypatch)
output = _private_output_directory(tmp_path) / "preflight.json"
assert preflight.main(["--output", str(output)]) == 0
assert json.loads(capsys.readouterr().out) == payload
assert json.loads(output.read_text(encoding="utf-8")) == payload
observed = output.stat(follow_symlinks=False)
assert stat.S_ISREG(observed.st_mode)
assert stat.S_IMODE(observed.st_mode) == 0o600
assert observed.st_uid == os.geteuid()
assert observed.st_nlink == 1
@pytest.mark.parametrize("entry_kind", ["file", "directory", "symlink"])
def test_cli_rejects_every_preexisting_output_before_live_observation(
entry_kind: str,
tmp_path: Path,
capsys: pytest.CaptureFixture[str],
monkeypatch: pytest.MonkeyPatch,
) -> None:
output = _private_output_directory(tmp_path) / "preflight.json"
if entry_kind == "file":
output.write_text("existing\n", encoding="utf-8")
elif entry_kind == "directory":
output.mkdir()
else:
target = output.with_name("target.json")
target.write_text("target\n", encoding="utf-8")
output.symlink_to(target)
called = False
def unexpected_live_observation(**_kwargs: object) -> dict[str, object]:
nonlocal called
called = True
raise AssertionError("live observation must not run")
monkeypatch.setattr(preflight, "build_preflight", unexpected_live_observation)
assert preflight.main(["--output", str(output)]) == 1
assert called is False
assert json.loads(capsys.readouterr().out) == {
"category": "invalid_output_path",
"schema": preflight.SCHEMA,
"status": "blocked",
}
@pytest.mark.parametrize("unsafe_mode", [0o720, 0o702, 0o777])
def test_cli_rejects_group_or_world_writable_output_parent(
unsafe_mode: int,
tmp_path: Path,
capsys: pytest.CaptureFixture[str],
monkeypatch: pytest.MonkeyPatch,
) -> None:
parent = _private_output_directory(tmp_path)
parent.chmod(unsafe_mode)
called = False
def unexpected_live_observation(**_kwargs: object) -> dict[str, object]:
nonlocal called
called = True
raise AssertionError("live observation must not run")
monkeypatch.setattr(preflight, "build_preflight", unexpected_live_observation)
assert preflight.main(["--output", str(parent / "preflight.json")]) == 1
assert called is False
assert json.loads(capsys.readouterr().out)["category"] == "invalid_output_path"
def test_publication_race_fails_without_overwriting_the_created_entry(
tmp_path: Path,
capsys: pytest.CaptureFixture[str],
monkeypatch: pytest.MonkeyPatch,
) -> None:
output = _private_output_directory(tmp_path) / "preflight.json"
monkeypatch.setattr(preflight, "_source_revision", lambda *_args, **_kwargs: REVISION)
def race(**_kwargs: object) -> dict[str, object]:
output.write_text("replacement-sentinel\n", encoding="utf-8")
return {"schema": preflight.SCHEMA, "status": "pass", "source_revision": REVISION}
monkeypatch.setattr(preflight, "build_preflight", race)
assert preflight.main(["--output", str(output)]) == 1
assert output.read_text(encoding="utf-8") == "replacement-sentinel\n"
assert json.loads(capsys.readouterr().out) == {
"category": "receipt_publication_failed",
"schema": preflight.SCHEMA,
"status": "blocked",
}
def test_publication_failure_is_bounded_and_preserves_created_residue(
tmp_path: Path,
capsys: pytest.CaptureFixture[str],
monkeypatch: pytest.MonkeyPatch,
) -> None:
_stub_successful_cli(monkeypatch)
output = _private_output_directory(tmp_path) / "preflight.json"
real_fsync = preflight.os.fsync
sentinel = "private-publication-fault-sentinel"
def fail_file_fsync(descriptor: int) -> None:
if stat.S_ISREG(os.fstat(descriptor).st_mode):
raise OSError(sentinel)
real_fsync(descriptor)
monkeypatch.setattr(preflight.os, "fsync", fail_file_fsync)
assert preflight.main(["--output", str(output)]) == 1
stdout = capsys.readouterr().out
assert json.loads(stdout) == {
"category": "receipt_publication_failed",
"schema": preflight.SCHEMA,
"status": "blocked",
}
assert sentinel not in stdout
assert output.is_file()
assert stat.S_IMODE(output.stat().st_mode) == 0o600
assert json.loads(output.read_text(encoding="utf-8"))["status"] == "pass"