Skip to content
Draft
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
17 changes: 16 additions & 1 deletion upki/src/revocation/fetch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,14 @@ pub async fn fetch(dry_run: bool, config: &Config) -> Result<ExitCode, Error> {

manifest.introduce()?;

let plan = Plan::construct(&manifest, &config.revocation.fetch_url, &cache_dir)?;
let old_manifest = Manifest::from_config(config).ok();

let plan = Plan::construct(
&old_manifest,
&manifest,
&config.revocation.fetch_url,
&cache_dir,
)?;

if dry_run {
println!(
Expand Down Expand Up @@ -110,10 +117,12 @@ pub(crate) struct Plan {
impl Plan {
/// Form a plan of how to synchronize with the remote server.
///
/// - `old_manifest` is an alleged current manifest, whose files are left alone.
/// - `manifest` describes the contents of the remote server.
/// - `remote_url` is the base URL.
/// - `local` is the path into which files are downloaded. The caller ensures this exists.
pub(crate) fn construct(
old_manifest: &Option<Manifest>,
manifest: &Manifest,
remote_url: &str,
local: &Path,
Expand Down Expand Up @@ -157,6 +166,12 @@ impl Plan {
steps.push(PlanStep::download(filter, remote_url, local));
}

if let Some(old_manifest) = &old_manifest {
for filter in &old_manifest.filters {
unwanted_files.remove(Path::new(&filter.filename));
}
}

steps.push(PlanStep::SaveManifest {
manifest: manifest.clone(),
local_dir: local.to_owned(),
Expand Down
2 changes: 1 addition & 1 deletion upki/src/revocation/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ impl Manifest {
/// This performs disk IO but does not perform network IO.
pub fn verify(&self, config: &Config) -> Result<ExitCode, Error> {
self.introduce()?;
let plan = Plan::construct(self, "https://.../", &config.revocation_cache_dir())?;
let plan = Plan::construct(&None, self, "https://.../", &config.revocation_cache_dir())?;
match plan.download_bytes() {
0 => Ok(ExitCode::SUCCESS),
bytes => Err(Error::Outdated(bytes)),
Expand Down
33 changes: 32 additions & 1 deletion upki/tests/integration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -260,7 +260,38 @@ fn full_fetch_and_incremental_update() {
GET /manifest.json -> 200 OK (547 bytes)
GET /filter4.delta -> 200 OK (3 bytes)
");
// filter2 is deleted, filter4 is new
// filter2 could be deleted, filter4 is new
assert_eq!(
list_dir(&temp.path().join("revocation")),
vec![
"filter1.filter",
"filter2.delta",
"filter3.delta",
"filter4.delta",
"manifest.json"
]
);

// a fetch of the same manifest clears away "filter2.delta" as it is now unused
let (server, _filters) = http_server("tests/data/evolution/");
write_config(&temp, server.url());
assert_cmd_snapshot!(
upki()
.arg("--config-file")
.arg(&config_file)
.arg("fetch"),
@r"
success: true
exit_code: 0
----- stdout -----

----- stderr -----
");
assert_snapshot!(
server.into_log(),
@"GET /manifest.json -> 200 OK (547 bytes)");

// filter2 is now deleted
assert_eq!(
list_dir(&temp.path().join("revocation")),
vec![
Expand Down