diff --git a/cache/contenthash/checksum.go b/cache/contenthash/checksum.go index 7b592c794f8ed..2b230decb5b38 100644 --- a/cache/contenthash/checksum.go +++ b/cache/contenthash/checksum.go @@ -12,6 +12,7 @@ import ( "sync" "sync/atomic" + "github.com/Microsoft/go-winio" iradix "github.com/hashicorp/go-immutable-radix/v2" simplelru "github.com/hashicorp/golang-lru/v2/simplelru" "github.com/moby/buildkit/cache" @@ -1034,7 +1035,7 @@ func (cc *cacheContext) scanPath(ctx context.Context, m *mount, p string, follow scanPath = resolvedPath } - err = filepath.Walk(scanPath, func(itemPath string, fi os.FileInfo, err error) error { + walkfn := func(itemPath string, fi os.FileInfo, err error) error { if scanCounterEnable { scanCounter.Add(1) } @@ -1073,7 +1074,13 @@ func (cc *cacheContext) scanPath(ctx context.Context, m *mount, p string, follow txn.Insert(k, cr) } return nil + } + + privileges := []string{winio.SeBackupPrivilege} + err = winio.RunWithPrivileges(privileges, func() error { + return filepath.Walk(scanPath, walkfn) }) + if err != nil { return err } diff --git a/frontend/dockerfile/dockerfile_test.go b/frontend/dockerfile/dockerfile_test.go index b34c95b4ec736..c9651a7c7c6f6 100644 --- a/frontend/dockerfile/dockerfile_test.go +++ b/frontend/dockerfile/dockerfile_test.go @@ -4404,13 +4404,20 @@ COPY foo bar } func testMultiStageImplicitFrom(t *testing.T, sb integration.Sandbox) { - integration.SkipOnPlatform(t, "windows") f := getFrontend(t, sb) - dockerfile := []byte(` + dockerfile := []byte(integration.UnixOrWindows( + ` FROM scratch COPY --from=busybox /etc/passwd test -`) +`, ` +FROM nanoserver AS build +RUN echo test> test + +FROM nanoserver +COPY --from=build /test /test +`, + )) dir := integration.Tmpdir( t, @@ -4439,17 +4446,24 @@ COPY --from=busybox /etc/passwd test dt, err := os.ReadFile(filepath.Join(destDir, "test")) require.NoError(t, err) - require.Contains(t, string(dt), "root") + require.Contains(t, string(dt), integration.UnixOrWindows("root", "test")) // testing masked image will load actual stage - dockerfile = []byte(` + dockerfile = []byte(integration.UnixOrWindows( + ` FROM busybox AS golang RUN mkdir -p /usr/bin && echo -n foo > /usr/bin/go FROM scratch COPY --from=golang /usr/bin/go go -`) +`, ` +FROM nanoserver AS golang +RUN echo foo> go + +FROM nanoserver +COPY --from=golang /go /go +`)) dir = integration.Tmpdir( t, @@ -4477,17 +4491,18 @@ COPY --from=golang /usr/bin/go go } func testMultiStageCaseInsensitive(t *testing.T, sb integration.Sandbox) { - integration.SkipOnPlatform(t, "windows") f := getFrontend(t, sb) - dockerfile := []byte(` -FROM scratch AS STAge0 + dockerfileStr := ` +FROM %s AS STAge0 COPY foo bar -FROM scratch AS staGE1 +FROM %s AS staGE1 COPY --from=staGE0 bar baz -FROM scratch +FROM %s COPY --from=stage1 baz bax -`) +` + baseImage := integration.UnixOrWindows("scratch", "nanoserver") + dockerfile := []byte(fmt.Sprintf(dockerfileStr, baseImage, baseImage, baseImage)) dir := integration.Tmpdir( t, fstest.CreateFile("Dockerfile", dockerfile, 0600), @@ -4647,7 +4662,6 @@ RUN dir file1 } func testOnBuildCleared(t *testing.T, sb integration.Sandbox) { - integration.SkipOnPlatform(t, "windows") workers.CheckFeatureCompat(t, sb, workers.FeatureDirectPush) f := getFrontend(t, sb) @@ -4657,10 +4671,15 @@ func testOnBuildCleared(t *testing.T, sb integration.Sandbox) { } require.NoError(t, err) - dockerfile := []byte(` + dockerfile := []byte(integration.UnixOrWindows( + ` FROM busybox ONBUILD RUN mkdir -p /out && echo -n 11 >> /out/foo -`) +`, ` +FROM nanoserver +ONBUILD RUN mkdir /out && echo 11 >> /out/foo +`, + )) dir := integration.Tmpdir( t, @@ -5496,19 +5515,27 @@ COPY --from=build out . } func testBuiltinArgs(t *testing.T, sb integration.Sandbox) { - integration.SkipOnPlatform(t, "windows") f := getFrontend(t, sb) - dockerfile := []byte(` + dockerfile := []byte(integration.UnixOrWindows( + ` FROM busybox AS build ARG FOO -ARG BAR ARG BAZ=bazcontent RUN echo -n $HTTP_PROXY::$NO_PROXY::$FOO::$BAR::$BAZ > /out FROM scratch COPY --from=build /out / -`) +`, ` +FROM nanoserver AS build +ARG FOO +ARG BAZ=bazcontent +RUN echo %HTTP_PROXY%::%NO_PROXY%::%FOO%::%BAR%::%BAZ%> out +FROM nanoserver +COPY --from=build out / +`, + )) + dir := integration.Tmpdir( t, fstest.CreateFile("Dockerfile", dockerfile, 0600), @@ -5543,7 +5570,9 @@ COPY --from=build /out / dt, err := os.ReadFile(filepath.Join(destDir, "out")) require.NoError(t, err) - require.Equal(t, "hpvalue::npvalue::foocontents::::bazcontent", string(dt)) + // Windows can't interpret empty env variables, %BAR% handles empty values. + expectedStr := integration.UnixOrWindows(`hpvalue::npvalue::foocontents::::bazcontent`, "hpvalue::npvalue::foocontents::%BAR%::bazcontent\r\n") + require.Equal(t, expectedStr, string(dt)) // repeat with changed default args should match the old cache destDir = t.TempDir() @@ -5570,7 +5599,8 @@ COPY --from=build /out / dt, err = os.ReadFile(filepath.Join(destDir, "out")) require.NoError(t, err) - require.Equal(t, "hpvalue::npvalue::foocontents::::bazcontent", string(dt)) + expectedStr = integration.UnixOrWindows("hpvalue::npvalue::foocontents::::bazcontent", "hpvalue::npvalue::foocontents::%BAR%::bazcontent\r\n") + require.Equal(t, expectedStr, string(dt)) // changing actual value invalidates cache destDir = t.TempDir() @@ -5597,7 +5627,8 @@ COPY --from=build /out / dt, err = os.ReadFile(filepath.Join(destDir, "out")) require.NoError(t, err) - require.Equal(t, "hpvalue2::::foocontents2::::bazcontent", string(dt)) + expectedStr = integration.UnixOrWindows("hpvalue2::::foocontents2::::bazcontent", "hpvalue2::%NO_PROXY%::foocontents2::%BAR%::bazcontent\r\n") + require.Equal(t, expectedStr, string(dt)) } func testTarContext(t *testing.T, sb integration.Sandbox) { @@ -5713,15 +5744,15 @@ COPY foo bar } func testFrontendUseForwardedSolveResults(t *testing.T, sb integration.Sandbox) { - integration.SkipOnPlatform(t, "windows") c, err := client.New(sb.Context(), sb.Address()) require.NoError(t, err) defer c.Close() - dockerfile := []byte(` -FROM scratch + dockerfileStr := ` +FROM %s COPY foo foo2 -`) +` + dockerfile := []byte(fmt.Sprintf(dockerfileStr, integration.UnixOrWindows("scratch", "nanoserver"))) dir := integration.Tmpdir( t, fstest.CreateFile("Dockerfile", dockerfile, 0600),