From 924ceea9b78a2d739edacee00e8fe7dbafd0d00e Mon Sep 17 00:00:00 2001 From: Emily McMullan Date: Tue, 3 Sep 2024 09:42:15 -0400 Subject: [PATCH 1/3] containerless support for java Signed-off-by: Emily McMullan --- cmd/analyze-bin.go | 842 ++++++++++++++++++++++++++++++++++++++++++ cmd/analyze.go | 99 +---- cmd/root.go | 1 + cmd/settings.go | 10 - cmd/static-report.go | 121 ++++++ cmd/util.go | 104 ++++++ cmd/version.go | 11 +- docs/containerless.md | 19 + go.mod | 27 +- go.sum | 75 +++- static-report.sh | 19 + 11 files changed, 1214 insertions(+), 114 deletions(-) create mode 100644 cmd/analyze-bin.go create mode 100644 cmd/static-report.go create mode 100644 cmd/util.go create mode 100644 docs/containerless.md create mode 100755 static-report.sh diff --git a/cmd/analyze-bin.go b/cmd/analyze-bin.go new file mode 100644 index 0000000..f9a21a0 --- /dev/null +++ b/cmd/analyze-bin.go @@ -0,0 +1,842 @@ +package cmd + +import ( + "bytes" + "context" + "encoding/json" + "errors" + "fmt" + "io" + "log" + "os" + "os/exec" + "path" + "path/filepath" + "runtime" + "sort" + "strings" + "sync" + + "github.com/bombsimon/logrusr/v3" + "github.com/go-logr/logr" + "github.com/konveyor/analyzer-lsp/engine" + "github.com/konveyor/analyzer-lsp/engine/labels" + java "github.com/konveyor/analyzer-lsp/external-providers/java-external-provider/pkg/java_external_provider" + "github.com/konveyor/analyzer-lsp/output/v1/konveyor" + outputv1 "github.com/konveyor/analyzer-lsp/output/v1/konveyor" + "github.com/konveyor/analyzer-lsp/parser" + "github.com/konveyor/analyzer-lsp/provider" + "github.com/konveyor/analyzer-lsp/provider/lib" + "github.com/konveyor/analyzer-lsp/tracing" + "github.com/sirupsen/logrus" + "go.lsp.dev/uri" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/trace" + "gopkg.in/yaml.v2" + + "github.com/spf13/cobra" +) + +type analyzeBinCommand struct { + listSources bool + listTargets bool + skipStaticReport bool + analyzeKnownLibraries bool + jsonOutput bool + overwrite bool + mavenSettingsFile string + sources []string + targets []string + labelSelector string + input string + output string + mode string + httpProxy string + httpsProxy string + noProxy string + rules []string + jaegerEndpoint string + enableDefaultRulesets bool + contextLines int + incidentSelector string + + //for cleaning + binMap map[string]string + homeKantraDir string + log logr.Logger + // isFileInput is set when input points to a file and not a dir + isFileInput bool + logLevel *uint32 + cleanup bool +} + +// analyzeCmd represents the analyze command +func NewAnalyzeBinCmd(log logr.Logger) *cobra.Command { + analyzeBinCmd := &analyzeBinCommand{ + log: log, + cleanup: true, + } + analyzeBinCommand := &cobra.Command{ + Use: "analyze-bin", + Short: "Analyze Java application source code", + PreRunE: func(cmd *cobra.Command, args []string) error { + if !cmd.Flags().Lookup("list-sources").Changed && + !cmd.Flags().Lookup("list-targets").Changed { + //cmd.MarkFlagRequired("input") + cmd.MarkFlagRequired("output") + if err := cmd.ValidateRequiredFlags(); err != nil { + return err + } + } + err := analyzeBinCmd.setKantraDir() + if err != nil { + log.Error(err, "unable to get binaries") + os.Exit(1) + } + err = analyzeBinCmd.Validate(cmd.Context()) + if err != nil { + log.Error(err, "failed to validate flags") + return err + } + return nil + }, + RunE: func(cmd *cobra.Command, args []string) error { + if val, err := cmd.Flags().GetUint32(logLevelFlag); err == nil { + analyzeBinCmd.logLevel = &val + } + if val, err := cmd.Flags().GetBool(noCleanupFlag); err == nil { + analyzeBinCmd.cleanup = !val + } + if analyzeBinCmd.listSources || analyzeBinCmd.listTargets { + err := analyzeBinCmd.listLabels(cmd.Context()) + if err != nil { + log.Error(err, "failed to list rule labels") + return err + } + return nil + } + + if analyzeBinCmd.binMap == nil { + analyzeBinCmd.binMap = make(map[string]string) + } + + defer os.Remove(filepath.Join(analyzeBinCmd.output, "settings.json")) + + ctx, cancelFunc := context.WithCancel(context.Background()) + defer cancelFunc() + + analysisLogFilePath := filepath.Join(analyzeBinCmd.output, "analysis.log") + analysisLog, err := os.Create(analysisLogFilePath) + if err != nil { + return fmt.Errorf("failed creating provider log file at %s", analysisLogFilePath) + } + defer analysisLog.Close() + + logrusLog := logrus.New() + logrusLog.SetOutput(analysisLog) + logrusLog.SetFormatter(&logrus.TextFormatter{}) + // need to do research on mapping in logrusr to level here TODO + logrusLog.SetLevel(logrus.Level(logLevel)) + log := logrusr.New(logrusLog) + + logrusErrLog := logrus.New() + logrusErrLog.SetOutput(analysisLog) + errLog := logrusr.New(logrusErrLog) + + fmt.Println("running analysis") + selectors := []engine.RuleSelector{} + if analyzeBinCmd.labelSelector != "" { + selector, err := labels.NewLabelSelector[*engine.RuleMeta](analyzeBinCmd.labelSelector, nil) + if err != nil { + log.Error(err, "failed to create label selector from expression", "selector", analyzeBinCmd.labelSelector) + os.Exit(1) + } + selectors = append(selectors, selector) + } + + err = analyzeBinCmd.setBins() + if err != nil { + log.Error(err, "unable to get binaries") + os.Exit(1) + } + + // Get the configs + configs, err := analyzeBinCmd.createJavaProviderConfig() + if err != nil { + log.Error(err, "unable to get Java configuration") + os.Exit(1) + } + // we add builtin configs by default for all locations + defaultBuiltinConfigs := []provider.InitConfig{} + seenBuiltinConfigs := map[string]bool{} + finalConfigs := []provider.Config{} + for _, config := range configs { + if config.Name != "builtin" { + finalConfigs = append(finalConfigs, config) + } + for _, initConf := range config.InitConfig { + if _, ok := seenBuiltinConfigs[initConf.Location]; !ok { + if initConf.Location != "" { + if stat, err := os.Stat(initConf.Location); err == nil && stat.IsDir() { + builtinLocation, err := filepath.Abs(initConf.Location) + if err != nil { + builtinLocation = initConf.Location + } + seenBuiltinConfigs[builtinLocation] = true + builtinConf := provider.InitConfig{Location: builtinLocation} + if config.Name == "builtin" { + builtinConf.ProviderSpecificConfig = initConf.ProviderSpecificConfig + } + defaultBuiltinConfigs = append(defaultBuiltinConfigs, builtinConf) + } + } + } + } + } + + finalConfigs = append(finalConfigs, provider.Config{ + Name: "builtin", + InitConfig: defaultBuiltinConfigs, + }) + + providers := map[string]provider.InternalProviderClient{} + providerLocations := []string{} + for _, config := range finalConfigs { + config.ContextLines = analyzeBinCmd.contextLines + for _, ind := range config.InitConfig { + providerLocations = append(providerLocations, ind.Location) + } + // IF analsyis mode is set from the CLI, then we will override this for each init config + if analyzeBinCmd.mode != "" { + inits := []provider.InitConfig{} + for _, i := range config.InitConfig { + i.AnalysisMode = provider.AnalysisMode(analyzeBinCmd.mode) + inits = append(inits, i) + } + config.InitConfig = inits + } + var prov provider.InternalProviderClient + // only create java and builtin providers + if config.Name == javaProvider { + prov = java.NewJavaProvider(log, "java", analyzeBinCmd.contextLines, config) + + } else if config.Name == "builtin" { + prov, err = lib.GetProviderClient(config, log) + if err != nil { + log.Error(err, "failed to create builtin provider") + os.Exit(1) + } + } + providers[config.Name] = prov + } + + engineCtx, engineSpan := tracing.StartNewSpan(ctx, "rule-engine") + //start up the rule eng + eng := engine.CreateRuleEngine(engineCtx, + 10, + log, + engine.WithContextLines(analyzeBinCmd.contextLines), + engine.WithIncidentSelector(analyzeBinCmd.incidentSelector), + engine.WithLocationPrefixes(providerLocations), + ) + + parser := parser.RuleParser{ + ProviderNameToClient: providers, + Log: log.WithName("parser"), + } + + ruleSets := []engine.RuleSet{} + needProviders := map[string]provider.InternalProviderClient{} + + if analyzeBinCmd.enableDefaultRulesets { + analyzeBinCmd.rules = append(analyzeBinCmd.rules, filepath.Join(analyzeBinCmd.homeKantraDir, RulesetsLocation)) + } + for _, f := range analyzeBinCmd.rules { + internRuleSet, internNeedProviders, err := parser.LoadRules(f) + if err != nil { + log.Error(err, "unable to parse all the rules for ruleset", "file", f) + } + ruleSets = append(ruleSets, internRuleSet...) + for k, v := range internNeedProviders { + needProviders[k] = v + } + } + + // Now that we have all the providers, we need to start them. + additionalBuiltinConfigs := []provider.InitConfig{} + for name, provider := range needProviders { + switch name { + // other providers can return additional configs for the builtin provider + // therefore, we initiate builtin provider separately at the end + case "builtin": + continue + default: + initCtx, initSpan := tracing.StartNewSpan(ctx, "init", + attribute.Key("provider").String(name)) + additionalBuiltinConfs, err := provider.ProviderInit(initCtx, nil) + if err != nil { + log.Error(err, "unable to init the providers", "provider", name) + os.Exit(1) + } + if additionalBuiltinConfs != nil { + additionalBuiltinConfigs = append(additionalBuiltinConfigs, additionalBuiltinConfs...) + } + initSpan.End() + } + } + + if builtinClient, ok := needProviders["builtin"]; ok { + if _, err = builtinClient.ProviderInit(ctx, additionalBuiltinConfigs); err != nil { + os.Exit(1) + } + } + + wg := &sync.WaitGroup{} + var depSpan trace.Span + + if analyzeBinCmd.mode == string(provider.FullAnalysisMode) { + var depCtx context.Context + depCtx, depSpan = tracing.StartNewSpan(ctx, "dep") + wg.Add(1) + + fmt.Println("running dependency analysis") + go analyzeBinCmd.DependencyOutput(depCtx, providers, log, errLog, "dependencies.yaml", wg) + } + + // This will already wait + rulesets := eng.RunRules(ctx, ruleSets, selectors...) + engineSpan.End() + wg.Wait() + if depSpan != nil { + depSpan.End() + } + eng.Stop() + + for _, provider := range needProviders { + provider.Stop() + } + + sort.SliceStable(rulesets, func(i, j int) bool { + return rulesets[i].Name < rulesets[j].Name + }) + + // Write results out to CLI + b, err := yaml.Marshal(rulesets) + if err != nil { + return err + } + + fmt.Println("writing analysis results to output", "output", analyzeBinCmd.output) + err = os.WriteFile(filepath.Join(analyzeBinCmd.output, "output.yaml"), b, 0644) + if err != nil { + os.Exit(1) // Treat the error as a fatal error + } + + err = analyzeBinCmd.createJSONOutput() + if err != nil { + log.Error(err, "failed to create json output file") + return err + } + + err = analyzeBinCmd.GenerateStaticReport(cmd.Context()) + if err != nil { + log.Error(err, "failed to generate static report") + return err + } + + return nil + }, + } + analyzeBinCommand.Flags().BoolVar(&analyzeBinCmd.listSources, "list-sources", false, "list rules for available migration sources") + analyzeBinCommand.Flags().BoolVar(&analyzeBinCmd.listTargets, "list-targets", false, "list rules for available migration targets") + analyzeBinCommand.Flags().StringArrayVarP(&analyzeBinCmd.sources, "source", "s", []string{}, "source technology to consider for analysis. Use multiple times for additional sources: --source --source ...") + analyzeBinCommand.Flags().StringArrayVarP(&analyzeBinCmd.targets, "target", "t", []string{}, "target technology to consider for analysis. Use multiple times for additional targets: --target --target ...") + analyzeBinCommand.Flags().StringVarP(&analyzeBinCmd.labelSelector, "label-selector", "l", "", "run rules based on specified label selector expression") + analyzeBinCommand.Flags().StringArrayVar(&analyzeBinCmd.rules, "rules", []string{}, "filename or directory containing rule files. Use multiple times for additional rules: --rules --rules ...") + analyzeBinCommand.Flags().StringVarP(&analyzeBinCmd.input, "input", "i", "", "path to application source code or a binary") + analyzeBinCommand.Flags().StringVarP(&analyzeBinCmd.output, "output", "o", "", "path to the directory for analysis output") + analyzeBinCommand.Flags().BoolVar(&analyzeBinCmd.skipStaticReport, "skip-static-report", false, "do not generate static report") + analyzeBinCommand.Flags().BoolVar(&analyzeBinCmd.analyzeKnownLibraries, "analyze-known-libraries", false, "analyze known open-source libraries") + analyzeBinCommand.Flags().StringVar(&analyzeBinCmd.mavenSettingsFile, "maven-settings", "", "path to a custom maven settings file to use") + analyzeBinCommand.Flags().StringVarP(&analyzeBinCmd.mode, "mode", "m", string(provider.FullAnalysisMode), "analysis mode. Must be one of 'full' (source + dependencies) or 'source-only'") + analyzeBinCommand.Flags().BoolVar(&analyzeBinCmd.jsonOutput, "json-output", false, "create analysis and dependency output as json") + analyzeBinCommand.Flags().BoolVar(&analyzeBinCmd.overwrite, "overwrite", false, "overwrite output directory") + analyzeBinCommand.Flags().StringVar(&analyzeBinCmd.httpProxy, "http-proxy", loadEnvInsensitive("http_proxy"), "HTTP proxy string URL") + analyzeBinCommand.Flags().StringVar(&analyzeBinCmd.httpsProxy, "https-proxy", loadEnvInsensitive("https_proxy"), "HTTPS proxy string URL") + analyzeBinCommand.Flags().StringVar(&analyzeBinCmd.noProxy, "no-proxy", loadEnvInsensitive("no_proxy"), "proxy excluded URLs (relevant only with proxy)") + analyzeBinCommand.Flags().StringVar(&analyzeBinCmd.jaegerEndpoint, "jaeger-endpoint", "", "jaeger endpoint to collect traces") + analyzeBinCommand.Flags().BoolVar(&analyzeBinCmd.enableDefaultRulesets, "enable-default-rulesets", true, "run default rulesets with analysis") + analyzeBinCommand.Flags().IntVar(&analyzeBinCmd.contextLines, "context-lines", 10, "number of lines of source code to include in the output for each incident") + analyzeBinCommand.Flags().StringVar(&analyzeBinCmd.incidentSelector, "incident-selector", "", "an expression to select incidents based on custom variables. ex: (!package=io.konveyor.demo.config-utils)") + + return analyzeBinCommand +} + +func (b *analyzeBinCommand) Validate(ctx context.Context) error { + if b.listSources || b.listTargets { + return nil + } + if b.labelSelector != "" && (len(b.sources) > 0 || len(b.targets) > 0) { + return fmt.Errorf("must not specify label-selector and sources or targets") + } + //Validate source labels + if len(b.sources) > 0 { + var sourcesRaw bytes.Buffer + b.fetchLabels(ctx, true, false, &sourcesRaw) + knownSources := strings.Split(sourcesRaw.String(), "\n") + for _, source := range b.sources { + found := false + for _, knownSource := range knownSources { + if source == knownSource { + found = true + } + } + if !found { + return fmt.Errorf("unknown source: \"%s\"", source) + } + } + } + // Validate target labels + if len(b.targets) > 0 { + var targetRaw bytes.Buffer + b.fetchLabels(ctx, false, true, &targetRaw) + knownTargets := strings.Split(targetRaw.String(), "\n") + for _, source := range b.targets { + found := false + for _, knownTarget := range knownTargets { + if source == knownTarget { + found = true + } + } + if !found { + return fmt.Errorf("unknown target: \"%s\"", source) + } + } + } + if b.input != "" { + // do not allow multiple input applications + inputNum := 0 + for _, arg := range os.Args { + if arg == "-i" || strings.Contains(arg, "--input") { + inputNum += 1 + if inputNum > 1 { + return fmt.Errorf("must specify only one input source") + } + } + } + stat, err := os.Stat(b.input) + if err != nil { + return fmt.Errorf("%w failed to stat input path %s", err, b.input) + } + // when input isn't a dir, it's pointing to a binary + // we need abs path to mount the file correctly + if !stat.Mode().IsDir() { + // validate file types + fileExt := filepath.Ext(b.input) + switch fileExt { + case JavaArchive, WebArchive, EnterpriseArchive, ClassFile: + b.log.V(5).Info("valid java file found") + default: + return fmt.Errorf("invalid file type %v", fileExt) + } + b.input, err = filepath.Abs(b.input) + if err != nil { + return fmt.Errorf("%w failed to get absolute path for input file %s", err, b.input) + } + // make sure we mount a file and not a dir + SourceMountPath = path.Join(SourceMountPath, filepath.Base(b.input)) + b.isFileInput = true + } + } + err := b.CheckOverwriteOutput() + if err != nil { + return err + } + stat, err := os.Stat(b.output) + if err != nil { + if errors.Is(err, os.ErrNotExist) { + err = os.MkdirAll(b.output, os.ModePerm) + if err != nil { + return fmt.Errorf("%w failed to create output dir %s", err, b.output) + } + } else { + return fmt.Errorf("failed to stat output directory %s", b.output) + } + } + if stat != nil && !stat.IsDir() { + return fmt.Errorf("output path %s is not a directory", b.output) + } + + if b.mode != string(provider.FullAnalysisMode) && + b.mode != string(provider.SourceOnlyAnalysisMode) { + return fmt.Errorf("mode must be one of 'full' or 'source-only'") + } + if _, err := os.Stat(b.mavenSettingsFile); b.mavenSettingsFile != "" && err != nil { + return fmt.Errorf("%w failed to stat maven settings file at path %s", err, b.mavenSettingsFile) + } + // try to get abs path, if not, continue with relative path + if absPath, err := filepath.Abs(b.output); err == nil { + b.output = absPath + } + if absPath, err := filepath.Abs(b.input); err == nil { + b.input = absPath + } + if absPath, err := filepath.Abs(b.mavenSettingsFile); b.mavenSettingsFile != "" && err == nil { + b.mavenSettingsFile = absPath + } + if !b.enableDefaultRulesets && len(b.rules) == 0 { + return fmt.Errorf("must specify rules if default rulesets are not enabled") + } + return nil +} + +func (b *analyzeBinCommand) listLabels(ctx context.Context) error { + return b.fetchLabels(ctx, b.listSources, b.listTargets, os.Stdout) +} + +func (b *analyzeBinCommand) fetchLabels(ctx context.Context, listSources, listTargets bool, out io.Writer) error { + // reserved labels + sourceLabel := outputv1.SourceTechnologyLabel + targetLabel := outputv1.TargetTechnologyLabel + + if listSources { + sourceSlice, err := b.walkRuleFilesForLabels(sourceLabel) + if err != nil { + b.log.Error(err, "failed to read rule labels") + return err + } + listOptionsFromLabels(sourceSlice, sourceLabel, out) + return nil + } + if listTargets { + targetsSlice, err := b.walkRuleFilesForLabels(targetLabel) + if err != nil { + b.log.Error(err, "failed to read rule labels") + return err + } + listOptionsFromLabels(targetsSlice, targetLabel, out) + return nil + } + + return nil +} + +func (b *analyzeBinCommand) walkRuleFilesForLabels(label string) ([]string, error) { + labelsSlice := []string{} + path := filepath.Join(b.homeKantraDir, RulesetsLocation) + err := filepath.WalkDir(path, walkRuleSets(path, label, &labelsSlice)) + if err != nil { + return nil, err + } + return labelsSlice, nil +} + +func (a *analyzeBinCommand) CheckOverwriteOutput() error { + // default overwrite to false so check for already existing output dir + stat, err := os.Stat(a.output) + if err != nil { + if !errors.Is(err, os.ErrNotExist) { + return err + } + } + if a.overwrite && stat != nil { + err := os.RemoveAll(a.output) + if err != nil { + return err + } + } + return nil +} + +func (b *analyzeBinCommand) setKantraDir() error { + var homeDir string + var set bool + ops := runtime.GOOS + if ops == "linux" { + homeDir, set = os.LookupEnv("XDG_CONFIG_HOME") + } + if ops != "linux" || homeDir == "" || !set { + // on Unix, including macOS, this returns the $HOME environment variable. On Windows, it returns %USERPROFILE% + var err error + homeDir, err = os.UserHomeDir() + if err != nil { + return err + } + } + b.homeKantraDir = filepath.Join(homeDir, ".kantra") + return nil +} + +func (b *analyzeBinCommand) setBins() error { + b.binMap["bundle"] = filepath.Join(b.homeKantraDir, JavaBundlesLocation) + b.binMap["jdtls"] = filepath.Join(b.homeKantraDir, JDTLSBinLocation) + + // validate + for _, v := range b.binMap { + stat, err := os.Stat(v) + if err != nil { + return fmt.Errorf("%w failed to stat bin %s", err, v) + } + if stat.Mode().IsDir() { + return fmt.Errorf("unable to find expected file at %s", v) + } + } + return nil +} + +func (b *analyzeBinCommand) createJavaProviderConfig() ([]provider.Config, error) { + javaConfig := provider.Config{ + Name: javaProvider, + BinaryPath: b.binMap["jdtls"], + InitConfig: []provider.InitConfig{ + { + Location: b.input, + AnalysisMode: provider.AnalysisMode(b.mode), + ProviderSpecificConfig: map[string]interface{}{ + "lspServerName": javaProvider, + "bundles": b.binMap["bundle"], + provider.LspServerPathConfigKey: b.binMap["jdtls"], + }, + }, + }, + } + if b.mavenSettingsFile != "" { + javaConfig.InitConfig[0].ProviderSpecificConfig["mavenSettingsFile"] = b.mavenSettingsFile + } + + provConfig := []provider.Config{ + { + Name: "builtin", + InitConfig: []provider.InitConfig{ + { + Location: b.input, + AnalysisMode: provider.AnalysisMode(b.mode), + }, + }, + }, + } + provConfig = append(provConfig, javaConfig) + + for i := range provConfig { + // Set proxy to providers + if b.httpProxy != "" || b.httpsProxy != "" { + proxy := provider.Proxy{ + HTTPProxy: b.httpProxy, + HTTPSProxy: b.httpsProxy, + NoProxy: b.noProxy, + } + + provConfig[i].Proxy = &proxy + } + provConfig[i].ContextLines = b.contextLines + } + + jsonData, err := json.MarshalIndent(&provConfig, "", " ") + if err != nil { + b.log.V(1).Error(err, "failed to marshal provider config") + return nil, err + } + err = os.WriteFile(filepath.Join(b.output, "settings.json"), jsonData, os.ModePerm) + if err != nil { + b.log.V(1).Error(err, + "failed to write provider config", "dir", b.output, "file", "settings.json") + return nil, err + } + return provConfig, nil +} + +func (b *analyzeBinCommand) DependencyOutput(ctx context.Context, providers map[string]provider.InternalProviderClient, log logr.Logger, errLog logr.Logger, depOutputFile string, wg *sync.WaitGroup) { + defer wg.Done() + var depsFlat []konveyor.DepsFlatItem + var depsTree []konveyor.DepsTreeItem + var err error + + for _, prov := range providers { + deps, err := prov.GetDependencies(ctx) + if err != nil { + errLog.Error(err, "failed to get list of dependencies for provider", "provider", "java") + } + for u, ds := range deps { + newDeps := ds + depsFlat = append(depsFlat, konveyor.DepsFlatItem{ + Provider: "java", + FileURI: string(u), + Dependencies: newDeps, + }) + } + + if depsFlat == nil && depsTree == nil { + errLog.Info("failed to get dependencies from all given providers") + return + } + } + + var by []byte + // Sort depsFlat + sort.SliceStable(depsFlat, func(i, j int) bool { + if depsFlat[i].Provider == depsFlat[j].Provider { + return depsFlat[i].FileURI < depsFlat[j].FileURI + } else { + return depsFlat[i].Provider < depsFlat[j].Provider + } + }) + + by, err = yaml.Marshal(depsFlat) + if err != nil { + errLog.Error(err, "failed to marshal dependency data as yaml") + return + } + + err = os.WriteFile(filepath.Join(b.output, depOutputFile), by, 0644) + if err != nil { + errLog.Error(err, "failed to write dependencies to output file", "file", depOutputFile) + return + } + +} + +func (b *analyzeBinCommand) createJSONOutput() error { + if !b.jsonOutput { + return nil + } + outputPath := filepath.Join(b.output, "output.yaml") + depPath := filepath.Join(b.output, "dependencies.yaml") + + data, err := os.ReadFile(outputPath) + if err != nil { + return err + } + ruleOutput := &[]outputv1.RuleSet{} + err = yaml.Unmarshal(data, ruleOutput) + if err != nil { + b.log.V(1).Error(err, "failed to unmarshal output yaml") + return err + } + + jsonData, err := json.MarshalIndent(ruleOutput, "", " ") + if err != nil { + b.log.V(1).Error(err, "failed to marshal output file to json") + return err + } + err = os.WriteFile(filepath.Join(b.output, "output.json"), jsonData, os.ModePerm) + if err != nil { + b.log.V(1).Error(err, "failed to write json output", "dir", b.output, "file", "output.json") + return err + } + + // in case of no dep output + _, noDepFileErr := os.Stat(filepath.Join(b.output, "dependencies.yaml")) + if errors.Is(noDepFileErr, os.ErrNotExist) || b.mode == string(provider.SourceOnlyAnalysisMode) { + b.log.Info("skipping dependency output for json output") + return nil + } + depData, err := os.ReadFile(depPath) + if err != nil { + return err + } + depOutput := &[]outputv1.DepsFlatItem{} + err = yaml.Unmarshal(depData, depOutput) + if err != nil { + b.log.V(1).Error(err, "failed to unmarshal dependencies yaml") + return err + } + + jsonDataDep, err := json.MarshalIndent(depOutput, "", " ") + if err != nil { + b.log.V(1).Error(err, "failed to marshal dependencies file to json") + return err + } + err = os.WriteFile(filepath.Join(b.output, "dependencies.json"), jsonDataDep, os.ModePerm) + if err != nil { + b.log.V(1).Error(err, "failed to write json dependencies output", "dir", b.output, "file", "dependencies.json") + return err + } + + return nil +} + +func (b *analyzeBinCommand) buildStaticReportFile(ctx context.Context, staticReportPath string, depsErr bool) error { + // Prepare report args list with single input analysis + applicationName := []string{filepath.Base(b.input)} + outputAnalysis := []string{filepath.Join(b.output, "output.yaml")} + outputDeps := []string{filepath.Join(b.output, "dependencies.yaml")} + outputJSPath := filepath.Join(staticReportPath, "public", "output.js") + + if depsErr { + outputDeps = []string{} + } + // create output.js file from analysis output.yaml + apps, err := validateFlags(outputAnalysis, applicationName, outputDeps) + if err != nil { + log.Fatalln("failed to validate flags", err) + } + + err = loadApplications(apps) + if err != nil { + log.Fatalln("failed to load report data from analysis output", err) + } + + err = generateJSBundle(apps, outputJSPath) + if err != nil { + log.Fatalln("failed to generate output.js file from template", err) + } + + return nil +} + +func (b *analyzeBinCommand) buildStaticReportOutput(ctx context.Context, log *os.File) error { + // build static report + cmd := exec.Command("./static-report.sh") + cmd.Stdout = log + err := cmd.Run() + if err != nil { + return err + } + + // move build dir to analysis output + cmd = exec.Command("cp", "-r", filepath.Join(b.homeKantraDir, "static-report", "static-report"), b.output) + cmd.Stdout = log + err = cmd.Run() + if err != nil { + return err + } + + return nil +} + +func (b *analyzeBinCommand) GenerateStaticReport(ctx context.Context) error { + if b.skipStaticReport { + return nil + } + staticReportLogFilePath := filepath.Join(b.output, "static-report.log") + staticReportLog, err := os.Create(staticReportLogFilePath) + if err != nil { + return fmt.Errorf("failed creating provider log file at %s", staticReportLogFilePath) + } + defer staticReportLog.Close() + + // it's possible for dependency analysis to fail + // in this case we still want to generate a static report for successful source analysis + _, noDepFileErr := os.Stat(filepath.Join(b.output, "dependencies.yaml")) + if errors.Is(noDepFileErr, os.ErrNotExist) { + b.log.Info("unable to get dependency output in static report. generating static report from source analysis only") + + // some other err + } else if noDepFileErr != nil && !errors.Is(noDepFileErr, os.ErrNotExist) { + return noDepFileErr + } + + staticReportAanlyzePath := filepath.Join(b.homeKantraDir, "static-report") + err = b.buildStaticReportFile(ctx, staticReportAanlyzePath, errors.Is(noDepFileErr, os.ErrNotExist)) + if err != nil { + return err + } + err = b.buildStaticReportOutput(ctx, staticReportLog) + if err != nil { + return err + } + uri := uri.File(filepath.Join(b.output, "static-report", "index.html")) + b.log.Info("Static report created. Access it at this URL:", "URL", string(uri)) + + return nil +} diff --git a/cmd/analyze.go b/cmd/analyze.go index 0a3c77a..42b02f3 100644 --- a/cmd/analyze.go +++ b/cmd/analyze.go @@ -1,7 +1,6 @@ package cmd import ( - "bufio" "bytes" "context" "encoding/json" @@ -17,7 +16,6 @@ import ( "path/filepath" "slices" - "sort" "strings" "github.com/devfile/alizer/pkg/apis/model" @@ -70,6 +68,17 @@ var ( } ) +// analyzer container paths +const ( + RulesetPath = "/opt/rulesets" + OpenRewriteRecipesPath = "/opt/openrewrite" + InputPath = "/opt/input" + OutputPath = "/opt/output" + XMLRulePath = "/opt/xmlrules" + ShimOutputPath = "/opt/shimoutput" + CustomRulePath = "/opt/input/rules" +) + // supported providers const ( javaProvider = "java" @@ -88,15 +97,6 @@ const ( ClassFile = ".class" ) -// provider config options -const ( - mavenSettingsFile = "mavenSettingsFile" - lspServerPath = "lspServerPath" - lspServerName = "lspServerName" - workspaceFolders = "workspaceFolders" - dependencyProviderPath = "dependencyProviderPath" -) - // TODO add network and volume w/ interface type ProviderInit struct { port int @@ -664,7 +664,7 @@ func (a *analyzeCommand) fetchLabels(ctx context.Context, listSources, listTarge runModeContainer := "container" if os.Getenv(runMode) == runModeContainer { if listSources { - sourceSlice, err := readRuleFilesForLabels(sourceLabel) + sourceSlice, err := a.readRuleFilesForLabels(sourceLabel) if err != nil { a.log.Error(err, "failed to read rule labels") return err @@ -673,7 +673,7 @@ func (a *analyzeCommand) fetchLabels(ctx context.Context, listSources, listTarge return nil } if listTargets { - targetsSlice, err := readRuleFilesForLabels(targetLabel) + targetsSlice, err := a.readRuleFilesForLabels(targetLabel) if err != nil { a.log.Error(err, "failed to read rule labels") return err @@ -713,7 +713,7 @@ func (a *analyzeCommand) fetchLabels(ctx context.Context, listSources, listTarge return nil } -func readRuleFilesForLabels(label string) ([]string, error) { +func (a *analyzeCommand) readRuleFilesForLabels(label string) ([]string, error) { labelsSlice := []string{} err := filepath.WalkDir(RulesetPath, walkRuleSets(RulesetPath, label, &labelsSlice)) if err != nil { @@ -722,77 +722,6 @@ func readRuleFilesForLabels(label string) ([]string, error) { return labelsSlice, nil } -func walkRuleSets(root string, label string, labelsSlice *[]string) fs.WalkDirFunc { - return func(path string, d fs.DirEntry, err error) error { - if !d.IsDir() { - *labelsSlice, err = readRuleFile(path, labelsSlice, label) - if err != nil { - return err - } - } - return err - } -} - -func readRuleFile(filePath string, labelsSlice *[]string, label string) ([]string, error) { - file, err := os.Open(filePath) - if err != nil { - return nil, err - } - defer file.Close() - - scanner := bufio.NewScanner(file) - scanner.Split(bufio.ScanWords) - - for scanner.Scan() { - // add source/target labels to slice - label := getSourceOrTargetLabel(scanner.Text(), label) - if len(label) > 0 && !slices.Contains(*labelsSlice, label) { - *labelsSlice = append(*labelsSlice, label) - } - } - if err := scanner.Err(); err != nil { - return nil, err - } - return *labelsSlice, nil -} - -func getSourceOrTargetLabel(text string, label string) string { - if strings.Contains(text, label) { - return text - } - return "" -} - -func listOptionsFromLabels(sl []string, label string, out io.Writer) { - var newSl []string - l := label + "=" - - for _, label := range sl { - newSt := strings.TrimPrefix(label, l) - - if newSt != label { - newSt = strings.TrimSuffix(newSt, "+") - newSt = strings.TrimSuffix(newSt, "-") - - if !slices.Contains(newSl, newSt) { - newSl = append(newSl, newSt) - - } - } - } - sort.Strings(newSl) - - if label == outputv1.SourceTechnologyLabel { - fmt.Fprintln(out, "available source technologies:") - } else { - fmt.Fprintln(out, "available target technologies:") - } - for _, tech := range newSl { - fmt.Fprintln(out, tech) - } -} - func (a *analyzeCommand) getDepsFolders() (map[string]string, []string) { vols := map[string]string{} dependencyFolders := []string{} diff --git a/cmd/root.go b/cmd/root.go index ec1927c..51ce5ac 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -48,6 +48,7 @@ func init() { rootCmd.AddCommand(NewAnalyzeCmd(logger)) rootCmd.AddCommand(NewTestCommand(logger)) rootCmd.AddCommand(NewVersionCommand()) + rootCmd.AddCommand(NewAnalyzeBinCmd(logger)) } // Execute adds all child commands to the root command and sets flags appropriately. diff --git a/cmd/settings.go b/cmd/settings.go index f72cd4f..96122c7 100644 --- a/cmd/settings.go +++ b/cmd/settings.go @@ -12,16 +12,6 @@ import ( var Settings = &Config{} -const ( - RulesetPath = "/opt/rulesets" - OpenRewriteRecipesPath = "/opt/openrewrite" - InputPath = "/opt/input" - OutputPath = "/opt/output" - XMLRulePath = "/opt/xmlrules" - ShimOutputPath = "/opt/shimoutput" - CustomRulePath = "/opt/input/rules" -) - type Config struct { RootCommandName string `env:"CMD_NAME" default:"kantra"` ContainerBinary string `env:"CONTAINER_TOOL" default:"/usr/bin/podman"` diff --git a/cmd/static-report.go b/cmd/static-report.go new file mode 100644 index 0000000..4fd8090 --- /dev/null +++ b/cmd/static-report.go @@ -0,0 +1,121 @@ +package cmd + +import ( + "encoding/json" + "fmt" + "log" + "os" + "text/template" + + "github.com/konveyor/analyzer-lsp/output/v1/konveyor" + "gopkg.in/yaml.v2" +) + +// taken from https://github.com/konveyor/static-report/blob/main/analyzer-output-parser/main.go + +type Application struct { + Id string `yaml:"id" json:"id"` + Name string `yaml:"name" json:"name"` + Rulesets []konveyor.RuleSet `yaml:"rulesets" json:"rulesets"` + DepItems []konveyor.DepsFlatItem `yaml:"depItems" json:"depItems"` + + analysisPath string `yaml:"-" json:"-"` + depsPath string `yaml:"-" json:"-"` +} + +func validateFlags(analysisOutputPaths []string, appNames []string, depsOutputs []string) ([]*Application, error) { + var applications []*Application + if len(analysisOutputPaths) == 0 { + return nil, fmt.Errorf("analysis output paths required") + } + if len(appNames) == 0 { + return nil, fmt.Errorf("application names required") + } + if len(depsOutputs) == 0 { + log.Println("dependency output path not provided, only parsing analysis output") + } + for idx, analysisPath := range analysisOutputPaths { + currApp := &Application{ + Id: fmt.Sprintf("%04d", idx), + Rulesets: make([]konveyor.RuleSet, 0), + DepItems: make([]konveyor.DepsFlatItem, 0), + analysisPath: analysisPath, + } + if len(depsOutputs) > 0 { + currApp.depsPath = depsOutputs[idx] + } + currApp.Name = appNames[idx] + applications = append(applications, currApp) + } + + return applications, nil +} + +// loadApplications loads applications from provider config +func loadApplications(apps []*Application) error { + for _, app := range apps { + analysisReport, err := os.ReadFile(app.analysisPath) + if err != nil { + return err + } + err = yaml.Unmarshal(analysisReport, &app.Rulesets) + if err != nil { + return err + } + if app.depsPath != "" { + depsReport, err := os.ReadFile(app.depsPath) + if err != nil { + return err + } + + err = yaml.Unmarshal(depsReport, &app.DepItems) + if err != nil { + return err + } + // extras on dependencies trip JSON marshaling + // we don't need them in the report, ignore them + for idx := range app.DepItems { + depItem := &app.DepItems[idx] + for _, dep := range depItem.Dependencies { + dep.Extras = make(map[string]interface{}) + } + } + } + // extras on incidents trip JSON marshaling + // we don't need them in the report, ignore them + for idx := range app.Rulesets { + rs := &app.Rulesets[idx] + for _, violation := range rs.Violations { + violation.Extras = nil + for idx := range violation.Incidents { + inc := &violation.Incidents[idx] + inc.Variables = make(map[string]interface{}) + } + } + } + } + + return nil +} + +func generateJSBundle(apps []*Application, outputPath string) error { + output, err := json.Marshal(apps) + if err != nil { + log.Fatal("failed to marshal applications", err) + } + + tmpl := template.Must(template.New("").Parse(` +window["apps"] = {{.Apps}} +`)) + file, err := os.Create(outputPath) + if err != nil { + log.Fatal("failed to create JS output bundle", err) + } + defer file.Close() + err = tmpl.Execute(file, struct { + Apps string + }{ + Apps: string(output), + }) + return err +} diff --git a/cmd/util.go b/cmd/util.go new file mode 100644 index 0000000..dcdf614 --- /dev/null +++ b/cmd/util.go @@ -0,0 +1,104 @@ +package cmd + +import ( + "bufio" + "fmt" + "io" + "io/fs" + "os" + "slices" + "sort" + "strings" + + outputv1 "github.com/konveyor/analyzer-lsp/output/v1/konveyor" +) + +var ( + RootCommandName = "kantra" + JavaBundlesLocation = "/jdtls/java-analyzer-bundle/java-analyzer-bundle.core/target/java-analyzer-bundle.core-1.0.0-SNAPSHOT.jar" + JDTLSBinLocation = "/jdtls/bin/jdtls" + RulesetsLocation = "rulesets/default/generated" + JavaProviderImage = "quay.io/konveyor/java-external-provider" + GenericProviderImage = "quay.io/konveyor/generic-external-provider" + DotnetProviderImage = "quay.io/konveyor/dotnet-external-provider" +) + +// provider config options +const ( + mavenSettingsFile = "mavenSettingsFile" + lspServerPath = "lspServerPath" + lspServerName = "lspServerName" + workspaceFolders = "workspaceFolders" + dependencyProviderPath = "dependencyProviderPath" +) + +func walkRuleSets(root string, label string, labelsSlice *[]string) fs.WalkDirFunc { + return func(path string, d fs.DirEntry, err error) error { + if !d.IsDir() { + *labelsSlice, err = readRuleFile(path, labelsSlice, label) + if err != nil { + return err + } + } + return err + } +} + +func readRuleFile(filePath string, labelsSlice *[]string, label string) ([]string, error) { + file, err := os.Open(filePath) + if err != nil { + return nil, err + } + defer file.Close() + + scanner := bufio.NewScanner(file) + scanner.Split(bufio.ScanWords) + + for scanner.Scan() { + // add source/target labels to slice + label := getSourceOrTargetLabel(scanner.Text(), label) + if len(label) > 0 && !slices.Contains(*labelsSlice, label) { + *labelsSlice = append(*labelsSlice, label) + } + } + if err := scanner.Err(); err != nil { + return nil, err + } + return *labelsSlice, nil +} + +func getSourceOrTargetLabel(text string, label string) string { + if strings.Contains(text, label) { + return text + } + return "" +} + +func listOptionsFromLabels(sl []string, label string, out io.Writer) { + var newSl []string + l := label + "=" + + for _, label := range sl { + newSt := strings.TrimPrefix(label, l) + + if newSt != label { + newSt = strings.TrimSuffix(newSt, "+") + newSt = strings.TrimSuffix(newSt, "-") + + if !slices.Contains(newSl, newSt) { + newSl = append(newSl, newSt) + + } + } + } + sort.Strings(newSl) + + if label == outputv1.SourceTechnologyLabel { + fmt.Fprintln(out, "available source technologies:") + } else { + fmt.Fprintln(out, "available target technologies:") + } + for _, tech := range newSl { + fmt.Fprintln(out, tech) + } +} diff --git a/cmd/version.go b/cmd/version.go index d485055..4e9c923 100644 --- a/cmd/version.go +++ b/cmd/version.go @@ -7,14 +7,9 @@ import ( ) var ( - BuildCommit = "" - Version = "latest" - RunnerImage = "quay.io/konveyor/kantra" - RootCommandName = "kantra" - JavaBundlesLocation = "/jdtls/java-analyzer-bundle/java-analyzer-bundle.core/target/java-analyzer-bundle.core-1.0.0-SNAPSHOT.jar" - JavaProviderImage = "quay.io/konveyor/java-external-provider" - GenericProviderImage = "quay.io/konveyor/generic-external-provider" - DotnetProviderImage = "quay.io/konveyor/dotnet-external-provider" + BuildCommit = "" + Version = "latest" + RunnerImage = "quay.io/konveyor/kantra" ) // Use build flags to set correct Version and BuildCommit diff --git a/docs/containerless.md b/docs/containerless.md new file mode 100644 index 0000000..76d6805 --- /dev/null +++ b/docs/containerless.md @@ -0,0 +1,19 @@ +## Test and Run Containerless Kantra + +### Clone the requirements: + +```sh +git clone https://github.com/eemcmullan/containerless-kantra-deps.git +``` + +## Move them to where kantra will look for packged binaries and default rulesets: + +```sh +mv $HOME/containerless-kantra-deps $HOME/.kantra +``` + +### From kantra, run: + +```sh +go run main.go analyze-bin --input --output --rules +``` diff --git a/go.mod b/go.mod index 60609db..e55ef7d 100644 --- a/go.mod +++ b/go.mod @@ -6,24 +6,37 @@ require ( github.com/devfile/alizer v1.6.1 github.com/getkin/kin-openapi v0.108.0 github.com/go-logr/logr v1.4.2 + github.com/nxadm/tail v1.4.8 github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 github.com/spf13/cobra v1.8.1 + github.com/swaggest/openapi-go v0.2.50 + github.com/vifraa/gopom v1.0.0 go.lsp.dev/uri v0.3.0 + go.opentelemetry.io/otel v1.22.0 + go.opentelemetry.io/otel/trace v1.22.0 gopkg.in/yaml.v2 v2.4.0 gopkg.in/yaml.v3 v3.0.1 ) require ( + cloud.google.com/go/compute v1.24.0 // indirect + cloud.google.com/go/compute/metadata v0.2.3 // indirect + github.com/antchfx/xpath v1.3.1 // indirect + github.com/bufbuild/protocompile v0.10.0 // indirect github.com/cbroglie/mustache v1.3.0 // indirect github.com/containerd/typeurl/v2 v2.1.1 // indirect + github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-logr/zapr v1.3.0 // indirect github.com/go-openapi/jsonpointer v0.19.6 // indirect github.com/go-openapi/swag v0.22.3 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang-jwt/jwt/v5 v5.2.1 // indirect + github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect + github.com/golang/protobuf v1.5.4 // indirect github.com/hashicorp/go-version v1.7.0 // indirect github.com/invopop/yaml v0.1.0 // indirect + github.com/jhump/protoreflect v1.16.0 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/kr/pretty v0.3.0 // indirect github.com/mailru/easyjson v0.7.7 // indirect @@ -31,33 +44,37 @@ require ( github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/sabhiram/go-gitignore v0.0.0-20210923224102-525f6e181f06 // indirect - github.com/swaggest/jsonschema-go v0.3.64 // indirect - github.com/swaggest/openapi-go v0.2.45 // indirect + github.com/swaggest/jsonschema-go v0.3.70 // indirect github.com/swaggest/refl v1.3.0 // indirect - go.opentelemetry.io/otel v1.21.0 // indirect go.opentelemetry.io/otel/exporters/jaeger v1.17.0 // indirect - go.opentelemetry.io/otel/metric v1.21.0 // indirect + go.opentelemetry.io/otel/metric v1.22.0 // indirect go.opentelemetry.io/otel/sdk v1.21.0 // indirect - go.opentelemetry.io/otel/trace v1.21.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.0 // indirect golang.org/x/mod v0.20.0 // indirect golang.org/x/net v0.24.0 // indirect + golang.org/x/oauth2 v0.17.0 // indirect golang.org/x/sys v0.22.0 // indirect golang.org/x/text v0.14.0 // indirect + google.golang.org/appengine v1.6.8 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240227224415-6ceb2ff114de // indirect google.golang.org/grpc v1.63.2 // indirect google.golang.org/protobuf v1.33.1-0.20240408130810-98873a205002 // indirect + gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect ) require ( github.com/PaesslerAG/gval v1.2.2 // indirect + github.com/antchfx/jsonquery v1.3.5 // indirect + github.com/antchfx/xmlquery v1.4.1 // indirect github.com/bombsimon/logrusr/v3 v3.1.0 github.com/codingconcepts/env v0.0.0-20200821220118-a8fbf8d84482 github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/konveyor/analyzer-lsp v0.5.3 + github.com/konveyor/analyzer-lsp/external-providers/java-external-provider v0.0.0-20240926004552-328558364c2f github.com/shopspring/decimal v1.3.1 // indirect github.com/sirupsen/logrus v1.9.3 github.com/spf13/pflag v1.0.5 // indirect golang.org/x/exp v0.0.0-20230725093048-515e97ebf090 ) + diff --git a/go.sum b/go.sum index 7f218d1..4456515 100644 --- a/go.sum +++ b/go.sum @@ -1,13 +1,25 @@ +cloud.google.com/go/compute v1.24.0 h1:phWcR2eWzRJaL/kOiJwfFsPs4BaKq1j6vnpZrc1YlVg= +cloud.google.com/go/compute v1.24.0/go.mod h1:kw1/T+h/+tK2LJK0wiPPx1intgdAM3j/g3hFDlscY40= +cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= +cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= github.com/PaesslerAG/gval v1.2.2 h1:Y7iBzhgE09IGTt5QgGQ2IdaYYYOU134YGHBThD+wm9E= github.com/PaesslerAG/gval v1.2.2/go.mod h1:XRFLwvmkTEdYziLdaCeCa5ImcGVrfQbeNUbVR+C6xac= github.com/PaesslerAG/jsonpath v0.1.0 h1:gADYeifvlqK3R3i2cR5B4DGgxLXIPb3TRTH1mGi0jPI= github.com/PaesslerAG/jsonpath v0.1.0/go.mod h1:4BzmtoM/PI8fPO4aQGIusjGxGir2BzcV0grWtFzq1Y8= +github.com/antchfx/jsonquery v1.3.5 h1:243OSaQh02EfmASa3w3weKC9UaiD8RRzJhgfvq3q408= +github.com/antchfx/jsonquery v1.3.5/go.mod h1:qH23yX2Jsj1/k378Yu/EOgPCNgJ35P9tiGOeQdt/GWc= +github.com/antchfx/xmlquery v1.4.1 h1:YgpSwbeWvLp557YFTi8E3z6t6/hYjmFEtiEKbDfEbl0= +github.com/antchfx/xmlquery v1.4.1/go.mod h1:lKezcT8ELGt8kW5L+ckFMTbgdR61/odpPgDv8Gvi1fI= +github.com/antchfx/xpath v1.3.1 h1:PNbFuUqHwWl0xRjvUPjJ95Agbmdj2uzzIwmQKgu4oCk= +github.com/antchfx/xpath v1.3.1/go.mod h1:i54GszH55fYfBmoZXapTHN8T8tkcHfRgLyVwwqzXNcs= github.com/bombsimon/logrusr/v3 v3.1.0 h1:zORbLM943D+hDMGgyjMhSAz/iDz86ZV72qaak/CA0zQ= github.com/bombsimon/logrusr/v3 v3.1.0/go.mod h1:PksPPgSFEL2I52pla2glgCyyd2OqOHAnFF5E+g8Ixco= github.com/bool64/dev v0.2.32 h1:DRZtloaoH1Igky3zphaUHV9+SLIV2H3lsf78JsJHFg0= github.com/bool64/dev v0.2.32/go.mod h1:iJbh1y/HkunEPhgebWRNcs8wfGq7sjvJ6W5iabL8ACg= github.com/bool64/shared v0.1.5 h1:fp3eUhBsrSjNCQPcSdQqZxxh9bBwrYiZ+zOKFkM0/2E= github.com/bool64/shared v0.1.5/go.mod h1:081yz68YC9jeFB3+Bbmno2RFWvGKv1lPKkMP6MHJlPs= +github.com/bufbuild/protocompile v0.10.0 h1:+jW/wnLMLxaCEG8AX9lD0bQ5v9h1RUiMKOBOT5ll9dM= +github.com/bufbuild/protocompile v0.10.0/go.mod h1:G9qQIQo0xZ6Uyj6CMNz0saGmx2so+KONo8/KrELABiY= github.com/cbroglie/mustache v1.3.0 h1:sj24GVYl8G7MH4b3zaROGsZnF8X79JqtjMx8/6H/nXM= github.com/cbroglie/mustache v1.3.0/go.mod h1:w58RIHjw/L7DPyRX2CcCTduNmcP1dvztaHP72ciSfh0= github.com/codingconcepts/env v0.0.0-20200821220118-a8fbf8d84482 h1:5/aEFreBh9hH/0G+33xtczJCvMaulqsm9nDuu2BZUEo= @@ -21,6 +33,10 @@ 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/devfile/alizer v1.6.1 h1:5G0SHFAcFNTwqsaZu5pir2pBJ04hg/F6d/lfQeAs7YY= github.com/devfile/alizer v1.6.1/go.mod h1:RHcz/nRPIlHNIfG3wTmVLrS8IyM+4CB841S/WKFXDiw= +github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +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/getkin/kin-openapi v0.108.0 h1:EYf0GtsKa4hQNIlplGS+Au7NEfGQ1F7MoHD2kcVevPQ= github.com/getkin/kin-openapi v0.108.0/go.mod h1:QtwUNt0PAAgIIBEvFWYfB7dfngxtAaqCX1zYHMZDeK8= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= @@ -40,7 +56,10 @@ github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk= github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= +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/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.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= @@ -56,12 +75,18 @@ github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2 github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/invopop/yaml v0.1.0 h1:YW3WGUoJEXYfzWBjn00zIlrw7brGVD0fUKRYDPAPhrc= github.com/invopop/yaml v0.1.0/go.mod h1:2XuRLgs/ouIrW3XNzuNj7J3Nvu/Dig5MXvbCEdiBN3Q= +github.com/jhump/protoreflect v1.16.0 h1:54fZg+49widqXYQ0b+usAFHbMkBGR4PpXrsHc8+TBDg= +github.com/jhump/protoreflect v1.16.0/go.mod h1:oYPd7nPvcBw/5wlDfm/AVmU9zH9BgqGCI469pGxfj/8= 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/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/konveyor/analyzer-lsp v0.5.3 h1:RPIcH5s5oQysfKz3o0rnK8pVmwp3MWpIdCheT1gklrw= github.com/konveyor/analyzer-lsp v0.5.3/go.mod h1:Gqj6MRUA2Jjjw19tUguJB6Bqj4dLwZzb68FmAUok0ac= +github.com/konveyor/analyzer-lsp/external-providers/java-external-provider v0.0.0-20240925163006-aa4d8cacbcc9 h1:ZzEI5OSXJ61zwtVZORlL6a91BxvWsGH9NV6hTT3Ufg0= +github.com/konveyor/analyzer-lsp/external-providers/java-external-provider v0.0.0-20240925163006-aa4d8cacbcc9/go.mod h1:O7Bh3ECVCvRdsDv2qR8UG5S3so4PXmI7PrYrrm78YIY= +github.com/konveyor/analyzer-lsp/external-providers/java-external-provider v0.0.0-20240926004552-328558364c2f h1:0jj9ayb1qpMP8wu+LdF+2jSHZN5JeGVP69iJqaYPpYA= +github.com/konveyor/analyzer-lsp/external-providers/java-external-provider v0.0.0-20240926004552-328558364c2f/go.mod h1:O7Bh3ECVCvRdsDv2qR8UG5S3so4PXmI7PrYrrm78YIY= 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= @@ -78,6 +103,8 @@ github.com/moby/buildkit v0.14.1 h1:2epLCZTkn4CikdImtsLtIa++7DzCimrrZCT1sway+oI= github.com/moby/buildkit v0.14.1/go.mod h1:1XssG7cAqv5Bz1xcGMxJL123iCv5TYN4Z/qf647gfuk= github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw= github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8= +github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= +github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 h1:Ii+DKncOVM8Cu1Hc+ETb5K+23HdAMvESYE3ZJ5b5cMI= github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= @@ -109,34 +136,42 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ 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.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/swaggest/assertjson v1.9.0 h1:dKu0BfJkIxv/xe//mkCrK5yZbs79jL7OVf9Ija7o2xQ= github.com/swaggest/assertjson v1.9.0/go.mod h1:b+ZKX2VRiUjxfUIal0HDN85W0nHPAYUbYH5WkkSsFsU= github.com/swaggest/jsonschema-go v0.3.64 h1:HyB41fkA4XP0BZkqWfGap5i2JtRHQGXG/21dGDPbyLM= github.com/swaggest/jsonschema-go v0.3.64/go.mod h1:DYuKqdpms/edvywsX6p1zHXCZkdwB28wRaBdFCe3Duw= +github.com/swaggest/jsonschema-go v0.3.70 h1:8Vx5nm5t/6DBFw2+WC0/Vp1ZVe9/4mpuA0tuAe0wwCI= +github.com/swaggest/jsonschema-go v0.3.70/go.mod h1:7N43/CwdaWgPUDfYV70K7Qm79tRqe/al7gLSt9YeGIE= github.com/swaggest/openapi-go v0.2.45 h1:LOMAEleKVLg4E86lSCyioJK7ltjWRx50AaP4LZIbJ+Q= github.com/swaggest/openapi-go v0.2.45/go.mod h1:/ykzNtS1ZO7X43OnEtyisMktxCiawQLyGd08rkjV68U= +github.com/swaggest/openapi-go v0.2.50 h1:5yQ7N/IhMK9bQSk2yFAEbB75DvoXzyEmji3Q2iS++is= +github.com/swaggest/openapi-go v0.2.50/go.mod h1:5R2TWYBz0U7P3vwIwN0ytwSxqONXZnbiAaa+DQ3Sq1k= github.com/swaggest/refl v1.3.0 h1:PEUWIku+ZznYfsoyheF97ypSduvMApYyGkYF3nabS0I= github.com/swaggest/refl v1.3.0/go.mod h1:3Ujvbmh1pfSbDYjC6JGG7nMgPvpG0ehQL4iNonnLNbg= +github.com/vifraa/gopom v1.0.0 h1:L9XlKbyvid8PAIK8nr0lihMApJQg/12OBvMA28BcWh0= +github.com/vifraa/gopom v1.0.0/go.mod h1:oPa1dcrGrtlO37WPDBm5SqHAT+wTgF8An1Q71Z6Vv4o= github.com/yudai/gojsondiff v1.0.0 h1:27cbfqXLVEJ1o8I6v3y9lg8Ydm53EKqHXAOMxEGlCOA= github.com/yudai/gojsondiff v1.0.0/go.mod h1:AY32+k2cwILAkW1fbgxQ5mUmMiZFgLIV+FBNExI05xg= github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82 h1:BHyfKlQyqbsFN5p3IfnEUduWvb9is428/nNb5L3U01M= github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82/go.mod h1:lgjkn3NuSvDfVJdfcVVdX+jpBxNmX4rDAzaS45IcYoM= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= go.lsp.dev/uri v0.3.0 h1:KcZJmh6nFIBeJzTugn5JTU6OOyG0lDOo3R9KwTxTYbo= go.lsp.dev/uri v0.3.0/go.mod h1:P5sbO1IQR+qySTWOCnhnK7phBx+W3zbLqSMDJNTw88I= -go.opentelemetry.io/otel v1.21.0 h1:hzLeKBZEL7Okw2mGzZ0cc4k/A7Fta0uoPgaJCr8fsFc= -go.opentelemetry.io/otel v1.21.0/go.mod h1:QZzNPQPm1zLX4gZK4cMi+71eaorMSGT3A4znnUvNNEo= +go.opentelemetry.io/otel v1.22.0 h1:xS7Ku+7yTFvDfDraDIJVpw7XPyuHlB9MCiqqX5mcJ6Y= +go.opentelemetry.io/otel v1.22.0/go.mod h1:eoV4iAi3Ea8LkAEI9+GFT44O6T/D0GWAVFyZVCC6pMI= go.opentelemetry.io/otel/exporters/jaeger v1.17.0 h1:D7UpUy2Xc2wsi1Ras6V40q806WM07rqoCWzXu7Sqy+4= go.opentelemetry.io/otel/exporters/jaeger v1.17.0/go.mod h1:nPCqOnEH9rNLKqH/+rrUjiMzHJdV1BlpKcTwRTyKkKI= -go.opentelemetry.io/otel/metric v1.21.0 h1:tlYWfeo+Bocx5kLEloTjbcDwBuELRrIFxwdQ36PlJu4= -go.opentelemetry.io/otel/metric v1.21.0/go.mod h1:o1p3CA8nNHW8j5yuQLdc1eeqEaPfzug24uvsyIEJRWM= +go.opentelemetry.io/otel/metric v1.22.0 h1:lypMQnGyJYeuYPhOM/bgjbFM6WE44W1/T45er4d8Hhg= +go.opentelemetry.io/otel/metric v1.22.0/go.mod h1:evJGjVpZv0mQ5QBRJoBF64yMuOf4xCWdXjK8pzFvliY= go.opentelemetry.io/otel/sdk v1.21.0 h1:FTt8qirL1EysG6sTQRZ5TokkU8d0ugCj8htOgThZXQ8= go.opentelemetry.io/otel/sdk v1.21.0/go.mod h1:Nna6Yv7PWTdgJHVRD9hIYywQBRx7pbox6nwBnZIxl/E= -go.opentelemetry.io/otel/trace v1.21.0 h1:WD9i5gzvoUPuXIXH24ZNBudiarZDKuekPqi/E8fpfLc= -go.opentelemetry.io/otel/trace v1.21.0/go.mod h1:LGbsEB0f9LGjN+OZaQQ26sohbOmiMR+BaslueVtS/qQ= +go.opentelemetry.io/otel/trace v1.22.0 h1:Hg6pPujv0XG9QaVbGOBVHunyuLcCC3jN7WEhPx83XD0= +go.opentelemetry.io/otel/trace v1.22.0/go.mod h1:RbbHXVqKES9QhzZq/fE5UnOSILqRt40a21sPw2He1xo= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= @@ -146,44 +181,70 @@ go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 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-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/exp v0.0.0-20230725093048-515e97ebf090 h1:Di6/M8l0O2lCLc6VVRWhgCiApHV8MnQurBnFSHsQtNY= golang.org/x/exp v0.0.0-20230725093048-515e97ebf090/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc= 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.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.20.0 h1:utOm6MM3R3dnawAiJgn0y+xvuYRsm1RKM/4giyfDgV0= golang.org/x/mod v0.20.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/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-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w= golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8= +golang.org/x/oauth2 v0.17.0 h1:6m3ZPmLEFdVxKKWnKq4VqZ60gutO35zm+zrAHVmHyDQ= +golang.org/x/oauth2 v0.17.0/go.mod h1:OzPDGQiuQMguemayvdylqddI7qcD9lnSDb+1FiwQ5HA= 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-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ= +golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/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-20210615035016-665e8c7367d1/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-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.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI= golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +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.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/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.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= 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= +google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM= +google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds= google.golang.org/genproto/googleapis/rpc v0.0.0-20240227224415-6ceb2ff114de h1:cZGRis4/ot9uVm639a+rHCUaG0JJHEsdyzSQTMX+suY= google.golang.org/genproto/googleapis/rpc v0.0.0-20240227224415-6ceb2ff114de/go.mod h1:H4O17MA/PE9BsGx3w+a+W2VOLLD1Qf7oJneAoU6WktY= google.golang.org/grpc v1.63.2 h1:MUeiw1B2maTVZthpU5xvASfTh3LDbxHd6IJ6QQVU+xM= google.golang.org/grpc v1.63.2/go.mod h1:WAX/8DgncnokcFUldAxq7GeB5DXHDbMF+lLvDomNkRA= 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.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.33.1-0.20240408130810-98873a205002 h1:V7Da7qt0MkY3noVANIMVBk28nOnijADeOR3i5Hcvpj4= google.golang.org/protobuf v1.33.1-0.20240408130810-98873a205002/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= @@ -192,6 +253,8 @@ gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8 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/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/yaml.v2 v2.2.2/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= diff --git a/static-report.sh b/static-report.sh new file mode 100755 index 0000000..048c40c --- /dev/null +++ b/static-report.sh @@ -0,0 +1,19 @@ +#!/bin/bash +set -x + +HOMEDIR="" + +if [ "$(uname)" == "Linux" ] || [ "$(uname)" == "Darwin" ]; then + HOMEDIR="$HOME" +else + # windows + HOMEDIR="%USERPROFILE%" +fi + +# TODO test this on windows +(cd ${HOMEDIR}/.kantra/static-report && +npm clean-install && +CI=true PUBLIC_URL=. npm run build && +cp ${HOMEDIR}/.kantra/static-report/public/output.js ${HOMEDIR}/.kantra/static-report/build/output.js && +rm -rf ${HOMEDIR}/.kantra/static-report/static-report && +mv ${HOMEDIR}/.kantra/static-report/build ${HOMEDIR}/.kantra/static-report/static-report) From 3ab472ba97ae8a1e1c4bc6d0eeffae47d7bffb07 Mon Sep 17 00:00:00 2001 From: Emily McMullan Date: Fri, 27 Sep 2024 01:07:51 -0400 Subject: [PATCH 2/3] clean up run func Signed-off-by: Emily McMullan --- cmd/analyze-bin.go | 215 ++++++++++++++++++++++++--------------------- 1 file changed, 113 insertions(+), 102 deletions(-) diff --git a/cmd/analyze-bin.go b/cmd/analyze-bin.go index f9a21a0..c750746 100644 --- a/cmd/analyze-bin.go +++ b/cmd/analyze-bin.go @@ -10,7 +10,6 @@ import ( "log" "os" "os/exec" - "path" "path/filepath" "runtime" "sort" @@ -161,74 +160,13 @@ func NewAnalyzeBinCmd(log logr.Logger) *cobra.Command { } // Get the configs - configs, err := analyzeBinCmd.createJavaProviderConfig() + finalConfigs, err := analyzeBinCmd.createProviderConfigs() if err != nil { log.Error(err, "unable to get Java configuration") os.Exit(1) } - // we add builtin configs by default for all locations - defaultBuiltinConfigs := []provider.InitConfig{} - seenBuiltinConfigs := map[string]bool{} - finalConfigs := []provider.Config{} - for _, config := range configs { - if config.Name != "builtin" { - finalConfigs = append(finalConfigs, config) - } - for _, initConf := range config.InitConfig { - if _, ok := seenBuiltinConfigs[initConf.Location]; !ok { - if initConf.Location != "" { - if stat, err := os.Stat(initConf.Location); err == nil && stat.IsDir() { - builtinLocation, err := filepath.Abs(initConf.Location) - if err != nil { - builtinLocation = initConf.Location - } - seenBuiltinConfigs[builtinLocation] = true - builtinConf := provider.InitConfig{Location: builtinLocation} - if config.Name == "builtin" { - builtinConf.ProviderSpecificConfig = initConf.ProviderSpecificConfig - } - defaultBuiltinConfigs = append(defaultBuiltinConfigs, builtinConf) - } - } - } - } - } - - finalConfigs = append(finalConfigs, provider.Config{ - Name: "builtin", - InitConfig: defaultBuiltinConfigs, - }) - providers := map[string]provider.InternalProviderClient{} - providerLocations := []string{} - for _, config := range finalConfigs { - config.ContextLines = analyzeBinCmd.contextLines - for _, ind := range config.InitConfig { - providerLocations = append(providerLocations, ind.Location) - } - // IF analsyis mode is set from the CLI, then we will override this for each init config - if analyzeBinCmd.mode != "" { - inits := []provider.InitConfig{} - for _, i := range config.InitConfig { - i.AnalysisMode = provider.AnalysisMode(analyzeBinCmd.mode) - inits = append(inits, i) - } - config.InitConfig = inits - } - var prov provider.InternalProviderClient - // only create java and builtin providers - if config.Name == javaProvider { - prov = java.NewJavaProvider(log, "java", analyzeBinCmd.contextLines, config) - - } else if config.Name == "builtin" { - prov, err = lib.GetProviderClient(config, log) - if err != nil { - log.Error(err, "failed to create builtin provider") - os.Exit(1) - } - } - providers[config.Name] = prov - } + providers, providerLocations := analyzeBinCmd.setInternalProviders(log, finalConfigs) engineCtx, engineSpan := tracing.StartNewSpan(ctx, "rule-engine") //start up the rule eng @@ -261,39 +199,14 @@ func NewAnalyzeBinCmd(log logr.Logger) *cobra.Command { needProviders[k] = v } } - - // Now that we have all the providers, we need to start them. - additionalBuiltinConfigs := []provider.InitConfig{} - for name, provider := range needProviders { - switch name { - // other providers can return additional configs for the builtin provider - // therefore, we initiate builtin provider separately at the end - case "builtin": - continue - default: - initCtx, initSpan := tracing.StartNewSpan(ctx, "init", - attribute.Key("provider").String(name)) - additionalBuiltinConfs, err := provider.ProviderInit(initCtx, nil) - if err != nil { - log.Error(err, "unable to init the providers", "provider", name) - os.Exit(1) - } - if additionalBuiltinConfs != nil { - additionalBuiltinConfigs = append(additionalBuiltinConfigs, additionalBuiltinConfs...) - } - initSpan.End() - } - } - - if builtinClient, ok := needProviders["builtin"]; ok { - if _, err = builtinClient.ProviderInit(ctx, additionalBuiltinConfigs); err != nil { - os.Exit(1) - } + err = analyzeBinCmd.startProviders(ctx, needProviders) + if err != nil { + os.Exit(1) } + // start dependency analysis for full analysis mode only wg := &sync.WaitGroup{} var depSpan trace.Span - if analyzeBinCmd.mode == string(provider.FullAnalysisMode) { var depCtx context.Context depCtx, depSpan = tracing.StartNewSpan(ctx, "dep") @@ -429,7 +342,6 @@ func (b *analyzeBinCommand) Validate(ctx context.Context) error { return fmt.Errorf("%w failed to stat input path %s", err, b.input) } // when input isn't a dir, it's pointing to a binary - // we need abs path to mount the file correctly if !stat.Mode().IsDir() { // validate file types fileExt := filepath.Ext(b.input) @@ -439,12 +351,6 @@ func (b *analyzeBinCommand) Validate(ctx context.Context) error { default: return fmt.Errorf("invalid file type %v", fileExt) } - b.input, err = filepath.Abs(b.input) - if err != nil { - return fmt.Errorf("%w failed to get absolute path for input file %s", err, b.input) - } - // make sure we mount a file and not a dir - SourceMountPath = path.Join(SourceMountPath, filepath.Base(b.input)) b.isFileInput = true } } @@ -584,7 +490,7 @@ func (b *analyzeBinCommand) setBins() error { return nil } -func (b *analyzeBinCommand) createJavaProviderConfig() ([]provider.Config, error) { +func (b *analyzeBinCommand) createProviderConfigs() ([]provider.Config, error) { javaConfig := provider.Config{ Name: javaProvider, BinaryPath: b.binMap["jdtls"], @@ -642,7 +548,112 @@ func (b *analyzeBinCommand) createJavaProviderConfig() ([]provider.Config, error "failed to write provider config", "dir", b.output, "file", "settings.json") return nil, err } - return provConfig, nil + configs := b.setConfigs(provConfig) + return configs, nil +} + +func (b *analyzeBinCommand) setConfigs(configs []provider.Config) []provider.Config { + // we add builtin configs by default for all locations + defaultBuiltinConfigs := []provider.InitConfig{} + seenBuiltinConfigs := map[string]bool{} + finalConfigs := []provider.Config{} + for _, config := range configs { + if config.Name != "builtin" { + finalConfigs = append(finalConfigs, config) + } + for _, initConf := range config.InitConfig { + if _, ok := seenBuiltinConfigs[initConf.Location]; !ok { + if initConf.Location != "" { + if stat, err := os.Stat(initConf.Location); err == nil && stat.IsDir() { + builtinLocation, err := filepath.Abs(initConf.Location) + if err != nil { + builtinLocation = initConf.Location + } + seenBuiltinConfigs[builtinLocation] = true + builtinConf := provider.InitConfig{Location: builtinLocation} + if config.Name == "builtin" { + builtinConf.ProviderSpecificConfig = initConf.ProviderSpecificConfig + } + defaultBuiltinConfigs = append(defaultBuiltinConfigs, builtinConf) + } + } + } + } + } + + finalConfigs = append(finalConfigs, provider.Config{ + Name: "builtin", + InitConfig: defaultBuiltinConfigs, + }) + + return finalConfigs +} + +func (b *analyzeBinCommand) setInternalProviders(log logr.Logger, finalConfigs []provider.Config) (map[string]provider.InternalProviderClient, []string) { + providers := map[string]provider.InternalProviderClient{} + providerLocations := []string{} + for _, config := range finalConfigs { + config.ContextLines = b.contextLines + for _, ind := range config.InitConfig { + providerLocations = append(providerLocations, ind.Location) + } + // IF analsyis mode is set from the CLI, then we will override this for each init config + if b.mode != "" { + inits := []provider.InitConfig{} + for _, i := range config.InitConfig { + i.AnalysisMode = provider.AnalysisMode(b.mode) + inits = append(inits, i) + } + config.InitConfig = inits + } + var prov provider.InternalProviderClient + var err error + // only create java and builtin providers + if config.Name == javaProvider { + prov = java.NewJavaProvider(log, "java", b.contextLines, config) + + } else if config.Name == "builtin" { + prov, err = lib.GetProviderClient(config, log) + if err != nil { + log.Error(err, "failed to create builtin provider") + os.Exit(1) + } + } + providers[config.Name] = prov + } + return providers, providerLocations +} + +func (b *analyzeBinCommand) startProviders(ctx context.Context, needProviders map[string]provider.InternalProviderClient) error { + // Now that we have all the providers, we need to start them. + additionalBuiltinConfigs := []provider.InitConfig{} + for name, provider := range needProviders { + switch name { + // other providers can return additional configs for the builtin provider + // therefore, we initiate builtin provider separately at the end + case "builtin": + continue + default: + initCtx, initSpan := tracing.StartNewSpan(ctx, "init", + attribute.Key("provider").String(name)) + additionalBuiltinConfs, err := provider.ProviderInit(initCtx, nil) + if err != nil { + b.log.Error(err, "unable to init the providers", "provider", name) + os.Exit(1) + } + if additionalBuiltinConfs != nil { + additionalBuiltinConfigs = append(additionalBuiltinConfigs, additionalBuiltinConfs...) + } + initSpan.End() + } + } + + if builtinClient, ok := needProviders["builtin"]; ok { + if _, err := builtinClient.ProviderInit(ctx, additionalBuiltinConfigs); err != nil { + return err + } + } + return nil } func (b *analyzeBinCommand) DependencyOutput(ctx context.Context, providers map[string]provider.InternalProviderClient, log logr.Logger, errLog logr.Logger, depOutputFile string, wg *sync.WaitGroup) { From c66548c68292a0eb6f2469ba6d60e72321c8b448 Mon Sep 17 00:00:00 2001 From: Emily McMullan Date: Fri, 27 Sep 2024 15:43:37 -0400 Subject: [PATCH 3/3] remove static report script Signed-off-by: Emily McMullan --- cmd/analyze-bin.go | 12 ++++++++---- static-report.sh | 19 ------------------- 2 files changed, 8 insertions(+), 23 deletions(-) delete mode 100755 static-report.sh diff --git a/cmd/analyze-bin.go b/cmd/analyze-bin.go index c750746..963bdf8 100644 --- a/cmd/analyze-bin.go +++ b/cmd/analyze-bin.go @@ -796,16 +796,20 @@ func (b *analyzeBinCommand) buildStaticReportFile(ctx context.Context, staticRep } func (b *analyzeBinCommand) buildStaticReportOutput(ctx context.Context, log *os.File) error { - // build static report - cmd := exec.Command("./static-report.sh") + outputFileSrcPath := filepath.Join(b.homeKantraDir, "static-report", "public") + outputFileDestPath := filepath.Join(b.homeKantraDir, "static-report", "static-report") + + // move output.js file to build dir + cmd := exec.Command("cp", filepath.Join(outputFileSrcPath, "output.js"), + filepath.Join(outputFileDestPath, "output.js")) cmd.Stdout = log err := cmd.Run() if err != nil { return err } - // move build dir to analysis output - cmd = exec.Command("cp", "-r", filepath.Join(b.homeKantraDir, "static-report", "static-report"), b.output) + // move build dir to user output dir + cmd = exec.Command("cp", "-r", outputFileDestPath, b.output) cmd.Stdout = log err = cmd.Run() if err != nil { diff --git a/static-report.sh b/static-report.sh deleted file mode 100755 index 048c40c..0000000 --- a/static-report.sh +++ /dev/null @@ -1,19 +0,0 @@ -#!/bin/bash -set -x - -HOMEDIR="" - -if [ "$(uname)" == "Linux" ] || [ "$(uname)" == "Darwin" ]; then - HOMEDIR="$HOME" -else - # windows - HOMEDIR="%USERPROFILE%" -fi - -# TODO test this on windows -(cd ${HOMEDIR}/.kantra/static-report && -npm clean-install && -CI=true PUBLIC_URL=. npm run build && -cp ${HOMEDIR}/.kantra/static-report/public/output.js ${HOMEDIR}/.kantra/static-report/build/output.js && -rm -rf ${HOMEDIR}/.kantra/static-report/static-report && -mv ${HOMEDIR}/.kantra/static-report/build ${HOMEDIR}/.kantra/static-report/static-report)