|
| 1 | +use super::*; |
| 2 | +use crate::jupiter::{ |
| 3 | + migration::test_upgrade_reader_retention, |
| 4 | + storage::qualified_metadata_family::{ |
| 5 | + RootedLookupStatus, RootedQualifiedMetadataRepository, |
| 6 | + provision_or_verify_rooted_qualified_family, reader_previous_fixture::restore_previous, |
| 7 | + }, |
| 8 | +}; |
| 9 | + |
| 10 | +async fn permanent_rows(fixture: &Fixture) -> Value { |
| 11 | + let txn = transaction(fixture).await; |
| 12 | + let rows=txn.query_one_raw(Statement::from_string(DbBackend::Postgres, |
| 13 | + "SELECT jsonb_build_object( |
| 14 | + 'sessions',(SELECT jsonb_agg(to_jsonb(x) ORDER BY snapshot_id,session_incarnation) FROM mst2_qualified_session_incarnation x), |
| 15 | + 'leases',(SELECT jsonb_agg(to_jsonb(x) ORDER BY lease_id) FROM mst2_qualified_lease_binding x), |
| 16 | + 'sources',(SELECT jsonb_agg(to_jsonb(x) ORDER BY attestation_id) FROM mst2_metadata_source_root_attestation x), |
| 17 | + 'certificates',(SELECT jsonb_agg(to_jsonb(x) ORDER BY page_id,generation) FROM mst2_metadata_page_certificate x)) AS rows")) |
| 18 | + .await.unwrap().unwrap().try_get("","rows").unwrap(); |
| 19 | + txn.commit().await.unwrap(); |
| 20 | + rows |
| 21 | +} |
| 22 | + |
| 23 | +#[tokio::test] |
| 24 | +async fn current_reader_retention_migration_verifies_fresh_family_without_rewriting_history() { |
| 25 | + let fixture = Fixture::new_with_pg_config(true).await; |
| 26 | + let before = permanent_rows(&fixture).await; |
| 27 | + let high_water = q_count( |
| 28 | + &fixture, |
| 29 | + "SELECT high_water FROM {q}.mst2_metadata_reader_issuance", |
| 30 | + ) |
| 31 | + .await; |
| 32 | + let mono = fixture.state.storage.mono_storage(); |
| 33 | + let core = mono.get_connection(); |
| 34 | + test_upgrade_reader_retention(core).await.unwrap(); |
| 35 | + assert_eq!(permanent_rows(&fixture).await, before); |
| 36 | + assert_eq!( |
| 37 | + q_count( |
| 38 | + &fixture, |
| 39 | + "SELECT high_water FROM {q}.mst2_metadata_reader_issuance" |
| 40 | + ) |
| 41 | + .await, |
| 42 | + high_water |
| 43 | + ); |
| 44 | + provision_or_verify_rooted_qualified_family(core) |
| 45 | + .await |
| 46 | + .unwrap(); |
| 47 | + fixture.counts.assert(0, 0); |
| 48 | +} |
| 49 | + |
| 50 | +#[tokio::test] |
| 51 | +async fn captured_previous_q_upgrade_preserves_old_sid_source_proofs_and_active_legacy_reader() { |
| 52 | + let fixture = Fixture::new_with_pg_config(true).await; |
| 53 | + let pinned = fixture |
| 54 | + .state |
| 55 | + .storage |
| 56 | + .snapshot_context(&fixture.snapshot, &fixture.lease) |
| 57 | + .await |
| 58 | + .unwrap(); |
| 59 | + let before = permanent_rows(&fixture).await; |
| 60 | + let txn = transaction(&fixture).await; |
| 61 | + let active = admission(&txn, &fixture).await; |
| 62 | + txn.commit().await.unwrap(); |
| 63 | + let schema = q_schema(&fixture).await; |
| 64 | + let mono = fixture.state.storage.mono_storage(); |
| 65 | + let core = mono.get_connection(); |
| 66 | + restore_previous(core, &schema, true).await; |
| 67 | + assert_eq!(permanent_rows(&fixture).await, before); |
| 68 | + test_upgrade_reader_retention(core).await.unwrap(); |
| 69 | + assert_eq!(permanent_rows(&fixture).await, before); |
| 70 | + assert_eq!(q_count(&fixture,"SELECT count(*) FROM {q}.mst2_metadata_reader_operation WHERE reader_issuance=0 AND state='ACTIVE'").await,1); |
| 71 | + assert_eq!(q_count(&fixture,"SELECT count(*) FROM {q}.mst2_metadata_root_anchor WHERE reader_issuance=0 AND anchor_kind IN ('REQUEST','READER')").await,2); |
| 72 | + let restarted = |
| 73 | + RootedQualifiedMetadataRepository::open(core, &fixture.state.storage.config().database) |
| 74 | + .await |
| 75 | + .unwrap(); |
| 76 | + let fixed = restarted |
| 77 | + .context(&fixture.snapshot, &fixture.lease, &pinned.built.instance_id) |
| 78 | + .await |
| 79 | + .unwrap(); |
| 80 | + assert_eq!(fixed.built.descriptor, pinned.built.descriptor); |
| 81 | + assert_eq!(fixed.commit_oid, pinned.commit_oid); |
| 82 | + let lookup = restarted |
| 83 | + .lookup_metadata(&fixed, &["/file".to_owned()]) |
| 84 | + .await |
| 85 | + .unwrap(); |
| 86 | + assert!(matches!( |
| 87 | + lookup.results.as_slice(), |
| 88 | + [RootedLookupStatus::File { .. }] |
| 89 | + )); |
| 90 | + assert_eq!(permanent_rows(&fixture).await, before); |
| 91 | + assert_eq!(q_count(&fixture,"SELECT count(*) FROM {q}.mst2_metadata_reader_operation WHERE reader_issuance=0 AND state='ACTIVE'").await,1); |
| 92 | + let txn = transaction(&fixture).await; |
| 93 | + finish(&txn, &(active.0.clone(), 0)).await; |
| 94 | + txn.commit().await.unwrap(); |
| 95 | + let txn = transaction(&fixture).await; |
| 96 | + assert!(prune(&txn, 64).await >= 1); |
| 97 | + txn.commit().await.unwrap(); |
| 98 | + assert_eq!( |
| 99 | + q_count( |
| 100 | + &fixture, |
| 101 | + "SELECT count(*) FROM {q}.mst2_metadata_reader_operation WHERE reader_issuance=0" |
| 102 | + ) |
| 103 | + .await, |
| 104 | + 0 |
| 105 | + ); |
| 106 | + provision_or_verify_rooted_qualified_family(core) |
| 107 | + .await |
| 108 | + .unwrap(); |
| 109 | + fixture.counts.assert(0, 0); |
| 110 | +} |
| 111 | + |
| 112 | +#[tokio::test] |
| 113 | +async fn captured_previous_core_without_q_upgrades_before_new_provisioning() { |
| 114 | + let temp = tempfile::tempdir().unwrap(); |
| 115 | + let (config, _schema) = test_db_config(temp.path()).await; |
| 116 | + let core = crate::jupiter::storage::init::database_connection(&config) |
| 117 | + .await |
| 118 | + .unwrap(); |
| 119 | + let old_schema: String = core |
| 120 | + .query_one_raw(Statement::from_string( |
| 121 | + DbBackend::Postgres, |
| 122 | + "SELECT metadata_schema FROM mst2_metadata_namespace WHERE graph_domain='qualified-v1'", |
| 123 | + )) |
| 124 | + .await |
| 125 | + .unwrap() |
| 126 | + .unwrap() |
| 127 | + .try_get_by_index(0) |
| 128 | + .unwrap(); |
| 129 | + restore_previous(&core, &old_schema, false).await; |
| 130 | + test_upgrade_reader_retention(&core).await.unwrap(); |
| 131 | + provision_or_verify_rooted_qualified_family(&core) |
| 132 | + .await |
| 133 | + .unwrap(); |
| 134 | + let schema: String = core |
| 135 | + .query_one_raw(Statement::from_string( |
| 136 | + DbBackend::Postgres, |
| 137 | + "SELECT metadata_schema FROM mst2_metadata_namespace WHERE graph_domain='qualified-v1'", |
| 138 | + )) |
| 139 | + .await |
| 140 | + .unwrap() |
| 141 | + .unwrap() |
| 142 | + .try_get_by_index(0) |
| 143 | + .unwrap(); |
| 144 | + assert_ne!(schema, old_schema); |
| 145 | + let water: i64 = core |
| 146 | + .query_one_raw(Statement::from_string( |
| 147 | + DbBackend::Postgres, |
| 148 | + format!( |
| 149 | + "SELECT high_water FROM \"{}\".mst2_metadata_reader_issuance", |
| 150 | + schema.replace('"', "\"\"") |
| 151 | + ), |
| 152 | + )) |
| 153 | + .await |
| 154 | + .unwrap() |
| 155 | + .unwrap() |
| 156 | + .try_get_by_index(0) |
| 157 | + .unwrap(); |
| 158 | + assert_eq!(water, 0); |
| 159 | + provision_or_verify_rooted_qualified_family(&core) |
| 160 | + .await |
| 161 | + .unwrap(); |
| 162 | +} |
| 163 | + |
| 164 | +#[tokio::test] |
| 165 | +async fn captured_previous_tampered_q_rejects_upgrade_without_partial_issuance_schema() { |
| 166 | + let fixture = Fixture::new_with_pg_config(true).await; |
| 167 | + let before = permanent_rows(&fixture).await; |
| 168 | + let schema = q_schema(&fixture).await; |
| 169 | + let mono = fixture.state.storage.mono_storage(); |
| 170 | + let core = mono.get_connection(); |
| 171 | + restore_previous(core, &schema, true).await; |
| 172 | + core.execute_unprepared(&format!( |
| 173 | + "ALTER TABLE \"{}\".mst2_metadata_reader_operation ADD COLUMN unexpected integer", |
| 174 | + schema.replace('"', "\"\"") |
| 175 | + )) |
| 176 | + .await |
| 177 | + .unwrap(); |
| 178 | + assert!(test_upgrade_reader_retention(core).await.is_err()); |
| 179 | + assert_eq!(permanent_rows(&fixture).await, before); |
| 180 | + let exists: bool = core |
| 181 | + .query_one_raw(Statement::from_sql_and_values( |
| 182 | + DbBackend::Postgres, |
| 183 | + "SELECT to_regclass($1) IS NULL AS absent", |
| 184 | + [format!("{schema}.mst2_metadata_reader_issuance").into()], |
| 185 | + )) |
| 186 | + .await |
| 187 | + .unwrap() |
| 188 | + .unwrap() |
| 189 | + .try_get("", "absent") |
| 190 | + .unwrap(); |
| 191 | + assert!(exists); |
| 192 | + let implementation:String=core.query_one_raw(Statement::from_string(DbBackend::Postgres, |
| 193 | + "SELECT encode(implementation_fingerprint,'hex') FROM mst2_qualified_family_policy WHERE singleton=1")) |
| 194 | + .await.unwrap().unwrap().try_get_by_index(0).unwrap(); |
| 195 | + assert_eq!( |
| 196 | + implementation, |
| 197 | + "6d7095dc052e60bf6de21a987b72e23fdfbfe819355f0e847d2a7f3c1cbd3f27" |
| 198 | + ); |
| 199 | +} |
0 commit comments