verify(v1.10): code review — 1 P0 auto-fixed, 1 P1 auto-fixed, 2 P1+ flagged
Multi-persona review of the v1.10 milestone (6 commits, 23 files).
P0-1 (auto-fixed): TOCTOU race in LocalEcsEmulator.deploy() — opened a
socket to find a free port, closed it, then bound TCPServer to that
port. Between close and bind, another process could grab the port,
causing serve_forever to fail with OSError: Address already in use.
Fix: bind TCPServer directly to port 0 (OS assigns a free port
atomically); read the assigned port back from server_address[1].
P1-1 (auto-fixed, upgraded): run_local_e2e() called os.chdir() as a
side-effect without restoring the prior CWD. Fix: wrapped the body in
try/finally that restores prior_cwd on exit.
P2-1 (flagged): regression registry covers microservice + static-assets
but not uptime-kuma or RDS stacks. Recommend adding in a future patch.
P2-2 (flagged): _check_outbox_writer uses an f-string to embed a temp
path into a python3 -c command. Safe in practice but fragile by design.
Verified after fixes: 513 fast tests + 5 slow local E2E tests pass.
No regressions.
---ci---
project: acdl
phase: 0
milestone: v1.10
status: verify
lessons:
- P0 fix: TOCTOU race in LocalEcsEmulator.deploy() — bind to port 0
directly instead of open/close/rebind.
- P1 fix: os.chdir side-effect in run_local_e2e() — restore prior
CWD in a finally block.
- The regression registry should be expanded to cover all L2 stacks
(uptime-kuma, RDS) to prevent untested-stack regressions.
---/ci---
This commit is contained in:
+76
-71
@@ -177,14 +177,15 @@ class LocalEcsEmulator:
|
||||
def log_message(self, *a, **k):
|
||||
pass # silence
|
||||
|
||||
# Bind to a free port.
|
||||
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
sock.bind(("127.0.0.1", 0))
|
||||
self._port = sock.getsockname()[1]
|
||||
sock.close()
|
||||
# Bind directly to port 0 (the OS assigns a free port atomically).
|
||||
# The prior approach (open a socket, read the port, close, then
|
||||
# bind TCPServer) was a TOCTOU race: another process could grab
|
||||
# the port between close and bind. Binding to port 0 avoids the
|
||||
# race entirely.
|
||||
self._server = socketserver.TCPServer(
|
||||
("127.0.0.1", self._port), Handler)
|
||||
("127.0.0.1", 0), Handler)
|
||||
self._server.allow_reuse_address = True
|
||||
self._port = self._server.server_address[1]
|
||||
self._thread = threading.Thread(
|
||||
target=self._server.serve_forever, daemon=True)
|
||||
self._thread.start()
|
||||
@@ -408,78 +409,82 @@ def run_local_e2e(contract_path: str, repo_root: Optional[Path] = None) -> Dict[
|
||||
Returns a dict of results. Raises AssertionError on any failure.
|
||||
"""
|
||||
root = Path(repo_root) if repo_root else ROOT
|
||||
prior_cwd = os.getcwd()
|
||||
os.chdir(str(root))
|
||||
sys.path.insert(0, str(root))
|
||||
from core.contract_resolver import resolve
|
||||
import adapters.terraform.adapter as adapter
|
||||
try:
|
||||
sys.path.insert(0, str(root))
|
||||
from core.contract_resolver import resolve
|
||||
import adapters.terraform.adapter as adapter
|
||||
|
||||
stack = resolve(contract_path, str(root))
|
||||
stack_name = stack["stack"]["name"]
|
||||
work = Path(tempfile.mkdtemp(prefix="acdl_local_e2e_"))
|
||||
tf_dir = work / "tf"
|
||||
tf_dir.mkdir(exist_ok=True)
|
||||
adapter.adapt(stack, str(tf_dir))
|
||||
stack = resolve(contract_path, str(root))
|
||||
stack_name = stack["stack"]["name"]
|
||||
work = Path(tempfile.mkdtemp(prefix="acdl_local_e2e_"))
|
||||
tf_dir = work / "tf"
|
||||
tf_dir.mkdir(exist_ok=True)
|
||||
adapter.adapt(stack, str(tf_dir))
|
||||
|
||||
# 3. Local S3 state backend rewrite.
|
||||
backend = LocalS3StateBackend.create(dir=work / "tfstate")
|
||||
tf_tf = tf_dir / "terraform.tf"
|
||||
backend.rewrite_terraform_tf(tf_tf, stack_name)
|
||||
assert "backend \"local\"" in tf_tf.read_text(), "backend not rewritten"
|
||||
# 3. Local S3 state backend rewrite.
|
||||
backend = LocalS3StateBackend.create(dir=work / "tfstate")
|
||||
tf_tf = tf_dir / "terraform.tf"
|
||||
backend.rewrite_terraform_tf(tf_tf, stack_name)
|
||||
assert "backend \"local\"" in tf_tf.read_text(), "backend not rewritten"
|
||||
|
||||
# 4. Local ECS emulator (only if the stack has an ECS service).
|
||||
ecs_result = None
|
||||
has_ecs = any(r["type"] == "aws:ecs:service" for r in stack["resources"])
|
||||
if has_ecs:
|
||||
ecs = LocalEcsEmulator(
|
||||
service_name=stack_name,
|
||||
service_definition={"desired_count": 1},
|
||||
)
|
||||
deploy_meta = ecs.deploy()
|
||||
ok, status = ecs.health_check(deploy_meta["endpoint"])
|
||||
assert ok, f"ECS emulator health check failed: status={status}"
|
||||
ecs_result = deploy_meta
|
||||
ecs.destroy()
|
||||
# 4. Local ECS emulator (only if the stack has an ECS service).
|
||||
ecs_result = None
|
||||
has_ecs = any(r["type"] == "aws:ecs:service" for r in stack["resources"])
|
||||
if has_ecs:
|
||||
ecs = LocalEcsEmulator(
|
||||
service_name=stack_name,
|
||||
service_definition={"desired_count": 1},
|
||||
)
|
||||
deploy_meta = ecs.deploy()
|
||||
ok, status = ecs.health_check(deploy_meta["endpoint"])
|
||||
assert ok, f"ECS emulator health check failed: status={status}"
|
||||
ecs_result = deploy_meta
|
||||
ecs.destroy()
|
||||
|
||||
# 5. Flat-file outbox: write a CONFIDENCE_COMPUTED event + verify chain.
|
||||
outbox = FlatFileOutbox.create(dir=work / "outbox")
|
||||
event = {
|
||||
"contractId": "local-e2e-test",
|
||||
"eventType": "CONFIDENCE_COMPUTED",
|
||||
"ts": datetime.datetime.now(datetime.timezone.utc)
|
||||
.strftime("%Y-%m-%dT%H:%M:%SZ"),
|
||||
"environment": "dev",
|
||||
"stack": stack_name,
|
||||
"score": 0.9,
|
||||
"band": "pass",
|
||||
"prev_event_hash": "GENESIS",
|
||||
}
|
||||
item = outbox.write_event(event)
|
||||
assert item["hash"], "outbox item missing hash"
|
||||
assert outbox.verify_chain(), "outbox hash chain broken"
|
||||
# 5. Flat-file outbox: write a CONFIDENCE_COMPUTED event + verify chain.
|
||||
outbox = FlatFileOutbox.create(dir=work / "outbox")
|
||||
event = {
|
||||
"contractId": "local-e2e-test",
|
||||
"eventType": "CONFIDENCE_COMPUTED",
|
||||
"ts": datetime.datetime.now(datetime.timezone.utc)
|
||||
.strftime("%Y-%m-%dT%H:%M:%SZ"),
|
||||
"environment": "dev",
|
||||
"stack": stack_name,
|
||||
"score": 0.9,
|
||||
"band": "pass",
|
||||
"prev_event_hash": "GENESIS",
|
||||
}
|
||||
item = outbox.write_event(event)
|
||||
assert item["hash"], "outbox item missing hash"
|
||||
assert outbox.verify_chain(), "outbox hash chain broken"
|
||||
|
||||
# 6. Local Lambda stub: invoke the contract_ingestor handler.
|
||||
lambda_stub = LocalLambdaStub(outbox=outbox)
|
||||
lambda_result = lambda_stub.invoke({
|
||||
"action": "submit_contract",
|
||||
"consumerRepo": "local-test/consumer",
|
||||
"contractId": "local-e2e-test",
|
||||
"contract": {"module": stack_name, "environment": "dev"},
|
||||
"environment": "dev",
|
||||
})
|
||||
assert lambda_result["statusCode"] == 200, (
|
||||
f"lambda stub returned {lambda_result['statusCode']}: {lambda_result.get('body')}")
|
||||
# 6. Local Lambda stub: invoke the contract_ingestor handler.
|
||||
lambda_stub = LocalLambdaStub(outbox=outbox)
|
||||
lambda_result = lambda_stub.invoke({
|
||||
"action": "submit_contract",
|
||||
"consumerRepo": "local-test/consumer",
|
||||
"contractId": "local-e2e-test",
|
||||
"contract": {"module": stack_name, "environment": "dev"},
|
||||
"environment": "dev",
|
||||
})
|
||||
assert lambda_result["statusCode"] == 200, (
|
||||
f"lambda stub returned {lambda_result['statusCode']}: {lambda_result.get('body')}")
|
||||
|
||||
return {
|
||||
"stack_name": stack_name,
|
||||
"tier": "local-emulator",
|
||||
"tf_dir": str(tf_dir),
|
||||
"backend": "local",
|
||||
"ecs": ecs_result,
|
||||
"outbox_dir": str(outbox.dir),
|
||||
"outbox_events": len(outbox.read_all()),
|
||||
"outbox_chain_verified": True,
|
||||
"lambda_status": lambda_result["statusCode"],
|
||||
}
|
||||
return {
|
||||
"stack_name": stack_name,
|
||||
"tier": "local-emulator",
|
||||
"tf_dir": str(tf_dir),
|
||||
"backend": "local",
|
||||
"ecs": ecs_result,
|
||||
"outbox_dir": str(outbox.dir),
|
||||
"outbox_events": len(outbox.read_all()),
|
||||
"outbox_chain_verified": True,
|
||||
"lambda_status": lambda_result["statusCode"],
|
||||
}
|
||||
finally:
|
||||
os.chdir(prior_cwd)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
Reference in New Issue
Block a user