List all provenance graph hashes the remote holds. This mirrors the `.change` sync model: the server advertises a flat inventory of content-addressed objects, the client computes the delta by presence (`has_provenance_graph`), and pulls missing objects by hash via [`download_provenance`](Self::download_provenance). Deliberately NOT a per-change relationship query ("which provenance explains chan
(&self)
| 449 | /// |
| 450 | /// Base32-encoded provenance graph hashes, one per line, in server order. |
| 451 | pub async fn get_provenance_list(&self) -> RemoteResult<Vec<String>> { |
| 452 | let url = format!("{}?provenance-list", self.base_url); |
| 453 | debug!("GET provenance-list: {}", url); |
| 454 | |
| 455 | let response = self |
| 456 | .client |
| 457 | .get(&url) |
| 458 | .send() |
| 459 | .await |
| 460 | .map_err(|e| RemoteError::connection_failed(&url, e))?; |
| 461 | |
| 462 | crate::check_min_version_header(response.headers()); |
| 463 | let status = response.status(); |
| 464 | |
| 465 | match status { |
| 466 | StatusCode::OK => { |
| 467 | let text = response |
| 468 | .text() |
| 469 | .await |
| 470 | .map_err(|e| RemoteError::connection_failed(&url, e))?; |
| 471 | Ok(text |
| 472 | .lines() |
| 473 | .map(str::trim) |
| 474 | .filter(|line| !line.is_empty()) |
| 475 | .map(|line| line.to_string()) |
| 476 | .collect()) |
| 477 | } |
| 478 | StatusCode::NOT_FOUND => Ok(Vec::new()), |
| 479 | StatusCode::UNAUTHORIZED | StatusCode::FORBIDDEN => { |
| 480 | let msg = response.text().await.unwrap_or_default(); |
| 481 | Err(RemoteError::auth_failed(&url, msg)) |
| 482 | } |
| 483 | _ => { |
| 484 | let msg = response.text().await.unwrap_or_default(); |
| 485 | Err(RemoteError::http(status.as_u16(), msg)) |
| 486 | } |
| 487 | } |
| 488 | } |
| 489 | |
| 490 | /// Download a provenance graph from the remote server. |
| 491 | /// |