Skip to content

Commit

Permalink
Clean up workspace dir from inside runner to avoid permission errors.
Browse files Browse the repository at this point in the history
When running privileged docker as an unprivileged user, the files that
are created in the WorkspaceDir are created as root. Even if the build
were run as non-root, they would not necessarily be the same ownership
as the user invoking melange.

As a result, WorkspaceDir would not be able to be cleaned up and
melange would just leave files there to later be cleaned up with
a dangerous 'sudo rm -Rf' by the user.

The change here is to clean up the WorkspaceDir from _inside_ the
container, where the uid is the same as the uid that created the files.

I believe this will waste IO and/or time on the qemu runner,
where /home/build isn't actually bind'd in.  Later we could expose a
CleanWorkspace from the runner that was a noop in qemu.

Signed-off-by: Scott Moser <[email protected]>
  • Loading branch information
smoser committed Nov 14, 2024
1 parent 997f9fd commit beaef88
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 9 deletions.
35 changes: 27 additions & 8 deletions pkg/build/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,22 @@ import (

const melangeOutputDirName = "melange-out"

var shellEmptyDir = []string{
"sh", "-c",
`d="$1";
[ $# -eq 1 ] || { echo "must provide dir. got $# args."; exit 1; }
cd "$d" || { echo "failed cd '$d'"; exit 1; }
set --
for e in * .*; do
[ "$e" = "." -o "$e" = ".." -o "$e" = "*" ] && continue
set -- "$@" "$e"
done
[ $# -gt 0 ] || { echo "nothing to cleanup. $d was empty."; exit 0; }
echo "cleaning Workspace by removing $# file/directories in $d"
rm -Rf "$@"`,
"shellEmptyDir",
}

var ErrSkipThisArch = errors.New("error: skip this arch")

type Build struct {
Expand Down Expand Up @@ -947,21 +963,24 @@ func (b *Build) BuildPackage(ctx context.Context) error {
}
}

// clean build environment
log.Debugf("cleaning workspacedir")
cleanEnv := map[string]string{}
if err := pr.runner.Run(ctx, pr.config, cleanEnv, append(shellEmptyDir, WorkDir)...); err != nil {
log.Warnf("unable to clean workspace: %s", err)
}
// if the Runner used WorkspaceDir as WorkDir, then this will be empty already.
if err := os.RemoveAll(b.WorkspaceDir); err != nil {
log.Warnf("unable to clean workspace: %s", err)
}

if !b.isBuildLess() {
// clean build guest container
if err := os.RemoveAll(b.GuestDir); err != nil {
log.Warnf("unable to clean guest container: %s", err)
}
}

// clean build environment
// TODO(epsilon-phase): implement a way to clean up files that are not owned by the user
// that is running melange. files created inside the build not owned by the build user are
// not be possible to delete with this strategy.
if err := os.RemoveAll(b.WorkspaceDir); err != nil {
log.Warnf("unable to clean workspace: %s", err)
}

// generate APKINDEX.tar.gz and sign it
if b.GenerateIndex {
packageDir := filepath.Join(b.OutDir, b.Arch.ToAPK())
Expand Down
4 changes: 3 additions & 1 deletion pkg/build/pipeline.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ import (
"github.com/chainguard-dev/clog"
)

const WorkDir = "/home/build"

func (sm *SubstitutionMap) MutateWith(with map[string]string) (map[string]string, error) {
nw := maps.Clone(sm.Substitutions)

Expand Down Expand Up @@ -187,7 +189,7 @@ func (r *pipelineRunner) runPipeline(ctx context.Context, pipeline *config.Pipel
envOverride[k] = v
}

workdir := "/home/build"
workdir := WorkDir
if pipeline.WorkDir != "" {
workdir = pipeline.WorkDir
}
Expand Down

0 comments on commit beaef88

Please sign in to comment.