mirror of
https://github.com/trustedsec/hate_crack.git
synced 2026-03-12 21:23:05 -07:00
feat: add Lima VM E2E tests and fix princeprocessor build
Add Ubuntu 24.04 Lima VM test track that runs hate_crack installation end-to-end in a real VM, giving higher confidence than Docker-based tests. - Add lima/hate-crack-test.yaml: Ubuntu 24.04 VM config with hashcat and build deps pre-installed via apt; uv installed via official installer - Add tests/test_lima_vm_install.py: mirrors Docker E2E test structure; uses rsync with targeted excludes (wordlists, compiled host binaries) and builds wheel directly to avoid setuptools-scm sdist file filtering - Fix Makefile: add princeprocessor build step with aarch64-compatible CFLAGS (drops -m64); copy binary to submodule root for vendor-assets - Add Lima tests to prek.toml pre-push hook - Document Lima VM tests in TESTING.md Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
6
Makefile
6
Makefile
@@ -16,6 +16,12 @@ submodules:
|
||||
echo "hashcat already installed in PATH, skipping submodule compilation"; \
|
||||
continue; \
|
||||
fi; \
|
||||
if [ "$$path" = "princeprocessor" ]; then \
|
||||
$(MAKE) -C "$$path/src" CFLAGS_LINUX64="-W -Wall -std=c99 -O2 -s -DLINUX"; \
|
||||
if [ -f "$$path/src/pp64.bin" ]; then cp "$$path/src/pp64.bin" "$$path/"; \
|
||||
elif [ -f "$$path/src/ppAppleArm64.bin" ]; then cp "$$path/src/ppAppleArm64.bin" "$$path/pp64.bin"; fi; \
|
||||
continue; \
|
||||
fi; \
|
||||
if [ -f "$$path/Makefile" ] || [ -f "$$path/makefile" ]; then \
|
||||
$(MAKE) -C "$$path"; \
|
||||
fi; \
|
||||
|
||||
26
TESTING.md
26
TESTING.md
@@ -90,6 +90,7 @@ By default, external service checks are skipped. Enable them explicitly:
|
||||
- `HATE_CRACK_RUN_LIVE_HASHVIEW_TESTS=1` — run live Hashview wordlist upload tests
|
||||
- `HATE_CRACK_RUN_E2E=1` — run end-to-end local installation tests
|
||||
- `HATE_CRACK_RUN_DOCKER_TESTS=1` — run Docker-based end-to-end tests
|
||||
- `HATE_CRACK_RUN_LIMA_TESTS=1` — run Lima VM-based end-to-end tests (requires Lima installed)
|
||||
|
||||
When `HASHMOB_TEST_REAL` is enabled, tests will still skip if Hashmob returns errors like HTTP 523 (origin unreachable).
|
||||
|
||||
@@ -110,6 +111,7 @@ Highlights:
|
||||
7. UI menu options (all attack modes)
|
||||
8. Hashcat-utils submodule verification
|
||||
9. Docker and E2E installation tests (opt-in)
|
||||
10. Lima VM installation tests (opt-in)
|
||||
|
||||
## Benefits
|
||||
|
||||
@@ -151,8 +153,32 @@ HATE_CRACK_RUN_E2E=1 uv run pytest tests/test_e2e_local_install.py -v
|
||||
|
||||
# Run Docker tests
|
||||
HATE_CRACK_RUN_DOCKER_TESTS=1 uv run pytest tests/test_docker_script_install.py -v
|
||||
|
||||
# Run Lima VM tests
|
||||
# Prerequisite: brew install lima
|
||||
HATE_CRACK_RUN_LIMA_TESTS=1 uv run pytest tests/test_lima_vm_install.py -v
|
||||
```
|
||||
|
||||
## Lima VM Tests
|
||||
|
||||
`tests/test_lima_vm_install.py` runs hate_crack inside a real Ubuntu 24.04 VM via [Lima](https://lima-vm.io/). Unlike the Docker tests, this exercises a real kernel and full Ubuntu userspace, giving higher confidence that installation works on the distros users actually run.
|
||||
|
||||
**Prerequisites:**
|
||||
|
||||
```bash
|
||||
brew install lima
|
||||
```
|
||||
|
||||
**Run:**
|
||||
|
||||
```bash
|
||||
HATE_CRACK_RUN_LIMA_TESTS=1 uv run pytest tests/test_lima_vm_install.py -v
|
||||
```
|
||||
|
||||
**Note:** The first run takes several minutes - the VM provision script runs `apt-get install` for hashcat and all build dependencies. Subsequent runs on the same machine are faster if Lima caches the base image.
|
||||
|
||||
The VM is created with a unique name per test session and deleted automatically in teardown. To verify cleanup: `limactl list`.
|
||||
|
||||
## Note on Real API Testing
|
||||
|
||||
While these mocked tests validate the code logic, you may still want to occasionally run integration tests against a real Hashview instance to ensure the API hasn't changed. The test files can be easily modified to toggle between mocked and real API calls if needed.
|
||||
|
||||
41
lima/hate-crack-test.yaml
Normal file
41
lima/hate-crack-test.yaml
Normal file
@@ -0,0 +1,41 @@
|
||||
# Lima VM configuration for hate_crack E2E testing
|
||||
# Ubuntu 24.04 LTS with hashcat and build dependencies pre-installed.
|
||||
# Usage: limactl start --name hate-crack-e2e lima/hate-crack-test.yaml
|
||||
|
||||
images:
|
||||
- location: "https://cloud-images.ubuntu.com/releases/24.04/release/ubuntu-24.04-server-cloudimg-amd64.img"
|
||||
arch: "x86_64"
|
||||
- location: "https://cloud-images.ubuntu.com/releases/24.04/release/ubuntu-24.04-server-cloudimg-arm64.img"
|
||||
arch: "aarch64"
|
||||
|
||||
cpus: 2
|
||||
memory: "4GiB"
|
||||
disk: "20GiB"
|
||||
|
||||
# No host mounts - full isolation mirrors a real user install
|
||||
mounts: []
|
||||
|
||||
provision:
|
||||
- mode: system
|
||||
script: |
|
||||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
export DEBIAN_FRONTEND=noninteractive
|
||||
apt-get update -qq
|
||||
apt-get install -y --no-install-recommends \
|
||||
build-essential \
|
||||
ca-certificates \
|
||||
curl \
|
||||
git \
|
||||
gzip \
|
||||
hashcat \
|
||||
ocl-icd-libopencl1 \
|
||||
pocl-opencl-icd \
|
||||
p7zip-full \
|
||||
transmission-cli
|
||||
|
||||
- mode: user
|
||||
script: |
|
||||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
curl -LsSf https://astral.sh/uv/install.sh | sh
|
||||
@@ -3,6 +3,7 @@ commands = [
|
||||
"uv run ruff check hate_crack",
|
||||
"uv run ty check hate_crack",
|
||||
"HATE_CRACK_SKIP_INIT=1 uv run pytest -q",
|
||||
"HATE_CRACK_RUN_LIMA_TESTS=1 uv run pytest tests/test_lima_vm_install.py -v",
|
||||
]
|
||||
|
||||
[hooks.post-commit]
|
||||
|
||||
156
tests/test_lima_vm_install.py
Normal file
156
tests/test_lima_vm_install.py
Normal file
@@ -0,0 +1,156 @@
|
||||
import os
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
import uuid
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
|
||||
def _require_lima():
|
||||
if os.environ.get("HATE_CRACK_RUN_LIMA_TESTS") != "1":
|
||||
pytest.skip("Set HATE_CRACK_RUN_LIMA_TESTS=1 to run Lima VM tests.")
|
||||
if shutil.which("limactl") is None:
|
||||
pytest.skip("limactl not available")
|
||||
|
||||
|
||||
@pytest.fixture(scope="session")
|
||||
def lima_vm():
|
||||
_require_lima()
|
||||
repo_root = Path(__file__).resolve().parents[1]
|
||||
vm_name = f"hate-crack-e2e-{uuid.uuid4().hex[:8]}"
|
||||
yaml_path = str(repo_root / "lima" / "hate-crack-test.yaml")
|
||||
|
||||
try:
|
||||
start = subprocess.run(
|
||||
["limactl", "start", "--name", vm_name, yaml_path],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
timeout=300,
|
||||
)
|
||||
except subprocess.TimeoutExpired as exc:
|
||||
pytest.fail(f"limactl start timed out after {exc.timeout}s")
|
||||
|
||||
assert start.returncode == 0, (
|
||||
f"limactl start failed. stdout={start.stdout} stderr={start.stderr}"
|
||||
)
|
||||
|
||||
ssh_config = Path.home() / ".lima" / vm_name / "ssh.config"
|
||||
# Use rsync directly to exclude large runtime-only directories that aren't
|
||||
# needed for installation (wordlists, crack results, the hashcat binary -
|
||||
# the VM has hashcat installed via apt).
|
||||
rsync_cmd = [
|
||||
"rsync", "-a", "--delete",
|
||||
"--exclude=wordlists/",
|
||||
"--exclude=hashcat/",
|
||||
"--exclude=results/",
|
||||
"--exclude=*.pot",
|
||||
"--exclude=*.ntds",
|
||||
"--exclude=*.ntds.*",
|
||||
# Exclude host-compiled binaries so the VM always builds from source.
|
||||
# Keep the bin/ dir itself (empty is fine); make clean recreates it anyway.
|
||||
"--exclude=princeprocessor/*.bin",
|
||||
"--exclude=princeprocessor/src/*.bin",
|
||||
"--exclude=hashcat-utils/bin/*.bin",
|
||||
"--exclude=hashcat-utils/bin/*.exe",
|
||||
"--exclude=hashcat-utils/bin/*.app",
|
||||
"-e", f"ssh -F {ssh_config}",
|
||||
f"{repo_root}/",
|
||||
f"lima-{vm_name}:/tmp/hate_crack/",
|
||||
]
|
||||
try:
|
||||
copy = subprocess.run(
|
||||
rsync_cmd,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
timeout=120,
|
||||
)
|
||||
except subprocess.TimeoutExpired as exc:
|
||||
pytest.fail(f"rsync copy timed out after {exc.timeout}s")
|
||||
|
||||
assert copy.returncode == 0, (
|
||||
f"rsync copy failed. stdout={copy.stdout} stderr={copy.stderr}"
|
||||
)
|
||||
|
||||
install_cmd = (
|
||||
"cd /tmp/hate_crack && "
|
||||
"make submodules vendor-assets && "
|
||||
# Build the wheel directly (skips sdist) so freshly-compiled binaries
|
||||
# in hate_crack/hashcat-utils/bin/ are included via package-data.
|
||||
"rm -rf dist && "
|
||||
"$HOME/.local/bin/uv build --wheel && "
|
||||
"$HOME/.local/bin/uv tool install dist/hate_crack-*.whl && "
|
||||
"make clean-vendor"
|
||||
)
|
||||
try:
|
||||
install = subprocess.run(
|
||||
["limactl", "shell", vm_name, "--", "bash", "-lc", install_cmd],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
timeout=600,
|
||||
)
|
||||
except subprocess.TimeoutExpired as exc:
|
||||
pytest.fail(f"Installation timed out after {exc.timeout}s")
|
||||
|
||||
assert install.returncode == 0, (
|
||||
f"Installation failed. stdout={install.stdout} stderr={install.stderr}"
|
||||
)
|
||||
|
||||
yield vm_name
|
||||
|
||||
try:
|
||||
result = subprocess.run(
|
||||
["limactl", "delete", "--force", vm_name],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
timeout=60,
|
||||
)
|
||||
if result.returncode != 0:
|
||||
print(
|
||||
f"Warning: Failed to delete Lima VM {vm_name}. stderr={result.stderr}",
|
||||
file=sys.stderr,
|
||||
)
|
||||
except Exception as e:
|
||||
print(
|
||||
f"Warning: Exception while deleting Lima VM {vm_name}: {e}",
|
||||
file=sys.stderr,
|
||||
)
|
||||
|
||||
|
||||
def _run_vm(vm_name, command, timeout=180):
|
||||
try:
|
||||
run = subprocess.run(
|
||||
["limactl", "shell", vm_name, "--", "bash", "-lc", command],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
timeout=timeout,
|
||||
)
|
||||
except subprocess.TimeoutExpired as exc:
|
||||
pytest.fail(f"Lima VM command timed out after {exc.timeout}s")
|
||||
return run
|
||||
|
||||
|
||||
def test_lima_vm_install_and_run(lima_vm):
|
||||
run = _run_vm(
|
||||
lima_vm,
|
||||
"cd /tmp/hate_crack && $HOME/.local/bin/hate_crack --help && ./hate_crack.py --help",
|
||||
timeout=120,
|
||||
)
|
||||
assert run.returncode == 0, (
|
||||
f"Lima VM install/run failed. stdout={run.stdout} stderr={run.stderr}"
|
||||
)
|
||||
|
||||
|
||||
def test_lima_hashcat_cracks_simple_password(lima_vm):
|
||||
command = (
|
||||
"set -euo pipefail; "
|
||||
"printf 'password\\nletmein\\n123456\\n' > /tmp/wordlist.txt; "
|
||||
"echo 5f4dcc3b5aa765d61d8327deb882cf99 > /tmp/hash.txt; "
|
||||
"hashcat -m 0 -a 0 --potfile-disable -o /tmp/out.txt /tmp/hash.txt /tmp/wordlist.txt --quiet; "
|
||||
"grep -q ':password' /tmp/out.txt"
|
||||
)
|
||||
run = _run_vm(lima_vm, command, timeout=180)
|
||||
assert run.returncode == 0, (
|
||||
f"Lima VM hashcat crack failed. stdout={run.stdout} stderr={run.stderr}"
|
||||
)
|
||||
Reference in New Issue
Block a user