Replace every remaining reference to the old Gitea infrastructure with the new GitHub-hosted equivalents across all documentation, wiki pages, test files, and historical ticket summaries. - README.md: CI badge, clone URL, releases link, CI/CD section, project structure - docs/wiki/CICD-Pipeline.md: full rewrite for GitHub Actions + ghcr.io - docs/wiki/Home.md: CI badge, releases link, phase status, tech stack - docs/wiki/Troubleshooting.md: rewrite CI troubleshooting for GitHub Actions - docs/architecture/README.md: update CI/CD pipeline diagram - AGENTS.md: CI/CD section, environment references - PLAN.md: directory structure, pipeline table - SECURITY_AUDIT.md: mark C3 and L4 findings as resolved - ticket-git-cliff-changelog.md: workflow path updated - tickets/ci-runner-speed-optimization.md: image registry updated - 2026-hackathon_AgenticFeature.md: workflow path updated - tests: workflow path assertions updated in all three test files
159 lines
7.2 KiB
Markdown
159 lines
7.2 KiB
Markdown
# 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 . --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`):
|
||
|
||
```rust
|
||
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`:
|
||
|
||
```rust
|
||
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 0–5, loading) — **not persisted**
|
||
- `settingsStore`: persisted to `localStorage` as `"tftsr-settings"`
|
||
|
||
---
|
||
|
||
## CI/CD (GitHub Actions)
|
||
|
||
| Workflow | Trigger | Jobs |
|
||
|----------|---------|------|
|
||
| `.github/workflows/test.yml` | Every push/PR targeting `main` | `rust-test` (fmt → clippy → cargo test) · `frontend-test` (tsc → vitest) |
|
||
| `.github/workflows/release.yml` | Push to `main` (auto-tag), `v*` tags | Auto-tag, build linux/amd64 + linux/arm64 + windows/amd64 + macOS ARM64 + macOS Intel, upload to GitHub Releases |
|
||
| `.github/workflows/build-images.yml` | `.docker/**` changes on `main` | Build and push pre-baked CI images to `ghcr.io/msicie/` |
|
||
|
||
**Artifacts**: `src-tauri/target/{target}/release/bundle/`
|
||
|
||
**Environments**:
|
||
- Test CI images at `ghcr.io/msicie/` (pull `trcaa-*:rust1.88-node22`)
|
||
- GitHub repo: `https://github.com/msicie/apollo_nxt-trcaa`
|
||
- Wiki: sync from `docs/wiki/*.md` → `https://github.com/msicie/apollo_nxt-trcaa/wiki`
|
||
|
||
---
|
||
|
||
## Environment Variables
|
||
|
||
| Variable | Default | Purpose |
|
||
|----------|---------|---------|
|
||
| `TFTSR_DATA_DIR` | Platform data dir | Override database location |
|
||
| `TFTSR_DB_KEY` | Auto-generated | SQLCipher encryption key override |
|
||
| `TFTSR_ENCRYPTION_KEY` | Auto-generated | Credential encryption key override |
|
||
| `RUST_LOG` | `info` | Tracing level (`debug`, `info`, `warn`, `error`) |
|
||
|
||
**Database path**:
|
||
- Linux: `~/.local/share/trcaa/trcaa.db`
|
||
- macOS: `~/Library/Application Support/trcaa/trcaa.db`
|
||
- Windows: `%APPDATA%\trcaa\trcaa.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 `TFTSR_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:coverage` → `tests/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 `ghcr.io/msicie/` registry for pre-baked builder images
|