fix: resolve OMEN binary path from repo root as fallback

In dev checkouts where submodules are built in the repo root rather than
vendored into hate_path, OMEN binaries were not found. Introduces _omen_dir
that checks hate_path/omen first and falls back to the repo root omen dir.
Also removes vendor-assets from install/update targets and drops vendored
submodule paths from pyproject.toml package data.
This commit is contained in:
Justin Bollinger
2026-03-10 12:28:14 -04:00
parent 5b0c119ec0
commit 0f141892b7
4 changed files with 29 additions and 18 deletions

View File

@@ -81,7 +81,7 @@ clean-vendor:
@echo "Cleaning up vendored assets from working tree..."
@rm -rf hate_crack/hashcat hate_crack/hashcat-utils hate_crack/princeprocessor hate_crack/omen
install: submodules vendor-assets
install: submodules
@echo "Detecting OS and installing dependencies..."
@if [ "$(shell uname)" = "Darwin" ]; then \
echo "Detected macOS"; \
@@ -105,7 +105,7 @@ install: submodules vendor-assets
@command -v uv >/dev/null 2>&1 || { echo "uv not found. Installing uv..."; curl -LsSf https://astral.sh/uv/install.sh | sh; }
@uv tool install -e .
update: submodules vendor-assets
update: submodules
@uv tool install -e . --force --reinstall
reinstall: uninstall install

View File

@@ -151,6 +151,13 @@ elif os.path.isdir(os.path.join(_repo_root, "hashcat-utils")):
hate_path = _repo_root
else:
hate_path = _package_path
# omen may not be vendored into hate_path (e.g. dev checkout with only some submodules built).
# Check hate_path first, then fall back to repo root.
_omen_dir = (
os.path.join(hate_path, "omen")
if os.path.isdir(os.path.join(hate_path, "omen"))
else os.path.join(_repo_root, "omen")
)
_config_path = _resolve_config_path()
if not _config_path:
print("Initializing config.json from config.json.example")
@@ -727,17 +734,17 @@ if not SKIP_INIT:
print("LLM attacks will not be available.")
# Verify OMEN binaries (optional, for OMEN attack)
omen_create_path = os.path.join(hate_path, "omen", hcatOmenCreateBin)
omen_enum_path = os.path.join(hate_path, "omen", hcatOmenEnumBin)
omen_create_path = os.path.join(_omen_dir, hcatOmenCreateBin)
omen_enum_path = os.path.join(_omen_dir, hcatOmenEnumBin)
try:
ensure_binary(
omen_create_path,
build_dir=os.path.join(hate_path, "omen"),
build_dir=_omen_dir,
name="OMEN createNG",
)
ensure_binary(
omen_enum_path,
build_dir=os.path.join(hate_path, "omen"),
build_dir=_omen_dir,
name="OMEN enumNG",
)
except SystemExit:
@@ -2173,7 +2180,7 @@ def _omen_model_dir():
# OMEN Attack - Train model
def hcatOmenTrain(training_file):
omen_dir = os.path.join(hate_path, "omen")
omen_dir = _omen_dir
create_bin = os.path.join(omen_dir, hcatOmenCreateBin)
if not os.path.isfile(create_bin):
print(f"Error: OMEN createNG binary not found: {create_bin}")
@@ -2217,7 +2224,7 @@ def hcatOmenTrain(training_file):
# OMEN Attack - Generate candidates and pipe to hashcat
def hcatOmen(hcatHashType, hcatHashFile, max_candidates):
global hcatProcess
omen_dir = os.path.join(hate_path, "omen")
omen_dir = _omen_dir
enum_bin = os.path.join(omen_dir, hcatOmenEnumBin)
if not os.path.isfile(enum_bin):
print(f"Error: OMEN enumNG binary not found: {enum_bin}")

View File

@@ -32,9 +32,6 @@ include = ["hate_crack*"]
[tool.setuptools.package-data]
hate_crack = [
"config.json.example",
"hashcat-utils/**",
"princeprocessor/**",
"omen/**",
]
[tool.setuptools_scm]
@@ -61,9 +58,8 @@ exclude = [
"wordlists/",
"HashcatRosetta/",
"hashcat-utils/",
"hate_crack/hashcat-utils/",
"hate_crack/omen/",
"hate_crack/princeprocessor/",
"omen/",
"princeprocessor/",
]
[tool.ty.rules]

View File

@@ -23,6 +23,8 @@ class TestHcatOmenTrain:
model_dir.mkdir()
with patch.object(main_module, "hate_path", str(tmp_path)), patch.object(
main_module, "_omen_dir", str(omen_dir)
), patch.object(
main_module, "hcatOmenCreateBin", "createNG"
), patch(
"hate_crack.main._omen_model_dir", return_value=str(model_dir)
@@ -58,8 +60,8 @@ class TestHcatOmenTrain:
training_file.write_text("test\n")
with patch.object(main_module, "hate_path", str(tmp_path)), patch.object(
main_module, "hcatOmenCreateBin", "createNG"
):
main_module, "_omen_dir", str(tmp_path / "omen")
), patch.object(main_module, "hcatOmenCreateBin", "createNG"):
main_module.hcatOmenTrain(str(training_file))
captured = capsys.readouterr()
assert "createNG binary not found" in captured.out
@@ -73,6 +75,8 @@ class TestHcatOmenTrain:
model_dir.mkdir()
with patch.object(main_module, "hate_path", str(tmp_path)), patch.object(
main_module, "_omen_dir", str(omen_dir)
), patch.object(
main_module, "hcatOmenCreateBin", "createNG"
), patch("hate_crack.main._omen_model_dir", return_value=str(model_dir)):
main_module.hcatOmenTrain("/nonexistent/file.txt")
@@ -92,6 +96,8 @@ class TestHcatOmen:
(model_dir / "createConfig").write_text("# test config\n")
with patch.object(main_module, "hate_path", str(tmp_path)), patch.object(
main_module, "_omen_dir", str(omen_dir)
), patch.object(
main_module, "hcatOmenEnumBin", "enumNG"
), patch.object(main_module, "hcatBin", "hashcat"), patch.object(
main_module, "hcatTuning", "--force"
@@ -132,8 +138,8 @@ class TestHcatOmen:
def test_missing_binary(self, main_module, tmp_path, capsys):
with patch.object(main_module, "hate_path", str(tmp_path)), patch.object(
main_module, "hcatOmenEnumBin", "enumNG"
):
main_module, "_omen_dir", str(tmp_path / "omen")
), patch.object(main_module, "hcatOmenEnumBin", "enumNG"):
main_module.hcatOmen("1000", "/tmp/hashes.txt", 500000)
captured = capsys.readouterr()
assert "enumNG binary not found" in captured.out
@@ -149,6 +155,8 @@ class TestHcatOmen:
# No createConfig in model_dir
with patch.object(main_module, "hate_path", str(tmp_path)), patch.object(
main_module, "_omen_dir", str(omen_dir)
), patch.object(
main_module, "hcatOmenEnumBin", "enumNG"
), patch("hate_crack.main._omen_model_dir", return_value=str(model_dir)):
main_module.hcatOmen("1000", "/tmp/hashes.txt", 500000)