Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,6 @@ go.work
go.work.sum

.idea/
.vscode/

cli-v2
cli-v2
4 changes: 2 additions & 2 deletions cmd/analyze.go
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ var analyzeCmd = &cobra.Command{
}

eslint := config.Config.Tools()["eslint"]
eslintInstallationDirectory := eslint.Info()["installDir"]
eslintInstallationDirectory := eslint.InstallDir
nodeRuntime := config.Config.Runtimes()["node"]
nodeBinary := nodeRuntime.Binaries["node"]

Expand All @@ -220,4 +220,4 @@ var analyzeCmd = &cobra.Command{

tools.RunEslint(workDirectory, eslintInstallationDirectory, nodeBinary, args, autoFix, outputFile, outputFormat)
},
}
}
20 changes: 5 additions & 15 deletions cmd/install.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package cmd

import (
cfg "codacy/cli-v2/config"
"fmt"
"log"

"github.com/spf13/cobra"
Expand Down Expand Up @@ -33,18 +32,9 @@ func installRuntimes(config *cfg.ConfigType) {
}

func installTools(config *cfg.ConfigType) {
for _, tool := range config.Tools() {
switch tool.Name() {
case "eslint":
// eslint needs node runtime
nodeRuntime := config.Runtimes()["node"]
err := cfg.InstallEslint(nodeRuntime, tool, registry)
if err != nil {
fmt.Println(err.Error())
log.Fatal(err)
}
default:
log.Fatal("Unknown tool:", tool.Name())
}
// Use the new tools-installer instead of manual installation
err := cfg.InstallTools()
if err != nil {
log.Fatal(err)
}
}
}
12 changes: 11 additions & 1 deletion config-file/configFile.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,22 @@ func parseConfigFile(configContents []byte) error {
return err
}

// Convert the tool strings to ToolConfig objects
toolConfigs := make([]plugins.ToolConfig, 0, len(configFile.TOOLS))
for _, tl := range configFile.TOOLS {
ct, err := parseConfigTool(tl)
if err != nil {
return err
}
config.Config.AddTool(config.NewRuntime(ct.name, ct.version))
toolConfigs = append(toolConfigs, plugins.ToolConfig{
Name: ct.name,
Version: ct.version,
})
}

// Add all tools at once
if err := config.Config.AddTools(toolConfigs); err != nil {
return err
}

return nil
Expand Down
22 changes: 16 additions & 6 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
projectConfigFile string

runtimes map[string]*plugins.RuntimeInfo
tools map[string]*Runtime
tools map[string]*plugins.ToolInfo
}

func (c *ConfigType) HomePath() string {
Expand Down Expand Up @@ -63,13 +63,23 @@
return nil
}

