Skip to content

Commit 852672b

Browse files
committed
fix: linting
1 parent de3f916 commit 852672b

File tree

7 files changed

+181
-55
lines changed

7 files changed

+181
-55
lines changed

.golangci.yml

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ linters:
77
- gosec
88
- govet
99
- ineffassign
10+
- lll
1011
- misspell
1112
- revive
1213
- staticcheck
@@ -15,12 +16,7 @@ linters:
1516
settings:
1617
gosec:
1718
excludes:
18-
- G107
19-
- G110
2019
- G204
21-
- G305
22-
- G401
23-
- G501
2420
exclusions:
2521
generated: lax
2622
presets:

environment/deploy/integration/coverout_test.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,9 @@ func Test_I_Coverout(t *testing.T) {
3232
},
3333
ExtraRuntimeValidation: func(t *testing.T, stack integration.RuntimeValidationStackInfo) {
3434
// Issue API call
35-
server := fmt.Sprintf("http://%s:%0.f/api/v1/coverout", os.Getenv("SERVER"), stack.Outputs["port"])
36-
res, err := http.Get(server)
35+
server := fmt.Sprintf("%s:%0.f", os.Getenv("SERVER"), stack.Outputs["port"])
36+
req, _ := http.NewRequest(http.MethodGet, fmt.Sprintf("%s/api/v1/coverout", server), nil)
37+
res, err := http.DefaultClient.Do(req)
3738
require.NoError(t, err)
3839
defer func() {
3940
_ = res.Body.Close()

environment/deploy/integration/main_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ var (
1313
func TestMain(m *testing.M) {
1414
server, ok := os.LookupEnv("SERVER")
1515
if !ok {
16+
//nolint:lll // the error message is not maintained
1617
fmt.Println("Environment variable SERVER is not set, please indicate the domain name/IP address to reach out the cluster.")
1718
}
1819
Server = server

environment/deploy/parts/romeo.go

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,12 @@ const (
7373
// NewRomeoEnvironment deploys a Romeo instance on Kubernetes.
7474
// The Romeo variable could be reused as a Pulumi ressource i.e. could
7575
// be a dependency, consumes inputs and produces outputs, etc.
76-
func NewRomeoEnvironment(ctx *pulumi.Context, name string, args *RomeoEnvironmentArgs, opts ...pulumi.ResourceOption) (*RomeoEnvironment, error) {
76+
func NewRomeoEnvironment(
77+
ctx *pulumi.Context,
78+
name string,
79+
args *RomeoEnvironmentArgs,
80+
opts ...pulumi.ResourceOption,
81+
) (*RomeoEnvironment, error) {
7782
renv := &RomeoEnvironment{}
7883

7984
args = renv.defaults(args)
@@ -158,7 +163,12 @@ func (renv *RomeoEnvironment) defaults(args *RomeoEnvironmentArgs) *RomeoEnviron
158163
return args
159164
}
160165

161-
func (renv *RomeoEnvironment) provision(ctx *pulumi.Context, name string, args *RomeoEnvironmentArgs, opts ...pulumi.ResourceOption) (err error) {
166+
func (renv *RomeoEnvironment) provision(
167+
ctx *pulumi.Context,
168+
name string,
169+
args *RomeoEnvironmentArgs,
170+
opts ...pulumi.ResourceOption,
171+
) (err error) {
162172
// Generate unique (random enough) PVC name
163173
renv.randName, err = random.NewRandomString(ctx, "romeo-name-"+name, &random.RandomStringArgs{
164174
Length: pulumi.Int(8),

install/deploy/parts/romeo.go

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,12 @@ type (
5353
// NewRomeoInstall deploys resources on on Kubernetes for Romeo environments.
5454
// The RomeoInstall variable could be reused as a Pulumi ressource i.e. could
5555
// be a dependency, consumes inputs and produces outputs, etc.
56-
func NewRomeoInstall(ctx *pulumi.Context, name string, args *RomeoInstallArgs, opts ...pulumi.ResourceOption) (*RomeoInstall, error) {
56+
func NewRomeoInstall(
57+
ctx *pulumi.Context,
58+
name string,
59+
args *RomeoInstallArgs,
60+
opts ...pulumi.ResourceOption,
61+
) (*RomeoInstall, error) {
5762
if args == nil {
5863
return nil, errors.New("romeo install does not support default arguments")
5964
}
@@ -74,7 +79,11 @@ func NewRomeoInstall(ctx *pulumi.Context, name string, args *RomeoInstallArgs, o
7479
return rist, nil
7580
}
7681

77-
func (rist *RomeoInstall) provision(ctx *pulumi.Context, args *RomeoInstallArgs, opts ...pulumi.ResourceOption) (err error) {
82+
func (rist *RomeoInstall) provision(
83+
ctx *pulumi.Context,
84+
args *RomeoInstallArgs,
85+
opts ...pulumi.ResourceOption,
86+
) (err error) {
7887
// Deploy Kubernetes resources
7988

8089
// => Namespace (deploy one if none specified)

webserver/api/v1/decoder.go

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
package apiv1
2+
3+
import (
4+
"archive/zip"
5+
"fmt"
6+
"io"
7+
"os"
8+
"path/filepath"
9+
"strings"
10+
11+
"github.com/pkg/errors"
12+
)
13+
14+
const (
15+
blockSize = 1 << 13 // arbitrary
16+
)
17+
18+
// Decompressor handle the load of
19+
type Decompressor struct {
20+
*Options
21+
}
22+
23+
type Options struct {
24+
MaxSize int64
25+
26+
currSize int64
27+
}
28+
29+
// NewDecompressor constructs a fresh Decompressor.
30+
func NewDecompressor(opts *Options) *Decompressor {
31+
if opts == nil {
32+
opts = &Options{}
33+
}
34+
return &Decompressor{
35+
Options: opts,
36+
}
37+
}
38+
39+
// Unzip extracts the content of the zip reader into cd.
40+
// It returns the directory it extracted into for Pulumi to use,
41+
// or an error if anything unexpected happens.
42+
func (dec *Decompressor) Unzip(r *zip.Reader, cd string) (string, error) {
43+
outDir := ""
44+
for _, f := range r.File {
45+
if f.FileInfo().IsDir() {
46+
continue
47+
}
48+
filePath, err := sanitizeArchivePath(cd, f.Name)
49+
if err != nil {
50+
return cd, err
51+
}
52+
53+
// Save output directory i.e. the directory containing the Pulumi.yaml file,
54+
// the scenario entrypoint.
55+
base := filepath.Base(filePath)
56+
if base == "Pulumi.yaml" || base == "Pulumi.yml" {
57+
if outDir != "" {
58+
return cd, errors.New("archive contain multiple Pulumi yaml/yml file, can't easily determine entrypoint")
59+
}
60+
outDir = filepath.Dir(filePath)
61+
}
62+
63+
// If the file is in a sub-directory, create it
64+
dir := filepath.Dir(filePath)
65+
if _, err := os.Stat(dir); err != nil {
66+
if err := os.MkdirAll(dir, os.ModePerm); err != nil {
67+
return cd, err
68+
}
69+
}
70+
71+
// Create and write the file
72+
if err := dec.copyTo(f, filePath); err != nil {
73+
return cd, err
74+
}
75+
}
76+
77+
return outDir, nil
78+
}
79+
80+
func sanitizeArchivePath(d, t string) (v string, err error) {
81+
v = filepath.Join(d, t)
82+
if strings.HasPrefix(v, filepath.Clean(d)) {
83+
return v, nil
84+
}
85+
return "", &ErrPathTainted{
86+
Path: t,
87+
}
88+
}
89+
90+
func (dec *Decompressor) copyTo(f *zip.File, filePath string) error {
91+
outFile, err := os.OpenFile(filePath, os.O_WRONLY|os.O_CREATE, f.Mode())
92+
if err != nil {
93+
return err
94+
}
95+
defer outFile.Close()
96+
97+
rc, err := f.Open()
98+
if err != nil {
99+
return err
100+
}
101+
defer rc.Close()
102+
103+
for {
104+
n, err := io.CopyN(outFile, rc, blockSize)
105+
if err != nil {
106+
if err == io.EOF {
107+
return nil
108+
}
109+
return err
110+
}
111+
dec.currSize += n
112+
113+
if dec.MaxSize > 0 && dec.currSize > dec.MaxSize {
114+
return ErrTooLargeContent{
115+
MaxSize: dec.MaxSize,
116+
}
117+
}
118+
}
119+
}
120+
121+
// ErrPathTainted is returned when a potential zip slip is detected
122+
// through an unzip.
123+
type ErrPathTainted struct {
124+
Path string
125+
}
126+
127+
func (err ErrPathTainted) Error() string {
128+
return fmt.Sprintf("filepath is tainted: %s", err.Path)
129+
}
130+
131+
var _ error = (*ErrPathTainted)(nil)
132+
133+
// ErrTooLargeContent is returned when a too large zip is processed
134+
// (e.g. a zip bomb).
135+
type ErrTooLargeContent struct {
136+
MaxSize int64
137+
}
138+
139+
func (err ErrTooLargeContent) Error() string {
140+
return fmt.Sprintf("too large archive content, maximum is %d", err.MaxSize)
141+
}
142+
143+
var _ error = (*ErrTooLargeContent)(nil)

webserver/api/v1/encoding.go

Lines changed: 10 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@ import (
1212
"github.com/pkg/errors"
1313
)
1414

15+
const (
16+
maxSize = 1 << 30 // 1Gb
17+
)
18+
1519
// Encode consumes a source directory, zip its content and encoded
1620
// base 64.
1721
func Encode(src string) (string, error) {
@@ -66,53 +70,15 @@ func Decode(buf string, dst string) error {
6670
return errors.Wrap(err, "base64 decoding")
6771
}
6872

69-
// Unzip content into it
73+
// Safely decompress the archive (borrowed from Chall-Manager)
7074
r, err := zip.NewReader(bytes.NewReader(raw), int64(len(raw)))
7175
if err != nil {
7276
return errors.Wrap(err, "base64 decoded invalid zip archive")
7377
}
74-
for _, f := range r.File {
75-
filePath := filepath.Join(dst, f.Name)
76-
if f.FileInfo().IsDir() {
77-
continue
78-
}
79-
80-
// If the file is in a sub-directory, create it
81-
dir := filepath.Dir(filePath)
82-
if _, err := os.Stat(dir); err != nil {
83-
if err := os.MkdirAll(dir, os.ModePerm); err != nil {
84-
return err
85-
}
86-
}
87-
88-
// Create and write the file
89-
if err := copyTo(filePath, f); err != nil {
90-
return err
91-
}
92-
}
9378

94-
return nil
95-
}
96-
97-
func copyTo(filePath string, f *zip.File) error {
98-
outFile, err := os.OpenFile(filePath, os.O_WRONLY|os.O_CREATE, 0777)
99-
if err != nil {
100-
return err
101-
}
102-
defer func() {
103-
_ = outFile.Close()
104-
}()
105-
106-
rc, err := f.Open()
107-
if err != nil {
108-
return err
109-
}
110-
defer func() {
111-
_ = rc.Close()
112-
}()
113-
114-
if _, err := io.Copy(outFile, rc); err != nil {
115-
return err
116-
}
117-
return nil
79+
dec := NewDecompressor(&Options{
80+
MaxSize: maxSize,
81+
})
82+
_, err = dec.Unzip(r, dst)
83+
return err
11884
}

0 commit comments

Comments
 (0)