GitHub Issues Integration
Status: Production Ready
Overview
End users in QRY can report issues from the Help menu. With the GitHub integration enabled, every report is automatically created as a GitHub issue in a configured repository — typically pueteam/QRY for QRY's own bug tracker, or a customer-owned internal repo for tenant-specific reporting.
The sync is bidirectional, with deliberately asymmetric latency:
- QRY → GitHub — immediate. The moment a user submits a report, QRY creates the GitHub issue.
- GitHub → QRY — on-demand. Admins trigger a sync to pull updated state (status, labels, comments) back into QRY's local mirror.
The on-demand pattern (instead of GitHub webhooks) avoids the operational overhead of exposing a public webhook ingress and managing webhook secrets — and it's enough for almost all tenants.
Architecture
┌──────────────┐ POST /issues ┌──────────────┐
│ QRY │ ─────────────────────→ │ GitHub │
│ backend │ │ API │
│ │ ←───── sync (cron) ──────│ │
└──────────────┘ └──────────────┘
│
│ stores
▼
┌──────────────┐
│ qry_issues │
│ table (PG) │
└──────────────┘
A local qry_issues table mirrors GitHub state. Users see the local state in Admin > Issues (admins) and My issues (any user, scoped to their own reports).
Data flow
QRY → GitHub (on report submission)
- User opens Help > Report Issue, fills the form (title, description, optional conversation attachment).
- Backend creates a record in
qry_issueswith statepending. - Backend calls
POST /repos/{owner}/{repo}/issueswith:- Title (with optional tenant prefix configured by the admin).
- Body — formatted with description, user email, conversation id, tenant id.
- Labels — configured defaults plus any tags from the user.
- On success, the local record's state moves to
syncedand stores the GitHub issue number / URL. - The user sees the confirmation with a clickable link.
If the GitHub call fails (token invalid, rate-limited, network), the local record stays in pending. The next periodic sync retries.
GitHub → QRY (on demand)
- Admin clicks Sync from GitHub in Admin > Issues, or the nightly cronjob fires.
- Backend calls
GET /repos/{owner}/{repo}/issues?state=all&since=<last_sync>. - For each issue with a matching
qry_issuesmirror, update local state:state(open / closed)labels(added / removed)commentscountclosed_attimestamp
- Issues created directly in GitHub (not from QRY) are imported as
externalissues if the integration is configured to import them — controlled by a setting.
Configuration
In Admin > System Settings > GitHub:
| Setting | Description |
|---|---|
| Repository | owner/repo slug (e.g. pueteam/QRY) |
| Personal access token | Stored Fernet-encrypted; needs repo scope |
| Default labels | Applied to every issue QRY creates |
| Tenant prefix | Optional; prepended to issue title (e.g. [acme]) |
| Sync schedule | Cron expression for the on-demand-but-cronjobbed sync (default daily) |
| Import external | Whether to import issues created directly in GitHub |
Token security
The personal access token is the most sensitive piece of the integration. Considerations:
- Use a dedicated bot account, not a real user's PAT.
- Scope the token to the single repo the integration uses.
- Rotate periodically; the integration's last-sync log shows authentication failures.
- The token is encrypted at rest with the same Fernet key (
JWT_SECRET_KEY-derived) used for datasource credentials.
User experience
End users see issues only as their own report and follow-up — they don't see other users' reports. My issues in their navbar is the entry point.
Admins see everything in Admin > Issues, with filters by user, tenant, state, and label.
Operational signals
qry_github_sync_failures_total— counter; alerts on rising trend.qry_github_pending_reports— gauge; should drop to zero quickly after submission. If it stays >0 for minutes, the sync worker is stuck.qry_github_last_sync_seconds_ago— gauge; alerts if no successful sync in N hours (cron is broken).
Limits
- GitHub issue body is capped at 65 KB. Large conversation attachments are truncated with a
…truncated, see QRY conversation <url>link. - GitHub API rate limits are 5,000 requests/hour for authenticated tokens. At normal report volume this is never hit; bulk sync of historical issues might.
See Also
- GitHub integration admin guide — operational walkthrough.
- Audit and compliance — integration activity is logged.
Last updated: 2026-05-04