Skip to content
Merged
Show file tree
Hide file tree
Changes from 9 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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ node_modules
frontend/dist
.idea
.vscode
.cursor

.scanoss
scanoss.json
Expand Down
36 changes: 35 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,37 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added
- Upcoming changes...

## [0.5.0]
## [0.6.0] 2024-02-03

### Added
- Add sort options for results:
- By path
- By match percentage
- Add empty state for results
- Add scan root selector and info in top bar


### Fixed
- Improved diff viewer scrolling performance
- Show help command without running the process
- Check for several python default install locations when running scan command
- Set proper scan root when executing the app from symlink

### Changed
- Use same color for left and right code viewers
- "Scan With Options" improvements
- Add advanced options input
- Do not allow to manually select output path
- Show boolean options as checkboxes
- Hide console output when no lines are available
- Create .scanoss directory if it does not exist

### Removed
- Remove "Scan Current Directory" menu option



## [0.5.0] - 2024-01-24
### Added
- Initial open source release
- React-based frontend for diff viewer
Expand All @@ -21,3 +51,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Keyboard shortcuts support
- Terminal output viewer
- Configuration management through CLI


[0.5.0]: https://github.com/scanoss/scanoss.cc/compare/v0.4.0...v0.5.0
[0.6.0]: https://github.com/scanoss/scanoss.cc/compare/v0.5.0...v0.6.0
26 changes: 11 additions & 15 deletions app.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ package main
import (
"context"
"fmt"
"os"
"slices"

"github.com/rs/zerolog/log"
Expand All @@ -43,6 +42,7 @@ type App struct {
ctx context.Context
scanossSettingsService service.ScanossSettingsService
keyboardService service.KeyboardService
cfg *config.Config
}

func NewApp() *App {
Expand All @@ -53,15 +53,16 @@ func (a *App) Init(ctx context.Context, scanossSettingsService service.ScanossSe
a.ctx = ctx
a.scanossSettingsService = scanossSettingsService
a.keyboardService = keyboardService
a.cfg = config.GetInstance()
a.startup()
}

func (a *App) startup() {
a.maybeSetWindowTitle()
a.initializeMenu()
log.Debug().Msgf("Scan Settings file path: %s", config.GetInstance().ScanSettingsFilePath)
log.Debug().Msgf("Results file path: %s", config.GetInstance().ResultFilePath)
log.Debug().Msgf("Scan Root file path: %s", config.GetInstance().ScanRoot)
log.Debug().Msgf("Scan Settings file path: %s", a.cfg.GetScanSettingsFilePath())
log.Debug().Msgf("Results file path: %s", a.cfg.GetResultFilePath())
log.Debug().Msgf("Scan Root file path: %s", a.cfg.GetScanRoot())
log.Info().Msgf("App Version: %s", entities.AppVersion)
}

Expand Down Expand Up @@ -186,31 +187,26 @@ func (a *App) SelectFile(defaultDir string) (string, error) {
return filePath, nil
}

func (a *App) GetWorkingDir() string {
workingDir, _ := os.Getwd()
return workingDir
}

func (a *App) GetScanRoot() (string, error) {
return config.GetInstance().ScanRoot, nil
return a.cfg.GetScanRoot(), nil
}

func (a *App) GetResultFilePath() (string, error) {
return config.GetInstance().ResultFilePath, nil
return a.cfg.GetResultFilePath(), nil
}

func (a *App) GetScanSettingsFilePath() (string, error) {
return config.GetInstance().ScanSettingsFilePath, nil
return a.cfg.GetScanSettingsFilePath(), nil
}

func (a *App) SetScanRoot(path string) {
config.GetInstance().SetScanRoot(path)
a.cfg.SetScanRoot(path)
}

func (a *App) SetResultFilePath(path string) {
config.GetInstance().SetResultFilePath(path)
a.cfg.SetResultFilePath(path)
}

func (a *App) SetScanSettingsFilePath(path string) {
config.GetInstance().SetScanSettingsFilePath(path)
a.cfg.SetScanSettingsFilePath(path)
}
41 changes: 41 additions & 0 deletions backend/entities/scan.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,44 @@ type ScanResponse struct {
ErrOutput string `json:"error_output,omitempty"`
Error error `json:"error,omitempty"`
}

type ScanArgDef struct {
Name string
Shorthand string
Default interface{}
Usage string
Type string
IsCore bool
IsFileSelector bool
}

var (
ScanArguments = []ScanArgDef{
{"wfp", "w", "", "Scan a WFP File instead of a folder (optional)", "string", false, true},
{"dep", "p", "", "Use a dependency file instead of a folder (optional)", "string", false, true},
{"stdin", "s", "", "Scan the file contents supplied via STDIN (optional)", "string", false, false},
{"files", "e", []string{}, "List of files to scan.", "stringSlice", false, false},
{"identify", "i", "", "Scan and identify components in SBOM file", "string", false, true},
{"ignore", "n", "", "Ignore components specified in the SBOM file", "string", false, true},
{"output", "o", "", "Output result file name (optional - default stdout).", "string", true, true},
{"format", "f", "plain", "Result output format (optional - default: plain)", "string", false, false},
{"threads", "T", 5, "Number of threads to use while scanning (optional - default 5)", "int", false, false},
{"flags", "F", 0, "Scanning engine flags", "int", false, false},
{"post-size", "P", 32, "Number of kilobytes to limit the post to while scanning (optional - default 32)", "int", false, false},
{"timeout", "M", 180, "Timeout (in seconds) for API communication (optional - default 180)", "int", false, false},
{"retry", "R", 5, "Retry limit for API communication (optional - default 5)", "int", false, false},
{"no-wfp-output", "", false, "Skip WFP file generation", "bool", false, false},
{"dependencies", "D", false, "Add Dependency scanning", "bool", false, false},
{"dependencies-only", "", false, "Run Dependency scanning only", "bool", false, false},
{"sc-command", "", "", "Scancode command and path if required (optional - default scancode).", "string", false, false},
{"sc-timeout", "", 600, "Timeout (in seconds) for scancode to complete (optional - default 600)", "int", false, false},
{"dep-scope", "", "", "Filter dependencies by scope - default all (options: dev/prod)", "string", false, false},
{"dep-scope-inc", "", "", "Include dependencies with declared scopes", "string", false, false},
{"dep-scope-exc", "", "", "Exclude dependencies with declared scopes", "string", false, false},
{"settings", "", "", "Settings file to use for scanning (optional - default scanoss.json)", "string", true, true},
{"skip-settings-file", "", false, "Skip default settings file (scanoss.json) if it exists", "bool", false, false},
{"debug", "d", false, "Enable debug messages", "bool", true, false},
{"trace", "t", false, "Enable trace messages, including API posts", "bool", true, false},
{"quiet", "q", true, "Enable quiet mode", "bool", true, false},
}
)
2 changes: 1 addition & 1 deletion backend/repository/component_repository_json_impl.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ func NewJSONComponentRepository(fr utils.FileReader) *JSONComponentRepository {
}

func (r *JSONComponentRepository) FindByFilePath(path string) (entities.Component, error) {
resultFilePath := config.GetInstance().ResultFilePath
resultFilePath := config.GetInstance().GetResultFilePath()

resultFileBytes, err := r.fr.ReadFile(resultFilePath)
if err != nil {
Expand Down
8 changes: 5 additions & 3 deletions backend/repository/file_repository_impl.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ func NewFileRepositoryImpl() FileRepository {
}

func (r *FileRepositoryImpl) ReadLocalFile(path string) (entities.File, error) {
scanRootPath := config.GetInstance().ScanRoot
scanRootPath := config.GetInstance().GetScanRoot()

absolutePath := filepath.Join(scanRootPath, path)

Expand All @@ -54,8 +54,10 @@ func (r *FileRepositoryImpl) ReadLocalFile(path string) (entities.File, error) {
}

func (r *FileRepositoryImpl) ReadRemoteFileByMD5(path string, md5 string) (entities.File, error) {
baseURL := config.GetInstance().ApiUrl
token := config.GetInstance().ApiToken
cfg := config.GetInstance()

baseURL := cfg.GetApiUrl()
token := cfg.GetApiToken()

url := fmt.Sprintf("%s/file_contents/%s", baseURL, md5)

Expand Down
2 changes: 1 addition & 1 deletion backend/repository/file_repository_impl_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ func TestFileRepositoryImpl(t *testing.T) {
err := os.WriteFile(absolutePath, testContent, 0644)
assert.NoError(t, err)

config.GetInstance().ScanRoot = currentPath
config.GetInstance().SetScanRoot(currentPath)

repo := NewFileRepositoryImpl()

Expand Down
7 changes: 5 additions & 2 deletions backend/repository/result_repository_json_impl.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ package repository

import (
"encoding/json"
"os"

"github.com/rs/zerolog/log"
"github.com/scanoss/scanoss.cc/backend/entities"
Expand All @@ -43,10 +44,12 @@ func NewResultRepositoryJsonImpl(fr utils.FileReader) *ResultRepositoryJsonImpl
}

func (r *ResultRepositoryJsonImpl) GetResults(filter entities.ResultFilter) ([]entities.Result, error) {
// Path to your JSON file
resultFilePath := config.GetInstance().ResultFilePath
resultFilePath := config.GetInstance().GetResultFilePath()
resultByte, err := r.fr.ReadFile(resultFilePath)
if err != nil {
if os.IsNotExist(err) {
return []entities.Result{}, nil
}
log.Error().Err(err).Msg("Error reading result file")
return []entities.Result{}, entities.ErrReadingResultFile
}
Expand Down
48 changes: 38 additions & 10 deletions backend/repository/scanoss_settings_repository_json_impl.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,35 +47,63 @@ func NewScanossSettingsJsonRepository(fr utils.FileReader) ScanossSettingsReposi
}

func (r *ScanossSettingsJsonRepository) Init() error {
r.mutex.Lock()
defer r.mutex.Unlock()
cfg := config.GetInstance()

if cfg == nil {
err := fmt.Errorf("config is not initialized")
log.Error().Err(err).Msg("Error initializing ScanossSettingsJsonRepository")
return err
}

r.setSettingsFile(cfg.GetScanSettingsFilePath())

cfg.RegisterListener(r.onConfigChange)

return nil
}

// Triggered when the config is changed (e.g. scan root, scan settings file path, etc.)
func (r *ScanossSettingsJsonRepository) onConfigChange(newCfg *config.Config) {
r.setSettingsFile(newCfg.GetScanSettingsFilePath())
}

func (r *ScanossSettingsJsonRepository) setSettingsFile(path string) {
sf, err := r.Read()

if err != nil {
log.Fatal().Err(err).Msgf("Error reading settings file: %v", config.GetInstance().ScanSettingsFilePath)
return err
log.Error().Err(err).Msgf("Error reading settings file: %v", path)
return
}

entities.ScanossSettingsJson = &entities.ScanossSettings{
SettingsFile: &sf,
if entities.ScanossSettingsJson == nil {
entities.ScanossSettingsJson = &entities.ScanossSettings{
SettingsFile: &sf,
}
}

return nil
entities.ScanossSettingsJson.SettingsFile = &sf
}

func (r *ScanossSettingsJsonRepository) Save() error {
r.mutex.Lock()
defer r.mutex.Unlock()

sf := r.GetSettings()
if err := utils.WriteJsonFile(config.GetInstance().ScanSettingsFilePath, sf); err != nil {
if err := utils.WriteJsonFile(config.GetInstance().GetScanSettingsFilePath(), sf); err != nil {
return err
}
return nil
}

func (r *ScanossSettingsJsonRepository) Read() (entities.SettingsFile, error) {
if config.GetInstance() == nil {
r.mutex.RLock()
defer r.mutex.RUnlock()

cfg := config.GetInstance()
if cfg == nil {
return entities.SettingsFile{}, fmt.Errorf("config is not initialized")
}
scanSettingsFileBytes, err := r.fr.ReadFile(config.GetInstance().ScanSettingsFilePath)
scanSettingsFileBytes, err := r.fr.ReadFile(cfg.GetScanSettingsFilePath())
if err != nil {
if errors.Is(err, os.ErrNotExist) {
return entities.SettingsFile{}, nil
Expand Down
46 changes: 38 additions & 8 deletions backend/service/scan_service_python_cli_impl.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,10 @@ import (
"io"
"os"
"os/exec"
"path/filepath"

"github.com/rs/zerolog/log"
"github.com/scanoss/scanoss.cc/backend/entities"
"github.com/scanoss/scanoss.cc/internal/config"
"github.com/wailsapp/wails/v2/pkg/runtime"
)
Expand Down Expand Up @@ -112,6 +115,9 @@ func (s *ScanServicePythonImpl) executeScanWithPipes(args []string) (*exec.Cmd,

cmdArgs = append(cmdArgs, sensitiveArgs...)

// If the output folder does not exist, create it. This should be handled by the python cli
s.maybeCreateOutputFolder(args)

cmd := exec.Command(s.cmd, cmdArgs...)

stdout, err := cmd.StdoutPipe()
Expand Down Expand Up @@ -182,12 +188,12 @@ func (s *ScanServicePythonImpl) GetDefaultScanArgs() []string {
args := []string{}
cfg := config.GetInstance()

if cfg.ResultFilePath != "" {
args = append(args, "--output", cfg.ResultFilePath)
if cfg.GetResultFilePath() != "" {
args = append(args, "--output", cfg.GetResultFilePath())
}

if cfg.ScanSettingsFilePath != "" {
args = append(args, "--settings", cfg.ScanSettingsFilePath)
if cfg.GetScanSettingsFilePath() != "" {
args = append(args, "--settings", cfg.GetScanSettingsFilePath())
}

return args
Expand All @@ -197,12 +203,12 @@ func (s *ScanServicePythonImpl) GetSensitiveDefaultScanArgs() []string {
args := make([]string, 0)
cfg := config.GetInstance()

if cfg.ApiToken != "" {
args = append(args, "--key", cfg.ApiToken)
if cfg.GetApiToken() != "" {
args = append(args, "--key", cfg.GetApiToken())
}

if cfg.ApiUrl != "" {
args = append(args, "--apiurl", fmt.Sprintf("%s/scan/direct", cfg.ApiUrl))
if cfg.GetApiUrl() != "" {
args = append(args, "--apiurl", fmt.Sprintf("%s/scan/direct", cfg.GetApiUrl()))
}

return args
Expand All @@ -213,3 +219,27 @@ func (s *ScanServicePythonImpl) emitEvent(eventName string, data ...interface{})
runtime.EventsEmit(s.ctx, eventName, data...)
}
}

func (s *ScanServicePythonImpl) GetScanArgs() []entities.ScanArgDef {
return entities.ScanArguments
}

func (s *ScanServicePythonImpl) maybeCreateOutputFolder(args []string) {
outputPath := s.getOutputPathFromArgs(args)
outputFolder := filepath.Dir(outputPath)
if outputFolder != "" {
if _, err := os.Stat(outputFolder); os.IsNotExist(err) {
log.Info().Msgf("The provided output path does not exist. Creating it: %s", outputFolder)
os.MkdirAll(outputFolder, os.ModePerm)
}
}
}

func (s *ScanServicePythonImpl) getOutputPathFromArgs(args []string) string {
for i := 0; i < len(args)-1; i++ {
if args[i] == "--output" {
return args[i+1]
}
}
return ""
}
Loading
Loading