Skip to content

feat: expose the app-content bucket, MCP, OAuth and artifact retention [ENG-1739] - #31

Merged
twk3 merged 3 commits into
mainfrom
feat/eng-1739-app-content-mcp-oauth-retention
Oct 13, 2026
Merged

twk3 merged 3 commits into
mainfrom
feat/eng-1739-app-content-mcp-oauth-retention

Conversation

@twk3

@twk3 twk3 commented Oct 13, 2026 •

Copy link
Copy Markdown
Contributor

Exposes the app-content bucket, remote MCP, the OAuth provider and artifact retention in the Docker Compose setup (ENG-1739).

The app-content bucket holds context shares, organization logos and session files. The services read it from PERMANENT_STORAGE_* (ENG-1738), but nothing in Compose set those, so on-prem context sharing, logo editing and session file uploads were off.

Changes

  • App-content bucket:
    • api, changestreams-worker and write-worker map APP_CONTENT_STORAGE_* from .env to PERMANENT_STORAGE_*. Each falls back to PERMANENT_STORAGE_* in .env, so an .env that sets those directly keeps working: the environment: entries override env_file.
    • .env.example reuses the artifact storage endpoint and credentials, with bucket currents-app-content.
    • The RustFS profile sets path-style for it, as it does for the artifact bucket.
  • rustfs-init:
    • Creates both buckets.
    • Puts lifecycle rules on the app-content bucket, scoped to ai-context-share/, share-3d/, share-7d/ and trace-links/ (2, 4, 8 and 8 days). They are never bucket-wide, because logos and session files live in the same bucket.
    • With DC_RUSTFS_DELETE_ARTIFACTS_AFTER_DAYS set, adds a bucket-wide expiry rule to the artifact bucket. When it's unset, removes that rule.
    • Exits 1 on a value that isn't a whole number above 0.
    • Rewrites only the rules it owns, matched by ID, and keeps any other rules on both buckets. When no rules are left on a bucket, it deletes the empty configuration.
  • MCP: MCP_ENABLED defaults to true. /mcp answers 401 without a credential.
  • OAuth:
    • .env.example sets OAUTH_PROVIDER_ENABLED=true and enables dynamic client registration.
    • An upgraded .env without these lines keeps OAuth off.
    • It needs an https APP_BASE_URL, or http on localhost:
      • On any other http host the API refuses to start, and the docs say to set OAUTH_PROVIDER_ENABLED=false there.
      • OAUTH_HTTP_ALLOWED_HOSTS gets the API to start on such a host, but Better Auth's validateIssuerUrl then advertises an https:// issuer that the install doesn't serve. So the docs offer the variable only for a *.localhost name, as an evaluation option; Better Auth counts those as loopback.
  • OAUTH_JWKS_URL: documented for the .localhost evaluation only, as http://localhost:4000/api/auth/jwks.
    • The API verifies every access token against its own signing keys, and fetches them from APP_BASE_URL unless this is set.
    • The container can't resolve a *.localhost name (ENOTFOUND), so without it every token is issued and then rejected at /mcp.
    • A real install leaves it unset and fetches from APP_BASE_URL, as cloud does. Plain http://localhost:4000 doesn't need it, since inside the container that address is the API.
  • SAML: SSO_SAML_SP_CERT_FILE is removed. The API only reads SSO_SAML_SP_KEY_FILE, and the docs say to upload the certificate to the IdP.
  • Docs:
    • configuration.md gets the new variables.
    • object-storage.md (now "Use AWS S3 for Object Storage") gets the app-content bucket's IAM, CORS (PUT for logo uploads) and lifecycle rules, plus artifact expiry on your own S3.
    • quickstart.md gets the second bucket and the OAuth/http note.
    • CHANGELOG [Unreleased].
  • docker-compose.{full,database,cache}.yml are regenerated. They match sync-templates.sh and pass docker compose config.

Testing

On the generated docker-compose.full.yml with images built from currents main (including ENG-1738), ports moved off the defaults:

  • rustfs-init:
    • Creates both buckets and the four app-content rules.
    • With retention set to 30 it adds the artifact rule; a re-run is a no-op.
    • Unsetting retention removes the rule, and it doesn't fail when no rule exists.
    • With a hand-added rule on each bucket, runs with retention unset, 30, 30 and unset keep those rules every time, and add and remove only delete-artifacts-after-days.
    • 0, 00, 007, -5, abc and 7d exit 1.
  • Session files and shares:
    • A POST /v1/sessions upload lands under currents-app-content/<orgId>/sessions/.
    • A share link created through MCP serves the screenshot byte for byte.
    • DELETE /v1/sessions/<id> clears the prefix through the writer, and the session then answers 404.
  • MCP with an API key: /mcp lists 43 tools.
  • OAuth:
    • Metadata on http://localhost is consistent, and dynamic client registration works.
    • On http://currents.localhost:14000 with the two .localhost lines from .env.example, the full flow passes: sign-in, client registration, authorize, consent, token, then /mcp with the token. Without OAUTH_JWKS_URL, the token is issued and /mcp rejects it.
    • On http://currents.internal with the host allowed, the API starts but advertises https://currents.internal.
  • Storage settings: docker compose config with only PERMANENT_STORAGE_* in .env passes them through to all three services; with both names set, APP_CONTENT_STORAGE_* wins.
  • Off switches:
    • MCP_ENABLED=false makes /mcp answer 503.
    • An .env without OAUTH_* serves no OAuth metadata (404), and MCP keeps working with keys.
  • Not tested here: logo upload. It was tested in the browser on ENG-1738 with the same variable mapping.

