Use JOSE-encrypted credentials locally and Infisical in cloud#492
Open
jrhizor wants to merge 6 commits into
Open
Use JOSE-encrypted credentials locally and Infisical in cloud#492jrhizor wants to merge 6 commits into
jrhizor wants to merge 6 commits into
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
jrhizor
force-pushed
the
jrhizor/db-secret-storage
branch
from
July 24, 2026 18:19
dc7aa86 to
9e96901
Compare
Fail loudly instead of silently unconfiguring providers. An Infisical read that succeeds but returns nothing is an outage, not an empty credential set, so the loader throws and the overlay keeps its last good values. Misread keys, undecryptable rows and vanished credentials log errors with the action to take. Take Infisical off the web request path. The cloud web app runs on Vercel serverless, where a runtime read would add an authentication round trip to every cold start and put Infisical in front of the whole site; Infisical's Vercel secret sync populates the environment at deploy time instead. Only the worker, which is long-lived and spends against these credentials, keeps the SDK loader — so the Infisical vars are no longer web startup requirements. Read one Infisical folder rather than recursing from the project root, so the machine identity needs no broader grant and two folders cannot both define OPENAI_API_KEY with no defined winner. Drop what the payload does not need: typ and v leave the JWE header, since ctx is what stops a ciphertext being re-homed onto another provider. Drop the hint column, which stored the last four characters of the longest value in a bundle — the password, for Oxylabs and DataForSEO — in plaintext beside the ciphertext, and which nothing reads. Delete the unused dataforseo client that captured credentials from the environment at module load.
The worker loads credentials before pg-boss starts, so a source that throws took the whole worker down. On an upgrade that source is a fresh query against provider_credentials, which fails if the database is briefly unreachable or not yet migrated — and the compose file only guarantees migration ordering when Postgres runs in Docker. Schedule the retry interval before the first load and let self-hosted modes carry on with their .env credentials when that load fails. Managed cloud still rethrows, since it has no environment fallback and a worker that started anyway would only take jobs it cannot run. This also fixes the web path never retrying after a failed initial load.
Only the worker reads them at runtime, but treating them as worker-only let a cloud deployment go out with a worker that had no way to reach Infisical. Make them cloud requirements again so that misconfiguration surfaces at startup. INFISICAL_SECRET_PATH and INFISICAL_SITE_URL stay optional — both have working defaults, and requiring the site URL would break any deployment relying on the US cloud default.
@infisical/sdk depends on @aws-sdk/credential-providers and @smithy/*, and Nitro traces a dynamic import into the output whether or not the branch can run. The cloud web app never loads credentials over the network, so that was megabytes of AWS SDK shipped into a Vercel serverless function that would never call it. Move the worker's source selection into its own entry point. startCredentialRefresh now takes a source and whether it is required, so the module the web app imports only ever references instanceCredentialSource. Tracing the import graph from apps/web/src/server.ts no longer reaches @infisical/sdk; from apps/worker/src/index.ts it still does.
Both only ever held their defaults, and each was another way for a cloud deployment to point the loader somewhere the credentials are not. Read the root of INFISICAL_ENVIRONMENT on Infisical's US cloud, with no way to override either. With the read already non-recursive, that fixes the folder contract in one place: one flat set of canonically named secrets at the environment root, and nothing else in the project is fetched.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This PR adds a provider-credential lifecycle for both self-hosted deployments and Elmo Cloud. It is additive: nobody is moved off environment variables here. With no stored credentials, every deployment behaves exactly as it does today, and
getCredentialfalls through toprocess.env.Self-hosted deployments
provider_credentialsas compact JWE.josewith direct key management (dir) andA256GCM; application code no longer implements the cryptographic primitive.joseis already in the tree at this exact version viabetter-auth, so this adds no new dependency.ELMO_ENCRYPTION_KEYduring CLI initialization and backfills it during upgrades.Elmo Cloud
The two runtimes read the same Infisical folder differently, because they have different shapes.
Worker (long-lived VM) authenticates once with the official
@infisical/sdkusing Universal Auth and refreshes every minute, so a rotation lands without a deploy. It reads a single folder rather than recursing from the project root, so the machine identity needs no broader grant and two folders cannot both defineOPENAI_API_KEYwith no defined winner.Web app (Vercel serverless) reads provider credentials from its environment, which Infisical's Vercel secret sync populates at deploy time. Reading Infisical at runtime would add an authentication round trip to every cold start and put Infisical's availability in front of the whole site, to serve credentials the request path barely uses. Rotations reach the web app on the next deploy.
Managed-cloud provider credentials never enter the Elmo database.
Required cloud configuration. Only the worker reads these at runtime, but they are required across cloud so a deployment cannot go out with a worker that has no way to reach Infisical:
INFISICAL_CLIENT_IDINFISICAL_CLIENT_SECRETINFISICAL_PROJECT_IDINFISICAL_ENVIRONMENTThere is nothing else to configure. Credentials are read from the root of that environment on Infisical's US cloud, non-recursively — neither the path nor the site URL is overridable, so there is no way to point the loader somewhere the credentials are not.
Failure behavior
Provider bundles are applied atomically, so multi-field credentials such as Oxylabs and DataForSEO cannot combine one managed value with an unrelated environment value.
Credentials disappearing is treated as a fault, not as a fallback:
ELMO_ENCRYPTION_KEY, a row that will not decrypt, an incomplete bundle, or a managed credential that vanishes each log an error naming the action to take. Nothing in this path fails silently.Verification
pnpm test— 574 tests passed