mirror of
https://github.com/fawney19/Aether.git
synced 2026-09-13 22:50:19 +08:00
fix(ci): make postgres bootstrap tests apply pending migrations
This commit is contained in:
@@ -573,19 +573,21 @@ fn harden_execution_runtime_socket(
|
||||
return Err(io::Error::last_os_error());
|
||||
}
|
||||
let stat = unsafe { stat.assume_init() };
|
||||
let fd_mode = stat.st_mode as libc::mode_t;
|
||||
if metadata.file_type().is_symlink()
|
||||
|| !metadata.file_type().is_socket()
|
||||
|| metadata.uid() != effective_uid
|
||||
|| metadata.nlink() != 1
|
||||
|| metadata.mode() & 0o777 != 0o600
|
||||
// On Linux a pathname socket is represented by the filesystem's
|
||||
// dentry while `fstat` reports the corresponding sockfs inode. The
|
||||
// inode number is shared, but the device id is intentionally not;
|
||||
// comparing `st_dev` would reject every valid socket on overlay/tmpfs
|
||||
// runners. The validated canonical parent and inode identity still
|
||||
// close the replacement window without relying on that differing
|
||||
// device number.
|
||||
|| (cfg!(target_os = "linux") && metadata.ino() != stat.st_ino)
|
||||
// A pathname Unix socket and its connected sockfs inode do not have
|
||||
// portable pathname identity. In particular, Linux can report a
|
||||
// different inode number (and always reports a different device) for
|
||||
// the descriptor than for the dentry. Validate the descriptor's own
|
||||
// type and owner instead; the canonical, owner-checked
|
||||
// parent and the path checks above prevent an untrusted user from
|
||||
// replacing this private socket.
|
||||
|| (fd_mode & libc::S_IFMT) != libc::S_IFSOCK
|
||||
|| stat.st_uid != effective_uid
|
||||
{
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::PermissionDenied,
|
||||
|
||||
@@ -167,6 +167,30 @@ impl ManagedPostgresServer {
|
||||
}
|
||||
}
|
||||
|
||||
/// A clean PostgreSQL database is bootstrapped from the schema snapshot first;
|
||||
/// migrations after the privacy/security frontier are intentionally left
|
||||
/// pending so their data-preserving changes still execute. Exercise the same
|
||||
/// prepare-then-run sequence used by gateway startup before asserting that the
|
||||
/// database is current.
|
||||
async fn prepare_and_apply_clean_postgres_database(pool: &PgPool) {
|
||||
let pending = prepare_database_for_startup(pool)
|
||||
.await
|
||||
.expect("clean database bootstrap should succeed");
|
||||
if !pending.is_empty() {
|
||||
super::run_migrations(pool)
|
||||
.await
|
||||
.expect("pending PostgreSQL migrations should apply");
|
||||
}
|
||||
|
||||
let pending = prepare_database_for_startup(pool)
|
||||
.await
|
||||
.expect("PostgreSQL startup preparation should re-check migrations");
|
||||
assert!(
|
||||
pending.is_empty(),
|
||||
"clean PostgreSQL database should be current after migrations: {pending:?}"
|
||||
);
|
||||
}
|
||||
|
||||
fn local_postgres_tests_required() -> bool {
|
||||
// CI can opt into failing when the isolated local PostgreSQL fixture is unavailable.
|
||||
std::env::var("AETHER_REQUIRE_LOCAL_POSTGRES_TESTS")
|
||||
@@ -3046,14 +3070,7 @@ async fn prepare_database_for_startup_bootstraps_clean_database() {
|
||||
let pool = PgPool::connect(server.database_url())
|
||||
.await
|
||||
.expect("pool should connect");
|
||||
let pending = prepare_database_for_startup(&pool)
|
||||
.await
|
||||
.expect("clean database bootstrap should succeed");
|
||||
|
||||
assert!(
|
||||
pending.is_empty(),
|
||||
"fresh databases should not report pending migrations after startup preparation"
|
||||
);
|
||||
prepare_and_apply_clean_postgres_database(&pool).await;
|
||||
assert!(table_exists(&pool, "users")
|
||||
.await
|
||||
.expect("users lookup should succeed"));
|
||||
@@ -3081,9 +3098,8 @@ async fn prepare_database_for_startup_bootstraps_clean_database() {
|
||||
.expect("migration count query should succeed");
|
||||
assert_eq!(
|
||||
applied_count,
|
||||
empty_database_snapshot_migrations(&POSTGRES_MIGRATOR)
|
||||
.expect("baseline migrations should resolve")
|
||||
.len() as i64
|
||||
all_up_migrations().len() as i64,
|
||||
"fresh database should record the snapshot and every post-snapshot migration"
|
||||
);
|
||||
}
|
||||
|
||||
@@ -3099,13 +3115,7 @@ async fn postgres_request_candidates_preserve_deleted_api_key_identity() {
|
||||
let pool = PgPool::connect(server.database_url())
|
||||
.await
|
||||
.expect("pool should connect");
|
||||
let pending = prepare_database_for_startup(&pool)
|
||||
.await
|
||||
.expect("clean database bootstrap should succeed");
|
||||
assert!(
|
||||
pending.is_empty(),
|
||||
"clean database bootstrap should not leave pending migrations: {pending:?}"
|
||||
);
|
||||
prepare_and_apply_clean_postgres_database(&pool).await;
|
||||
|
||||
query(
|
||||
r#"
|
||||
@@ -3318,13 +3328,7 @@ async fn postgres_expired_api_key_cleanup_preserves_historical_identity() {
|
||||
let pool = PgPool::connect(database_url)
|
||||
.await
|
||||
.expect("pool should connect");
|
||||
let pending = prepare_database_for_startup(&pool)
|
||||
.await
|
||||
.expect("clean database bootstrap should succeed");
|
||||
assert!(
|
||||
pending.is_empty(),
|
||||
"clean database bootstrap should not leave pending migrations: {pending:?}"
|
||||
);
|
||||
prepare_and_apply_clean_postgres_database(&pool).await;
|
||||
|
||||
query(
|
||||
r#"
|
||||
@@ -3482,13 +3486,7 @@ async fn postgres_api_key_leaderboard_user_filter_preserves_aggregate_history()
|
||||
let pool = PgPool::connect(database_url)
|
||||
.await
|
||||
.expect("pool should connect");
|
||||
let pending = prepare_database_for_startup(&pool)
|
||||
.await
|
||||
.expect("clean database bootstrap should succeed");
|
||||
assert!(
|
||||
pending.is_empty(),
|
||||
"clean database bootstrap should not leave pending migrations: {pending:?}"
|
||||
);
|
||||
prepare_and_apply_clean_postgres_database(&pool).await;
|
||||
|
||||
query(
|
||||
r#"
|
||||
@@ -3808,10 +3806,7 @@ async fn postgres_usage_billing_facts_total_tokens_counts_cached_input_once() {
|
||||
let pool = PgPool::connect(server.database_url())
|
||||
.await
|
||||
.expect("pool should connect");
|
||||
let pending = prepare_database_for_startup(&pool)
|
||||
.await
|
||||
.expect("clean database bootstrap should succeed");
|
||||
assert!(pending.is_empty());
|
||||
prepare_and_apply_clean_postgres_database(&pool).await;
|
||||
|
||||
let legacy_view_migration = POSTGRES_MIGRATOR
|
||||
.iter()
|
||||
@@ -4011,10 +4006,7 @@ async fn postgres_migrations_repair_invalid_concurrent_cleanup_index() {
|
||||
let pool = PgPool::connect(server.database_url())
|
||||
.await
|
||||
.expect("pool should connect");
|
||||
let pending = prepare_database_for_startup(&pool)
|
||||
.await
|
||||
.expect("clean database bootstrap should succeed");
|
||||
assert!(pending.is_empty());
|
||||
prepare_and_apply_clean_postgres_database(&pool).await;
|
||||
|
||||
query("DROP INDEX CONCURRENTLY public.idx_usage_legacy_body_ref_cleanup_created_at")
|
||||
.execute(&pool)
|
||||
@@ -4104,14 +4096,7 @@ async fn prepare_database_for_startup_bootstraps_when_only_unrelated_public_tabl
|
||||
.await
|
||||
.expect("fixture table should be created");
|
||||
|
||||
let pending = prepare_database_for_startup(&pool)
|
||||
.await
|
||||
.expect("startup preparation should tolerate unrelated public tables");
|
||||
|
||||
assert!(
|
||||
pending.is_empty(),
|
||||
"unrelated public tables should not block baseline bootstrap on first startup"
|
||||
);
|
||||
prepare_and_apply_clean_postgres_database(&pool).await;
|
||||
assert!(table_exists(&pool, "vendor_bootstrap_marker")
|
||||
.await
|
||||
.expect("fixture table lookup should succeed"));
|
||||
|
||||
Reference in New Issue
Block a user