Skip to main content

awreport — Aither World Report

File structured bug reports and feature requests to GitHub, with automatic redaction of secrets and deduplication.

A standalone Python package for any application to file issues to GitHub:

  • ✅ Works standalone — just a GitHub token and repo
  • ✅ Automatic secret redaction (API keys, tokens, home paths, etc.)
  • ✅ Duplicate detection with fingerprinting
  • ✅ Supports bug reports, feature requests, and general feedback
  • ✅ Zero monorepo dependencies — pure Python + requests
  • ✅ Fully typed, comprehensive tests

Installation

pip install awreport

Or install from source:

git clone <repo-url>
cd awreport
pip install -e .

Quick Start

Via Python API

from awreport import ReportClient

# Initialize client with your GitHub token and target repo
client = ReportClient(
    token="ghp_...",
    repo="owner/repo"
)

# Verify access
result = client.verify_access()
if result.status.value != "success":
    print(f"Error: {result.message}")
    exit(1)

# Report a bug
result = client.report_bug(
    title="Login fails with special characters",
    description="When using email+tag@example.com, login is rejected",
    environment={"os": "Linux", "python": "3.10"},
    stack_trace="Traceback...",
)

if result.is_success():
    print(f"✓ Issue #{result.issue_number} filed")
    print(f"  {result.issue_url}")
elif result.was_duplicate:
    print(f"✓ Duplicate of issue #{result.duplicate_issue_number}")
else:
    print(f"✗ Error: {result.message}")
    if result.error_details:
        print(f"  {result.error_details}")

# Report a feature request
feature_result = client.report_feature(
    title="Add dark mode",
    description="Users have requested a dark mode toggle"
)

# Send general feedback
feedback_result = client.report_feedback(
    message="Great app! Love the new dashboard.",
    tags=["praise", "dashboard"]
)

Via CLI

# Verify access
awreport --token ghp_... --repo owner/repo verify

# Report a bug (with optional stack trace file)
awreport --token ghp_... --repo owner/repo bug \
  "Login fails with special characters" \
  "Cannot log in with email+tag@example.com" \
  --env-json '{"os":"Linux","python":"3.10"}' \
  --stack-trace-file /path/to/traceback.txt

# Report a feature request
awreport --token ghp_... --repo owner/repo feature \
  "Add dark mode" \
  "Users want a dark mode toggle"

# Send feedback
awreport --token ghp_... --repo owner/repo feedback \
  "Great app! Love the UI." \
  --tags praise,ui

Or use environment variables:

export GITHUB_TOKEN="ghp_..."
export GITHUB_REPO="owner/repo"

awreport verify
awreport bug "Title" "Description"

Secret Redaction

All feedback is automatically redacted before filing to GitHub. Secrets detected and redacted include:

  • API Keys: Anthropic (sk-ant-*), OpenAI (sk-*), AWS (AKIA*)
  • Tokens: GitHub PAT (ghp_*), Slack (xoxb-*, xoxp-*), Bearer tokens
  • Paths: Home directory paths (/home/user/, C:\Users\...)
  • High-entropy strings: Base64-like tokens >40 characters
  • Other patterns: api_key=, password=, etc.

Redaction is fail-closed: if redaction cannot complete safely, the report is NOT filed:

from awreport import RedactionError, ReportClient

client = ReportClient(token="...", repo="...")

try:
    result = client.report_bug(title, description, environment, stack_trace)
except RedactionError:
    print("Could not safely redact sensitive data. Report not filed.")
    # Application should log this and possibly alert a human

Duplicate Detection

Feedback is fingerprinted and compared against existing issues:

  1. Title normalization: lowercase, strip, remove extra whitespace
  2. Stack trace hashing: last 5 frames, SHA-256 hash (first 16 chars)
  3. Existing issue search: GitHub API search with filters
  4. Match logic:
    • Bugs: must match title + stack trace hash (strong match)
    • Features/feedback: title match alone is sufficient

If a duplicate is found:

  • The existing issue number is returned in ReportResult.duplicate_issue_number
  • A comment is added to the existing issue with new environment info
  • Status is ReportStatus.DUPLICATE but is_success() still returns True
