1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
//! Name validation utilities for `libvctrl_core`.
//!
//! # Purpose
//!
//! This module provides utility functions to validate the structural and
//! security constraints of names used in the version control system (e.g.,
//! branch names, tag names, tree entry names). The central function,
//! [`validate_name`], enforces a strict set of rules before a string is
//! accepted as a valid identifier.
//!
//! # Design Rationale
//!
//! - **Security defense**: The primary rationale is to prevent path traversal
//! attacks. If a malicious actor supplies a name like `../../etc/passwd`,
//! it could cause a naive filesystem backend to write or read outside the
//! designated repository directory. By strictly forbidding slashes (`/`)
//! and special directory names (`.` and `..`), this module enforces a safe
//! namespace.
//! - **Resource exhaustion prevention**: Enforcing a maximum length
//! ([`MAX_NAME_LENGTH`](libvctrl_handler::MAX_NAME_LENGTH)) prevents
//! pathologically long names from causing excessive memory allocations or
//! exceeding filesystem limits.
//! - **Centralized logic**: By centralizing these rules, all object builders
//! and reference stores can delegate to this function, ensuring consistent
//! validation across the entire system.
//!
//! # Relationship to `libvctrl_handler`
//!
//! The handler crate provides its own internal validation helpers for use in
//! its constructors. This module reimplements the same rules in a standalone
//! function so that `libvctrl_core` can validate names before passing them to
//! handler constructors. This avoids duplicating validation logic in multiple
//! backend implementations.
//!
//! # Security Considerations
//!
//! The validation rules are intentionally strict. A name must:
//!
//! 1. Be non-empty.
//! 2. Not exceed [`MAX_NAME_LENGTH`](libvctrl_handler::MAX_NAME_LENGTH)
//! bytes.
//! 3. Not contain a forward slash (`/`), which is a path separator on
//! Unix-like systems.
//! 4. Not be exactly `.` or `..`, which are special directory aliases.
//!
//! These rules are the minimum required to prevent directory traversal and
//! filesystem confusion. They do not enforce character-set restrictions
//! (e.g., forbidding control characters), which may be added later if needed.
//!
//! # Performance
//!
//! The function performs a constant number of checks and one linear scan for
//! the slash character. The overall time complexity is O(n), where n is the
//! length of the name. The checks are ordered from cheapest to most expensive
//! to fail fast on common invalid inputs.
//!
//! # Examples
//!
//! Validating a correct name:
//!
//! ```
//! use libvctrl_core::validate::name::validate_name;
//!
//! assert!(validate_name("feature_branch").is_ok());
//! assert!(validate_name("v1.0.0").is_ok());
//! ```
//!
//! Rejecting an empty name:
//!
//! ```
//! use libvctrl_core::validate::name::validate_name;
//! assert!(validate_name("").is_err());
//! ```
//!
//! Rejecting a name with a path separator:
//!
//! ```
//! use libvctrl_core::validate::name::validate_name;
//! assert!(validate_name("dir/file").is_err());
//! ```
//!
//! Rejecting directory aliases:
//!
//! ```
//! use libvctrl_core::validate::name::validate_name;
//! assert!(validate_name(".").is_err());
//! assert!(validate_name("..").is_err());
//! ```
use ;
/// Validates a name string against length and security rules.
///
/// # Purpose
///
/// This function acts as a gatekeeper for any string used as an identifier
/// or filename within the version control system. It returns `Ok(())` if the
/// name passes all checks, or an error describing the first failure.
///
/// # Design Rationale
///
/// The checks are ordered from cheapest to most expensive:
///
/// 1. Emptiness check (fast length check).
/// 2. Maximum length check (bounds resource usage).
/// 3. Slash containment check (prevents directory traversal).
/// 4. Exact match for `.` and `..` (prevents directory hijacking).
///
/// This ordering ensures that the most common invalid inputs fail quickly,
/// reducing the average cost of validation.
///
/// # Internal Mechanism
///
/// The function uses standard string slicing and searching methods. The
/// [`str::contains`] method is used for slash detection, which performs a
/// linear scan but is highly optimized in the standard library. The exact
/// equality checks for `.` and `..` are simple pointer comparisons after the
/// length and slash checks have already run.
///
/// # Errors
///
/// Returns
/// [`VctrlError::InvalidName`](libvctrl_handler::VctrlError::InvalidName)
/// if the name:
///
/// - Is empty.
/// - Exceeds
/// [`MAX_NAME_LENGTH`](libvctrl_handler::MAX_NAME_LENGTH).
/// - Contains a forward slash (`/`).
/// - Is exactly `.` or `..`.
///
/// The error message provides a descriptive reason for the failure.
///
/// # Panics
///
/// Panics if [`MAX_NAME_LENGTH`](libvctrl_handler::MAX_NAME_LENGTH) cannot
/// be converted to `usize`. This is a programmer error that indicates a
/// misconfigured constant on a platform where `usize` is too small to hold
/// the value. In practice this cannot happen on 32-bit or 64-bit systems.
///
/// # Examples
///
/// Validating a correct name:
///
/// ```
/// use libvctrl_core::validate::name::validate_name;
///
/// assert!(validate_name("feature_branch").is_ok());
/// assert!(validate_name("v1.0.0").is_ok());
/// ```
///
/// Rejecting an empty name:
///
/// ```
/// use libvctrl_core::validate::name::validate_name;
/// assert!(validate_name("").is_err());
/// ```
///
/// Rejecting a name with a path separator:
///
/// ```
/// use libvctrl_core::validate::name::validate_name;
/// assert!(validate_name("dir/file").is_err());
/// ```
///
/// Rejecting directory aliases:
///
/// ```
/// use libvctrl_core::validate::name::validate_name;
/// assert!(validate_name(".").is_err());
/// assert!(validate_name("..").is_err());
/// ```