fix(carrier): C-04 — document hidden vault capacity limit and add 80% mount warning

This commit is contained in:
2026-09-19 23:17:04 +02:00
parent c606fa8132
commit c21d63ad28
6 changed files with 201 additions and 6 deletions
+142
View File
@@ -1312,3 +1312,145 @@ async fn test_c03_manifest_dirty_decoupling_and_unmount_flush() {
drop(db);
let _ = std::fs::remove_file(&path);
}
#[tokio::test]
async fn test_c04_manifest_capacity_limit_and_warning() {
let path = temp_db_path("c04_capacity");
let carrier_size_bytes = 10 * 1024 * 1024; // 10 MB
let carrier_name = "carrier_c04.bin";
let pass_decoy = "DecoyPass2026!";
let pass_hidden = "HiddenPass2026!";
let kdf_params = KdfParams {
memory_cost: MIN_MEMORY_COST_KIB,
time_cost: MIN_TIME_COST,
parallelism: 1,
};
let salt_0 = generate_salt();
let kek_0 = derive_kek(pass_decoy, &salt_0, &kdf_params).unwrap();
let dek_0 = generate_dek();
let salt_1 = generate_salt();
let kek_1 = derive_kek(pass_hidden, &salt_1, &kdf_params).unwrap();
let dek_1 = generate_dek();
let carrier_node_id = 3i64;
let (wrapped_0, nonce_0, tag_0) = wrap_slot0_payload(&kek_0, &dek_0, carrier_node_id).unwrap();
let (wrapped_1, nonce_1, tag_1) =
wrap_slot1_payload(&kek_1, &dek_1, &dek_0, carrier_node_id).unwrap();
let db = Database::open(&path).expect("Open database");
db.init_schema_with_carrier(
&salt_0,
&kdf_params,
&wrapped_0,
&nonce_0,
&tag_0,
Some((
carrier_name,
carrier_size_bytes,
&salt_1,
&kdf_params,
&wrapped_1,
&nonce_1,
&tag_1,
&dek_0,
&dek_1,
)),
)
.expect("Init carrier schema");
db.checkpoint().unwrap();
let meta = db.read_meta().unwrap();
let auth_hidden = meta.authenticate(pass_hidden).expect("Auth hidden");
let cfs = sanctum::carrier::CarrierFs::load(
db.clone(),
carrier_node_id,
std::sync::Arc::new(auth_hidden.carrier_dek().unwrap().clone()),
std::sync::Arc::new(auth_hidden.dek().clone()),
auth_hidden.version(),
true,
)
.expect("CarrierFs load");
// 1. Initialer Zustand: Manifest minimal (< 5 KB, << 80%)
let (len, cap, pct) = cfs.manifest_usage();
assert_eq!(cap, sanctum::carrier::CARRIER_MANIFEST_CAPACITY);
assert!(len < 5_000);
assert!(pct < 1.0);
// 2. Fülle Manifest gezielt auf > 80% (> 838.809 Bytes)
// Erstelle Verzeichnisse mit langen Pfadnamen, bis die Größe über 840 KB liegt
for i in 0..1000 {
let dir_path = DavPath::new(&format!("/d_{:04}_{}", i, "a".repeat(1000))).unwrap();
cfs.create_dir(&dir_path).await.expect("create_dir");
let (current_len, _, _) = cfs.manifest_usage();
if current_len >= sanctum::carrier::CARRIER_MANIFEST_WARN_THRESHOLD {
break;
}
}
let (len80, _, pct80) = cfs.manifest_usage();
assert!(
len80 >= sanctum::carrier::CARRIER_MANIFEST_WARN_THRESHOLD,
"Manifest size must exceed 80% threshold, got: {}",
len80
);
assert!(
pct80 >= 80.0,
"Manifest pct must be >= 80.0%, got: {}",
pct80
);
// Speichern (sync_manifest) muss mit Warnung gelingen
cfs.sync_manifest()
.expect("sync_manifest at > 80% must succeed");
drop(cfs);
// Neu laden: muss erfolgreich laden und beim Laden die 80%-Warnung auslösen
let cfs_loaded = sanctum::carrier::CarrierFs::load(
db.clone(),
carrier_node_id,
std::sync::Arc::new(auth_hidden.carrier_dek().unwrap().clone()),
std::sync::Arc::new(auth_hidden.dek().clone()),
auth_hidden.version(),
true,
)
.expect("CarrierFs load at > 80% must succeed");
let (reloaded_len, _, reloaded_pct) = cfs_loaded.manifest_usage();
assert!(reloaded_pct >= 80.0);
assert_eq!(reloaded_len, len80);
// 3. Grenze überschreiten: weiter füllen bis > 1.048.512 Bytes
for i in 1000..1500 {
let dir_path = DavPath::new(&format!("/overflow_{:04}_{}", i, "x".repeat(1000))).unwrap();
cfs_loaded
.create_dir(&dir_path)
.await
.expect("create_dir overflow");
let (cur_len, _, _) = cfs_loaded.manifest_usage();
if cur_len > sanctum::carrier::CARRIER_MANIFEST_CAPACITY {
break;
}
}
// sync_manifest() MUSS jetzt mit Fehler abbrechen
let err = cfs_loaded.sync_manifest().unwrap_err();
let err_str = err.to_string();
assert!(
err_str.contains("Carrier-Manifest überschreitet die maximale Blockgröße"),
"Error message must specify carrier capacity limit: {}",
err_str
);
assert!(
err_str.contains("7.000 Dateien/Verzeichnisse"),
"Error message must recommend file limit: {}",
err_str
);
drop(cfs_loaded);
drop(db);
let _ = std::fs::remove_file(&path);
}