Commit Graph

93 Commits

Author SHA1 Message Date
Shaun Arman
05d8b28159 fix(kube): network/config/storage list actions use item.namespace not filter prop
Service/Ingress/ConfigMap/Secret/HPA/PVC/ServiceAccount/Role/RoleBinding/
NetworkPolicy/ResourceQuota/LimitRange action handlers now use the resource's
own .namespace field instead of the UI filter namespace='all'. Removes the
now-unused ns local variable from CronJobList/JobList/ReplicaSetList.

24 new TDD tests verify the correct namespace is passed to getResourceYamlCmd
and deleteResourceCmd for each of the 12 affected components.
2026-06-08 22:00:23 -05:00
Shaun Arman
84bac9aa34 fix(kube): add namespace to PodInfo; pod actions use pod.namespace not filter
Pod actions (logs, shell, attach, edit, delete) were receiving namespace='all'
from the UI filter prop and passing it to kubectl as -n all. Fixes by adding
namespace field to PodInfo (Rust + TypeScript) and using pod.namespace in all
action command calls in PodList.
2026-06-08 21:56:56 -05:00
Shaun Arman
bf8443c9f5 fix(kube): WorkloadOverview loads data; single connect on mount; visible error on failure
- workloads_overview now fetches pods/deployments/statefulsets/daemonsets/jobs/
  cronjobs in parallel via Promise.allSettled
- loadInitialData initializedRef guard prevents double connectClusterFromKubeconfig
- connection errors now surface as a dismissible banner instead of being swallowed
2026-06-08 21:55:34 -05:00
Shaun Arman
c871318009 fix(ui): replace hardcoded colors with semantic Tailwind vars for dark mode
Non-adaptive text-gray-* and bg-white classes replaced with text-foreground,
text-muted-foreground, bg-card, bg-background — ensuring readable contrast
in both light and dark themes.
2026-06-08 21:52:01 -05:00
Shaun Arman
aee739c078 feat(kube): nav restructure, action menus, new resource lists, advanced components
Navigation:
- Restructure to match requested layout: Cluster, Nodes, Workloads, Config,
  Network, Storage, Namespaces, Events, Helm, Access Control, Custom Resources
- Workloads: add Overview dashboard and Replication Controllers
- Config: add PDB, PriorityClass, RuntimeClass, Lease, Mutating/Validating Webhooks
- Network: add Endpoints, EndpointSlices, IngressClasses; move Port Forwarding here
- Helm and Custom Resources sections wired through

New shared components:
- ResourceActionMenu: state-aware MoreHorizontal dropdown
- ConfirmDeleteDialog: confirmation guard for all destructive operations
- ScaleModal: replica count dialog (Deployments, StatefulSets, ReplicaSets, RCs)
- LogsModal: container log viewer replacing PodList inline dialog
- ShellExecModal: kubectl exec -it with container and shell selector
- AttachModal: kubectl attach -it with container selector

New resource list components (12):
ReplicationControllerList, PodDisruptionBudgetList, PriorityClassList,
RuntimeClassList, LeaseList, MutatingWebhookList, ValidatingWebhookList,
EndpointList, EndpointSliceList, IngressClassList, NamespaceList,
WorkloadOverview

New advanced components (5):
LogStreamPanel (Tauri-event streaming, follow/search/download),
HelmChartList, HelmReleaseList, CrdList, CustomResourceList

Updated 24 existing list components with context-appropriate action menus:
- Pods: Logs, Shell, Attach, Edit, Delete, Force Delete (state-aware)
- Deployments: Scale, Restart, Rollback, Edit, Delete
- StatefulSets/ReplicaSets: Scale, Restart/none, Edit, Delete
- DaemonSets: Restart, Edit, Delete
- Jobs: Edit, Delete
- CronJobs: Suspend/Resume (state-aware), Trigger, Edit, Delete
- Services/Ingresses/ConfigMaps/Secrets/HPAs/PVCs/PVs/StorageClasses/
  NetworkPolicies/ResourceQuotas/LimitRanges: Edit, Delete
- Nodes: Cordon/Uncordon (state-aware), Drain, Edit
- All RBAC resources: Edit, Delete

Co-Authored-By: TFTSR Engineering <noreply@tftsr.com>
2026-06-08 20:38:05 -05:00
Shaun Arman
879fdf4239 feat(kube): add TypeScript types and command stubs for all new K8s resources
Add interfaces and invoke() wrappers for new resource types, Helm, CRDs,
resource actions (attach, force-delete, describe, get-yaml, log streaming),
and workload controls (restart/scale statefulset/daemonset/replicaset, cronjob ops).

