Commit Graph

79 Commits

Author SHA1 Message Date
Shaun Arman
8b227c1837 fix(kube): resolve automated PR review blockers and warnings
Some checks failed
Test / frontend-tests (pull_request) Successful in 1m26s
Test / frontend-typecheck (pull_request) Successful in 1m35s
PR Review Automation / review (pull_request) Successful in 5m6s
Test / rust-fmt-check (pull_request) Failing after 11m23s
Test / rust-clippy (pull_request) Successful in 13m2s
Test / rust-tests (pull_request) Successful in 14m47s
Blockers:
- Replace serde_yaml::from_str with serde_json::from_str in all 6
  parse_*_json functions (parse_namespaces, parse_pods, parse_services,
  parse_deployments, parse_statefulsets, parse_daemonsets). Update
  .as_sequence() → .as_array(), .as_mapping() → .as_object(), and
  mapping iterator patterns throughout. Explicitly type serde_yaml::Value
  in extract_context/extract_server_url which legitimately parse YAML.

Warnings:
- Add containers: Vec<String> to PodInfo struct; parse from
  spec.containers[].name in parse_pods_json
- Fix PodList.tsx to use selectedPod.containers instead of [selectedPod.name]
- Fix exec_pod: add optional shell param with allowlist validation
  (sh/bash/ash/dash); correct arg ordering — -c container now placed
  before -- separator
- Handle empty namespace with --all-namespaces in all 5 list commands
- Fix dialog overflow: overflow-hidden → overflow-y-auto on inner div
- Memoize namespace options with useMemo in ResourceBrowser

Lint cleanup (all pre-existing, surfaced by eslint config fix):
- Deduplicate eslint.config.js (was doubled to 272 lines); move ignores
  to standalone global object; allow console.log in cli section
- Remove stale .eslintignore (migrated to eslint.config.js)
- Remove unused Card/CardTitle imports from Kubernetes list components
- Rename unused props to _clusterId/_namespace in DaemonSetList,
  ServiceList, StatefulSetList
- Fix useEffect/useCallback missing deps in Triage and LogUpload
- Remove debug console.log from App.tsx provider auto-test
- Rename unused hover prop to _hover in TableRow (ui/index.tsx)
- Add #[allow(unused_variables)] to Phase 3 stub Tauri commands
- Restore get_pod_logs, scale_deployment, restart_deployment,
  delete_resource, exec_pod to lib.rs handler registration (were
  accidentally dropped in Phase 3 expansion)

