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