()
| 532 | |
| 533 | #[test] |
| 534 | fn tampered_same_signer_is_x() { |
| 535 | // A fresh attestation whose stored body was mutated after signing, with a |
| 536 | // DID that MATCHES the resolving key ⇒ DID-match passes, verify() returns |
| 537 | // a hash mismatch ⇒ '✗'. Distinguishes ✗ (real failure) from '–'. |
| 538 | let (repo, ids, _dir) = repo_with_intents(1); |
| 539 | let kp = KeyPair::generate(); |
| 540 | let mut node = attest_with(&repo, &ids[0], &kp); |
| 541 | write_tracked(&repo, &ids[0], &node); |
| 542 | // Confirm untampered verifies. |
| 543 | assert_eq!(row_for(&repo, &ids[0], Some(&kp)).verifies, Verifies::Yes); |
| 544 | |
| 545 | // Tamper a signed field (the title/text) AFTER signing but keep the same |
| 546 | // attributedTo DID and the same recorded sourceContentHash (so it stays |
| 547 | // Fresh). The content hash / signature no longer match the body. |
| 548 | node.title = "tampered title".to_string(); |
| 549 | write_tracked(&repo, &ids[0], &node); |
| 550 | |
| 551 | let row = row_for(&repo, &ids[0], Some(&kp)); |
| 552 | assert_eq!( |
| 553 | row.attested, |
| 554 | Attested::Fresh, |
| 555 | "still fresh (hash anchor kept)" |
| 556 | ); |
| 557 | assert_eq!(row.verifies, Verifies::No, "tampered same-signer ⇒ '✗'"); |
| 558 | assert_eq!(row.verifies.table(), "✗"); |
| 559 | } |
| 560 | |
| 561 | #[test] |
| 562 | fn other_signer_is_na_not_x() { |
nothing calls this directly
no test coverage detected