mirror of
https://github.com/kemko/nomad.git
synced 2026-01-05 09:55:44 +03:00
This adds artifact inspection after download to detect any issues with the content fetched. Currently this means checking for any symlinks within the artifact that resolve outside the task or allocation directories. On platforms where lockdown is available (some Linux) this inspection is not performed. The inspection can be disabled with the DisableArtifactInspection option. A dedicated option for disabling this behavior allows the DisableFilesystemIsolation option to be enabled but still have artifacts inspected after download.
165 lines
4.1 KiB
Go
165 lines
4.1 KiB
Go
// Copyright (c) HashiCorp, Inc.
|
|
// SPDX-License-Identifier: BUSL-1.1
|
|
|
|
package getter
|
|
|
|
import (
|
|
"context"
|
|
"io"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/hashicorp/go-getter"
|
|
"github.com/shoenig/test/must"
|
|
)
|
|
|
|
const paramsAsJSON = `
|
|
{
|
|
"http_read_timeout": 1000000000,
|
|
"http_max_bytes": 2000,
|
|
"gcs_timeout": 2000000000,
|
|
"git_timeout": 3000000000,
|
|
"hg_timeout": 4000000000,
|
|
"s3_timeout": 5000000000,
|
|
"decompression_limit_file_count": 3,
|
|
"decompression_limit_size": 98765,
|
|
"disable_artifact_inspection": false,
|
|
"disable_filesystem_isolation": true,
|
|
"filesystem_isolation_extra_paths": [
|
|
"f:r:/dev/urandom",
|
|
"d:rx:/opt/bin",
|
|
"d:r:/tmp/stash"
|
|
],
|
|
"set_environment_variables": "",
|
|
"artifact_mode": 2,
|
|
"artifact_insecure": false,
|
|
"artifact_source": "https://example.com/file.txt",
|
|
"artifact_destination": "local/out.txt",
|
|
"artifact_headers": {
|
|
"X-Nomad-Artifact": ["hi"]
|
|
},
|
|
"alloc_dir": "/path/to/alloc",
|
|
"task_dir": "/path/to/alloc/task",
|
|
"chown": true,
|
|
"user":"nobody"
|
|
}`
|
|
|
|
var paramsAsStruct = ¶meters{
|
|
HTTPReadTimeout: 1 * time.Second,
|
|
HTTPMaxBytes: 2000,
|
|
GCSTimeout: 2 * time.Second,
|
|
GitTimeout: 3 * time.Second,
|
|
HgTimeout: 4 * time.Second,
|
|
S3Timeout: 5 * time.Second,
|
|
DecompressionLimitFileCount: 3,
|
|
DecompressionLimitSize: 98765,
|
|
DisableFilesystemIsolation: true,
|
|
FilesystemIsolationExtraPaths: []string{
|
|
"f:r:/dev/urandom",
|
|
"d:rx:/opt/bin",
|
|
"d:r:/tmp/stash",
|
|
},
|
|
Mode: getter.ClientModeFile,
|
|
Source: "https://example.com/file.txt",
|
|
Destination: "local/out.txt",
|
|
AllocDir: "/path/to/alloc",
|
|
TaskDir: "/path/to/alloc/task",
|
|
Headers: map[string][]string{
|
|
"X-Nomad-Artifact": {"hi"},
|
|
},
|
|
User: "nobody",
|
|
Chown: true,
|
|
}
|
|
|
|
func TestParameters_reader(t *testing.T) {
|
|
p := paramsAsStruct
|
|
reader := p.reader()
|
|
b, err := io.ReadAll(reader)
|
|
must.NoError(t, err)
|
|
must.EqJSON(t, paramsAsJSON, string(b))
|
|
}
|
|
|
|
func TestParameters_read(t *testing.T) {
|
|
reader := strings.NewReader(paramsAsJSON)
|
|
p := new(parameters)
|
|
err := p.read(reader)
|
|
must.NoError(t, err)
|
|
must.Equal(t, paramsAsStruct, p)
|
|
}
|
|
|
|
func TestParameters_deadline(t *testing.T) {
|
|
t.Run("typical", func(t *testing.T) {
|
|
dur := paramsAsStruct.deadline()
|
|
must.Eq(t, 31*time.Minute, dur)
|
|
})
|
|
|
|
t.Run("long", func(t *testing.T) {
|
|
params := ¶meters{
|
|
HTTPReadTimeout: 1 * time.Hour,
|
|
GCSTimeout: 2 * time.Hour,
|
|
GitTimeout: 3 * time.Hour,
|
|
HgTimeout: 4 * time.Hour,
|
|
S3Timeout: 5 * time.Hour,
|
|
}
|
|
dur := params.deadline()
|
|
must.Eq(t, 5*time.Hour+1*time.Minute, dur)
|
|
})
|
|
}
|
|
|
|
func TestParameters_client(t *testing.T) {
|
|
ctx := context.Background()
|
|
c := paramsAsStruct.client(ctx)
|
|
must.NotNil(t, c)
|
|
|
|
// security options
|
|
must.False(t, c.Insecure)
|
|
must.True(t, c.DisableSymlinks)
|
|
must.Eq(t, umask, c.Umask)
|
|
|
|
// artifact options
|
|
must.Eq(t, "https://example.com/file.txt", c.Src)
|
|
must.Eq(t, "local/out.txt", c.Dst)
|
|
|
|
// decompression limits
|
|
const fileCountLimit = 3
|
|
const fileSizeLimit = 98765
|
|
must.Eq(t, fileSizeLimit, c.Decompressors["zip"].(*getter.ZipDecompressor).FileSizeLimit)
|
|
must.Eq(t, fileCountLimit, c.Decompressors["zip"].(*getter.ZipDecompressor).FilesLimit)
|
|
must.Eq(t, fileSizeLimit, c.Decompressors["tar.gz"].(*getter.TarGzipDecompressor).FileSizeLimit)
|
|
must.Eq(t, fileCountLimit, c.Decompressors["tar.gz"].(*getter.TarGzipDecompressor).FilesLimit)
|
|
must.Eq(t, fileSizeLimit, c.Decompressors["xz"].(*getter.XzDecompressor).FileSizeLimit)
|
|
// xz does not support files count limit
|
|
}
|
|
|
|
func TestParameters_Equal_headers(t *testing.T) {
|
|
p1 := ¶meters{
|
|
Headers: map[string][]string{
|
|
"East": []string{"New York", "Florida"},
|
|
"West": []string{"California"},
|
|
},
|
|
}
|
|
|
|
p2 := ¶meters{
|
|
Headers: map[string][]string{
|
|
"East": []string{"New York", "Florida"},
|
|
"West": []string{"California"},
|
|
},
|
|
}
|
|
|
|
// equal
|
|
must.Equal(t, p1, p2)
|
|
|
|
// equal
|
|
must.Equal(t, p1, ¶meters{
|
|
Headers: map[string][]string{
|
|
"West": {"California"},
|
|
"East": {"Florida", "New York"},
|
|
},
|
|
})
|
|
|
|
// not equal
|
|
p2.Headers["East"] = []string{"New York"}
|
|
must.NotEqual(t, p1, p2)
|
|
}
|