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