Related

Checklist

  • PR title is Changelog-friendly: (fix|feat|chore): title [CSR-xxx]
  • User-friendly and meaningful description of the changes
  • Documentation was updated

🤖 Generated with Claude Code

https://claude.ai/code/session_01UhM4wHR2xPP8bbrkXGaqUD

…n [ENG-1739]

- api, changestreams-worker and write-worker read the app-content bucket
  (context shares, organization logos, session files) from
  APP_CONTENT_STORAGE_*, mapped to the PERMANENT_STORAGE_* the services read.
  .env.example reuses the artifact storage endpoint and credentials.
- rustfs-init creates the app-content bucket with lifecycle rules scoped to the
  four share prefixes, and applies DC_RUSTFS_DELETE_ARTIFACTS_AFTER_DAYS to the
  artifact bucket (unset removes the rule).
- MCP_ENABLED defaults to true. .env.example turns the OAuth provider and
  dynamic client registration on; an upgraded .env without them keeps OAuth off.
  OAuth needs https, or http on localhost or (for an evaluation) a .localhost
  name in OAUTH_HTTP_ALLOWED_HOSTS: Better Auth advertises an https issuer for
  any other http host.
- The api verifies OAuth access tokens against http://localhost:4000. The
  default JWKS URL is on APP_BASE_URL, which the container cannot resolve for
  a .localhost name, so every token was rejected.
- Drop SSO_SAML_SP_CERT_FILE: the API never read it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UhM4wHR2xPP8bbrkXGaqUD
@baz-reviewer

baz-reviewer Bot commented Oct 13, 2026 •

Copy link
Copy Markdown

Review this PR on Baz

Baz Summary

Expose configurable app-content storage, authenticated remote MCP/OAuth access, and artifact retention across Docker Compose deployments, while preserving direct PERMANENT_STORAGE_* compatibility. Document the resulting storage, security, lifecycle, SAML, and upgrade behavior, and update RustFS initialization to create buckets and maintain scoped lifecycle rules.

Topics

TopicDetails
App Content Storage Map app-content settings to API, changestreams, and writer services, create the dedicated RustFS bucket, and manage scoped share and optional artifact lifecycle rules without deleting persistent logos or session files.
Modified files (9)
  • docs/configuration.md
  • docs/object-storage.md
  • docs/quickstart.md
  • on-prem/.env.example
  • on-prem/docker-compose.cache.yml
  • on-prem/docker-compose.database.yml
  • on-prem/docker-compose.full.yml
  • on-prem/templates/compose.currents.yml
  • on-prem/templates/compose.rustfs.yml
Latest Contributors(1)
UserCommitDate
dj@currents.devdocs: describe which l...October 13, 2026
MCP and OAuth Access Enable and document authenticated remote MCP and OAuth endpoints, including defaults, registration, issuer and JWKS behavior, HTTP restrictions, origin configuration, and deployment off switches.
Modified files (8)
  • docs/configuration.md
  • docs/quickstart.md
  • on-prem/.env.example
  • on-prem/CHANGELOG.md
  • on-prem/docker-compose.cache.yml
  • on-prem/docker-compose.database.yml
  • on-prem/docker-compose.full.yml
  • on-prem/templates/compose.currents.yml
Latest Contributors(1)
UserCommitDate
dj@currents.devdocs: describe which l...October 13, 2026
Deployment Documentation Update operator-facing deployment guidance and release notes to reflect the expanded object-storage model, removed SAML certificate setting, RustFS lifecycle behavior, and regenerated Compose configuration.
Modified files (4)
  • docs/README.md
  • docs/index.md
  • docs/sso-saml.md
  • on-prem/CHANGELOG.md
Latest Contributors(1)
UserCommitDate
dj@currents.devfeat: expose the app-c...October 13, 2026

Merger  Activate to get a short verdict whether this PR is good to go or not

Skills  Activate Skill Maintainer to keep your skills up to date

Planner  This PR would have been improved with Baz Planner - Try it now

Comment thread on-prem/templates/compose.currents.yml Outdated
Comment thread on-prem/templates/compose.rustfs.yml Outdated
…UTH_JWKS_URL to .localhost setups [ENG-1739]

- PERMANENT_STORAGE_* falls back to the same names in .env when
  APP_CONTENT_STORAGE_* is unset. The environment entries override env_file,
  so an .env that set PERMANENT_STORAGE_* directly got empty values.
- rustfs-init rewrites only the lifecycle rules it owns, matched by ID, and
  keeps any others on both buckets. It deleted the artifact bucket's whole
  configuration when retention was unset, and replaced the app-content one.
- The api no longer sets OAUTH_JWKS_URL. A real install fetches its signing
  keys from APP_BASE_URL as cloud does; the .localhost evaluation sets it to
  localhost in .env, since the container cannot resolve .localhost names.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UhM4wHR2xPP8bbrkXGaqUD
Comment thread on-prem/templates/compose.currents.yml
Comment thread on-prem/templates/compose.rustfs.yml
…o set OAUTH_JWKS_URL [ENG-1739]

The CHANGELOG still said rustfs-init replaces both buckets' lifecycle
configuration. OAUTH_JWKS_URL also applies when the container cannot reach or
trust APP_BASE_URL.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UhM4wHR2xPP8bbrkXGaqUD
@twk3
twk3 merged commit 49904fd into main Oct 13, 2026
6 of 7 checks passed
@twk3
twk3 deleted the feat/eng-1739-app-content-mcp-oauth-retention branch October 13, 2026 22:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant