Skip to main content

Sentin8:Storage — Business Requirements & Functionality

Audience: product owners, business analysts, and anyone evaluating what Sentin8:Storage does for the business. For architecture read README.md; for wire-level detail read DESIGN.md.

1. Business Purpose​

Sentin8:Storage is the platform's object-storage service — the one place every file and blob lives. AI chunk text, trace archives, app uploads, media, and vertical blobs all share one storage plane with tenant-isolated semantics. The business value it delivers:

  • One object plane. No vertical owns an S3 account or a filesystem; one plane means one credential owner, one audit surface, and one tenant-isolation model.
  • All access requires a token. Every read/write requires an Auth-issued token; signed URLs are the time-boxed escape hatch for untrusted clients (browser uploads/downloads) — auditable and tamper-proof.
  • Path traversal is a security invariant. Keys must stay inside their bucket root — traversal attempts are rejected BEFORE any IO, not sanitized after.
  • Idempotent, content-addressed friendly. Content-addressed verticals short-circuit duplicate uploads (If-None-Match / X-If-Absent) and probe with HEAD — the dedup fast path is a first-class API.
  • Pluggable backend. The local FS backend ships today; S3-style object stores are an adapter away without any caller change.

2. Business Scope (What the Service Provides)​

AreaCapabilities
Object CRUDPUT (with idempotency hints), GET, HEAD (existence + size, no payload), DELETE, list by prefix, copy/move
Dedup fast pathX-If-Absent / If-None-Match: * → X-Storage-Deduped: true; optional X-Content-Sha256 verification on dedup hits
Signed URLsHMAC-SHA256 token-embedded authorization, method-scoped (GET/PUT), TTL 3600s — browser-direct uploads/downloads without credentials
Public readsImage-only extension allowlist (svg/png/jpg/jpeg/gif/webp/ico) for platform + per-env paths, Cache-Control cached
Tenant isolationKeys org/{org_id}/env/{env_id}/{path} — env from the verified token, org resolved server-side (never in URLs)
Path safetyComponent-level traversal rejection pre-IO + canonicalize-deepest-existing + containment — symlink escapes rejected
Admin surfacesRFW bucket admin (create/delete/upload/download/link objects) with cross-env authority checks; Shield policy-admin API
EventsObject lifecycle events (created/deleted/moved) via the local outbox with the caller's publisher identity
Adapter abstractionStorageAdapter trait — LocalFsAdapter today, pluggable backends (native HEAD/range) tomorrow

What the service does NOT own (business boundary)​

Out of scopeOwner
Object semanticsCallers decide what a key means (services store references/keys in their own schemas)
Object metadata tablesNone — the service holds no domain tables; buckets are .keep marker objects
Tenant identitySentin8:Auth (env from the verified token; org resolved from sys.environments)
Object versioningNon-goal — copy-then-delete + audit journal cover the requirement
Multipart uploadsRide the presigned-PUT pattern (N part-PUTs + a commit endpoint)

3. Business Capabilities​

3.1 Object API​

CapabilityBusiness rule
Put / get / head / deleteShield-gated (env:write / env:read / env:admin); HEAD answers existence + size without shipping bytes
List?prefix= filtering; a 403 propagates (never masked as an empty list)
Copy / moveAdmin scope; move is copy-then-delete (no partial state); both emit object:moved
DedupOpt-in: a dedup hit returns 200 + X-Storage-Deduped: true without re-writing bytes; with X-Content-Sha256 present the hash is verified (407 on mismatch)
Signed-URL flowsSign-read / sign-upload via POST dispatch; the signed route itself needs no bearer

3.2 Signed URLs (browser-direct transfers)​

CapabilityBusiness rule
IssuanceWrite-scoped caller requests a signed URL for one key + method (GET/PUT), TTL 3600s
VerificationHMAC + expiry + method checked BEFORE any IO; expired/tampered → 403; malformed → 400; wrong method → 405
ScopeSingle-key, single-operation capability — no broad token exposure to browsers
No eventsSigned serving/upload flows emit no lifecycle events (the sign-issuing mutation does)

3.3 Public Reads​

CapabilityBusiness rule
AllowlistImage extensions only — arbitrary object leakage through the public route is impossible
Platform variantPinned to the system org/env (branding/logos)
Per-env variantOrg resolved from the env_id path segment
CachingCache-Control: public, max-age=3600

3.4 Administration​

CapabilityBusiness rule
Bucket adminRFW pages: create/delete buckets (.keep markers, name-sanitized), upload/download/link objects
Cross-env authorityRequires platform/org/env-admin scopes
Policy adminShared Shield surface (policy sets, relations, attributes)

