Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 33 additions & 1 deletion crates/gitlawb-node/src/api/events.rs
Original file line number Diff line number Diff line change
Expand Up @@ -137,9 +137,30 @@ pub async fn list_ref_updates(
let caller = auth.as_ref().map(|e| e.0 .0.as_str());
let updates = collect_visible_ref_updates(&state.db, None, limit, caller).await?;

// Prefer the stored wire owner_did (full DID, may differ from local
// record's trailing-segment match). Fall back to the local record's
// owner_did only for backward-compat rows (stored as None) that name a
// repo this node hosts, so legacy rows still display an owner.
let deduped = state.db.list_all_repos_deduped().await?;
let resolve_local = |slug: &str| -> Option<&str> {
for record in &deduped {
if crate::visibility::ref_update_row_names_repo(record, slug) {
return Some(&record.owner_did);
}
}
None
};

let events: Vec<serde_json::Value> = updates
.iter()
.map(|u| {
let owner_did = match &u.owner_did {
Some(wire) => serde_json::json!(wire),
None => match resolve_local(&u.repo) {
Some(local) => serde_json::json!(local),
None => serde_json::Value::Null,
},
};
serde_json::json!({
"id": u.id,
"node_did": u.node_did,
Expand All @@ -152,6 +173,7 @@ pub async fn list_ref_updates(
"cert_id": u.cert_id,
"received_at": u.received_at,
"from_peer": u.from_peer,
"owner_did": owner_did,
})
})
.collect();
Expand Down Expand Up @@ -223,6 +245,7 @@ pub async fn list_repo_events(
"pusher_did": c.pusher_did,
"node_did": c.node_did,
"timestamp": c.issued_at,
"owner_did": record.owner_did,
"source": "local",
})
})
Expand Down Expand Up @@ -256,6 +279,7 @@ pub async fn list_repo_events(
"cert_id": u.cert_id,
"received_at": u.received_at,
"from_peer": u.from_peer,
"owner_did": serde_json::json!(record.owner_did),
"source": "gossipsub",
})
})
Expand Down Expand Up @@ -322,6 +346,7 @@ mod ref_updates_feed_tests {
new_sha: "a".repeat(40),
timestamp: Utc::now().to_rfc3339(),
cert_id: None,
owner_did: None,
received_at: Utc::now().to_rfc3339(),
from_peer: "peer1".into(),
}
Expand Down Expand Up @@ -1103,7 +1128,14 @@ mod ref_updates_feed_tests {
.await
.unwrap();
assert_eq!(resp.status(), StatusCode::OK);
assert_eq!(count(&body_json(resp).await), 2);
let body = body_json(resp).await;
assert_eq!(count(&body), 2);
for event in body["events"].as_array().unwrap() {
assert_eq!(
event["owner_did"], OWNER,
"each event must carry the local owner_did"
);
}
}

// Anon reads a quarantined mirror → 404 (withheld without disclosing existence
Expand Down
5 changes: 5 additions & 0 deletions crates/gitlawb-node/src/api/peers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,10 @@ pub struct NotifyRequest {
pub timestamp: Option<String>,
#[serde(default)]
pub cert_id: Option<String>,
/// Full owner DID — added in #144 for DID-aware feed gating.
/// Optional for backward compat with older senders.
#[serde(default)]
pub owner_did: Option<String>,
}

