Skip to content

feat(admin): add atomic config mutations and revision rollback - #15458

Open
romy651 wants to merge 7 commits into
danny-avila:devfrom
fdj-united:feat/admin-config-atomic-mutate
Open

romy651 wants to merge 7 commits into
danny-avila:devfrom
fdj-united:feat/admin-config-atomic-mutate

Conversation

@romy651

@romy651 romy651 commented Sep 1, 2026

Copy link
Copy Markdown

Summary

Adds atomic, versioned mutation and revision rollback for database-backed admin configuration.

  • Route base configuration field patches, resets, full replacement, logical deletion, activation changes, and restore-from-revision through one compare-and-set endpoint.
  • Record the pre-mutation revision and apply the change in the same MongoDB transaction.
  • Require expectedVersion and expectedTenantId; return 409 for stale configuration or tenant context, 400 for invalid mutations, and 404 for missing revisions.
  • Keep versions monotonic across reset/recreation, retain a versioned empty document for logical deletion, and initialize revision/version indexes.
  • Scope authorization, configuration snapshots, revision history, and Langfuse operations to the backend-resolved effective tenant, including the default tenant.
  • Preserve protected sections and inactive-document behavior; normalize legacy secrets after protected-section preservation and retain encryption/redaction through mutation and restore.
  • Resolve encrypted runtime credentials for Azure OpenAI/Assistants, MCP headers and keys, and web search without accidentally expanding literal secrets as templates.
  • Reject legacy base-configuration writes that bypass the atomic endpoint; retain scoped-profile routes.
  • Configure bundled Compose MongoDB for transactions and document explicit Helm architecture selection and upgrade requirements.

Scope

  • Tenant authorization, configuration reads, cache isolation, and tenant-switch protection.
  • Protected configuration fields and field-path validation.
  • Secret preservation, encryption, and runtime decryption.
  • MongoDB replica-set support and deployment configuration.
  • Atomic configuration updates, revision history, rollback, version checks, and Langfuse UI integration.

This is a large PR. It changes how configuration is saved, who can access it, how secrets are handled, and how MongoDB is deployed. These changes support safe configuration updates, but they also make the PR harder to review and require a careful rollout.

Paired admin-panel PR: LibreChat-AI/admin-panel#143

The panel now uses authenticated backend APIs for snapshots and revision history; it no longer connects directly to MongoDB. No new backend dependencies are introduced.

Deployment and compatibility

  • Deploy the matching backend before, or in the same release train as, the paired panel. Do not run an older panel that uses legacy base-write routes against this backend.
  • Atomic configuration and Langfuse updates require a transaction-capable MongoDB replica set. Standalone MongoDB cannot perform these mutations.
  • For the first upgrade from a pre-version-epoch release, stop/drain old backend pods before starting the new image. Use the documented one-time Recreate rollout; old and new writers must not coexist during this transition.
  • Fresh Helm installs using bundled MongoDB require matching mongodb.architecture and librechat.mongoArchitectureAck. Existing standalone-to-replica-set upgrades require a backup and validated PVC/data migration; changing the chart setting does not migrate data automatically.
  • See helm/librechat/readme.md for the deployment procedure.

Change Type

  • Bug fix
  • New feature
  • Breaking change: legacy base-write routes and deployment prerequisites
  • Documentation update
  • English translation update

Latest validation

The latest focused review passed:

  • packages/data-schemas: 6 suites, 195 tests covering override policy, indexed paths, resolution, atomic transactions, config methods, and tenant isolation.
  • packages/api: 9 suites, 765 tests covering config handlers, real atomic transactions, secrets, Langfuse, grants, app configuration, and tenant middleware.
  • Express/API server: 5 suites, 97 tests covering Langfuse/config routes, JWT tenant context, config middleware, and cluster startup.
  • tsc --noEmit in packages/api and packages/data-schemas.
  • git diff --check.
  • Normal pre-commit formatting, import sorting, lint, package validation, and circular-dependency checks passed when committing this update.
  • Paired panel: 39 suites, 1,078 tests; typecheck and lint passed.

Checklist

  • My code adheres to this project's style guidelines
  • I have performed a self-review of my own code
  • I have written tests demonstrating that my changes are effective or that my feature works
  • Local unit tests pass with my changes

@romy651
romy651 marked this pull request as ready for review September 1, 2026 14:11
@romy651

romy651 commented Sep 1, 2026

