diff --git a/go/cmd/ocitool/createlayer_cmd.go b/go/cmd/ocitool/createlayer_cmd.go index b1b3922..197c7c7 100644 --- a/go/cmd/ocitool/createlayer_cmd.go +++ b/go/cmd/ocitool/createlayer_cmd.go @@ -9,11 +9,13 @@ import ( "os" "path" "path/filepath" + "strconv" + "strings" "github.com/DataDog/rules_oci/go/internal/flagutil" "github.com/DataDog/rules_oci/go/internal/tarutil" - "github.com/DataDog/rules_oci/go/pkg/ociutil" "github.com/DataDog/rules_oci/go/pkg/layer" + "github.com/DataDog/rules_oci/go/pkg/ociutil" "github.com/opencontainers/go-digest" ocispec "github.com/opencontainers/image-spec/specs-go/v1" "github.com/urfave/cli/v2" @@ -43,25 +45,63 @@ func CreateLayerCmd(c *cli.Context) error { defer tw.Close() for _, filePath := range files { - err = tarutil.AppendFileToTarWriter(filePath, filepath.Join(dir, filepath.Base(filePath)), tw) + storePath := filepath.Join(dir, filepath.Base(filePath)) + + mode := config.mode(storePath) + uname := config.uname(storePath) + gname := config.gname(storePath) + + err = tarutil.AppendFileToTarWriter( + /* filePath */ filePath, + /* loc */ storePath, + /* mode */ mode, + /* uname */ uname, + /* gname */ gname, + /* tw */ tw, + ) + if err != nil { return err } } for filePath, storePath := range config.FileMapping { - err = tarutil.AppendFileToTarWriter(filePath, storePath, tw) + mode := config.mode(storePath) + uname := config.uname(storePath) + gname := config.gname(storePath) + + err = tarutil.AppendFileToTarWriter( + /* filePath */ filePath, + /* loc */ storePath, + /* mode */ mode, + /* uname */ uname, + /* gname */ gname, + /* tw */ tw, + ) + if err != nil { return err } } for k, v := range config.SymlinkMapping { - err = tw.WriteHeader(&tar.Header{ + header := &tar.Header{ Typeflag: tar.TypeSymlink, Name: k, Linkname: v, - }) + } + + if mode := config.mode(k); mode != nil { + header.Mode = *mode + } + if uname := config.uname(k); uname != nil { + header.Uname = *uname + } + if gname := config.gname(k); gname != nil { + header.Gname = *gname + } + + err = tw.WriteHeader(header) if err != nil { return fmt.Errorf("failed to create symlink: %w", err) } @@ -98,20 +138,32 @@ type createLayerConfig struct { BazelLabel string `json:"bazel-label" toml:"bazel-label" yaml:"bazel-label"` Descriptor string `json:"outd" toml:"outd" yaml:"outd"` Directory string `json:"dir" toml:"dir" yaml:"dir"` - Files []string `json:"file" toml:"file" yaml:"file"` FileMapping map[string]string `json:"file-map" toml:"file-map" yaml:"file-map"` + Files []string `json:"file" toml:"file" yaml:"file"` + ModeMapping map[string]int64 `json:"mode-map" toml:"mode-map" yaml:"mode-map"` OutputLayer string `json:"out" toml:"out" yaml:"out"` + OwnerMapping map[string]string `json:"owner-map" toml:"owner-map" yaml:"owner-map"` SymlinkMapping map[string]string `json:"symlink" toml:"symlink" yaml:"symlink"` } func newCreateLayerConfig(c *cli.Context) *createLayerConfig { + modeMapping := make(map[string]int64) + for k, v := range c.Generic("mode-map").(*flagutil.KeyValueFlag).Map { + i, err := strconv.ParseInt(v, 10, 64) + if err != nil { + continue + } + modeMapping[k] = i + } return &createLayerConfig{ BazelLabel: c.String("bazel-label"), + Descriptor: c.String("outd"), Directory: c.String("dir"), - Files: c.StringSlice("file"), FileMapping: c.Generic("file-map").(*flagutil.KeyValueFlag).Map, + Files: c.StringSlice("file"), + ModeMapping: modeMapping, OutputLayer: c.String("out"), - Descriptor: c.String("outd"), + OwnerMapping: c.Generic("owner-map").(*flagutil.KeyValueFlag).Map, SymlinkMapping: c.Generic("symlink").(*flagutil.KeyValueFlag).Map, } } @@ -135,3 +187,29 @@ func parseConfig(c *cli.Context) (*createLayerConfig, error) { return &config, nil } + +func (c *createLayerConfig) mode(path string) *int64 { + if i, exists := c.ModeMapping[path]; exists { + return &i + } + return nil +} + +func (c *createLayerConfig) uname(path string) *string { + if s, exists := c.OwnerMapping[path]; exists { + uname := strings.SplitN(s, ":", 2)[0] + return &uname + } + return nil +} + +func (c *createLayerConfig) gname(path string) *string { + if s, exists := c.OwnerMapping[path]; exists { + parts := strings.SplitN(s, ":", 2) + if len(parts) > 1 { + gname := parts[1] + return &gname + } + } + return nil +} diff --git a/go/internal/tarutil/tarappend.go b/go/internal/tarutil/tarappend.go index e169e64..9699ca6 100644 --- a/go/internal/tarutil/tarappend.go +++ b/go/internal/tarutil/tarappend.go @@ -9,7 +9,14 @@ import ( // AppendFileToTarWriter appends a file (given as a filepath) to a tarfile // through the tarfile interface. -func AppendFileToTarWriter(filePath string, loc string, tw *tar.Writer) error { +func AppendFileToTarWriter( + filePath string, + loc string, + mode *int64, + uname, + gname *string, + tw *tar.Writer, +) error { f, err := os.Open(filePath) if err != nil { return err @@ -30,6 +37,18 @@ func AppendFileToTarWriter(filePath string, loc string, tw *tar.Writer) error { hdr.ModTime = time.Time{} hdr.AccessTime = time.Time{} + if mode != nil { + hdr.Mode = *mode + } + + if uname != nil { + hdr.Uname = *uname + } + + if gname != nil { + hdr.Gname = *gname + } + hdr.Name = loc if err := tw.WriteHeader(hdr); err != nil {