Skip to content

Propagate X-Data-Env from request onto outbound calls - #228

Merged
eliorh merged 2 commits into
mainfrom
forward-data-env-from-request
Jul 14, 2026
Merged

Propagate X-Data-Env from request onto outbound calls#228
eliorh merged 2 commits into
mainfrom
forward-data-env-from-request

Conversation

@eliorh

@eliorh eliorh commented Jul 12, 2026

Copy link
Copy Markdown
Collaborator

Problem

A Base44-hosted backend function that uses the user client to touch data — e.g.

const base44 = createClientFromRequest(req);
await base44.entities.ActivityLog.create({ ... });

always writes/reads production data, even when the app is running in test-data ("dev") mode.

createClientFromRequest extracts the auth tokens, Base44-App-Id, Base44-Api-Url, Base44-Functions-Version, and Base44-State — but no data-env signal. The backend forwards the environment to the function as X-Data-Env (and the browser sets a base44_data_env cookie), yet neither is read here, so it never rides on the outbound entity calls.

For asServiceRole this happens to work anyway because the environment is carried inside the service token as a claim, and the SDK forwards that token. But the user-scoped path sends the user JWT, which carries no environment — so those callbacks silently fall back to production.

Fix

Read X-Data-Env from the incoming request and add it to additionalHeaders, which createClient merges into every axios client's default headers. Now both the user and service-role clients carry the environment, keeping a function's data operations in the same environment as the triggering request.

Mirrors the existing Base44-State propagation exactly.

Tests

Added two cases in tests/unit/client.test.js (mirroring the Base44-State tests):

  • user-scoped entities.Todo.list() sends X-Data-Env: dev when the request had it
  • no X-Data-Env header when the request didn't

npm run build, eslint src, and vitest run tests/unit/client.test.js (26 passed) all green.

Paired backend change

Requires the backend to forward an explicit X-Data-Env: dev header into the function (the browser only sends the cookie, which this function doesn't read). That half is in apper PR #15514.

🤖 Generated with Claude Code

@claude

claude Bot commented Jul 12, 2026

Copy link
Copy Markdown
Contributor

Claude encountered an error —— View job


I'll analyze this and get back to you.

@github-actions

github-actions Bot commented Jul 12, 2026

Copy link
Copy Markdown

🚀 Package Preview Available!


Install this PR's preview build with npm:

npm i @base44-preview/sdk@0.8.38-pr.228.85deaff

Prefer not to change any import paths? Install using npm alias so your code still imports @base44/sdk:

npm i "@base44/sdk@npm:@base44-preview/sdk@0.8.38-pr.228.85deaff"

Or add it to your package.json dependencies:

{
  "dependencies": {
    "@base44/sdk": "npm:@base44-preview/sdk@0.8.38-pr.228.85deaff"
  }
}

Preview published to npm registry — try new features instantly!

@claude

claude Bot commented Jul 12, 2026

Copy link
Copy Markdown
Contributor

Claude encountered an error —— View job


I'll analyze this and get back to you.

createClientFromRequest extracted the auth tokens and Base44-State but no
data-env signal, so a backend function's user-scoped entity calls
(base44.entities.X...) always hit production data even when the app runs in
test-data mode — the user JWT carries no environment, unlike the service token.

Read X-Data-Env from the incoming request and add it to additionalHeaders so
every outbound call (user + service role) carries it, keeping function data
operations in the same environment as the triggering request.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@eliorh
eliorh force-pushed the forward-data-env-from-request branch from 658cd87 to 125c36c Compare July 12, 2026 08:51
@claude

claude Bot commented Jul 12, 2026

Copy link
Copy Markdown
Contributor

Claude encountered an error —— View job


I'll analyze this and get back to you.

@natansil natansil left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Reviewed with focus on security, regressions, backward compatibility, and the deploy pairing with apper #15514.

Correct fix at the right layer: the SDK is a courier running inside the function, so it can't judge whether the env signal is trustworthy — trust enforcement belongs at the invocation gateway, and #15514 puts it there (_trusted_request_data_env drops a dev signal unless is_preview_request, explicitly to stop a public prod-domain caller from redirecting an asServiceRole function onto the dev partition). Nested-call inheritance is gated on the verified service token, not raw request input. Additive and inert until #15514 ships: no X-Data-Env header → byte-identical behavior (pinned by the negative test); older backends ignore the unknown header; older SDKs keep the current prod-fallback bug. Mirrors the adjacent Base44-State propagation exactly, tests included.

No new vulnerability introduced by this PR. The security follow-ups are on the backend side (#15514), not here: (1) the preview-trust gate keys on is_preview_request, which classifies by Host AND Origin — Origin is spoofable in direct HTTP, so a deliberate attacker can still mint the dev signal on a prod function URL (impact is integrity/audit-evasion — writes land in test data, validations run against the near-empty dev partition — not data theft; user-scoped stays RLS-bounded and service-role dev writes touch only the app's own test partition); worth hardening that gate to Host-only or a server-side signal. (2) Deploy-order safety depends on functions only ever receiving backend-constructed headers (not the client's raw headers); worth confirming there's no raw-header passthrough path. Both raised on #15514.

Approving; one optional SDK-side hardening note inline.

Comment thread src/client.ts Outdated
Defense-in-depth: gate the propagated header on the closed dev/prod set
instead of any truthy string, matching the backend contract and avoiding
relaying an arbitrary caller-supplied header value onward.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@claude

claude Bot commented Jul 12, 2026

Copy link
Copy Markdown
Contributor

Claude encountered an error —— View job


I'll analyze this and get back to you.

@eliorh
eliorh merged commit d6dd7ef into main Jul 14, 2026
6 of 7 checks passed
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