Commit Graph

78 Commits

Author SHA1 Message Date
Shaun Arman
5b45c6c418 fix(integrations): security and correctness improvements
All checks were successful
Test / rust-fmt-check (pull_request) Successful in 12s
Test / frontend-typecheck (pull_request) Successful in 1m18s
Test / frontend-tests (pull_request) Successful in 1m21s
Test / rust-clippy (pull_request) Successful in 3m56s
PR Review Automation / review (pull_request) Successful in 4m20s
Test / rust-tests (pull_request) Successful in 5m22s
- Add url canonicalization for deduplication (strip fragments/query params)
- Add WIQL injection escaping for Azure DevOps work item searches
- Add CQL injection escaping for Confluence searches
- Add MAX_EXPANDED_QUERIES constant for consistency
- Fix logging to show expanded_query instead of search_url
- Add input validation for empty queries
- Add url crate dependency for URL parsing

All 142 tests pass.
2026-04-14 19:55:32 -05:00
Shaun Arman
096068ed2b feat(integrations): implement query expansion for semantic search
All checks were successful
Test / rust-fmt-check (pull_request) Successful in 12s
Test / frontend-typecheck (pull_request) Successful in 1m11s
Test / frontend-tests (pull_request) Successful in 1m15s
PR Review Automation / review (pull_request) Successful in 3m13s
Test / rust-clippy (pull_request) Successful in 3m45s
Test / rust-tests (pull_request) Successful in 5m9s
- Add query_expansion.rs module with product synonyms and keyword extraction
- Update confluence_search.rs to use expanded queries
- Update servicenow_search.rs to use expanded queries
- Update azuredevops_search.rs to use expanded queries
- Update webview_fetch.rs to use expanded queries
- Fix extract_keywords infinite loop bug for non-alphanumeric endings

All 142 tests pass.
2026-04-14 19:37:27 -05:00
Shaun Arman
75fc3ca67c fix: add Windows nsis target and update CHANGELOG to v0.2.61
All checks were successful
Auto Tag / autotag (push) Successful in 6s
Auto Tag / wiki-sync (push) Successful in 6s
Auto Tag / changelog (push) Successful in 43s
Auto Tag / build-macos-arm64 (push) Successful in 3m0s
Auto Tag / build-linux-amd64 (push) Successful in 11m29s
Auto Tag / build-linux-arm64 (push) Successful in 13m31s
Auto Tag / build-windows-amd64 (push) Successful in 14m10s
- Update CHANGELOG to include releases v0.2.54 through v0.2.61
- Add 'nsis' to bundle targets in tauri.conf.json for Windows builds
- This fixes Windows artifact upload failures by enabling .exe/.msi generation

The Windows build was failing because tauri.conf.json only had Linux bundle
targets (['deb', 'rpm']). Without nsis target, no Windows installers were
produced, causing the upload step to fail with 'No Windows amd64 artifacts
were found'.
2026-04-13 15:25:05 -05:00
Shaun Arman
62e3570a15 fix: remove AppImage bundling to fix linux-amd64 build
Some checks failed
Auto Tag / autotag (push) Successful in 6s
Auto Tag / wiki-sync (push) Successful in 6s
Build CI Docker Images / windows-cross (push) Successful in 7s
Build CI Docker Images / linux-arm64 (push) Successful in 6s
Auto Tag / changelog (push) Has been cancelled
Auto Tag / build-windows-amd64 (push) Has been cancelled
Auto Tag / build-linux-amd64 (push) Has been cancelled
Auto Tag / build-macos-arm64 (push) Has been cancelled
Auto Tag / build-linux-arm64 (push) Has been cancelled
Build CI Docker Images / linux-amd64 (push) Successful in 2m37s
- Remove appimage from bundle targets in tauri.conf.json
- Remove linuxdeploy from Dockerfile
- Update Dockerfile to remove fuse dependency (not needed)
2026-04-13 13:41:56 -05:00
Shaun Arman
8e1d43da43 fix: address critical AI review issues
All checks were successful
Test / rust-fmt-check (pull_request) Successful in 28s
Test / frontend-typecheck (pull_request) Successful in 1m29s
Test / frontend-tests (pull_request) Successful in 1m31s
PR Review Automation / review (pull_request) Successful in 3m28s
Test / rust-clippy (pull_request) Successful in 4m29s
Test / rust-tests (pull_request) Successful in 5m42s
- Fix linuxdeploy AppImage extraction using --appimage-extract
- Remove 'has no column named' from duplicate column error handling
- Use strftime instead of datetime for created_at default format
2026-04-13 08:50:34 -05:00
Shaun Arman
2d7aac8413 fix: address AI review findings
All checks were successful
Test / rust-fmt-check (pull_request) Successful in 15s
Test / frontend-typecheck (pull_request) Successful in 1m21s
Test / frontend-tests (pull_request) Successful in 1m25s
PR Review Automation / review (pull_request) Successful in 3m32s
Test / rust-clippy (pull_request) Successful in 4m1s
Test / rust-tests (pull_request) Successful in 5m18s
- Add -L flag to curl for linuxdeploy redirects
- Split migration 015 into 015_add_use_datastore_upload and 016_add_created_at
- Use separate execute calls for ALTER TABLE statements
- Add idempotency test for migration 015
- Use bool type for use_datastore_upload instead of i64
2026-04-13 08:38:43 -05:00
Shaun Arman
84c69fbea8 fix: add missing ai_providers columns and fix linux-amd64 build
Some checks failed
Test / rust-fmt-check (pull_request) Successful in 15s
Test / rust-clippy (pull_request) Failing after 17s
Test / frontend-typecheck (pull_request) Successful in 1m23s
Test / frontend-tests (pull_request) Successful in 1m23s
PR Review Automation / review (pull_request) Successful in 3m16s
Test / rust-tests (pull_request) Successful in 4m19s
- Add migration 015 to add use_datastore_upload and created_at columns
- Handle column-already-exists errors gracefully
- Update Dockerfile to install linuxdeploy for AppImage bundling
- Add fuse dependency for AppImage support
2026-04-13 08:22:08 -05:00
Shaun Arman
2ce38b9477 fix(ci): resolve test.yml failures — Cargo.lock, updated test assertions
Cargo.lock:
- Commit the pre-existing version bump (0.1.0 → 0.2.50) so cargo
  --locked does not fail in CI; Cargo.toml already at 0.2.50

