Skip to content

Commit 3a2f3b1

Browse files
authored
Limit files that get uploaded to Cloudflare (#123)
* Limit files that get uploaded to CF and add tests * Remove outdated test * Fix another outdated tests
1 parent 6e6f75d commit 3a2f3b1

File tree

4 files changed

+300
-39
lines changed

4 files changed

+300
-39
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ thiserror = "2.0"
8787
[dev-dependencies]
8888
pretty_assertions.workspace = true
8989
static_assertions.workspace = true
90+
tempfile = "3.8"
9091

9192
[features]
9293
proxy = ["dep:pingora"]

src/adapters/cloudflare/mod.rs

Lines changed: 1 addition & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -752,7 +752,7 @@ mod tests {
752752
assert!(result.is_ok());
753753

754754
// Verify that all files are included
755-
assert_eq!(manifest.files().len(), 3);
755+
assert_eq!(manifest.files().len(), 2);
756756

757757
// Clean up
758758
let _ = std::fs::remove_dir_all(&temp_dir);
@@ -932,38 +932,4 @@ mod tests {
932932
// Clean up
933933
let _ = std::fs::remove_dir_all(&temp_dir);
934934
}
935-
936-
#[tokio::test]
937-
async fn test_cloudflare_manifest_excludes_manifest_files() {
938-
let temp_dir = std::env::temp_dir().join("test_manifest_excludes");
939-
let _ = std::fs::create_dir_all(&temp_dir);
940-
941-
// Create both regular files and manifest files
942-
let files = vec![
943-
("index.js", b"// worker code" as &[u8]),
944-
("utils.js", b"// utility functions" as &[u8]),
945-
("MultiTool.toml", b"# manifest file" as &[u8]),
946-
("wrangler.toml", b"# wrangler config" as &[u8]),
947-
];
948-
949-
for (filename, content) in files {
950-
let file_path = temp_dir.join(filename);
951-
let mut file = File::create(&file_path)
952-
.await
953-
.expect("Failed to create test file");
954-
file.write_all(content)
955-
.await
956-
.expect("Failed to write test content");
957-
}
958-
959-
let manifest = CloudflareFileManifest::new(&temp_dir)
960-
.await
961-
.expect("Failed to create manifest");
962-
963-
// Should exclude MultiTool manfiest file
964-
assert_eq!(manifest.files().len(), 3);
965-
966-
// Clean up
967-
let _ = std::fs::remove_dir_all(&temp_dir);
968-
}
969935
}

src/artifacts/cloudflare/manifest.rs

Lines changed: 297 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
use std::path::{Path, PathBuf};
22

33
use derive_getters::Getters;
4-
use ignore::WalkBuilder;
4+
use ignore::{
5+
Walk, WalkBuilder,
6+
types::{Types, TypesBuilder},
7+
};
58
use miette::{IntoDiagnostic as _, Result, miette};
69

710
use tracing::debug;
@@ -35,9 +38,7 @@ impl CloudflareFileManifest {
3538
let manifest_filenames = manifest_filenames();
3639

3740
// Build the file tree walker.
38-
let walker = WalkBuilder::new(directory.clone())
39-
.standard_filters(false)
40-
.build();
41+
let walker = walk_builder(directory.clone());
4142

4243
for entry in walker {
4344
debug!("Processing entry: {:?}", entry.clone().unwrap().path());
@@ -76,3 +77,295 @@ impl CloudflareFileManifest {
7677
Ok(Self { files })
7778
}
7879
}
80+
81+
/// Build a file loader that loads web development files.
82+
fn types_matches() -> Types {
83+
let mut builder = TypesBuilder::new();
84+
builder.add_defaults();
85+
builder
86+
.select("ts")
87+
.select("js")
88+
.select("css")
89+
.select("html");
90+
builder.build().unwrap()
91+
}
92+
93+
/// Builder the Walker that walks the file tree looking for files.
94+
/// It obeys the type filters we created.
95+
fn walk_builder(dir: PathBuf) -> Walk {
96+
let types = types_matches();
97+
WalkBuilder::new(dir)
98+
.standard_filters(true)
99+
.parents(false)
100+
.types(types)
101+
.build()
102+
}
103+
104+
#[cfg(test)]
105+
mod tests {
106+
use super::*;
107+
use pretty_assertions::assert_eq;
108+
use std::fs;
109+
use tempfile::TempDir;
110+
111+
/// Create a temporary directory with the given structure
112+
fn create_test_directory(files: &[(&str, &str)]) -> TempDir {
113+
let temp_dir = TempDir::new().expect("Failed to create temp directory");
114+
115+
for (path, content) in files {
116+
let file_path = temp_dir.path().join(path);
117+
118+
// Create parent directories if they don't exist
119+
if let Some(parent) = file_path.parent() {
120+
fs::create_dir_all(parent).expect("Failed to create parent directories");
121+
}
122+
123+
fs::write(&file_path, content).expect("Failed to write test file");
124+
}
125+
126+
temp_dir
127+
}
128+
129+
#[tokio::test]
130+
async fn test_new_with_valid_js_and_ts_files() {
131+
let temp_dir = create_test_directory(&[
132+
("index.js", "console.log('Hello World');"),
133+
("main.ts", "console.log('TypeScript Hello');"),
134+
("utils.js", "export function helper() {}"),
135+
]);
136+
137+
let manifest = CloudflareFileManifest::new(temp_dir.path())
138+
.await
139+
.expect("Failed to create manifest");
140+
141+
let files = manifest.files();
142+
assert_eq!(files.len(), 3);
143+
144+
// Check that all files are present
145+
let file_names: Vec<String> = files
146+
.iter()
147+
.filter_map(|p| p.file_name().and_then(|n| n.to_str()))
148+
.map(String::from)
149+
.collect();
150+
151+
assert!(file_names.contains(&"index.js".to_string()));
152+
assert!(file_names.contains(&"main.ts".to_string()));
153+
assert!(file_names.contains(&"utils.js".to_string()));
154+
}
155+
156+
#[tokio::test]
157+
async fn test_new_excludes_manifest_files() {
158+
let temp_dir = create_test_directory(&[
159+
("index.js", "console.log('Hello World');"),
160+
("MultiTool.toml", "name = 'test'"),
161+
("MultiTool.json", r#"{"name": "test"}"#),
162+
("main.ts", "console.log('TypeScript Hello');"),
163+
]);
164+
165+
let manifest = CloudflareFileManifest::new(temp_dir.path())
166+
.await
167+
.expect("Failed to create manifest");
168+
169+
let files = manifest.files();
170+
assert_eq!(files.len(), 2);
171+
172+
let file_names: Vec<String> = files
173+
.iter()
174+
.filter_map(|p| p.file_name().and_then(|n| n.to_str()))
175+
.map(String::from)
176+
.collect();
177+
178+
// Should include JS/TS files
179+
assert!(file_names.contains(&"index.js".to_string()));
180+
assert!(file_names.contains(&"main.ts".to_string()));
181+
182+
// Should NOT include manifest files
183+
assert!(!file_names.contains(&"MultiTool.toml".to_string()));
184+
assert!(!file_names.contains(&"MultiTool.json".to_string()));
185+
}
186+
187+
#[tokio::test]
188+
async fn test_new_includes_web_files() {
189+
let temp_dir = create_test_directory(&[
190+
("index.js", "console.log('Hello World');"),
191+
("style.css", "body { margin: 0; }"),
192+
("README.md", "# Test Project"),
193+
("config.yaml", "version: 1"),
194+
("data.json", r#"{"test": true}"#),
195+
("script.ts", "interface Test {}"),
196+
("page.html", "<html><body>Hello</body></html>"),
197+
("settings.toml", "[section]"),
198+
("data.xml", "<root><item>test</item></root>"),
199+
("notes.txt", "Some notes here"),
200+
]);
201+
202+
let manifest = CloudflareFileManifest::new(temp_dir.path())
203+
.await
204+
.expect("Failed to create manifest");
205+
206+
let files = manifest.files();
207+
assert_eq!(files.len(), 4);
208+
209+
let file_names: Vec<String> = files
210+
.iter()
211+
.filter_map(|p| p.file_name().and_then(|n| n.to_str()))
212+
.map(String::from)
213+
.collect();
214+
215+
// Should include web development file types
216+
assert!(file_names.contains(&"index.js".to_string()));
217+
assert!(file_names.contains(&"script.ts".to_string()));
218+
assert!(file_names.contains(&"style.css".to_string()));
219+
assert!(file_names.contains(&"page.html".to_string()));
220+
221+
// Should NOT include configuration, text, and JSON files
222+
assert!(!file_names.contains(&"data.json".to_string()));
223+
assert!(!file_names.contains(&"README.md".to_string()));
224+
assert!(!file_names.contains(&"config.yaml".to_string()));
225+
assert!(!file_names.contains(&"settings.toml".to_string()));
226+
assert!(!file_names.contains(&"data.xml".to_string()));
227+
assert!(!file_names.contains(&"notes.txt".to_string()));
228+
}
229+
230+
#[tokio::test]
231+
async fn test_new_with_nested_directories() {
232+
let temp_dir = create_test_directory(&[
233+
("src/index.js", "console.log('Main');"),
234+
("src/components/Button.ts", "export class Button {}"),
235+
("lib/utils.js", "export const helper = () => {};"),
236+
("tests/test.ts", "describe('test', () => {});"),
237+
("deep/nested/path/module.js", "export default {};"),
238+
]);
239+
240+
let manifest = CloudflareFileManifest::new(temp_dir.path())
241+
.await
242+
.expect("Failed to create manifest");
243+
244+
let files = manifest.files();
245+
assert_eq!(files.len(), 5);
246+
247+
// Check that nested files are included with correct paths
248+
let paths: Vec<String> = files
249+
.iter()
250+
.map(|p| {
251+
p.strip_prefix(temp_dir.path())
252+
.unwrap()
253+
.to_string_lossy()
254+
.to_string()
255+
})
256+
.collect();
257+
258+
assert!(paths.iter().any(|p| p.ends_with("src/index.js")));
259+
assert!(
260+
paths
261+
.iter()
262+
.any(|p| p.ends_with("src/components/Button.ts"))
263+
);
264+
assert!(paths.iter().any(|p| p.ends_with("lib/utils.js")));
265+
assert!(paths.iter().any(|p| p.ends_with("tests/test.ts")));
266+
assert!(
267+
paths
268+
.iter()
269+
.any(|p| p.ends_with("deep/nested/path/module.js"))
270+
);
271+
}
272+
273+
#[tokio::test]
274+
async fn test_new_ignores_directories() {
275+
let temp_dir = create_test_directory(&[("index.js", "console.log('Hello World');")]);
276+
277+
// Create some empty directories
278+
fs::create_dir_all(temp_dir.path().join("empty_dir")).unwrap();
279+
fs::create_dir_all(temp_dir.path().join("src/components")).unwrap();
280+
281+
let manifest = CloudflareFileManifest::new(temp_dir.path())
282+
.await
283+
.expect("Failed to create manifest");
284+
285+
let files = manifest.files();
286+
assert_eq!(files.len(), 1);
287+
288+
let file_names: Vec<String> = files
289+
.iter()
290+
.filter_map(|p| p.file_name().and_then(|n| n.to_str()))
291+
.map(String::from)
292+
.collect();
293+
294+
assert_eq!(file_names, vec!["index.js"]);
295+
}
296+
297+
#[tokio::test]
298+
async fn test_new_with_empty_directory_returns_error() {
299+
let temp_dir = TempDir::new().expect("Failed to create temp directory");
300+
301+
let result = CloudflareFileManifest::new(temp_dir.path()).await;
302+
303+
assert!(result.is_err());
304+
let error = result.unwrap_err();
305+
let error_msg = error.to_string();
306+
assert!(error_msg.contains("No files found in directory"));
307+
}
308+
309+
#[tokio::test]
310+
async fn test_new_with_only_unsupported_files_returns_error() {
311+
let temp_dir = create_test_directory(&[
312+
("image.png", "binary image data"),
313+
("video.mp4", "binary video data"),
314+
("archive.zip", "binary archive data"),
315+
("README.md", "# Documentation"),
316+
("config.yaml", "version: 1"),
317+
("settings.toml", "[section]"),
318+
("notes.txt", "Some notes"),
319+
]);
320+
321+
let result = CloudflareFileManifest::new(temp_dir.path()).await;
322+
323+
assert!(result.is_err());
324+
let error = result.unwrap_err();
325+
let error_msg = error.to_string();
326+
assert!(error_msg.contains("No files found in directory"));
327+
assert!(error_msg.contains("to upload"));
328+
}
329+
330+
#[tokio::test]
331+
async fn test_new_with_only_manifest_files_returns_error() {
332+
let temp_dir = create_test_directory(&[
333+
("MultiTool.toml", "[package]\nname = 'test'"),
334+
("MultiTool.json", r#"{"name": "test"}"#),
335+
]);
336+
337+
let result = CloudflareFileManifest::new(temp_dir.path()).await;
338+
339+
assert!(result.is_err());
340+
let error = result.unwrap_err();
341+
let error_msg = error.to_string();
342+
assert!(error_msg.contains("No files found in directory"));
343+
assert!(error_msg.contains("to upload"));
344+
}
345+
346+
#[tokio::test]
347+
async fn test_new_with_invalid_path_returns_error() {
348+
let invalid_path = "/this/path/does/not/exist";
349+
350+
let result = CloudflareFileManifest::new(invalid_path).await;
351+
352+
assert!(result.is_err());
353+
let error = result.unwrap_err();
354+
let error_msg = error.to_string();
355+
assert!(error_msg.contains("is not a valid directory"));
356+
}
357+
358+
#[tokio::test]
359+
async fn test_new_with_file_instead_of_directory_returns_error() {
360+
let temp_dir = TempDir::new().expect("Failed to create temp directory");
361+
let file_path = temp_dir.path().join("not_a_directory.txt");
362+
fs::write(&file_path, "some content").expect("Failed to write test file");
363+
364+
let result = CloudflareFileManifest::new(&file_path).await;
365+
366+
assert!(result.is_err());
367+
let error = result.unwrap_err();
368+
let error_msg = error.to_string();
369+
assert!(error_msg.contains("is not a valid directory"));
370+
}
371+
}

0 commit comments

Comments
 (0)