From 4403980c265ef31cbdc15a1aa89c090000c6232e Mon Sep 17 00:00:00 2001 From: Integralist Date: Tue, 19 Sep 2023 09:53:52 +0100 Subject: [PATCH 01/60] refactor(main): simplify/clean-up flow --- cmd/fastly/main.go | 75 +++++++++++++++++++--------------------------- pkg/env/env.go | 14 +++++++++ 2 files changed, 44 insertions(+), 45 deletions(-) diff --git a/cmd/fastly/main.go b/cmd/fastly/main.go index 92e9c3fa1..b837f45fe 100644 --- a/cmd/fastly/main.go +++ b/cmd/fastly/main.go @@ -6,13 +6,15 @@ import ( "io" "net/http" "os" - "strings" "time" + "github.com/fastly/go-fastly/v8/fastly" "github.com/fatih/color" + "github.com/fastly/cli/pkg/api" "github.com/fastly/cli/pkg/app" "github.com/fastly/cli/pkg/config" + "github.com/fastly/cli/pkg/env" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/github" "github.com/fastly/cli/pkg/manifest" @@ -21,28 +23,24 @@ import ( ) func main() { - // Some configuration options can come from env vars. - var env config.Environment - env.Read(parseEnv(os.Environ())) + // Parse the arguments provided by the user via the command-line interface. + args := os.Args[1:] - // All of the work of building the set of commands and subcommands, wiring - // them together, picking which one to call, and executing it, occurs in a - // helper function, Run. We parameterize all of the dependencies so we can - // test it more easily. Here, we declare all of the dependencies, using - // the "real" versions that pull e.g. actual commandline arguments, the - // user's real environment, etc. + // Define a HTTP client that will be used for making arbitrary HTTP requests. + httpClient := &http.Client{Timeout: time.Minute * 2} + + // Define the standard input/output streams. var ( - args = os.Args[1:] - clientFactory = app.FastlyAPIClient - httpClient = &http.Client{Timeout: time.Minute * 2} - in io.Reader = os.Stdin - out io.Writer = sync.NewWriter(color.Output) + in io.Reader = os.Stdin + out io.Writer = sync.NewWriter(color.Output) ) - // We have to manually handle the inclusion of the verbose flag here because - // Kingpin doesn't evaluate the provided arguments until app.Run which - // happens later in the file and yet we need to know if we should be printing - // output related to the application configuration file in this file. + // Read relevant configuration options from the user's environment. + var e config.Environment + e.Read(env.Parse(os.Environ())) + + // Identify verbose flag early (before Kingpin parser has executed) so we can + // print additional output related to the CLI configuration. var verboseOutput bool for _, seg := range args { if seg == "-v" || seg == "--verbose" { @@ -50,9 +48,9 @@ func main() { } } - // Similarly for the --auto-yes/--non-interactive flags, we need access to - // these for handling interactive error prompts to the user, in case the CLI - // is being run in a CI environment. + // Identify auto-yes/non-interactive flag early (before Kingpin parser has + // executed) so we can handle the interactive prompts appropriately with + // regards to processing the CLI configuration. var autoYes, nonInteractive bool for _, seg := range args { if seg == "-y" || seg == "--auto-yes" { @@ -63,20 +61,19 @@ func main() { } } - // Extract a subset of configuration options from the local application directory. + // Extract a subset of configuration options from the local app directory. var cfg config.File cfg.SetAutoYes(autoYes) cfg.SetNonInteractive(nonInteractive) - // The CLI relies on a valid configuration, otherwise we can't continue. err := cfg.Read(config.FilePath, in, out, fsterr.Log, verboseOutput) if err != nil { fsterr.Deduce(err).Print(color.Error) - // WARNING: os.Exit will exit, and any `defer` calls will not be run. os.Exit(1) } + // Extract user's project configuration from the fastly.toml manifest. var md manifest.Data md.File.Args = args md.File.SetErrLog(fsterr.Log) @@ -85,13 +82,16 @@ func main() { // NOTE: We skip handling the error because not all commands relate to Compute. _ = md.File.Read(manifest.Filename) - // Main is basically just a shim to call Run, so we do that here. - opts := app.RunOpts{ - APIClient: clientFactory, + // The `main` function is a shim for calling `app.Run()`. + err = app.Run(app.RunOpts{ + APIClient: func(token, endpoint string) (api.Interface, error) { + client, err := fastly.NewClientForEndpoint(token, endpoint) + return client, err + }, Args: args, ConfigFile: cfg, ConfigPath: config.FilePath, - Env: env, + Env: e, ErrLog: fsterr.Log, HTTPClient: httpClient, Manifest: &md, @@ -112,8 +112,7 @@ func main() { Version: md.File.LocalServer.ViceroyVersion, }), }, - } - err = app.Run(opts) + }) // NOTE: We persist any error log entries to disk before attempting to handle // a possible error response from app.Run as there could be errors recorded @@ -124,7 +123,6 @@ func main() { if logErr != nil { fsterr.Deduce(logErr).Print(color.Error) } - if err != nil { text.Break(out) fsterr.Deduce(err).Print(color.Error) @@ -137,16 +135,3 @@ func main() { os.Exit(1) } } - -func parseEnv(environ []string) map[string]string { - env := map[string]string{} - for _, kv := range environ { - toks := strings.SplitN(kv, "=", 2) - if len(toks) != 2 { - continue - } - k, v := toks[0], toks[1] - env[k] = v - } - return env -} diff --git a/pkg/env/env.go b/pkg/env/env.go index 645553712..83bd511df 100644 --- a/pkg/env/env.go +++ b/pkg/env/env.go @@ -26,6 +26,20 @@ const ( CustomerID = "FASTLY_CUSTOMER_ID" ) +// Parse transforms the local environment data structure into a map type. +func Parse(environ []string) map[string]string { + env := map[string]string{} + for _, kv := range environ { + toks := strings.SplitN(kv, "=", 2) + if len(toks) != 2 { + continue + } + k, v := toks[0], toks[1] + env[k] = v + } + return env +} + // Vars returns a slice of environment variables appropriate to platform. // *nix: $HOME, $USER, ... // Windows: %HOME%, %USER%, ... From a37fd6b501692db3bd98936e19c8abdb7477f6d3 Mon Sep 17 00:00:00 2001 From: Integralist Date: Tue, 19 Sep 2023 11:08:17 +0100 Subject: [PATCH 02/60] refactor: pass wasmtools versioner throughout codebase --- cmd/fastly/main.go | 6 ++++++ pkg/app/commands.go | 4 ++-- pkg/app/run.go | 5 +++-- pkg/commands/compute/build.go | 6 +++++- pkg/commands/compute/compute_test.go | 8 ++++---- pkg/commands/compute/init.go | 18 +++++++++++------- pkg/commands/compute/serve.go | 20 ++++++++++---------- 7 files changed, 41 insertions(+), 26 deletions(-) diff --git a/cmd/fastly/main.go b/cmd/fastly/main.go index b837f45fe..021f3c151 100644 --- a/cmd/fastly/main.go +++ b/cmd/fastly/main.go @@ -111,6 +111,12 @@ func main() { Binary: "viceroy", Version: md.File.LocalServer.ViceroyVersion, }), + WasmTools: github.New(github.Opts{ + HTTPClient: httpClient, + Org: "bytecodealliance", + Repo: "wasm-tools", + Binary: "wasm-tools", + }), }, }) diff --git a/pkg/app/commands.go b/pkg/app/commands.go index c69bc8848..968e6763d 100644 --- a/pkg/app/commands.go +++ b/pkg/app/commands.go @@ -111,11 +111,11 @@ func defineCommands( backendList := backend.NewListCommand(backendCmdRoot.CmdClause, g, m) backendUpdate := backend.NewUpdateCommand(backendCmdRoot.CmdClause, g, m) computeCmdRoot := compute.NewRootCommand(app, g) - computeBuild := compute.NewBuildCommand(computeCmdRoot.CmdClause, g) + computeBuild := compute.NewBuildCommand(computeCmdRoot.CmdClause, g, opts.Versioners.WasmTools) computeDeploy := compute.NewDeployCommand(computeCmdRoot.CmdClause, g) computeHashFiles := compute.NewHashFilesCommand(computeCmdRoot.CmdClause, g, computeBuild) computeHashsum := compute.NewHashsumCommand(computeCmdRoot.CmdClause, g, computeBuild) - computeInit := compute.NewInitCommand(computeCmdRoot.CmdClause, g, m) + computeInit := compute.NewInitCommand(computeCmdRoot.CmdClause, g, m, opts.Versioners.WasmTools) computePack := compute.NewPackCommand(computeCmdRoot.CmdClause, g, m) computePublish := compute.NewPublishCommand(computeCmdRoot.CmdClause, g, computeBuild, computeDeploy) computeServe := compute.NewServeCommand(computeCmdRoot.CmdClause, g, computeBuild, opts.Versioners.Viceroy) diff --git a/pkg/app/run.go b/pkg/app/run.go index f04de52aa..d17fcd993 100644 --- a/pkg/app/run.go +++ b/pkg/app/run.go @@ -212,8 +212,9 @@ type APIClientFactory func(token, endpoint string, debugMode bool) (api.Interfac // Versioners represents all supported versioner types. type Versioners struct { - CLI github.AssetVersioner - Viceroy github.AssetVersioner + CLI github.AssetVersioner + Viceroy github.AssetVersioner + WasmTools github.AssetVersioner } // displayTokenSource prints the token source. diff --git a/pkg/commands/compute/build.go b/pkg/commands/compute/build.go index f69e2273f..31657188f 100644 --- a/pkg/commands/compute/build.go +++ b/pkg/commands/compute/build.go @@ -17,6 +17,7 @@ import ( "github.com/fastly/cli/pkg/cmd" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/filesystem" + "github.com/fastly/cli/pkg/github" "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/text" @@ -42,6 +43,7 @@ type Flags struct { // BuildCommand produces a deployable artifact from files on the local disk. type BuildCommand struct { cmd.Base + wasmtoolsVersioner github.AssetVersioner // NOTE: these are public so that the "serve" and "publish" composite // commands can set the values appropriately before calling Exec(). @@ -49,9 +51,11 @@ type BuildCommand struct { } // NewBuildCommand returns a usable command registered under the parent. -func NewBuildCommand(parent cmd.Registerer, g *global.Data) *BuildCommand { +func NewBuildCommand(parent cmd.Registerer, g *global.Data, wasmtoolsVersioner github.AssetVersioner) *BuildCommand { var c BuildCommand c.Globals = g + c.wasmtoolsVersioner = wasmtoolsVersioner + c.CmdClause = parent.Command("build", "Build a Compute package locally") // NOTE: when updating these flags, be sure to update the composite commands: diff --git a/pkg/commands/compute/compute_test.go b/pkg/commands/compute/compute_test.go index 5de982a2e..66933bd63 100644 --- a/pkg/commands/compute/compute_test.go +++ b/pkg/commands/compute/compute_test.go @@ -23,7 +23,7 @@ func TestPublishFlagDivergence(t *testing.T) { acmd := kingpin.New("foo", "bar") rcmd := compute.NewRootCommand(acmd, &g) - bcmd := compute.NewBuildCommand(rcmd.CmdClause, &g) + bcmd := compute.NewBuildCommand(rcmd.CmdClause, &g, nil) dcmd := compute.NewDeployCommand(rcmd.CmdClause, &g) pcmd := compute.NewPublishCommand(rcmd.CmdClause, &g, bcmd, dcmd) @@ -68,7 +68,7 @@ func TestServeFlagDivergence(t *testing.T) { acmd := kingpin.New("foo", "bar") rcmd := compute.NewRootCommand(acmd, &cfg) - bcmd := compute.NewBuildCommand(rcmd.CmdClause, &cfg) + bcmd := compute.NewBuildCommand(rcmd.CmdClause, &cfg, nil) scmd := compute.NewServeCommand(rcmd.CmdClause, &cfg, bcmd, versioner) buildFlags := getFlags(bcmd.CmdClause) @@ -120,7 +120,7 @@ func TestHashsumFlagDivergence(t *testing.T) { acmd := kingpin.New("foo", "bar") rcmd := compute.NewRootCommand(acmd, &cfg) - bcmd := compute.NewBuildCommand(rcmd.CmdClause, &cfg) + bcmd := compute.NewBuildCommand(rcmd.CmdClause, &cfg, nil) hcmd := compute.NewHashsumCommand(rcmd.CmdClause, &cfg, bcmd) buildFlags := getFlags(bcmd.CmdClause) @@ -164,7 +164,7 @@ func TestHashfilesFlagDivergence(t *testing.T) { acmd := kingpin.New("foo", "bar") rcmd := compute.NewRootCommand(acmd, &cfg) - bcmd := compute.NewBuildCommand(rcmd.CmdClause, &cfg) + bcmd := compute.NewBuildCommand(rcmd.CmdClause, &cfg, nil) hcmd := compute.NewHashFilesCommand(rcmd.CmdClause, &cfg, bcmd) buildFlags := getFlags(bcmd.CmdClause) diff --git a/pkg/commands/compute/init.go b/pkg/commands/compute/init.go index 55577cdc6..44d098953 100644 --- a/pkg/commands/compute/init.go +++ b/pkg/commands/compute/init.go @@ -23,6 +23,7 @@ import ( fstexec "github.com/fastly/cli/pkg/exec" "github.com/fastly/cli/pkg/file" "github.com/fastly/cli/pkg/filesystem" + "github.com/fastly/cli/pkg/github" "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/profile" @@ -39,22 +40,25 @@ var ( type InitCommand struct { cmd.Base - branch string - dir string - cloneFrom string - language string - manifest manifest.Data - tag string + branch string + dir string + cloneFrom string + language string + manifest manifest.Data + tag string + wasmtoolsVersioner github.AssetVersioner } // Languages is a list of supported language options. var Languages = []string{"rust", "javascript", "go", "other"} // NewInitCommand returns a usable command registered under the parent. -func NewInitCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *InitCommand { +func NewInitCommand(parent cmd.Registerer, g *global.Data, m manifest.Data, wasmtoolsVersioner github.AssetVersioner) *InitCommand { var c InitCommand c.Globals = g c.manifest = m + c.wasmtoolsVersioner = wasmtoolsVersioner + c.CmdClause = parent.Command("init", "Initialize a new Compute package locally") c.CmdClause.Flag("directory", "Destination to write the new package, defaulting to the current directory").Short('p').StringVar(&c.dir) c.CmdClause.Flag("author", "Author(s) of the package").Short('a').StringsVar(&c.manifest.File.Authors) diff --git a/pkg/commands/compute/serve.go b/pkg/commands/compute/serve.go index 9ea76d378..1bd5217d8 100644 --- a/pkg/commands/compute/serve.go +++ b/pkg/commands/compute/serve.go @@ -42,8 +42,8 @@ var viceroyError = fsterr.RemediationError{ // ServeCommand produces and runs an artifact from files on the local disk. type ServeCommand struct { cmd.Base - build *BuildCommand - av github.AssetVersioner + build *BuildCommand + viceroyVersioner github.AssetVersioner // Build fields dir cmd.OptionalString @@ -67,11 +67,11 @@ type ServeCommand struct { } // NewServeCommand returns a usable command registered under the parent. -func NewServeCommand(parent cmd.Registerer, g *global.Data, build *BuildCommand, av github.AssetVersioner) *ServeCommand { +func NewServeCommand(parent cmd.Registerer, g *global.Data, build *BuildCommand, viceroyVersioner github.AssetVersioner) *ServeCommand { var c ServeCommand c.build = build - c.av = av + c.viceroyVersioner = viceroyVersioner c.Globals = g c.CmdClause = parent.Command("serve", "Build and run a Compute package locally") @@ -163,13 +163,13 @@ func (c *ServeCommand) Exec(in io.Reader, out io.Writer) (err error) { if err != nil { return fmt.Errorf("failed to parse manifest '%s': %w", manifestPath, err) } - c.av.SetRequestedVersion(c.Globals.Manifest.File.LocalServer.ViceroyVersion) + c.viceroyVersioner.SetRequestedVersion(c.Globals.Manifest.File.LocalServer.ViceroyVersion) if c.Globals.Verbose() { text.Info(out, "Fastly manifest set to: %s\n\n", manifestPath) } } - bin, err := GetViceroy(spinner, out, c.av, c.Globals, manifestPath, c.viceroyBinPath, c.forceCheckViceroyLatest) + bin, err := GetViceroy(spinner, out, c.viceroyVersioner, c.Globals, manifestPath, c.viceroyBinPath, c.forceCheckViceroyLatest) if err != nil { return err } @@ -293,7 +293,7 @@ func (c *ServeCommand) setBackendsWithDefaultOverrideHostIfMissing(out io.Writer func GetViceroy( spinner text.Spinner, out io.Writer, - av github.AssetVersioner, + viceroyVersioner github.AssetVersioner, g *global.Data, manifestPath, viceroyBinPath string, forceCheckViceroyLatest bool, @@ -317,7 +317,7 @@ func GetViceroy( return filepath.Abs(path) } - bin = filepath.Join(InstallDir, av.BinaryName()) + bin = filepath.Join(InstallDir, viceroyVersioner.BinaryName()) // NOTE: When checking if Viceroy is installed we don't use // exec.LookPath("viceroy") because PATH is unreliable across OS platforms, @@ -351,7 +351,7 @@ func GetViceroy( // If the user hasn't explicitly set a Viceroy version, then we'll use // whatever the latest version is. versionToInstall := "latest" - if v := av.RequestedVersion(); v != "" { + if v := viceroyVersioner.RequestedVersion(); v != "" { versionToInstall = v if _, err := semver.Parse(versionToInstall); err != nil { @@ -362,7 +362,7 @@ func GetViceroy( } } - err = installViceroy(installedVersion, versionToInstall, manifestPath, forceCheckViceroyLatest, spinner, av, bin, g) + err = installViceroy(installedVersion, versionToInstall, manifestPath, forceCheckViceroyLatest, spinner, viceroyVersioner, bin, g) if err != nil { g.ErrLog.Add(err) return bin, err From d0ff38b9bf7e042bb586cde0c43a1351bc6b5227 Mon Sep 17 00:00:00 2001 From: Integralist Date: Tue, 19 Sep 2023 11:14:55 +0100 Subject: [PATCH 03/60] refactor(version): clarify versioner used --- pkg/commands/version/root.go | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/pkg/commands/version/root.go b/pkg/commands/version/root.go index 7c3ce6679..b7d7928e5 100644 --- a/pkg/commands/version/root.go +++ b/pkg/commands/version/root.go @@ -7,12 +7,13 @@ import ( "path/filepath" "strings" + "github.com/fastly/go-fastly/v8/fastly" + "github.com/fastly/cli/pkg/cmd" "github.com/fastly/cli/pkg/commands/compute" "github.com/fastly/cli/pkg/github" "github.com/fastly/cli/pkg/revision" "github.com/fastly/cli/pkg/useragent" - "github.com/fastly/go-fastly/v8/fastly" ) func init() { @@ -27,13 +28,13 @@ func init() { // It should be installed under the primary root command. type RootCommand struct { cmd.Base - av github.AssetVersioner + viceroyVersioner github.AssetVersioner } // NewRootCommand returns a new command registered in the parent. -func NewRootCommand(parent cmd.Registerer, av github.AssetVersioner) *RootCommand { +func NewRootCommand(parent cmd.Registerer, viceroyVersioner github.AssetVersioner) *RootCommand { var c RootCommand - c.av = av + c.viceroyVersioner = viceroyVersioner c.CmdClause = parent.Command("version", "Display version information for the Fastly CLI") return &c } @@ -43,7 +44,7 @@ func (c *RootCommand) Exec(_ io.Reader, out io.Writer) error { fmt.Fprintf(out, "Fastly CLI version %s (%s)\n", revision.AppVersion, revision.GitCommit) fmt.Fprintf(out, "Built with %s\n", revision.GoVersion) - viceroy := filepath.Join(compute.InstallDir, c.av.BinaryName()) + viceroy := filepath.Join(compute.InstallDir, c.viceroyVersioner.BinaryName()) // gosec flagged this: // G204 (CWE-78): Subprocess launched with variable // Disabling as we lookup the binary in a trusted location. For this to be a From e98f808bf846aaeba45a6b7d36ef8ed45ccfc7d7 Mon Sep 17 00:00:00 2001 From: Integralist Date: Tue, 19 Sep 2023 11:24:33 +0100 Subject: [PATCH 04/60] refactor(compute/init): sort flags --- pkg/commands/compute/init.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pkg/commands/compute/init.go b/pkg/commands/compute/init.go index 44d098953..1427c96d7 100644 --- a/pkg/commands/compute/init.go +++ b/pkg/commands/compute/init.go @@ -62,9 +62,10 @@ func NewInitCommand(parent cmd.Registerer, g *global.Data, m manifest.Data, wasm c.CmdClause = parent.Command("init", "Initialize a new Compute package locally") c.CmdClause.Flag("directory", "Destination to write the new package, defaulting to the current directory").Short('p').StringVar(&c.dir) c.CmdClause.Flag("author", "Author(s) of the package").Short('a').StringsVar(&c.manifest.File.Authors) - c.CmdClause.Flag("language", "Language of the package").Short('l').HintOptions(Languages...).EnumVar(&c.language, Languages...) - c.CmdClause.Flag("from", "Local project directory, or Git repository URL, or URL referencing a .zip/.tar.gz file, containing a package template").Short('f').StringVar(&c.cloneFrom) c.CmdClause.Flag("branch", "Git branch name to clone from package template repository").Hidden().StringVar(&c.branch) + c.CmdClause.Flag("directory", "Destination to write the new package, defaulting to the current directory").Short('p').StringVar(&c.dir) + c.CmdClause.Flag("from", "Local project directory, or Git repository URL, or URL referencing a .zip/.tar.gz file, containing a package template").Short('f').StringVar(&c.cloneFrom) + c.CmdClause.Flag("language", "Language of the package").Short('l').HintOptions(Languages...).EnumVar(&c.language, Languages...) c.CmdClause.Flag("tag", "Git tag name to clone from package template repository").Hidden().StringVar(&c.tag) return &c From c61fe49463a4fe444ea45d423c97d07ab456c532 Mon Sep 17 00:00:00 2001 From: Integralist Date: Tue, 19 Sep 2023 11:33:15 +0100 Subject: [PATCH 05/60] refactor: move InstallDir to github package --- pkg/commands/compute/serve.go | 18 +----------------- pkg/commands/compute/serve_test.go | 3 ++- pkg/commands/version/root.go | 3 +-- pkg/commands/version/version_test.go | 7 +++---- pkg/github/github.go | 15 +++++++++++++++ 5 files changed, 22 insertions(+), 24 deletions(-) diff --git a/pkg/commands/compute/serve.go b/pkg/commands/compute/serve.go index 1bd5217d8..4579d5316 100644 --- a/pkg/commands/compute/serve.go +++ b/pkg/commands/compute/serve.go @@ -317,7 +317,7 @@ func GetViceroy( return filepath.Abs(path) } - bin = filepath.Join(InstallDir, viceroyVersioner.BinaryName()) + bin = filepath.Join(github.InstallDir, viceroyVersioner.BinaryName()) // NOTE: When checking if Viceroy is installed we don't use // exec.LookPath("viceroy") because PATH is unreliable across OS platforms, @@ -386,22 +386,6 @@ func checkViceroyEnvVar(value string) bool { return false } -// InstallDir represents the directory where the Viceroy binary should be -// installed. -// -// NOTE: This is a package level variable as it makes testing the behaviour of -// the package easier because the test code can replace the value when running -// the test suite. -var InstallDir = func() string { - if dir, err := os.UserConfigDir(); err == nil { - return filepath.Join(dir, "fastly") - } - if dir, err := os.UserHomeDir(); err == nil { - return filepath.Join(dir, ".fastly") - } - panic("unable to deduce user config dir or user home dir") -}() - // installViceroy downloads the binary from GitHub. // // The logic flow is as follows: diff --git a/pkg/commands/compute/serve_test.go b/pkg/commands/compute/serve_test.go index 61fa8aac9..4255bdd27 100644 --- a/pkg/commands/compute/serve_test.go +++ b/pkg/commands/compute/serve_test.go @@ -10,6 +10,7 @@ import ( "github.com/fastly/cli/pkg/commands/compute" "github.com/fastly/cli/pkg/config" fsterr "github.com/fastly/cli/pkg/errors" + "github.com/fastly/cli/pkg/github" "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/mock" "github.com/fastly/cli/pkg/testutil" @@ -63,7 +64,7 @@ func TestGetViceroy(t *testing.T) { } defer os.Chdir(wd) - compute.InstallDir = installDir + github.InstallDir = installDir var out bytes.Buffer diff --git a/pkg/commands/version/root.go b/pkg/commands/version/root.go index b7d7928e5..8e91557d6 100644 --- a/pkg/commands/version/root.go +++ b/pkg/commands/version/root.go @@ -10,7 +10,6 @@ import ( "github.com/fastly/go-fastly/v8/fastly" "github.com/fastly/cli/pkg/cmd" - "github.com/fastly/cli/pkg/commands/compute" "github.com/fastly/cli/pkg/github" "github.com/fastly/cli/pkg/revision" "github.com/fastly/cli/pkg/useragent" @@ -44,7 +43,7 @@ func (c *RootCommand) Exec(_ io.Reader, out io.Writer) error { fmt.Fprintf(out, "Fastly CLI version %s (%s)\n", revision.AppVersion, revision.GitCommit) fmt.Fprintf(out, "Built with %s\n", revision.GoVersion) - viceroy := filepath.Join(compute.InstallDir, c.viceroyVersioner.BinaryName()) + viceroy := filepath.Join(github.InstallDir, c.viceroyVersioner.BinaryName()) // gosec flagged this: // G204 (CWE-78): Subprocess launched with variable // Disabling as we lookup the binary in a trusted location. For this to be a diff --git a/pkg/commands/version/version_test.go b/pkg/commands/version/version_test.go index 4ecc2cf77..26c5c31c9 100644 --- a/pkg/commands/version/version_test.go +++ b/pkg/commands/version/version_test.go @@ -10,7 +10,6 @@ import ( "testing" "github.com/fastly/cli/pkg/app" - "github.com/fastly/cli/pkg/commands/compute" "github.com/fastly/cli/pkg/github" "github.com/fastly/cli/pkg/testutil" ) @@ -49,10 +48,10 @@ func TestVersion(t *testing.T) { } // Override the InstallDir where the viceroy binary is looked up. - orgInstallDir := compute.InstallDir - compute.InstallDir = rootdir + orgInstallDir := github.InstallDir + github.InstallDir = rootdir defer func() { - compute.InstallDir = orgInstallDir + github.InstallDir = orgInstallDir }() // Before running the test, chdir into the temp environment. diff --git a/pkg/github/github.go b/pkg/github/github.go index b88dec3d4..1816a9162 100644 --- a/pkg/github/github.go +++ b/pkg/github/github.go @@ -22,6 +22,21 @@ const ( metadataURL = "https://developer.fastly.com/api/internal/releases/meta/%s/%s/%s" ) +// InstallDir represents the directory where the assets should be installed. +// +// NOTE: This is a package level variable as it makes testing the behaviour of +// the package easier because the test code can replace the value when running +// the test suite. +var InstallDir = func() string { + if dir, err := os.UserConfigDir(); err == nil { + return filepath.Join(dir, "fastly") + } + if dir, err := os.UserHomeDir(); err == nil { + return filepath.Join(dir, ".fastly") + } + panic("unable to deduce user config dir or user home dir") +}() + // New returns a usable asset. func New(opts Opts) *Asset { binary := opts.Binary From 68d117ce14764a9c8a437d6efaf4f2fe10ec7813 Mon Sep 17 00:00:00 2001 From: Integralist Date: Tue, 19 Sep 2023 12:01:30 +0100 Subject: [PATCH 06/60] refactor: move setBinPerms to github package --- pkg/commands/compute/serve.go | 16 +--------------- pkg/github/github.go | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/pkg/commands/compute/serve.go b/pkg/commands/compute/serve.go index 4579d5316..5ae7dcfd3 100644 --- a/pkg/commands/compute/serve.go +++ b/pkg/commands/compute/serve.go @@ -368,7 +368,7 @@ func GetViceroy( return bin, err } - err = setBinPerms(bin) + err = github.SetBinPerms(bin) if err != nil { g.ErrLog.Add(err) return bin, err @@ -531,20 +531,6 @@ func installViceroy( return spinner.Stop() } -// setBinPerms ensures 0777 perms are set on the Viceroy binary. -func setBinPerms(bin string) error { - // G302 (CWE-276): Expect file permissions to be 0600 or less - // gosec flagged this: - // Disabling as the file was not executable without it and we need all users - // to be able to execute the binary. - /* #nosec */ - err := os.Chmod(bin, 0o777) - if err != nil { - return fmt.Errorf("error setting executable permissions on Viceroy binary: %w", err) - } - return nil -} - // localOpts represents the inputs for `local()`. type localOpts struct { addr string diff --git a/pkg/github/github.go b/pkg/github/github.go index 1816a9162..280e3636e 100644 --- a/pkg/github/github.go +++ b/pkg/github/github.go @@ -337,3 +337,17 @@ func moveExtractedBinary(binName, oldpath string) (path string, err error) { return tmpBin.Name(), nil } + +// SetBinPerms ensures 0777 perms are set on the Viceroy binary. +func SetBinPerms(bin string) error { + // G302 (CWE-276): Expect file permissions to be 0600 or less + // gosec flagged this: + // Disabling as the file was not executable without it and we need all users + // to be able to execute the binary. + // #nosec + err := os.Chmod(bin, 0o777) + if err != nil { + return fmt.Errorf("error setting executable permissions for %s: %w", bin, err) + } + return nil +} From c8055f46b68d5ea3320130ce75ea7e8101b6e338 Mon Sep 17 00:00:00 2001 From: Integralist Date: Tue, 19 Sep 2023 13:41:59 +0100 Subject: [PATCH 07/60] remove(compute/init): wasm-tools NOTE: It's only needed for after a Wasm binary is produced. --- pkg/app/commands.go | 2 +- pkg/commands/compute/init.go | 17 +++++++---------- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/pkg/app/commands.go b/pkg/app/commands.go index 968e6763d..52bfaeeaa 100644 --- a/pkg/app/commands.go +++ b/pkg/app/commands.go @@ -115,7 +115,7 @@ func defineCommands( computeDeploy := compute.NewDeployCommand(computeCmdRoot.CmdClause, g) computeHashFiles := compute.NewHashFilesCommand(computeCmdRoot.CmdClause, g, computeBuild) computeHashsum := compute.NewHashsumCommand(computeCmdRoot.CmdClause, g, computeBuild) - computeInit := compute.NewInitCommand(computeCmdRoot.CmdClause, g, m, opts.Versioners.WasmTools) + computeInit := compute.NewInitCommand(computeCmdRoot.CmdClause, g, m) computePack := compute.NewPackCommand(computeCmdRoot.CmdClause, g, m) computePublish := compute.NewPublishCommand(computeCmdRoot.CmdClause, g, computeBuild, computeDeploy) computeServe := compute.NewServeCommand(computeCmdRoot.CmdClause, g, computeBuild, opts.Versioners.Viceroy) diff --git a/pkg/commands/compute/init.go b/pkg/commands/compute/init.go index 1427c96d7..8f0002d66 100644 --- a/pkg/commands/compute/init.go +++ b/pkg/commands/compute/init.go @@ -23,7 +23,6 @@ import ( fstexec "github.com/fastly/cli/pkg/exec" "github.com/fastly/cli/pkg/file" "github.com/fastly/cli/pkg/filesystem" - "github.com/fastly/cli/pkg/github" "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/profile" @@ -40,24 +39,22 @@ var ( type InitCommand struct { cmd.Base - branch string - dir string - cloneFrom string - language string - manifest manifest.Data - tag string - wasmtoolsVersioner github.AssetVersioner + branch string + dir string + cloneFrom string + language string + manifest manifest.Data + tag string } // Languages is a list of supported language options. var Languages = []string{"rust", "javascript", "go", "other"} // NewInitCommand returns a usable command registered under the parent. -func NewInitCommand(parent cmd.Registerer, g *global.Data, m manifest.Data, wasmtoolsVersioner github.AssetVersioner) *InitCommand { +func NewInitCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *InitCommand { var c InitCommand c.Globals = g c.manifest = m - c.wasmtoolsVersioner = wasmtoolsVersioner c.CmdClause = parent.Command("init", "Initialize a new Compute package locally") c.CmdClause.Flag("directory", "Destination to write the new package, defaulting to the current directory").Short('p').StringVar(&c.dir) From 589a2898c36f1498e7d97ba537a59521cf41f68d Mon Sep 17 00:00:00 2001 From: Integralist Date: Tue, 19 Sep 2023 18:18:25 +0100 Subject: [PATCH 08/60] feat: add wasm-tools versioner --- .fastly/config.toml | 5 +- cmd/fastly/main.go | 2 + pkg/commands/compute/build.go | 197 +++++++++++++++++++++++++++++ pkg/commands/compute/build_test.go | 161 +++++++++++++++++++++++ pkg/config/config.go | 14 +- pkg/github/github.go | 133 +++++++++++++++++-- 6 files changed, 493 insertions(+), 19 deletions(-) diff --git a/.fastly/config.toml b/.fastly/config.toml index 9011bc049..f3a58700a 100644 --- a/.fastly/config.toml +++ b/.fastly/config.toml @@ -1,4 +1,4 @@ -config_version = 4 +config_version = 5 [fastly] api_endpoint = "https://api.fastly.com" @@ -14,5 +14,8 @@ toolchain_constraint_tinygo = ">= 1.18" # Go toolchain constraint for use wit toolchain_constraint = ">= 1.56.1" wasm_wasi_target = "wasm32-wasi" +[wasm-tools] +ttl = "24h" + [viceroy] ttl = "24h" diff --git a/cmd/fastly/main.go b/cmd/fastly/main.go index 021f3c151..6c0725b74 100644 --- a/cmd/fastly/main.go +++ b/cmd/fastly/main.go @@ -116,6 +116,8 @@ func main() { Org: "bytecodealliance", Repo: "wasm-tools", Binary: "wasm-tools", + External: true, + Nested: true, }), }, }) diff --git a/pkg/commands/compute/build.go b/pkg/commands/compute/build.go index 31657188f..bbd2df391 100644 --- a/pkg/commands/compute/build.go +++ b/pkg/commands/compute/build.go @@ -7,6 +7,7 @@ import ( "fmt" "io" "os" + "os/exec" "path/filepath" "strings" "time" @@ -14,7 +15,9 @@ import ( "github.com/kennygrant/sanitize" "github.com/mholt/archiver/v3" + "github.com/fastly/cli/pkg/check" "github.com/fastly/cli/pkg/cmd" + "github.com/fastly/cli/pkg/config" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/filesystem" "github.com/fastly/cli/pkg/github" @@ -30,6 +33,12 @@ const IgnoreFilePath = ".fastlyignore" // either a post_init or post_build script defined. const CustomPostScriptMessage = "This project has a custom post_%s script defined in the %s manifest" +// ErrWasmtoolsNotFound represents an error finding the binary installed. +var ErrWasmtoolsNotFound = fsterr.RemediationError{ + Inner: fmt.Errorf("wasm-tools not found"), + Remediation: fsterr.BugRemediation, +} + // Flags represents the flags defined for the command. type Flags struct { Dir string @@ -107,6 +116,12 @@ func (c *BuildCommand) Exec(in io.Reader, out io.Writer) (err error) { return err } + wasmtools, err := GetWasmTools(spinner, out, c.wasmtoolsVersioner, c.Globals) + if err != nil { + return err + } + fmt.Fprintf(io.Discard, "%#v\n", wasmtools) + defer func(errLog fsterr.LogInterface) { if err != nil { errLog.Add(err) @@ -315,6 +330,188 @@ func (c *BuildCommand) PackageName(manifestFilename string) (string, error) { return sanitize.BaseName(name), nil } +// GetWasmTools returns the path to the wasm-tools binary. +// If there is no version installed, install the latest version. +// If there is a version installed, update to the latest version if not already. +func GetWasmTools(spinner text.Spinner, out io.Writer, wasmtoolsVersioner github.AssetVersioner, g *global.Data) (binPath string, err error) { + binPath = filepath.Join(github.InstallDir, wasmtoolsVersioner.BinaryName()) + + // NOTE: When checking if wasm-tools is installed we don't use $PATH. + // + // $PATH is unreliable across OS platforms, but also we actually install + // wasm-tools in the same location as the CLI's app config, which means it + // wouldn't be found in the $PATH any way. We could pass the path for the app + // config into exec.LookPath() but it's simpler to attempt executing the binary. + // + // gosec flagged this: + // G204 (CWE-78): Subprocess launched with variable + // Disabling as the variables come from trusted sources. + // #nosec + // nosemgrep + c := exec.Command(binPath, "--version") + + var installedVersion string + + stdoutStderr, err := c.CombinedOutput() + if err != nil { + g.ErrLog.Add(err) + } else { + // Check the version output has the expected format: `wasm-tools 1.0.40` + installedVersion = strings.TrimSpace(string(stdoutStderr)) + segs := strings.Split(installedVersion, " ") + if len(segs) < 2 { + return binPath, ErrWasmtoolsNotFound + } + installedVersion = segs[1] + } + + if installedVersion == "" { + if g.Verbose() { + text.Info(out, "wasm-tools is not already installed, so we will install the latest version.") + text.Break(out) + } + err = installLatestWasmtools(binPath, spinner, wasmtoolsVersioner) + if err != nil { + g.ErrLog.Add(err) + return binPath, err + } + + latestVersion, err := wasmtoolsVersioner.LatestVersion() + if err != nil { + return binPath, fmt.Errorf("failed to retrieve wasm-tools latest version: %w", err) + } + + g.Config.WasmTools.LatestVersion = latestVersion + g.Config.WasmTools.LastChecked = time.Now().Format(time.RFC3339) + + err = g.Config.Write(g.ConfigPath) + if err != nil { + return binPath, err + } + } + + if installedVersion != "" { + err = updateWasmtools(binPath, spinner, out, wasmtoolsVersioner, g.Verbose(), installedVersion, g.Config.WasmTools, g.Config, g.ConfigPath) + if err != nil { + g.ErrLog.Add(err) + return binPath, err + } + } + + err = github.SetBinPerms(binPath) + if err != nil { + g.ErrLog.Add(err) + return binPath, err + } + + return binPath, nil +} + +func installLatestWasmtools(binPath string, spinner text.Spinner, wasmtoolsVersioner github.AssetVersioner) error { + err := spinner.Start() + if err != nil { + return err + } + msg := "Fetching latest wasm-tools release" + spinner.Message(msg + "...") + + tmpBin, err := wasmtoolsVersioner.DownloadLatest() + if err != nil { + spinner.StopFailMessage(msg) + spinErr := spinner.StopFail() + if spinErr != nil { + return spinErr + } + return fmt.Errorf("failed to download latest wasm-tools release: %w", err) + } + defer os.RemoveAll(tmpBin) + + if err := os.Rename(tmpBin, binPath); err != nil { + if err := filesystem.CopyFile(tmpBin, binPath); err != nil { + spinner.StopFailMessage(msg) + spinErr := spinner.StopFail() + if spinErr != nil { + return spinErr + } + return fmt.Errorf("failed to move wasm-tools binary to accessible location: %w", err) + } + } + + spinner.StopMessage(msg) + return spinner.Stop() +} + +func updateWasmtools( + binPath string, + spinner text.Spinner, + out io.Writer, + wasmtoolsVersioner github.AssetVersioner, + verbose bool, + installedVersion string, + wasmtoolsConfig config.Versioner, + cfg config.File, + cfgPath string, +) error { + stale := wasmtoolsConfig.LastChecked != "" && wasmtoolsConfig.LatestVersion != "" && check.Stale(wasmtoolsConfig.LastChecked, wasmtoolsConfig.TTL) + if !stale { + if verbose { + text.Info(out, "wasm-tools is installed but the CLI config (`fastly config`) shows the TTL, checking for a newer version, hasn't expired.") + text.Break(out) + } + return nil + } + + err := spinner.Start() + if err != nil { + return err + } + msg := "Checking latest wasm-tools release" + spinner.Message(msg + "...") + + latestVersion, err := wasmtoolsVersioner.LatestVersion() + if err != nil { + spinner.StopFailMessage(msg) + spinErr := spinner.StopFail() + if spinErr != nil { + return spinErr + } + + return fsterr.RemediationError{ + Inner: fmt.Errorf("error fetching latest version: %w", err), + Remediation: fsterr.NetworkRemediation, + } + } + + spinner.StopMessage(msg) + err = spinner.Stop() + if err != nil { + return err + } + + wasmtoolsConfig.LatestVersion = latestVersion + wasmtoolsConfig.LastChecked = time.Now().Format(time.RFC3339) + + // Before attempting to write the config data back to disk we need to + // ensure we reassign the modified struct which is a copy (not reference). + cfg.WasmTools = wasmtoolsConfig + + err = cfg.Write(cfgPath) + if err != nil { + return err + } + + if verbose { + text.Info(out, "The CLI config (`fastly config`) has been updated with the latest wasm-tools version: %s", latestVersion) + text.Break(out) + } + + if installedVersion == latestVersion { + return nil + } + + return installLatestWasmtools(binPath, spinner, wasmtoolsVersioner) +} + // identifyToolchain determines the programming language. // // It prioritises the --language flag over the manifest field. diff --git a/pkg/commands/compute/build_test.go b/pkg/commands/compute/build_test.go index d702850e5..216bdfaa9 100644 --- a/pkg/commands/compute/build_test.go +++ b/pkg/commands/compute/build_test.go @@ -2,6 +2,7 @@ package compute_test import ( "fmt" + "net/http" "os" "os/exec" "path/filepath" @@ -11,7 +12,9 @@ import ( "github.com/fastly/cli/pkg/app" "github.com/fastly/cli/pkg/commands/compute" "github.com/fastly/cli/pkg/config" + "github.com/fastly/cli/pkg/github" "github.com/fastly/cli/pkg/manifest" + "github.com/fastly/cli/pkg/mock" "github.com/fastly/cli/pkg/testutil" "github.com/fastly/cli/pkg/threadsafe" ) @@ -22,6 +25,13 @@ func TestBuildRust(t *testing.T) { t.Skip("Set TEST_COMPUTE_BUILD to run this test") } + wasmtoolsVersioner := github.New(github.Opts{ + HTTPClient: mock.HTMLClient([]*http.Response{}, []error{}), + Org: "bytecodealliance", + Repo: "wasm-tools", + Binary: "wasm-tools", + }) + args := testutil.Args scenarios := []struct { @@ -33,12 +43,16 @@ func TestBuildRust(t *testing.T) { wantError string wantRemediationError string wantOutput []string + versioners *app.Versioners }{ { name: "no fastly.toml manifest", args: args("compute build"), wantError: "error reading fastly.toml", wantRemediationError: "Run `fastly compute init` to ensure a correctly configured manifest.", + versioners: &app.Versioners{ + WasmTools: wasmtoolsVersioner, + }, }, { name: "empty language", @@ -47,6 +61,9 @@ func TestBuildRust(t *testing.T) { manifest_version = 2 name = "test"`, wantError: "language cannot be empty, please provide a language", + versioners: &app.Versioners{ + WasmTools: wasmtoolsVersioner, + }, }, { name: "unknown language", @@ -56,6 +73,9 @@ func TestBuildRust(t *testing.T) { name = "test" language = "foobar"`, wantError: "unsupported language foobar", + versioners: &app.Versioners{ + WasmTools: wasmtoolsVersioner, + }, }, // The following test validates that the project compiles successfully even // though the fastly.toml manifest has no build script. There should be a @@ -90,6 +110,9 @@ func TestBuildRust(t *testing.T) { "The following default build command for", "cargo build --bin my-project", }, + versioners: &app.Versioners{ + WasmTools: wasmtoolsVersioner, + }, }, { name: "build error", @@ -117,6 +140,9 @@ func TestBuildRust(t *testing.T) { [scripts] build = "echo no compilation happening"`, wantRemediationError: compute.DefaultBuildErrorRemediation, + versioners: &app.Versioners{ + WasmTools: wasmtoolsVersioner, + }, }, // NOTE: This test passes --verbose so we can validate specific outputs. { @@ -148,6 +174,9 @@ func TestBuildRust(t *testing.T) { "Creating ./bin directory (for Wasm binary)", "Built package", }, + versioners: &app.Versioners{ + WasmTools: wasmtoolsVersioner, + }, }, } for testcaseIdx := range scenarios { @@ -187,9 +216,17 @@ func TestBuildRust(t *testing.T) { var stdout threadsafe.Buffer opts := testutil.NewRunOpts(testcase.args, &stdout) opts.ConfigFile = testcase.applicationConfig + + if testcase.versioners != nil { + opts.Versioners = *testcase.versioners + } + err = app.Run(opts) + t.Log(stdout.String()) + testutil.AssertRemediationErrorContains(t, err, testcase.wantRemediationError) + // NOTE: Some errors we want to assert only the remediation. // e.g. a 'stat' error isn't the same across operating systems/platforms. if testcase.wantError != "" { @@ -208,6 +245,13 @@ func TestBuildGo(t *testing.T) { t.Skip("Set TEST_COMPUTE_BUILD to run this test") } + wasmtoolsVersioner := github.New(github.Opts{ + HTTPClient: mock.HTMLClient([]*http.Response{}, []error{}), + Org: "bytecodealliance", + Repo: "wasm-tools", + Binary: "wasm-tools", + }) + args := testutil.Args scenarios := []struct { @@ -218,12 +262,16 @@ func TestBuildGo(t *testing.T) { wantError string wantRemediationError string wantOutput []string + versioners *app.Versioners }{ { name: "no fastly.toml manifest", args: args("compute build"), wantError: "error reading fastly.toml", wantRemediationError: "Run `fastly compute init` to ensure a correctly configured manifest.", + versioners: &app.Versioners{ + WasmTools: wasmtoolsVersioner, + }, }, { name: "empty language", @@ -232,6 +280,9 @@ func TestBuildGo(t *testing.T) { manifest_version = 2 name = "test"`, wantError: "language cannot be empty, please provide a language", + versioners: &app.Versioners{ + WasmTools: wasmtoolsVersioner, + }, }, { name: "unknown language", @@ -241,6 +292,9 @@ func TestBuildGo(t *testing.T) { name = "test" language = "foobar"`, wantError: "unsupported language foobar", + versioners: &app.Versioners{ + WasmTools: wasmtoolsVersioner, + }, }, // The following test validates that the project compiles successfully even // though the fastly.toml manifest has no build script. There should be a @@ -275,6 +329,9 @@ func TestBuildGo(t *testing.T) { "Creating ./bin directory (for Wasm binary)", "Built package", }, + versioners: &app.Versioners{ + WasmTools: wasmtoolsVersioner, + }, }, // The following test case is expected to fail because we specify a custom // build script that doesn't actually produce a ./bin/main.wasm @@ -298,6 +355,9 @@ func TestBuildGo(t *testing.T) { [scripts] build = "echo no compilation happening"`, wantRemediationError: compute.DefaultBuildErrorRemediation, + versioners: &app.Versioners{ + WasmTools: wasmtoolsVersioner, + }, }, } for testcaseIdx := range scenarios { @@ -334,9 +394,17 @@ func TestBuildGo(t *testing.T) { var stdout threadsafe.Buffer opts := testutil.NewRunOpts(testcase.args, &stdout) opts.ConfigFile = testcase.applicationConfig + + if testcase.versioners != nil { + opts.Versioners = *testcase.versioners + } + err = app.Run(opts) + t.Log(stdout.String()) + testutil.AssertRemediationErrorContains(t, err, testcase.wantRemediationError) + // NOTE: Some errors we want to assert only the remediation. // e.g. a 'stat' error isn't the same across operating systems/platforms. if testcase.wantError != "" { @@ -355,6 +423,13 @@ func TestBuildJavaScript(t *testing.T) { t.Skip("Set TEST_COMPUTE_BUILD to run this test") } + wasmtoolsVersioner := github.New(github.Opts{ + HTTPClient: mock.HTMLClient([]*http.Response{}, []error{}), + Org: "bytecodealliance", + Repo: "wasm-tools", + Binary: "wasm-tools", + }) + args := testutil.Args scenarios := []struct { @@ -365,12 +440,16 @@ func TestBuildJavaScript(t *testing.T) { wantRemediationError string wantOutput []string npmInstall bool + versioners *app.Versioners }{ { name: "no fastly.toml manifest", args: args("compute build"), wantError: "error reading fastly.toml", wantRemediationError: "Run `fastly compute init` to ensure a correctly configured manifest.", + versioners: &app.Versioners{ + WasmTools: wasmtoolsVersioner, + }, }, { name: "empty language", @@ -379,6 +458,9 @@ func TestBuildJavaScript(t *testing.T) { manifest_version = 2 name = "test"`, wantError: "language cannot be empty, please provide a language", + versioners: &app.Versioners{ + WasmTools: wasmtoolsVersioner, + }, }, { name: "unknown language", @@ -388,6 +470,9 @@ func TestBuildJavaScript(t *testing.T) { name = "test" language = "foobar"`, wantError: "unsupported language foobar", + versioners: &app.Versioners{ + WasmTools: wasmtoolsVersioner, + }, }, // The following test validates that the project compiles successfully even // though the fastly.toml manifest has no build script. There should be a @@ -406,6 +491,9 @@ func TestBuildJavaScript(t *testing.T) { "The following default build command for", "npm exec webpack", // our testdata package.json references webpack }, + versioners: &app.Versioners{ + WasmTools: wasmtoolsVersioner, + }, }, { name: "build error", @@ -418,6 +506,9 @@ func TestBuildJavaScript(t *testing.T) { [scripts] build = "echo no compilation happening"`, wantRemediationError: compute.DefaultBuildErrorRemediation, + versioners: &app.Versioners{ + WasmTools: wasmtoolsVersioner, + }, }, // NOTE: This test passes --verbose so we can validate specific outputs. { @@ -435,6 +526,9 @@ func TestBuildJavaScript(t *testing.T) { "Built package", }, npmInstall: true, + versioners: &app.Versioners{ + WasmTools: wasmtoolsVersioner, + }, }, } for testcaseIdx := range scenarios { @@ -486,9 +580,17 @@ func TestBuildJavaScript(t *testing.T) { var stdout threadsafe.Buffer opts := testutil.NewRunOpts(testcase.args, &stdout) + + if testcase.versioners != nil { + opts.Versioners = *testcase.versioners + } + err = app.Run(opts) + t.Log(stdout.String()) + testutil.AssertRemediationErrorContains(t, err, testcase.wantRemediationError) + // NOTE: Some errors we want to assert only the remediation. // e.g. a 'stat' error isn't the same across operating systems/platforms. if testcase.wantError != "" { @@ -507,6 +609,13 @@ func TestBuildAssemblyScript(t *testing.T) { t.Skip("Set TEST_COMPUTE_BUILD to run this test") } + wasmtoolsVersioner := github.New(github.Opts{ + HTTPClient: mock.HTMLClient([]*http.Response{}, []error{}), + Org: "bytecodealliance", + Repo: "wasm-tools", + Binary: "wasm-tools", + }) + args := testutil.Args scenarios := []struct { @@ -517,12 +626,16 @@ func TestBuildAssemblyScript(t *testing.T) { wantRemediationError string wantOutput []string npmInstall bool + versioners *app.Versioners }{ { name: "no fastly.toml manifest", args: args("compute build"), wantError: "error reading fastly.toml", wantRemediationError: "Run `fastly compute init` to ensure a correctly configured manifest.", + versioners: &app.Versioners{ + WasmTools: wasmtoolsVersioner, + }, }, { name: "empty language", @@ -531,6 +644,9 @@ func TestBuildAssemblyScript(t *testing.T) { manifest_version = 2 name = "test"`, wantError: "language cannot be empty, please provide a language", + versioners: &app.Versioners{ + WasmTools: wasmtoolsVersioner, + }, }, { name: "unknown language", @@ -540,6 +656,9 @@ func TestBuildAssemblyScript(t *testing.T) { name = "test" language = "foobar"`, wantError: "unsupported language foobar", + versioners: &app.Versioners{ + WasmTools: wasmtoolsVersioner, + }, }, // The following test validates that the project compiles successfully even // though the fastly.toml manifest has no build script. There should be a @@ -558,6 +677,9 @@ func TestBuildAssemblyScript(t *testing.T) { "The following default build command for", "npm exec -- asc", }, + versioners: &app.Versioners{ + WasmTools: wasmtoolsVersioner, + }, }, { name: "build error", @@ -570,6 +692,9 @@ func TestBuildAssemblyScript(t *testing.T) { [scripts] build = "echo no compilation happening"`, wantRemediationError: compute.DefaultBuildErrorRemediation, + versioners: &app.Versioners{ + WasmTools: wasmtoolsVersioner, + }, }, // NOTE: This test passes --verbose so we can validate specific outputs. { @@ -587,6 +712,9 @@ func TestBuildAssemblyScript(t *testing.T) { "Built package", }, npmInstall: true, + versioners: &app.Versioners{ + WasmTools: wasmtoolsVersioner, + }, }, } for testcaseIdx := range scenarios { @@ -639,9 +767,17 @@ func TestBuildAssemblyScript(t *testing.T) { var stdout threadsafe.Buffer opts := testutil.NewRunOpts(testcase.args, &stdout) + + if testcase.versioners != nil { + opts.Versioners = *testcase.versioners + } + err = app.Run(opts) + t.Log(stdout.String()) + testutil.AssertRemediationErrorContains(t, err, testcase.wantRemediationError) + // NOTE: Some errors we want to assert only the remediation. // e.g. a 'stat' error isn't the same across operating systems/platforms. if testcase.wantError != "" { @@ -656,6 +792,13 @@ func TestBuildAssemblyScript(t *testing.T) { // NOTE: TestBuildOther also validates the post_build settings. func TestBuildOther(t *testing.T) { + wasmtoolsVersioner := github.New(github.Opts{ + HTTPClient: mock.HTMLClient([]*http.Response{}, []error{}), + Org: "bytecodealliance", + Repo: "wasm-tools", + Binary: "wasm-tools", + }) + args := testutil.Args if os.Getenv("TEST_COMPUTE_BUILD") == "" { t.Log("skipping test") @@ -712,6 +855,7 @@ func TestBuildOther(t *testing.T) { wantError string wantOutput []string wantRemediationError string + versioners *app.Versioners }{ { name: "stop build process", @@ -728,6 +872,9 @@ func TestBuildOther(t *testing.T) { "Do you want to run this now?", }, wantError: "build process stopped by user", + versioners: &app.Versioners{ + WasmTools: wasmtoolsVersioner, + }, }, // NOTE: All following tests pass --verbose so we can see post_build output. { @@ -745,6 +892,9 @@ func TestBuildOther(t *testing.T) { "Do you want to run this now?", "Built package", }, + versioners: &app.Versioners{ + WasmTools: wasmtoolsVersioner, + }, }, { name: "language pulled from manifest", @@ -762,6 +912,9 @@ func TestBuildOther(t *testing.T) { "Do you want to run this now?", "Built package", }, + versioners: &app.Versioners{ + WasmTools: wasmtoolsVersioner, + }, }, { name: "avoid prompt confirmation", @@ -779,6 +932,9 @@ func TestBuildOther(t *testing.T) { "Do you want to run this now?", }, wantError: "exit status 1", // because we have to trigger an error to see the post_build output + versioners: &app.Versioners{ + WasmTools: wasmtoolsVersioner, + }, }, } { t.Run(testcase.name, func(t *testing.T) { @@ -791,6 +947,11 @@ func TestBuildOther(t *testing.T) { var stdout threadsafe.Buffer opts := testutil.NewRunOpts(testcase.args, &stdout) opts.Stdin = strings.NewReader(testcase.stdin) // NOTE: build only has one prompt when dealing with a custom build + + if testcase.versioners != nil { + opts.Versioners = *testcase.versioners + } + err = app.Run(opts) t.Log(stdout.String()) diff --git a/pkg/config/config.go b/pkg/config/config.go index 147cf1248..0daef92c3 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -67,13 +67,14 @@ type CLI struct { Version string `toml:"version"` } -// Viceroy represents viceroy specific configuration. -type Viceroy struct { - // LastChecked is when the version of Viceroy was last checked. +// Versioner represents GitHub assets configuration. +// e.g. viceroy, wasm-tools etc +type Versioner struct { + // LastChecked is when the asset version was last checked. LastChecked string `toml:"last_checked"` - // LatestVersion is the latest Viceroy version at the time it is set. + // LatestVersion is the latest asset version at the time it is set. LatestVersion string `toml:"latest_version"` - // TTL is how long the CLI waits before considering the version stale. + // TTL is how long the CLI waits before considering the asset version stale. TTL string `toml:"ttl"` } @@ -154,7 +155,8 @@ type File struct { Language Language `toml:"language"` Profiles Profiles `toml:"profile"` StarterKits StarterKitLanguages `toml:"starter-kits"` - Viceroy Viceroy `toml:"viceroy"` + Viceroy Versioner `toml:"viceroy"` + WasmTools Versioner `toml:"wasm-tools"` // We store off a possible legacy configuration so that we can later extract // the relevant email and token values that may pre-exist. diff --git a/pkg/github/github.go b/pkg/github/github.go index 280e3636e..a51204ce9 100644 --- a/pkg/github/github.go +++ b/pkg/github/github.go @@ -7,6 +7,7 @@ import ( "net/http" "os" "path/filepath" + "regexp" "runtime" "strings" @@ -46,7 +47,9 @@ func New(opts Opts) *Asset { return &Asset{ binary: binary, + external: opts.External, httpClient: opts.HTTPClient, + nested: opts.Nested, org: opts.Org, repo: opts.Repo, versionRequested: opts.Version, @@ -57,8 +60,15 @@ func New(opts Opts) *Asset { type Opts struct { // Binary is the name of the executable binary. Binary string + // External indicates the repository is a non-Fastly repo. + // This means we need a custom metadata fetcher (i.e. dont use metadataURL). + External bool // HTTPClient is able to make HTTP requests. HTTPClient api.HTTPClient + // Nested indicates if the binary is at the root of the archive or not. + // e.g. wasm-tools archive contains a folder which contains the binary. + // Where as Viceroy and CLI archives directly contain the binary. + Nested bool // Org is a GitHub organisation. Org string // Repo is a GitHub repository. @@ -73,8 +83,12 @@ type Opts struct { type Asset struct { // binary is the name of the executable binary. binary string + // external indicates the repository is a non-Fastly repo. + external bool // httpClient is able to make HTTP requests. httpClient api.HTTPClient + // nested indicates if the binary is at the root of the archive or not. + nested bool // org is a GitHub organisation. org string // repo is a GitHub repository. @@ -146,12 +160,13 @@ func (g *Asset) Download(endpoint string) (bin string, err error) { } defer os.RemoveAll(tmpDir) - archive, err := createArchive(filepath.Base(endpoint), tmpDir, res.Body) + assetBase := filepath.Base(endpoint) + archive, err := createArchive(assetBase, tmpDir, res.Body) if err != nil { return "", err } - extractedBinary, err := extractBinary(archive, g.binary, tmpDir) + extractedBinary, err := extractBinary(archive, g.binary, tmpDir, assetBase, g.nested) if err != nil { return "", err } @@ -206,8 +221,11 @@ func (g *Asset) SetRequestedVersion(version string) { } // metadata acquires GitHub metadata. -func (g *Asset) metadata() (m Metadata, err error) { +func (g *Asset) metadata() (m DevHubMetadata, err error) { endpoint := fmt.Sprintf(metadataURL, g.repo, runtime.GOOS, runtime.GOARCH) + if g.external { + endpoint = fmt.Sprintf("https://api.github.com/repos/%s/%s/releases/latest", g.org, g.repo) + } req, err := http.NewRequest(http.MethodGet, endpoint, nil) if err != nil { @@ -231,6 +249,10 @@ func (g *Asset) metadata() (m Metadata, err error) { return m, fmt.Errorf("failed to read GitHub's metadata response: %w", err) } + if g.external { + return g.parseExternalMetadata(data) + } + err = json.Unmarshal(data, &m) if err != nil { return m, fmt.Errorf("failed to parse GitHub's metadata: %w", err) @@ -239,8 +261,8 @@ func (g *Asset) metadata() (m Metadata, err error) { return m, nil } -// Metadata represents the DevHub API response for software metadata. -type Metadata struct { +// DevHubMetadata represents the DevHub API response for software metadata. +type DevHubMetadata struct { // URL is the endpoint for downloading the release asset. URL string `json:"url"` // Version is the release version of the asset (e.g. 10.1.0). @@ -274,7 +296,7 @@ func createArchive(assetBase, tmpDir string, data io.ReadCloser) (path string, e // G304 (CWE-22): Potential file inclusion via variable // // Disabling as the inputs need to be dynamically determined. - /* #nosec */ + // #nosec archive, err := os.Create(filepath.Join(tmpDir, assetBase)) if err != nil { return "", fmt.Errorf("failed to create a temporary file: %w", err) @@ -292,13 +314,29 @@ func createArchive(assetBase, tmpDir string, data io.ReadCloser) (path string, e return archive.Name(), nil } -// extractBinary extracts the executable binary (e.g. fastly or viceroy) from -// the specified archive file, modifies its permissions and returns the path. -func extractBinary(archive, filename, dst string) (bin string, err error) { - if err := archiver.Extract(archive, filename, dst); err != nil { +// extractBinary extracts the executable binary (e.g. fastly, viceroy, +// wasm-tools) from the specified archive file, modifies its permissions and +// returns the path. +// +// NOTE: wasm-tools binary is within a nested directory. +// So we have to account for that by extracting the directory from the archive +// and then correct the path before attempting to modify the permissions. +func extractBinary(archive, binaryName, dst, assetBase string, nested bool) (bin string, err error) { + extractPath := binaryName + if nested { + // e.g. extract the nested directory "wasm-tools-1.0.42-aarch64-macos" + // which itself contains the `wasm-tools` binary + extractPath = strings.TrimSuffix(assetBase, ".tar.gz") + } + if err := archiver.Extract(archive, extractPath, dst); err != nil { return "", fmt.Errorf("failed to extract binary: %w", err) } - extractedBinary := filepath.Join(dst, filename) + + extractedBinary := filepath.Join(dst, binaryName) + if nested { + // e.g. reference the binary from within the nested directory + extractedBinary = filepath.Join(dst, extractPath, binaryName) + } // G302 (CWE-276): Expect file permissions to be 0600 or less // gosec flagged this: @@ -338,7 +376,7 @@ func moveExtractedBinary(binName, oldpath string) (path string, err error) { return tmpBin.Name(), nil } -// SetBinPerms ensures 0777 perms are set on the Viceroy binary. +// SetBinPerms ensures 0777 perms are set on the binary. func SetBinPerms(bin string) error { // G302 (CWE-276): Expect file permissions to be 0600 or less // gosec flagged this: @@ -351,3 +389,74 @@ func SetBinPerms(bin string) error { } return nil } + +// RawAsset represents a GitHub release asset. +type RawAsset struct { + // BrowserDownloadURL is a fully qualified URL to download the release asset. + BrowserDownloadURL string `json:"browser_download_url"` +} + +// Metadata represents the GitHub API metadata response for releases. +type Metadata struct { + // Name is the release name. + Name string `json:"name"` + // Assets a list of all available assets within the release. + Assets []RawAsset `json:"assets"` + + org, repo, binary string +} + +// Version parses a semver from the name field. +func (m Metadata) Version() string { + r := regexp.MustCompile(`[0-9]+\.[0-9]+\.[0-9]+(-(.*))?`) + return r.FindString(m.Name) +} + +// URL filters the assets for a platform correct asset. +// +// NOTE: This only works with wasm-tools naming conventions. +// If we add more tools to download in future then we can abstract as necessary. +func (m Metadata) URL() string { + platform := runtime.GOOS + if platform == "darwin" { + platform = "macos" + } + + arch := runtime.GOARCH + if arch == "arm64" { + arch = "aarch64" + } + + for _, a := range m.Assets { + version := m.Version() + pattern := fmt.Sprintf("https://github.com/%s/%s/releases/download/%s-%s/%s-%s-%s-%s.tar.gz", m.org, m.repo, m.binary, version, m.binary, version, arch, platform) + if matched, _ := regexp.MatchString(pattern, a.BrowserDownloadURL); matched { + return a.BrowserDownloadURL + } + } + + return "" +} + +// parseExternalMetadata takes the raw GitHub metadata and coerces it into a +// DevHub specific metadata format. +func (g *Asset) parseExternalMetadata(data []byte) (DevHubMetadata, error) { + var ( + dhm DevHubMetadata + m Metadata + ) + + err := json.Unmarshal(data, &m) + if err != nil { + return dhm, fmt.Errorf("failed to parse GitHub's metadata: %w", err) + } + + m.org = g.org + m.repo = g.repo + m.binary = g.binary + + dhm.Version = m.Version() + dhm.URL = m.URL() + + return dhm, nil +} From d51b4e9980c660dd363fc7638404ea5e927e7405 Mon Sep 17 00:00:00 2001 From: Integralist Date: Wed, 20 Sep 2023 11:55:16 +0100 Subject: [PATCH 09/60] feat: add skeleton wasm-tools annotation --- pkg/commands/compute/build.go | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/pkg/commands/compute/build.go b/pkg/commands/compute/build.go index bbd2df391..b460cab5a 100644 --- a/pkg/commands/compute/build.go +++ b/pkg/commands/compute/build.go @@ -120,7 +120,6 @@ func (c *BuildCommand) Exec(in io.Reader, out io.Writer) (err error) { if err != nil { return err } - fmt.Fprintf(io.Discard, "%#v\n", wasmtools) defer func(errLog fsterr.LogInterface) { if err != nil { @@ -188,8 +187,34 @@ func (c *BuildCommand) Exec(in io.Reader, out io.Writer) (err error) { return err } - dest := filepath.Join("pkg", fmt.Sprintf("%s.tar.gz", pkgName)) + args := []string{ + "metadata", "add", "bin/main.wasm", + "--language=whatever", + "--processed-by=FOO=BAR", + "--sdk=BEEP=BOOP", + } + // gosec flagged this: + // G204 (CWE-78): Subprocess launched with function call as argument or command arguments + // Disabling as we trust the source of the variable. + // #nosec + // nosemgrep: go.lang.security.audit.dangerous-exec-command.dangerous-exec-command + command := exec.Command(wasmtools, args...) + wasmtoolsOutput, err := command.Output() + if err != nil { + return fmt.Errorf("failed to annotate binary with metadata: %w", err) + } + // Ensure the Wasm binary can be executed. + // + // G302 (CWE-276): Expect file permissions to be 0600 or less + // gosec flagged this: + // Disabling as we want all users to be able to execute this binary. + // #nosec + err = os.WriteFile("bin/main.wasm", wasmtoolsOutput, 0o777) + if err != nil { + return fmt.Errorf("failed to annotate binary with metadata: %w", err) + } + dest := filepath.Join("pkg", fmt.Sprintf("%s.tar.gz", pkgName)) err = spinner.Process("Creating package archive", func(_ *text.SpinnerWrapper) error { // IMPORTANT: The minimum package requirement is `fastly.toml` and `main.wasm`. // From 241c2678118d554d11315c7e19a2b6bd7d732619 Mon Sep 17 00:00:00 2001 From: Integralist Date: Wed, 20 Sep 2023 13:55:59 +0100 Subject: [PATCH 10/60] feat: add more data to wasm-tools annotation --- pkg/commands/compute/build.go | 28 +++++++++++++++++-- .../compute/language_assemblyscript.go | 18 ++++++++++-- pkg/commands/compute/language_go.go | 14 ++++++++++ pkg/commands/compute/language_javascript.go | 19 ++++++++++--- pkg/commands/compute/language_other.go | 14 ++++++++++ pkg/commands/compute/language_rust.go | 20 ++++++++++--- pkg/commands/compute/language_toolchain.go | 4 +++ 7 files changed, 103 insertions(+), 14 deletions(-) diff --git a/pkg/commands/compute/build.go b/pkg/commands/compute/build.go index b460cab5a..70ad3c400 100644 --- a/pkg/commands/compute/build.go +++ b/pkg/commands/compute/build.go @@ -9,6 +9,7 @@ import ( "os" "os/exec" "path/filepath" + "runtime" "strings" "time" @@ -180,19 +181,40 @@ func (c *BuildCommand) Exec(in io.Reader, out io.Writer) (err error) { return err } + var memBefore, memAfter runtime.MemStats + runtime.ReadMemStats(&memBefore) + startTime := time.Now() if err := language.Build(); err != nil { c.Globals.ErrLog.AddWithContext(err, map[string]any{ "Language": language.Name, }) return err } + endTime := time.Now() + runtime.ReadMemStats(&memAfter) args := []string{ "metadata", "add", "bin/main.wasm", - "--language=whatever", - "--processed-by=FOO=BAR", - "--sdk=BEEP=BOOP", + "--language=" + language.Name, + fmt.Sprintf("--processed-by=RUNTIME_OS=%s", runtime.GOOS), + fmt.Sprintf("--processed-by=RUNTIME_ARCH=%s", runtime.GOARCH), + fmt.Sprintf("--processed-by=RUNTIME_COMPILER=%s", runtime.Compiler), + fmt.Sprintf("--processed-by=RUNTIME_MEM_USAGE_BEFORE=%d", memBefore.HeapAlloc), + fmt.Sprintf("--processed-by=RUNTIME_MEM_USAGE_AFTER=%d", memAfter.HeapAlloc), + fmt.Sprintf("--processed-by=RUNTIME_NUM_CPU=%d", runtime.NumCPU()), + fmt.Sprintf("--processed-by=RUNTIME_GO_VERSION=%s", runtime.Version()), + fmt.Sprintf("--processed-by=RUNTIME_BUILD_TIME=%s", endTime.Sub(startTime)), + fmt.Sprintf("--processed-by=SCRIPTS_DEFAULTBUILD=%t", language.DefaultBuildScript()), + fmt.Sprintf("--processed-by=SCRIPTS_BUILD=%s", c.Manifest.File.Scripts.Build), + fmt.Sprintf("--processed-by=SCRIPTS_ENVVARS=%s", c.Manifest.File.Scripts.EnvVars), + fmt.Sprintf("--processed-by=SCRIPTS_POSTINIT=%s", c.Manifest.File.Scripts.PostInit), + fmt.Sprintf("--processed-by=SCRIPTS_POSTBUILD=%s", c.Manifest.File.Scripts.PostBuild), + } + + for k, v := range language.Dependencies() { + args = append(args, fmt.Sprintf("--sdk=%s=%s", k, v)) } + // gosec flagged this: // G204 (CWE-78): Subprocess launched with function call as argument or command arguments // Disabling as we trust the source of the variable. diff --git a/pkg/commands/compute/language_assemblyscript.go b/pkg/commands/compute/language_assemblyscript.go index 24465ea4a..247702325 100644 --- a/pkg/commands/compute/language_assemblyscript.go +++ b/pkg/commands/compute/language_assemblyscript.go @@ -68,6 +68,8 @@ type AssemblyScript struct { autoYes bool // build is a shell command defined in fastly.toml using [scripts.build]. build string + // defaultBuild indicates if the default build script was used. + defaultBuild bool // errlog is an abstraction for recording errors to disk. errlog fsterr.LogInterface // input is the user's terminal stdin stream @@ -89,6 +91,17 @@ type AssemblyScript struct { verbose bool } +// DefaultBuildScript indicates if a custom build script was used. +func (a *AssemblyScript) DefaultBuildScript() bool { + return a.defaultBuild +} + +// Dependencies returns all dependencies used by the project. +func (a *AssemblyScript) Dependencies() map[string]string { + deps := make(map[string]string) + return deps +} + // Build compiles the user's source code into a Wasm binary. func (a *AssemblyScript) Build() error { if !a.verbose { @@ -96,10 +109,9 @@ func (a *AssemblyScript) Build() error { } text.Deprecated(a.output, "The Fastly AssemblyScript SDK is being deprecated in favor of the more up-to-date and feature-rich JavaScript SDK. You can learn more about the JavaScript SDK on our Developer Hub Page - https://developer.fastly.com/learning/compute/javascript/\n\n") - var noBuildScript bool if a.build == "" { a.build = AsDefaultBuildCommand - noBuildScript = true + a.defaultBuild = true } usesWebpack, err := a.checkForWebpack() @@ -110,7 +122,7 @@ func (a *AssemblyScript) Build() error { a.build = AsDefaultBuildCommandForWebpack } - if noBuildScript && a.verbose { + if a.defaultBuild && a.verbose { text.Info(a.output, "No [scripts.build] found in %s. The following default build command for AssemblyScript will be used: `%s`\n\n", a.manifestFilename, a.build) } diff --git a/pkg/commands/compute/language_go.go b/pkg/commands/compute/language_go.go index 509d8f72d..9d34aa992 100644 --- a/pkg/commands/compute/language_go.go +++ b/pkg/commands/compute/language_go.go @@ -76,6 +76,8 @@ type Go struct { build string // config is the Go specific application configuration. config config.Go + // defaultBuild indicates if the default build script was used. + defaultBuild bool // env is environment variables to be set. env []string // errlog is an abstraction for recording errors to disk. @@ -99,6 +101,17 @@ type Go struct { verbose bool } +// DefaultBuildScript indicates if a custom build script was used. +func (g *Go) DefaultBuildScript() bool { + return g.defaultBuild +} + +// Dependencies returns all dependencies used by the project. +func (g *Go) Dependencies() map[string]string { + deps := make(map[string]string) + return deps +} + // Build compiles the user's source code into a Wasm binary. func (g *Go) Build() error { var ( @@ -108,6 +121,7 @@ func (g *Go) Build() error { if g.build == "" { g.build = TinyGoDefaultBuildCommand + g.defaultBuild = true tinygoToolchain = true toolchainConstraint = g.config.ToolchainConstraintTinyGo if !g.verbose { diff --git a/pkg/commands/compute/language_javascript.go b/pkg/commands/compute/language_javascript.go index 811aa8c91..5aa012d95 100644 --- a/pkg/commands/compute/language_javascript.go +++ b/pkg/commands/compute/language_javascript.go @@ -73,6 +73,8 @@ type JavaScript struct { autoYes bool // build is a shell command defined in fastly.toml using [scripts.build]. build string + // defaultBuild indicates if the default build script was used. + defaultBuild bool // env is environment variables to be set. env []string // errlog is an abstraction for recording errors to disk. @@ -96,13 +98,22 @@ type JavaScript struct { verbose bool } +// DefaultBuildScript indicates if a custom build script was used. +func (j *JavaScript) DefaultBuildScript() bool { + return j.defaultBuild +} + +// Dependencies returns all dependencies used by the project. +func (j *JavaScript) Dependencies() map[string]string { + deps := make(map[string]string) + return deps +} + // Build compiles the user's source code into a Wasm binary. func (j *JavaScript) Build() error { - var noBuildScript bool if j.build == "" { - noBuildScript = true - j.build = JsDefaultBuildCommand + j.defaultBuild = true usesWebpack, err := j.checkForWebpack() if err != nil { @@ -113,7 +124,7 @@ func (j *JavaScript) Build() error { } } - if noBuildScript && j.verbose { + if j.defaultBuild && j.verbose { text.Info(j.output, "No [scripts.build] found in %s. The following default build command for JavaScript will be used: `%s`\n\n", j.manifestFilename, j.build) } diff --git a/pkg/commands/compute/language_other.go b/pkg/commands/compute/language_other.go index 051d3f51f..1e3a31d6a 100644 --- a/pkg/commands/compute/language_other.go +++ b/pkg/commands/compute/language_other.go @@ -24,6 +24,7 @@ func NewOther( autoYes: globals.Flags.AutoYes, build: fastlyManifest.Scripts.Build, + defaultBuild: true, // technically there is no default build for 'other' env: fastlyManifest.Scripts.EnvVars, errlog: globals.ErrLog, input: in, @@ -45,6 +46,8 @@ type Other struct { autoYes bool // build is a shell command defined in fastly.toml using [scripts.build]. build string + // defaultBuild indicates if the default build script was used. + defaultBuild bool // env is environment variables to be set. env []string // errlog is an abstraction for recording errors to disk. @@ -68,6 +71,17 @@ type Other struct { verbose bool } +// DefaultBuildScript indicates if a custom build script was used. +func (o Other) DefaultBuildScript() bool { + return o.defaultBuild +} + +// Dependencies returns all dependencies used by the project. +func (o Other) Dependencies() map[string]string { + deps := make(map[string]string) + return deps +} + // Build implements the Toolchain interface and attempts to compile the package // source to a Wasm binary. func (o Other) Build() error { diff --git a/pkg/commands/compute/language_rust.go b/pkg/commands/compute/language_rust.go index d490ebb01..c5f458c71 100644 --- a/pkg/commands/compute/language_rust.go +++ b/pkg/commands/compute/language_rust.go @@ -81,6 +81,8 @@ type Rust struct { build string // config is the Rust specific application configuration. config config.Rust + // defaultBuild indicates if the default build script was used. + defaultBuild bool // env is environment variables to be set. env []string // errlog is an abstraction for recording errors to disk. @@ -108,20 +110,30 @@ type Rust struct { verbose bool } +// DefaultBuildScript indicates if a custom build script was used. +func (r *Rust) DefaultBuildScript() bool { + return r.defaultBuild +} + +// Dependencies returns all dependencies used by the project. +func (r *Rust) Dependencies() map[string]string { + deps := make(map[string]string) + return deps +} + // Build compiles the user's source code into a Wasm binary. func (r *Rust) Build() error { - var noBuildScript bool if r.build == "" { r.build = fmt.Sprintf(RustDefaultBuildCommand, RustDefaultPackageName) - noBuildScript = true + r.defaultBuild = true } - err := r.modifyCargoPackageName(noBuildScript) + err := r.modifyCargoPackageName(r.defaultBuild) if err != nil { return err } - if noBuildScript && r.verbose { + if r.defaultBuild && r.verbose { text.Info(r.output, "No [scripts.build] found in %s. The following default build command for Rust will be used: `%s`\n\n", r.manifestFilename, r.build) } diff --git a/pkg/commands/compute/language_toolchain.go b/pkg/commands/compute/language_toolchain.go index 516e46b33..d91fb3af3 100644 --- a/pkg/commands/compute/language_toolchain.go +++ b/pkg/commands/compute/language_toolchain.go @@ -43,6 +43,10 @@ For more information on fastly.toml configuration settings, refer to https://dev type Toolchain interface { // Build compiles the user's source code into a Wasm binary. Build() error + // DefaultBuildScript indicates if a default build script was used. + DefaultBuildScript() bool + // Dependencies returns all dependencies used by the project. + Dependencies() map[string]string } // BuildToolchain enables a language toolchain to compile their build script. From b5cff866738a4d8bfec91bfec7821158a971bb73 Mon Sep 17 00:00:00 2001 From: Integralist Date: Wed, 20 Sep 2023 14:51:27 +0100 Subject: [PATCH 11/60] feat: support data collection for all languages --- pkg/commands/compute/build.go | 2 +- .../compute/language_assemblyscript.go | 19 +++++++++++++ pkg/commands/compute/language_go.go | 15 ++++++++++ pkg/commands/compute/language_javascript.go | 28 +++++++++++++++++++ pkg/commands/compute/language_rust.go | 21 ++++++++++++++ 5 files changed, 84 insertions(+), 1 deletion(-) diff --git a/pkg/commands/compute/build.go b/pkg/commands/compute/build.go index 70ad3c400..a739074f4 100644 --- a/pkg/commands/compute/build.go +++ b/pkg/commands/compute/build.go @@ -195,7 +195,7 @@ func (c *BuildCommand) Exec(in io.Reader, out io.Writer) (err error) { args := []string{ "metadata", "add", "bin/main.wasm", - "--language=" + language.Name, + "--language=CLI_" + strings.ToUpper(language.Name), fmt.Sprintf("--processed-by=RUNTIME_OS=%s", runtime.GOOS), fmt.Sprintf("--processed-by=RUNTIME_ARCH=%s", runtime.GOARCH), fmt.Sprintf("--processed-by=RUNTIME_COMPILER=%s", runtime.Compiler), diff --git a/pkg/commands/compute/language_assemblyscript.go b/pkg/commands/compute/language_assemblyscript.go index 247702325..5b141ff9e 100644 --- a/pkg/commands/compute/language_assemblyscript.go +++ b/pkg/commands/compute/language_assemblyscript.go @@ -2,6 +2,7 @@ package compute import ( "encoding/json" + "errors" "io" "os" @@ -99,6 +100,24 @@ func (a *AssemblyScript) DefaultBuildScript() bool { // Dependencies returns all dependencies used by the project. func (a *AssemblyScript) Dependencies() map[string]string { deps := make(map[string]string) + + lockfile := "npm-shrinkwrap.json" + _, err := os.Stat(lockfile) + if errors.Is(err, os.ErrNotExist) { + lockfile = "package-lock.json" + } + + var jlf JavaScriptLockFile + if f, err := os.Open(lockfile); err == nil { + if err := json.NewDecoder(f).Decode(&jlf); err == nil { + for k, v := range jlf.Packages { + if k != "" { // avoid "root" package + deps[k] = v.Version + } + } + } + } + return deps } diff --git a/pkg/commands/compute/language_go.go b/pkg/commands/compute/language_go.go index 9d34aa992..1d6bf7307 100644 --- a/pkg/commands/compute/language_go.go +++ b/pkg/commands/compute/language_go.go @@ -109,6 +109,21 @@ func (g *Go) DefaultBuildScript() bool { // Dependencies returns all dependencies used by the project. func (g *Go) Dependencies() map[string]string { deps := make(map[string]string) + + if f, err := os.Open("go.sum"); err == nil { + defer f.Close() + scanner := bufio.NewScanner(f) + for scanner.Scan() { + line := scanner.Text() + segs := strings.Split(line, " ") + if len(segs) >= 2 { + pkg := segs[0] + version := strings.Split(segs[1], "/")[0] // e.g. `v0.2.0/go.mod` + deps[pkg] = version + } + } + } + return deps } diff --git a/pkg/commands/compute/language_javascript.go b/pkg/commands/compute/language_javascript.go index 5aa012d95..aeef560a7 100644 --- a/pkg/commands/compute/language_javascript.go +++ b/pkg/commands/compute/language_javascript.go @@ -103,9 +103,37 @@ func (j *JavaScript) DefaultBuildScript() bool { return j.defaultBuild } +// JavaScriptPackage represents a package within a JavaScript lockfile. +type JavaScriptPackage struct { + Version string `json:"version"` +} + +// JavaScriptLockFile represents a JavaScript lockfile. +type JavaScriptLockFile struct { + Packages map[string]JavaScriptPackage `json:"packages"` +} + // Dependencies returns all dependencies used by the project. func (j *JavaScript) Dependencies() map[string]string { deps := make(map[string]string) + + lockfile := "npm-shrinkwrap.json" + _, err := os.Stat(lockfile) + if errors.Is(err, os.ErrNotExist) { + lockfile = "package-lock.json" + } + + var jlf JavaScriptLockFile + if f, err := os.Open(lockfile); err == nil { + if err := json.NewDecoder(f).Decode(&jlf); err == nil { + for k, v := range jlf.Packages { + if k != "" { // avoid "root" package + deps[k] = v.Version + } + } + } + } + return deps } diff --git a/pkg/commands/compute/language_rust.go b/pkg/commands/compute/language_rust.go index c5f458c71..6976a44df 100644 --- a/pkg/commands/compute/language_rust.go +++ b/pkg/commands/compute/language_rust.go @@ -115,9 +115,30 @@ func (r *Rust) DefaultBuildScript() bool { return r.defaultBuild } +// CargoLockFilePackage represents a package within a Rust lockfile. +type CargoLockFilePackage struct { + Name string `toml:"name"` + Version string `toml:"version"` +} + +// CargoLockFile represents a Rust lockfile. +type CargoLockFile struct { + Packages []CargoLockFilePackage `toml:"package"` +} + // Dependencies returns all dependencies used by the project. func (r *Rust) Dependencies() map[string]string { deps := make(map[string]string) + + var clf CargoLockFile + if data, err := os.ReadFile("Cargo.lock"); err == nil { + if err := toml.Unmarshal(data, &clf); err == nil { + for _, v := range clf.Packages { + deps[v.Name] = v.Version + } + } + } + return deps } From 8f665125ae102a278351ec9f2d06601aa3978715 Mon Sep 17 00:00:00 2001 From: Integralist Date: Wed, 20 Sep 2023 16:05:05 +0100 Subject: [PATCH 12/60] remove(config): don't increment version --- .fastly/config.toml | 2 +- pkg/commands/version/version_test.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.fastly/config.toml b/.fastly/config.toml index f3a58700a..61f9722ab 100644 --- a/.fastly/config.toml +++ b/.fastly/config.toml @@ -1,4 +1,4 @@ -config_version = 5 +config_version = 4 [fastly] api_endpoint = "https://api.fastly.com" diff --git a/pkg/commands/version/version_test.go b/pkg/commands/version/version_test.go index 26c5c31c9..7783cc5cb 100644 --- a/pkg/commands/version/version_test.go +++ b/pkg/commands/version/version_test.go @@ -41,7 +41,7 @@ func TestVersion(t *testing.T) { // G302 (CWE-276): Expect file permissions to be 0600 or less // gosec flagged this: // Disabling as this is for test suite purposes only. - /* #nosec */ + // #nosec err = os.Chmod(filepath.Join(rootdir, "viceroy"), 0o777) if err != nil { t.Fatal(err) From 5777ce516a0d27b53248896f9b33d104d2cd3605 Mon Sep 17 00:00:00 2001 From: Integralist Date: Wed, 20 Sep 2023 16:24:36 +0100 Subject: [PATCH 13/60] fix(telemetry): disable unless hidden flag is set --- pkg/commands/compute/build.go | 114 +++++++++++++++++++--------------- 1 file changed, 65 insertions(+), 49 deletions(-) diff --git a/pkg/commands/compute/build.go b/pkg/commands/compute/build.go index a739074f4..d75913916 100644 --- a/pkg/commands/compute/build.go +++ b/pkg/commands/compute/build.go @@ -53,6 +53,7 @@ type Flags struct { // BuildCommand produces a deployable artifact from files on the local disk. type BuildCommand struct { cmd.Base + enableTelemetry bool wasmtoolsVersioner github.AssetVersioner // NOTE: these are public so that the "serve" and "publish" composite @@ -77,6 +78,9 @@ func NewBuildCommand(parent cmd.Registerer, g *global.Data, wasmtoolsVersioner g c.CmdClause.Flag("package-name", "Package name").StringVar(&c.Flags.PackageName) c.CmdClause.Flag("timeout", "Timeout, in seconds, for the build compilation step").IntVar(&c.Flags.Timeout) + // Hidden + c.CmdClause.Flag("enable-telemetry", "Feature flag to trial the Wasm binary metadata annotations").Hidden().BoolVar(&c.enableTelemetry) + return &c } @@ -117,9 +121,12 @@ func (c *BuildCommand) Exec(in io.Reader, out io.Writer) (err error) { return err } - wasmtools, err := GetWasmTools(spinner, out, c.wasmtoolsVersioner, c.Globals) - if err != nil { - return err + var wasmtools string + if c.enableTelemetry { + wasmtools, err = GetWasmTools(spinner, out, c.wasmtoolsVersioner, c.Globals) + if err != nil { + return err + } } defer func(errLog fsterr.LogInterface) { @@ -181,59 +188,68 @@ func (c *BuildCommand) Exec(in io.Reader, out io.Writer) (err error) { return err } - var memBefore, memAfter runtime.MemStats - runtime.ReadMemStats(&memBefore) - startTime := time.Now() + var ( + memBefore, memAfter runtime.MemStats + startTime time.Time + ) + if c.enableTelemetry { + runtime.ReadMemStats(&memBefore) + startTime = time.Now() + } + if err := language.Build(); err != nil { c.Globals.ErrLog.AddWithContext(err, map[string]any{ "Language": language.Name, }) return err } - endTime := time.Now() - runtime.ReadMemStats(&memAfter) - - args := []string{ - "metadata", "add", "bin/main.wasm", - "--language=CLI_" + strings.ToUpper(language.Name), - fmt.Sprintf("--processed-by=RUNTIME_OS=%s", runtime.GOOS), - fmt.Sprintf("--processed-by=RUNTIME_ARCH=%s", runtime.GOARCH), - fmt.Sprintf("--processed-by=RUNTIME_COMPILER=%s", runtime.Compiler), - fmt.Sprintf("--processed-by=RUNTIME_MEM_USAGE_BEFORE=%d", memBefore.HeapAlloc), - fmt.Sprintf("--processed-by=RUNTIME_MEM_USAGE_AFTER=%d", memAfter.HeapAlloc), - fmt.Sprintf("--processed-by=RUNTIME_NUM_CPU=%d", runtime.NumCPU()), - fmt.Sprintf("--processed-by=RUNTIME_GO_VERSION=%s", runtime.Version()), - fmt.Sprintf("--processed-by=RUNTIME_BUILD_TIME=%s", endTime.Sub(startTime)), - fmt.Sprintf("--processed-by=SCRIPTS_DEFAULTBUILD=%t", language.DefaultBuildScript()), - fmt.Sprintf("--processed-by=SCRIPTS_BUILD=%s", c.Manifest.File.Scripts.Build), - fmt.Sprintf("--processed-by=SCRIPTS_ENVVARS=%s", c.Manifest.File.Scripts.EnvVars), - fmt.Sprintf("--processed-by=SCRIPTS_POSTINIT=%s", c.Manifest.File.Scripts.PostInit), - fmt.Sprintf("--processed-by=SCRIPTS_POSTBUILD=%s", c.Manifest.File.Scripts.PostBuild), - } - - for k, v := range language.Dependencies() { - args = append(args, fmt.Sprintf("--sdk=%s=%s", k, v)) - } - // gosec flagged this: - // G204 (CWE-78): Subprocess launched with function call as argument or command arguments - // Disabling as we trust the source of the variable. - // #nosec - // nosemgrep: go.lang.security.audit.dangerous-exec-command.dangerous-exec-command - command := exec.Command(wasmtools, args...) - wasmtoolsOutput, err := command.Output() - if err != nil { - return fmt.Errorf("failed to annotate binary with metadata: %w", err) - } - // Ensure the Wasm binary can be executed. - // - // G302 (CWE-276): Expect file permissions to be 0600 or less - // gosec flagged this: - // Disabling as we want all users to be able to execute this binary. - // #nosec - err = os.WriteFile("bin/main.wasm", wasmtoolsOutput, 0o777) - if err != nil { - return fmt.Errorf("failed to annotate binary with metadata: %w", err) + if c.enableTelemetry { + endTime := time.Now() + runtime.ReadMemStats(&memAfter) + + args := []string{ + "metadata", "add", "bin/main.wasm", + "--language=CLI_" + strings.ToUpper(language.Name), + fmt.Sprintf("--processed-by=RUNTIME_OS=%s", runtime.GOOS), + fmt.Sprintf("--processed-by=RUNTIME_ARCH=%s", runtime.GOARCH), + fmt.Sprintf("--processed-by=RUNTIME_COMPILER=%s", runtime.Compiler), + fmt.Sprintf("--processed-by=RUNTIME_MEM_USAGE_BEFORE=%d", memBefore.HeapAlloc), + fmt.Sprintf("--processed-by=RUNTIME_MEM_USAGE_AFTER=%d", memAfter.HeapAlloc), + fmt.Sprintf("--processed-by=RUNTIME_NUM_CPU=%d", runtime.NumCPU()), + fmt.Sprintf("--processed-by=RUNTIME_GO_VERSION=%s", runtime.Version()), + fmt.Sprintf("--processed-by=RUNTIME_BUILD_TIME=%s", endTime.Sub(startTime)), + fmt.Sprintf("--processed-by=SCRIPTS_DEFAULTBUILD=%t", language.DefaultBuildScript()), + fmt.Sprintf("--processed-by=SCRIPTS_BUILD=%s", c.Manifest.File.Scripts.Build), + fmt.Sprintf("--processed-by=SCRIPTS_ENVVARS=%s", c.Manifest.File.Scripts.EnvVars), + fmt.Sprintf("--processed-by=SCRIPTS_POSTINIT=%s", c.Manifest.File.Scripts.PostInit), + fmt.Sprintf("--processed-by=SCRIPTS_POSTBUILD=%s", c.Manifest.File.Scripts.PostBuild), + } + + for k, v := range language.Dependencies() { + args = append(args, fmt.Sprintf("--sdk=%s=%s", k, v)) + } + + // gosec flagged this: + // G204 (CWE-78): Subprocess launched with function call as argument or command arguments + // Disabling as we trust the source of the variable. + // #nosec + // nosemgrep: go.lang.security.audit.dangerous-exec-command.dangerous-exec-command + command := exec.Command(wasmtools, args...) + wasmtoolsOutput, err := command.Output() + if err != nil { + return fmt.Errorf("failed to annotate binary with metadata: %w", err) + } + // Ensure the Wasm binary can be executed. + // + // G302 (CWE-276): Expect file permissions to be 0600 or less + // gosec flagged this: + // Disabling as we want all users to be able to execute this binary. + // #nosec + err = os.WriteFile("bin/main.wasm", wasmtoolsOutput, 0o777) + if err != nil { + return fmt.Errorf("failed to annotate binary with metadata: %w", err) + } } dest := filepath.Join("pkg", fmt.Sprintf("%s.tar.gz", pkgName)) From 6ecb888a0ead136c3b6afe2450f300a8c92ce542 Mon Sep 17 00:00:00 2001 From: Integralist Date: Wed, 20 Sep 2023 16:54:31 +0100 Subject: [PATCH 14/60] fix(compute/test): ignore enable-telemetry flag --- pkg/commands/compute/compute_test.go | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/pkg/commands/compute/compute_test.go b/pkg/commands/compute/compute_test.go index 66933bd63..f865ce695 100644 --- a/pkg/commands/compute/compute_test.go +++ b/pkg/commands/compute/compute_test.go @@ -36,10 +36,19 @@ func TestPublishFlagDivergence(t *testing.T) { have = make(map[string]int) ) + // Some flags on `compute build` are unique to it. + ignoreBuildFlags := []string{ + "enable-telemetry", + } + iter := buildFlags.MapRange() for iter.Next() { - expect[iter.Key().String()] = 1 + flag := iter.Key().String() + if !ignoreFlag(ignoreBuildFlags, flag) { + expect[flag] = 1 + } } + iter = deployFlags.MapRange() for iter.Next() { expect[iter.Key().String()] = 1 @@ -79,9 +88,17 @@ func TestServeFlagDivergence(t *testing.T) { have = make(map[string]int) ) + // Some flags on `compute build` are unique to it. + ignoreBuildFlags := []string{ + "enable-telemetry", + } + iter := buildFlags.MapRange() for iter.Next() { - expect[iter.Key().String()] = 1 + flag := iter.Key().String() + if !ignoreFlag(ignoreBuildFlags, flag) { + expect[flag] = 1 + } } // Some flags on `compute serve` are unique to it. From 7bb89e750d5a962960b17bee0a64b50f67f7c053 Mon Sep 17 00:00:00 2001 From: Integralist Date: Wed, 20 Sep 2023 17:47:14 +0100 Subject: [PATCH 15/60] feat(telemetry): disable telemetry via env var --- pkg/commands/compute/build.go | 8 +++++--- pkg/config/config.go | 6 ++++-- pkg/env/env.go | 4 ++++ 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/pkg/commands/compute/build.go b/pkg/commands/compute/build.go index d75913916..1519fd6d4 100644 --- a/pkg/commands/compute/build.go +++ b/pkg/commands/compute/build.go @@ -10,6 +10,7 @@ import ( "os/exec" "path/filepath" "runtime" + "strconv" "strings" "time" @@ -122,7 +123,8 @@ func (c *BuildCommand) Exec(in io.Reader, out io.Writer) (err error) { } var wasmtools string - if c.enableTelemetry { + disableTelemetry, _ := strconv.ParseBool(c.Globals.Env.TelemetryDisable) + if c.enableTelemetry || !disableTelemetry { wasmtools, err = GetWasmTools(spinner, out, c.wasmtoolsVersioner, c.Globals) if err != nil { return err @@ -192,7 +194,7 @@ func (c *BuildCommand) Exec(in io.Reader, out io.Writer) (err error) { memBefore, memAfter runtime.MemStats startTime time.Time ) - if c.enableTelemetry { + if c.enableTelemetry || !disableTelemetry { runtime.ReadMemStats(&memBefore) startTime = time.Now() } @@ -204,7 +206,7 @@ func (c *BuildCommand) Exec(in io.Reader, out io.Writer) (err error) { return err } - if c.enableTelemetry { + if c.enableTelemetry || !disableTelemetry { endTime := time.Now() runtime.ReadMemStats(&memAfter) diff --git a/pkg/config/config.go b/pkg/config/config.go index 0daef92c3..710f67f73 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -393,14 +393,16 @@ func (f *File) Write(path string) error { // Environment represents all of the configuration parameters that can come // from environment variables. type Environment struct { - Token string - Endpoint string + Token string + Endpoint string + TelemetryDisable string } // Read populates the fields from the provided environment. func (e *Environment) Read(state map[string]string) { e.Token = state[env.Token] e.Endpoint = state[env.Endpoint] + e.TelemetryDisable = state[env.TelemetryDisable] } // invalidStaticConfigErr generates an error to alert the user to an issue with diff --git a/pkg/env/env.go b/pkg/env/env.go index 83bd511df..9211f674d 100644 --- a/pkg/env/env.go +++ b/pkg/env/env.go @@ -24,6 +24,10 @@ const ( // CustomerID is the env var we look in for a Customer ID. CustomerID = "FASTLY_CUSTOMER_ID" + + // TelemetryDisable is the env var we look in to disable all telemetry. + // Set to "true" to disable all telemetry. + TelemetryDisable = "FASTLY_TELEMETRY_DISABLE" ) // Parse transforms the local environment data structure into a map type. From 0ac476a0b011ebbff85490015e7b02059cae1d20 Mon Sep 17 00:00:00 2001 From: Integralist Date: Wed, 20 Sep 2023 18:06:52 +0100 Subject: [PATCH 16/60] debugging --- pkg/github/github.go | 1 + 1 file changed, 1 insertion(+) diff --git a/pkg/github/github.go b/pkg/github/github.go index a51204ce9..b30f15681 100644 --- a/pkg/github/github.go +++ b/pkg/github/github.go @@ -235,6 +235,7 @@ func (g *Asset) metadata() (m DevHubMetadata, err error) { if g.httpClient == nil { g.httpClient = http.DefaultClient } + fmt.Printf("g.httpClient: %#v\n", g.httpClient) res, err := g.httpClient.Do(req) if err != nil { return m, fmt.Errorf("failed to request GitHub metadata: %w", err) From bfbddb8e757cbbf7694a49b4e7b3c3c2ed83b666 Mon Sep 17 00:00:00 2001 From: Integralist Date: Thu, 21 Sep 2023 11:06:11 +0100 Subject: [PATCH 17/60] fix(compute/build): fix broken ci test --- pkg/commands/compute/build_test.go | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/pkg/commands/compute/build_test.go b/pkg/commands/compute/build_test.go index 216bdfaa9..a8d9803e6 100644 --- a/pkg/commands/compute/build_test.go +++ b/pkg/commands/compute/build_test.go @@ -2,6 +2,7 @@ package compute_test import ( "fmt" + "io" "net/http" "os" "os/exec" @@ -26,10 +27,16 @@ func TestBuildRust(t *testing.T) { } wasmtoolsVersioner := github.New(github.Opts{ - HTTPClient: mock.HTMLClient([]*http.Response{}, []error{}), - Org: "bytecodealliance", - Repo: "wasm-tools", - Binary: "wasm-tools", + HTTPClient: mock.HTMLClient([]*http.Response{ + { + Body: io.NopCloser(strings.NewReader("...")), + Status: http.StatusText(http.StatusOK), + StatusCode: http.StatusOK, + }, + }, []error{}), + Org: "bytecodealliance", + Repo: "wasm-tools", + Binary: "wasm-tools", }) args := testutil.Args From 79399827e157080aa1332f3d3d19cb3ab8f0c0c5 Mon Sep 17 00:00:00 2001 From: Integralist Date: Thu, 21 Sep 2023 11:35:17 +0100 Subject: [PATCH 18/60] debugging --- pkg/manifest/file.go | 1 + pkg/mock/client.go | 2 ++ 2 files changed, 3 insertions(+) diff --git a/pkg/manifest/file.go b/pkg/manifest/file.go index 63a67a066..4a332d047 100644 --- a/pkg/manifest/file.go +++ b/pkg/manifest/file.go @@ -67,6 +67,7 @@ func (f *File) Read(path string) (err error) { // This file is decoded into a predefined struct, any unrecognised fields are dropped. /* #nosec */ tree, err := toml.LoadFile(path) + fmt.Printf("%#v | %v\n", tree, err) if err != nil { // IMPORTANT: Only `fastly compute` references the fastly.toml file. if len(f.Args) > 0 && f.Args[0] == "compute" { diff --git a/pkg/mock/client.go b/pkg/mock/client.go index 54eb4f7be..d0008ca37 100644 --- a/pkg/mock/client.go +++ b/pkg/mock/client.go @@ -1,6 +1,7 @@ package mock import ( + "fmt" "net/http" "github.com/fastly/cli/pkg/api" @@ -23,6 +24,7 @@ type mockHTTPClient struct { func (c mockHTTPClient) Do(_ *http.Request) (*http.Response, error) { c.index++ + fmt.Printf("res: %#v | len res: %d | index: %d\n", c.res, len(c.res), c.index) return c.res[c.index], c.err[c.index] } From dfc8cd8a098e5bd8d4ed3f4280996ba642a9066e Mon Sep 17 00:00:00 2001 From: Integralist Date: Thu, 21 Sep 2023 11:52:51 +0100 Subject: [PATCH 19/60] fix(compute/build): fix broken ci test --- pkg/commands/compute/build.go | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/pkg/commands/compute/build.go b/pkg/commands/compute/build.go index 1519fd6d4..7d8785f64 100644 --- a/pkg/commands/compute/build.go +++ b/pkg/commands/compute/build.go @@ -10,7 +10,6 @@ import ( "os/exec" "path/filepath" "runtime" - "strconv" "strings" "time" @@ -123,8 +122,9 @@ func (c *BuildCommand) Exec(in io.Reader, out io.Writer) (err error) { } var wasmtools string - disableTelemetry, _ := strconv.ParseBool(c.Globals.Env.TelemetryDisable) - if c.enableTelemetry || !disableTelemetry { + // FIXME: When we remove feature flag, put in ability to disable telemetry. + // disableTelemetry, _ := strconv.ParseBool(c.Globals.Env.TelemetryDisable) + if c.enableTelemetry /*|| !disableTelemetry*/ { wasmtools, err = GetWasmTools(spinner, out, c.wasmtoolsVersioner, c.Globals) if err != nil { return err @@ -194,7 +194,8 @@ func (c *BuildCommand) Exec(in io.Reader, out io.Writer) (err error) { memBefore, memAfter runtime.MemStats startTime time.Time ) - if c.enableTelemetry || !disableTelemetry { + // FIXME: When we remove feature flag, put in ability to disable telemetry. + if c.enableTelemetry /*|| !disableTelemetry*/ { runtime.ReadMemStats(&memBefore) startTime = time.Now() } @@ -206,7 +207,8 @@ func (c *BuildCommand) Exec(in io.Reader, out io.Writer) (err error) { return err } - if c.enableTelemetry || !disableTelemetry { + // FIXME: When we remove feature flag, put in ability to disable telemetry. + if c.enableTelemetry /*|| !disableTelemetry*/ { endTime := time.Now() runtime.ReadMemStats(&memAfter) From 66e23e473afd0a152a86c56159bbd1c913b3e0e8 Mon Sep 17 00:00:00 2001 From: Integralist Date: Thu, 21 Sep 2023 12:02:45 +0100 Subject: [PATCH 20/60] Revert "debugging" This reverts commit fb3f84019b744f12520078bda9373cf65fea20dd. --- pkg/manifest/file.go | 1 - pkg/mock/client.go | 2 -- 2 files changed, 3 deletions(-) diff --git a/pkg/manifest/file.go b/pkg/manifest/file.go index 4a332d047..63a67a066 100644 --- a/pkg/manifest/file.go +++ b/pkg/manifest/file.go @@ -67,7 +67,6 @@ func (f *File) Read(path string) (err error) { // This file is decoded into a predefined struct, any unrecognised fields are dropped. /* #nosec */ tree, err := toml.LoadFile(path) - fmt.Printf("%#v | %v\n", tree, err) if err != nil { // IMPORTANT: Only `fastly compute` references the fastly.toml file. if len(f.Args) > 0 && f.Args[0] == "compute" { diff --git a/pkg/mock/client.go b/pkg/mock/client.go index d0008ca37..54eb4f7be 100644 --- a/pkg/mock/client.go +++ b/pkg/mock/client.go @@ -1,7 +1,6 @@ package mock import ( - "fmt" "net/http" "github.com/fastly/cli/pkg/api" @@ -24,7 +23,6 @@ type mockHTTPClient struct { func (c mockHTTPClient) Do(_ *http.Request) (*http.Response, error) { c.index++ - fmt.Printf("res: %#v | len res: %d | index: %d\n", c.res, len(c.res), c.index) return c.res[c.index], c.err[c.index] } From b825e0ae7696e681261fac1e6fca2a9f177c6c5c Mon Sep 17 00:00:00 2001 From: Integralist Date: Thu, 21 Sep 2023 12:02:59 +0100 Subject: [PATCH 21/60] Revert "debugging" This reverts commit 456126f22e96a657f42acd31e368d1ae7f8fd78b. --- pkg/github/github.go | 1 - 1 file changed, 1 deletion(-) diff --git a/pkg/github/github.go b/pkg/github/github.go index b30f15681..a51204ce9 100644 --- a/pkg/github/github.go +++ b/pkg/github/github.go @@ -235,7 +235,6 @@ func (g *Asset) metadata() (m DevHubMetadata, err error) { if g.httpClient == nil { g.httpClient = http.DefaultClient } - fmt.Printf("g.httpClient: %#v\n", g.httpClient) res, err := g.httpClient.Do(req) if err != nil { return m, fmt.Errorf("failed to request GitHub metadata: %w", err) From 3832fd33b10d930410e9f58ed9881b2ee4e31d9f Mon Sep 17 00:00:00 2001 From: Integralist Date: Fri, 22 Sep 2023 10:18:12 +0100 Subject: [PATCH 22/60] feat(telemetry): track starter kit --- pkg/commands/compute/build.go | 41 +++++++++++++++++--------- pkg/commands/compute/init.go | 7 +++-- pkg/commands/compute/language_other.go | 2 +- pkg/manifest/file.go | 3 ++ 4 files changed, 36 insertions(+), 17 deletions(-) diff --git a/pkg/commands/compute/build.go b/pkg/commands/compute/build.go index 7d8785f64..8529c6e02 100644 --- a/pkg/commands/compute/build.go +++ b/pkg/commands/compute/build.go @@ -214,20 +214,33 @@ func (c *BuildCommand) Exec(in io.Reader, out io.Writer) (err error) { args := []string{ "metadata", "add", "bin/main.wasm", - "--language=CLI_" + strings.ToUpper(language.Name), - fmt.Sprintf("--processed-by=RUNTIME_OS=%s", runtime.GOOS), - fmt.Sprintf("--processed-by=RUNTIME_ARCH=%s", runtime.GOARCH), - fmt.Sprintf("--processed-by=RUNTIME_COMPILER=%s", runtime.Compiler), - fmt.Sprintf("--processed-by=RUNTIME_MEM_USAGE_BEFORE=%d", memBefore.HeapAlloc), - fmt.Sprintf("--processed-by=RUNTIME_MEM_USAGE_AFTER=%d", memAfter.HeapAlloc), - fmt.Sprintf("--processed-by=RUNTIME_NUM_CPU=%d", runtime.NumCPU()), - fmt.Sprintf("--processed-by=RUNTIME_GO_VERSION=%s", runtime.Version()), - fmt.Sprintf("--processed-by=RUNTIME_BUILD_TIME=%s", endTime.Sub(startTime)), - fmt.Sprintf("--processed-by=SCRIPTS_DEFAULTBUILD=%t", language.DefaultBuildScript()), - fmt.Sprintf("--processed-by=SCRIPTS_BUILD=%s", c.Manifest.File.Scripts.Build), - fmt.Sprintf("--processed-by=SCRIPTS_ENVVARS=%s", c.Manifest.File.Scripts.EnvVars), - fmt.Sprintf("--processed-by=SCRIPTS_POSTINIT=%s", c.Manifest.File.Scripts.PostInit), - fmt.Sprintf("--processed-by=SCRIPTS_POSTBUILD=%s", c.Manifest.File.Scripts.PostBuild), + "--language=CLI: " + strings.ToUpper(language.Name), + fmt.Sprintf("--processed-by=BuildInfoMemoryHeapAlloc=%d", memAfter.HeapAlloc-memBefore.HeapAlloc), + fmt.Sprintf("--processed-by=BuildInfoTime=%s", endTime.Sub(startTime)), + fmt.Sprintf("--processed-by=MachineInfoOS=%s", runtime.GOOS), + fmt.Sprintf("--processed-by=MachineInfoArch=%s", runtime.GOARCH), + fmt.Sprintf("--processed-by=MachineInfoCompiler=%s", runtime.Compiler), + fmt.Sprintf("--processed-by=MachineInfoGoVersion=%s", runtime.Version()), + fmt.Sprintf("--processed-by=MachineInfoCPUs=%d", runtime.NumCPU()), + } + + if c.Manifest.File.ClonedFrom != "" { + args = append(args, fmt.Sprintf("--processed-by=PackageInfoClonedFrom=%s", c.Manifest.File.ClonedFrom)) + } + + args = append(args, fmt.Sprintf("--processed-by=ScriptsDefaultBuildUsed=%t", language.DefaultBuildScript())) + + if c.Manifest.File.Scripts.Build != "" { + args = append(args, fmt.Sprintf("--processed-by=ScriptsBuild=%s", c.Manifest.File.Scripts.Build)) + } + if len(c.Manifest.File.Scripts.EnvVars) > 0 { + args = append(args, fmt.Sprintf("--processed-by=ScriptsEnvVars=%s", c.Manifest.File.Scripts.EnvVars)) + } + if c.Manifest.File.Scripts.PostInit != "" { + args = append(args, fmt.Sprintf("--processed-by=ScriptsPostInit=%s", c.Manifest.File.Scripts.PostInit)) + } + if c.Manifest.File.Scripts.PostBuild != "" { + args = append(args, fmt.Sprintf("--processed-by=ScriptsPostBuild=%s", c.Manifest.File.Scripts.PostBuild)) } for k, v := range language.Dependencies() { diff --git a/pkg/commands/compute/init.go b/pkg/commands/compute/init.go index 8f0002d66..33368ffd0 100644 --- a/pkg/commands/compute/init.go +++ b/pkg/commands/compute/init.go @@ -228,7 +228,7 @@ func (c *InitCommand) Exec(in io.Reader, out io.Writer) (err error) { text.Break(out) } - mf, err = updateManifest(mf, spinner, c.dir, name, desc, authors, language) + mf, err = updateManifest(mf, spinner, c.dir, name, desc, c.cloneFrom, authors, language) if err != nil { c.Globals.ErrLog.AddWithContext(err, map[string]any{ "Directory": c.dir, @@ -996,7 +996,7 @@ func tempDir(prefix string) (abspath string, err error) { func updateManifest( m manifest.File, spinner text.Spinner, - path, name, desc string, + path, name, desc, clonedFrom string, authors []string, language *Language, ) (manifest.File, error) { @@ -1014,6 +1014,7 @@ func updateManifest( m.Description = desc m.Authors = authors m.Language = language.Name + m.ClonedFrom = clonedFrom if err := m.Write(mp); err != nil { return fmt.Errorf("error saving fastly.toml: %w", err) } @@ -1074,6 +1075,8 @@ func updateManifest( } } + m.ClonedFrom = clonedFrom + err = spinner.Process("Saving manifest changes", func(_ *text.SpinnerWrapper) error { if err := m.Write(mp); err != nil { return fmt.Errorf("error saving fastly.toml: %w", err) diff --git a/pkg/commands/compute/language_other.go b/pkg/commands/compute/language_other.go index 1e3a31d6a..45f77f1a1 100644 --- a/pkg/commands/compute/language_other.go +++ b/pkg/commands/compute/language_other.go @@ -24,7 +24,7 @@ func NewOther( autoYes: globals.Flags.AutoYes, build: fastlyManifest.Scripts.Build, - defaultBuild: true, // technically there is no default build for 'other' + defaultBuild: false, // there is no default build for 'other' env: fastlyManifest.Scripts.EnvVars, errlog: globals.ErrLog, input: in, diff --git a/pkg/manifest/file.go b/pkg/manifest/file.go index 63a67a066..eeb027b32 100644 --- a/pkg/manifest/file.go +++ b/pkg/manifest/file.go @@ -19,6 +19,9 @@ type File struct { Args []string `toml:"-"` // Authors is a list of project authors (typically an email). Authors []string `toml:"authors"` + // ClonedFrom indicates the GitHub repo the starter kit was cloned from. + // This could be an empty value if the user doesn't use `compute init`. + ClonedFrom string `toml:"cloned_from,omitempty"` // Description is the project description. Description string `toml:"description"` // Language is the programming language used for the project. From aa77a7e8f849a2a71968a7fc0101bbc908cd54ad Mon Sep 17 00:00:00 2001 From: Integralist Date: Fri, 22 Sep 2023 16:23:08 +0100 Subject: [PATCH 23/60] feat(telemetry): capture imports for Go/Rust from source files --- pkg/commands/compute/build.go | 4 + .../compute/language_assemblyscript.go | 5 + pkg/commands/compute/language_go.go | 49 ++++++ pkg/commands/compute/language_javascript.go | 5 + pkg/commands/compute/language_other.go | 5 + pkg/commands/compute/language_rust.go | 148 ++++++++++++++++++ pkg/commands/compute/language_toolchain.go | 2 + 7 files changed, 218 insertions(+) diff --git a/pkg/commands/compute/build.go b/pkg/commands/compute/build.go index 8529c6e02..660dd7edf 100644 --- a/pkg/commands/compute/build.go +++ b/pkg/commands/compute/build.go @@ -228,6 +228,10 @@ func (c *BuildCommand) Exec(in io.Reader, out io.Writer) (err error) { args = append(args, fmt.Sprintf("--processed-by=PackageInfoClonedFrom=%s", c.Manifest.File.ClonedFrom)) } + for i, v := range language.Imports() { + args = append(args, fmt.Sprintf("--processed-by=PackageInfoImported%d=%s", i, v)) + } + args = append(args, fmt.Sprintf("--processed-by=ScriptsDefaultBuildUsed=%t", language.DefaultBuildScript())) if c.Manifest.File.Scripts.Build != "" { diff --git a/pkg/commands/compute/language_assemblyscript.go b/pkg/commands/compute/language_assemblyscript.go index 5b141ff9e..926e3f728 100644 --- a/pkg/commands/compute/language_assemblyscript.go +++ b/pkg/commands/compute/language_assemblyscript.go @@ -121,6 +121,11 @@ func (a *AssemblyScript) Dependencies() map[string]string { return deps } +// Imports returns all source code imported packages. +func (a *AssemblyScript) Imports() []string { + return []string{} +} + // Build compiles the user's source code into a Wasm binary. func (a *AssemblyScript) Build() error { if !a.verbose { diff --git a/pkg/commands/compute/language_go.go b/pkg/commands/compute/language_go.go index 1d6bf7307..a41cee0e8 100644 --- a/pkg/commands/compute/language_go.go +++ b/pkg/commands/compute/language_go.go @@ -3,10 +3,15 @@ package compute import ( "bufio" "fmt" + "go/ast" + "go/parser" + "go/token" "io" "os" "os/exec" + "path/filepath" "regexp" + "sort" "strings" "github.com/Masterminds/semver/v3" @@ -127,6 +132,50 @@ func (g *Go) Dependencies() map[string]string { return deps } +// Imports returns all source code imported packages. +func (g *Go) Imports() []string { + fs := token.NewFileSet() + importedPackages := make(map[string]bool) + var importPaths []string + + root := "." + _ = filepath.Walk(root, func(path string, _ os.FileInfo, _ error) error { + if strings.HasSuffix(path, ".go") { + // gosec flagged this: + // G304 (CWE-22): Potential file inclusion via variable + // Disabling as we need to read files from the users machine. + // #nosec + data, err := os.ReadFile(path) + if err != nil { + return nil + } + + node, err := parser.ParseFile(fs, path, string(data), parser.AllErrors) + if err != nil { + return nil + } + + for _, decl := range node.Decls { + if gd, isGenDecl := decl.(*ast.GenDecl); isGenDecl && gd.Tok == token.IMPORT { + for _, spec := range gd.Specs { + if ispec, isImportSpec := spec.(*ast.ImportSpec); isImportSpec { + importPath := strings.TrimSpace(ispec.Path.Value) + if !importedPackages[importPath] { + importPaths = append(importPaths, importPath) + importedPackages[importPath] = true + } + } + } + } + } + } + return nil + }) + + sort.Strings(importPaths) + return importPaths +} + // Build compiles the user's source code into a Wasm binary. func (g *Go) Build() error { var ( diff --git a/pkg/commands/compute/language_javascript.go b/pkg/commands/compute/language_javascript.go index aeef560a7..e61a13397 100644 --- a/pkg/commands/compute/language_javascript.go +++ b/pkg/commands/compute/language_javascript.go @@ -137,6 +137,11 @@ func (j *JavaScript) Dependencies() map[string]string { return deps } +// Imports returns all source code imported packages. +func (j *JavaScript) Imports() []string { + return []string{} +} + // Build compiles the user's source code into a Wasm binary. func (j *JavaScript) Build() error { if j.build == "" { diff --git a/pkg/commands/compute/language_other.go b/pkg/commands/compute/language_other.go index 45f77f1a1..0aefc9992 100644 --- a/pkg/commands/compute/language_other.go +++ b/pkg/commands/compute/language_other.go @@ -82,6 +82,11 @@ func (o Other) Dependencies() map[string]string { return deps } +// Imports returns all source code imported packages. +func (o Other) Imports() []string { + return []string{} +} + // Build implements the Toolchain interface and attempts to compile the package // source to a Wasm binary. func (o Other) Build() error { diff --git a/pkg/commands/compute/language_rust.go b/pkg/commands/compute/language_rust.go index 6976a44df..c535b7fd3 100644 --- a/pkg/commands/compute/language_rust.go +++ b/pkg/commands/compute/language_rust.go @@ -1,6 +1,7 @@ package compute import ( + "bufio" "bytes" "encoding/json" "fmt" @@ -9,6 +10,7 @@ import ( "os/exec" "path/filepath" "regexp" + "sort" "strings" "github.com/Masterminds/semver/v3" @@ -142,6 +144,152 @@ func (r *Rust) Dependencies() map[string]string { return deps } +// Variables used as part of parsing imports from Rust source files. +var ( + useSinglePattern = regexp.MustCompile(`^\s*use\s+([^;]+);`) + useMultilineStartPattern = regexp.MustCompile(`^\s*use\s+\{$`) + useMultilineEndPattern = regexp.MustCompile(`^\s*};$`) + useMultilineNestedStartPattern = regexp.MustCompile(`^\s*((\w+::)+)\{$`) + useMultilineNestedEndPattern = regexp.MustCompile(`^\s*}$`) + multilineNested bool + multilineNestedPrefix string +) + +// Imports returns all source code imported packages. +func (r *Rust) Imports() []string { + importedPackages := make(map[string]bool) + + var importPaths []string + + root := "/Users/integralist/Code/test-projects/testing-fastly-cli" + _ = filepath.Walk(root, func(path string, _ os.FileInfo, _ error) error { + if strings.HasSuffix(path, ".rs") { + if strings.Contains(path, "/target/") { + return nil + } + + // gosec flagged this: + // G304 (CWE-22): Potential f inclusion via variable + // Disabling as we need to read files from the users machine. + // #nosec + f, err := os.Open(path) + if err != nil { + return nil + } + defer f.Close() + + scanner := bufio.NewScanner(f) + + var multilineUse bool + + for scanner.Scan() { + line := scanner.Text() + + // Parse single `use` declaration + match := useSinglePattern.FindStringSubmatch(line) + if len(match) >= 2 { + usePath := strings.TrimSpace(match[1]) + var cont bool + importPaths, cont = parseUseDeclarations(usePath, importPaths, importedPackages) + if cont { + continue + } + } + + // Parse multiline `use` declaration + if useMultilineStartPattern.MatchString(line) { + multilineUse = true + continue + } + if useMultilineEndPattern.MatchString(line) { + multilineUse = false + continue + } + if multilineUse && !useMultilineEndPattern.MatchString(line) { + usePath := strings.TrimSpace(line) + usePath = strings.TrimSuffix(usePath, ",") + importPaths, _ = parseUseDeclarations(usePath, importPaths, importedPackages) + } + } + } + return nil + }) + + sort.Strings(importPaths) + return importPaths +} + +func parseUseDeclarations( + usePath string, + importPaths []string, + importedPackages map[string]bool, +) ([]string, bool) { + // Parse a nested multiline crate declaration + // + // e.g. + // use { + // fastly::http::header, + // fastly::http::Method, + // fastly::http::StatusCode, + // fastly::{ <<< this + // mime, Error, Request, Response, <<< this + // }, <<< this + // }; + match := useMultilineNestedStartPattern.FindStringSubmatch(usePath) + if len(match) >= 2 { + multilineNested = true + multilineNestedPrefix = strings.TrimSpace(match[1]) + return importPaths, true + } + if useMultilineNestedEndPattern.MatchString(usePath) { + multilineNested = false + multilineNestedPrefix = "" + return importPaths, true + } + if multilineNested && !useMultilineNestedEndPattern.MatchString(usePath) { + usePath := strings.TrimSpace(usePath) + usePath = strings.TrimSuffix(usePath, ",") + for _, v := range strings.Split(usePath, ",") { + item := fmt.Sprintf("%s%s", multilineNestedPrefix, strings.TrimSpace(v)) + if !importedPackages[item] { + importPaths = append(importPaths, item) + importedPackages[item] = true + } + } + return importPaths, true + } + + // Find the position of the opening and closing curly braces + openBraceIndex := strings.Index(usePath, "{") + closeBraceIndex := strings.Index(usePath, "}") + + // Parse `use ::{, , }` + if openBraceIndex != -1 && closeBraceIndex != -1 { + // Extract the prefix before the opening curly brace + prefix := usePath[:openBraceIndex] + // Extract the contents inside the curly braces + contents := usePath[openBraceIndex+1 : closeBraceIndex] + + for _, item := range strings.Split(contents, ",") { + item = fmt.Sprintf("%s%s", strings.TrimSpace(prefix), strings.TrimSpace(item)) + if !importedPackages[item] { + importPaths = append(importPaths, item) + importedPackages[item] = true + } + } + return importPaths, true + } + + // Parse `use ;` + usePath = strings.TrimSpace(usePath) + if !importedPackages[usePath] { + importPaths = append(importPaths, usePath) + importedPackages[usePath] = true + } + + return importPaths, false +} + // Build compiles the user's source code into a Wasm binary. func (r *Rust) Build() error { if r.build == "" { diff --git a/pkg/commands/compute/language_toolchain.go b/pkg/commands/compute/language_toolchain.go index d91fb3af3..996002bd4 100644 --- a/pkg/commands/compute/language_toolchain.go +++ b/pkg/commands/compute/language_toolchain.go @@ -47,6 +47,8 @@ type Toolchain interface { DefaultBuildScript() bool // Dependencies returns all dependencies used by the project. Dependencies() map[string]string + // Imports returns all source code imported packages/crates/modules. + Imports() []string } // BuildToolchain enables a language toolchain to compile their build script. From 6fdce441cdac1768d3f66534c04c173a443b5d2e Mon Sep 17 00:00:00 2001 From: Integralist Date: Fri, 22 Sep 2023 16:48:09 +0100 Subject: [PATCH 24/60] feat(telemetry): add --show-metadata to compute build --- pkg/commands/compute/build.go | 28 ++++++++++++++++++++++++++++ pkg/commands/compute/compute_test.go | 2 ++ 2 files changed, 30 insertions(+) diff --git a/pkg/commands/compute/build.go b/pkg/commands/compute/build.go index 660dd7edf..6e987960f 100644 --- a/pkg/commands/compute/build.go +++ b/pkg/commands/compute/build.go @@ -2,7 +2,9 @@ package compute import ( "bufio" + "bytes" "crypto/rand" + "encoding/json" "errors" "fmt" "io" @@ -54,6 +56,7 @@ type Flags struct { type BuildCommand struct { cmd.Base enableTelemetry bool + showMetadata bool wasmtoolsVersioner github.AssetVersioner // NOTE: these are public so that the "serve" and "publish" composite @@ -80,6 +83,7 @@ func NewBuildCommand(parent cmd.Registerer, g *global.Data, wasmtoolsVersioner g // Hidden c.CmdClause.Flag("enable-telemetry", "Feature flag to trial the Wasm binary metadata annotations").Hidden().BoolVar(&c.enableTelemetry) + c.CmdClause.Flag("show-metadata", "Use wasm-tools to inspect metadata (requires --enable-telemetry)").Hidden().BoolVar(&c.showMetadata) return &c } @@ -271,6 +275,30 @@ func (c *BuildCommand) Exec(in io.Reader, out io.Writer) (err error) { if err != nil { return fmt.Errorf("failed to annotate binary with metadata: %w", err) } + + if c.showMetadata { + // gosec flagged this: + // G204 (CWE-78): Subprocess launched with variable + // Disabling as the variables come from trusted sources. + // #nosec + // nosemgrep + command := exec.Command(wasmtools, "metadata", "show", "bin/main.wasm", "--json") + wasmtoolsOutput, err := command.Output() + if err != nil { + return fmt.Errorf("failed to execute wasm-tools metadata command: %w", err) + } + text.Info(out, "Below is the metadata attached to the Wasm binary") + text.Break(out) + + var prettyJSON bytes.Buffer + err = json.Indent(&prettyJSON, wasmtoolsOutput, "", " ") + if err != nil { + return fmt.Errorf("failed to indent JSON metadata response from wasm-tools: %w", err) + } + + fmt.Fprintln(out, prettyJSON.String()) + text.Break(out) + } } dest := filepath.Join("pkg", fmt.Sprintf("%s.tar.gz", pkgName)) diff --git a/pkg/commands/compute/compute_test.go b/pkg/commands/compute/compute_test.go index f865ce695..eb239dd48 100644 --- a/pkg/commands/compute/compute_test.go +++ b/pkg/commands/compute/compute_test.go @@ -39,6 +39,7 @@ func TestPublishFlagDivergence(t *testing.T) { // Some flags on `compute build` are unique to it. ignoreBuildFlags := []string{ "enable-telemetry", + "show-metadata", } iter := buildFlags.MapRange() @@ -91,6 +92,7 @@ func TestServeFlagDivergence(t *testing.T) { // Some flags on `compute build` are unique to it. ignoreBuildFlags := []string{ "enable-telemetry", + "show-metadata", } iter := buildFlags.MapRange() From 96135245e11064114164a85c79999af34537e317 Mon Sep 17 00:00:00 2001 From: Integralist Date: Fri, 22 Sep 2023 17:03:46 +0100 Subject: [PATCH 25/60] fix: remove temporary path --- pkg/commands/compute/language_rust.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/commands/compute/language_rust.go b/pkg/commands/compute/language_rust.go index c535b7fd3..fddc10a61 100644 --- a/pkg/commands/compute/language_rust.go +++ b/pkg/commands/compute/language_rust.go @@ -161,7 +161,7 @@ func (r *Rust) Imports() []string { var importPaths []string - root := "/Users/integralist/Code/test-projects/testing-fastly-cli" + root := "." _ = filepath.Walk(root, func(path string, _ os.FileInfo, _ error) error { if strings.HasSuffix(path, ".rs") { if strings.Contains(path, "/target/") { From 713759c011ead5f6ecaa77d8168e1115517e65c6 Mon Sep 17 00:00:00 2001 From: Integralist Date: Fri, 22 Sep 2023 17:48:26 +0100 Subject: [PATCH 26/60] refactor(env): replace SplitN with Cut --- pkg/env/env.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/pkg/env/env.go b/pkg/env/env.go index 9211f674d..5f605e05c 100644 --- a/pkg/env/env.go +++ b/pkg/env/env.go @@ -34,11 +34,10 @@ const ( func Parse(environ []string) map[string]string { env := map[string]string{} for _, kv := range environ { - toks := strings.SplitN(kv, "=", 2) - if len(toks) != 2 { + k, v, ok := strings.Cut(kv, "=") + if !ok { continue } - k, v := toks[0], toks[1] env[k] = v } return env From c9717413f68de14e5288d222f2131a18a7020ed9 Mon Sep 17 00:00:00 2001 From: Integralist Date: Fri, 22 Sep 2023 17:48:57 +0100 Subject: [PATCH 27/60] feat(telemetry): parse JavaScript imports --- pkg/commands/compute/language_javascript.go | 51 ++++++++++++++++++++- 1 file changed, 50 insertions(+), 1 deletion(-) diff --git a/pkg/commands/compute/language_javascript.go b/pkg/commands/compute/language_javascript.go index e61a13397..259859341 100644 --- a/pkg/commands/compute/language_javascript.go +++ b/pkg/commands/compute/language_javascript.go @@ -1,11 +1,15 @@ package compute import ( + "bufio" "encoding/json" "errors" "io" "os" "path/filepath" + "regexp" + "sort" + "strings" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" @@ -137,9 +141,54 @@ func (j *JavaScript) Dependencies() map[string]string { return deps } +// Variables used as part of parsing imports from JavaScript source files. +var ( + importSingleLineBlockPattern = regexp.MustCompile(`^import (\{ [^;]+);`) + importAsPattern = regexp.MustCompile(`as [^\s]+\s*`) +) + // Imports returns all source code imported packages. func (j *JavaScript) Imports() []string { - return []string{} + importedPackages := make(map[string]bool) + + var importPaths []string + + root := "." + _ = filepath.Walk(root, func(path string, _ os.FileInfo, _ error) error { + if strings.HasSuffix(path, ".js") { + if strings.Contains(path, "node_modules") { + return nil + } + + // gosec flagged this: + // G304 (CWE-22): Potential f inclusion via variable + // Disabling as we need to read files from the users machine. + // #nosec + f, err := os.Open(path) + if err != nil { + return nil + } + defer f.Close() + + scanner := bufio.NewScanner(f) + + for scanner.Scan() { + line := scanner.Text() + match := importSingleLineBlockPattern.FindStringSubmatch(line) + if len(match) >= 2 { + item := importAsPattern.ReplaceAllString(match[1], "") + if !importedPackages[item] { + importPaths = append(importPaths, item) + importedPackages[item] = true + } + } + } + } + return nil + }) + + sort.Strings(importPaths) + return importPaths } // Build compiles the user's source code into a Wasm binary. From c44f76f8f785c38d3fc755abc8f7633f8855a2f6 Mon Sep 17 00:00:00 2001 From: Integralist Date: Fri, 22 Sep 2023 18:07:46 +0100 Subject: [PATCH 28/60] refactor(compute/build): namespace metadata --- pkg/commands/compute/build.go | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/pkg/commands/compute/build.go b/pkg/commands/compute/build.go index 6e987960f..f84d8a1ba 100644 --- a/pkg/commands/compute/build.go +++ b/pkg/commands/compute/build.go @@ -26,6 +26,7 @@ import ( "github.com/fastly/cli/pkg/github" "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/manifest" + "github.com/fastly/cli/pkg/revision" "github.com/fastly/cli/pkg/text" ) @@ -218,37 +219,37 @@ func (c *BuildCommand) Exec(in io.Reader, out io.Writer) (err error) { args := []string{ "metadata", "add", "bin/main.wasm", - "--language=CLI: " + strings.ToUpper(language.Name), - fmt.Sprintf("--processed-by=BuildInfoMemoryHeapAlloc=%d", memAfter.HeapAlloc-memBefore.HeapAlloc), - fmt.Sprintf("--processed-by=BuildInfoTime=%s", endTime.Sub(startTime)), - fmt.Sprintf("--processed-by=MachineInfoOS=%s", runtime.GOOS), - fmt.Sprintf("--processed-by=MachineInfoArch=%s", runtime.GOARCH), - fmt.Sprintf("--processed-by=MachineInfoCompiler=%s", runtime.Compiler), - fmt.Sprintf("--processed-by=MachineInfoGoVersion=%s", runtime.Version()), - fmt.Sprintf("--processed-by=MachineInfoCPUs=%d", runtime.NumCPU()), + fmt.Sprintf("--language=CLI_%s: %s", revision.AppVersion, strings.ToUpper(language.Name)), + fmt.Sprintf("--processed-by=CLI_BuildInfoMemoryHeapAlloc=%d", memAfter.HeapAlloc-memBefore.HeapAlloc), + fmt.Sprintf("--processed-by=CLI_BuildInfoTime=%s", endTime.Sub(startTime)), + fmt.Sprintf("--processed-by=CLI_MachineInfoOS=%s", runtime.GOOS), + fmt.Sprintf("--processed-by=CLI_MachineInfoArch=%s", runtime.GOARCH), + fmt.Sprintf("--processed-by=CLI_MachineInfoCompiler=%s", runtime.Compiler), + fmt.Sprintf("--processed-by=CLI_MachineInfoGoVersion=%s", runtime.Version()), + fmt.Sprintf("--processed-by=CLI_MachineInfoCPUs=%d", runtime.NumCPU()), } if c.Manifest.File.ClonedFrom != "" { - args = append(args, fmt.Sprintf("--processed-by=PackageInfoClonedFrom=%s", c.Manifest.File.ClonedFrom)) + args = append(args, fmt.Sprintf("--processed-by=CLI_PackageInfoClonedFrom=%s", c.Manifest.File.ClonedFrom)) } for i, v := range language.Imports() { - args = append(args, fmt.Sprintf("--processed-by=PackageInfoImported%d=%s", i, v)) + args = append(args, fmt.Sprintf("--processed-by=CLI_PackageInfoImported%d=%s", i, v)) } - args = append(args, fmt.Sprintf("--processed-by=ScriptsDefaultBuildUsed=%t", language.DefaultBuildScript())) + args = append(args, fmt.Sprintf("--processed-by=CLI_ScriptsDefaultBuildUsed=%t", language.DefaultBuildScript())) if c.Manifest.File.Scripts.Build != "" { - args = append(args, fmt.Sprintf("--processed-by=ScriptsBuild=%s", c.Manifest.File.Scripts.Build)) + args = append(args, fmt.Sprintf("--processed-by=CLI_ScriptsBuild=%s", c.Manifest.File.Scripts.Build)) } if len(c.Manifest.File.Scripts.EnvVars) > 0 { - args = append(args, fmt.Sprintf("--processed-by=ScriptsEnvVars=%s", c.Manifest.File.Scripts.EnvVars)) + args = append(args, fmt.Sprintf("--processed-by=CLI_ScriptsEnvVars=%s", c.Manifest.File.Scripts.EnvVars)) } if c.Manifest.File.Scripts.PostInit != "" { - args = append(args, fmt.Sprintf("--processed-by=ScriptsPostInit=%s", c.Manifest.File.Scripts.PostInit)) + args = append(args, fmt.Sprintf("--processed-by=CLI_ScriptsPostInit=%s", c.Manifest.File.Scripts.PostInit)) } if c.Manifest.File.Scripts.PostBuild != "" { - args = append(args, fmt.Sprintf("--processed-by=ScriptsPostBuild=%s", c.Manifest.File.Scripts.PostBuild)) + args = append(args, fmt.Sprintf("--processed-by=CLI_ScriptsPostBuild=%s", c.Manifest.File.Scripts.PostBuild)) } for k, v := range language.Dependencies() { From a1b52999f04a918e74fadc7d3446f7c6d104afa1 Mon Sep 17 00:00:00 2001 From: Integralist Date: Tue, 26 Sep 2023 10:37:39 +0100 Subject: [PATCH 29/60] remove: Imports() --- pkg/commands/compute/build.go | 4 - .../compute/language_assemblyscript.go | 5 - pkg/commands/compute/language_go.go | 49 ------ pkg/commands/compute/language_javascript.go | 54 ------- pkg/commands/compute/language_other.go | 5 - pkg/commands/compute/language_rust.go | 148 ------------------ pkg/commands/compute/language_toolchain.go | 2 - 7 files changed, 267 deletions(-) diff --git a/pkg/commands/compute/build.go b/pkg/commands/compute/build.go index f84d8a1ba..f23528ddb 100644 --- a/pkg/commands/compute/build.go +++ b/pkg/commands/compute/build.go @@ -233,10 +233,6 @@ func (c *BuildCommand) Exec(in io.Reader, out io.Writer) (err error) { args = append(args, fmt.Sprintf("--processed-by=CLI_PackageInfoClonedFrom=%s", c.Manifest.File.ClonedFrom)) } - for i, v := range language.Imports() { - args = append(args, fmt.Sprintf("--processed-by=CLI_PackageInfoImported%d=%s", i, v)) - } - args = append(args, fmt.Sprintf("--processed-by=CLI_ScriptsDefaultBuildUsed=%t", language.DefaultBuildScript())) if c.Manifest.File.Scripts.Build != "" { diff --git a/pkg/commands/compute/language_assemblyscript.go b/pkg/commands/compute/language_assemblyscript.go index 926e3f728..5b141ff9e 100644 --- a/pkg/commands/compute/language_assemblyscript.go +++ b/pkg/commands/compute/language_assemblyscript.go @@ -121,11 +121,6 @@ func (a *AssemblyScript) Dependencies() map[string]string { return deps } -// Imports returns all source code imported packages. -func (a *AssemblyScript) Imports() []string { - return []string{} -} - // Build compiles the user's source code into a Wasm binary. func (a *AssemblyScript) Build() error { if !a.verbose { diff --git a/pkg/commands/compute/language_go.go b/pkg/commands/compute/language_go.go index a41cee0e8..1d6bf7307 100644 --- a/pkg/commands/compute/language_go.go +++ b/pkg/commands/compute/language_go.go @@ -3,15 +3,10 @@ package compute import ( "bufio" "fmt" - "go/ast" - "go/parser" - "go/token" "io" "os" "os/exec" - "path/filepath" "regexp" - "sort" "strings" "github.com/Masterminds/semver/v3" @@ -132,50 +127,6 @@ func (g *Go) Dependencies() map[string]string { return deps } -// Imports returns all source code imported packages. -func (g *Go) Imports() []string { - fs := token.NewFileSet() - importedPackages := make(map[string]bool) - var importPaths []string - - root := "." - _ = filepath.Walk(root, func(path string, _ os.FileInfo, _ error) error { - if strings.HasSuffix(path, ".go") { - // gosec flagged this: - // G304 (CWE-22): Potential file inclusion via variable - // Disabling as we need to read files from the users machine. - // #nosec - data, err := os.ReadFile(path) - if err != nil { - return nil - } - - node, err := parser.ParseFile(fs, path, string(data), parser.AllErrors) - if err != nil { - return nil - } - - for _, decl := range node.Decls { - if gd, isGenDecl := decl.(*ast.GenDecl); isGenDecl && gd.Tok == token.IMPORT { - for _, spec := range gd.Specs { - if ispec, isImportSpec := spec.(*ast.ImportSpec); isImportSpec { - importPath := strings.TrimSpace(ispec.Path.Value) - if !importedPackages[importPath] { - importPaths = append(importPaths, importPath) - importedPackages[importPath] = true - } - } - } - } - } - } - return nil - }) - - sort.Strings(importPaths) - return importPaths -} - // Build compiles the user's source code into a Wasm binary. func (g *Go) Build() error { var ( diff --git a/pkg/commands/compute/language_javascript.go b/pkg/commands/compute/language_javascript.go index 259859341..aeef560a7 100644 --- a/pkg/commands/compute/language_javascript.go +++ b/pkg/commands/compute/language_javascript.go @@ -1,15 +1,11 @@ package compute import ( - "bufio" "encoding/json" "errors" "io" "os" "path/filepath" - "regexp" - "sort" - "strings" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" @@ -141,56 +137,6 @@ func (j *JavaScript) Dependencies() map[string]string { return deps } -// Variables used as part of parsing imports from JavaScript source files. -var ( - importSingleLineBlockPattern = regexp.MustCompile(`^import (\{ [^;]+);`) - importAsPattern = regexp.MustCompile(`as [^\s]+\s*`) -) - -// Imports returns all source code imported packages. -func (j *JavaScript) Imports() []string { - importedPackages := make(map[string]bool) - - var importPaths []string - - root := "." - _ = filepath.Walk(root, func(path string, _ os.FileInfo, _ error) error { - if strings.HasSuffix(path, ".js") { - if strings.Contains(path, "node_modules") { - return nil - } - - // gosec flagged this: - // G304 (CWE-22): Potential f inclusion via variable - // Disabling as we need to read files from the users machine. - // #nosec - f, err := os.Open(path) - if err != nil { - return nil - } - defer f.Close() - - scanner := bufio.NewScanner(f) - - for scanner.Scan() { - line := scanner.Text() - match := importSingleLineBlockPattern.FindStringSubmatch(line) - if len(match) >= 2 { - item := importAsPattern.ReplaceAllString(match[1], "") - if !importedPackages[item] { - importPaths = append(importPaths, item) - importedPackages[item] = true - } - } - } - } - return nil - }) - - sort.Strings(importPaths) - return importPaths -} - // Build compiles the user's source code into a Wasm binary. func (j *JavaScript) Build() error { if j.build == "" { diff --git a/pkg/commands/compute/language_other.go b/pkg/commands/compute/language_other.go index 0aefc9992..45f77f1a1 100644 --- a/pkg/commands/compute/language_other.go +++ b/pkg/commands/compute/language_other.go @@ -82,11 +82,6 @@ func (o Other) Dependencies() map[string]string { return deps } -// Imports returns all source code imported packages. -func (o Other) Imports() []string { - return []string{} -} - // Build implements the Toolchain interface and attempts to compile the package // source to a Wasm binary. func (o Other) Build() error { diff --git a/pkg/commands/compute/language_rust.go b/pkg/commands/compute/language_rust.go index fddc10a61..6976a44df 100644 --- a/pkg/commands/compute/language_rust.go +++ b/pkg/commands/compute/language_rust.go @@ -1,7 +1,6 @@ package compute import ( - "bufio" "bytes" "encoding/json" "fmt" @@ -10,7 +9,6 @@ import ( "os/exec" "path/filepath" "regexp" - "sort" "strings" "github.com/Masterminds/semver/v3" @@ -144,152 +142,6 @@ func (r *Rust) Dependencies() map[string]string { return deps } -// Variables used as part of parsing imports from Rust source files. -var ( - useSinglePattern = regexp.MustCompile(`^\s*use\s+([^;]+);`) - useMultilineStartPattern = regexp.MustCompile(`^\s*use\s+\{$`) - useMultilineEndPattern = regexp.MustCompile(`^\s*};$`) - useMultilineNestedStartPattern = regexp.MustCompile(`^\s*((\w+::)+)\{$`) - useMultilineNestedEndPattern = regexp.MustCompile(`^\s*}$`) - multilineNested bool - multilineNestedPrefix string -) - -// Imports returns all source code imported packages. -func (r *Rust) Imports() []string { - importedPackages := make(map[string]bool) - - var importPaths []string - - root := "." - _ = filepath.Walk(root, func(path string, _ os.FileInfo, _ error) error { - if strings.HasSuffix(path, ".rs") { - if strings.Contains(path, "/target/") { - return nil - } - - // gosec flagged this: - // G304 (CWE-22): Potential f inclusion via variable - // Disabling as we need to read files from the users machine. - // #nosec - f, err := os.Open(path) - if err != nil { - return nil - } - defer f.Close() - - scanner := bufio.NewScanner(f) - - var multilineUse bool - - for scanner.Scan() { - line := scanner.Text() - - // Parse single `use` declaration - match := useSinglePattern.FindStringSubmatch(line) - if len(match) >= 2 { - usePath := strings.TrimSpace(match[1]) - var cont bool - importPaths, cont = parseUseDeclarations(usePath, importPaths, importedPackages) - if cont { - continue - } - } - - // Parse multiline `use` declaration - if useMultilineStartPattern.MatchString(line) { - multilineUse = true - continue - } - if useMultilineEndPattern.MatchString(line) { - multilineUse = false - continue - } - if multilineUse && !useMultilineEndPattern.MatchString(line) { - usePath := strings.TrimSpace(line) - usePath = strings.TrimSuffix(usePath, ",") - importPaths, _ = parseUseDeclarations(usePath, importPaths, importedPackages) - } - } - } - return nil - }) - - sort.Strings(importPaths) - return importPaths -} - -func parseUseDeclarations( - usePath string, - importPaths []string, - importedPackages map[string]bool, -) ([]string, bool) { - // Parse a nested multiline crate declaration - // - // e.g. - // use { - // fastly::http::header, - // fastly::http::Method, - // fastly::http::StatusCode, - // fastly::{ <<< this - // mime, Error, Request, Response, <<< this - // }, <<< this - // }; - match := useMultilineNestedStartPattern.FindStringSubmatch(usePath) - if len(match) >= 2 { - multilineNested = true - multilineNestedPrefix = strings.TrimSpace(match[1]) - return importPaths, true - } - if useMultilineNestedEndPattern.MatchString(usePath) { - multilineNested = false - multilineNestedPrefix = "" - return importPaths, true - } - if multilineNested && !useMultilineNestedEndPattern.MatchString(usePath) { - usePath := strings.TrimSpace(usePath) - usePath = strings.TrimSuffix(usePath, ",") - for _, v := range strings.Split(usePath, ",") { - item := fmt.Sprintf("%s%s", multilineNestedPrefix, strings.TrimSpace(v)) - if !importedPackages[item] { - importPaths = append(importPaths, item) - importedPackages[item] = true - } - } - return importPaths, true - } - - // Find the position of the opening and closing curly braces - openBraceIndex := strings.Index(usePath, "{") - closeBraceIndex := strings.Index(usePath, "}") - - // Parse `use ::{, , }` - if openBraceIndex != -1 && closeBraceIndex != -1 { - // Extract the prefix before the opening curly brace - prefix := usePath[:openBraceIndex] - // Extract the contents inside the curly braces - contents := usePath[openBraceIndex+1 : closeBraceIndex] - - for _, item := range strings.Split(contents, ",") { - item = fmt.Sprintf("%s%s", strings.TrimSpace(prefix), strings.TrimSpace(item)) - if !importedPackages[item] { - importPaths = append(importPaths, item) - importedPackages[item] = true - } - } - return importPaths, true - } - - // Parse `use ;` - usePath = strings.TrimSpace(usePath) - if !importedPackages[usePath] { - importPaths = append(importPaths, usePath) - importedPackages[usePath] = true - } - - return importPaths, false -} - // Build compiles the user's source code into a Wasm binary. func (r *Rust) Build() error { if r.build == "" { diff --git a/pkg/commands/compute/language_toolchain.go b/pkg/commands/compute/language_toolchain.go index 996002bd4..d91fb3af3 100644 --- a/pkg/commands/compute/language_toolchain.go +++ b/pkg/commands/compute/language_toolchain.go @@ -47,8 +47,6 @@ type Toolchain interface { DefaultBuildScript() bool // Dependencies returns all dependencies used by the project. Dependencies() map[string]string - // Imports returns all source code imported packages/crates/modules. - Imports() []string } // BuildToolchain enables a language toolchain to compile their build script. From 39fa5cc952fa5aa870feba218cc464600bf71950 Mon Sep 17 00:00:00 2001 From: Integralist Date: Tue, 26 Sep 2023 10:44:40 +0100 Subject: [PATCH 30/60] refactor: rename env var to disable wasm metadata collection --- pkg/commands/compute/build.go | 8 ++++---- pkg/config/config.go | 8 ++++---- pkg/env/env.go | 7 ++++--- 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/pkg/commands/compute/build.go b/pkg/commands/compute/build.go index f23528ddb..3d8b0ecac 100644 --- a/pkg/commands/compute/build.go +++ b/pkg/commands/compute/build.go @@ -128,8 +128,8 @@ func (c *BuildCommand) Exec(in io.Reader, out io.Writer) (err error) { var wasmtools string // FIXME: When we remove feature flag, put in ability to disable telemetry. - // disableTelemetry, _ := strconv.ParseBool(c.Globals.Env.TelemetryDisable) - if c.enableTelemetry /*|| !disableTelemetry*/ { + // disableWasmMetadata, _ := strconv.ParseBool(c.Globals.Env.WasmMetadataDisable) + if c.enableTelemetry /*|| !disableWasmMetadata*/ { wasmtools, err = GetWasmTools(spinner, out, c.wasmtoolsVersioner, c.Globals) if err != nil { return err @@ -200,7 +200,7 @@ func (c *BuildCommand) Exec(in io.Reader, out io.Writer) (err error) { startTime time.Time ) // FIXME: When we remove feature flag, put in ability to disable telemetry. - if c.enableTelemetry /*|| !disableTelemetry*/ { + if c.enableTelemetry /*|| !disableWasmMetadata*/ { runtime.ReadMemStats(&memBefore) startTime = time.Now() } @@ -213,7 +213,7 @@ func (c *BuildCommand) Exec(in io.Reader, out io.Writer) (err error) { } // FIXME: When we remove feature flag, put in ability to disable telemetry. - if c.enableTelemetry /*|| !disableTelemetry*/ { + if c.enableTelemetry /*|| !disableWasmMetadata*/ { endTime := time.Now() runtime.ReadMemStats(&memAfter) diff --git a/pkg/config/config.go b/pkg/config/config.go index 710f67f73..953bafdd0 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -393,16 +393,16 @@ func (f *File) Write(path string) error { // Environment represents all of the configuration parameters that can come // from environment variables. type Environment struct { - Token string - Endpoint string - TelemetryDisable string + Token string + Endpoint string + WasmMetadataDisable string } // Read populates the fields from the provided environment. func (e *Environment) Read(state map[string]string) { e.Token = state[env.Token] e.Endpoint = state[env.Endpoint] - e.TelemetryDisable = state[env.TelemetryDisable] + e.WasmMetadataDisable = state[env.WasmMetadataDisable] } // invalidStaticConfigErr generates an error to alert the user to an issue with diff --git a/pkg/env/env.go b/pkg/env/env.go index 5f605e05c..86b150a66 100644 --- a/pkg/env/env.go +++ b/pkg/env/env.go @@ -25,9 +25,10 @@ const ( // CustomerID is the env var we look in for a Customer ID. CustomerID = "FASTLY_CUSTOMER_ID" - // TelemetryDisable is the env var we look in to disable all telemetry. - // Set to "true" to disable all telemetry. - TelemetryDisable = "FASTLY_TELEMETRY_DISABLE" + // WasmMetadataDisable is the env var we look in to disable all data + // collection related to a Wasm binary. + // Set to "true" to disable all forms of data collection. + WasmMetadataDisable = "FASTLY_WASM_METADATA_DISABLE" ) // Parse transforms the local environment data structure into a map type. From 0032563621fa65ff5ee6a45fb1379c151267ddd3 Mon Sep 17 00:00:00 2001 From: Integralist Date: Tue, 26 Sep 2023 14:26:00 +0100 Subject: [PATCH 31/60] fix(compute/build): switch metadata from go.sum to go.mod --- pkg/commands/compute/build.go | 18 +++++------ pkg/commands/compute/compute_test.go | 4 +-- pkg/commands/compute/language_go.go | 46 +++++++++++++++++++++++++--- 3 files changed, 52 insertions(+), 16 deletions(-) diff --git a/pkg/commands/compute/build.go b/pkg/commands/compute/build.go index 3d8b0ecac..02051c9ec 100644 --- a/pkg/commands/compute/build.go +++ b/pkg/commands/compute/build.go @@ -56,7 +56,7 @@ type Flags struct { // BuildCommand produces a deployable artifact from files on the local disk. type BuildCommand struct { cmd.Base - enableTelemetry bool + enableMetadata bool showMetadata bool wasmtoolsVersioner github.AssetVersioner @@ -83,8 +83,8 @@ func NewBuildCommand(parent cmd.Registerer, g *global.Data, wasmtoolsVersioner g c.CmdClause.Flag("timeout", "Timeout, in seconds, for the build compilation step").IntVar(&c.Flags.Timeout) // Hidden - c.CmdClause.Flag("enable-telemetry", "Feature flag to trial the Wasm binary metadata annotations").Hidden().BoolVar(&c.enableTelemetry) - c.CmdClause.Flag("show-metadata", "Use wasm-tools to inspect metadata (requires --enable-telemetry)").Hidden().BoolVar(&c.showMetadata) + c.CmdClause.Flag("enable-metadata", "Feature flag to trial the Wasm binary metadata annotations").Hidden().BoolVar(&c.enableMetadata) + c.CmdClause.Flag("show-metadata", "Use wasm-tools to inspect metadata (requires --enable-metadata)").Hidden().BoolVar(&c.showMetadata) return &c } @@ -127,9 +127,9 @@ func (c *BuildCommand) Exec(in io.Reader, out io.Writer) (err error) { } var wasmtools string - // FIXME: When we remove feature flag, put in ability to disable telemetry. + // FIXME: When we remove feature flag, put in ability to disable metadata. // disableWasmMetadata, _ := strconv.ParseBool(c.Globals.Env.WasmMetadataDisable) - if c.enableTelemetry /*|| !disableWasmMetadata*/ { + if c.enableMetadata /*|| !disableWasmMetadata*/ { wasmtools, err = GetWasmTools(spinner, out, c.wasmtoolsVersioner, c.Globals) if err != nil { return err @@ -199,8 +199,8 @@ func (c *BuildCommand) Exec(in io.Reader, out io.Writer) (err error) { memBefore, memAfter runtime.MemStats startTime time.Time ) - // FIXME: When we remove feature flag, put in ability to disable telemetry. - if c.enableTelemetry /*|| !disableWasmMetadata*/ { + // FIXME: When we remove feature flag, put in ability to disable metadata. + if c.enableMetadata /*|| !disableWasmMetadata*/ { runtime.ReadMemStats(&memBefore) startTime = time.Now() } @@ -212,8 +212,8 @@ func (c *BuildCommand) Exec(in io.Reader, out io.Writer) (err error) { return err } - // FIXME: When we remove feature flag, put in ability to disable telemetry. - if c.enableTelemetry /*|| !disableWasmMetadata*/ { + // FIXME: When we remove feature flag, put in ability to disable metadata. + if c.enableMetadata /*|| !disableWasmMetadata*/ { endTime := time.Now() runtime.ReadMemStats(&memAfter) diff --git a/pkg/commands/compute/compute_test.go b/pkg/commands/compute/compute_test.go index eb239dd48..cac220744 100644 --- a/pkg/commands/compute/compute_test.go +++ b/pkg/commands/compute/compute_test.go @@ -38,7 +38,7 @@ func TestPublishFlagDivergence(t *testing.T) { // Some flags on `compute build` are unique to it. ignoreBuildFlags := []string{ - "enable-telemetry", + "enable-metadata", "show-metadata", } @@ -91,7 +91,7 @@ func TestServeFlagDivergence(t *testing.T) { // Some flags on `compute build` are unique to it. ignoreBuildFlags := []string{ - "enable-telemetry", + "enable-metadata", "show-metadata", } diff --git a/pkg/commands/compute/language_go.go b/pkg/commands/compute/language_go.go index 1d6bf7307..d78bd4958 100644 --- a/pkg/commands/compute/language_go.go +++ b/pkg/commands/compute/language_go.go @@ -110,15 +110,51 @@ func (g *Go) DefaultBuildScript() bool { func (g *Go) Dependencies() map[string]string { deps := make(map[string]string) - if f, err := os.Open("go.sum"); err == nil { + if f, err := os.Open("go.mod"); err == nil { defer f.Close() + var insideRequireBlock bool + scanner := bufio.NewScanner(f) for scanner.Scan() { line := scanner.Text() - segs := strings.Split(line, " ") - if len(segs) >= 2 { - pkg := segs[0] - version := strings.Split(segs[1], "/")[0] // e.g. `v0.2.0/go.mod` + parts := strings.Fields(line) + + // go.mod has two separate `require` definitions: + // + // 1. + // require github.com/fastly/compute-sdk-go v1.0.0 + // + // 2. + // require ( + // github.com/fastly/compute-sdk-go v1.0.0 + // golang.org/x/mod v0.4.2 // indirect + // ) + // + // We avoid including 'indirect' dependencies by ignoring lines with a + // length greater than three segments. + + if len(parts) >= 2 && parts[0] == "require" && parts[1] == "(" { + insideRequireBlock = true + continue + } + if len(parts) == 1 && parts[0] == ")" { + insideRequireBlock = false + continue + } + if len(parts) >= 2 && !insideRequireBlock && parts[0] != "require" { + continue + } + + var pkg, version string + switch len(parts) { + case 2: + pkg = parts[0] + version = parts[1] + case 3: + pkg = parts[1] + version = parts[2] + } + if pkg != "" && version != "" { deps[pkg] = version } } From 944ec5f3c1bafe55d3b5c51aafcc18efe9c310d6 Mon Sep 17 00:00:00 2001 From: Integralist Date: Tue, 26 Sep 2023 14:53:38 +0100 Subject: [PATCH 32/60] feat: set only CLI version in metadata when metadata disabled --- pkg/commands/compute/build.go | 78 +++++++++++++++++++---------------- 1 file changed, 42 insertions(+), 36 deletions(-) diff --git a/pkg/commands/compute/build.go b/pkg/commands/compute/build.go index 02051c9ec..84bcd852b 100644 --- a/pkg/commands/compute/build.go +++ b/pkg/commands/compute/build.go @@ -2,9 +2,7 @@ package compute import ( "bufio" - "bytes" "crypto/rand" - "encoding/json" "errors" "fmt" "io" @@ -126,14 +124,9 @@ func (c *BuildCommand) Exec(in io.Reader, out io.Writer) (err error) { return err } - var wasmtools string - // FIXME: When we remove feature flag, put in ability to disable metadata. - // disableWasmMetadata, _ := strconv.ParseBool(c.Globals.Env.WasmMetadataDisable) - if c.enableMetadata /*|| !disableWasmMetadata*/ { - wasmtools, err = GetWasmTools(spinner, out, c.wasmtoolsVersioner, c.Globals) - if err != nil { - return err - } + wasmtools, err := GetWasmTools(spinner, out, c.wasmtoolsVersioner, c.Globals) + if err != nil { + return err } defer func(errLog fsterr.LogInterface) { @@ -217,6 +210,7 @@ func (c *BuildCommand) Exec(in io.Reader, out io.Writer) (err error) { endTime := time.Now() runtime.ReadMemStats(&memAfter) + // FIXME: Once #1013 and #1016 merged, integrate granular disabling. args := []string{ "metadata", "add", "bin/main.wasm", fmt.Sprintf("--language=CLI_%s: %s", revision.AppVersion, strings.ToUpper(language.Name)), @@ -252,25 +246,9 @@ func (c *BuildCommand) Exec(in io.Reader, out io.Writer) (err error) { args = append(args, fmt.Sprintf("--sdk=%s=%s", k, v)) } - // gosec flagged this: - // G204 (CWE-78): Subprocess launched with function call as argument or command arguments - // Disabling as we trust the source of the variable. - // #nosec - // nosemgrep: go.lang.security.audit.dangerous-exec-command.dangerous-exec-command - command := exec.Command(wasmtools, args...) - wasmtoolsOutput, err := command.Output() + err = c.executeWasmtools(wasmtools, args) if err != nil { - return fmt.Errorf("failed to annotate binary with metadata: %w", err) - } - // Ensure the Wasm binary can be executed. - // - // G302 (CWE-276): Expect file permissions to be 0600 or less - // gosec flagged this: - // Disabling as we want all users to be able to execute this binary. - // #nosec - err = os.WriteFile("bin/main.wasm", wasmtoolsOutput, 0o777) - if err != nil { - return fmt.Errorf("failed to annotate binary with metadata: %w", err) + return err } if c.showMetadata { @@ -279,7 +257,7 @@ func (c *BuildCommand) Exec(in io.Reader, out io.Writer) (err error) { // Disabling as the variables come from trusted sources. // #nosec // nosemgrep - command := exec.Command(wasmtools, "metadata", "show", "bin/main.wasm", "--json") + command := exec.Command(wasmtools, "metadata", "show", "bin/main.wasm") wasmtoolsOutput, err := command.Output() if err != nil { return fmt.Errorf("failed to execute wasm-tools metadata command: %w", err) @@ -287,15 +265,19 @@ func (c *BuildCommand) Exec(in io.Reader, out io.Writer) (err error) { text.Info(out, "Below is the metadata attached to the Wasm binary") text.Break(out) - var prettyJSON bytes.Buffer - err = json.Indent(&prettyJSON, wasmtoolsOutput, "", " ") - if err != nil { - return fmt.Errorf("failed to indent JSON metadata response from wasm-tools: %w", err) - } - - fmt.Fprintln(out, prettyJSON.String()) + fmt.Fprintln(out, string(wasmtoolsOutput)) text.Break(out) } + } else { + // NOTE: If not collecting metadata, just record the CLI version. + args := []string{ + "metadata", "add", "bin/main.wasm", + fmt.Sprintf("--language=CLI_%s: %s", revision.AppVersion, strings.ToUpper(language.Name)), + } + err = c.executeWasmtools(wasmtools, args) + if err != nil { + return err + } } dest := filepath.Join("pkg", fmt.Sprintf("%s.tar.gz", pkgName)) @@ -378,6 +360,30 @@ func (c *BuildCommand) Exec(in io.Reader, out io.Writer) (err error) { return nil } +func (c *BuildCommand) executeWasmtools(wasmtools string, args []string) error { + // gosec flagged this: + // G204 (CWE-78): Subprocess launched with function call as argument or command arguments + // Disabling as we trust the source of the variable. + // #nosec + // nosemgrep: go.lang.security.audit.dangerous-exec-command.dangerous-exec-command + command := exec.Command(wasmtools, args...) + wasmtoolsOutput, err := command.Output() + if err != nil { + return fmt.Errorf("failed to annotate binary with metadata: %w", err) + } + // Ensure the Wasm binary can be executed. + // + // G302 (CWE-276): Expect file permissions to be 0600 or less + // gosec flagged this: + // Disabling as we want all users to be able to execute this binary. + // #nosec + err = os.WriteFile("bin/main.wasm", wasmtoolsOutput, 0o777) + if err != nil { + return fmt.Errorf("failed to annotate binary with metadata: %w", err) + } + return nil +} + // includeSourceCode calculates what source code files to include in the final // package.tar.gz that is uploaded to the Fastly API. // From 847530f95e9b0b3ca28508142dc0e1e535d50879 Mon Sep 17 00:00:00 2001 From: Integralist Date: Tue, 26 Sep 2023 15:18:44 +0100 Subject: [PATCH 33/60] fix: move placement of wasmtools install --- pkg/commands/compute/build.go | 10 +++++----- pkg/commands/compute/build_test.go | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/pkg/commands/compute/build.go b/pkg/commands/compute/build.go index 84bcd852b..fcd5a7c43 100644 --- a/pkg/commands/compute/build.go +++ b/pkg/commands/compute/build.go @@ -124,11 +124,6 @@ func (c *BuildCommand) Exec(in io.Reader, out io.Writer) (err error) { return err } - wasmtools, err := GetWasmTools(spinner, out, c.wasmtoolsVersioner, c.Globals) - if err != nil { - return err - } - defer func(errLog fsterr.LogInterface) { if err != nil { errLog.Add(err) @@ -154,6 +149,11 @@ func (c *BuildCommand) Exec(in io.Reader, out io.Writer) (err error) { return err } + wasmtools, err := GetWasmTools(spinner, out, c.wasmtoolsVersioner, c.Globals) + if err != nil { + return err + } + var pkgName string err = spinner.Process("Identifying package name", func(_ *text.SpinnerWrapper) error { pkgName, err = c.PackageName(manifestFilename) diff --git a/pkg/commands/compute/build_test.go b/pkg/commands/compute/build_test.go index a8d9803e6..a1b6384b3 100644 --- a/pkg/commands/compute/build_test.go +++ b/pkg/commands/compute/build_test.go @@ -33,7 +33,7 @@ func TestBuildRust(t *testing.T) { Status: http.StatusText(http.StatusOK), StatusCode: http.StatusOK, }, - }, []error{}), + }, []error{nil}), Org: "bytecodealliance", Repo: "wasm-tools", Binary: "wasm-tools", From 0fafb8bff2c493ece7e7ce08243ffa9be20f2aca Mon Sep 17 00:00:00 2001 From: Integralist Date: Tue, 26 Sep 2023 17:56:11 +0100 Subject: [PATCH 34/60] fix: compute tests --- pkg/commands/compute/build.go | 2 +- pkg/commands/compute/build_test.go | 223 ++++++++++------------------- pkg/github/github.go | 6 + pkg/mock/versioner.go | 14 +- pkg/testutil/env.go | 10 +- 5 files changed, 104 insertions(+), 151 deletions(-) diff --git a/pkg/commands/compute/build.go b/pkg/commands/compute/build.go index fcd5a7c43..d287a51dd 100644 --- a/pkg/commands/compute/build.go +++ b/pkg/commands/compute/build.go @@ -449,7 +449,7 @@ func (c *BuildCommand) PackageName(manifestFilename string) (string, error) { // If there is no version installed, install the latest version. // If there is a version installed, update to the latest version if not already. func GetWasmTools(spinner text.Spinner, out io.Writer, wasmtoolsVersioner github.AssetVersioner, g *global.Data) (binPath string, err error) { - binPath = filepath.Join(github.InstallDir, wasmtoolsVersioner.BinaryName()) + binPath = wasmtoolsVersioner.InstallPath() // NOTE: When checking if wasm-tools is installed we don't use $PATH. // diff --git a/pkg/commands/compute/build_test.go b/pkg/commands/compute/build_test.go index a1b6384b3..e4a7bfcc6 100644 --- a/pkg/commands/compute/build_test.go +++ b/pkg/commands/compute/build_test.go @@ -2,8 +2,6 @@ package compute_test import ( "fmt" - "io" - "net/http" "os" "os/exec" "path/filepath" @@ -13,7 +11,6 @@ import ( "github.com/fastly/cli/pkg/app" "github.com/fastly/cli/pkg/commands/compute" "github.com/fastly/cli/pkg/config" - "github.com/fastly/cli/pkg/github" "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/mock" "github.com/fastly/cli/pkg/testutil" @@ -26,19 +23,6 @@ func TestBuildRust(t *testing.T) { t.Skip("Set TEST_COMPUTE_BUILD to run this test") } - wasmtoolsVersioner := github.New(github.Opts{ - HTTPClient: mock.HTMLClient([]*http.Response{ - { - Body: io.NopCloser(strings.NewReader("...")), - Status: http.StatusText(http.StatusOK), - StatusCode: http.StatusOK, - }, - }, []error{nil}), - Org: "bytecodealliance", - Repo: "wasm-tools", - Binary: "wasm-tools", - }) - args := testutil.Args scenarios := []struct { @@ -50,16 +34,12 @@ func TestBuildRust(t *testing.T) { wantError string wantRemediationError string wantOutput []string - versioners *app.Versioners }{ { name: "no fastly.toml manifest", args: args("compute build"), wantError: "error reading fastly.toml", wantRemediationError: "Run `fastly compute init` to ensure a correctly configured manifest.", - versioners: &app.Versioners{ - WasmTools: wasmtoolsVersioner, - }, }, { name: "empty language", @@ -68,9 +48,6 @@ func TestBuildRust(t *testing.T) { manifest_version = 2 name = "test"`, wantError: "language cannot be empty, please provide a language", - versioners: &app.Versioners{ - WasmTools: wasmtoolsVersioner, - }, }, { name: "unknown language", @@ -80,9 +57,6 @@ func TestBuildRust(t *testing.T) { name = "test" language = "foobar"`, wantError: "unsupported language foobar", - versioners: &app.Versioners{ - WasmTools: wasmtoolsVersioner, - }, }, // The following test validates that the project compiles successfully even // though the fastly.toml manifest has no build script. There should be a @@ -117,9 +91,6 @@ func TestBuildRust(t *testing.T) { "The following default build command for", "cargo build --bin my-project", }, - versioners: &app.Versioners{ - WasmTools: wasmtoolsVersioner, - }, }, { name: "build error", @@ -147,9 +118,6 @@ func TestBuildRust(t *testing.T) { [scripts] build = "echo no compilation happening"`, wantRemediationError: compute.DefaultBuildErrorRemediation, - versioners: &app.Versioners{ - WasmTools: wasmtoolsVersioner, - }, }, // NOTE: This test passes --verbose so we can validate specific outputs. { @@ -181,9 +149,6 @@ func TestBuildRust(t *testing.T) { "Creating ./bin directory (for Wasm binary)", "Built package", }, - versioners: &app.Versioners{ - WasmTools: wasmtoolsVersioner, - }, }, } for testcaseIdx := range scenarios { @@ -196,6 +161,8 @@ func TestBuildRust(t *testing.T) { t.Fatal(err) } + wasmtoolsBinName := "wasm-tools" + // Create test environment rootdir := testutil.NewEnv(testutil.EnvOpts{ T: t, @@ -206,11 +173,14 @@ func TestBuildRust(t *testing.T) { {Src: filepath.Join("testdata", "deploy", "pkg", "package.tar.gz"), Dst: filepath.Join("pkg", "package.tar.gz")}, }, Write: []testutil.FileIO{ + {Src: `#!/usr/bin/env bash + echo wasm-tools 1.0.4`, Dst: wasmtoolsBinName, Executable: true}, {Src: testcase.fastlyManifest, Dst: manifest.Filename}, {Src: testcase.cargoManifest, Dst: "Cargo.toml"}, }, }) defer os.RemoveAll(rootdir) + wasmtoolsBinPath := filepath.Join(rootdir, wasmtoolsBinName) // Before running the test, chdir into the build environment. // When we're done, chdir back to our original location. @@ -223,9 +193,14 @@ func TestBuildRust(t *testing.T) { var stdout threadsafe.Buffer opts := testutil.NewRunOpts(testcase.args, &stdout) opts.ConfigFile = testcase.applicationConfig - - if testcase.versioners != nil { - opts.Versioners = *testcase.versioners + opts.Versioners = app.Versioners{ + WasmTools: mock.AssetVersioner{ + AssetVersion: "1.2.3", + BinaryFilename: wasmtoolsBinName, + DownloadOK: true, + DownloadedFile: wasmtoolsBinPath, + InstallFilePath: wasmtoolsBinPath, // avoid overwriting developer's actual wasm-tools install + }, } err = app.Run(opts) @@ -252,13 +227,6 @@ func TestBuildGo(t *testing.T) { t.Skip("Set TEST_COMPUTE_BUILD to run this test") } - wasmtoolsVersioner := github.New(github.Opts{ - HTTPClient: mock.HTMLClient([]*http.Response{}, []error{}), - Org: "bytecodealliance", - Repo: "wasm-tools", - Binary: "wasm-tools", - }) - args := testutil.Args scenarios := []struct { @@ -269,16 +237,12 @@ func TestBuildGo(t *testing.T) { wantError string wantRemediationError string wantOutput []string - versioners *app.Versioners }{ { name: "no fastly.toml manifest", args: args("compute build"), wantError: "error reading fastly.toml", wantRemediationError: "Run `fastly compute init` to ensure a correctly configured manifest.", - versioners: &app.Versioners{ - WasmTools: wasmtoolsVersioner, - }, }, { name: "empty language", @@ -287,9 +251,6 @@ func TestBuildGo(t *testing.T) { manifest_version = 2 name = "test"`, wantError: "language cannot be empty, please provide a language", - versioners: &app.Versioners{ - WasmTools: wasmtoolsVersioner, - }, }, { name: "unknown language", @@ -299,9 +260,6 @@ func TestBuildGo(t *testing.T) { name = "test" language = "foobar"`, wantError: "unsupported language foobar", - versioners: &app.Versioners{ - WasmTools: wasmtoolsVersioner, - }, }, // The following test validates that the project compiles successfully even // though the fastly.toml manifest has no build script. There should be a @@ -336,9 +294,6 @@ func TestBuildGo(t *testing.T) { "Creating ./bin directory (for Wasm binary)", "Built package", }, - versioners: &app.Versioners{ - WasmTools: wasmtoolsVersioner, - }, }, // The following test case is expected to fail because we specify a custom // build script that doesn't actually produce a ./bin/main.wasm @@ -362,9 +317,6 @@ func TestBuildGo(t *testing.T) { [scripts] build = "echo no compilation happening"`, wantRemediationError: compute.DefaultBuildErrorRemediation, - versioners: &app.Versioners{ - WasmTools: wasmtoolsVersioner, - }, }, } for testcaseIdx := range scenarios { @@ -377,6 +329,8 @@ func TestBuildGo(t *testing.T) { t.Fatal(err) } + wasmtoolsBinName := "wasm-tools" + // Create test environment rootdir := testutil.NewEnv(testutil.EnvOpts{ T: t, @@ -385,10 +339,13 @@ func TestBuildGo(t *testing.T) { {Src: filepath.Join("testdata", "build", "go", "main.go"), Dst: "main.go"}, }, Write: []testutil.FileIO{ + {Src: `#!/usr/bin/env bash + echo wasm-tools 1.0.4`, Dst: wasmtoolsBinName, Executable: true}, {Src: testcase.fastlyManifest, Dst: manifest.Filename}, }, }) defer os.RemoveAll(rootdir) + wasmtoolsBinPath := filepath.Join(rootdir, wasmtoolsBinName) // Before running the test, chdir into the build environment. // When we're done, chdir back to our original location. @@ -401,9 +358,14 @@ func TestBuildGo(t *testing.T) { var stdout threadsafe.Buffer opts := testutil.NewRunOpts(testcase.args, &stdout) opts.ConfigFile = testcase.applicationConfig - - if testcase.versioners != nil { - opts.Versioners = *testcase.versioners + opts.Versioners = app.Versioners{ + WasmTools: mock.AssetVersioner{ + AssetVersion: "1.2.3", + BinaryFilename: wasmtoolsBinName, + DownloadOK: true, + DownloadedFile: wasmtoolsBinPath, + InstallFilePath: wasmtoolsBinPath, // avoid overwriting developer's actual wasm-tools install + }, } err = app.Run(opts) @@ -430,13 +392,6 @@ func TestBuildJavaScript(t *testing.T) { t.Skip("Set TEST_COMPUTE_BUILD to run this test") } - wasmtoolsVersioner := github.New(github.Opts{ - HTTPClient: mock.HTMLClient([]*http.Response{}, []error{}), - Org: "bytecodealliance", - Repo: "wasm-tools", - Binary: "wasm-tools", - }) - args := testutil.Args scenarios := []struct { @@ -454,9 +409,6 @@ func TestBuildJavaScript(t *testing.T) { args: args("compute build"), wantError: "error reading fastly.toml", wantRemediationError: "Run `fastly compute init` to ensure a correctly configured manifest.", - versioners: &app.Versioners{ - WasmTools: wasmtoolsVersioner, - }, }, { name: "empty language", @@ -465,9 +417,6 @@ func TestBuildJavaScript(t *testing.T) { manifest_version = 2 name = "test"`, wantError: "language cannot be empty, please provide a language", - versioners: &app.Versioners{ - WasmTools: wasmtoolsVersioner, - }, }, { name: "unknown language", @@ -477,9 +426,6 @@ func TestBuildJavaScript(t *testing.T) { name = "test" language = "foobar"`, wantError: "unsupported language foobar", - versioners: &app.Versioners{ - WasmTools: wasmtoolsVersioner, - }, }, // The following test validates that the project compiles successfully even // though the fastly.toml manifest has no build script. There should be a @@ -498,9 +444,6 @@ func TestBuildJavaScript(t *testing.T) { "The following default build command for", "npm exec webpack", // our testdata package.json references webpack }, - versioners: &app.Versioners{ - WasmTools: wasmtoolsVersioner, - }, }, { name: "build error", @@ -513,9 +456,6 @@ func TestBuildJavaScript(t *testing.T) { [scripts] build = "echo no compilation happening"`, wantRemediationError: compute.DefaultBuildErrorRemediation, - versioners: &app.Versioners{ - WasmTools: wasmtoolsVersioner, - }, }, // NOTE: This test passes --verbose so we can validate specific outputs. { @@ -533,9 +473,6 @@ func TestBuildJavaScript(t *testing.T) { "Built package", }, npmInstall: true, - versioners: &app.Versioners{ - WasmTools: wasmtoolsVersioner, - }, }, } for testcaseIdx := range scenarios { @@ -548,6 +485,8 @@ func TestBuildJavaScript(t *testing.T) { t.Fatal(err) } + wasmtoolsBinName := "wasm-tools" + // Create test environment rootdir := testutil.NewEnv(testutil.EnvOpts{ T: t, @@ -557,10 +496,13 @@ func TestBuildJavaScript(t *testing.T) { {Src: filepath.Join("testdata", "build", "javascript", "src", "index.js"), Dst: filepath.Join("src", "index.js")}, }, Write: []testutil.FileIO{ + {Src: `#!/usr/bin/env bash + echo wasm-tools 1.0.4`, Dst: wasmtoolsBinName, Executable: true}, {Src: testcase.fastlyManifest, Dst: manifest.Filename}, }, }) defer os.RemoveAll(rootdir) + wasmtoolsBinPath := filepath.Join(rootdir, wasmtoolsBinName) // Before running the test, chdir into the build environment. // When we're done, chdir back to our original location. @@ -587,9 +529,14 @@ func TestBuildJavaScript(t *testing.T) { var stdout threadsafe.Buffer opts := testutil.NewRunOpts(testcase.args, &stdout) - - if testcase.versioners != nil { - opts.Versioners = *testcase.versioners + opts.Versioners = app.Versioners{ + WasmTools: mock.AssetVersioner{ + AssetVersion: "1.2.3", + BinaryFilename: wasmtoolsBinName, + DownloadOK: true, + DownloadedFile: wasmtoolsBinPath, + InstallFilePath: wasmtoolsBinPath, // avoid overwriting developer's actual wasm-tools install + }, } err = app.Run(opts) @@ -616,13 +563,6 @@ func TestBuildAssemblyScript(t *testing.T) { t.Skip("Set TEST_COMPUTE_BUILD to run this test") } - wasmtoolsVersioner := github.New(github.Opts{ - HTTPClient: mock.HTMLClient([]*http.Response{}, []error{}), - Org: "bytecodealliance", - Repo: "wasm-tools", - Binary: "wasm-tools", - }) - args := testutil.Args scenarios := []struct { @@ -633,16 +573,12 @@ func TestBuildAssemblyScript(t *testing.T) { wantRemediationError string wantOutput []string npmInstall bool - versioners *app.Versioners }{ { name: "no fastly.toml manifest", args: args("compute build"), wantError: "error reading fastly.toml", wantRemediationError: "Run `fastly compute init` to ensure a correctly configured manifest.", - versioners: &app.Versioners{ - WasmTools: wasmtoolsVersioner, - }, }, { name: "empty language", @@ -651,9 +587,6 @@ func TestBuildAssemblyScript(t *testing.T) { manifest_version = 2 name = "test"`, wantError: "language cannot be empty, please provide a language", - versioners: &app.Versioners{ - WasmTools: wasmtoolsVersioner, - }, }, { name: "unknown language", @@ -663,9 +596,6 @@ func TestBuildAssemblyScript(t *testing.T) { name = "test" language = "foobar"`, wantError: "unsupported language foobar", - versioners: &app.Versioners{ - WasmTools: wasmtoolsVersioner, - }, }, // The following test validates that the project compiles successfully even // though the fastly.toml manifest has no build script. There should be a @@ -684,9 +614,6 @@ func TestBuildAssemblyScript(t *testing.T) { "The following default build command for", "npm exec -- asc", }, - versioners: &app.Versioners{ - WasmTools: wasmtoolsVersioner, - }, }, { name: "build error", @@ -699,9 +626,6 @@ func TestBuildAssemblyScript(t *testing.T) { [scripts] build = "echo no compilation happening"`, wantRemediationError: compute.DefaultBuildErrorRemediation, - versioners: &app.Versioners{ - WasmTools: wasmtoolsVersioner, - }, }, // NOTE: This test passes --verbose so we can validate specific outputs. { @@ -719,9 +643,6 @@ func TestBuildAssemblyScript(t *testing.T) { "Built package", }, npmInstall: true, - versioners: &app.Versioners{ - WasmTools: wasmtoolsVersioner, - }, }, } for testcaseIdx := range scenarios { @@ -734,6 +655,8 @@ func TestBuildAssemblyScript(t *testing.T) { t.Fatal(err) } + wasmtoolsBinName := "wasm-tools" + // Create test environment rootdir := testutil.NewEnv(testutil.EnvOpts{ T: t, @@ -742,10 +665,13 @@ func TestBuildAssemblyScript(t *testing.T) { {Src: filepath.Join("testdata", "build", "assemblyscript", "assembly", "index.ts"), Dst: filepath.Join("assembly", "index.ts")}, }, Write: []testutil.FileIO{ + {Src: `#!/usr/bin/env bash + echo wasm-tools 1.0.4`, Dst: wasmtoolsBinName, Executable: true}, {Src: testcase.fastlyManifest, Dst: manifest.Filename}, }, }) defer os.RemoveAll(rootdir) + wasmtoolsBinPath := filepath.Join(rootdir, wasmtoolsBinName) // Before running the test, chdir into the build environment. // When we're done, chdir back to our original location. @@ -774,9 +700,14 @@ func TestBuildAssemblyScript(t *testing.T) { var stdout threadsafe.Buffer opts := testutil.NewRunOpts(testcase.args, &stdout) - - if testcase.versioners != nil { - opts.Versioners = *testcase.versioners + opts.Versioners = app.Versioners{ + WasmTools: mock.AssetVersioner{ + AssetVersion: "1.2.3", + BinaryFilename: wasmtoolsBinName, + DownloadOK: true, + DownloadedFile: wasmtoolsBinPath, + InstallFilePath: wasmtoolsBinPath, // avoid overwriting developer's actual wasm-tools install + }, } err = app.Run(opts) @@ -799,13 +730,6 @@ func TestBuildAssemblyScript(t *testing.T) { // NOTE: TestBuildOther also validates the post_build settings. func TestBuildOther(t *testing.T) { - wasmtoolsVersioner := github.New(github.Opts{ - HTTPClient: mock.HTMLClient([]*http.Response{}, []error{}), - Org: "bytecodealliance", - Repo: "wasm-tools", - Binary: "wasm-tools", - }) - args := testutil.Args if os.Getenv("TEST_COMPUTE_BUILD") == "" { t.Log("skipping test") @@ -819,6 +743,8 @@ func TestBuildOther(t *testing.T) { t.Fatal(err) } + wasmtoolsBinName := "wasm-tools" + // Create test environment // // NOTE: Our only requirement is that there be a bin directory. The custom @@ -840,10 +766,14 @@ func TestBuildOther(t *testing.T) { {Src: "./testdata/main.wasm", Dst: "bin/main.wasm"}, }, Write: []testutil.FileIO{ + {Src: `#!/usr/bin/env bash + echo wasm-tools 1.0.4`, Dst: wasmtoolsBinName, Executable: true}, {Src: "mock content", Dst: "bin/testfile"}, }, }) defer os.RemoveAll(rootdir) + wasmtoolsBinPath := filepath.Join(rootdir, wasmtoolsBinName) + mainwasmBinPath := filepath.Join(rootdir, "bin", "main.wasm") // Before running the test, chdir into the build environment. // When we're done, chdir back to our original location. @@ -862,7 +792,6 @@ func TestBuildOther(t *testing.T) { wantError string wantOutput []string wantRemediationError string - versioners *app.Versioners }{ { name: "stop build process", @@ -879,9 +808,6 @@ func TestBuildOther(t *testing.T) { "Do you want to run this now?", }, wantError: "build process stopped by user", - versioners: &app.Versioners{ - WasmTools: wasmtoolsVersioner, - }, }, // NOTE: All following tests pass --verbose so we can see post_build output. { @@ -899,9 +825,6 @@ func TestBuildOther(t *testing.T) { "Do you want to run this now?", "Built package", }, - versioners: &app.Versioners{ - WasmTools: wasmtoolsVersioner, - }, }, { name: "language pulled from manifest", @@ -919,9 +842,6 @@ func TestBuildOther(t *testing.T) { "Do you want to run this now?", "Built package", }, - versioners: &app.Versioners{ - WasmTools: wasmtoolsVersioner, - }, }, { name: "avoid prompt confirmation", @@ -939,12 +859,22 @@ func TestBuildOther(t *testing.T) { "Do you want to run this now?", }, wantError: "exit status 1", // because we have to trigger an error to see the post_build output - versioners: &app.Versioners{ - WasmTools: wasmtoolsVersioner, - }, }, } { t.Run(testcase.name, func(t *testing.T) { + // Make a backup of the bin/main.wasm as it will get modified by the + // post_build script and that will cause it to fail validation. + mainWasmBackup, err := os.ReadFile(mainwasmBinPath) + if err != nil { + t.Fatal(err) + } + defer func() { + err := os.WriteFile(mainwasmBinPath, mainWasmBackup, 0o777) + if err != nil { + t.Fatal(err) + } + }() + if testcase.fastlyManifest != "" { if err := os.WriteFile(filepath.Join(rootdir, manifest.Filename), []byte(testcase.fastlyManifest), 0o777); err != nil { t.Fatal(err) @@ -954,9 +884,14 @@ func TestBuildOther(t *testing.T) { var stdout threadsafe.Buffer opts := testutil.NewRunOpts(testcase.args, &stdout) opts.Stdin = strings.NewReader(testcase.stdin) // NOTE: build only has one prompt when dealing with a custom build - - if testcase.versioners != nil { - opts.Versioners = *testcase.versioners + opts.Versioners = app.Versioners{ + WasmTools: mock.AssetVersioner{ + AssetVersion: "1.2.3", + BinaryFilename: wasmtoolsBinName, + DownloadOK: true, + DownloadedFile: wasmtoolsBinPath, + InstallFilePath: wasmtoolsBinPath, // avoid overwriting developer's actual wasm-tools install + }, } err = app.Run(opts) diff --git a/pkg/github/github.go b/pkg/github/github.go index a51204ce9..d12f793b8 100644 --- a/pkg/github/github.go +++ b/pkg/github/github.go @@ -261,6 +261,10 @@ func (g *Asset) metadata() (m DevHubMetadata, err error) { return m, nil } +func (g *Asset) InstallPath() string { + return filepath.Join(InstallDir, g.BinaryName()) +} + // DevHubMetadata represents the DevHub API response for software metadata. type DevHubMetadata struct { // URL is the endpoint for downloading the release asset. @@ -279,6 +283,8 @@ type AssetVersioner interface { DownloadLatest() (bin string, err error) // DownloadVersion downloads the specified version of the asset. DownloadVersion(version string) (bin string, err error) + // InstallPath returns the location of where the binary should be installed. + InstallPath() string // RequestedVersion returns the version defined in the fastly.toml file. RequestedVersion() (version string) // SetRequestedVersion sets the version of the asset to be downloaded. diff --git a/pkg/mock/versioner.go b/pkg/mock/versioner.go index 080de7437..97c9d5993 100644 --- a/pkg/mock/versioner.go +++ b/pkg/mock/versioner.go @@ -4,10 +4,11 @@ import "fmt" // AssetVersioner mocks the github.AssetVersioner interface. type AssetVersioner struct { - AssetVersion string - BinaryFilename string - DownloadOK bool - DownloadedFile string + AssetVersion string + BinaryFilename string + DownloadOK bool + DownloadedFile string + InstallFilePath string } // BinaryName implements github.Versioner interface. @@ -52,3 +53,8 @@ func (av AssetVersioner) RequestedVersion() (version string) { func (av AssetVersioner) SetRequestedVersion(_ string) { // no-op } + +// InstallPath returns the location of where the binary should be installed. +func (av AssetVersioner) InstallPath() string { + return av.InstallFilePath +} diff --git a/pkg/testutil/env.go b/pkg/testutil/env.go index d481da631..32b03f9c4 100644 --- a/pkg/testutil/env.go +++ b/pkg/testutil/env.go @@ -10,8 +10,9 @@ import ( // FileIO represents a source file and a destination. type FileIO struct { - Src string // path to a file inside ./testdata/ OR file content - Dst string // path to a file relative to test environment's root directory + Src string // path to a file inside ./testdata/ OR file content + Dst string // path to a file relative to test environment's root directory + Executable bool // if path can be executed as a binary } // EnvOpts represents configuration when creating a new environment. @@ -59,6 +60,11 @@ func NewEnv(opts EnvOpts) (rootdir string) { if err := os.WriteFile(dst, []byte(src), 0o777); err != nil /* #nosec */ { opts.T.Fatal(err) } + if f.Executable { + if err := os.Chmod(dst, os.FileMode(0o755)); err != nil { + opts.T.Fatal(err) + } + } } if len(opts.Exec) > 0 { From a5de50c9c2285f7918a132e16442a4ab7fff1bb7 Mon Sep 17 00:00:00 2001 From: Integralist Date: Tue, 26 Sep 2023 18:12:47 +0100 Subject: [PATCH 35/60] fix: Windows test --- pkg/testutil/args.go | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/pkg/testutil/args.go b/pkg/testutil/args.go index 6e3eb027b..a40bd1837 100644 --- a/pkg/testutil/args.go +++ b/pkg/testutil/args.go @@ -12,6 +12,7 @@ import ( "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/manifest" "github.com/fastly/cli/pkg/mock" + "github.com/fastly/cli/pkg/runtime" ) var argsPattern = regexp.MustCompile("`.+`") @@ -62,8 +63,13 @@ func NewRunOpts(args []string, stdout io.Writer) app.RunOpts { md.File.SetOutput(stdout) _ = md.File.Read(manifest.Filename) + configPath := "/dev/null" + if runtime.Windows { + configPath = "NUL" + } + return app.RunOpts{ - ConfigPath: "/dev/null", + ConfigPath: configPath, Args: args, APIClient: mock.APIClient(mock.API{}), Env: config.Environment{}, From b966c72e8f3d624c40bd0776120227978d1ca880 Mon Sep 17 00:00:00 2001 From: Integralist Date: Wed, 27 Sep 2023 11:35:00 +0100 Subject: [PATCH 36/60] debugging windows --- .github/workflows/pr_test.yml | 2 +- cmd/fastly/main.go | 20 +-- pkg/app/run.go | 38 ++--- pkg/commands/compute/build.go | 52 +++---- pkg/commands/compute/build_test.go | 219 +++++++++++++++++++++-------- pkg/global/global.go | 2 + pkg/testutil/args.go | 9 +- 7 files changed, 228 insertions(+), 114 deletions(-) diff --git a/.github/workflows/pr_test.yml b/.github/workflows/pr_test.yml index fc0c48e15..3d19f0bf5 100644 --- a/.github/workflows/pr_test.yml +++ b/.github/workflows/pr_test.yml @@ -152,7 +152,7 @@ jobs: shell: bash env: # NOTE: The following lets us focus the test run while debugging. - # TEST_ARGS: "-run TestDeploy ./pkg/commands/compute/..." + # TEST_ARGS: "-run TestBuild ./pkg/commands/compute/..." TEST_COMPUTE_INIT: true TEST_COMPUTE_BUILD: true TEST_COMPUTE_DEPLOY: true diff --git a/cmd/fastly/main.go b/cmd/fastly/main.go index 6c0725b74..3d5ad1054 100644 --- a/cmd/fastly/main.go +++ b/cmd/fastly/main.go @@ -13,6 +13,7 @@ import ( "github.com/fastly/cli/pkg/api" "github.com/fastly/cli/pkg/app" + "github.com/fastly/cli/pkg/commands/compute" "github.com/fastly/cli/pkg/config" "github.com/fastly/cli/pkg/env" fsterr "github.com/fastly/cli/pkg/errors" @@ -88,15 +89,16 @@ func main() { client, err := fastly.NewClientForEndpoint(token, endpoint) return client, err }, - Args: args, - ConfigFile: cfg, - ConfigPath: config.FilePath, - Env: e, - ErrLog: fsterr.Log, - HTTPClient: httpClient, - Manifest: &md, - Stdin: in, - Stdout: out, + Args: args, + ConfigFile: cfg, + ConfigPath: config.FilePath, + Env: e, + ErrLog: fsterr.Log, + ExecuteWasmTools: compute.ExecuteWasmTools, + HTTPClient: httpClient, + Manifest: &md, + Stdin: in, + Stdout: out, Versioners: app.Versioners{ CLI: github.New(github.Opts{ HTTPClient: httpClient, diff --git a/pkg/app/run.go b/pkg/app/run.go index d17fcd993..f01a7f3d4 100644 --- a/pkg/app/run.go +++ b/pkg/app/run.go @@ -48,13 +48,14 @@ func Run(opts RunOpts) error { // The g will hold generally-applicable configuration parameters // from a variety of sources, and is provided to each concrete command. g := global.Data{ - Env: opts.Env, - ErrLog: opts.ErrLog, - Config: opts.ConfigFile, - ConfigPath: opts.ConfigPath, - HTTPClient: opts.HTTPClient, - Manifest: *opts.Manifest, - Output: opts.Stdout, + Config: opts.ConfigFile, + ConfigPath: opts.ConfigPath, + Env: opts.Env, + ErrLog: opts.ErrLog, + ExecuteWasmTools: opts.ExecuteWasmTools, + HTTPClient: opts.HTTPClient, + Manifest: *opts.Manifest, + Output: opts.Stdout, } // Set up the main application root, including global flags, and then each @@ -190,17 +191,18 @@ func Run(opts RunOpts) error { // RunOpts represent arguments to Run() type RunOpts struct { - APIClient APIClientFactory - Args []string - ConfigFile config.File - ConfigPath string - Env config.Environment - ErrLog fsterr.LogInterface - HTTPClient api.HTTPClient - Manifest *manifest.Data - Stdin io.Reader - Stdout io.Writer - Versioners Versioners + APIClient APIClientFactory + Args []string + ConfigFile config.File + ConfigPath string + Env config.Environment + ErrLog fsterr.LogInterface + ExecuteWasmTools func(bin string, args []string) error + HTTPClient api.HTTPClient + Manifest *manifest.Data + Stdin io.Reader + Stdout io.Writer + Versioners Versioners } // APIClientFactory creates a Fastly API client (modeled as an api.Interface) diff --git a/pkg/commands/compute/build.go b/pkg/commands/compute/build.go index d287a51dd..ec26f5915 100644 --- a/pkg/commands/compute/build.go +++ b/pkg/commands/compute/build.go @@ -246,7 +246,7 @@ func (c *BuildCommand) Exec(in io.Reader, out io.Writer) (err error) { args = append(args, fmt.Sprintf("--sdk=%s=%s", k, v)) } - err = c.executeWasmtools(wasmtools, args) + err = c.Globals.ExecuteWasmTools(wasmtools, args) if err != nil { return err } @@ -274,7 +274,7 @@ func (c *BuildCommand) Exec(in io.Reader, out io.Writer) (err error) { "metadata", "add", "bin/main.wasm", fmt.Sprintf("--language=CLI_%s: %s", revision.AppVersion, strings.ToUpper(language.Name)), } - err = c.executeWasmtools(wasmtools, args) + err = c.Globals.ExecuteWasmTools(wasmtools, args) if err != nil { return err } @@ -360,30 +360,6 @@ func (c *BuildCommand) Exec(in io.Reader, out io.Writer) (err error) { return nil } -func (c *BuildCommand) executeWasmtools(wasmtools string, args []string) error { - // gosec flagged this: - // G204 (CWE-78): Subprocess launched with function call as argument or command arguments - // Disabling as we trust the source of the variable. - // #nosec - // nosemgrep: go.lang.security.audit.dangerous-exec-command.dangerous-exec-command - command := exec.Command(wasmtools, args...) - wasmtoolsOutput, err := command.Output() - if err != nil { - return fmt.Errorf("failed to annotate binary with metadata: %w", err) - } - // Ensure the Wasm binary can be executed. - // - // G302 (CWE-276): Expect file permissions to be 0600 or less - // gosec flagged this: - // Disabling as we want all users to be able to execute this binary. - // #nosec - err = os.WriteFile("bin/main.wasm", wasmtoolsOutput, 0o777) - if err != nil { - return fmt.Errorf("failed to annotate binary with metadata: %w", err) - } - return nil -} - // includeSourceCode calculates what source code files to include in the final // package.tar.gz that is uploaded to the Fastly API. // @@ -445,6 +421,30 @@ func (c *BuildCommand) PackageName(manifestFilename string) (string, error) { return sanitize.BaseName(name), nil } +func ExecuteWasmTools(wasmtools string, args []string) error { + // gosec flagged this: + // G204 (CWE-78): Subprocess launched with function call as argument or command arguments + // Disabling as we trust the source of the variable. + // #nosec + // nosemgrep: go.lang.security.audit.dangerous-exec-command.dangerous-exec-command + command := exec.Command(wasmtools, args...) + wasmtoolsOutput, err := command.Output() + if err != nil { + return fmt.Errorf("failed to annotate binary with metadata: %w", err) + } + // Ensure the Wasm binary can be executed. + // + // G302 (CWE-276): Expect file permissions to be 0600 or less + // gosec flagged this: + // Disabling as we want all users to be able to execute this binary. + // #nosec + err = os.WriteFile("bin/main.wasm", wasmtoolsOutput, 0o777) + if err != nil { + return fmt.Errorf("failed to annotate binary with metadata: %w", err) + } + return nil +} + // GetWasmTools returns the path to the wasm-tools binary. // If there is no version installed, install the latest version. // If there is a version installed, update to the latest version if not already. diff --git a/pkg/commands/compute/build_test.go b/pkg/commands/compute/build_test.go index e4a7bfcc6..d4004dcb6 100644 --- a/pkg/commands/compute/build_test.go +++ b/pkg/commands/compute/build_test.go @@ -85,7 +85,7 @@ func TestBuildRust(t *testing.T) { fastlyManifest: ` manifest_version = 2 name = "test" - language = "rust"`, + language = "rust"`, wantOutput: []string{ "No [scripts.build] found in fastly.toml.", // requires --verbose "The following default build command for", @@ -115,8 +115,8 @@ func TestBuildRust(t *testing.T) { name = "test" language = "rust" - [scripts] - build = "echo no compilation happening"`, + [scripts] + build = "echo no compilation happening"`, wantRemediationError: compute.DefaultBuildErrorRemediation, }, // NOTE: This test passes --verbose so we can validate specific outputs. @@ -143,8 +143,8 @@ func TestBuildRust(t *testing.T) { name = "test" language = "rust" - [scripts] - build = "%s"`, fmt.Sprintf(compute.RustDefaultBuildCommand, compute.RustDefaultPackageName)), + [scripts] + build = "%s"`, fmt.Sprintf(compute.RustDefaultBuildCommand, compute.RustDefaultPackageName)), wantOutput: []string{ "Creating ./bin directory (for Wasm binary)", "Built package", @@ -163,6 +163,24 @@ func TestBuildRust(t *testing.T) { wasmtoolsBinName := "wasm-tools" + // Windows was having issues when trying to move a tmpBin file (which + // represents the latest binary downloaded from GitHub) to binPath (which + // represents the existing binary installed on a user's machine). + // + // The problem was, for the sake of the tests, I just create one file + // `wasmtoolsBinName` and used that for both `tmpBin` and `binPath` and + // this works fine on *nix systems. But once Windows did `os.Rename()` and + // move tmpBin to binPath it would no longer be able to set permissions on + // the binPath because it didn't think the file existed any more. My guess + // is that moving a file over itself causes Windows to remove the file. + // + // So to work around that issue I just create two separate files because + // in reality that's what the CLI will be dealing with. I only used one + // file for the sake of test case convenience (which ironically became + // very INCONVENIENT when the tests started unexpectedly failing on + // Windows and caused me a long time debugging). + latestDownloaded := wasmtoolsBinName + "-latest-downloaded" + // Create test environment rootdir := testutil.NewEnv(testutil.EnvOpts{ T: t, @@ -175,6 +193,8 @@ func TestBuildRust(t *testing.T) { Write: []testutil.FileIO{ {Src: `#!/usr/bin/env bash echo wasm-tools 1.0.4`, Dst: wasmtoolsBinName, Executable: true}, + {Src: `#!/usr/bin/env bash + echo wasm-tools 2.0.0`, Dst: latestDownloaded, Executable: true}, {Src: testcase.fastlyManifest, Dst: manifest.Filename}, {Src: testcase.cargoManifest, Dst: "Cargo.toml"}, }, @@ -198,7 +218,7 @@ func TestBuildRust(t *testing.T) { AssetVersion: "1.2.3", BinaryFilename: wasmtoolsBinName, DownloadOK: true, - DownloadedFile: wasmtoolsBinPath, + DownloadedFile: latestDownloaded, InstallFilePath: wasmtoolsBinPath, // avoid overwriting developer's actual wasm-tools install }, } @@ -331,6 +351,24 @@ func TestBuildGo(t *testing.T) { wasmtoolsBinName := "wasm-tools" + // Windows was having issues when trying to move a tmpBin file (which + // represents the latest binary downloaded from GitHub) to binPath (which + // represents the existing binary installed on a user's machine). + // + // The problem was, for the sake of the tests, I just create one file + // `wasmtoolsBinName` and used that for both `tmpBin` and `binPath` and + // this works fine on *nix systems. But once Windows did `os.Rename()` and + // move tmpBin to binPath it would no longer be able to set permissions on + // the binPath because it didn't think the file existed any more. My guess + // is that moving a file over itself causes Windows to remove the file. + // + // So to work around that issue I just create two separate files because + // in reality that's what the CLI will be dealing with. I only used one + // file for the sake of test case convenience (which ironically became + // very INCONVENIENT when the tests started unexpectedly failing on + // Windows and caused me a long time debugging). + latestDownloaded := wasmtoolsBinName + "-latest-downloaded" + // Create test environment rootdir := testutil.NewEnv(testutil.EnvOpts{ T: t, @@ -341,6 +379,8 @@ func TestBuildGo(t *testing.T) { Write: []testutil.FileIO{ {Src: `#!/usr/bin/env bash echo wasm-tools 1.0.4`, Dst: wasmtoolsBinName, Executable: true}, + {Src: `#!/usr/bin/env bash + echo wasm-tools 2.0.0`, Dst: latestDownloaded, Executable: true}, {Src: testcase.fastlyManifest, Dst: manifest.Filename}, }, }) @@ -363,7 +403,7 @@ func TestBuildGo(t *testing.T) { AssetVersion: "1.2.3", BinaryFilename: wasmtoolsBinName, DownloadOK: true, - DownloadedFile: wasmtoolsBinPath, + DownloadedFile: latestDownloaded, InstallFilePath: wasmtoolsBinPath, // avoid overwriting developer's actual wasm-tools install }, } @@ -487,6 +527,24 @@ func TestBuildJavaScript(t *testing.T) { wasmtoolsBinName := "wasm-tools" + // Windows was having issues when trying to move a tmpBin file (which + // represents the latest binary downloaded from GitHub) to binPath (which + // represents the existing binary installed on a user's machine). + // + // The problem was, for the sake of the tests, I just create one file + // `wasmtoolsBinName` and used that for both `tmpBin` and `binPath` and + // this works fine on *nix systems. But once Windows did `os.Rename()` and + // move tmpBin to binPath it would no longer be able to set permissions on + // the binPath because it didn't think the file existed any more. My guess + // is that moving a file over itself causes Windows to remove the file. + // + // So to work around that issue I just create two separate files because + // in reality that's what the CLI will be dealing with. I only used one + // file for the sake of test case convenience (which ironically became + // very INCONVENIENT when the tests started unexpectedly failing on + // Windows and caused me a long time debugging). + latestDownloaded := wasmtoolsBinName + "-latest-downloaded" + // Create test environment rootdir := testutil.NewEnv(testutil.EnvOpts{ T: t, @@ -498,6 +556,8 @@ func TestBuildJavaScript(t *testing.T) { Write: []testutil.FileIO{ {Src: `#!/usr/bin/env bash echo wasm-tools 1.0.4`, Dst: wasmtoolsBinName, Executable: true}, + {Src: `#!/usr/bin/env bash + echo wasm-tools 2.0.0`, Dst: latestDownloaded, Executable: true}, {Src: testcase.fastlyManifest, Dst: manifest.Filename}, }, }) @@ -534,7 +594,7 @@ func TestBuildJavaScript(t *testing.T) { AssetVersion: "1.2.3", BinaryFilename: wasmtoolsBinName, DownloadOK: true, - DownloadedFile: wasmtoolsBinPath, + DownloadedFile: latestDownloaded, InstallFilePath: wasmtoolsBinPath, // avoid overwriting developer's actual wasm-tools install }, } @@ -657,6 +717,24 @@ func TestBuildAssemblyScript(t *testing.T) { wasmtoolsBinName := "wasm-tools" + // Windows was having issues when trying to move a tmpBin file (which + // represents the latest binary downloaded from GitHub) to binPath (which + // represents the existing binary installed on a user's machine). + // + // The problem was, for the sake of the tests, I just create one file + // `wasmtoolsBinName` and used that for both `tmpBin` and `binPath` and + // this works fine on *nix systems. But once Windows did `os.Rename()` and + // move tmpBin to binPath it would no longer be able to set permissions on + // the binPath because it didn't think the file existed any more. My guess + // is that moving a file over itself causes Windows to remove the file. + // + // So to work around that issue I just create two separate files because + // in reality that's what the CLI will be dealing with. I only used one + // file for the sake of test case convenience (which ironically became + // very INCONVENIENT when the tests started unexpectedly failing on + // Windows and caused me a long time debugging). + latestDownloaded := wasmtoolsBinName + "-latest-downloaded" + // Create test environment rootdir := testutil.NewEnv(testutil.EnvOpts{ T: t, @@ -667,6 +745,8 @@ func TestBuildAssemblyScript(t *testing.T) { Write: []testutil.FileIO{ {Src: `#!/usr/bin/env bash echo wasm-tools 1.0.4`, Dst: wasmtoolsBinName, Executable: true}, + {Src: `#!/usr/bin/env bash + echo wasm-tools 2.0.0`, Dst: latestDownloaded, Executable: true}, {Src: testcase.fastlyManifest, Dst: manifest.Filename}, }, }) @@ -705,7 +785,7 @@ func TestBuildAssemblyScript(t *testing.T) { AssetVersion: "1.2.3", BinaryFilename: wasmtoolsBinName, DownloadOK: true, - DownloadedFile: wasmtoolsBinPath, + DownloadedFile: latestDownloaded, InstallFilePath: wasmtoolsBinPath, // avoid overwriting developer's actual wasm-tools install }, } @@ -736,53 +816,6 @@ func TestBuildOther(t *testing.T) { t.Skip("Set TEST_COMPUTE_BUILD to run this test") } - // We're going to chdir to a build environment, - // so save the PWD to return to, afterwards. - pwd, err := os.Getwd() - if err != nil { - t.Fatal(err) - } - - wasmtoolsBinName := "wasm-tools" - - // Create test environment - // - // NOTE: Our only requirement is that there be a bin directory. The custom - // build script we're using in the test is not going to use any files in the - // directory (the script will just `echo` a message). - // - // NOTE: We create a "valid" main.wasm file with a quick shell script. - // - // Previously we set the build script to "touch ./bin/main.wasm" but since - // adding Wasm validation this no longer works as it's an empty file. - // - // So we use the following script to produce a file that LOOKS valid but isn't. - // - // magic="\x00\x61\x73\x6d\x01\x00\x00\x00" - // printf "$magic" > ./pkg/commands/compute/testdata/main.wasm - rootdir := testutil.NewEnv(testutil.EnvOpts{ - T: t, - Copy: []testutil.FileIO{ - {Src: "./testdata/main.wasm", Dst: "bin/main.wasm"}, - }, - Write: []testutil.FileIO{ - {Src: `#!/usr/bin/env bash - echo wasm-tools 1.0.4`, Dst: wasmtoolsBinName, Executable: true}, - {Src: "mock content", Dst: "bin/testfile"}, - }, - }) - defer os.RemoveAll(rootdir) - wasmtoolsBinPath := filepath.Join(rootdir, wasmtoolsBinName) - mainwasmBinPath := filepath.Join(rootdir, "bin", "main.wasm") - - // Before running the test, chdir into the build environment. - // When we're done, chdir back to our original location. - // This is so we can reliably copy the testdata/ fixtures. - if err := os.Chdir(rootdir); err != nil { - t.Fatal(err) - } - defer os.Chdir(pwd) - for _, testcase := range []struct { args []string dontWantOutput []string @@ -862,8 +895,80 @@ func TestBuildOther(t *testing.T) { }, } { t.Run(testcase.name, func(t *testing.T) { + // We're going to chdir to a build environment, + // so save the PWD to return to, afterwards. + pwd, err := os.Getwd() + if err != nil { + t.Fatal(err) + } + + wasmtoolsBinName := "wasm-tools" + + // Windows was having issues when trying to move a tmpBin file (which + // represents the latest binary downloaded from GitHub) to binPath (which + // represents the existing binary installed on a user's machine). + // + // The problem was, for the sake of the tests, I just create one file + // `wasmtoolsBinName` and used that for both `tmpBin` and `binPath` and + // this works fine on *nix systems. But once Windows did `os.Rename()` and + // move tmpBin to binPath it would no longer be able to set permissions on + // the binPath because it didn't think the file existed any more. My guess + // is that moving a file over itself causes Windows to remove the file. + // + // So to work around that issue I just create two separate files because + // in reality that's what the CLI will be dealing with. I only used one + // file for the sake of test case convenience (which ironically became + // very INCONVENIENT when the tests started unexpectedly failing on + // Windows and caused me a long time debugging). + latestDownloaded := wasmtoolsBinName + "-latest-downloaded" + + // Create test environment + // + // NOTE: Our only requirement is that there be a bin directory. The custom + // build script we're using in the test is not going to use any files in the + // directory (the script will just `echo` a message). + // + // NOTE: We create a "valid" main.wasm file with a quick shell script. + // + // Previously we set the build script to "touch ./bin/main.wasm" but since + // adding Wasm validation this no longer works as it's an empty file. + // + // So we use the following script to produce a file that LOOKS valid but isn't. + // + // magic="\x00\x61\x73\x6d\x01\x00\x00\x00" + // printf "$magic" > ./pkg/commands/compute/testdata/main.wasm + rootdir := testutil.NewEnv(testutil.EnvOpts{ + T: t, + Copy: []testutil.FileIO{ + {Src: "./testdata/main.wasm", Dst: "bin/main.wasm"}, + }, + Write: []testutil.FileIO{ + {Src: `#!/usr/bin/env bash + echo wasm-tools 1.0.4`, Dst: wasmtoolsBinName, Executable: true}, + {Src: `#!/usr/bin/env bash + echo wasm-tools 2.0.0`, Dst: latestDownloaded, Executable: true}, + {Src: "mock content", Dst: "bin/testfile"}, + }, + }) + defer os.RemoveAll(rootdir) + wasmtoolsBinPath := filepath.Join(rootdir, wasmtoolsBinName) + mainwasmBinPath := filepath.Join(rootdir, "bin", "main.wasm") + + // Before running the test, chdir into the build environment. + // When we're done, chdir back to our original location. + // This is so we can reliably copy the testdata/ fixtures. + if err := os.Chdir(rootdir); err != nil { + t.Fatal(err) + } + defer os.Chdir(pwd) + // Make a backup of the bin/main.wasm as it will get modified by the // post_build script and that will cause it to fail validation. + // + // TODO: Check if this backup is still needed? + // We had this back when the test environment was setup once. + // But we've moved to having the test environment created for each test case. + // So we might not need to restore mainwasmBinPath as it's created afresh. mainWasmBackup, err := os.ReadFile(mainwasmBinPath) if err != nil { t.Fatal(err) @@ -889,7 +994,7 @@ func TestBuildOther(t *testing.T) { AssetVersion: "1.2.3", BinaryFilename: wasmtoolsBinName, DownloadOK: true, - DownloadedFile: wasmtoolsBinPath, + DownloadedFile: latestDownloaded, InstallFilePath: wasmtoolsBinPath, // avoid overwriting developer's actual wasm-tools install }, } diff --git a/pkg/global/global.go b/pkg/global/global.go index 94a463f1e..35afd303b 100644 --- a/pkg/global/global.go +++ b/pkg/global/global.go @@ -33,6 +33,8 @@ type Data struct { Config config.File // ConfigPath is the path to the CLI's application configuration. ConfigPath string + // ExecuteWasmTools is a function that executes the wasm-tools binary. + ExecuteWasmTools func(bin string, args []string) error // Flags are all the global CLI flags. Flags Flags // Manifest is the fastly.toml manifest file. diff --git a/pkg/testutil/args.go b/pkg/testutil/args.go index a40bd1837..15e4af1bc 100644 --- a/pkg/testutil/args.go +++ b/pkg/testutil/args.go @@ -69,12 +69,15 @@ func NewRunOpts(args []string, stdout io.Writer) app.RunOpts { } return app.RunOpts{ - ConfigPath: configPath, - Args: args, APIClient: mock.APIClient(mock.API{}), + Args: args, + ConfigFile: config.File{}, + ConfigPath: configPath, Env: config.Environment{}, ErrLog: errors.Log, - ConfigFile: config.File{}, + ExecuteWasmTools: func(bin string, args []string) error { + return nil + }, HTTPClient: &http.Client{Timeout: time.Second * 5}, Manifest: &md, Stdout: stdout, From d9cc287c0522d1781cc5b85071e10f10ec70fd08 Mon Sep 17 00:00:00 2001 From: Integralist Date: Thu, 28 Sep 2023 09:11:03 +0100 Subject: [PATCH 37/60] refactor: annotate public methods --- pkg/commands/compute/build.go | 21 +++++++++++---------- pkg/github/github.go | 1 + 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/pkg/commands/compute/build.go b/pkg/commands/compute/build.go index ec26f5915..0287311bd 100644 --- a/pkg/commands/compute/build.go +++ b/pkg/commands/compute/build.go @@ -223,23 +223,23 @@ func (c *BuildCommand) Exec(in io.Reader, out io.Writer) (err error) { fmt.Sprintf("--processed-by=CLI_MachineInfoCPUs=%d", runtime.NumCPU()), } - if c.Manifest.File.ClonedFrom != "" { - args = append(args, fmt.Sprintf("--processed-by=CLI_PackageInfoClonedFrom=%s", c.Manifest.File.ClonedFrom)) + if c.Globals.Manifest.File.ClonedFrom != "" { + args = append(args, fmt.Sprintf("--processed-by=CLI_PackageInfoClonedFrom=%s", c.Globals.Manifest.File.ClonedFrom)) } args = append(args, fmt.Sprintf("--processed-by=CLI_ScriptsDefaultBuildUsed=%t", language.DefaultBuildScript())) - if c.Manifest.File.Scripts.Build != "" { - args = append(args, fmt.Sprintf("--processed-by=CLI_ScriptsBuild=%s", c.Manifest.File.Scripts.Build)) + if c.Globals.Manifest.File.Scripts.Build != "" { + args = append(args, fmt.Sprintf("--processed-by=CLI_ScriptsBuild=%s", c.Globals.Manifest.File.Scripts.Build)) } - if len(c.Manifest.File.Scripts.EnvVars) > 0 { - args = append(args, fmt.Sprintf("--processed-by=CLI_ScriptsEnvVars=%s", c.Manifest.File.Scripts.EnvVars)) + if len(c.Globals.Manifest.File.Scripts.EnvVars) > 0 { + args = append(args, fmt.Sprintf("--processed-by=CLI_ScriptsEnvVars=%s", c.Globals.Manifest.File.Scripts.EnvVars)) } - if c.Manifest.File.Scripts.PostInit != "" { - args = append(args, fmt.Sprintf("--processed-by=CLI_ScriptsPostInit=%s", c.Manifest.File.Scripts.PostInit)) + if c.Globals.Manifest.File.Scripts.PostInit != "" { + args = append(args, fmt.Sprintf("--processed-by=CLI_ScriptsPostInit=%s", c.Globals.Manifest.File.Scripts.PostInit)) } - if c.Manifest.File.Scripts.PostBuild != "" { - args = append(args, fmt.Sprintf("--processed-by=CLI_ScriptsPostBuild=%s", c.Manifest.File.Scripts.PostBuild)) + if c.Globals.Manifest.File.Scripts.PostBuild != "" { + args = append(args, fmt.Sprintf("--processed-by=CLI_ScriptsPostBuild=%s", c.Globals.Manifest.File.Scripts.PostBuild)) } for k, v := range language.Dependencies() { @@ -421,6 +421,7 @@ func (c *BuildCommand) PackageName(manifestFilename string) (string, error) { return sanitize.BaseName(name), nil } +// ExecuteWasmTools calls the wasm-tools binary. func ExecuteWasmTools(wasmtools string, args []string) error { // gosec flagged this: // G204 (CWE-78): Subprocess launched with function call as argument or command arguments diff --git a/pkg/github/github.go b/pkg/github/github.go index d12f793b8..a525a2d6d 100644 --- a/pkg/github/github.go +++ b/pkg/github/github.go @@ -261,6 +261,7 @@ func (g *Asset) metadata() (m DevHubMetadata, err error) { return m, nil } +// InstallPath returns the location of where the asset should be installed. func (g *Asset) InstallPath() string { return filepath.Join(InstallDir, g.BinaryName()) } From f38ecc9f405a058cd48b106e37a45842cf02d5c2 Mon Sep 17 00:00:00 2001 From: Integralist Date: Mon, 2 Oct 2023 11:01:58 +0100 Subject: [PATCH 38/60] refactor(compute/build): use gomod parser --- go.mod | 1 + go.sum | 2 + pkg/commands/compute/language_go.go | 62 ++++++----------------------- 3 files changed, 16 insertions(+), 49 deletions(-) diff --git a/go.mod b/go.mod index f878038f0..e01b13048 100644 --- a/go.mod +++ b/go.mod @@ -36,6 +36,7 @@ require ( github.com/theckman/yacspin v0.13.12 golang.org/x/crypto v0.14.0 golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 + golang.org/x/mod v0.12.0 ) require ( diff --git a/go.sum b/go.sum index aaa138ea6..1d73d649f 100644 --- a/go.sum +++ b/go.sum @@ -130,6 +130,8 @@ golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 h1:k/i9J1pBpvlfR+9QsetwPyERsqu1GIbi967PQMq3Ivc= golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w= +golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc= +golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= diff --git a/pkg/commands/compute/language_go.go b/pkg/commands/compute/language_go.go index d78bd4958..27b202540 100644 --- a/pkg/commands/compute/language_go.go +++ b/pkg/commands/compute/language_go.go @@ -10,6 +10,7 @@ import ( "strings" "github.com/Masterminds/semver/v3" + "golang.org/x/mod/modfile" "github.com/fastly/cli/pkg/config" fsterr "github.com/fastly/cli/pkg/errors" @@ -109,57 +110,20 @@ func (g *Go) DefaultBuildScript() bool { // Dependencies returns all dependencies used by the project. func (g *Go) Dependencies() map[string]string { deps := make(map[string]string) - - if f, err := os.Open("go.mod"); err == nil { - defer f.Close() - var insideRequireBlock bool - - scanner := bufio.NewScanner(f) - for scanner.Scan() { - line := scanner.Text() - parts := strings.Fields(line) - - // go.mod has two separate `require` definitions: - // - // 1. - // require github.com/fastly/compute-sdk-go v1.0.0 - // - // 2. - // require ( - // github.com/fastly/compute-sdk-go v1.0.0 - // golang.org/x/mod v0.4.2 // indirect - // ) - // - // We avoid including 'indirect' dependencies by ignoring lines with a - // length greater than three segments. - - if len(parts) >= 2 && parts[0] == "require" && parts[1] == "(" { - insideRequireBlock = true - continue - } - if len(parts) == 1 && parts[0] == ")" { - insideRequireBlock = false - continue - } - if len(parts) >= 2 && !insideRequireBlock && parts[0] != "require" { - continue - } - - var pkg, version string - switch len(parts) { - case 2: - pkg = parts[0] - version = parts[1] - case 3: - pkg = parts[1] - version = parts[2] - } - if pkg != "" && version != "" { - deps[pkg] = version - } + data, err := os.ReadFile("go.mod") + if err != nil { + return deps + } + f, err := modfile.ParseLax("go.mod", data, nil) + if err != nil { + return deps + } + for _, req := range f.Require { + if req.Indirect { + continue } + deps[req.Mod.Path] = req.Mod.Version } - return deps } From b71aae020348e6394e70dd8cc18e67ae2a588efb Mon Sep 17 00:00:00 2001 From: Integralist Date: Mon, 2 Oct 2023 11:22:15 +0100 Subject: [PATCH 39/60] refactor(compute/build): use processed-by flag for CLI version --- go.mod | 1 + go.sum | 2 ++ pkg/commands/compute/build.go | 8 ++++++-- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/go.mod b/go.mod index e01b13048..a250658a3 100644 --- a/go.mod +++ b/go.mod @@ -60,5 +60,6 @@ require ( github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 // indirect golang.org/x/net v0.17.0 // indirect golang.org/x/sync v0.3.0 // indirect + golang.org/x/text v0.13.0 gopkg.in/yaml.v2 v2.4.0 // indirect ) diff --git a/go.sum b/go.sum index 1d73d649f..4424b1038 100644 --- a/go.sum +++ b/go.sum @@ -141,6 +141,8 @@ golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek= golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= +golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= +golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 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= diff --git a/pkg/commands/compute/build.go b/pkg/commands/compute/build.go index 0287311bd..2bc54eb4a 100644 --- a/pkg/commands/compute/build.go +++ b/pkg/commands/compute/build.go @@ -15,6 +15,8 @@ import ( "github.com/kennygrant/sanitize" "github.com/mholt/archiver/v3" + "golang.org/x/text/cases" + textlang "golang.org/x/text/language" "github.com/fastly/cli/pkg/check" "github.com/fastly/cli/pkg/cmd" @@ -205,6 +207,8 @@ func (c *BuildCommand) Exec(in io.Reader, out io.Writer) (err error) { return err } + languageTitle := cases.Title(textlang.English).String(language.Name) + // FIXME: When we remove feature flag, put in ability to disable metadata. if c.enableMetadata /*|| !disableWasmMetadata*/ { endTime := time.Now() @@ -213,7 +217,7 @@ func (c *BuildCommand) Exec(in io.Reader, out io.Writer) (err error) { // FIXME: Once #1013 and #1016 merged, integrate granular disabling. args := []string{ "metadata", "add", "bin/main.wasm", - fmt.Sprintf("--language=CLI_%s: %s", revision.AppVersion, strings.ToUpper(language.Name)), + fmt.Sprintf("--processed-by=fastly=%s (%s)", revision.AppVersion, languageTitle), fmt.Sprintf("--processed-by=CLI_BuildInfoMemoryHeapAlloc=%d", memAfter.HeapAlloc-memBefore.HeapAlloc), fmt.Sprintf("--processed-by=CLI_BuildInfoTime=%s", endTime.Sub(startTime)), fmt.Sprintf("--processed-by=CLI_MachineInfoOS=%s", runtime.GOOS), @@ -272,7 +276,7 @@ func (c *BuildCommand) Exec(in io.Reader, out io.Writer) (err error) { // NOTE: If not collecting metadata, just record the CLI version. args := []string{ "metadata", "add", "bin/main.wasm", - fmt.Sprintf("--language=CLI_%s: %s", revision.AppVersion, strings.ToUpper(language.Name)), + fmt.Sprintf("--processed-by=fastly=%s (%s)", revision.AppVersion, languageTitle), } err = c.Globals.ExecuteWasmTools(wasmtools, args) if err != nil { From 4dc42e17eab8c68408c06802cc62cfa0dd51a713 Mon Sep 17 00:00:00 2001 From: Integralist Date: Mon, 2 Oct 2023 11:46:47 +0100 Subject: [PATCH 40/60] refactor(compute/build): replace individual flags with single json data --- pkg/commands/compute/build.go | 94 +++++++++++++++++++++++++---------- 1 file changed, 68 insertions(+), 26 deletions(-) diff --git a/pkg/commands/compute/build.go b/pkg/commands/compute/build.go index 2bc54eb4a..d01c2776d 100644 --- a/pkg/commands/compute/build.go +++ b/pkg/commands/compute/build.go @@ -3,6 +3,7 @@ package compute import ( "bufio" "crypto/rand" + "encoding/json" "errors" "fmt" "io" @@ -214,36 +215,40 @@ func (c *BuildCommand) Exec(in io.Reader, out io.Writer) (err error) { endTime := time.Now() runtime.ReadMemStats(&memAfter) + dc := DataCollection{ + BuildInfo: DataCollectionBuildInfo{ + MemoryHeapAlloc: memAfter.HeapAlloc - memBefore.HeapAlloc, + Time: endTime.Sub(startTime), + }, + MachineInfo: DataCollectionMachineInfo{ + Arch: runtime.GOARCH, + CPUs: runtime.Version(), + Compiler: runtime.Compiler, + GoVersion: runtime.Version(), + OS: runtime.GOOS, + }, + PackageInfo: DataCollectionPackageInfo{ + ClonedFrom: c.Globals.Manifest.File.ClonedFrom, + }, + ScriptInfo: DataCollectionScriptInfo{ + DefaultBuildUsed: language.DefaultBuildScript(), + BuildScript: c.Globals.Manifest.File.Scripts.Build, + EnvVars: c.Globals.Manifest.File.Scripts.EnvVars, + PostInitScript: c.Globals.Manifest.File.Scripts.PostInit, + PostBuildScript: c.Globals.Manifest.File.Scripts.PostBuild, + }, + } + + data, err := json.Marshal(dc) + if err != nil { + return err + } + // FIXME: Once #1013 and #1016 merged, integrate granular disabling. args := []string{ "metadata", "add", "bin/main.wasm", fmt.Sprintf("--processed-by=fastly=%s (%s)", revision.AppVersion, languageTitle), - fmt.Sprintf("--processed-by=CLI_BuildInfoMemoryHeapAlloc=%d", memAfter.HeapAlloc-memBefore.HeapAlloc), - fmt.Sprintf("--processed-by=CLI_BuildInfoTime=%s", endTime.Sub(startTime)), - fmt.Sprintf("--processed-by=CLI_MachineInfoOS=%s", runtime.GOOS), - fmt.Sprintf("--processed-by=CLI_MachineInfoArch=%s", runtime.GOARCH), - fmt.Sprintf("--processed-by=CLI_MachineInfoCompiler=%s", runtime.Compiler), - fmt.Sprintf("--processed-by=CLI_MachineInfoGoVersion=%s", runtime.Version()), - fmt.Sprintf("--processed-by=CLI_MachineInfoCPUs=%d", runtime.NumCPU()), - } - - if c.Globals.Manifest.File.ClonedFrom != "" { - args = append(args, fmt.Sprintf("--processed-by=CLI_PackageInfoClonedFrom=%s", c.Globals.Manifest.File.ClonedFrom)) - } - - args = append(args, fmt.Sprintf("--processed-by=CLI_ScriptsDefaultBuildUsed=%t", language.DefaultBuildScript())) - - if c.Globals.Manifest.File.Scripts.Build != "" { - args = append(args, fmt.Sprintf("--processed-by=CLI_ScriptsBuild=%s", c.Globals.Manifest.File.Scripts.Build)) - } - if len(c.Globals.Manifest.File.Scripts.EnvVars) > 0 { - args = append(args, fmt.Sprintf("--processed-by=CLI_ScriptsEnvVars=%s", c.Globals.Manifest.File.Scripts.EnvVars)) - } - if c.Globals.Manifest.File.Scripts.PostInit != "" { - args = append(args, fmt.Sprintf("--processed-by=CLI_ScriptsPostInit=%s", c.Globals.Manifest.File.Scripts.PostInit)) - } - if c.Globals.Manifest.File.Scripts.PostBuild != "" { - args = append(args, fmt.Sprintf("--processed-by=CLI_ScriptsPostBuild=%s", c.Globals.Manifest.File.Scripts.PostBuild)) + fmt.Sprintf("--processed-by=fastly_data=%s", data), } for k, v := range language.Dependencies() { @@ -873,3 +878,40 @@ func GetNonIgnoredFiles(base string, ignoredFiles map[string]bool) ([]string, er return files, err } + +// DataCollection represents data annotated onto the Wasm binary. +type DataCollection struct { + BuildInfo DataCollectionBuildInfo `json:"build_info"` + MachineInfo DataCollectionMachineInfo `json:"machine_info"` + PackageInfo DataCollectionPackageInfo `json:"package_info"` + ScriptInfo DataCollectionScriptInfo `json:"script_info"` +} + +// DataCollectionBuildInfo represents build data annotated onto the Wasm binary. +type DataCollectionBuildInfo struct { + MemoryHeapAlloc uint64 `json:"mem_heap_alloc"` + Time time.Duration `json:"time"` +} + +// DataCollectionMachineInfo represents machine data annotated onto the Wasm binary. +type DataCollectionMachineInfo struct { + Arch string `json:"arch"` + CPUs string `json:"cpus"` + Compiler string `json:"compiler"` + GoVersion string `json:"go_version"` + OS string `json:"os"` +} + +// DataCollectionPackageInfo represents package data annotated onto the Wasm binary. +type DataCollectionPackageInfo struct { + ClonedFrom string `json:"cloned_from"` +} + +// DataCollectionScriptInfo represents script data annotated onto the Wasm binary. +type DataCollectionScriptInfo struct { + DefaultBuildUsed bool `json:"default_build_used"` + BuildScript string `json:"build_script"` + EnvVars []string `json:"env_vars"` + PostInitScript string `json:"post_init_script"` + PostBuildScript string `json:"post_build_script"` +} From a3548302110ed233c9e41618abe2046020496a99 Mon Sep 17 00:00:00 2001 From: Integralist Date: Tue, 3 Oct 2023 10:03:38 +0100 Subject: [PATCH 41/60] fix(compute/build): record only current memory allocation --- pkg/commands/compute/build.go | 20 ++++---------------- 1 file changed, 4 insertions(+), 16 deletions(-) diff --git a/pkg/commands/compute/build.go b/pkg/commands/compute/build.go index d01c2776d..b256235ba 100644 --- a/pkg/commands/compute/build.go +++ b/pkg/commands/compute/build.go @@ -191,16 +191,6 @@ func (c *BuildCommand) Exec(in io.Reader, out io.Writer) (err error) { return err } - var ( - memBefore, memAfter runtime.MemStats - startTime time.Time - ) - // FIXME: When we remove feature flag, put in ability to disable metadata. - if c.enableMetadata /*|| !disableWasmMetadata*/ { - runtime.ReadMemStats(&memBefore) - startTime = time.Now() - } - if err := language.Build(); err != nil { c.Globals.ErrLog.AddWithContext(err, map[string]any{ "Language": language.Name, @@ -212,13 +202,12 @@ func (c *BuildCommand) Exec(in io.Reader, out io.Writer) (err error) { // FIXME: When we remove feature flag, put in ability to disable metadata. if c.enableMetadata /*|| !disableWasmMetadata*/ { - endTime := time.Now() - runtime.ReadMemStats(&memAfter) + var ms runtime.MemStats + runtime.ReadMemStats(&ms) dc := DataCollection{ BuildInfo: DataCollectionBuildInfo{ - MemoryHeapAlloc: memAfter.HeapAlloc - memBefore.HeapAlloc, - Time: endTime.Sub(startTime), + MemoryHeapAlloc: ms.HeapAlloc, }, MachineInfo: DataCollectionMachineInfo{ Arch: runtime.GOARCH, @@ -889,8 +878,7 @@ type DataCollection struct { // DataCollectionBuildInfo represents build data annotated onto the Wasm binary. type DataCollectionBuildInfo struct { - MemoryHeapAlloc uint64 `json:"mem_heap_alloc"` - Time time.Duration `json:"time"` + MemoryHeapAlloc uint64 `json:"mem_heap_alloc"` } // DataCollectionMachineInfo represents machine data annotated onto the Wasm binary. From 7b1d17532c1fd444986640fa9ff8df80cd42e9c2 Mon Sep 17 00:00:00 2001 From: Integralist Date: Tue, 3 Oct 2023 10:07:16 +0100 Subject: [PATCH 42/60] fix(compute/build): invert conditional and move show-metadata --- pkg/commands/compute/build.go | 52 +++++++++++++++++------------------ 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/pkg/commands/compute/build.go b/pkg/commands/compute/build.go index b256235ba..c16d21490 100644 --- a/pkg/commands/compute/build.go +++ b/pkg/commands/compute/build.go @@ -201,7 +201,17 @@ func (c *BuildCommand) Exec(in io.Reader, out io.Writer) (err error) { languageTitle := cases.Title(textlang.English).String(language.Name) // FIXME: When we remove feature flag, put in ability to disable metadata. - if c.enableMetadata /*|| !disableWasmMetadata*/ { + if !c.enableMetadata /*|| disableWasmMetadata*/ { + // NOTE: If not collecting metadata, just record the CLI version. + args := []string{ + "metadata", "add", "bin/main.wasm", + fmt.Sprintf("--processed-by=fastly=%s (%s)", revision.AppVersion, languageTitle), + } + err = c.Globals.ExecuteWasmTools(wasmtools, args) + if err != nil { + return err + } + } else { var ms runtime.MemStats runtime.ReadMemStats(&ms) @@ -248,34 +258,24 @@ func (c *BuildCommand) Exec(in io.Reader, out io.Writer) (err error) { if err != nil { return err } + } - if c.showMetadata { - // gosec flagged this: - // G204 (CWE-78): Subprocess launched with variable - // Disabling as the variables come from trusted sources. - // #nosec - // nosemgrep - command := exec.Command(wasmtools, "metadata", "show", "bin/main.wasm") - wasmtoolsOutput, err := command.Output() - if err != nil { - return fmt.Errorf("failed to execute wasm-tools metadata command: %w", err) - } - text.Info(out, "Below is the metadata attached to the Wasm binary") - text.Break(out) - - fmt.Fprintln(out, string(wasmtoolsOutput)) - text.Break(out) - } - } else { - // NOTE: If not collecting metadata, just record the CLI version. - args := []string{ - "metadata", "add", "bin/main.wasm", - fmt.Sprintf("--processed-by=fastly=%s (%s)", revision.AppVersion, languageTitle), - } - err = c.Globals.ExecuteWasmTools(wasmtools, args) + if c.showMetadata { + // gosec flagged this: + // G204 (CWE-78): Subprocess launched with variable + // Disabling as the variables come from trusted sources. + // #nosec + // nosemgrep + command := exec.Command(wasmtools, "metadata", "show", "bin/main.wasm") + wasmtoolsOutput, err := command.Output() if err != nil { - return err + return fmt.Errorf("failed to execute wasm-tools metadata command: %w", err) } + text.Info(out, "Below is the metadata attached to the Wasm binary") + text.Break(out) + + fmt.Fprintln(out, string(wasmtoolsOutput)) + text.Break(out) } dest := filepath.Join("pkg", fmt.Sprintf("%s.tar.gz", pkgName)) From 4bfedd58805a02924e789a0c5ec8c8731272bd50 Mon Sep 17 00:00:00 2001 From: Integralist Date: Tue, 3 Oct 2023 10:10:44 +0100 Subject: [PATCH 43/60] fix(compute/build): don't hide show-metadata flag This is because we now always annotate the Wasm binary. If the user enables metadata then we annotate lots of data, otherwise we'll default to annotating the binary with the CLI version and the project language. --- pkg/commands/compute/build.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/commands/compute/build.go b/pkg/commands/compute/build.go index c16d21490..ae849962c 100644 --- a/pkg/commands/compute/build.go +++ b/pkg/commands/compute/build.go @@ -81,11 +81,11 @@ func NewBuildCommand(parent cmd.Registerer, g *global.Data, wasmtoolsVersioner g c.CmdClause.Flag("include-source", "Include source code in built package").BoolVar(&c.Flags.IncludeSrc) c.CmdClause.Flag("language", "Language type").StringVar(&c.Flags.Lang) c.CmdClause.Flag("package-name", "Package name").StringVar(&c.Flags.PackageName) + c.CmdClause.Flag("show-metadata", "Use wasm-tools to inspect the Wasm binary metadata").BoolVar(&c.showMetadata) c.CmdClause.Flag("timeout", "Timeout, in seconds, for the build compilation step").IntVar(&c.Flags.Timeout) // Hidden c.CmdClause.Flag("enable-metadata", "Feature flag to trial the Wasm binary metadata annotations").Hidden().BoolVar(&c.enableMetadata) - c.CmdClause.Flag("show-metadata", "Use wasm-tools to inspect metadata (requires --enable-metadata)").Hidden().BoolVar(&c.showMetadata) return &c } From d4d213370230f1ed4c8614ed10da3523cea96a91 Mon Sep 17 00:00:00 2001 From: Integralist Date: Fri, 6 Oct 2023 15:57:42 +0100 Subject: [PATCH 44/60] feat(compute/build): display IMPORTANT message related to wasm-tools --- pkg/commands/compute/build.go | 8 ++++++-- pkg/text/text_test.go | 7 +++++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/pkg/commands/compute/build.go b/pkg/commands/compute/build.go index ae849962c..beac1a26e 100644 --- a/pkg/commands/compute/build.go +++ b/pkg/commands/compute/build.go @@ -355,6 +355,11 @@ func (c *BuildCommand) Exec(in io.Reader, out io.Writer) (err error) { out = originalOut text.Success(out, "\nBuilt package (%s)", dest) + + // FIXME: Remove this notice in the CLI version 10.6.0 + if !c.Globals.Flags.Quiet { + text.Important(out, "\nIn the next release (10.6.0), the Fastly CLI will collect data related to Wasm builds. If you have questions, comments or feedback, join the discussion at https://bit.ly/wasm-metadata") + } return nil } @@ -569,8 +574,7 @@ func updateWasmtools( stale := wasmtoolsConfig.LastChecked != "" && wasmtoolsConfig.LatestVersion != "" && check.Stale(wasmtoolsConfig.LastChecked, wasmtoolsConfig.TTL) if !stale { if verbose { - text.Info(out, "wasm-tools is installed but the CLI config (`fastly config`) shows the TTL, checking for a newer version, hasn't expired.") - text.Break(out) + text.Info(out, "\nwasm-tools is installed but the CLI config (`fastly config`) shows the TTL, checking for a newer version, hasn't expired.\n\n") } return nil } diff --git a/pkg/text/text_test.go b/pkg/text/text_test.go index 671336fba..bcb073bbb 100644 --- a/pkg/text/text_test.go +++ b/pkg/text/text_test.go @@ -144,6 +144,13 @@ func TestPrefixes(t *testing.T) { args: []any{123}, want: "ERROR: Test string 123.\n", }, + { + name: "Important", + f: text.Important, + format: "Test string %d.", + args: []any{123}, + want: "IMPORTANT: Test string 123.\n", + }, { name: "Info", f: text.Info, From 1c21f6e0842e88ff653289a55e5fd1e143dc2d08 Mon Sep 17 00:00:00 2001 From: Integralist Date: Mon, 9 Oct 2023 12:43:11 +0100 Subject: [PATCH 45/60] feat(compute/build): filter specified env vars --- pkg/commands/compute/build.go | 39 +++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/pkg/commands/compute/build.go b/pkg/commands/compute/build.go index beac1a26e..95a5594b4 100644 --- a/pkg/commands/compute/build.go +++ b/pkg/commands/compute/build.go @@ -58,6 +58,7 @@ type Flags struct { type BuildCommand struct { cmd.Base enableMetadata bool + filterEnvVars string showMetadata bool wasmtoolsVersioner github.AssetVersioner @@ -86,6 +87,7 @@ func NewBuildCommand(parent cmd.Registerer, g *global.Data, wasmtoolsVersioner g // Hidden c.CmdClause.Flag("enable-metadata", "Feature flag to trial the Wasm binary metadata annotations").Hidden().BoolVar(&c.enableMetadata) + c.CmdClause.Flag("filter-metadata-envvars", "Redact specified environment variables from [scripts.env_vars] using comma-separated list").Hidden().StringVar(&c.filterEnvVars) return &c } @@ -238,6 +240,43 @@ func (c *BuildCommand) Exec(in io.Reader, out io.Writer) (err error) { }, } + filters := []string{ + "GITHUB_TOKEN", + "AWS_SECRET_ACCESS_KEY", + "AWS_SESSION_TOKEN", + "DOCKER_PASSWORD", + "VAULT_TOKEN", + } + + customFilters := strings.Split(c.filterEnvVars, ",") + for _, v := range customFilters { + if v == "" { + continue + } + var found bool + for _, f := range filters { + if f == v { + found = true + break + } + } + if !found { + filters = append(filters, v) + } + } + + for i, v := range dc.ScriptInfo.EnvVars { + for _, f := range filters { + k := strings.Split(v, "=")[0] + if strings.HasPrefix(k, f) { + dc.ScriptInfo.EnvVars[i] = k + "=REDACTED" + if c.Globals.Verbose() { + text.Important(out, "The fastly.toml [scripts.env_vars] contains a possible security key '%s' so we've redacted it from the Wasm binary metadata annotation", k) + } + } + } + } + data, err := json.Marshal(dc) if err != nil { return err From 52f543db1173a2e1a04f9d8ee47024c0e2d36615 Mon Sep 17 00:00:00 2001 From: Integralist Date: Mon, 9 Oct 2023 13:59:35 +0100 Subject: [PATCH 46/60] fix(compute/build): add new flag to test suite --- pkg/commands/compute/compute_test.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pkg/commands/compute/compute_test.go b/pkg/commands/compute/compute_test.go index cac220744..9705b6b62 100644 --- a/pkg/commands/compute/compute_test.go +++ b/pkg/commands/compute/compute_test.go @@ -39,6 +39,7 @@ func TestPublishFlagDivergence(t *testing.T) { // Some flags on `compute build` are unique to it. ignoreBuildFlags := []string{ "enable-metadata", + "filter-metadata-envvars", "show-metadata", } @@ -92,6 +93,7 @@ func TestServeFlagDivergence(t *testing.T) { // Some flags on `compute build` are unique to it. ignoreBuildFlags := []string{ "enable-metadata", + "filter-metadata-envvars", "show-metadata", } From 1698c51455414600e71b75a78b8677902874167c Mon Sep 17 00:00:00 2001 From: Integralist Date: Tue, 10 Oct 2023 16:44:48 +0100 Subject: [PATCH 47/60] fix(compute/build): fix formatting line breaks + use correct CPU value --- pkg/commands/compute/build.go | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/pkg/commands/compute/build.go b/pkg/commands/compute/build.go index 95a5594b4..570c1e6f9 100644 --- a/pkg/commands/compute/build.go +++ b/pkg/commands/compute/build.go @@ -223,7 +223,7 @@ func (c *BuildCommand) Exec(in io.Reader, out io.Writer) (err error) { }, MachineInfo: DataCollectionMachineInfo{ Arch: runtime.GOARCH, - CPUs: runtime.Version(), + CPUs: runtime.NumCPU(), Compiler: runtime.Compiler, GoVersion: runtime.Version(), OS: runtime.GOOS, @@ -271,7 +271,7 @@ func (c *BuildCommand) Exec(in io.Reader, out io.Writer) (err error) { if strings.HasPrefix(k, f) { dc.ScriptInfo.EnvVars[i] = k + "=REDACTED" if c.Globals.Verbose() { - text.Important(out, "The fastly.toml [scripts.env_vars] contains a possible security key '%s' so we've redacted it from the Wasm binary metadata annotation", k) + text.Important(out, "The fastly.toml [scripts.env_vars] contains a possible security key '%s' so we've redacted it from the Wasm binary metadata annotation\n\n", k) } } } @@ -525,8 +525,7 @@ func GetWasmTools(spinner text.Spinner, out io.Writer, wasmtoolsVersioner github if installedVersion == "" { if g.Verbose() { - text.Info(out, "wasm-tools is not already installed, so we will install the latest version.") - text.Break(out) + text.Info(out, "\nwasm-tools is not already installed, so we will install the latest version.\n\n") } err = installLatestWasmtools(binPath, spinner, wasmtoolsVersioner) if err != nil { @@ -658,8 +657,7 @@ func updateWasmtools( } if verbose { - text.Info(out, "The CLI config (`fastly config`) has been updated with the latest wasm-tools version: %s", latestVersion) - text.Break(out) + text.Info(out, "\nThe CLI config (`fastly config`) has been updated with the latest wasm-tools version: %s\n\n", latestVersion) } if installedVersion == latestVersion { @@ -927,7 +925,7 @@ type DataCollectionBuildInfo struct { // DataCollectionMachineInfo represents machine data annotated onto the Wasm binary. type DataCollectionMachineInfo struct { Arch string `json:"arch"` - CPUs string `json:"cpus"` + CPUs int `json:"cpus"` Compiler string `json:"compiler"` GoVersion string `json:"go_version"` OS string `json:"os"` From 23a4be19a274f0fb288ed2a1728a50db967ad8b3 Mon Sep 17 00:00:00 2001 From: Integralist Date: Tue, 10 Oct 2023 16:45:03 +0100 Subject: [PATCH 48/60] temp --- go.mod | 199 +++++++- go.sum | 857 +++++++++++++++++++++++++++++++++- pkg/commands/compute/build.go | 42 ++ 3 files changed, 1073 insertions(+), 25 deletions(-) diff --git a/go.mod b/go.mod index a250658a3..941533e93 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.21 require ( github.com/Masterminds/semver/v3 v3.2.1 - github.com/alecthomas/units v0.0.0-20210208195552-ff826a37aa15 // indirect + github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 // indirect github.com/bep/debounce v1.2.1 github.com/blang/semver v3.5.1+incompatible github.com/dustinkirkland/golang-petname v0.0.0-20191129215211-8e5a1ed0cff0 @@ -13,7 +13,7 @@ require ( github.com/frankban/quicktest v1.13.1 // indirect github.com/fsnotify/fsnotify v1.7.0 github.com/google/go-cmp v0.6.0 - github.com/mattn/go-isatty v0.0.17 // indirect + github.com/mattn/go-isatty v0.0.19 // indirect github.com/mholt/archiver/v3 v3.5.1 github.com/mitchellh/go-wordwrap v1.0.1 github.com/mitchellh/mapstructure v1.5.0 @@ -24,7 +24,6 @@ require ( github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80 golang.org/x/sys v0.13.0 // indirect golang.org/x/term v0.13.0 - gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect ) require ( @@ -34,11 +33,195 @@ require ( github.com/otiai10/copy v1.14.0 github.com/sabhiram/go-gitignore v0.0.0-20210923224102-525f6e181f06 github.com/theckman/yacspin v0.13.12 + github.com/trufflesecurity/trufflehog/v3 v3.59.0 golang.org/x/crypto v0.14.0 golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 golang.org/x/mod v0.12.0 ) +require ( + cloud.google.com/go v0.110.4 // indirect + cloud.google.com/go/compute v1.20.1 // indirect + cloud.google.com/go/compute/metadata v0.2.3 // indirect + cloud.google.com/go/iam v1.1.0 // indirect + cloud.google.com/go/secretmanager v1.11.1 // indirect + cloud.google.com/go/storage v1.33.0 // indirect + dario.cat/mergo v1.0.0 // indirect + github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 // indirect + github.com/99designs/keyring v1.2.2 // indirect + github.com/Azure/azure-sdk-for-go/sdk/azcore v1.4.0 // indirect + github.com/Azure/azure-sdk-for-go/sdk/internal v1.1.2 // indirect + github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.0.0 // indirect + github.com/Azure/go-autorest v14.2.0+incompatible // indirect + github.com/Azure/go-autorest/autorest v0.11.24 // indirect + github.com/Azure/go-autorest/autorest/adal v0.9.18 // indirect + github.com/Azure/go-autorest/autorest/azure/auth v0.5.11 // indirect + github.com/Azure/go-autorest/autorest/azure/cli v0.4.5 // indirect + 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/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 // indirect + github.com/AzureAD/microsoft-authentication-library-for-go v1.2.0 // indirect + github.com/BobuSumisu/aho-corasick v1.0.3 // indirect + github.com/JohnCGriffin/overflow v0.0.0-20211019200055-46fa312c352c // indirect + github.com/Microsoft/go-winio v0.6.1 // indirect + github.com/ProtonMail/go-crypto v0.0.0-20230717121422-5aa5874ade95 // indirect + github.com/TheZeroSlave/zapsentry v1.17.0 // indirect + github.com/acomagu/bufpipe v1.0.4 // indirect + github.com/apache/arrow/go/v12 v12.0.1 // indirect + github.com/apache/thrift v0.16.0 // indirect + github.com/aws/aws-sdk-go v1.45.19 // indirect + github.com/aws/aws-sdk-go-v2 v1.17.7 // indirect + github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.10 // indirect + github.com/aws/aws-sdk-go-v2/credentials v1.13.18 // indirect + github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.59 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.31 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.25 // indirect + github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.23 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.11 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.26 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.25 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.14.0 // indirect + github.com/aws/aws-sdk-go-v2/service/s3 v1.31.0 // indirect + github.com/aws/smithy-go v1.13.5 // indirect + github.com/beorn7/perks v1.0.1 // indirect + github.com/bill-rich/disk-buffer-reader v0.1.7 // indirect + github.com/bill-rich/go-syslog v0.0.0-20220413021637-49edb52a574c // indirect + github.com/bitfinexcom/bitfinex-api-go v0.0.0-20210608095005-9e0b26f200fb // indirect + github.com/bodgit/plumbing v1.2.0 // indirect + github.com/bodgit/sevenzip v1.3.0 // indirect + github.com/bodgit/windows v1.0.0 // indirect + github.com/bradleyfalzon/ghinstallation/v2 v2.7.0 // indirect + github.com/cespare/xxhash/v2 v2.2.0 // indirect + github.com/cloudflare/circl v1.3.3 // indirect + github.com/connesc/cipherio v0.2.1 // indirect + github.com/containerd/stargz-snapshotter/estargz v0.14.3 // indirect + github.com/couchbase/gocb/v2 v2.6.3 // indirect + github.com/couchbase/gocbcore/v10 v10.2.4 // indirect + github.com/crewjam/rfc5424 v0.1.0 // indirect + github.com/danieljoos/wincred v1.1.2 // indirect + github.com/denisenkom/go-mssqldb v0.12.3 // indirect + github.com/dimchansky/utfbom v1.1.1 // indirect + github.com/docker/cli v23.0.5+incompatible // indirect + github.com/docker/distribution v2.8.2+incompatible // indirect + github.com/docker/docker v23.0.5+incompatible // indirect + github.com/docker/docker-credential-helpers v0.7.0 // indirect + github.com/dvsekhvalnov/jose2go v1.5.0 // indirect + github.com/emirpasic/gods v1.18.1 // indirect + github.com/envoyproxy/protoc-gen-validate v1.0.2 // indirect + github.com/form3tech-oss/jwt-go v3.2.5+incompatible // indirect + github.com/gabriel-vasile/mimetype v1.4.2 // indirect + github.com/getsentry/sentry-go v0.24.1 // indirect + github.com/go-asn1-ber/asn1-ber v1.5.5 // indirect + github.com/go-errors/errors v1.4.2 // indirect + github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect + github.com/go-git/go-billy/v5 v5.4.1 // indirect + github.com/go-git/go-git/v5 v5.8.1 // indirect + github.com/go-ldap/ldap/v3 v3.4.6 // indirect + github.com/go-logr/logr v1.2.4 // indirect + github.com/go-logr/zapr v1.2.4 // indirect + github.com/go-redis/redis v6.15.9+incompatible // indirect + github.com/go-sql-driver/mysql v1.7.1 // indirect + github.com/gobwas/glob v0.2.3 // indirect + github.com/goccy/go-json v0.10.0 // indirect + github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 // indirect + github.com/golang-jwt/jwt v3.2.2+incompatible // indirect + github.com/golang-jwt/jwt/v4 v4.5.0 // indirect + github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe // indirect + github.com/golang-sql/sqlexp v0.1.0 // indirect + github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect + github.com/golang/protobuf v1.5.3 // indirect + github.com/google/flatbuffers v23.1.21+incompatible // indirect + github.com/google/go-containerregistry v0.15.2 // indirect + github.com/google/go-github/v42 v42.0.0 // indirect + github.com/google/go-github/v55 v55.0.0 // indirect + github.com/google/s2a-go v0.1.4 // indirect + github.com/google/uuid v1.3.1 // indirect + github.com/googleapis/enterprise-certificate-proxy v0.2.5 // indirect + github.com/googleapis/gax-go/v2 v2.12.0 // indirect + github.com/gregjones/httpcache v0.0.0-20171119193500-2bcd89a1743f // indirect + github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c // indirect + github.com/h2non/filetype v1.1.3 // indirect + github.com/hashicorp/errwrap v1.0.0 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/go-retryablehttp v0.7.4 // indirect + github.com/hashicorp/golang-lru v0.5.1 // indirect + github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect + github.com/jlaffaye/ftp v0.2.0 // indirect + github.com/jmespath/go-jmespath v0.4.0 // indirect + github.com/joho/godotenv v1.5.1 // indirect + github.com/josharian/intern v1.0.0 // indirect + github.com/kevinburke/ssh_config v1.2.0 // indirect + github.com/klauspost/asmfmt v1.3.2 // indirect + github.com/klauspost/cpuid/v2 v2.2.3 // indirect + github.com/kylelemons/godebug v1.1.0 // indirect + github.com/launchdarkly/ccache v1.1.0 // indirect + github.com/launchdarkly/eventsource v1.6.2 // indirect + github.com/launchdarkly/go-jsonstream/v3 v3.0.0 // indirect + github.com/launchdarkly/go-sdk-common/v3 v3.0.1 // indirect + github.com/launchdarkly/go-sdk-events/v2 v2.0.1 // indirect + github.com/launchdarkly/go-semver v1.0.2 // indirect + github.com/launchdarkly/go-server-sdk-evaluation/v2 v2.0.2 // indirect + github.com/launchdarkly/go-server-sdk/v6 v6.1.0 // indirect + github.com/lib/pq v1.10.9 // indirect + github.com/mailru/easyjson v0.7.7 // indirect + github.com/marusama/semaphore/v2 v2.5.0 // indirect + github.com/mattn/go-sqlite3 v1.14.17 // indirect + github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect + github.com/mholt/archiver/v4 v4.0.0-alpha.8 // indirect + github.com/minio/asm2plan9s v0.0.0-20200509001527-cdd76441f9d8 // indirect + github.com/minio/c2goasm v0.0.0-20190812172519-36a3d3bbc4f3 // indirect + github.com/mitchellh/go-homedir v1.1.0 // indirect + github.com/montanaflynn/stats v0.7.0 // indirect + github.com/mtibben/percent v0.2.1 // indirect + github.com/nwaples/rardecode/v2 v2.0.0-beta.2 // indirect + github.com/nxadm/tail v1.4.11 // indirect + github.com/opencontainers/go-digest v1.0.0 // indirect + github.com/opencontainers/image-spec v1.1.0-rc3 // indirect + github.com/patrickmn/go-cache v2.1.0+incompatible // indirect + github.com/pjbgf/sha1cd v0.3.0 // indirect + github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 // indirect + github.com/pkg/diff v0.0.0-20200914180035-5b29258ca4f7 // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/prometheus/client_golang v1.16.0 // indirect + github.com/prometheus/client_model v0.3.0 // indirect + github.com/prometheus/common v0.42.0 // indirect + github.com/prometheus/procfs v0.10.1 // indirect + github.com/sergi/go-diff v1.3.1 // indirect + github.com/sirupsen/logrus v1.9.0 // indirect + github.com/skeema/knownhosts v1.2.0 // indirect + github.com/snowflakedb/gosnowflake v1.6.23 // indirect + github.com/tailscale/depaware v0.0.0-20210622194025-720c4b409502 // indirect + github.com/therootcompany/xz v1.0.1 // indirect + github.com/vbatts/tar-split v0.11.3 // indirect + github.com/xanzy/go-gitlab v0.92.3 // indirect + github.com/xanzy/ssh-agent v0.3.3 // indirect + github.com/xdg-go/pbkdf2 v1.0.0 // indirect + github.com/xdg-go/scram v1.1.2 // indirect + github.com/xdg-go/stringprep v1.0.4 // indirect + github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d // indirect + github.com/zeebo/xxh3 v1.0.2 // indirect + go.mongodb.org/mongo-driver v1.12.1 // indirect + go.opencensus.io v0.24.0 // indirect + go.uber.org/atomic v1.7.0 // indirect + go.uber.org/multierr v1.6.0 // indirect + go.uber.org/zap v1.24.0 // indirect + go4.org v0.0.0-20200411211856-f5505b9728dd // indirect + golang.org/x/oauth2 v0.12.0 // indirect + golang.org/x/time v0.3.0 // indirect + golang.org/x/tools v0.12.0 // indirect + golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect + google.golang.org/api v0.132.0 // indirect + google.golang.org/appengine v1.6.7 // indirect + google.golang.org/genproto v0.0.0-20230706204954-ccb25ca9f130 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20230706204954-ccb25ca9f130 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98 // indirect + google.golang.org/grpc v1.56.2 // indirect + google.golang.org/protobuf v1.31.0 // indirect + gopkg.in/warnings.v0 v0.1.2 // indirect + sigs.k8s.io/yaml v1.3.0 // indirect +) + require ( github.com/andybalholm/brotli v1.0.5 // indirect github.com/dsnet/compress v0.0.2-0.20210315054119-f66993602bf5 // indirect @@ -46,16 +229,14 @@ require ( github.com/google/go-querystring v1.1.0 // indirect github.com/google/jsonapi v1.0.0 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect - github.com/klauspost/compress v1.16.0 // indirect + github.com/klauspost/compress v1.16.5 // indirect github.com/klauspost/pgzip v1.2.5 // indirect github.com/mattn/go-colorable v0.1.13 // indirect - github.com/mattn/go-runewidth v0.0.13 // indirect + github.com/mattn/go-runewidth v0.0.14 // indirect github.com/nwaples/rardecode v1.1.2 // indirect github.com/peterhellberg/link v1.1.0 // indirect - github.com/pierrec/lz4/v4 v4.1.8 // indirect - github.com/rivo/uniseg v0.2.0 // indirect - github.com/rogpeppe/go-internal v1.8.0 // indirect - github.com/stretchr/testify v1.8.2 // indirect + github.com/pierrec/lz4/v4 v4.1.17 // indirect + github.com/rivo/uniseg v0.4.2 // indirect github.com/ulikunitz/xz v0.5.10 // indirect github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 // indirect golang.org/x/net v0.17.0 // indirect diff --git a/go.sum b/go.sum index 4424b1038..e8464be50 100644 --- a/go.sum +++ b/go.sum @@ -1,90 +1,541 @@ +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= +cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= +cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= +cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= +cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= +cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= +cloud.google.com/go v0.110.4 h1:1JYyxKMN9hd5dR2MYTPWkGUgcoxVVhg0LKNKEo0qvmk= +cloud.google.com/go v0.110.4/go.mod h1:+EYjdK8e5RME/VY/qLCAtuyALQ9q67dvuum8i+H5xsI= +cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= +cloud.google.com/go/compute v1.20.1 h1:6aKEtlUiwEpJzM001l0yFkpXmUVXaN8W+fbkb2AZNbg= +cloud.google.com/go/compute v1.20.1/go.mod h1:4tCnrn48xsqlwSAiLf1HXMQk8CONslYbdiEZc9FEIbM= +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= +cloud.google.com/go/iam v1.1.0 h1:67gSqaPukx7O8WLLHMa0PNs3EBGd2eE4d+psbO/CO94= +cloud.google.com/go/iam v1.1.0/go.mod h1:nxdHjaKfCr7fNYx/HJMM8LgiMugmveWlkatear5gVyk= +cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= +cloud.google.com/go/secretmanager v1.11.1 h1:cLTCwAjFh9fKvU6F13Y4L9vPcx9yiWPyWXE4+zkuEQs= +cloud.google.com/go/secretmanager v1.11.1/go.mod h1:znq9JlXgTNdBeQk9TBW/FnR/W4uChEKGeqQWAJ8SXFw= +cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= +cloud.google.com/go/storage v1.33.0 h1:PVrDOkIC8qQVa1P3SXGpQvfuJhN2LHOoyZvWs8D2X5M= +cloud.google.com/go/storage v1.33.0/go.mod h1:Hhh/dogNRGca7IWv1RC2YqEn0c0G77ctA/OxflYkiD8= +dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk= +dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 h1:/vQbFIOMbk2FiG/kXiLl8BRyzTWDw7gX/Hz7Dd5eDMs= +github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4/go.mod h1:hN7oaIRCjzsZ2dE+yG5k+rsdt3qcwykqK6HVGcKwsw4= +github.com/99designs/keyring v1.2.2 h1:pZd3neh/EmUzWONb35LxQfvuY7kiSXAq3HQd97+XBn0= +github.com/99designs/keyring v1.2.2/go.mod h1:wes/FrByc8j7lFOAGLGSNEg8f/PaI3cgTBqhFkHUrPk= +github.com/Azure/azure-sdk-for-go/sdk/azcore v0.19.0/go.mod h1:h6H6c8enJmmocHUbLiiGY6sx7f9i+X3m1CHdd5c6Rdw= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.4.0 h1:rTnT/Jrcm+figWlYz4Ixzt0SJVR2cMC8lvZcimipiEY= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.4.0/go.mod h1:ON4tFdPTwRcgWEaVDrN3584Ef+b7GgSJaXxe5fW9t4M= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v0.11.0/go.mod h1:HcM1YX14R7CJcghJGOYCgdezslRSVzqwLf/q+4Y2r/0= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.1.0 h1:QkAcEIAKbNL4KoFr4SathZPhDhF4mVwpBMFlYjyAqy8= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.1.0/go.mod h1:bhXu1AjYL+wutSL/kpSq6s7733q2Rb0yuot9Zgfqa/0= +github.com/Azure/azure-sdk-for-go/sdk/internal v0.7.0/go.mod h1:yqy467j36fJxcRV2TzfVZ1pCb5vxm4BtZPUdYWe/Xo8= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.1.2 h1:+5VZ72z0Qan5Bog5C+ZkgSqUbeVUd9wgtHOrIKuc5b8= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.1.2/go.mod h1:eWRD7oawr1Mu1sLCawqVc0CUiF43ia3qQMxLscsKQ9w= +github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.0.0 h1:u/LLAOFgsMv7HmNL4Qufg58y+qElGOt5qv0z1mURkRY= +github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.0.0/go.mod h1:2e8rMJtl2+2j+HXbTBwnyGpm5Nou7KhvSfxOq8JpTag= +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 h1:1fIGgHKqVm54KIPT+q8Zmd1QlVsmHqeUGso5qm2BqqE= +github.com/Azure/go-autorest/autorest v0.11.24/go.mod h1:G6kyRlFnTuSbEYkQGawPfsCswgme4iYf6rfSKUDzbCc= +github.com/Azure/go-autorest/autorest/adal v0.9.18 h1:kLnPsRjzZZUF3K5REu/Kc+qMQrvuza2bwSnNdhmzLfQ= +github.com/Azure/go-autorest/autorest/adal v0.9.18/go.mod h1:XVVeme+LZwABT8K5Lc3hA4nAe8LDBVle26gTrguhhPQ= +github.com/Azure/go-autorest/autorest/azure/auth v0.5.11 h1:P6bYXFoao05z5uhOQzbC3Qd8JqF3jUoocoTeIxkp2cA= +github.com/Azure/go-autorest/autorest/azure/auth v0.5.11/go.mod h1:84w/uV8E37feW2NCJ08uT9VBfjfUHpgLVnG2InYD6cg= +github.com/Azure/go-autorest/autorest/azure/cli v0.4.5 h1:0W/yGmFdTIT77fvdlGZ0LMISoLHFJ7Tx4U0yeB+uFs4= +github.com/Azure/go-autorest/autorest/azure/cli v0.4.5/go.mod h1:ADQAXrkgm7acgWVUNamOgh8YNrv4p27l3Wc55oVfpzg= +github.com/Azure/go-autorest/autorest/date v0.3.0 h1:7gUk1U5M/CQbp9WoqinNzJar+8KY+LPI6wiWrP/myHw= +github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74= +github.com/Azure/go-autorest/autorest/mocks v0.4.1 h1:K0laFcLE6VLTOwNgSxaGbUcLPuGXlNkbVvq4cW4nIHk= +github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= +github.com/Azure/go-autorest/logger v0.2.1 h1:IG7i4p/mDa2Ce4TRyAO8IHnVhAVF3RFU+ZtXWSmf4Tg= +github.com/Azure/go-autorest/logger v0.2.1/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= +github.com/Azure/go-autorest/tracing v0.6.0 h1:TYi4+3m5t6K48TGI9AUdb+IzbnSxvnvUMfuitfgcfuo= +github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= +github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 h1:mFRzDkZVAjdal+s7s0MwaRv9igoPqLRdzOLzw/8Xvq8= +github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= +github.com/AzureAD/microsoft-authentication-library-for-go v1.2.0 h1:hVeq+yCyUi+MsoO/CU95yqCIcdzra5ovzk8Q2BBpV2M= +github.com/AzureAD/microsoft-authentication-library-for-go v1.2.0/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI= +github.com/BobuSumisu/aho-corasick v1.0.3 h1:uuf+JHwU9CHP2Vx+wAy6jcksJThhJS9ehR8a+4nPE9g= +github.com/BobuSumisu/aho-corasick v1.0.3/go.mod h1:hm4jLcvZKI2vRF2WDU1N4p/jpWtpOzp3nLmi9AzX/XE= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/JohnCGriffin/overflow v0.0.0-20211019200055-46fa312c352c h1:RGWPOewvKIROun94nF7v2cua9qP+thov/7M50KEoeSU= +github.com/JohnCGriffin/overflow v0.0.0-20211019200055-46fa312c352c/go.mod h1:X0CRv0ky0k6m906ixxpzmDRLvX58TFUKS2eePweuyxk= github.com/Masterminds/semver/v3 v3.2.1 h1:RN9w6+7QoMeJVGyfmbcgs28Br8cvmnucEXnY0rYXWg0= github.com/Masterminds/semver/v3 v3.2.1/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ= -github.com/alecthomas/units v0.0.0-20210208195552-ff826a37aa15 h1:AUNCr9CiJuwrRYS3XieqF+Z9B9gNxo/eANAJCF2eiN4= -github.com/alecthomas/units v0.0.0-20210208195552-ff826a37aa15/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE= +github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY= +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/ProtonMail/go-crypto v0.0.0-20230217124315-7d5c6f04bbb8/go.mod h1:I0gYDMZ6Z5GRU7l58bNFSkPTFN6Yl12dsUlAZ8xy98g= +github.com/ProtonMail/go-crypto v0.0.0-20230717121422-5aa5874ade95 h1:KLq8BE0KwCL+mmXnjLWEAOYO+2l2AE4YMmqG1ZpZHBs= +github.com/ProtonMail/go-crypto v0.0.0-20230717121422-5aa5874ade95/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0= +github.com/TheZeroSlave/zapsentry v1.17.0 h1:RIQCG89U7vWWZVmmCxeUz/g32WEcAYXUrXHoMlbSDmc= +github.com/TheZeroSlave/zapsentry v1.17.0/go.mod h1:D1YMfSuu6xnkhwFXxrronesmsiyDhIqo+86I3Ok+r64= +github.com/acomagu/bufpipe v1.0.4 h1:e3H4WUzM3npvo5uv95QuJM3cQspFNtFBzvJ2oNjKIDQ= +github.com/acomagu/bufpipe v1.0.4/go.mod h1:mxdxdup/WdsKVreO5GpW4+M/1CE2sMG4jeGJ2sYmHc4= +github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 h1:s6gZFSlWYmbqAuRjVTiNNhvNRfY2Wxp9nhfyel4rklc= +github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE= +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/andybalholm/brotli v1.0.1/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y= github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs= github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= +github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8= +github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4= +github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= +github.com/apache/arrow/go/v12 v12.0.1 h1:JsR2+hzYYjgSUkBSaahpqCetqZMr76djX80fF/DiJbg= +github.com/apache/arrow/go/v12 v12.0.1/go.mod h1:weuTY7JvTG/HDPtMQxEUp7pU73vkLWMLpY67QwZ/WWw= +github.com/apache/thrift v0.16.0 h1:qEy6UW60iVOlUy+b9ZR0d5WzUWYGOo4HfopoyBaNmoY= +github.com/apache/thrift v0.16.0/go.mod h1:PHK3hniurgQaNMZYaCLEqXKsYK8upmhPbmdP2FXSqgU= +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 v1.45.19 h1:+4yXWhldhCVXWFOQRF99ZTJ92t4DtoHROZIbN7Ujk/U= +github.com/aws/aws-sdk-go v1.45.19/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= +github.com/aws/aws-sdk-go-v2 v1.17.7 h1:CLSjnhJSTSogvqUGhIC6LqFKATMRexcxLZ0i/Nzk9Eg= +github.com/aws/aws-sdk-go-v2 v1.17.7/go.mod h1:uzbQtefpm44goOPmdKyAlXSNcwlRgF3ePWVW6EtJvvw= +github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.10 h1:dK82zF6kkPeCo8J1e+tGx4JdvDIQzj7ygIoLg8WMuGs= +github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.10/go.mod h1:VeTZetY5KRJLuD/7fkQXMU6Mw7H5m/KP2J5Iy9osMno= +github.com/aws/aws-sdk-go-v2/config v1.18.19 h1:AqFK6zFNtq4i1EYu+eC7lcKHYnZagMn6SW171la0bGw= +github.com/aws/aws-sdk-go-v2/config v1.18.19/go.mod h1:XvTmGMY8d52ougvakOv1RpiTLPz9dlG/OQHsKU/cMmY= +github.com/aws/aws-sdk-go-v2/credentials v1.13.18 h1:EQMdtHwz0ILTW1hoP+EwuWhwCG1hD6l3+RWFQABET4c= +github.com/aws/aws-sdk-go-v2/credentials v1.13.18/go.mod h1:vnwlwjIe+3XJPBYKu1et30ZPABG3VaXJYr8ryohpIyM= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.1 h1:gt57MN3liKiyGopcqgNzJb2+d9MJaKT/q1OksHNXVE4= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.1/go.mod h1:lfUx8puBRdM5lVVMQlwt2v+ofiG/X6Ms+dy0UkG/kXw= +github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.59 h1:E3Y+OfzOK1+rmRo/K2G0ml8Vs+Xqk0kOnf4nS0kUtBc= +github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.59/go.mod h1:1M4PLSBUVfBI0aP+C9XI7SM6kZPCGYyI6izWz0TGprE= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.31 h1:sJLYcS+eZn5EeNINGHSCRAwUJMFVqklwkH36Vbyai7M= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.31/go.mod h1:QT0BqUvX1Bh2ABdTGnjqEjvjzrCfIniM9Sc8zn9Yndo= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.25 h1:1mnRASEKnkqsntcxHaysxwgVoUUp5dkiB+l3llKnqyg= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.25/go.mod h1:zBHOPwhBc3FlQjQJE/D3IfPWiWaQmT06Vq9aNukDo0k= +github.com/aws/aws-sdk-go-v2/internal/ini v1.3.32 h1:p5luUImdIqywn6JpQsW3tq5GNOxKmOnEpybzPx+d1lk= +github.com/aws/aws-sdk-go-v2/internal/ini v1.3.32/go.mod h1:XGhIBZDEgfqmFIugclZ6FU7v75nHhBDtzuB4xB/tEi4= +github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.23 h1:DWYZIsyqagnWL00f8M/SOr9fN063OEQWn9LLTbdYXsk= +github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.23/go.mod h1:uIiFgURZbACBEQJfqTZPb/jxO7R+9LeoHUFudtIdeQI= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.11 h1:y2+VQzC6Zh2ojtV2LoC0MNwHWc6qXv/j2vrQtlftkdA= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.11/go.mod h1:iV4q2hsqtNECrfmlXyord9u4zyuFEJX9eLgLpSPzWA8= +github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.26 h1:CeuSeq/8FnYpPtnuIeLQEEvDv9zUjneuYi8EghMBdwQ= +github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.26/go.mod h1:2UqAAwMUXKeRkAHIlDJqvMVgOWkUi/AUXPk/YIe+Dg4= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.25 h1:5LHn8JQ0qvjD9L9JhMtylnkcw7j05GDZqM9Oin6hpr0= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.25/go.mod h1:/95IA+0lMnzW6XzqYJRpjjsAbKEORVeO0anQqjd2CNU= +github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.14.0 h1:e2ooMhpYGhDnBfSvIyusvAwX7KexuZaHbQY2Dyei7VU= +github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.14.0/go.mod h1:bh2E0CXKZsQN+faiKVqC40vfNMAWheoULBCnEgO9K+8= +github.com/aws/aws-sdk-go-v2/service/s3 v1.31.0 h1:B1G2pSPvbAtQjilPq+Y7jLIzCOwKzuVEl+aBBaNG0AQ= +github.com/aws/aws-sdk-go-v2/service/s3 v1.31.0/go.mod h1:ncltU6n4Nof5uJttDtcNQ537uNuwYqsZZQcpkd2/GUQ= +github.com/aws/aws-sdk-go-v2/service/sso v1.12.6 h1:5V7DWLBd7wTELVz5bPpwzYy/sikk0gsgZfj40X+l5OI= +github.com/aws/aws-sdk-go-v2/service/sso v1.12.6/go.mod h1:Y1VOmit/Fn6Tz1uFAeCO6Q7M2fmfXSCLeL5INVYsLuY= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.6 h1:B8cauxOH1W1v7rd8RdI/MWnoR4Ze0wIHWrb90qczxj4= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.6/go.mod h1:Lh/bc9XUf8CfOY6Jp5aIkQtN+j1mc+nExc+KXj9jx2s= +github.com/aws/aws-sdk-go-v2/service/sts v1.18.7 h1:bWNgNdRko2x6gqa0blfATqAZKZokPIeM1vfmQt2pnvM= +github.com/aws/aws-sdk-go-v2/service/sts v1.18.7/go.mod h1:JuTnSoeePXmMVe9G8NcjjwgOKEfZ4cOjMuT2IBT/2eI= +github.com/aws/smithy-go v1.13.5 h1:hgz0X/DX0dGqTYpGALqXJoRKRj5oQ7150i5FdTePzO8= +github.com/aws/smithy-go v1.13.5/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA= +github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= +github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= +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/debounce v1.2.1/go.mod h1:H8yggRPQKLUhUoqrJC1bO2xNya7vanpDl7xR3ISbCJ0= +github.com/bill-rich/disk-buffer-reader v0.1.7 h1:oPgDjsbeqErOrFJeWID/51LhIOGjU3cqN1Tj3V6RiwE= +github.com/bill-rich/disk-buffer-reader v0.1.7/go.mod h1:VVzzsK1Ac2AnpOfp/5r9JlIFaFkZ9uSf7zisZayCt0Y= +github.com/bill-rich/go-syslog v0.0.0-20220413021637-49edb52a574c h1:tSME5FDS02qQll3JYodI6RZR/g4EKOHApGv1wMZT+Z0= +github.com/bill-rich/go-syslog v0.0.0-20220413021637-49edb52a574c/go.mod h1:+sCc6hztur+oZCLOsNk6wCCy+GLrnSNHSRmTnnL+8iQ= +github.com/bitfinexcom/bitfinex-api-go v0.0.0-20210608095005-9e0b26f200fb h1:9v7Bzlg+1EBYi2IYcUmOwHReBEfqBbYIj3ZCi9cIe1Q= +github.com/bitfinexcom/bitfinex-api-go v0.0.0-20210608095005-9e0b26f200fb/go.mod h1:EkOqCuelvo7DY8vCOoZ09p7pHvAK9B1PHI9GeM4Rdxc= github.com/blang/semver v3.5.1+incompatible h1:cQNTCjp13qL8KC3Nbxr/y2Bqb63oX6wdnnjpJbkM4JQ= github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= +github.com/bodgit/plumbing v1.2.0 h1:gg4haxoKphLjml+tgnecR4yLBV5zo4HAZGCtAh3xCzM= +github.com/bodgit/plumbing v1.2.0/go.mod h1:b9TeRi7Hvc6Y05rjm8VML3+47n4XTZPtQ/5ghqic2n8= +github.com/bodgit/sevenzip v1.3.0 h1:1ljgELgtHqvgIp8W8kgeEGHIWP4ch3xGI8uOBZgLVKY= +github.com/bodgit/sevenzip v1.3.0/go.mod h1:omwNcgZTEooWM8gA/IJ2Nk/+ZQ94+GsytRzOJJ8FBlM= +github.com/bodgit/windows v1.0.0 h1:rLQ/XjsleZvx4fR1tB/UxQrK+SJ2OFHzfPjLWWOhDIA= +github.com/bodgit/windows v1.0.0/go.mod h1:a6JLwrB4KrTR5hBpp8FI9/9W9jJfeQ2h4XDXU74ZCdM= +github.com/bradleyfalzon/ghinstallation/v2 v2.7.0 h1:ranXaC3Zz/F6G/f0Joj3LrFp2OzOKfJZev5Q7OaMc88= +github.com/bradleyfalzon/ghinstallation/v2 v2.7.0/go.mod h1:ymxfmloxXBFXvvF1KpeUhOQM6Dfz9NYtfvTiJyk82UE= +github.com/bwesterb/go-ristretto v1.2.0/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= +github.com/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= +github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +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-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= +github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/connesc/cipherio v0.2.1 h1:FGtpTPMbKNNWByNrr9aEBtaJtXjqOzkIXNYJp6OEycw= +github.com/connesc/cipherio v0.2.1/go.mod h1:ukY0MWJDFnJEbXMQtOcn2VmTpRfzcTz4OoVrWGGJZcA= +github.com/containerd/stargz-snapshotter/estargz v0.14.3 h1:OqlDCK3ZVUO6C3B/5FSkDwbkEETK84kQgEeFwDC+62k= +github.com/containerd/stargz-snapshotter/estargz v0.14.3/go.mod h1:KY//uOCIkSuNAHhJogcZtrNHdKrA99/FCCRjE3HD36o= +github.com/couchbase/gocb/v2 v2.6.3 h1:5RsMo+RRfK0mVxHLAfpBz3/tHlgXZb1WBNItLk9Ab+c= +github.com/couchbase/gocb/v2 v2.6.3/go.mod h1:yF5F6BHTZ/ZowhEuZbySbXrlI4rHd1TIhm5azOaMbJU= +github.com/couchbase/gocbcore/v10 v10.2.3/go.mod h1:lYQIIk+tzoMcwtwU5GzPbDdqEkwkH3isI2rkSpfL0oM= +github.com/couchbase/gocbcore/v10 v10.2.4 h1:TDTQ1mSBUw9eajuV71ZDJcLRbmfGcsvZV9SMeUDAVGc= +github.com/couchbase/gocbcore/v10 v10.2.4/go.mod h1:lYQIIk+tzoMcwtwU5GzPbDdqEkwkH3isI2rkSpfL0oM= +github.com/couchbaselabs/gocaves/client v0.0.0-20230307083111-cc3960c624b1/go.mod h1:AVekAZwIY2stsJOMWLAS/0uA/+qdp7pjO8EHnl61QkY= +github.com/couchbaselabs/gocaves/client v0.0.0-20230404095311-05e3ba4f0259 h1:2TXy68EGEzIMHOx9UvczR5ApVecwCfQZ0LjkmwMI6g4= +github.com/couchbaselabs/gocaves/client v0.0.0-20230404095311-05e3ba4f0259/go.mod h1:AVekAZwIY2stsJOMWLAS/0uA/+qdp7pjO8EHnl61QkY= +github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/crewjam/rfc5424 v0.1.0 h1:MSeXJm22oKovLzWj44AHwaItjIMUMugYGkEzfa831H8= +github.com/crewjam/rfc5424 v0.1.0/go.mod h1:RCi9M3xHVOeerf6ULZzqv2xOGRO/zYaVUeRyPnBW3gQ= +github.com/danieljoos/wincred v1.1.2 h1:QLdCxFs1/Yl4zduvBdcHB8goaYk9RARS2SgLLRuAyr0= +github.com/danieljoos/wincred v1.1.2/go.mod h1:GijpziifJoIBfYh+S7BbkdUTU4LfM+QnGqR5Vl2tAx0= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 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/denisenkom/go-mssqldb v0.12.3 h1:pBSGx9Tq67pBOTLmxNuirNTeB8Vjmf886Kx+8Y+8shw= +github.com/denisenkom/go-mssqldb v0.12.3/go.mod h1:k0mtMFOnU+AihqFxPMiF05rtiDrorD1Vrm1KEz5hxDo= +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/dnaeon/go-vcr v1.2.0 h1:zHCHvJYTMh1N7xnV7zf1m1GPBF9Ad0Jk/whtQ1663qI= github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ= +github.com/docker/cli v23.0.5+incompatible h1:ufWmAOuD3Vmr7JP2G5K3cyuNC4YZWiAsuDEvFVVDafE= +github.com/docker/cli v23.0.5+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= +github.com/docker/distribution v2.8.2+incompatible h1:T3de5rq0dB1j30rp0sA2rER+m322EBzniBPB6ZIzuh8= +github.com/docker/distribution v2.8.2+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/docker v23.0.5+incompatible h1:DaxtlTJjFSnLOXVNUBU1+6kXGz2lpDoEAH6QoxaSg8k= +github.com/docker/docker v23.0.5+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker-credential-helpers v0.7.0 h1:xtCHsjxogADNZcdv1pKUHXryefjlVRqWqIhk/uXJp0A= +github.com/docker/docker-credential-helpers v0.7.0/go.mod h1:rETQfLdHNT3foU5kuNkFR1R1V12OJRRO5lzt2D1b5X0= github.com/dsnet/compress v0.0.2-0.20210315054119-f66993602bf5 h1:iFaUwBSo5Svw6L7HYpRu/0lE3e0BaElwnNO1qkNQxBY= github.com/dsnet/compress v0.0.2-0.20210315054119-f66993602bf5/go.mod h1:qssHWj60/X5sZFNxpG4HBPDHVqxNm4DfnCKgrbZOT+s= github.com/dsnet/golib v0.0.0-20171103203638-1ea166775780/go.mod h1:Lj+Z9rebOhdfkVLjJ8T6VcRQv3SXugXy999NBtR9aFY= github.com/dustinkirkland/golang-petname v0.0.0-20191129215211-8e5a1ed0cff0 h1:90Ly+6UfUypEF6vvvW5rQIv9opIL8CbmW9FT20LDQoY= github.com/dustinkirkland/golang-petname v0.0.0-20191129215211-8e5a1ed0cff0/go.mod h1:V+Qd57rJe8gd4eiGzZyg4h54VLHmYVVw54iMnlAMrF8= +github.com/dvsekhvalnov/jose2go v1.5.0 h1:3j8ya4Z4kMCwT5nXIKFSV84YS+HdqSSO0VsTQxaLAeM= +github.com/dvsekhvalnov/jose2go v1.5.0/go.mod h1:QsHjhyTlD/lAVqn/NSbVZmSCGeDehTB/mPZadG+mhXU= +github.com/elazarl/goproxy v0.0.0-20221015165544-a0805db90819 h1:RIB4cRk+lBqKK3Oy0r2gRX4ui7tuhiZq2SuTtTCi0/0= +github.com/elazarl/goproxy v0.0.0-20221015165544-a0805db90819/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM= +github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= +github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= +github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/envoyproxy/protoc-gen-validate v1.0.2 h1:QkIBuU5k+x7/QXPvPPnWXWlCdaBFApVqftFV6k087DA= +github.com/envoyproxy/protoc-gen-validate v1.0.2/go.mod h1:GpiZQP3dDbg4JouG/NNS7QWXpgx6x8QiMKdmN72jogE= github.com/fastly/go-fastly/v8 v8.6.4 h1:/jf1j8VwpXDR+b7PA6RBhBcRo3OoEWFwFHFeOba7pk8= github.com/fastly/go-fastly/v8 v8.6.4/go.mod h1:sC3WMOjQxwXk+gRI68ooTJJsI+/6AMA/4JLvrhNgpVk= github.com/fastly/kingpin v2.1.12-0.20191105091915-95d230a53780+incompatible h1:FhrXlfhgGCS+uc6YwyiFUt04alnjpoX7vgDKJxS6Qbk= github.com/fastly/kingpin v2.1.12-0.20191105091915-95d230a53780+incompatible/go.mod h1:U8UynVoU1SQaqD2I4ZqgYd5lx3A1ipQYn4aSt2Y5h6c= github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs= github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw= +github.com/form3tech-oss/jwt-go v3.2.5+incompatible h1:/l4kBbb4/vGSsdtB5nUe8L7B9mImVMaBPw9L/0TBHU8= +github.com/form3tech-oss/jwt-go v3.2.5+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= github.com/frankban/quicktest v1.13.1 h1:xVm/f9seEhZFL9+n5kv5XLrGwy6elc4V9v/XFY2vmd8= github.com/frankban/quicktest v1.13.1/go.mod h1:NeW+ay9A/U67EYXNFA1nPE8e/tnQv/09mUdL/ijj8og= +github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= +github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU= +github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA= +github.com/getsentry/sentry-go v0.24.1 h1:W6/0GyTy8J6ge6lVCc94WB6Gx2ZuLrgopnn9w8Hiwuk= +github.com/getsentry/sentry-go v0.24.1/go.mod h1:lc76E2QywIyW8WuBnwl8Lc4bkmQH4+w1gwTf25trprY= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +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-asn1-ber/asn1-ber v1.5.5 h1:MNHlNMBDgEKD4TcKr36vQN68BA00aDfjIt3/bD50WnA= +github.com/go-asn1-ber/asn1-ber v1.5.5/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= +github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA= +github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= +github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI= +github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic= +github.com/go-git/go-billy/v5 v5.4.1 h1:Uwp5tDRkPr+l/TnbHOQzp+tmJfLceOlbVucgpTz8ix4= +github.com/go-git/go-billy/v5 v5.4.1/go.mod h1:vjbugF6Fz7JIflbVpl1hJsGjSHNltrSw45YK/ukIvQg= +github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20230305113008-0c11038e723f h1:Pz0DHeFij3XFhoBRGUDPzSJ+w2UcK5/0JvF8DRI58r8= +github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20230305113008-0c11038e723f/go.mod h1:8LHG1a3SRW71ettAD/jW13h8c6AqjVSeL11RAdgaqpo= +github.com/go-git/go-git/v5 v5.8.1 h1:Zo79E4p7TRk0xoRgMq0RShiTHGKcKI4+DI6BfJc/Q+A= +github.com/go-git/go-git/v5 v5.8.1/go.mod h1:FHFuoD6yGz5OSKEBK+aWN9Oah0q54Jxl0abmj6GnqAo= +github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-ldap/ldap/v3 v3.4.6 h1:ert95MdbiG7aWo/oPYp9btL3KJlMPKnP58r09rI8T+A= +github.com/go-ldap/ldap/v3 v3.4.6/go.mod h1:IGMQANNtxpsOzj7uUAMjpGBaOVTC4DYyIy8VsTdxmtc= +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/zapr v1.2.4 h1:QHVo+6stLbfJmYGkQ7uGHUCu5hnAFAj6mDe6Ea0SeOo= +github.com/go-logr/zapr v1.2.4/go.mod h1:FyHWQIzQORZ0QVE1BtVHv3cKtNLuXsbNLtpuhNapBOA= +github.com/go-redis/redis v6.15.9+incompatible h1:K0pv1D7EQUjfyoMql+r/jZqCLizCGKFlFgcHWWmHQjg= +github.com/go-redis/redis v6.15.9+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= +github.com/go-sql-driver/mysql v1.7.1 h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrtU8EI= +github.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= +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-20200921212729-da3d93bc3c58/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo= +github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= +github.com/gobwas/ws v1.0.4/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM= +github.com/goccy/go-json v0.10.0 h1:mXKd9Qw4NuzShiRlOXKews24ufknHO7gx30lsDyokKA= +github.com/goccy/go-json v0.10.0/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= +github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 h1:ZpnhV/YsD2/4cESfV5+Hoeu/iUR3ruzNvZ+yQfO03a0= +github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4= +github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY= +github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= +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-jwt/jwt/v5 v5.0.0 h1:1n1XNM9hk7O9mnQoNBGolZvzebBQ7p93ULHRc28XJUE= +github.com/golang-jwt/jwt/v5 v5.0.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= +github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY= +github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= +github.com/golang-sql/sqlexp v0.1.0 h1:ZCD6MBpcuOVfGVqsEmY5/4FtYiKz6tSyUv9LPEDei6A= +github.com/golang-sql/sqlexp v0.1.0/go.mod h1:J4ad9Vo8ZCWQ2GMrC4UCQy1JpCbwU9m3EOqtpKwwwHI= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +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= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.5.0 h1:jlYHihg//f7RRwuPfptm04yp4s7O6Kw8EZiVYIGcH0g= +github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= +github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.2/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/flatbuffers v23.1.21+incompatible h1:bUqzx/MXCDxuS0hRJL2EfjyZL3uQrPbMocUa8zGqsTA= +github.com/google/flatbuffers v23.1.21+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-containerregistry v0.15.2 h1:MMkSh+tjSdnmJZO7ljvEqV1DjfekB6VUEAZgy3a+TQE= +github.com/google/go-containerregistry v0.15.2/go.mod h1:wWK+LnOv4jXMM23IT/F1wdYftGWGr47Is8CG+pmHK1Q= +github.com/google/go-github/v42 v42.0.0 h1:YNT0FwjPrEysRkLIiKuEfSvBPCGKphW5aS5PxwaoLec= +github.com/google/go-github/v42 v42.0.0/go.mod h1:jgg/jvyI0YlDOM1/ps6XYh04HNQ3vKf0CVko62/EhRg= +github.com/google/go-github/v55 v55.0.0 h1:4pp/1tNMB9X/LuAhs5i0KQAE40NmiR/y6prLNb9x9cg= +github.com/google/go-github/v55 v55.0.0/go.mod h1:JLahOTA1DnXzhxEymmFF5PP2tSS9JVNj68mSZNDwskA= github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= github.com/google/jsonapi v1.0.0 h1:qIGgO5Smu3yJmSs+QlvhQnrscdZfFhiV6S8ryJAglqU= github.com/google/jsonapi v1.0.0/go.mod h1:YYHiRPJT8ARXGER8In9VuLv4qvLfDmA9ULQqptbLE4s= +github.com/google/martian v2.1.0+incompatible h1:/CP5g8u/VJHijgedC/Legn3BAbAaWPgecwXBIDzw5no= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/martian/v3 v3.3.2 h1:IqNFLAmvJOgVlpdEBiQbDc2EwKW77amAycfTuWKdfvw= +github.com/google/martian/v3 v3.3.2/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/s2a-go v0.1.4 h1:1kZ/sQM3srePvKs3tXAvQzo66XfcReoqFpIpIccE7Oc= +github.com/google/s2a-go v0.1.4/go.mod h1:Ej+mSEMGRnqRzjc7VtF+jdBwYG5fuJfiZ8ELkjEwM0A= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= +github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/enterprise-certificate-proxy v0.2.5 h1:UR4rDjcgpgEnqpIEvkiqTYKBCKLNmlge2eVjoZfySzM= +github.com/googleapis/enterprise-certificate-proxy v0.2.5/go.mod h1:RxW0N9901Cko1VOCW3SXCpWP+mlIEkk2tP7jnHy9a3w= +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.12.0 h1:A+gCJKdRfqXkr+BIRGtZLibNXf0m1f9E4HG56etFpas= +github.com/googleapis/gax-go/v2 v2.12.0/go.mod h1:y+aIqrI5eb1YGMVJfuV3185Ts/D7qKpsEkdD5+I6QGU= +github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gregjones/httpcache v0.0.0-20171119193500-2bcd89a1743f h1:kOkUP6rcVVqC+KlKKENKtgfFfJyDySYhqL9srXooghY= +github.com/gregjones/httpcache v0.0.0-20171119193500-2bcd89a1743f/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= +github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= +github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c h1:6rhixN/i8ZofjG1Y75iExal34USq5p+wiN1tpie8IrU= +github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c/go.mod h1:NMPJylDgVpX0MLRlPy15sqSwOFv/U1GZ2m21JhFfek0= +github.com/h2non/filetype v1.1.3 h1:FKkx9QbD7HR/zjK1Ia5XiBsq9zdLi5Kf3zGyFTAFkGg= +github.com/h2non/filetype v1.1.3/go.mod h1:319b3zT68BvV+WRj7cwy856M2ehB3HqNOt6sy1HndBY= +github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542 h1:2VTzZjLZBgl62/EtslCrtky5vbi9dd7HrQPQIx6wqiw= +github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542/go.mod h1:Ow0tF8D4Kplbc8s8sSb3V2oUCygFHVp8gC3Dn6U4MNI= +github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= +github.com/hashicorp/go-hclog v0.9.2 h1:CG6TE5H9/JXsFWJCfoIVpKFIkFe6ysEuHirp4DxCsHI= +github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-retryablehttp v0.7.4 h1:ZQgVdpTdAL7WpMIwLzCfbalOcSUdkDZnpUv3/+BxzFA= +github.com/hashicorp/go-retryablehttp v0.7.4/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5wjtH1ewM9u8iYVjtX8= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= +github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= +github.com/jlaffaye/ftp v0.2.0 h1:lXNvW7cBu7R/68bknOX3MrRIIqZ61zELs1P2RAiA3lg= +github.com/jlaffaye/ftp v0.2.0/go.mod h1:is2Ds5qkhceAPy2xD6RLI6hmp/qysSoymZ+Z2uTnspI= +github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= +github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= +github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= +github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= +github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= +github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= +github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= +github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= +github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= +github.com/karlseguin/expect v1.0.2-0.20190806010014-778a5f0c6003 h1:vJ0Snvo+SLMY72r5J4sEfkuE7AFbixEP2qRbEcum/wA= +github.com/karlseguin/expect v1.0.2-0.20190806010014-778a5f0c6003/go.mod h1:zNBxMY8P21owkeogJELCLeHIt+voOSduHYTFUbwRAV8= github.com/kennygrant/sanitize v1.2.4 h1:gN25/otpP5vAsO2djbMhF/LQX6R7+O1TB4yv8NzpJ3o= github.com/kennygrant/sanitize v1.2.4/go.mod h1:LGsjYYtgxbetdg5owWB2mpgUL6e2nfw2eObZ0u0qvak= +github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4= +github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/klauspost/asmfmt v1.3.2 h1:4Ri7ox3EwapiOjCki+hw14RyKk201CN4rzyCJRFLpK4= +github.com/klauspost/asmfmt v1.3.2/go.mod h1:AG8TuvYojzulgDAMCnYn50l/5QV3Bs/tp6j0HLHbNSE= github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= github.com/klauspost/compress v1.11.4/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= -github.com/klauspost/compress v1.16.0 h1:iULayQNOReoYUe+1qtKOqw9CwJv3aNQu8ivo7lw1HU4= -github.com/klauspost/compress v1.16.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= +github.com/klauspost/compress v1.16.5 h1:IFV2oUNUzZaz+XyusxpLzpzS8Pt5rh0Z16For/djlyI= +github.com/klauspost/compress v1.16.5/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= +github.com/klauspost/cpuid/v2 v2.2.3 h1:sxCkb+qR91z4vsqw4vGGZlDgPz3G7gjaLyK3V8y70BU= +github.com/klauspost/cpuid/v2 v2.2.3/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY= github.com/klauspost/pgzip v1.2.5 h1:qnWYvvKqedOF2ulHpMG72XQol4ILEJ8k2wwRl/Km8oE= github.com/klauspost/pgzip v1.2.5/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= -github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= +github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= +github.com/launchdarkly/ccache v1.1.0 h1:voD1M+ZJXR3MREOKtBwgTF9hYHl1jg+vFKS/+VAkR2k= +github.com/launchdarkly/ccache v1.1.0/go.mod h1:TlxzrlnzvYeXiLHmesMuvoZetu4Z97cV1SsdqqBJi1Q= +github.com/launchdarkly/eventsource v1.6.2 h1:5SbcIqzUomn+/zmJDrkb4LYw7ryoKFzH/0TbR0/3Bdg= +github.com/launchdarkly/eventsource v1.6.2/go.mod h1:LHxSeb4OnqznNZxCSXbFghxS/CjIQfzHovNoAqbO/Wk= +github.com/launchdarkly/go-jsonstream/v3 v3.0.0 h1:qJF/WI09EUJ7kSpmP5d1Rhc81NQdYUhP17McKfUq17E= +github.com/launchdarkly/go-jsonstream/v3 v3.0.0/go.mod h1:/1Gyml6fnD309JOvunOSfyysWbZ/ZzcA120gF/cQtC4= +github.com/launchdarkly/go-sdk-common/v3 v3.0.1 h1:rVdLusAIViduNvyjNKy06RA+SPwk0Eq+NocNd1opDhk= +github.com/launchdarkly/go-sdk-common/v3 v3.0.1/go.mod h1:H/zISoCNhviHTTqqBjIKQy2YgSHT8ioL1FtgBKpiEGg= +github.com/launchdarkly/go-sdk-events/v2 v2.0.1 h1:vnUN2Y7og/5wtOCcCZW7wYpmZcS++GAyclasc7gaTIY= +github.com/launchdarkly/go-sdk-events/v2 v2.0.1/go.mod h1:Msqbl6brgFO83RUxmLaJAUx2sYG+WKULcy+Vf3+tKww= +github.com/launchdarkly/go-semver v1.0.2 h1:sYVRnuKyvxlmQCnCUyDkAhtmzSFRoX6rG2Xa21Mhg+w= +github.com/launchdarkly/go-semver v1.0.2/go.mod h1:xFmMwXba5Mb+3h72Z+VeSs9ahCvKo2QFUTHRNHVqR28= +github.com/launchdarkly/go-server-sdk-evaluation/v2 v2.0.2 h1:PAM0GvE0nIUBeOkjdiymIEKI+8FFLJ+fEsWTupW1yGU= +github.com/launchdarkly/go-server-sdk-evaluation/v2 v2.0.2/go.mod h1:Mztipcz+7ZMatXVun3k/IfPa8IOgUnAqiZawtFh2MRg= +github.com/launchdarkly/go-server-sdk/v6 v6.1.0 h1:pp/VBIon5JNbtSw7ih7I5MXN9mXHfo6T5xikKVy52dI= +github.com/launchdarkly/go-server-sdk/v6 v6.1.0/go.mod h1:3TfS6vNsNksPT4LGeGuGKtT3zTjTbbOsCUK3nrj1neA= +github.com/launchdarkly/go-test-helpers/v2 v2.2.0 h1:L3kGILP/6ewikhzhdNkHy1b5y4zs50LueWenVF0sBbs= +github.com/launchdarkly/go-test-helpers/v2 v2.2.0/go.mod h1:L7+th5govYp5oKU9iN7To5PgznBuIjBPn+ejqKR0avw= +github.com/launchdarkly/go-test-helpers/v3 v3.0.2 h1:rh0085g1rVJM5qIukdaQ8z1XTWZztbJ49vRZuveqiuU= +github.com/launchdarkly/go-test-helpers/v3 v3.0.2/go.mod h1:u2ZvJlc/DDJTFrshWW50tWMZHLVYXofuSHUfTU/eIwM= +github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= +github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= +github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= +github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/marusama/semaphore/v2 v2.5.0 h1:o/1QJD9DBYOWRnDhPwDVAXQn6mQYD0gZaS1Tpx6DJGM= +github.com/marusama/semaphore/v2 v2.5.0/go.mod h1:z9nMiNUekt/LTpTUQdpp+4sJeYqUGpwMHfW0Z8V8fnQ= +github.com/matryer/is v1.2.0 h1:92UTHpy8CDwaJ08GqLDzhhuixiBUUD1p3AU6PHddz4A= +github.com/matryer/is v1.2.0/go.mod h1:2fLPjFQM9rhQ15aVEtbuwhJinnOqrmgXPNdZsdwlWXA= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= 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-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU= -github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +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-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/mattn/go-sqlite3 v1.14.17 h1:mCRHCLDUBXgpKAqIKsaAaAsrAlbkeomtRFKXh2L6YIM= +github.com/mattn/go-sqlite3 v1.14.17/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= +github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= +github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= github.com/mholt/archiver v3.1.1+incompatible h1:1dCVxuqs0dJseYEhi5pl7MYPH9zDa1wBi7mF09cbNkU= github.com/mholt/archiver v3.1.1+incompatible/go.mod h1:Dh2dOXnSdiLxRiPoVfIr/fI1TwETms9B8CTWfeh7ROU= github.com/mholt/archiver/v3 v3.5.1 h1:rDjOBX9JSF5BvoJGvjqK479aL70qh9DIpZCl+k7Clwo= github.com/mholt/archiver/v3 v3.5.1/go.mod h1:e3dqJ7H78uzsRSEACH1joayhuSyhnonssnDhppzS1L4= +github.com/mholt/archiver/v4 v4.0.0-alpha.8 h1:tRGQuDVPh66WCOelqe6LIGh0gwmfwxUrSSDunscGsRM= +github.com/mholt/archiver/v4 v4.0.0-alpha.8/go.mod h1:5f7FUYGXdJWUjESffJaYR4R60VhnHxb2X3T1teMyv5A= +github.com/minio/asm2plan9s v0.0.0-20200509001527-cdd76441f9d8 h1:AMFGa4R4MiIpspGNG7Z948v4n35fFGB3RR3G/ry4FWs= +github.com/minio/asm2plan9s v0.0.0-20200509001527-cdd76441f9d8/go.mod h1:mC1jAcsrzbxHt8iiaC+zU4b1ylILSosueou12R++wfY= +github.com/minio/c2goasm v0.0.0-20190812172519-36a3d3bbc4f3 h1:+n/aFZefKZp7spd8DFdX7uMikMLXX4oubIzJF4kv/wI= +github.com/minio/c2goasm v0.0.0-20190812172519-36a3d3bbc4f3/go.mod h1:RagcQ7I8IeTMnF8JTXieKnO4Z6JCsikNEzj0DwauVzE= +github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0= github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/modocache/gover v0.0.0-20171022184752-b58185e213c5/go.mod h1:caMODM3PzxT8aQXRPkAt8xlV/e7d7w8GM5g0fa5F0D8= +github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc= +github.com/montanaflynn/stats v0.7.0 h1:r3y12KyNxj/Sb/iOE46ws+3mS1+MZca1wlHQFPsY/JU= +github.com/montanaflynn/stats v0.7.0/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow= +github.com/mtibben/percent v0.2.1 h1:5gssi8Nqo8QU/r2pynCm+hBQHpkB/uNK7BJCFogWdzs= +github.com/mtibben/percent v0.2.1/go.mod h1:KG9uO+SZkUp+VkRHsCdYQV3XSZrrSpR3O9ibNBTZrns= github.com/nicksnyder/go-i18n v1.10.1 h1:isfg77E/aCD7+0lD/D00ebR2MV5vgeQ276WYyDaCRQc= github.com/nicksnyder/go-i18n v1.10.1/go.mod h1:e4Di5xjP9oTVrC6y3C7C0HoSYXjSbhh/dU0eUV32nB4= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/nwaples/rardecode v1.1.0/go.mod h1:5DzqNKiOdpKKBH87u8VlvAnPZMXcGRhxWkRpHbbfGS0= github.com/nwaples/rardecode v1.1.2 h1:Cj0yZY6T1Zx1R7AhTbyGSALm44/Mmq+BAPc4B/p/d3M= github.com/nwaples/rardecode v1.1.2/go.mod h1:5DzqNKiOdpKKBH87u8VlvAnPZMXcGRhxWkRpHbbfGS0= +github.com/nwaples/rardecode/v2 v2.0.0-beta.2 h1:e3mzJFJs4k83GXBEiTaQ5HgSc/kOK8q0rDaRO0MPaOk= +github.com/nwaples/rardecode/v2 v2.0.0-beta.2/go.mod h1:yntwv/HfMc/Hbvtq9I19D1n58te3h6KsqCf3GxyfBGY= +github.com/nxadm/tail v1.4.11 h1:8feyoE3OzPrcshW5/MJ4sGESc5cqmGkGCWlco4l0bqY= +github.com/nxadm/tail v1.4.11/go.mod h1:OTaG3NK980DZzxbRq6lEuzgU+mug70nY11sMd4JXXHc= +github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= +github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= +github.com/onsi/gomega v1.23.0 h1:/oxKu9c2HVap+F3PfKort2Hw5DEU+HGlW8n+tguWsys= +github.com/onsi/gomega v1.23.0/go.mod h1:Z/NWtiqwBrwUt4/2loMmHL63EDLnYHmVbuBpDr2vQAg= +github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= +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-rc3 h1:fzg1mXZFj8YdPeNkRXMg+zb88BFV0Ys52cJydRwBkb8= +github.com/opencontainers/image-spec v1.1.0-rc3/go.mod h1:X4pATf0uXsnn3g5aiGIsVnJBR4mxhKzfwmvK/B2NTm8= github.com/otiai10/copy v1.14.0 h1:dCI/t1iTdYGtkvCuBG2BgR6KZa83PTclw4U5n2wAllU= github.com/otiai10/copy v1.14.0/go.mod h1:ECfuL02W+/FkTWZWgQqXPWZgW9oeKCSQ5qVfSc4qc4w= github.com/otiai10/mint v1.5.1 h1:XaPLeE+9vGbuyEHem1JNk3bYc7KKqyI/na0/mLd/Kks= github.com/otiai10/mint v1.5.1/go.mod h1:MJm72SBthJjz8qhefc4z1PYEieWmy8Bku7CjcAqyUSM= +github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= +github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= @@ -93,66 +544,440 @@ github.com/peterhellberg/link v1.1.0/go.mod h1:gtSlOT4jmkY8P47hbTc8PTgiDDWpdPbFY github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM= github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pierrec/lz4/v4 v4.1.2/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= -github.com/pierrec/lz4/v4 v4.1.8 h1:ieHkV+i2BRzngO4Wd/3HGowuZStgq6QkPsD1eolNAO4= -github.com/pierrec/lz4/v4 v4.1.8/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= -github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= +github.com/pierrec/lz4/v4 v4.1.17 h1:kV4Ip+/hUBC+8T6+2EgburRtkE9ef4nbY3f4dFhGjMc= +github.com/pierrec/lz4/v4 v4.1.17/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= +github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4= +github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8= +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/browser v0.0.0-20180916011732-0a3d74bf9ce4/go.mod h1:4OwLy04Bl9Ef3GJJCoec+30X3LQs/0/m4HFRt/2LUSA= +github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 h1:KoWmjvw+nsYOo29YJK9vDA65RGE3NrOnUtO7a+RF9HU= +github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI= +github.com/pkg/diff v0.0.0-20200914180035-5b29258ca4f7 h1:+/+DxvQaYifJ+grD4klzrS5y+KJXldn/2YTl5JG+vZ8= +github.com/pkg/diff v0.0.0-20200914180035-5b29258ca4f7/go.mod h1:zO8QMzTeZd5cpnIkz/Gn6iK0jDfGicM1nynOkkPIl28= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= +github.com/prometheus/client_golang v1.16.0 h1:yk/hx9hDbrGHovbci4BY+pRMfSuuat626eFsHb7tmT8= +github.com/prometheus/client_golang v1.16.0/go.mod h1:Zsulrv/L9oM40tJ7T815tM89lFEugiJ9HzIqaAx4LKc= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4= +github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= +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.10.1 h1:kYK1Va/YMlutzCGazswoHKo//tZVlFpKYh+PymziUAg= +github.com/prometheus/procfs v0.10.1/go.mod h1:nwNm2aOCAYw8uTR/9bWRREkZFxAUcWzPHWJq+XBB/FM= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +github.com/rivo/uniseg v0.4.2 h1:YwD0ulJSJytLpiaWua0sBDusfsCZohxjxzVTYjwxfV8= +github.com/rivo/uniseg v0.4.2/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= +github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= -github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8= -github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= +github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= +github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/rwcarlsen/goexif v0.0.0-20190401172101-9e8deecbddbd/go.mod h1:hPqNNc0+uJM6H+SuU8sEs5K5IQeKccPqeSjfgcKGgPk= github.com/sabhiram/go-gitignore v0.0.0-20210923224102-525f6e181f06 h1:OkMGxebDjyw0ULyrTYWeN0UNCCkmCWfjPnIA2W6oviI= github.com/sabhiram/go-gitignore v0.0.0-20210923224102-525f6e181f06/go.mod h1:+ePHsJ1keEjQtpvf9HHw0f4ZeJ0TLRsxhunSI2hYJSs= github.com/segmentio/textio v1.2.0 h1:Ug4IkV3kh72juJbG8azoSBlgebIbUUxVNrfFcKHfTSQ= github.com/segmentio/textio v1.2.0/go.mod h1:+Rb7v0YVODP+tK5F7FD9TCkV7gOYx9IgLHWiqtvY8ag= +github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= +github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8= +github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I= +github.com/sirupsen/logrus v1.7.0/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/skeema/knownhosts v1.2.0 h1:h9r9cf0+u7wSE+M183ZtMGgOJKiL96brpaz5ekfJCpM= +github.com/skeema/knownhosts v1.2.0/go.mod h1:g4fPeYpque7P0xefxtGzV81ihjC8sX2IqpAoNkjxbMo= +github.com/snowflakedb/gosnowflake v1.6.23 h1:uO+zMTXJcSHzOm6ks5To8ergNjt5Dy6cr5QtStpRFT8= +github.com/snowflakedb/gosnowflake v1.6.23/go.mod h1:KfO4F7bk+aXPUIvBqYxvPhxLlu2/w4TtSC8Rw/yr5Mg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.6.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= 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/tailscale/depaware v0.0.0-20210622194025-720c4b409502 h1:34icjjmqJ2HPjrSuJYEkdZ+0ItmGQAQ75cRHIiftIyE= +github.com/tailscale/depaware v0.0.0-20210622194025-720c4b409502/go.mod h1:p9lPsd+cx33L3H9nNoecRRxPssFKUwwI50I3pZ0yT+8= github.com/theckman/yacspin v0.13.12 h1:CdZ57+n0U6JMuh2xqjnjRq5Haj6v1ner2djtLQRzJr4= github.com/theckman/yacspin v0.13.12/go.mod h1:Rd2+oG2LmQi5f3zC3yeZAOl245z8QOvrH4OPOJNZxLg= +github.com/therootcompany/xz v1.0.1 h1:CmOtsn1CbtmyYiusbfmhmkpAAETj0wBIH6kCYaX+xzw= +github.com/therootcompany/xz v1.0.1/go.mod h1:3K3UH1yCKgBneZYhuQUvJ9HPD19UEXEI0BWbMn8qNMY= github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80 h1:nrZ3ySNYwJbSpD6ce9duiP+QkD3JuLCcWkdaehUS/3Y= github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80/go.mod h1:iFyPdL66DjUD96XmzVL3ZntbzcflLnznH0fr99w5VqE= +github.com/trufflesecurity/trufflehog/v3 v3.59.0 h1:nn1Iu0+Rlf6XQIT2R2Sbi4EeH1DHnCMLrm8VkxFQt/w= +github.com/trufflesecurity/trufflehog/v3 v3.59.0/go.mod h1:QLztXrk/khlbQda7ucq9cMzbFVvZxHBQnR/0V8dG7UI= github.com/ulikunitz/xz v0.5.8/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= github.com/ulikunitz/xz v0.5.9/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= github.com/ulikunitz/xz v0.5.10 h1:t92gobL9l3HE202wg3rlk19F6X+JOxl9BBrCCMYEYd8= github.com/ulikunitz/xz v0.5.10/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= +github.com/urfave/cli v1.22.12/go.mod h1:sSBEIC79qR6OvcmsD4U3KABeOTxDqQtdDnaFuUN30b8= +github.com/vbatts/tar-split v0.11.3 h1:hLFqsOLQ1SsppQNTMpkpPXClLDfC2A3Zgy9OUU+RVck= +github.com/vbatts/tar-split v0.11.3/go.mod h1:9QlHN18E+fEH7RdG+QAJJcuya3rqT7eXSTY7wGrAokY= +github.com/wsxiaoys/terminal v0.0.0-20160513160801-0940f3fc43a0 h1:3UeQBvD0TFrlVjOeLOBz+CPAI8dnbqNSVwUwRrkp7vQ= +github.com/wsxiaoys/terminal v0.0.0-20160513160801-0940f3fc43a0/go.mod h1:IXCdmsXIht47RaVFLEdVnh1t+pgYtTAhQGj73kz+2DM= +github.com/xanzy/go-gitlab v0.92.3 h1:bMtUHSV5BIhKeka6RyjLOOMZ31byVGDN5pGWmqBsIUs= +github.com/xanzy/go-gitlab v0.92.3/go.mod h1:5ryv+MnpZStBH8I/77HuQBsMbBGANtVpLWC15qOjWAw= +github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM= +github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw= +github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c= +github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= +github.com/xdg-go/scram v1.1.2 h1:FHX5I5B4i4hKRVRBCFRxq1iQRej7WO3hhBuJf+UUySY= +github.com/xdg-go/scram v1.1.2/go.mod h1:RT/sEzTbU5y00aCK8UOx6R7YryM0iF1N2MOmC3kKLN4= +github.com/xdg-go/stringprep v1.0.4 h1:XLI/Ng3O1Atzq0oBs3TWm+5ZVgkq2aqdlvP9JtoZ6c8= +github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM= github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 h1:nIPpBwaJSVYIxUFsDv3M8ofmx9yWTog9BfvIu0q41lo= github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8/go.mod h1:HUYIGzjTL3rfEspMxjDjgmT5uz5wzYJKVo23qUhYTos= +github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d h1:splanxYIlg+5LfHAM6xpdFEAYOk8iySO56hMFq6uLyA= +github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +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/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/xxh3 v1.0.2 h1:xZmwmqxHZA8AI603jOQ0tMqmBr9lPeFwGg6d+xy9DC0= +github.com/zeebo/xxh3 v1.0.2/go.mod h1:5NWz9Sef7zIDm2JHfFlcQvNekmcEl9ekUZQQKCYaDcA= +go.mongodb.org/mongo-driver v1.12.1 h1:nLkghSU8fQNaK7oUmDhQFsnrtcoNy7Z6LVFKsEecqgE= +go.mongodb.org/mongo-driver v1.12.1/go.mod h1:/rGBTebI3XYboVmgz+Wv3Bcbl3aD0QF9zl6kDDw18rQ= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= +go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= +go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= +go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= +go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= +go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI= +go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= +go.uber.org/mock v0.2.0 h1:TaP3xedm7JaAgScZO7tlvlKrqT0p7I6OsdGB5YNSMDU= +go.uber.org/mock v0.2.0/go.mod h1:J0y0rp9L3xiff1+ZBfKxlC1fz2+aO16tw0tsDOixfuM= +go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4= +go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= +go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60= +go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg= +go4.org v0.0.0-20200411211856-f5505b9728dd h1:BNJlw5kRTzdmyfh5U8F93HA2OwkP7ZGwA51eJ/0wKOU= +go4.org v0.0.0-20200411211856-f5505b9728dd/go.mod h1:CIiUVy99QCPfoE13bO4EZaz5GZMZXMSBGhxRdsvzbkg= +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-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-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220314234659-1baeb1ce4c0b/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= +golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= +golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= +golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= +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= +golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= +golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 h1:k/i9J1pBpvlfR+9QsetwPyERsqu1GIbi967PQMq3Ivc= golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w= +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= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= +golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc= golang.org/x/mod v0.12.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-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20210610132358-84b48f89b13b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= +golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= +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= +golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.12.0 h1:smVPGxink+n1ZI5pkQa8y6fZT0RW0MgCO5bFpepy4B4= +golang.org/x/oauth2 v0.12.0/go.mod h1:A74bZ3aGXgCY0qaIC9Ahg6Lglin4AMAco8cIv9baba4= +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= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +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-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210819135213-f52c844e1c1c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220906165534-d0df966e6959/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= golang.org/x/sys v0.13.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.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= +golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= +golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU= +golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= golang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek= golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= +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= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= +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/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= golang.org/x/text v0.13.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.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= +golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20201211185031-d93e913c1a58/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/tools v0.12.0 h1:YW6HUoUmYBpwSgyaGaZq1fHjrBjX1rlpZ54T6mu2kss= +golang.org/x/tools v0.12.0/go.mod h1:Sc0INKfu04TlqNoRA1hgpFZbhYXHPr4V5DzpSBTPqQM= +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= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk= +golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= +gonum.org/v1/gonum v0.11.0 h1:f1IJhK4Km5tBJmaiJXtk/PkL4cdVX6J+tGiM187uT5E= +gonum.org/v1/gonum v0.11.0/go.mod h1:fSG4YDCxxUZQJ7rKsQrj0gMOg00Il0Z96/qMA4bVQhA= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= +google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.132.0 h1:8t2/+qZ26kAOGSmOiHwVycqVaDg7q3JDILrNi/Z6rvc= +google.golang.org/api v0.132.0/go.mod h1:AeTBC6GpJnJSRJjktDcPX0QwtS8pGYZOV6MSuSCusw0= +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= +google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= +google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20230706204954-ccb25ca9f130 h1:Au6te5hbKUV8pIYWHqOUZ1pva5qK/rwbIhoXEUB9Lu8= +google.golang.org/genproto v0.0.0-20230706204954-ccb25ca9f130/go.mod h1:O9kGHb51iE/nOGvQaDUuadVYqovW56s5emA88lQnj6Y= +google.golang.org/genproto/googleapis/api v0.0.0-20230706204954-ccb25ca9f130 h1:XVeBY8d/FaK4848myy41HBqnDwvxeV3zMZhwN1TvAMU= +google.golang.org/genproto/googleapis/api v0.0.0-20230706204954-ccb25ca9f130/go.mod h1:mPBs5jNgx2GuQGvFwUvVKqtn6HsUw9nP64BedgvqEsQ= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98 h1:bVf09lpb+OJbByTj913DRJioFFAjf/ZGxEz7MajTp2U= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98/go.mod h1:TUfxEVdsvPg18p6AslUXFoLdpED4oBnGwyqk3dV1XzM= +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= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= +google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= +google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ= +google.golang.org/grpc v1.56.2 h1:fVRFRnXvU+x6C4IlHZewvJOVHoOv1TUuQyoRsYnB4bI= +google.golang.org/grpc v1.56.2/go.mod h1:I9bI3vqKfayGqPUAwGdOSu7kt6oIJLixfffKrpXqQ9s= +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= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= +google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= 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= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/h2non/gock.v1 v1.1.2 h1:jBbHXgGBK/AoPVfJh5x4r/WxIrElvbLel8TCZkkZJoY= +gopkg.in/h2non/gock.v1 v1.1.2/go.mod h1:n7UGz/ckNChHiK05rDoiC4MYSunEC/lyaUm2WWaDva0= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= +gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gotest.tools/v3 v3.0.3 h1:4AuOwCGf4lLR9u3YOe2awrHygurzhO/HeQ6laiA6Sx0= +gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= +sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= +sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= diff --git a/pkg/commands/compute/build.go b/pkg/commands/compute/build.go index 570c1e6f9..e8f70de6b 100644 --- a/pkg/commands/compute/build.go +++ b/pkg/commands/compute/build.go @@ -2,6 +2,7 @@ package compute import ( "bufio" + "bytes" "crypto/rand" "encoding/json" "errors" @@ -16,6 +17,10 @@ import ( "github.com/kennygrant/sanitize" "github.com/mholt/archiver/v3" + "github.com/trufflesecurity/trufflehog/v3/pkg/context" + "github.com/trufflesecurity/trufflehog/v3/pkg/detectors" + "github.com/trufflesecurity/trufflehog/v3/pkg/engine" + "github.com/trufflesecurity/trufflehog/v3/pkg/sources" "golang.org/x/text/cases" textlang "golang.org/x/text/language" @@ -240,6 +245,37 @@ func (c *BuildCommand) Exec(in io.Reader, out io.Writer) (err error) { }, } + // NOTE: To debug pass printer to Start() + // printer := new(output.JSONPrinter) + // engine.Start(ctx, engine.WithPrinter(printer)) + ctx := context.Background() + e, err := engine.Start( + ctx, + engine.WithConcurrency(uint8(runtime.NumCPU())), // prevent log output + ) + if err != nil { + return err + } + cfg := sources.FilesystemConfig{ + Paths: []string{manifest.Filename}, + } + if err = e.ScanFileSystem(ctx, cfg); err != nil { + return err + } + err = e.Finish(ctx) + if err != nil { + return err + } + metrics := e.GetMetrics() + fmt.Printf("metrics.VerifiedSecretsFound: %d\n", metrics.VerifiedSecretsFound) + fmt.Printf("metrics.UnverifiedSecretsFound: %d\n", metrics.UnverifiedSecretsFound) + var results []detectors.ResultWithMetadata + ch := e.ResultsChan() + for result := range ch { + fmt.Printf("result: %#v\n", result) + results = append(results, result) + } + filters := []string{ "GITHUB_TOKEN", "AWS_SECRET_ACCESS_KEY", @@ -282,6 +318,12 @@ func (c *BuildCommand) Exec(in io.Reader, out io.Writer) (err error) { return err } + fmt.Printf("%#v\n", "LOOP OVER RESULTS ARRAY POPULATED BY RANGING OVER CHANNEL") + for _, r := range results { + fmt.Printf("TO REDACT: %q | Verified: %t\n", r.Redacted, r.Verified) + data = bytes.ReplaceAll(data, []byte(r.Redacted), []byte("REDACTED")) + } + // FIXME: Once #1013 and #1016 merged, integrate granular disabling. args := []string{ "metadata", "add", "bin/main.wasm", From a0759aaecf506b84eb1bf6dcce96b0e4fd320357 Mon Sep 17 00:00:00 2001 From: Integralist Date: Fri, 13 Oct 2023 13:51:42 +0100 Subject: [PATCH 49/60] refactor(compute/build): clean-up debug log --- pkg/commands/compute/build.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/commands/compute/build.go b/pkg/commands/compute/build.go index e8f70de6b..bec11a171 100644 --- a/pkg/commands/compute/build.go +++ b/pkg/commands/compute/build.go @@ -318,7 +318,7 @@ func (c *BuildCommand) Exec(in io.Reader, out io.Writer) (err error) { return err } - fmt.Printf("%#v\n", "LOOP OVER RESULTS ARRAY POPULATED BY RANGING OVER CHANNEL") + fmt.Printf("results: %#v\n", results) for _, r := range results { fmt.Printf("TO REDACT: %q | Verified: %t\n", r.Redacted, r.Verified) data = bytes.ReplaceAll(data, []byte(r.Redacted), []byte("REDACTED")) From d55dde666cf791949b4ced7385f070be8687d643 Mon Sep 17 00:00:00 2001 From: Integralist Date: Fri, 13 Oct 2023 18:34:30 +0100 Subject: [PATCH 50/60] fix(compute/build): trufflehog --- pkg/commands/compute/build.go | 57 +++++++++++++++++++++++------------ 1 file changed, 37 insertions(+), 20 deletions(-) diff --git a/pkg/commands/compute/build.go b/pkg/commands/compute/build.go index bec11a171..4918ea098 100644 --- a/pkg/commands/compute/build.go +++ b/pkg/commands/compute/build.go @@ -13,6 +13,7 @@ import ( "path/filepath" "runtime" "strings" + "sync" "time" "github.com/kennygrant/sanitize" @@ -245,13 +246,17 @@ func (c *BuildCommand) Exec(in io.Reader, out io.Writer) (err error) { }, } - // NOTE: To debug pass printer to Start() - // printer := new(output.JSONPrinter) - // engine.Start(ctx, engine.WithPrinter(printer)) + // NOTE: There's an open issue (2023.10.13) with ResultsChan(). + // https://github.com/trufflesecurity/trufflehog/issues/1881 + // + // So as a workaround I have implemented a custom printer that tracks the + // results from trufflehog. + printer := new(SecretPrinter) ctx := context.Background() e, err := engine.Start( ctx, engine.WithConcurrency(uint8(runtime.NumCPU())), // prevent log output + engine.WithPrinter(printer), ) if err != nil { return err @@ -266,15 +271,6 @@ func (c *BuildCommand) Exec(in io.Reader, out io.Writer) (err error) { if err != nil { return err } - metrics := e.GetMetrics() - fmt.Printf("metrics.VerifiedSecretsFound: %d\n", metrics.VerifiedSecretsFound) - fmt.Printf("metrics.UnverifiedSecretsFound: %d\n", metrics.UnverifiedSecretsFound) - var results []detectors.ResultWithMetadata - ch := e.ResultsChan() - for result := range ch { - fmt.Printf("result: %#v\n", result) - results = append(results, result) - } filters := []string{ "GITHUB_TOKEN", @@ -307,7 +303,7 @@ func (c *BuildCommand) Exec(in io.Reader, out io.Writer) (err error) { if strings.HasPrefix(k, f) { dc.ScriptInfo.EnvVars[i] = k + "=REDACTED" if c.Globals.Verbose() { - text.Important(out, "The fastly.toml [scripts.env_vars] contains a possible security key '%s' so we've redacted it from the Wasm binary metadata annotation\n\n", k) + text.Important(out, "The fastly.toml [scripts.env_vars] contains a possible SECRET key '%s' so we've redacted it from the Wasm binary metadata annotation\n\n", k) } } } @@ -318,10 +314,11 @@ func (c *BuildCommand) Exec(in io.Reader, out io.Writer) (err error) { return err } - fmt.Printf("results: %#v\n", results) - for _, r := range results { - fmt.Printf("TO REDACT: %q | Verified: %t\n", r.Redacted, r.Verified) - data = bytes.ReplaceAll(data, []byte(r.Redacted), []byte("REDACTED")) + for _, r := range printer.Results { + data = bytes.ReplaceAll(data, []byte(r.Secret), []byte("REDACTED")) + if c.Globals.Verbose() { + text.Important(out, "The fastly.toml contains a possible SECRET value so we've redacted it from the Wasm binary metadata annotation\n\n") + } } // FIXME: Once #1013 and #1016 merged, integrate granular disabling. @@ -352,9 +349,7 @@ func (c *BuildCommand) Exec(in io.Reader, out io.Writer) (err error) { if err != nil { return fmt.Errorf("failed to execute wasm-tools metadata command: %w", err) } - text.Info(out, "Below is the metadata attached to the Wasm binary") - text.Break(out) - + text.Info(out, "\nBelow is the metadata attached to the Wasm binary\n\n") fmt.Fprintln(out, string(wasmtoolsOutput)) text.Break(out) } @@ -986,3 +981,25 @@ type DataCollectionScriptInfo struct { PostInitScript string `json:"post_init_script"` PostBuildScript string `json:"post_build_script"` } + +type Result struct { + Secret string + Verified bool +} + +// SecretPrinter tracks the results returned by trufflehog. +type SecretPrinter struct { + mu sync.Mutex + Results []Result +} + +// Print implements the trufflehog Printer interface. +func (p *SecretPrinter) Print(_ context.Context, r *detectors.ResultWithMetadata) error { + p.mu.Lock() + p.Results = append(p.Results, Result{ + Secret: string(r.Raw), + Verified: r.Verified, + }) + p.mu.Unlock() + return nil +} From 4015fa9f05364bfba92af46f64df9765d9736477 Mon Sep 17 00:00:00 2001 From: Integralist Date: Mon, 16 Oct 2023 10:02:18 +0100 Subject: [PATCH 51/60] fix(compute/build): only display secrets result once --- pkg/commands/compute/build.go | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/pkg/commands/compute/build.go b/pkg/commands/compute/build.go index 4918ea098..90ddccc6d 100644 --- a/pkg/commands/compute/build.go +++ b/pkg/commands/compute/build.go @@ -316,9 +316,16 @@ func (c *BuildCommand) Exec(in io.Reader, out io.Writer) (err error) { for _, r := range printer.Results { data = bytes.ReplaceAll(data, []byte(r.Secret), []byte("REDACTED")) - if c.Globals.Verbose() { - text.Important(out, "The fastly.toml contains a possible SECRET value so we've redacted it from the Wasm binary metadata annotation\n\n") + } + resultsLength := len(printer.Results) + if resultsLength > 0 && c.Globals.Verbose() { + var plural string + pronoun := "it" + if resultsLength > 1 { + plural = "s" + pronoun = "them" } + text.Important(out, "The fastly.toml might contain %d SECRET value%s, so we've redacted %s from the Wasm binary metadata annotation\n\n", resultsLength, plural, pronoun) } // FIXME: Once #1013 and #1016 merged, integrate granular disabling. From e4de2fdb38f2526bac6d2e9c0c4abd73782167e3 Mon Sep 17 00:00:00 2001 From: Integralist Date: Tue, 17 Oct 2023 13:18:17 +0100 Subject: [PATCH 52/60] doc(compute/build): annotate Result type --- pkg/commands/compute/build.go | 1 + 1 file changed, 1 insertion(+) diff --git a/pkg/commands/compute/build.go b/pkg/commands/compute/build.go index 90ddccc6d..b9c126bcb 100644 --- a/pkg/commands/compute/build.go +++ b/pkg/commands/compute/build.go @@ -989,6 +989,7 @@ type DataCollectionScriptInfo struct { PostBuildScript string `json:"post_build_script"` } +// Result represents an identified secret. type Result struct { Secret string Verified bool From 9293a10d377dbf0225947c0fb060149130c081aa Mon Sep 17 00:00:00 2001 From: Integralist Date: Tue, 17 Oct 2023 13:59:25 +0100 Subject: [PATCH 53/60] fix(compute/init): prevent runtime panic by removing duplicate flag --- pkg/commands/compute/init.go | 1 - 1 file changed, 1 deletion(-) diff --git a/pkg/commands/compute/init.go b/pkg/commands/compute/init.go index 33368ffd0..3055f0d88 100644 --- a/pkg/commands/compute/init.go +++ b/pkg/commands/compute/init.go @@ -57,7 +57,6 @@ func NewInitCommand(parent cmd.Registerer, g *global.Data, m manifest.Data) *Ini c.manifest = m c.CmdClause = parent.Command("init", "Initialize a new Compute package locally") - c.CmdClause.Flag("directory", "Destination to write the new package, defaulting to the current directory").Short('p').StringVar(&c.dir) c.CmdClause.Flag("author", "Author(s) of the package").Short('a').StringsVar(&c.manifest.File.Authors) c.CmdClause.Flag("branch", "Git branch name to clone from package template repository").Hidden().StringVar(&c.branch) c.CmdClause.Flag("directory", "Destination to write the new package, defaulting to the current directory").Short('p').StringVar(&c.dir) From 8a066359a5d41f84d5cbc8ae449fc0312ec60d10 Mon Sep 17 00:00:00 2001 From: Integralist Date: Wed, 18 Oct 2023 14:45:55 +0100 Subject: [PATCH 54/60] fix(compute): add ignore rules for new build flag to existing tests --- pkg/commands/compute/compute_test.go | 32 ++++++++++++++++++++++------ 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/pkg/commands/compute/compute_test.go b/pkg/commands/compute/compute_test.go index 9705b6b62..c86b4258b 100644 --- a/pkg/commands/compute/compute_test.go +++ b/pkg/commands/compute/compute_test.go @@ -152,14 +152,24 @@ func TestHashsumFlagDivergence(t *testing.T) { have = make(map[string]int) ) + // Some flags on `compute build` are unique to it. + ignoreBuildFlags := []string{ + "enable-metadata", + "filter-metadata-envvars", + "show-metadata", + } + iter := buildFlags.MapRange() for iter.Next() { - expect[iter.Key().String()] = 1 + flag := iter.Key().String() + if !ignoreFlag(ignoreBuildFlags, flag) { + expect[flag] = 1 + } } // Some flags on `compute hashsum` are unique to it. // We only want to be sure hashsum contains all build flags. - ignoreServeFlags := []string{ + ignoreHashsumFlags := []string{ "package", "skip-build", } @@ -167,7 +177,7 @@ func TestHashsumFlagDivergence(t *testing.T) { iter = hashsumFlags.MapRange() for iter.Next() { flag := iter.Key().String() - if !ignoreFlag(ignoreServeFlags, flag) { + if !ignoreFlag(ignoreHashsumFlags, flag) { have[flag] = 1 } } @@ -196,14 +206,24 @@ func TestHashfilesFlagDivergence(t *testing.T) { have = make(map[string]int) ) + // Some flags on `compute build` are unique to it. + ignoreBuildFlags := []string{ + "enable-metadata", + "filter-metadata-envvars", + "show-metadata", + } + iter := buildFlags.MapRange() for iter.Next() { - expect[iter.Key().String()] = 1 + flag := iter.Key().String() + if !ignoreFlag(ignoreBuildFlags, flag) { + expect[flag] = 1 + } } // Some flags on `compute hashsum` are unique to it. // We only want to be sure hashsum contains all build flags. - ignoreServeFlags := []string{ + ignoreHashfilesFlags := []string{ "package", "skip-build", } @@ -211,7 +231,7 @@ func TestHashfilesFlagDivergence(t *testing.T) { iter = hashfilesFlags.MapRange() for iter.Next() { flag := iter.Key().String() - if !ignoreFlag(ignoreServeFlags, flag) { + if !ignoreFlag(ignoreHashfilesFlags, flag) { have[flag] = 1 } } From f4be4580bad2caf18236a69b7d30b4c322d77381 Mon Sep 17 00:00:00 2001 From: Integralist Date: Wed, 25 Oct 2023 11:36:26 +0100 Subject: [PATCH 55/60] refactor(compute/build): clean-up annotation logic --- pkg/commands/compute/build.go | 393 +++++++++++++-------------- pkg/commands/compute/compute_test.go | 8 +- 2 files changed, 192 insertions(+), 209 deletions(-) diff --git a/pkg/commands/compute/build.go b/pkg/commands/compute/build.go index b9c126bcb..5a3f356b8 100644 --- a/pkg/commands/compute/build.go +++ b/pkg/commands/compute/build.go @@ -63,10 +63,10 @@ type Flags struct { // BuildCommand produces a deployable artifact from files on the local disk. type BuildCommand struct { cmd.Base - enableMetadata bool - filterEnvVars string - showMetadata bool - wasmtoolsVersioner github.AssetVersioner + metadataEnable bool + metadataFilterEnvVars string + metadataShow bool + wasmtoolsVersioner github.AssetVersioner // NOTE: these are public so that the "serve" and "publish" composite // commands can set the values appropriately before calling Exec(). @@ -87,13 +87,13 @@ func NewBuildCommand(parent cmd.Registerer, g *global.Data, wasmtoolsVersioner g c.CmdClause.Flag("env", "The manifest environment config to use (e.g. 'stage' will attempt to read 'fastly.stage.toml')").StringVar(&c.Flags.Env) c.CmdClause.Flag("include-source", "Include source code in built package").BoolVar(&c.Flags.IncludeSrc) c.CmdClause.Flag("language", "Language type").StringVar(&c.Flags.Lang) + c.CmdClause.Flag("metadata-show", "Inspect the Wasm binary metadata").BoolVar(&c.metadataShow) c.CmdClause.Flag("package-name", "Package name").StringVar(&c.Flags.PackageName) - c.CmdClause.Flag("show-metadata", "Use wasm-tools to inspect the Wasm binary metadata").BoolVar(&c.showMetadata) c.CmdClause.Flag("timeout", "Timeout, in seconds, for the build compilation step").IntVar(&c.Flags.Timeout) // Hidden - c.CmdClause.Flag("enable-metadata", "Feature flag to trial the Wasm binary metadata annotations").Hidden().BoolVar(&c.enableMetadata) - c.CmdClause.Flag("filter-metadata-envvars", "Redact specified environment variables from [scripts.env_vars] using comma-separated list").Hidden().StringVar(&c.filterEnvVars) + c.CmdClause.Flag("metadata-enable", "Feature flag to trial the Wasm binary metadata annotations").Hidden().BoolVar(&c.metadataEnable) + c.CmdClause.Flag("metadata-filter-envvars", "Redact specified environment variables from [scripts.env_vars] using comma-separated list").Hidden().StringVar(&c.metadataFilterEnvVars) return &c } @@ -206,159 +206,30 @@ func (c *BuildCommand) Exec(in io.Reader, out io.Writer) (err error) { return err } - languageTitle := cases.Title(textlang.English).String(language.Name) + metadataProcessedBy := fmt.Sprintf( + "--processed-by=fastly=%s (%s)", + revision.AppVersion, cases.Title(textlang.English).String(language.Name), + ) + metadataArgs := []string{ + "metadata", "add", "bin/main.wasm", metadataProcessedBy, + } // FIXME: When we remove feature flag, put in ability to disable metadata. - if !c.enableMetadata /*|| disableWasmMetadata*/ { - // NOTE: If not collecting metadata, just record the CLI version. - args := []string{ - "metadata", "add", "bin/main.wasm", - fmt.Sprintf("--processed-by=fastly=%s (%s)", revision.AppVersion, languageTitle), - } - err = c.Globals.ExecuteWasmTools(wasmtools, args) - if err != nil { + // e.g. define --metadata-disable and FASTlY_WASM_METADATA_DISABLE=true + // And check for those first, and if set, only annotate CLI version. + if c.metadataEnable { + if err := c.AnnotateWasmBinaryLong(wasmtools, metadataArgs, language, out); err != nil { return err } } else { - var ms runtime.MemStats - runtime.ReadMemStats(&ms) - - dc := DataCollection{ - BuildInfo: DataCollectionBuildInfo{ - MemoryHeapAlloc: ms.HeapAlloc, - }, - MachineInfo: DataCollectionMachineInfo{ - Arch: runtime.GOARCH, - CPUs: runtime.NumCPU(), - Compiler: runtime.Compiler, - GoVersion: runtime.Version(), - OS: runtime.GOOS, - }, - PackageInfo: DataCollectionPackageInfo{ - ClonedFrom: c.Globals.Manifest.File.ClonedFrom, - }, - ScriptInfo: DataCollectionScriptInfo{ - DefaultBuildUsed: language.DefaultBuildScript(), - BuildScript: c.Globals.Manifest.File.Scripts.Build, - EnvVars: c.Globals.Manifest.File.Scripts.EnvVars, - PostInitScript: c.Globals.Manifest.File.Scripts.PostInit, - PostBuildScript: c.Globals.Manifest.File.Scripts.PostBuild, - }, - } - - // NOTE: There's an open issue (2023.10.13) with ResultsChan(). - // https://github.com/trufflesecurity/trufflehog/issues/1881 - // - // So as a workaround I have implemented a custom printer that tracks the - // results from trufflehog. - printer := new(SecretPrinter) - ctx := context.Background() - e, err := engine.Start( - ctx, - engine.WithConcurrency(uint8(runtime.NumCPU())), // prevent log output - engine.WithPrinter(printer), - ) - if err != nil { - return err - } - cfg := sources.FilesystemConfig{ - Paths: []string{manifest.Filename}, - } - if err = e.ScanFileSystem(ctx, cfg); err != nil { - return err - } - err = e.Finish(ctx) - if err != nil { - return err - } - - filters := []string{ - "GITHUB_TOKEN", - "AWS_SECRET_ACCESS_KEY", - "AWS_SESSION_TOKEN", - "DOCKER_PASSWORD", - "VAULT_TOKEN", - } - - customFilters := strings.Split(c.filterEnvVars, ",") - for _, v := range customFilters { - if v == "" { - continue - } - var found bool - for _, f := range filters { - if f == v { - found = true - break - } - } - if !found { - filters = append(filters, v) - } - } - - for i, v := range dc.ScriptInfo.EnvVars { - for _, f := range filters { - k := strings.Split(v, "=")[0] - if strings.HasPrefix(k, f) { - dc.ScriptInfo.EnvVars[i] = k + "=REDACTED" - if c.Globals.Verbose() { - text.Important(out, "The fastly.toml [scripts.env_vars] contains a possible SECRET key '%s' so we've redacted it from the Wasm binary metadata annotation\n\n", k) - } - } - } - } - - data, err := json.Marshal(dc) - if err != nil { - return err - } - - for _, r := range printer.Results { - data = bytes.ReplaceAll(data, []byte(r.Secret), []byte("REDACTED")) - } - resultsLength := len(printer.Results) - if resultsLength > 0 && c.Globals.Verbose() { - var plural string - pronoun := "it" - if resultsLength > 1 { - plural = "s" - pronoun = "them" - } - text.Important(out, "The fastly.toml might contain %d SECRET value%s, so we've redacted %s from the Wasm binary metadata annotation\n\n", resultsLength, plural, pronoun) - } - - // FIXME: Once #1013 and #1016 merged, integrate granular disabling. - args := []string{ - "metadata", "add", "bin/main.wasm", - fmt.Sprintf("--processed-by=fastly=%s (%s)", revision.AppVersion, languageTitle), - fmt.Sprintf("--processed-by=fastly_data=%s", data), - } - - for k, v := range language.Dependencies() { - args = append(args, fmt.Sprintf("--sdk=%s=%s", k, v)) - } - - err = c.Globals.ExecuteWasmTools(wasmtools, args) - if err != nil { + if err := c.AnnotateWasmBinaryShort(wasmtools, metadataArgs); err != nil { return err } } - - if c.showMetadata { - // gosec flagged this: - // G204 (CWE-78): Subprocess launched with variable - // Disabling as the variables come from trusted sources. - // #nosec - // nosemgrep - command := exec.Command(wasmtools, "metadata", "show", "bin/main.wasm") - wasmtoolsOutput, err := command.Output() - if err != nil { - return fmt.Errorf("failed to execute wasm-tools metadata command: %w", err) + if c.metadataShow { + if err := c.ShowMetadata(wasmtools, out); err != nil { + return err } - text.Info(out, "\nBelow is the metadata attached to the Wasm binary\n\n") - fmt.Fprintln(out, string(wasmtoolsOutput)) - text.Break(out) } dest := filepath.Join("pkg", fmt.Sprintf("%s.tar.gz", pkgName)) @@ -439,10 +310,153 @@ func (c *BuildCommand) Exec(in io.Reader, out io.Writer) (err error) { out = originalOut text.Success(out, "\nBuilt package (%s)", dest) - // FIXME: Remove this notice in the CLI version 10.6.0 + // FIXME: Remove this notice in the CLI version 10.7.0 if !c.Globals.Flags.Quiet { - text.Important(out, "\nIn the next release (10.6.0), the Fastly CLI will collect data related to Wasm builds. If you have questions, comments or feedback, join the discussion at https://bit.ly/wasm-metadata") + text.Important(out, "\nIn the next release (10.7.0), the Fastly CLI will collect data related to Wasm builds. If you have questions, comments or feedback, join the discussion at https://bit.ly/wasm-metadata") + } + return nil +} + +// AnnotateWasmBinaryShort annotates the Wasm binary with only the CLI version. +func (c *BuildCommand) AnnotateWasmBinaryShort(wasmtools string, args []string) error { + return c.Globals.ExecuteWasmTools(wasmtools, args) +} + +// AnnotateWasmBinaryLong annotates the Wasm binary will all available data. +func (c *BuildCommand) AnnotateWasmBinaryLong(wasmtools string, args []string, language *Language, out io.Writer) error { + var ms runtime.MemStats + runtime.ReadMemStats(&ms) + + dc := DataCollection{ + BuildInfo: DataCollectionBuildInfo{ + MemoryHeapAlloc: ms.HeapAlloc, + }, + MachineInfo: DataCollectionMachineInfo{ + Arch: runtime.GOARCH, + CPUs: runtime.NumCPU(), + Compiler: runtime.Compiler, + GoVersion: runtime.Version(), + OS: runtime.GOOS, + }, + PackageInfo: DataCollectionPackageInfo{ + ClonedFrom: c.Globals.Manifest.File.ClonedFrom, + }, + ScriptInfo: DataCollectionScriptInfo{ + DefaultBuildUsed: language.DefaultBuildScript(), + BuildScript: c.Globals.Manifest.File.Scripts.Build, + EnvVars: c.Globals.Manifest.File.Scripts.EnvVars, + PostInitScript: c.Globals.Manifest.File.Scripts.PostInit, + PostBuildScript: c.Globals.Manifest.File.Scripts.PostBuild, + }, + } + + // NOTE: There's an open issue (2023.10.13) with ResultsChan(). + // https://github.com/trufflesecurity/trufflehog/issues/1881 + // As a workaround: I've implemented a custom printer to track results. + // + // IMPORTANT: This is a 'best effort' approach. + // We'll evaluate during the trial period and consider other approaches. + printer := new(SecretPrinter) + ctx := context.Background() + e, err := engine.Start( + ctx, + engine.WithConcurrency(uint8(runtime.NumCPU())), // prevent log output + engine.WithPrinter(printer), + ) + if err != nil { + return err + } + cfg := sources.FilesystemConfig{ + Paths: []string{manifest.Filename}, + } + if err = e.ScanFileSystem(ctx, cfg); err != nil { + return err + } + err = e.Finish(ctx) + if err != nil { + return err + } + + filters := []string{ + "GITHUB_TOKEN", + "AWS_SECRET_ACCESS_KEY", + "AWS_SESSION_TOKEN", + "DOCKER_PASSWORD", + "VAULT_TOKEN", + } + + customFilters := strings.Split(c.metadataFilterEnvVars, ",") + for _, v := range customFilters { + if v == "" { + continue + } + var found bool + for _, f := range filters { + if f == v { + found = true + break + } + } + if !found { + filters = append(filters, v) + } + } + + for i, v := range dc.ScriptInfo.EnvVars { + for _, f := range filters { + k := strings.Split(v, "=")[0] + if strings.HasPrefix(k, f) { + dc.ScriptInfo.EnvVars[i] = k + "=REDACTED" + if c.Globals.Verbose() { + text.Important(out, "The fastly.toml [scripts.env_vars] contains a possible SECRET key '%s' so we've redacted it from the Wasm binary metadata annotation\n\n", k) + } + } + } + } + + data, err := json.Marshal(dc) + if err != nil { + return err } + + for _, r := range printer.Results { + data = bytes.ReplaceAll(data, []byte(r.Secret), []byte("REDACTED")) + } + resultsLength := len(printer.Results) + if resultsLength > 0 && c.Globals.Verbose() { + var plural string + pronoun := "it" + if resultsLength > 1 { + plural = "s" + pronoun = "them" + } + text.Important(out, "The fastly.toml might contain %d SECRET value%s, so we've redacted %s from the Wasm binary metadata annotation\n\n", resultsLength, plural, pronoun) + } + + args = append(args, fmt.Sprintf("--processed-by=fastly_data=%s", data)) + + for k, v := range language.Dependencies() { + args = append(args, fmt.Sprintf("--sdk=%s=%s", k, v)) + } + + return c.Globals.ExecuteWasmTools(wasmtools, args) +} + +// ShowMetadata displays the metadata attached to the Wasm binary. +func (c *BuildCommand) ShowMetadata(wasmtools string, out io.Writer) error { + // gosec flagged this: + // G204 (CWE-78): Subprocess launched with variable + // Disabling as the variables come from trusted sources. + // #nosec + // nosemgrep + command := exec.Command(wasmtools, "metadata", "show", "bin/main.wasm") + wasmtoolsOutput, err := command.Output() + if err != nil { + return fmt.Errorf("failed to execute wasm-tools metadata command: %w", err) + } + text.Info(out, "\nBelow is the metadata attached to the Wasm binary\n\n") + fmt.Fprintln(out, string(wasmtoolsOutput)) + text.Break(out) return nil } @@ -609,37 +623,19 @@ func GetWasmTools(spinner text.Spinner, out io.Writer, wasmtoolsVersioner github } func installLatestWasmtools(binPath string, spinner text.Spinner, wasmtoolsVersioner github.AssetVersioner) error { - err := spinner.Start() - if err != nil { - return err - } - msg := "Fetching latest wasm-tools release" - spinner.Message(msg + "...") - - tmpBin, err := wasmtoolsVersioner.DownloadLatest() - if err != nil { - spinner.StopFailMessage(msg) - spinErr := spinner.StopFail() - if spinErr != nil { - return spinErr + return spinner.Process("Fetching latest wasm-tools release", func(_ *text.SpinnerWrapper) error { + tmpBin, err := wasmtoolsVersioner.DownloadLatest() + if err != nil { + return fmt.Errorf("failed to download latest wasm-tools release: %w", err) } - return fmt.Errorf("failed to download latest wasm-tools release: %w", err) - } - defer os.RemoveAll(tmpBin) - - if err := os.Rename(tmpBin, binPath); err != nil { - if err := filesystem.CopyFile(tmpBin, binPath); err != nil { - spinner.StopFailMessage(msg) - spinErr := spinner.StopFail() - if spinErr != nil { - return spinErr + defer os.RemoveAll(tmpBin) + if err := os.Rename(tmpBin, binPath); err != nil { + if err := filesystem.CopyFile(tmpBin, binPath); err != nil { + return fmt.Errorf("failed to move wasm-tools binary to accessible location: %w", err) } - return fmt.Errorf("failed to move wasm-tools binary to accessible location: %w", err) } - } - - spinner.StopMessage(msg) - return spinner.Stop() + return nil + }) } func updateWasmtools( @@ -661,29 +657,18 @@ func updateWasmtools( return nil } - err := spinner.Start() - if err != nil { - return err - } - msg := "Checking latest wasm-tools release" - spinner.Message(msg + "...") - - latestVersion, err := wasmtoolsVersioner.LatestVersion() - if err != nil { - spinner.StopFailMessage(msg) - spinErr := spinner.StopFail() - if spinErr != nil { - return spinErr - } - - return fsterr.RemediationError{ - Inner: fmt.Errorf("error fetching latest version: %w", err), - Remediation: fsterr.NetworkRemediation, + var latestVersion string + err := spinner.Process("Checking latest wasm-tools release", func(_ *text.SpinnerWrapper) error { + var err error + latestVersion, err = wasmtoolsVersioner.LatestVersion() + if err != nil { + return fsterr.RemediationError{ + Inner: fmt.Errorf("error fetching latest version: %w", err), + Remediation: fsterr.NetworkRemediation, + } } - } - - spinner.StopMessage(msg) - err = spinner.Stop() + return nil + }) if err != nil { return err } @@ -699,11 +684,9 @@ func updateWasmtools( if err != nil { return err } - if verbose { text.Info(out, "\nThe CLI config (`fastly config`) has been updated with the latest wasm-tools version: %s\n\n", latestVersion) } - if installedVersion == latestVersion { return nil } diff --git a/pkg/commands/compute/compute_test.go b/pkg/commands/compute/compute_test.go index c86b4258b..9e74714a7 100644 --- a/pkg/commands/compute/compute_test.go +++ b/pkg/commands/compute/compute_test.go @@ -38,8 +38,8 @@ func TestPublishFlagDivergence(t *testing.T) { // Some flags on `compute build` are unique to it. ignoreBuildFlags := []string{ - "enable-metadata", - "filter-metadata-envvars", + "metadata-enable", + "metadata-filter-envvars", "show-metadata", } @@ -92,8 +92,8 @@ func TestServeFlagDivergence(t *testing.T) { // Some flags on `compute build` are unique to it. ignoreBuildFlags := []string{ - "enable-metadata", - "filter-metadata-envvars", + "metadata-enable", + "metadata-filter-envvars", "show-metadata", } From 53db118eb5b57a394fb2a825ae0a4f93411c1a96 Mon Sep 17 00:00:00 2001 From: Integralist Date: Wed, 25 Oct 2023 13:25:08 +0100 Subject: [PATCH 56/60] feat(compute/build): better secret scrubbing --- pkg/commands/compute/build.go | 45 ++++++++++++++++++----------------- pkg/config/config.go | 9 +++++-- 2 files changed, 30 insertions(+), 24 deletions(-) diff --git a/pkg/commands/compute/build.go b/pkg/commands/compute/build.go index 5a3f356b8..204f14579 100644 --- a/pkg/commands/compute/build.go +++ b/pkg/commands/compute/build.go @@ -11,7 +11,9 @@ import ( "os" "os/exec" "path/filepath" + "regexp" "runtime" + "strconv" "strings" "sync" "time" @@ -214,10 +216,10 @@ func (c *BuildCommand) Exec(in io.Reader, out io.Writer) (err error) { "metadata", "add", "bin/main.wasm", metadataProcessedBy, } - // FIXME: When we remove feature flag, put in ability to disable metadata. - // e.g. define --metadata-disable and FASTlY_WASM_METADATA_DISABLE=true - // And check for those first, and if set, only annotate CLI version. - if c.metadataEnable { + // FIXME: For feature launch replace enable flag with disable equivalent. + // e.g. define --metadata-disable and check for that first with env var. + metadataDisable, _ := strconv.ParseBool(c.Globals.Env.WasmMetadataDisable) + if c.metadataEnable && !metadataDisable { if err := c.AnnotateWasmBinaryLong(wasmtools, metadataArgs, language, out); err != nil { return err } @@ -377,14 +379,19 @@ func (c *BuildCommand) AnnotateWasmBinaryLong(wasmtools string, args []string, l return err } + // Miscellaneous env vars. + // Most other variables should be caught by `filterPattern` below. filters := []string{ - "GITHUB_TOKEN", - "AWS_SECRET_ACCESS_KEY", - "AWS_SESSION_TOKEN", - "DOCKER_PASSWORD", - "VAULT_TOKEN", + "AZURE_CLIENT_ID", + "CI_JOB_JWT", + "CI_JOB_JWT_V2", + "FACEBOOK_APP_ID", + "MSI_ENDPOINT", + "OKTA_AUTHN_GROUPID", + "OKTA_OAUTH2_CLIENTID", } + // Allow customer to specify their own env variables to be filtered. customFilters := strings.Split(c.metadataFilterEnvVars, ",") for _, v := range customFilters { if v == "" { @@ -402,14 +409,13 @@ func (c *BuildCommand) AnnotateWasmBinaryLong(wasmtools string, args []string, l } } + // Filter environment variables using combination of user provided filters and + // the CLI hard-coded filters. for i, v := range dc.ScriptInfo.EnvVars { for _, f := range filters { k := strings.Split(v, "=")[0] if strings.HasPrefix(k, f) { dc.ScriptInfo.EnvVars[i] = k + "=REDACTED" - if c.Globals.Verbose() { - text.Important(out, "The fastly.toml [scripts.env_vars] contains a possible SECRET key '%s' so we've redacted it from the Wasm binary metadata annotation\n\n", k) - } } } } @@ -419,19 +425,14 @@ func (c *BuildCommand) AnnotateWasmBinaryLong(wasmtools string, args []string, l return err } + // Opt on the side of caution and filter anything that matches this pattern. + filterPattern := regexp.MustCompile(`(?i)_(?:API|CLIENTSECRET|CREDENTIALS|KEY|PASSWORD|SECRET|TOKEN)(?:[^=]+)?=\s?[^\s"]+`) + data = filterPattern.ReplaceAll(data, []byte("_REDACTED")) + + // Use TruffleHog last to hopefully catch any secret 'values'. for _, r := range printer.Results { data = bytes.ReplaceAll(data, []byte(r.Secret), []byte("REDACTED")) } - resultsLength := len(printer.Results) - if resultsLength > 0 && c.Globals.Verbose() { - var plural string - pronoun := "it" - if resultsLength > 1 { - plural = "s" - pronoun = "them" - } - text.Important(out, "The fastly.toml might contain %d SECRET value%s, so we've redacted %s from the Wasm binary metadata annotation\n\n", resultsLength, plural, pronoun) - } args = append(args, fmt.Sprintf("--processed-by=fastly_data=%s", data)) diff --git a/pkg/config/config.go b/pkg/config/config.go index 953bafdd0..144a6b5e4 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -393,8 +393,13 @@ func (f *File) Write(path string) error { // Environment represents all of the configuration parameters that can come // from environment variables. type Environment struct { - Token string - Endpoint string + // Token is the env var we look in for the Fastly API token. + Token string + // Endpoint is the env var we look in for the API endpoint. + Endpoint string + // WasmMetadataDisable is the env var we look in to disable all data + // collection related to a Wasm binary. + // Set to "true" to disable all forms of data collection. WasmMetadataDisable string } From ccb0ee358eb42a7b56531d4527bbfd9b7c8ab08a Mon Sep 17 00:00:00 2001 From: Integralist Date: Wed, 25 Oct 2023 15:24:01 +0100 Subject: [PATCH 57/60] fix: add missing metadata flags to composite commands --- pkg/commands/compute/build.go | 30 ++++++++++--------- pkg/commands/compute/compute_test.go | 44 ++++++++++------------------ pkg/commands/compute/hashfiles.go | 30 +++++++++++++++---- pkg/commands/compute/hashsum.go | 30 +++++++++++++++---- pkg/commands/compute/publish.go | 27 +++++++++++++---- pkg/commands/compute/serve.go | 27 +++++++++++++---- 6 files changed, 124 insertions(+), 64 deletions(-) diff --git a/pkg/commands/compute/build.go b/pkg/commands/compute/build.go index 204f14579..241c3b76a 100644 --- a/pkg/commands/compute/build.go +++ b/pkg/commands/compute/build.go @@ -65,14 +65,15 @@ type Flags struct { // BuildCommand produces a deployable artifact from files on the local disk. type BuildCommand struct { cmd.Base - metadataEnable bool - metadataFilterEnvVars string - metadataShow bool - wasmtoolsVersioner github.AssetVersioner - - // NOTE: these are public so that the "serve" and "publish" composite - // commands can set the values appropriately before calling Exec(). - Flags Flags + wasmtoolsVersioner github.AssetVersioner + + // NOTE: Composite commands require these build flags to be public. + // e.g. serve, publish, hashsum, hash-files + // This is so they can set values appropriately before calling Build.Exec(). + Flags Flags + MetadataEnable bool + MetadataFilterEnvVars string + MetadataShow bool } // NewBuildCommand returns a usable command registered under the parent. @@ -89,13 +90,13 @@ func NewBuildCommand(parent cmd.Registerer, g *global.Data, wasmtoolsVersioner g c.CmdClause.Flag("env", "The manifest environment config to use (e.g. 'stage' will attempt to read 'fastly.stage.toml')").StringVar(&c.Flags.Env) c.CmdClause.Flag("include-source", "Include source code in built package").BoolVar(&c.Flags.IncludeSrc) c.CmdClause.Flag("language", "Language type").StringVar(&c.Flags.Lang) - c.CmdClause.Flag("metadata-show", "Inspect the Wasm binary metadata").BoolVar(&c.metadataShow) + c.CmdClause.Flag("metadata-show", "Inspect the Wasm binary metadata").BoolVar(&c.MetadataShow) c.CmdClause.Flag("package-name", "Package name").StringVar(&c.Flags.PackageName) c.CmdClause.Flag("timeout", "Timeout, in seconds, for the build compilation step").IntVar(&c.Flags.Timeout) // Hidden - c.CmdClause.Flag("metadata-enable", "Feature flag to trial the Wasm binary metadata annotations").Hidden().BoolVar(&c.metadataEnable) - c.CmdClause.Flag("metadata-filter-envvars", "Redact specified environment variables from [scripts.env_vars] using comma-separated list").Hidden().StringVar(&c.metadataFilterEnvVars) + c.CmdClause.Flag("metadata-enable", "Feature flag to trial the Wasm binary metadata annotations").Hidden().BoolVar(&c.MetadataEnable) + c.CmdClause.Flag("metadata-filter-envvars", "Redact specified environment variables from [scripts.env_vars] using comma-separated list").Hidden().StringVar(&c.MetadataFilterEnvVars) return &c } @@ -218,8 +219,9 @@ func (c *BuildCommand) Exec(in io.Reader, out io.Writer) (err error) { // FIXME: For feature launch replace enable flag with disable equivalent. // e.g. define --metadata-disable and check for that first with env var. + // Also make sure hidden flags (across all composite commands) aren't hidden. metadataDisable, _ := strconv.ParseBool(c.Globals.Env.WasmMetadataDisable) - if c.metadataEnable && !metadataDisable { + if c.MetadataEnable && !metadataDisable { if err := c.AnnotateWasmBinaryLong(wasmtools, metadataArgs, language, out); err != nil { return err } @@ -228,7 +230,7 @@ func (c *BuildCommand) Exec(in io.Reader, out io.Writer) (err error) { return err } } - if c.metadataShow { + if c.MetadataShow { if err := c.ShowMetadata(wasmtools, out); err != nil { return err } @@ -392,7 +394,7 @@ func (c *BuildCommand) AnnotateWasmBinaryLong(wasmtools string, args []string, l } // Allow customer to specify their own env variables to be filtered. - customFilters := strings.Split(c.metadataFilterEnvVars, ",") + customFilters := strings.Split(c.MetadataFilterEnvVars, ",") for _, v := range customFilters { if v == "" { continue diff --git a/pkg/commands/compute/compute_test.go b/pkg/commands/compute/compute_test.go index 9e74714a7..a96f07cbe 100644 --- a/pkg/commands/compute/compute_test.go +++ b/pkg/commands/compute/compute_test.go @@ -15,10 +15,10 @@ import ( "github.com/fastly/cli/pkg/testutil" ) -// TestPublishFlagDivergence validates that the manually curated list of flags +// TestFlagDivergencePublish validates that the manually curated list of flags // within the `compute publish` command doesn't fall out of sync with the // `compute build` and `compute deploy` commands from which publish is composed. -func TestPublishFlagDivergence(t *testing.T) { +func TestFlagDivergencePublish(t *testing.T) { var g global.Data acmd := kingpin.New("foo", "bar") @@ -37,11 +37,8 @@ func TestPublishFlagDivergence(t *testing.T) { ) // Some flags on `compute build` are unique to it. - ignoreBuildFlags := []string{ - "metadata-enable", - "metadata-filter-envvars", - "show-metadata", - } + // NOTE: There are no flags to ignore but I'm keeping the logic for future. + ignoreBuildFlags := []string{} iter := buildFlags.MapRange() for iter.Next() { @@ -66,10 +63,10 @@ func TestPublishFlagDivergence(t *testing.T) { } } -// TestServeFlagDivergence validates that the manually curated list of flags +// TestFlagDivergenceServe validates that the manually curated list of flags // within the `compute serve` command doesn't fall out of sync with the // `compute build` command as `compute serve` delegates to build. -func TestServeFlagDivergence(t *testing.T) { +func TestFlagDivergenceServe(t *testing.T) { var cfg global.Data versioner := github.New(github.Opts{ Org: "fastly", @@ -91,11 +88,8 @@ func TestServeFlagDivergence(t *testing.T) { ) // Some flags on `compute build` are unique to it. - ignoreBuildFlags := []string{ - "metadata-enable", - "metadata-filter-envvars", - "show-metadata", - } + // NOTE: There are no flags to ignore but I'm keeping the logic for future. + ignoreBuildFlags := []string{} iter := buildFlags.MapRange() for iter.Next() { @@ -133,10 +127,10 @@ func TestServeFlagDivergence(t *testing.T) { } } -// TestHashsumFlagDivergence validates that the manually curated list of flags +// TestFlagDivergenceHashSum validates that the manually curated list of flags // within the `compute hashsum` command doesn't fall out of sync with the // `compute build` command as `compute hashsum` delegates to build. -func TestHashsumFlagDivergence(t *testing.T) { +func TestFlagDivergenceHashSum(t *testing.T) { var cfg global.Data acmd := kingpin.New("foo", "bar") @@ -153,11 +147,8 @@ func TestHashsumFlagDivergence(t *testing.T) { ) // Some flags on `compute build` are unique to it. - ignoreBuildFlags := []string{ - "enable-metadata", - "filter-metadata-envvars", - "show-metadata", - } + // NOTE: There are no flags to ignore but I'm keeping the logic for future. + ignoreBuildFlags := []string{} iter := buildFlags.MapRange() for iter.Next() { @@ -187,10 +178,10 @@ func TestHashsumFlagDivergence(t *testing.T) { } } -// TestHashfilesFlagDivergence validates that the manually curated list of flags +// TestFlagDivergenceHashFiles validates that the manually curated list of flags // within the `compute hashsum` command doesn't fall out of sync with the // `compute build` command as `compute hashsum` delegates to build. -func TestHashfilesFlagDivergence(t *testing.T) { +func TestFlagDivergenceHashFiles(t *testing.T) { var cfg global.Data acmd := kingpin.New("foo", "bar") @@ -207,11 +198,8 @@ func TestHashfilesFlagDivergence(t *testing.T) { ) // Some flags on `compute build` are unique to it. - ignoreBuildFlags := []string{ - "enable-metadata", - "filter-metadata-envvars", - "show-metadata", - } + // NOTE: There are no flags to ignore but I'm keeping the logic for future. + ignoreBuildFlags := []string{} iter := buildFlags.MapRange() for iter.Next() { diff --git a/pkg/commands/compute/hashfiles.go b/pkg/commands/compute/hashfiles.go index 2c2a7cdcd..39cb4a143 100644 --- a/pkg/commands/compute/hashfiles.go +++ b/pkg/commands/compute/hashfiles.go @@ -33,12 +33,15 @@ type HashFilesCommand struct { cmd.Base // Build fields - dir cmd.OptionalString - env cmd.OptionalString - includeSrc cmd.OptionalBool - lang cmd.OptionalString - packageName cmd.OptionalString - timeout cmd.OptionalInt + dir cmd.OptionalString + env cmd.OptionalString + includeSrc cmd.OptionalBool + lang cmd.OptionalString + metadataEnable cmd.OptionalBool + metadataFilterEnvVars cmd.OptionalString + metadataShow cmd.OptionalBool + packageName cmd.OptionalString + timeout cmd.OptionalInt buildCmd *BuildCommand Package string @@ -55,10 +58,16 @@ func NewHashFilesCommand(parent cmd.Registerer, g *global.Data, build *BuildComm c.CmdClause.Flag("env", "The manifest environment config to use (e.g. 'stage' will attempt to read 'fastly.stage.toml')").Action(c.env.Set).StringVar(&c.env.Value) c.CmdClause.Flag("include-source", "Include source code in built package").Action(c.includeSrc.Set).BoolVar(&c.includeSrc.Value) c.CmdClause.Flag("language", "Language type").Action(c.lang.Set).StringVar(&c.lang.Value) + c.CmdClause.Flag("metadata-show", "Inspect the Wasm binary metadata").Action(c.metadataShow.Set).BoolVar(&c.metadataShow.Value) c.CmdClause.Flag("package", "Path to a package tar.gz").Short('p').StringVar(&c.Package) c.CmdClause.Flag("package-name", "Package name").Action(c.packageName.Set).StringVar(&c.packageName.Value) c.CmdClause.Flag("skip-build", "Skip the build step").BoolVar(&c.SkipBuild) c.CmdClause.Flag("timeout", "Timeout, in seconds, for the build compilation step").Action(c.timeout.Set).IntVar(&c.timeout.Value) + + // Hidden + c.CmdClause.Flag("metadata-enable", "Feature flag to trial the Wasm binary metadata annotations").Hidden().Action(c.metadataEnable.Set).BoolVar(&c.metadataEnable.Value) + c.CmdClause.Flag("metadata-filter-envvars", "Redact specified environment variables from [scripts.env_vars] using comma-separated list").Hidden().Action(c.metadataFilterEnvVars.Set).StringVar(&c.metadataFilterEnvVars.Value) + return &c } @@ -154,6 +163,15 @@ func (c *HashFilesCommand) Build(in io.Reader, out io.Writer) error { if c.timeout.WasSet { c.buildCmd.Flags.Timeout = c.timeout.Value } + if c.metadataEnable.WasSet { + c.buildCmd.MetadataEnable = c.metadataEnable.Value + } + if c.metadataFilterEnvVars.WasSet { + c.buildCmd.MetadataFilterEnvVars = c.metadataFilterEnvVars.Value + } + if c.metadataShow.WasSet { + c.buildCmd.MetadataShow = c.metadataShow.Value + } return c.buildCmd.Exec(in, output) } diff --git a/pkg/commands/compute/hashsum.go b/pkg/commands/compute/hashsum.go index cc9292a59..079f884cf 100644 --- a/pkg/commands/compute/hashsum.go +++ b/pkg/commands/compute/hashsum.go @@ -22,12 +22,15 @@ type HashsumCommand struct { cmd.Base // Build fields - dir cmd.OptionalString - env cmd.OptionalString - includeSrc cmd.OptionalBool - lang cmd.OptionalString - packageName cmd.OptionalString - timeout cmd.OptionalInt + dir cmd.OptionalString + env cmd.OptionalString + includeSrc cmd.OptionalBool + lang cmd.OptionalString + metadataEnable cmd.OptionalBool + metadataFilterEnvVars cmd.OptionalString + metadataShow cmd.OptionalBool + packageName cmd.OptionalString + timeout cmd.OptionalInt buildCmd *BuildCommand PackagePath string @@ -45,10 +48,16 @@ func NewHashsumCommand(parent cmd.Registerer, g *global.Data, build *BuildComman c.CmdClause.Flag("env", "The manifest environment config to use (e.g. 'stage' will attempt to read 'fastly.stage.toml')").Action(c.env.Set).StringVar(&c.env.Value) c.CmdClause.Flag("include-source", "Include source code in built package").Action(c.includeSrc.Set).BoolVar(&c.includeSrc.Value) c.CmdClause.Flag("language", "Language type").Action(c.lang.Set).StringVar(&c.lang.Value) + c.CmdClause.Flag("metadata-show", "Inspect the Wasm binary metadata").Action(c.metadataShow.Set).BoolVar(&c.metadataShow.Value) c.CmdClause.Flag("package", "Path to a package tar.gz").Short('p').StringVar(&c.PackagePath) c.CmdClause.Flag("package-name", "Package name").Action(c.packageName.Set).StringVar(&c.packageName.Value) c.CmdClause.Flag("skip-build", "Skip the build step").BoolVar(&c.SkipBuild) c.CmdClause.Flag("timeout", "Timeout, in seconds, for the build compilation step").Action(c.timeout.Set).IntVar(&c.timeout.Value) + + // Hidden + c.CmdClause.Flag("metadata-enable", "Feature flag to trial the Wasm binary metadata annotations").Hidden().Action(c.metadataEnable.Set).BoolVar(&c.metadataEnable.Value) + c.CmdClause.Flag("metadata-filter-envvars", "Redact specified environment variables from [scripts.env_vars] using comma-separated list").Hidden().Action(c.metadataFilterEnvVars.Set).StringVar(&c.metadataFilterEnvVars.Value) + return &c } @@ -157,6 +166,15 @@ func (c *HashsumCommand) Build(in io.Reader, out io.Writer) error { if c.timeout.WasSet { c.buildCmd.Flags.Timeout = c.timeout.Value } + if c.metadataEnable.WasSet { + c.buildCmd.MetadataEnable = c.metadataEnable.Value + } + if c.metadataFilterEnvVars.WasSet { + c.buildCmd.MetadataFilterEnvVars = c.metadataFilterEnvVars.Value + } + if c.metadataShow.WasSet { + c.buildCmd.MetadataShow = c.metadataShow.Value + } return c.buildCmd.Exec(in, output) } diff --git a/pkg/commands/compute/publish.go b/pkg/commands/compute/publish.go index 9434db38c..146092f3a 100644 --- a/pkg/commands/compute/publish.go +++ b/pkg/commands/compute/publish.go @@ -17,11 +17,14 @@ type PublishCommand struct { deploy *DeployCommand // Build fields - dir cmd.OptionalString - includeSrc cmd.OptionalBool - lang cmd.OptionalString - packageName cmd.OptionalString - timeout cmd.OptionalInt + dir cmd.OptionalString + includeSrc cmd.OptionalBool + lang cmd.OptionalString + metadataEnable cmd.OptionalBool + metadataFilterEnvVars cmd.OptionalString + metadataShow cmd.OptionalBool + packageName cmd.OptionalString + timeout cmd.OptionalInt // Deploy fields comment cmd.OptionalString @@ -50,6 +53,7 @@ func NewPublishCommand(parent cmd.Registerer, g *global.Data, build *BuildComman c.CmdClause.Flag("env", "The manifest environment config to use (e.g. 'stage' will attempt to read 'fastly.stage.toml')").Action(c.env.Set).StringVar(&c.env.Value) c.CmdClause.Flag("include-source", "Include source code in built package").Action(c.includeSrc.Set).BoolVar(&c.includeSrc.Value) c.CmdClause.Flag("language", "Language type").Action(c.lang.Set).StringVar(&c.lang.Value) + c.CmdClause.Flag("metadata-show", "Inspect the Wasm binary metadata").Action(c.metadataShow.Set).BoolVar(&c.metadataShow.Value) c.CmdClause.Flag("package", "Path to a package tar.gz").Short('p').Action(c.pkg.Set).StringVar(&c.pkg.Value) c.CmdClause.Flag("package-name", "Package name").Action(c.packageName.Set).StringVar(&c.packageName.Value) c.RegisterFlag(cmd.StringFlagOpts{ @@ -76,6 +80,10 @@ func NewPublishCommand(parent cmd.Registerer, g *global.Data, build *BuildComman }) c.CmdClause.Flag("timeout", "Timeout, in seconds, for the build compilation step").Action(c.timeout.Set).IntVar(&c.timeout.Value) + // Hidden + c.CmdClause.Flag("metadata-enable", "Feature flag to trial the Wasm binary metadata annotations").Hidden().Action(c.metadataEnable.Set).BoolVar(&c.metadataEnable.Value) + c.CmdClause.Flag("metadata-filter-envvars", "Redact specified environment variables from [scripts.env_vars] using comma-separated list").Hidden().Action(c.metadataFilterEnvVars.Set).StringVar(&c.metadataFilterEnvVars.Value) + return &c } @@ -106,6 +114,15 @@ func (c *PublishCommand) Exec(in io.Reader, out io.Writer) (err error) { if c.timeout.WasSet { c.build.Flags.Timeout = c.timeout.Value } + if c.metadataEnable.WasSet { + c.build.MetadataEnable = c.metadataEnable.Value + } + if c.metadataFilterEnvVars.WasSet { + c.build.MetadataFilterEnvVars = c.metadataFilterEnvVars.Value + } + if c.metadataShow.WasSet { + c.build.MetadataShow = c.metadataShow.Value + } err = c.build.Exec(in, out) if err != nil { diff --git a/pkg/commands/compute/serve.go b/pkg/commands/compute/serve.go index 5ae7dcfd3..7c5e814cb 100644 --- a/pkg/commands/compute/serve.go +++ b/pkg/commands/compute/serve.go @@ -46,11 +46,14 @@ type ServeCommand struct { viceroyVersioner github.AssetVersioner // Build fields - dir cmd.OptionalString - includeSrc cmd.OptionalBool - lang cmd.OptionalString - packageName cmd.OptionalString - timeout cmd.OptionalInt + dir cmd.OptionalString + includeSrc cmd.OptionalBool + lang cmd.OptionalString + metadataEnable cmd.OptionalBool + metadataFilterEnvVars cmd.OptionalString + metadataShow cmd.OptionalBool + packageName cmd.OptionalString + timeout cmd.OptionalInt // Serve fields addr string @@ -83,6 +86,7 @@ func NewServeCommand(parent cmd.Registerer, g *global.Data, build *BuildCommand, c.CmdClause.Flag("file", "The Wasm file to run").Default("bin/main.wasm").StringVar(&c.file) c.CmdClause.Flag("include-source", "Include source code in built package").Action(c.includeSrc.Set).BoolVar(&c.includeSrc.Value) c.CmdClause.Flag("language", "Language type").Action(c.lang.Set).StringVar(&c.lang.Value) + c.CmdClause.Flag("metadata-show", "Inspect the Wasm binary metadata").Action(c.metadataShow.Set).BoolVar(&c.metadataShow.Value) c.CmdClause.Flag("package-name", "Package name").Action(c.packageName.Set).StringVar(&c.packageName.Value) c.CmdClause.Flag("profile-guest", "Profile the Wasm guest under Viceroy (requires Viceroy 0.9.1 or higher). View profiles at https://profiler.firefox.com/.").BoolVar(&c.profileGuest) c.CmdClause.Flag("profile-guest-dir", "The directory where the per-request profiles are saved to. Defaults to guest-profiles.").Action(c.profileGuestDir.Set).StringVar(&c.profileGuestDir.Value) @@ -93,6 +97,10 @@ func NewServeCommand(parent cmd.Registerer, g *global.Data, build *BuildCommand, c.CmdClause.Flag("watch", "Watch for file changes, then rebuild project and restart local server").BoolVar(&c.watch) c.CmdClause.Flag("watch-dir", "The directory to watch files from (can be relative or absolute). Defaults to current directory.").Action(c.watchDir.Set).StringVar(&c.watchDir.Value) + // Hidden + c.CmdClause.Flag("metadata-enable", "Feature flag to trial the Wasm binary metadata annotations").Hidden().Action(c.metadataEnable.Set).BoolVar(&c.metadataEnable.Value) + c.CmdClause.Flag("metadata-filter-envvars", "Redact specified environment variables from [scripts.env_vars] using comma-separated list").Hidden().Action(c.metadataFilterEnvVars.Set).StringVar(&c.metadataFilterEnvVars.Value) + return &c } @@ -252,6 +260,15 @@ func (c *ServeCommand) Build(in io.Reader, out io.Writer) error { if c.timeout.WasSet { c.build.Flags.Timeout = c.timeout.Value } + if c.metadataEnable.WasSet { + c.build.MetadataEnable = c.metadataEnable.Value + } + if c.metadataFilterEnvVars.WasSet { + c.build.MetadataFilterEnvVars = c.metadataFilterEnvVars.Value + } + if c.metadataShow.WasSet { + c.build.MetadataShow = c.metadataShow.Value + } err := c.build.Exec(in, out) if err != nil { From 1099ab19b42b165265a3aef99734374bff3f58f9 Mon Sep 17 00:00:00 2001 From: Integralist Date: Wed, 25 Oct 2023 15:36:48 +0100 Subject: [PATCH 58/60] fix(compute/hashsum): pass correct variable --- pkg/commands/compute/hashsum.go | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/pkg/commands/compute/hashsum.go b/pkg/commands/compute/hashsum.go index 079f884cf..41ff85f41 100644 --- a/pkg/commands/compute/hashsum.go +++ b/pkg/commands/compute/hashsum.go @@ -66,9 +66,6 @@ func (c *HashsumCommand) Exec(in io.Reader, out io.Writer) (err error) { if !c.Globals.Flags.Quiet { // FIXME: Remove `hashsum` subcommand before v11.0.0 is released. text.Warning(out, "This command is deprecated. Use `fastly compute hash-files` instead.") - if c.Globals.Verbose() || c.SkipBuild { - text.Break(out) - } } // No point in building a package if the user provides a package path. @@ -77,7 +74,9 @@ func (c *HashsumCommand) Exec(in io.Reader, out io.Writer) (err error) { if err != nil { return err } - text.Break(out) + if !c.Globals.Flags.Quiet { + text.Break(out) + } } pkgPath := c.PackagePath @@ -133,7 +132,7 @@ func (c *HashsumCommand) Exec(in io.Reader, out io.Writer) (err error) { } } - hashSum, err := getHashSum(c.PackagePath) + hashSum, err := getHashSum(pkgPath) if err != nil { return err } @@ -145,8 +144,10 @@ func (c *HashsumCommand) Exec(in io.Reader, out io.Writer) (err error) { // Build constructs and executes the build logic. func (c *HashsumCommand) Build(in io.Reader, out io.Writer) error { output := out - if !c.Globals.Verbose() { + if !c.Globals.Verbose() && !c.metadataShow.WasSet { output = io.Discard + } else { + text.Break(out) } if c.dir.WasSet { c.buildCmd.Flags.Dir = c.dir.Value From 16095fe1af5ba5ce12ce8de8598368aa74d4373d Mon Sep 17 00:00:00 2001 From: Integralist Date: Tue, 31 Oct 2023 16:14:53 +0000 Subject: [PATCH 59/60] fix: correct main package after bad rebase --- cmd/fastly/main.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/cmd/fastly/main.go b/cmd/fastly/main.go index 3d5ad1054..6b8c62cb6 100644 --- a/cmd/fastly/main.go +++ b/cmd/fastly/main.go @@ -85,8 +85,11 @@ func main() { // The `main` function is a shim for calling `app.Run()`. err = app.Run(app.RunOpts{ - APIClient: func(token, endpoint string) (api.Interface, error) { + APIClient: func(token, endpoint string, debugMode bool) (api.Interface, error) { client, err := fastly.NewClientForEndpoint(token, endpoint) + if debugMode { + client.DebugMode = true + } return client, err }, Args: args, From 64c2230a7de5768724fb00a8a7fa2e412fd7f2a5 Mon Sep 17 00:00:00 2001 From: Integralist Date: Tue, 31 Oct 2023 16:42:20 +0000 Subject: [PATCH 60/60] fix(compute/build): avoid empty config value --- pkg/commands/compute/build.go | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/pkg/commands/compute/build.go b/pkg/commands/compute/build.go index 241c3b76a..c10f8c0b4 100644 --- a/pkg/commands/compute/build.go +++ b/pkg/commands/compute/build.go @@ -609,7 +609,7 @@ func GetWasmTools(spinner text.Spinner, out io.Writer, wasmtoolsVersioner github } if installedVersion != "" { - err = updateWasmtools(binPath, spinner, out, wasmtoolsVersioner, g.Verbose(), installedVersion, g.Config.WasmTools, g.Config, g.ConfigPath) + err = updateWasmtools(binPath, spinner, out, wasmtoolsVersioner, g.Verbose(), installedVersion, g.Config, g.ConfigPath) if err != nil { g.ErrLog.Add(err) return binPath, err @@ -648,12 +648,17 @@ func updateWasmtools( wasmtoolsVersioner github.AssetVersioner, verbose bool, installedVersion string, - wasmtoolsConfig config.Versioner, cfg config.File, cfgPath string, ) error { - stale := wasmtoolsConfig.LastChecked != "" && wasmtoolsConfig.LatestVersion != "" && check.Stale(wasmtoolsConfig.LastChecked, wasmtoolsConfig.TTL) - if !stale { + // NOTE: We shouldn't see LastChecked with no value if wasm-tools installed. + if cfg.WasmTools.LastChecked == "" { + cfg.WasmTools.LastChecked = time.Now().Format(time.RFC3339) + if err := cfg.Write(cfgPath); err != nil { + return err + } + } + if !check.Stale(cfg.WasmTools.LastChecked, cfg.WasmTools.TTL) { if verbose { text.Info(out, "\nwasm-tools is installed but the CLI config (`fastly config`) shows the TTL, checking for a newer version, hasn't expired.\n\n") } @@ -676,12 +681,8 @@ func updateWasmtools( return err } - wasmtoolsConfig.LatestVersion = latestVersion - wasmtoolsConfig.LastChecked = time.Now().Format(time.RFC3339) - - // Before attempting to write the config data back to disk we need to - // ensure we reassign the modified struct which is a copy (not reference). - cfg.WasmTools = wasmtoolsConfig + cfg.WasmTools.LatestVersion = latestVersion + cfg.WasmTools.LastChecked = time.Now().Format(time.RFC3339) err = cfg.Write(cfgPath) if err != nil {