diff --git a/README.md b/README.md index ea65947..c3ef51b 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,33 @@ --- -## Quickstart +## Install + +Requires Python 3.9+. + +### Recommended: uv (fast, isolated) + +```bash +uv tool install outervoid-dat +``` + +### pipx (isolated CLI install) + +```bash +pipx install outervoid-dat +``` + +### curl/wget bootstrap (uv → pipx → pip --user) + +```bash +curl -fsSL https://raw.githubusercontent.com/Outer-Void/dat/main/install.sh | bash +``` + +```bash +wget -qO- https://raw.githubusercontent.com/Outer-Void/dat/main/install.sh | bash +``` + +> Need PDF output? Install with `outervoid-dat[pdf]` (e.g., `uv tool install "outervoid-dat[pdf]"`). ### From source (recommended while 3.x is in flux) @@ -157,6 +183,27 @@ Repo link: **LRC — Local Repo Compiler** → [Outer-Void/lrc](https://github.c --- +## Build & Publish + +```bash +python -m build +twine check dist/* +``` + +TestPyPI: + +```bash +twine upload --repository-url https://test.pypi.org/legacy/ dist/* +``` + +PyPI: + +```bash +twine upload dist/* +``` + +--- + ## Security & Telemetry - No outbound connections; deterministic local outputs. @@ -175,4 +222,3 @@ Repo link: **LRC — Local Repo Compiler** → [Outer-Void/lrc](https://github.c ## License MIT — see [`LICENSE`](./LICENSE). - diff --git a/dat b/dat index 319168a..90abbff 100755 --- a/dat +++ b/dat @@ -11,7 +11,7 @@ import os import sys from pathlib import Path -MIN_PY = (3, 8) +MIN_PY = (3, 9) if sys.version_info < MIN_PY: raise SystemExit(f"DAT requires Python {MIN_PY[0]}.{MIN_PY[1]}+ (found {sys.version.split()[0]})") diff --git a/install.sh b/install.sh new file mode 100755 index 0000000..d135eb8 --- /dev/null +++ b/install.sh @@ -0,0 +1,69 @@ +#!/usr/bin/env bash +set -euo pipefail +IFS=$'\n\t' + +PKG_NAME="outervoid-dat" +EXTRAS="${DAT_EXTRAS:-}" + +if [[ -n "$EXTRAS" ]]; then + PKG_SPEC="${PKG_NAME}[${EXTRAS}]" +else + PKG_SPEC="${PKG_NAME}" +fi + +log() { + printf '%s\n' "$*" >&2 +} + +ensure_on_path() { + if command -v dat >/dev/null 2>&1; then + return 0 + fi + log "⚠️ 'dat' not found on PATH. You may need to add ~/.local/bin or the pipx bin dir." + return 0 +} + +install_with_uv() { + log "→ Installing via uv tool install: ${PKG_SPEC}" + uv tool install "${PKG_SPEC}" + ensure_on_path +} + +install_with_pipx() { + log "→ Installing via pipx: ${PKG_SPEC}" + pipx install "${PKG_SPEC}" + if command -v pipx >/dev/null 2>&1; then + pipx ensurepath >/dev/null 2>&1 || true + fi + ensure_on_path +} + +install_with_pip() { + local python_bin="${1}" + log "→ Installing via pip --user: ${PKG_SPEC}" + "${python_bin}" -m pip install --user "${PKG_SPEC}" + ensure_on_path +} + +main() { + if command -v uv >/dev/null 2>&1; then + install_with_uv + return 0 + fi + + if command -v pipx >/dev/null 2>&1; then + install_with_pipx + return 0 + fi + + local python_bin="" + python_bin="$(command -v python3 || command -v python || true)" + if [[ -z "$python_bin" ]]; then + log "❌ Python not found. Install Python 3.9+ and re-run." + exit 1 + fi + + install_with_pip "$python_bin" +} + +main "$@" diff --git a/install_deps.sh b/install_deps.sh index f10af3f..99c481a 100755 --- a/install_deps.sh +++ b/install_deps.sh @@ -43,7 +43,7 @@ detect_python() { log_info "Detecting Python..." # Try different Python commands in order of preference - for py_cmd in python3.11 python3.10 python3.9 python3.8 python3 python; do + for py_cmd in python3.12 python3.11 python3.10 python3.9 python3 python; do if command -v "$py_cmd" >/dev/null 2>&1; then # Check Python version version=$("$py_cmd" -c "import sys; print(f'{sys.version_info.major}.{sys.version_info.minor}')" 2>/dev/null || echo "0.0") @@ -52,18 +52,18 @@ detect_python() { major=$(echo "$version" | cut -d. -f1) minor=$(echo "$version" | cut -d. -f2) - if [[ $major -eq 3 ]] && [[ $minor -ge 8 ]]; then + if [[ $major -eq 3 ]] && [[ $minor -ge 9 ]]; then log_success "Found Python $version using $py_cmd" printf '%s\n' "$py_cmd" return 0 else - log_warning "Python $version found but 3.8+ required" + log_warning "Python $version found but 3.9+ required" fi fi done - log_error "No suitable Python 3.8+ installation found" - log_info "Please install Python 3.8 or newer from: https://python.org/downloads/" + log_error "No suitable Python 3.9+ installation found" + log_info "Please install Python 3.9 or newer from: https://python.org/downloads/" return 1 } diff --git a/pyproject.toml b/pyproject.toml index dc0abfb..2d212b4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -6,12 +6,12 @@ authors = [ {name = "Outer Void Team, Justadudeinspace", email = "outervoid.blux@gmail.com"} ] readme = "README.md" -license = {text = "MIT"} +license = "MIT" +license-files = ["LICENSE"] keywords = ["security", "audit", "dependencies", "vulnerability", "scanner"] classifiers = [ "Development Status :: 4 - Beta", "Intended Audience :: Developers", - "License :: OSI Approved :: MIT License", "Operating System :: OS Independent", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.9", @@ -28,6 +28,7 @@ dependencies = [ "pyyaml>=5.4.0", "rich>=10.0.0", "typer>=0.20.0", + "cryptography>=42.0.0", ] requires-python = ">=3.9" diff --git a/requirements.txt b/requirements.txt index f09bbec..2202ef7 100644 --- a/requirements.txt +++ b/requirements.txt @@ -5,6 +5,7 @@ packaging>=25.0 pyyaml>=6.0.3 rich>=14.2.0 typer>=0.20.0 +cryptography>=42.0.0 # Optional: PDF reporting # reportlab>=4.4.4 diff --git a/scripts/bootstrap.sh b/scripts/bootstrap.sh index 74c76c6..2716e79 100755 --- a/scripts/bootstrap.sh +++ b/scripts/bootstrap.sh @@ -155,7 +155,7 @@ bootstrap() { # --- Python availability check --- print_step "Checking Python installation..." if ! command -v "$PYTHON_BIN" >/dev/null 2>&1; then - print_error "Python3 not found. Please install Python 3.8+ first." + print_error "Python3 not found. Please install Python 3.9+ first." case "$PLATFORM" in macOS) diff --git a/src/dat/__init__.py b/src/dat/__init__.py index 079ef27..4f84578 100644 --- a/src/dat/__init__.py +++ b/src/dat/__init__.py @@ -82,7 +82,7 @@ def repository_root(start: Path | None = None, marker: str = ".git") -> Path: raise FileNotFoundError(f"No repository root found (looking for '{marker}' marker)") -def ensure_python_version(min_version: tuple[int, int] = (3, 8)) -> None: +def ensure_python_version(min_version: tuple[int, int] = (3, 9)) -> None: """ Ensure the current Python version meets minimum requirements. diff --git a/src/dat/cli.py b/src/dat/cli.py index 22163b8..9ae64fb 100644 --- a/src/dat/cli.py +++ b/src/dat/cli.py @@ -33,7 +33,6 @@ ) from .integration.signing import sign_artifact from .logging.audit import append_encrypted_log -from .pdf import write_pdf_report from .report import ( build_metadata, calculate_report_fingerprint, @@ -52,6 +51,21 @@ no_args_is_help=False, help="DAT - Dev Audit Tool | Enterprise Security Scanning" ) + +def _write_pdf_report( + path: Path, result: ScanResult, findings: Iterable[RuleFinding], metadata: dict +) -> None: + try: + from .pdf import write_pdf_report + except ModuleNotFoundError: + console.print( + "[red]PDF output requires ReportLab. Install with " + '`pip install "outervoid-dat[pdf]"`.[/red]' + ) + raise typer.Exit(1) from None + write_pdf_report(path, result, findings, metadata) + + # ============================================================================= # dat cmd — print main code files (incl. scripts) into a single Markdown file # ============================================================================= @@ -740,7 +754,7 @@ def write_report_file( atomic_write(path, ("\n".join(lines) + "\n").encode("utf-8")) console.print(f"[green]✓ JSONL report saved:[/green] {path}") elif format_type == "pdf": - write_pdf_report(path, result, findings, metadata) + _write_pdf_report(path, result, findings, metadata) console.print(f"[green]✓ PDF report saved:[/green] {path}") elif format_type in {"md", "markdown"}: write_markdown_report(path, result, findings, metadata)