@@ -75,6 +75,8 @@ services:
7575 condition : service_healthy
7676 redis-durable :
7777 condition : service_healthy
78+ seaweedfs :
79+ condition : service_healthy
7880 # === LABELS =============================================== #
7981 labels :
8082 - " traefik.http.routers.api.rule=PathPrefix(`/api/`)"
@@ -409,6 +411,65 @@ services:
409411 retries : 5
410412 start_period : 5s
411413
414+ seaweedfs :
415+ # === IMAGE ================================================ #
416+ # The bundled durable object store for session/agent mounts. Without it, runner mount
417+ # signing returns 503 and agent file writes are silently lost. Pinned (not :latest) so the
418+ # IAM/STS subsystem stays on a known-good build — it has regressed across releases.
419+ image : chrislusf/seaweedfs:4.37
420+ # === EXECUTION ============================================ #
421+ # ONLY FOR SEAWEEDFS (the bundled store). Real S3/R2/MinIO ship their own STS/IAM and ignore
422+ # all of this. Two configs, both generated from env (no committed files):
423+ # - s3.json: the master identity only (admin; the API holds these creds, never the runner).
424+ # - iam.json: the ADVANCED IAM config — the only path SeaweedFS authorizes STS credentials.
425+ # An OIDC provider points at the API's self-served JWKS; the API mints a short-lived
426+ # RS256 web-identity token and calls AssumeRoleWithWebIdentity to assume `agenta-store`.
427+ entrypoint :
428+ - sh
429+ - -c
430+ - |
431+ cat > /etc/seaweedfs/s3.json <<EOF
432+ {"identities":[{"name":"agenta","credentials":[{"accessKey":"$${AGENTA_STORE_ACCESS_KEY}","secretKey":"$${AGENTA_STORE_SECRET_KEY}"}],"actions":["Admin","Read","Write","List","Tagging"]}]}
433+ EOF
434+ cat > /etc/seaweedfs/iam.json <<EOF
435+ {"sts":{"tokenDuration":"1h","maxSessionLength":"12h","issuer":"seaweedfs-sts","signingKey":"$${AGENTA_STORE_SIGNING_KEY}"},"providers":[{"name":"agenta","type":"oidc","enabled":true,"config":{"issuer":"$${AGENTA_STORE_JWT_ISSUER}","clientId":"agenta-store","jwksUri":"$${AGENTA_STORE_JWT_ISSUER}/.well-known/jwks.json"}}],"policies":[{"name":"store-rw","document":{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Action":["s3:*"],"Resource":["arn:aws:s3:::$${AGENTA_STORE_BUCKET}","arn:aws:s3:::$${AGENTA_STORE_BUCKET}/*"]}]}}],"roles":[{"roleName":"agenta-store","roleArn":"arn:aws:iam::role/agenta-store","attachedPolicies":["store-rw"],"trustPolicy":{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Principal":{"Federated":"agenta"},"Action":["sts:AssumeRoleWithWebIdentity"]}]}}]}
436+ EOF
437+ exec weed server -dir=/data -ip=seaweedfs -volume.max=64 -s3 -s3.port=8333 -s3.config=/etc/seaweedfs/s3.json -s3.iam.config=/etc/seaweedfs/iam.json
438+ # === CONFIGURATION ======================================== #
439+ env_file :
440+ - ${ENV_FILE:-./.env.oss.gh}
441+ environment :
442+ # The entrypoint bakes these into s3.json/iam.json via raw shell expansion, so they must
443+ # be present in this service's env (defaults here are for the bundled store, the same way
444+ # supertokens carries its own connection URI). Keys come from the env file — secrets never
445+ # get a baked-in default. Override the whole trio via the env file to use S3/R2/MinIO.
446+ AGENTA_STORE_ACCESS_KEY : ${AGENTA_STORE_ACCESS_KEY}
447+ AGENTA_STORE_SECRET_KEY : ${AGENTA_STORE_SECRET_KEY}
448+ AGENTA_STORE_BUCKET : ${AGENTA_STORE_BUCKET:-agenta-store}
449+ AGENTA_STORE_SIGNING_KEY : ${AGENTA_STORE_SIGNING_KEY}
450+ AGENTA_STORE_JWT_ISSUER : ${AGENTA_STORE_JWT_ISSUER:-http://api:8000}
451+ # === STORAGE ============================================== #
452+ volumes :
453+ - seaweed-data:/data
454+ # === NETWORK ============================================== #
455+ networks :
456+ - agenta-oss-gh-network
457+ # Loopback-only by default (never expose the store to a public IP); override AGENTA_STORE_PORT
458+ # to change. In-network services reach it directly at seaweedfs:8333, no publish needed.
459+ ports :
460+ - " ${AGENTA_STORE_PORT:-127.0.0.1:8333}:8333"
461+ # === LABELS =============================================== #
462+ labels :
463+ - " traefik.enable=false"
464+ # === LIFECYCLE ============================================ #
465+ restart : always
466+ healthcheck :
467+ test : ["CMD-SHELL", "curl -sf http://localhost:9333/cluster/healthz >/dev/null || exit 1"]
468+ interval : 5s
469+ timeout : 5s
470+ retries : 30
471+ start_period : 5s
472+
412473 traefik :
413474 # === ACTIVATION =========================================== #
414475 profiles :
@@ -524,3 +585,4 @@ volumes:
524585 postgres-data :
525586 redis-volatile-data :
526587 redis-durable-data :
588+ seaweed-data :
0 commit comments