Skip to main content

Shared CLI/terminal UX primitives for CommonHuman-Lab tools

Project description

commonhuman-cli

Python PyPI License Zero deps Coverage

Shared CLI/terminal UX primitives for CommonHuman-Lab tools — colour, logging, output formatting, interactive prompts, and scan result infrastructure. One place. No duplication.

pip install commonhuman-cli

Why it exists

The CommonHuman-Lab toolkit is built around a consistent operator experience — every tool speaks the same visual language, responds to the same flags, and produces output you can pipe without surprises.

commonhuman-cli is the single source of truth for that experience. Tools that use it get:

  • Instant consistency — colour conventions, log prefixes, and summary layout are shared, not agreed upon.
  • Zero boilerplate — interactive wizard mode, URL list loading, header parsing, and exclude-pattern compilation are one import away.
  • Correct behaviour from day one — lazy TTY detection, thread-safe scan results, and namespace-isolated logging come built in.
  • A single place to improve — a fix or a new UX pattern lands in every tool at once.

Quick start

from commonhuman_cli.output import success, warning, error
from commonhuman_cli.logging import setup_logging, get_logger
from commonhuman_cli.reporter import ScanResultBase
from commonhuman_cli.prompts import prompt, prompt_bool, section
from commonhuman_cli.entrypoint import load_url_list, parse_headers

What's in it

Module Purpose
commonhuman_cli.colour ANSI colour functions, lazy TTY detection, banner rendering
commonhuman_cli.logging FINDING custom level, StingLogger, coloured handler, setup_logging()
commonhuman_cli.output Status printers, summary block helpers, proof_url()
commonhuman_cli.prompts Interactive prompt helpers for wizard-mode CLIs
commonhuman_cli.reporter ScanResultBase dataclass — thread-safe, serialisable
commonhuman_cli.entrypoint URL list loading, header parsing, exclude pattern compilation

Modules

colour

Lazy TTY detection — evaluated at call time, not import time, so pipe redirections are always respected.

from commonhuman_cli.colour import RED, GREEN, YELLOW, CYAN, BOLD, DIM, render_banner

print(GREEN("[+] finding confirmed"))
print(RED("[!] critical"))
print(DIM("[*] scanning..."))
print(render_banner(BANNER))   # wraps your tool's ASCII art in CYAN

Colour is automatically stripped when stdout is not a TTY (files, pipes, CI).


logging

Custom FINDING level (25 — between INFO and WARNING), coloured handler, and namespaced setup so two tools can run in the same process without interfering.

from commonhuman_cli.logging import setup_logging as _base

# In your tool's _cli/logging.py:
def setup_logging(verbose: bool, quiet: bool) -> None:
    _base(verbose, quiet, logger_name="breachsql")
from commonhuman_cli.logging import get_logger

log = get_logger("breachsql.scanner")
log.info("scanning %s", url)
log.finding("SQLi confirmed in param %s", param)   # GREEN [+]
log.warning("WAF detected")                         # YELLOW [!]
log.debug("raw response: %s", body[:200])           # CYAN [~]
Level Prefix Colour
DEBUG [~] CYAN
INFO [*] DIM
FINDING (25) [+] GREEN
WARNING+ [!] YELLOW

output

One-liner status printers and structured summary block helpers.

from commonhuman_cli.output import (
    success, warning, error, info, debug,
    print_header, print_footer, print_scan_meta, print_finding, print_errors,
    proof_url,
)

# Status lines
success("3 findings confirmed")
warning("WAF detected — switching to evasion mode")
error("connection refused")         # → stderr

# Summary block
print_header("BreachSQL — Scan Summary")
print_scan_meta(
    target="https://target.com",
    duration_s=4.2,
    requests_sent=312,
    crawled_urls=18,
    params_tested=47,
    waf_detected="Cloudflare",
    **{"DBMS detected": "mysql"},   # tool-specific extra rows
)

# Finding block
from commonhuman_cli.colour import RED
print_finding(
    index=1,
    tag="ERROR-BASED SQLi",
    tag_colour_fn=RED,
    fields=[
        ("Param",    "id"),
        ("URL",      "https://target.com/item?id=1"),
        ("DBMS",     "mysql"),
        ("Payload",  "' AND 1=1--"),
        ("Evidence", "You have an error in your SQL syntax"),
    ],
    proof=proof_url("https://target.com/item?id=1", "id", "' AND 1=1--", append=True),
)

print_errors(result.errors)
print_footer()

proof_url()

Builds a percent-encoded PoC URL. The append flag controls injection style:

# SQLi style — appends payload to the original value
proof_url("https://t.com/s?id=1", "id", "' AND 1=1--", append=True)
# → https://t.com/s?id=1%27+AND+1%3D1--

