huskies: merge 1072

This commit is contained in:
dave
2026-05-15 01:21:38 +00:00
parent ae69cd50b1
commit 1506141155
4 changed files with 236 additions and 12 deletions
+107 -1
View File
@@ -29,7 +29,7 @@ pub mod shadow_write;
pub use content_store::{ContentKey, all_content_ids, delete_content, read_content, write_content};
pub use ops::{ItemMeta, delete_item, move_item_stage, next_item_number, write_item_with_content};
pub use shadow_write::{get_shared_pool, init};
pub use shadow_write::{check_schema_drift, get_shared_pool, init};
#[cfg(test)]
pub use content_store::ensure_content_store;
@@ -395,6 +395,112 @@ mod tests {
);
}
/// Regression: root cause of the 2026-05-14 21:07 production outage.
///
/// A headless agent on a feature branch (whose binary includes a new
/// sqlx migration) must NEVER apply that migration to the production
/// pipeline.db. Verify that opening an agent-local DB and running
/// migrations on it leaves the production DB's `_sqlx_migrations` table
/// unchanged.
///
/// The enforcement mechanism is in `init_subsystems(is_agent=true)`, which
/// redirects to a temp path. This test validates the SQLite isolation
/// property: migrations applied to one file are confined to that file.
#[tokio::test]
async fn agent_db_isolation_does_not_affect_production_db() {
let tmp = tempfile::tempdir().unwrap();
let prod_db_path = tmp.path().join("production.db");
let agent_db_path = tmp.path().join("agent_temp.db");
// Set up the production DB — apply the current compiled-in migrations.
let prod_opts = sqlx::sqlite::SqliteConnectOptions::new()
.filename(&prod_db_path)
.create_if_missing(true);
let prod_pool = sqlx::SqlitePool::connect_with(prod_opts).await.unwrap();
sqlx::migrate!("./migrations")
.run(&prod_pool)
.await
.unwrap();
// Record the migration versions present in the production DB.
let before: Vec<(i64,)> =
sqlx::query_as("SELECT version FROM _sqlx_migrations ORDER BY version")
.fetch_all(&prod_pool)
.await
.unwrap();
// Simulate the agent opening its own isolated DB and running migrations.
let agent_opts = sqlx::sqlite::SqliteConnectOptions::new()
.filename(&agent_db_path)
.create_if_missing(true);
let agent_pool = sqlx::SqlitePool::connect_with(agent_opts).await.unwrap();
sqlx::migrate!("./migrations")
.run(&agent_pool)
.await
.unwrap();
// Production DB must be completely unaffected by the agent's migration run.
let after: Vec<(i64,)> =
sqlx::query_as("SELECT version FROM _sqlx_migrations ORDER BY version")
.fetch_all(&prod_pool)
.await
.unwrap();
assert_eq!(
before, after,
"agent opening its own DB must not alter the production DB migration table"
);
}
/// Verify that `check_schema_drift` returns an empty list when all
/// migrations in the database are recognised by this binary.
#[tokio::test]
async fn check_schema_drift_empty_when_all_known() {
let tmp = tempfile::tempdir().unwrap();
let db_path = tmp.path().join("drift_test.db");
let opts = sqlx::sqlite::SqliteConnectOptions::new()
.filename(&db_path)
.create_if_missing(true);
let pool = sqlx::SqlitePool::connect_with(opts).await.unwrap();
sqlx::migrate!("./migrations").run(&pool).await.unwrap();
let drift = super::shadow_write::check_schema_drift(&pool).await;
assert!(
drift.is_empty(),
"no drift expected when DB matches the compiled-in migration set"
);
}
/// Verify that `check_schema_drift` identifies a manually-inserted
/// migration row that is not part of the compiled-in set.
#[tokio::test]
async fn check_schema_drift_detects_unknown_migration() {
let tmp = tempfile::tempdir().unwrap();
let db_path = tmp.path().join("drift_future.db");
let opts = sqlx::sqlite::SqliteConnectOptions::new()
.filename(&db_path)
.create_if_missing(true);
let pool = sqlx::SqlitePool::connect_with(opts).await.unwrap();
sqlx::migrate!("./migrations").run(&pool).await.unwrap();
// Inject a fake "future" migration that no binary compiled today would know.
let fake_checksum: Vec<u8> = vec![0u8; 20];
sqlx::query(
"INSERT INTO _sqlx_migrations \
(version, description, installed_on, success, checksum, execution_time) \
VALUES (99999999999999, 'future_migration', '2099-01-01T00:00:00Z', 1, ?1, 0)",
)
.bind(&fake_checksum)
.execute(&pool)
.await
.unwrap();
let drift = super::shadow_write::check_schema_drift(&pool).await;
assert_eq!(drift.len(), 1, "exactly one unknown migration expected");
assert_eq!(drift[0].version, 99999999999999_i64);
assert_eq!(drift[0].description, "future_migration");
}
/// Story 864: passing `ItemMeta::default()` against a content blob that
/// LOOKS like front-matter must NOT silently extract metadata into the
/// CRDT. The whole point of removing the implicit YAML round-trip is