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