refactor: massive codebase restructuring — naming, splitting, DRY

Crate renames:
  - zesdex-entities::seaorm → domain (misleading name, no SeaORM used)
  - zesdex-dto → merged into zesdex-entities (100% re-exports)
  - zesdex-libs → zesdex-infra (vague name)

Module renames:
  - app/harness → guard (misleading: safety gatekeeper, not test harness)
  - runtime/commands → action_dispatch (name clashed with controller/command)
  - resources → prompts (embedded prompt text, not general resources)
  - tool/seqthink → sequential_think (unreadable abbreviation)
  - msglog/query → insert (module only inserts, never queries)

Dead code removal:
  - app/mode/help.rs (orphaned — not declared in mod.rs)
  - app/mode/loading.rs (orphaned — not declared in mod.rs)

File splitting (71 new files, avg ~115 lines/file):
  - app/runtime/actions/: 1→8 files (was 2030 lines)
  - view/overlays/: 1→16 files (was 1167 lines)
  - tool/lsp/: 1→8 per-tool files (was 909 lines)
  - main.rs: 1→5 files (session, daemon, attach, event_loop)
  - workflow/engine + hive_mind: 2→10 files
  - subagent/engine + auto: 2→9 files
  - lsp/provisioner: 1→5 files
  - review/: 1→6 files
  - guard/: 1→2 files (extracted patterns)
  - state/misc: 1→3 files (input, scroll)
  - mcp/: 1→3 files (transport, adapter)
  - stream/json_repair extracted from turn.rs

DRY:
  - Pattern constants (STUB_PATTERNS etc) in guard/patterns shared with subagent
  - 3 near-identical background spawners → 1 generic + thin wrappers
  - Shared spawn_subagent_with_drain() extracted
  - Shared create_session() in main
  - write_osc52 deduplicated

Bug fixes:
  - archive_message(): sess.db → db (wrong variable name)
  - execute_one_tool(): wrong parameter name
  - check_credential_read() function was missing (restored from test expectations)
This commit is contained in:
asepharyana
2026-07-17 09:08:41 +07:00
parent 1f0ae9f551
commit 9a67137954
139 changed files with 9704 additions and 8858 deletions
+86
View File
@@ -0,0 +1,86 @@
#![allow(
clippy::cast_possible_truncation,
clippy::cast_sign_loss,
clippy::cast_precision_loss,
clippy::cast_possible_wrap
)]
//! Argon2 password hashing and verification utilities.
//!
//! Uses the `argon2` crate (Argon2id variant) with default parameters,
//! which provide a good security / performance trade-off for interactive
//! authentication.
use anyhow::Result;
use argon2::{
password_hash::{PasswordHash, PasswordHasher, PasswordVerifier, SaltString},
Argon2,
};
use rand_core::OsRng;
/// Hash a plaintext password using Argon2id with a random salt.
///
/// The returned string is in the PHC string format
/// (`$argon2id$v=19$...`) and can be stored directly in the database.
///
/// # Errors
///
/// Returns an error if the argon2 library fails (extremely rare —
/// typically indicates an OOM or system-level crypto failure).
pub fn hash_password(password: &str) -> Result<String> {
let salt = SaltString::generate(&mut OsRng);
let argon2 = Argon2::default();
let hash = argon2
.hash_password(password.as_bytes(), &salt)
.map_err(|e| anyhow::anyhow!("failed to hash password: {e}"))?;
Ok(hash.to_string())
}
/// Verify a plaintext password against a previously-hashed PHC string.
///
/// Returns `Ok(true)` if the password matches, `Ok(false)` if it does not,
/// and `Err` if the hash string is malformed.
///
/// # Errors
///
/// Returns an error if the hash string is not a valid PHC string or if
/// the argon2 library encounters an internal failure.
pub fn verify_password(password: &str, hash: &str) -> Result<bool> {
let parsed_hash = PasswordHash::new(hash)
.map_err(|e| anyhow::anyhow!("failed to parse password hash: {e}"))?;
let argon2 = Argon2::default();
Ok(argon2
.verify_password(password.as_bytes(), &parsed_hash)
.is_ok())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_hash_and_verify() {
let password = "my-secure-password-123!";
let hash = hash_password(password).unwrap();
assert!(verify_password(password, &hash).unwrap());
}
#[test]
fn test_wrong_password_fails() {
let hash = hash_password("correct-password").unwrap();
assert!(!verify_password("wrong-password", &hash).unwrap());
}
#[test]
fn test_hashes_are_different() {
let h1 = hash_password("same-password").unwrap();
let h2 = hash_password("same-password").unwrap();
// Different salts → different hashes.
assert_ne!(h1, h2);
}
#[test]
fn test_invalid_hash_returns_error() {
let result = verify_password("password", "not-a-valid-hash");
assert!(result.is_err());
}
}