Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
55 commits
Select commit Hold shift + click to select a range
2b76b7c
Add chat agent file navigation, write guardrails, and browser tools
kovtcharov Mar 11, 2026
fbfeb8d
Merge branch 'main' into feature/chat-agent-file-navigation
kovtcharov Mar 12, 2026
1553b2a
Fix lint formatting and resolve 17 CodeQL security alerts
kovtcharov Mar 13, 2026
3eff2dd
Merge remote-tracking branch 'origin/main' into feature/chat-agent-fi…
kovtcharov Mar 18, 2026
6bb6eba
Merge remote-tracking branch 'origin/main' into feature/chat-agent-fi…
kovtcharov Mar 29, 2026
7c3da04
Merge remote-tracking branch 'origin/main' into feature/chat-agent-fi…
kovtcharov Apr 1, 2026
77a29c4
Merge branch 'main' into feature/chat-agent-file-navigation
kovtcharov Apr 17, 2026
49182ec
fix(495): address PR review + security issues
kovtcharov Apr 17, 2026
4309aae
Merge remote-tracking branch 'origin/main' into feature/chat-agent-fi…
kovtcharov Apr 17, 2026
e647909
fix(495): CI lint + CodeQL XSS follow-ups
kovtcharov Apr 17, 2026
3bb3fe4
fix(495): bulletproofing pass — size caps, column-key validation, blo…
kovtcharov Apr 17, 2026
f15cd11
fix(495): cap insert_data JSON payload + per-call row count
kovtcharov Apr 17, 2026
94d9c1b
fix(495): ScratchpadService heals a corrupt ~/.gaia/scratchpad.db on …
kovtcharov Apr 17, 2026
624039e
fix(495): rate-limit /auth/logout and /auth/login-error
kovtcharov Apr 17, 2026
a73a1f3
fix(495): FileSystemIndexService heals corrupt DB at init
kovtcharov Apr 17, 2026
6c5b503
fix(495): close remaining PR-scope CodeQL alerts + enforce scratchpad…
kovtcharov Apr 17, 2026
184ea3f
fix(495): ReDoS-harden _sanitize_response_text regex patterns
kovtcharov Apr 17, 2026
d16b0ed
fix(495): harden EMR dashboard upload path — reject traversal slips
kovtcharov Apr 17, 2026
67ceb1a
fix(495): stop urlparse'ing the Jira URL for a debug log line
kovtcharov Apr 17, 2026
0af92a4
fix(495): close remaining CodeQL alerts + add edit_file size regressi…
kovtcharov Apr 17, 2026
c1a7308
fix(495): reject '..' segments in the docs-server safe-redirect path
kovtcharov Apr 17, 2026
1d75315
fix(495): bulletproof _sanitize_filename against Windows reserved names
kovtcharov Apr 17, 2026
00652d0
fix(495): close streamed response if a redirect target fails SSRF check
kovtcharov Apr 17, 2026
4690712
fix(495): aggressive pass at remaining CodeQL alerts
kovtcharov Apr 17, 2026
9ee15f0
fix(495): replace silent 'except RuntimeError: pass' in SSE broadcast
kovtcharov Apr 17, 2026
ba6e3de
fix(495): replace three more silent except/pass with debug logs (CLAU…
kovtcharov Apr 17, 2026
191cb35
fix(495): final CodeQL sweep — 9 alerts down to 0 on PR files
kovtcharov Apr 18, 2026
73ad566
fix(495): sanitize clear_database return body + tighten deleted dict
kovtcharov Apr 18, 2026
13566b4
fix(495): route watch-dir path through regex-group rebuild for CodeQL
kovtcharov Apr 18, 2026
b92cb32
fix(495): route watch-dir through os.path.normpath + abspath sanitizers
kovtcharov Apr 18, 2026
5ff4613
fix(495): clear_database success branch returns compile-time constants
kovtcharov Apr 18, 2026
e47e0a7
revert(495): undo os.path.normpath + abspath round-trip on watch-dir
kovtcharov Apr 18, 2026
671f533
fix(495): extract named int fields instead of dict-comp in clear_data…
kovtcharov Apr 18, 2026
e03682e
chore(495): black-format emr dashboard server
kovtcharov Apr 18, 2026
e8999cc
fix(495): read_file PDF path tries modern 'pypdf' before deprecated '…
kovtcharov Apr 18, 2026
e838a27
chore(495): black-format filesystem_tools.py after pypdf fallback fix
kovtcharov Apr 18, 2026
684fdfd
Merge remote-tracking branch 'origin/main' into feature/chat-agent-fi…
May 4, 2026
1500176
fix(ci): resolve CodeQL path-injection alert and unit test failure
May 4, 2026
eb4a552
fix(ci): resolve second CodeQL path-injection alert in file upload
May 4, 2026
a2a5053
Merge remote-tracking branch 'origin/main' into feature/chat-agent-fi…
May 6, 2026
ca3b345
fix(495): address review feedback — DB path, init fallbacks, registry…
May 6, 2026
49ef925
fix(electron): update tests for SettingsModal→SettingsPage rename and…
May 6, 2026
096b934
Merge remote-tracking branch 'origin/main' into feature/chat-agent-fi…
May 6, 2026
dcff73b
fix(ui): handle plain strings in required_connections and fix field name
May 6, 2026
c1ed956
fix(chat): disable filesystem/scratchpad/browser tools by default
May 6, 2026
f69345c
feat(agents): split chat agent into task-specific agents with prompt …
May 7, 2026
f5fc285
fix(tests): update tests for agent split defaults and timeout changes
May 7, 2026
d451789
fix(eval): handle missing claude CLI on Windows without crashing
May 7, 2026
78eb0d9
Merge remote-tracking branch 'origin/main' into feature/chat-agent-fi…
May 7, 2026
ccaa268
Merge remote-tracking branch 'origin/main' into feature/chat-agent-fi…
May 7, 2026
9b5d4d5
fix(495): per-instance tool registry, prompt gating, bookmark isolation
May 7, 2026
dd1372c
fix(495): add _TOOL_REGISTRY import for MCP counting in _register_tools
May 8, 2026
5a3a259
fix(web): IP pinning for DNS rebinding prevention + monotonic rate li…
May 8, 2026
cd2731b
fix(495): download path validation, scratchpad size guard, security h…
May 8, 2026
c28c898
fix(test): remove unused MagicMock import (flake8 F401)
May 8, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion .github/workflows/test_unit.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,8 @@ jobs:

- name: Install dependencies
run: |
uv pip install --system pytest pytest-cov
uv pip install --system pytest pytest-cov pytest-asyncio pytest-mock
uv pip install --system beautifulsoup4
uv pip install --system -e ".[api]"

- name: Validate packaging integrity
Expand Down Expand Up @@ -120,6 +121,17 @@ jobs:
echo " - ASR: Automatic speech recognition utilities"
echo " - TTS: Text-to-speech utilities"
echo " - InitCommand: gaia init profiles and installer logic"
echo " - FileSystemIndex: Persistent file index with FTS5 search"
echo " - FileSystemToolsMixin: browse_directory, tree, file_info, find_files, read_file, bookmark tools"
echo " - ScratchpadService: SQLite working memory for data analysis"
echo " - ScratchpadToolsMixin: create_table, insert_data, query_data, list_tables, drop_table tools"
echo " - BrowserTools: WebClient SSRF prevention, HTML extraction, downloads"
echo " - WebClient Edge Cases: parse_html fallback, extract_text, tables, links, download redirects"
echo " - Categorizer: auto_categorize, category map completeness, extension uniqueness"
echo " - ChatAgent Integration: filesystem, scratchpad, browser init/config/cleanup"
echo " - File Write Guardrails: blocked dirs, sensitive files, size limits, backup, audit"
echo " - Security Edge Cases: symlinks, audit logging, TOCTOU, prompt_overwrite"
echo " - Service Edge Cases: DB corruption rebuild, shared DB, row limits, transaction atomicity"
echo ""
echo "Integration Tests:"
echo " - DatabaseMixin + Agent: Full agent lifecycle with database"
Expand Down
31 changes: 30 additions & 1 deletion docs/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -290,7 +290,9 @@
const parsed = url.parse(target || '');
// Only redirect to relative paths (no host/protocol) to prevent open redirects
if (!parsed.host && !parsed.protocol && parsed.pathname) {
res.redirect(303, parsed.pathname);
// Sanitize pathname to prevent protocol-relative URLs (e.g., //evil.com)
const safePath = parsed.pathname.startsWith('/') && !parsed.pathname.startsWith('//') ? parsed.pathname : '/';
res.redirect(303, safePath);
Comment thread Fixed
} else {
res.redirect(303, '/');
}
Expand All @@ -317,6 +319,33 @@
res.redirect('/');
});

// Simple in-memory rate limiter for general requests (no external dependencies)
const rateLimitStore = new Map();
const RATE_LIMIT_WINDOW = 60 * 1000; // 1 minute
const RATE_LIMIT_MAX = 100; // max requests per window

function rateLimiter(req, res, next) {
const ip = req.ip || req.connection.remoteAddress;
const now = Date.now();
const record = rateLimitStore.get(ip) || { count: 0, resetAt: now + RATE_LIMIT_WINDOW };

if (now > record.resetAt) {
record.count = 0;
record.resetAt = now + RATE_LIMIT_WINDOW;
}

record.count++;
rateLimitStore.set(ip, record);

if (record.count > RATE_LIMIT_MAX) {
return res.status(429).send('Too Many Requests');
}
next();
}

// Apply rate limiter before auth middleware
app.use(rateLimiter);

// Apply auth middleware
app.use(authMiddleware);

Expand Down
Loading
Loading