Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/support-bundle.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"comicarr": minor
---

Settings → About can create a Support bundle for troubleshooting. Review the three files in the ZIP before attaching it to a public issue; share it privately with a maintainer if anything looks sensitive.
12 changes: 6 additions & 6 deletions .github/ISSUE_TEMPLATE/bug_report.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,13 @@ assignees: ''
**Describe the bug**
A clear and concise description of what the bug is.

**CarePackage**
On the config page, there is a button labelled "CarePackage". Pressing this button will download a zip file containing a redacted copy of your config, your database, a summary of your operating environment, and your logs. Upload that file here.
**Support bundle**
1. Go to **Settings → About → Support bundle**.
2. Choose **Create support bundle**, then **Create and download**.
3. Open the ZIP and review its three files (`README.txt`, `manifest.json`, `diagnostics.json`).
4. Attach the archive to this issue only if you are comfortable with every value; otherwise share it privately with a maintainer.

If you're uncomfortable with pasting your CarePackage, include a DEBUG log containing the error from disk.

Do not paste from the GUI log.
Do not just paste a traceback/error.
The bundle contains allowlisted diagnostic facts only. It is not a copy of your database, settings values, raw logs, library names, paths, or free text.


**Environment (please complete the following information):**
Expand Down
5 changes: 5 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,11 @@ jobs:
DATABASE_URL: ${{ matrix.database_url }}
run: uv run pytest tests/integration/test_schema_migration_dialects.py -q

- name: Support bundle dialect projection
env:
DATABASE_URL: ${{ matrix.database_url }}
run: uv run pytest tests/integration/test_support_bundle_dialects.py -q

- name: Check adopted schema
env:
DATABASE_URL: ${{ matrix.database_url }}
Expand Down
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ When to add one:
## Reporting Issues

- Use the [Bug Report](https://github.com/frankieramirez/comicarr/issues/new?template=bug_report.md) template
- Include a CarePackage (available on the config page) when reporting bugs
- Include a Support bundle from **Settings → About** when reporting bugs (review the three files first; share privately with a maintainer if anything looks sensitive)
- For feature requests, use the [Feature Request](https://github.com/frankieramirez/comicarr/issues/new?template=feature_request.md) template

## License
Expand Down
2 changes: 1 addition & 1 deletion SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ You should receive a response within 72 hours. We will work with you to understa
- Configuration files with credentials (`config.ini`) are excluded from version control
- The Docker image runs as a non-root user with configurable PUID/PGID
- All database queries use parameterized statements to prevent SQL injection
- The CarePackage feature redacts sensitive fields before export
- The Support bundle exports only allowlisted diagnostic facts; operators must review the archive before public attachment

## Known Scanner Findings

Expand Down
53 changes: 52 additions & 1 deletion comicarr/app/system/router.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
import json
import threading

from fastapi import APIRouter, Depends, Request
from fastapi import APIRouter, Depends, Request, Response
from fastapi.responses import JSONResponse
from sse_starlette.sse import EventSourceResponse, ServerSentEvent

Expand All @@ -32,6 +32,7 @@
validate_jwt_token,
)
from comicarr.app.system import service as system_service
from comicarr.app.system import support_bundle as support_bundle_module

router = APIRouter(prefix="/api", tags=["system"])

Expand Down Expand Up @@ -625,3 +626,53 @@ async def release_acquisition_canary(
reason=reason,
)
return _repair_response(result)


# ---------------------------------------------------------------------------
# Support bundle
# ---------------------------------------------------------------------------


@router.post("/system/support-bundle", dependencies=[Depends(require_session)])
def create_support_bundle(ctx: AppContext = Depends(get_context)):
"""Generate and download a Support bundle ZIP (session-authenticated only)."""
try:
artifact = support_bundle_module.generate_support_bundle(ctx)
except support_bundle_module.SupportBundleInProgress:
body = support_bundle_module.error_body("support_bundle_in_progress")
return JSONResponse(
status_code=409,
content=body,
headers={"Retry-After": "2"},
)
except support_bundle_module.SupportBundleUnavailable:
return JSONResponse(
status_code=503,
content=support_bundle_module.error_body("support_bundle_unavailable"),
)
except support_bundle_module.SupportBundleValidationFailed:
return JSONResponse(
status_code=500,
content=support_bundle_module.error_body("support_bundle_validation_failed"),
)
except support_bundle_module.SupportBundleError as exc:
status = 503 if exc.code == "support_bundle_unavailable" else 500
return JSONResponse(status_code=status, content=support_bundle_module.error_body(exc.code))
except Exception as e:
logger.error("[SUPPORT-BUNDLE] unexpected adapter failure: %s" % type(e).__name__)
return JSONResponse(
status_code=500,
content=support_bundle_module.error_body("support_bundle_generation_failed"),
)

return Response(
content=artifact.content,
media_type="application/zip",
headers={
"Content-Disposition": f'attachment; filename="{artifact.filename}"',
"Cache-Control": "no-store, private",
"Pragma": "no-cache",
"X-Comicarr-Support-Bundle-Contract": str(artifact.contract_version),
"X-Comicarr-Support-Bundle-Status": artifact.status,
},
)
Loading
Loading