releaseWorkflowCrossPlatformArtifacts.test.ts:
- Update test that previously checked for ubuntu:22.04 / ports mirror
  inline in auto-tag.yml; that setup moved to the pre-baked
  trcaa-linux-arm64 image so the test now verifies the image reference
  and cross-compile env vars instead

ciDockerBuilders.test.ts:
- Update test that checked for docker:24-cli; changed to alpine:latest
  + docker-cli to avoid act_runner v0.3.1 duplicate socket mount bug;
  negative assertion on docker:24-cli retained
2026-04-12 20:16:32 -05:00
Shaun Arman
61cb5db63e fix: harden pr-review workflow and sync versions to 0.2.50
Workflow changes:
- Switch Ollama to https://ollama-ui.tftsr.com/ollama/v1 (OpenAI-compat)
  with OLLAMA_API_KEY secret — removes hardcoded internal IP
- Update endpoint to /chat/completions and response parsing to
  .choices[0].message.content for OpenAI-compat format
- Add concurrency block to prevent racing on same PR number
- Add shell: bash + set -euo pipefail to all steps
- Add TF_TOKEN presence validation before posting review
- Add --max-time 30 and HTTP status check to comment POST curl
- Redact common secret patterns from diff before sending to Ollama
- Add binary diff warning via grep for "^Binary files"
- Add UTC timestamps to Ollama call and review post log lines
- Add always-run Cleanup step to remove /tmp artifacts

Version consistency:
- Sync Cargo.toml and package.json from 0.1.0 to 0.2.50 to match
  tauri.conf.json
2026-04-12 17:40:12 -05:00
Shaun Arman
44584d6302 fix: restore migration 014, bump version to 0.2.50, harden pr-review workflow
- Restore 014_create_ai_providers migration and tests missing due to
  branch diverging from master before PR #34 merged
- Bump version from 0.2.10 to 0.2.50 to match master and avoid regression
- Trim diff input to 20 KB to prevent Ollama token overflow
- Add --max-time 120 to curl to prevent workflow hanging indefinitely
2026-04-12 17:40:12 -05:00
Shaun Arman
68d815e3e1 fix: add missing ai_providers migration (014)
All checks were successful
Test / frontend-tests (pull_request) Successful in 1m13s
Test / frontend-typecheck (pull_request) Successful in 1m15s
Test / rust-fmt-check (pull_request) Successful in 2m48s
Test / rust-clippy (pull_request) Successful in 18m34s
Test / rust-tests (pull_request) Successful in 20m17s
- Re-add migration 014_create_ai_providers to create ai_providers table
- Add test_create_ai_providers_table() to verify table schema
- Add test_store_and_retrieve_ai_provider() to verify CRUD operations
- Bump version to 0.2.49 in tauri.conf.json

Fixes missing AI provider data when upgrading from v0.2.42
2026-04-10 12:03:22 -05:00
Shaun Arman
6ebe3612cd fix: lint fixes and formatting cleanup
All checks were successful
Test / frontend-tests (pull_request) Successful in 1m9s
Test / frontend-typecheck (pull_request) Successful in 1m15s
Test / rust-fmt-check (pull_request) Successful in 2m44s
Test / rust-clippy (pull_request) Successful in 24m22s
Test / rust-tests (pull_request) Successful in 25m43s
- Fix TypeScript lint errors in setup.ts and LogUpload
- Remove unused imports and variables
- Fix duplicate Separator exports in ui/index.tsx
- Apply cargo fmt formatting to Rust code
- Update ESLint configuration
2026-04-09 20:42:40 -05:00
Shaun Arman
420411882e feat: support GenAI datastore file uploads and fix paste image upload
Some checks failed
Test / frontend-tests (pull_request) Successful in 59s
Test / frontend-typecheck (pull_request) Successful in 1m5s
Test / rust-fmt-check (pull_request) Failing after 2m25s
Test / rust-clippy (pull_request) Failing after 18m25s
Test / rust-tests (pull_request) Successful in 19m42s
- Add use_datastore_upload field to ProviderConfig for enabling datastore uploads
- Add upload_file_to_datastore and upload_file_to_datastore_any commands
- Add upload_log_file_by_content and upload_image_attachment_by_content commands for drag-and-drop without file paths
- Add multipart/form-data support for file uploads to GenAI datastore
- Add support for image/bmp MIME type in image validation
- Add x-generic-api-key header support for GenAI API authentication

