fix(build): make local/recipes/* sources unconditionally immutable
Internal Red Bear subprojects (tlc, redbear-*, redbear-greeter, etc.) live under local/recipes/* and have no upstream source — they are committed to our own gitea only. If lost, they cannot be recovered from any public source. The previous guard used is_local_overlay() && !redbear_allow_local_unfetch() which could be bypassed by setting REDBEAR_ALLOW_LOCAL_UNFETCH=1. This was triggered inadvertently (exact trigger unknown) and destroyed the source tree of local/recipes/tui/tlc/source/. This commit makes the protection UNCONDITIONAL: - is_local_overlay() already correctly identifies any path under local/recipes/ as internal. - The handle_clean unfetch path now refuses ALL local/recipes/* sources with a clear error message. No env var can override this. - The fetch() path's git-reset/git-clean-ffdx and source-wipe guards now also refuse local overlays unconditionally. - The dead redbear_allow_local_unfetch() function is removed. - Makefile distclean-nuclear target is documented as a no-op for local/. distclean still works for non-local recipes (upstream sources from sources/redbear-0.1.0/ or git mirrors can be safely re-fetched).
This commit is contained in:
+7
-12
@@ -39,7 +39,10 @@ use termion::{color, style};
|
||||
// A repo manager, to replace repo.sh
|
||||
|
||||
/// Check if a recipe directory is a local Red Bear overlay (symlink into local/).
|
||||
/// Local overlay recipes must never have their source/ deleted by unfetch/clean.
|
||||
/// Local overlay recipes are INTERNAL Red Bear subprojects (tlc, redbear-*, etc.).
|
||||
/// They have no upstream apart from our gitea — losing them is not recoverable
|
||||
/// from a public source. They must NEVER be deleted by any command, regardless
|
||||
/// of env vars or flags. The check is unconditional.
|
||||
fn is_local_overlay(recipe_dir: &Path) -> bool {
|
||||
if let Ok(resolved) = recipe_dir.canonicalize() {
|
||||
let resolved_str = resolved.to_string_lossy();
|
||||
@@ -48,14 +51,6 @@ fn is_local_overlay(recipe_dir: &Path) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
/// Check if the operator has explicitly allowed destructive operations on local overlays.
|
||||
fn redbear_allow_local_unfetch() -> bool {
|
||||
matches!(
|
||||
std::env::var("REDBEAR_ALLOW_LOCAL_UNFETCH").ok().as_deref(),
|
||||
Some("1" | "true" | "TRUE" | "yes" | "YES")
|
||||
)
|
||||
}
|
||||
|
||||
const REPO_HELP_STR: &str = r#"
|
||||
Usage: repo <command> [flags] <recipe1> <recipe2> ...
|
||||
|
||||
@@ -853,10 +848,10 @@ fn handle_clean(
|
||||
}
|
||||
}
|
||||
if dir.exists() && matches!(*command, CliCommand::Unfetch) {
|
||||
if is_local_overlay(&recipe.dir) && !redbear_allow_local_unfetch() {
|
||||
if is_local_overlay(&recipe.dir) {
|
||||
eprintln!(
|
||||
"[WARN] skipping unfetch for local overlay recipe {} \
|
||||
(source lives in local/; set REDBEAR_ALLOW_LOCAL_UNFETCH=1 to override)",
|
||||
"[WARN] refusing to unfetch local overlay recipe {} \
|
||||
(local/recipes/* sources are immutable; internal Red Bear subprojects have no upstream)",
|
||||
recipe.name.name()
|
||||
);
|
||||
} else {
|
||||
|
||||
+8
-4
@@ -294,6 +294,10 @@ fn redbear_ensure_offline_git_source(
|
||||
}
|
||||
|
||||
/// Check if a recipe directory is a local Red Bear overlay (symlink into local/).
|
||||
/// Local overlay recipes are INTERNAL Red Bear subprojects (tlc, redbear-*, etc.).
|
||||
/// They have no upstream apart from our gitea — losing them is not recoverable
|
||||
/// from a public source. They must NEVER be deleted by any command, regardless
|
||||
/// of env vars or flags. The check is unconditional.
|
||||
fn is_local_overlay(recipe_dir: &Path) -> bool {
|
||||
if let Ok(resolved) = recipe_dir.canonicalize() {
|
||||
let resolved_str = resolved.to_string_lossy();
|
||||
@@ -645,11 +649,11 @@ pub fn fetch(recipe: &CookRecipe, check_source: bool, logger: &PtyOut) -> Result
|
||||
}
|
||||
|
||||
if !patches.is_empty() || script.is_some() {
|
||||
if is_local_overlay(recipe_dir) && !redbear_allow_protected_fetch() {
|
||||
if is_local_overlay(recipe_dir) {
|
||||
log_to_pty!(
|
||||
logger,
|
||||
"[WARN] skipping git reset --hard for local overlay recipe at {} \
|
||||
(set REDBEAR_ALLOW_PROTECTED_FETCH=1 to override)",
|
||||
(local overlay sources are immutable)",
|
||||
recipe_dir.display()
|
||||
);
|
||||
} else {
|
||||
@@ -772,11 +776,11 @@ pub fn fetch(recipe: &CookRecipe, check_source: bool, logger: &PtyOut) -> Result
|
||||
let mut cached = true;
|
||||
if source_dir.is_dir() {
|
||||
if tar_updated || fetch_is_patches_newer(recipe_dir, patches, &source_dir)? {
|
||||
if is_local_overlay(recipe_dir) && !redbear_allow_protected_fetch() {
|
||||
if is_local_overlay(recipe_dir) {
|
||||
log_to_pty!(
|
||||
logger,
|
||||
"[WARN] refusing to wipe source for local overlay recipe at {} \
|
||||
(set REDBEAR_ALLOW_PROTECTED_FETCH=1 to override)",
|
||||
(local overlay sources are immutable)",
|
||||
recipe_dir.display()
|
||||
);
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user