// TODO do inheritance with tool
func (c *ConfigType) Tools() map[string]*Runtime {
func (c *ConfigType) Tools() map[string]*plugins.ToolInfo {
return c.tools
}

func (c *ConfigType) AddTool(t *Runtime) {
c.tools[t.Name()] = t
func (c *ConfigType) AddTools(configs []plugins.ToolConfig) error {

Check notice on line 70 in config/config.go

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

config/config.go#L70

exported method ConfigType.AddTools should have comment or be unexported
// Process the tool configurations using the plugins.ProcessTools function
toolInfoMap, err := plugins.ProcessTools(configs, c.toolsDirectory)
if err != nil {
return err
}

// Store the tool information in the config
for name, info := range toolInfoMap {
c.tools[name] = info
}

return nil
}

func (c *ConfigType) initCodacyDirs() {
Expand Down Expand Up @@ -117,7 +127,7 @@
Config.initCodacyDirs()

Config.runtimes = make(map[string]*plugins.RuntimeInfo)
Config.tools = make(map[string]*Runtime)
Config.tools = make(map[string]*plugins.ToolInfo)
}

// Global singleton config-file
Expand Down
50 changes: 0 additions & 50 deletions config/eslint-utils.go

This file was deleted.

45 changes: 0 additions & 45 deletions config/runtime.go

This file was deleted.

127 changes: 127 additions & 0 deletions config/tools-installer.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
package config

import (
"bytes"
"codacy/cli-v2/plugins"
"fmt"
"log"
"os"
"os/exec"
"strings"
"text/template"

Check warning on line 11 in config/tools-installer.go

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

config/tools-installer.go#L11

When working with web applications that involve rendering user-generated content, it's important to properly escape any HTML content to prevent Cross-Site Scripting (XSS) attacks.
)

// InstallTools installs all tools defined in the configuration
func InstallTools() error {
for name, toolInfo := range Config.Tools() {
err := InstallTool(name, toolInfo)
if err != nil {
return fmt.Errorf("failed to install tool %s: %w", name, err)
}
}
return nil
}

// InstallTool installs a specific tool
func InstallTool(name string, toolInfo *plugins.ToolInfo) error {

Check failure on line 26 in config/tools-installer.go

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

config/tools-installer.go#L26

Method InstallTool has a cyclomatic complexity of 12 (limit is 10)
// Check if the tool is already installed
if isToolInstalled(toolInfo) {
fmt.Printf("Tool %s v%s is already installed\n", name, toolInfo.Version)
return nil
}

// Get the runtime for this tool
runtimeInfo, ok := Config.Runtimes()[toolInfo.Runtime]
if !ok {
return fmt.Errorf("required runtime %s not found for tool %s", toolInfo.Runtime, name)
}

// Make sure the installation directory exists
err := os.MkdirAll(toolInfo.InstallDir, 0755)

Check warning on line 40 in config/tools-installer.go

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

config/tools-installer.go#L40

Detected file permissions that are set to more than `0600` (user/owner can read and write). Setting file permissions to higher than `0600` is most likely unnecessary and violates the principle of least privilege.

Check warning on line 40 in config/tools-installer.go

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

config/tools-installer.go#L40

The application was found setting directory permissions to overly permissive values.
if err != nil {
return fmt.Errorf("failed to create installation directory: %w", err)
}

// Prepare template data
templateData := map[string]string{
"InstallDir": toolInfo.InstallDir,
"PackageName": toolInfo.Name,
"Version": toolInfo.Version,
"Registry": "", // TODO: Get registry from config
}

// Get package manager binary based on the tool configuration
packageManagerName := toolInfo.PackageManager
packageManagerBinary, ok := runtimeInfo.Binaries[packageManagerName]
if !ok {
return fmt.Errorf("package manager binary %s not found in runtime %s", packageManagerName, toolInfo.Runtime)
}

// Set registry if provided
if toolInfo.RegistryCommand != "" {
regCmd, err := executeToolTemplate(toolInfo.RegistryCommand, templateData)
if err != nil {
return fmt.Errorf("failed to prepare registry command: %w", err)
}

if regCmd != "" {
registryCmd := exec.Command(packageManagerBinary, strings.Split(regCmd, " ")...)

Check failure on line 68 in config/tools-installer.go

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

config/tools-installer.go#L68

Detected non-static command inside Command.

Check failure on line 68 in config/tools-installer.go

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

config/tools-installer.go#L68

OS command injection is a critical vulnerability that can lead to a full system compromise as it may allow an adversary to pass in arbitrary commands or arguments to be executed.
if output, err := registryCmd.CombinedOutput(); err != nil {
return fmt.Errorf("failed to set registry: %s: %w", string(output), err)
}
}
}

// Execute installation command
installCmd, err := executeToolTemplate(toolInfo.InstallCommand, templateData)
if err != nil {
return fmt.Errorf("failed to prepare install command: %w", err)
}

// Execute the installation command using the package manager
cmd := exec.Command(packageManagerBinary, strings.Split(installCmd, " ")...)

Check failure on line 82 in config/tools-installer.go

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

config/tools-installer.go#L82

Detected non-static command inside Command.

Check failure on line 82 in config/tools-installer.go

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

config/tools-installer.go#L82

OS command injection is a critical vulnerability that can lead to a full system compromise as it may allow an adversary to pass in arbitrary commands or arguments to be executed.

log.Printf("Installing %s v%s...\n", toolInfo.Name, toolInfo.Version)
output, err := cmd.CombinedOutput()
if err != nil {
return fmt.Errorf("failed to install tool: %s: %w", string(output), err)
}

log.Printf("Successfully installed %s v%s\n", toolInfo.Name, toolInfo.Version)
return nil
}

// isToolInstalled checks if a tool is already installed by checking for the binary
func isToolInstalled(toolInfo *plugins.ToolInfo) bool {
// If there are no binaries, check the install directory
if len(toolInfo.Binaries) == 0 {
_, err := os.Stat(toolInfo.InstallDir)
return err == nil
}

// Check if at least one binary exists
for _, binaryPath := range toolInfo.Binaries {
_, err := os.Stat(binaryPath)
if err == nil {
return true
}
}

return false
}

// executeToolTemplate executes a template with the given data
func executeToolTemplate(tmplStr string, data map[string]string) (string, error) {
tmpl, err := template.New("command").Parse(tmplStr)
if err != nil {
return "", err
}

var buf bytes.Buffer
err = tmpl.Execute(&buf, data)
if err != nil {
return "", err
}

return buf.String(), nil
}
Loading