This addresses:
- Paste fails to attach screenshot (clipboard)
- File upload fails with 500 error when using GenAI API
- GenAI datastore upload endpoint support for non-text files
2026-04-09 18:05:44 -05:00
Shaun Arman
e83dc19dcc chore: Format Rust code after merge
All checks were successful
Test / frontend-typecheck (pull_request) Successful in 59s
Test / frontend-tests (pull_request) Successful in 57s
Test / rust-fmt-check (pull_request) Successful in 2m13s
Test / rust-clippy (pull_request) Successful in 16m57s
Test / rust-tests (pull_request) Successful in 18m36s
2026-04-08 21:03:36 -05:00
Shaun Arman
d83e8598e0 Merge branch 'bug/branch-creation' into feat/image-attachments
Some checks failed
Test / frontend-typecheck (pull_request) Successful in 1m4s
Test / frontend-tests (pull_request) Successful in 57s
Test / rust-fmt-check (pull_request) Failing after 2m19s
Test / rust-tests (pull_request) Has been cancelled
Test / rust-clippy (pull_request) Has been cancelled
2026-04-08 20:58:25 -05:00
Shaun Arman
f6f48b934b fix: Fix encryption test race condition with parallel tests
Some checks failed
Test / frontend-tests (pull_request) Failing after 59s
Test / frontend-typecheck (pull_request) Failing after 1m1s
Test / rust-fmt-check (pull_request) Failing after 2m8s
Test / rust-clippy (pull_request) Has been cancelled
Test / rust-tests (pull_request) Has been cancelled
- Use test-specific key derivation instead of env vars
- Add helper functions encrypt_token_with_key/decrypt_token_with_key
- Avoid conflicts when tests run in parallel
2026-04-08 20:55:37 -05:00
Shaun Arman
9f6cab2436 fix: OpenWebUI provider connection and missing command registrations
- Add debug logging to OpenAI provider for troubleshooting
- Trim trailing periods from model names
- Fix HTTP error handling to capture response details
- Register missing AI provider commands (save/load/delete)
- Fix authenticateWithWebviewCmd to accept optional projectName parameter
2026-04-08 20:44:51 -05:00
Shaun Arman
19cc78a05f feat: add image attachment support with PII detection
Some checks failed
Test / frontend-tests (pull_request) Successful in 1m4s
Test / frontend-typecheck (pull_request) Failing after 1m6s
Test / rust-fmt-check (pull_request) Successful in 2m42s
Test / rust-clippy (pull_request) Successful in 19m1s
Test / rust-tests (pull_request) Failing after 20m7s
- Add image_attachments table to database schema (migration 013)
- Implement image upload, list, delete, and clipboard paste commands
- Add image file PII detection with user approval workflow
- Register image attachment commands in Tauri IPC
- Update TypeScript types and frontend components
- Add unit tests for image attachment functionality
- Update README and wiki documentation
2026-04-08 20:03:34 -05:00
Shaun Arman
93d396bde3 chore: add MIT license, security hardening, and repo hygiene
All checks were successful
Test / frontend-tests (pull_request) Successful in 56s
Test / frontend-typecheck (pull_request) Successful in 1m4s
Test / rust-fmt-check (pull_request) Successful in 2m50s
Test / rust-clippy (pull_request) Successful in 27m48s
Test / rust-tests (pull_request) Successful in 29m52s
License:
- Add MIT LICENSE file (Copyright 2025 Shaun Arman)
- Add MIT badge and Support/Buy-Me-A-Coffee section to README
- Update license section from private to MIT with attribution note

Security (from pre-release audit):
- Remove unscoped fs:allow-read and fs:allow-write from Tauri capabilities
  (H5: unscoped fs permissions undermined filesystem sandboxing; the
  scoped app/temp variants already cover all required paths)
- Add SECURITY_AUDIT.md to .gitignore

Repo hygiene:
- Untrack src-tauri/target/ (6347 build artifacts that should never
  have been committed; .gitignore already listed the path)
- Update .gitignore: remove vendor-specific filenames, replace with
  generic internal-doc patterns (TICKET_*.md, ~$*.docx, etc.)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-07 12:50:13 -05:00
Shaun Arman
9a132cce74 fix(fmt): apply rustfmt formatting to webview_fetch.rs
Some checks failed
Test / frontend-tests (pull_request) Successful in 2m10s
Test / frontend-typecheck (pull_request) Failing after 2m16s
Test / rust-fmt-check (pull_request) Has been cancelled
Test / rust-tests (pull_request) Has been cancelled
Test / rust-clippy (pull_request) Has been cancelled
Adjusted line breaks to match rustfmt conventions

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-04-07 09:47:57 -05:00
Shaun Arman
ead585f583 fix(lint): resolve all clippy warnings for CI compliance
Fixed 42 clippy warnings across integration and command modules:
- unnecessary_lazy_evaluations: Changed unwrap_or_else to unwrap_or
- uninlined_format_args: Modernized format strings to use inline syntax
- needless_borrows_for_generic_args: Removed unnecessary borrows
- only_used_in_recursion: Prefixed unused recursive param with underscore

