Skip to content
Merged
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
38 changes: 38 additions & 0 deletions .github/workflows/repository-gates.yml
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,44 @@ jobs:
docker compose -p mega2-it -f docker/docker-compose.test.yml --profile git \
up -d --build --wait postgres redis rustfs rustfs-init git-cli

- name: Verify necessary v3 publication and performance regressions
shell: bash
run: |
set -euo pipefail
source .env.test
export no_proxy="$NO_PROXY"
test_inventory="$(cargo test --lib -- --list)"
tests=(
api::router::snapshot_router::content::tests::rooted_metadata::descriptor_wire::rooted_postgres_descriptor_matches_codec_bytes_for_root_ascii_long_and_utf8_scopes
jupiter::migration::tests::import_repo_alias_rows_canonicalized
api::router::snapshot_router::content::tests::rooted_metadata::reader_retention::committed_metadata_requests_retire_owners_without_retiring_source_history
api::router::snapshot_router::content::tests::rooted_metadata::reader_retention::terminal_owner_survives_its_deferred_completion_and_prunes_in_a_later_transaction
api::router::snapshot_router::content::tests::rooted_metadata::reader_retention::reader_pruning_respects_the_64_owner_budget_with_a_committed_backlog
api::router::snapshot_router::content::tests::rooted_metadata::reader_retention::stale_actual_reader_cannot_read_or_finish_a_reissued_uuid
api::router::snapshot_router::content::tests::rooted_metadata::reader_retention::rolled_back_reader_issuance_is_unpublished_and_extreme_issuance_fails_closed
api::router::snapshot_router::content::tests::rooted_metadata::reader_retention::upgrade::current_reader_retention_migration_verifies_fresh_family_without_rewriting_history
api::router::snapshot_router::content::tests::rooted_metadata::reader_retention::upgrade::captured_previous_q_upgrade_preserves_old_sid_source_proofs_and_active_legacy_reader
api::router::snapshot_router::content::tests::rooted_metadata::reader_retention::upgrade::captured_previous_core_without_q_upgrades_before_new_provisioning
api::router::snapshot_router::content::tests::rooted_metadata::reader_retention::upgrade::captured_previous_tampered_q_rejects_upgrade_without_partial_issuance_schema
api::router::snapshot_router::content::tests::rooted_metadata::reader_retention::upgrade::native_runtime::captured_cc90_upgrade_preserves_nonzero_reader_issuance_all_owners_oids_and_old_sid
api::router::snapshot_router::content::tests::rooted_metadata::reader_retention::upgrade::native_runtime::captured_cc90_interrupted_before_reader_migration_resumes_without_reader_ddl
api::router::snapshot_router::content::tests::rooted_metadata::reader_retention::upgrade::native_runtime::captured_cc90_qless_canonical_policy_upgrades_before_new_provisioning
api::router::snapshot_router::content::tests::rooted_metadata::reader_retention::upgrade::native_runtime::captured_cc90_qless_exact_legacy_deparse_policy_upgrades_before_new_provisioning
api::router::snapshot_router::content::tests::rooted_metadata::reader_retention::upgrade::native_runtime::captured_cc90_tampered_decoder_rejects_upgrade_without_rewriting_owners_or_policy
api::router::snapshot_router::content::tests::rooted_metadata::reader_retention::upgrade::native_runtime::captured_cc90_qless_arbitrary_policy_shape_is_never_resigned
api::router::snapshot_router::content::tests::mst2_rooted_streamed_fact_persists_one_source_pass_and_reuses_warm_alias_facts
jupiter::storage::qualified_metadata_family::tests::canonical_tests::actual_rooted_cold_and_zero_delta_reuse_keep_one_canonical_graph
jupiter::storage::qualified_metadata_family::tests::canonical_tests::changed_ancestor_installs_only_delta_and_accepts_independently_attested_source_aliases
api::router::snapshot_router::content::tests::rooted_metadata::rooted_wide_directory_windows_and_lookup_survive_rebuild_with_valid_proofs
api::router::snapshot_router::content::tests::rooted_metadata::reader_retention::upgrade::native_runtime::descriptor_wire::captured_87b_descriptor_upgrade_preserves_owners_oids_and_replays_missing_ledgers
api::router::snapshot_router::content::tests::rooted_metadata::reader_retention::upgrade::native_runtime::descriptor_wire::captured_87b_qless_descriptor_upgrade_replays_missing_ledgers_before_provisioning
api::router::snapshot_router::content::tests::rooted_metadata::reader_retention::upgrade::native_runtime::descriptor_wire::captured_87b_tampered_descriptor_rejects_without_resigning_history
)
for test_name in "${tests[@]}"; do
grep -Fqx "$test_name: test" <<< "$test_inventory"
done
cargo test --lib -- --exact --nocapture "${tests[@]}"

