feat: account purge handler, tombstone cleanup, AP tombstone signing + 410

This commit is contained in:
2026-10-26 02:30:09 +01:00
parent 9a03de8956
commit 51a70b5260
32 changed files with 1708 additions and 27 deletions

View File

@@ -129,6 +129,7 @@ async fn handler_names_are_unique() {
// Names key the ledger: a rename re-runs events inside the retention
// window, so changing this list must be a deliberate edit.
let mut expected = vec![
"account_purge",
"image_cleanup",
"movie_discovery_indexer",
"movie_enrichment",
@@ -253,3 +254,49 @@ async fn a_deleted_users_token_is_rejected() {
assert_eq!(headers.get("location"), anon_headers.get("location"));
assert_eq!(headers.get("location").unwrap(), "/login");
}
/// A deleted account stays resolvable inside k-ap (to sign its `Delete`), but
/// every ActivityPub document for it answers 410, while the classic profile
/// page stays 404.
#[cfg(feature = "federation")]
#[tokio::test]
async fn actor_document_for_a_tombstone_is_gone() {
let (router, pool) = support::server().await;
let alice = support::register(&router, "alice", "alice@example.com").await;
let ap_get = |path: String| {
axum::http::Request::builder()
.uri(path)
.header("accept", "application/activity+json")
.body(axum::body::Body::empty())
.unwrap()
};
let paths = |id: &str| {
[
format!("/users/{id}"),
format!("/users/{id}/followers"),
format!("/users/{id}/following"),
format!("/users/{id}/outbox"),
format!("/users/{id}/featured"),
]
};
let (status, _, body) =
support::send(&router, ap_get(format!("/users/{}", alice.user_id))).await;
assert_eq!(status, 200, "live actor: {body}");
sqlx::query("UPDATE users SET deleted_at = '2026-01-01T00:00:00Z' WHERE id = ?")
.bind(&alice.user_id)
.execute(&pool)
.await
.unwrap();
for path in paths(&alice.user_id) {
let (status, _, body) = support::send(&router, ap_get(path.clone())).await;
assert_eq!(status, 410, "{path}: {body}");
}
let (status, _, _) = support::send(
&router,
support::get(&format!("/users/{}", alice.user_id), None),
)
.await;
assert_eq!(status, 404, "the classic profile page stays 404");
}