Split into a FastAPI backend and a React frontend, add case state and SSO
The single-file stdlib server became the limit: no way to track what had been done about an alert, no accounts, and a UI that had to be hand-rolled in template strings. This restructures it into something deployable. Backend (FastAPI) - app/ holds config, database, auth, delivery and the routers; triagelib keeps the triage engine unchanged, so the validated screening and runbook logic is untouched. - Cases persist per alert fingerprint with a status workflow (investigating, customer contacted, escalated to Infra, waiting, remediated, resolved, won't fix, false positive), an assignee, notes and an append-only history. An alert that stops and re-fires lands back on the same case and counts as a reopen. - Suppression rules move from a JSON file into the database. Auth - Signed session cookies over PBKDF2 local accounts, plus an OIDC flow ready for Authentik: users are created on first login and admin follows a group claim. Local login can be switched off entirely once SSO is live. Zendesk and Jira - Delivery is now implemented, behind three gates: the integration must be configured, its feature flag on, and CX_FEATURE_SEND_ENABLED on. A demo instance leaves the last off and cannot mail anyone. Both search before creating, so re-diagnosing an alert updates one ticket rather than opening several, and a rolling daily cap stops a loop mailing everybody. Deployment - Multi-stage Dockerfile builds the bundle and serves it from the API origin. - docker-compose for local and single-host use; Gitea Actions runs the tests, builds the image and renders deploy/k8s with envsubst. Two fixes found while testing: assigning a case returned a null assignee, and add_event could leave an already-loaded history collection stale. Known gap: the engine reaches OpenStack via `docker exec <region>-osc`, which does not work in a pod without the CX-Tools containers alongside it. docs/DEPLOYMENT.md sets out the three ways to close that. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
133
docs/INTEGRATIONS.md
Normal file
133
docs/INTEGRATIONS.md
Normal file
@@ -0,0 +1,133 @@
|
||||
# Enabling Zendesk and Jira
|
||||
|
||||
Nothing leaves this app until **three separate gates** are open. Until then the
|
||||
UI builds the full payload, shows it to you, and the Send button stays disabled
|
||||
with the reason written on it.
|
||||
|
||||
```
|
||||
1. the integration is configured CX_ZENDESK_* / CX_JIRA_*
|
||||
2. its feature flag is on CX_FEATURE_ZENDESK / CX_FEATURE_JIRA
|
||||
3. sending is enabled globally CX_FEATURE_SEND_ENABLED
|
||||
```
|
||||
|
||||
Gate 3 is the important one. A demo or staging instance simply leaves it off,
|
||||
and then no combination of clicks can email a customer.
|
||||
|
||||
Check where you stand at any time on **Settings → Integrations**, or:
|
||||
|
||||
```bash
|
||||
curl -s localhost:8080/api/health | python3 -m json.tool
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Zendesk
|
||||
|
||||
### 1. Create an API token
|
||||
|
||||
Zendesk **Admin Center → Apps and integrations → APIs → Zendesk API**, turn on
|
||||
*Token access*, then **Add API token**. Copy it — Zendesk shows it once.
|
||||
|
||||
### 2. Decide which agent owns the tickets
|
||||
|
||||
Use a dedicated agent (e.g. `cx-triage@…`) rather than a person's account, so
|
||||
the audit trail stays clear when someone leaves.
|
||||
|
||||
### 3. Set the variables
|
||||
|
||||
```bash
|
||||
CX_FEATURE_ZENDESK=true
|
||||
CX_ZENDESK_SUBDOMAIN=nexgencloud # from https://<this>.zendesk.com
|
||||
CX_ZENDESK_EMAIL=cx-triage@nexgencloud.com
|
||||
CX_ZENDESK_TOKEN=<the token>
|
||||
CX_ZENDESK_PUBLIC_REPLY=true # false posts an internal note instead
|
||||
|
||||
CX_FEATURE_SEND_ENABLED=true # the master switch
|
||||
```
|
||||
|
||||
Restart. The Send button becomes live.
|
||||
|
||||
### What happens on send
|
||||
|
||||
1. Searches for `external_id:cx-triage-<fingerprint>`.
|
||||
2. If a ticket exists → adds a comment. If not → creates one, with the requester
|
||||
set from the Infrahub owner, priority from the screening verdict, and tags
|
||||
`cx-triage`, `alert-<kind>`.
|
||||
3. Records a `zendesk_sent` event on the case and moves it to
|
||||
**Customer contacted**.
|
||||
|
||||
So re-diagnosing the same alert updates one ticket instead of opening five.
|
||||
|
||||
---
|
||||
|
||||
## Jira
|
||||
|
||||
### 1. Create an API token
|
||||
|
||||
<https://id.atlassian.com/manage-profile/security/api-tokens> → *Create API
|
||||
token*.
|
||||
|
||||
### 2. Confirm the project and issue type
|
||||
|
||||
The defaults are `INFRA` / `Task`. If your Infrastructure project uses something
|
||||
else, set it — a wrong `issuetype` is the usual cause of a 400 from Jira.
|
||||
|
||||
### 3. Set the variables
|
||||
|
||||
```bash
|
||||
CX_FEATURE_JIRA=true
|
||||
CX_JIRA_BASE=https://nexgencloud.atlassian.net
|
||||
CX_JIRA_EMAIL=cx-triage@nexgencloud.com
|
||||
CX_JIRA_TOKEN=<the token>
|
||||
CX_JIRA_PROJECT=INFRA
|
||||
CX_JIRA_ISSUE_TYPE=Task
|
||||
|
||||
CX_FEATURE_SEND_ENABLED=true
|
||||
```
|
||||
|
||||
Issues are labelled `cx-triage-<fingerprint>` and searched for before creating,
|
||||
so the same alert never opens two tickets.
|
||||
|
||||
---
|
||||
|
||||
## Where the credentials go
|
||||
|
||||
**Never commit them.**
|
||||
|
||||
| Where | How |
|
||||
|---|---|
|
||||
| Local | `.env` (git-ignored) — copy from `.env.example` |
|
||||
| Kubernetes | The `cx-triage` Secret, written by the pipeline from Gitea secrets |
|
||||
| Gitea | Repository → Settings → Actions → Secrets |
|
||||
|
||||
The deploy job creates the Secret imperatively from the secret store, so no
|
||||
credential is ever in a manifest in git.
|
||||
|
||||
---
|
||||
|
||||
## Safety rails that stay on
|
||||
|
||||
- Every send needs a click **and** a confirm naming the recipient.
|
||||
- No auto-send: a verdict never triggers an email by itself.
|
||||
- `CX_SEND_DAILY_CAP` (default 25) refuses further sends in a rolling 24 hours,
|
||||
so a loop cannot mail every customer.
|
||||
- The body is editable before sending.
|
||||
- Every attempt is written to the case history — including failures.
|
||||
- Deleting, shelving and InfraInsight edits stay copy-a-command. The read-only
|
||||
guarantee is what makes this safe against production.
|
||||
|
||||
## First run
|
||||
|
||||
Point at a **Zendesk sandbox**, or send the first ticket to your own address by
|
||||
editing the To field. Once one round trip looks right, switch it on for real.
|
||||
|
||||
## When it fails
|
||||
|
||||
| Symptom | Cause |
|
||||
|---|---|
|
||||
| Button disabled, "sending is switched off" | `CX_FEATURE_SEND_ENABLED` is false |
|
||||
| Button disabled, "not configured" | A `CX_ZENDESK_*` / `CX_JIRA_*` value is missing |
|
||||
| `401` from Zendesk | The email must be the **agent** address, and token access must be enabled |
|
||||
| `400` from Jira | Usually `issuetype` or `project` does not exist |
|
||||
| "Daily send cap reached" | Raise `CX_SEND_DAILY_CAP` if deliberate |
|
||||
| "Open the case first" | The alert has no case yet — open it in the queue once |
|
||||
Reference in New Issue
Block a user