diff --git a/build/env/env.go b/build/env/env.go index 81078fa7..b1f4ad16 100644 --- a/build/env/env.go +++ b/build/env/env.go @@ -7,8 +7,6 @@ import ( "path/filepath" "strings" "sync" - - "github.com/oasisprotocol/cli/cmd/common" ) // ExecEnv is an execution environment. @@ -195,19 +193,19 @@ func (de *ContainerEnv) PathToEnv(path string) (string, error) { } // FixPermissions implements ExecEnv. +// For container environments, we use chmod to make files accessible rather than chown, +// because chown doesn't work correctly with rootless containers due to user namespace +// UID mapping. Using chmod 666 works for both rootful and rootless containers. func (de *ContainerEnv) FixPermissions(path string) error { - path, err := de.PathToEnv(path) + pathEnv, err := de.PathToEnv(path) if err != nil { return err } - cmd := exec.Command("chown", fmt.Sprintf("%d:%d", os.Getuid(), os.Getgid()), path) //nolint: gosec + cmd := exec.Command("chmod", "666", pathEnv) if err = de.WrapCommand(cmd); err != nil { return err } - if common.IsVerbose() { - fmt.Println(cmd) - } return cmd.Run() } diff --git a/cmd/rofl/build/artifacts.go b/cmd/rofl/build/artifacts.go index b86cc983..a937afe2 100644 --- a/cmd/rofl/build/artifacts.go +++ b/cmd/rofl/build/artifacts.go @@ -459,6 +459,7 @@ func createVerityHashTree(buildEnv env.ExecEnv, fsFn, hashFn string) (string, er return "", fmt.Errorf("%w\n%s", err, out.String()) } + // Fix permissions so files are accessible from the host. if err = buildEnv.FixPermissions(fsFn); err != nil { return "", err } @@ -476,22 +477,31 @@ func createVerityHashTree(buildEnv env.ExecEnv, fsFn, hashFn string) (string, er return string(data), nil } -// concatFiles appends the contents of file b to a. -func concatFiles(a, b string) error { - df, err := os.OpenFile(a, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0o644) +// concatFiles appends the contents of file b to a using the given build environment. +func concatFiles(buildEnv env.ExecEnv, a, b string) error { + aEnv, err := buildEnv.PathToEnv(a) if err != nil { - return err + return fmt.Errorf("failed to translate path: %w", err) } - defer df.Close() - - sf, err := os.Open(b) + bEnv, err := buildEnv.PathToEnv(b) if err != nil { - return err + return fmt.Errorf("failed to translate path: %w", err) } - defer sf.Close() - _, err = io.Copy(df, sf) - return err + // Use shell to append file b to file a instead of os/io packages. This ensures + // the operation works correctly with containerized builds where the host may not + // have write permissions to container-created files. + cmd := exec.Command("sh", "-c", fmt.Sprintf("cat %q >> %q", bEnv, aEnv)) //nolint:gosec + var out strings.Builder + cmd.Stderr = &out + cmd.Stdout = &out + if err = buildEnv.WrapCommand(cmd); err != nil { + return err + } + if err = cmd.Run(); err != nil { + return fmt.Errorf("%w\n%s", err, out.String()) + } + return nil } // padWithEmptySpace pads the given file with empty space to make it the given size. See diff --git a/cmd/rofl/build/tdx.go b/cmd/rofl/build/tdx.go index dc66ce68..81d88d6b 100644 --- a/cmd/rofl/build/tdx.go +++ b/cmd/rofl/build/tdx.go @@ -166,7 +166,7 @@ func tdxPrepareStage2( } // Concatenate filesystem and hash tree into one image. - if err = concatFiles(rootfsImage, hashFile); err != nil { + if err = concatFiles(buildEnv, rootfsImage, hashFile); err != nil { return nil, fmt.Errorf("failed to concatenate rootfs and hash tree files: %w", err) }