Updated 5 wiki pages: Home.md: - Updated version to v0.2.6 - Added Custom REST provider and custom provider support to features - Updated integration status from stubs to complete - Updated release table with v0.2.3 and v0.2.6 highlights Integrations.md: - Complete rewrite: Changed from 'v0.2 stubs' to fully implemented - Added detailed docs for Confluence REST API client (6 tests) - Added detailed docs for ServiceNow REST API client (7 tests) - Added detailed docs for Azure DevOps REST API client (6 tests) - Documented OAuth2 PKCE flow implementation - Added database schema for credentials and integration_config tables - Added troubleshooting section with common OAuth/API errors AI-Providers.md: - Added section for Custom Provider (Custom REST provider) - Documented Custom REST provider API format differences from OpenAI - Added request/response format examples - Added configuration instructions and troubleshooting - Documented custom provider fields (api_format, custom_endpoint_path, etc) - Added available Custom REST provider models list IPC-Commands.md: - Replaced 'v0.2 stubs' section with full implementation details - Added OAuth2 commands (initiate_oauth, handle_oauth_callback) - Added Confluence commands (5 functions) - Added ServiceNow commands (5 functions) - Added Azure DevOps commands (5 functions) - Documented authentication storage with AES-256-GCM encryption - Added common types (ConnectionResult, PublishResult, TicketResult) Database.md: - Updated migration count from 10 to 11 - Added migration 011: credentials and integration_config tables - Documented AES-256-GCM encryption for OAuth tokens - Added usage notes for OAuth2 vs basic auth storage
9.3 KiB
Integrations
Status: ✅ Fully Implemented (v0.2.6) — All three integrations (Confluence, ServiceNow, Azure DevOps) are production-ready with complete OAuth2/authentication flows and REST API clients.
Confluence
Purpose: Publish RCA and post-mortem documents to Confluence spaces.
Status: ✅ Implemented (v0.2.3)
Features
- OAuth2 authentication with PKCE flow
- List accessible spaces
- Search pages by CQL query
- Create new pages with optional parent
- Update existing pages with version management
API Client (src-tauri/src/integrations/confluence.rs)
Functions:
test_connection(config: &ConfluenceConfig) -> Result<ConnectionResult, String>
list_spaces(config: &ConfluenceConfig) -> Result<Vec<Space>, String>
search_pages(config: &ConfluenceConfig, query: &str, space_key: Option<&str>) -> Result<Vec<Page>, String>
publish_page(config: &ConfluenceConfig, space_key: &str, title: &str, content_html: &str, parent_page_id: Option<&str>) -> Result<PublishResult, String>
update_page(config: &ConfluenceConfig, page_id: &str, title: &str, content_html: &str, version: i32) -> Result<PublishResult, String>
Configuration (Settings → Integrations → Confluence)
Base URL: https://yourorg.atlassian.net
Authentication: OAuth2 (bearer token, encrypted at rest)
Default Space: PROJ
Implementation Details
- API: Confluence REST API v1 (
/rest/api/) - Auth: OAuth2 bearer token (encrypted with AES-256-GCM)
- Endpoints:
GET /rest/api/user/current— Test connectionGET /rest/api/space— List spacesGET /rest/api/content/search— Search with CQLPOST /rest/api/content— Create pagePUT /rest/api/content/{id}— Update page
- Page format: Confluence Storage Format (XHTML)
- TDD Tests: 6 tests with mockito HTTP mocking
ServiceNow
Purpose: Create and manage incident records in ServiceNow.
Status: ✅ Implemented (v0.2.3)
Features
- Basic authentication (username/password)
- Search incidents by description
- Create new incidents with urgency/impact
- Get incident by sys_id or number
- Update existing incidents
API Client (src-tauri/src/integrations/servicenow.rs)
Functions:
test_connection(config: &ServiceNowConfig) -> Result<ConnectionResult, String>
search_incidents(config: &ServiceNowConfig, query: &str) -> Result<Vec<Incident>, String>
create_incident(config: &ServiceNowConfig, short_description: &str, description: &str, urgency: &str, impact: &str) -> Result<TicketResult, String>
get_incident(config: &ServiceNowConfig, incident_id: &str) -> Result<Incident, String>
update_incident(config: &ServiceNowConfig, sys_id: &str, updates: serde_json::Value) -> Result<TicketResult, String>
Configuration (Settings → Integrations → ServiceNow)
Instance URL: https://yourorg.service-now.com
Username: admin
Password: (encrypted with AES-256-GCM)
Implementation Details
- API: ServiceNow Table API (
/api/now/table/incident) - Auth: HTTP Basic authentication
- Severity mapping: TFTSR P1-P4 → ServiceNow urgency/impact (1-3)
- Incident lookup: Supports both sys_id (UUID) and incident number (INC0010001)
- TDD Tests: 7 tests with mockito HTTP mocking
Azure DevOps
Purpose: Create and manage work items (bugs/tasks) in Azure DevOps.
Status: ✅ Implemented (v0.2.3)
Features
- OAuth2 authentication with PKCE flow
- Search work items via WIQL queries
- Create work items (Bug, Task, User Story)
- Get work item details by ID
- Update work items with JSON-PATCH operations
API Client (src-tauri/src/integrations/azuredevops.rs)
Functions:
test_connection(config: &AzureDevOpsConfig) -> Result<ConnectionResult, String>
search_work_items(config: &AzureDevOpsConfig, query: &str) -> Result<Vec<WorkItem>, String>
create_work_item(config: &AzureDevOpsConfig, title: &str, description: &str, work_item_type: &str, severity: &str) -> Result<TicketResult, String>
get_work_item(config: &AzureDevOpsConfig, work_item_id: i64) -> Result<WorkItem, String>
update_work_item(config: &AzureDevOpsConfig, work_item_id: i64, updates: serde_json::Value) -> Result<TicketResult, String>
Configuration (Settings → Integrations → Azure DevOps)
Organization URL: https://dev.azure.com/yourorg
Authentication: OAuth2 (bearer token, encrypted at rest)
Project: MyProject
Implementation Details
- API: Azure DevOps REST API v7.0
- Auth: OAuth2 bearer token (encrypted with AES-256-GCM)
- WIQL: Work Item Query Language for advanced search
- Work item types: Bug, Task, User Story, Issue, Incident
- Severity mapping: Bug-specific field
Microsoft.VSTS.Common.Severity - TDD Tests: 6 tests with mockito HTTP mocking
OAuth2 Authentication Flow
All integrations using OAuth2 (Confluence, Azure DevOps) follow the same flow:
- User clicks "Connect" in Settings → Integrations
- Backend generates PKCE challenge and stores code verifier
- Local callback server starts on
http://localhost:8765 - Browser opens with OAuth authorization URL
- User authenticates with service provider
- Service redirects to
http://localhost:8765/callback?code=... - Callback server extracts code and triggers token exchange
- Backend exchanges code for token using PKCE verifier
- Token encrypted with AES-256-GCM and stored in DB
- UI shows "Connected" status
Implementation:
src-tauri/src/integrations/auth.rs— PKCE generation, token exchange, encryptionsrc-tauri/src/integrations/callback_server.rs— Local HTTP server (warp)src-tauri/src/commands/integrations.rs— IPC command handlers
Security:
- Tokens encrypted at rest with AES-256-GCM (256-bit key)
- Key derived from environment variable
TFTSR_DB_KEY - PKCE prevents authorization code interception
- Callback server only accepts from
localhost
Database Schema
Credentials Table (migration 011):
CREATE TABLE credentials (
id TEXT PRIMARY KEY,
service TEXT NOT NULL CHECK(service IN ('confluence','servicenow','azuredevops')),
token_hash TEXT NOT NULL, -- SHA-256 hash for audit
encrypted_token TEXT NOT NULL, -- AES-256-GCM encrypted
created_at TEXT NOT NULL,
expires_at TEXT,
UNIQUE(service)
);
Integration Config Table:
CREATE TABLE integration_config (
id TEXT PRIMARY KEY,
service TEXT NOT NULL CHECK(service IN ('confluence','servicenow','azuredevops')),
base_url TEXT NOT NULL,
username TEXT, -- ServiceNow only
project_name TEXT, -- Azure DevOps only
space_key TEXT, -- Confluence only
auto_create_enabled INTEGER NOT NULL DEFAULT 0,
updated_at TEXT NOT NULL,
UNIQUE(service)
);
Testing
All integrations have comprehensive test coverage:
# Run all integration tests
cargo test --manifest-path src-tauri/Cargo.toml --lib integrations
# Run specific integration tests
cargo test --manifest-path src-tauri/Cargo.toml confluence
cargo test --manifest-path src-tauri/Cargo.toml servicenow
cargo test --manifest-path src-tauri/Cargo.toml azuredevops
Test statistics:
- Confluence: 6 tests (connection, spaces, search, publish, update)
- ServiceNow: 7 tests (connection, search, create, get by sys_id, get by number, update)
- Azure DevOps: 6 tests (connection, WIQL search, create, get, update)
- Total: 19 integration tests (all passing)
Test approach:
- TDD methodology (tests written first)
- HTTP mocking with
mockitocrate - No external API calls in tests
- All auth flows tested with mock responses
CSP Configuration
All integration domains are whitelisted in src-tauri/tauri.conf.json:
"connect-src": "... https://auth.atlassian.com https://*.atlassian.net https://login.microsoftonline.com https://dev.azure.com"
Adding a New Integration
- Create API client:
src-tauri/src/integrations/{name}.rs - Implement functions:
test_connection(), create/read/update operations - Add TDD tests: Use
mockitofor HTTP mocking - Update migration: Add service to
credentialsandintegration_configCHECK constraints - Add IPC commands:
src-tauri/src/commands/integrations.rs - Update CSP: Add API domains to
tauri.conf.json - Wire up UI:
src/pages/Settings/Integrations.tsx - Update capabilities: Add any required Tauri permissions
- Document: Update this wiki page
Troubleshooting
OAuth "Command plugin:shell|open not allowed"
Fix: Add "shell:allow-open" to src-tauri/capabilities/default.json
Token Exchange Fails
Check:
- PKCE verifier matches challenge
- Redirect URI exactly matches registered callback
- Authorization code hasn't expired
- Client ID/secret are correct
ServiceNow 401 Unauthorized
Check:
- Username/password are correct
- User has API access enabled
- Instance URL is correct (no trailing slash)
Confluence API 404
Check:
- Base URL format:
https://yourorg.atlassian.net(no/wiki/) - Space key exists and user has access
- OAuth token has required scopes (
read:confluence-content.all,write:confluence-content)
Azure DevOps 403 Forbidden
Check:
- OAuth token has required scopes (
vso.work_write) - User has permissions in the project
- Project name is case-sensitive