Co-Authored-By: TFTSR Engineering <noreply@tftsr.com>
2026-06-08 20:16:55 -05:00
Shaun Arman
d331e9c7c7 fix(ui): correct font contrast and background colors in dark mode
All checks were successful
Test / frontend-tests (pull_request) Successful in 1m38s
Test / frontend-typecheck (pull_request) Successful in 1m40s
Test / rust-fmt-check (pull_request) Successful in 14m53s
Test / rust-tests (pull_request) Successful in 18m2s
Test / rust-clippy (pull_request) Successful in 15m46s
PR Review Automation / review (pull_request) Successful in 3m46s
Replace hardcoded light-mode Tailwind colors with dark: variants
across six components. Issues that broke readability:

- PiiDiffViewer / Security: toggle knob was bg-white (invisible on
  bg-muted in dark mode) -> bg-background
- ImageGallery: thumbnail container, filename labels, alert banners,
  and modal chrome all used hardcoded gray/white backgrounds with dark
  text; added full dark: variants throughout
- ShellExecution TIER_CONFIG: tier cards used bg-green/yellow/red-50
  (near-white) with dark text; added dark:bg-*-950/30 backgrounds and
  light text for all three tiers
- ShellApprovalModal: tier 2 badge hardcoded bg-yellow-50/text-yellow-700;
  added dark: variants
- LogUpload: PII warning alert used bg-amber-50/text-amber-800; added
  dark:bg-amber-900/20 and lighter text for dark mode
2026-06-07 21:30:50 -05:00
Shaun Arman
48292e959e fix(kube): switch to --kubeconfig flag; add Test Connection diagnostic
Some checks failed
PR Review Automation / review (pull_request) Has been cancelled
Test / frontend-typecheck (pull_request) Successful in 1m37s
Test / frontend-tests (pull_request) Successful in 1m39s
Test / rust-fmt-check (pull_request) Successful in 10m45s
Test / rust-clippy (pull_request) Successful in 12m27s
Test / rust-tests (pull_request) Successful in 14m43s
Credential error persists: switch all 40 kubectl invocations from using
KUBECONFIG env var to the explicit --kubeconfig CLI flag. The flag has higher
precedence in kubectl's lookup order and is unambiguous regardless of any
inherited KUBECONFIG env var in the parent process environment.

Also adds test_kubectl_connection Tauri command (runs kubectl cluster-info
with the stored kubeconfig) and a Test button in Settings → Kubeconfig so
the exact kubectl output — context name, exit code, full stdout/stderr — is
visible without needing to inspect tracing logs. This output will reveal
whether the issue is expired certs, a missing exec-auth plugin, wrong context,
or something else entirely.
2026-06-07 20:31:50 -05:00
Shaun Arman
a2cff014e9 fix(kube): use current-context for kubectl auth; fix SelectValue label display
Some checks failed
Test / rust-tests (pull_request) Successful in 14m31s
PR Review Automation / review (pull_request) Has been cancelled
Test / frontend-typecheck (pull_request) Successful in 1m35s
Test / frontend-tests (pull_request) Successful in 1m40s
Test / rust-fmt-check (pull_request) Successful in 11m1s
Test / rust-clippy (pull_request) Successful in 12m39s
## kubectl credentials still failing after --context fix

Root cause: both extract_context() (kube.rs) and upload_kubeconfig() (shell.rs)
ignored the kubeconfig's current-context field and always picked contexts[0] from
the contexts array. If a kubeconfig has multiple contexts and current-context
points to entry N>0, we silently used the wrong context — one that may have empty
or expired credentials — causing the 401 "the server has asked for the client to
provide credentials" error on every kubectl call.

Fixes:
- extract_context(): read current-context field first; fall back to contexts[0]
  only when current-context is absent or empty.
- extract_current_context_name(): new helper in kubeconfig.rs using the same
  line-scanner approach as parse_kubeconfig_contexts (no extra dependencies).
- upload_kubeconfig(): use current-context to select the matching context entry
  when storing context name in kubeconfig_files; falls back to first entry.

NOTE: existing kubeconfig rows in the database have the old (wrong) context
stored. Re-uploading kubeconfig files after deploying this build will fix them.

## Cluster dropdown still showing UUID

