Skip to content

Commit f0dc04c

Browse files
committed
Add bundle image validation feature to bundle library and bundle cli
1. Enable bundle image validation: manifests and annotations.yaml 2. Add internal opm cli to use validation feature Signed-off-by: Vu Dinh <vdinh@redhat.com>
1 parent b1b0a41 commit f0dc04c

File tree

4 files changed

+397
-0
lines changed

4 files changed

+397
-0
lines changed

cmd/opm/alpha/bundle/cmd.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ func NewCmd() *cobra.Command {
1313

1414
runCmd.AddCommand(newBundleGenerateCmd())
1515
runCmd.AddCommand(newBundleBuildCmd())
16+
runCmd.AddCommand(newBundleValidateCmd())
1617
runCmd.AddCommand(extractCmd)
1718
return runCmd
1819
}

cmd/opm/alpha/bundle/validate.go

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
package bundle
2+
3+
import (
4+
"github.com/operator-framework/operator-registry/pkg/lib/bundle"
5+
log "github.com/sirupsen/logrus"
6+
"github.com/spf13/cobra"
7+
)
8+
9+
func newBundleValidateCmd() *cobra.Command {
10+
bundleValidateCmd := &cobra.Command{
11+
Use: "validate",
12+
Short: "Validate bundle image",
13+
Long: `The "opm alpha bundle validate" command will validate bundle image
14+
from a remote source to determine if its format and content information are
15+
accurate.
16+
17+
$ opm alpha bundle validate --tag quay.io/test/test-operator:latest \
18+
--image-builder docker`,
19+
RunE: validateFunc,
20+
}
21+
22+
bundleValidateCmd.Flags().StringVarP(&tagBuildArgs, "tag", "t", "",
23+
"The path of a registry to pull from, image name and its tag that present the bundle image (e.g. quay.io/test/test-operator:latest)")
24+
if err := bundleValidateCmd.MarkFlagRequired("tag"); err != nil {
25+
log.Fatalf("Failed to mark `tag` flag for `validate` subcommand as required")
26+
}
27+
28+
bundleValidateCmd.Flags().StringVarP(&imageBuilderArgs, "image-builder", "b", "docker", "Tool to build container images. One of: [docker, podman]")
29+
30+
return bundleValidateCmd
31+
}
32+
33+
func validateFunc(cmd *cobra.Command, args []string) error {
34+
err := bundle.ValidateFunc(tagBuildArgs, imageBuilderArgs)
35+
if err != nil {
36+
return err
37+
}
38+
39+
return nil
40+
}

pkg/lib/bundle/untar.go

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
// Copyright 2017 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
// Package untar untars a tarball to disk.
6+
package bundle
7+
8+
import (
9+
"archive/tar"
10+
"fmt"
11+
"io"
12+
"log"
13+
"os"
14+
"path"
15+
"path/filepath"
16+
"strings"
17+
)
18+
19+
// Untar reads the tar file from r and writes it into dir.
20+
func Untar(r io.Reader, dir string) error {
21+
return untar(r, dir)
22+
}
23+
24+
func untar(r io.Reader, dir string) (err error) {
25+
madeDir := map[string]bool{}
26+
27+
tr := tar.NewReader(r)
28+
for {
29+
f, err := tr.Next()
30+
if err == io.EOF {
31+
break
32+
}
33+
if err != nil {
34+
log.Printf("tar reading error: %v", err)
35+
return fmt.Errorf("tar error: %v", err)
36+
}
37+
if !validRelPath(f.Name) {
38+
return fmt.Errorf("tar contained invalid name error %q", f.Name)
39+
}
40+
rel := filepath.FromSlash(f.Name)
41+
abs := filepath.Join(dir, rel)
42+
43+
fi := f.FileInfo()
44+
mode := fi.Mode()
45+
switch {
46+
case mode.IsRegular():
47+
// Make the directory. This is redundant because it should
48+
// already be made by a directory entry in the tar
49+
// beforehand. Thus, don't check for errors; the next
50+
// write will fail with the same error.
51+
dir := filepath.Dir(abs)
52+
if !madeDir[dir] {
53+
if err := os.MkdirAll(filepath.Dir(abs), 0755); err != nil {
54+
return err
55+
}
56+
madeDir[dir] = true
57+
}
58+
wf, err := os.OpenFile(abs, os.O_RDWR|os.O_CREATE|os.O_TRUNC, mode.Perm())
59+
if err != nil {
60+
return err
61+
}
62+
n, err := io.Copy(wf, tr)
63+
if closeErr := wf.Close(); closeErr != nil && err == nil {
64+
err = closeErr
65+
}
66+
if err != nil {
67+
return fmt.Errorf("error writing to %s: %v", abs, err)
68+
}
69+
if n != f.Size {
70+
return fmt.Errorf("only wrote %d bytes to %s; expected %d", n, abs, f.Size)
71+
}
72+
case mode.IsDir():
73+
if err := os.MkdirAll(abs, 0755); err != nil {
74+
return err
75+
}
76+
madeDir[abs] = true
77+
default:
78+
return fmt.Errorf("tar file entry %s contained unsupported file type %v", f.Name, mode)
79+
}
80+
}
81+
return nil
82+
}
83+
84+
func validRelativeDir(dir string) bool {
85+
if strings.Contains(dir, `\`) || path.IsAbs(dir) {
86+
return false
87+
}
88+
dir = path.Clean(dir)
89+
if strings.HasPrefix(dir, "../") || strings.HasSuffix(dir, "/..") || dir == ".." {
90+
return false
91+
}
92+
return true
93+
}
94+
95+
func validRelPath(p string) bool {
96+
if p == "" || strings.Contains(p, `\`) || strings.HasPrefix(p, "/") || strings.Contains(p, "../") {
97+
return false
98+
}
99+
return true
100+
}

0 commit comments

Comments
 (0)