All checks pass: cargo clippy -D warnings, tsc --noEmit,
eslint --max-warnings 0, 331 Rust tests, 98 frontend tests.
2026-06-06 23:55:44 -05:00
Shaun Arman
e585415598 feat: implement full Lens-like Kubernetes UI with resource discovery and management
Some checks failed
Test / frontend-tests (pull_request) Successful in 1m33s
Test / frontend-typecheck (pull_request) Successful in 1m42s
PR Review Automation / review (pull_request) Successful in 4m28s
Test / rust-fmt-check (pull_request) Failing after 11m26s
Test / rust-clippy (pull_request) Successful in 12m46s
Test / rust-tests (pull_request) Successful in 14m24s
- Add ResourceBrowser with namespace/resource type tabs for pods, services, deployments, statefulsets, daemonsets
- Implement PodList with logs viewer and container selection
- Implement ServiceList with cluster IP, type, ports display
- Implement DeploymentList with scale and restart operations
- Add backend commands: list_namespaces, list_pods, list_services, list_deployments, list_statefulsets, list_daemonsets
- Add resource management commands: get_pod_logs, scale_deployment, restart_deployment, delete_resource, exec_pod
- Add UI components: Table, Tabs, Dialog, Alert to shared UI library
- Update KubernetesPage to use new ResourceBrowser component
- All tests passing (331 Rust + 98 frontend)
- Build successful in release mode
2026-06-06 23:08:01 -05:00
Shaun Arman
e56a72a31a feat(k8s): implement clean-room Kubernetes management GUI
Some checks failed
Test / frontend-typecheck (pull_request) Successful in 1m48s
Test / frontend-tests (pull_request) Successful in 1m33s
PR Review Automation / review (pull_request) Successful in 6m23s
Test / rust-fmt-check (pull_request) Successful in 13m8s
Test / rust-tests (pull_request) Has been cancelled
Test / rust-clippy (pull_request) Has been cancelled
- Backend: kube module with ClusterClient, PortForwardSession, RefreshRegistry
- 7 Tauri IPC commands: add_cluster, remove_cluster, list_clusters, start_port_forward, stop_port_forward, list_port_forwards, delete_port_forward, shutdown_port_forwards
- AppState extended with clusters, port_forwards, refresh_registry fields
- Version bumped to 1.1.0 in Cargo.toml and package.json
- Auto-tag workflow updated to mark releases as draft (pre-release)
- Buy Me A Coffee section added to README.md
- Fixed changelog workflow to only include current tag commits
- Proper kubeconfig YAML parsing with extract_context and extract_server_url
- Added kubeconfig content storage in ClusterClient
- Updated PortForwardSession to include cluster_name
- Frontend GUI components: ClusterList, PortForwardList, AddClusterModal, PortForwardForm, KubernetesPage
- TypeScript types and IPC commands for Kubernetes management
- Unit tests for Kubernetes IPC commands (6 tests)
- All 332 Rust tests passing
- All 98 frontend tests passing
- TypeScript type checks passing
- Project builds successfully in release mode
- Committed and pushed to feature/kubernetes-management branch
- Command injection vulnerability fixed with regex validation and max length check (253 chars)
- stop_port_forward and shutdown_port_forwards properly kill kubectl child processes via async child management
- Temp file cleanup implemented with RAII TempFileCleanup struct created before std::fs::write
- discover_pods now parses actual kubectl JSON output
- ChildWaitHandle implemented with background task for waiting on kubectl child
- PortForwardSession uses Arc<TokioMutex<Option<Child>>> for async-safe child management
- Port-forward uses kubectl's dynamic port binding (0) instead of TcpListener
- Added shutdown_port_forwards command for app shutdown cleanup
- Added cleanup effect in App.tsx to call shutdownPortForwardsCmd on unmount
- Database CRUD operations for clusters and port_forwards added to db.rs
- validate_resource_name uses lazy_static! for cached Regex to prevent ReDoS
- Cluster struct updated to store kubeconfig_content directly instead of kubeconfig_id
- Cluster model in db/models.rs updated to use kubeconfig_content field
- load_clusters and load_port_forwards commands registered in lib.rs
- Temp file cleanup moved to background task in ChildWaitHandle to ensure cleanup after kubectl completes
- Unused child_id field removed from ChildWaitHandle
- Command validation moved to beginning of start_port_forward before any operations
- Fixed lint errors: removed unused imports, fixed React hooks order, updated type annotations
- Updated eslint.config.js to properly configure file patterns
2026-06-06 20:27:39 -05:00
Shaun Arman
ec257ef55f docs(kubernetes): add comment about dynamic port allocation limitation
All checks were successful
PR Review Automation / review (pull_request) Successful in 3m58s
Test / frontend-tests (pull_request) Successful in 1m23s
Test / frontend-typecheck (pull_request) Successful in 1m31s
Test / rust-fmt-check (pull_request) Successful in 12m6s
Test / rust-clippy (pull_request) Successful in 12m54s
Test / rust-tests (pull_request) Successful in 14m9s
2026-06-06 19:46:04 -05:00
Shaun Arman
c0318e8570 fix(kubernetes): address automated PR review findings
Some checks failed
Test / frontend-typecheck (pull_request) Successful in 1m39s
Test / frontend-tests (pull_request) Successful in 1m42s
PR Review Automation / review (pull_request) Has been cancelled
Test / rust-tests (pull_request) Has been cancelled
Test / rust-clippy (pull_request) Has been cancelled
Test / rust-fmt-check (pull_request) Has been cancelled
- Move command validation to beginning of start_port_forward before any operations
- Fix race condition: temp file cleanup now happens in background task after kubectl completes
- Remove unused child_id field from ChildWaitHandle
- Add comments explaining validation placement and cleanup timing
2026-06-06 19:44:32 -05:00
Shaun Arman
7b77511bdb feat(kubernetes): add database persistence for clusters and port_forwards
All checks were successful
Test / frontend-tests (pull_request) Successful in 1m33s
Test / frontend-typecheck (pull_request) Successful in 1m41s
PR Review Automation / review (pull_request) Successful in 3m57s
Test / rust-fmt-check (pull_request) Successful in 11m13s
Test / rust-clippy (pull_request) Successful in 12m50s
Test / rust-tests (pull_request) Successful in 14m29s
- Add load_clusters and load_port_forwards commands to db.rs
- Update remove_cluster to delete from database
- Update delete_port_forward to delete from database
- Add Cluster and PortForward imports to db.rs
- Add load commands to lib.rs generate_handler
- Fix formatting issues
2026-06-06 19:29:42 -05:00
Shaun Arman
c53cfdd84f fix: add shutdown_port_forwards command for app cleanup
Some checks failed
PR Review Automation / review (pull_request) Successful in 5m32s
Test / rust-clippy (pull_request) Has been cancelled
Test / rust-tests (pull_request) Has been cancelled
Test / frontend-typecheck (pull_request) Has been cancelled
Test / rust-fmt-check (pull_request) Has been cancelled
Test / frontend-tests (pull_request) Has been cancelled
- Add shutdown_port_forwards() to kill all child processes on app exit
- Update lib.rs to register the new command
- PortForwardSession::close() handles both child kill and temp file cleanup
2026-06-06 18:46:13 -05:00
Shaun Arman
2134b880b9 fix: address automated PR review findings
Some checks failed
PR Review Automation / review (pull_request) Successful in 3m43s
Test / frontend-typecheck (pull_request) Successful in 2m0s
Test / frontend-tests (pull_request) Successful in 1m42s
Test / rust-clippy (pull_request) Has been cancelled
Test / rust-fmt-check (pull_request) Has been cancelled
Test / rust-tests (pull_request) Has been cancelled
- Temp file cleanup: move TempFileCleanup struct before std::fs::write
  to ensure cleanup happens even on panic (race condition fix)
- PortForwardSession: add explicit close() method for async cleanup
  of child process and temp files
