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..." @echo "Cleaning up vendored assets from working tree..."
@rm -rf hate_crack/hashcat hate_crack/hashcat-utils hate_crack/princeprocessor hate_crack/omen @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..." @echo "Detecting OS and installing dependencies..."
@if [ "$(shell uname)" = "Darwin" ]; then \ @if [ "$(shell uname)" = "Darwin" ]; then \
echo "Detected macOS"; \ 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; } @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 . @uv tool install -e .
update: submodules vendor-assets update: submodules
@uv tool install -e . --force --reinstall @uv tool install -e . --force --reinstall
reinstall: uninstall install reinstall: uninstall install

View File

@@ -151,6 +151,13 @@ elif os.path.isdir(os.path.join(_repo_root, "hashcat-utils")):
hate_path = _repo_root hate_path = _repo_root
else: else:
hate_path = _package_path 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() _config_path = _resolve_config_path()
if not _config_path: if not _config_path:
print("Initializing config.json from config.json.example") print("Initializing config.json from config.json.example")
@@ -727,17 +734,17 @@ if not SKIP_INIT:
print("LLM attacks will not be available.") print("LLM attacks will not be available.")
# Verify OMEN binaries (optional, for OMEN attack) # Verify OMEN binaries (optional, for OMEN attack)
omen_create_path = os.path.join(hate_path, "omen", hcatOmenCreateBin) omen_create_path = os.path.join(_omen_dir, hcatOmenCreateBin)
omen_enum_path = os.path.join(hate_path, "omen", hcatOmenEnumBin) omen_enum_path = os.path.join(_omen_dir, hcatOmenEnumBin)
try: try:
ensure_binary( ensure_binary(
omen_create_path, omen_create_path,
build_dir=os.path.join(hate_path, "omen"), build_dir=_omen_dir,
name="OMEN createNG", name="OMEN createNG",
) )
ensure_binary( ensure_binary(
omen_enum_path, omen_enum_path,
build_dir=os.path.join(hate_path, "omen"), build_dir=_omen_dir,
name="OMEN enumNG", name="OMEN enumNG",
) )
except SystemExit: except SystemExit:
@@ -2173,7 +2180,7 @@ def _omen_model_dir():
# OMEN Attack - Train model # OMEN Attack - Train model
def hcatOmenTrain(training_file): def hcatOmenTrain(training_file):
omen_dir = os.path.join(hate_path, "omen") omen_dir = _omen_dir
create_bin = os.path.join(omen_dir, hcatOmenCreateBin) create_bin = os.path.join(omen_dir, hcatOmenCreateBin)
if not os.path.isfile(create_bin): if not os.path.isfile(create_bin):
print(f"Error: OMEN createNG binary not found: {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 # OMEN Attack - Generate candidates and pipe to hashcat
def hcatOmen(hcatHashType, hcatHashFile, max_candidates): def hcatOmen(hcatHashType, hcatHashFile, max_candidates):
global hcatProcess global hcatProcess
omen_dir = os.path.join(hate_path, "omen") omen_dir = _omen_dir
enum_bin = os.path.join(omen_dir, hcatOmenEnumBin) enum_bin = os.path.join(omen_dir, hcatOmenEnumBin)
if not os.path.isfile(enum_bin): if not os.path.isfile(enum_bin):
print(f"Error: OMEN enumNG binary not found: {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] [tool.setuptools.package-data]
hate_crack = [ hate_crack = [
"config.json.example", "config.json.example",
"hashcat-utils/**",
"princeprocessor/**",
"omen/**",
] ]
[tool.setuptools_scm] [tool.setuptools_scm]
@@ -61,9 +58,8 @@ exclude = [
"wordlists/", "wordlists/",
"HashcatRosetta/", "HashcatRosetta/",
"hashcat-utils/", "hashcat-utils/",
"hate_crack/hashcat-utils/", "omen/",
"hate_crack/omen/", "princeprocessor/",
"hate_crack/princeprocessor/",
] ]
[tool.ty.rules] [tool.ty.rules]

View File

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