result = client.report_bug(title, description)
if result.was_duplicate:
    print(f"Already reported as issue #{result.duplicate_issue_number}")

Return Values

Every report returns a ReportResult with:

  • status: SUCCESS, DUPLICATE, ERROR, or REDACTION_FAILED
  • message: Human-readable status message
  • issue_number: GitHub issue number (if successful)
  • issue_url: GitHub issue URL (if successful)
  • was_duplicate: True if a duplicate was found
  • duplicate_issue_number: Number of duplicate issue (if applicable)
  • error_details: Error details (if status == ERROR)
result = client.report_bug(...)

if result.is_success():
    # SUCCESS or DUPLICATE
    print(f"Issue: {result.issue_url}")
else:
    # ERROR or REDACTION_FAILED
    print(f"Failed: {result.message}")
    print(f"Details: {result.error_details}")

Type Safety

All public functions are fully typed for IDE autocomplete:

from awreport import ReportClient, ReportResult, FeedbackKind

def handle_bug(client: ReportClient, title: str, desc: str) -> ReportResult:
    return client.report_bug(title, desc)

# IDE provides full autocomplete and type checking

Testing

Run tests:

pip install -e ".[dev]"
pytest tests/

Tests include:

  • Redaction: secrets are redacted, normal text is preserved
  • GitHub integration: API calls are mocked, various scenarios tested
  • Deduplication: fingerprints match similar issues, exact duplicates detected
  • CLI: argument parsing, error handling

All tests use positive assertions — they verify that successful operations produce the expected output:

def test_report_bug_creates_issue():
    """Test report_bug creates an issue."""
    result = client.report_bug(title, description)
    assert result.status == ReportStatus.SUCCESS
    assert result.issue_number == 42
    assert result.issue_url is not None

Design Principles

  1. Standalone: No monorepo imports, no internal dependencies. Just GitHub token + repo.
  2. Fail-closed: If redaction fails, do NOT send. If verification fails, report it.
  3. Fully typed: Every public function has type hints. Mypy-clean.
  4. Comprehensive redaction: Better to over-redact than under-redact.
  5. Dedup prevents spam: Same issue = one thread with new comments, not N issues.
  6. Graceful degradation: Search failure doesn't block issue creation. Comment failure doesn't block duplicate detection.

Environment Variables

  • GITHUB_TOKEN: GitHub personal access token (required if --token not provided)
  • GITHUB_REPO: Repository in format owner/repo (required if --repo not provided)

Development

Install dev dependencies:

pip install -e ".[dev]"

Run linting:

ruff check awreport/ tests/
mypy awreport/

Format code:

black awreport/ tests/

License

Apache-2.0

Contributing

Contributions welcome! Please:

  1. Write tests for new functionality
  2. Run pytest and linting before submitting
  3. Keep redaction comprehensive — err on the side of over-redacting
  4. Maintain zero monorepo dependencies

Metadata

Release files for awreport 0.2.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for awreport 0.2.0
File Size Uploaded
awreport-0.2.0.tar.gz 33.9 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for awreport 0.2.0
File Interpreter ABI Platform
awreport-0.2.0-py3-none-any.whl Python 3 none any Details

Total release size: 61.8 kB

Release files / awreport-0.2.0.tar.gz

Download URL awreport-0.2.0.tar.gz
Size 33.9 kB
Tags Source
SHA-256 checksum
How to use checksums
fc2f7654b90b7cb20c1dbf33b1f5656cc52cfab7499bbe394b44ca32b8c661dc
BLAKE2b-256 checksum
How to use checksums
1d416ecfaa585abb4a8317058006c0e42728b3ad8318d971deb9aabf860897d6
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.3

Release files / awreport-0.2.0-py3-none-any.whl

Download URL awreport-0.2.0-py3-none-any.whl
Size 27.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
0efab42e97405ef48e499782dae90921f1ecc3be066148a9a89f465c61c14469
BLAKE2b-256 checksum
How to use checksums
1de61057b99c4b7acf5b0394a59d928d1cb4ad6ef9c32f9651f2467be6251bad
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.3

Release history Release notifications | RSS feed

This release

0.2.0 This release

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page