util/llbtodagger/WHITEBOARD.md
Last updated: 2026-02-28
./util/llbtodagger that converts BuildKit LLB + Docker image metadata into a Dagger *call.ID.*pb.Definition (BuildKit LLB definition).*dockerspec.DockerOCIImage (Docker OCI image metadata/config, e.g. from dockerfile2llb).*call.ID (must reference Dagger API calls/fields).Container for Docker-build-derived LLB.engine/buildkit/llbdefinition.go (DefToDAG / OpDAG).WHITEBOARD.md) is the persistent task log for:
dagger.customOp handling is intentionally out of scope.Container-typed ID and preserve container metadata where representable from LLB.cache-expert core references and debugging guidance.engine/buildkit/llbdefinition.go (OpDAG, op type helpers).dagql/call/id.go construction/digest rules.container, directory, file, git, http, host.util/llbtodagger.dockerfile2llb -> pb.Definition -> DefinitionToID) for simple and complex supported cases.core/integration end-to-end suite validating Dockerfile -> dockerfile2llb -> DefinitionToID -> LoadContainerFromID execution path.ExecOp mount handling.copy to explicit file destination paths by mapping single-file copies to withFile.chown (--chown=:gid) in converted file ops.chown on copy actions when container context is available.func DefinitionToID(def *pb.Definition, img *dockerspec.DockerOCIImage) (*call.ID, error)
img=nil when metadata input is unavailable.func DefinitionToIDWithTrace(def *pb.Definition) (*call.ID, *Trace, error)Trace is diagnostic only, not a fallback mechanism.buildkit.DefToDAG(def)mapOp(dag *buildkit.OpDAG) (*call.ID, error) with memoization by (opDigest, outputIndex).util/llbtodagger/convert.goutil/llbtodagger/types.goutil/llbtodagger/ops_*.go (split by op class)util/llbtodagger/convert_test.go(*call.ID, error)*pb.Definition into *buildkit.OpDAG.Op == nil case).call.NewArgument + call.WithArgs.docker-image:// -> query.container(...).from(address: ...) chain.git:// -> query.git(url: ...).<ref/head/...>.tree(...) chain.local:// -> query.host().directory(...) chain.http:///https:// -> query.http(url: ...).oci-layout:// currently returns explicit unsupported error.blob:// is explicitly unsupported; returns error.ExecOp mapping to container API chain:
withMountedDirectory, withMountedCache, withMountedTemp) for supported caseswithExec(args: ...) and output mount projectionFileOp mapping:
copy -> withDirectory mapping for supported casesmkfile -> withNewFilemkdir -> withNewDirectoryrm -> withoutFileMergeOp mapping (directory composition chain).DiffOp mapping (directory.diff(other: ...) style chain).BuildOp behavior:
llb definitions.BuildOp, blob://) return deterministic errors.README or doc comments explaining:
dockerfile2llb.Dockerfile2LLBMarshal(...).ToPB()DefinitionToIDFROM ...)COPY ... from main context)RUN ...)COPY, WORKDIR, ENV)ADD https://...)ADD https://...git)DefinitionToID output is container-typed for Docker-build LLB.pb.Definition + DockerOCIImage) for metadata-complete conversion.pb.Definition alone../core/integration with suite name LLBToDaggerSuite.dockerfile2llb.Dockerfile2LLBMarshal(...).ToPB()llbtodagger.DefinitionToIDSync and/or WithExec/StdoutRUN, COPY, ADD, WORKDIR, ENVconfig JSON),withDirectory Permissions Support (copy mode override)permissions argument to Directory.withDirectory.permissions argument to Container.withDirectory for API parity.core/integration/directory_test.go:
Directory.withDirectory(..., permissions: ...) applies mode recursively to copied tree.LLBToDaggerSuite.LLBToDaggerSuite integration coverage for COPY --chmod:
COPY --chmod case.util/llbtodagger copy mapping:
pb.FileActionCopy.Mode to the new withDirectory(permissions: ...) API instead of erroring.dagger -y call -m ./toolchains/go-sdk-dev generatecopy mode override once implemented.readOnly (or readonly, schema-consistent naming) argument to Container.withMountedDirectory.WithMountedDirectory(..., readonly bool) call.dagger -y call -m ./toolchains/go-sdk-dev generate; use --workspace=. in this worktree if needed).ExecOp bind-mount conversion for read-only mounts.
m.Readonly bind mounts.pb.Mount{MountType=BIND, Readonly=true} to withMountedDirectory(..., readOnly: true).ExecOp do not leak/stick into subsequent execs.withoutMount(path: ...) cleanup in the generated chain where needed so post-exec state matches BuildKit behavior.util/llbtodagger.
withMountedDirectory + cleanup structure for sticky/non-sticky semantics.RUN --mount=type=bind,readonly conversion/runtime behavior.withMountedDirectory(readOnly: true) behavior.go test ./util/llbtodagger.chown Support0:<gid> baseline) instead of erroring.COPY --chown=:<gid> conversion test and assert owner field in emitted ID chain.go test ./util/llbtodagger.core/integration llbtodagger tests via debugging.md command shape.chown via Container-Aware FileOp MappingCOPY/ADD --chown=<name> path first; do not broaden with fallback heuristics.UserOpt_ByName values in chownOwnerString normalization.user/group names vs numeric ids).withFile / withDirectory calls (with rootfs sync) so Dagger resolves names through container /etc/passwd and /etc/group.COPY --chown=<name>.LoadContainerFromID.go test ./util/llbtodagger.core/integration llbtodagger tests following skills/cache-expert/references/debugging.md._...) so it is callable from raw ID construction but intentionally not codegen'd for SDKs.healthcheckonBuildshellvolumesstopSignalhealthcheck: JSON-encoded dockerspec.HealthcheckConfig.volumes: sorted []string of volume paths (re-hydrated to map/set in schema resolver).Container.Config is updated deterministically.dagger -y call -m ./toolchains/go-sdk-dev generatedockerBuild Integrationdirectory.dockerBuild to the new LLB->ID pipeline while keeping API shape unchanged.container.build via the same Container.Build implementation path.Container.Build internals with llbtodagger pipeline.
dockerfileDir.contextDir.LLB to llb.State and call dockerfile2llb.Dockerfile2LLB.*pb.Definition.*call.ID via llbtodagger.DefinitionToID.ContainerID through DAGQL/server load path and return resulting *core.Container.Container.Build for this transition only.
bk.Solve path.WithSecretTranslator / WithSSHTranslator setup.DefToDAG walk/marshal mutation path.TODO: remove commented code once fully replaced, just a reference on how it used to work for now#syntax=...) in this phase.noInit behavior in cutover path.WHITEBOARD.md updated with exactly which dockerBuild tests fail post-cutover.dagger --progress=plain call engine-dev test --pkg ./core/integration --run='TestDockerfile/TestDockerBuild' -> faildagger --progress=plain call engine-dev test --pkg ./core/integration --run='TestDockerfile/TestBuildMergesWithParent' -> passTestDockerfile/TestDockerBuild:
with_syntax_pragma, with_old_syntax_pragma: expected for Phase 15 (#syntax=... unsupported in cutover path).with_build_secrets*, with_unknown_build_secrets*, TestDockerBuildSSH/*): expected for Phase 15 (secret/ssh unsupported).default_Dockerfile_location, custom/subdirectory Dockerfile location, .dockerignore compatibility, with_build_args, prevent_duplicate_secret_transform) failed due:
llbtodagger: unsupported op "file.copy": copy without createDestPath is unsupported.file.copy createDestPath=false gap was the major non-secret/non-ssh blocker for broad dockerBuild cutover coverage (resolved in Phase 16).file.copy createDestPath=false SupportGoal:
FileActionCopy.CreateDestPath=false semantics in llbtodagger conversion.Semantics to preserve (BuildKit reference behavior):
createDestPath=false, copy should fail if destination parent path does not exist.internal/buildkit/solver/llbsolver/file/backend.go, docopy).Initial gap (before this phase):
createDestPath=false.Directory.withDirectory / Directory.withFile implementations always created parent directories (MkdirAll path), so they could not express createDestPath=false faithfully.Decision:
Option B (selected):
internal:"true") to existing copy schema args using inverted naming: doNotCreateDestPath.doNotCreateDestPath=false so current Dagger behavior (create destination parent paths) remains unchanged.doNotCreateDestPath=true via raw ID construction when LLB has createDestPath=false.Option B execution plan:
internal:"true") to existing directory/container copy schema args:
doNotCreateDestPath bool with default false.doNotCreateDestPath=false, keep current behavior (create destination parent path as today).doNotCreateDestPath=true, verify destination parent exists and return error if missing.applyCopy:
CreateDestPath=true as today.CreateDestPath=false by setting hidden internal arg doNotCreateDestPath=true in call IDs.createDestPath=false copy path.createDestPath=false after landing.dagger -y call -m ./toolchains/go-sdk-dev generate -> pass (no changes to apply)go test ./util/llbtodagger ./core ./core/schema -> passdagger --progress=plain call engine-dev test --pkg ./core/integration --run='TestLLBToDagger/TestLoadContainerFromConvertedIDCopyDoNotCreateDestPath' -> passdagger --progress=plain call engine-dev test --pkg ./core/integration --run='TestLLBToDagger' -> passdagger --progress=plain call engine-dev test --pkg ./core/integration --run='TestDockerfile/TestDockerBuild' -> fail (expected for known unsupported areas); createDestPath=false unsupported error is gone.
stat /src: no such file or directory, stat /subcontext: no such file or directory).TestDockerfile/TestDockerBuild/default_Dockerfile_location):
directory(path: "/src") inside source resolution (stat /src: no such file or directory).directory(path: "/src") comes from Directory.StateWithSourcePath() copy-shim (llb.Copy(dirSt, dir.Dir, ".", CopyDirContentsOnly:true) with dir.Dir=/src).createDestPath=false blocker, this is the next concrete failure to address.MainContext + Structural Context Rebinding (No Directory.State* Dependency)Goal:
dockerBuild reliance on Directory.State() / Directory.StateWithSourcePath() for Dockerfile context injection.stat /src / stat /subcontext class failures without text-based ID hacks.Approach:
dockerfile2llb a synthetic, deterministic sentinel MainContext local source state.llbtodagger conversion so sentinel local-source ops are rebound to the actual Dagger context directory ID provided by caller.Checklist:
llb.State for ConvertOpt.MainContext (valid non-nil output graph; deterministic marker).core.Container.Build to stop calling contextDir.State* for Dockerfile2LLB MainContext.Directory ID/call ID) alongside def + img.TestDockerfile/TestDockerBuild/default_Dockerfile_location passes.subdirectory_with_default_Dockerfile_location passes.2026-02-28 validation runs:
go test ./util/llbtodagger ./core ./core/schema -> pass.dagger --progress=plain call engine-dev test --pkg ./core/integration --run='TestDockerfile/TestDockerBuild/default_Dockerfile_location' -> pass.dagger --progress=plain call engine-dev test --pkg ./core/integration --run='TestDockerfile/TestDockerBuild/(custom_Dockerfile_location|subdirectory_with_default_Dockerfile_location|subdirectory_with_custom_Dockerfile_location)' -> pass.dagger --progress=plain call engine-dev test --pkg ./core/integration --run='TestDockerfile/TestDockerBuild' -> fail (expected+known unsupported plus one newly surfaced copy-semantics issue):
onbuild_command_is_published exposed COPY source-missing behavior mismatch (include-filter no-op vs BuildKit error).dagger --progress=plain call engine-dev test --pkg ./core/integration --run='TestDockerfile/TestDockerBuild/onbuild_command_is_published' -> pass after strict source-path existence wiring (requiredSourcePath internal arg on withDirectory path).Follow-up tie-in (future branch):
Directory.State() usage from dockerBuild path in the branch where LLB is no longer a general Dagger runtime dependency.Goal:
dockerBuild through llbtodagger conversion.Scope:
ExecOp.Secretenv and ExecOp mounts with MountType_SECRET.MountType_SSH (stays unsupported until a dedicated follow-up phase).Design checklist:
DefinitionToIDOptions field for mapping LLB secret IDs -> Dagger Secret call IDs.core package types; use *call.ID mapping data only.core.Container.Build.
secrets []dagql.ObjectResult[*Secret] + secretStore.GetSecretName(...).DefinitionToIDWithOptions(...).ExecOp.Secretenv conversion.
container.withSecretVariable(name: ..., secret: ...).withSecretVariable.optional=true: skip.optional=false: return explicit error.MountType_SECRET conversion.
container.withMountedSecret(path: ..., source: ..., owner: ..., mode: ...).uid/gid to owner string (<uid>:<gid>).mode arg.withMountedSecret.optional=true: skip.optional=false: return explicit error.withoutSecretVariable.withoutMount(path).core.Container.WithoutMount also removes secret mounts with matching MountPath.container.Secrets (legacy-compatible persistence on returned container object).Test checklist:
util/llbtodagger/convert_test.go):
withSecretVariable + cleanup.withMountedSecret + cleanup.util/llbtodagger/dockerfile_convert_test.go):
RUN --mount=type=secret,id=...,env=... converts as expected.RUN --mount=type=secret,id=... mount path/mode/owner mapping.core/integration):
llbtodagger_test.go for secret env + secret mount behavior.TestDockerfile/TestDockerBuild secret cases and make builtin frontend path pass:
with_build_secretswith_unknown_build_secrets#syntax=... remote frontend expectations unchanged for now (still unsupported by cutover path).skills/cache-expert/references/debugging.md for integration test runs.Completion notes:
with_build_secrets and with_unknown_build_secrets now pass on dockerBuild hard-cutover path.RUN --mount=type=secret/env=... behavior is non-sticky per-run via cleanup calls.Post-landing bookkeeping:
Unsupported and relevant to Dockerfile-generated LLB.Current Explicit Unsupported Cases and nuanced catalogs accordingly.Goal:
RUN --mount=type=ssh) in hard-cutover dockerBuild through llbtodagger conversion.Scope:
ExecOp mounts with MountType_SSH.Design checklist:
DefinitionToIDOptions field mapping LLB SSH IDs -> Dagger Socket call IDs.core package types; mapping stays *call.ID.core.Container.Build.
dockerBuild SSH mounts are not supported....MountType_SSH conversion in util/llbtodagger/exec.go.
container.withUnixSocket(path: ..., source: ..., owner: ...).uid/gid to owner string (<uid>:<gid>).withUnixSocket.optional=true: skip.optional=false: return explicit error.withoutUnixSocket(path) after withExec.withUnixSocket API has no explicit mode control.Test checklist:
util/llbtodagger/convert_test.go):
withUnixSocket + cleanup.util/llbtodagger/dockerfile_convert_test.go):
RUN --mount=type=ssh converts as expected.core/integration):
TestDockerBuildSSH/* coverage on cutover path.llbtodagger_test.go for SSH mount behavior + non-sticky cleanup.skills/cache-expert/references/debugging.md exactly.Completion notes:
MountType_SSH via withUnixSocket + withoutUnixSocket cleanup.RUN --mount=type=ssh.Goal:
Scope:
#syntax=... handling in core.Container.Build preflight checks around Dockerfile bytes.Design checklist:
dockerfile2llb + llbtodagger conversion path.Test checklist:
core/integration/dockerfile_test.go):
with_syntax_pragma passes on cutover path.with_old_syntax_pragma passes on cutover path.skills/cache-expert/references/debugging.md command conventions.Completion notes:
docker/dockerfile:*) are now accepted and ignored by the hard-cutover path.Post-landing bookkeeping:
query.http Checksum EnforcementGoal:
query.http API.Scope:
query.http schema/API and HTTP download execution path in core.ADD --checksum support (separate track).Design checklist:
checksum to query.http.
core/schema/http.go argument docs + httpArgs.digest.Parse(...).query.http resolver identity digest.
core/schema/http.go (hashutil.HashStrings(...) path).dagger -y call -m ./toolchains/go-sdk-dev generatedagger -y call -m ./toolchains/go-sdk-dev --workspace=. generateTest checklist:
core/integration/http_test.go):
skills/cache-expert/references/debugging.md format for integration runs.Completion notes:
query.http now supports an optional public checksum argument and enforces digest match against downloaded content.--workspace=.) to pick up local schema changes.skills/cache-expert/references/debugging.md.followPaths Support (Internal-Only Path)Goal:
local.followpaths emitted by Dockerfile->LLB conversion, without exposing this knob in public Dagger APIs.Design principles:
Implementation checklist:
pb.AttrFollowPaths JSON in local source conversion.followPaths arg on host.directory(...) when present.followPaths: [String!] arg to host.directory args struct (internal:"true").core.Host.Directory into filesync.SnapshotOpts.SnapshotOpts.FollowPaths through filesync snapshot/sync into:
engine.LocalImportOpts.FollowPaths)fsutil.FilterOpt.FollowPaths)skills/cache-expert/references/debugging.mdNon-goals for this phase:
Completion notes:
local.followpaths now converts to hidden host.directory(followPaths: [...]) in llbtodagger IDs.SnapshotOpts into remote and local filesync filters.go test ./util/llbtodagger -run 'TestDefinitionToIDLocal(Source|FollowPaths|FollowPathsInvalidUnsupported)$' -count=1go test ./engine/filesync -count=1dagger --progress=plain call engine-dev test --pkg ./core/integration --run='TestLLBToDagger/TestLoadContainerFromConvertedIDLocalFollowPaths' --parallel=1Expected touchpoints (planning index):
util/llbtodagger/source.gocore/schema/host.gocore/host.goengine/filesync/filesyncer.goengine/filesync/remotefs.goengine/filesync/localfs.goutil/llbtodagger/* and core/integration/*Goal:
FileActionCopy.attemptUnpackDockerCompatibility semantics (Dockerfile ADD local archive behavior) without exposing new public SDK surface.Design principles:
Implementation checklist:
attemptUnpackDockerCompatibility bool arg to WithDirectoryArgs (internal:"true" default:"false").attemptUnpackDockerCompatibility bool arg to WithFileArgs (internal:"true" default:"false").directorySchema.withDirectory -> core.Directory.WithDirectory.directorySchema.withFile -> core.Directory.WithFile.core/directory.go copy path:
doNotCreateDestPath and requiredSourcePath.cp.AttemptUnpackDockerCompatibility.attemptUnpackDockerCompatibility: true on generated withDirectory/withFile call IDs when LLB copy action sets it.util/llbtodagger/convert_test.go:
AttemptUnpackDockerCompatibility maps to hidden arg (instead of unsupported error).core/integration/llbtodagger_test.go:
ADD archive produces expected extracted tree via converted ID.skills/cache-expert/references/debugging.md.Non-goals for this phase:
AttemptUnpackDockerCompatibility.mkdir (Dockerfile WORKDIR path)Goal:
FileActionMkDir in llbtodagger without adding new Dagger schema APIs.USER <name> precedes WORKDIR and BuildKit emits named-owner mkdir actions.Approach (conversion-only):
withDirectory so name resolution uses existing container /etc/passwd and /etc/group behavior.Implementation checklist:
applyMkdir to accept/return container context like copy path.withRootfs(directory: baseID)).directory().withNewDirectory(...).directory(...)).withDirectory(path, source, owner, permissions).makeParents=true required (no behavior change for unsupported makeParents=false).withDirectory (not unsupported).USER <name> + WORKDIR converts successfully via container-level path.skills/cache-expert/references/debugging.md.Non-goals:
RUN --security=insecure)INSECURE by mapping it to Dagger withExec(insecureRootCapabilities: true).pb.SecurityMode_INSECURE in addition to sandbox/default.withExec arg insecureRootCapabilities: true when exec security mode is insecure.util/llbtodagger/convert_test.go.withExec(insecureRootCapabilities: true)).none Mapping (RUN --network=none)Goal:
NONE by mapping to a hidden/internal-only withExec argument.RUN --network=none.Design:
withExec for this narrow behavior (proposed: noNetwork).pb.NetMode_NONE).HOST network mode out of scope for this phase only; track as a medium-priority follow-up.Implementation checklist:
noNetwork bool to containerExecArgs / ContainerExecOpts path.internal:"true").withExec resolver to pass this hidden arg into core exec opts.core/container_exec.go metaSpec, set metaSpec.NetMode = pb.NetMode_NONE when noNetwork is true.noNetwork is false/unset.util/llbtodagger/exec.go, accept pb.NetMode_UNSET and pb.NetMode_NONE.withExec(noNetwork: true) only for pb.NetMode_NONE.pb.NetMode_HOST unsupported (explicit error).exec with NetMode_NONE maps to withExec hidden noNetwork: true.NetMode_HOST unsupported behavior remains.RUN --network=none ... includes hidden arg.RUN --network=none behavior validates successfully through converted ID.skills/cache-expert/references/debugging.md shape.RUN --network unsupported item once none is implemented.host remains unsupported (and why, entitlement/runtime constraints).Status note:
engine/buildkit/resources/netstat.go:113 due to nil network samples from none/host providers.engine/buildkit/resources/netstat.go.dagger --progress=plain call engine-dev test --pkg ./core/integration --run='TestLLBToDagger/TestLoadContainerFromConvertedIDRunNetworkNone'Non-goals:
RUN --network=host in this phase (tracked as medium-priority follow-up).withExec options.host Mapping (RUN --network=host) With Security-Setting GateGoal:
HOST by mapping to a hidden/internal-only withExec argument.insecureRootCapabilities (security.insecureRootCapabilities), via entitlement enforcement.Design:
hostNetwork) in the withExec/ContainerExecOpts path.hostNetwork: true to pb.NetMode_HOST in exec metadata.noNetwork support from Phase 26 and reject contradictory combinations (hostNetwork && noNetwork).Implementation checklist:
hostNetwork bool to ContainerExecOpts/withExec arg path (internal:"true").hostNetwork and noNetwork are not both true (fail fast with clear error).core/container_exec.go metaSpec, map hostNetwork: true -> metaSpec.NetMode = pb.NetMode_HOST.noNetwork mapping behavior.security.insecure and network.host from security.insecureRootCapabilities policy.security.insecureRootCapabilities=false denies host-network execs with entitlement error.validateEntitlements) as enforcement point.util/llbtodagger/exec.go, accept pb.NetMode_HOST in addition to UNSET/NONE.withExec(hostNetwork: true) for pb.NetMode_HOST.NetMode_HOST maps to hidden hostNetwork: true.hostNetwork && noNetwork fails.RUN --network=host ... includes hidden hostNetwork.RUN --network=host succeeds when security setting allows.security.insecureRootCapabilities=false (use engineWithConfig in core integration suite).skills/cache-expert/references/debugging.md shape.RUN --network=host once implemented and gated.security.insecureRootCapabilities.Status note:
RUN --network=host now converts to hidden withExec(hostNetwork: true) and executes when policy allows.security.insecureRootCapabilities through network.host entitlement setup.network.host is not allowed).Non-goals:
hostNetwork publicly in SDK-generated APIs.dockerBuild(noInit) Support in Hard-Cutover PathGoal:
dockerBuild(noInit: true) behavior in the hard-cutover path (currently hard-erroring).RUN execs run without injected init when noInit is set.noInit is unset/false.Design:
llbtodagger.DefinitionToIDWithOptions that means: set withExec(noInit: true) on converted ExecOps.Container.Build(..., noInit bool, ...) when caller requested noInit.directory.dockerBuild / container.build noInit arg.Implementation checklist:
NoInit bool (or equivalently named) to DefinitionToIDOptions.convertExec, append withExec(noInit: true) when option is enabled.insecureRootCapabilities, noNetwork, hostNetwork) intact and composable.dockerBuild noInit is not supported in hard-cutover path yet.noInit from Container.Build into llbtodagger.DefinitionToIDWithOptions.withExec(noInit: true) when option is set.noInit when option is unset.withExec(noInit: true) for RUN.ContainerSuite/TestExecInit/disable automatic init in dockerfile build passes in hard-cutover mode.withExec.noInit == true when converter option is enabled.skills/cache-expert/references/debugging.md command shape.restore/port noInit behavior in cutover path) done after landing.Status note:
dockerBuild(noInit: true) is now supported in hard-cutover by passing conversion option NoInit.withExec(noInit: true) when requested.dagger --progress=plain call engine-dev test --pkg ./core/integration --run='TestContainer/TestExecInit'dagger --progress=plain call engine-dev test --pkg ./core/integration --run='TestLLBToDagger/TestLoadContainerFromConvertedIDRunNoInitOption'Non-goals:
withExec unless noInit is explicitly requested.SHA256SUMS.d regression)Goal:
withFile(...) even when source is actually a directory, causing runtime error: path ... is a directory, not a file.Design:
withFile arg to allow directory-source fallback when file load fails.<dir>.file(path: X) to <dir>.directory(path: X) and performs withDirectory(...) with equivalent options.Implementation checklist:
allowDirectorySourceFallback bool arg to WithFileArgs (internal:"true", default false).directorySchema.withFile: on source-file load failure and hidden flag set, try directory-source rewrite and call Directory.WithDirectory(...).WithFileArgs.Inputs to apply the same fallback during dependency loading (pre-resolver path), otherwise fallback never triggers.containerSchema.withFile (for named-owner/container-path copy mapping).withFile path), include hidden arg allowDirectorySourceFallback: true.TestLLBToDagger/TestLoadContainerFromConvertedIDCopyDirectoryToExplicitDestinationPathTestDockerfile/TestDockerBuild/copy-directory-to-explicit-destination-pathStatus note:
go test ./util/llbtodagger -run 'TestDefinitionToIDFileCopyExplicitDestPathUsesWithFile|TestDefinitionToIDFileCopyModeOverride|TestDefinitionToIDDockerfileCopyToExplicitFileDestWithChmod|TestDefinitionToIDDockerfileCopyGroupOnlyChown|TestDefinitionToIDDockerfileCopyNamedChown' -count=1dagger --progress=plain call engine-dev test --pkg ./core/integration --run='TestLLBToDagger/TestLoadContainerFromConvertedIDCopyDirectoryToExplicitDestinationPath'dagger --progress=plain call engine-dev test --pkg ./core/integration --run='TestDockerfile/TestDockerBuild/copy-directory-to-explicit-destination-path'Non-goals:
deriveCopySelection semantics in this phase.| LLB op kind | Intended Dagger API representation | Confidence | Status |
|---|---|---|---|
SourceOp docker-image | query.container().from(address) (possibly followed by rootfs projection) | High | Implemented |
SourceOp git | query.git(url...).{head/ref/branch/tag/commit}.tree(...) | Medium | Implemented |
SourceOp local | query.host().directory(path, include/exclude/...) | Low-Medium | Implemented (strict attrs) |
SourceOp http/https | query.http(url, ...) | Low-Medium | Implemented (strict attrs) |
SourceOp oci-layout | likely partial (host.containerImage or unsupported) | Low | Unsupported (explicit error) |
SourceOp blob | explicitly unsupported -> error | N/A | Unsupported-by-design |
ExecOp | container.* + withExec(...) chain | High | Implemented (strict subset) |
FileOp | directory.with*/without* / file.with* chain | High | Implemented (strict subset) |
MergeOp | directory merge chain | Medium | Implemented |
DiffOp | directory.diff(other) | Medium | Implemented |
BuildOp | explicitly unsupported -> error | N/A | Unsupported-by-design |
BuildOp nested build semantics are not supported here; immediate error by policy.local:// source identifiers include session-specific attributes that may not round-trip to a user-level host path.blob:// source is explicitly unsupported here; immediate error by policy.ExecOp mount/metadata details (certain cache/secret/socket internals) may be partially representable only.dockerfile2llb coverage note: COPY --link currently lowered to FileOp in this test path (not MergeOp), so MergeOp integration is still primarily covered by synthetic LLB tests.DefinitionToID now returns a container-typed ID for Dockerfile-derived paths.withRootfs/withExec, so tests should not assume withRootfs is the terminal field.dockerfile2llb returns final image config (img) separately from *pb.Definition.Config.ArgsEscaped is ignored on non-Windows images (no Dagger API equivalent needed for Linux behavior).Config.ArgsEscaped on Windows images is still unsupported and returns error.TestDockerfile/TestDockerBuild/onbuild_command_is_published failed because file-op COPY lowered to withDirectory(include: [...]) silently no-oped when source was missing.requiredSourcePath propagation to enforce BuildKit-like missing-source error for literal single-path COPY cases.BuildOp vertices.blob:// sources.oci-layout:// sources (currently unsupported).ExecOp with unsupported network modes (unknown/invalid enum values), non-default mount content cache, or unsupported metadata fields.FileOp copy actions with alwaysReplaceExistingDestPaths.FileOp mkdir without makeParents=true.FileOp mkfile with non-UTF8 content.mkdir actions when no container context is available.mkfile file actions.Platform OSVersion and OSFeatures are unsupported.
ArgsEscaped on Windows images is unsupported.
OS or Architecture is rejected.BuildOp is explicitly unsupported.blob:// source ops are explicitly unsupported.oci-layout:// source ops are currently unsupported.dest="/", bind type) is unsupported.resultID usage is unsupported.{SHARED, PRIVATE, LOCKED} are unsupported.name=value are rejected.mkdir, mkfile, rm, copy are unsupported.mkdir without makeParents=true is unsupported.mkdir timestamp override is unsupported.mkdir actions without container context is unsupported.mkfile actions is unsupported.mkfile timestamp override is unsupported.mkfile non-UTF8/binary payload is unsupported.copy alwaysReplaceExistingDestPaths=true is unsupported.copy actions without container context is unsupported (non-Dockerfile/non-canonical LLB path).UserOpt discriminator in chown is unsupported.name=value) are rejected.1..65535 are rejected.skills/cache-expert/references/debugging.md is the authoritative source for how to run integration tests; follow it exactly.
core/schema, APIs prefixed with _ are internal-only:
internal:"true" are hidden from callers/codegen even without an _ prefix on the field/function name.dagger -y call -m ./toolchains/go-sdk-dev generate--workspace=. explicitly:
dagger -y call -m ./toolchains/go-sdk-dev --workspace=. generatedagger.customOp.dagop.fs, dagop.raw, dagop.ctr.Unsupported and relevant to Dockerfile-generated LLB must contain only Dockerfile-relevant items.Unsupported but outside Dockerfile instruction support (or malformed/non-canonical LLB).