Skip to content

Commit 99f5942

Browse files
committed
remove most usage of read_manifest_unsigned for safety
1 parent 23314e4 commit 99f5942

File tree

4 files changed

+86
-65
lines changed

4 files changed

+86
-65
lines changed

src/build/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ pub fn build(build_manifest_path: &Path, repo_path: &Path) -> Result<PackageMani
2828
let build_manifest: BuildManifest =
2929
serde_yaml::from_str(&fs::read_to_string(build_manifest_path)?)?;
3030

31-
let repo_manifest = repo::read_manifest_unsigned(repo_path)?;
31+
let repo_manifest = repo::read_manifest(repo_path)?;
3232

3333
let chunks = save_tree(
3434
&build_manifest_path.join(build_manifest.directory),

src/main.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ fn main() -> Result<()> {
130130
let repo_name = repo_dir.file_name();
131131
let repo_name_str = repo_name.to_str().unwrap();
132132

133-
let repo = repo::read_manifest_unsigned(&repo_dir.path())?;
133+
let repo = repo::read_manifest(&repo_dir.path())?;
134134

135135
table.add_row(vec![
136136
&repo_name_str,
@@ -161,7 +161,7 @@ fn main() -> Result<()> {
161161
repo_name,
162162
} => {
163163
let repo_path = &path.join(repo_name);
164-
let mut repo = repo::read_manifest_unsigned(repo_path)?;
164+
let mut repo = repo::read_manifest(repo_path)?;
165165

166166
if title.is_some() {
167167
repo.metadata.title = title;

src/repo/manifest_io.rs

Lines changed: 80 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,6 @@ use crate::{
77
repo::RepoManifest,
88
};
99

10-
/// Reads a manifest without verifying. This is best for AFTER it has been downloaded.
11-
///
12-
/// # Errors
13-
///
14-
/// - Filesystem errors (Permissions or doesn't exist)
15-
pub fn read_manifest_unsigned(repo_path: &Path) -> Result<RepoManifest> {
16-
let manifest_serialized = fs::read_to_string(repo_path.join("manifest.yml"))?;
17-
let manifest = serde_yaml::from_str(&manifest_serialized)?;
18-
19-
Ok(manifest)
20-
}
21-
2210
/// Reads a manifest and verifys it from the EXISTING key. This is best for GENERAL reading.
2311
///
2412
/// # Warning
@@ -42,6 +30,14 @@ pub fn read_manifest(repo_path: &Path) -> Result<RepoManifest> {
4230
Ok(manifest)
4331
}
4432

33+
fn read_manifest_unsigned(repo_path: &Path) -> Result<RepoManifest> {
34+
let manifest_serialized = fs::read_to_string(repo_path.join("manifest.yml"))?;
35+
36+
let manifest: RepoManifest = serde_yaml::from_str(&manifest_serialized)?;
37+
38+
Ok(manifest)
39+
}
40+
4541
/// Reads a manifest and verifys it. This is best for WHEN it has been downloaded.
4642
///
4743
/// # Errors
@@ -62,8 +58,7 @@ pub fn read_manifest_signed(repo_path: &Path, public_key_serialized: &str) -> Re
6258
Ok(manifest)
6359
}
6460

65-
/// Replaces the existing manifest with another one
66-
/// Verifies that it is correct
61+
/// Replaces the existing manifest with another one, and verifies that it is correct
6762
///
6863
/// # Errors
6964
///
@@ -98,11 +93,79 @@ pub fn update_manifest(
9893
Ok(())
9994
}
10095

101-
fn atomic_replace(repo_path: &Path, filename: &str, contents: &[u8]) -> Result<()> {
102-
let new_path = &repo_path.join(filename.to_owned() + ".new");
96+
fn atomic_replace(base_path: &Path, filename: &str, contents: &[u8]) -> Result<()> {
97+
let new_path = &base_path.join(filename.to_owned() + ".new");
10398

10499
fs::write(new_path, contents)?;
105-
fs::rename(new_path, repo_path.join(filename))?;
100+
fs::rename(new_path, base_path.join(filename))?;
106101

107102
Ok(())
108103
}
104+
105+
#[cfg(test)]
106+
mod tests {
107+
use temp_dir::TempDir;
108+
109+
use crate::{crypto::signing::sign, repo::create};
110+
111+
use super::*;
112+
113+
#[test]
114+
fn test_atomic_replace_basic() -> Result<()> {
115+
let temp_dir = TempDir::new()?;
116+
fs::write(temp_dir.path().join("file"), "previous_contents")?;
117+
atomic_replace(temp_dir.path(), "file", b"new_contents")?;
118+
119+
assert_eq!(
120+
fs::read_to_string(temp_dir.path().join("file"))?,
121+
"new_contents"
122+
);
123+
assert!(!temp_dir.path().join("file.new").exists());
124+
125+
Ok(())
126+
}
127+
128+
#[test]
129+
fn test_update_manifest_valid_and_invalid() -> Result<()> {
130+
let repo = TempDir::new()?;
131+
let repo_path = repo.path();
132+
create(repo_path)?;
133+
134+
let old_manifest = read_manifest(repo_path)?;
135+
136+
// Build a new manifest with small change
137+
let mut new_manifest = old_manifest;
138+
new_manifest.metadata.title = Some("NewName".into());
139+
140+
let serialized = serde_yaml::to_string(&new_manifest)?;
141+
142+
// Sign it with the right key
143+
let signature = sign(repo_path, &serialized)?;
144+
145+
// Update should succeed
146+
update_manifest(repo_path, &serialized, &signature.to_bytes())?;
147+
148+
let updated = read_manifest(repo_path)?;
149+
assert_eq!(updated.metadata.title, Some("NewName".into()));
150+
151+
// Now try with invalid signature
152+
let bad_signature = b"garbage_signature";
153+
assert!(update_manifest(repo_path, &serialized, bad_signature).is_err());
154+
155+
Ok(())
156+
}
157+
158+
#[test]
159+
fn test_read_signed_manifest() -> Result<()> {
160+
let repo = TempDir::new()?;
161+
let repo_path = repo.path();
162+
create(repo_path)?;
163+
164+
let manifest = read_manifest(repo_path)?;
165+
let manifest_signed = read_manifest_signed(repo_path, &manifest.public_key)?;
166+
167+
assert_eq!(manifest.edition, manifest_signed.edition);
168+
169+
Ok(())
170+
}
171+
}

src/repo/mod.rs

Lines changed: 3 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -170,15 +170,15 @@ mod tests {
170170
}
171171

172172
#[test]
173-
fn test_create_and_read_unsigned() {
173+
fn test_create_and_read() {
174174
let tmp = TempDir::new().unwrap();
175175
let repo_path = tmp.path();
176176

177177
// Create repo
178178
create(repo_path).unwrap();
179179

180180
// Read unsigned manifest
181-
let manifest = read_manifest_unsigned(repo_path).unwrap();
181+
let manifest = read_manifest(repo_path).unwrap();
182182
assert_eq!(manifest.edition, "2025");
183183
assert!(manifest.public_key.len() > 10);
184184
assert!(manifest.packages.is_empty());
@@ -188,18 +188,6 @@ mod tests {
188188
assert!(repo_path.join("manifest.yml.sig").exists());
189189
}
190190

191-
#[test]
192-
fn test_read_signed_manifest() {
193-
let tmp = TempDir::new().unwrap();
194-
let repo_path = tmp.path();
195-
create(repo_path).unwrap();
196-
197-
let manifest = read_manifest_unsigned(repo_path).unwrap();
198-
let manifest_signed = read_manifest_signed(repo_path, &manifest.public_key).unwrap();
199-
200-
assert_eq!(manifest.edition, manifest_signed.edition);
201-
}
202-
203191
#[test]
204192
fn test_tampered_manifest_fails() -> Result<()> {
205193
let tmp = TempDir::new()?;
@@ -211,8 +199,7 @@ mod tests {
211199
contents.push_str("\n# sneaky hacker change");
212200
fs::write(repo_path.join("manifest.yml"), contents)?;
213201

214-
let manifest = read_manifest_unsigned(repo_path)?;
215-
let result = read_manifest_signed(repo_path, &manifest.public_key);
202+
let result = read_manifest(repo_path);
216203

217204
assert!(
218205
result.is_err(),
@@ -221,33 +208,4 @@ mod tests {
221208

222209
Ok(())
223210
}
224-
225-
#[test]
226-
fn test_update_manifest_valid_and_invalid() {
227-
let tmp = TempDir::new().unwrap();
228-
let repo_path = tmp.path();
229-
create(repo_path).unwrap();
230-
231-
let old_manifest = read_manifest_unsigned(repo_path).unwrap();
232-
233-
// Build a new manifest with small change
234-
let mut new_manifest = old_manifest;
235-
new_manifest.metadata.title = Some("NewName".into());
236-
237-
let serialized = serde_yaml::to_string(&new_manifest).unwrap();
238-
239-
// Sign it with the right key
240-
let signature = sign(repo_path, &serialized).unwrap();
241-
242-
// Update should succeed
243-
update_manifest(repo_path, &serialized, &signature.to_bytes()).unwrap();
244-
245-
let updated = read_manifest_unsigned(repo_path).unwrap();
246-
assert_eq!(updated.metadata.title, Some("NewName".into()));
247-
248-
// Now try with invalid signature
249-
let bad_sig = b"garbage_signature";
250-
let result = update_manifest(repo_path, &serialized, bad_sig);
251-
assert!(result.is_err());
252-
}
253211
}

0 commit comments

Comments
 (0)