Copy link
Copy Markdown
Author

@danny-avila, I need your review on this. Thanks

@danny-avila

Copy link
Copy Markdown
Owner

@codex review

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 2, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-09-02T06:29:02.421186Z 0f1ca2b Manual request
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 92c585cd46

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/data-schemas/src/methods/config.ts Outdated
Comment thread packages/data-schemas/src/methods/config.ts
@danny-avila

Copy link
Copy Markdown
Owner

@codex review the latest head

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 0f1ca2b29d

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

if (hasLangfuseHeadersOverride(rawOverrides)) {
return res.status(400).json({ error: LANGFUSE_HEADERS_CONFIG_ERROR });
}
const sanitizedOverrides = sanitizeConfigOverrides(rawOverrides) as Record<string, unknown>;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Reject NUL bytes in nested atomic override keys

In atomic overrides mode, only the outer payload shape is validated; sanitizeConfigOverrides does not recursively reject BSON-invalid property names. A request such as {"expectedVersion":null,"overrides":{"foo":{"\u0000bar":1}}} therefore reaches Config.create/findOneAndUpdate, where BSON serialization rejects the NUL-containing key and the handler returns HTTP 500 rather than a validation error. Recursively validate override keys before beginning the mutation; the same validation should cover object values supplied through atomic field entries.

Useful? React with 👍 / 👎.

Comment thread api/server/index.js
axios.defaults.headers.common['Accept-Encoding'] = 'gzip';
}
await connectDb();
await ensureConfigIndexes(mongoose);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Initialize config indexes in the experimental server

The supported backend:experimental entry point connects in api/server/experimental.js without calling this new initializer. When that deployment runs with MONGO_AUTO_INDEX=false, the config, revision, and epoch uniqueness indexes and the deduplication migration are never installed before the atomic route accepts traffic; two concurrent first saves of an absent base config can therefore both commit separate config and epoch documents instead of one losing with a version conflict. Mirror this blocking initialization in the experimental startup path as well.

Useful? React with 👍 / 👎.

tenantId: params.actor.tenantId,
principalType: params.principalType,
principalId: params.principalId,
overrides: cloneOverrides(current?.overrides),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Encrypt legacy secrets before snapshotting revisions

When an existing base config contains a legacy plaintext credential, snapshotFromConfig copies that credential verbatim into admin_config_revisions. An atomic replace can encrypt or rotate the live config in the same transaction, but the predecessor plaintext then remains recoverable from the revision collection for up to 50 saves, and restoring it writes the plaintext back to the config document. Normalize registered secret fields to ciphertext when constructing and restoring revision snapshots so rollback history does not bypass the at-rest encryption applied by the admin handlers.

Useful? React with 👍 / 👎.

Comment on lines +1490 to +1493
const existing = await findConfigByPrincipal(principalType, principalId, {
includeInactive: true,
...(user.tenantId !== undefined ? { tenantId: user.tenantId } : {}),
});

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Scope default-tenant reads before preserving secrets

In a non-strict deployment where a no-tenant/platform admin coexists with tenant-scoped configs, user.tenantId is undefined and this omits the explicit default-tenant predicate, so the tenant plugin leaves the query unscoped. findOne can then return another tenant's base config, while the subsequent atomic mutation deliberately targets the default tenant via actor.tenantId === ''; preserveConfigSecrets may consequently copy that tenant's omitted credentials into the default config. Pass tenantId: user.tenantId ?? '' for this read and the identical fields-mode preflight read so they use the same scope as the transactional mutation.

Useful? React with 👍 / 👎.

romy651 commented Sep 5, 2026

Copy link
Copy Markdown
Author

Resolved the conflicts with current dev (673325739) and pushed merge commit fcdd51472. No history rewrite or force push.

Validation on the merged tree:

  • Data schemas: 6 suites / 195 tests passed.
  • API package: 9 suites / 769 tests passed.
  • Express routes/startup/authentication: 7 suites / 134 tests passed. This run used --forceExit because the startup suite retains server handles after its assertions finish.
  • tsc --noEmit passed in packages/api and packages/data-schemas after directly rebuilding the merged schema/API packages to replace stale cached artifacts.
  • npm run build:data-provider, npm run build, PR-scoped static checks, normal commit hooks, and git diff --check passed.

@romy651

romy651 commented Sep 5, 2026

Copy link
Copy Markdown
Author

Hi @danny-avila, could you take a look at this PR

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants