1#![deny(unsafe_code)]
8
9use std::sync::OnceLock;
10
11mod remote_scoped_launch;
12pub use remote_scoped_launch::REMOTE_PROCESS_IDENTITY_SCRIPT;
14
15pub mod admission_recommendation;
16pub mod admission_rejection;
17pub mod admit_preflight;
18pub mod api;
19pub mod artifact_cost;
20pub mod artifact_pattern;
21pub mod artifact_verify;
22pub mod binary_hash;
23pub mod bypass_record;
24pub mod bypass_recovery;
25pub mod capability_probe;
26pub mod cargo_path_deps;
27pub mod classifier_drift;
28pub mod closure_explain;
29pub mod config;
30pub mod dependency_closure_planner;
31pub mod discovery;
32pub mod disk_pressure_report;
33pub mod disk_reclaim;
34pub mod e2e;
35pub mod errors;
36pub mod exec_misuse;
37pub mod exec_policy;
38pub mod exec_response;
39pub mod fleet_diff;
40pub mod fleet_provenance;
41pub mod fleet_smoke_profile;
42pub mod fleet_status;
43pub mod force_resync;
44pub mod gc_roots;
45pub mod hooks;
46pub mod incident;
47pub mod incident_ledger;
48pub mod isolated_staging;
49pub mod job_identity;
50pub mod job_recovery;
51pub mod log_retention;
52pub mod logging;
53pub mod mock;
54pub mod mock_worker;
55pub mod orphan_quarantine;
56pub mod path_topology;
57pub mod patterns;
58#[cfg(test)]
59mod patterns_security_test;
60pub mod placement;
61pub mod pooled_target_key;
62pub mod process_identity;
63pub mod proof_handoff;
64pub mod proof_intent;
65pub mod proof_policy;
66pub mod proof_replay;
67#[cfg(test)]
68mod proptest_tests;
69pub mod protocol;
70pub mod queue_contract;
71pub mod readiness;
72pub mod redaction;
73pub mod remediation_config;
74pub mod remediation_view;
75#[cfg(unix)]
76pub mod remote_compilation;
77#[cfg(unix)]
78pub mod remote_verification;
79pub mod repo_updater_contract;
80pub mod rsync_flavor;
81pub mod schema_versions;
82#[cfg(unix)]
83pub mod ssh;
84#[cfg(all(test, unix))]
85mod ssh_timeout_test;
86pub mod ssh_utils;
87pub mod stale_target_reap;
88pub mod storm_control;
89pub mod telemetry_explain;
90pub mod telemetry_freshness;
91pub mod test_change;
92pub mod testing;
93pub mod toolchain;
94pub mod transfer_hardening;
95pub mod types;
96pub mod ui;
97pub mod util;
98pub mod worker_config_validation;
99pub mod worker_facts;
100
101pub const BUILD_COMMIT_ENV_VARS: &[&str] = &[
102 "RCH_GIT_COMMIT",
103 "VERGEN_GIT_SHA",
104 "GIT_COMMIT",
105 "GITHUB_SHA",
106];
107
108pub fn build_commit() -> Option<&'static str> {
114 first_build_commit([
115 option_env!("RCH_GIT_COMMIT"),
116 option_env!("VERGEN_GIT_SHA"),
117 option_env!("GIT_COMMIT"),
118 option_env!("GITHUB_SHA"),
119 ])
120}
121
122fn first_build_commit<'a>(
123 candidates: impl IntoIterator<Item = Option<&'a str>>,
124) -> Option<&'a str> {
125 candidates
126 .into_iter()
127 .flatten()
128 .map(str::trim)
129 .find(|value| is_build_commit_stamp(value))
130}
131
132fn is_build_commit_stamp(value: &str) -> bool {
135 fn is_commit_hash(value: &str) -> bool {
136 (7..=64).contains(&value.len()) && value.bytes().all(|byte| byte.is_ascii_hexdigit())
137 }
138 is_commit_hash(value)
139 || value.strip_suffix("-dirty").is_some_and(is_commit_hash)
140 || value
141 .split_once("-overlay-")
142 .is_some_and(|(commit, fingerprint)| {
143 is_commit_hash(commit)
144 && fingerprint.len() == 64
145 && fingerprint.bytes().all(|byte| byte.is_ascii_hexdigit())
146 })
147}
148
149pub fn build_version_value() -> String {
150 build_version_value_with_commit(env!("CARGO_PKG_VERSION"), build_commit())
151}
152
153pub fn build_version_value_static() -> &'static str {
154 static VERSION_VALUE: OnceLock<String> = OnceLock::new();
155
156 VERSION_VALUE.get_or_init(build_version_value).as_str()
157}
158
159pub fn build_version_value_with_commit(package_version: &str, commit: Option<&str>) -> String {
160 let mut value = package_version.to_string();
161
162 if let Some(commit) = commit.map(str::trim).filter(|value| !value.is_empty()) {
163 value.push_str(" (commit ");
164 let (revision, suffix) = commit
165 .split_once('-')
166 .map_or((commit, None), |(revision, suffix)| {
167 (revision, Some(suffix))
168 });
169 value.push_str(short_commit(revision));
170 if let Some(suffix) = suffix {
171 value.push('-');
172 value.push_str(suffix);
173 }
174 value.push(')');
175 }
176
177 value
178}
179
180fn short_commit(commit: &str) -> &str {
181 commit
182 .char_indices()
183 .nth(12)
184 .map_or(commit, |(index, _)| &commit[..index])
185}
186
187pub use artifact_cost::{
188 ArtifactCostReport, ArtifactPhaseTimings, GlobAdvice, RetrievalMode, assess_glob_expansion,
189 compute_artifact_cost, is_broad_recursive_glob,
190};
191pub use artifact_pattern::{
192 ARTIFACT_OUTPUT_ROOTS, ArtifactPatternRewrite, ArtifactRetrievalDiagnostics,
193 artifact_dest_is_safe, rewrite_artifact_pattern,
194};
195pub use artifact_verify::{
196 ArtifactManifest, FileHash, VerificationFailure, VerificationResult, compute_file_hash,
197 create_manifest, verify_artifacts,
198};
199pub use binary_hash::{
200 BinaryHashResult, binaries_equivalent, binary_contains_marker, compute_binary_hash,
201};
202pub use bypass_record::{
203 AutoRejoinCriteria, BypassBackoff, BypassFailureClass, BypassRecord, BypassRecordStore,
204 BypassState, DisabledMigration, DisabledWorkerSnapshot, MAX_DIAGNOSTIC_CHARS,
205 bypass_record_schema, bypass_record_schema_version, classify_disable_reason,
206 default_bypass_record_path, migrate_disabled_worker, truncate_diagnostic,
207};
208pub use bypass_recovery::{
209 CanaryDecision, CanaryOutcome, ProbeDecision, RecoveryProbe, decide_canary, decide_probe,
210};
211pub use cargo_path_deps::{
212 CargoPathDependencyEdge, CargoPathDependencyError, CargoPathDependencyErrorKind,
213 CargoPathDependencyGraph, CargoPathDependencyPackage, CargoPathMaterializationClosure,
214 resolve_cargo_path_dependency_graph, resolve_cargo_path_dependency_graph_with_policy,
215 resolve_cargo_path_materialization_closure,
216 resolve_cargo_path_materialization_closure_with_policy,
217};
218pub use closure_explain::{
219 ClosureExplainEntry, ClosureExplainReport, RootConvergence, RootSyncOutcome, derive_outcome,
220 explain_closure,
221};
222pub use dependency_closure_planner::{
223 DependencyClosurePlan, DependencyClosurePlanState, DependencyPlanIssue, DependencyRiskClass,
224 DependencySyncAction, DependencySyncMetadata, DependencySyncReason,
225 build_dependency_closure_plan, build_dependency_closure_plan_with_policy,
226 plan_dependency_closure_from_graph,
227};
228pub use force_resync::{
229 ForceResyncPlan, ForceResyncReport, InvalidationAction, RefusedInvalidation, ResyncOutcome,
230 StaleRoot, apply_force_resync, is_safe_invalidation_target, plan_force_resync,
231};
232pub use gc_roots::{
233 RCH_CARGO_CACHE_PREFIX, RCH_CARGO_HOME_BASE_VAR, RCH_CARGO_HOME_PREFIX,
234 remote_cargo_cache_expr, remote_cargo_home_base_prelude, remote_cargo_home_expr,
235};
236pub use logging::{LogConfig, LogFormat, LoggingGuards, init_logging, init_logging_with_layer};
237pub use mock_worker::MockWorkerServer;
238pub use path_topology::{
239 DEFAULT_ALIAS_PROJECT_ROOT, DEFAULT_CANONICAL_PROJECT_ROOT, NormalizationDecision,
240 NormalizedProjectPath, PathNormalizationError, PathNormalizationErrorKind, PathTopologyPolicy,
241 normalize_project_path, normalize_project_path_with_policy,
242};
243pub use patterns::{
244 Classification, ClassificationDetails, ClassificationTier, CompilationKind, TierDecision,
245 classify_command, classify_command_detailed, compound_local_compilation_segments,
246 declined_compilation_due_to_structure, split_shell_commands,
247};
248pub use protocol::{HookInput, HookOutput, ToolInput};
249pub use queue_contract::{
250 AdmissionState, QueueContractOutcome, QueueContractResponse, QueueOptions, StartState,
251 WaitResult, resolve_queue_contract,
252};
253pub use repo_updater_contract::{
254 MockRepoUpdaterAdapter, REPO_UPDATER_ALIAS_PROJECTS_ROOT, REPO_UPDATER_CANONICAL_PROJECTS_ROOT,
255 REPO_UPDATER_CONTRACT_SCHEMA_VERSION, REPO_UPDATER_DEFAULT_BINARY,
256 REPO_UPDATER_MIN_SUPPORTED_VERSION, RepoUpdaterAdapter, RepoUpdaterAdapterCommand,
257 RepoUpdaterAdapterContract, RepoUpdaterAdapterRequest, RepoUpdaterAdapterResponse,
258 RepoUpdaterFailure, RepoUpdaterFailureKind, RepoUpdaterFallbackMode,
259 RepoUpdaterIdempotencyGuarantee, RepoUpdaterJsonEnvelope, RepoUpdaterOutputFormat,
260 RepoUpdaterResponseStatus, RepoUpdaterVersionCompatibility, RepoUpdaterVersionPolicy,
261 build_invocation, classify_exit_code, evaluate_version_compatibility,
262 map_failure_kind_to_error_code, repo_updater_envelope_schema, repo_updater_request_schema,
263 repo_updater_response_schema,
264};
265pub use ssh_utils::{
267 CommandResult, EnvPrefix, build_env_prefix, is_retryable_transport_error,
268 is_retryable_transport_error_text, shell_escape_value,
269};
270#[cfg(unix)]
272pub use ssh::{KnownHostsPolicy, SshClient, SshOptions, SshPool};
273pub use test_change::{TestChangeGuard, TestCodeChange};
274pub use toolchain::{ToolchainInfo, wrap_command_with_color, wrap_command_with_toolchain};
275pub use transfer_hardening::{
276 FirstFailure, RetryDecision, RsyncFailureClass, classify_rsync_outcome, is_ephemeral_path,
277};
278pub use types::{
279 AffinityConfig, ApiConfig, BoxRole, BuildCancellationMetadata, BuildCancellationWorkerHealth,
280 BuildHeartbeatPhase, BuildHeartbeatRequest, BuildLocation, BuildRecord, BuildStats,
281 CircuitBreakerConfig, CircuitState, CircuitStats, ColorMode, CommandPriority,
282 CommandTimingBreakdown, CompilationConfig, CompilationMetrics, CompilationTimer,
283 CompilationTimingBreakdown, DashboardConfig, DoctorConfig, DoctorWebhookEndpoint,
284 DoctorWebhookFormat, DoctorWebhooksConfig, EnvironmentConfig, ExecutionConfig, FairnessConfig,
285 FleetConfig, GeneralConfig, MetricsAggregator, OS_TAG_PREFIX, OutputConfig, OutputVisibility,
286 PathTopologyConfig, RchConfig, ReleaseRequest, RemoteBuildJobs, RequiredRuntime, RetryConfig,
287 SELECTION_RESPONSE_PROTOCOL_VERSION, SavedTimeStats, SelectedWorker, SelectionConfig,
288 SelectionDiagnostics, SelectionReason, SelectionRequest, SelectionResponse, SelectionStrategy,
289 SelectionWeightConfig, SelfHealingConfig, SelfHealingLogLevel, SelfTestConfig,
290 SelfTestFailureAction, SelfTestWorkers, TransferConfig, WorkerCapabilities, WorkerConfig,
291 WorkerId, WorkerSelectionDiagnostic, WorkerSelectionDiagnosticDecision, WorkerStatus,
292 declared_os, default_socket_path, os_tag, validate_remote_base,
293 x86_64_microarch_level_from_flags,
294};
295
296pub use testing::{TestLogEntry, TestLogger, TestPhase, TestResult};
298
299pub use config::{
301 ConfigSource, ConfigValueSource, ConfigWarning, EnvError, EnvParser, Profile, Severity,
302 Sourced, validate_config,
303};
304
305pub use discovery::{
307 DiscoveredHost, DiscoverySource, discover_all, parse_shell_aliases,
308 parse_shell_aliases_content, parse_ssh_config, parse_ssh_config_content,
309};
310
311pub use ui::{
313 ErrorPanel, ErrorSeverity, Icons, IntoErrorPanel, OutputContext, RchTheme, ResultExt,
314 anyhow_to_json, anyhow_to_panel, display_anyhow_error, display_error, display_error_with_code,
315 error_to_json, error_to_panel,
316};
317
318pub use capability_probe::{
320 CapabilityRequirement, CapabilityVerdict, EligibilityVerdict, ProbeSpec, ProbedFacts,
321 WorkerLiveness, assess_admissibility, assess_worker_eligibility, build_capability_probe_script,
322 parse_capability_probe, remote_worker_binary_path,
323};
324pub use incident::{
325 ControlState, IncidentEvent, IncidentEventType, IncidentReasonCode, IncidentSource,
326 SelectedMode, incident_schema_version,
327};
328pub use incident_ledger::{
329 IncidentFilter, IncidentLedger, IncidentLedgerConfig, LedgerReadStats, default_ledger_path,
330};
331pub use placement::{
332 ControlDiagnostic, ControlDiagnosticLevel, ControlKind, PlacementControl, PlacementPlan,
333 QueuePolicy, RequestedWorkerFacts, RequestedWorkerOutcome, RequestedWorkerStatus,
334 StrictRemotePolicy, TargetDirPolicy, VisibilityMode, evaluate_requested_worker,
335 placement_controls, resolve_placement,
336};
337pub use proof_intent::{
338 ProofIntent, ProofIntentStore, ReplayConstraints, ReplayContext, ReplayDecision,
339 SourceFingerprint, StaleSourcePolicy, derive_intent_id, proof_intent_schema,
340 proof_intent_schema_version, validate_replay,
341};
342pub use telemetry_explain::{
343 ProbeOutcome, TelemetrySignals, TelemetryUnavailabilityReason, WhyUnhealthy,
344 explain_unavailability,
345};
346pub use telemetry_freshness::{
347 FreshnessAssessment, FreshnessInputs, FreshnessVerdict, assess as assess_telemetry_freshness,
348};
349pub use worker_config_validation::{
350 ConfigDriftFinding, ConfigDriftKind, LiveHostObservation, validate_worker_config,
351};
352pub use worker_facts::{
353 DiskFacts, DiskRootFacts, HostFacts, RuntimeFacts, RustFacts, UserFacts, WorkerBinaryFacts,
354 WorkerFacts, derive_target_triple, worker_facts_schema, worker_facts_schema_version,
355};
356
357pub use errors::{
359 CodeExplanation, CodeNamespace, ErrorCategory, ErrorCode, ErrorEntry, ReliabilityCategoryKind,
360 ReliabilityReasonCode, RunbookEntry,
361};
362
363pub use schema_versions::current_version as schema_version;
365pub use schema_versions::{ALL_COMPONENTS as SCHEMA_VERSION_COMPONENTS, SchemaComponent};
366
367pub use api::{API_VERSION, ApiError, ApiResponse, ErrorContext, LegacyErrorCode};
369
370pub use hooks::{HookResult, is_claude_code_installed, verify_and_install_claude_code_hook};
372
373#[cfg(test)]
374mod build_version_tests {
375 use super::{BUILD_COMMIT_ENV_VARS, build_version_value_with_commit, first_build_commit};
376
377 #[test]
378 fn build_commit_skips_values_the_build_script_rejects() {
379 assert_eq!(
381 first_build_commit([None, None, Some("not-a-commit"), None]),
382 None
383 );
384 let hash = "0123456789abcdef0123456789abcdef01234567";
385 assert_eq!(
386 first_build_commit([Some(""), None, Some("v2.0.0-3-gdeadbee"), Some(hash)]),
387 Some(hash)
388 );
389 assert_eq!(first_build_commit([Some(" abc1234 ")]), Some("abc1234"));
390 assert_eq!(first_build_commit([Some("abc123")]), None, "too short");
391 let dirty = format!("{hash}-dirty");
392 assert_eq!(
393 first_build_commit([Some(dirty.as_str())]),
394 Some(dirty.as_str())
395 );
396 let overlay = format!("{hash}-overlay-{}", "b".repeat(64));
397 assert_eq!(
398 first_build_commit([Some(overlay.as_str())]),
399 Some(overlay.as_str())
400 );
401 let short_overlay = format!("{hash}-overlay-{}", "b".repeat(63));
402 assert_eq!(first_build_commit([Some(short_overlay.as_str())]), None);
403 }
404
405 #[test]
406 fn build_version_value_omits_missing_commit() {
407 assert_eq!(build_version_value_with_commit("1.0.24", None), "1.0.24");
408 }
409
410 #[test]
411 fn build_version_value_trims_and_shortens_commit() {
412 assert_eq!(
413 build_version_value_with_commit(
414 "1.0.24",
415 Some(" 2fa1249a18dfd05ae5e319e8d10bfd3c9ea1af55 "),
416 ),
417 "1.0.24 (commit 2fa1249a18df)"
418 );
419 }
420
421 #[test]
422 fn build_version_value_ignores_empty_commit() {
423 assert_eq!(
424 build_version_value_with_commit("1.0.24", Some(" ")),
425 "1.0.24"
426 );
427 }
428
429 #[test]
430 fn build_source_stamp_version_preserves_nonclean_suffixes() {
431 let hash = "a".repeat(40);
432 for suffix in ["dirty".to_string(), format!("overlay-{}", "b".repeat(64))] {
433 assert_eq!(
434 build_version_value_with_commit("2.0.0", Some(&format!("{hash}-{suffix}"))),
435 format!("2.0.0 (commit {}-{suffix})", "a".repeat(12))
436 );
437 }
438 }
439
440 #[test]
441 fn build_commit_env_var_order_is_documented() {
442 assert_eq!(
443 BUILD_COMMIT_ENV_VARS,
444 &[
445 "RCH_GIT_COMMIT",
446 "VERGEN_GIT_SHA",
447 "GIT_COMMIT",
448 "GITHUB_SHA"
449 ]
450 );
451 }
452}