All files now pass cargo clippy -- -D warnings

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-04-07 09:47:57 -05:00
Shaun Arman
1de50f1c87 chore: remove all proprietary vendor references for public release
- Delete internal vendor API documentation and handoff docs
- Remove vendor-specific AI gateway URLs from CSP whitelist
- Replace vendor-specific log prefixes and comments with generic 'Custom REST'
- Remove vendor-specific default auth header from custom REST implementation
- Remove vendor-specific client header from HTTP requests
- Remove backward-compat vendor format identifier from is_custom_rest_format()
- Remove LEGACY_API_FORMAT constant and normalizeApiFormat() helper
- Update test to not reference legacy format identifier
- Update wiki docs to use generic enterprise gateway configuration
- Update architecture diagrams and ADR-003 to remove vendor references
- Add Buy Me A Coffee link to README
- Update .gitignore to exclude internal user guide and ticket files

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-07 09:46:25 -05:00
Shaun Arman
d294847210 fix(lint): use inline format args in auth.rs
Fixes clippy::uninlined_format_args warnings by using inline
variable formatting (e.g., {e} instead of {}, e).

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-04-07 09:35:35 -05:00
Shaun Arman
f0358cfb13 fix(db,auth): auto-generate encryption keys for release builds
Fixes two critical issues preventing Mac release builds from working:

1. Database encryption key auto-generation: Release builds now
   auto-generate and persist the SQLCipher encryption key to
   ~/.../trcaa/.dbkey (mode 0600) instead of requiring the
   TFTSR_DB_KEY env var. This prevents 'file is not a database'
   errors when users don't set the env var.

2. Plain SQLite to encrypted migration: When a release build
   encounters a plain SQLite database (from a previous debug build),
   it now automatically migrates it to encrypted SQLCipher format
   using ATTACH DATABASE + sqlcipher_export. Creates a backup at
   .db.plain-backup before migration.

3. Credential encryption key auto-generation: Applied the same
   pattern to TFTSR_ENCRYPTION_KEY for encrypting AI provider API
   keys and integration tokens. Release builds now auto-generate
   and persist to ~/.../trcaa/.enckey (mode 0600) instead of
   failing with 'TFTSR_ENCRYPTION_KEY must be set'.

4. Refactored app data directory helper: Moved dirs_data_dir()
   from lib.rs to state.rs as get_app_data_dir() so it can be
   reused by both database and auth modules.

Testing:
- All unit tests pass (db::connection::tests + integrations::auth::tests)
- Verified manual migration from plain to encrypted database
- No clippy warnings

Impact: Users installing the Mac release build will now have a
working app out-of-the-box without needing to set environment
variables. Developers switching from debug to release builds will
have their databases automatically migrated.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-04-07 09:35:34 -05:00
Shaun Arman
9e8db9dc81 feat(ai): add tool-calling and integration search as AI data source
This commit implements two major features:

1. Integration Search as Primary AI Data Source
   - Confluence, ServiceNow, and Azure DevOps searches execute before AI queries
   - Search results injected as system context for AI providers
   - Parallel search execution for performance
   - Webview-based fetch for HttpOnly cookie support
   - Persistent browser windows maintain authenticated sessions

2. AI Tool-Calling (Function Calling)
   - Allows AI to automatically execute functions during conversation
   - Implemented for OpenAI-compatible providers and Custom REST provider
   - Created add_ado_comment tool for updating Azure DevOps tickets
   - Iterative tool-calling loop supports multi-step workflows
   - Extensible architecture for adding new tools

