fix(ownership): bound snapshot download by manifest size; clean refused builds

Addresses review on #31:
- the snapshot download limit is the manifest's size_bytes (+1, since
  ureq fails once a body reaches its limit), capped at 1 GiB; a body
  larger than advertised fails during download. New CLI test; the
  >10 MiB test also caught the off-by-one.
- a refused (oversized) standalone build removes its sqlite and
  manifest from --output-dir.
- docs: downloads are buffered, not streamed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017a5Cv5Z1NzdYKgKnTiAF4E
This commit is contained in:
hermes 2026-09-25 22:31:40 +00:00
commit fea1a0e906
4 changed files with 71 additions and 7 deletions

View file

@ -1917,6 +1917,44 @@ fn ownership_sync_downloads_snapshot_larger_than_ten_mib_over_http() {
.stdout(predicate::str::contains("Installed ownership snapshot"));
}
#[test]
fn ownership_sync_rejects_body_larger_than_manifest_size() {
let publisher_root = test_env_dir("ownership-sync-oversized-body");
let (source_db, manifest_path) = prepare_snapshot_fixture(&publisher_root);
write_snapshot_manifest(&manifest_path, &source_db, None);
let mut body = fs::read(&source_db).expect("read snapshot");
body.extend_from_slice(&[0u8; 4096]);
let snapshot_url = spawn_single_response_server("application/octet-stream", body);
let mut manifest: Value =
serde_json::from_str(&fs::read_to_string(&manifest_path).expect("read manifest"))
.expect("parse manifest");
manifest["snapshot"]["download_url"] = Value::String(format!("{snapshot_url}/snapshot.sqlite"));
fs::write(&manifest_path, manifest.to_string()).expect("write http manifest");
let sync_root = test_env_dir("ownership-sync-oversized-body-consumer");
bin_with_root(&sync_root)
.args([
"config",
"set",
"ownership.db_path",
sync_root.join("ownership.db").to_str().unwrap(),
])
.assert()
.success();
bin_with_root(&sync_root)
.args([
"ownership",
"sync",
"--manifest",
manifest_path.to_str().unwrap(),
])
.assert()
.failure()
.stderr(predicate::str::contains(
"larger than the manifest's size_bytes",
));
}
#[test]
fn ownership_sync_installs_snapshot_and_preserves_query_behavior() {
let publisher_root = test_env_dir("ownership-sync-publisher");