Skip to content

Add File Search and File Share (#1379) - #1395

Merged
helpcodeai merged 23 commits into
mainfrom
helpcodeai/filesearch
Nov 1, 2026
Merged

helpcodeai merged 23 commits into
mainfrom
helpcodeai/filesearch

Conversation

@helpcodeai

Copy link
Copy Markdown
Contributor

Summary

File Search connects a folder on an SFTP, FTP/FTPS, WebDAV or S3 server (and, self-hosted, a folder mounted into the install), indexes file names and the text of every page, and gives AI clients tools to search, read pages, grep exact codes and hand the file over. File Share turns files into temporary download links, also for files an AI client writes.

Plan and decisions: docs/plans/file-search.md (epic #1379). User docs: docs/connectors/file-search.md.

ee/ authorization: Matteo, the owner, explicitly chose "option B" for this feature: the sync engine (packages/backend/src/ee/file-search/) and the text extractor (deploy/ee/file-extractor/) are under the AnythingMCP Commercial License, so a self-hosted install without a licence cannot use File Search after the 30-day trial. Nothing else under ee/ is touched.

Behaviour in both deployments

Cloud Self-hosted
Who Every plan incl. the trial, within its limits Paid licence (Starter, Team, Enterprise) or the 30-day trial; Community locked afterwards
Sources SFTP, FTP/FTPS, WebDAV, S3 on public hosts (SSRF policy) Same, plus folders below FILE_SOURCE_ROOTS; private hosts via the outbound allowlist
Limits Trial/Starter 1 connector, 500 files, daily sync; Team 3, 2,000, daily; Enterprise by contract, down to 15 min Starter 500, Team 2,000, Enterprise unlimited (down to 5 min); file size FILES_MAX_FILE_BYTES
File Share Starter 24 h / 100 MB total / 10 MB per file; Team 7 d / 2 GB / 50 MB; Enterprise 90 d; no trial; storage S3 (Spaces) Paid plans; storage local volume or S3
Services files-worker + file-extractor (Compose profile files) Same, COMPOSE_PROFILES=files

Nothing changes for an install that does not enable the files profile: the wizard says File Search is not running, and no new process starts.

Changes

Type

  • Bug fix
  • New feature
  • Documentation
  • Refactoring
  • Performance improvement
  • Other (describe below)

Testing

  • Added/updated unit tests
  • Tested manually (describe steps below)
  • No tests needed (explain why)

Commands run on the rebased branch (macOS, Node 22, local PostgreSQL 17 on 5433):

Directory Command Result
packages/backend npm run lint 0 errors, 11 warnings (existing)
packages/backend npx tsc --noEmit -p tsconfig.json clean
packages/backend npx jest --maxWorkers=4 954 suites passed, 6 skipped (gated live specs); 29,706 tests passed
packages/backend RUN_FILES_INTEGRATION=1 npx jest src/ee/file-search/file-search.integration.spec.ts 5/5 passed (with FILES_IT_SFTP, FILES_IT_FTPS, FILES_IT_WEBDAV, FILES_IT_DATABASE_URL set to local test containers)
packages/frontend npm run lint 0 errors, 49 warnings (existing)
packages/frontend npx tsc --noEmit -p tsconfig.json clean
deploy/ee/file-extractor ./test.sh (host) and container tests 74 host + 78 container tests passed
root node scripts/validate-adapters.mjs --warn exit 0; no warnings from the new entries (existing warnings in other adapters)
root node scripts/adapter-count.mjs --check OK, 684 adapters
root node scripts/generate-llms-txt.mjs --check fresh

Manual, locally against SFTP (atmoz/sftp), FTPS (pure-ftpd, self-signed), WebDAV, S3 (MinIO) and a mounted folder with a 508-file seed: the wizard end to end, scans and budget, full and delta syncs, quota pause, licence pause and automatic resume, every MCP tool through a real MCP endpoint, File Share links, RLS; UI screenshot by screenshot at 1440×900 and 390×844, light and dark.

Pen test (two workspaces, plus VIEWER and EDITOR members): 31 API checks (cross-tenant on every File Search, File Share and generic connector route; secrets never returned; generic create and catalog import refused; malicious configs; forged tokens), MCP isolation, bounded regex, file-name XSS and header injection, 41 driver checks (loopback, RFC 1918, CGNAT, metadata IP, IPv6 and IPv4-mapped, decimal/hex/short IPv4, DNS to loopback, WebDAV redirect to an internal address, PASV to a foreign host, local symlinks and traversal, local driver on Cloud) and 29 role checks. Two findings, fixed in this PR with regression specs: an S3 endpoint given as a literal private IP skipped the lookup-based guard, and PASV handling refused NAT servers instead of ignoring the announced host.

Checklist

  • My code follows the existing code style
  • I have tested my changes locally
  • I have updated documentation (if applicable)
  • All existing tests pass (npm test)
  • This PR has a descriptive title

Related Issues

Closes #1380, #1381, #1382, #1383, #1384, #1385, #1386, #1387, #1388, #1389. Relates to #1379.

helpcodeai added a commit that referenced this pull request Nov 1, 2026
CodeQL flagged the slash-trimming regexes as quadratic on user and
server input, and the unanchored S3 host patterns.
helpcodeai added a commit that referenced this pull request Nov 1, 2026
CodeQL flagged the slash-trimming regexes as quadratic on user and
server input, and the unanchored S3 host patterns.
, #1387)

Check an S3 endpoint given as a literal IP before connecting, take only
the port from FTP PASV replies, and send HTML, SVG, XML and script files
from share links as application/octet-stream.
Record the pen test and the same-domain download decision in the plan.
…osted (#1389)

The network folder entry is self-hosted only, so the keyless count is 34.
CodeQL flagged the slash-trimming regexes as quadratic on user and
server input, and the unanchored S3 host patterns.
…r Database (#1385, #1387)

Settings -> File Share loads links 20 at a time with a file-name search,
an access filter, Only mine for administrators, a count and an inline
revoke confirmation; without Enterprise the policy shows as a read-only
summary. The Files panel pages the files that could not be read. On
Connectors -> New the File Search card follows Database.
The worker image crashed with MODULE_NOT_FOUND: nest build writes the
entry to dist/src/ee/file-search/. Cap its heap below the container's
1 GB limit.
A Fritz!Box FTP server answers 'LIST -a /folder' with the root, so every
folder looked like the root and a sync would never see the real files.
A model asks for 'Preisliste Brandschutztür' where the folder says
Preisliste and the page says Brandschutztür: no page had both words, so
the search found nothing. Quoted phrases and OR queries stay literal.
_find without name or glob now says what to pass instead of listing
every file.
…and Storage Box (#1389)

Seven catalog entries open the File Search wizard with the protocol and
the product preset (?preset=) filled in: S3 bucket, Nextcloud, ownCloud,
Synology, QNAP, Fritz!Box storage and Hetzner Storage Box.
On a managed database whose user may not create roles, the migration
skips amcp_files with a notice and the RLS policies apply to the
application user itself; the repository switches role only when it is
granted.
@helpcodeai
helpcodeai force-pushed the helpcodeai/filesearch branch from a3e86b9 to d15df10 Compare November 1, 2026 14:37
@helpcodeai
helpcodeai enabled auto-merge (squash) November 1, 2026 14:37
@helpcodeai
helpcodeai merged commit c3314e0 into main Nov 1, 2026
14 checks passed
@helpcodeai
helpcodeai deleted the helpcodeai/filesearch branch November 1, 2026 14:50
@github-actions github-actions Bot locked and limited conversation to collaborators Nov 1, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

File Search: schema (FILE_SEARCH connector type, file_* tables, RLS)

2 participants