- M7.1-M7.10: Extensible SourceConnector trait, Obsidian/paperless/git/S3 connectors, sync framework, CLI, HTTP endpoints, health monitoring, gate - M3.5.10: Auth integration with Authentik OIDC → Vault token validation - DESIGN.md: Add source connectors architecture, update auth to Authentik/Vault (Kong removed from cluster) - INDEX.md: 75 tasks, 11 gates - Fix all Kong references in M3.5.1 task
4.1 KiB
M7.5 — S3-compatible storage connector
| Field | Value |
|---|---|
| Phase | M7 — Source connectors |
| Size | M — 1–3 days |
| Status | ⬜ Not started |
| Flags | — |
| Spec | inlined below |
| Blocks | M7.10 |
| Depends | M7.1 |
Goal
Implement a SourceConnector for S3-compatible object storage (MinIO, AWS S3,
R2, etc.) so documents stored in buckets become searchable through the memory
service.
Facts (inlined — no spec read needed)
S3 is the universal storage protocol. MinIO runs in many homelabs, and cloud providers expose the same API. This connector makes any S3 bucket a knowledge source.
Configuration:
connectors:
- kind: s3
name: knowledge-bucket
config:
endpoint: https://minio.riotpiao.com
bucket: knowledge-base
prefix: docs/ # only this prefix
extensions: [md, txt, pdf] # filter by key suffix
access_key_secret: minio-creds # k8s secret with access/secret keys
region: us-east-1 # for AWS; ignored by MinIO
ETag for change detection. S3 objects have ETags (usually MD5 of content).
Use this as content_hash in SourceDocument — the sync framework skips objects
whose ETag hasn't changed.
Text extraction. S3 stores raw files. Markdown and text files are read directly. PDF/DOCX support is out of scope for M7.5 — those MIME types are skipped with a warning. Future: add a text extraction layer or require pre-processed text.
Pagination via continuation tokens. S3 ListObjectsV2 returns max 1000 keys
per request. Use ContinuationToken for subsequent pages.
Steps
- Implement
S3Connectorinmem-ingest/src/connectors/s3.rs. list_documents()—ListObjectsV2withPrefix, paginate, filter by extension, returnSourceDocumentper object.fetch_document()—GetObject, read body as text (UTF-8), return with metadata (key, size, last_modified, ETag).health_check()—HeadBucketto verify access.- Auth via access key + secret key from k8s secret.
- Use
aws-sdk-s3orrust-s3crate for S3 API. - Register
"s3"kind in connector registry factory. source_type()returnsReference.
Acceptance
S3ConnectorimplementsSourceConnectorfully.- Prefix filtering limits to configured path.
- Extension filtering skips non-text objects.
- ETag is used as
content_hashfor change detection. - Pagination handles > 1000 objects.
- Auth works with MinIO and AWS-style credentials.
Verify
Harness: mock S3 server (localstack or in-process mock) with fixture objects.
Integration test — tests/it_s3_connector.rs:
a1_list_with_prefix— mock bucket with objects underdocs/andimages/; assert onlydocs/objects listed.a2_extension_filtering— mock with .md, .png, .txt; assert .png excluded.a3_fetch_returns_content— fetch a .md object; assert content matches.a4_etag_as_content_hash— assertSourceDocument.content_hashequals the object's ETag.a5_pagination— mock 1500 objects; assert all listed via continuation tokens.a6_health_check_valid_bucket— mock HeadBucket 200; assert reachable.a7_health_check_no_access— mock HeadBucket 403; assert not reachable with error message.a8_non_utf8_skipped— mock object with binary content; assert skipped with warning, not crash.a9_config_from_yaml— parse connector from YAML; assert fields match.
Command: cargo test --test it_s3_connector
False pass:
- Testing with a local filesystem mock instead of S3 API mock. The pagination and ETag handling are S3-specific.
Traps
- Assuming ETags are always MD5. Multipart uploads produce composite ETags
(
hash-N). These are still unique per version — use as-is for change detection. - Not handling
NoSuchBucketvsAccessDenied. Both are errors but mean different things for health reporting. - Reading binary files as UTF-8. A JPEG read as text produces garbage. Check content-type header and skip non-text MIME types.
Background: DESIGN.md — source connectors section