Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
feat(internal): add logic from pkg-runtime
  • Loading branch information
jbrockopp committed Oct 26, 2021
commit b1464f2dbf6d9b19c9abe1137e39d49cf4576836
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ go 1.16

require (
github.com/Masterminds/semver/v3 v3.1.1
github.com/docker/distribution v2.7.1+incompatible
github.com/gin-gonic/gin v1.7.4
github.com/go-vela/mock v0.10.0
github.com/go-vela/pkg-executor v0.10.0
Expand Down
11 changes: 11 additions & 0 deletions internal/image/doc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// Copyright (c) 2021 Target Brands, Inc. All rights reserved.
//
// Use of this source code is governed by the LICENSE file in this repository.

// Package image provides the ability for Vela to manage
// and manipulate an image provided for a container.
//
// Usage:
//
// import "github.com/go-vela/worker/internal/image"
package image
87 changes: 87 additions & 0 deletions internal/image/image.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
// Copyright (c) 2021 Target Brands, Inc. All rights reserved.
//
// Use of this source code is governed by the LICENSE file in this repository.

package image

import (
"github.com/docker/distribution/reference"
)

// Parse digests the provided image into a fully
// qualified canonical reference. If an error
// occurs, it will return the provided image.
func Parse(_image string) string {
// parse the image provided into a fully qualified canonical reference
//
// https://pkg.go.dev/github.com/go-vela/worker/runtime/internal/image?tab=doc#ParseWithError
_canonical, err := ParseWithError(_image)
if err != nil {
return _image
}

return _canonical
}

// ParseWithError digests the provided image into a
// fully qualified canonical reference. If an error
// occurs, it will return the last digested form of
// the image.
func ParseWithError(_image string) (string, error) {
// parse the image provided into a
// named, fully qualified reference
//
// https://pkg.go.dev/github.com/docker/distribution/reference?tab=doc#ParseAnyReference
_reference, err := reference.ParseAnyReference(_image)
if err != nil {
return _image, err
}

// ensure we have the canonical form of the named reference
//
// https://pkg.go.dev/github.com/docker/distribution/reference?tab=doc#ParseNamed
_canonical, err := reference.ParseNamed(_reference.String())
if err != nil {
return _reference.String(), err
}

// ensure the canonical reference has a tag
//
// https://pkg.go.dev/github.com/docker/distribution/reference?tab=doc#TagNameOnly
return reference.TagNameOnly(_canonical).String(), nil
}

// IsPrivilegedImage digests the provided image with a
// privileged pattern to see if the image meets the criteria
// needed to allow a Docker Socket mount.
func IsPrivilegedImage(image, privileged string) (bool, error) {
// parse the image provided into a
// named, fully qualified reference
//
// https://pkg.go.dev/github.com/docker/distribution/reference?tab=doc#ParseAnyReference
_refImg, err := reference.ParseAnyReference(image)
if err != nil {
return false, err
}

// ensure we have the canonical form of the named reference
//
// https://pkg.go.dev/github.com/docker/distribution/reference?tab=doc#ParseNamed
_canonical, err := reference.ParseNamed(_refImg.String())
if err != nil {
return false, err
}

// add default tag "latest" when tag does not exist
_refImg = reference.TagNameOnly(_canonical)

// check if the image matches the privileged pattern
//
// https://pkg.go.dev/github.com/docker/distribution/reference#FamiliarMatch
match, err := reference.FamiliarMatch(privileged, _refImg)
if err != nil {
return false, err
}

return match, nil
}
188 changes: 188 additions & 0 deletions internal/image/image_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
// Copyright (c) 2021 Target Brands, Inc. All rights reserved.
//
// Use of this source code is governed by the LICENSE file in this repository.

package image

import (
"strings"
"testing"
)

func TestImage_Parse(t *testing.T) {
// setup tests
tests := []struct {
image string
want string
}{
{
image: "golang",
want: "docker.io/library/golang:latest",
},
{
image: "golang:latest",
want: "docker.io/library/golang:latest",
},
{
image: "library/golang",
want: "docker.io/library/golang:latest",
},
{
image: "library/golang:1.14",
want: "docker.io/library/golang:1.14",
},
{
image: "docker.io/library/golang",
want: "docker.io/library/golang:latest",
},
{
image: "docker.io/library/golang:latest",
want: "docker.io/library/golang:latest",
},
{
image: "index.docker.io/library/golang",
want: "docker.io/library/golang:latest",
},
{
image: "index.docker.io/library/golang:latest",
want: "docker.io/library/golang:latest",
},
{
image: "gcr.io/library/golang",
want: "gcr.io/library/golang:latest",
},
{
image: "gcr.io/library/golang:latest",
want: "gcr.io/library/golang:latest",
},
{
image: "!@#$%^&*()",
want: "!@#$%^&*()",
},
}

// run tests
for _, test := range tests {
got := Parse(test.image)

if !strings.EqualFold(got, test.want) {
t.Errorf("Parse is %s want %s", got, test.want)
}
}
}

func TestImage_ParseWithError(t *testing.T) {
// setup tests
tests := []struct {
failure bool
image string
want string
}{
{
failure: false,
image: "golang",
want: "docker.io/library/golang:latest",
},
{
failure: false,
image: "golang:latest",
want: "docker.io/library/golang:latest",
},
{
failure: false,
image: "golang:1.14",
want: "docker.io/library/golang:1.14",
},
{
failure: true,
image: "!@#$%^&*()",
want: "!@#$%^&*()",
},
{
failure: true,
image: "1a3f5e7d9c1b3a5f7e9d1c3b5a7f9e1d3c5b7a9f1e3d5d7c9b1a3f5e7d9c1b3a",
want: "sha256:1a3f5e7d9c1b3a5f7e9d1c3b5a7f9e1d3c5b7a9f1e3d5d7c9b1a3f5e7d9c1b3a",
},
}

// run tests
for _, test := range tests {
got, err := ParseWithError(test.image)

if test.failure {
if err == nil {
t.Errorf("ParseWithError should have returned err")
}

if !strings.EqualFold(got, test.want) {
t.Errorf("ParseWithError is %s want %s", got, test.want)
}

continue
}

if err != nil {
t.Errorf("ParseWithError returned err: %v", err)
}

if !strings.EqualFold(got, test.want) {
t.Errorf("ParseWithError is %s want %s", got, test.want)
}
}
}

func TestImage_IsPrivilegedImage(t *testing.T) {
// setup tests
tests := []struct {
name string
image string
pattern string
want bool
}{
{
name: "test privileged image without tag",
image: "docker.company.com/foo/bar",
pattern: "docker.company.com/foo/bar",
want: true,
},
{
name: "test privileged image with tag",
image: "docker.company.com/foo/bar:v0.1.0",
pattern: "docker.company.com/foo/bar",
want: true,
},
{
name: "test privileged image with tag",
image: "docker.company.com/foo/bar",
pattern: "docker.company.com/foo/bar:v0.1.0",
want: false,
},
{
name: "test privileged with bad image",
image: "!@#$%^&*()",
pattern: "docker.company.com/foo/bar",
want: false,
},
{
name: "test privileged with bad pattern",
image: "docker.company.com/foo/bar",
pattern: "!@#$%^&*()",
want: false,
},
{
name: "test privileged with on extended path image",
image: "docker.company.com/foo/bar",
pattern: "docker.company.com/foo",
want: false,
},
}

for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
got, _ := IsPrivilegedImage(test.image, test.pattern)
if got != test.want {
t.Errorf("IsPrivilegedImage is %v want %v", got, test.want)
}
})
}
}
11 changes: 11 additions & 0 deletions internal/volume/doc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// Copyright (c) 2021 Target Brands, Inc. All rights reserved.
//
// Use of this source code is governed by the LICENSE file in this repository.

