[project] name = "dropkit" version = "0.1.0" description = "Manage DigitalOcean droplets for ToB engineers" readme = "README.md" requires-python = ">=3.11" authors = [{name = "Trail of Bits", email = "opensource@trailofbits.com"}] license = {text = "Apache-2.0"} keywords = ["digitalocean", "droplet", "cli", "devops", "ssh", "tailscale", "cloud"] classifiers = [ "Development Status :: 4 - Beta", "Environment :: Console", "Intended Audience :: Developers", "License :: OSI Approved :: Apache Software License", "Operating System :: MacOS", "Operating System :: POSIX :: Linux", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Topic :: System :: Systems Administration", ] dependencies = [ "typer>=0.9.0", "rich>=13.0.0", "requests>=2.31.0", "pyyaml>=6.0.1", "jinja2>=3.1.0", "shellingham>=1.5.0", "pydantic>=2.12.3", "cryptography>=46.0.3", ] [project.scripts] dropkit = "dropkit.main:app" [project.urls] Homepage = "https://github.com/trailofbits/dropkit" Repository = "https://github.com/trailofbits/dropkit" Issues = "https://github.com/trailofbits/dropkit/issues" [tool.uv] package = true default-groups = ["dev"] [build-system] requires = ["hatchling"] build-backend = "hatchling.build" [tool.hatch.build.hooks.custom] [tool.hatch.build.targets.wheel] packages = ["dropkit"] [tool.hatch.build.targets.wheel.force-include] "dropkit/_version.txt" = "dropkit/_version.txt" [tool.hatch.build.targets.sdist] [tool.hatch.build.targets.sdist.force-include] "dropkit/_version.txt" = "dropkit/_version.txt" [dependency-groups] dev = [ "jsonschema>=4.26.0", "pytest>=9.0.3", "pytest-cov", "ruff>=0.8.0", "ty", {include-group = "audit"}, ] audit = ["pip-audit"] [tool.ruff] target-version = "py311" line-length = 100 [tool.ruff.format] quote-style = "double" indent-style = "space" line-ending = "auto" [tool.ruff.lint] select = ["ALL"] ignore = [ # Documentation "D", # pydocstyle - skip for existing code # Formatter conflicts "COM812", # missing trailing comma "ISC001", # implicit string concat # Line length (handled by formatter) "E501", # Exception handling style (CLI prefers clean messages) "B904", # raise ... from err "TRY003", # avoid specifying long messages outside exception class "EM101", # exception must not use string literal "EM102", # exception must not use f-string literal "BLE001", # blind exception catching (acceptable in CLI error handling) # Type annotations (existing code not fully annotated) "ANN", # flake8-annotations # Boolean arguments (common in CLI tools) "FBT001", # boolean positional arg in function definition "FBT002", # boolean default value in function definition "FBT003", # boolean positional value in function call # Magic values (acceptable in existing code) "PLR2004", # Import organization (acceptable for lazy imports in CLI) "PLC0415", # Complexity (existing code, would require significant refactoring) "PLR0912", # too many branches "PLR0913", # too many arguments "PLR0915", # too many statements "C901", # function too complex # Subprocess (intentional CLI tool usage) "S603", # subprocess call without shell=True check "S607", # partial executable path # pytest style "PT011", # pytest.raises too broad # Other "TRY300", # try-except-else instead of try-except "TRY301", # abstract raise to inner function "RET504", # unnecessary assignment before return "RET505", # unnecessary else after return "RET506", # unnecessary elif after raise "PLW1510", # subprocess.run without check "ERA001", # commented out code (false positives on format comments) "RUF059", # unused unpacked variable (prefixing with _ breaks readability) "S110", # try-except-pass (acceptable in version detection) "S108", # hardcoded temp file (intentional for lockfile) "S324", # insecure hash md5 (used for SSH key fingerprints, industry standard) "PTH123", # use Path.open instead of open (existing code pattern) "PGH003", # use specific rule codes (existing code) "PIE807", # prefer list over lambda (existing code) ] [tool.ruff.lint.per-file-ignores] "tests/*" = [ "S101", # assert is fine in tests "S105", # hardcoded password in tests "S106", # hardcoded password argument in tests "ARG", # unused arguments in test fixtures "SLF001", # private member access in tests "PLR0913", # too many arguments in test functions "PT022", # yield vs return in fixtures ] "hatch_build.py" = [ "T201", # print is fine in build hooks "ARG002", # unused arguments in hatch hooks ] [tool.ruff.lint.pyupgrade] # Enforce Python 3.10+ syntax keep-runtime-typing = false [tool.ty.terminal] error-on-warning = true [tool.ty.environment] python-version = "3.11" [tool.pytest.ini_options] testpaths = ["tests"] python_files = ["test_*.py"] python_classes = ["Test*"] python_functions = ["test_*"] addopts = "--cov=dropkit --cov-fail-under=29"