Root cause: SelectValue rendered ctx.value (the raw UUID passed to SelectItem's
value prop) instead of the display label (SelectItem's children). The custom
Select component had no mechanism to mirror a selected item's children into the
trigger area.

Fix: Select now builds a value→label Map by walking the children tree at render
time (collectLabels). The map is memoised on children. SelectValue reads the
display label from the map; if found, shows the label; otherwise falls back to
the raw value so existing behaviour is preserved for callers that don't need it.
2026-06-07 19:40:53 -05:00
Shaun Arman
fb55601e3b fix(kube): correct kubectl context, dialog close, icon visibility, cluster name
Some checks failed
Test / rust-tests (pull_request) Successful in 14m38s
PR Review Automation / review (pull_request) Has been cancelled
Test / frontend-tests (pull_request) Successful in 1m50s
Test / frontend-typecheck (pull_request) Successful in 1m56s
Test / rust-fmt-check (pull_request) Successful in 11m10s
Test / rust-clippy (pull_request) Successful in 12m54s
1. kubectl credentials error (41 places in kube.rs)
   Every kubectl invocation used .env("KUBERNETES_CONTEXT", context) which
   is not a real kubectl environment variable — kubectl silently ignores it
   and falls back to whatever current-context is set in the kubeconfig YAML.
   If that context has expired or wrong credentials the auth failure occurs.
   Replaced all 41 instances with .arg("--context").arg(context) so kubectl
   always uses the correct context from the stored kubeconfig.

2. Cluster name still showed UUID (two causes)
   a) Hotbar read from kubernetesStore.clusters (ClusterInfo[]) which is never
      populated by the kubeconfig-based flow — always empty, so selectedCluster
      was always undefined. Removed the Zustand cluster lookup from Hotbar and
      added a clusterName prop passed from KubernetesPage.tsx (selectedConfig?.name).
   b) ClusterOverview fell back to showing raw clusterId UUID when clusterName
      was undefined. Changed subtitle to render conditionally so UUID never shows.

3. Bell dialog had no way to close
   Custom DialogContent had no X button and no backdrop-click handler.
   Added X close button (top-right) and backdrop-click-to-close.

4. Hotbar icons invisible in dark mode
   variant="ghost" only styles hover state with no baseline text color.
   Added className="text-foreground" to all icon-only ghost buttons.
2026-06-07 18:58:16 -05:00
Shaun Arman
7d8d5bdbba fix(classifier): fix 3 safety bugs, extract const arrays, make tier UI dynamic
All checks were successful
Test / frontend-typecheck (pull_request) Successful in 1m36s
Test / frontend-tests (pull_request) Successful in 1m40s
PR Review Automation / review (pull_request) Successful in 10m27s
Test / rust-fmt-check (pull_request) Successful in 11m4s
Test / rust-clippy (pull_request) Successful in 12m50s
Test / rust-tests (pull_request) Successful in 14m20s
Bug 1 — Dead multi-word tier3 entries / missing single-token commands
  parse_single_command() extracts only the first token as `command`, so
  multi-word entries like "kill -9", "init 0", "service stop" in the tier3
  array never matched. Adding the single-token forms "kill", "pkill",
  "killall", "init" to TIER3_COMMANDS ensures these commands are always
  denied. Removed all dead multi-word entries.

Bug 2 — systemctl Tier 1 special case was dead code
  systemctl was not in tier1_general, so the block that was supposed to
  auto-execute `systemctl status` never ran. Moved systemctl handling into
  its own block (TIER1_SYSTEMCTL_SUBCOMMANDS / TIER2_SYSTEMCTL_SUBCOMMANDS)
  evaluated before the general tier checks. status, is-active, is-enabled,
  list-units, list-unit-files → Tier 1; all others → Tier 2.

Bug 3 — ldapmodify / ldapdelete / ldapadd misclassified as Tier 1
  Both appeared in the old tier1_general and tier2_general arrays; the tier1
  check ran first, so LDAP write operations auto-executed. Removed them from
  tier1. ldapsearch (read-only) remains Tier 1.

Dynamic Safety Architecture UI
  Extracted all tier classification arrays to module-level pub const slices
  (TIER3_COMMANDS, TIER1_KUBECTL_SUBCOMMANDS, etc.) so both the classifier
  logic and a new get_classifier_rules() Tauri command share a single source
  of truth. ShellExecution.tsx now calls getClassifierRulesCmd() on mount and
  renders the actual command lists in collapsible per-tier cards — any change
  to the const arrays is automatically reflected in the UI with no manual
  documentation update needed.