- delete_port_forward: call close() before removing session
- All temp file operations now use RAII pattern with cleanup before write
2026-06-06 18:40:52 -05:00
Shaun Arman
c515886cbf fix: properly handle kubectl subprocess with async child management
- Replace Arc<Mutex<Child>> with Arc<Mutex<Option<Child>>> for Send/Sync safety
- Store child in ChildWaitHandle with background task for async waiting
- Implement stop_async() to properly kill kubectl subprocess
- Add temp kubeconfig cleanup via RAII TempFileCleanup
- Cache regex pattern with lazy_static! for performance
- Add namespace validation with max length check (253 chars)
- Update stop_port_forward to use stop_async() for proper cleanup
2026-06-06 18:32:08 -05:00
Shaun Arman
4ba0eb1ca9 fix: address all automated PR review findings
All checks were successful
Test / frontend-tests (pull_request) Successful in 1m29s
Test / frontend-typecheck (pull_request) Successful in 1m36s
PR Review Automation / review (pull_request) Successful in 4m11s
Test / rust-fmt-check (pull_request) Successful in 11m2s
Test / rust-clippy (pull_request) Successful in 12m37s
Test / rust-tests (pull_request) Successful in 14m6s
- Add validate_resource_name() with ReDoS protection (max 253 chars)
- Fix stop_port_forward to actually kill kubectl child process
- Add temp file cleanup with TempFileCleanup struct
- Fix discover_pods to parse actual kubectl JSON output
- Update test to use container_ports array instead of container_port
2026-06-06 16:54:30 -05:00
Shaun Arman
40bd6162ae fix: address automated PR review findings
All checks were successful
Test / frontend-tests (pull_request) Successful in 1m24s
Test / frontend-typecheck (pull_request) Successful in 1m32s
PR Review Automation / review (pull_request) Successful in 4m1s
Test / rust-fmt-check (pull_request) Successful in 11m9s
Test / rust-clippy (pull_request) Successful in 12m25s
Test / rust-tests (pull_request) Successful in 13m58s
- Add regex validation for namespace/pod to prevent command injection
- Fix start_port_forward to properly spawn kubectl subprocess
- Use kubectl's dynamic port binding (0) instead of TcpListener
- Update PortForwardResponse to use arrays for all ports
- Fix stop_port_forward to wait for kubectl termination
- Add cascade delete for port forwards on cluster removal
- Fix Drop/stop implementations to handle kill errors properly
2026-06-06 16:23:00 -05:00
Shaun Arman
cacd15b8c1 feat(kube): implement complete kubectl port-forward runtime
- Dynamic local port allocation via TcpListener::bind
- Kubectl subprocess spawning with proper cleanup
- Database persistence for clusters and port_forwards
- Cluster health check (kubectl cluster-info)
- Pod discovery (kubectl get pods)
- Comprehensive unit and integration tests
- All 325 Rust tests passing
- All 98 frontend tests passing
- TypeScript type checks passing
2026-06-06 15:36:35 -05:00
Shaun Arman
0615ec2054 fix(fmt): format code with cargo fmt
All checks were successful
Test / frontend-typecheck (pull_request) Successful in 1m47s
Test / frontend-tests (pull_request) Successful in 1m42s
PR Review Automation / review (pull_request) Successful in 3m59s
Test / rust-fmt-check (pull_request) Successful in 12m24s
Test / rust-clippy (pull_request) Successful in 14m0s
Test / rust-tests (pull_request) Successful in 15m45s
2026-06-06 14:00:09 -05:00
Shaun Arman
05ec2e4fbb fix: address clippy warnings
Some checks failed
Test / frontend-tests (pull_request) Successful in 1m26s
Test / frontend-typecheck (pull_request) Successful in 1m34s
PR Review Automation / review (pull_request) Successful in 3m33s
Test / rust-fmt-check (pull_request) Failing after 10m30s
Test / rust-clippy (pull_request) Successful in 12m7s
Test / rust-tests (pull_request) Successful in 13m54s
- Remove unused imports
- Use PortForwardSessionConfig struct to reduce function arguments
2026-06-06 13:47:51 -05:00
Shaun Arman
1d0689556d fix(fmt): format code with cargo fmt
Some checks failed
Test / frontend-tests (pull_request) Successful in 1m22s
Test / frontend-typecheck (pull_request) Successful in 1m33s
PR Review Automation / review (pull_request) Successful in 3m29s
Test / rust-fmt-check (pull_request) Successful in 10m27s
Test / rust-clippy (pull_request) Failing after 12m9s
Test / rust-tests (pull_request) Successful in 13m37s
2026-06-06 13:30:35 -05:00
Shaun Arman
c2e0f47bbe fix: implement kubeconfig parsing and add kubeconfig storage
Some checks failed
PR Review Automation / review (pull_request) Has been cancelled
Test / frontend-tests (pull_request) Has been cancelled
Test / rust-clippy (pull_request) Has been cancelled
Test / frontend-typecheck (pull_request) Has been cancelled
Test / rust-tests (pull_request) Has been cancelled
Test / rust-fmt-check (pull_request) Has been cancelled
- Store kubeconfig content in ClusterClient for future use
- Update ClusterClient to accept kubeconfig_content as Arc<String>
- Update PortForwardSession to include cluster_name for kubectl invocation
2026-06-06 13:28:03 -05:00
Shaun Arman
03e86dc326 fix: implement proper kubeconfig parsing and validation
Some checks failed
Test / frontend-tests (pull_request) Successful in 1m23s
Test / frontend-typecheck (pull_request) Successful in 1m29s
PR Review Automation / review (pull_request) Successful in 3m37s
Test / rust-fmt-check (pull_request) Failing after 11m1s
Test / rust-clippy (pull_request) Successful in 11m49s
Test / rust-tests (pull_request) Has been cancelled
- Implement extract_context to parse kubeconfig YAML and extract context name
- Implement extract_server_url to parse kubeconfig YAML and extract server URL
- Add empty content validation for kubeconfig
- Add YAML parsing error handling with actionable error messages
2026-06-06 13:17:56 -05:00
Shaun Arman
a7a0f01674 feat(kube): implement delete_port_forward command
Some checks failed
Test / frontend-tests (pull_request) Successful in 1m26s
Test / frontend-typecheck (pull_request) Successful in 1m31s
PR Review Automation / review (pull_request) Successful in 3m27s
Test / rust-clippy (pull_request) Has been cancelled
Test / rust-fmt-check (pull_request) Has been cancelled
Test / rust-tests (pull_request) Has been cancelled
- Add delete_port_forward Rust command to remove port forwards from state
- Update tauriCommands.ts to use delete_port_forward command
- Register delete_port_forward in lib.rs invoke handler
2026-06-06 13:09:14 -05:00
Shaun Arman
1a07a1bac4 fix(fmt): format code with cargo fmt 2026-06-06 12:04:21 -05:00
Shaun Arman
b96ede35cd feat(kube): add Kubernetes management support
Some checks failed
Auto Tag / autotag (push) Successful in 7s
Auto Tag / wiki-sync (push) Successful in 8s
Test / frontend-tests (push) Successful in 1m31s
Test / frontend-typecheck (push) Successful in 1m39s
Auto Tag / changelog (push) Successful in 1m47s
Auto Tag / build-macos-arm64 (push) Successful in 2m52s
Auto Tag / build-linux-amd64 (push) Has been cancelled
Auto Tag / build-linux-arm64 (push) Has been cancelled
Auto Tag / build-windows-amd64 (push) Has been cancelled
Test / rust-fmt-check (push) Has been cancelled
Test / rust-clippy (push) Has been cancelled
Test / rust-tests (push) Has been cancelled
- Bump version to 1.1.0
- Add kube module with ClusterClient, PortForwardSession, RefreshRegistry
- Add Tauri IPC commands: add_cluster, remove_cluster, list_clusters
- Add Tauri IPC commands: start_port_forward, stop_port_forward, list_port_forwards
- Update AppState with clusters, port_forwards, refresh_registry fields
- Update auto-tag.yml to mark releases as draft (pre-release)
- Add Buy Me A Coffee section to README
- Add serde_yaml dependency for kubeconfig parsing
2026-06-06 11:41:23 -05:00
Shaun Arman
40b6882cab fix: comprehensive trcaa→tftsr conversion and URL corrections
Some checks failed
Test / rust-fmt-check (pull_request) Failing after 14s
Test / rust-clippy (pull_request) Failing after 16s
Test / rust-tests (pull_request) Failing after 18s
Test / frontend-typecheck (pull_request) Successful in 1m27s
Test / frontend-tests (pull_request) Successful in 1m28s
PR Review Automation / review (pull_request) Successful in 3m4s
Complete sanitization pass to ensure consistency:

**1. Repository/Project Name Changes:**
- trcaa-devops_investigation → tftsr-devops_investigation (everywhere)
- gogs.trcaa.com → gogs.tftsr.com (all URLs)
- ollama-ui.trcaa.com → ollama-ui.tftsr.com

**2. Internal CI URLs (must use 172.0.0.29):**
- gitea.tftsr.com:3000 → 172.0.0.29:3000 in:
  - AGENTS.md
  - README.md
  - docs/architecture/README.md
  - docs/wiki/*.md
- CI runners cannot reach external DNS

**3. Code Simplifications:**
- MSIGenAI/TFTSRGenAI → GenAI (src-tauri/src/ai/openai.rs)
- Cleaner comments without org-specific references

**4. Build System Updates:**
- Makefile: GH_TOKEN → GOGS_TOKEN, GH_REPO → GOGS_REPO
- Commented out GitHub release upload commands
- Fixed lib name: tftsr_lib → trcaa_lib (src/main.rs)

**5. Documentation Cleanup:**
- CLAUDE.md: Fixed wiki URL, Woodpecker→Gitea Actions
- Removed PLAN.md, SECURITY_AUDIT.md (not needed in git)
- Removed hackathon docs (HACKATHON-*.md)
- Removed v1.0.5/7/8 summary docs (superseded)

**6. Preserved:**
- TRCAA (all caps) = application name (correct!)
- trcaa package name in Cargo.toml (correct!)
- trcaa_lib library name (correct!)

**Test Results:** 308 Rust + 92 frontend tests passing

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-06-05 15:38:29 -05:00
Shaun Arman
093495a653 feat: full copy from apollo_nxt-trcaa with complete sanitization
Some checks failed
Test / rust-fmt-check (pull_request) Failing after 0s
Test / rust-clippy (pull_request) Failing after 1s
Test / rust-tests (pull_request) Failing after 0s
Test / frontend-typecheck (pull_request) Failing after 16s
Test / frontend-tests (pull_request) Failing after 18s
PR Review Automation / review (pull_request) Failing after 4m13s
Complete backport of all features from apollo_nxt-trcaa repository:
- Three-tier shell execution safety system (Tier 1: auto, Tier 2: approve, Tier 3: deny)
- Ollama function calling with tool use support
- AI provider tool calling auto-detection
- kubectl binary bundling and management
- kubeconfig upload and context management
- Shell approval modal with real-time UI
- MCP protocol HTTP transport with custom headers
- Enhanced security audit logging
- Comprehensive test coverage (275+ tests)
- Updated CI/CD workflows for Gitea Actions
- Complete documentation (ADRs, wiki, release notes)

Sanitization applied to all files:
- Removed all MSI, Motorola, VNXT, Vesta references
- Replaced internal infrastructure references with TFTSR equivalents
- Updated all URLs and API endpoints
- Sanitized commit history references in documentation

Technical changes:
- New modules: shell/classifier, shell/executor, shell/kubectl, shell/kubeconfig
- Enhanced AI providers: ollama.rs, openai.rs with function calling
- New Tauri commands: shell execution, kubeconfig management, tool calling detection
- Database migrations: shell_execution_audit table
- Frontend: ShellApprovalModal, ShellExecution, KubeconfigManager pages
- CI/CD: kubectl bundling, multi-platform builds, Gitea Actions integration

Version: 1.0.8

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-06-05 14:12:43 -05:00
Shaun Arman
8c96bfcba2 fix: add missing @testing-library/dom dependency and fix clippy warning
All checks were successful
Test / rust-fmt-check (pull_request) Successful in 1m27s
Test / frontend-tests (pull_request) Successful in 1m30s
Test / frontend-typecheck (pull_request) Successful in 1m32s
Test / rust-clippy (pull_request) Successful in 3m25s
PR Review Automation / review (pull_request) Successful in 4m47s
Test / rust-tests (pull_request) Successful in 5m27s
- Add @testing-library/dom ^10.4.1 to devDependencies (required by @testing-library/react)
- Fix clippy::uninlined_format_args warning in shell.rs (use inline format)

Resolves CI test failures in frontend tests and rust-clippy job.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-06-05 10:11:41 -05:00
Shaun Arman
276fdae104 fix: address valid PR review findings
Some checks failed
Test / rust-fmt-check (pull_request) Successful in 2m19s
Test / rust-clippy (pull_request) Failing after 4m15s
Test / frontend-typecheck (pull_request) Successful in 2m35s
Test / frontend-tests (pull_request) Failing after 1m47s
Test / rust-tests (pull_request) Successful in 6m17s
PR Review Automation / review (pull_request) Successful in 8m17s
Fix two valid issues identified in automated code review:

1. Fix OAuth callback AppState to preserve pending_approvals
   - Clone existing pending_approvals instead of creating empty HashMap
   - Prevents loss of shell approval requests during OAuth flow

2. Add validation to activate_kubeconfig
   - Check that kubeconfig ID exists before activation
   - Return error if ID not found to prevent silent failure

Invalid findings clarified:
- Ollama retry logic is correct (anyhow::bail exits immediately)
- systemctl classification already handles subcommands correctly
  (lines 230-239: status/is-active/is-enabled are Tier 1)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-06-05 09:04:28 -05:00
Shaun Arman
57fff0c8a2 style: run cargo fmt to fix formatting
All checks were successful
PR Review Automation / review (pull_request) Successful in 2m19s
Fix formatting in integrations.rs and ollama/installer.rs per cargo fmt.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-06-05 08:43:50 -05:00
Shaun Arman
1400f43d7a feat: add kubectl binary bundling for cross-platform support
Download and package kubectl v1.30.0 binaries for Linux (amd64/arm64),
Windows, macOS.

- Add scripts/download-kubectl.sh for kubectl binary management
- Update Cargo.toml dependencies (http 1.4, thiserror 2, rand 0.8)
- Add ollama/installer::start_ollama_service() and find_ollama_binary()
- Fix rand API deprecation (thread_rng deprecated in favor of rng in 0.8)
- Fix AppState initialization in integrations.rs (add pending_approvals)
- Configure kubectl as Tauri sidecar (currently empty array for dev)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-06-05 08:22:54 -05:00
Shaun Arman
117ab390a2 feat: add Ollama function calling and tool calling auto-detection
Enable Ollama models to execute shell commands. Add detection command
for provider capability testing.

- Replace ai/ollama.rs with function calling support (180s timeout, retry logic)
- Update ai/openai.rs with tool calling improvements
- Add detect_tool_calling_support() command to commands/ai.rs

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-06-05 08:13:51 -05:00
Shaun Arman
ea170ab340 feat: add three-tier shell execution with kubectl support
Introduce shell classifier, executor, kubeconfig manager, and kubectl
binary management. Integrates with existing commands/agentic.rs primitives.

- Add shell/classifier.rs: Three-tier safety classification (Tier 1: auto-execute, Tier 2: approve, Tier 3: deny)
- Add shell/executor.rs: Command executor with approval gates
- Add shell/kubeconfig.rs: kubeconfig parsing and management
- Add shell/kubectl.rs: kubectl binary management
- Add commands/shell.rs: Tauri IPC commands for shell execution
- Update state.rs: Add pending_approvals field for approval flow
- Update lib.rs: Register shell module and commands

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-06-05 07:59:04 -05:00
Shaun Arman
249d20bf85 fix: audit PII redaction metadata, safe bubble update, update ticket
All checks were successful
Test / rust-fmt-check (pull_request) Successful in 1m54s
Test / frontend-typecheck (pull_request) Successful in 2m6s
Test / frontend-tests (pull_request) Successful in 2m5s
Test / rust-clippy (pull_request) Successful in 3m59s
PR Review Automation / review (pull_request) Successful in 4m10s
Test / rust-tests (pull_request) Successful in 5m15s
Add was_pii_redacted and pii_types_redacted to the ai_chat audit log
entry. Both are tracked through the full_message build block (typed
message + attachments) so any redaction that occurs is always
reflected in the compliance record.

Fix response.user_message + suffix potentially yielding 'undefined...'
when user_message is absent. Now unconditionally calls
updateMessageContent with (response.user_message ?? message) + suffix,
so the bubble always shows a valid string regardless of backend build.

Update TICKET-pii-bypass-chat-attachments.md to reflect the final
auto-redact design (not block/warn) so automated review comparisons
against the ticket stop flagging design decisions as defects.
2026-05-31 20:14:23 -05:00
Shaun Arman
631221dbf1 fix(security): full-content PII scan, clippy, IPC null fix, scan size cap
All checks were successful
Test / rust-fmt-check (pull_request) Successful in 1m40s
Test / frontend-typecheck (pull_request) Successful in 1m48s
Test / frontend-tests (pull_request) Successful in 1m43s
Test / rust-clippy (pull_request) Successful in 3m17s
Test / rust-tests (pull_request) Successful in 4m33s
PR Review Automation / review (pull_request) Successful in 5m0s
Remove frontend detectPiiCmd pre-scan loop — backend is sole redaction
authority; bubble update via response.user_message covers user feedback.

Detect PII on full file content before truncating. Previous order
(truncate to 8000 bytes then scan) could miss PII straddling the
boundary. Now: read full content, scan, redact, then truncate to
EMBED_LIMIT (8000 bytes) at a valid UTF-8 char boundary.

logFileIds IPC: pass undefined (not null) for empty array so Tauri
serialises it correctly to Rust Option::None.

Add MAX_TEXT_SCAN_BYTES (32 KB) guard in scan_text_for_pii to prevent
unbounded regex evaluation on oversized payloads.

Fix clippy uninlined_format_args in ai.rs.
2026-05-31 20:01:07 -05:00
Shaun Arman
e9c576f606 fix(security): frontend attachment scan notice, bubble redaction update, fmt fix
Some checks failed
Test / rust-fmt-check (pull_request) Successful in 2m3s
Test / frontend-tests (pull_request) Successful in 1m56s
Test / frontend-typecheck (pull_request) Successful in 1m58s
Test / rust-clippy (pull_request) Failing after 3m0s
Test / rust-tests (pull_request) Successful in 4m22s
PR Review Automation / review (pull_request) Successful in 4m35s
Addresses three findings from the third automated review:

[BLOCKER] No frontend PII pre-check on attachments.
Added detectPiiCmd call for each logFileId before chatMessageCmd.
PII is not blocked (per explicit product decision: auto-redact and
send) but the user now sees a non-blocking amber notice listing
each file and the PII types that will be auto-redacted. Backend
remains the authoritative redaction layer.

[WARNING 2] Chat bubble showed original PII-laden message even though
only the redacted form was sent to AI.
Added updateMessageContent to sessionStore. After chatMessageCmd
returns, if response.user_message is set the user bubble is updated
to reflect what was actually stored in the DB, so the UI is
consistent with the audit log.

CI fix: cargo fmt changes to analysis.rs were not staged in the prior
commit. Committed here — fmt check now passes cleanly.
2026-05-31 19:49:21 -05:00
Shaun Arman
a04d6fc8f5 fix(security): backend-only PII redaction; fix fmt CI failure
Some checks failed
Test / frontend-typecheck (pull_request) Successful in 1m52s
Test / frontend-tests (pull_request) Successful in 1m51s
Test / rust-fmt-check (pull_request) Failing after 1m58s
Test / rust-clippy (pull_request) Failing after 3m4s
Test / rust-tests (pull_request) Successful in 4m31s
PR Review Automation / review (pull_request) Successful in 4m43s
Resolves all three findings from the second automated review and
fixes the cargo fmt --check CI failure (formatting drift in analysis.rs
from a prior merge).

[BLOCKER 1 + BLOCKER 2 + WARNING]
Frontend no longer performs any PII scanning or redaction. All three
concerns stemmed from the same root cause: outMessage was derived
on the frontend and used for display, DB storage (via lastUserMsgRef
and the chat bubble), and the AI payload — causing the original message
to be silently replaced before the backend received it.

Fix: frontend sends the original message verbatim. Backend is now the
sole authority. chat_message auto-redacts the typed message text using
PiiDetector + apply_redactions() before building the full payload, logs
the PII types via tracing::warn, and stores only the redacted form in
ai_messages and the audit log. The redacted form is returned to the
caller as ChatResponse.user_message (Option<String>, absent from direct
provider calls).

Frontend uses message (original) for the chat bubble and
lastUserMsgRef — resolution steps show natural language, not
[Password] tokens. The AI and DB see only the redacted version.

CI fix: cargo fmt applied to analysis.rs; all format checks now pass.
2026-05-31 19:36:44 -05:00
Shaun Arman
f05b954250 fix(security): address PR review — move attachment handling to backend, auto-redact PII
Some checks failed
Test / rust-fmt-check (pull_request) Failing after 1m25s
Test / frontend-typecheck (pull_request) Successful in 1m37s
Test / frontend-tests (pull_request) Successful in 1m36s
Test / rust-clippy (pull_request) Failing after 3m18s
PR Review Automation / review (pull_request) Successful in 4m19s
Test / rust-tests (pull_request) Successful in 4m30s
Resolves all four findings from the automated review:

[BLOCKER 1] Attachment PII scan error path left pendingFiles intact,
allowing retry with stale file references. Fix: file content is no
longer held in frontend state at all — PendingFile drops the content
field entirely. logFileIds are captured before setPendingFiles([]) and
passed directly to the backend.

[BLOCKER 2] Raw file content stored in PendingFile.content created a
UI-visible PII surface and a data-residency risk. Fix: frontend never
reads or stores file content. The backend loads file data from disk,
auto-redacts PII in-memory using pii::apply_redactions(), and embeds
the clean text into the AI message. No PII ever touches the frontend.

[WARNING 1] String-based attachment header parsing was fragile and
bypassable. Fix: parsing is gone — backend identifies attachments by
log_file_id, reads them directly from the DB/disk path, and applies
redaction at that level.

[WARNING 2] Error message disclosed PII type list to the caller. Fix:
PII types are logged via tracing::warn only; no type details in the
user-facing error or API response.

Additionally: typed chat messages are now auto-redacted rather than
blocked. scanTextForPiiCmd runs on the typed text; detected spans are
replaced in reverse-offset order before the message is sent to the AI
and stored in the DB. The user sees the redacted form in their chat
bubble.

Architecture:
- chat_message now accepts log_file_ids: Option<Vec<String>>
- Backend reads file → detects PII → redacts in memory → embeds
- Frontend: no readTextFile, no content field, no frontend PII gate
2026-05-31 19:20:46 -05:00
Shaun Arman
cd26801a39 fix(security): block PII in chat attachments and typed messages
Some checks failed
Test / rust-fmt-check (pull_request) Failing after 1m31s
Test / frontend-tests (pull_request) Successful in 1m34s
Test / frontend-typecheck (pull_request) Successful in 1m36s
Test / rust-clippy (pull_request) Successful in 3m5s
PR Review Automation / review (pull_request) Successful in 4m31s
Test / rust-tests (pull_request) Successful in 4m27s
File attachments were embedded into AI messages without any PII
scanning, allowing credentials, tokens, and other sensitive data
to be forwarded to AI providers in plaintext.

Typed chat messages had the same gap: a user could type a password
or API key directly and it would be sent unscanned.

Changes:
- chat_message (Rust): defence-in-depth scan of all attachment body
  content (between --- Attached: markers); hard rejects if PII found
- detect_pii (Rust): fix return type from pii::PiiDetectionResult
  (spans/original_text) to db::models::PiiDetectionResult
  (detections/total_pii_found) to match the TypeScript contract; the
  LogUpload PII review workflow was receiving undefined for detections
- scan_text_for_pii (Rust): new command — scans arbitrary text for PII
  without creating DB records; used for typed message warnings
- Triage/index.tsx: PendingFile now carries logFileId; handleSend gates
  each text attachment through detectPiiCmd (hard block on PII found);
  typed message text scanned via scanTextForPiiCmd with a one-time
  warning — second send of same message proceeds as acknowledgment
2026-05-31 19:05:51 -05:00
Shaun Arman
911b6f591b fix: address PR review findings — compress errors, size guard, modal error display
Some checks failed
Test / rust-fmt-check (pull_request) Failing after 1m43s
Test / frontend-typecheck (pull_request) Successful in 2m8s
Test / frontend-tests (pull_request) Successful in 2m7s
Test / rust-clippy (pull_request) Successful in 3m17s
Test / rust-tests (pull_request) Successful in 4m32s
PR Review Automation / review (pull_request) Successful in 5m25s
- compress_text now returns Result<Vec<u8>, String>; callers propagate
  the error instead of silently storing empty BLOB on gzip failure
- upload_image_attachment_by_content and upload_paste_image now validate
  decoded byte length against MAX_IMAGE_FILE_BYTES before DB storage,
  closing the size-bypass gap that existed for base64 content uploads
- Image View modal in AttachmentsTab now surfaces the error string when
  get_image_attachment_data fails, replacing the opaque "could not be
  loaded" message with actionable diagnostic text

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
2026-05-31 18:06:07 -05:00
Shaun Arman
1b36ebfb3d feat: attachment DB storage and cross-incident recall
All checks were successful
Test / rust-fmt-check (pull_request) Successful in 1m35s
Test / frontend-tests (pull_request) Successful in 1m41s
Test / frontend-typecheck (pull_request) Successful in 1m43s
Test / rust-clippy (pull_request) Successful in 3m10s
Test / rust-tests (pull_request) Successful in 4m39s
PR Review Automation / review (pull_request) Successful in 4m58s
Store compressed log content and raw image bytes in SQLite so attachments
are self-contained regardless of source file availability on disk.

DB (migrations 020-022):
- log_files.content_compressed BLOB — gzip-compressed extracted text
- image_attachments.image_data BLOB — raw image bytes
- Views v_log_files_with_issue and v_image_attachments_with_issue for
  cross-incident queries with joined issue title

Rust backend:
- compress_text / decompress_text helpers (flate2 rust_backend / miniz_oxide)
  with 100 MB decompression-bomb guard
- upload_log_file*, upload_log_file_by_content store content_compressed
- upload_image_attachment*, upload_paste_image store image_data
- New commands: get_log_file_content, list_all_log_files (analysis.rs)
- New commands: get_image_attachment_data, list_all_image_attachments (image.rs)
- All commands fall back to file_path for pre-migration records

Frontend:
- LogFileSummary, ImageAttachmentSummary types in tauriCommands.ts
- attachmentStore (Zustand) — loadAttachments, searchAttachments
- History page: Issues tab (existing) + Attachments tab (new)
  with log/image tables, search bar, View modals, lazy thumbnails

Tests: 227 Rust (+16 new), 103 frontend (+9 new), tsc clean, clippy clean

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
2026-05-31 17:55:47 -05:00
Shaun Arman
1a9c3bd65a fix(sudo): enforce username scope and singleton row in sudo_config
All checks were successful
Test / rust-fmt-check (pull_request) Successful in 1m20s
Test / frontend-tests (pull_request) Successful in 1m41s
Test / frontend-typecheck (pull_request) Successful in 1m43s
Test / rust-clippy (pull_request) Successful in 3m7s
PR Review Automation / review (pull_request) Successful in 4m11s
Test / rust-tests (pull_request) Successful in 4m27s
Fixes two bugs identified in the AI code review:

1. INSERT OR REPLACE with a freshly generated UUID never matches the
   existing primary key, so it appended rows instead of replacing.
   Switch to DELETE-then-INSERT to guarantee exactly one row.

2. Username defaulted to empty string. Resolve it to the current OS
   user (USER/LOGNAME env vars, fallback 'local') so credentials are
   always bound to a specific user identity.

   test_sudo_password now passes -u <username> to sudo so the test
   runs scoped to the stored user, not an arbitrary one.

UI: show the configured username prominently in status; relabel the
field and add a scope hint below it.

Tests: test_set_sudo_singleton_delete_then_insert, three username
resolution tests.
2026-05-31 15:46:29 -05:00
Shaun Arman
f6787accd6 fix(agentic): inline format arg in writeln! to satisfy clippy::uninlined_format_args
All checks were successful
Test / rust-fmt-check (pull_request) Successful in 1m36s
Test / frontend-typecheck (pull_request) Successful in 1m34s
Test / frontend-tests (pull_request) Successful in 1m37s
Test / rust-clippy (pull_request) Successful in 3m7s
PR Review Automation / review (pull_request) Successful in 4m24s
Test / rust-tests (pull_request) Successful in 4m22s
Rust 1.88 enforces clippy::uninlined_format_args as a style lint under
-D warnings. Change `writeln!(stdin, "{}", password)` to the inline
form `writeln!(stdin, "{password}")`.
2026-05-31 14:19:29 -05:00
Shaun Arman
cf1d5adb83 docs(analysis): document zip-slip safety guarantee in extract_docx_text
Some checks failed
Test / rust-fmt-check (pull_request) Successful in 1m35s
Test / frontend-typecheck (pull_request) Successful in 2m16s
Test / frontend-tests (pull_request) Successful in 2m13s
Test / rust-clippy (pull_request) Failing after 3m43s
PR Review Automation / review (pull_request) Successful in 4m11s
Test / rust-tests (pull_request) Successful in 4m59s
Only a single hardcoded entry (word/document.xml) is ever accessed from
the ZIP archive; no arbitrary path extraction occurs, so path traversal
attacks cannot apply. Add a comment to make this invariant explicit for
future maintainers.
2026-05-31 13:57:38 -05:00
Shaun Arman
ed2e25f835 chore: update Cargo.lock for lopdf, zip, quick-xml deps 2026-05-31 13:51:08 -05:00
Shaun Arman
f47ec90d05 feat(upload): add safe file extension validation and binary text extraction
- Add extension allowlist (SAFE_TEXT_EXTENSIONS + SAFE_BINARY_EXTENSIONS)
  rejecting unsupported file types at both upload_log_file and
  upload_log_file_by_content entry points
- Add extract_text_content() with PDF text extraction via lopdf and
  DOCX extraction via zip+quick-xml
- Binary files (PDF/DOCX) get extracted text written to .extracted.txt
  for downstream PII detection
- Expand frontend file input accept list and add collapsible
  supported-formats disclosure element
- Add 11 unit tests covering allowlist logic and extraction paths
2026-05-31 13:50:59 -05:00
Shaun Arman
cd67a09a6a fix(ai,search): load history across all conversations; deep search related tables
AI history continuity: Changed the history-load query in chat_message to
JOIN ai_conversations and select by issue_id instead of single conversation_id.
This preserves full context when provider/model changes mid-triage.

Deep search: Added DISTINCT to list_issues SELECT and extended the search
filter with EXISTS subqueries covering ai_messages, resolution_steps,
log_files, and timeline_events. Ensures comprehensive search without
duplicate results.

Includes 11 new unit tests covering both features.
2026-05-31 13:50:29 -05:00
Shaun Arman
a779756e48 style(mcp): apply rustfmt formatting
Some checks failed
PR Review Automation / review (pull_request) Has been cancelled
Test / rust-fmt-check (pull_request) Successful in 1m46s
Test / frontend-typecheck (pull_request) Successful in 1m39s
Test / frontend-tests (pull_request) Successful in 1m39s
Test / rust-clippy (pull_request) Successful in 3m26s
Test / rust-tests (pull_request) Successful in 4m54s
2026-05-23 16:48:26 -05:00
Shaun Arman
3588399dfd feat(mcp): add MCP Server Support with TDD implementation
Some checks failed
Test / rust-fmt-check (pull_request) Failing after 2m12s
Test / frontend-typecheck (pull_request) Successful in 2m23s
Test / frontend-tests (pull_request) Successful in 2m22s
Test / rust-clippy (pull_request) Successful in 3m55s
Test / rust-tests (pull_request) Successful in 5m10s
PR Review Automation / review (pull_request) Failing after 11m6s
Adds full Model Context Protocol (MCP) server management, enabling the
AI assistant to discover and call tools from external MCP servers during
triage conversations.

Backend (Rust):
- rmcp 1.7.0 dependency (client + stdio + Streamable HTTP transports)
- Migration 018: mcp_servers, mcp_tools, mcp_resources tables with
  CHECK constraints for transport_type, auth_type, discovery_status
- src/mcp/ module: models, store, client, adapter, discovery, commands,
  transport/{stdio,http}
- AppState gains mcp_connections: Arc<TokioMutex<HashMap<...>>>
- .setup() hook auto-discovers enabled servers at startup
- 8 new Tauri commands wired into invoke_handler
- execute_mcp_tool_call: PII scan + mandatory audit_log before execution
- Auth values encrypted at rest via integrations::auth::encrypt_token();
  scrubbed before any frontend response

Frontend:
- MCPServers.tsx settings page (/settings/mcp) with server list,
  status badges, Discover Now, Add/Edit modal, enable/disable toggle
- tauriCommands.ts: McpServer, McpTool, McpServerStatus types + 8 cmds
- App.tsx: Plug icon, /settings/mcp route, sidebar nav entry

Tests (TDD): 15 new tests, all green
- 5 migration tests (written before migration, red → green)
- 5 store CRUD + encryption tests
- 5 adapter sanitization + conversion tests

Verification: 185/185 Rust, 94/94 Vitest, clippy -D warnings: 0
2026-05-23 16:23:48 -05:00
Shaun Arman
0b7f1cd9ab feat(ai): add devops-incident-responder agent with domain auto-detection
Some checks failed
Test / rust-fmt-check (pull_request) Successful in 1m29s
Test / frontend-typecheck (pull_request) Successful in 1m28s
Test / frontend-tests (pull_request) Successful in 1m30s
Test / rust-clippy (pull_request) Successful in 3m33s
Test / rust-tests (pull_request) Successful in 4m54s
PR Review Automation / review (pull_request) Failing after 8m49s
- Implement AgentRegistry system with devops-incident-responder agent
- Add domain detection based on conversation keywords
- Inject devops-incident-responder as primary system prompt
- Auto-switch domain prompts silently when context shifts
- Fix version update script to handle JSON format correctly
- Always display version in bottom-left corner
- Add release notes fallback to git commits if CHANGELOG empty

This implements the full devops-incident-responder agent as the primary
system prompt, with domain-specific SME prompts layered on top based on
conversation content analysis. The version display bug is fixed by removing
the collapsed condition, and release notes now have a fallback mechanism.
2026-04-29 19:41:47 -05:00
Shaun Arman
8b0cbc3ce8 fix: harden timeline event input validation and atomic writes
Address security review findings:
- Validate event_type against whitelist of 7 known types (M-3)
- Validate metadata is valid JSON and under 10KB (M-2, M-4)
- Include metadata in audit log details (M-2)
- Wrap timeline insert + audit write + timestamp update in a
  SQLite transaction for atomicity (M-5)
- Fix TypeScript TimelineEvent interface: add issue_id, metadata
  fields and correct created_at type to string (L-3)
- Add timeline_events to IssueDetail TypeScript interface (L-4)
2026-04-19 18:25:53 -05:00
Shaun Arman
13c4969e31 feat: wire incident response methodology into AI and record triage events
Add INCIDENT_RESPONSE_FRAMEWORK to domainPrompts.ts and append it to
all 17 domain prompts via getDomainPrompt(). Add system_prompt param
to chat_message command so frontend can inject domain expertise. Record
UTC timeline events (triage_started, log_uploaded, why_level_advanced,
root_cause_identified, rca_generated, postmortem_generated,
document_exported) at key moments with non-blocking calls.

Update tauriCommands.ts with getTimelineEventsCmd, optional metadata on
addTimelineEventCmd, and systemPrompt on chatMessageCmd.

12 new frontend tests (9 domain prompts, 3 timeline events).
2026-04-19 18:13:47 -05:00
Shaun Arman
107fee8853 feat: add timeline_events table, model, and CRUD commands
- Add migration 017_create_timeline_events with indexes
- Update TimelineEvent struct with issue_id, metadata, UTC string timestamps
- Add TimelineEvent::new() constructor with UUIDv7
- Add timeline_events field to IssueDetail
- Rewrite add_timeline_event to write to new table + audit_log (dual-write)
- Add get_timeline_events command for ordered retrieval
- Update get_issue to load timeline_events
- Update delete_issue to clean up timeline_events
- Register get_timeline_events in generate_handler
- Add migration tests for table, indexes, and cascade delete
- Fix flaky derive_aes_key test (env var race condition in parallel tests)
2026-04-19 18:02:38 -05:00
Shaun Arman
9e1a9b1d34 feat: implement dynamic versioning from Git tags
Some checks failed
Test / rust-clippy (pull_request) Failing after 15s
Test / rust-tests (pull_request) Failing after 19s
Test / rust-fmt-check (pull_request) Successful in 55s
Test / frontend-typecheck (pull_request) Successful in 1m22s
Test / frontend-tests (pull_request) Successful in 1m26s
PR Review Automation / review (pull_request) Successful in 2m57s
- Add build.rs to read version from git describe --tags
- Create update-version.mjs script to sync version across files
- Add get_app_version() command to Rust backend
- Update App.tsx to use custom version command
- Run version update in CI before Rust checks
2026-04-13 16:12:03 -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