-
Notifications
You must be signed in to change notification settings - Fork 1k
fix(js-sdk): parse Dockerfile ENV/ARG values with spaces #1789
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| --- | ||
| 'e2b': patch | ||
| --- | ||
|
|
||
| Fix `Template.fromDockerfile` parsing of `ENV`/`ARG` values that contain whitespace. A quoted value like `ENV NAME="John Doe"` (and an unquoted `ENV KEY=hello world`) was split into a malformed key; it is now parsed as a single value with surrounding quotes stripped, matching the Python SDK. Multiple `key=value` pairs on one line stay separated. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -231,67 +231,36 @@ function handleEnvInstruction( | |
| const argumentsData = instruction.getArguments() | ||
| const keyword = instruction.getKeyword() | ||
|
|
||
| if (argumentsData && argumentsData.length >= 1) { | ||
| const envVars: Record<string, string> = {} | ||
|
|
||
| if (argumentsData.length === 2) { | ||
| // ENV key value format OR multiple key=value pairs (from line continuation) | ||
| const firstArg = argumentsData[0].getValue() | ||
| const secondArg = argumentsData[1].getValue() | ||
|
|
||
| // Check if both arguments contain '=' (multiple key=value pairs) | ||
| if (firstArg.includes('=') && secondArg.includes('=')) { | ||
| // Both are key=value pairs (line continuation) | ||
| for (const arg of argumentsData) { | ||
| const envString = arg.getValue() | ||
| const equalIndex = envString.indexOf('=') | ||
| if (equalIndex > 0) { | ||
| const key = envString.substring(0, equalIndex) | ||
| const value = envString.substring(equalIndex + 1) | ||
| envVars[key] = value | ||
| } | ||
| } | ||
| } else { | ||
| // Traditional ENV key value format | ||
| envVars[firstArg] = secondArg | ||
| } | ||
| } else if (argumentsData.length === 1) { | ||
| // ENV/ARG key=value format (single argument) or ARG key (without default) | ||
| const envString = argumentsData[0].getValue() | ||
|
|
||
| // Check if it's a simple key=value or just a key (for ARG without default) | ||
| const equalIndex = envString.indexOf('=') | ||
| if (equalIndex > 0) { | ||
| const key = envString.substring(0, equalIndex) | ||
| const value = envString.substring(equalIndex + 1) | ||
| envVars[key] = value | ||
| } else if (keyword === 'ARG' && envString.trim()) { | ||
| // ARG without default value - set as empty ENV | ||
| const key = envString.trim() | ||
| envVars[key] = '' | ||
| } | ||
| } else { | ||
| // Multiple arguments (from line continuation with backslashes) | ||
| for (const arg of argumentsData) { | ||
| const envString = arg.getValue() | ||
| const equalIndex = envString.indexOf('=') | ||
| if (equalIndex > 0) { | ||
| const key = envString.substring(0, equalIndex) | ||
| const value = envString.substring(equalIndex + 1) | ||
| envVars[key] = value | ||
| } else if (keyword === 'ARG') { | ||
| // ARG without default value | ||
| const key = envString | ||
| envVars[key] = '' | ||
| } | ||
| } | ||
| } | ||
| if (!argumentsData || argumentsData.length === 0) { | ||
| return | ||
| } | ||
|
|
||
| // Call setEnvs once with all environment variables from this instruction | ||
| if (Object.keys(envVars).length > 0) { | ||
| templateBuilder.setEnvs(envVars) | ||
| // dockerfile-ast splits arguments on whitespace, including inside quotes, so | ||
| // rejoin them to recover the raw value and parse it like the Python SDK: in | ||
| // the `key=value` form a value runs across whitespace until the next `key=` | ||
| // token, and surrounding quotes are stripped. Parsing each token in isolation | ||
| // mangled `ENV NAME="John Doe"` and `ENV KEY=a b` into a broken key. | ||
| const value = argumentsData.map((arg) => arg.getValue()).join(' ') | ||
| const envVars: Record<string, string> = {} | ||
|
|
||
| if (value.includes('=')) { | ||
| const pairRegex = /(\w+)=([^\s]*(?:\s+(?!\w+=)[^\s]*)*)/g | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Docker ENV keys are not restricted to JavaScript's ASCII AGENTS.md reference: AGENTS.md:L3-L3 Useful? React with 👍 / 👎. |
||
| let match: RegExpExecArray | null | ||
| while ((match = pairRegex.exec(value)) !== null) { | ||
| envVars[match[1]] = match[2].replace(/^["']+|["']+$/g, '') | ||
| } | ||
| } else { | ||
| const spaceForm = value.match(/^(\S+)\s+([\s\S]+)$/) | ||
| if (spaceForm) { | ||
| envVars[spaceForm[1]] = spaceForm[2].replace(/^["']+|["']+$/g, '') | ||
| } else if (keyword === 'ARG' && value.trim()) { | ||
| envVars[value.trim()] = '' | ||
| } | ||
| } | ||
|
|
||
| if (Object.keys(envVars).length > 0) { | ||
| templateBuilder.setEnvs(envVars) | ||
| } | ||
| } | ||
|
|
||
| function handleCmdEntrypointInstruction( | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Docker's legacy
ENV <key> <value>form permits=inside the value, but selecting the assignment form whenever the whole line contains=misparsesENV KEY value=fooas{ value: "foo" }and dropsKEY; the parent implementation's two-token branch correctly producedKEY=value=foo. Determine the syntax from the leading token rather than from any equals sign in the joined value, and make the equivalent correction in the shared Python parser, which currently uses the same faulty test.AGENTS.md reference: AGENTS.md:L3-L3
Useful? React with 👍 / 👎.