4. Business Events (Outbound)​

Event family storage; publisher identity = the caller's JWT.

EventWhen
sentin8:storage:object:createdPUT (payload: key, content_type, size)
sentin8:storage:object:deletedDELETE (payload: key)
sentin8:storage:object:movedCopy or move (payload: from_key, to_key)

5. Business Rules & Invariants (the "always true" guarantees)​

  1. Key containment validated pre-IO — traversal and symlink escapes are rejected before any filesystem IO.
  2. Fail-closed tenant resolution — unknown env → 404 (never a system-org fallback); pool/context errors → 500; context and lookup share one transaction on one connection.
  3. Signed URLs are token-embedded, HMAC-tamper-proof, method-scoped, expiry-checked before IO; unsigned legacy tokens rejected.
  4. Dedup semantics are opt-in and never verify bytes unless the caller supplies X-Content-Sha256.
  5. Public reads are image-only — arbitrary object leakage through the public route is impossible.
  6. org_id never appears in URL paths — resolved server-side from env_id.
  7. Move is copy-then-delete — no partial state on failure.
  8. Shield (step 5) is the only access gate on tenant routes; signed and public routes are bearer-free by contract.
  9. Production fails fast without a signing key (SENTIN8_STORAGE_SIGNING_KEY required at boot in production; the ephemeral fallback deliberately invalidates URLs on restart).
  10. No unsafe code; the FS adapter is the only IO surface.

6. Target-User Roles & Use Cases​

PersonaWhat they do with Sentin8:Storage
Platform serviceStores/retrieves blobs (AI chunks, trace archives, module binaries, app media) via the shared SDK; stores only keys in its own schema
Browser userUploads/downloads large files directly via signed URLs (no bytes proxied through the BFF, no credentials exposed)
Public visitorReads branding images via the public read surface
Platform operatorManages buckets and objects via the RFW admin; monitors lifecycle events
ComplianceVerifies traversal rejection, fail-closed tenant resolution, and event-attributed mutations

7. KPIs / Success Criteria​

  • Isolation: zero cross-tenant object access (token env + server-side org resolution + containment).
  • Safety: zero traversal escapes (pre-IO rejection); zero arbitrary public reads (image allowlist).
  • Convenience: browser-direct transfers work without credential exposure; dedup avoids wasted IO/egress.
  • Reliability: copy/move never leaves partial state; relay failures retry (rows unrelayed, never lost).

8. Dependencies & Reliance on Other Services​

The business relies on…For
Sentin8:AuthBearer verification (JWKS); M2M workload identities
Shield (Sentin8:Policy)env:read/write/admin scope-mirror gates
Sentin8:Syssys.environments lookups (org resolution, context-first)
Sentin8:BusLifecycle event publication via the local outbox relay
Local filesystem / adapter backendPhysical object storage ({state_dir}/storage)
Shell (platform)Outbox relay, middleware, TLS listener, pool cap

9. Acceptance Criteria (what "done" looks like for the business)​

  1. A service can put/get/head/delete/list objects through one API, storing only keys in its own schema.
  2. A browser can upload or download a specific object via a signed URL that expires within the hour — no platform credentials in the client.
  3. Traversal attempts (.., absolute paths, URL-encoded traversal, symlink escapes) are rejected before any IO.
  4. Dedup works: identical content-addressed uploads short-circuit; X-Content-Sha256 verifies hits.
  5. Public reads serve branding images (image allowlist, cache headers) for the platform and per-env.
  6. Cross-tenant access is impossible — org_id never in URLs, unknown envs 404 fail-closed.
  7. Copy/move complete atomically (copy-then-delete) and emit lifecycle events with caller attribution.
  8. Bucket admin works end-to-end via the RFW UI with proper cross-env authority checks.
  9. Production boots only with a real signing key.
  10. Object lifecycle events reach the Bus durably (outbox relay with retries).

10. Open Business Questions​

  • The S3-compatible backend adapter is deliberate future work behind the adapter trait (the seam exists; only LocalFs ships).
  • Per-bucket quota enforcement tracks bytes-per-namespace in metadata (the dedup path already scans sizes).
  • Multipart uploads ride the presigned-PUT pattern (N part-PUTs + a commit endpoint).
  • Object versioning stays a non-goal — the copy-then-delete contract plus the audit journal cover the requirement.

Design attribution: sentin8:storage and its underlying concepts were designed by Hamid Jahanzad Hamid@Jahanzad.com.