Commit Graph

523 Commits

Author SHA1 Message Date
Shaun Arman
4f7dd086d5 chore: trigger changelog update for latest fixes 2026-06-04 22:22:34 -05:00
efe8d4caf0 chore: update CHANGELOG.md for v0.2.53 [skip ci] 2026-06-04 22:22:34 -05:00
3e4b044f7d chore: update CHANGELOG.md for v0.2.53 [skip ci] 2026-06-04 22:22:34 -05:00
Shaun Arman
620d597cbb ci: final test run — arm64 runner labels fixed (linux-arm64 only) 2026-06-04 22:22:34 -05:00
Shaun Arman
d918596c5b ci: retrigger after amd64 runner config fix (CONFIG_FILE env var) 2026-06-04 22:22:34 -05:00
Shaun Arman
e753df8eac ci: retrigger after runner capacity=1 fix 2026-06-04 22:22:34 -05:00
Shaun Arman
f2f622bcd0 ci: retrigger after act_runner host network fix 2026-06-04 22:22:34 -05:00
Shaun Arman
5d56a2dd94 ci: retrigger after making repo public 2026-06-04 22:22:34 -05:00
Shaun Arman
6a36e01f7b ci: retrigger test pipeline after act_runner network fix 2026-06-04 22:22:34 -05:00
gitea-actions[bot]
6105f5af2b chore: update CHANGELOG.md for v0.3.11 [skip ci] 2026-06-01 18:29:28 +00:00
590fec7dd4 Merge pull request 'fix(mcp): add environment variable support for stdio MCP servers' (#62) from bug/mcp-env-vars-support into master
All checks were successful
Auto Tag / autotag (push) Successful in 7s
Auto Tag / wiki-sync (push) Successful in 6s
Test / rust-fmt-check (push) Successful in 1m18s
Test / frontend-typecheck (push) Successful in 1m32s
Test / frontend-tests (push) Successful in 1m31s
Auto Tag / changelog (push) Successful in 1m29s
Test / rust-clippy (push) Successful in 3m52s
Test / rust-tests (push) Successful in 5m28s
Auto Tag / build-macos-arm64 (push) Successful in 5m46s
Auto Tag / build-linux-amd64 (push) Successful in 9m28s
Auto Tag / build-windows-amd64 (push) Successful in 11m20s
Auto Tag / build-linux-arm64 (push) Successful in 11m31s
Reviewed-on: #62
2026-06-01 18:27:58 +00:00
Shaun Arman
e5d3ff42f5 docs(wiki): update MCP-Servers.md with env var support, PATH requirement, and new schema column
All checks were successful
Test / rust-fmt-check (pull_request) Successful in 1m24s
Test / frontend-tests (pull_request) Successful in 1m40s
Test / frontend-typecheck (pull_request) Successful in 1m44s
Test / rust-clippy (pull_request) Successful in 3m13s
Test / rust-tests (pull_request) Successful in 4m35s
PR Review Automation / review (pull_request) Successful in 4m41s
2026-06-01 13:21:09 -05:00
Shaun Arman
7cc4f0f689 fix(mcp): treat missing resources/list as non-fatal for servers that don't implement it 2026-06-01 13:19:34 -05:00
gitea-actions[bot]
eb45551a8f chore: update CHANGELOG.md for v0.3.10 [skip ci] 2026-06-01 17:48:26 +00:00
02b97134d5 Merge pull request 'bug/mcp-env-vars-support' (#61) from bug/mcp-env-vars-support into master
All checks were successful
Auto Tag / autotag (push) Successful in 6s
Auto Tag / wiki-sync (push) Successful in 8s
Test / rust-fmt-check (push) Successful in 1m23s
Test / frontend-typecheck (push) Successful in 1m30s
Auto Tag / changelog (push) Successful in 1m32s
Test / frontend-tests (push) Successful in 1m36s
Test / rust-clippy (push) Successful in 3m40s
Test / rust-tests (push) Successful in 4m58s
Auto Tag / build-macos-arm64 (push) Successful in 5m31s
Auto Tag / build-linux-amd64 (push) Successful in 8m44s
Auto Tag / build-windows-amd64 (push) Successful in 10m45s
Auto Tag / build-linux-arm64 (push) Successful in 10m54s
Reviewed-on: #61
2026-06-01 17:46:52 +00:00
Shaun Arman
7c2452e3f7 fix(mcp): fix test_allows_safe_env_vars test failure
All checks were successful
Test / rust-fmt-check (pull_request) Successful in 1m27s
Test / frontend-tests (pull_request) Successful in 1m31s
Test / frontend-typecheck (pull_request) Successful in 1m34s
Test / rust-clippy (pull_request) Successful in 3m8s
Test / rust-tests (pull_request) Successful in 4m33s
PR Review Automation / review (pull_request) Successful in 4m47s
The test was trying to spawn a process which requires a Tokio runtime.
Changed the test to only verify validation logic by checking that safe
environment variables don't trigger 'Dangerous environment variable' errors.

Uses /usr/bin/nonexistent as command so spawn will fail (command not found)
but validation will pass for safe env vars like DEBUG, API_KEY, PATH, etc.

All 243 tests now passing.
2026-06-01 12:41:26 -05:00
Shaun Arman
0469f121b1 fix(mcp): add validation to block dangerous environment variables
Some checks failed
Test / rust-fmt-check (pull_request) Successful in 1m55s
Test / frontend-typecheck (pull_request) Successful in 1m47s
Test / frontend-tests (pull_request) Successful in 1m46s
Test / rust-clippy (pull_request) Successful in 3m8s
PR Review Automation / review (pull_request) Successful in 4m25s
Test / rust-tests (pull_request) Failing after 4m39s
Add defense-in-depth security validation for stdio transport to reject
environment variables that could be used for privilege escalation attacks.
Blocks the following dangerous variables (case-insensitive):
- LD_PRELOAD (Linux)
- LD_LIBRARY_PATH (Linux)
- DYLD_INSERT_LIBRARIES (macOS)
- DYLD_LIBRARY_PATH (macOS)
- DYLD_FRAMEWORK_PATH (macOS)
- DYLD_FALLBACK_LIBRARY_PATH (macOS)

These variables can inject malicious libraries into spawned processes and
should never be user-configurable for MCP servers.

Add comprehensive tests:
- test_rejects_relative_path: Verify existing path validation
- test_rejects_dangerous_env_vars: Test all blocked variables
- test_rejects_dangerous_env_vars_case_insensitive: Verify lowercase variants blocked
- test_allows_safe_env_vars: Verify legitimate vars (DEBUG, PATH, API_KEY) allowed

All tests passing.
2026-06-01 12:16:11 -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
ed49de1edd Update README.md 2026-06-01 17:02:03 +00: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
2ffe2bb6d8 fix(mcp): parse and merge env vars in discovery layer
- Parse plaintext env from transport_config.env (stdio)
- Decrypt encrypted env from env_config column (stdio)
- Merge env vars with encrypted taking precedence
- Parse custom headers from transport_config.headers (HTTP)
- Update connect_stdio() to accept HashMap<String, String> for env
- Update connect_http() to accept HashMap<String, String> for headers
- Apply env vars to tokio::process::Command in stdio transport
- Log warning for HTTP custom headers (rmcp v1.7.0 limitation)

All 19 MCP tests passing.
2026-06-01 08:25:49 -05:00
Shaun Arman
a970f171a8 fix(mcp): add env encryption to store layer
- Add env_config field to McpServer, CreateMcpServerRequest, UpdateMcpServerRequest
- Encrypt env_config using encrypt_token() on create/update
- Decrypt env_config in get_server_env_config() helper function
- Handle clearing env_config with empty string
- Add comprehensive tests:
  - test_env_config_encrypted_at_rest()
  - test_update_env_config()
  - test_clear_env_config_with_empty_string()
  - test_env_config_none_preserves_existing()

All tests passing. Follows same encryption pattern as auth_value.
2026-06-01 08:22:29 -05:00
Shaun Arman
0efeb5163a test(mcp): add migration 023 test for env_config column
- Add test_023_mcp_env_config_column() to verify env_config column exists
- Add test_023_idempotent() to ensure migration runs only once
- Following TDD methodology: test written first, then implementation
2026-06-01 08:17:31 -05:00
gitea-actions[bot]
95a63e18bf chore: update CHANGELOG.md for v0.3.9 [skip ci] 2026-06-01 01:55:47 +00:00
ba94f446c1 Merge pull request 'fix(security): expand Password PII patterns to catch pass: and natural language forms' (#60) from fix/pii-detection-bypass into master
All checks were successful
Auto Tag / autotag (push) Successful in 6s
Auto Tag / wiki-sync (push) Successful in 7s
Test / rust-fmt-check (push) Successful in 1m25s
Auto Tag / changelog (push) Successful in 1m34s
Test / frontend-tests (push) Successful in 1m42s
Test / frontend-typecheck (push) Successful in 1m43s
Auto Tag / build-macos-arm64 (push) Successful in 2m34s
Test / rust-clippy (push) Successful in 3m26s
Test / rust-tests (push) Successful in 5m4s
Auto Tag / build-linux-amd64 (push) Successful in 8m50s
Auto Tag / build-windows-amd64 (push) Successful in 10m41s
Auto Tag / build-linux-arm64 (push) Successful in 11m1s
Reviewed-on: #60
2026-06-01 01:54:13 +00:00
Shaun Arman
fbd6aab7fe fix(security): expand Password PII patterns; add regression tests
All checks were successful
Test / rust-fmt-check (pull_request) Successful in 1m20s
Test / frontend-typecheck (pull_request) Successful in 1m37s
Test / frontend-tests (pull_request) Successful in 1m35s
Test / rust-clippy (pull_request) Successful in 3m11s
PR Review Automation / review (pull_request) Successful in 4m22s
Test / rust-tests (pull_request) Successful in 4m28s
Two credential patterns were missing from the PiiDetector, confirmed
by live audit log showing was_pii_redacted: false with plaintext creds:

1. Abbreviated key form (pass: abc123!!): the pattern only matched
   password|passwd|pwd. Added pass, passphrase, secret with a word
   boundary to prevent substring false positives (bypass:, compass:).

2. Natural language form (Is the password password123 good): added a
   second Password sub-pattern for keyword-adjacent values without a
   key separator. Value must contain a digit or special char to avoid
   flagging plain words (password strength, password policy).

5 new regression tests added. 233/233 Rust tests pass.
2026-05-31 20:47:59 -05:00
gitea-actions[bot]
2f3b1b826c chore: update CHANGELOG.md for v0.3.8 [skip ci] 2026-06-01 01:21:56 +00:00
19645c06e2 Merge pull request 'fix(security): block PII in chat attachments and typed messages' (#59) from fix/pii-detection-bypass into master
All checks were successful
Auto Tag / autotag (push) Successful in 7s
Auto Tag / wiki-sync (push) Successful in 8s
Test / rust-fmt-check (push) Successful in 1m20s
Test / frontend-typecheck (push) Successful in 1m29s
Test / frontend-tests (push) Successful in 1m31s
Auto Tag / changelog (push) Successful in 1m29s
Auto Tag / build-macos-arm64 (push) Successful in 2m41s
Test / rust-clippy (push) Successful in 3m28s
Test / rust-tests (push) Successful in 5m33s
Auto Tag / build-linux-amd64 (push) Successful in 8m55s
Auto Tag / build-windows-amd64 (push) Successful in 10m41s
Auto Tag / build-linux-arm64 (push) Successful in 10m46s
Reviewed-on: #59
2026-06-01 01:20:25 +00: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
gitea-actions[bot]
fb57c629a9 chore: update CHANGELOG.md for v0.3.7 [skip ci] 2026-05-31 23:14:06 +00:00
0f1f4fcb92 Merge pull request 'feat: attachment DB storage and cross-incident recall' (#58) from feature/attachment-db-storage-recall into master
Some checks failed
Auto Tag / autotag (push) Successful in 7s
Auto Tag / wiki-sync (push) Successful in 7s
Test / rust-fmt-check (push) Failing after 1m24s
Test / frontend-typecheck (push) Successful in 1m43s
Auto Tag / changelog (push) Successful in 1m31s
Test / frontend-tests (push) Successful in 1m42s
Auto Tag / build-macos-arm64 (push) Successful in 2m57s
Test / rust-clippy (push) Successful in 3m51s
Test / rust-tests (push) Successful in 5m17s
Auto Tag / build-linux-amd64 (push) Successful in 10m3s
Auto Tag / build-windows-amd64 (push) Successful in 11m35s
Auto Tag / build-linux-arm64 (push) Successful in 11m34s
Reviewed-on: #58
2026-05-31 23:12:38 +00: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
gitea-actions[bot]
f496748cd3 chore: update CHANGELOG.md for v0.3.6 [skip ci] 2026-05-31 21:45:02 +00:00
3fe06ce498 Merge pull request 'fix(ci): push detached HEAD to master using HEAD:master refspec' (#57) from fix/auto-tag-push-master into master
All checks were successful
Auto Tag / autotag (push) Successful in 7s
Auto Tag / wiki-sync (push) Successful in 6s
Test / rust-fmt-check (push) Successful in 1m36s
Test / frontend-tests (push) Successful in 2m14s
Test / frontend-typecheck (push) Successful in 2m15s
Auto Tag / changelog (push) Successful in 2m14s
Auto Tag / build-macos-arm64 (push) Successful in 3m9s
Test / rust-clippy (push) Successful in 4m58s
Test / rust-tests (push) Successful in 6m24s
Auto Tag / build-linux-amd64 (push) Successful in 8m52s
Auto Tag / build-windows-amd64 (push) Successful in 10m51s
Auto Tag / build-linux-arm64 (push) Successful in 11m1s
Reviewed-on: #57
2026-05-31 21:43:18 +00:00
Shaun Arman
34a69620f5 fix(ci): consolidate all auto-tag changelog fixes
All checks were successful
Test / rust-fmt-check (pull_request) Successful in 1m25s
Test / frontend-typecheck (pull_request) Successful in 1m53s
Test / frontend-tests (pull_request) Successful in 1m53s
Test / rust-clippy (pull_request) Successful in 3m12s
PR Review Automation / review (pull_request) Successful in 4m24s
Test / rust-tests (pull_request) Successful in 4m37s
Three issues addressed together:

1. Race condition (was PR #56): changelog job now CREATES the Gitea
   release rather than assuming build jobs have already created it.
   Build jobs continue to use create-or-skip + upload unchanged.

2. Detached HEAD push: 'git push origin master' fails when HEAD is
   detached (no local branch named master). Changed to 'HEAD:master'.

3. git-cliff tag guard: verify tag is present locally before running
   git-cliff, to fail fast with a clear message rather than silently
   generating a wrong changelog.

4. git commit idiom: replaced 'git commit || echo' (swallows all
   non-zero exit codes including real failures) with an explicit
   'git diff --staged --quiet' guard so set -euo pipefail is not
   undermined.
2026-05-31 16:38:02 -05:00
Shaun Arman
f90c76911a fix(ci): push detached HEAD to master using HEAD:master refspec
The changelog job checks out a specific SHA (detached HEAD) then
commits CHANGELOG.md and tries to push with 'git push origin master'.
Since there is no local branch named 'master', git rejects the push
with 'src refspec master does not match any'.

Fix: use 'git push origin HEAD:master' which explicitly maps the
current detached HEAD to the remote master branch regardless of
local branch state.
2026-05-31 16:37:25 -05:00
8eccea96ec Merge pull request 'fix(ci): changelog job creates release, eliminating race with build jobs' (#56) from fix/auto-tag-changelog-race into master
Some checks failed
Auto Tag / autotag (push) Successful in 6s
Auto Tag / wiki-sync (push) Successful in 7s
Test / rust-fmt-check (push) Successful in 1m46s
Test / frontend-typecheck (push) Successful in 1m43s
Test / frontend-tests (push) Successful in 2m21s
Auto Tag / changelog (push) Failing after 2m20s
Auto Tag / build-macos-arm64 (push) Successful in 2m36s
Test / rust-clippy (push) Successful in 4m2s
Test / rust-tests (push) Successful in 5m43s
Auto Tag / build-linux-amd64 (push) Successful in 10m42s
Auto Tag / build-linux-arm64 (push) Successful in 13m6s
Auto Tag / build-windows-amd64 (push) Successful in 13m37s
Reviewed-on: #56
2026-05-31 21:13:11 +00:00
Shaun Arman
7ee4f58bfd fix(ci): verify tag exists locally before running git-cliff
All checks were successful
Test / rust-fmt-check (pull_request) Successful in 1m42s
Test / rust-clippy (pull_request) Successful in 3m31s
Test / frontend-typecheck (pull_request) Successful in 2m40s
Test / frontend-tests (pull_request) Successful in 1m54s
Test / rust-tests (pull_request) Successful in 4m23s
PR Review Automation / review (pull_request) Successful in 6m15s
Addresses the review warning: git rev-parse confirms the tag is
present in the local repo after git fetch --tags before git-cliff
or git tag --sort= runs against it. Fails fast with a clear error
if the tag is missing rather than silently generating an incomplete
changelog.
2026-05-31 16:05:18 -05:00
Shaun Arman
cc99aa815b fix(ci): changelog job creates release to avoid race with build jobs
Some checks failed
Test / rust-fmt-check (pull_request) Waiting to run
PR Review Automation / review (pull_request) Successful in 4m38s
Test / frontend-typecheck (pull_request) Successful in 1m22s
Test / rust-clippy (pull_request) Successful in 6m12s
Test / frontend-tests (pull_request) Successful in 1m13s
Test / rust-tests (pull_request) Has been cancelled
The changelog and build-* jobs all fan out from autotag in parallel.
Build jobs create the Gitea release with 'curl ... || true', but the
changelog job was trying to GET the release before any build job had
run, reliably failing with 'Could not find release for tag vX.Y.Z'.

Fix: changelog job owns release creation. It creates the release with
the git-cliff body if it does not exist, or patches the body if a
prior run already created it. Build jobs continue using their existing
create-or-skip + upload pattern unchanged.
2026-05-31 15:57:26 -05:00
d3dfa41d83 Merge pull request 'fix: safe uploads, AI history continuity, deep search, sudo credentials' (#55) from fix/safe-uploads-history-search-sudo into master
Some checks failed
Auto Tag / autotag (push) Successful in 7s
Auto Tag / wiki-sync (push) Successful in 6s
Test / rust-fmt-check (push) Successful in 1m18s
Test / frontend-tests (push) Successful in 1m27s
Test / frontend-typecheck (push) Successful in 1m30s
Auto Tag / changelog (push) Failing after 1m27s
Auto Tag / build-macos-arm64 (push) Successful in 2m45s
Test / rust-clippy (push) Successful in 3m12s
Test / rust-tests (push) Successful in 5m22s
Auto Tag / build-linux-amd64 (push) Successful in 10m55s
Auto Tag / build-windows-amd64 (push) Successful in 13m53s
Auto Tag / build-linux-arm64 (push) Successful in 14m11s
Reviewed-on: #55
2026-05-31 20:52:31 +00: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
26507ad3ff fix(ci): install python3 in pr-review container (ubuntu:22.04 omits it)
All checks were successful
Test / rust-fmt-check (pull_request) Successful in 1m22s
Test / frontend-typecheck (pull_request) Successful in 1m33s
Test / frontend-tests (pull_request) Successful in 1m31s
Test / rust-clippy (pull_request) Successful in 3m17s
PR Review Automation / review (pull_request) Successful in 4m18s
Test / rust-tests (pull_request) Successful in 4m25s
2026-05-31 15:37:10 -05:00
Shaun Arman
0057c570ba fix(ci): write curl body to file to avoid ARG_MAX limit
Some checks failed
Test / rust-fmt-check (pull_request) Successful in 1m23s
Test / frontend-tests (pull_request) Successful in 1m30s
Test / frontend-typecheck (pull_request) Successful in 1m32s
Test / rust-clippy (pull_request) Successful in 3m19s
PR Review Automation / review (pull_request) Failing after 4m19s
Test / rust-tests (pull_request) Successful in 4m40s
The 147KB JSON body was being passed as a shell argument to curl,
hitting the kernel ARG_MAX limit. Write it to /tmp/body.json via
jq redirection and use curl --data @/tmp/body.json instead.
2026-05-31 15:32:16 -05:00