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.1.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.1.0
File Size Uploaded
awreport-0.1.0.tar.gz 26.5 kB Details

Built distribution (wheel)

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

Total release size: 47.4 kB

Release files / awreport-0.1.0.tar.gz

Download URL awreport-0.1.0.tar.gz
Size 26.5 kB
Tags Source
SHA-256 checksum
How to use checksums
9ac06dddc6da97b79d29c0518ff106b259830babf7751bbf8e1489dc2d5d937c
BLAKE2b-256 checksum
How to use checksums
ac5a70249a9e4b332d6117501e2d67be4ec4126427d8d7b4e32abadbf8191e93
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.1.0-py3-none-any.whl

Download URL awreport-0.1.0-py3-none-any.whl
Size 20.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
be4a274abcf9b03d171c10f1bc91e87cfee0e8815a33d9f11e163c6c8409370d
BLAKE2b-256 checksum
How to use checksums
355e704a7e1a377b20cd5cd2ab102d793f38e2745884efab7699cbafbd1fe2b6
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

0.2.0

2 release files

This release

0.1.0 This release

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