# XSS style — replaces the value entirely
proof_url("https://t.com/s?q=x", "q", "<script>alert(1)</script>", append=False)
# → https://t.com/s?q=%3Cscript%3Ealert%281%29%3C%2Fscript%3E

# Returns "" on malformed or schemeless URLs — never throws
proof_url("not-a-url", "q", "payload")  # → ""

prompts

Interactive wizard helpers — identical behaviour across all tools.

from commonhuman_cli.prompts import prompt, prompt_bool, section, safe_int

section("Target")
url = prompt("  Target URL", hint="https://target.com/search?q=test")

section("Scan options")
level = safe_int(prompt("  Scan level", default="1"), default=1, lo=1, hi=3)
crawl = prompt_bool("  Enable crawler", default=False)

safe_int clamps to [lo, hi] and returns default on non-numeric input. prompt and prompt_bool both exit cleanly on Ctrl+C / EOF.


reporter

Base dataclass for scan results. Inherit from it and add tool-specific finding lists.

from commonhuman_cli.reporter import ScanResultBase
from dataclasses import dataclass, field

@dataclass
class ScanResult(ScanResultBase):
    # base provides: target, duration_s, waf_detected, stats, log, errors, _lock
    dbms_detected: str | None = None
    error_based:   list = field(default_factory=list)
    boolean_based: list = field(default_factory=list)

    @property
    def total_findings(self) -> int:
        return len(self.error_based) + len(self.boolean_based)

    def to_dict(self) -> dict:
        d = self._base_dict()            # common fields pre-populated
        d["dbms_detected"] = self.dbms_detected
        d["total_findings"] = self.total_findings
        return d

# Usage
result = ScanResult(target="https://target.com")
result.requests_sent += 1
result.append_error("connection timeout")   # thread-safe
result.finish()                              # sets duration_s

All _append() calls are protected by a threading.Lock — safe for multi-threaded scanners.


entrypoint

Boilerplate that every __main__.py needs, extracted once.

from commonhuman_cli.entrypoint import (
    load_url_list, compile_exclude_patterns, parse_headers, validate_timeout,
)

urls     = load_url_list(args.url_list)          # skips blanks and # comments, exit(2) on IOError
patterns = compile_exclude_patterns(args.exclude) # exit(2) on bad regex
headers  = parse_headers(args.header)             # ["Key:Val"] → {"Key": "Val"}
validate_timeout(args.timeout)                    # warns to stderr if below minimum

Design principles

  • Zero runtime dependencies — stdlib only. Tools keep their own deps (requests, selenium, etc.).
  • No framework — plain functions and one dataclass. Nothing to learn, nothing to fight.
  • Lazy TTY detection — colour is checked at print time, not import time. Pipes and redirects always work.
  • Namespace isolationsetup_logging(logger_name="yourtool") scopes all logging so two tools coexist in the same process.
  • Composition over inheritanceScanResultBase gives you the shared fields; your ScanResult adds finding lists. No abstract base classes.

Tests

git clone https://github.com/CommonHuman-Lab/commonhuman-cli.git
cd commonhuman-cli
python -m venv .venv && source .venv/bin/activate
pip install -e ".[dev]"
pytest
pytest tests/unit/            # isolated unit tests only
pytest tests/regression/      # behavioural contracts from migrated tools

📜 License

Licensed under the AGPLv3. You are free to use, modify, and distribute this software. If you run it as a service or distribute it, the source must remain open.

For commercial licensing, contact the author.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

commonhuman_cli-0.1.0.tar.gz (18.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

commonhuman_cli-0.1.0-py3-none-any.whl (12.9 kB view details)

Uploaded Python 3

File details

Details for the file commonhuman_cli-0.1.0.tar.gz.

File metadata

  • Download URL: commonhuman_cli-0.1.0.tar.gz
  • Upload date:
  • Size: 18.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.12

File hashes

Hashes for commonhuman_cli-0.1.0.tar.gz
Algorithm Hash digest
SHA256 f84cdcf7d3f9f31360a9793786aea553c376c8b8aa3e7bfd7c2aa1945221e4f4
MD5 f544bac457b34191c9f80a27a78cb222
BLAKE2b-256 66cb99597a08f7ccc218ae9c59e85c39aa3d346e29f9f434242c9bb2a3c30a65

See more details on using hashes here.

File details

Details for the file commonhuman_cli-0.1.0-py3-none-any.whl.

File metadata

File hashes

Hashes for commonhuman_cli-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 2110b4ef8e5c248e9bbbd9c90b84e64138c1e35d3716f170e426b87a5d8e7e2b
MD5 46dca65c5afc0b38550eb4c7a65545f5
BLAKE2b-256 daf0a10b007238c88ff675a29db5a94ceb0d93cb9f219876d1bdbe916dd119fc

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page