Skip to content

Commit 6cb7139

Browse files
wan9chicodex
andcommitted
fix(cache): invalidate non-utf8 getEnvs values
Co-authored-by: GPT-5 Codex <codex@openai.com>
1 parent 19a03b7 commit 6cb7139

2 files changed

Lines changed: 63 additions & 16 deletions

File tree

crates/vite_task/src/session/cache/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -252,7 +252,7 @@ pub fn split_path(path: &str) -> (Option<&str>, &str) {
252252
/// its own cache warm across branch switches, and a cache from a different
253253
/// version is simply ignored (it lives in a directory this build never looks
254254
/// at) rather than aborting the run. Bumping the version starts a fresh cache.
255-
const CACHE_SCHEMA_VERSION: u32 = 15;
255+
const CACHE_SCHEMA_VERSION: u32 = 16;
256256

257257
/// Name of the per-version subdirectory (e.g. `v14`) under the task-cache
258258
/// directory that holds the database and output archives for the current

crates/vite_task/src/session/execute/fingerprint.rs

Lines changed: 62 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,15 @@ impl PostRunFingerprint {
188188
}
189189

190190
for (pattern, stored_matches) in &self.tracked_env_globs {
191-
let current_matches = match_env_glob(pattern.as_str(), unfiltered_envs)?;
191+
let current_matches = match match_env_glob(pattern.as_str(), unfiltered_envs)? {
192+
EnvGlobValidation::Matches(matches) => matches,
193+
EnvGlobValidation::NonUtf8Value(mismatch) => {
194+
return Ok(Some(PostRunMismatch::TrackedEnvGlob {
195+
pattern: pattern.clone(),
196+
mismatch,
197+
}));
198+
}
199+
};
192200
if let Some(mismatch) = first_env_glob_mismatch(stored_matches, &current_matches) {
193201
return Ok(Some(PostRunMismatch::TrackedEnvGlob {
194202
pattern: pattern.clone(),
@@ -202,24 +210,35 @@ impl PostRunFingerprint {
202210
}
203211

204212
/// Build the current match-set for `pattern` by enumerating the given env
205-
/// snapshot and keeping UTF-8 names whose representation matches the glob.
213+
/// snapshot and keeping UTF-8 names whose representation matches the glob. If
214+
/// a matching env has a non-UTF-8 value, return a changed mismatch so the stale
215+
/// cache entry is not replayed.
206216
fn match_env_glob(
207217
pattern: &str,
208218
envs: &FxHashMap<Arc<OsStr>, Arc<OsStr>>,
209-
) -> anyhow::Result<BTreeMap<Str, EnvValueHash>> {
219+
) -> anyhow::Result<EnvGlobValidation> {
210220
let glob = vite_glob::env::EnvGlob::new(pattern)?;
211-
Ok(envs
212-
.iter()
213-
.filter_map(|(name, value)| {
214-
let name_str = name.to_str()?;
215-
let value_str = value.to_str()?;
216-
if glob.is_match(name_str) {
217-
Some((Str::from(name_str), EnvValueHash::new(value_str)))
218-
} else {
219-
None
220-
}
221-
})
222-
.collect())
221+
let mut matches = BTreeMap::new();
222+
for (name, value) in envs {
223+
let Some(name_str) = name.to_str() else {
224+
continue;
225+
};
226+
if !glob.is_match(name_str) {
227+
continue;
228+
}
229+
let Some(value_str) = value.to_str() else {
230+
return Ok(EnvGlobValidation::NonUtf8Value(EnvMismatch::Changed {
231+
name: Str::from(name_str),
232+
}));
233+
};
234+
matches.insert(Str::from(name_str), EnvValueHash::new(value_str));
235+
}
236+
Ok(EnvGlobValidation::Matches(matches))
237+
}
238+
239+
enum EnvGlobValidation {
240+
Matches(BTreeMap<Str, EnvValueHash>),
241+
NonUtf8Value(EnvMismatch),
223242
}
224243

225244
/// Find the first deterministic difference between stored and current env
@@ -487,4 +506,32 @@ mod tests {
487506

488507
assert!(err.to_string().contains("tracked env value for PROBE_ENV is not valid UTF-8"));
489508
}
509+
510+
#[test]
511+
fn validate_reports_current_non_utf8_tracked_env_glob_value_as_changed() {
512+
let mut tracked_env_globs = BTreeMap::new();
513+
tracked_env_globs.insert(Str::from("PROBE_*"), BTreeMap::new());
514+
let fingerprint = PostRunFingerprint { tracked_env_globs, ..PostRunFingerprint::default() };
515+
516+
let mut unfiltered_envs = FxHashMap::default();
517+
unfiltered_envs.insert(
518+
Arc::<OsStr>::from(OsStr::new("PROBE_BAD")),
519+
Arc::<OsStr>::from(non_utf8_os_string()),
520+
);
521+
522+
let workspace_root = vite_path::current_dir().expect("cwd");
523+
let mismatch =
524+
fingerprint.validate(&workspace_root, &unfiltered_envs).expect("validation succeeds");
525+
526+
match mismatch {
527+
Some(PostRunMismatch::TrackedEnvGlob {
528+
pattern,
529+
mismatch: EnvMismatch::Changed { name },
530+
}) => {
531+
assert_eq!(pattern.as_str(), "PROBE_*");
532+
assert_eq!(name.as_str(), "PROBE_BAD");
533+
}
534+
other => panic!("expected changed tracked env glob mismatch, got {other:?}"),
535+
}
536+
}
490537
}

0 commit comments

Comments
 (0)