//! Manifest verification integration test. #![expect(clippy::expect_used)] use konservejo::{ core::pipeline::Pipeline, crypto::manifest::{ compute_merkle_root, get_inclusion_proof, verify_inclusion_proof, }, storage::Storage, }; mod common; use common::{ MockRepo, TestContext, create_test_archive, load_config, setup_mock_server, }; #[tokio::test] async fn test_manifest_root_computed_correctly() { let archive1 = create_test_archive("repo1"); let archive2 = create_test_archive("repo2"); let repos = vec![ MockRepo::new("test-org", "repo1", archive1), MockRepo::new("test-org", "repo2", archive2), ]; let (_server, mock_url) = setup_mock_server(repos).await; let ctx = TestContext::new(mock_url); ctx.write_config(&["test-org".to_string()], &[], 4, 1, 10); let config = load_config(&ctx).expect("Failed to load config"); let pipeline = Pipeline::new(config) .await .expect("Failed to create pipeline"); let run_id = pipeline.run().await.expect("Backup failed"); let db_url = format!("sqlite://{}", ctx.db_path().display()); let storage = Storage::new(&db_url) .await .expect("Failed to connect to DB"); let jobs = storage .list_jobs_by_run(&run_id) .await .expect("Failed to list jobs"); assert_eq!(jobs.len(), 2); let leaf_hashes: Vec<_> = jobs.iter().map(|j| j.artifact_hash.clone()).collect(); let computed_root = compute_merkle_root(&leaf_hashes).expect("Failed to compute root"); let stored_root = storage .get_manifest_root(&run_id) .await .expect("Failed to get manifest root") .expect("Should have stored root"); assert_eq!( stored_root.as_ref(), computed_root.as_ref(), "Stored root should match computed root" ); } #[tokio::test] async fn test_inclusion_proofs_valid() { let archive1 = create_test_archive("proof-repo1"); let archive2 = create_test_archive("proof-repo2"); let repos = vec![ MockRepo::new("test-org", "repo1", archive1), MockRepo::new("test-org", "repo2", archive2), ]; let (_server, mock_url) = setup_mock_server(repos).await; let ctx = TestContext::new(mock_url); ctx.write_config(&["test-org".to_string()], &[], 4, 1, 10); let config = load_config(&ctx).expect("Failed to load config"); let pipeline = Pipeline::new(config) .await .expect("Failed to create pipeline"); let run_id = pipeline.run().await.expect("Backup failed"); let db_url = format!("sqlite://{}", ctx.db_path().display()); let storage = Storage::new(&db_url) .await .expect("Failed to connect to DB"); let jobs = storage .list_jobs_by_run(&run_id) .await .expect("Failed to list jobs"); let leaf_hashes: Vec<_> = jobs.iter().map(|j| j.artifact_hash.clone()).collect(); let computed_root = compute_merkle_root(&leaf_hashes).expect("Failed to compute root"); for (i, job) in jobs.iter().enumerate() { let proof = get_inclusion_proof(&leaf_hashes, i).expect("Failed to generate proof"); let valid = verify_inclusion_proof(&computed_root, &job.artifact_hash, &proof); assert!(valid, "Proof for job {i} should be valid"); } }