This repository has no description
1use std::path::Path;
2use std::sync::atomic::AtomicBool;
3
4use knot_git::{ArchiveFormat, ArchiveLimit};
5use knot_types::Oid;
6
7mod common;
8use common::{commit_file, contains, git_ok as git, seeded};
9
10fn archive_without_isolation(bare_path: &Path, head: Oid) -> Vec<u8> {
11 let permissive = gix::open_opts(bare_path, gix::open::Options::default()).unwrap();
12 let tree = permissive
13 .find_object(head.object_id())
14 .unwrap()
15 .peel_to_tree()
16 .unwrap();
17 let (stream, _index) = permissive.worktree_stream(tree.id).unwrap();
18 let mut out = std::io::Cursor::new(Vec::new());
19 permissive
20 .worktree_archive(
21 stream,
22 &mut out,
23 gix::progress::Discard,
24 &AtomicBool::new(false),
25 gix_archive::Options {
26 format: gix_archive::Format::Tar,
27 tree_prefix: None,
28 modification_time: 0,
29 },
30 )
31 .unwrap();
32 out.into_inner()
33}
34
35#[test]
36fn a_filter_driver_pulled_in_by_an_include_never_runs_for_a_served_archive() {
37 let (_scan, work_dir, layout, did) = seeded();
38 let work = work_dir.path();
39 let bare_path = layout.repo_path(&did).unwrap();
40 std::fs::write(work.join(".gitattributes"), "payload.txt filter=knotpwn\n").unwrap();
41 commit_file(work, "payload.txt", "kelp\n", "seed");
42 git(work, &["push", "-q", bare_path.to_str().unwrap(), "main"]);
43 let head = Oid::from_hex(&git(work, &["rev-parse", "HEAD"])).unwrap();
44
45 let ambient = tempfile::tempdir().unwrap();
46 let driver = ambient.path().join("driver.cfg");
47 std::fs::write(
48 &driver,
49 "[filter \"knotpwn\"]\n\tsmudge = sed s/kelp/pwned/\n\trequired = true\n",
50 )
51 .unwrap();
52 let config_path = bare_path.join("config");
53 let local = std::fs::read_to_string(&config_path).unwrap();
54 std::fs::write(
55 &config_path,
56 format!("{local}[include]\n\tpath = {}\n", driver.display()),
57 )
58 .unwrap();
59
60 let via_git = knot_fixtures::command(&bare_path)
61 .args(["archive", "--format=tar", "main"])
62 .output()
63 .unwrap();
64 assert!(
65 via_git.status.success(),
66 "git archive failed:\n{}",
67 String::from_utf8_lossy(&via_git.stderr)
68 );
69 assert!(
70 contains(&via_git.stdout, b"pwned"),
71 "git archived with the include in place and its output has no pwned in it, so the driver \
72 never ran"
73 );
74 assert!(
75 contains(&archive_without_isolation(&bare_path, head), b"pwned"),
76 "gix archived the same repo under default permissions and its output has no pwned in it, \
77 so worktree_stream no longer applies filters"
78 );
79
80 let bare = layout.open(&did).unwrap();
81 let tree = bare.peel_to_tree(head).unwrap();
82 let mut out = std::io::Cursor::new(Vec::new());
83 bare.write_archive(
84 tree,
85 ArchiveFormat::Tar,
86 None,
87 ArchiveLimit::new(u64::MAX),
88 &mut out,
89 )
90 .unwrap();
91 let served = out.into_inner();
92
93 assert!(
94 std::fs::read_to_string(&config_path)
95 .unwrap()
96 .contains("[include]"),
97 "opening the repo rewrote its config and removed the include, so gix never read the \
98 driver definition for the archive below"
99 );
100 assert!(
101 contains(&served, b"kelp"),
102 "the served archive contains the blob as it was pushed"
103 );
104 assert!(
105 !contains(&served, b"pwned"),
106 "the knot ran a filter driver defined by config outside the repository"
107 );
108}
109
110#[test]
111fn a_pushed_replace_ref_never_substitutes_an_object_the_knot_reads() {
112 let (_scan, work_dir, layout, did) = seeded();
113 let work = work_dir.path();
114 let bare_path = layout.repo_path(&did).unwrap();
115
116 commit_file(work, "payload.txt", "kelp\n", "seed");
117 git(work, &["push", "-q", bare_path.to_str().unwrap(), "main"]);
118 let original = Oid::from_hex(&git(work, &["rev-parse", "HEAD:payload.txt"])).unwrap();
119 commit_file(work, "payload.txt", "pwned\n", "second");
120 git(work, &["push", "-q", bare_path.to_str().unwrap(), "main"]);
121 let substitute = Oid::from_hex(&git(work, &["rev-parse", "HEAD:payload.txt"])).unwrap();
122
123 git(
124 &bare_path,
125 &[
126 "update-ref",
127 &format!("refs/replace/{}", original.to_hex()),
128 &substitute.to_hex(),
129 ],
130 );
131
132 assert_eq!(
133 git(&bare_path, &["cat-file", "blob", &original.to_hex()]),
134 "pwned",
135 "git read the replaced object as itself, so this fixture never armed the substitution"
136 );
137 assert_eq!(
138 layout.open(&did).unwrap().read_blob(original).unwrap(),
139 b"kelp\n",
140 "a pushed replace ref rewrote what the knot serves for an object"
141 );
142}