Key Files:
- src-tauri/src/ai/tools.rs (NEW) - Tool definitions
- src-tauri/src/integrations/*_search.rs (NEW) - Integration search modules
- src-tauri/src/integrations/webview_fetch.rs (NEW) - HttpOnly cookie workaround
- src-tauri/src/commands/ai.rs - Tool execution and integration search
- src-tauri/src/ai/openai.rs - Tool-calling for OpenAI and Custom REST provider
- All providers updated with tools parameter support

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-04-07 09:35:34 -05:00
Shaun Arman
9175faf0b4 refactor(ollama): remove download/install buttons — show plain install instructions only 2026-04-05 20:53:57 -05:00
Shaun Arman
2d02cfa9e8 style: apply cargo fmt to install_ollama_from_bundle 2026-04-05 19:41:59 -05:00
Shaun Arman
dffd26a6fd fix(security): add path canonicalization and actionable permission error in install_ollama_from_bundle 2026-04-05 19:34:47 -05:00
Shaun Arman
215c0ae218 feat(ui): fix model dropdown, auth prefill, PII persistence, theme toggle, and Ollama bundle
- AIProviders: hide top model row when custom_rest active (dropdown lower in form handles it);
  clear auth header prefill on format switch; rename User ID / CORE ID → Email Address
- Dashboard + Ollama: add border-border/bg-card classes to Refresh buttons for dark-bg contrast
- Security + settingsStore: wire PII toggle state to persisted Zustand store so pattern
  selections survive app restarts
- App: add Sun/Moon theme toggle button to sidebar footer (always visible when collapsed)
- system.rs: add install_ollama_from_bundle command (copies bundled binary to /usr/local/bin)
- auto-tag.yml: add Download Ollama step to all 4 platform build jobs with SHA256 verification
- tauri.conf.json: add resources/ollama/* to bundle resources
- docs: add install_ollama_from_bundle to IPC-Commands wiki

Security: CI download steps verify SHA256 against Ollama's published sha256sums.txt before bundling.
2026-04-05 19:30:41 -05:00
Shaun Arman
d87b01b154 feat(rebrand): rename binary to trcaa and auto-generate DB key
- Rename Cargo package from 'tftsr' to 'trcaa' — installed command
  becomes 'trcaa' instead of 'tftsr'
- Update app data directories to ~/.local/share/trcaa (Linux),
  ~/Library/Application Support/trcaa (macOS), %APPDATA%/trcaa (Windows)
- Update bundle identifier to com.trcaa.app
- Auto-generate per-installation DB encryption key on first launch and
  persist to <data_dir>/.dbkey (mode 0600 on Unix) — removes the hard
  requirement for TFTSR_DB_KEY to be set before the app will start
2026-04-05 17:50:16 -05:00
Shaun Arman
abab5c3153 fix(security): enforce PII redaction before AI log transmission
analyze_logs() was reading the original log file from disk and sending its
full contents to external AI providers, completely bypassing the redaction
pipeline. The redacted flag in log_files and the .redacted file on disk were
written by apply_redactions() but never consulted on the read path.

Fix: query the redacted column alongside file_path. If the file has not been
redacted, return an error to the caller before any AI provider call is made.
When redacted, read from {path}.redacted instead of the original.

Adds redacted_path_for() helper and two unit tests covering the rejection
and happy-path cases.
2026-04-05 10:08:16 -05:00
Shaun Arman
0a25ca7692 fix(pii): remove lookahead from hostname regex, fix fmt in analysis test
Rust's `regex` crate does not support lookaround assertions. The hostname
pattern `(?=.{1,253}\b)` caused a panic on every `PiiDetector::new()` call,
failing all four PII detector tests in CI (rust-fmt-check, rust-clippy,
rust-tests). Removed the lookahead; the remaining pattern correctly matches
valid FQDNs without the RFC 1035 length pre-check.

Also reformatted analysis.rs:253 to satisfy `rustfmt` (line break after `=`).

All 127 Rust tests pass and `cargo fmt --check` and `cargo clippy -- -D
warnings` are clean.
2026-04-05 09:59:19 -05:00
Shaun Arman
281e676ad1 fix(security): harden secret handling and audit integrity
Remove high-risk defaults and tighten data handling across auth, storage, IPC, provider calls, and capabilities so sensitive data is better protected by default. Also update README/wiki security guidance and add targeted tests for the new hardening behaviors.

Made-with: Cursor
2026-04-04 23:37:05 -05:00
Shaun Arman
c4ea32e660 feat: add custom_rest provider mode and rebrand application name
Rename custom API format handling from custom_rest to custom_rest with backward compatibility, add guided model selection with custom entry in provider settings, and rebrand app naming to Troubleshooting and RCA Assistant across UI, metadata, and docs.

Made-with: Cursor
2026-04-04 15:35:58 -05:00
Shaun Arman
0bc20f09f6 style: apply rustfmt output for clippy-related edits
Apply canonical rustfmt formatting in files touched by the clippy format-args cleanup so cargo fmt --check passes consistently in CI.

Made-with: Cursor
2026-04-04 15:10:17 -05:00
Shaun Arman
85a8d0a4c0 fix: resolve clippy format-args failures and OpenSSL vendoring issue
Inline format arguments across Rust modules to satisfy clippy -D warnings, and configure Cargo to prefer system OpenSSL so clippy builds do not fail on missing vendored Perl modules.

Made-with: Cursor
2026-04-04 15:05:13 -05:00
Shaun Arman
bdb63f3aee fix: resolve clippy uninlined_format_args in integrations and related modules
Replace format!("msg: {}", var) with format!("msg: {var}") across 8 files
to satisfy the uninlined_format_args lint (-D warnings) in CI run 178.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 12:27:26 -05:00
Shaun Arman
a7903db904 fix: persist integration settings and implement persistent browser windows
Some checks failed
Release / build-macos-arm64 (push) Successful in 4m52s
Release / build-linux-amd64 (push) Has been cancelled
Release / build-linux-arm64 (push) Has been cancelled
Release / build-windows-amd64 (push) Has been cancelled
## Integration Settings Persistence
- Add database commands to save/load integration configs (base_url, username, project_name, space_key)
- Frontend now loads configs from DB on mount and saves changes automatically
- Fixes issue where settings were lost on app restart

## Persistent Browser Window Architecture
- Integration browser windows now stay open for user browsing and authentication
- Extract fresh cookies before each API call to handle token rotation
- Track open windows in app state (integration_webviews HashMap)
- Windows titled as "{Service} Browser (TFTSR)" for clarity
- Support easy navigation between app and browser windows (Cmd+Tab/Alt+Tab)
- Gracefully handle closed windows with automatic cleanup

## Bug Fixes
- Fix Rust formatting issues across 8 files
- Fix clippy warnings:
  - Use is_some_and() instead of map_or() in openai.rs
  - Use .to_string() instead of format!() in integrations.rs
- Add missing OptionalExtension import for .optional() method

## Tests
- Add test_integration_config_serialization
- Add test_webview_tracking
- Add test_token_auth_request_serialization
- All 6 integration tests passing

## Files Modified
- src-tauri/src/state.rs: Add integration_webviews tracking
- src-tauri/src/lib.rs: Register 3 new commands, initialize webviews HashMap
- src-tauri/src/commands/integrations.rs: Config persistence, fresh cookie extraction (+151 lines)
- src-tauri/src/integrations/webview_auth.rs: Persistent window behavior
- src/lib/tauriCommands.ts: TypeScript wrappers for new commands
- src/pages/Settings/Integrations.tsx: Load/save configs from DB

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-04-04 09:57:22 -05:00
Shaun Arman
fbce897608 feat: complete webview cookie extraction implementation
Some checks failed
Release / build-macos-arm64 (push) Successful in 5m4s
Release / build-windows-amd64 (push) Has been cancelled
Release / build-linux-amd64 (push) Has been cancelled
Release / build-linux-arm64 (push) Has been cancelled
Implement working cookie extraction using Tauri's IPC event system:

**How it works:**
1. Opens embedded browser window for user to login
2. User completes authentication (including SSO)
3. User clicks "Complete Login" button in UI
4. JavaScript injected into webview extracts `document.cookie`
5. Parsed cookies emitted via Tauri event: `tftsr-cookies-extracted`
6. Rust listens for event and receives cookie data
7. Cookies encrypted and stored in database

**Technical implementation:**
- Uses `window.__TAURI__.event.emit()` from injected JavaScript
- Rust listens via `app_handle.listen()` with Listener trait
- 10-second timeout with clear error messages
- Handles empty cookies and JavaScript errors gracefully
- Cross-platform compatible (no platform-specific APIs)

**Cookie limitations:**
- `document.cookie` only exposes non-HttpOnly cookies
- HttpOnly session cookies won't be captured via JavaScript
- For HttpOnly cookies, services must provide API tokens as fallback

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-04-03 17:31:48 -05:00
Shaun Arman
32d83df3cf feat: add multi-mode authentication for integrations (v0.2.10)
Some checks failed
Release / build-windows-amd64 (push) Has been cancelled
Release / build-linux-amd64 (push) Has been cancelled
Release / build-macos-arm64 (push) Has been cancelled
Release / build-linux-arm64 (push) Has been cancelled
Implement three authentication methods for Confluence, ServiceNow, and Azure DevOps:

1. **OAuth2** - Traditional OAuth flow for enterprise SSO environments
2. **Embedded Browser** - Webview-based login that captures session cookies/tokens
   - Solves VPN constraints: users authenticate off-VPN via web UI
   - Extracted credentials work on-VPN for API calls
   - Based on confluence-publisher agent pattern
3. **Manual Token** - Direct API token/PAT input as fallback

**Changes:**
- Add webview_auth.rs module for embedded browser authentication
- Implement authenticate_with_webview and extract_cookies_from_webview commands
- Implement save_manual_token command with validation
- Add AuthMethod enum to support all three modes
- Add RadioGroup UI component for mode selection
- Complete rewrite of Integrations settings page with mode-specific UI
- Add secondary button variant for UI consistency

**VPN-friendly design:**
Users can authenticate via webview when off-VPN (web UI accessible), then use extracted cookies for API calls when on-VPN (API requires VPN). Addresses enterprise SSO limitations where OAuth app registration is blocked.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-04-03 17:26:09 -05:00
Shaun Arman
2c5e04a6ce feat: add temperature and max_tokens support for Custom REST providers (v0.2.9)
Some checks failed
Release / build-linux-amd64 (push) Has been cancelled
Release / build-windows-amd64 (push) Has been cancelled
Release / build-macos-arm64 (push) Has been cancelled
Release / build-linux-arm64 (push) Has been cancelled
- Added max_tokens and temperature fields to ProviderConfig
- Custom REST providers now send modelConfig with temperature and max_tokens
- OpenAI-compatible providers now use configured max_tokens/temperature
- Both formats fall back to defaults if not specified
- Bumped version to 0.2.9

This allows users to configure response length and randomness for all
AI providers, including Custom REST providers which require modelConfig format.
2026-04-03 17:08:34 -05:00
Shaun Arman
1d40dfb15b fix: use Wiki secret for authenticated wiki sync (v0.2.8)
Some checks failed
Release / build-macos-arm64 (push) Has been cancelled
Release / build-windows-amd64 (push) Has been cancelled
Release / build-linux-arm64 (push) Has been cancelled
Release / build-linux-amd64 (push) Has been cancelled
- Updated wiki-sync job to use secrets.Wiki for authentication
- Simplified clone/push logic with token-based auth
- Wiki push will now succeed with proper credentials
- Bumped version to 0.2.8

The workflow now uses the 'Wiki' secret created in Gitea Actions
to authenticate wiki repository pushes. This fixes the authentication
issue that was preventing automatic wiki synchronization.
2026-04-03 16:47:32 -05:00
Shaun Arman
94b486b801 feat: add automatic wiki sync to CI workflow (v0.2.7)
- Added wiki-sync job to .gitea/workflows/test.yml
- Runs only on pushes to master branch
- Automatically copies docs/wiki/*.md to Gogs wiki repository
- Supports token-based authentication via secrets.GITHUB_TOKEN
- Handles wiki initialization if repository doesn't exist
- Bumped version to 0.2.7

Wiki sync will now automatically update the Gogs wiki at
https://gogs.tftsr.com/sarman/tftsr-devops_investigation/wiki
whenever docs/wiki/ files are modified on master.
2026-04-03 16:42:37 -05:00
Shaun Arman
a42745b791 fix: add user_id support and OAuth shell permission (v0.2.6)
Some checks failed
Release / build-linux-arm64 (push) Has been cancelled
Release / build-linux-amd64 (push) Has been cancelled
Release / build-macos-arm64 (push) Has been cancelled
Release / build-windows-amd64 (push) Has been cancelled
Fixes:
- Added shell:allow-open permission to fix OAuth integration flows
- Added user_id field to ProviderConfig for Custom REST provider CORE ID
- Added UI field for user_id when api_format is custom_rest
- Made userId optional in Custom REST provider requests (only sent if provided)
- Added X-msi-genai-client header to Custom REST provider requests
- Updated CSP to include Custom REST provider domains
- Bumped version to 0.2.6

This fixes:
- OAuth error: 'Command plugin:shell|open not allowed by ACL'
- Missing User ID field in Custom REST provider configuration UI
2026-04-03 16:34:00 -05:00
Shaun Arman
190084888c feat: add Custom REST provider support
- Extended ProviderConfig with optional custom fields for non-OpenAI APIs
- Added custom_endpoint_path, custom_auth_header, custom_auth_prefix fields
- Added api_format field to distinguish between OpenAI and Custom REST provider formats
- Added session_id field for stateful conversation APIs
- Implemented chat_custom_rest() method in OpenAI provider
- Custom REST provider uses different request format (prompt+sessionId) and response (msg field)
- Updated TypeScript types to match Rust schema
- Added UI controls in Settings/AIProviders for custom provider configuration
- API format selector auto-populates appropriate defaults (OpenAI vs Custom REST provider)
- Backward compatible: existing providers default to OpenAI format
2026-04-03 15:45:42 -05:00
Shaun Arman
4172616c8b feat: implement Confluence, ServiceNow, and Azure DevOps REST API clients
- Confluence: OAuth2 bearer auth, list_spaces, search_pages, publish_page, update_page
- ServiceNow: Basic auth, search_incidents, create_incident, get_incident, update_incident
- Azure DevOps: OAuth2 bearer auth, search_work_items, create_work_item, get_work_item, update_work_item
- Added TicketResult.id field to support both sys_id and ticket_number
- All implementations follow TDD with mockito HTTP mocking
- 19 tests passing across all three integrations
2026-04-03 15:43:37 -05:00
Shaun Arman
1e8ef41e64 feat: add OAuth2 frontend UI and complete integration flow
Some checks failed
Auto Tag / auto-tag (push) Successful in 4s
Test / rust-fmt-check (push) Successful in 2m5s
Release / build-macos-arm64 (push) Successful in 10m29s
Test / rust-clippy (push) Failing after 18m4s
Release / build-linux-arm64 (push) Failing after 22m1s
Test / rust-tests (push) Successful in 12m44s
Test / frontend-typecheck (push) Successful in 1m29s
Test / frontend-tests (push) Has been cancelled
Release / build-windows-amd64 (push) Has been cancelled
Release / build-linux-amd64 (push) Has been cancelled
Phase 2.2: OAuth2 flow - FRONTEND COMPLETE 

Implemented:
- TypeScript command wrappers in tauriCommands.ts
  * initiateOauthCmd(service) -> OAuthInitResponse
  * handleOauthCallbackCmd(service, code, stateKey)
  * test*ConnectionCmd() for all services
  * OAuthInitResponse and ConnectionResult types

- Complete Settings/Integrations UI
  * Three integration cards: Confluence, ServiceNow, ADO
  * Connect with OAuth2 buttons (Confluence, ADO)
  * Basic auth note for ServiceNow
  * Configuration inputs: baseUrl, username, projectName, spaceKey
  * Test connection buttons with loading states
  * Success/error feedback with color-coded messages
  * OAuth2 flow instructions for users

- OAuth2 flow in browser
  * Opens auth URL in default browser via shell plugin
  * User authenticates with service
  * Redirected to localhost:8765/callback
  * Callback server handles token exchange automatically
  * Success message shown to user

- CSP updates in tauri.conf.json
  * Added http://localhost:8765 (callback server)
  * Added https://auth.atlassian.com (Confluence OAuth)
  * Added https://*.atlassian.net (Confluence API)
  * Added https://login.microsoftonline.com (ADO OAuth)
  * Added https://dev.azure.com (ADO API)

- UI improvements
  * Fixed Cancel button variant (ghost instead of secondary)
  * Loading spinners with Loader2 icon
  * Check/X icons for success/error states
  * Disabled states when not configured
  * Optimistic UI updates on connect

Frontend + Backend = COMPLETE END-TO-END OAUTH2 FLOW:
1. User goes to Settings → Integrations
2. Enters base URL and config
3. Clicks 'Connect with OAuth2'
4. Browser opens with service auth page
5. User logs in and authorizes
6. Redirected to localhost:8765/callback
7. Token exchanged and encrypted automatically
8. Stored in SQLite credentials table
9. Ready for API calls to external services 

TypeScript: All types checked, no errors
Frontend build:  Built in 2.26s
Total lines: ~400 lines of new UI code

Next: Phase 2.3 - Integration API clients (Confluence REST, ServiceNow REST, ADO REST)
2026-04-03 15:04:12 -05:00
Shaun Arman
05f4b51370 feat: implement OAuth2 callback server with automatic token exchange
Some checks are pending
Auto Tag / auto-tag (push) Waiting to run
Test / rust-fmt-check (push) Waiting to run
Test / rust-clippy (push) Waiting to run
Test / rust-tests (push) Waiting to run
Test / frontend-typecheck (push) Waiting to run
Test / frontend-tests (push) Waiting to run
Phase 2.2: OAuth2 flow - Part 3 (Callback server) COMPLETE 

Implemented:
- Local HTTP server on localhost:8765 using warp
  * GET /callback?code=...&state=... - OAuth redirect handler
  * GET /health - Health check endpoint
  * Graceful shutdown with oneshot channel

- Automatic callback handling
  * Server auto-starts on first initiate_oauth call
  * Background task listens for OAuth redirects
  * Automatically exchanges code for token
  * Stores encrypted token in database
  * Logs audit event for each successful OAuth

- Updated initiate_oauth command
  * Starts callback server if not running
  * Stores (service, verifier) tuple in OAuth state
  * Returns auth URL to open in browser/webview

- Updated handle_oauth_callback_internal
  * Accepts AppState reference (not State)
  * Called automatically by callback server
  * Exchanges code, encrypts token, stores in DB

- Beautiful success/error HTML pages
  * Green checkmark on success
  * Auto-closes window after 3 seconds
  * Clear error messages on failure

- Global state management
  * OAUTH_STATE: Maps state key -> (service, verifier)
  * CALLBACK_SERVER_SHUTDOWN: Holds shutdown channel
  * Thread-safe with Mutex wrappers

Dependencies added:
- warp 0.3 - Lightweight HTTP framework

TDD tests (7 passing with --test-threads=1):
Callback server tests:
  * Health endpoint verification
  * Callback parameter parsing
  * Missing/partial parameter handling
  * Graceful shutdown

Integration command tests:
  * OAuth state storage and retrieval
  * Multiple key management
  * OAuthInitResponse serialization

COMPLETE OAUTH2 FLOW:
1. User calls initiate_oauth("confluence")
2. Callback server starts (if not running)
3. Frontend receives auth URL
4. User opens URL in browser/webview
5. User authorizes, redirected to localhost:8765/callback?code=...
6. Callback server receives redirect
7. Token exchanged automatically
8. Token encrypted and stored in DB
9. Success page shown to user
10. Window auto-closes

Next: Frontend components (AuthWindow, Settings UI, CSP updates)
2026-04-03 14:59:39 -05:00
Shaun Arman
75302a1cc7 feat: add OAuth2 Tauri commands for integration authentication
Some checks are pending
Auto Tag / auto-tag (push) Waiting to run
Test / rust-fmt-check (push) Waiting to run
Test / rust-clippy (push) Waiting to run
Test / rust-tests (push) Waiting to run
Test / frontend-typecheck (push) Waiting to run
Test / frontend-tests (push) Waiting to run
Phase 2.2: OAuth2 flow - Part 2 (Tauri commands)

Implemented:
- initiate_oauth command
  * Generates PKCE challenge
  * Creates state key for OAuth session
  * Stores verifier in global OAuth state
  * Returns authorization URL for Confluence/ADO
  * ServiceNow uses basic auth (not OAuth2)

- handle_oauth_callback command
  * Retrieves and removes verifier from state
  * Exchanges authorization code for access token
  * Encrypts and stores token in DB
  * Logs audit event for successful OAuth

- OAuthInitResponse type for frontend
  * auth_url: Full OAuth authorization URL
  * state: Session key for callback matching

- Global OAUTH_STATE storage (lazy_static)
  * Thread-safe HashMap for PKCE verifiers
  * Temporary storage during OAuth flow
  * Automatically cleaned up after exchange

Service configuration:
- Confluence: auth.atlassian.com OAuth2
- Azure DevOps: login.microsoftonline.com OAuth2
- ServiceNow: Basic auth (not OAuth2)

Client IDs from env vars:
- CONFLUENCE_CLIENT_ID
- ADO_CLIENT_ID

Dependencies added:
- lazy_static 1.4 - Global static initialization

TDD tests (3 passing):
- OAuth state storage and retrieval
- Multiple key management
- OAuthInitResponse serialization

Commands registered in lib.rs generate_handler![]

Next: Local HTTP callback server for OAuth redirects
2026-04-03 14:50:13 -05:00
Shaun Arman
01474fb5f2 feat: implement OAuth2 token exchange and AES-256-GCM encryption
Phase 2.2: OAuth2 flow - Part 1 (Token exchange + encryption)

Implemented:
- OAuth2 authorization code exchange with PKCE
  * Real HTTP POST to token endpoint
  * Parses access_token, refresh_token, expires_in, token_type
  * Calculates expires_at timestamp

- AES-256-GCM token encryption
  * Uses TFTSR_ENCRYPTION_KEY env var (or dev default)
  * Random nonce per encryption (12 bytes)
  * Base64-encoded output with nonce prepended
  * Proper key derivation (32 bytes)

- Updated credential storage
  * store_pat() now encrypts tokens before DB storage
  * get_pat() decrypts tokens on retrieval
  * Stores both token_hash (audit) and encrypted_token (actual)

Dependencies added:
- mockito 1.7.2 (dev) - HTTP mocking for tests
- aes-gcm 0.10 - AES-256-GCM encryption
- rand 0.8 - Cryptographically secure RNG

TDD tests (20 passing with --test-threads=1):
- OAuth exchange: success, missing token, HTTP error, network error
- Encryption: roundtrip, different nonces, invalid data, wrong key
- PAT storage: store/retrieve, nonexistent service, replacement

Note: Tests require single-threaded execution due to env var
test isolation. This is acceptable for CI/CD.
2026-04-03 14:32:17 -05:00