fix: allow custom storage uploads through admin CSP#1979
Conversation
🦋 Changeset detectedLatest commit: 29fadd8 The changes in this PR will be included in the next version bump. This PR includes changesets to release 16 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
|
All contributors have signed the CLA ✍️ ✅ |
@emdash-cms/admin
@emdash-cms/auth
@emdash-cms/auth-atproto
@emdash-cms/blocks
@emdash-cms/cloudflare
@emdash-cms/contentful-to-portable-text
emdash
create-emdash
@emdash-cms/gutenberg-to-portable-text
@emdash-cms/plugin-cli
@emdash-cms/plugin-types
@emdash-cms/registry-client
@emdash-cms/registry-lexicons
@emdash-cms/sandbox-workerd
@emdash-cms/x402
@emdash-cms/plugin-ai-moderation
@emdash-cms/plugin-atproto
@emdash-cms/plugin-audit-log
@emdash-cms/plugin-color
@emdash-cms/plugin-embeds
@emdash-cms/plugin-field-kit
@emdash-cms/plugin-forms
@emdash-cms/plugin-webhook-notifier
commit: |
There was a problem hiding this comment.
Review: fix runtime storage upload origin in admin CSP
The approach is sound and narrowly targeted: custom storage adapters that resolve their upload origin at runtime need a way to tell the admin CSP what to allow, since the descriptor and S3_ENDPOINT fallbacks are static. Falling back to a runtime hook after the existing precedence rules keeps the change additive and matches the architecture (runtime decisions live on emdash.storage, descriptor decisions live in config).
However, the PR introduces getClientUploadOrigin() as a runtime Storage contract but never adds it to the Storage interface in packages/core/src/storage/types.ts. The CSP helper is typed as Pick<Storage, "getClientUploadOrigin">, and context.locals.emdash.storage is typed as Storage | null. Since Storage currently has no such method, passing the runtime storage is a type-checked contract violation and custom adapters have no typed surface to implement. This is a real omission that blocks type-correct custom adapters.
The rest of the change is clean: precedence is respected (descriptor → S3_ENDPOINT → runtime), the new hook result is still run through getHttpOrigin() so malformed/non-HTTP origins are discarded, a reproducing unit test is added, the changeset is present, and no user-facing strings/SQL/content-table queries are involved.
Recommendation: add getClientUploadOrigin?(): string to the Storage interface, then this is good to go.
c08fb42 to
c138d62
Compare
|
recheck |
What does this PR do?
Fixes direct browser uploads for custom S3-compatible storage adapters.
The admin CSP previously discovered upload origins only from a static storage descriptor or the built-in S3 adapter's
S3_ENDPOINT. Runtime-resolved custom adapters could generate a valid signed upload URL, butconnect-src 'self'blocked the browser's PUT before it reached storage.This change falls back to the existing runtime
getClientUploadOrigin()hook when the descriptor does not expose an endpoint. Explicit descriptor configuration and the built-in S3 environment fallback keep their current precedence.Related issue: none; reproduced against a live custom-adapter deployment.
Type of change
Checklist
pnpm typecheckpassespnpm lintpassespnpm testpasses (or targeted tests for my change)pnpm formathas been runmessages.pochanges except in translation PRs — a workflow extracts catalogs on merge tomain.AI-generated code disclosure
Screenshots / test output
No visual change.
pnpm build— passedpnpm typecheck— passedpnpm lint— passedpnpm --filter emdash exec vitest run tests/unit/middleware/csp.test.ts— 19 passedpnpm test— all core/admin/auth/cloudflare and other package tests passed; one unrelated existing Workerd integration test failed because two runner processes contended for hard-coded port127.0.0.1:18788, including when rerun in isolation