tftsr-devops_investigation/AGENTS.md
Shaun Arman e56a72a31a
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
feat(k8s): implement clean-room Kubernetes management GUI
- 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

7.2 KiB
Raw Blame History

AGENTS.md — Quick Start for OpenCode

Commands

Task Command
Run full dev (Tauri + Vite) cargo tauri dev
Frontend only (port 1420) npm run dev
Frontend production build npm run build
Rust fmt check cargo fmt --manifest-path src-tauri/Cargo.toml --check
Rust fmt fix cargo fmt --manifest-path src-tauri/Cargo.toml
Rust clippy cargo clippy --manifest-path src-tauri/Cargo.toml -- -D warnings
Rust tests cargo test --manifest-path src-tauri/Cargo.toml -- --test-threads=1
Rust single test module cargo test --manifest-path src-tauri/Cargo.toml -- --test-threads=1 pii::detector
Rust single test cargo test --manifest-path src-tauri/Cargo.toml -- --test-threads=1 test_detect_ipv4
Frontend test (single run) npm run test:run
Frontend test (watch) npm run test
Frontend coverage npm run test:coverage
TypeScript type check npx tsc --noEmit
Frontend lint npx eslint src/ tests/ --quiet

Lint Policy: ALWAYS run cargo fmt and cargo clippy after any Rust code change. Fix all issues before proceeding.

Note: The build runs npm run build before Rust build (via beforeBuildCommand in tauri.conf.json). This ensures TS is type-checked before packaging.

Requirement: Rust toolchain must be in PATH: source ~/.cargo/env


Project Structure

Path Responsibility
src-tauri/src/lib.rs Entry point: app builder, plugin registration, IPC handler registration
src-tauri/src/state.rs AppState (DB, settings, integration_webviews)
src-tauri/src/commands/ Tauri IPC handlers (db, ai, analysis, docs, integrations, system)
src-tauri/src/ai/provider.rs Provider trait + create_provider() factory
src-tauri/src/pii/ Detection engine (12 patterns) + redaction
src-tauri/src/db/models.rs DB types: Issue, IssueDetail (nested), LogFile, ResolutionStep, AiConversation
src-tauri/src/audit/log.rs write_audit_event() before every external send
src/lib/tauriCommands.ts Source of truth for all Tauri IPC calls
src/lib/domainPrompts.ts 15 domain system prompts (Linux, Windows, Network, K8s, DBs, etc.)
src/stores/ Zustand: sessionStore (ephemeral), settingsStore (persisted), historyStore

Key Patterns

Rust Mutex Usage

Lock Mutex inside a block and release before .await. Holding MutexGuard across await points fails to compile (not Send):

let state: State<'_, AppState> = app.state();
let db = state.db.clone();
// Lock and release before await
{ let conn = state.db.lock().unwrap(); /* use conn */ }
// Now safe to .await
db.query(...).await?;

IssueDetail Nesting

get_issue() returns a nested struct — use detail.issue.title, not detail.title:

pub struct IssueDetail {
    pub issue: Issue,
    pub log_files: Vec<LogFile>,
    pub resolution_steps: Vec<ResolutionStep>,
    pub conversations: Vec<AiConversation>,
}

TypeScript mirrors this shape exactly in tauriCommands.ts.

PII Before AI Send

apply_redactions must be called before sending logs to AI. Record the SHA-256 hash via audit::log::write_audit_event(). PII spans are non-overlapping (longest span wins on overlap); redactor iterates in reverse order to preserve offsets.

State Persistence

  • sessionStore: ephemeral triage session (issue, messages, PII spans, why-level 05, loading) — not persisted
  • settingsStore: persisted to localStorage as "tftsr-settings"

CI/CD (Gitea Actions)

Workflow Trigger Jobs
.gitea/workflows/test.yml Every push/PR rustfmtclippycargo test (64 tests) → tsc --noEmitvitest run (13 tests)
.gitea/workflows/auto-tag.yml Push to master Auto-tag, build linux/amd64 + windows/amd64 + linux/arm64 + macOS, upload assets to Gitea release

Artifacts: src-tauri/target/{target}/release/bundle/

Environments:

  • Test CI images at 172.0.0.29:3000 (pull tftsr-*:rust1.88-node22)
  • Gitea instance: http://172.0.0.29:3000
  • Wiki: sync from docs/wiki/*.mdhttps://gogs.tftsr.com/sarman/tftsr-devops_investigation/wiki

Environment Variables

Variable Default Purpose
TRCAA_DATA_DIR (or legacy TRCAA_DATA_DIR) Platform data dir Override database location
TRCAA_DB_KEY (or legacy TRCAA_DB_KEY) Auto-generated SQLCipher encryption key override
TRCAA_ENCRYPTION_KEY (or legacy TRCAA_ENCRYPTION_KEY) Auto-generated Credential encryption key override
RUST_LOG info Tracing level (debug, info, warn, error)

Database path:

  • Linux: ~/.local/share/tftsr/tftsr.db
  • macOS: ~/Library/Application Support/tftsr/tftsr.db
  • Windows: %APPDATA%\tftsr\tftsr.db

Architecture Highlights

Rust Backend

  • Entry point: src-tauri/src/lib.rs::run() → init tracing → init DB → register plugins → generate_handler![]
  • Database: rusqlite + bundled-sqlcipher-vendored-openssl (AES-256). cfg!(debug_assertions) → plain SQLite; release → SQLCipher
  • AI providers: Provider trait with factory dispatch on config.name. Adding a provider: implement Provider trait + add match arm
  • Integration clients: Confluence, ServiceNow, Azure DevOps stubs (v0.2). OAuth2 via WebView + callback server (warp, port 8765)

Frontend (React + Vite)

  • Dev server: port 1420 (hardcoded)
  • IPC: All invoke() calls in src/lib/tauriCommands.ts — typed wrappers for every backend command
  • Domain prompts: 15 expert prompts injected as first message in every triage conversation (Linux, Windows, Network, K8s, DBs, Virtualization, Hardware, Observability, Telephony, Security, Public Safety, Application, Automation, HPE, Dell, Identity)

Security

  • Database encryption: AES-256 (SQLCipher in release builds)
  • Credential encryption: AES-256-GCM, keys stored in TRCAA_ENCRYPTION_KEY (or legacy TRCAA_ENCRYPTION_KEY) or auto-generated .enckey (mode 0600)
  • Audit trail: Hash-chained entries (prev_hash + entry_hash) for tamper evidence
  • PII protection: 12-pattern detector → user approval gate → hash-chained audit entry

Testing

Layer Command Notes
Rust cargo test --manifest-path src-tauri/Cargo.toml 64 tests, runs in rust:1.88-slim container
TypeScript npm run test:run Vitest, 13 tests
Type check npx tsc --noEmit skipLibCheck: true
E2E TAURI_BINARY_PATH=./src-tauri/target/release/tftsr npm run test:e2e WebdriverIO, requires compiled binary

Frontend coverage: npm run test:coveragetests/unit/ coverage report


Critical Gotchas

  1. Mutex across await: Never lock().unwrap() and .await without releasing the guard
  2. IssueDetail nesting: detail.issue.title, never detail.title
  3. PII before AI: Always redact and record hash before external send
  4. Port 1420: Vite dev server is hard-coded to 1420, not 3000
  5. Build order: Rust fmt → clippy → test → TS check → JS test
  6. CI images: Use 172.0.0.29:3000 registry for pre-baked builder images