Reconcile obsolete staging assets before verifying a new Nightly generation

Aperta
#1,078 0 commenti 0 reazioni 0 assegnatari Vedi su GitHub

I maintainer di solito rispondono entro 1 giorno

Nessuno ha ancora preso questa issue.

Valutazione

Difficoltà
4/5
Tempo stimato
3-5 giorni
Idoneità per principianti
48/100
Tipo di issue
Bug
Chiarezza
Specificata chiaramente
Stato di attività
Attiva
Stack tecnologico
rust
Ambito
release

Direzione di ricerca

Start with the staging upload, verification and cleanup flow in tools/src/publication.rs near line 777, then read the Remote and generation helpers in tools/tests/publication.rs. Run the focused audit_stale_staging_generation test with the provided Cargo command to reproduce the extra-asset failure. Done means mocked regressions cover interrupted, repeated, stale and conflicting attempts plus cleanup failures, while final verification still checks all 29 assets and preserves the previous public Nightly.

Scritto dal modello di indicizzazione a partire dal testo della issue.

Descrizione

bug ci help wanted

Problem

A partial upload to the private nightly-staging draft can prevent a later Nightly generation from being published. The publisher uploads the new generation and verifies an exact remote asset set before it removes obsolete assets from the previous staging generation. Any leftover old filename therefore makes verification fail before cleanup can run.

Starting point: staging upload, verification and cleanup.

Reproduction

Audited canonical master e1f8effd195b6339c3979b1e091e63c25f1da983 on Linux amd64 with checkout-built Wave 0.0.1-alpha-dev, matching std, Rust 1.89.0, Cargo jobs=2 and LLVM 21.1.8. The master SHA was rechecked before registration. Publication was exercised through the existing stateful mock API, without creating or changing any real GitHub release.

Using the Remote and generation helpers in tools/tests/publication.rs, append this focused test to an isolated copy of that integration-test fixture:

#[test]
fn audit_stale_staging_generation() {
    let temporary = tempfile::tempdir().unwrap();
    let mut remote = Remote::new();

    let (directory, mut first) = generation(temporary.path(), 'a', 1);
    publication::promote(&mut remote, &directory, &mut first).unwrap();
    let previous_public = remote.releases[&1].clone();

    let (directory, mut partial) = generation(temporary.path(), 'b', 2);
    remote.fault = Some((
        "GET".into(),
        "releases/2/assets?per_page=100&page=1".into(),
        false,
    ));
    assert!(publication::promote(&mut remote, &directory, &mut partial).is_err());
    let asset = storage::files(&directory).unwrap().into_iter().next().unwrap();
    remote.upload(&asset, "nightly-staging").unwrap();

    let (directory, mut next) = generation(temporary.path(), 'c', 3);
    let result = publication::promote(&mut remote, &directory, &mut next);
    println!("result={result:?}");
    println!("staging assets={}", remote.assets[&2].len());
    println!("previous public retained={}", remote.releases[&1] == previous_public);
    println!("obsolete deletions={:?}", remote.calls.iter()
        .filter(|call| call.starts_with("DELETE releases/assets"))
        .collect::<Vec<_>>());
}

Run the focused test against the audited wave-tools crate. For a temporary local test added to that fixture, the equivalent Cargo command is:

cargo +1.89.0 test --locked --jobs 2 -p wave-tools --test publication audit_stale_staging_generation -- --nocapture

The audit ran the same fixture-based sequence from an isolated test harness linked against the current crate. It first creates a valid published generation, leaves one real staged asset from a partial later generation, and then promotes a newer generation.

Observed:

result=Err("remote Nightly asset set differs from the verified generation")
staging assets=30
previous public retained=true
obsolete deletions=[]

The simulated partial upload is intentional: one old-generation artifact remains alongside the 29 artifacts of the new generation. The final exact-set verifier rejects the extra artifact, so the subsequent deletion loop is unreachable. Repeating the new promotion does not remove the obsolete asset.

Scope

Reconcile obsolete assets owned by the staging draft before final exact-set verification, or use an equivalent retry-safe generation transition. Preserve digest/size/source/run/attempt identity checks and fail on conflicting current-generation assets. Never delete assets from the active public generation to repair staging.

Related: #831 owns the broader Nightly publication contract and final-cutover recovery. This issue isolates the independently reproducible stale-draft asset ordering defect.

Completion criteria

  • A partial older staging generation does not permanently block a valid newer generation or workflow attempt.
  • Final verification still requires exactly the expected 29 assets for all nine package targets with correct digests, sizes and identity.
  • Interrupted upload, repeated identical attempts, stale attempts, conflicting current filenames and cleanup failures have deterministic mocked regressions.
  • Failures preserve the previously usable public Nightly and all canonical CI/installer approval gates.
Lingua principale
Rust
Stelle
56
Fork
21
Merge medio
20h 49m
PR unite (30g)
45

Preparare l'ambiente

Come iniziare

  1. Leggi tutta la issue e poi la guida ai contributi del progetto.
  2. Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
  3. Fai un fork del repository e lavora su un branch.
  4. Apri una pull request che faccia riferimento al numero della issue.

Altre issue di wavefnd/Wave

Tutte le issue di wavefnd/Wave

Issue simili

Altre issue su Rust

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.