|
@@ -282,8 +282,25 @@ async fn run_cluster_repair(
|
|
|
Ok(repaired_tag)
|
|
Ok(repaired_tag)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+/// Validate docker image name to prevent Dockerfile injection.
|
|
|
|
|
+/// Returns true if the image name is safe to use in a FROM statement.
|
|
|
|
|
+fn is_valid_docker_image(image: &str) -> bool {
|
|
|
|
|
+ // Valid docker image pattern: [registry/]namespace/repo[:tag|@digest]
|
|
|
|
|
+ // Allow alphanumeric, dots, dashes, underscores, slashes, colons, and @
|
|
|
|
|
+ // No newlines, no shell metacharacters
|
|
|
|
|
+ image
|
|
|
|
|
+ .chars()
|
|
|
|
|
+ .all(|c| c.is_alphanumeric() || ".-_/:@".contains(c))
|
|
|
|
|
+ && !image.contains('\\')
|
|
|
|
|
+ && !image.contains('\n')
|
|
|
|
|
+ && !image.contains('\r')
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
/// Generate a Dockerfile to repair a container.
|
|
/// Generate a Dockerfile to repair a container.
|
|
|
fn generate_repair_dockerfile(base_image: &str, recipe: &Recipe) -> String {
|
|
fn generate_repair_dockerfile(base_image: &str, recipe: &Recipe) -> String {
|
|
|
|
|
+ if !is_valid_docker_image(base_image) {
|
|
|
|
|
+ panic!("Invalid docker image name: {}", base_image);
|
|
|
|
|
+ }
|
|
|
let mut lines = vec![format!("FROM {}", base_image)];
|
|
let mut lines = vec![format!("FROM {}", base_image)];
|
|
|
|
|
|
|
|
if recipe.distributed_backend == Some(crate::config::DistributedBackend::Ray) {
|
|
if recipe.distributed_backend == Some(crate::config::DistributedBackend::Ray) {
|