// Package volume provides the ability for Vela to manage
// and manipulate a volume provided for a container.
//
// Usage:
//
// import "github.com/go-vela/worker/internal/volume"
package volume
70 changes: 70 additions & 0 deletions internal/volume/volume.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
// Copyright (c) 2021 Target Brands, Inc. All rights reserved.
//
// Use of this source code is governed by the LICENSE file in this repository.

package volume

import (
"fmt"
"strings"
)

// Volume represents the volume definition used
// to create volumes for a container.
type Volume struct {
Source string `json:"source,omitempty"`
Destination string `json:"destination,omitempty"`
AccessMode string `json:"access_mode,omitempty"`
}

// Parse digests the provided volume into a fully
// qualified volume reference. If an error
// occurs, it will return a nil volume.
func Parse(_volume string) *Volume {
// parse the image provided into a fully qualified canonical reference
//
// https://pkg.go.dev/github.com/go-vela/worker/runtime/internal/image?tab=doc#ParseWithError
v, err := ParseWithError(_volume)
if err != nil {
return nil
}

return v
}

// ParseWithError digests the provided volume into a
// fully qualified volume reference. If an error
// occurs, it will return a nil volume and the
// produced error.
func ParseWithError(_volume string) (*Volume, error) {
// split each slice element into source, destination and access mode
parts := strings.Split(_volume, ":")

switch len(parts) {
case 1:
// return the read-only volume with the same source and destination
return &Volume{
Source: parts[0],
Destination: parts[0],
AccessMode: "ro",
}, nil
// nolint: gomnd // ignore magic number
case 2:
// return the read-only volume with different source and destination
return &Volume{
Source: parts[0],
Destination: parts[1],
AccessMode: "ro",
}, nil
// nolint: gomnd // ignore magic number
case 3:
// return the full volume with source, destination and access mode
return &Volume{
Source: parts[0],
Destination: parts[1],
AccessMode: parts[2],
}, nil
default:
return nil, fmt.Errorf("volume %s requires at least 1, but no more than 2, `:`", _volume)
}
}
Loading