Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions cmd/nerdctl/builder/builder_build.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ If Dockerfile is not present and -f is not specified, it will look for Container

cmd.Flags().String("iidfile", "", "Write the image ID to the file")
cmd.Flags().StringArray("label", nil, "Set metadata for an image")
cmd.Flags().String("source-policy-file", "", "BuildKit source policy file (see https://github.com/moby/buildkit/blob/master/docs/build-repro.md)")

return cmd
}
Expand Down Expand Up @@ -209,6 +210,10 @@ func processBuildCommandFlag(cmd *cobra.Command, args []string) (types.BuilderBu
if err != nil {
return types.BuilderBuildOptions{}, err
}
sourcePolicyFile, err := cmd.Flags().GetString("source-policy-file")
if err != nil {
return types.BuilderBuildOptions{}, err
}

usernsRemap, err := cmd.Flags().GetString("userns-remap")
if err != nil {
Expand Down Expand Up @@ -246,6 +251,7 @@ func processBuildCommandFlag(cmd *cobra.Command, args []string) (types.BuilderBu
NetworkMode: network,
ExtendedBuildContext: extendedBuildCtx,
ExtraHosts: extraHosts,
SourcePolicyFile: sourcePolicyFile,
}, nil
}

Expand Down
2 changes: 2 additions & 0 deletions docs/command-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -780,6 +780,8 @@ Flags:
- :whale: `--network=(default|host|none)`: Set the networking mode for the RUN instructions during build.(compatible with `buildctl build`)
- :whale: `--build-context`: Set additional contexts for build (e.g. dir2=/path/to/dir2, myorg/myapp=docker-image://path/to/myorg/myapp)
- :whale: `--add-host`: Add a custom host-to-IP mapping (format: `host:ip`)
- :nerd_face: `--source-policy-file`: BuildKit source policy JSON file for reproducible builds. See [BuildKit build-repro docs](https://github.com/moby/buildkit/blob/master/docs/build-repro.md).
For compatibility with Docker Buildx, the `EXPERIMENTAL_BUILDKIT_SOURCE_POLICY` environment variable is also supported. Example no-op policy: `{"rules":[]}`

Unimplemented `docker build` flags: `--squash`

Expand Down
3 changes: 3 additions & 0 deletions pkg/api/types/builder_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,9 @@ type BuilderBuildOptions struct {
Pull *bool
// ExtraHosts is a set of custom host-to-IP mappings.
ExtraHosts []string
// SourcePolicyFile is the path to a BuildKit source policy file.
// Passed through to buildctl as --source-policy-file.
SourcePolicyFile string
}

// BuilderPruneOptions specifies options for `nerdctl builder prune`.
Expand Down
15 changes: 15 additions & 0 deletions pkg/cmd/builder/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,16 @@ func loadImage(ctx context.Context, in io.Reader, namespace, address, snapshotte
return nil
}

// GetEffectiveSourcePolicyFile returns the effective source policy file path.
// If optionValue is set, it takes precedence. Otherwise, the EXPERIMENTAL_BUILDKIT_SOURCE_POLICY
// environment variable is used for Docker Buildx compatibility.
func GetEffectiveSourcePolicyFile(optionValue string) string {
if optionValue != "" {
return optionValue
}
return os.Getenv("EXPERIMENTAL_BUILDKIT_SOURCE_POLICY")
}

func generateBuildctlArgs(ctx context.Context, client *containerd.Client, options types.BuilderBuildOptions) (buildCtlBinary string,
buildctlArgs []string, needsLoading bool, metaFile string, tags []string, cleanup func(), err error) {

Expand Down Expand Up @@ -472,6 +482,11 @@ func generateBuildctlArgs(ctx context.Context, client *containerd.Client, option
buildctlArgs = append(buildctlArgs, "--opt=add-hosts="+strings.Join(extraHosts, ","))
}

// Source policy file: use explicit option if set, otherwise fallback to env var for Buildx compatibility
if sourcePolicyFile := GetEffectiveSourcePolicyFile(options.SourcePolicyFile); sourcePolicyFile != "" {
buildctlArgs = append(buildctlArgs, "--source-policy-file="+sourcePolicyFile)
}

return buildctlBinary, buildctlArgs, needsLoading, metaFile, tags, cleanup, nil
}

Expand Down
46 changes: 46 additions & 0 deletions pkg/cmd/builder/build_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -238,3 +238,49 @@ func TestParseBuildctlArgsForOCILayout(t *testing.T) {
})
}
}

func TestGetEffectiveSourcePolicyFile(t *testing.T) {
// Cannot use t.Parallel() since subtests modify environment variables

tests := []struct {
name string
optionValue string
envValue string
expected string
}{
{
name: "option value takes precedence over env var",
optionValue: "/path/from/flag.json",
envValue: "/path/from/env.json",
expected: "/path/from/flag.json",
},
{
name: "env var is used when option is empty",
optionValue: "",
envValue: "/path/from/env.json",
expected: "/path/from/env.json",
},
{
name: "empty when both are unset",
optionValue: "",
envValue: "",
expected: "",
},
{
name: "option value used when env var is empty",
optionValue: "/path/from/flag.json",
envValue: "",
expected: "/path/from/flag.json",
},
}

for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
// Set up the environment variable for this test
t.Setenv("EXPERIMENTAL_BUILDKIT_SOURCE_POLICY", tc.envValue)

result := GetEffectiveSourcePolicyFile(tc.optionValue)
assert.Equal(t, result, tc.expected)
})
}
}