Skip to main content

tfparser_core/discovery/
mod.rs

1//! Workspace discovery — the first cross-trust-boundary phase.
2//!
3//! Given a workspace root, walk the filesystem with the [`ignore`] crate (the
4//! same engine `ripgrep` uses), classify each directory as a component,
5//! module, or environment, and emit an ordered, deterministic
6//! [`Discovered`] structure for the loader and Terragrunt resolver to
7//! consume.
8//!
9//! No HCL parsing happens here — only a regex-grade shallow probe of file
10//! bytes (per [11-discovery.md § 3.3]) that the loader will redo definitively.
11//!
12//! This module is the **first slice of code** that touches user-controlled
13//! filesystem state. Every byte off disk is treated as hostile per
14//! [70-security.md § 1]: paths are NUL-rejected, canonicalised, and verified
15//! to remain underneath the workspace root before any open.
16//!
17//! [11-discovery.md § 3.3]: ../../../specs/11-discovery.md
18//! [70-security.md § 1]: ../../../specs/70-security.md
19
20mod classifier;
21mod fs_walker;
22mod options;
23mod types;
24
25use std::path::Path;
26
27pub use classifier::ClassificationReason;
28pub use fs_walker::FsDiscoverer;
29pub use options::{
30    DiscoveryOptions, DiscoveryOptionsBuilder, GlobConfigError, MAX_DISCOVERY_THREADS,
31    MAX_GLOB_PATTERN_BYTES, compile_glob_set,
32};
33pub use types::{DirKind, Discovered, DiscoveredDir, DiscoveredFile};
34
35use crate::Result;
36
37/// Trait every discoverer implements. The default impl is [`FsDiscoverer`];
38/// downstream tests / embedders may supply an in-memory variant by
39/// implementing this trait directly.
40pub trait Discoverer: Send + Sync {
41    /// Walk `root` according to `opts` and produce a [`Discovered`].
42    ///
43    /// # Errors
44    ///
45    /// Returns [`crate::Error`] when the root is missing, the workspace
46    /// breaches a configured cap, or the discovery walk hits a fatal I/O
47    /// failure. Non-fatal anomalies (broken symlinks, oversized files,
48    /// ambiguous classifications) accumulate in
49    /// [`Discovered::diagnostics`].
50    fn discover(&self, root: &Path, opts: &DiscoveryOptions) -> Result<Discovered>;
51}