1919 validate_multi_mode_deployment ,
2020 validate_running_environment ,
2121)
22+ from openenv .validation import (
23+ format_shared_validation_report ,
24+ run_local_validation ,
25+ ValidationProfile ,
26+ )
2227
2328
2429def _looks_like_url (value : str ) -> bool :
@@ -48,9 +53,23 @@ def validate(
4853 bool ,
4954 typer .Option (
5055 "--json" ,
51- help = "Output local validation report as JSON (runtime validation is JSON by default) " ,
56+ help = "Output the RFC 008 shared validation report as JSON " ,
5257 ),
5358 ] = False ,
59+ profile : Annotated [
60+ str | None ,
61+ typer .Option (
62+ "--profile" ,
63+ help = "Validation profile: static, runtime, or full" ,
64+ ),
65+ ] = None ,
66+ output : Annotated [
67+ Path | None ,
68+ typer .Option (
69+ "--output" ,
70+ help = "Write the shared JSON validation report to this path" ,
71+ ),
72+ ] = None ,
5473 timeout : Annotated [
5574 float ,
5675 typer .Option (
@@ -74,6 +93,9 @@ def validate(
7493
7594 Runtime validation checks if a live OpenEnv server conforms to the
7695 versioned runtime API contract and returns a criteria-based JSON report.
96+ Explicit static, runtime, and full profiles emit the RFC 008 shared report.
97+ Automatic runtime launch is intended for trusted local source; connect to
98+ an already isolated server with `--url` for untrusted environments.
7799
78100 Examples:
79101
@@ -91,6 +113,9 @@ def validate(
91113
92114 # Validate specific environment
93115 $ openenv validate envs/echo_env
116+
117+ # Run every locally available check and record remote-only skips
118+ $ openenv validate envs/echo_env --profile full --output report.json
94119 ```
95120 """
96121 runtime_target = url
@@ -114,6 +139,80 @@ def validate(
114139 raise typer .Exit (1 )
115140 runtime_target = target
116141
142+ # Machine-readable and explicit-profile invocations use the RFC 008 shared
143+ # report. Only the unqualified human rendering stays on the legacy path.
144+ if profile is not None or output is not None or json_output :
145+ if profile is None :
146+ selected_profile = (
147+ ValidationProfile .RUNTIME
148+ if runtime_target is not None
149+ else ValidationProfile .STATIC
150+ )
151+ else :
152+ try :
153+ selected_profile = ValidationProfile (profile .lower ())
154+ except ValueError as exc :
155+ typer .echo (
156+ "Error: --profile must be one of: static, runtime, full" ,
157+ err = True ,
158+ )
159+ raise typer .Exit (1 ) from exc
160+
161+ if runtime_target is not None and selected_profile is ValidationProfile .STATIC :
162+ typer .echo (
163+ "Error: The static profile requires a local source directory" ,
164+ err = True ,
165+ )
166+ raise typer .Exit (1 )
167+
168+ if runtime_target is not None :
169+ shared_target : str | Path = runtime_target
170+ shared_runtime_url = runtime_target
171+ else :
172+ shared_target = Path .cwd () if target is None else Path (target )
173+ shared_runtime_url = None
174+ if not shared_target .exists ():
175+ typer .echo (f"Error: Path does not exist: { shared_target } " , err = True )
176+ raise typer .Exit (1 )
177+ if not shared_target .is_dir ():
178+ typer .echo (f"Error: Path is not a directory: { shared_target } " , err = True )
179+ raise typer .Exit (1 )
180+
181+ try :
182+ report = run_local_validation (
183+ shared_target ,
184+ profile = selected_profile ,
185+ runtime_url = shared_runtime_url ,
186+ timeout_s = timeout ,
187+ )
188+ except ValueError as exc :
189+ typer .echo (f"Error: { exc } " , err = True )
190+ raise typer .Exit (1 ) from exc
191+ payload = report .to_dict ()
192+ serialized = json .dumps (payload , indent = 2 )
193+
194+ if output is not None :
195+ try :
196+ output .parent .mkdir (parents = True , exist_ok = True )
197+ output .write_text (f"{ serialized } \n " , encoding = "utf-8" )
198+ except OSError as exc :
199+ typer .echo (
200+ f"Error: Unable to write validation report: { type (exc ).__name__ } " ,
201+ err = True ,
202+ )
203+ raise typer .Exit (1 ) from exc
204+
205+ if json_output :
206+ typer .echo (serialized )
207+ else :
208+ typer .echo (format_shared_validation_report (report ))
209+ if output is not None :
210+ typer .echo (f"Report written to { output } " )
211+
212+ if not report .passed :
213+ raise typer .Exit (1 )
214+ return
215+
117216 if runtime_target is not None :
118217 try :
119218 report = validate_running_environment (runtime_target , timeout_s = timeout )
0 commit comments