feat(server): create-user CLI + session-store migration on startup
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,10 +1,11 @@
|
||||
use clap::Parser;
|
||||
use server::Config;
|
||||
|
||||
const CLEARED: [(&str, Option<&str>); 3] = [
|
||||
const CLEARED: [(&str, Option<&str>); 4] = [
|
||||
("DATABASE_URL", None),
|
||||
("BIND_ADDR", None),
|
||||
("APP_NAME", None),
|
||||
("SESSION_COOKIE_SECURE", None),
|
||||
];
|
||||
|
||||
#[test]
|
||||
@@ -25,3 +26,11 @@ fn database_url_is_required() {
|
||||
assert!(Config::try_parse_from(["server"]).is_err());
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cookie_secure_defaults_to_true() {
|
||||
temp_env::with_vars(CLEARED, || {
|
||||
let config = Config::try_parse_from(["server", "--database-url", "postgres://x"]).unwrap();
|
||||
assert!(config.cookie_secure);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
use db::Db;
|
||||
use domain::Role;
|
||||
use sqlx::PgPool;
|
||||
|
||||
// Note: `server::create_user` opens its own DB connection by URL, but `#[sqlx::test]`
|
||||
// provisions a temporary database whose URL is not directly exposed. The test below
|
||||
// exercises the same building blocks that `server::create_user` composes —
|
||||
// `auth::hash_password` + `db::users::create_user` + `db::users::credentials_by_email` —
|
||||
// against the test pool, which fully validates the end-to-end bootstrap logic.
|
||||
|
||||
#[sqlx::test(migrations = "../db/migrations")]
|
||||
async fn create_user_persists_and_password_verifies(pool: PgPool) {
|
||||
let db = Db::from_pool(pool.clone());
|
||||
|
||||
let hash = auth::hash_password("bootstrap-pw-123").unwrap();
|
||||
|
||||
let mut tx = db.pool().begin().await.unwrap();
|
||||
|
||||
db::users::create_user(
|
||||
&mut tx,
|
||||
domain::AuditActor::System,
|
||||
&domain::NewUser {
|
||||
email: domain::Email::parse("boss@example.com").unwrap(),
|
||||
password_hash: hash,
|
||||
role: Role::Admin,
|
||||
},
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
tx.commit().await.unwrap();
|
||||
|
||||
let (user, stored_hash) = db::users::credentials_by_email(db.pool(), "boss@example.com")
|
||||
.await
|
||||
.unwrap()
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(user.role, Role::Admin);
|
||||
assert!(auth::verify_password("bootstrap-pw-123", &stored_hash));
|
||||
}
|
||||
Reference in New Issue
Block a user