From f8991fedf092f48f3f5f42ce904dd4ae09143bb9 Mon Sep 17 00:00:00 2001 From: Kyle Carberry Date: Fri, 30 Jun 2023 10:04:29 -0500 Subject: [PATCH 1/8] feat: add support for devcontainer features --- devcontainer.go | 85 -------- devcontainer/devcontainer.go | 187 +++++++++++++++++ .../devcontainer_test.go | 13 +- devcontainer/features/features.go | 195 ++++++++++++++++++ devcontainer/features/features_test.go | 116 +++++++++++ envbuilder.go | 32 ++- go.mod | 4 +- go.sum | 2 + integration/integration_test.go | 46 +++++ registrytest/registrytest.go | 120 +++++++++++ 10 files changed, 687 insertions(+), 113 deletions(-) delete mode 100644 devcontainer.go create mode 100644 devcontainer/devcontainer.go rename devcontainer_test.go => devcontainer/devcontainer_test.go (85%) create mode 100644 devcontainer/features/features.go create mode 100644 devcontainer/features/features_test.go create mode 100644 registrytest/registrytest.go diff --git a/devcontainer.go b/devcontainer.go deleted file mode 100644 index bd92ad98..00000000 --- a/devcontainer.go +++ /dev/null @@ -1,85 +0,0 @@ -package envbuilder - -import ( - "os" - "path/filepath" - - "github.com/go-git/go-billy/v5" - "muzzammil.xyz/jsonc" -) - -// ParseDevcontainer parses a devcontainer.json file. -func ParseDevcontainer(content []byte) (*DevContainer, error) { - content = jsonc.ToJSON(content) - var schema DevContainer - return &schema, jsonc.Unmarshal(content, &schema) -} - -type DevContainer struct { - Image string `json:"image"` - Build DevContainerBuild `json:"build"` - RemoteUser string `json:"remoteUser"` - RemoteEnv map[string]string `json:"remoteEnv"` - - // Deprecated but still frequently used... - Dockerfile string `json:"dockerFile"` - Context string `json:"context"` -} - -type DevContainerBuild struct { - Dockerfile string `json:"dockerfile"` - Context string `json:"context"` - Args map[string]string `json:"args"` - Target string `json:"target"` - CacheFrom string `json:"cache_from"` -} - -// Compile returns the build parameters for the workspace. -// devcontainerDir is the path to the directory where the devcontainer.json file -// is located. scratchDir is the path to the directory where the Dockerfile will -// be written to if one doesn't exist. -func (d *DevContainer) Compile(fs billy.Filesystem, devcontainerDir, scratchDir string) (*BuildParameters, error) { - env := make([]string, 0) - for key, value := range d.RemoteEnv { - env = append(env, key+"="+value) - } - params := &BuildParameters{ - User: d.RemoteUser, - Env: env, - } - - if d.Image != "" { - // We just write the image to a file and return it. - dockerfilePath := filepath.Join(scratchDir, "Dockerfile") - file, err := fs.OpenFile(dockerfilePath, os.O_CREATE|os.O_WRONLY, 0644) - if err != nil { - return nil, err - } - defer file.Close() - _, err = file.Write([]byte("FROM " + d.Image)) - if err != nil { - return nil, err - } - params.DockerfilePath = dockerfilePath - params.BuildContext = scratchDir - return params, nil - } - buildArgs := make([]string, 0) - for key, value := range d.Build.Args { - buildArgs = append(buildArgs, key+"="+value) - } - params.BuildArgs = buildArgs - params.Cache = true - - // Deprecated values! - if d.Dockerfile != "" { - d.Build.Dockerfile = d.Dockerfile - } - if d.Context != "" { - d.Build.Context = d.Context - } - - params.DockerfilePath = filepath.Join(devcontainerDir, d.Build.Dockerfile) - params.BuildContext = filepath.Join(devcontainerDir, d.Build.Context) - return params, nil -} diff --git a/devcontainer/devcontainer.go b/devcontainer/devcontainer.go new file mode 100644 index 00000000..8611fbf9 --- /dev/null +++ b/devcontainer/devcontainer.go @@ -0,0 +1,187 @@ +package devcontainer + +import ( + "bufio" + "crypto/md5" + "fmt" + "io" + "os" + "path/filepath" + "strings" + + "github.com/coder/envbuilder/devcontainer/features" + "github.com/go-git/go-billy/v5" + "muzzammil.xyz/jsonc" +) + +// Parse parses a devcontainer.json file. +func Parse(content []byte) (*Spec, error) { + content = jsonc.ToJSON(content) + var schema Spec + return &schema, jsonc.Unmarshal(content, &schema) +} + +type Spec struct { + Image string `json:"image"` + Build BuildSpec `json:"build"` + RemoteUser string `json:"remoteUser"` + RemoteEnv map[string]string `json:"remoteEnv"` + // Features is a map of feature names to feature configurations. + Features map[string]map[string]any `json:"features"` + + // Deprecated but still frequently used... + Dockerfile string `json:"dockerFile"` + Context string `json:"context"` +} + +type BuildSpec struct { + Dockerfile string `json:"dockerfile"` + Context string `json:"context"` + Args map[string]string `json:"args"` + Target string `json:"target"` + CacheFrom string `json:"cache_from"` +} + +// Compiled is the result of compiling a devcontainer.json file. +type Compiled struct { + DockerfilePath string + DockerfileContent string + BuildContext string + BuildArgs []string + Cache bool + + User string + Env []string +} + +// Compile returns the build parameters for the workspace. +// devcontainerDir is the path to the directory where the devcontainer.json file +// is located. scratchDir is the path to the directory where the Dockerfile will +// be written to if one doesn't exist. +func (s *Spec) Compile(fs billy.Filesystem, devcontainerDir, scratchDir string) (*Compiled, error) { + env := make([]string, 0) + for key, value := range s.RemoteEnv { + env = append(env, key+"="+value) + } + params := &Compiled{ + User: s.RemoteUser, + Env: env, + } + + if s.Image != "" { + // We just write the image to a file and return it. + dockerfilePath := filepath.Join(scratchDir, "Dockerfile") + file, err := fs.OpenFile(dockerfilePath, os.O_CREATE|os.O_WRONLY, 0644) + if err != nil { + return nil, err + } + defer file.Close() + _, err = file.Write([]byte("FROM " + s.Image)) + if err != nil { + return nil, err + } + params.DockerfilePath = dockerfilePath + params.BuildContext = scratchDir + } + buildArgs := make([]string, 0) + for key, value := range s.Build.Args { + buildArgs = append(buildArgs, key+"="+value) + } + params.BuildArgs = buildArgs + params.Cache = true + + // Deprecated values! + if s.Dockerfile != "" { + s.Build.Dockerfile = s.Dockerfile + } + if s.Context != "" { + s.Build.Context = s.Context + } + + params.DockerfilePath = filepath.Join(devcontainerDir, s.Build.Dockerfile) + params.BuildContext = filepath.Join(devcontainerDir, s.Build.Context) + + dockerfile, err := fs.Open(params.DockerfilePath) + if err != nil { + return nil, err + } + defer dockerfile.Close() + dockerfileContent, err := io.ReadAll(dockerfile) + if err != nil { + return nil, err + } + params.DockerfileContent = string(dockerfileContent) + + // If we don't have a user provided, we look for the latest USER directive + // in the Dockerfile. This is what devcontainers/cli does. + if params.User == "" { + reader := bufio.NewScanner(strings.NewReader(params.DockerfileContent)) + for reader.Scan() { + line := reader.Text() + if !strings.HasPrefix(line, "USER ") { + continue + } + params.User = strings.TrimPrefix(line, "USER ") + break + } + } + + if len(s.Features) > 0 { + featuresDir := filepath.Join(scratchDir, "features") + err := fs.MkdirAll(featuresDir, 0644) + if err != nil { + return nil, fmt.Errorf("create features directory: %w", err) + } + params.DockerfileContent, err = s.appendFeaturesToDockerfile(fs, scratchDir, params) + if err != nil { + return nil, err + } + + fmt.Printf("Content: %s\n", params.DockerfileContent) + } + return params, nil +} + +func (s *Spec) appendFeaturesToDockerfile(fs billy.Filesystem, scratchDir string, params *Compiled) (string, error) { + featuresDir := filepath.Join(scratchDir, "features") + err := fs.MkdirAll(featuresDir, 0644) + if err != nil { + return "", fmt.Errorf("create features directory: %w", err) + } + featureDirectives := []string{} + for featureRef, featureOpts := range s.Features { + // It's important for caching that this directory is static. + // If it changes on each run then the container will not be cached. + // + // devcontainers/cli has a very complex method of computing the feature + // name from the feature reference. We're just going to hash it for simplicity. + featureSha := md5.Sum([]byte(featureRef)) + featureName := strings.Split(filepath.Base(featureRef), ":")[0] + featureDir := filepath.Join(featuresDir, fmt.Sprintf("%s-%x", featureName, featureSha[:4])) + err = fs.MkdirAll(featureDir, 0644) + if err != nil { + return "", err + } + spec, err := features.Extract(fs, featureDir, featureRef) + if err != nil { + return "", fmt.Errorf("extract feature %s: %w", featureRef, err) + } + directive, err := spec.Compile(featureOpts) + if err != nil { + return "", fmt.Errorf("compile feature %s: %w", featureRef, err) + } + featureDirectives = append(featureDirectives, directive) + } + + lines := []string{"\nUSER root"} + lines = append(lines, featureDirectives...) + if params.User != "" { + // TODO: We should warn! + lines = append(lines, fmt.Sprintf("USER %s", params.User)) + } + return strings.Join(append([]string{params.DockerfileContent}, lines...), "\n"), err +} + +func (s *Spec) User() { + +} diff --git a/devcontainer_test.go b/devcontainer/devcontainer_test.go similarity index 85% rename from devcontainer_test.go rename to devcontainer/devcontainer_test.go index a2bbe88c..c7f4d9b2 100644 --- a/devcontainer_test.go +++ b/devcontainer/devcontainer_test.go @@ -1,15 +1,16 @@ -package envbuilder_test +package devcontainer_test import ( "path/filepath" "testing" "github.com/coder/envbuilder" + "github.com/coder/envbuilder/devcontainer" "github.com/go-git/go-billy/v5/memfs" "github.com/stretchr/testify/require" ) -func TestParseDevContainer(t *testing.T) { +func TestParse(t *testing.T) { t.Parallel() raw := `{ "build": { @@ -19,7 +20,7 @@ func TestParseDevContainer(t *testing.T) { // Comments here! "image": "codercom/code-server:latest" }` - parsed, err := envbuilder.ParseDevcontainer([]byte(raw)) + parsed, err := devcontainer.Parse([]byte(raw)) require.NoError(t, err) require.Equal(t, "Dockerfile", parsed.Build.Dockerfile) } @@ -29,7 +30,7 @@ func TestCompileDevContainer(t *testing.T) { t.Run("WithImage", func(t *testing.T) { t.Parallel() fs := memfs.New() - dc := &envbuilder.DevContainer{ + dc := &devcontainer.Spec{ Image: "codercom/code-server:latest", } params, err := dc.Compile(fs, "", envbuilder.MagicDir) @@ -40,8 +41,8 @@ func TestCompileDevContainer(t *testing.T) { t.Run("WithBuild", func(t *testing.T) { t.Parallel() fs := memfs.New() - dc := &envbuilder.DevContainer{ - Build: envbuilder.DevContainerBuild{ + dc := &devcontainer.Spec{ + Build: devcontainer.BuildSpec{ Dockerfile: "Dockerfile", Context: ".", Args: map[string]string{ diff --git a/devcontainer/features/features.go b/devcontainer/features/features.go new file mode 100644 index 00000000..c5cc5d81 --- /dev/null +++ b/devcontainer/features/features.go @@ -0,0 +1,195 @@ +package features + +import ( + "archive/tar" + "encoding/json" + "errors" + "fmt" + "io" + "os" + "path/filepath" + "regexp" + "strings" + + "github.com/go-git/go-billy/v5" + "github.com/google/go-containerregistry/pkg/name" + "github.com/google/go-containerregistry/pkg/v1/remote" +) + +// Extract unpacks the feature from the image and returns the +// parsed specification. +func Extract(fs billy.Filesystem, directory, reference string) (*Spec, error) { + ref, err := name.ParseReference(reference) + if err != nil { + return nil, fmt.Errorf("parse feature ref %s: %w", reference, err) + } + image, err := remote.Image(ref) + if err != nil { + return nil, fmt.Errorf("fetch feature image %s: %w", reference, err) + } + manifest, err := image.Manifest() + if err != nil { + return nil, fmt.Errorf("fetch feature manifest %s: %w", reference, err) + } + + var tarLayer *tar.Reader + for _, manifestLayer := range manifest.Layers { + if manifestLayer.MediaType != TarLayerMediaType { + continue + } + layer, err := image.LayerByDigest(manifestLayer.Digest) + if err != nil { + return nil, fmt.Errorf("fetch feature layer %s: %w", reference, err) + } + layerReader, err := layer.Uncompressed() + if err != nil { + return nil, fmt.Errorf("uncompress feature layer %s: %w", reference, err) + } + tarLayer = tar.NewReader(layerReader) + break + } + if tarLayer == nil { + return nil, fmt.Errorf("no tar layer found with media type %q: are you sure this is a devcontainer feature?", TarLayerMediaType) + } + + for { + header, err := tarLayer.Next() + if err == io.EOF { + break + } + if err != nil { + return nil, fmt.Errorf("read feature layer %s: %w", reference, err) + } + path := filepath.Join(directory, header.Name) + switch header.Typeflag { + case tar.TypeDir: + err = fs.MkdirAll(path, 0755) + if err != nil { + return nil, fmt.Errorf("mkdir %s: %w", path, err) + } + case tar.TypeReg: + outFile, err := fs.Create(path) + if err != nil { + return nil, fmt.Errorf("create %s: %w", path, err) + } + _, err = io.Copy(outFile, tarLayer) + if err != nil { + return nil, fmt.Errorf("copy %s: %w", path, err) + } + err = outFile.Close() + if err != nil { + return nil, fmt.Errorf("close %s: %w", path, err) + } + default: + return nil, fmt.Errorf("unknown type %d in %s", header.Typeflag, path) + } + } + + installScriptPath := filepath.Join(directory, "install.sh") + _, err = fs.Stat(installScriptPath) + if err != nil { + if errors.Is(err, os.ErrNotExist) { + return nil, errors.New("install.sh must be in the root of the feature") + } + return nil, fmt.Errorf("stat install.sh: %w", err) + } + err = os.Chmod(installScriptPath, 0755) + if err != nil { + return nil, fmt.Errorf("chmod install.sh: %w", err) + } + + featureFile, err := fs.Open(filepath.Join(directory, "devcontainer-feature.json")) + if err != nil { + if errors.Is(err, os.ErrNotExist) { + return nil, errors.New("devcontainer-feature.json must be in the root of the feature") + } + return nil, fmt.Errorf("open devcontainer-feature.json: %w", err) + } + defer featureFile.Close() + var spec *Spec + err = json.NewDecoder(featureFile).Decode(&spec) + if err != nil { + return nil, fmt.Errorf("decode devcontainer-feature.json: %w", err) + } + // See https://containers.dev/implementors/features/#devcontainer-feature-json-properties + if spec.ID == "" { + return nil, errors.New(`devcontainer-feature.json: id is required`) + } + if spec.Version == "" { + return nil, errors.New(`devcontainer-feature.json: version is required`) + } + if spec.Name == "" { + return nil, errors.New(`devcontainer-feature.json: name is required`) + } + + spec.InstallScriptPath = installScriptPath + return spec, nil +} + +const ( + TarLayerMediaType = "application/vnd.devcontainers.layer.v1+tar" +) + +type Option struct { + Type string `json:"type"` // "boolean" or "string" + Proposals []string `json:"proposals"` + Enum []string `json:"enum"` + Default any `json:"default"` // boolean or string + Description string `json:"description"` +} + +type Spec struct { + ID string `json:"id"` + Version string `json:"version"` + Name string `json:"name"` + Description string `json:"description"` + DocumentationURL string `json:"documentationURL"` + LicenseURL string `json:"licenseURL"` + Keywords []string `json:"keywords"` + Options map[string]Option `json:"options"` + ContainerEnv map[string]string `json:"containerEnv"` + + InstallScriptPath string `json:"-"` +} + +// Extract unpacks the feature from the image and returns a set of lines +// that should be appended to a Dockerfile to install the feature. +func (s *Spec) Compile(options map[string]any) (string, error) { + // See https://containers.dev/implementors/features/#invoking-installsh + runDirective := []string{"RUN"} + for key, value := range s.Options { + strValue := fmt.Sprintf("%v", value.Default) + provided, ok := options[key] + if ok { + strValue = fmt.Sprintf("%v", provided) + // delete so we can check if there are any unknown options + delete(options, key) + } + runDirective = append(runDirective, fmt.Sprintf("%s=%s", convertOptionNameToEnv(key), strValue)) + } + if len(options) > 0 { + return "", fmt.Errorf("unknown option: %v", options) + } + runDirective = append(runDirective, s.InstallScriptPath) + + // Prefix and suffix with a newline to ensure the RUN command is on its own line. + lines := []string{"\n"} + for key, value := range s.ContainerEnv { + lines = append(lines, fmt.Sprintf("ENV %s=%s", key, value)) + } + lines = append(lines, strings.Join(runDirective, " "), "\n") + + return strings.Join(lines, "\n"), nil +} + +var ( + matchNonWords = regexp.MustCompile(`/[^\w_]/g`) + matchPrefixDigitsAndUnderscores = regexp.MustCompile(`/^[\d_]+/g`) +) + +// See https://containers.dev/implementors/features/#option-resolution +func convertOptionNameToEnv(optionName string) string { + optionName = matchNonWords.ReplaceAllString(optionName, "_") + optionName = matchPrefixDigitsAndUnderscores.ReplaceAllString(optionName, "") + return strings.ToUpper(optionName) +} diff --git a/devcontainer/features/features_test.go b/devcontainer/features/features_test.go new file mode 100644 index 00000000..33e1b030 --- /dev/null +++ b/devcontainer/features/features_test.go @@ -0,0 +1,116 @@ +package features_test + +import ( + "strings" + "testing" + + "github.com/coder/envbuilder/devcontainer/features" + "github.com/coder/envbuilder/registrytest" + "github.com/go-git/go-billy/v5/memfs" + "github.com/stretchr/testify/require" +) + +func TestExtract(t *testing.T) { + t.Parallel() + t.Run("MissingMediaType", func(t *testing.T) { + t.Parallel() + registry := registrytest.New(t) + ref := registrytest.WriteContainer(t, registry, "coder/test:latest", "some/type", nil) + fs := memfs.New() + _, err := features.Extract(fs, "/", ref) + require.ErrorContains(t, err, "no tar layer found") + }) + t.Run("MissingInstallScript", func(t *testing.T) { + t.Parallel() + registry := registrytest.New(t) + ref := registrytest.WriteContainer(t, registry, "coder/test:latest", features.TarLayerMediaType, map[string]any{ + "devcontainer-feature.json": "{}", + }) + fs := memfs.New() + _, err := features.Extract(fs, "/", ref) + require.ErrorContains(t, err, "install.sh") + }) + t.Run("MissingFeatureFile", func(t *testing.T) { + t.Parallel() + registry := registrytest.New(t) + ref := registrytest.WriteContainer(t, registry, "coder/test:latest", features.TarLayerMediaType, map[string]any{ + "install.sh": "hey", + }) + fs := memfs.New() + _, err := features.Extract(fs, "/", ref) + require.ErrorContains(t, err, "devcontainer-feature.json") + }) + t.Run("MissingFeatureProperties", func(t *testing.T) { + t.Parallel() + registry := registrytest.New(t) + ref := registrytest.WriteContainer(t, registry, "coder/test:latest", features.TarLayerMediaType, map[string]any{ + "install.sh": "hey", + "devcontainer-feature.json": features.Spec{}, + }) + fs := memfs.New() + _, err := features.Extract(fs, "/", ref) + require.ErrorContains(t, err, "id is required") + }) + t.Run("Success", func(t *testing.T) { + t.Parallel() + registry := registrytest.New(t) + ref := registrytest.WriteContainer(t, registry, "coder/test:latest", features.TarLayerMediaType, map[string]any{ + "install.sh": "hey", + "devcontainer-feature.json": features.Spec{ + ID: "go", + Version: "1.0.0", + Name: "Go", + }, + }) + fs := memfs.New() + _, err := features.Extract(fs, "/", ref) + require.NoError(t, err) + }) +} + +func TestCompile(t *testing.T) { + t.Parallel() + t.Run("UnknownOption", func(t *testing.T) { + t.Parallel() + spec := &features.Spec{} + _, err := spec.Compile(map[string]any{ + "unknown": "value", + }) + require.ErrorContains(t, err, "unknown option") + }) + t.Run("Basic", func(t *testing.T) { + t.Parallel() + spec := &features.Spec{ + InstallScriptPath: "install.sh", + } + directive, err := spec.Compile(nil) + require.NoError(t, err) + require.Equal(t, "RUN install.sh", strings.TrimSpace(directive)) + }) + t.Run("ContainerEnv", func(t *testing.T) { + t.Parallel() + spec := &features.Spec{ + InstallScriptPath: "install.sh", + ContainerEnv: map[string]string{ + "FOO": "bar", + }, + } + directive, err := spec.Compile(nil) + require.NoError(t, err) + require.Equal(t, "ENV FOO=bar\nRUN install.sh", strings.TrimSpace(directive)) + }) + t.Run("OptionsEnv", func(t *testing.T) { + t.Parallel() + spec := &features.Spec{ + InstallScriptPath: "install.sh", + Options: map[string]features.Option{ + "foo": { + Default: "bar", + }, + }, + } + directive, err := spec.Compile(nil) + require.NoError(t, err) + require.Equal(t, "RUN FOO=bar install.sh", strings.TrimSpace(directive)) + }) +} diff --git a/envbuilder.go b/envbuilder.go index a6052965..f45cd2b4 100644 --- a/envbuilder.go +++ b/envbuilder.go @@ -24,6 +24,7 @@ import ( "github.com/GoogleContainerTools/kaniko/pkg/config" "github.com/GoogleContainerTools/kaniko/pkg/executor" "github.com/coder/coder/codersdk" + "github.com/coder/envbuilder/devcontainer" "github.com/containerd/containerd/platforms" "github.com/docker/cli/cli/config/configfile" "github.com/fatih/color" @@ -255,7 +256,7 @@ func Run(ctx context.Context, options Options) error { } } - var buildParams *BuildParameters + var buildParams *devcontainer.Compiled defaultBuildParams := func() error { dockerfile := filepath.Join(MagicDir, "Dockerfile") @@ -276,7 +277,7 @@ func Run(ctx context.Context, options Options) error { if err != nil { return err } - buildParams = &BuildParameters{ + buildParams = &devcontainer.Compiled{ DockerfilePath: dockerfile, BuildContext: MagicDir, } @@ -301,7 +302,7 @@ func Run(ctx context.Context, options Options) error { if err != nil { return fmt.Errorf("read devcontainer.json: %w", err) } - devContainer, err := ParseDevcontainer(content) + devContainer, err := devcontainer.Parse(content) if err == nil { buildParams, err = devContainer.Compile(options.Filesystem, devcontainerDir, MagicDir) if err != nil { @@ -317,7 +318,7 @@ func Run(ctx context.Context, options Options) error { dockerfilePath := filepath.Join(options.WorkspaceFolder, options.DockerfilePath) _, err := options.Filesystem.Stat(dockerfilePath) if err == nil { - buildParams = &BuildParameters{ + buildParams = &devcontainer.Compiled{ DockerfilePath: dockerfilePath, BuildContext: options.WorkspaceFolder, Cache: true, @@ -356,11 +357,12 @@ func Run(ctx context.Context, options Options) error { // Cache for a week by default! CacheTTL: time.Hour * 24 * 7, }, - ForceUnpack: true, - BuildArgs: buildParams.BuildArgs, - CacheRepo: options.CacheRepo, - Cache: buildParams.Cache && options.CacheRepo != "", - DockerfilePath: buildParams.DockerfilePath, + ForceUnpack: true, + BuildArgs: buildParams.BuildArgs, + CacheRepo: options.CacheRepo, + Cache: buildParams.Cache && options.CacheRepo != "", + DockerfilePath: buildParams.DockerfilePath, + DockerfileContent: buildParams.DockerfileContent, RegistryOptions: config.RegistryOptions{ Insecure: options.Insecure, InsecurePull: options.Insecure, @@ -412,7 +414,7 @@ func Run(ctx context.Context, options Options) error { // devcontainer metadata can be persisted through a standard label devContainerMetadata, exists := configFile.Config.Labels["devcontainer.metadata"] if exists { - var devContainer []*DevContainer + var devContainer []*devcontainer.Spec err := json.Unmarshal([]byte(devContainerMetadata), &devContainer) if err != nil { return fmt.Errorf("unmarshal metadata: %w", err) @@ -565,16 +567,6 @@ func DefaultWorkspaceFolder(repoURL string) (string, error) { return fmt.Sprintf("/workspaces/%s", name[len(name)-1]), nil } -type BuildParameters struct { - DockerfilePath string - BuildContext string - BuildArgs []string - Cache bool - - User string - Env []string -} - // findUser looks up a user by name or ID. func findUser(nameOrID string) (*user.User, error) { if nameOrID == "" { diff --git a/go.mod b/go.mod index 2ef3391f..cbd6b221 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.20 // There are a few options we need added to Kaniko! // See: https://github.com/GoogleContainerTools/kaniko/compare/main...coder:kaniko:main -replace github.com/GoogleContainerTools/kaniko => github.com/coder/kaniko v0.0.0-20230406190105-1c7cb9148d0e +replace github.com/GoogleContainerTools/kaniko => github.com/coder/kaniko v0.0.0-20230630144655-c825422ea1d2 // Required to import the codersdk! replace tailscale.com => github.com/coder/tailscale v1.1.1-0.20230323204624-bf5761af4a29 @@ -26,6 +26,7 @@ require ( github.com/spf13/cobra v1.6.1 github.com/stretchr/testify v1.8.2 github.com/zeebo/assert v1.3.0 + golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 muzzammil.xyz/jsonc v1.0.0 ) @@ -238,7 +239,6 @@ require ( golang.org/x/text v0.8.0 // indirect golang.org/x/time v0.3.0 // indirect golang.org/x/tools v0.7.0 // indirect - golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 // indirect golang.zx2c4.com/wireguard/windows v0.5.3 // indirect google.golang.org/appengine v1.6.7 // indirect diff --git a/go.sum b/go.sum index f540ab77..ff13733e 100644 --- a/go.sum +++ b/go.sum @@ -241,6 +241,8 @@ github.com/coder/coder v0.22.1-0.20230410192959-81e2b2500afa h1:9o19S9sl4SlBqrwH github.com/coder/coder v0.22.1-0.20230410192959-81e2b2500afa/go.mod h1:63FrVmS8jPGx892zW2LJ3j6hqipGE6Rc4oBLPfgsTlM= github.com/coder/kaniko v0.0.0-20230406190105-1c7cb9148d0e h1:J1cV6TxuIYJuRSf3aRQsbhekQTcF1t8jUjGHojz62sE= github.com/coder/kaniko v0.0.0-20230406190105-1c7cb9148d0e/go.mod h1:9spnlHjZQmvPavDUKdrSntKEKT1Z5aROo3Vbcx1TKCk= +github.com/coder/kaniko v0.0.0-20230630144655-c825422ea1d2 h1:18QPpYBj9zVR0kzZ4dMldhFv1PiYNjp/7yljkpNeLfk= +github.com/coder/kaniko v0.0.0-20230630144655-c825422ea1d2/go.mod h1:9spnlHjZQmvPavDUKdrSntKEKT1Z5aROo3Vbcx1TKCk= github.com/coder/retry v1.3.1-0.20230210155434-e90a2e1e091d h1:09JG37IgTB6n3ouX9BXdUiibGzkGGbslFuDZO9Ru9aw= github.com/coder/retry v1.3.1-0.20230210155434-e90a2e1e091d/go.mod h1:r+1J5i/989wt6CUeNSuvFKKA9hHuKKPMxdzDbTuvwwk= github.com/coder/tailscale v1.1.1-0.20230323204624-bf5761af4a29 h1:bZAOib5uT7ohTYcKKj8w5jH+HwBStBrZ/KcU26X0g+A= diff --git a/integration/integration_test.go b/integration/integration_test.go index 0b52fc62..1195918e 100644 --- a/integration/integration_test.go +++ b/integration/integration_test.go @@ -20,7 +20,9 @@ import ( "time" "github.com/coder/envbuilder" + "github.com/coder/envbuilder/devcontainer/features" "github.com/coder/envbuilder/gittest" + "github.com/coder/envbuilder/registrytest" clitypes "github.com/docker/cli/cli/config/types" "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/container" @@ -74,6 +76,50 @@ func TestSucceedsGitAuth(t *testing.T) { require.NoError(t, err) } +func TestBuildFromDevcontainerWithFeatures(t *testing.T) { + t.Parallel() + + registry := registrytest.New(t) + ref := registrytest.WriteContainer(t, registry, "coder/test:latest", features.TarLayerMediaType, map[string]any{ + "devcontainer-feature.json": &features.Spec{ + ID: "test", + Name: "test", + Version: "1.0.0", + Options: map[string]features.Option{ + "bananas": { + Type: "string", + }, + }, + }, + "install.sh": "echo $BANANAS > /test", + }) + + // Ensures that a Git repository with a devcontainer.json is cloned and built. + url := createGitServer(t, gitServerOptions{ + files: map[string]string{ + ".devcontainer/devcontainer.json": `{ + "name": "Test", + "build": { + "dockerfile": "Dockerfile" + }, + "features": { + "` + ref + `": { + "bananas": "hello" + } + } + }`, + ".devcontainer/Dockerfile": "FROM ubuntu", + }, + }) + ctr, err := runEnvbuilder(t, []string{ + "GIT_URL=" + url, + }) + require.NoError(t, err) + + output := execContainer(t, ctr, "cat /test") + require.Equal(t, "hello", strings.TrimSpace(output)) +} + func TestBuildFromDockerfile(t *testing.T) { // Ensures that a Git repository with a Dockerfile is cloned and built. url := createGitServer(t, gitServerOptions{ diff --git a/registrytest/registrytest.go b/registrytest/registrytest.go new file mode 100644 index 00000000..e835b324 --- /dev/null +++ b/registrytest/registrytest.go @@ -0,0 +1,120 @@ +package registrytest + +import ( + "archive/tar" + "bytes" + "crypto" + "encoding/hex" + "encoding/json" + "io" + "log" + "net/http/httptest" + "net/url" + "strings" + "testing" + "time" + + "github.com/google/go-containerregistry/pkg/name" + "github.com/google/go-containerregistry/pkg/registry" + v1 "github.com/google/go-containerregistry/pkg/v1" + "github.com/google/go-containerregistry/pkg/v1/empty" + "github.com/google/go-containerregistry/pkg/v1/mutate" + "github.com/google/go-containerregistry/pkg/v1/partial" + "github.com/google/go-containerregistry/pkg/v1/remote" + "github.com/google/go-containerregistry/pkg/v1/types" + "github.com/stretchr/testify/require" +) + +// New creates a new registry server that discards all logs. +func New(t *testing.T) string { + srv := httptest.NewServer(registry.New(registry.Logger(log.New(io.Discard, "", 0)))) + t.Cleanup(srv.Close) + return srv.URL +} + +// WriteContainer uploads a container to the registry server. +// It returns the reference to the uploaded container. +func WriteContainer(t *testing.T, serverURL, containerRef, mediaType string, files map[string]any) string { + var buf bytes.Buffer + hasher := crypto.SHA256.New() + mw := io.MultiWriter(&buf, hasher) + wtr := tar.NewWriter(mw) + for name, content := range files { + var data []byte + switch content := content.(type) { + case string: + data = []byte(content) + case []byte: + data = content + default: + var err error + data, err = json.Marshal(content) + require.NoError(t, err) + } + err := wtr.WriteHeader(&tar.Header{ + Mode: 0777, + Name: name, + Typeflag: tar.TypeReg, + Size: int64(len(data)), + }) + require.NoError(t, err) + _, err = wtr.Write(data) + require.NoError(t, err) + } + + h := v1.Hash{ + Algorithm: "sha256", + Hex: hex.EncodeToString(hasher.Sum(make([]byte, 0, hasher.Size()))), + } + layer, err := partial.UncompressedToLayer(&uncompressedLayer{ + diffID: h, + mediaType: types.MediaType(mediaType), + content: buf.Bytes(), + }) + require.NoError(t, err) + + image, err := mutate.Append(empty.Image, mutate.Addendum{ + Layer: layer, + History: v1.History{ + Author: "registrytest", + Created: v1.Time{Time: time.Now()}, + Comment: "created by the registrytest package", + CreatedBy: "registrytest", + }, + }) + require.NoError(t, err) + + parsed, err := url.Parse(serverURL) + require.NoError(t, err) + parsed.Path = containerRef + + ref, err := name.ParseReference(strings.TrimPrefix(parsed.String(), "http://")) + require.NoError(t, err) + + err = remote.Write(ref, image) + require.NoError(t, err) + + return ref.String() +} + +// uncompressedLayer implements partial.UncompressedLayer from raw bytes. +type uncompressedLayer struct { + diffID v1.Hash + mediaType types.MediaType + content []byte +} + +// DiffID implements partial.UncompressedLayer +func (ul *uncompressedLayer) DiffID() (v1.Hash, error) { + return ul.diffID, nil +} + +// Uncompressed implements partial.UncompressedLayer +func (ul *uncompressedLayer) Uncompressed() (io.ReadCloser, error) { + return io.NopCloser(bytes.NewBuffer(ul.content)), nil +} + +// MediaType returns the media type of the layer +func (ul *uncompressedLayer) MediaType() (types.MediaType, error) { + return ul.mediaType, nil +} From d0c29c19610dbe2134e3dd03946656616c7f4a33 Mon Sep 17 00:00:00 2001 From: Kyle Carberry Date: Fri, 30 Jun 2023 10:49:54 -0500 Subject: [PATCH 2/8] Add support for fetching the present user --- devcontainer/devcontainer.go | 96 ++++++++++++++++++++++--------- devcontainer/devcontainer_test.go | 58 +++++++++++++++++++ 2 files changed, 127 insertions(+), 27 deletions(-) diff --git a/devcontainer/devcontainer.go b/devcontainer/devcontainer.go index 8611fbf9..9fb7328a 100644 --- a/devcontainer/devcontainer.go +++ b/devcontainer/devcontainer.go @@ -1,7 +1,6 @@ package devcontainer import ( - "bufio" "crypto/md5" "fmt" "io" @@ -9,8 +8,11 @@ import ( "path/filepath" "strings" + "github.com/GoogleContainerTools/kaniko/pkg/creds" "github.com/coder/envbuilder/devcontainer/features" "github.com/go-git/go-billy/v5" + "github.com/google/go-containerregistry/pkg/name" + "github.com/google/go-containerregistry/pkg/v1/remote" "muzzammil.xyz/jsonc" ) @@ -112,37 +114,36 @@ func (s *Spec) Compile(fs billy.Filesystem, devcontainerDir, scratchDir string) } params.DockerfileContent = string(dockerfileContent) - // If we don't have a user provided, we look for the latest USER directive - // in the Dockerfile. This is what devcontainers/cli does. if params.User == "" { - reader := bufio.NewScanner(strings.NewReader(params.DockerfileContent)) - for reader.Scan() { - line := reader.Text() - if !strings.HasPrefix(line, "USER ") { - continue - } - params.User = strings.TrimPrefix(line, "USER ") - break - } + // We should make a best-effort attempt to find the user. + // Features must be executed as root, so we need to swap back + // to the running user afterwards. + params.User = UserFromDockerfile(params.DockerfileContent) } - - if len(s.Features) > 0 { - featuresDir := filepath.Join(scratchDir, "features") - err := fs.MkdirAll(featuresDir, 0644) + if params.User == "" { + image := ImageFromDockerfile(params.DockerfileContent) + imageRef, err := name.ParseReference(image) if err != nil { - return nil, fmt.Errorf("create features directory: %w", err) + return nil, fmt.Errorf("parse image from dockerfile %q: %w", image, err) } - params.DockerfileContent, err = s.appendFeaturesToDockerfile(fs, scratchDir, params) + params.User, err = UserFromImage(imageRef) if err != nil { - return nil, err + return nil, fmt.Errorf("get user from image %q: %w", image, err) } - - fmt.Printf("Content: %s\n", params.DockerfileContent) + } + params.DockerfileContent, err = s.compileFeatures(fs, scratchDir, params.User, params.DockerfileContent) + if err != nil { + return nil, err } return params, nil } -func (s *Spec) appendFeaturesToDockerfile(fs billy.Filesystem, scratchDir string, params *Compiled) (string, error) { +func (s *Spec) compileFeatures(fs billy.Filesystem, scratchDir, remoteUser, dockerfileContent string) (string, error) { + // If there are no features, we don't need to do anything! + if len(s.Features) == 0 { + return dockerfileContent, nil + } + featuresDir := filepath.Join(scratchDir, "features") err := fs.MkdirAll(featuresDir, 0644) if err != nil { @@ -175,13 +176,54 @@ func (s *Spec) appendFeaturesToDockerfile(fs billy.Filesystem, scratchDir string lines := []string{"\nUSER root"} lines = append(lines, featureDirectives...) - if params.User != "" { - // TODO: We should warn! - lines = append(lines, fmt.Sprintf("USER %s", params.User)) + if remoteUser != "" { + // TODO: We should warn that because we were unable to find the remote user, + // we're going to run as root. + lines = append(lines, fmt.Sprintf("USER %s", remoteUser)) } - return strings.Join(append([]string{params.DockerfileContent}, lines...), "\n"), err + return strings.Join(append([]string{dockerfileContent}, lines...), "\n"), err } -func (s *Spec) User() { +// UserFromDockerfile inspects the contents of a provided Dockerfile +// and returns the user that will be used to run the container. +func UserFromDockerfile(dockerfileContent string) string { + lines := strings.Split(dockerfileContent, "\n") + // Iterate over lines in reverse + for i := len(lines) - 1; i >= 0; i-- { + line := lines[i] + if !strings.HasPrefix(line, "USER ") { + continue + } + return strings.TrimSpace(strings.TrimPrefix(line, "USER ")) + } + return "" +} + +// ImageFromDockerfile inspects the contents of a provided Dockerfile +// and returns the image that will be used to run the container. +func ImageFromDockerfile(dockerfileContent string) string { + lines := strings.Split(dockerfileContent, "\n") + // Iterate over lines in reverse + for i := len(lines) - 1; i >= 0; i-- { + line := lines[i] + if !strings.HasPrefix(line, "FROM ") { + continue + } + return strings.TrimSpace(strings.TrimPrefix(line, "FROM ")) + } + return "" +} +// UserFromImage inspects the remote reference and returns the user +// that will be used to run the container. +func UserFromImage(ref name.Reference) (string, error) { + image, err := remote.Image(ref, remote.WithAuthFromKeychain(creds.GetKeychain())) + if err != nil { + return "", fmt.Errorf("fetch image %s: %w", ref.Name(), err) + } + config, err := image.ConfigFile() + if err != nil { + return "", fmt.Errorf("fetch config %s: %w", ref.Name(), err) + } + return config.Config.User, nil } diff --git a/devcontainer/devcontainer_test.go b/devcontainer/devcontainer_test.go index c7f4d9b2..707f0b50 100644 --- a/devcontainer/devcontainer_test.go +++ b/devcontainer/devcontainer_test.go @@ -1,12 +1,21 @@ package devcontainer_test import ( + "fmt" + "net/url" "path/filepath" + "strings" "testing" "github.com/coder/envbuilder" "github.com/coder/envbuilder/devcontainer" + "github.com/coder/envbuilder/registrytest" "github.com/go-git/go-billy/v5/memfs" + "github.com/google/go-containerregistry/pkg/name" + v1 "github.com/google/go-containerregistry/pkg/v1" + "github.com/google/go-containerregistry/pkg/v1/partial" + "github.com/google/go-containerregistry/pkg/v1/remote" + "github.com/google/go-containerregistry/pkg/v1/types" "github.com/stretchr/testify/require" ) @@ -60,3 +69,52 @@ func TestCompileDevContainer(t *testing.T) { require.Equal(t, dcDir, params.BuildContext) }) } + +func TestUserFromDockerfile(t *testing.T) { + t.Parallel() + user := devcontainer.UserFromDockerfile("FROM ubuntu\nUSER kyle") + require.Equal(t, "kyle", user) +} + +func TestUserFromImage(t *testing.T) { + t.Parallel() + registry := registrytest.New(t) + image, err := partial.UncompressedToImage(emptyImage{configFile: &v1.ConfigFile{ + Config: v1.Config{ + User: "example", + }, + }}) + require.NoError(t, err) + + parsed, err := url.Parse(registry) + require.NoError(t, err) + parsed.Path = "coder/test:latest" + ref, err := name.ParseReference(strings.TrimPrefix(parsed.String(), "http://")) + require.NoError(t, err) + err = remote.Write(ref, image) + require.NoError(t, err) + + user, err := devcontainer.UserFromImage(ref) + require.NoError(t, err) + require.Equal(t, "example", user) +} + +type emptyImage struct { + configFile *v1.ConfigFile +} + +func (i emptyImage) MediaType() (types.MediaType, error) { + return types.DockerManifestSchema2, nil +} + +func (i emptyImage) RawConfigFile() ([]byte, error) { + return partial.RawConfigFile(i) +} + +func (i emptyImage) ConfigFile() (*v1.ConfigFile, error) { + return i.configFile, nil +} + +func (i emptyImage) LayerByDiffID(h v1.Hash) (partial.UncompressedLayer, error) { + return nil, fmt.Errorf("LayerByDiffID(%s): empty image", h) +} From b2f516404612f36878937aff7d8c4d9d55b7d011 Mon Sep 17 00:00:00 2001 From: Kyle Carberry Date: Fri, 30 Jun 2023 11:39:55 -0500 Subject: [PATCH 3/8] Remove unused cache property --- devcontainer/devcontainer.go | 2 -- envbuilder.go | 13 +++++++++---- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/devcontainer/devcontainer.go b/devcontainer/devcontainer.go index 9fb7328a..d03899ad 100644 --- a/devcontainer/devcontainer.go +++ b/devcontainer/devcontainer.go @@ -50,7 +50,6 @@ type Compiled struct { DockerfileContent string BuildContext string BuildArgs []string - Cache bool User string Env []string @@ -90,7 +89,6 @@ func (s *Spec) Compile(fs billy.Filesystem, devcontainerDir, scratchDir string) buildArgs = append(buildArgs, key+"="+value) } params.BuildArgs = buildArgs - params.Cache = true // Deprecated values! if s.Dockerfile != "" { diff --git a/envbuilder.go b/envbuilder.go index f45cd2b4..1e2c515f 100644 --- a/envbuilder.go +++ b/envbuilder.go @@ -30,7 +30,7 @@ import ( "github.com/fatih/color" "github.com/go-git/go-billy/v5" "github.com/go-git/go-billy/v5/osfs" - "github.com/go-git/go-git/v5/plumbing/transport/http" + githttp "github.com/go-git/go-git/v5/plumbing/transport/http" v1 "github.com/google/go-containerregistry/pkg/v1" "github.com/mattn/go-isatty" "github.com/sirupsen/logrus" @@ -65,6 +65,11 @@ type Options struct { // will not be pushed. CacheRepo string `env:"CACHE_REPO"` + // CacheDir is the path to the directory where the cache + // will be stored. If this is empty, the cache will not + // be used. + CacheDir string `env:"CACHE_DIR"` + // DockerfilePath is a relative path to the workspace // folder that will be used to build the workspace. // This is an alternative to using a devcontainer @@ -236,7 +241,7 @@ func Run(ctx context.Context, options Options) error { RepoURL: options.GitURL, Insecure: options.Insecure, Progress: writer, - RepoAuth: &http.BasicAuth{ + RepoAuth: &githttp.BasicAuth{ Username: options.GitUsername, Password: options.GitPassword, }, @@ -321,7 +326,6 @@ func Run(ctx context.Context, options Options) error { buildParams = &devcontainer.Compiled{ DockerfilePath: dockerfilePath, BuildContext: options.WorkspaceFolder, - Cache: true, } } } @@ -356,11 +360,12 @@ func Run(ctx context.Context, options Options) error { CacheOptions: config.CacheOptions{ // Cache for a week by default! CacheTTL: time.Hour * 24 * 7, + CacheDir: options.CacheDir, }, ForceUnpack: true, BuildArgs: buildParams.BuildArgs, CacheRepo: options.CacheRepo, - Cache: buildParams.Cache && options.CacheRepo != "", + Cache: true, DockerfilePath: buildParams.DockerfilePath, DockerfileContent: buildParams.DockerfileContent, RegistryOptions: config.RegistryOptions{ From db959e3c128a5b88d0c81bc4f1b637ba4ce062ac Mon Sep 17 00:00:00 2001 From: Kyle Carberry Date: Fri, 30 Jun 2023 11:41:58 -0500 Subject: [PATCH 4/8] Fix chmod --- devcontainer/features/features.go | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/devcontainer/features/features.go b/devcontainer/features/features.go index c5cc5d81..3a9dc68f 100644 --- a/devcontainer/features/features.go +++ b/devcontainer/features/features.go @@ -93,11 +93,13 @@ func Extract(fs billy.Filesystem, directory, reference string) (*Spec, error) { } return nil, fmt.Errorf("stat install.sh: %w", err) } - err = os.Chmod(installScriptPath, 0755) - if err != nil { - return nil, fmt.Errorf("chmod install.sh: %w", err) + changer, ok := fs.(billy.Change) + if ok { + err = changer.Chmod(installScriptPath, 0755) + if err != nil { + return nil, fmt.Errorf("chmod install.sh: %w", err) + } } - featureFile, err := fs.Open(filepath.Join(directory, "devcontainer-feature.json")) if err != nil { if errors.Is(err, os.ErrNotExist) { From 434d9659a00195867fe0801df07e35fb7088ea11 Mon Sep 17 00:00:00 2001 From: Kyle Carberry Date: Fri, 30 Jun 2023 13:26:56 -0500 Subject: [PATCH 5/8] Fix chmod again --- devcontainer/features/features.go | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/devcontainer/features/features.go b/devcontainer/features/features.go index 3a9dc68f..9812d970 100644 --- a/devcontainer/features/features.go +++ b/devcontainer/features/features.go @@ -96,9 +96,13 @@ func Extract(fs billy.Filesystem, directory, reference string) (*Spec, error) { changer, ok := fs.(billy.Change) if ok { err = changer.Chmod(installScriptPath, 0755) - if err != nil { - return nil, fmt.Errorf("chmod install.sh: %w", err) - } + } else { + // For some reason the filesystem abstraction doesn't support chmod. + // https://github.com/src-d/go-billy/issues/56 + err = os.Chmod(installScriptPath, 0755) + } + if err != nil { + return nil, fmt.Errorf("chmod install.sh: %w", err) } featureFile, err := fs.Open(filepath.Join(directory, "devcontainer-feature.json")) if err != nil { From 837ed6a26a8622fa5041d242a44d27d7cca34a8f Mon Sep 17 00:00:00 2001 From: Kyle Carberry Date: Fri, 30 Jun 2023 13:41:53 -0500 Subject: [PATCH 6/8] Fix tests --- devcontainer/devcontainer.go | 26 +++++++++++++------------- devcontainer/devcontainer_test.go | 7 +++++++ devcontainer/features/features.go | 8 ++++---- envbuilder.go | 10 +++++++++- 4 files changed, 33 insertions(+), 18 deletions(-) diff --git a/devcontainer/devcontainer.go b/devcontainer/devcontainer.go index d03899ad..1ae5f3d3 100644 --- a/devcontainer/devcontainer.go +++ b/devcontainer/devcontainer.go @@ -74,7 +74,7 @@ func (s *Spec) Compile(fs billy.Filesystem, devcontainerDir, scratchDir string) dockerfilePath := filepath.Join(scratchDir, "Dockerfile") file, err := fs.OpenFile(dockerfilePath, os.O_CREATE|os.O_WRONLY, 0644) if err != nil { - return nil, err + return nil, fmt.Errorf("open dockerfile: %w", err) } defer file.Close() _, err = file.Write([]byte("FROM " + s.Image)) @@ -83,6 +83,17 @@ func (s *Spec) Compile(fs billy.Filesystem, devcontainerDir, scratchDir string) } params.DockerfilePath = dockerfilePath params.BuildContext = scratchDir + } else { + // Deprecated values! + if s.Dockerfile != "" { + s.Build.Dockerfile = s.Dockerfile + } + if s.Context != "" { + s.Build.Context = s.Context + } + + params.DockerfilePath = filepath.Join(devcontainerDir, s.Build.Dockerfile) + params.BuildContext = filepath.Join(devcontainerDir, s.Build.Context) } buildArgs := make([]string, 0) for key, value := range s.Build.Args { @@ -90,20 +101,9 @@ func (s *Spec) Compile(fs billy.Filesystem, devcontainerDir, scratchDir string) } params.BuildArgs = buildArgs - // Deprecated values! - if s.Dockerfile != "" { - s.Build.Dockerfile = s.Dockerfile - } - if s.Context != "" { - s.Build.Context = s.Context - } - - params.DockerfilePath = filepath.Join(devcontainerDir, s.Build.Dockerfile) - params.BuildContext = filepath.Join(devcontainerDir, s.Build.Context) - dockerfile, err := fs.Open(params.DockerfilePath) if err != nil { - return nil, err + return nil, fmt.Errorf("open dockerfile %q: %w", params.DockerfilePath, err) } defer dockerfile.Close() dockerfileContent, err := io.ReadAll(dockerfile) diff --git a/devcontainer/devcontainer_test.go b/devcontainer/devcontainer_test.go index 707f0b50..c19dfd96 100644 --- a/devcontainer/devcontainer_test.go +++ b/devcontainer/devcontainer_test.go @@ -2,7 +2,9 @@ package devcontainer_test import ( "fmt" + "io" "net/url" + "os" "path/filepath" "strings" "testing" @@ -62,6 +64,11 @@ func TestCompileDevContainer(t *testing.T) { dcDir := "/workspaces/coder/.devcontainer" err := fs.MkdirAll(dcDir, 0755) require.NoError(t, err) + file, err := fs.OpenFile(filepath.Join(dcDir, "Dockerfile"), os.O_CREATE|os.O_WRONLY, 0644) + require.NoError(t, err) + _, err = io.WriteString(file, "FROM ubuntu") + require.NoError(t, err) + _ = file.Close() params, err := dc.Compile(fs, dcDir, envbuilder.MagicDir) require.NoError(t, err) require.Equal(t, "ARG1=value1", params.BuildArgs[0]) diff --git a/devcontainer/features/features.go b/devcontainer/features/features.go index 9812d970..70e4435c 100644 --- a/devcontainer/features/features.go +++ b/devcontainer/features/features.go @@ -93,13 +93,13 @@ func Extract(fs billy.Filesystem, directory, reference string) (*Spec, error) { } return nil, fmt.Errorf("stat install.sh: %w", err) } - changer, ok := fs.(billy.Change) + chmodder, ok := fs.(interface { + Chmod(name string, mode os.FileMode) error + }) if ok { - err = changer.Chmod(installScriptPath, 0755) - } else { // For some reason the filesystem abstraction doesn't support chmod. // https://github.com/src-d/go-billy/issues/56 - err = os.Chmod(installScriptPath, 0755) + err = chmodder.Chmod(installScriptPath, 0755) } if err != nil { return nil, fmt.Errorf("chmod install.sh: %w", err) diff --git a/envbuilder.go b/envbuilder.go index 1e2c515f..7ccad373 100644 --- a/envbuilder.go +++ b/envbuilder.go @@ -141,7 +141,7 @@ func Run(ctx context.Context, options Options) error { options.InitScript = "sleep infinity" } if options.Filesystem == nil { - options.Filesystem = osfs.New("/") + options.Filesystem = &osfsWithChmod{osfs.New("/")} } if options.WorkspaceFolder == "" { var err error @@ -654,3 +654,11 @@ func newColor(value ...color.Attribute) *color.Color { c.EnableColor() return c } + +type osfsWithChmod struct { + billy.Filesystem +} + +func (fs *osfsWithChmod) Chmod(name string, mode os.FileMode) error { + return os.Chmod(name, mode) +} From 4301f526336a9b92ad617488f7008baa034d7368 Mon Sep 17 00:00:00 2001 From: Kyle Carberry Date: Fri, 30 Jun 2023 13:42:10 -0500 Subject: [PATCH 7/8] Remove pull request step --- .github/workflows/ci.yaml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index e973a751..37a8de3c 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -3,8 +3,6 @@ name: ci on: push: - pull_request: - workflow_dispatch: permissions: From ecbf17eb27bd110d57b285e2372011d23d4b1cad Mon Sep 17 00:00:00 2001 From: Kyle Carberry Date: Fri, 30 Jun 2023 13:56:19 -0500 Subject: [PATCH 8/8] Use agentsdk log sending --- cmd/envbuilder/main.go | 17 +++---- go.mod | 83 ++++++++++++++++-------------- go.sum | 113 +++++++++++++++++++++++++++++++++++++++++ log.go | 108 --------------------------------------- log_test.go | 32 ------------ 5 files changed, 164 insertions(+), 189 deletions(-) diff --git a/cmd/envbuilder/main.go b/cmd/envbuilder/main.go index 7f00d530..5ad2f458 100644 --- a/cmd/envbuilder/main.go +++ b/cmd/envbuilder/main.go @@ -1,6 +1,7 @@ package main import ( + "context" "crypto/tls" "errors" "fmt" @@ -9,6 +10,7 @@ import ( "os" "time" + "cdr.dev/slog" "github.com/coder/coder/codersdk" "github.com/coder/coder/codersdk/agentsdk" "github.com/coder/envbuilder" @@ -30,7 +32,7 @@ func main() { RunE: func(cmd *cobra.Command, args []string) error { options := envbuilder.OptionsFromEnv(os.Getenv) - var sendLogs func(log agentsdk.StartupLog) + var sendLogs func(ctx context.Context, log ...agentsdk.StartupLog) error agentURL := os.Getenv("CODER_AGENT_URL") agentToken := os.Getenv("CODER_AGENT_TOKEN") if agentToken != "" { @@ -50,21 +52,16 @@ func main() { }, }, } - var flushAndClose func() - sendLogs, flushAndClose, err = envbuilder.SendLogsToCoder(cmd.Context(), client, func(format string, args ...any) { - fmt.Fprintf(cmd.ErrOrStderr(), format, args...) - }) - if err != nil { - return err - } - defer flushAndClose() + var flushAndClose func(ctx context.Context) error + sendLogs, flushAndClose = agentsdk.StartupLogsSender(client.PatchStartupLogs, slog.Logger{}) + defer flushAndClose(cmd.Context()) } options.Logger = func(level codersdk.LogLevel, format string, args ...interface{}) { output := fmt.Sprintf(format, args...) fmt.Fprintln(cmd.ErrOrStderr(), output) if sendLogs != nil { - sendLogs(agentsdk.StartupLog{ + sendLogs(cmd.Context(), agentsdk.StartupLog{ CreatedAt: time.Now(), Output: output, Level: level, diff --git a/go.mod b/go.mod index cbd6b221..caf101df 100644 --- a/go.mod +++ b/go.mod @@ -7,13 +7,13 @@ go 1.20 replace github.com/GoogleContainerTools/kaniko => github.com/coder/kaniko v0.0.0-20230630144655-c825422ea1d2 // Required to import the codersdk! -replace tailscale.com => github.com/coder/tailscale v1.1.1-0.20230323204624-bf5761af4a29 +replace tailscale.com => github.com/coder/tailscale v0.0.0-20230522123520-74712221d00f require ( github.com/GoogleContainerTools/kaniko v1.9.2 github.com/breml/rootcerts v0.2.10 - github.com/coder/coder v0.22.1-0.20230410192959-81e2b2500afa - github.com/coder/retry v1.3.1-0.20230210155434-e90a2e1e091d + github.com/coder/coder v0.24.2-0.20230630184129-6015319e9d30 + github.com/coder/retry v1.4.0 github.com/containerd/containerd v1.7.0 github.com/docker/cli v23.0.1+incompatible github.com/docker/docker v23.0.3+incompatible @@ -21,22 +21,22 @@ require ( github.com/go-git/go-billy/v5 v5.4.1 github.com/go-git/go-git/v5 v5.6.1 github.com/google/go-containerregistry v0.14.0 - github.com/mattn/go-isatty v0.0.17 - github.com/sirupsen/logrus v1.9.0 + github.com/mattn/go-isatty v0.0.19 + github.com/sirupsen/logrus v1.9.2 github.com/spf13/cobra v1.6.1 - github.com/stretchr/testify v1.8.2 + github.com/stretchr/testify v1.8.4 github.com/zeebo/assert v1.3.0 golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 muzzammil.xyz/jsonc v1.0.0 ) require ( - cdr.dev/slog v1.4.2 // indirect - cloud.google.com/go/compute v1.18.0 // indirect + cdr.dev/slog v1.5.4 // indirect + cloud.google.com/go/compute v1.19.3 // indirect cloud.google.com/go/compute/metadata v0.2.3 // indirect filippo.io/edwards25519 v1.0.0-rc.1 // indirect github.com/Azure/azure-sdk-for-go v61.3.0+incompatible // indirect - github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect + github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // indirect github.com/Azure/go-autorest v14.2.0+incompatible // indirect github.com/Azure/go-autorest/autorest v0.11.28 // indirect github.com/Azure/go-autorest/autorest/adal v0.9.23 // indirect @@ -45,7 +45,7 @@ require ( github.com/Azure/go-autorest/autorest/date v0.3.0 // indirect github.com/Azure/go-autorest/logger v0.2.1 // indirect github.com/Azure/go-autorest/tracing v0.6.0 // indirect - github.com/Microsoft/go-winio v0.6.0 // indirect + github.com/Microsoft/go-winio v0.6.1 // indirect github.com/OneOfOne/xxhash v1.2.8 // indirect github.com/ProtonMail/go-crypto v0.0.0-20230217124315-7d5c6f04bbb8 // indirect github.com/acomagu/bufpipe v1.0.4 // indirect @@ -53,7 +53,9 @@ require ( github.com/agnivade/levenshtein v1.1.1 // indirect github.com/akutz/memconn v0.1.0 // indirect github.com/alexbrainman/sspi v0.0.0-20210105120005-909beea2cc74 // indirect + github.com/ammario/tlru v0.3.0 // indirect github.com/apparentlymart/go-textseg/v13 v13.0.0 // indirect + github.com/armon/go-radix v1.0.0 // indirect github.com/aws/aws-sdk-go-v2 v1.17.3 // indirect github.com/aws/aws-sdk-go-v2/config v1.15.5 // indirect github.com/aws/aws-sdk-go-v2/credentials v1.12.0 // indirect @@ -73,15 +75,15 @@ require ( github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/chrismellard/docker-credential-acr-env v0.0.0-20230304212654-82a0ddb27589 // indirect github.com/cilium/ebpf v0.9.1 // indirect - github.com/cloudflare/circl v1.1.0 // indirect - github.com/coder/terraform-provider-coder v0.6.23 // indirect + github.com/cloudflare/circl v1.3.3 // indirect + github.com/coder/terraform-provider-coder v0.9.0 // indirect github.com/containerd/cgroups v1.1.0 // indirect github.com/containerd/continuity v0.3.0 // indirect github.com/containerd/fifo v1.1.0 // indirect github.com/containerd/stargz-snapshotter/estargz v0.14.3 // indirect github.com/containerd/typeurl v1.0.2 // indirect github.com/coreos/go-iptables v0.6.0 // indirect - github.com/coreos/go-oidc/v3 v3.4.0 // indirect + github.com/coreos/go-oidc/v3 v3.6.0 // indirect github.com/coreos/go-systemd/v22 v22.5.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/dimchansky/utfbom v1.1.1 // indirect @@ -95,16 +97,17 @@ require ( github.com/emirpasic/gods v1.18.1 // indirect github.com/fxamacker/cbor/v2 v2.4.0 // indirect github.com/ghodss/yaml v1.0.0 // indirect - github.com/go-chi/chi/v5 v5.0.7 // indirect + github.com/go-chi/chi/v5 v5.0.8 // indirect github.com/go-git/gcfg v1.5.0 // indirect - github.com/go-logr/logr v1.2.3 // indirect + github.com/go-jose/go-jose/v3 v3.0.0 // indirect + github.com/go-logr/logr v1.2.4 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-ole/go-ole v1.2.6 // indirect github.com/gobwas/glob v0.2.3 // indirect github.com/godbus/dbus/v5 v5.1.0 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang-jwt/jwt/v4 v4.5.0 // indirect - github.com/golang/glog v1.0.0 // indirect + github.com/golang/glog v1.1.0 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.3 // indirect github.com/google/btree v1.1.2 // indirect @@ -121,12 +124,12 @@ require ( github.com/hashicorp/go-version v1.6.0 // indirect github.com/hashicorp/golang-lru v0.5.4 // indirect github.com/hashicorp/golang-lru/v2 v2.0.1 // indirect - github.com/hashicorp/hcl/v2 v2.14.0 // indirect + github.com/hashicorp/hcl/v2 v2.17.0 // indirect github.com/hashicorp/logutils v1.0.0 // indirect github.com/hashicorp/terraform-plugin-go v0.12.0 // indirect github.com/hashicorp/terraform-plugin-log v0.7.0 // indirect github.com/hashicorp/terraform-plugin-sdk/v2 v2.20.0 // indirect - github.com/hashicorp/yamux v0.0.0-20220718163420-dd80a7ee44ce // indirect + github.com/hashicorp/yamux v0.1.1 // indirect github.com/hdevalence/ed25519consensus v0.0.0-20220222234857-c00d1f31bab3 // indirect github.com/illarion/gonotify v1.0.1 // indirect github.com/imdario/mergo v0.3.13 // indirect @@ -166,11 +169,11 @@ require ( github.com/moby/sys/sequential v0.5.0 // indirect github.com/moby/sys/signal v0.7.0 // indirect github.com/moby/sys/symlink v0.2.0 // indirect - github.com/moby/term v0.0.0-20221120202655-abb19827d345 // indirect + github.com/moby/term v0.5.0 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/morikuni/aec v1.0.0 // indirect - github.com/open-policy-agent/opa v0.44.0 // indirect + github.com/open-policy-agent/opa v0.51.0 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/image-spec v1.1.0-rc2.0.20221005185240-3a7f492d3f1b // indirect github.com/opencontainers/runc v1.1.5 // indirect @@ -180,15 +183,15 @@ require ( github.com/pjbgf/sha1cd v0.3.0 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/prometheus/client_golang v1.14.0 // indirect + github.com/prometheus/client_golang v1.15.1 // indirect github.com/prometheus/client_model v0.3.0 // indirect - github.com/prometheus/common v0.40.0 // indirect + github.com/prometheus/common v0.42.0 // indirect github.com/prometheus/procfs v0.9.0 // indirect github.com/rcrowley/go-metrics v0.0.0-20200313005456-10cdbea86bc0 // indirect github.com/rootless-containers/rootlesskit v1.1.0 // indirect github.com/sergi/go-diff v1.3.1 // indirect github.com/skeema/knownhosts v1.1.0 // indirect - github.com/spf13/afero v1.9.3 // indirect + github.com/spf13/afero v1.9.5 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/tabbed/pqtype v0.1.1 // indirect github.com/tailscale/certstore v0.1.1-0.20220316223106-78d6e1c49d8d // indirect @@ -200,7 +203,7 @@ require ( github.com/tcnksm/go-httpstat v0.2.0 // indirect github.com/tonistiigi/fsutil v0.0.0-20230105215944-fb433841cbfa // indirect github.com/u-root/uio v0.0.0-20221213070652-c3537552635f // indirect - github.com/valyala/fasthttp v1.44.0 // indirect + github.com/valyala/fasthttp v1.48.0 // indirect github.com/vbatts/tar-split v0.11.2 // indirect github.com/vishvananda/netlink v1.2.1-beta.2 // indirect github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 // indirect @@ -212,7 +215,7 @@ require ( github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect github.com/yashtewari/glob-intersection v0.1.0 // indirect - github.com/zclconf/go-cty v1.10.0 // indirect + github.com/zclconf/go-cty v1.13.2 // indirect github.com/zeebo/errs v1.3.0 // indirect go.etcd.io/etcd/raft/v3 v3.5.6 // indirect go.nhat.io/otelsql v0.9.0 // indirect @@ -228,23 +231,25 @@ require ( go.opentelemetry.io/proto/otlp v0.19.0 // indirect go4.org/mem v0.0.0-20210711025021-927187094b94 // indirect go4.org/netipx v0.0.0-20220725152314-7e7bdc8411bf // indirect - golang.org/x/crypto v0.7.0 // indirect - golang.org/x/exp v0.0.0-20221205204356-47842c84f3db // indirect - golang.org/x/mod v0.9.0 // indirect - golang.org/x/net v0.8.0 // indirect - golang.org/x/oauth2 v0.6.0 // indirect - golang.org/x/sync v0.1.0 // indirect - golang.org/x/sys v0.6.0 // indirect - golang.org/x/term v0.6.0 // indirect - golang.org/x/text v0.8.0 // indirect + golang.org/x/crypto v0.10.0 // indirect + golang.org/x/exp v0.0.0-20230315142452-642cacee5cc0 // indirect + golang.org/x/mod v0.11.0 // indirect + golang.org/x/net v0.11.0 // indirect + golang.org/x/oauth2 v0.9.0 // indirect + golang.org/x/sync v0.3.0 // indirect + golang.org/x/sys v0.9.0 // indirect + golang.org/x/term v0.9.0 // indirect + golang.org/x/text v0.10.0 // indirect golang.org/x/time v0.3.0 // indirect - golang.org/x/tools v0.7.0 // indirect + golang.org/x/tools v0.9.3 // indirect golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 // indirect golang.zx2c4.com/wireguard/windows v0.5.3 // indirect google.golang.org/appengine v1.6.7 // indirect - google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 // indirect - google.golang.org/grpc v1.53.0 // indirect - google.golang.org/protobuf v1.29.1 // indirect + google.golang.org/genproto v0.0.0-20230530153820-e85fd2cbaebc // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20230530153820-e85fd2cbaebc // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20230530153820-e85fd2cbaebc // indirect + google.golang.org/grpc v1.56.0 // indirect + google.golang.org/protobuf v1.30.0 // indirect gopkg.in/square/go-jose.v2 v2.6.0 // indirect gopkg.in/warnings.v0 v0.1.2 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect @@ -252,6 +257,6 @@ require ( gvisor.dev/gvisor v0.0.0-20221203005347-703fd9b7fbc0 // indirect inet.af/peercred v0.0.0-20210906144145-0893ea02156a // indirect nhooyr.io/websocket v1.8.7 // indirect - storj.io/drpc v0.0.33-0.20220622181519-9206537a4db7 // indirect + storj.io/drpc v0.0.33-0.20230420154621-9716137f6037 // indirect tailscale.com v1.38.2 // indirect ) diff --git a/go.sum b/go.sum index ff13733e..98cc5a72 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,7 @@ cdr.dev/slog v1.4.2 h1:fIfiqASYQFJBZiASwL825atyzeA96NsqSxx2aL61P8I= cdr.dev/slog v1.4.2/go.mod h1:0EkH+GkFNxizNR+GAXUEdUHanxUH5t9zqPILmPM/Vn8= +cdr.dev/slog v1.5.4 h1:X6kCMUnpqowjSDQCariOmph8veInR9OXutzxDCDG2yU= +cdr.dev/slog v1.5.4/go.mod h1:vu8IV5XS8oDrLwv0dOs3p0P17Q2k3QlPW/ytXP5JYA8= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= @@ -47,6 +49,8 @@ cloud.google.com/go/compute v1.6.1/go.mod h1:g85FgpzFvNULZ+S8AYq87axRKuf2Kh7deLq cloud.google.com/go/compute v1.7.0/go.mod h1:435lt8av5oL9P3fv1OEzSbSUe+ybHXGMPQHHZWZxy9U= cloud.google.com/go/compute v1.18.0 h1:FEigFqoDbys2cvFkZ9Fjq4gnHBP55anJ0yQyau2f9oY= cloud.google.com/go/compute v1.18.0/go.mod h1:1X7yHxec2Ga+Ss6jPyjxRxpu2uu7PLgsOVXvgU0yacs= +cloud.google.com/go/compute v1.19.3 h1:DcTwsFgGev/wV5+q8o2fzgcHOaac+DKGC91ZlvpsQds= +cloud.google.com/go/compute v1.19.3/go.mod h1:qxvISKp/gYnXkSAD1ppcSOveRAmzxicEv/JlizULFrI= cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= @@ -73,6 +77,8 @@ github.com/Azure/azure-sdk-for-go v61.3.0+incompatible h1:k7MKrYcGwX5qh+fC9xVhcE github.com/Azure/azure-sdk-for-go v61.3.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8= github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= +github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0= +github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/Azure/go-autorest v14.2.0+incompatible h1:V5VMDjClD3GiElqLWO7mz2MxNAK/vTfRHdAubSIPRgs= github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= github.com/Azure/go-autorest/autorest v0.11.24/go.mod h1:G6kyRlFnTuSbEYkQGawPfsCswgme4iYf6rfSKUDzbCc= @@ -102,6 +108,8 @@ github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY= github.com/Microsoft/go-winio v0.6.0 h1:slsWYD/zyx7lCXoZVlvQrj0hPTM1HI4+v1sIda2yDvg= github.com/Microsoft/go-winio v0.6.0/go.mod h1:cTAf44im0RAYeL23bpB+fzCyDH2MJiz2BO69KH/soAE= +github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= +github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= github.com/Microsoft/hcsshim v0.10.0-rc.7 h1:HBytQPxcv8Oy4244zbQbe6hnOnx544eL5QPUqhJldz8= github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 h1:TngWCqHvy9oXAN6lEVMRuU21PR1EtLVZJmdB18Gu3Rw= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= @@ -124,6 +132,8 @@ github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuy github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alexbrainman/sspi v0.0.0-20210105120005-909beea2cc74 h1:Kk6a4nehpJ3UuJRqlA3JxYxBZEqCeOmATOvrbT4p9RA= github.com/alexbrainman/sspi v0.0.0-20210105120005-909beea2cc74/go.mod h1:cEWa1LVoE5KvSD9ONXsZrj0z6KqySlCCNKHlLzbqAt4= +github.com/ammario/tlru v0.3.0 h1:yK8ESoFlEyz/BVVL8yZQKAUzJwFJR/j9EfxjnKxtR/Q= +github.com/ammario/tlru v0.3.0/go.mod h1:aYzRFu0XLo4KavE9W8Lx7tzjkX+pAApz+NgcKYIFUBQ= github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883 h1:bvNMNQO63//z+xNgfBlViaCIJKLlCJ6/fmUseuG0wVQ= github.com/andybalholm/brotli v1.0.4 h1:V7DdXeJtZscaqfNuAdSRuRFzuiKlHSC/Zh3zl9qY3JY= github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= @@ -136,6 +146,8 @@ github.com/apparentlymart/go-textseg/v13 v13.0.0 h1:Y+KvPE1NYz0xl601PVImeQfFyEy6 github.com/apparentlymart/go-textseg/v13 v13.0.0/go.mod h1:ZK2fH7c4NqDTLtiYLvIkEghdlcqw7yxLeM89kiTRPUo= github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0 h1:jfIu9sQUG6Ig+0+Ap1h4unLjW6YQJpKZVmUzxsD4E/Q= github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0/go.mod h1:t2tdKJDJF9BV14lnkjHmOQgcvEKgtqs5a1N3LNdJhGE= +github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= +github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= github.com/aws/aws-sdk-go-v2 v1.7.1/go.mod h1:L5LuPC1ZgDr2xQS7AmIec/Jlc7O/Y1u2KxJyNVab250= @@ -193,7 +205,9 @@ github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bep/debounce v1.2.1 h1:v67fRdBA9UQu2NhLFXrSg0Brw7CexQekrBwDMM8bzeY= github.com/bep/godartsass v0.16.0 h1:nTpenrZBQjVSjLkCw3AgnYmBB2czauTJa4BLLv448qg= +github.com/bep/godartsass v1.2.0 h1:E2VvQrxAHAFwbjyOIExAMmogTItSKodoKuijNrGm5yU= github.com/bep/golibsass v1.1.0 h1:pjtXr00IJZZaOdfryNa9wARTB3Q0BmxC3/V1KNcgyTw= +github.com/bep/golibsass v1.1.1 h1:xkaet75ygImMYjM+FnHIT3xJn7H0xBA9UxSOJjk8Khw= github.com/bool64/shared v0.1.5 h1:fp3eUhBsrSjNCQPcSdQqZxxh9bBwrYiZ+zOKFkM0/2E= github.com/breml/rootcerts v0.2.10 h1:UGVZ193UTSUASpGtg6pbDwzOd7XQP+at0Ssg1/2E4h8= github.com/breml/rootcerts v0.2.10/go.mod h1:24FDtzYMpqIeYC7QzaE8VPRQaFZU5TIUDlyk8qwjD88= @@ -222,9 +236,12 @@ github.com/cilium/ebpf v0.9.1 h1:64sn2K3UKw8NbP/blsixRpF3nXuyhz/VjRlRzvlBRu4= github.com/cilium/ebpf v0.9.1/go.mod h1:+OhNOIXx/Fnu1IE8bJz2dzOA+VSfyTfdNUVdlQnxUFY= github.com/clbanning/mxj/v2 v2.5.7 h1:7q5lvUpaPF/WOkqgIDiwjBJaznaLCCBd78pi8ZyAnE0= github.com/cli/safeexec v1.0.0 h1:0VngyaIyqACHdcMNWfo6+KdUYnqEr2Sg+bSP1pdF+dI= +github.com/cli/safeexec v1.0.1 h1:e/C79PbXF4yYTN/wauC4tviMxEV13BwljGj0N9j+N00= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cloudflare/circl v1.1.0 h1:bZgT/A+cikZnKIwn7xL2OBj012Bmvho/o6RpRvv3GKY= github.com/cloudflare/circl v1.1.0/go.mod h1:prBCrKB9DV4poKZY1l9zBXg2QJY7mvgRvtMxxK7fi4I= +github.com/cloudflare/circl v1.3.3 h1:fE/Qz0QdIGqeWfnwq0RE0R7MI51s0M2E4Ga9kq5AEMs= +github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= @@ -239,16 +256,24 @@ github.com/cockroachdb/errors v1.2.4/go.mod h1:rQD95gz6FARkaKkQXUksEje/d9a6wBJoC github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f/go.mod h1:i/u985jwjWRlyHXQbwatDASoW0RMlZ/3i9yJHE2xLkI= github.com/coder/coder v0.22.1-0.20230410192959-81e2b2500afa h1:9o19S9sl4SlBqrwH3H60aSX10A9VrD4wsMgD93RBo4c= github.com/coder/coder v0.22.1-0.20230410192959-81e2b2500afa/go.mod h1:63FrVmS8jPGx892zW2LJ3j6hqipGE6Rc4oBLPfgsTlM= +github.com/coder/coder v0.24.2-0.20230630184129-6015319e9d30 h1:7IhsN7OAQEKbIsEhsx2/ay8JQHqDWYzt/uWx9VkKfFY= +github.com/coder/coder v0.24.2-0.20230630184129-6015319e9d30/go.mod h1:BlHKuGJCK7V41oe8J5b9vQhjjXnnd+RcAmasG3Tyq1E= github.com/coder/kaniko v0.0.0-20230406190105-1c7cb9148d0e h1:J1cV6TxuIYJuRSf3aRQsbhekQTcF1t8jUjGHojz62sE= github.com/coder/kaniko v0.0.0-20230406190105-1c7cb9148d0e/go.mod h1:9spnlHjZQmvPavDUKdrSntKEKT1Z5aROo3Vbcx1TKCk= github.com/coder/kaniko v0.0.0-20230630144655-c825422ea1d2 h1:18QPpYBj9zVR0kzZ4dMldhFv1PiYNjp/7yljkpNeLfk= github.com/coder/kaniko v0.0.0-20230630144655-c825422ea1d2/go.mod h1:9spnlHjZQmvPavDUKdrSntKEKT1Z5aROo3Vbcx1TKCk= github.com/coder/retry v1.3.1-0.20230210155434-e90a2e1e091d h1:09JG37IgTB6n3ouX9BXdUiibGzkGGbslFuDZO9Ru9aw= github.com/coder/retry v1.3.1-0.20230210155434-e90a2e1e091d/go.mod h1:r+1J5i/989wt6CUeNSuvFKKA9hHuKKPMxdzDbTuvwwk= +github.com/coder/retry v1.4.0 h1:g0fojHFxcdgM3sBULqgjFDxw1UIvaCqk4ngUDu0EWag= +github.com/coder/retry v1.4.0/go.mod h1:blHMk9vs6LkoRT9ZHyuZo360cufXEhrxqvEzeMtRGoY= +github.com/coder/tailscale v0.0.0-20230522123520-74712221d00f h1:F0Xr1d8h8dAHn7tab1HXuzYFkcjmCydnEfdMbkOhlVk= +github.com/coder/tailscale v0.0.0-20230522123520-74712221d00f/go.mod h1:jpg+77g19FpXL43U1VoIqoSg1K/Vh5CVxycGldQ8KhA= github.com/coder/tailscale v1.1.1-0.20230323204624-bf5761af4a29 h1:bZAOib5uT7ohTYcKKj8w5jH+HwBStBrZ/KcU26X0g+A= github.com/coder/tailscale v1.1.1-0.20230323204624-bf5761af4a29/go.mod h1:jpg+77g19FpXL43U1VoIqoSg1K/Vh5CVxycGldQ8KhA= github.com/coder/terraform-provider-coder v0.6.23 h1:O2Rcj0umez4DfVdGnKZi63z1Xzxd0IQOn9VQDB8YU8g= github.com/coder/terraform-provider-coder v0.6.23/go.mod h1:UIfU3bYNeSzJJvHyJ30tEKjD6Z9utloI+HUM/7n94CY= +github.com/coder/terraform-provider-coder v0.9.0 h1:OJazaeBz6O2h7tDDUyUWgNW71lTPbvbI2raX1CGuBzI= +github.com/coder/terraform-provider-coder v0.9.0/go.mod h1:UIfU3bYNeSzJJvHyJ30tEKjD6Z9utloI+HUM/7n94CY= github.com/containerd/cgroups v1.1.0 h1:v8rEWFl6EoqHB+swVNjVoCJE8o3jX7e8nqBGPLaDFBM= github.com/containerd/cgroups v1.1.0/go.mod h1:6ppBcbh/NOOUU+dMKrykgaBnK9lCIBxHqJDGwsa1mIw= github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U= @@ -266,6 +291,8 @@ github.com/coreos/go-iptables v0.6.0 h1:is9qnZMPYjLd8LYqmm/qlE+wwEgJIkTYdhV3rfZo github.com/coreos/go-iptables v0.6.0/go.mod h1:Qe8Bv2Xik5FyTXwgIbLAnv2sWSBmvWdFETJConOQ//Q= github.com/coreos/go-oidc/v3 v3.4.0 h1:xz7elHb/LDwm/ERpwHd+5nb7wFHL32rsr6bBOgaeu6g= github.com/coreos/go-oidc/v3 v3.4.0/go.mod h1:eHUXhZtXPQLgEaDrOVTgwbgmz1xGOkJNye6h3zkD2Pw= +github.com/coreos/go-oidc/v3 v3.6.0 h1:AKVxfYw1Gmkn/w96z0DbT/B/xFnzTd3MkZvWLjF4n/o= +github.com/coreos/go-oidc/v3 v3.6.0/go.mod h1:ZpHUsHBucTUj6WOkrP4E20UPynbLZzhTQ1XKCXkxyPc= github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs= github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= @@ -279,12 +306,14 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dgraph-io/badger/v3 v3.2103.5 h1:ylPa6qzbjYRQMU6jokoj4wzcaweHylt//CH0AKt0akg= github.com/dgraph-io/ristretto v0.1.0 h1:Jv3CGQHp9OjuMBSne1485aDpUkTKEcUqF+jm/LuerPI= +github.com/dgraph-io/ristretto v0.1.1 h1:6CWw5tJNgpegArSHpNHJKldNeq03FQCwYvfMVWajOK8= github.com/dgryski/trifles v0.0.0-20200323201526-dd97f9abfb48 h1:fRzb/w+pyskVMQ+UbP35JkH8yB7MYb4q/qhBarqZE6g= github.com/dgryski/trifles v0.0.0-20200323201526-dd97f9abfb48/go.mod h1:if7Fbed8SFyPtHLHbg49SI7NAdJiC5WIA09pe59rfAA= github.com/dimchansky/utfbom v1.1.1 h1:vV6w1AhK4VMnhBno/TPVCoK9U/LP0PkLCS9tbxHdi/U= github.com/dimchansky/utfbom v1.1.1/go.mod h1:SxdoEBH5qIqFocHMyGOXVAybYJdr71b1Q/j0mACtrfE= github.com/dlclark/regexp2 v1.4.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= github.com/dlclark/regexp2 v1.8.1 h1:6Lcdwya6GjPUNsBct8Lg/yRPwMhABj269AAzdGSiR+0= +github.com/dlclark/regexp2 v1.10.0 h1:+/GIL799phkJqYW+3YbOd8LCcbHzT0Pbo8zl70MHsq0= github.com/docker/cli v23.0.1+incompatible h1:LRyWITpGzl2C9e9uGxzisptnxAn1zfZKXy13Ul2Q5oM= github.com/docker/cli v23.0.1+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= github.com/docker/distribution v2.8.1+incompatible h1:Q50tZOPR6T/hjNsyc9g8/syEs6bk8XXApsHjKukMl68= @@ -307,6 +336,7 @@ github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkp github.com/ePirat/docker-credential-gitlabci v1.0.0 h1:YRkUSvkON6rT88vtscClAmPEYWhtltGEAuRVYtz1/+Y= github.com/ePirat/docker-credential-gitlabci v1.0.0/go.mod h1:Ptmh+D0lzBQtgb6+QHjXl9HqOn3T1P8fKUHldiSQQGA= github.com/elastic/go-sysinfo v1.9.0 h1:usICqY/Nw4Mpn9f4LdtpFrKxXroJDe81GaxxUlCckIo= +github.com/elastic/go-sysinfo v1.11.0 h1:QW+6BF1oxBoAprH3w2yephF7xLkrrSXj7gl2xC2BM4w= github.com/elastic/go-windows v1.0.0 h1:qLURgZFkkrYyTTkvYpsZIgf83AUsdIHfvlJaqaZ7aSY= github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= @@ -326,6 +356,7 @@ github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs= github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw= github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw= github.com/foxcpp/go-mockdns v0.0.0-20210729171921-fb145fc6f897 h1:E52jfcE64UG42SwLmrW0QByONfGynWuzBvm86BoB9z8= +github.com/foxcpp/go-mockdns v1.0.0 h1:7jBqxd3WDWwi/6WhDvacvH1XsN3rOLXyHM1uhvIx6FI= github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= github.com/frankban/quicktest v1.14.0 h1:+cqqvzZV87b4adx/5ayVOaYZ2CrvM4ejQvUdBzPPUss= github.com/frankban/quicktest v1.14.0/go.mod h1:NeW+ay9A/U67EYXNFA1nPE8e/tnQv/09mUdL/ijj8og= @@ -339,12 +370,15 @@ github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M= github.com/gin-gonic/gin v1.7.7 h1:3DoBmSbJbZAWqXJC3SLjAPfutPJJRN1U5pALB7EeTTs= +github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg= github.com/github/fakeca v0.1.0 h1:Km/MVOFvclqxPM9dZBC4+QE564nU4gz4iZ0D9pMw28I= github.com/github/fakeca v0.1.0/go.mod h1:+bormgoGMMuamOscx7N91aOuUST7wdaJ2rNjeohylyo= github.com/gliderlabs/ssh v0.3.5 h1:OcaySEmAQJgyYcArR+gGGTHCyE7nvhEMTlYY+Dp8CpY= github.com/gliderlabs/ssh v0.3.5/go.mod h1:8XB4KraRrX39qHhT6yxPsHedjA08I/uBVwj4xC+/+z4= github.com/go-chi/chi/v5 v5.0.7 h1:rDTPXLDHGATaeHvVlLcR4Qe0zftYethFucbjVQ1PxU8= github.com/go-chi/chi/v5 v5.0.7/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= +github.com/go-chi/chi/v5 v5.0.8 h1:lD+NLqFcAi1ovnVZpsnObHGW4xb4J8lNmoYVfECH1Y0= +github.com/go-chi/chi/v5 v5.0.8/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= github.com/go-chi/httprate v0.7.1 h1:d5kXARdms2PREQfU4pHvq44S6hJ1hPu4OXLeBKmCKWs= github.com/go-chi/render v1.0.1 h1:4/5tis2cKaNdnv9zFLfXzcquC9HbeZgCnxGnKrltBS8= github.com/go-git/gcfg v1.5.0 h1:Q5ViNfGF8zFgyJWPqYwA7qGFoMTEiBmdlkcfRmpIMa4= @@ -360,12 +394,15 @@ github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9 github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-jose/go-jose/v3 v3.0.0 h1:s6rrhirfEP/CGIoc6p+PZAeogN2SxKav6Wp7+dyMWVo= +github.com/go-jose/go-jose/v3 v3.0.0/go.mod h1:RNkWWRld676jZEYoV3+XK8L2ZnNSvIsxFMht0mSX+u8= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= +github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= @@ -381,10 +418,12 @@ github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+ github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI= github.com/go-playground/validator/v10 v10.12.0 h1:E4gtWgxWxp8YSxExrQFv5BpCahla0PVF2oTTEYaWQGI= +github.com/go-playground/validator/v10 v10.14.0 h1:vgvQWe3XCz3gIeFDm/HnTIbj6UGmg/+t63MyGU2n5js= github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE= github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-test/deep v1.0.3 h1:ZrJSEWsXzPOxaZnFteGEfooLba+ju3FYIbOrS+rQd68= +github.com/go-test/deep v1.0.8 h1:TDsG77qcSprGbC6vTN8OuXp5g+J+b5Pcguhf7Zt61VM= github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee h1:s+21KNqlpePfkah2I+gwHF8xmJWRjooY+5248k6m4A0= @@ -402,15 +441,19 @@ github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXP github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/gohugoio/hugo v0.110.0 h1:FBBypy+UXD9BWaMReIZ+y2FSxFwlJCqoutVi7jKa90o= +github.com/gohugoio/hugo v0.114.1 h1:G1Huj3N8nuaNZ4SaNvf8JHH6yG9MA/gajdMaOOXjkkU= github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY= github.com/golang-jwt/jwt/v4 v4.0.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= github.com/golang-jwt/jwt/v4 v4.2.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/golang-migrate/migrate/v4 v4.15.2 h1:vU+M05vs6jWHKDdmE1Ecwj0BznygFc4QsdRe2E/L7kc= +github.com/golang-migrate/migrate/v4 v4.16.0 h1:FU2GR7EdAO0LmhNLcKthfDzuYCtMcWNR7rUbZjsgH3o= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/glog v1.0.0 h1:nfP3RFugxnNRyKgeWd4oI1nYvXpxrx8ck8ZrcizshdQ= github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= +github.com/golang/glog v1.1.0 h1:/d3pCKDPWNnvIWe0vVUpNP32qc8U3PDVxySP/y360qE= +github.com/golang/glog v1.1.0/go.mod h1:pfYeQZ3JWZoXTV5sFc986z3HTpwQs9At6P4ImfuP3NQ= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -501,6 +544,7 @@ github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/enterprise-certificate-proxy v0.0.0-20220520183353-fd19c99a87aa/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8= github.com/googleapis/enterprise-certificate-proxy v0.2.3 h1:yk9/cqRKtT9wXZSsRH9aurXEpJX+U6FLtpYTdC3R06k= +github.com/googleapis/enterprise-certificate-proxy v0.2.4 h1:uGy6JWR/uMIILU8wbf+OkstIrNiMjGpEIyhx8f6W7s4= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0= @@ -547,12 +591,16 @@ github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uG github.com/hashicorp/golang-lru/v2 v2.0.1 h1:5pv5N1lT1fjLg2VQ5KWc7kmucp2x/kvFOnxuVTqZ6x4= github.com/hashicorp/golang-lru/v2 v2.0.1/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= github.com/hashicorp/hc-install v0.4.1-0.20220912074615-4487b02cbcbb h1:0AmumMAu6gi5zXEyXvLKDu/HALK+rIcVBZU5XJNyjRM= +github.com/hashicorp/hc-install v0.5.2 h1:SfwMFnEXVVirpwkDuSF5kymUOhrUxrTq3udEseZdOD0= github.com/hashicorp/hcl/v2 v2.14.0 h1:jX6+Q38Ly9zaAJlAjnFVyeNSNCKKW8D0wvyg7vij5Wc= github.com/hashicorp/hcl/v2 v2.14.0/go.mod h1:e4z5nxYlWNPdDSNYX+ph14EvWYMFm3eP0zIUqPc2jr0= +github.com/hashicorp/hcl/v2 v2.17.0 h1:z1XvSUyXd1HP10U4lrLg5e0JMVz6CPaJvAgxM0KNZVY= +github.com/hashicorp/hcl/v2 v2.17.0/go.mod h1:gJyW2PTShkJqQBKpAmPO3yxMxIuoXkOF2TpqXzrQyx4= github.com/hashicorp/logutils v1.0.0 h1:dLEQVugN8vlakKOUE3ihGLTZJRB4j+M2cdTm/ORI65Y= github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= github.com/hashicorp/terraform-exec v0.17.2 h1:EU7i3Fh7vDUI9nNRdMATCEfnm9axzTnad8zszYZ73Go= github.com/hashicorp/terraform-json v0.14.0 h1:sh9iZ1Y8IFJLx+xQiKHGud6/TSUCM0N8e17dKDpqV7s= +github.com/hashicorp/terraform-json v0.17.0 h1:EiA1Wp07nknYQAiv+jIt4dX4Cq5crgP+TsTE45MjMmM= github.com/hashicorp/terraform-plugin-go v0.12.0 h1:6wW9mT1dSs0Xq4LR6HXj1heQ5ovr5GxXNJwkErZzpJw= github.com/hashicorp/terraform-plugin-go v0.12.0/go.mod h1:kwhmaWHNDvT1B3QiSJdAtrB/D4RaKSY/v3r2BuoWK4M= github.com/hashicorp/terraform-plugin-log v0.7.0 h1:SDxJUyT8TwN4l5b5/VkiTIaQgY6R+Y2BQ0sRZftGKQs= @@ -563,6 +611,8 @@ github.com/hashicorp/terraform-registry-address v0.0.0-20220623143253-7d51757b57 github.com/hashicorp/terraform-svchost v0.0.0-20200729002733-f050f53b9734 h1:HKLsbzeOsfXmKNpr3GiT18XAblV0BjCbzL8KQAMZGa0= github.com/hashicorp/yamux v0.0.0-20220718163420-dd80a7ee44ce h1:7FO+LmZwiG/eDsBWo50ZeqV5PoH0gwiM1mxFajXAkas= github.com/hashicorp/yamux v0.0.0-20220718163420-dd80a7ee44ce/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= +github.com/hashicorp/yamux v0.1.1 h1:yrQxtgseBDrq9Y652vSRDvsKCJKOUD+GzTS4Y0Y8pvE= +github.com/hashicorp/yamux v0.1.1/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= github.com/hdevalence/ed25519consensus v0.0.0-20220222234857-c00d1f31bab3 h1:aSVUgRRRtOrZOC1fYmY9gV0e9z/Iu+xNVSASWjsuyGU= github.com/hdevalence/ed25519consensus v0.0.0-20220222234857-c00d1f31bab3/go.mod h1:5PC6ZNPde8bBqU/ewGZig35+UIZtw9Ytxez8/q5ZyFE= github.com/hugelgupf/socketpair v0.0.0-20190730060125-05d35a94e714/go.mod h1:2Goc3h8EklBH5mspfHFxBnEoURQCGzQQH1ga9Myjvis= @@ -638,6 +688,7 @@ github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= github.com/leodido/go-urn v1.2.2 h1:7z68G0FCGvDk646jz1AelTYNYWrTNm0bEcFAo147wt4= +github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q= github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.10.6 h1:jbk+ZieJ0D7EVGJYpL9QTz7/YW6UHbmdnZWYyK5cdBs= github.com/lib/pq v1.10.6/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= @@ -654,7 +705,10 @@ github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27k github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= +github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU= +github.com/mattn/go-sqlite3 v1.14.6 h1:dNPt6NO46WmLVt2DLNpwczCmdV5boIZ6g/tlDrlRUbg= github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= github.com/mattn/go-sqlite3 v1.14.15 h1:vfoHhTN1af61xCRSWzFIWzx2YskyMTwHLrExkBOjvxI= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= @@ -701,6 +755,7 @@ github.com/moby/buildkit v0.11.4/go.mod h1:P5Qi041LvCfhkfYBHry+Rwoo3Wi6H971J2ggE github.com/moby/locker v1.0.1 h1:fOXqR41zeveg4fFODix+1Ch4mj/gT0NE1XJbp/epuBg= github.com/moby/locker v1.0.1/go.mod h1:S7SDdo5zpBK84bzzVlKr2V0hz+7x9hWbYC/kq7oQppc= github.com/moby/moby v20.10.23+incompatible h1:5+Q6jGL7oH89tx+ms0fGsTYEXrQ3P4vuL3i7DayMUuM= +github.com/moby/moby v24.0.1+incompatible h1:VzcmrGPwKZLMsjylQP6yqYz3D+MTwFnPt2BDAPYuzQE= github.com/moby/patternmatcher v0.5.0 h1:YCZgJOeULcxLw1Q+sVR636pmS7sPEn1Qo2iAN6M7DBo= github.com/moby/patternmatcher v0.5.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc= github.com/moby/swarmkit/v2 v2.0.0-20230315203717-e28e8ba9bc83 h1:jUbNDiRMDXd2rYoa4bcI+g3nIb4A1R8HNCe9wdCdh8I= @@ -718,6 +773,8 @@ github.com/moby/sys/symlink v0.2.0 h1:tk1rOM+Ljp0nFmfOIBtlV3rTDlWOwFRhjEeAhZB0nZ github.com/moby/sys/symlink v0.2.0/go.mod h1:7uZVF2dqJjG/NsClqul95CqKOBRQyYSNnJ6BMgR/gFs= github.com/moby/term v0.0.0-20221120202655-abb19827d345 h1:J9c53/kxIH+2nTKBEfZYFMlhghtHpIHSXpm5VRGHSnU= github.com/moby/term v0.0.0-20221120202655-abb19827d345/go.mod h1:15ce4BGCFxt7I5NQKT+HV0yEDxmf6fSysfEDiVo3zFM= +github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0= +github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -733,11 +790,14 @@ github.com/muesli/termenv v0.14.0 h1:8x9NFfOe8lmIWK4pgy3IfVEy47f+ppe3tUqdPZG2Uy0 github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/niklasfasching/go-org v1.6.5 h1:5YAIqNTdl6lAOb7lD2AyQ1RuFGPVrAKvUexphk8PGbo= +github.com/niklasfasching/go-org v1.6.6 h1:U6+mJ80p3weR4oP+Z+Pb2EVkSbt1MUwweBbUcF1hVqQ= github.com/nsf/jsondiff v0.0.0-20200515183724-f29ed568f4ce h1:RPclfga2SEJmgMmz2k+Mg7cowZ8yv4Trqw9UsJby758= github.com/oklog/run v1.0.0 h1:Ru7dDtJNOyC66gQ5dQmaCa0qIsAUFY3sFpK1Xk8igrw= github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= github.com/open-policy-agent/opa v0.44.0 h1:sEZthsrWBqIN+ShTMJ0Hcz6a3GkYsY4FaB2S/ou2hZk= github.com/open-policy-agent/opa v0.44.0/go.mod h1:YpJaFIk5pq89n/k72c1lVvfvR5uopdJft2tMg1CW/yU= +github.com/open-policy-agent/opa v0.51.0 h1:2hS5xhos8HtkN+mgpqMhNJSFtn/1n/h3wh+AeTPJg6Q= +github.com/open-policy-agent/opa v0.51.0/go.mod h1:OjmwLfXdeR7skSxrt8Yd3ScXTqPxyJn7GeTRJrcEerU= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.1.0-rc2.0.20221005185240-3a7f492d3f1b h1:YWuSjZCQAPM8UUBLkYUk1e+rZcvWHJmFb6i6rM44Xs8= @@ -751,6 +811,7 @@ github.com/opencontainers/selinux v1.10.0/go.mod h1:2i0OySw99QjzBBQByd1Gr9gSjvuh github.com/opencontainers/selinux v1.11.0 h1:+5Zbo97w3Lbmb3PeqQtpmTkMwsW5nRI3YaLpt7tQ7oU= github.com/opencontainers/selinux v1.11.0/go.mod h1:E5dMC3VPuVvVHDYmi78qvhJp8+M586T4DlDRYpFkyec= github.com/ory/dockertest/v3 v3.9.1 h1:v4dkG+dlu76goxMiTT2j8zV7s4oPPEppKT8K8p2f1kY= +github.com/ory/dockertest/v3 v3.10.0 h1:4K3z2VMe8Woe++invjaTB7VRyQXQy5UY+loujO4aNE4= github.com/otiai10/copy v1.7.0 h1:hVoPiN+t+7d2nzzwMiDHPSOogsWAStewq3TwU05+clE= github.com/otiai10/copy v1.7.0/go.mod h1:rmRl6QPdJj6EiUqXQ/4Nn2lLXoNQjFCQbbNrxgc/t3U= github.com/otiai10/curr v0.0.0-20150429015615-9b4961190c95/go.mod h1:9qAhocn7zKJG+0mI8eUu6xqkFDYS2kb2saOteoSB3cE= @@ -760,6 +821,7 @@ github.com/otiai10/mint v1.3.3 h1:7JgpsBaN0uMkyju4tbYHu0mnM55hNKVYLsXmwr15NQI= github.com/otiai10/mint v1.3.3/go.mod h1:/yxELlJQ0ufhjUwhshSj+wFjZ78CnZ48/1wtmBH1OTc= github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= github.com/pelletier/go-toml/v2 v2.0.6 h1:nrzqCb7j9cDFj2coyLNLaZuJTLjWjlaz6nvTvIwycIU= +github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ= github.com/pjbgf/sha1cd v0.3.0 h1:4D5XXmUUBUl/xQ6IjCkEAbqXskkq/4O7LmGn0AqMDs4= github.com/pjbgf/sha1cd v0.3.0/go.mod h1:nZ1rrWOcGJ5uZgEEVL1VUM9iRQiZvWdbZjkKyFzPPsI= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -775,6 +837,8 @@ github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5Fsn github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g= github.com/prometheus/client_golang v1.14.0 h1:nJdhIvne2eSX/XRAFV9PcvFFRbrjbcTUj0VP62TMhnw= github.com/prometheus/client_golang v1.14.0/go.mod h1:8vpkKitgIVNcqrRBWh1C4TIUQgYNtG/XQE4E/Zae36Y= +github.com/prometheus/client_golang v1.15.1 h1:8tXpTmJbyH5lydzFPoxSIJ0J46jdh3tylbvM1xCv0LI= +github.com/prometheus/client_golang v1.15.1/go.mod h1:e9yaBhRPU2pPNsZwE+JdQl0KEt1N9XgF6zxWmaC0xOk= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= @@ -784,6 +848,8 @@ github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y8 github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc= github.com/prometheus/common v0.40.0 h1:Afz7EVRqGg2Mqqf4JuF9vdvp1pi220m55Pi9T2JnO4Q= github.com/prometheus/common v0.40.0/go.mod h1:L65ZJPSmfn/UBWLQIHV7dBrKFidB/wPlF1y5TlSt9OE= +github.com/prometheus/common v0.42.0 h1:EKsfXEYo4JpWMHH5cg+KOUWeuJSov1Id8zGR8eeI1YM= +github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr1yjz4b7Zbc= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= @@ -812,6 +878,8 @@ github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/sirupsen/logrus v1.9.2 h1:oxx1eChJGI6Uks2ZC4W1zpLlVgqB8ner4EuQwV4Ik1Y= +github.com/sirupsen/logrus v1.9.2/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/skeema/knownhosts v1.1.0 h1:Wvr9V0MxhjRbl3f9nMnKnFfiWTJmtECJ9Njkea3ysW0= github.com/skeema/knownhosts v1.1.0/go.mod h1:sKFq3RD6/TKZkSWn8boUbDC7Qkgcv+8XXijpFO6roag= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= @@ -819,7 +887,10 @@ github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9 github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.9.3 h1:41FoI0fD7OR7mGcKE/aOiLkGreyf8ifIOQmJANWogMk= github.com/spf13/afero v1.9.3/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y= +github.com/spf13/afero v1.9.5 h1:stMpOSZFs//0Lv29HduCmli3GUfpFoF3Y1Q/aXj/wVM= +github.com/spf13/afero v1.9.5/go.mod h1:UBogFpq8E9Hx+xc5CNTTEpTnuHVmXDwZcZcE1eb/UhQ= github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w= +github.com/spf13/cast v1.5.1 h1:R+kOtfhWQE6TVQzY+4D7wJLBgkdVasCEFxSUBYBYIlA= github.com/spf13/cobra v1.6.1 h1:o94oiPyS4KD1mPy2fmcYYHHfCxLqYjJOhGsCHFZtEzA= github.com/spf13/cobra v1.6.1/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUqzrY= github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= @@ -841,6 +912,8 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/swaggest/assertjson v1.7.0 h1:SKw5Rn0LQs6UvmGrIdaKQbMR1R3ncXm5KNon+QJ7jtw= github.com/swaggo/files/v2 v2.0.0 h1:hmAt8Dkynw7Ssz46F6pn8ok6YmGZqHSVLZ+HQM7i0kw= github.com/swaggo/http-swagger/v2 v2.0.1 h1:mNOBLxDjSNwCKlMxcErjjvct/xhc9t2KIO48xzz/V/k= @@ -863,6 +936,7 @@ github.com/tchap/go-patricia/v2 v2.3.1/go.mod h1:VZRHKAb53DLaG+nA9EaYYiaEx6YztwD github.com/tcnksm/go-httpstat v0.2.0 h1:rP7T5e5U2HfmOBmZzGgGZjBQ5/GluWUylujl0tJ04I0= github.com/tcnksm/go-httpstat v0.2.0/go.mod h1:s3JVJFtQxtBEBC9dwcdTTXS9xFnM3SXAZwPG41aurT8= github.com/tdewolff/parse/v2 v2.6.4 h1:KCkDvNUMof10e3QExio9OPZJT8SbdKojLBumw8YZycQ= +github.com/tdewolff/parse/v2 v2.6.6 h1:Yld+0CrKUJaCV78DL1G2nk3C9lKrxyRTux5aaK/AkDo= github.com/tonistiigi/fsutil v0.0.0-20230105215944-fb433841cbfa h1:XOFp/3aBXlqmOFAg3r6e0qQjPnK5I970LilqX+Is1W8= github.com/tonistiigi/fsutil v0.0.0-20230105215944-fb433841cbfa/go.mod h1:AvLEd1LEIl64G2Jpgwo7aVV5lGH0ePcKl0ygGIHNYl8= github.com/u-root/u-root v0.11.0 h1:6gCZLOeRyevw7gbTwMj3fKxnr9+yHFlgF3N7udUVNO8= @@ -879,6 +953,8 @@ github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6Kllzaw github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= github.com/valyala/fasthttp v1.44.0 h1:R+gLUhldIsfg1HokMuQjdQ5bh9nuXHPIfvkYUu9eR5Q= github.com/valyala/fasthttp v1.44.0/go.mod h1:f6VbjjoI3z1NDOZOv17o6RvtRSWxC77seBFc2uWtgiY= +github.com/valyala/fasthttp v1.48.0 h1:oJWvHb9BIZToTQS3MuQ2R3bJZiNSa2KiNdeI8A+79Tc= +github.com/valyala/fasthttp v1.48.0/go.mod h1:k2zXd82h/7UZc3VOdJ2WaUqt1uZ/XpXAfE9i+HBC3lA= github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc= github.com/vbatts/tar-split v0.11.2 h1:Via6XqJr0hceW4wff3QRzD5gAk/tatMw/4ZA7cTlIME= github.com/vbatts/tar-split v0.11.2/go.mod h1:vV3ZuO2yWSVsz+pfFzDG/upWH1JhjOiEaWq6kXyQ3VI= @@ -917,9 +993,12 @@ github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9dec github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/yuin/goldmark v1.5.3 h1:3HUJmBFbQW9fhQOzMgseU134xfi6hU+mjWywx5Ty+/M= +github.com/yuin/goldmark v1.5.4 h1:2uY/xC0roWy8IBEGLgB1ywIoEJFGmRrX21YQcvGZzjU= github.com/yuin/goldmark-emoji v1.0.1 h1:ctuWEyzGBwiucEqxzwe0SOYDXPAucOrE9NQC18Wa1os= github.com/zclconf/go-cty v1.10.0 h1:mp9ZXQeIcN8kAwuqorjH+Q+njbJKjLrvB2yIh4q7U+0= github.com/zclconf/go-cty v1.10.0/go.mod h1:vVKLxnk3puL4qRAv72AO+W99LUD4da90g3uUAzyuvAk= +github.com/zclconf/go-cty v1.13.2 h1:4GvrUxe/QUDYuJKAav4EYqdM47/kZa672LwmXFmEKT0= +github.com/zclconf/go-cty v1.13.2/go.mod h1:YKQzy/7pZ7iq2jNFzy5go57xdxdWoLLpaEp4u238AE0= github.com/zeebo/assert v1.3.0 h1:g7C04CbJuIDKNPFHmsk4hwZDO5O+kntRxzaUoNXj+IQ= github.com/zeebo/assert v1.3.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0= github.com/zeebo/errs v1.3.0 h1:hmiaKqgYZzcVgRL1Vkc1Mn2914BbzB0IBxs+ebeutGs= @@ -978,6 +1057,7 @@ golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnf golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= @@ -993,6 +1073,8 @@ golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= golang.org/x/crypto v0.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A= golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= +golang.org/x/crypto v0.10.0 h1:LKqV2xt9+kDzSTfOhx4FrkEBcMrAgHSYgzywV9zcGmM= +golang.org/x/crypto v0.10.0/go.mod h1:o4eNf7Ede1fv+hwOwZsTHl9EsPFO6q6ZvYR8vYfY45I= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -1005,6 +1087,8 @@ golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EH golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= golang.org/x/exp v0.0.0-20221205204356-47842c84f3db h1:D/cFflL63o2KSLJIwjlcIt8PR064j/xsmdEJL/YvY/o= golang.org/x/exp v0.0.0-20221205204356-47842c84f3db/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= +golang.org/x/exp v0.0.0-20230315142452-642cacee5cc0 h1:pVgRXcIictcr+lBQIFeiwuwtDIs4eL21OuM9nyAADmo= +golang.org/x/exp v0.0.0-20230315142452-642cacee5cc0/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= golang.org/x/exp/typeparams v0.0.0-20221208152030-732eee02a75a h1:Jw5wfR+h9mnIYH+OtGT2im5wV1YGGDora5vTv/aa5bE= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= @@ -1035,6 +1119,8 @@ golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91 golang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI= golang.org/x/mod v0.9.0 h1:KENHtAZL2y3NLMYZeHY9DW8HW8V+kQyJsY/V9JlKvCs= golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.11.0 h1:bUO06HqtnRcc/7l71XBe4WcqTZ+3AH1J59zWDDwLKgU= +golang.org/x/mod v0.11.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -1094,6 +1180,8 @@ golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/net v0.11.0 h1:Gi2tvZIJyBtO9SDr1q9h5hEQCp/4L2RQ+ar0qjx2oNU= +golang.org/x/net v0.11.0/go.mod h1:2L/ixqYpgIVXmeoSA/4Lu7BzTG4KIyPIryS4IsOd1oQ= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -1117,6 +1205,8 @@ golang.org/x/oauth2 v0.0.0-20220608161450-d0670ef3b1eb/go.mod h1:jaDAt6Dkxork7Lm golang.org/x/oauth2 v0.0.0-20220822191816-0ebed06d0094/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= golang.org/x/oauth2 v0.6.0 h1:Lh8GPgSKBfWSwFvtuWOfeI3aAAnbXTSutYxJiOJFgIw= golang.org/x/oauth2 v0.6.0/go.mod h1:ycmewcwgD4Rpr3eZJLSB4Kyyljb3qDh40vJ8STE5HKw= +golang.org/x/oauth2 v0.9.0 h1:BPpt2kU7oMRq3kCHAA1tbSEshXRw1LpG2ztgDwrzuAs= +golang.org/x/oauth2 v0.9.0/go.mod h1:qYgFZaFiu6Wg24azG8bdV52QJXJGbZzIIsRCdVKzbLw= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -1132,6 +1222,8 @@ golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= +golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -1231,6 +1323,8 @@ golang.org/x/sys v0.4.1-0.20230131160137-e7d7f63158de/go.mod h1:oPkhp1MJrh7nUepC golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.9.0 h1:KS/R3tvhPqvJvwcKfnBHJwwthS11LRhmM5D59eEXa0s= +golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.0.0-20220722155259-a9ba230a4035/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= @@ -1238,6 +1332,8 @@ golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.6.0 h1:clScbb1cHjoCkyRbWwBEUZ5H/tIFu5TAXIqaZD0Gcjw= golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= +golang.org/x/term v0.9.0 h1:GRRCnKYhdQrD8kfRAdQ6Zcw1P0OcELxGLKJvtjVMZ28= +golang.org/x/term v0.9.0/go.mod h1:M6DEAAIenWoTxdKrOltXcmDY3rSplQUkrvaDU5FcQyo= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1251,6 +1347,8 @@ golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.10.0 h1:UpjohKhiEgNc0CSauXmwYftY1+LlaC75SJwh0SgCX58= +golang.org/x/text v0.10.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -1316,6 +1414,8 @@ golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA= golang.org/x/tools v0.7.0 h1:W4OVu8VVOaIO0yzWMNdepAulS7YfoS3Zabrm8DOXXU4= golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s= +golang.org/x/tools v0.9.3 h1:Gn1I8+64MsuTb/HpH+LmQtNas23LhUVr3rYZ0eKuaMM= +golang.org/x/tools v0.9.3/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -1369,6 +1469,7 @@ google.golang.org/api v0.78.0/go.mod h1:1Sg78yoMLOhlQTeF+ARBoytAcH1NNyyl390YMy6r google.golang.org/api v0.80.0/go.mod h1:xY3nI94gbvBrE0J6NHXhxOmW97HG7Khjkku6AFB3Hyg= google.golang.org/api v0.84.0/go.mod h1:NTsGnUFJMYROtiquksZHBWtHfeMC7iYthki7Eq3pa8o= google.golang.org/api v0.110.0 h1:l+rh0KYUooe9JGbGVx71tbFo4SMbMTXK3I3ia2QSEeU= +google.golang.org/api v0.128.0 h1:RjPESny5CnQRn9V6siglged+DZCgfu9l6mO9dkX9VOg= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -1459,6 +1560,12 @@ google.golang.org/genproto v0.0.0-20220608133413-ed9918b62aac/go.mod h1:KEWEmljW google.golang.org/genproto v0.0.0-20220616135557-88e70c0c3a90/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 h1:DdoeryqhaXp1LtT/emMP1BRJPHHKFi5akj/nbx/zNTA= google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= +google.golang.org/genproto v0.0.0-20230530153820-e85fd2cbaebc h1:8DyZCyvI8mE1IdLy/60bS+52xfymkE72wv1asokgtao= +google.golang.org/genproto v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:xZnkP7mREFX5MORlOPEzLMr+90PPZQ2QWzrVTWfAq64= +google.golang.org/genproto/googleapis/api v0.0.0-20230530153820-e85fd2cbaebc h1:kVKPf/IiYSBWEWtkIn6wZXwWGCnLKcC8oWfZvXjsGnM= +google.golang.org/genproto/googleapis/api v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230530153820-e85fd2cbaebc h1:XSJ8Vk1SWuNr8S18z1NZSziL0CPIXLCCMDOEFtHBOFc= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= @@ -1493,6 +1600,8 @@ google.golang.org/grpc v1.46.2/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACu google.golang.org/grpc v1.47.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc= google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= +google.golang.org/grpc v1.56.0 h1:+y7Bs8rtMd07LeXmL3NxcTLn7mUkbKZqEpPhMNkwJEE= +google.golang.org/grpc v1.56.0/go.mod h1:I9bI3vqKfayGqPUAwGdOSu7kt6oIJLixfffKrpXqQ9s= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= @@ -1510,6 +1619,8 @@ google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQ google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.29.1 h1:7QBf+IK2gx70Ap/hDsOmam3GE0v9HicjfEdAxE62UoM= google.golang.org/protobuf v1.29.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= +google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -1559,3 +1670,5 @@ rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= software.sslmate.com/src/go-pkcs12 v0.2.0 h1:nlFkj7bTysH6VkC4fGphtjXRbezREPgrHuJG20hBGPE= storj.io/drpc v0.0.33-0.20220622181519-9206537a4db7 h1:6jIp39oQGZMjfrG3kiafK2tcL0Fbprh2kvaoJNfhvuM= storj.io/drpc v0.0.33-0.20220622181519-9206537a4db7/go.mod h1:6rcOyR/QQkSTX/9L5ZGtlZaE2PtXTTZl8d+ulSeeYEg= +storj.io/drpc v0.0.33-0.20230420154621-9716137f6037 h1:SYRl2YUthhsXNkrP30KwxkDGN9TESdNrbpr14rOxsnM= +storj.io/drpc v0.0.33-0.20230420154621-9716137f6037/go.mod h1:vR804UNzhBa49NOJ6HeLjd2H3MakC1j5Gv8bsOQT6N4= diff --git a/log.go b/log.go index 08c0f7cd..ad476c1d 100644 --- a/log.go +++ b/log.go @@ -1,16 +1,8 @@ package envbuilder import ( - "context" - "errors" "io" - "net/http" - "sync" - "time" - "github.com/coder/coder/codersdk" - "github.com/coder/coder/codersdk/agentsdk" - "github.com/coder/retry" "github.com/sirupsen/logrus" ) @@ -34,103 +26,3 @@ func (f *logrusFormatter) Format(entry *logrus.Entry) ([]byte, error) { f.callback(entry) return f.empty, nil } - -// SendLogsToCoder returns a function that will automatically queue and -// debounce logs to send to Coder. -func SendLogsToCoder(ctx context.Context, client *agentsdk.Client, logf func(format string, args ...any)) (func(log agentsdk.StartupLog), func(), error) { - // Initialize variables for log management - queuedLogs := make([]agentsdk.StartupLog, 0) - var flushLogsTimer *time.Timer - var logMutex sync.Mutex - logsFlushed := sync.NewCond(&sync.Mutex{}) - var logsSending bool - defer func() { - logMutex.Lock() - if flushLogsTimer != nil { - flushLogsTimer.Stop() - } - logMutex.Unlock() - }() - - // sendLogs function uploads the queued logs to the server - sendLogs := func() { - // Lock logMutex and check if logs are already being sent - logMutex.Lock() - if logsSending { - logMutex.Unlock() - return - } - if flushLogsTimer != nil { - flushLogsTimer.Stop() - } - if len(queuedLogs) == 0 { - logMutex.Unlock() - return - } - // Move the current queued logs to logsToSend and clear the queue - logsToSend := queuedLogs - logsSending = true - queuedLogs = make([]agentsdk.StartupLog, 0) - logMutex.Unlock() - - // Retry uploading logs until successful or a specific error occurs - for r := retry.New(time.Second, 5*time.Second); r.Wait(ctx); { - err := client.PatchStartupLogs(ctx, agentsdk.PatchStartupLogs{ - Logs: logsToSend, - }) - if err == nil { - break - } - var sdkErr *codersdk.Error - if errors.As(err, &sdkErr) { - if sdkErr.StatusCode() == http.StatusRequestEntityTooLarge { - logf("startup logs too large, dropping logs") - break - } - if sdkErr.StatusCode() == http.StatusUnauthorized { - // We just retry! It's likely the build hasn't completed yet. - continue - } - } - logf("upload startup logs (queued %d): %s", len(logsToSend), err) - } - // Reset logsSending flag - logMutex.Lock() - logsSending = false - flushLogsTimer.Reset(100 * time.Millisecond) - logMutex.Unlock() - logsFlushed.Broadcast() - } - // queueLog function appends a log to the queue and triggers sendLogs if necessary - queueLog := func(log agentsdk.StartupLog) { - logMutex.Lock() - defer logMutex.Unlock() - - // Append log to the queue - queuedLogs = append(queuedLogs, log) - - // If there are more than 100 logs, send them immediately - if len(queuedLogs) > 100 { - // Don't early return after this, because we still want - // to reset the timer just in case logs come in while - // we're sending. - go sendLogs() - } - // Reset or set the flushLogsTimer to trigger sendLogs after 100 milliseconds - if flushLogsTimer != nil { - flushLogsTimer.Reset(100 * time.Millisecond) - return - } - flushLogsTimer = time.AfterFunc(100*time.Millisecond, sendLogs) - } - - return func(log agentsdk.StartupLog) { - queueLog(log) - }, func() { - logMutex.Lock() - defer logMutex.Unlock() - for len(queuedLogs) > 0 || logsSending { - logsFlushed.Wait() - } - }, nil -} diff --git a/log_test.go b/log_test.go index 0bc3f920..63d5e6cd 100644 --- a/log_test.go +++ b/log_test.go @@ -1,18 +1,11 @@ package envbuilder_test import ( - "context" - "encoding/json" - "net/http" - "net/http/httptest" - "net/url" "testing" - "github.com/coder/coder/codersdk/agentsdk" "github.com/coder/envbuilder" "github.com/sirupsen/logrus" "github.com/stretchr/testify/require" - "github.com/zeebo/assert" ) func TestHijackLogrus(t *testing.T) { @@ -24,28 +17,3 @@ func TestHijackLogrus(t *testing.T) { message := <-messages require.Equal(t, "Testing!", message.Message) } - -func TestSendLogsToCoder(t *testing.T) { - t.Parallel() - queued := make(chan agentsdk.PatchStartupLogs, 1) - srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - var req agentsdk.PatchStartupLogs - err := json.NewDecoder(r.Body).Decode(&req) - assert.NoError(t, err) - queued <- req - })) - srvURL, err := url.Parse(srv.URL) - require.NoError(t, err) - client := agentsdk.New(srvURL) - sendLog, closeFunc, err := envbuilder.SendLogsToCoder(context.Background(), client, func(format string, args ...any) { - t.Logf(format, args...) - }) - require.NoError(t, err) - defer closeFunc() - sendLog(agentsdk.StartupLog{ - Output: "Hello, world!", - }) - logs := <-queued - require.Len(t, logs.Logs, 1) - require.Equal(t, "Hello, world!", logs.Logs[0].Output) -}