Files
poimen-memory/tasks/M7.5-s3-connector.md
T
Story Crater Bot 71ecf482e7
Build and Push / Test (push) Successful in 3m36s
Build and Push / Build and push image (push) Successful in 20s
docs: Add M7 source connectors (10 tasks), M3.5.10 auth integration, remove Kong refs
- 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
2026-08-26 16:56:39 -07:00

4.1 KiB
Raw Blame History

M7.5 — S3-compatible storage connector

Field Value
Phase M7 — Source connectors
Size M — 13 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

  1. Implement S3Connector in mem-ingest/src/connectors/s3.rs.
  2. list_documents()ListObjectsV2 with Prefix, paginate, filter by extension, return SourceDocument per object.
  3. fetch_document()GetObject, read body as text (UTF-8), return with metadata (key, size, last_modified, ETag).
  4. health_check()HeadBucket to verify access.
  5. Auth via access key + secret key from k8s secret.
  6. Use aws-sdk-s3 or rust-s3 crate for S3 API.
  7. Register "s3" kind in connector registry factory.
  8. source_type() returns Reference.

Acceptance

  • S3Connector implements SourceConnector fully.
  • Prefix filtering limits to configured path.
  • Extension filtering skips non-text objects.
  • ETag is used as content_hash for 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 testtests/it_s3_connector.rs:

  1. a1_list_with_prefix — mock bucket with objects under docs/ and images/; assert only docs/ objects listed.
  2. a2_extension_filtering — mock with .md, .png, .txt; assert .png excluded.
  3. a3_fetch_returns_content — fetch a .md object; assert content matches.
  4. a4_etag_as_content_hash — assert SourceDocument.content_hash equals the object's ETag.
  5. a5_pagination — mock 1500 objects; assert all listed via continuation tokens.
  6. a6_health_check_valid_bucket — mock HeadBucket 200; assert reachable.
  7. a7_health_check_no_access — mock HeadBucket 403; assert not reachable with error message.
  8. a8_non_utf8_skipped — mock object with binary content; assert skipped with warning, not crash.
  9. 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 NoSuchBucket vs AccessDenied. 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