Skip to content

Commit

Permalink
Merge branch 'main' into 3626-disable-license-content
Browse files Browse the repository at this point in the history
* main:
  Add file catalogers to selection configuration (#3505)
  chore: replace all shorthand tags of mapstruct -> mapstructure (#3633)
  chore(deps): update tools to latest versions (#3637)
  chore(deps): update CPE dictionary index (#3638)
  feat: syft 3435 - add file components to cyclonedx bom output when file metadata is available (#3539)
  chore(deps): update tools to latest versions (#3635)
  chore(deps): bump github/codeql-action from 3.28.7 to 3.28.8 (#3634)
  • Loading branch information
spiffcs committed Feb 5, 2025
2 parents 578a3d4 + 684b6e3 commit 2b91d09
Show file tree
Hide file tree
Showing 33 changed files with 1,504 additions and 381 deletions.
2 changes: 1 addition & 1 deletion .binny.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ tools:
# used for triggering a release
- name: gh
version:
want: v2.65.0
want: v2.66.1
method: github-release
with:
repo: cli/cli
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/codeql-analysis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ jobs:

# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@6e5455904168f98c75d8e5ad848b4dc4ab3ae77e #v3.28.7
uses: github/codeql-action/init@dd746615b3b9d728a6a37ca2045b68ca76d4841a #v3.28.8
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
Expand All @@ -56,7 +56,7 @@ jobs:
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@6e5455904168f98c75d8e5ad848b4dc4ab3ae77e #v3.28.7
uses: github/codeql-action/autobuild@dd746615b3b9d728a6a37ca2045b68ca76d4841a #v3.28.8

# ℹ️ Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl
Expand All @@ -70,4 +70,4 @@ jobs:
# make release

- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@6e5455904168f98c75d8e5ad848b4dc4ab3ae77e #v3.28.7
uses: github/codeql-action/analyze@dd746615b3b9d728a6a37ca2045b68ca76d4841a #v3.28.8
4 changes: 2 additions & 2 deletions cmd/syft/internal/clio_setup_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import (

"github.com/anchore/clio"
"github.com/anchore/stereoscope"
ui2 "github.com/anchore/syft/cmd/syft/cli/ui"
handler "github.com/anchore/syft/cmd/syft/cli/ui"
"github.com/anchore/syft/cmd/syft/internal/ui"
"github.com/anchore/syft/internal/bus"
"github.com/anchore/syft/internal/log"
Expand All @@ -28,7 +28,7 @@ func AppClioSetupConfig(id clio.Identification, out io.Writer) *clio.SetupConfig

return clio.NewUICollection(
ui.New(out, cfg.Log.Quiet,
ui2.New(ui2.DefaultHandlerConfig()),
handler.New(handler.DefaultHandlerConfig()),
),
noUI,
), nil
Expand Down
152 changes: 106 additions & 46 deletions cmd/syft/internal/commands/cataloger_list.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package commands
import (
"encoding/json"
"fmt"
"os"
"sort"
"strings"

Expand All @@ -14,7 +15,15 @@ import (
"github.com/anchore/clio"
"github.com/anchore/syft/internal/bus"
"github.com/anchore/syft/internal/task"
"github.com/anchore/syft/syft/cataloging/pkgcataloging"
"github.com/anchore/syft/syft/cataloging"
)

var (
activelyAddedStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("10")) // hi green
deselectedStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("8")) // dark grey
activelyRemovedStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("9")) // high red
defaultStyle = lipgloss.NewStyle().Underline(true)
deselectedDefaultStyle = lipgloss.NewStyle().Inherit(deselectedStyle).Underline(true)
)

type catalogerListOptions struct {
Expand Down Expand Up @@ -44,22 +53,29 @@ func CatalogerList(app clio.Application) *cobra.Command {
opts := defaultCatalogerListOptions()

return app.SetupCommand(&cobra.Command{
Use: "list [OPTIONS]",
Short: "List available catalogers",
Use: "list [OPTIONS]",
Short: "List available catalogers",
PreRunE: disableUI(app, os.Stdout),
RunE: func(_ *cobra.Command, _ []string) error {
return runCatalogerList(opts)
},
}, opts)
}

func runCatalogerList(opts *catalogerListOptions) error {
factories := task.DefaultPackageTaskFactories()
allTasks, err := factories.Tasks(task.DefaultCatalogingFactoryConfig())
pkgTaskFactories := task.DefaultPackageTaskFactories()
fileTaskFactories := task.DefaultFileTaskFactories()
allPkgTasks, err := pkgTaskFactories.Tasks(task.DefaultCatalogingFactoryConfig())
if err != nil {
return fmt.Errorf("unable to create pkg cataloger tasks: %w", err)
}

allFileTasks, err := fileTaskFactories.Tasks(task.DefaultCatalogingFactoryConfig())
if err != nil {
return fmt.Errorf("unable to create cataloger tasks: %w", err)
return fmt.Errorf("unable to create file cataloger tasks: %w", err)
}

report, err := catalogerListReport(opts, allTasks)
report, err := catalogerListReport(opts, [][]task.Task{allPkgTasks, allFileTasks})
if err != nil {
return fmt.Errorf("unable to generate cataloger list report: %w", err)
}
Expand All @@ -69,9 +85,10 @@ func runCatalogerList(opts *catalogerListOptions) error {
return nil
}

func catalogerListReport(opts *catalogerListOptions, allTasks []task.Task) (string, error) {
selectedTasks, selectionEvidence, err := task.Select(allTasks,
pkgcataloging.NewSelectionRequest().
func catalogerListReport(opts *catalogerListOptions, allTaskGroups [][]task.Task) (string, error) {
selectedTaskGroups, selectionEvidence, err := task.SelectInGroups(
allTaskGroups,
cataloging.NewSelectionRequest().
WithDefaults(opts.DefaultCatalogers...).
WithExpression(opts.SelectCatalogers...),
)
Expand All @@ -82,12 +99,12 @@ func catalogerListReport(opts *catalogerListOptions, allTasks []task.Task) (stri

switch opts.Output {
case "json":
report, err = renderCatalogerListJSON(selectedTasks, selectionEvidence, opts.DefaultCatalogers, opts.SelectCatalogers)
report, err = renderCatalogerListJSON(flattenTaskGroups(selectedTaskGroups), selectionEvidence, opts.DefaultCatalogers, opts.SelectCatalogers)
case "table", "":
if opts.ShowHidden {
report = renderCatalogerListTable(allTasks, selectionEvidence, opts.DefaultCatalogers, opts.SelectCatalogers)
report = renderCatalogerListTables(allTaskGroups, selectionEvidence)
} else {
report = renderCatalogerListTable(selectedTasks, selectionEvidence, opts.DefaultCatalogers, opts.SelectCatalogers)
report = renderCatalogerListTables(selectedTaskGroups, selectionEvidence)
}
}

Expand All @@ -98,6 +115,14 @@ func catalogerListReport(opts *catalogerListOptions, allTasks []task.Task) (stri
return report, nil
}

func flattenTaskGroups(taskGroups [][]task.Task) []task.Task {
var allTasks []task.Task
for _, tasks := range taskGroups {
allTasks = append(allTasks, tasks...)
}
return allTasks
}

func renderCatalogerListJSON(tasks []task.Task, selection task.Selection, defaultSelections, selections []string) (string, error) {
type node struct {
Name string `json:"name"`
Expand All @@ -109,7 +134,12 @@ func renderCatalogerListJSON(tasks []task.Task, selection task.Selection, defaul
nodesByName := make(map[string]node)

for name := range tagsByName {
tagsSelected := selection.TokensByTask[name].SelectedOn.List()
tokensByTask, ok := selection.TokensByTask[name]

var tagsSelected []string
if ok {
tagsSelected = tokensByTask.SelectedOn.List()
}

if len(tagsSelected) == 1 && tagsSelected[0] == "all" {
tagsSelected = tagsByName[name]
Expand Down Expand Up @@ -153,10 +183,56 @@ func renderCatalogerListJSON(tasks []task.Task, selection task.Selection, defaul
return string(by), err
}

func renderCatalogerListTable(tasks []task.Task, selection task.Selection, defaultSelections, selections []string) string {
func renderCatalogerListTables(taskGroups [][]task.Task, selection task.Selection) string {
pkgCatalogerTable := renderCatalogerListTable(taskGroups[0], selection, "Package Cataloger")
fileCatalogerTable := renderCatalogerListTable(taskGroups[1], selection, "File Cataloger")

report := fileCatalogerTable + "\n" + pkgCatalogerTable + "\n"

hasAdditions := len(selection.Request.AddNames) > 0
hasDefaults := len(selection.Request.DefaultNamesOrTags) > 0
hasRemovals := len(selection.Request.RemoveNamesOrTags) > 0
hasSubSelections := len(selection.Request.SubSelectTags) > 0
expressions := len(selection.Request.SubSelectTags) + len(selection.Request.AddNames) + len(selection.Request.RemoveNamesOrTags)

var header string

header += fmt.Sprintf("Default selections: %d\n", len(selection.Request.DefaultNamesOrTags))
if hasDefaults {
for _, expr := range selection.Request.DefaultNamesOrTags {
header += fmt.Sprintf(" • '%s'\n", expr)
}
}

header += fmt.Sprintf("Selection expressions: %d\n", expressions)

if hasSubSelections {
for _, n := range selection.Request.SubSelectTags {
header += fmt.Sprintf(" • '%s' (intersect)\n", n)
}
}
if hasRemovals {
for _, n := range selection.Request.RemoveNamesOrTags {
header += fmt.Sprintf(" • '-%s' (remove)\n", n)
}
}
if hasAdditions {
for _, n := range selection.Request.AddNames {
header += fmt.Sprintf(" • '+%s' (add)\n", n)
}
}

return header + report
}

func renderCatalogerListTable(tasks []task.Task, selection task.Selection, kindTitle string) string {
if len(tasks) == 0 {
return activelyRemovedStyle.Render(fmt.Sprintf("No %ss selected", strings.ToLower(kindTitle)))
}

t := table.NewWriter()
t.SetStyle(table.StyleLight)
t.AppendHeader(table.Row{"Cataloger", "Tags"})
t.AppendHeader(table.Row{kindTitle, "Tags"})

names, tagsByName := extractTaskInfo(tasks)

Expand All @@ -172,74 +248,58 @@ func renderCatalogerListTable(tasks []task.Task, selection task.Selection, defau

report := t.Render()

if len(selections) > 0 {
header := "Selected by expressions:\n"
for _, expr := range selections {
header += fmt.Sprintf(" - %q\n", expr)
}
report = header + report
}

if len(defaultSelections) > 0 {
header := "Default selections:\n"
for _, expr := range defaultSelections {
header += fmt.Sprintf(" - %q\n", expr)
}
report = header + report
}

return report
}

func formatRow(name string, tags []string, selection task.Selection) table.Row {
isIncluded := selection.Result.Has(name)
defaults := strset.New(selection.Request.DefaultNamesOrTags...)
var selections *task.TokenSelection
if s, exists := selection.TokensByTask[name]; exists {
selections = &s
}

var formattedTags []string
for _, tag := range tags {
formattedTags = append(formattedTags, formatToken(tag, selections, isIncluded))
formattedTags = append(formattedTags, formatToken(tag, selections, isIncluded, defaults))
}

var tagStr string
if isIncluded {
tagStr = strings.Join(formattedTags, ", ")
} else {
tagStr = strings.Join(formattedTags, grey.Render(", "))
tagStr = strings.Join(formattedTags, deselectedStyle.Render(", "))
}

// TODO: selection should keep warnings (non-selections) in struct

return table.Row{
formatToken(name, selections, isIncluded),
formatToken(name, selections, isIncluded, defaults),
tagStr,
}
}

var (
green = lipgloss.NewStyle().Foreground(lipgloss.Color("10")) // hi green
grey = lipgloss.NewStyle().Foreground(lipgloss.Color("8")) // dark grey
red = lipgloss.NewStyle().Foreground(lipgloss.Color("9")) // high red
)

func formatToken(token string, selection *task.TokenSelection, included bool) string {
func formatToken(token string, selection *task.TokenSelection, included bool, defaults *strset.Set) string {
if included && selection != nil {
// format all tokens in selection in green
if selection.SelectedOn.Has(token) {
return green.Render(token)
if defaults.Has(token) {
return defaultStyle.Render(token)
}
return activelyAddedStyle.Render(token)
}

return token
}

// format all tokens in selection in red, all others in grey
if selection != nil && selection.DeselectedOn.Has(token) {
return red.Render(token)
return activelyRemovedStyle.Render(token)
}

return grey.Render(token)
if defaults.Has(token) {
return deselectedDefaultStyle.Render(token)
}
return deselectedStyle.Render(token)
}

func extractTaskInfo(tasks []task.Task) ([]string, map[string][]string) {
Expand Down
Loading

0 comments on commit 2b91d09

Please sign in to comment.