Files
hate_crack/pyproject.toml
T
c04c111af1 feat: e2e tests for non-interactive CLI subcommands (#164)
* feat: add e2e test suite skeleton and shared fixtures

New tests/e2e/ subpackage for a real-subprocess, real-hashcat CLI
end-to-end suite, gated behind HATE_CRACK_HASHCAT_REAL=1 (never runs in
standard CI — ubuntu-latest CI runners have no hashcat installed).
Adds shared fixtures: e2e_home (HOME-isolated config, since
_candidate_roots() doesn't search cwd), e2e_hash_file (NTLM hashes for
three known plaintexts), e2e_wordlist/e2e_wordlist_no_target,
e2e_rules_dir, plus a preflight fixture that skips with an actionable
message on missing binaries or an unisolatable local config.json.

* feat: e2e tests for the 4 non-interactive CLI subcommands

Real subprocess + real hashcat coverage for quick/dict/brute/topmask,
plus a harness smoke test proving the suite can tell "ran clean, zero
cracks" apart from "actually cracked something" (test_harness_smoke_*).

* fix: pure-Python MD4 for e2e NTLM fixture (hashlib md4 unavailable)

hashlib.new("md4", ...) raises ValueError/UnsupportedDigestmodError on
OpenSSL 3.x builds that don't load the legacy provider (confirmed on
real developer hardware — uv's managed Python, backed by Homebrew's
OpenSSL 3.6.2, has no MD4 at all; only the platform's separately
bundled /usr/bin/python3 happened to work, which nothing in this
suite's subprocess calls actually uses). Replaced with a small,
dependency-free pure-Python MD4 (RFC 1320) verified against the
"password"/empty-string NTLM test vectors and cross-checked by having
real hashcat crack a hash this helper computes.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-28 22:36:22 -04:00

117 lines
2.8 KiB
TOML

[build-system]
requires = ["setuptools>=83.0.0", "setuptools-scm>=10.2.1"]
build-backend = "setuptools.build_meta"
[project]
name = "hate_crack"
dynamic = ["version"]
description = "Menu driven Python wrapper for hashcat"
readme = "README.md"
requires-python = ">=3.13"
dependencies = [
"requests>=2.34.2",
"openpyxl>=3.0.0",
"packaging>=26.2",
"simple-term-menu==1.6.6",
"click>=8.4.2",
"atomic-agents>=2.9.1",
# Imported directly by hate_crack/llm.py; declared explicitly rather than
# relying on atomic-agents pulling them in transitively.
"instructor>=1.14.5",
"openai>=2.49.0",
"pydantic>=2.13.4",
]
[project.scripts]
hate_crack = "hate_crack.__main__:main"
[tool.setuptools.packages.find]
include = ["hate_crack*"]
[tool.setuptools.package-data]
hate_crack = [
"config.json.example",
]
[tool.setuptools_scm]
version_scheme = "no-guess-dev"
local_scheme = "no-local-version"
[tool.ruff]
exclude = [
"build",
"dist",
"PACK",
"hashcat-utils",
"omen",
"princeprocessor",
"wordlists",
"rules",
]
[tool.ruff.lint]
# Pin to the pre-0.16.0 default rule set so future ruff bumps stay
# behaviour-neutral. Broadening the ruleset is a separate cleanup, not
# a dep-bump side effect.
select = ["E4", "E7", "E9", "F"]
[tool.bandit]
# hate_crack shells out to hashcat and its helper binaries extensively, so the
# scan produces many low-severity subprocess/shlex findings. These are reviewed
# and captured in .bandit-baseline.json; CI compares against that baseline so
# only NEW findings fail the build (mirrors the hashview approach). Scan the
# first-party package only — bundled third-party trees are excluded.
exclude_dirs = [
"tests",
".venv",
"build",
"dist",
"PACK",
"hashcat-utils",
"omen",
"princeprocessor",
]
[tool.ty.src]
exclude = [
"build/",
"dist/",
"PACK/",
"wordlists/",
"HashcatRosetta/",
"hashcat-utils/",
"omen/",
"princeprocessor/",
]
[tool.ty.rules]
# Module-level globals in main.py are assigned at runtime
unresolved-reference = "warn"
# Optional deps (hashcat_rosetta) not always installed
unresolved-import = "warn"
# Module-level globals and dynamic attribute access
unresolved-attribute = "warn"
invalid-argument-type = "warn"
# ty 0.0.63 tightened these to error for the same legacy pattern
# (module-level `hcatHashFile = None` etc. in main.py, later used as
# strings). Downgrade to warn to match the rest.
unsupported-operator = "warn"
no-matching-overload = "warn"
invalid-assignment = "warn"
unresolved-global = "warn"
[tool.pytest.ini_options]
testpaths = [
"tests",
]
[dependency-groups]
dev = [
"ty==0.0.64",
"ruff==0.16.0",
"pytest==9.0.3",
"pytest-cov==7.1.0",
"pytest-timeout>=2.4.0",
"pexpect>=4.9.0",
]