Also fixes the cargo fmt CI failure introduced in the previous commit
(ClusterClient::new call reformatted to a single line).
2026-06-07 18:15:42 -05:00
Shaun Arman
ef3709ffe9 fix(kube): bridge kubeconfig storage to in-memory cluster map and fix UI issues
Some checks failed
PR Review Automation / review (pull_request) Has been cancelled
Test / frontend-tests (pull_request) Successful in 1m37s
Test / frontend-typecheck (pull_request) Successful in 1m46s
Test / rust-fmt-check (pull_request) Failing after 10m52s
Test / rust-clippy (pull_request) Successful in 12m34s
Test / rust-tests (pull_request) Successful in 14m8s
Resolves four bugs in the Kubernetes management interface:

1. **Cluster not found error** - commands/kube.rs::list_nodes (and all other
   kube resource commands) look up clusters from state.clusters (in-memory map)
   which was never populated from the kubeconfig_files table. Add a new
   connect_cluster_from_kubeconfig Tauri command that reads the encrypted
   kubeconfig from the DB, decrypts it, and inserts a ClusterClient into
   state.clusters. Wire it into KubernetesPage on initial load and cluster
   change so the in-memory map is always populated before any kube command runs.

2. **Dropdown selection has no effect** - same root cause as #1; activating a
   kubeconfig only updated the DB flag but never loaded the client into memory.
   handleClusterChange now calls connectClusterFromKubeconfigCmd after activation.

3. **GUID shown instead of cluster name** - ClusterOverview displayed the raw
   internal UUID as the page subtitle. Now accepts a clusterName prop (populated
   from kubeconfig.context) and renders that instead. ClusterDetails similarly
   changed to show kubeconfig.context in the header, not the UUID.

4. **Bell icon not clickable** - Hotbar bell button had no onClick handler. Add
   optional onNotifications / notificationCount props; badge count is now dynamic
   rather than hardcoded. KubernetesPage wires up a notifications dialog showing
   active cluster context and a link to the Events section.

All changes follow TDD: failing tests written first, then implementation.
2026-06-07 17:39:07 -05:00
Shaun Arman
3f4869af01 feat(kubernetes): implement Lens Desktop v5 feature-parity UI
Some checks failed
PR Review Automation / review (pull_request) Has been cancelled
Test / frontend-typecheck (pull_request) Has been cancelled
Test / rust-clippy (pull_request) Has been cancelled
Test / frontend-tests (pull_request) Has been cancelled
Test / rust-fmt-check (pull_request) Has been cancelled
Test / rust-tests (pull_request) Has been cancelled
Complete overhaul of the Kubernetes management page from a basic config
panel into a full Lens-style IDE shell with 26 resource types, real-time
data, and a comprehensive test suite.

Layout & navigation:
- Rewrite KubernetesPage as a Lens v5-style shell: collapsible sidebar
  (Workloads / Services & Networking / Config & Storage / Access Control /
  Cluster), top hotbar with cluster+namespace selectors, Ctrl+K command
  palette
- All 26 resource types now accessible via sidebar navigation (previously 5)

New resource types (Rust + TypeScript + React):
- StorageClasses, NetworkPolicies, ResourceQuotas, LimitRanges
- 4 new Tauri commands registered in generate_handler![]

Component implementations (replacing stubs with real IPC):
- Terminal: full xterm.js with multi-tab sessions and exec_pod IPC
- YamlEditor: Monaco editor with YAML syntax highlighting
- MetricsChart: recharts LineChart/BarChart
- ClusterOverview: live node/pod/deployment/namespace counts
- ClusterDetails: real kubeconfig + node data
- PodDetail, DeploymentDetail, ServiceDetail, ConfigMapDetail, SecretDetail:
  all connected to real IPC data, zero hardcoded values
- CreateResourceModal, EditResourceModal: wired to createResourceCmd /
  editResourceCmd
- RbacViewer: live data from 4 RBAC IPC commands
- RbacEditor: create roles/cluster-roles via YAML editor
- CommandPalette: 12 real navigation commands, keyboard nav

Dependencies added: xterm@5, xterm-addon-fit, xterm-addon-web-links,
@monaco-editor/react@4, recharts@2

Tooling:
- Replace eslint-plugin-react (incompatible with ESLint 10) with
  @eslint-react/eslint-plugin; fix eslint.config.js for flat config
- Fix pre-existing hoisting lint errors in Security.tsx, PortForwardForm.tsx
- Fix eventBus.ts: replace all `any` generics with `unknown`

Tests: 251 passing across 35 test files (was 94/19)
- 16 new test files covering all new and fixed components (TDD)
- npx tsc --noEmit: 0 errors
- cargo clippy -- -D warnings: 0 warnings
- cargo fmt --check: passes
- eslint src/ --max-warnings 0: 0 issues
2026-06-07 16:41:28 -05:00
Shaun Arman
5b85480608 fix(kubernetes): sync active kubeconfig to store's selectedClusterId
All checks were successful
PR Review Automation / review (pull_request) Successful in 3m31s
Test / frontend-tests (pull_request) Successful in 1m34s
Test / frontend-typecheck (pull_request) Successful in 1m37s
Test / rust-fmt-check (pull_request) Successful in 11m55s
Test / rust-clippy (pull_request) Successful in 12m56s
Test / rust-tests (pull_request) Successful in 13m59s
- Update handleActivateKubeconfig to call setSelectedCluster after activation
- ResourceBrowser now loads resources for the activated kubeconfig's cluster
- All tests passing, build successful
2026-06-07 12:29:39 -05:00
Shaun Arman
e928011839 fix(kubernetes): use kubeconfig files from Settings instead of duplicate cluster management
Some checks failed
Test / frontend-tests (pull_request) Successful in 1m28s
Test / frontend-typecheck (pull_request) Successful in 1m34s
PR Review Automation / review (pull_request) Successful in 3m42s
Test / rust-tests (pull_request) Has been cancelled
Test / rust-fmt-check (pull_request) Has been cancelled
Test / rust-clippy (pull_request) Has been cancelled
- Remove duplicate 'Add Cluster' button and modal
- Remove duplicate 'Start Port Forward' button and modal
- KubernetesPage now uses kubeconfig files from Settings → Kubeconfig
- Clusters section displays kubeconfig files with active indicator
- Port forwarding section shows active port forwards without duplicate controls
- All tests passing, build successful
2026-06-07 12:19:08 -05:00
Shaun Arman
468a69d89e fix(kubernetes): remove redundant TS cast and fix cargo fmt failures
All checks were successful
Test / frontend-tests (pull_request) Successful in 1m28s
Test / frontend-typecheck (pull_request) Successful in 1m36s
PR Review Automation / review (pull_request) Successful in 4m1s
Test / rust-fmt-check (pull_request) Successful in 10m59s
Test / rust-clippy (pull_request) Successful in 12m49s
Test / rust-tests (pull_request) Successful in 14m17s
- Remove redundant `as Set<ResourceType>` cast in kubernetesStore initial
  state; the generic parameter already constrains the type
- Reformat watcher.rs vec! literal and Watcher::new call to satisfy
  rustfmt line-length rules (CI was failing cargo fmt --check)
2026-06-07 11:37:17 -05:00
Shaun Arman
664aeaafad docs: update documentation for Kubernetes Management UI
Some checks failed
Test / frontend-tests (pull_request) Successful in 1m29s
Test / frontend-typecheck (pull_request) Successful in 1m38s
PR Review Automation / review (pull_request) Successful in 3m58s
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 ADR-010: Kubernetes Management UI with Lens Desktop v5.x feature parity
- Add Kubernetes-Management.md wiki page
- Update CHANGELOG.md with Phase 7 features
- Update README.md with kubernetesStore and components
- Update docs/architecture/README.md with ADR-010
- Fix build issues: downgrade tailwindcss v4 to v3, add vite-env.d.ts, fix tsconfig
- All 114 frontend tests passing, 331 Rust tests passing, build successful
2026-06-07 11:09:22 -05:00
Shaun Arman
e51bfc4ce9 feat(kubernetes): implement Phase 7 - real-time updates
- Add event bus (src/lib/eventBus.ts) for frontend event handling
- Add watcher module (src-tauri/src/kube/watcher.rs) for K8s resource watching
- Add backend commands: subscribe_to_k8s_events, subscribe_to_all_k8s_events, unsubscribe_from_k8s_events
- Add watchers field to AppState for tracking active watchers
- Update mod.rs to export watcher module
- All tests pass, build successful
2026-06-07 10:53:18 -05:00
Shaun Arman
512feb5e49 feat(kubernetes): implement Phase 3 - detail views and cluster management
- Add detail views: PodDetail, DeploymentDetail, ServiceDetail, ConfigMapDetail, SecretDetail
- Add cluster management views: ClusterOverview, ClusterDetails
- Add UX components: Hotbar, CommandPalette, Toast, LoadingSpinner
- Add resource management: CreateResourceModal, EditResourceModal
- Add RBAC management: RbacViewer, RbacEditor
- Update index.tsx exports for all new components
- All components pass ESLint, TypeScript, and pass 114 tests
- Build successful
2026-06-07 10:43:20 -05:00
Shaun Arman
a3da4f5ce7 feat(kubernetes): implement Phase 1 & 2: resource discovery UIs and advanced features
- Add kubernetesStore.ts with Zustand state management (clusters, namespaces, resources, terminals, search, bulk selection)
- Create 15 resource list components (Secret, ReplicaSet, Job, CronJob, Ingress, PVC, PV, ServiceAccount, Role, ClusterRole, RoleBinding, ClusterRoleBinding, HPA, Node, Event, ConfigMap)
- Add advanced components (Terminal, YamlEditor, MetricsChart, SearchBar, ContextSwitcher, ApplicationView, PodDetail)
- Update KubernetesPage.tsx to integrate kubernetesStore and add cluster management
- Add ContextInfo and ResourceInfo types to tauriCommands.ts
- All components pass ESLint, TypeScript, and pass 114 tests
- Build successful
2026-06-07 10:24:26 -05:00
Shaun Arman
b884cadd8a feat: implement additional Kubernetes resource discovery and management commands
Some checks failed
Test / frontend-tests (pull_request) Successful in 1m34s
Test / frontend-typecheck (pull_request) Successful in 1m54s
PR Review Automation / review (pull_request) Successful in 4m27s
Test / rust-fmt-check (pull_request) Failing after 12m1s
Test / rust-clippy (pull_request) Successful in 13m12s
Test / rust-tests (pull_request) Successful in 14m59s
- Add 16 new resource discovery commands: replicasets, jobs, cronjobs, configmaps, secrets, nodes, events, ingresses, pvcs, pvs, serviceaccounts, roles, clusterroles, rolebindings, clusterrolebindings, hpas
- Add 6 new management commands: cordon_node, uncordon_node, drain_node, rollback_deployment, create_resource, edit_resource
- All commands follow existing patterns with proper temp file cleanup and error handling
- All tests passing (331 Rust + 98 frontend)
- TypeScript type checks passing
- Build successful in release mode
2026-06-07 00:10:19 -05:00
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
b6453b0f75 fix: add app shutdown cleanup for port forward processes
Some checks failed
Test / frontend-tests (pull_request) Successful in 1m32s
Test / frontend-typecheck (pull_request) Successful in 1m34s
PR Review Automation / review (pull_request) Successful in 3m28s
Test / rust-fmt-check (pull_request) Failing after 11m18s
Test / rust-clippy (pull_request) Successful in 13m0s
Test / rust-tests (pull_request) Successful in 14m38s
- Add shutdown_port_forwards() Rust command to kill all child processes
- Add shutdownPortForwardsCmd() frontend command wrapper
- Add cleanup effect in App.tsx to call shutdown on unmount
- All port forward child processes now killed on app exit
2026-06-06 18:48:52 -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
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
44c631961d fix: address PR review findings
Some checks failed
PR Review Automation / review (pull_request) Successful in 4m35s
Test / frontend-tests (pull_request) Has been cancelled
Test / frontend-typecheck (pull_request) Has been cancelled
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
- Add separate deletePortForwardCmd wrapper (currently calls stop_port_forward - backend limitation)
- Add explicit empty string check for containerPort validation
- Improve status badge handling for empty/unknown status
- Update PortForwardList to use distinct handleDeletePortForward handler
2026-06-06 13:01:35 -05:00
Shaun Arman
aefe935de5 fix: address PR review findings
Some checks failed
PR Review Automation / review (pull_request) Successful in 2m58s
Test / frontend-typecheck (pull_request) Successful in 1m49s
Test / frontend-tests (pull_request) Successful in 1m43s
Test / rust-fmt-check (pull_request) Has been cancelled
Test / rust-clippy (pull_request) Has been cancelled
Test / rust-tests (pull_request) Has been cancelled
- Add separate onDelete handler for PortForwardList (Stop vs Delete actions)
- Add namespace validation in PortForwardForm (required field)
- Update KubernetesPage to pass onDelete handler to PortForwardList
2026-06-06 12:55:23 -05:00
Shaun Arman
f5fb9bd0e2 feat(kube): add Kubernetes management GUI components
- Add ClusterList, PortForwardList, AddClusterModal, PortForwardForm components
- Add KubernetesPage component with cluster and port forward management
- Add TypeScript types for Kubernetes management (ClusterInfo, PortForwardRequest, PortForwardResponse)
- Add 6 IPC commands to tauriCommands.ts for cluster and port forward management
- Write unit tests for Kubernetes IPC commands (6 tests)
- All 308 Rust tests passing
- All 98 frontend tests passing
- TypeScript type check passing
- Project builds successfully
2026-06-06 12:55:14 -05:00
Shaun Arman
bbd235f750 fix(lint): resolve ESLint errors
Some checks failed
Auto Tag / autotag (push) Successful in 8s
Auto Tag / wiki-sync (push) Successful in 9s
Test / frontend-tests (push) Successful in 1m42s
Test / frontend-typecheck (push) Successful in 1m54s
Auto Tag / changelog (push) Successful in 1m56s
Auto Tag / build-macos-arm64 (push) Successful in 3m3s
Auto Tag / build-linux-amd64 (push) Successful in 9m37s
Auto Tag / build-windows-amd64 (push) Successful in 11m16s
Auto Tag / build-linux-arm64 (push) Successful in 11m41s
Test / rust-fmt-check (push) Failing after 15m46s
Test / rust-clippy (push) Successful in 17m15s
Test / rust-tests (push) Successful in 18m57s
- Add eslint-disable comment for unused handlePaste in LogUpload
- Fix unused 'get' parameter in attachmentStore.ts
- Fix ESLint setup.ts parsing error by adding it to test files config
2026-06-06 11:44:40 -05:00
Shaun Arman
6b911a2106 fix: remove ALL remaining proprietary references (MSI/Vesta/VNXT)
Some checks failed
Test / rust-clippy (pull_request) Failing after 13s
Test / rust-tests (pull_request) Failing after 16s
Test / frontend-tests (pull_request) Successful in 1m22s
Test / frontend-typecheck (pull_request) Successful in 1m32s
Test / rust-fmt-check (pull_request) Failing after 3m12s
PR Review Automation / review (pull_request) Successful in 3m17s
Comprehensive cleanup of ALL proprietary terms:

