Skip to content

Commit c504288

Browse files
committed
Add the client side of the pre-render environment preflight
A render against a machine that is missing a runtime, a library, a credential or an executable test script cannot succeed. It loops through failing tests until it gives up, spending a credit on every attempt. This adds a preflight that runs before the first functionality is rendered and turns that into a single actionable failure up front. The preflight has two layers. The static layer is deterministic and needs no server: git and bash are installed, every configured test script exists and is executable, the script flavour matches the platform, the build folder is writable. The planned layer asks the server which checks this particular project needs, given its specs, linked resources, test scripts and a description of the host. A plan from the server is untrusted input, so env_check/checks.py is the only place that turns a plan entry into an action, and it never executes a string the plan supplied. A plan selects a type from a fixed registry and supplies arguments that are validated first; binaries are resolved through which() and spawned from an argument list without a shell; the only flags ever passed to a binary the client did not choose are version flags from an allowlist. Everything that does not validate is dropped with a recorded reason rather than raising, so a malformed or unrecognised entry can never stop a render. Only a failed error-severity finding blocks. Warnings, skipped checks, an unreachable server and a context that cannot be assembled all leave the render free to proceed. Adds --skip-env-check to bypass the preflight and --env-check-only to run it without rendering, which exits non-zero when the environment is not ready.
1 parent 6ddfa74 commit c504288

17 files changed

Lines changed: 2035 additions & 6 deletions

‎codeplain_REST_api.py‎

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,27 @@ def status(self):
173173
}
174174
return self.post_request(endpoint_url, headers, payload, None, num_retries=0, silent=True)
175175

176+
def check_environment(self, environment_context: dict, run_state: RunState) -> dict:
177+
"""
178+
Asks the server which environment checks this project needs before rendering starts.
179+
180+
Args:
181+
environment_context (dict): The specs of every module, their linked resources,
182+
the configured testing scripts and a description of
183+
the host machine.
184+
run_state (RunState): The current state of the rendering process.
185+
186+
Returns:
187+
dict: A check plan with "checks" (probes the client executes locally) and
188+
"advisories" (findings that need no probe).
189+
"""
190+
endpoint_url = f"{self.api_url}/check_environment"
191+
headers = {"X-API-Key": self.api_key, "Content-Type": "application/json"}
192+
193+
# The planned layer is best effort: the caller falls back to the client's own
194+
# deterministic checks when this call does not succeed, so it retries only once.
195+
return self.post_request(endpoint_url, headers, dict(environment_context), run_state, num_retries=1)
196+
176197
def render_functional_requirement(
177198
self,
178199
frid: str,

‎env_check/__init__.py‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
"""Pre-render verification that the machine can actually build and test the project."""
2+
3+
from env_check.preflight import run_environment_preflight
4+
from env_check.report import format_failure_summary, print_report
5+
from env_check.types import PreflightReport
6+
7+
__all__ = [
8+
"run_environment_preflight",
9+
"print_report",
10+
"format_failure_summary",
11+
"PreflightReport",
12+
]

0 commit comments

Comments
 (0)