Skip to content

Commit

Permalink
Merge pull request #4819 from hashicorp/b-artifacts-checksum
Browse files Browse the repository at this point in the history
Allow artifacts checksum interpolation
  • Loading branch information
notnoop committed Oct 31, 2018
2 parents 61ff185 + abd2451 commit e7e7302
Show file tree
Hide file tree
Showing 4 changed files with 93 additions and 38 deletions.
5 changes: 5 additions & 0 deletions helper/args/args.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,8 @@ func ReplaceEnv(arg string, environments ...map[string]string) string {
func ReplaceEnvWithPlaceHolder(arg string, placeholder string) string {
return envRe.ReplaceAllString(arg, placeholder)
}

// ContainsEnv takes an arg and returns true if if contains an environment variable reference
func ContainsEnv(arg string) bool {
return envRe.MatchString(arg)
}
29 changes: 29 additions & 0 deletions helper/args/args_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,3 +75,32 @@ func TestArgs_ReplaceEnv_Chained(t *testing.T) {
t.Fatalf("ReplaceEnv(%v, %v) returned %#v; want %#v", input, envVars, act, exp)
}
}

func TestArgs_ContainsEnv(t *testing.T) {
positiveCases := []string{
"test-${env_var}",
}
for _, c := range positiveCases {
t.Run(fmt.Sprintf("positive case: %v", c), func(t *testing.T) {
if !ContainsEnv(c) {
t.Fatalf("ContainsEnv(%v) returned false; want true", c)
}
})
}

negativeCases := []string{
"test",
"test-$",
"test-${asdf",
"test-{asdf}",
"$test",
}
for _, c := range negativeCases {
t.Run(fmt.Sprintf("negative case: %v", c), func(t *testing.T) {
if ContainsEnv(c) {
t.Fatalf("ContainsEnv(%v) returned true; want false", c)
}
})
}

}
88 changes: 50 additions & 38 deletions nomad/structs/structs.go
Original file line number Diff line number Diff line change
Expand Up @@ -6154,50 +6154,62 @@ func (ta *TaskArtifact) Validate() error {
mErr.Errors = append(mErr.Errors, fmt.Errorf("destination escapes allocation directory"))
}

// Verify the checksum
if check, ok := ta.GetterOptions["checksum"]; ok {
check = strings.TrimSpace(check)
if check == "" {
mErr.Errors = append(mErr.Errors, fmt.Errorf("checksum value cannot be empty"))
return mErr.ErrorOrNil()
}
if err := ta.validateChecksum(); err != nil {
mErr.Errors = append(mErr.Errors, err)
}

parts := strings.Split(check, ":")
if l := len(parts); l != 2 {
mErr.Errors = append(mErr.Errors, fmt.Errorf(`checksum must be given as "type:value"; got %q`, check))
return mErr.ErrorOrNil()
}
return mErr.ErrorOrNil()
}

checksumVal := parts[1]
checksumBytes, err := hex.DecodeString(checksumVal)
if err != nil {
mErr.Errors = append(mErr.Errors, fmt.Errorf("invalid checksum: %v", err))
return mErr.ErrorOrNil()
}
func (ta *TaskArtifact) validateChecksum() error {
check, ok := ta.GetterOptions["checksum"]
if !ok {
return nil
}

checksumType := parts[0]
expectedLength := 0
switch checksumType {
case "md5":
expectedLength = md5.Size
case "sha1":
expectedLength = sha1.Size
case "sha256":
expectedLength = sha256.Size
case "sha512":
expectedLength = sha512.Size
default:
mErr.Errors = append(mErr.Errors, fmt.Errorf("unsupported checksum type: %s", checksumType))
return mErr.ErrorOrNil()
}
// Job struct validation occurs before interpolation resolution can be effective.
// Skip checking if checksum contain variable reference, and artifacts fetching will
// eventually fail, if checksum is indeed invalid.
if args.ContainsEnv(check) {
return nil
}

if len(checksumBytes) != expectedLength {
mErr.Errors = append(mErr.Errors, fmt.Errorf("invalid %s checksum: %v", checksumType, checksumVal))
return mErr.ErrorOrNil()
}
check = strings.TrimSpace(check)
if check == "" {
return fmt.Errorf("checksum value cannot be empty")
}

return mErr.ErrorOrNil()
parts := strings.Split(check, ":")
if l := len(parts); l != 2 {
return fmt.Errorf(`checksum must be given as "type:value"; got %q`, check)
}

checksumVal := parts[1]
checksumBytes, err := hex.DecodeString(checksumVal)
if err != nil {
return fmt.Errorf("invalid checksum: %v", err)
}

checksumType := parts[0]
expectedLength := 0
switch checksumType {
case "md5":
expectedLength = md5.Size
case "sha1":
expectedLength = sha1.Size
case "sha256":
expectedLength = sha256.Size
case "sha512":
expectedLength = sha512.Size
default:
return fmt.Errorf("unsupported checksum type: %s", checksumType)
}

if len(checksumBytes) != expectedLength {
return fmt.Errorf("invalid %s checksum: %v", checksumType, checksumVal)
}

return nil
}

const (
Expand Down
9 changes: 9 additions & 0 deletions nomad/structs/structs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2672,6 +2672,15 @@ func TestTaskArtifact_Validate_Checksum(t *testing.T) {
},
true,
},
{
&TaskArtifact{
GetterSource: "foo.com",
GetterOptions: map[string]string{
"checksum": "md5:${ARTIFACT_CHECKSUM}",
},
},
false,
},
}

for i, tc := range cases {
Expand Down

0 comments on commit e7e7302

Please sign in to comment.