**1. API Format Renaming:**
- msi-genai → generic-genai (everywhere)
- is_msi_genai_format() → is_generic_genai_format()
- chat_msi_genai() → chat_generic_genai()
- All test function names updated

**2. Vesta/VNXT Complete Removal:**
- VESTA NXT → DevOps Platform
- All vesta/vnxt references → platform/devops
- Files: CHANGELOG.md, query_expansion.rs, domainPrompts.ts
- Fixed test expectations (removed nxt keyword check)

**3. CI Workflow Fix:**
- Moved Node.js installation BEFORE cache action
- actions/cache@v4 requires Node to be installed first
- Fixes: 'exec: "node": executable file not found in /Users/sarman/.local/bin:/Users/sarman/.bun/bin:/Users/sarman/.codeium/windsurf/bin:/opt/homebrew/bin:/opt/homebrew/sbin:/Users/sarman/.local/bin:/Users/sarman/.opencode/bin:/Users/sarman/.cargo/bin:/opt/homebrew/opt/gnu-sed/libexec/gnubin:/Library/Frameworks/Python.framework/Versions/3.6/bin:/opt/local/bin:/opt/local/sbin:/usr/local/opt/coreutils/libexec/gnubin:/opt/metasploit-framework/bin:/Users/sarman/git/SQL:/Users/sarman/git/mass-scripts:/Users/sarman/gitpersonal:/Users/sarman/git/scripts:/Users/sarman/git/sysadmin-util:/usr/local/mysql/bin:/opt/bin/:/usr/local/bin:/System/Cryptexes/App/usr/bin:/usr/bin:/bin:/usr/sbin:/sbin:/var/run/com.apple.security.cryptexd/codex.system/bootstrap/usr/local/bin:/var/run/com.apple.security.cryptexd/codex.system/bootstrap/usr/bin:/var/run/com.apple.security.cryptexd/codex.system/bootstrap/usr/appleinternal/bin:/Library/Apple/usr/bin:/Applications/iTerm.app/Contents/Resources/utilities:/libexec/bin:/Users/sarman/bin/:/Users/sarman/bin/mass_scripts/:/usr/local/Cellar/mysql/5.7.21/bin:/usr/local/mariadb10/bin:/Users/sarman/bin/scripts:/Users/sarman/bin/SQL/:/Users/sarman/bin/bert_scripts/:/Users/sarman/bin/ecw/:/Users/sarman/bin/mass-scripts/:/Users/sarman/bin/nhudson:/Users/sarman/bin/personal/:/Users/sarman/bin/python_learning/:/Users/sarman/bin/svn/:/Users/sarman/sysadmin-util/:/Users/sarman/was_scripts/:/Users/sarman/.lmstudio/bin:/Users/sarman/.lmstudio/bin:/Users/sarman/.claude/plugins/cache/claude-plugins-official/swift-lsp/1.0.0/bin:/Users/sarman/.claude/plugins/cache/claude-plugins-official/rust-analyzer-lsp/1.0.0/bin:/Users/sarman/.claude/plugins/cache/knowledge-work-plugins/productivity/1.3.0/bin:/Users/sarman/.claude/plugins/cache/knowledge-work-plugins/customer-support/1.3.0/bin:/Users/sarman/.claude/plugins/cache/knowledge-work-plugins/product-management/1.2.0/bin:/Users/sarman/.claude/plugins/cache/knowledge-work-plugins/engineering/1.2.0/bin'

**4. Preserved:**
- .msi file extension (Windows installer format - valid)
- .exe file extension (Windows executable - valid)

**Verification:**
-  308 Rust tests passing
-  92 frontend tests passing
-  Zero proprietary references remaining

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-06-05 16:13:39 -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
dd9e6c0d3d feat: add shell execution and kubeconfig management UI
Real-time approval modal, settings pages, tool calling auto-detect button,
and IPC command wrappers.

- Add ShellApprovalModal component for Tier 2 command approvals
- Add ShellExecution settings page
- Add KubeconfigManager settings page
- Update AIProviders page with tool calling detection button
- Add shell command wrappers to tauriCommands.ts
- Add routes for new settings pages

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-06-05 08:14:03 -05:00
Shaun Arman
922f90a794 fix(mcp): change plaintext env input to type=text
Change plaintext_env input field from type='password' to type='text' since
this field is explicitly for non-sensitive values (DEBUG, LOG_LEVEL, etc.).
Using password type for plaintext config was misleading and prevented
copy/paste of legitimate non-sensitive configuration.

Only the encrypted_env and http_headers fields remain as type='password'
for sensitive values like API keys and tokens.
2026-06-01 12:06:04 -05:00
Shaun Arman
d264e6b09d fix(mcp): improve UX clarity for encrypted env vars during edit
Add clearer placeholder and helper text to explain that encrypted environment
variables are never displayed for security reasons. When editing an existing
server, the encrypted_env field shows a placeholder explaining that leaving it
blank will preserve existing values.

Also apply cargo fmt formatting fixes to store.rs.
2026-06-01 11:58:52 -05:00
Shaun Arman
8b354bb861 fix(mcp): add environment variable and HTTP header support for MCP servers
Some checks failed
Test / rust-fmt-check (pull_request) Failing after 1m26s
Test / frontend-tests (pull_request) Successful in 1m32s
Test / frontend-typecheck (pull_request) Successful in 1m34s
Test / rust-clippy (pull_request) Successful in 3m13s
Test / rust-tests (pull_request) Successful in 4m33s
PR Review Automation / review (pull_request) Successful in 4m56s
Add dual-mode environment variable support for stdio MCP servers and custom
HTTP headers for HTTP-based MCP servers to enable proper authentication and
configuration.

Backend changes (Rust):
- Add migration 023 for env_config column in mcp_servers table
- Add env_config field to McpServer, CreateMcpServerRequest, UpdateMcpServerRequest
- Encrypt env_config using AES-256-GCM on create/update in store.rs
- Add get_server_env_config() helper to decrypt and parse env vars
- Parse plaintext env from transport_config.env (stdio only)
- Parse custom headers from transport_config.headers (HTTP only)
- Merge plaintext and encrypted env vars (encrypted takes precedence)
- Update connect_stdio() to accept HashMap<String, String> for env vars
- Update connect_http() to accept HashMap<String, String> for headers
- Apply env vars to tokio::process::Command via .env() method
- Add warning for HTTP headers (rmcp v1.7.0 limitation - no .header() method)
- Add comprehensive tests for encryption, merging, and clearing

Frontend changes (TypeScript/React):
- Add env_config field to CreateMcpServerRequest and UpdateMcpServerRequest
- Add plaintext_env, encrypted_env, http_headers to ServerForm interface
- Add parsing helpers: parseEnvVars(), formatEnvVars(), parseHeaders(), formatHeaders()
- Update startEdit() to extract and format env vars/headers from transport_config
- Update handleSave() to build transport_config with env/headers and env_config JSON
- Add conditional UI fields: stdio (plaintext + encrypted env), HTTP (custom headers)
- Use password input type for all sensitive fields

Security:
- Encrypted env vars stored using AES-256-GCM (matching auth_value pattern)
- Plaintext env vars in transport_config for non-sensitive values
- UI masks all env/header fields with password input type
- Never display decrypted values when editing

Fixes inability to configure MCP servers that require environment variables
(e.g., GitHub MCP server with GITHUB_PERSONAL_ACCESS_TOKEN).

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-06-01 08:32:51 -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
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
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