()
| 430 | |
| 431 | #[test] |
| 432 | fn tampered_same_signer_is_x() { |
| 433 | // A fresh attestation whose stored body was mutated after signing, with a |
| 434 | // DID that MATCHES the resolving key ⇒ DID-match passes, verify() returns |
| 435 | // a hash mismatch ⇒ '✗'. Distinguishes ✗ (real failure) from '–'. |
| 436 | let (repo, ids, _dir) = repo_with_intents(1); |
| 437 | let kp = KeyPair::generate(); |
| 438 | let mut node = attest_with(&repo, &ids[0], &kp); |
| 439 | write_tracked(&repo, &ids[0], &node); |
| 440 | // Confirm untampered verifies. |
| 441 | assert_eq!(row_for(&repo, &ids[0], Some(&kp)).verifies, Verifies::Yes); |
| 442 | |
| 443 | // Tamper a signed field (the title/text) AFTER signing but keep the same |
| 444 | // attributedTo DID and the same recorded sourceContentHash (so it stays |
| 445 | // Fresh). The content hash / signature no longer match the body. |
| 446 | node.title = "tampered title".to_string(); |
| 447 | write_tracked(&repo, &ids[0], &node); |
| 448 | |
| 449 | let row = row_for(&repo, &ids[0], Some(&kp)); |
| 450 | assert_eq!( |
| 451 | row.attested, |
| 452 | Attested::Fresh, |
| 453 | "still fresh (hash anchor kept)" |
| 454 | ); |
| 455 | assert_eq!(row.verifies, Verifies::No, "tampered same-signer ⇒ '✗'"); |
| 456 | assert_eq!(row.verifies.table(), "✗"); |
| 457 | } |
| 458 | |
| 459 | #[test] |
| 460 | fn other_signer_is_na_not_x() { |
nothing calls this directly
no test coverage detected