From d8da7f8482ffbab3783e3f079f12b127e7b9df20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yuniel=20Acosta=20P=C3=A9rez?= <33158051+yacosta738@users.noreply.github.com> Date: Mon, 1 Jun 2026 08:01:54 +0200 Subject: [PATCH 1/5] fix(build): allow cargo check without node_modules in worktree The build.rs unconditionally ran which requires node_modules/.bin/vite to exist. This caused pre-commit hooks to fail on worktrees where node_modules may not be freshly installed. Now the build script only runs vite if node_modules already exists, skipping the dashboard embedding when deps are not present. This allows and pre-commit hooks to pass in any state, while still embedding the dashboard when running a full build. --- .github/workflows/ci.yml | 7 +++++++ apps/rook/build.rs | 38 +++++++++++++++++++++++++------------- sonar-project.properties | 2 +- 3 files changed, 33 insertions(+), 14 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 13e3c19b..8b3c9683 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -188,6 +188,13 @@ jobs: - uses: actions/checkout@v6.0.2 with: persist-credentials: false + - uses: pnpm/action-setup@v4.1.0 + - uses: actions/setup-node@v4.2.0 + with: + node-version: 22 + cache: 'pnpm' + - name: Install dependencies + run: pnpm install - name: SonarQube Scan uses: SonarSource/sonarqube-scan-action@7006c4492b2e0ee0f816d36501671557c97f5995 # v8.1.0 env: diff --git a/apps/rook/build.rs b/apps/rook/build.rs index 4565f3d0..74be68f5 100644 --- a/apps/rook/build.rs +++ b/apps/rook/build.rs @@ -2,21 +2,33 @@ use std::path::Path; use std::process::Command; fn main() { - let dashboard_dir = Path::new("dashboard"); - let status = Command::new("sh") - .current_dir(dashboard_dir) - .arg("-c") - .arg("./node_modules/.bin/vite build") - .status() - .expect("failed to run dashboard build: sh or vite not found"); - - if !status.success() { - eprintln!("dashboard build failed with exit code: {}", status); - std::process::exit(1); - } - + // Emit rerun-if-changed unconditionally so Cargo knows when to rebuild println!("cargo:rerun-if-changed=dashboard/dist"); println!("cargo:rerun-if-changed=dashboard/src"); println!("cargo:rerun-if-changed=dashboard/vite.config.ts"); println!("cargo:rerun-if-changed=dashboard/package.json"); + + // Only build dashboard if node_modules/.bin/vite exists (i.e. deps are installed) + // This allows `cargo check` to pass without running the full vite build + let dashboard_dir = Path::new("dashboard"); + let vite_path = dashboard_dir.join("node_modules/.bin/vite"); + + if vite_path.exists() { + let status = Command::new("sh") + .current_dir(dashboard_dir) + .arg("-c") + .arg("./node_modules/.bin/vite build") + .status() + .expect("failed to run dashboard build: sh or vite not found"); + + if !status.success() { + eprintln!("dashboard build failed with exit code: {}", status); + std::process::exit(1); + } + } else { + eprintln!( + "warning: dashboard/node_modules/.bin/vite not found, skipping dashboard build" + ); + eprintln!("hint: run `pnpm install` in the repo root to enable dashboard embedding"); + } } diff --git a/sonar-project.properties b/sonar-project.properties index 04710fe4..2ba603ad 100644 --- a/sonar-project.properties +++ b/sonar-project.properties @@ -11,7 +11,7 @@ sonar.sources=apps/rook,crates/domain/rook-core,crates/application/rook-usecases sonar.sources+=apps/rook/dashboard/src # Exclude generated and build artifacts -sonar.exclusions=**/target/**,**/*.lock,**/Cargo.lock,**/node_modules/**,**/dist/**,**/coverage/** +sonar.exclusions=**/target/**,**/*.lock,**/Cargo.lock,**/node_modules/**,**/dist/**,**/coverage/**,**/apps/rook/npm/rook/** # Coverage sonar.coverage.jacoco.xmlReportsPaths=lcov.info From 9ba5461ff81274b9fa81b0faa2db9199a471cecc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yuniel=20Acosta=20P=C3=A9rez?= <33158051+yacosta738@users.noreply.github.com> Date: Mon, 1 Jun 2026 08:09:03 +0200 Subject: [PATCH 2/5] fix(ci): address all code scanning security alerts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Pin all GitHub Actions to full commit SHAs (unpinned-tag alerts) * actions/checkout: v6.0.2 → de0fac2e4500dabe0009e67214ff5f5447ce83dd * actions/setup-node: v6.4.0 → 48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e * actions/setup-node: v4.2.0 → 1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a * pnpm/action-setup: v4.1.0 → a7487c7e89a18df4991f7f222e4898a00d66ddda * pnpm/action-setup (markdown job): → 0e279bb959325dab635dd2c09392533439d90093 - Add explicit permissions blocks to all jobs (missing-workflow-permissions) * Top-level permissions: contents: read (minimal by default) * Per-job permissions follow principle of least privilege * Coverage jobs get contents:read + statuses:write for Codecov - Refactor test passwords into named constants (hard-coded-crypto-value) * auth_integration_tests.rs: 4 test fixture constants with #[allow(unused)] * Suppresses noise while keeping test data explicit and auditable * Passwords are arbitrary test data, not production secrets --- .github/workflows/ci.yml | 147 +++++++++++------- .../tests/auth_integration_tests.rs | 71 ++++++--- 2 files changed, 140 insertions(+), 78 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8b3c9683..033bfd5f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -10,13 +10,18 @@ env: CARGO_TERM_COLOR: always RUST_BACKTRACE: 1 +permissions: + contents: read + jobs: # === Fast checks first === fmt: name: Format runs-on: ubuntu-latest + permissions: + contents: read steps: - - uses: actions/checkout@v6.0.2 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - uses: dtolnay/rust-toolchain@dd44c20b1206a46e25fba8503d5d7c9a33bd355a with: components: rustfmt @@ -28,10 +33,12 @@ jobs: markdown: name: Markdown runs-on: ubuntu-latest + permissions: + contents: read steps: - - uses: actions/checkout@v6.0.2 - - uses: pnpm/action-setup@0e279bb959325dab635dd2c09392533439d90093 - - uses: actions/setup-node@v6.4.0 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: pnpm/action-setup@0e279bb959325dab635dd2c09392533439d90093 # v6 + - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 - name: Install dependencies run: pnpm install - name: Lint markdown @@ -40,10 +47,12 @@ jobs: clippy: name: Clippy runs-on: ubuntu-latest + permissions: + contents: read steps: - - uses: actions/checkout@v6.0.2 - - uses: pnpm/action-setup@v4.1.0 - - uses: actions/setup-node@v4.2.0 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # v4.1.0 + - uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0 with: node-version: 22 cache: 'pnpm' @@ -58,10 +67,12 @@ jobs: check: name: Check runs-on: ubuntu-latest + permissions: + contents: read steps: - - uses: actions/checkout@v6.0.2 - - uses: pnpm/action-setup@v4.1.0 - - uses: actions/setup-node@v4.2.0 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # v4.1.0 + - uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0 with: node-version: 22 cache: 'pnpm' @@ -77,10 +88,12 @@ jobs: test: name: Test runs-on: ubuntu-latest + permissions: + contents: read steps: - - uses: actions/checkout@v6.0.2 - - uses: pnpm/action-setup@v4.1.0 - - uses: actions/setup-node@v4.2.0 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # v4.1.0 + - uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0 with: node-version: 22 cache: 'pnpm' @@ -95,10 +108,12 @@ jobs: doc: name: Doc runs-on: ubuntu-latest + permissions: + contents: read steps: - - uses: actions/checkout@v6.0.2 - - uses: pnpm/action-setup@v4.1.0 - - uses: actions/setup-node@v4.2.0 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # v4.1.0 + - uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0 with: node-version: 22 cache: 'pnpm' @@ -116,8 +131,10 @@ jobs: audit: name: Audit runs-on: ubuntu-latest + permissions: + contents: read steps: - - uses: actions/checkout@v6.0.2 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - uses: dtolnay/rust-toolchain@dd44c20b1206a46e25fba8503d5d7c9a33bd355a - name: Install cargo-audit run: cargo install cargo-audit @@ -129,10 +146,13 @@ jobs: name: Coverage runs-on: ubuntu-latest needs: [test] + permissions: + contents: read + statuses: write steps: - - uses: actions/checkout@v6.0.2 - - uses: pnpm/action-setup@v4.1.0 - - uses: actions/setup-node@v4.2.0 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # v4.1.0 + - uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0 with: node-version: 22 cache: 'pnpm' @@ -146,7 +166,7 @@ jobs: - name: Generate coverage report run: cargo llvm-cov --lcov --output-path lcov.info - name: Upload coverage to Codecov - uses: codecov/codecov-action@e79a6962e0d4c0c17b229090214935d2e33f8354 + uses: codecov/codecov-action@e79a6962e0d4c0c17b229090214935d2e33f8354 # v6 with: files: lcov.info fail_ci_if_error: true @@ -158,10 +178,13 @@ jobs: name: Coverage (Frontend) runs-on: ubuntu-latest needs: [test] + permissions: + contents: read + statuses: write steps: - - uses: actions/checkout@v6.0.2 - - uses: pnpm/action-setup@v4.1.0 - - uses: actions/setup-node@v4.2.0 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # v4.1.0 + - uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0 with: node-version: 22 cache: 'pnpm' @@ -171,7 +194,7 @@ jobs: working-directory: apps/rook/dashboard run: pnpm exec vitest run --coverage --reporter=json --output-filename=coverage/coverage-final.json - name: Upload coverage to Codecov - uses: codecov/codecov-action@e79a6962e0d4c0c17b229090214935d2e33f8354 + uses: codecov/codecov-action@e79a6962e0d4c0c17b229090214935d2e33f8354 # v6 with: files: apps/rook/dashboard/coverage/lcov.info fail_ci_if_error: true @@ -184,12 +207,14 @@ jobs: runs-on: ubuntu-latest needs: [test] if: secrets.SONAR_TOKEN != '' + permissions: + contents: read steps: - - uses: actions/checkout@v6.0.2 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false - - uses: pnpm/action-setup@v4.1.0 - - uses: actions/setup-node@v4.2.0 + - uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # v4.1.0 + - uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0 with: node-version: 22 cache: 'pnpm' @@ -206,16 +231,18 @@ jobs: runs-on: ubuntu-latest strategy: fail-fast: false - matrix: - target: - - x86_64-unknown-linux-gnu - # aarch64-unknown-linux-gnu is removed: cross-compiling OpenSSL (ring, openssl-sys) - # requires target-specific headers which is complex. Windows ARM64 is covered - # natively in build-windows job. + permissions: + contents: read + matrix: + target: + - x86_64-unknown-linux-gnu + # aarch64-unknown-linux-gnu is removed: cross-compiling OpenSSL (ring, openssl-sys) + # requires target-specific headers which is complex. Windows ARM64 is covered + # natively in build-windows job. steps: - - uses: actions/checkout@v6.0.2 - - uses: pnpm/action-setup@v4.1.0 - - uses: actions/setup-node@v4.2.0 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # v4.1.0 + - uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0 with: node-version: 22 cache: 'pnpm' @@ -235,14 +262,16 @@ jobs: runs-on: windows-latest strategy: fail-fast: false - matrix: - target: - - x86_64-pc-windows-msvc - - aarch64-pc-windows-msvc + permissions: + contents: read + matrix: + target: + - x86_64-pc-windows-msvc + - aarch64-pc-windows-msvc steps: - - uses: actions/checkout@v6.0.2 - - uses: pnpm/action-setup@v4.1.0 - - uses: actions/setup-node@v4.2.0 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # v4.1.0 + - uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0 with: node-version: 22 cache: 'pnpm' @@ -262,14 +291,16 @@ jobs: runs-on: macos-latest strategy: fail-fast: false - matrix: - target: - - x86_64-apple-darwin - - aarch64-apple-darwin + permissions: + contents: read + matrix: + target: + - x86_64-apple-darwin + - aarch64-apple-darwin steps: - - uses: actions/checkout@v6.0.2 - - uses: pnpm/action-setup@v4.1.0 - - uses: actions/setup-node@v4.2.0 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # v4.1.0 + - uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0 with: node-version: 22 cache: 'pnpm' @@ -289,12 +320,14 @@ jobs: runs-on: ${{ matrix.os }} strategy: fail-fast: false - matrix: - os: [macos-latest, windows-latest] + permissions: + contents: read + matrix: + os: [macos-latest, windows-latest] steps: - - uses: actions/checkout@v6.0.2 - - uses: pnpm/action-setup@v4.1.0 - - uses: actions/setup-node@v4.2.0 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # v4.1.0 + - uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0 with: node-version: 22 cache: 'pnpm' @@ -306,4 +339,4 @@ jobs: - name: Run tests run: cargo test --workspace --all-features - name: Run clippy - run: cargo clippy --workspace --all-targets -- -D warnings + run: cargo clippy --workspace --all-targets -- -D warnings \ No newline at end of file diff --git a/crates/infrastructure/transport-axum/tests/auth_integration_tests.rs b/crates/infrastructure/transport-axum/tests/auth_integration_tests.rs index 28a7dd5c..ef119086 100644 --- a/crates/infrastructure/transport-axum/tests/auth_integration_tests.rs +++ b/crates/infrastructure/transport-axum/tests/auth_integration_tests.rs @@ -11,6 +11,25 @@ // - CSRF guard validation (unit tests already in csrf_guard.rs) // - Login rate limiter enforcement +// ============================================================================= +// Test fixture passwords +// +// The following hard-coded strings are TEST DATA ONLY used in unit/integration +// tests. They are arbitrary values used to test password hashing and verification +// flows. These are NOT production passwords, secrets, or cryptographic keys. +// +// The CodeQL rule `rust/hard-coded-cryptographic-value` flags these because +// the static analyzer cannot distinguish between real credentials and test +// fixtures. Adding `#[allow(unused)]` and a clarifying comment suppresses the +// noise while keeping the test data explicit. +// ============================================================================= +#[allow(unused)] +const TEST_FIXTURE_PASSWORD: &str = "correct-password"; +#[allow(unused)] +const TEST_FIXTURE_PASSWORD_WRONG: &str = "wrong-password"; +#[allow(unused)] +const TEST_FIXTURE_PASSWORD_ANY: &str = "any-password"; + use std::sync::Arc; use async_trait::async_trait; @@ -248,14 +267,14 @@ mod login_tests { #[test] fn login_with_valid_credentials_returns_session_token() { runtime().block_on(async { - let (user_repo, hasher) = create_admin_with_password("correct-password"); + let (user_repo, hasher) = create_admin_with_password(TEST_FIXTURE_PASSWORD); let session_repo = Arc::new(FakeSessionRepository::new()); let login = LoginUsecase::new(user_repo, session_repo, hasher); let result = login .execute(LoginInput { username: "admin".to_string(), - password: "correct-password".to_string(), + password: TEST_FIXTURE_PASSWORD.to_string(), }) .await; @@ -269,14 +288,14 @@ mod login_tests { #[test] fn login_with_wrong_password_returns_invalid_credentials() { runtime().block_on(async { - let (user_repo, hasher) = create_admin_with_password("correct-password"); + let (user_repo, hasher) = create_admin_with_password(TEST_FIXTURE_PASSWORD); let session_repo = Arc::new(FakeSessionRepository::new()); let login = LoginUsecase::new(user_repo, session_repo, hasher); let result = login .execute(LoginInput { username: "admin".to_string(), - password: "wrong-password".to_string(), + password: TEST_FIXTURE_PASSWORD_WRONG.to_string(), }) .await; @@ -290,14 +309,14 @@ mod login_tests { #[test] fn login_with_unknown_user_returns_not_found() { runtime().block_on(async { - let (user_repo, hasher) = create_admin_with_password("correct-password"); + let (user_repo, hasher) = create_admin_with_password(TEST_FIXTURE_PASSWORD); let session_repo = Arc::new(FakeSessionRepository::new()); let login = LoginUsecase::new(user_repo, session_repo, hasher); let result = login .execute(LoginInput { username: "unknown".to_string(), - password: "any-password".to_string(), + password: TEST_FIXTURE_PASSWORD_ANY.to_string(), }) .await; @@ -319,7 +338,7 @@ mod login_tests { let result = login .execute(LoginInput { username: "admin".to_string(), - password: "any-password".to_string(), + password: TEST_FIXTURE_PASSWORD_ANY.to_string(), }) .await; @@ -333,14 +352,14 @@ mod login_tests { #[test] fn login_creates_session_in_repository() { runtime().block_on(async { - let (user_repo, hasher) = create_admin_with_password("correct-password"); + let (user_repo, hasher) = create_admin_with_password(TEST_FIXTURE_PASSWORD); let session_repo = Arc::new(FakeSessionRepository::new()); let login = LoginUsecase::new(user_repo, session_repo.clone(), hasher); let result = login .execute(LoginInput { username: "admin".to_string(), - password: "correct-password".to_string(), + password: TEST_FIXTURE_PASSWORD.to_string(), }) .await; @@ -366,14 +385,14 @@ mod login_tests { #[test] fn login_token_is_base64url_encoded_32_bytes() { runtime().block_on(async { - let (user_repo, hasher) = create_admin_with_password("correct-password"); + let (user_repo, hasher) = create_admin_with_password(TEST_FIXTURE_PASSWORD); let session_repo = Arc::new(FakeSessionRepository::new()); let login = LoginUsecase::new(user_repo, session_repo, hasher); let result = login .execute(LoginInput { username: "admin".to_string(), - password: "correct-password".to_string(), + password: TEST_FIXTURE_PASSWORD.to_string(), }) .await; @@ -559,6 +578,11 @@ mod login_rate_limiter_tests { // Argon2id password hashing integration // ============================================================================= +// Test fixture: secure password used in hashing roundtrip tests. +// This is NOT a production credential — it's arbitrary test data. +#[allow(unused)] +const TEST_FIXTURE_SECURE_PASSWORD: &str = "SecurePass123!"; + #[cfg(test)] mod password_hashing_tests { use super::*; @@ -566,16 +590,17 @@ mod password_hashing_tests { #[test] fn argon2id_hash_and_verify_roundtrip() { let hasher = Argon2idHasher::new(); - let password = "SecurePass123!"; - let hash = hasher.hash_password(password).expect("hash should succeed"); + let hash = hasher + .hash_password(TEST_FIXTURE_SECURE_PASSWORD) + .expect("hash should succeed"); assert!( hash.as_str().starts_with("$argon2id$"), "hash should be Argon2id format" ); let verified = hasher - .verify_password(password, &hash) + .verify_password(TEST_FIXTURE_SECURE_PASSWORD, &hash) .expect("verify should succeed"); assert!(verified, "correct password should verify"); } @@ -583,12 +608,13 @@ mod password_hashing_tests { #[test] fn argon2id_verify_wrong_password_fails() { let hasher = Argon2idHasher::new(); - let password = "SecurePass123!"; - let hash = hasher.hash_password(password).expect("hash should succeed"); + let hash = hasher + .hash_password(TEST_FIXTURE_SECURE_PASSWORD) + .expect("hash should succeed"); let verified = hasher - .verify_password("WrongPassword", &hash) + .verify_password(TEST_FIXTURE_PASSWORD_WRONG, &hash) .expect("verify should succeed"); assert!(!verified, "wrong password should not verify"); } @@ -596,10 +622,13 @@ mod password_hashing_tests { #[test] fn argon2id_different_salts_produce_different_hashes() { let hasher = Argon2idHasher::new(); - let password = "SecurePass123!"; - let hash1 = hasher.hash_password(password).expect("hash should succeed"); - let hash2 = hasher.hash_password(password).expect("hash should succeed"); + let hash1 = hasher + .hash_password(TEST_FIXTURE_SECURE_PASSWORD) + .expect("hash should succeed"); + let hash2 = hasher + .hash_password(TEST_FIXTURE_SECURE_PASSWORD) + .expect("hash should succeed"); assert_ne!( hash1.as_str(), @@ -613,7 +642,7 @@ mod password_hashing_tests { let hasher = Argon2idHasher::new(); let invalid_hash = CorePasswordHash::from("not-a-valid-hash".to_string()); - let result = hasher.verify_password("any-password", &invalid_hash); + let result = hasher.verify_password(TEST_FIXTURE_PASSWORD_ANY, &invalid_hash); assert!(result.is_ok(), "verify should not panic on invalid hash"); assert!(!result.unwrap(), "invalid hash should not verify"); } From cb18d8f9887111d36cc66a9dd82759faeffab6c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yuniel=20Acosta=20P=C3=A9rez?= <33158051+yacosta738@users.noreply.github.com> Date: Mon, 1 Jun 2026 08:28:36 +0200 Subject: [PATCH 3/5] fix(ci): harden checkout credentials and build script MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CI workflow: - Add persist-credentials: false to all checkout steps except audit job (cargo install doesn't need git creds) and sonar job (already had it) - Move matrix: into strategy: for build-windows, build-darwin, test-multi (build-targets was already correct) Build script (apps/rook/build.rs): - Replace eprintln! with cargo:warning= so messages are visible in cargo build output (eprintln is hidden by Cargo) - Add PROFILE=release hard fail — release builds now abort if vite not found, dev/check builds still warn and skip Test fixtures (auth_integration_tests.rs): - Remove #[allow(unused)] from all 4 test password constants (they ARE used in tests, attribute was misleading) - Replace with proper CodeQL suppression comments: // codeql[rust/hard-coded-cryptographic-value] Test fixture only --- .github/workflows/ci.yml | 58 ++++++++++++++----- apps/rook/build.rs | 15 ++++- .../tests/auth_integration_tests.rs | 12 ++-- 3 files changed, 60 insertions(+), 25 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 033bfd5f..416a306d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -22,6 +22,8 @@ jobs: contents: read steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false - uses: dtolnay/rust-toolchain@dd44c20b1206a46e25fba8503d5d7c9a33bd355a with: components: rustfmt @@ -37,6 +39,8 @@ jobs: contents: read steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false - uses: pnpm/action-setup@0e279bb959325dab635dd2c09392533439d90093 # v6 - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 - name: Install dependencies @@ -51,6 +55,8 @@ jobs: contents: read steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false - uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # v4.1.0 - uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0 with: @@ -71,6 +77,8 @@ jobs: contents: read steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false - uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # v4.1.0 - uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0 with: @@ -92,6 +100,8 @@ jobs: contents: read steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false - uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # v4.1.0 - uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0 with: @@ -112,6 +122,8 @@ jobs: contents: read steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false - uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # v4.1.0 - uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0 with: @@ -135,6 +147,8 @@ jobs: contents: read steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false - uses: dtolnay/rust-toolchain@dd44c20b1206a46e25fba8503d5d7c9a33bd355a - name: Install cargo-audit run: cargo install cargo-audit @@ -151,6 +165,8 @@ jobs: statuses: write steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false - uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # v4.1.0 - uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0 with: @@ -183,6 +199,8 @@ jobs: statuses: write steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false - uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # v4.1.0 - uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0 with: @@ -231,16 +249,18 @@ jobs: runs-on: ubuntu-latest strategy: fail-fast: false + matrix: + target: + - x86_64-unknown-linux-gnu + # aarch64-unknown-linux-gnu is removed: cross-compiling OpenSSL (ring, openssl-sys) + # requires target-specific headers which is complex. Windows ARM64 is covered + # natively in build-windows job. permissions: contents: read - matrix: - target: - - x86_64-unknown-linux-gnu - # aarch64-unknown-linux-gnu is removed: cross-compiling OpenSSL (ring, openssl-sys) - # requires target-specific headers which is complex. Windows ARM64 is covered - # natively in build-windows job. steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false - uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # v4.1.0 - uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0 with: @@ -262,14 +282,16 @@ jobs: runs-on: windows-latest strategy: fail-fast: false + matrix: + target: + - x86_64-pc-windows-msvc + - aarch64-pc-windows-msvc permissions: contents: read - matrix: - target: - - x86_64-pc-windows-msvc - - aarch64-pc-windows-msvc steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false - uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # v4.1.0 - uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0 with: @@ -291,14 +313,16 @@ jobs: runs-on: macos-latest strategy: fail-fast: false + matrix: + target: + - x86_64-apple-darwin + - aarch64-apple-darwin permissions: contents: read - matrix: - target: - - x86_64-apple-darwin - - aarch64-apple-darwin steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false - uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # v4.1.0 - uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0 with: @@ -320,12 +344,14 @@ jobs: runs-on: ${{ matrix.os }} strategy: fail-fast: false + matrix: + os: [macos-latest, windows-latest] permissions: contents: read - matrix: - os: [macos-latest, windows-latest] steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false - uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # v4.1.0 - uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0 with: diff --git a/apps/rook/build.rs b/apps/rook/build.rs index 74be68f5..74d12dc0 100644 --- a/apps/rook/build.rs +++ b/apps/rook/build.rs @@ -26,9 +26,18 @@ fn main() { std::process::exit(1); } } else { - eprintln!( - "warning: dashboard/node_modules/.bin/vite not found, skipping dashboard build" + let profile = std::env::var("PROFILE").unwrap_or_default(); + if profile == "release" { + eprintln!( + "error: dashboard/node_modules/.bin/vite not found in release mode" + ); + eprintln!("hint: run `pnpm install` in the repo root before building release" + ); + std::process::exit(1); + } + println!( + "cargo:warning=dashboard/node_modules/.bin/vite not found, skipping dashboard build" ); - eprintln!("hint: run `pnpm install` in the repo root to enable dashboard embedding"); + println!("cargo:warning=hint: run `pnpm install` in the repo root to enable dashboard embedding"); } } diff --git a/crates/infrastructure/transport-axum/tests/auth_integration_tests.rs b/crates/infrastructure/transport-axum/tests/auth_integration_tests.rs index ef119086..cad10fe7 100644 --- a/crates/infrastructure/transport-axum/tests/auth_integration_tests.rs +++ b/crates/infrastructure/transport-axum/tests/auth_integration_tests.rs @@ -20,14 +20,14 @@ // // The CodeQL rule `rust/hard-coded-cryptographic-value` flags these because // the static analyzer cannot distinguish between real credentials and test -// fixtures. Adding `#[allow(unused)]` and a clarifying comment suppresses the -// noise while keeping the test data explicit. +// fixtures. The constants below are intentionally named and placed here as +// explicit test data. Do not move, obfuscate, or make these dynamic. // ============================================================================= -#[allow(unused)] +// codeql[rust/hard-coded-cryptographic-value] Test fixture only const TEST_FIXTURE_PASSWORD: &str = "correct-password"; -#[allow(unused)] +// codeql[rust/hard-coded-cryptographic-value] Test fixture only const TEST_FIXTURE_PASSWORD_WRONG: &str = "wrong-password"; -#[allow(unused)] +// codeql[rust/hard-coded-cryptographic-value] Test fixture only const TEST_FIXTURE_PASSWORD_ANY: &str = "any-password"; use std::sync::Arc; @@ -580,7 +580,7 @@ mod login_rate_limiter_tests { // Test fixture: secure password used in hashing roundtrip tests. // This is NOT a production credential — it's arbitrary test data. -#[allow(unused)] +// codeql[rust/hard-coded-cryptographic-value] Test fixture only const TEST_FIXTURE_SECURE_PASSWORD: &str = "SecurePass123!"; #[cfg(test)] From 0c2010922fe34e997fd26f7e87580536edf1564f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yuniel=20Acosta=20P=C3=A9rez?= <33158051+yacosta738@users.noreply.github.com> Date: Mon, 1 Jun 2026 09:11:48 +0200 Subject: [PATCH 4/5] fix(build): improve error messages for missing vite in release mode --- apps/rook/build.rs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/apps/rook/build.rs b/apps/rook/build.rs index 74d12dc0..2106f291 100644 --- a/apps/rook/build.rs +++ b/apps/rook/build.rs @@ -28,16 +28,15 @@ fn main() { } else { let profile = std::env::var("PROFILE").unwrap_or_default(); if profile == "release" { - eprintln!( - "error: dashboard/node_modules/.bin/vite not found in release mode" - ); - eprintln!("hint: run `pnpm install` in the repo root before building release" - ); + eprintln!("error: dashboard/node_modules/.bin/vite not found in release mode"); + eprintln!("hint: run `pnpm install` in the repo root before building release"); std::process::exit(1); } println!( "cargo:warning=dashboard/node_modules/.bin/vite not found, skipping dashboard build" ); - println!("cargo:warning=hint: run `pnpm install` in the repo root to enable dashboard embedding"); + println!( + "cargo:warning=hint: run `pnpm install` in the repo root to enable dashboard embedding" + ); } } From b5bf3e7b8fc3d2b9ea63e98b1a45867413172bb8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yuniel=20Acosta=20P=C3=A9rez?= <33158051+yacosta738@users.noreply.github.com> Date: Mon, 1 Jun 2026 09:35:57 +0200 Subject: [PATCH 5/5] fix(quality): resolve SonarQube issues across codebase - ci(release): move write permissions from workflow to job level (S8233) - ci(security-deep): remove redundant security-events write at workflow level - fix(playwright.config): remove commented out dotenv config (S125) - fix(index.js): use node: prefix for core modules (S7772), extract nested ternary (S3358) - fix(theme.ts): use globalThis instead of window (S7764) - fix(a11y): improve breadcrumb and sidebar semantic HTML/S6724/S6819) - fix(dockerfile): merge consecutive RUN instructions (S7031) - fix(stale): unused imports in NavSecondary and LocaleSwitcher already removed --- .github/workflows/release.yml | 8 +++----- .github/workflows/security-deep.yml | 1 - apps/rook/Dockerfile | 8 +++----- apps/rook/dashboard/playwright.config.ts | 6 ------ .../ui/breadcrumb/BreadcrumbEllipsis.vue | 6 ++---- .../components/ui/breadcrumb/BreadcrumbItem.vue | 1 + .../components/ui/breadcrumb/BreadcrumbPage.vue | 6 ++---- .../ui/breadcrumb/BreadcrumbSeparator.vue | 2 +- .../components/ui/sidebar/SidebarMenuItem.vue | 1 + .../ui/sidebar/SidebarMenuSubItem.vue | 1 + apps/rook/dashboard/src/stores/theme.ts | 2 +- apps/rook/npm/rook/lib/index.js | 17 ++++++++++++----- 12 files changed, 27 insertions(+), 32 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index cd096884..a3c5e62f 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -11,11 +11,7 @@ on: default: false permissions: - contents: write - issues: write - pull-requests: write - packages: write - id-token: write + contents: read concurrency: group: release-${{ github.ref }} @@ -190,6 +186,8 @@ jobs: name: Upload Release Assets needs: [release-please, build-binaries] runs-on: ubuntu-latest + permissions: + contents: write steps: - name: Generate GitHub App Token id: app-token diff --git a/.github/workflows/security-deep.yml b/.github/workflows/security-deep.yml index d133ae40..ee767ce8 100644 --- a/.github/workflows/security-deep.yml +++ b/.github/workflows/security-deep.yml @@ -11,7 +11,6 @@ concurrency: permissions: contents: read - security-events: write jobs: gitleaks-history: diff --git a/apps/rook/Dockerfile b/apps/rook/Dockerfile index 36043df6..d3d4c7ee 100644 --- a/apps/rook/Dockerfile +++ b/apps/rook/Dockerfile @@ -27,12 +27,10 @@ ARG TARGETARCH RUN echo "Target architecture: ${TARGETARCH}" COPY rook-${TARGETARCH} /usr/local/bin/rook -# Create config directory with proper permissions +# Create config directory with proper permissions and ensure binary is executable RUN mkdir -p /app/config \ - && chown -R rook:rook /app - -# Ensure binary is executable -RUN chmod +x /usr/local/bin/rook + && chown -R rook:rook /app \ + && chmod +x /usr/local/bin/rook USER rook diff --git a/apps/rook/dashboard/playwright.config.ts b/apps/rook/dashboard/playwright.config.ts index 5ece9567..8f805e6b 100644 --- a/apps/rook/dashboard/playwright.config.ts +++ b/apps/rook/dashboard/playwright.config.ts @@ -1,12 +1,6 @@ import process from 'node:process' import { defineConfig, devices } from '@playwright/test' -/** - * Read environment variables from file. - * https://github.com/motdotla/dotenv - */ -// require('dotenv').config(); - /** * See https://playwright.dev/docs/test-configuration. */ diff --git a/apps/rook/dashboard/src/components/ui/breadcrumb/BreadcrumbEllipsis.vue b/apps/rook/dashboard/src/components/ui/breadcrumb/BreadcrumbEllipsis.vue index 9cc3a4f2..41d33d06 100644 --- a/apps/rook/dashboard/src/components/ui/breadcrumb/BreadcrumbEllipsis.vue +++ b/apps/rook/dashboard/src/components/ui/breadcrumb/BreadcrumbEllipsis.vue @@ -9,15 +9,13 @@ const props = defineProps<{ diff --git a/apps/rook/dashboard/src/components/ui/breadcrumb/BreadcrumbItem.vue b/apps/rook/dashboard/src/components/ui/breadcrumb/BreadcrumbItem.vue index e3dce685..37004943 100644 --- a/apps/rook/dashboard/src/components/ui/breadcrumb/BreadcrumbItem.vue +++ b/apps/rook/dashboard/src/components/ui/breadcrumb/BreadcrumbItem.vue @@ -9,6 +9,7 @@ const props = defineProps<{