Skip to content

fix(dockerfile): parse FROM --platform flag in splitIntoStages (#1178) - #1240

Merged
joryirving merged 1 commit into
mainfrom
courier/misospace/dispatch/issue-1178
Oct 13, 2026
Merged

joryirving merged 1 commit into
mainfrom
courier/misospace/dispatch/issue-1178

Conversation

@itsmiso-ai

Copy link
Copy Markdown
Contributor

What

Fixes #1178. The splitIntoStages helper in Dockerfile.test.ts parsed FROM lines as FROM <image> [AS <name>], capturing the first token after FROM as the image and treating AS as optional. A FROM --platform=... base AS name line therefore registered the stage under the wrong key — the --platform=... flag (or the base image) — so every stage-scoped assertion silently read the wrong section and could give false pass/fail results.

The regex now skips leading --flag tokens and captures the image and the optional AS <name> separately:

  • before: /^\s*FROM\s+\S+\s+(?:AS\s+)?(\S+)/i (name = capture 1)
  • after: /^\s*FROM\s+(?:--\S+\s+)*(\S+)(?:\s+AS\s+(\S+))?/i (name = capture 2)

The current Dockerfile has no --platform usage, so the bug was latent; the fix is scoped to the test helper only. No production code and no Dockerfile instructions change.

Invariants this change keeps

  1. Every named stage in the current Dockerfile is still keyed by its AS <name>. Kept by the third new test (base, deps, prod-deps, mcp-deps, builder, runner, mcp all resolve), and the existing #533 / #1173 stage-scoped assertions still pass unchanged.
  2. A stage name only ever comes from an explicit AS clause — the base-image token is never used as a key. Kept by (?:\s+AS\s+(\S+))?; name capture moved from group 1 to group 2.
  3. Leading --flags never shift the image/name tokens. Kept by (?:--\S+\s+)*.
  4. Each stage body still starts at the line after its FROM (the FROM line is not part of the body). Unchanged: flush() + buffer = [] reset is untouched.
  5. Behavior on the current Dockerfile is byte-for-byte identical to before (no regression). Verified: new regex yields the same 7 keys as the old one on Dockerfile; differs only on the previously-misparsed --platform shape.

Other code paths enforcing the same rule

splitIntoStages is a file-local helper with no production callers, and there is no other FROM parser in the repo. The other regexes in this same file (# Dockerfile.test.ts ARG DATABASE_URL / ENV DATABASE_URL) match ARG/ENV, not FROM, so they are unaffected and need no change. Stage membership for the #533 and #1173 assertions depends only on splitIntoStages, which is kept correct by invariant 1.

Local validation (run against the integrated change on this branch)

  • npx vitest run Dockerfile.test.ts → 8 passed (5 existing + 3 new).
  • npx vitest run (full suite) → 4305 passed | 16 skipped | 1 todo; 0 failed.
  • npx tsc --noEmit → clean.
  • npx eslint . → 0 errors (1 pre-existing warning in src/app/login/page.tsx, unrelated to this change).
  • Standalone node harness confirmed old regex keys FROM --platform=linux/amd64 node:24 AS foo as node:24 while the fix keys it foo, and the plain-Dockerfile key set is unchanged.

CI is left as-is for the operator to observe; nothing here is claimed green beyond the local runs above.

The test helper's FROM regex captured the first token after FROM as the
base image and made the AS keyword optional, so a line like
'FROM --platform=linux/amd64 node:24 AS foo' registered stage foo under
the platform flag (or the base image) instead of its real name. Capture
the image separately from an optional 'AS <name>' clause, skipping any
leading --flags, and add regression tests for the --platform shape.

@its-saffron its-saffron Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

AI Automated Review

Full PR review.

Analysis engine: MiniMax-M3 (anthropic) — primary route · pr-reviewer-action v3.4.1

Recommendation

Approve. This PR correctly fixes the splitIntoStages test helper to handle FROM --platform=... base AS name lines per issue PR 1178. The change is scoped entirely to Dockerfile.test.ts (the only caller of the helper), the new regex preserves the 7 named stages currently in Dockerfile, and the three new tests cover the regression paths including the downstream FROM <prev> AS <next> reference shape.

Change-by-change findings

  • fromRe regex (Dockerfile.test.ts:27) — Old pattern /^\s*FROM\s+\S+\s+(?:AS\s+)?(\S+)/i made AS optional and captured the first non-space token after FROM as the stage name. New pattern /^\s*FROM\s+(?:--\S+\s+)*(\S+)(?:\s+AS\s+(\S+))?/i correctly strips any leading --flag tokens, captures the image in group 1, and the optional AS <name> in group 2. On the current Dockerfile (no flags, named stages) the resulting map keys are identical to before; only the previously-misparsed --platform shape changes. Held.
  • currentName = match[2] ?? null (Dockerfile.test.ts:41) — Uses the new AS-name capture group, with ?? null correctly handling unnamed FROM lines so they still flush the prior stage but are not themselves keyed. Consistent with the docstring. Held.
  • flush() and body accumulation — Untouched; the FROM line is not part of the body, matching prior behavior. Held.
  • Three new tests — Cover single-stage --platform shape, downstream stage referencing a --platform base, and a regression test that all 7 named stages (base, deps, prod-deps, mcp-deps, builder, runner, mcp) still resolve from the real Dockerfile. Held.
  • Existing PR 533 / PR 1173 stage-scoped assertions — Unchanged; they use splitIntoStages to read builder, mcp, mcp-deps and depend only on the named stages remaining keyed by their AS clause, which the third new test pins. Held.

Claim verification

  • Claim 1 (FROM --platform mis-key bug): Held. Old regex made the stage keyword match match[1] from the first non-space token after FROM; the new regex moves the AS-name capture to group 2 and skips leading --flag tokens.
  • Claim 2 (no production code / Dockerfile changes): Held. Only Dockerfile.test.ts modified; Dockerfile and production source are untouched. grep --platform shows zero occurrences outside the new docstring and tests in this file.
  • Claim 3 (all 7 named stages still keyed): Held. Confirmed by manual regex walk against the 7 FROM ... AS <name> lines in Dockerfile and by the third new test ("still parses plain named stages without a flag").
  • Claim 4 (regex invariants / byte-for-byte identical on current Dockerfile): Held. flush() + buffer = [] untouched; old regex would produce identical keys for the plain-shape FROM lines; new regex produces the same keys for the same input.
  • Claim 5 (same 7 keys as old on Dockerfile, differs only on --platform shape): Held.

Standards Compliance

  • No secrets, credentials, or tokens touched; DISPATCH_AGENT_TOKEN / GITHUB_TOKEN policy is not engaged.
  • No production code paths change; the helper is file-local and only invoked from tests within the same file.
  • Lint and Typecheck CI checks reported as success on the head SHA. Local npx tsc --noEmit and npx eslint . reported clean by the author; CI matches.
  • Multi-stage Docker conventions and the existing ARG DATABASE_URL / ENV DATABASE_URL rules (issue PR 533) are unaffected by the test regex.

Linked Issue Fit

Issue PR 1178 asked for:

  1. A fix to splitIntoStages so FROM --platform=... base AS name parses to stage name keyed correctly — delivered (regex + capture-group shift).
  2. A unit test covering FROM --platform=linux/amd64 node:24 AS foo — delivered as the first new test.
  3. Scope: only Dockerfile.test.ts — held.

The author additionally added a downstream-stage test and a 7-stage regression test, both reasonable extensions of the requested coverage.

Tool Harness Findings

  • read_file Dockerfile.test.ts — Full file confirmed; only fromRe and currentName = match[2] ?? null change in the helper, plus three new tests appended after the existing describe("Dockerfile MCP image wiring") block.
  • read_file Dockerfile — Confirmed no --platform usage and exactly 7 named stages (base, deps, prod-deps, mcp-deps, builder, runner, mcp).
  • git_grep splitIntoStages — All 8 references are inside Dockerfile.test.ts (definition + 5 existing call sites + 3 new test call sites). No production callers.
  • git_grep --platform — All matches are in Dockerfile.test.ts (docstring, comment, test inputs/asserts). Zero in Dockerfile or production source.

CI Check Results

The PR head SHA a8758f8c shows all checks green (Docker Build, Docker Build (MCP), smoke, npm audit, Lint, Workflow lint, Database migrations, Coverage, Build, Tests, Database integration, Typecheck). No CI evidence to dispute.

No findings warrant a request for changes.

@joryirving
joryirving merged commit a8fd35e into main Oct 13, 2026
13 checks passed
@joryirving
joryirving deleted the courier/misospace/dispatch/issue-1178 branch October 13, 2026 14:48
@its-miso its-miso Bot mentioned this pull request Oct 13, 2026
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.

Dockerfile.test.ts splitIntoStages mis-parses FROM lines with --platform flag

2 participants