- name: Run repository tests with test environment
shell: bash
run: |
Expand Down
181 changes: 181 additions & 0 deletions src/api/router/snapshot_descriptor_upgrade_tests.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
use super::*;
use crate::jupiter::storage::qualified_metadata_family::reader_previous_fixture::restore_native_runtime;

async fn remove_upgrade_ledgers(core: &sea_orm::DatabaseConnection) {
core.execute_unprepared(
"DELETE FROM seaql_migrations WHERE version IN (
'm20261008_000400_add_mst2_reader_retention',
'm20261008_000500_fix_mst2_native_runtime',
'm20261008_000600_fix_mst2_descriptor_wire')",
)
.await
.unwrap();
}

async fn assert_upgrade_ledgers(core: &sea_orm::DatabaseConnection) {
let count: i64 = core
.query_one_raw(Statement::from_string(
DbBackend::Postgres,
"SELECT count(*) FROM seaql_migrations WHERE version IN (
'm20261008_000400_add_mst2_reader_retention',
'm20261008_000500_fix_mst2_native_runtime',
'm20261008_000600_fix_mst2_descriptor_wire')",
))
.await
.unwrap()
.unwrap()
.try_get_by_index(0)
.unwrap();
assert_eq!(count, 3);
}

async fn descriptor_matches_stored(fixture: &Fixture) -> i64 {
q_count(
fixture,
"SELECT count(*) FROM {q}.mst2_qualified_session_incarnation session
WHERE session.state='READY' AND session.canonical_descriptor=
{q}.mst2_metadata_descriptor(session.prepare_id,session.instance_id,
session.commit_oid,session.root_tree_oid)",
)
.await
}

#[tokio::test]
async fn captured_87b_descriptor_upgrade_preserves_owners_oids_and_replays_missing_ledgers() {
let fixture = Fixture::new_with_pg_config(true).await;
seed_live_and_terminal(&fixture).await;
let schema = q_schema(&fixture).await;
let mono = fixture.state.storage.mono_storage();
let core = mono.get_connection();
for missing_ledgers in [false, true] {
let rows = permanent_rows(&fixture).await;
let owners = retained_owners(&fixture).await;
restore_native_runtime(core, &schema, true).await;
assert_eq!(descriptor_matches_stored(&fixture).await, 0);
assert_eq!(permanent_rows(&fixture).await, rows);
assert_eq!(retained_owners(&fixture).await, owners);
if missing_ledgers {
remove_upgrade_ledgers(core).await;
apply_migrations(core, false).await.unwrap();
assert_upgrade_ledgers(core).await;
} else {
test_upgrade_native_runtime(core).await.unwrap();
}
assert_eq!(descriptor_matches_stored(&fixture).await, 1);
assert_eq!(permanent_rows(&fixture).await, rows);
assert_eq!(retained_owners(&fixture).await, owners);
let stamp = policy(core).await;
if missing_ledgers {
apply_migrations(core, false).await.unwrap();
} else {
test_upgrade_native_runtime(core).await.unwrap();
}
assert_eq!(policy(core).await, stamp);
assert_eq!(permanent_rows(&fixture).await, rows);
assert_eq!(retained_owners(&fixture).await, owners);
assert_old_sid_works(&fixture).await;
}
let rows = permanent_rows(&fixture).await;
let owners = retained_owners(&fixture).await;
let stamp = policy(core).await;
core.execute_unprepared(
"DELETE FROM seaql_migrations WHERE version IN (
'm20261008_000400_add_mst2_reader_retention',
'm20261008_000500_fix_mst2_native_runtime')",
)
.await
.unwrap();
apply_migrations(core, false).await.unwrap();
assert_upgrade_ledgers(core).await;
assert_eq!(descriptor_matches_stored(&fixture).await, 1);
assert_eq!(policy(core).await, stamp);
assert_eq!(permanent_rows(&fixture).await, rows);
assert_eq!(retained_owners(&fixture).await, owners);
assert_old_sid_works(&fixture).await;
}

#[tokio::test]
async fn captured_87b_qless_descriptor_upgrade_replays_missing_ledgers_before_provisioning() {
let temp = tempfile::tempdir().unwrap();
let (config, _schema) = test_db_config(temp.path()).await;
let core = crate::jupiter::storage::init::database_connection(&config)
.await
.unwrap();
let schema: String = core
.query_one_raw(Statement::from_string(
DbBackend::Postgres,
"SELECT metadata_schema FROM mst2_metadata_namespace WHERE graph_domain='qualified-v1'",
))
.await
.unwrap()
.unwrap()
.try_get_by_index(0)
.unwrap();
restore_native_runtime(&core, &schema, false).await;
remove_upgrade_ledgers(&core).await;
apply_migrations(&core, false).await.unwrap();
assert_upgrade_ledgers(&core).await;
let stamp = policy(&core).await;
apply_migrations(&core, false).await.unwrap();
test_upgrade_native_runtime(&core).await.unwrap();
assert_eq!(policy(&core).await, stamp);
let namespace = provision_or_verify_rooted_qualified_family(&core)
.await
.unwrap();
let current_schema: String = core
.query_one_raw(Statement::from_string(
DbBackend::Postgres,
"SELECT metadata_schema FROM mst2_metadata_namespace WHERE graph_domain='qualified-v1'",
))
.await
.unwrap()
.unwrap()
.try_get_by_index(0)
.unwrap();
assert_ne!(current_schema, schema);
assert_eq!(
provision_or_verify_rooted_qualified_family(&core)
.await
.unwrap(),
namespace
);
let high_water: i64 = core
.query_one_raw(Statement::from_string(
DbBackend::Postgres,
format!(
"SELECT high_water FROM \"{}\".mst2_metadata_reader_issuance",
current_schema.replace('"', "\"\"")
),
))
.await
.unwrap()
.unwrap()
.try_get_by_index(0)
.unwrap();
assert_eq!(high_water, 0);
}

#[tokio::test]
async fn captured_87b_tampered_descriptor_rejects_without_resigning_history() {
let fixture = Fixture::new_with_pg_config(true).await;
seed_live_and_terminal(&fixture).await;
let schema = q_schema(&fixture).await;
let mono = fixture.state.storage.mono_storage();
let core = mono.get_connection();
restore_native_runtime(core, &schema, true).await;
let rows = permanent_rows(&fixture).await;
let owners = retained_owners(&fixture).await;
let before = policy(core).await;
core.execute_unprepared(&format!(
"CREATE OR REPLACE FUNCTION \"{}\".mst2_metadata_descriptor(
pid text,instance text,commit_id text,tree_id text) RETURNS bytea
LANGUAGE sql AS 'SELECT decode(''0000'',''hex'')'",
schema.replace('"', "\"\"")
))
.await
.unwrap();
assert!(test_upgrade_native_runtime(core).await.is_err());
assert_eq!(policy(core).await, before);
assert_eq!(permanent_rows(&fixture).await, rows);
assert_eq!(retained_owners(&fixture).await, owners);
}
118 changes: 118 additions & 0 deletions src/api/router/snapshot_descriptor_wire_tests.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
use mst2_codec::descriptor::ServingDescriptor;

use super::*;

async fn assert_postgres_descriptor_matches_codec(fixture: &Fixture, scope: &str) {
let resolved = success_json(
fixture
.app
.clone()
.oneshot(
Request::builder()
.method("POST")
.uri("/api/v2/snapshots/resolve")
.header("authorization", format!("Bearer {TOKEN}"))
.header("content-type", "application/json")
.body(Body::from(
json!({"target":{"kind":"latest"},"scope":scope}).to_string(),
))
.unwrap(),
)
.await
.unwrap(),
)
.await;
let snapshot = resolved["descriptor"]["snapshot_id"].as_str().unwrap();
let lease = resolved["lease_id"].as_str().unwrap();
assert_eq!(
fixture
.state
.storage
.snapshot_metadata_family(lease, true)
.await
.unwrap(),
Some(SnapshotMetadataFamily::Rooted)
);
let context = fixture
.state
.storage
.snapshot_context(snapshot, lease)
.await
.unwrap();
let descriptor = &context.built.descriptor;
assert_eq!(descriptor.scope, scope);
let codec_bytes = descriptor.encode().unwrap();
let schema = q_schema(fixture).await;
let quoted = format!("\"{}\"", schema.replace('"', "\"\""));
let row = fixture
.state
.storage
.mono_storage()
.get_connection()
.query_one_raw(Statement::from_sql_and_values(
DbBackend::Postgres,
format!(
"SELECT {q}.mst2_metadata_descriptor(session.prepare_id,session.instance_id,
session.commit_oid,session.root_tree_oid) AS descriptor,
session.canonical_descriptor,session.metadata_root,session.snapshot_id
FROM {q}.mst2_qualified_session_incarnation session
JOIN {q}.mst2_qualified_lease_binding lease USING(snapshot_id,session_incarnation)
WHERE session.snapshot_id=$1 AND lease.lease_id=$2 AND session.state='READY'
AND lease.state='ACTIVE'",
q = quoted,
),
[snapshot.into(), lease.into()],
))
.await
.unwrap()
.unwrap();
let database_bytes: Vec<u8> = row.try_get("", "descriptor").unwrap();
assert_eq!(database_bytes, codec_bytes, "scope {scope:?}");
assert_eq!(
row.try_get::<Vec<u8>>("", "canonical_descriptor").unwrap(),
codec_bytes
);
assert_eq!(
ServingDescriptor::decode(&database_bytes).unwrap(),
*descriptor
);
assert_eq!(
&database_bytes[56..58],
&u16::try_from(scope.len()).unwrap().to_le_bytes()
);
assert_eq!(&database_bytes[58..58 + scope.len()], scope.as_bytes());
assert_eq!(
row.try_get::<Vec<u8>>("", "metadata_root").unwrap(),
descriptor.metadata_root.to_vec()
);
assert_eq!(
resolved["descriptor"]["metadata_root"],
format!("sha256:{}", hex::encode(descriptor.metadata_root))
);
let codec_snapshot = format!("sha256:{}", hex::encode(descriptor.snapshot_id().unwrap()));
assert_eq!(snapshot, codec_snapshot);
assert_eq!(context.built.snapshot_id, codec_snapshot);
assert_eq!(
row.try_get::<String>("", "snapshot_id").unwrap(),
codec_snapshot
);
}

#[tokio::test]
async fn rooted_postgres_descriptor_matches_codec_bytes_for_root_ascii_long_and_utf8_scopes() {
let component = "a".repeat(247);
let fixture = Fixture::new_with_pg_config_directories_and_objects(
true,
0,
&[(format!("{component}/é/file"), b"descriptor wire".to_vec())],
)
.await;
let long_scope = format!("/project/{component}");
let utf8_scope = format!("{long_scope}/é");
assert_eq!(long_scope.len(), 256);
assert_eq!(utf8_scope.len(), 259);
assert_ne!(utf8_scope.len(), utf8_scope.chars().count());
for scope in ["/", "/project", long_scope.as_str(), utf8_scope.as_str()] {
assert_postgres_descriptor_matches_codec(&fixture, scope).await;
}
}
11 changes: 8 additions & 3 deletions src/api/router/snapshot_native_runtime_upgrade_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ use crate::jupiter::{
storage::qualified_metadata_family::reader_previous_fixture::restore_retention,
};

#[path = "snapshot_descriptor_upgrade_tests.rs"]
mod descriptor_wire;

async fn retained_owners(fixture: &Fixture) -> Value {
let txn = transaction(fixture).await;
let value = txn.query_one_raw(Statement::from_string(DbBackend::Postgres,
Expand Down Expand Up @@ -135,10 +138,11 @@ async fn captured_cc90_interrupted_before_reader_migration_resumes_without_reade
let owners = retained_owners(&fixture).await;
core.execute_raw(Statement::from_sql_and_values(
DbBackend::Postgres,
"DELETE FROM seaql_migrations WHERE version IN ($1,$2)",
"DELETE FROM seaql_migrations WHERE version IN ($1,$2,$3)",
[
"m20261008_000400_add_mst2_reader_retention".into(),
"m20261008_000500_fix_mst2_native_runtime".into(),
"m20261008_000600_fix_mst2_descriptor_wire".into(),
],
))
.await
Expand All @@ -148,9 +152,10 @@ async fn captured_cc90_interrupted_before_reader_migration_resumes_without_reade
assert_eq!(retained_owners(&fixture).await, owners);
let count: i64 = core.query_one_raw(Statement::from_string(DbBackend::Postgres,
"SELECT count(*) FROM seaql_migrations WHERE version IN
('m20261008_000400_add_mst2_reader_retention','m20261008_000500_fix_mst2_native_runtime')"))
('m20261008_000400_add_mst2_reader_retention','m20261008_000500_fix_mst2_native_runtime',
'm20261008_000600_fix_mst2_descriptor_wire')"))
.await.unwrap().unwrap().try_get_by_index(0).unwrap();
assert_eq!(count, 2);
assert_eq!(count, 3);
assert_old_sid_works(&fixture).await;
}

Expand Down
3 changes: 3 additions & 0 deletions src/api/router/snapshot_rooted_metadata_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ use crate::jupiter::storage::qualified_metadata_family::{
#[path = "snapshot_reader_retention_tests.rs"]
mod reader_retention;

#[path = "snapshot_descriptor_wire_tests.rs"]
mod descriptor_wire;

async fn q_schema(fixture: &Fixture) -> String {
fixture
.state
Expand Down
Loading
Loading