pub async fn notify_sync(
Expand Down Expand Up @@ -391,6 +395,7 @@ pub async fn notify_sync(
node_did: req.node_did.clone(),
pusher_did: req.pusher_did.clone().unwrap_or_default(),
repo: req.repo.clone(),
owner_did: req.owner_did.clone(),
ref_name: req.ref_name.clone(),
old_sha: req.old_sha.clone().unwrap_or_default(),
new_sha: req.new_sha.clone(),
Expand Down
18 changes: 18 additions & 0 deletions crates/gitlawb-node/src/api/repos.rs
Original file line number Diff line number Diff line change
Expand Up @@ -739,6 +739,7 @@ async fn notify_peer_of_ref(
new_sha: &str,
node_did: &str,
pusher_did: &str,
owner_did: &str,
) {
let body = serde_json::json!({
"repo": repo_slug,
Expand All @@ -748,6 +749,7 @@ async fn notify_peer_of_ref(
"pusher_did": pusher_did,
"old_sha": old_sha,
"timestamp": chrono::Utc::now().to_rfc3339(),
"owner_did": owner_did,
});
let body_bytes = match serde_json::to_vec(&body) {
Ok(bytes) => bytes,
Expand Down Expand Up @@ -795,6 +797,7 @@ async fn notify_peer_of_refs(
ref_updates: &[(String, String, String)],
node_did: &str,
pusher_did: &str,
owner_did: &str,
) {
for (ref_name, old_sha, new_sha) in ref_updates {
notify_peer_of_ref(
Expand All @@ -808,6 +811,7 @@ async fn notify_peer_of_refs(
new_sha,
node_did,
pusher_did,
owner_did,
)
.await;
}
Expand Down Expand Up @@ -1220,6 +1224,7 @@ pub async fn git_receive_pack(
node_did: node_did_str.clone(),
pusher_did: pusher_did_clone.clone(),
repo: repo_slug.clone(),
owner_did: Some(record.owner_did.clone()),
ref_name: ref_name.clone(),
old_sha: old_sha.clone(),
new_sha: new_sha.clone(),
Expand Down Expand Up @@ -1251,6 +1256,7 @@ pub async fn git_receive_pack(
pusher_did: pusher_did_clone.clone(),
node_did: node_did_str.clone(),
timestamp: now_ts.clone(),
owner_did: record.owner_did.clone(),
});
}
}
Expand Down Expand Up @@ -1321,6 +1327,7 @@ pub async fn git_receive_pack(
&ref_updates_clone,
&node_did_str,
&pusher_did_clone,
&record.owner_did,
)
.await;
}
Expand Down Expand Up @@ -2318,6 +2325,9 @@ mod tests {
mockito::Matcher::PartialJsonString(format!(r#"{{"ref_name":"{ref_a}"}}"#)),
mockito::Matcher::PartialJsonString(format!(r#"{{"old_sha":"{old_a}"}}"#)),
mockito::Matcher::PartialJsonString(format!(r#"{{"new_sha":"{new_a}"}}"#)),
mockito::Matcher::PartialJsonString(
r#"{"owner_did":"did:key:zOwner"}"#.to_string(),
),
]))
.with_status(200)
.expect(1)
Expand All @@ -2329,6 +2339,9 @@ mod tests {
mockito::Matcher::PartialJsonString(format!(r#"{{"ref_name":"{ref_b}"}}"#)),
mockito::Matcher::PartialJsonString(format!(r#"{{"old_sha":"{old_b}"}}"#)),
mockito::Matcher::PartialJsonString(format!(r#"{{"new_sha":"{new_b}"}}"#)),
mockito::Matcher::PartialJsonString(
r#"{"owner_did":"did:key:zOwner"}"#.to_string(),
),
]))
.with_status(200)
.expect(1)
Expand All @@ -2350,6 +2363,7 @@ mod tests {
&ref_updates,
"did:key:zNode",
"did:key:zPusher",
"did:key:zOwner",
)
.await;

Expand All @@ -2372,6 +2386,9 @@ mod tests {
.match_body(mockito::Matcher::AllOf(vec![
mockito::Matcher::PartialJsonString(format!(r#"{{"old_sha":"{zero}"}}"#)),
mockito::Matcher::PartialJsonString(format!(r#"{{"new_sha":"{new_sha}"}}"#)),
mockito::Matcher::PartialJsonString(
r#"{"owner_did":"did:key:zOwner"}"#.to_string(),
),
]))
.with_status(200)
.expect(1)
Expand All @@ -2394,6 +2411,7 @@ mod tests {
&ref_updates,
"did:key:zNode",
"did:key:zPusher",
"did:key:zOwner",
)
.await;

Expand Down
Loading
Loading