mirror of
https://github.com/anchore/syft.git
synced 2026-10-15 15:47:23 +02:00
Compare commits
57
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3cffa0b7fd | ||
|
|
da03e981c3 | ||
|
|
4aa2d8c0af | ||
|
|
a635d66657 | ||
|
|
51d3cd0066 | ||
|
|
4846639ee4 | ||
|
|
6030a69b17 | ||
|
|
8b9194eb81 | ||
|
|
56a1ab54d2 | ||
|
|
f4dd36ca9d | ||
|
|
17c605822e | ||
|
|
4eace4b141 | ||
|
|
05660da8d7 | ||
|
|
2f378d806e | ||
|
|
b83cc8485a | ||
|
|
38a12bd91a | ||
|
|
649d152548 | ||
|
|
f5d5892434 | ||
|
|
51831d303c | ||
|
|
09e62c3282 | ||
|
|
d39ef44e40 | ||
|
|
8bca0ac39e | ||
|
|
67dbd1fe4c | ||
|
|
402227f0b3 | ||
|
|
2bcf825857 | ||
|
|
9cb7c3d350 | ||
|
|
e789e0714d | ||
|
|
790ecc6f28 | ||
|
|
b9462db59e | ||
|
|
bfad9659a8 | ||
|
|
b345752f49 | ||
|
|
ba9dd1d5fd | ||
|
|
68f35815d6 | ||
|
|
4d4b502174 | ||
|
|
ea80f94c0e | ||
|
|
2c145f70b2 | ||
|
|
bcc7e90fcc | ||
|
|
fa1baabc05 | ||
|
|
b5906824cb | ||
|
|
16dee41b4b | ||
|
|
23778de112 | ||
|
|
3ba9df4ff3 | ||
|
|
bbf223b2c9 | ||
|
|
b126276f97 | ||
|
|
40d766a257 | ||
|
|
814960f65a | ||
|
|
13758260dd | ||
|
|
11039f4b4e | ||
|
|
413ffdb233 | ||
|
|
e53fe51612 | ||
|
|
facbc486a8 | ||
|
|
5d42a349e6 | ||
|
|
4adfbeb5f0 | ||
|
|
b943da6433 | ||
|
|
e8119acf93 | ||
|
|
06b9a79e3d | ||
|
|
ef5c1651ef |
+4
-4
@@ -1,7 +1,7 @@
|
||||
tools:
|
||||
- name: binny
|
||||
version:
|
||||
want: v0.6.2
|
||||
want: v0.6.3
|
||||
method: github-release
|
||||
with:
|
||||
repo: anchore/binny
|
||||
@@ -29,7 +29,7 @@ tools:
|
||||
|
||||
- name: cosign
|
||||
version:
|
||||
want: v2.2.1
|
||||
want: v2.2.2
|
||||
method: github-release
|
||||
with:
|
||||
repo: sigstore/cosign
|
||||
@@ -83,14 +83,14 @@ tools:
|
||||
|
||||
- name: task
|
||||
version:
|
||||
want: v3.31.0
|
||||
want: v3.32.0
|
||||
method: github-release
|
||||
with:
|
||||
repo: go-task/task
|
||||
|
||||
- name: gh
|
||||
version:
|
||||
want: v2.39.2
|
||||
want: v2.40.1
|
||||
method: github-release
|
||||
with:
|
||||
repo: cli/cli
|
||||
|
||||
@@ -39,7 +39,7 @@ jobs:
|
||||
OUTPUT="${OUTPUT//$'\r'/'%0D'}" # URL encode all '\r' characters
|
||||
echo "result=$OUTPUT" >> $GITHUB_OUTPUT
|
||||
|
||||
- uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3
|
||||
- uses: actions/upload-artifact@c7d193f32edcb7bfad88892161225aeda64e9392 # v4.0.0
|
||||
with:
|
||||
name: benchmark-test-results
|
||||
path: test/results/**/*
|
||||
|
||||
@@ -39,13 +39,13 @@ jobs:
|
||||
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 #v4.1.1
|
||||
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe #v4.1.0
|
||||
uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 #v5.0.0
|
||||
with:
|
||||
go-version-file: go.mod
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@407ffafae6a767df3e0230c3df91b6443ae8df75 #v2.22.8
|
||||
uses: github/codeql-action/init@b374143c1149a9115d881581d29b8390bbcbb59c #v3.22.11
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||
@@ -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@407ffafae6a767df3e0230c3df91b6443ae8df75 #v2.22.8
|
||||
uses: github/codeql-action/autobuild@b374143c1149a9115d881581d29b8390bbcbb59c #v3.22.11
|
||||
|
||||
# ℹ️ Command-line programs to run using the OS shell.
|
||||
# 📚 https://git.io/JvXDl
|
||||
@@ -70,4 +70,4 @@ jobs:
|
||||
# make release
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@407ffafae6a767df3e0230c3df91b6443ae8df75 #v2.22.8
|
||||
uses: github/codeql-action/analyze@b374143c1149a9115d881581d29b8390bbcbb59c #v3.22.11
|
||||
|
||||
@@ -30,7 +30,7 @@ jobs:
|
||||
echo -n "commit=$(git rev-parse HEAD)" | tee -a $GITHUB_OUTPUT
|
||||
|
||||
- name: Update Homebrew formula
|
||||
uses: dawidd6/action-homebrew-bump-formula@d3667e5ae14df19579e4414897498e3e88f2f458 # v3.10.0
|
||||
uses: dawidd6/action-homebrew-bump-formula@75ed025ff3ad1d617862838b342b06d613a0ddf3 # v3.10.1
|
||||
with:
|
||||
token: ${{ secrets.HOMEBREW_TOKEN }}
|
||||
org: anchore
|
||||
|
||||
@@ -141,7 +141,7 @@ jobs:
|
||||
AWS_ACCESS_KEY_ID: ${{ secrets.TOOLBOX_AWS_ACCESS_KEY_ID }}
|
||||
AWS_SECRET_ACCESS_KEY: ${{ secrets.TOOLBOX_AWS_SECRET_ACCESS_KEY }}
|
||||
|
||||
- uses: anchore/sbom-action@fd74a6fb98a204a1ad35bbfae0122c1a302ff88b #v0.15.0
|
||||
- uses: anchore/sbom-action@5ecf649a417b8ae17dc8383dc32d46c03f2312df #v0.15.1
|
||||
continue-on-error: true
|
||||
with:
|
||||
artifact-name: sbom.spdx.json
|
||||
|
||||
@@ -19,7 +19,7 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 #v4.1.1
|
||||
|
||||
- uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe #v4.1.0
|
||||
- uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 #v5.0.0
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
stable: ${{ env.GO_STABLE_VERSION }}
|
||||
|
||||
@@ -121,7 +121,7 @@ syft <image> --scope all-layers
|
||||
|
||||
### Supported sources
|
||||
|
||||
Syft can generate a SBOM from a variety of sources:
|
||||
Syft can generate an SBOM from a variety of sources:
|
||||
|
||||
```
|
||||
# catalog a container image archive (from the result of `docker image save ...`, `podman save ...`, or `skopeo copy` commands)
|
||||
@@ -656,6 +656,10 @@ python:
|
||||
# when given an arbitrary constraint will be used (even if that version may not be available/published).
|
||||
guess-unpinned-requirements: false
|
||||
|
||||
javascript:
|
||||
search-remote-licenses: false
|
||||
npm-base-url: "https://registry.npmjs.org"
|
||||
|
||||
file-contents:
|
||||
cataloger:
|
||||
# enable/disable cataloging of file contents
|
||||
|
||||
@@ -16,6 +16,7 @@ import (
|
||||
"github.com/anchore/syft/syft/pkg/cataloger"
|
||||
golangCataloger "github.com/anchore/syft/syft/pkg/cataloger/golang"
|
||||
javaCataloger "github.com/anchore/syft/syft/pkg/cataloger/java"
|
||||
javascriptCataloger "github.com/anchore/syft/syft/pkg/cataloger/javascript"
|
||||
"github.com/anchore/syft/syft/pkg/cataloger/kernel"
|
||||
pythonCataloger "github.com/anchore/syft/syft/pkg/cataloger/python"
|
||||
"github.com/anchore/syft/syft/source"
|
||||
@@ -26,6 +27,7 @@ type Catalog struct {
|
||||
Package pkg `yaml:"package" json:"package" mapstructure:"package"`
|
||||
Golang golang `yaml:"golang" json:"golang" mapstructure:"golang"`
|
||||
Java java `yaml:"java" json:"java" mapstructure:"java"`
|
||||
Javascript javascript `yaml:"javascript" json:"javascript" mapstructure:"javascript"`
|
||||
LinuxKernel linuxKernel `yaml:"linux-kernel" json:"linux-kernel" mapstructure:"linux-kernel"`
|
||||
Python python `yaml:"python" json:"python" mapstructure:"python"`
|
||||
FileMetadata fileMetadata `yaml:"file-metadata" json:"file-metadata" mapstructure:"file-metadata"`
|
||||
@@ -145,6 +147,9 @@ func (cfg Catalog) ToCatalogerConfig() cataloger.Config {
|
||||
IncludeUnindexedArchives: cfg.Package.SearchUnindexedArchives,
|
||||
},
|
||||
cfg.Java.MaxParentRecursiveDepth),
|
||||
Javascript: javascriptCataloger.DefaultCatalogerConfig().
|
||||
WithSearchRemoteLicenses(cfg.Javascript.SearchRemoteLicenses).
|
||||
WithNpmBaseURL(cfg.Javascript.NpmBaseURL),
|
||||
Python: pythonCataloger.CatalogerConfig{
|
||||
GuessUnpinnedRequirements: cfg.Python.GuessUnpinnedRequirements,
|
||||
},
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
package options
|
||||
|
||||
type javascript struct {
|
||||
SearchRemoteLicenses bool `json:"search-remote-licenses" yaml:"search-remote-licenses" mapstructure:"search-remote-licenses"`
|
||||
NpmBaseURL string `json:"npm-base-url" yaml:"npm-base-url" mapstructure:"npm-base-url"`
|
||||
}
|
||||
@@ -1,16 +1,24 @@
|
||||
|
||||
[TestHandler_handleCatalogerTaskStarted/cataloging_task_in_progress - 1]
|
||||
some task title [some value]
|
||||
⠙ Cataloging contents
|
||||
⠙ some task title ━━━━━━━━━━━━━━━━━━━━ [some stage]
|
||||
---
|
||||
|
||||
[TestHandler_handleCatalogerTaskStarted/cataloging_sub_task_in_progress - 1]
|
||||
└── some task title [some value]
|
||||
⠙ Cataloging contents
|
||||
└── ⠙ some task title ━━━━━━━━━━━━━━━━━━━━ [some stage]
|
||||
---
|
||||
|
||||
[TestHandler_handleCatalogerTaskStarted/cataloging_sub_task_complete - 1]
|
||||
✔ └── some task done [some value]
|
||||
⠙ Cataloging contents
|
||||
└── ✔ some task done [some stage]
|
||||
---
|
||||
|
||||
[TestHandler_handleCatalogerTaskStarted/cataloging_sub_task_complete_--_hide_stage - 1]
|
||||
⠙ Cataloging contents
|
||||
└── ✔ some task done
|
||||
---
|
||||
|
||||
[TestHandler_handleCatalogerTaskStarted/cataloging_sub_task_complete_with_removal - 1]
|
||||
|
||||
⠙ Cataloging contents
|
||||
---
|
||||
|
||||
@@ -100,18 +100,21 @@ func TestHandler_handleAttestationStarted(t *testing.T) {
|
||||
Height: 80,
|
||||
}
|
||||
|
||||
models := handler.Handle(event)
|
||||
models, _ := handler.Handle(event)
|
||||
require.Len(t, models, 2)
|
||||
|
||||
t.Run("task line", func(t *testing.T) {
|
||||
tsk, ok := models[0].(taskprogress.Model)
|
||||
require.True(t, ok)
|
||||
|
||||
got := runModel(t, tsk, tt.iterations, taskprogress.TickMsg{
|
||||
gotModel := runModel(t, tsk, tt.iterations, taskprogress.TickMsg{
|
||||
Time: time.Now(),
|
||||
Sequence: tsk.Sequence(),
|
||||
ID: tsk.ID(),
|
||||
})
|
||||
|
||||
got := gotModel.View()
|
||||
|
||||
t.Log(got)
|
||||
snaps.MatchSnapshot(t, got)
|
||||
})
|
||||
@@ -119,11 +122,15 @@ func TestHandler_handleAttestationStarted(t *testing.T) {
|
||||
t.Run("log", func(t *testing.T) {
|
||||
log, ok := models[1].(attestLogFrame)
|
||||
require.True(t, ok)
|
||||
got := runModel(t, log, tt.iterations, attestLogFrameTickMsg{
|
||||
|
||||
gotModel := runModel(t, log, tt.iterations, attestLogFrameTickMsg{
|
||||
Time: time.Now(),
|
||||
Sequence: log.sequence,
|
||||
ID: log.id,
|
||||
}, log.reader.running)
|
||||
|
||||
got := gotModel.View()
|
||||
|
||||
t.Log(got)
|
||||
snaps.MatchSnapshot(t, got)
|
||||
})
|
||||
|
||||
@@ -3,70 +3,121 @@ package ui
|
||||
import (
|
||||
tea "github.com/charmbracelet/bubbletea"
|
||||
"github.com/charmbracelet/lipgloss"
|
||||
"github.com/google/uuid"
|
||||
"github.com/wagoodman/go-partybus"
|
||||
"github.com/wagoodman/go-progress"
|
||||
|
||||
"github.com/anchore/bubbly/bubbles/taskprogress"
|
||||
"github.com/anchore/bubbly/bubbles/tree"
|
||||
"github.com/anchore/syft/internal/log"
|
||||
"github.com/anchore/syft/syft/event/monitor"
|
||||
syftEventParsers "github.com/anchore/syft/syft/event/parsers"
|
||||
)
|
||||
|
||||
var _ progress.Stager = (*catalogerTaskStageAdapter)(nil)
|
||||
// we standardize how rows are instantiated to ensure consistency in the appearance across the UI
|
||||
type taskModelFactory func(title taskprogress.Title, opts ...taskprogress.Option) taskprogress.Model
|
||||
|
||||
type catalogerTaskStageAdapter struct {
|
||||
mon *monitor.CatalogerTask
|
||||
var _ tea.Model = (*catalogerTaskModel)(nil)
|
||||
|
||||
type catalogerTaskModel struct {
|
||||
model tree.Model
|
||||
modelFactory taskModelFactory
|
||||
}
|
||||
|
||||
func newCatalogerTaskStageAdapter(mon *monitor.CatalogerTask) *catalogerTaskStageAdapter {
|
||||
return &catalogerTaskStageAdapter{
|
||||
mon: mon,
|
||||
func newCatalogerTaskTreeModel(f taskModelFactory) *catalogerTaskModel {
|
||||
t := tree.NewModel()
|
||||
t.Padding = " "
|
||||
t.RootsWithoutPrefix = true
|
||||
return &catalogerTaskModel{
|
||||
modelFactory: f,
|
||||
model: t,
|
||||
}
|
||||
}
|
||||
|
||||
func (c catalogerTaskStageAdapter) Stage() string {
|
||||
return c.mon.GetValue()
|
||||
type newCatalogerTaskRowEvent struct {
|
||||
info monitor.GenericTask
|
||||
prog progress.StagedProgressable
|
||||
}
|
||||
|
||||
func (m *Handler) handleCatalogerTaskStarted(e partybus.Event) []tea.Model {
|
||||
mon, err := syftEventParsers.ParseCatalogerTaskStarted(e)
|
||||
if err != nil {
|
||||
log.WithFields("error", err).Warn("unable to parse event")
|
||||
return nil
|
||||
func (cts catalogerTaskModel) Init() tea.Cmd {
|
||||
return cts.model.Init()
|
||||
}
|
||||
|
||||
func (cts catalogerTaskModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
event, ok := msg.(newCatalogerTaskRowEvent)
|
||||
if !ok {
|
||||
model, cmd := cts.model.Update(msg)
|
||||
cts.model = model.(tree.Model)
|
||||
|
||||
return cts, cmd
|
||||
}
|
||||
|
||||
var prefix string
|
||||
if mon.SubStatus {
|
||||
// TODO: support list of sub-statuses, not just a single leaf
|
||||
prefix = "└── "
|
||||
}
|
||||
info, prog := event.info, event.prog
|
||||
|
||||
tsk := m.newTaskProgress(
|
||||
tsk := cts.modelFactory(
|
||||
taskprogress.Title{
|
||||
// TODO: prefix should not be part of the title, but instead a separate field that is aware of the tree structure
|
||||
Default: prefix + mon.Title,
|
||||
Running: prefix + mon.Title,
|
||||
Success: prefix + mon.TitleOnCompletion,
|
||||
Default: info.Title.Default,
|
||||
Running: info.Title.WhileRunning,
|
||||
Success: info.Title.OnSuccess,
|
||||
},
|
||||
taskprogress.WithStagedProgressable(
|
||||
struct {
|
||||
progress.Stager
|
||||
progress.Progressable
|
||||
}{
|
||||
Progressable: mon.GetMonitor(),
|
||||
Stager: newCatalogerTaskStageAdapter(mon),
|
||||
},
|
||||
),
|
||||
taskprogress.WithStagedProgressable(prog),
|
||||
)
|
||||
|
||||
// TODO: this isn't ideal since the model stays around after it is no longer needed, but it works for now
|
||||
tsk.HideOnSuccess = mon.RemoveOnCompletion
|
||||
tsk.HideStageOnSuccess = false
|
||||
tsk.HideProgressOnSuccess = false
|
||||
if info.Context != "" {
|
||||
tsk.Context = []string{info.Context}
|
||||
}
|
||||
|
||||
tsk.TitleStyle = lipgloss.NewStyle()
|
||||
// TODO: this is a hack to get the spinner to not show up, but ideally the component would support making the spinner optional
|
||||
tsk.Spinner.Spinner.Frames = []string{" "}
|
||||
tsk.HideOnSuccess = info.HideOnSuccess
|
||||
tsk.HideStageOnSuccess = info.HideStageOnSuccess
|
||||
tsk.HideProgressOnSuccess = true
|
||||
|
||||
return []tea.Model{tsk}
|
||||
if info.ParentID != "" {
|
||||
tsk.TitleStyle = lipgloss.NewStyle()
|
||||
}
|
||||
|
||||
if err := cts.model.Add(info.ParentID, info.ID, tsk); err != nil {
|
||||
log.WithFields("error", err).Error("unable to add cataloger task to tree model")
|
||||
}
|
||||
|
||||
return cts, tsk.Init()
|
||||
}
|
||||
|
||||
func (cts catalogerTaskModel) View() string {
|
||||
return cts.model.View()
|
||||
}
|
||||
|
||||
func (m *Handler) handleCatalogerTaskStarted(e partybus.Event) ([]tea.Model, tea.Cmd) {
|
||||
mon, info, err := syftEventParsers.ParseCatalogerTaskStarted(e)
|
||||
if err != nil {
|
||||
log.WithFields("error", err).Warn("unable to parse event")
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
var models []tea.Model
|
||||
|
||||
// only create the new cataloger task tree once to manage all cataloger task events
|
||||
m.onNewCatalogerTask.Do(func() {
|
||||
models = append(models, newCatalogerTaskTreeModel(m.newTaskProgress))
|
||||
})
|
||||
|
||||
// we need to update the cataloger task model with a new row. We should never update the model outside of the
|
||||
// bubbletea update-render event loop. Instead, we return a command that will be executed by the bubbletea runtime,
|
||||
// producing a message that is passed to the cataloger task model. This is the prescribed way to update models
|
||||
// in bubbletea.
|
||||
|
||||
if info.ID == "" {
|
||||
// ID is optional from the consumer perspective, but required internally
|
||||
info.ID = uuid.Must(uuid.NewRandom()).String()
|
||||
}
|
||||
|
||||
cmd := func() tea.Msg {
|
||||
// this message will cause the cataloger task model to add a new row to the output based on the given task
|
||||
// information and progress data.
|
||||
return newCatalogerTaskRowEvent{
|
||||
info: *info,
|
||||
prog: mon,
|
||||
}
|
||||
}
|
||||
|
||||
return models, cmd
|
||||
}
|
||||
|
||||
@@ -2,19 +2,22 @@ package ui
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
tea "github.com/charmbracelet/bubbletea"
|
||||
"github.com/gkampitakis/go-snaps/snaps"
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/wagoodman/go-partybus"
|
||||
"github.com/wagoodman/go-progress"
|
||||
|
||||
"github.com/anchore/bubbly/bubbles/taskprogress"
|
||||
syftEvent "github.com/anchore/syft/syft/event"
|
||||
"github.com/anchore/syft/syft/event/monitor"
|
||||
)
|
||||
|
||||
func TestHandler_handleCatalogerTaskStarted(t *testing.T) {
|
||||
title := monitor.Title{
|
||||
Default: "some task title",
|
||||
OnSuccess: "some task done",
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
eventFn func(*testing.T) partybus.Event
|
||||
@@ -23,99 +26,171 @@ func TestHandler_handleCatalogerTaskStarted(t *testing.T) {
|
||||
{
|
||||
name: "cataloging task in progress",
|
||||
eventFn: func(t *testing.T) partybus.Event {
|
||||
src := &monitor.CatalogerTask{
|
||||
SubStatus: false,
|
||||
RemoveOnCompletion: false,
|
||||
Title: "some task title",
|
||||
TitleOnCompletion: "some task done",
|
||||
value := &monitor.CatalogerTaskProgress{
|
||||
AtomicStage: progress.NewAtomicStage("some stage"),
|
||||
Manual: progress.NewManual(100),
|
||||
}
|
||||
|
||||
src.SetValue("some value")
|
||||
value.Manual.Add(50)
|
||||
|
||||
return partybus.Event{
|
||||
Type: syftEvent.CatalogerTaskStarted,
|
||||
Source: src,
|
||||
Type: syftEvent.CatalogerTaskStarted,
|
||||
Source: monitor.GenericTask{
|
||||
Title: title,
|
||||
HideOnSuccess: false,
|
||||
HideStageOnSuccess: false,
|
||||
ID: "my-id",
|
||||
},
|
||||
Value: value,
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "cataloging sub task in progress",
|
||||
eventFn: func(t *testing.T) partybus.Event {
|
||||
src := &monitor.CatalogerTask{
|
||||
SubStatus: true,
|
||||
RemoveOnCompletion: false,
|
||||
Title: "some task title",
|
||||
TitleOnCompletion: "some task done",
|
||||
value := &monitor.CatalogerTaskProgress{
|
||||
AtomicStage: progress.NewAtomicStage("some stage"),
|
||||
Manual: progress.NewManual(100),
|
||||
}
|
||||
|
||||
src.SetValue("some value")
|
||||
value.Manual.Add(50)
|
||||
|
||||
return partybus.Event{
|
||||
Type: syftEvent.CatalogerTaskStarted,
|
||||
Source: src,
|
||||
Type: syftEvent.CatalogerTaskStarted,
|
||||
Source: monitor.GenericTask{
|
||||
Title: title,
|
||||
HideOnSuccess: false,
|
||||
HideStageOnSuccess: false,
|
||||
ID: "my-id",
|
||||
ParentID: "top-level-task",
|
||||
},
|
||||
Value: value,
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "cataloging sub task complete",
|
||||
eventFn: func(t *testing.T) partybus.Event {
|
||||
src := &monitor.CatalogerTask{
|
||||
SubStatus: true,
|
||||
RemoveOnCompletion: false,
|
||||
Title: "some task title",
|
||||
TitleOnCompletion: "some task done",
|
||||
value := &monitor.CatalogerTaskProgress{
|
||||
AtomicStage: progress.NewAtomicStage("some stage"),
|
||||
Manual: progress.NewManual(100),
|
||||
}
|
||||
|
||||
src.SetValue("some value")
|
||||
src.SetCompleted()
|
||||
value.SetCompleted()
|
||||
|
||||
return partybus.Event{
|
||||
Type: syftEvent.CatalogerTaskStarted,
|
||||
Source: src,
|
||||
Type: syftEvent.CatalogerTaskStarted,
|
||||
Source: monitor.GenericTask{
|
||||
Title: title,
|
||||
HideOnSuccess: false,
|
||||
HideStageOnSuccess: false,
|
||||
ID: "my-id",
|
||||
ParentID: "top-level-task",
|
||||
},
|
||||
Value: value,
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "cataloging sub task complete -- hide stage",
|
||||
eventFn: func(t *testing.T) partybus.Event {
|
||||
value := &monitor.CatalogerTaskProgress{
|
||||
AtomicStage: progress.NewAtomicStage("some stage"),
|
||||
Manual: progress.NewManual(100),
|
||||
}
|
||||
|
||||
value.SetCompleted()
|
||||
|
||||
return partybus.Event{
|
||||
Type: syftEvent.CatalogerTaskStarted,
|
||||
Source: monitor.GenericTask{
|
||||
Title: title,
|
||||
HideOnSuccess: false,
|
||||
HideStageOnSuccess: true,
|
||||
ID: "my-id",
|
||||
ParentID: "top-level-task",
|
||||
},
|
||||
Value: value,
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "cataloging sub task complete with removal",
|
||||
eventFn: func(t *testing.T) partybus.Event {
|
||||
src := &monitor.CatalogerTask{
|
||||
SubStatus: true,
|
||||
RemoveOnCompletion: true,
|
||||
Title: "some task title",
|
||||
TitleOnCompletion: "some task done",
|
||||
value := &monitor.CatalogerTaskProgress{
|
||||
AtomicStage: progress.NewAtomicStage("some stage"),
|
||||
Manual: progress.NewManual(100),
|
||||
}
|
||||
|
||||
src.SetValue("some value")
|
||||
src.SetCompleted()
|
||||
value.SetCompleted()
|
||||
|
||||
return partybus.Event{
|
||||
Type: syftEvent.CatalogerTaskStarted,
|
||||
Source: src,
|
||||
Type: syftEvent.CatalogerTaskStarted,
|
||||
Source: monitor.GenericTask{
|
||||
Title: title,
|
||||
HideOnSuccess: true,
|
||||
HideStageOnSuccess: false,
|
||||
ID: "my-id",
|
||||
ParentID: "top-level-task",
|
||||
},
|
||||
Value: value,
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
event := tt.eventFn(t)
|
||||
// need to be able to get the initial newCatalogerTaskRowEvent + initialize the nested taskprogress model
|
||||
if tt.iterations == 0 {
|
||||
tt.iterations = 2
|
||||
}
|
||||
|
||||
e := tt.eventFn(t)
|
||||
handler := New(DefaultHandlerConfig())
|
||||
handler.WindowSize = tea.WindowSizeMsg{
|
||||
Width: 100,
|
||||
Height: 80,
|
||||
}
|
||||
|
||||
models := handler.Handle(event)
|
||||
info := monitor.GenericTask{
|
||||
Title: monitor.Title{
|
||||
Default: "Catalog contents",
|
||||
WhileRunning: "Cataloging contents",
|
||||
OnSuccess: "Cataloged contents",
|
||||
},
|
||||
ID: "top-level-task",
|
||||
}
|
||||
|
||||
// note: this line / event is not under test, only needed to show a sub status
|
||||
kickoffEvent := &monitor.CatalogerTaskProgress{
|
||||
AtomicStage: progress.NewAtomicStage(""),
|
||||
Manual: progress.NewManual(-1),
|
||||
}
|
||||
|
||||
models, cmd := handler.Handle(
|
||||
partybus.Event{
|
||||
Type: syftEvent.CatalogerTaskStarted,
|
||||
Source: info,
|
||||
Value: progress.StagedProgressable(kickoffEvent),
|
||||
},
|
||||
)
|
||||
require.Len(t, models, 1)
|
||||
require.NotNil(t, cmd)
|
||||
model := models[0]
|
||||
|
||||
tsk, ok := model.(taskprogress.Model)
|
||||
tr, ok := model.(*catalogerTaskModel)
|
||||
require.True(t, ok)
|
||||
|
||||
got := runModel(t, tsk, tt.iterations, taskprogress.TickMsg{
|
||||
Time: time.Now(),
|
||||
Sequence: tsk.Sequence(),
|
||||
ID: tsk.ID(),
|
||||
})
|
||||
gotModel := runModel(t, tr, tt.iterations, cmd())
|
||||
|
||||
models, cmd = handler.Handle(e)
|
||||
require.Len(t, models, 0)
|
||||
require.NotNil(t, cmd)
|
||||
|
||||
gotModel = runModel(t, gotModel, tt.iterations, cmd())
|
||||
|
||||
got := gotModel.View()
|
||||
|
||||
t.Log(got)
|
||||
snaps.MatchSnapshot(t, got)
|
||||
})
|
||||
|
||||
@@ -80,18 +80,21 @@ func TestHandler_handleFetchImage(t *testing.T) {
|
||||
Height: 80,
|
||||
}
|
||||
|
||||
models := handler.Handle(event)
|
||||
models, _ := handler.Handle(event)
|
||||
require.Len(t, models, 1)
|
||||
model := models[0]
|
||||
|
||||
tsk, ok := model.(taskprogress.Model)
|
||||
require.True(t, ok)
|
||||
|
||||
got := runModel(t, tsk, tt.iterations, taskprogress.TickMsg{
|
||||
gotModel := runModel(t, tsk, tt.iterations, taskprogress.TickMsg{
|
||||
Time: time.Now(),
|
||||
Sequence: tsk.Sequence(),
|
||||
ID: tsk.ID(),
|
||||
})
|
||||
|
||||
got := gotModel.View()
|
||||
|
||||
t.Log(got)
|
||||
snaps.MatchSnapshot(t, got)
|
||||
})
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
package ui
|
||||
|
||||
import (
|
||||
tea "github.com/charmbracelet/bubbletea"
|
||||
"github.com/wagoodman/go-partybus"
|
||||
|
||||
"github.com/anchore/bubbly/bubbles/taskprogress"
|
||||
"github.com/anchore/syft/internal/log"
|
||||
syftEventParsers "github.com/anchore/syft/syft/event/parsers"
|
||||
)
|
||||
|
||||
func (m *Handler) handleFileDigestsCatalogerStarted(e partybus.Event) []tea.Model {
|
||||
prog, err := syftEventParsers.ParseFileDigestsCatalogingStarted(e)
|
||||
if err != nil {
|
||||
log.WithFields("error", err).Warn("unable to parse event")
|
||||
return nil
|
||||
}
|
||||
|
||||
tsk := m.newTaskProgress(
|
||||
taskprogress.Title{
|
||||
Default: "Catalog file digests",
|
||||
Running: "Cataloging file digests",
|
||||
Success: "Cataloged file digests",
|
||||
}, taskprogress.WithStagedProgressable(prog),
|
||||
)
|
||||
|
||||
return []tea.Model{tsk}
|
||||
}
|
||||
@@ -1,97 +0,0 @@
|
||||
package ui
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
tea "github.com/charmbracelet/bubbletea"
|
||||
"github.com/gkampitakis/go-snaps/snaps"
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/wagoodman/go-partybus"
|
||||
"github.com/wagoodman/go-progress"
|
||||
|
||||
"github.com/anchore/bubbly/bubbles/taskprogress"
|
||||
syftEvent "github.com/anchore/syft/syft/event"
|
||||
)
|
||||
|
||||
func TestHandler_handleFileDigestsCatalogerStarted(t *testing.T) {
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
eventFn func(*testing.T) partybus.Event
|
||||
iterations int
|
||||
}{
|
||||
{
|
||||
name: "cataloging in progress",
|
||||
eventFn: func(t *testing.T) partybus.Event {
|
||||
prog := &progress.Manual{}
|
||||
prog.SetTotal(100)
|
||||
prog.Set(50)
|
||||
|
||||
mon := struct {
|
||||
progress.Progressable
|
||||
progress.Stager
|
||||
}{
|
||||
Progressable: prog,
|
||||
Stager: &progress.Stage{
|
||||
Current: "current",
|
||||
},
|
||||
}
|
||||
|
||||
return partybus.Event{
|
||||
Type: syftEvent.FileDigestsCatalogerStarted,
|
||||
Value: mon,
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "cataloging complete",
|
||||
eventFn: func(t *testing.T) partybus.Event {
|
||||
prog := &progress.Manual{}
|
||||
prog.SetTotal(100)
|
||||
prog.Set(100)
|
||||
prog.SetCompleted()
|
||||
|
||||
mon := struct {
|
||||
progress.Progressable
|
||||
progress.Stager
|
||||
}{
|
||||
Progressable: prog,
|
||||
Stager: &progress.Stage{
|
||||
Current: "current",
|
||||
},
|
||||
}
|
||||
|
||||
return partybus.Event{
|
||||
Type: syftEvent.FileDigestsCatalogerStarted,
|
||||
Value: mon,
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
event := tt.eventFn(t)
|
||||
handler := New(DefaultHandlerConfig())
|
||||
handler.WindowSize = tea.WindowSizeMsg{
|
||||
Width: 100,
|
||||
Height: 80,
|
||||
}
|
||||
|
||||
models := handler.Handle(event)
|
||||
require.Len(t, models, 1)
|
||||
model := models[0]
|
||||
|
||||
tsk, ok := model.(taskprogress.Model)
|
||||
require.True(t, ok)
|
||||
|
||||
got := runModel(t, tsk, tt.iterations, taskprogress.TickMsg{
|
||||
Time: time.Now(),
|
||||
Sequence: tsk.Sequence(),
|
||||
ID: tsk.ID(),
|
||||
})
|
||||
t.Log(got)
|
||||
snaps.MatchSnapshot(t, got)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -80,18 +80,21 @@ func TestHandler_handleFileIndexingStarted(t *testing.T) {
|
||||
Height: 80,
|
||||
}
|
||||
|
||||
models := handler.Handle(event)
|
||||
models, _ := handler.Handle(event)
|
||||
require.Len(t, models, 1)
|
||||
model := models[0]
|
||||
|
||||
tsk, ok := model.(taskprogress.Model)
|
||||
require.True(t, ok)
|
||||
|
||||
got := runModel(t, tsk, tt.iterations, taskprogress.TickMsg{
|
||||
gotModel := runModel(t, tsk, tt.iterations, taskprogress.TickMsg{
|
||||
Time: time.Now(),
|
||||
Sequence: tsk.Sequence(),
|
||||
ID: tsk.ID(),
|
||||
})
|
||||
|
||||
got := gotModel.View()
|
||||
|
||||
t.Log(got)
|
||||
snaps.MatchSnapshot(t, got)
|
||||
})
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
package ui
|
||||
|
||||
import (
|
||||
tea "github.com/charmbracelet/bubbletea"
|
||||
"github.com/wagoodman/go-partybus"
|
||||
|
||||
"github.com/anchore/bubbly/bubbles/taskprogress"
|
||||
"github.com/anchore/syft/internal/log"
|
||||
syftEventParsers "github.com/anchore/syft/syft/event/parsers"
|
||||
)
|
||||
|
||||
func (m *Handler) handleFileMetadataCatalogerStarted(e partybus.Event) []tea.Model {
|
||||
prog, err := syftEventParsers.ParseFileMetadataCatalogingStarted(e)
|
||||
if err != nil {
|
||||
log.WithFields("error", err).Warn("unable to parse event")
|
||||
return nil
|
||||
}
|
||||
|
||||
tsk := m.newTaskProgress(
|
||||
taskprogress.Title{
|
||||
Default: "Catalog file metadata",
|
||||
Running: "Cataloging file metadata",
|
||||
Success: "Cataloged file metadata",
|
||||
},
|
||||
taskprogress.WithStagedProgressable(prog),
|
||||
)
|
||||
|
||||
return []tea.Model{tsk}
|
||||
}
|
||||
@@ -1,97 +0,0 @@
|
||||
package ui
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
tea "github.com/charmbracelet/bubbletea"
|
||||
"github.com/gkampitakis/go-snaps/snaps"
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/wagoodman/go-partybus"
|
||||
"github.com/wagoodman/go-progress"
|
||||
|
||||
"github.com/anchore/bubbly/bubbles/taskprogress"
|
||||
syftEvent "github.com/anchore/syft/syft/event"
|
||||
)
|
||||
|
||||
func TestHandler_handleFileMetadataCatalogerStarted(t *testing.T) {
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
eventFn func(*testing.T) partybus.Event
|
||||
iterations int
|
||||
}{
|
||||
{
|
||||
name: "cataloging in progress",
|
||||
eventFn: func(t *testing.T) partybus.Event {
|
||||
prog := &progress.Manual{}
|
||||
prog.SetTotal(100)
|
||||
prog.Set(50)
|
||||
|
||||
mon := struct {
|
||||
progress.Progressable
|
||||
progress.Stager
|
||||
}{
|
||||
Progressable: prog,
|
||||
Stager: &progress.Stage{
|
||||
Current: "current",
|
||||
},
|
||||
}
|
||||
|
||||
return partybus.Event{
|
||||
Type: syftEvent.FileMetadataCatalogerStarted,
|
||||
Value: mon,
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "cataloging complete",
|
||||
eventFn: func(t *testing.T) partybus.Event {
|
||||
prog := &progress.Manual{}
|
||||
prog.SetTotal(100)
|
||||
prog.Set(100)
|
||||
prog.SetCompleted()
|
||||
|
||||
mon := struct {
|
||||
progress.Progressable
|
||||
progress.Stager
|
||||
}{
|
||||
Progressable: prog,
|
||||
Stager: &progress.Stage{
|
||||
Current: "current",
|
||||
},
|
||||
}
|
||||
|
||||
return partybus.Event{
|
||||
Type: syftEvent.FileMetadataCatalogerStarted,
|
||||
Value: mon,
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
event := tt.eventFn(t)
|
||||
handler := New(DefaultHandlerConfig())
|
||||
handler.WindowSize = tea.WindowSizeMsg{
|
||||
Width: 100,
|
||||
Height: 80,
|
||||
}
|
||||
|
||||
models := handler.Handle(event)
|
||||
require.Len(t, models, 1)
|
||||
model := models[0]
|
||||
|
||||
tsk, ok := model.(taskprogress.Model)
|
||||
require.True(t, ok)
|
||||
|
||||
got := runModel(t, tsk, tt.iterations, taskprogress.TickMsg{
|
||||
Time: time.Now(),
|
||||
Sequence: tsk.Sequence(),
|
||||
ID: tsk.ID(),
|
||||
})
|
||||
t.Log(got)
|
||||
snaps.MatchSnapshot(t, got)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1,87 +0,0 @@
|
||||
package ui
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
tea "github.com/charmbracelet/bubbletea"
|
||||
"github.com/wagoodman/go-partybus"
|
||||
"github.com/wagoodman/go-progress"
|
||||
|
||||
"github.com/anchore/bubbly/bubbles/taskprogress"
|
||||
"github.com/anchore/syft/internal/log"
|
||||
syftEventParsers "github.com/anchore/syft/syft/event/parsers"
|
||||
"github.com/anchore/syft/syft/pkg/cataloger"
|
||||
)
|
||||
|
||||
var _ progress.StagedProgressable = (*packageCatalogerProgressAdapter)(nil)
|
||||
|
||||
type packageCatalogerProgressAdapter struct {
|
||||
monitor *cataloger.Monitor
|
||||
monitors []progress.Monitorable
|
||||
}
|
||||
|
||||
func newPackageCatalogerProgressAdapter(monitor *cataloger.Monitor) packageCatalogerProgressAdapter {
|
||||
return packageCatalogerProgressAdapter{
|
||||
monitor: monitor,
|
||||
monitors: []progress.Monitorable{
|
||||
monitor.FilesProcessed,
|
||||
monitor.PackagesDiscovered,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (p packageCatalogerProgressAdapter) Stage() string {
|
||||
return fmt.Sprintf("%d packages", p.monitor.PackagesDiscovered.Current())
|
||||
}
|
||||
|
||||
func (p packageCatalogerProgressAdapter) Current() int64 {
|
||||
return p.monitor.PackagesDiscovered.Current()
|
||||
}
|
||||
|
||||
func (p packageCatalogerProgressAdapter) Error() error {
|
||||
completedMonitors := 0
|
||||
for _, monitor := range p.monitors {
|
||||
err := monitor.Error()
|
||||
if err == nil {
|
||||
continue
|
||||
}
|
||||
if progress.IsErrCompleted(err) {
|
||||
completedMonitors++
|
||||
continue
|
||||
}
|
||||
// something went wrong
|
||||
return err
|
||||
}
|
||||
if completedMonitors == len(p.monitors) && len(p.monitors) > 0 {
|
||||
return p.monitors[0].Error()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p packageCatalogerProgressAdapter) Size() int64 {
|
||||
// this is an inherently unknown value (indeterminate total number of packages to discover)
|
||||
return -1
|
||||
}
|
||||
|
||||
func (m *Handler) handlePackageCatalogerStarted(e partybus.Event) []tea.Model {
|
||||
monitor, err := syftEventParsers.ParsePackageCatalogerStarted(e)
|
||||
if err != nil {
|
||||
log.WithFields("error", err).Warn("unable to parse event")
|
||||
return nil
|
||||
}
|
||||
|
||||
tsk := m.newTaskProgress(
|
||||
taskprogress.Title{
|
||||
Default: "Catalog packages",
|
||||
Running: "Cataloging packages",
|
||||
Success: "Cataloged packages",
|
||||
},
|
||||
taskprogress.WithStagedProgressable(
|
||||
newPackageCatalogerProgressAdapter(monitor),
|
||||
),
|
||||
)
|
||||
|
||||
tsk.HideStageOnSuccess = false
|
||||
|
||||
return []tea.Model{tsk}
|
||||
}
|
||||
@@ -1,133 +0,0 @@
|
||||
package ui
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
tea "github.com/charmbracelet/bubbletea"
|
||||
"github.com/gkampitakis/go-snaps/snaps"
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/wagoodman/go-partybus"
|
||||
"github.com/wagoodman/go-progress"
|
||||
|
||||
"github.com/anchore/bubbly/bubbles/taskprogress"
|
||||
syftEvent "github.com/anchore/syft/syft/event"
|
||||
"github.com/anchore/syft/syft/pkg/cataloger"
|
||||
)
|
||||
|
||||
func TestHandler_handlePackageCatalogerStarted(t *testing.T) {
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
eventFn func(*testing.T) partybus.Event
|
||||
iterations int
|
||||
}{
|
||||
{
|
||||
name: "cataloging in progress",
|
||||
eventFn: func(t *testing.T) partybus.Event {
|
||||
prog := &progress.Manual{}
|
||||
prog.SetTotal(100)
|
||||
prog.Set(50)
|
||||
|
||||
mon := cataloger.Monitor{
|
||||
FilesProcessed: progress.NewManual(-1),
|
||||
PackagesDiscovered: prog,
|
||||
}
|
||||
|
||||
return partybus.Event{
|
||||
Type: syftEvent.PackageCatalogerStarted,
|
||||
Value: mon,
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "cataloging only files complete",
|
||||
eventFn: func(t *testing.T) partybus.Event {
|
||||
prog := &progress.Manual{}
|
||||
prog.SetTotal(100)
|
||||
prog.Set(50)
|
||||
|
||||
files := progress.NewManual(-1)
|
||||
files.SetCompleted()
|
||||
|
||||
mon := cataloger.Monitor{
|
||||
FilesProcessed: files,
|
||||
PackagesDiscovered: prog,
|
||||
}
|
||||
|
||||
return partybus.Event{
|
||||
Type: syftEvent.PackageCatalogerStarted,
|
||||
Value: mon,
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "cataloging only packages complete",
|
||||
eventFn: func(t *testing.T) partybus.Event {
|
||||
prog := &progress.Manual{}
|
||||
prog.SetTotal(100)
|
||||
prog.Set(100)
|
||||
prog.SetCompleted()
|
||||
|
||||
files := progress.NewManual(-1)
|
||||
|
||||
mon := cataloger.Monitor{
|
||||
FilesProcessed: files,
|
||||
PackagesDiscovered: prog,
|
||||
}
|
||||
|
||||
return partybus.Event{
|
||||
Type: syftEvent.PackageCatalogerStarted,
|
||||
Value: mon,
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "cataloging complete",
|
||||
eventFn: func(t *testing.T) partybus.Event {
|
||||
prog := &progress.Manual{}
|
||||
prog.SetTotal(100)
|
||||
prog.Set(100)
|
||||
prog.SetCompleted()
|
||||
|
||||
files := progress.NewManual(-1)
|
||||
files.SetCompleted()
|
||||
|
||||
mon := cataloger.Monitor{
|
||||
FilesProcessed: files,
|
||||
PackagesDiscovered: prog,
|
||||
}
|
||||
|
||||
return partybus.Event{
|
||||
Type: syftEvent.PackageCatalogerStarted,
|
||||
Value: mon,
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
event := tt.eventFn(t)
|
||||
handler := New(DefaultHandlerConfig())
|
||||
handler.WindowSize = tea.WindowSizeMsg{
|
||||
Width: 100,
|
||||
Height: 80,
|
||||
}
|
||||
|
||||
models := handler.Handle(event)
|
||||
require.Len(t, models, 1)
|
||||
model := models[0]
|
||||
|
||||
tsk, ok := model.(taskprogress.Model)
|
||||
require.True(t, ok)
|
||||
|
||||
got := runModel(t, tsk, tt.iterations, taskprogress.TickMsg{
|
||||
Time: time.Now(),
|
||||
Sequence: tsk.Sequence(),
|
||||
ID: tsk.ID(),
|
||||
})
|
||||
t.Log(got)
|
||||
snaps.MatchSnapshot(t, got)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -98,18 +98,21 @@ func TestHandler_handleReadImage(t *testing.T) {
|
||||
Height: 80,
|
||||
}
|
||||
|
||||
models := handler.Handle(event)
|
||||
models, _ := handler.Handle(event)
|
||||
require.Len(t, models, 1)
|
||||
model := models[0]
|
||||
|
||||
tsk, ok := model.(taskprogress.Model)
|
||||
require.True(t, ok)
|
||||
|
||||
got := runModel(t, tsk, tt.iterations, taskprogress.TickMsg{
|
||||
gotModel := runModel(t, tsk, tt.iterations, taskprogress.TickMsg{
|
||||
Time: time.Now(),
|
||||
Sequence: tsk.Sequence(),
|
||||
ID: tsk.ID(),
|
||||
})
|
||||
|
||||
got := gotModel.View()
|
||||
|
||||
t.Log(got)
|
||||
snaps.MatchSnapshot(t, got)
|
||||
})
|
||||
|
||||
+19
-13
@@ -29,6 +29,8 @@ type Handler struct {
|
||||
Config HandlerConfig
|
||||
|
||||
bubbly.EventHandler
|
||||
|
||||
onNewCatalogerTask *sync.Once
|
||||
}
|
||||
|
||||
func DefaultHandlerConfig() HandlerConfig {
|
||||
@@ -41,28 +43,32 @@ func New(cfg HandlerConfig) *Handler {
|
||||
d := bubbly.NewEventDispatcher()
|
||||
|
||||
h := &Handler{
|
||||
EventHandler: d,
|
||||
Running: &sync.WaitGroup{},
|
||||
Config: cfg,
|
||||
EventHandler: d,
|
||||
Running: &sync.WaitGroup{},
|
||||
Config: cfg,
|
||||
onNewCatalogerTask: &sync.Once{},
|
||||
}
|
||||
|
||||
// register all supported event types with the respective handler functions
|
||||
d.AddHandlers(map[partybus.EventType]bubbly.EventHandlerFn{
|
||||
stereoscopeEvent.PullDockerImage: h.handlePullDockerImage,
|
||||
stereoscopeEvent.PullContainerdImage: h.handlePullContainerdImage,
|
||||
stereoscopeEvent.ReadImage: h.handleReadImage,
|
||||
stereoscopeEvent.FetchImage: h.handleFetchImage,
|
||||
syftEvent.PackageCatalogerStarted: h.handlePackageCatalogerStarted,
|
||||
syftEvent.FileDigestsCatalogerStarted: h.handleFileDigestsCatalogerStarted,
|
||||
syftEvent.FileMetadataCatalogerStarted: h.handleFileMetadataCatalogerStarted,
|
||||
syftEvent.FileIndexingStarted: h.handleFileIndexingStarted,
|
||||
syftEvent.AttestationStarted: h.handleAttestationStarted,
|
||||
syftEvent.CatalogerTaskStarted: h.handleCatalogerTaskStarted,
|
||||
stereoscopeEvent.PullDockerImage: simpleHandler(h.handlePullDockerImage),
|
||||
stereoscopeEvent.PullContainerdImage: simpleHandler(h.handlePullContainerdImage),
|
||||
stereoscopeEvent.ReadImage: simpleHandler(h.handleReadImage),
|
||||
stereoscopeEvent.FetchImage: simpleHandler(h.handleFetchImage),
|
||||
syftEvent.FileIndexingStarted: simpleHandler(h.handleFileIndexingStarted),
|
||||
syftEvent.AttestationStarted: simpleHandler(h.handleAttestationStarted),
|
||||
syftEvent.CatalogerTaskStarted: h.handleCatalogerTaskStarted,
|
||||
})
|
||||
|
||||
return h
|
||||
}
|
||||
|
||||
func simpleHandler(fn func(partybus.Event) []tea.Model) bubbly.EventHandlerFn {
|
||||
return func(e partybus.Event) ([]tea.Model, tea.Cmd) {
|
||||
return fn(e), nil
|
||||
}
|
||||
}
|
||||
|
||||
func (m *Handler) OnMessage(msg tea.Msg) {
|
||||
if msg, ok := msg.(tea.WindowSizeMsg); ok {
|
||||
m.WindowSize = msg
|
||||
|
||||
@@ -4,12 +4,11 @@ import (
|
||||
"reflect"
|
||||
"sync"
|
||||
"testing"
|
||||
"unsafe"
|
||||
|
||||
tea "github.com/charmbracelet/bubbletea"
|
||||
)
|
||||
|
||||
func runModel(t testing.TB, m tea.Model, iterations int, message tea.Msg, h ...*sync.WaitGroup) string {
|
||||
func runModel(t testing.TB, m tea.Model, iterations int, message tea.Msg, h ...*sync.WaitGroup) tea.Model {
|
||||
t.Helper()
|
||||
if iterations == 0 {
|
||||
iterations = 1
|
||||
@@ -37,34 +36,21 @@ func runModel(t testing.TB, m tea.Model, iterations int, message tea.Msg, h ...*
|
||||
cmd = tea.Batch(nextCmds...)
|
||||
}
|
||||
|
||||
return m.View()
|
||||
return m
|
||||
}
|
||||
|
||||
func flatten(p tea.Msg) (msgs []tea.Msg) {
|
||||
if reflect.TypeOf(p).Name() == "batchMsg" {
|
||||
partials := extractBatchMessages(p)
|
||||
for _, m := range partials {
|
||||
msgs = append(msgs, flatten(m)...)
|
||||
func flatten(ps ...tea.Msg) (msgs []tea.Msg) {
|
||||
for _, p := range ps {
|
||||
if bm, ok := p.(tea.BatchMsg); ok {
|
||||
for _, m := range bm {
|
||||
if m == nil {
|
||||
continue
|
||||
}
|
||||
msgs = append(msgs, flatten(m())...)
|
||||
}
|
||||
} else {
|
||||
msgs = []tea.Msg{p}
|
||||
}
|
||||
} else {
|
||||
msgs = []tea.Msg{p}
|
||||
}
|
||||
return msgs
|
||||
}
|
||||
|
||||
func extractBatchMessages(m tea.Msg) (ret []tea.Msg) {
|
||||
sliceMsgType := reflect.SliceOf(reflect.TypeOf(tea.Cmd(nil)))
|
||||
value := reflect.ValueOf(m) // note: this is technically unaddressable
|
||||
|
||||
// make our own instance that is addressable
|
||||
valueCopy := reflect.New(value.Type()).Elem()
|
||||
valueCopy.Set(value)
|
||||
|
||||
cmds := reflect.NewAt(sliceMsgType, unsafe.Pointer(valueCopy.UnsafeAddr())).Elem()
|
||||
for i := 0; i < cmds.Len(); i++ {
|
||||
item := cmds.Index(i)
|
||||
r := item.Call(nil)
|
||||
ret = append(ret, r[0].Interface().(tea.Msg))
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
@@ -155,7 +155,11 @@ func (m *UI) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
return m, nil
|
||||
}
|
||||
|
||||
for _, newModel := range m.handler.Handle(msg) {
|
||||
models, cmd := m.handler.Handle(msg)
|
||||
if cmd != nil {
|
||||
cmds = append(cmds, cmd)
|
||||
}
|
||||
for _, newModel := range models {
|
||||
if newModel == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -3,25 +3,25 @@ module github.com/anchore/syft
|
||||
go 1.21.0
|
||||
|
||||
require (
|
||||
github.com/CycloneDX/cyclonedx-go v0.7.2
|
||||
github.com/CycloneDX/cyclonedx-go v0.8.0
|
||||
github.com/Masterminds/semver v1.5.0
|
||||
github.com/Masterminds/sprig/v3 v3.2.3
|
||||
github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d
|
||||
github.com/acobaugh/osrelease v0.1.0
|
||||
github.com/anchore/bubbly v0.0.0-20230801194016-acdb4981b461
|
||||
github.com/anchore/bubbly v0.0.0-20231115134915-def0aba654a9
|
||||
github.com/anchore/clio v0.0.0-20231016125544-c98a83e1c7fc
|
||||
github.com/anchore/fangs v0.0.0-20231103141714-84c94dc43a2e
|
||||
github.com/anchore/fangs v0.0.0-20231201140849-5075d28d6d8b
|
||||
github.com/anchore/go-logger v0.0.0-20230725134548-c21dafa1ec5a
|
||||
github.com/anchore/go-macholibre v0.0.0-20220308212642-53e6d0aaf6fb
|
||||
github.com/anchore/go-testutils v0.0.0-20200925183923-d5f45b0d3c04
|
||||
github.com/anchore/go-version v1.2.2-0.20200701162849-18adb9c92b9b
|
||||
github.com/anchore/packageurl-go v0.1.1-0.20230104203445-02e0a6721501
|
||||
github.com/anchore/stereoscope v0.0.0-20231117203853-3610f4ef3e83
|
||||
github.com/anchore/stereoscope v0.0.0-20231215220732-4b999b76ca89
|
||||
// we are hinting brotli to latest due to warning when installing archiver v3:
|
||||
// go: warning: github.com/andybalholm/brotli@v1.0.1: retracted by module author: occasional panics and data corruption
|
||||
github.com/aquasecurity/go-pep440-version v0.0.0-20210121094942-22b2f8951d46
|
||||
github.com/bmatcuk/doublestar/v4 v4.6.1
|
||||
github.com/charmbracelet/bubbletea v0.24.2
|
||||
github.com/charmbracelet/bubbletea v0.25.0
|
||||
github.com/charmbracelet/lipgloss v0.9.1
|
||||
github.com/dave/jennifer v1.7.0
|
||||
github.com/deitch/magic v0.0.0-20230404182410-1ff89d7342da
|
||||
@@ -32,12 +32,12 @@ require (
|
||||
github.com/github/go-spdx/v2 v2.2.0
|
||||
github.com/gkampitakis/go-snaps v0.4.12
|
||||
github.com/go-git/go-billy/v5 v5.5.0
|
||||
github.com/go-git/go-git/v5 v5.10.1
|
||||
github.com/go-git/go-git/v5 v5.11.0
|
||||
github.com/go-test/deep v1.1.0
|
||||
github.com/google/go-cmp v0.6.0
|
||||
github.com/google/go-containerregistry v0.16.1
|
||||
github.com/google/go-containerregistry v0.17.0
|
||||
github.com/google/licensecheck v0.3.1
|
||||
github.com/google/uuid v1.4.0
|
||||
github.com/google/uuid v1.5.0
|
||||
github.com/gookit/color v1.5.4
|
||||
github.com/hashicorp/go-multierror v1.1.1
|
||||
github.com/iancoleman/strcase v0.3.0
|
||||
@@ -53,7 +53,7 @@ require (
|
||||
github.com/olekukonko/tablewriter v0.0.5
|
||||
github.com/opencontainers/go-digest v1.0.0
|
||||
github.com/pelletier/go-toml v1.9.5
|
||||
github.com/saferwall/pe v1.4.7
|
||||
github.com/saferwall/pe v1.4.8
|
||||
github.com/saintfish/chardet v0.0.0-20230101081208-5e3ef4b5456d
|
||||
github.com/sanity-io/litter v1.5.5
|
||||
github.com/sassoftware/go-rpmutils v0.2.0
|
||||
@@ -73,7 +73,7 @@ require (
|
||||
golang.org/x/mod v0.14.0
|
||||
golang.org/x/net v0.19.0
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
modernc.org/sqlite v1.27.0
|
||||
modernc.org/sqlite v1.28.0
|
||||
)
|
||||
|
||||
require (
|
||||
|
||||
@@ -58,8 +58,8 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03
|
||||
github.com/BurntSushi/toml v0.4.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
|
||||
github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
|
||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
github.com/CycloneDX/cyclonedx-go v0.7.2 h1:kKQ0t1dPOlugSIYVOMiMtFqeXI2wp/f5DBIdfux8gnQ=
|
||||
github.com/CycloneDX/cyclonedx-go v0.7.2/go.mod h1:K2bA+324+Og0X84fA8HhN2X066K7Bxz4rpMQ4ZhjtSk=
|
||||
github.com/CycloneDX/cyclonedx-go v0.8.0 h1:FyWVj6x6hoJrui5uRQdYZcSievw3Z32Z88uYzG/0D6M=
|
||||
github.com/CycloneDX/cyclonedx-go v0.8.0/go.mod h1:K2bA+324+Og0X84fA8HhN2X066K7Bxz4rpMQ4ZhjtSk=
|
||||
github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=
|
||||
github.com/DataDog/zstd v1.4.5 h1:EndNeuB0l9syBZhut0wns3gV1hL8zX8LIu6ZiVHWLIQ=
|
||||
github.com/DataDog/zstd v1.4.5/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo=
|
||||
@@ -89,12 +89,12 @@ github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuy
|
||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/anchore/bubbly v0.0.0-20230801194016-acdb4981b461 h1:xGu4/uMWucwWV0YV3fpFIQZ6KVfS/Wfhmma8t0s0vRo=
|
||||
github.com/anchore/bubbly v0.0.0-20230801194016-acdb4981b461/go.mod h1:Ger02eh5NpPm2IqkPAy396HU1KlK3BhOeCljDYXySSk=
|
||||
github.com/anchore/bubbly v0.0.0-20231115134915-def0aba654a9 h1:p0ZIe0htYOX284Y4axJaGBvXHU0VCCzLN5Wf5XbKStU=
|
||||
github.com/anchore/bubbly v0.0.0-20231115134915-def0aba654a9/go.mod h1:3ZsFB9tzW3vl4gEiUeuSOMDnwroWxIxJelOOHUp8dSw=
|
||||
github.com/anchore/clio v0.0.0-20231016125544-c98a83e1c7fc h1:A1KFO+zZZmbNlz1+WKsCF0RKVx6XRoxsAG3lrqH9hUQ=
|
||||
github.com/anchore/clio v0.0.0-20231016125544-c98a83e1c7fc/go.mod h1:QeWvNzxsrUNxcs6haQo3OtISfXUXW0qAuiG4EQiz0GU=
|
||||
github.com/anchore/fangs v0.0.0-20231103141714-84c94dc43a2e h1:O8ZubApaSl7dRzKNvyfGq9cLIPLQ5v3Iz0Y3huHKCgg=
|
||||
github.com/anchore/fangs v0.0.0-20231103141714-84c94dc43a2e/go.mod h1:yPsN3NUGhU5dcBtYBa1dMNzGu1yT5ZAfSjKq9DY4aV8=
|
||||
github.com/anchore/fangs v0.0.0-20231201140849-5075d28d6d8b h1:L/djgY7ZbZ/38+wUtdkk398W3PIBJLkt1N8nU/7e47A=
|
||||
github.com/anchore/fangs v0.0.0-20231201140849-5075d28d6d8b/go.mod h1:TLcE0RE5+8oIx2/NPWem/dq1DeaMoC+fPEH7hoSzPLo=
|
||||
github.com/anchore/go-logger v0.0.0-20230725134548-c21dafa1ec5a h1:nJ2G8zWKASyVClGVgG7sfM5mwoZlZ2zYpIzN2OhjWkw=
|
||||
github.com/anchore/go-logger v0.0.0-20230725134548-c21dafa1ec5a/go.mod h1:ubLFmlsv8/DFUQrZwY5syT5/8Er3ugSr4rDFwHsE3hg=
|
||||
github.com/anchore/go-macholibre v0.0.0-20220308212642-53e6d0aaf6fb h1:iDMnx6LIjtjZ46C0akqveX83WFzhpTD3eqOthawb5vU=
|
||||
@@ -107,8 +107,8 @@ github.com/anchore/go-version v1.2.2-0.20200701162849-18adb9c92b9b h1:e1bmaoJfZV
|
||||
github.com/anchore/go-version v1.2.2-0.20200701162849-18adb9c92b9b/go.mod h1:Bkc+JYWjMCF8OyZ340IMSIi2Ebf3uwByOk6ho4wne1E=
|
||||
github.com/anchore/packageurl-go v0.1.1-0.20230104203445-02e0a6721501 h1:AV7qjwMcM4r8wFhJq3jLRztew3ywIyPTRapl2T1s9o8=
|
||||
github.com/anchore/packageurl-go v0.1.1-0.20230104203445-02e0a6721501/go.mod h1:Blo6OgJNiYF41ufcgHKkbCKF2MDOMlrqhXv/ij6ocR4=
|
||||
github.com/anchore/stereoscope v0.0.0-20231117203853-3610f4ef3e83 h1:mxGIOmj+asEm8LUkPTG3/v0hi27WIlDVjiEVsUB9eqY=
|
||||
github.com/anchore/stereoscope v0.0.0-20231117203853-3610f4ef3e83/go.mod h1:GKAnytSVV1hoqB5r5Gd9M5Ph3Rzqq0zPdEJesewjC2w=
|
||||
github.com/anchore/stereoscope v0.0.0-20231215220732-4b999b76ca89 h1:dymFMCwnENqLr74KQppq8zHKwOPL0M1ToYAU+KVfTew=
|
||||
github.com/anchore/stereoscope v0.0.0-20231215220732-4b999b76ca89/go.mod h1:GKAnytSVV1hoqB5r5Gd9M5Ph3Rzqq0zPdEJesewjC2w=
|
||||
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8=
|
||||
github.com/andybalholm/brotli v1.0.1/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y=
|
||||
github.com/andybalholm/brotli v1.0.4 h1:V7DdXeJtZscaqfNuAdSRuRFzuiKlHSC/Zh3zl9qY3JY=
|
||||
@@ -147,8 +147,8 @@ github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XL
|
||||
github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/charmbracelet/bubbles v0.16.1 h1:6uzpAAaT9ZqKssntbvZMlksWHruQLNxg49H5WdeuYSY=
|
||||
github.com/charmbracelet/bubbles v0.16.1/go.mod h1:2QCp9LFlEsBQMvIYERr7Ww2H2bA7xen1idUDIzm/+Xc=
|
||||
github.com/charmbracelet/bubbletea v0.24.2 h1:uaQIKx9Ai6Gdh5zpTbGiWpytMU+CfsPp06RaW2cx/SY=
|
||||
github.com/charmbracelet/bubbletea v0.24.2/go.mod h1:XdrNrV4J8GiyshTtx3DNuYkR1FDaJmO3l2nejekbsgg=
|
||||
github.com/charmbracelet/bubbletea v0.25.0 h1:bAfwk7jRz7FKFl9RzlIULPkStffg5k6pNt5dywy4TcM=
|
||||
github.com/charmbracelet/bubbletea v0.25.0/go.mod h1:EN3QDR1T5ZdWmdfDzYcqOCAps45+QIJbLOBxmVNWNNg=
|
||||
github.com/charmbracelet/harmonica v0.2.0 h1:8NxJWRWg/bzKqqEaaeFNipOu77YR5t8aSwG4pgaUBiQ=
|
||||
github.com/charmbracelet/harmonica v0.2.0/go.mod h1:KSri/1RMQOZLbw7AHqgcBycp8pgJnQMYYT8QZRqZ1Ao=
|
||||
github.com/charmbracelet/lipgloss v0.9.1 h1:PNyd3jvaJbg4jRHKWXnCj1akQm4rh8dbEzN1p/u1KWg=
|
||||
@@ -288,8 +288,8 @@ github.com/go-git/go-billy/v5 v5.5.0 h1:yEY4yhzCDuMGSv83oGxiBotRzhwhNr8VZyphhiu+
|
||||
github.com/go-git/go-billy/v5 v5.5.0/go.mod h1:hmexnoNsr2SJU1Ju67OaNz5ASJY3+sHgFRpCtpDCKow=
|
||||
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399 h1:eMje31YglSBqCdIqdhKBW8lokaMrL3uTkpGYlE2OOT4=
|
||||
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399/go.mod h1:1OCfN199q1Jm3HZlxleg+Dw/mwps2Wbk9frAWm+4FII=
|
||||
github.com/go-git/go-git/v5 v5.10.1 h1:tu8/D8i+TWxgKpzQ3Vc43e+kkhXqtsZCKI/egajKnxk=
|
||||
github.com/go-git/go-git/v5 v5.10.1/go.mod h1:uEuHjxkHap8kAl//V5F/nNWwqIYtP/402ddd05mp0wg=
|
||||
github.com/go-git/go-git/v5 v5.11.0 h1:XIZc1p+8YzypNr34itUfSvYJcv+eYdTnTvOZ2vD3cA4=
|
||||
github.com/go-git/go-git/v5 v5.11.0/go.mod h1:6GFcX2P3NM7FPBfpePbpLd21XxsgdAt+lKqXmCUiUCY=
|
||||
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
@@ -368,8 +368,8 @@ github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
|
||||
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/go-containerregistry v0.16.1 h1:rUEt426sR6nyrL3gt+18ibRcvYpKYdpsa5ZW7MA08dQ=
|
||||
github.com/google/go-containerregistry v0.16.1/go.mod h1:u0qB2l7mvtWVR5kNcbFIhFY1hLbf8eeGapA+vbFDCtQ=
|
||||
github.com/google/go-containerregistry v0.17.0 h1:5p+zYs/R4VGHkhyvgWurWrpJ2hW4Vv9fQI+GzdcwXLk=
|
||||
github.com/google/go-containerregistry v0.17.0/go.mod h1:u0qB2l7mvtWVR5kNcbFIhFY1hLbf8eeGapA+vbFDCtQ=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/licensecheck v0.3.1 h1:QoxgoDkaeC4nFrtGN1jV7IPmDCHFNIVh54e5hSt6sPs=
|
||||
github.com/google/licensecheck v0.3.1/go.mod h1:ORkR35t/JjW+emNKtfJDII0zlciG9JgbT7SmsohlHmY=
|
||||
@@ -397,8 +397,8 @@ github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26/go.mod h1:dDKJzRmX4S3
|
||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4=
|
||||
github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.5.0 h1:1p67kYwdtXjb0gL0BPiP1Av9wiZPo5A8z2cWkTZ+eyU=
|
||||
github.com/google/uuid v1.5.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
||||
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
||||
github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0=
|
||||
@@ -664,8 +664,8 @@ github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUz
|
||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
||||
github.com/saferwall/pe v1.4.7 h1:A+G3DxX49paJ5OsxBfHKskhyDtmTjShlDmBd81IsHlQ=
|
||||
github.com/saferwall/pe v1.4.7/go.mod h1:SNzv3cdgk8SBI0UwHfyTcdjawfdnN+nbydnEL7GZ25s=
|
||||
github.com/saferwall/pe v1.4.8 h1:ey/L8FGBMrJ1Xh+Rltj1MAFPZ4LOQYGJqNa5B1Na6B0=
|
||||
github.com/saferwall/pe v1.4.8/go.mod h1:SNzv3cdgk8SBI0UwHfyTcdjawfdnN+nbydnEL7GZ25s=
|
||||
github.com/sagikazarmark/crypt v0.3.0/go.mod h1:uD/D+6UF4SrIR1uGEv7bBNkNqLGqUr43MRiaGWX1Nig=
|
||||
github.com/sagikazarmark/locafero v0.3.0 h1:zT7VEGWC2DTflmccN/5T1etyKvxSxpHsjb9cJvm4SvQ=
|
||||
github.com/sagikazarmark/locafero v0.3.0/go.mod h1:w+v7UsPNFwzF1cHuOajOOzoq4U7v/ig1mpRjqV+Bu1U=
|
||||
@@ -1353,8 +1353,8 @@ modernc.org/memory v1.7.2 h1:Klh90S215mmH8c9gO98QxQFsY+W451E8AnzjoE2ee1E=
|
||||
modernc.org/memory v1.7.2/go.mod h1:NO4NVCQy0N7ln+T9ngWqOQfi7ley4vpwvARR+Hjw95E=
|
||||
modernc.org/opt v0.1.3 h1:3XOZf2yznlhC+ibLltsDGzABUGVx8J6pnFMS3E4dcq4=
|
||||
modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0=
|
||||
modernc.org/sqlite v1.27.0 h1:MpKAHoyYB7xqcwnUwkuD+npwEa0fojF0B5QRbN+auJ8=
|
||||
modernc.org/sqlite v1.27.0/go.mod h1:Qxpazz0zH8Z1xCFyi5GSL3FzbtZ3fvbjmywNogldEW0=
|
||||
modernc.org/sqlite v1.28.0 h1:Zx+LyDDmXczNnEQdvPuEfcFVA2ZPyaD7UCZDjef3BHQ=
|
||||
modernc.org/sqlite v1.28.0/go.mod h1:Qxpazz0zH8Z1xCFyi5GSL3FzbtZ3fvbjmywNogldEW0=
|
||||
modernc.org/strutil v1.1.3 h1:fNMm+oJklMGYfU9Ylcywl0CO5O6nTfaowNsh2wpPjzY=
|
||||
modernc.org/strutil v1.1.3/go.mod h1:MEHNA7PdEnEwLvspRMtWTNnp2nnyvMfkimT1NKNAGbw=
|
||||
modernc.org/tcl v1.15.2 h1:C4ybAYCGJw968e+Me18oW55kD/FexcHbqH2xak1ROSY=
|
||||
|
||||
@@ -2,10 +2,12 @@ package bus
|
||||
|
||||
import (
|
||||
"github.com/wagoodman/go-partybus"
|
||||
"github.com/wagoodman/go-progress"
|
||||
|
||||
"github.com/anchore/clio"
|
||||
"github.com/anchore/syft/internal/redact"
|
||||
"github.com/anchore/syft/syft/event"
|
||||
"github.com/anchore/syft/syft/event/monitor"
|
||||
)
|
||||
|
||||
func Exit() {
|
||||
@@ -33,3 +35,18 @@ func Notify(message string) {
|
||||
Value: message,
|
||||
})
|
||||
}
|
||||
|
||||
func StartCatalogerTask(info monitor.GenericTask, size int64, initialStage string) *monitor.CatalogerTaskProgress {
|
||||
t := &monitor.CatalogerTaskProgress{
|
||||
AtomicStage: progress.NewAtomicStage(initialStage),
|
||||
Manual: progress.NewManual(size),
|
||||
}
|
||||
|
||||
Publish(partybus.Event{
|
||||
Type: event.CatalogerTaskStarted,
|
||||
Source: info,
|
||||
Value: progress.StagedProgressable(t),
|
||||
})
|
||||
|
||||
return t
|
||||
}
|
||||
|
||||
@@ -4,3 +4,10 @@ type ArchiveSearchConfig struct {
|
||||
IncludeIndexedArchives bool `yaml:"include-indexed-archives" json:"include-indexed-archives" mapstructure:"include-indexed-archives"`
|
||||
IncludeUnindexedArchives bool `yaml:"include-unindexed-archives" json:"include-unindexed-archives" mapstructure:"include-unindexed-archives"`
|
||||
}
|
||||
|
||||
func DefaultArchiveSearchConfig() ArchiveSearchConfig {
|
||||
return ArchiveSearchConfig{
|
||||
IncludeIndexedArchives: true,
|
||||
IncludeUnindexedArchives: false,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,15 +14,6 @@ const (
|
||||
|
||||
// Events from the syft library
|
||||
|
||||
// PackageCatalogerStarted is a partybus event that occurs when the package cataloging has begun
|
||||
PackageCatalogerStarted partybus.EventType = typePrefix + "-package-cataloger-started-event"
|
||||
|
||||
// FileMetadataCatalogerStarted is a partybus event that occurs when the file metadata cataloging has begun
|
||||
FileMetadataCatalogerStarted partybus.EventType = typePrefix + "-file-metadata-cataloger-started-event"
|
||||
|
||||
// FileDigestsCatalogerStarted is a partybus event that occurs when the file digests cataloging has begun
|
||||
FileDigestsCatalogerStarted partybus.EventType = typePrefix + "-file-digests-cataloger-started-event"
|
||||
|
||||
// FileIndexingStarted is a partybus event that occurs when the directory resolver begins indexing a filesystem
|
||||
FileIndexingStarted partybus.EventType = typePrefix + "-file-indexing-started-event"
|
||||
|
||||
|
||||
@@ -1,55 +0,0 @@
|
||||
package monitor
|
||||
|
||||
import (
|
||||
"github.com/wagoodman/go-partybus"
|
||||
"github.com/wagoodman/go-progress"
|
||||
|
||||
"github.com/anchore/syft/internal/bus"
|
||||
"github.com/anchore/syft/syft/event"
|
||||
)
|
||||
|
||||
// TODO: this should be refactored to support read-only/write-only access using idioms of the progress lib
|
||||
|
||||
type CatalogerTask struct {
|
||||
prog *progress.Manual
|
||||
// Title
|
||||
Title string
|
||||
// TitleOnCompletion a string to use as title when completed
|
||||
TitleOnCompletion string
|
||||
// SubStatus indicates this progress should be rendered as a sub-item
|
||||
SubStatus bool
|
||||
// RemoveOnCompletion indicates this progress line will be removed when completed
|
||||
RemoveOnCompletion bool
|
||||
// value is the value to display -- not public as SetValue needs to be called to initialize this progress
|
||||
value string
|
||||
}
|
||||
|
||||
func (e *CatalogerTask) init() {
|
||||
e.prog = progress.NewManual(-1)
|
||||
|
||||
bus.Publish(partybus.Event{
|
||||
Type: event.CatalogerTaskStarted,
|
||||
Source: e,
|
||||
})
|
||||
}
|
||||
|
||||
func (e *CatalogerTask) SetCompleted() {
|
||||
if e.prog != nil {
|
||||
e.prog.SetCompleted()
|
||||
}
|
||||
}
|
||||
|
||||
func (e *CatalogerTask) SetValue(value string) {
|
||||
if e.prog == nil {
|
||||
e.init()
|
||||
}
|
||||
e.value = value
|
||||
}
|
||||
|
||||
func (e *CatalogerTask) GetValue() string {
|
||||
return e.value
|
||||
}
|
||||
|
||||
func (e *CatalogerTask) GetMonitor() *progress.Manual {
|
||||
return e.prog
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package monitor
|
||||
|
||||
import (
|
||||
"github.com/wagoodman/go-progress"
|
||||
)
|
||||
|
||||
type CatalogerTaskProgress struct {
|
||||
*progress.AtomicStage
|
||||
*progress.Manual
|
||||
}
|
||||
@@ -18,6 +18,19 @@ type Title struct {
|
||||
}
|
||||
|
||||
type GenericTask struct {
|
||||
Title Title
|
||||
Context string
|
||||
|
||||
// required fields
|
||||
|
||||
Title Title
|
||||
|
||||
// optional format fields
|
||||
|
||||
HideOnSuccess bool
|
||||
HideStageOnSuccess bool
|
||||
|
||||
// optional fields
|
||||
|
||||
ID string
|
||||
ParentID string
|
||||
Context string
|
||||
}
|
||||
|
||||
@@ -12,7 +12,6 @@ import (
|
||||
|
||||
"github.com/anchore/syft/syft/event"
|
||||
"github.com/anchore/syft/syft/event/monitor"
|
||||
"github.com/anchore/syft/syft/pkg/cataloger"
|
||||
)
|
||||
|
||||
type ErrBadPayload struct {
|
||||
@@ -40,45 +39,6 @@ func checkEventType(actual, expected partybus.EventType) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func ParsePackageCatalogerStarted(e partybus.Event) (*cataloger.Monitor, error) {
|
||||
if err := checkEventType(e.Type, event.PackageCatalogerStarted); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
monitor, ok := e.Value.(cataloger.Monitor)
|
||||
if !ok {
|
||||
return nil, newPayloadErr(e.Type, "Value", e.Value)
|
||||
}
|
||||
|
||||
return &monitor, nil
|
||||
}
|
||||
|
||||
func ParseFileMetadataCatalogingStarted(e partybus.Event) (progress.StagedProgressable, error) {
|
||||
if err := checkEventType(e.Type, event.FileMetadataCatalogerStarted); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prog, ok := e.Value.(progress.StagedProgressable)
|
||||
if !ok {
|
||||
return nil, newPayloadErr(e.Type, "Value", e.Value)
|
||||
}
|
||||
|
||||
return prog, nil
|
||||
}
|
||||
|
||||
func ParseFileDigestsCatalogingStarted(e partybus.Event) (progress.StagedProgressable, error) {
|
||||
if err := checkEventType(e.Type, event.FileDigestsCatalogerStarted); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prog, ok := e.Value.(progress.StagedProgressable)
|
||||
if !ok {
|
||||
return nil, newPayloadErr(e.Type, "Value", e.Value)
|
||||
}
|
||||
|
||||
return prog, nil
|
||||
}
|
||||
|
||||
func ParseFileIndexingStarted(e partybus.Event) (string, progress.StagedProgressable, error) {
|
||||
if err := checkEventType(e.Type, event.FileIndexingStarted); err != nil {
|
||||
return "", nil, err
|
||||
@@ -97,17 +57,24 @@ func ParseFileIndexingStarted(e partybus.Event) (string, progress.StagedProgress
|
||||
return path, prog, nil
|
||||
}
|
||||
|
||||
func ParseCatalogerTaskStarted(e partybus.Event) (*monitor.CatalogerTask, error) {
|
||||
func ParseCatalogerTaskStarted(e partybus.Event) (progress.StagedProgressable, *monitor.GenericTask, error) {
|
||||
if err := checkEventType(e.Type, event.CatalogerTaskStarted); err != nil {
|
||||
return nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
source, ok := e.Source.(*monitor.CatalogerTask)
|
||||
var mon progress.StagedProgressable
|
||||
|
||||
source, ok := e.Source.(monitor.GenericTask)
|
||||
if !ok {
|
||||
return nil, newPayloadErr(e.Type, "Source", e.Source)
|
||||
return nil, nil, newPayloadErr(e.Type, "Source", e.Source)
|
||||
}
|
||||
|
||||
return source, nil
|
||||
mon, ok = e.Value.(progress.StagedProgressable)
|
||||
if !ok {
|
||||
mon = nil
|
||||
}
|
||||
|
||||
return mon, &source, nil
|
||||
}
|
||||
|
||||
func ParseAttestationStartedEvent(e partybus.Event) (io.Reader, progress.Progressable, *monitor.GenericTask, error) {
|
||||
|
||||
@@ -3,16 +3,16 @@ package filedigest
|
||||
import (
|
||||
"crypto"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/wagoodman/go-partybus"
|
||||
"github.com/wagoodman/go-progress"
|
||||
"github.com/dustin/go-humanize"
|
||||
|
||||
stereoscopeFile "github.com/anchore/stereoscope/pkg/file"
|
||||
"github.com/anchore/syft/internal"
|
||||
"github.com/anchore/syft/internal/bus"
|
||||
intFile "github.com/anchore/syft/internal/file"
|
||||
"github.com/anchore/syft/internal/log"
|
||||
"github.com/anchore/syft/syft/event"
|
||||
"github.com/anchore/syft/syft/event/monitor"
|
||||
"github.com/anchore/syft/syft/file"
|
||||
intCataloger "github.com/anchore/syft/syft/file/cataloger/internal"
|
||||
)
|
||||
@@ -37,13 +37,19 @@ func (i *Cataloger) Catalog(resolver file.Resolver, coordinates ...file.Coordina
|
||||
locations = intCataloger.AllRegularFiles(resolver)
|
||||
} else {
|
||||
for _, c := range coordinates {
|
||||
locations = append(locations, file.NewLocationFromCoordinates(c))
|
||||
locs, err := resolver.FilesByPath(c.RealPath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to get file locations for path %q: %w", c.RealPath, err)
|
||||
}
|
||||
locations = append(locations, locs...)
|
||||
}
|
||||
}
|
||||
|
||||
stage, prog := digestsCatalogingProgress(int64(len(locations)))
|
||||
prog := digestsCatalogingProgress(int64(len(locations)))
|
||||
for _, location := range locations {
|
||||
stage.Current = location.RealPath
|
||||
prog.Increment()
|
||||
prog.AtomicStage.Set(location.Path())
|
||||
|
||||
result, err := i.catalogLocation(resolver, location)
|
||||
|
||||
if errors.Is(err, ErrUndigestableFile) {
|
||||
@@ -61,8 +67,12 @@ func (i *Cataloger) Catalog(resolver file.Resolver, coordinates ...file.Coordina
|
||||
prog.Increment()
|
||||
results[location.Coordinates] = result
|
||||
}
|
||||
|
||||
log.Debugf("file digests cataloger processed %d files", prog.Current())
|
||||
|
||||
prog.AtomicStage.Set(fmt.Sprintf("%s digests", humanize.Comma(prog.Current())))
|
||||
prog.SetCompleted()
|
||||
|
||||
return results, nil
|
||||
}
|
||||
|
||||
@@ -91,20 +101,14 @@ func (i *Cataloger) catalogLocation(resolver file.Resolver, location file.Locati
|
||||
return digests, nil
|
||||
}
|
||||
|
||||
func digestsCatalogingProgress(locations int64) (*progress.Stage, *progress.Manual) {
|
||||
stage := &progress.Stage{}
|
||||
prog := progress.NewManual(locations)
|
||||
|
||||
bus.Publish(partybus.Event{
|
||||
Type: event.FileDigestsCatalogerStarted,
|
||||
Value: struct {
|
||||
progress.Stager
|
||||
progress.Progressable
|
||||
}{
|
||||
Stager: progress.Stager(stage),
|
||||
Progressable: prog,
|
||||
func digestsCatalogingProgress(locations int64) *monitor.CatalogerTaskProgress {
|
||||
info := monitor.GenericTask{
|
||||
Title: monitor.Title{
|
||||
Default: "Catalog file digests",
|
||||
WhileRunning: "Cataloging file digests",
|
||||
OnSuccess: "Cataloged file digests",
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
return stage, prog
|
||||
return bus.StartCatalogerTask(info, locations, "")
|
||||
}
|
||||
|
||||
@@ -160,3 +160,47 @@ func TestDigestsCataloger_MixFileTypes(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestFileDigestCataloger_GivenCoordinates(t *testing.T) {
|
||||
testImage := "image-file-type-mix"
|
||||
|
||||
img := imagetest.GetFixtureImage(t, "docker-archive", testImage)
|
||||
|
||||
c := NewCataloger([]crypto.Hash{crypto.SHA256})
|
||||
|
||||
src, err := source.NewFromStereoscopeImageObject(img, testImage, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
resolver, err := src.FileResolver(source.SquashedScope)
|
||||
require.NoError(t, err)
|
||||
|
||||
tests := []struct {
|
||||
path string
|
||||
exists bool
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
path: "/file-1.txt",
|
||||
exists: true,
|
||||
expected: "b089629781f05ef805b4511e93717f2ffa4c9d991771d5cbfa4b7242b4ef5fff",
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.path, func(t *testing.T) {
|
||||
_, ref, err := img.SquashedTree().File(stereoscopeFile.Path(test.path))
|
||||
require.NoError(t, err)
|
||||
|
||||
l := file.NewLocationFromImage(test.path, *ref.Reference, img)
|
||||
|
||||
// note: an important difference between this test and the previous is that this test is using a list
|
||||
// of specific coordinates to catalog
|
||||
actual, err := c.Catalog(resolver, l.Coordinates)
|
||||
require.NoError(t, err)
|
||||
require.Len(t, actual, 1)
|
||||
|
||||
assert.Equal(t, test.expected, actual[l.Coordinates][0].Value, "mismatched digests")
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
package filemetadata
|
||||
|
||||
import (
|
||||
"github.com/wagoodman/go-partybus"
|
||||
"github.com/wagoodman/go-progress"
|
||||
"fmt"
|
||||
|
||||
"github.com/dustin/go-humanize"
|
||||
|
||||
"github.com/anchore/syft/internal/bus"
|
||||
"github.com/anchore/syft/internal/log"
|
||||
"github.com/anchore/syft/syft/event"
|
||||
"github.com/anchore/syft/syft/event/monitor"
|
||||
"github.com/anchore/syft/syft/file"
|
||||
)
|
||||
|
||||
@@ -20,7 +21,6 @@ func NewCataloger() *Cataloger {
|
||||
func (i *Cataloger) Catalog(resolver file.Resolver, coordinates ...file.Coordinates) (map[file.Coordinates]file.Metadata, error) {
|
||||
results := make(map[file.Coordinates]file.Metadata)
|
||||
var locations <-chan file.Location
|
||||
|
||||
if len(coordinates) == 0 {
|
||||
locations = resolver.AllLocations()
|
||||
} else {
|
||||
@@ -43,36 +43,35 @@ func (i *Cataloger) Catalog(resolver file.Resolver, coordinates ...file.Coordina
|
||||
}()
|
||||
}
|
||||
|
||||
stage, prog := metadataCatalogingProgress(int64(len(locations)))
|
||||
prog := metadataCatalogingProgress(int64(len(locations)))
|
||||
for location := range locations {
|
||||
stage.Current = location.RealPath
|
||||
prog.Increment()
|
||||
prog.AtomicStage.Set(location.Path())
|
||||
|
||||
metadata, err := resolver.FileMetadataByLocation(location)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
results[location.Coordinates] = metadata
|
||||
prog.Increment()
|
||||
}
|
||||
|
||||
log.Debugf("file metadata cataloger processed %d files", prog.Current())
|
||||
|
||||
prog.AtomicStage.Set(fmt.Sprintf("%s locations", humanize.Comma(prog.Current())))
|
||||
prog.SetCompleted()
|
||||
|
||||
return results, nil
|
||||
}
|
||||
|
||||
func metadataCatalogingProgress(locations int64) (*progress.Stage, *progress.Manual) {
|
||||
stage := &progress.Stage{}
|
||||
prog := progress.NewManual(locations)
|
||||
|
||||
bus.Publish(partybus.Event{
|
||||
Type: event.FileMetadataCatalogerStarted,
|
||||
Value: struct {
|
||||
progress.Stager
|
||||
progress.Progressable
|
||||
}{
|
||||
Stager: progress.Stager(stage),
|
||||
Progressable: prog,
|
||||
func metadataCatalogingProgress(locations int64) *monitor.CatalogerTaskProgress {
|
||||
info := monitor.GenericTask{
|
||||
Title: monitor.Title{
|
||||
Default: "Catalog file metadata",
|
||||
WhileRunning: "Cataloging file metadata",
|
||||
OnSuccess: "Cataloged file metadata",
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
return stage, prog
|
||||
return bus.StartCatalogerTask(info, locations, "")
|
||||
}
|
||||
|
||||
@@ -168,7 +168,6 @@ func TestFileMetadataCataloger_GivenCoordinates(t *testing.T) {
|
||||
path string
|
||||
exists bool
|
||||
expected file.Metadata
|
||||
err bool
|
||||
}{
|
||||
{
|
||||
path: "/file-1.txt",
|
||||
|
||||
@@ -249,9 +249,22 @@ func extractDescriptor(meta *cyclonedx.Metadata) (desc sbom.Descriptor) {
|
||||
return
|
||||
}
|
||||
|
||||
for _, t := range *meta.Tools {
|
||||
desc.Name = t.Name
|
||||
desc.Version = t.Version
|
||||
// handle 1.5 component element
|
||||
if meta.Tools.Components != nil {
|
||||
for _, t := range *meta.Tools.Components {
|
||||
desc.Name = t.Name
|
||||
desc.Version = t.Version
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// handle pre-1.5 tool element
|
||||
if meta.Tools.Tools != nil {
|
||||
for _, t := range *meta.Tools.Tools {
|
||||
desc.Name = t.Name
|
||||
desc.Version = t.Version
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
|
||||
@@ -114,11 +114,14 @@ func formatCPE(cpeString string) string {
|
||||
func toBomDescriptor(name, version string, srcMetadata source.Description) *cyclonedx.Metadata {
|
||||
return &cyclonedx.Metadata{
|
||||
Timestamp: time.Now().Format(time.RFC3339),
|
||||
Tools: &[]cyclonedx.Tool{
|
||||
{
|
||||
Vendor: "anchore",
|
||||
Name: name,
|
||||
Version: version,
|
||||
Tools: &cyclonedx.ToolsChoice{
|
||||
Components: &[]cyclonedx.Component{
|
||||
{
|
||||
Type: cyclonedx.ComponentTypeApplication,
|
||||
Author: "anchore",
|
||||
Name: name,
|
||||
Version: version,
|
||||
},
|
||||
},
|
||||
},
|
||||
Properties: toBomProperties(srcMetadata),
|
||||
|
||||
@@ -168,13 +168,14 @@ func Test_toBomDescriptor(t *testing.T) {
|
||||
want: &cyclonedx.Metadata{
|
||||
Timestamp: "",
|
||||
Lifecycles: nil,
|
||||
Tools: &[]cyclonedx.Tool{
|
||||
{
|
||||
Vendor: "anchore",
|
||||
Name: "test-image",
|
||||
Version: "1.0.0",
|
||||
Hashes: nil,
|
||||
ExternalReferences: nil,
|
||||
Tools: &cyclonedx.ToolsChoice{
|
||||
Components: &[]cyclonedx.Component{
|
||||
{
|
||||
Type: cyclonedx.ComponentTypeApplication,
|
||||
Author: "anchore",
|
||||
Name: "test-image",
|
||||
Version: "1.0.0",
|
||||
},
|
||||
},
|
||||
},
|
||||
Authors: nil,
|
||||
|
||||
+10
-7
@@ -6,13 +6,16 @@
|
||||
"version": 1,
|
||||
"metadata": {
|
||||
"timestamp": "timestamp:redacted",
|
||||
"tools": [
|
||||
{
|
||||
"vendor": "anchore",
|
||||
"name": "syft",
|
||||
"version": "v0.42.0-bogus"
|
||||
}
|
||||
],
|
||||
"tools": {
|
||||
"components": [
|
||||
{
|
||||
"type": "application",
|
||||
"author": "anchore",
|
||||
"name": "syft",
|
||||
"version": "v0.42.0-bogus"
|
||||
}
|
||||
]
|
||||
},
|
||||
"component": {
|
||||
"bom-ref":"redacted",
|
||||
"type": "file",
|
||||
|
||||
@@ -6,13 +6,16 @@
|
||||
"version": 1,
|
||||
"metadata": {
|
||||
"timestamp": "timestamp:redacted",
|
||||
"tools": [
|
||||
{
|
||||
"vendor": "anchore",
|
||||
"name": "syft",
|
||||
"version": "v0.42.0-bogus"
|
||||
}
|
||||
],
|
||||
"tools": {
|
||||
"components": [
|
||||
{
|
||||
"type": "application",
|
||||
"author": "anchore",
|
||||
"name": "syft",
|
||||
"version": "v0.42.0-bogus"
|
||||
}
|
||||
]
|
||||
},
|
||||
"component": {
|
||||
"bom-ref":"redacted",
|
||||
"type": "container",
|
||||
|
||||
+7
-5
@@ -3,11 +3,13 @@
|
||||
<metadata>
|
||||
<timestamp>redacted</timestamp>
|
||||
<tools>
|
||||
<tool>
|
||||
<vendor>anchore</vendor>
|
||||
<name>syft</name>
|
||||
<version>v0.42.0-bogus</version>
|
||||
</tool>
|
||||
<components>
|
||||
<component type="application">
|
||||
<author>anchore</author>
|
||||
<name>syft</name>
|
||||
<version>v0.42.0-bogus</version>
|
||||
</component>
|
||||
</components>
|
||||
</tools>
|
||||
<component bom-ref="redacted" type="file">
|
||||
<name>some/path</name>
|
||||
|
||||
@@ -3,11 +3,13 @@
|
||||
<metadata>
|
||||
<timestamp>redacted</timestamp>
|
||||
<tools>
|
||||
<tool>
|
||||
<vendor>anchore</vendor>
|
||||
<name>syft</name>
|
||||
<version>v0.42.0-bogus</version>
|
||||
</tool>
|
||||
<components>
|
||||
<component type="application">
|
||||
<author>anchore</author>
|
||||
<name>syft</name>
|
||||
<version>v0.42.0-bogus</version>
|
||||
</component>
|
||||
</components>
|
||||
</tools>
|
||||
<component bom-ref="redacted" type="container">
|
||||
<name>user-image-input</name>
|
||||
|
||||
@@ -297,10 +297,15 @@ func TestEncodeFullJSONDocument(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
cfg := DefaultEncoderConfig()
|
||||
cfg.Pretty = true
|
||||
enc, err := NewFormatEncoderWithConfig(cfg)
|
||||
require.NoError(t, err)
|
||||
|
||||
testutil.AssertEncoderAgainstGoldenSnapshot(t,
|
||||
testutil.EncoderSnapshotTestConfig{
|
||||
Subject: s,
|
||||
Format: NewFormatEncoder(),
|
||||
Format: enc,
|
||||
UpdateSnapshot: *updateSnapshot,
|
||||
PersistRedactionsInSnapshot: true,
|
||||
IsJSON: true,
|
||||
|
||||
@@ -640,6 +640,9 @@ func TestAllLayersResolver_AllLocations(t *testing.T) {
|
||||
// this isn't important for the test, so we remove them.
|
||||
paths.Remove("/proc", "/sys", "/dev", "/etc")
|
||||
|
||||
// Remove cache created by Mac Rosetta when emulating different arches
|
||||
paths.Remove("/.cache/rosetta", "/.cache")
|
||||
|
||||
pathsList := paths.List()
|
||||
sort.Strings(pathsList)
|
||||
|
||||
|
||||
@@ -547,6 +547,9 @@ func TestSquashResolver_AllLocations(t *testing.T) {
|
||||
// this isn't important for the test, so we remove them.
|
||||
paths.Remove("/proc", "/sys", "/dev", "/etc")
|
||||
|
||||
// Remove cache created by Mac Rosetta when emulating different arches
|
||||
paths.Remove("/.cache/rosetta", "/.cache")
|
||||
|
||||
pathsList := paths.List()
|
||||
sort.Strings(pathsList)
|
||||
|
||||
|
||||
@@ -715,6 +715,18 @@ func Test_Cataloger_DefaultClassifiers_PositiveCases(t *testing.T) {
|
||||
Metadata: metadata("consul-binary"),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "positive-erlang-25.3.2.7",
|
||||
fixtureDir: "test-fixtures/classifiers/positive/erlang-25.3.2.7",
|
||||
expected: pkg.Package{
|
||||
Name: "erlang",
|
||||
Version: "25.3.2.7",
|
||||
Type: "binary",
|
||||
PURL: "pkg:generic/erlang@25.3.2.7",
|
||||
Locations: locations("erlexec"),
|
||||
Metadata: metadata("erlang-binary"),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "positive-nginx-1.25.1",
|
||||
fixtureDir: "test-fixtures/classifiers/positive/nginx-1.25.1",
|
||||
|
||||
@@ -46,6 +46,15 @@ var defaultClassifiers = []classifier{
|
||||
PURL: mustPURL("pkg:generic/go@version"),
|
||||
CPEs: singleCPE("cpe:2.3:a:golang:go:*:*:*:*:*:*:*:*"),
|
||||
},
|
||||
{
|
||||
Class: "julia-binary",
|
||||
FileGlob: "**/libjulia-internal.so",
|
||||
EvidenceMatcher: fileContentsVersionMatcher(
|
||||
`(?m)__init__\x00(?P<version>[0-9]+\.[0-9]+\.[0-9]+)\x00verify`),
|
||||
Package: "julia",
|
||||
PURL: mustPURL("pkg:generic/julia@version"),
|
||||
CPEs: singleCPE("cpe:2.3:a:julialang:julia:*:*:*:*:*:*:*:*"),
|
||||
},
|
||||
{
|
||||
Class: "helm",
|
||||
FileGlob: "**/helm",
|
||||
@@ -172,6 +181,15 @@ var defaultClassifiers = []classifier{
|
||||
PURL: mustPURL("pkg:generic/php@version"),
|
||||
CPEs: singleCPE("cpe:2.3:a:php:php:*:*:*:*:*:*:*:*"),
|
||||
},
|
||||
{
|
||||
Class: "php-composer-binary",
|
||||
FileGlob: "**/composer*",
|
||||
EvidenceMatcher: fileContentsVersionMatcher(
|
||||
`(?m)'pretty_version'\s*=>\s*'(?P<version>[0-9]+\.[0-9]+\.[0-9]+(beta[0-9]+|alpha[0-9]+|RC[0-9]+)?)'`),
|
||||
Package: "composer",
|
||||
PURL: mustPURL("pkg:generic/composer@version"),
|
||||
CPEs: singleCPE("cpe:2.3:a:getcomposer:composer:*:*:*:*:*:*:*:*"),
|
||||
},
|
||||
{
|
||||
Class: "httpd-binary",
|
||||
FileGlob: "**/httpd",
|
||||
@@ -265,6 +283,17 @@ var defaultClassifiers = []classifier{
|
||||
PURL: mustPURL("pkg:generic/ruby@version"),
|
||||
CPEs: singleCPE("cpe:2.3:a:ruby-lang:ruby:*:*:*:*:*:*:*:*"),
|
||||
},
|
||||
{
|
||||
Class: "erlang-binary",
|
||||
FileGlob: "**/erlexec",
|
||||
EvidenceMatcher: fileContentsVersionMatcher(
|
||||
// <artificial>[NUL]/usr/local/src/otp-25.3.2.7/erts/
|
||||
`(?m)\<artificial\>\x00/usr/local/src/otp-(?P<version>[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+?)/erts/`,
|
||||
),
|
||||
Package: "erlang",
|
||||
PURL: mustPURL("pkg:generic/erlang@version"),
|
||||
CPEs: singleCPE("cpe:2.3:a:erlang:erlang\\/otp:*:*:*:*:*:*:*:*"),
|
||||
},
|
||||
{
|
||||
Class: "consul-binary",
|
||||
FileGlob: "**/consul",
|
||||
|
||||
Binary file not shown.
Executable → Regular
Binary file not shown.
Executable → Regular
Executable → Regular
Executable → Regular
Executable → Regular
Executable → Regular
Executable → Regular
Executable → Regular
Executable → Regular
Executable → Regular
Executable → Regular
Executable → Regular
@@ -6,14 +6,14 @@ import (
|
||||
"runtime/debug"
|
||||
"sync"
|
||||
|
||||
"github.com/dustin/go-humanize"
|
||||
"github.com/hashicorp/go-multierror"
|
||||
"github.com/wagoodman/go-partybus"
|
||||
"github.com/wagoodman/go-progress"
|
||||
|
||||
"github.com/anchore/syft/internal/bus"
|
||||
"github.com/anchore/syft/internal/log"
|
||||
"github.com/anchore/syft/syft/artifact"
|
||||
"github.com/anchore/syft/syft/event"
|
||||
"github.com/anchore/syft/syft/event/monitor"
|
||||
"github.com/anchore/syft/syft/file"
|
||||
"github.com/anchore/syft/syft/linux"
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
@@ -35,21 +35,6 @@ type catalogResult struct {
|
||||
Error error
|
||||
}
|
||||
|
||||
// newMonitor creates a new Monitor object and publishes the object on the bus as a PackageCatalogerStarted event.
|
||||
func newMonitor() (*progress.Manual, *progress.Manual) {
|
||||
filesProcessed := progress.Manual{}
|
||||
packagesDiscovered := progress.Manual{}
|
||||
|
||||
bus.Publish(partybus.Event{
|
||||
Type: event.PackageCatalogerStarted,
|
||||
Value: Monitor{
|
||||
FilesProcessed: progress.Monitorable(&filesProcessed),
|
||||
PackagesDiscovered: progress.Monitorable(&packagesDiscovered),
|
||||
},
|
||||
})
|
||||
return &filesProcessed, &packagesDiscovered
|
||||
}
|
||||
|
||||
func runCataloger(cataloger pkg.Cataloger, resolver file.Resolver) (catalogerResult *catalogResult, err error) {
|
||||
// handle individual cataloger panics
|
||||
defer func() {
|
||||
@@ -101,6 +86,7 @@ func runCataloger(cataloger pkg.Cataloger, resolver file.Resolver) (catalogerRes
|
||||
}
|
||||
catalogerResult.Packages = append(catalogerResult.Packages, p)
|
||||
}
|
||||
|
||||
catalogerResult.Relationships = append(catalogerResult.Relationships, relationships...)
|
||||
log.WithFields("cataloger", cataloger.Name()).Trace("cataloging complete")
|
||||
return catalogerResult, err
|
||||
@@ -116,9 +102,7 @@ func Catalog(resolver file.Resolver, _ *linux.Release, parallelism int, cataloge
|
||||
catalog := pkg.NewCollection()
|
||||
var allRelationships []artifact.Relationship
|
||||
|
||||
filesProcessed, packagesDiscovered := newMonitor()
|
||||
defer filesProcessed.SetCompleted()
|
||||
defer packagesDiscovered.SetCompleted()
|
||||
prog := monitorPackageCatalogingTask()
|
||||
|
||||
// perform analysis, accumulating errors for each failed analysis
|
||||
var errs error
|
||||
@@ -131,10 +115,11 @@ func Catalog(resolver file.Resolver, _ *linux.Release, parallelism int, cataloge
|
||||
|
||||
jobs := make(chan pkg.Cataloger, nCatalogers)
|
||||
results := make(chan *catalogResult, nCatalogers)
|
||||
discoveredPackages := make(chan int64, nCatalogers)
|
||||
|
||||
waitGroup := sync.WaitGroup{}
|
||||
|
||||
var totalPackagesDiscovered int64
|
||||
|
||||
for i := 0; i < parallelism; i++ {
|
||||
waitGroup.Add(1)
|
||||
|
||||
@@ -148,20 +133,16 @@ func Catalog(resolver file.Resolver, _ *linux.Release, parallelism int, cataloge
|
||||
// ensure we set the error to be aggregated
|
||||
result.Error = err
|
||||
|
||||
discoveredPackages <- result.Discovered
|
||||
prog.Add(result.Discovered)
|
||||
totalPackagesDiscovered += result.Discovered
|
||||
count := humanize.Comma(totalPackagesDiscovered)
|
||||
prog.AtomicStage.Set(fmt.Sprintf("%s packages", count))
|
||||
|
||||
results <- result
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
// dynamically show updated discovered package status
|
||||
go func() {
|
||||
for discovered := range discoveredPackages {
|
||||
packagesDiscovered.Add(discovered)
|
||||
}
|
||||
}()
|
||||
|
||||
// Enqueue the jobs
|
||||
for _, cataloger := range catalogers {
|
||||
jobs <- cataloger
|
||||
@@ -171,7 +152,6 @@ func Catalog(resolver file.Resolver, _ *linux.Release, parallelism int, cataloge
|
||||
// Wait for the jobs to finish
|
||||
waitGroup.Wait()
|
||||
close(results)
|
||||
close(discoveredPackages)
|
||||
|
||||
// collect the results
|
||||
for result := range results {
|
||||
@@ -186,6 +166,12 @@ func Catalog(resolver file.Resolver, _ *linux.Release, parallelism int, cataloge
|
||||
|
||||
allRelationships = append(allRelationships, pkg.NewRelationships(catalog)...)
|
||||
|
||||
if errs != nil {
|
||||
prog.SetError(errs)
|
||||
} else {
|
||||
prog.SetCompleted()
|
||||
}
|
||||
|
||||
return catalog, allRelationships, errs
|
||||
}
|
||||
|
||||
@@ -228,3 +214,16 @@ func packageFileOwnershipRelationships(p pkg.Package, resolver file.PathResolver
|
||||
}
|
||||
return relationships, nil
|
||||
}
|
||||
|
||||
func monitorPackageCatalogingTask() *monitor.CatalogerTaskProgress {
|
||||
info := monitor.GenericTask{
|
||||
Title: monitor.Title{
|
||||
Default: "Catalog packages",
|
||||
WhileRunning: "Cataloging packages",
|
||||
OnSuccess: "Cataloged packages",
|
||||
},
|
||||
HideOnSuccess: false,
|
||||
}
|
||||
|
||||
return bus.StartCatalogerTask(info, -1, "")
|
||||
}
|
||||
|
||||
@@ -83,9 +83,9 @@ func DirectoryCatalogers(cfg Config) []pkg.Cataloger {
|
||||
haskell.NewHackageCataloger(),
|
||||
java.NewArchiveCataloger(cfg.JavaConfig()),
|
||||
java.NewGradleLockfileCataloger(),
|
||||
java.NewPomCataloger(),
|
||||
java.NewPomCataloger(cfg.JavaConfig()),
|
||||
java.NewNativeImageCataloger(),
|
||||
javascript.NewLockCataloger(),
|
||||
javascript.NewLockCataloger(cfg.Javascript),
|
||||
nix.NewStoreCataloger(),
|
||||
php.NewComposerLockCataloger(),
|
||||
gentoo.NewPortageCataloger(),
|
||||
@@ -122,9 +122,9 @@ func AllCatalogers(cfg Config) []pkg.Cataloger {
|
||||
haskell.NewHackageCataloger(),
|
||||
java.NewArchiveCataloger(cfg.JavaConfig()),
|
||||
java.NewGradleLockfileCataloger(),
|
||||
java.NewPomCataloger(),
|
||||
java.NewPomCataloger(cfg.JavaConfig()),
|
||||
java.NewNativeImageCataloger(),
|
||||
javascript.NewLockCataloger(),
|
||||
javascript.NewLockCataloger(cfg.Javascript),
|
||||
javascript.NewPackageCataloger(),
|
||||
kernel.NewLinuxKernelCataloger(cfg.LinuxKernel),
|
||||
nix.NewStoreCataloger(),
|
||||
|
||||
@@ -115,6 +115,7 @@
|
||||
"google-kubernetes-engine": "cpe:2.3:a:jenkins:google_kubernetes_engine:*:*:*:*:*:jenkins:*:*",
|
||||
"google-oauth": "cpe:2.3:a:jenkins:google_oauth_credentials:*:*:*:*:*:jenkins:*:*",
|
||||
"google-play-android-publisher": "cpe:2.3:a:jenkins:google-play-android-publisher:*:*:*:*:*:jenkins:*:*",
|
||||
"gradle": "cpe:2.3:a:jenkins:gradle:*:*:*:*:*:jenkins:*:*",
|
||||
"groovy": "cpe:2.3:a:jenkins:groovy:*:*:*:*:*:jenkins:*:*",
|
||||
"harvest": "cpe:2.3:a:jenkins:harvest_scm:*:*:*:*:*:jenkins:*:*",
|
||||
"hipchat": "cpe:2.3:a:atlassian:hipchat:*:*:*:*:*:jenkins:*:*",
|
||||
@@ -288,6 +289,7 @@
|
||||
"@awsui/components-react": "cpe:2.3:a:amazon:awsui\\/components-react:*:*:*:*:*:node.js:*:*",
|
||||
"@azure/ms-rest-nodeauth": "cpe:2.3:a:microsoft:ms-rest-nodeauth:*:*:*:*:*:node.js:*:*",
|
||||
"@backstage/plugin-auth-backend": "cpe:2.3:a:linuxfoundation:auth_backend:*:*:*:*:*:node.js:*:*",
|
||||
"@evershop/evershop": "cpe:2.3:a:evershop:evershop:*:*:*:*:*:node.js:*:*",
|
||||
"@fastly/js-compute": "cpe:2.3:a:fastly:js-compute:*:*:*:*:*:node.js:*:*",
|
||||
"@firebase/util": "cpe:2.3:a:google:firebase\\/util:*:*:*:*:*:node.js:*:*",
|
||||
"@github/paste-markdown": "cpe:2.3:a:paste-markdown_project:paste-markdown:*:*:*:*:*:node.js:*:*",
|
||||
@@ -295,9 +297,11 @@
|
||||
"@nuxt/devalue": "cpe:2.3:a:nuxtjs:\\@nuxt\\/devalue:*:*:*:*:*:node.js:*:*",
|
||||
"@progfay/scrapbox-parser": "cpe:2.3:a:scrapbox-parser_project:scrapbox-parser:*:*:*:*:*:node.js:*:*",
|
||||
"@rkesters/gnuplot": "cpe:2.3:a:gnuplot_project:gnuplot:*:*:*:*:*:node.js:*:*",
|
||||
"@sap/xssec": "cpe:2.3:a:sap:\\@sap\\/xssec:*:*:*:*:*:node.js:*:*",
|
||||
"@solana/pay": "cpe:2.3:a:solanalabs:pay:*:*:*:*:*:*:*:*",
|
||||
"@strikeentco/set": "cpe:2.3:a:set_project:set:*:*:*:*:*:node.js:*:*",
|
||||
"@thi.ng/egf": "cpe:2.3:a:\\@thi.ng\\/egf_project:\\@thi.ng\\/egf:*:*:*:*:*:node.js:*:*",
|
||||
"@vue/devtools": "cpe:2.3:a:vuejs:devtools:*:*:*:*:*:node.js:*:*",
|
||||
"@zxcvbn-ts/core": "cpe:2.3:a:zxcvbn-ts_project:zxcvbn-ts:*:*:*:*:*:node.js:*:*",
|
||||
"Proto": "cpe:2.3:a:proto_project:proto:*:*:*:*:*:node.js:*:*",
|
||||
"Templ8": "cpe:2.3:a:templ8_project:templ8:*:*:*:*:*:node.js:*:*",
|
||||
@@ -389,6 +393,7 @@
|
||||
"conf-cfg-ini": "cpe:2.3:a:conf-cfg-ini_project:conf-cfg-ini:*:*:*:*:*:node.js:*:*",
|
||||
"confinit": "cpe:2.3:a:confinit_project:confinit:*:*:*:*:*:node.js:*:*",
|
||||
"confucious": "cpe:2.3:a:realseriousgames:confucious:*:*:*:*:*:node.js:*:*",
|
||||
"connect-multiparty": "cpe:2.3:a:connect-multiparty_project:connect-multiparty:*:*:*:*:*:*:*:*",
|
||||
"connect-pg-simple": "cpe:2.3:a:connect-pg-simple_project:connect-pg-simple:*:*:*:*:*:node.js:*:*",
|
||||
"connection-tester": "cpe:2.3:a:connection-tester_project:connection-tester:*:*:*:*:*:node.js:*:*",
|
||||
"console-io": "cpe:2.3:a:console-io_project:console-io:*:*:*:*:*:node.js:*:*",
|
||||
@@ -1084,11 +1089,15 @@
|
||||
"reqmgr2": "cpe:2.3:a:reqmgr2_project:reqmgr2:*:*:*:*:*:python:*:*",
|
||||
"reqmon": "cpe:2.3:a:reqmon_project:reqmon:*:*:*:*:*:python:*:*",
|
||||
"requests-xml": "cpe:2.3:a:requests-xml_project:requests-xml:*:*:*:*:*:python:*:*",
|
||||
"rondolu-yt-concate": "cpe:2.3:a:rondolu-yt-concate_project:rondolu-yt-concate:*:*:*:*:*:pypi:*:*",
|
||||
"rope": "cpe:2.3:a:rope_project:rope:*:*:*:*:*:python:*:*",
|
||||
"rply": "cpe:2.3:a:rply_project:rply:*:*:*:*:*:*:*:*",
|
||||
"rsa": "cpe:2.3:a:python:rsa:*:*:*:*:*:python:*:*",
|
||||
"ruamel.yaml": "cpe:2.3:a:ruamel.yaml_project:ruamel.yaml:*:*:*:*:*:*:*:*",
|
||||
"sap-xssec": "cpe:2.3:a:sap:sap-xssec:*:*:*:*:*:python:*:*",
|
||||
"scoptrial": "cpe:2.3:a:scoptrial_project:scoptrial:*:*:*:*:*:pypi:*:*",
|
||||
"simiki": "cpe:2.3:a:simiki_project:simiki:*:*:*:*:*:*:*:*",
|
||||
"sixfab-power-python-api": "cpe:2.3:a:sixfab-tool_project:sixfab-tool:*:*:*:*:*:pypi:*:*",
|
||||
"slashify": "cpe:2.3:a:google:slashify:*:*:*:*:*:node.js:*:*",
|
||||
"sopel-plugins.channelmgnt": "cpe:2.3:a:mirahezebots:channelmgnt:*:*:*:*:*:sopel:*:*",
|
||||
"spacy": "cpe:2.3:a:explosion:spacy:*:*:*:*:*:python:*:*",
|
||||
@@ -1219,6 +1228,7 @@
|
||||
"bzip2": "cpe:2.3:a:bzip2_project:bzip2:*:*:*:*:*:rust:*:*",
|
||||
"cache": "cpe:2.3:a:cache_project:cache:*:*:*:*:*:rust:*:*",
|
||||
"cached": "cpe:2.3:a:cached_project:cached:*:*:*:*:*:rust:*:*",
|
||||
"candid": "cpe:2.3:a:dfinity:candid:*:*:*:*:*:rust:*:*",
|
||||
"cbox": "cpe:2.3:a:cbox_project:cbox:*:*:*:*:*:rust:*:*",
|
||||
"ckb": "cpe:2.3:a:nervos:ckb:*:*:*:*:*:rust:*:*",
|
||||
"conduit-hyper": "cpe:2.3:a:conduit-hyper_project:conduit-hyper:*:*:*:*:*:rust:*:*",
|
||||
|
||||
@@ -294,7 +294,7 @@ func GetManifestFieldGroupIDs(manifest *pkg.JavaManifest, fields []string) (grou
|
||||
}
|
||||
|
||||
func cleanGroupID(groupID string) string {
|
||||
return strings.TrimSpace(removeOSCIDirectives(groupID))
|
||||
return strings.TrimSpace(strings.Split(removeOSCIDirectives(groupID), "#")[0])
|
||||
}
|
||||
|
||||
func removeOSCIDirectives(groupID string) string {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -161,6 +161,17 @@ func Test_groupIDsFromJavaPackage(t *testing.T) {
|
||||
},
|
||||
expects: []string{"io.jenkins-ci.plugin.thing"},
|
||||
},
|
||||
{
|
||||
name: "clean # suffixes",
|
||||
pkg: pkg.Package{
|
||||
Metadata: pkg.JavaArchive{
|
||||
PomProperties: &pkg.JavaPomProperties{
|
||||
GroupID: "org.elasticsearch.plugin#parent-join;6.8.15",
|
||||
},
|
||||
},
|
||||
},
|
||||
expects: []string{"org.elasticsearch.plugin"},
|
||||
},
|
||||
{
|
||||
name: "from artifactID",
|
||||
pkg: pkg.Package{
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"github.com/anchore/syft/syft/cataloging"
|
||||
"github.com/anchore/syft/syft/pkg/cataloger/golang"
|
||||
"github.com/anchore/syft/syft/pkg/cataloger/java"
|
||||
"github.com/anchore/syft/syft/pkg/cataloger/javascript"
|
||||
"github.com/anchore/syft/syft/pkg/cataloger/kernel"
|
||||
"github.com/anchore/syft/syft/pkg/cataloger/python"
|
||||
)
|
||||
@@ -15,6 +16,7 @@ type Config struct {
|
||||
LinuxKernel kernel.LinuxKernelCatalogerConfig
|
||||
Python python.CatalogerConfig
|
||||
Java java.ArchiveCatalogerConfig
|
||||
Javascript javascript.CatalogerConfig
|
||||
Catalogers []string
|
||||
Parallelism int
|
||||
ExcludeBinaryOverlapByOwnership bool
|
||||
@@ -27,6 +29,7 @@ func DefaultConfig() Config {
|
||||
LinuxKernel: kernel.DefaultLinuxCatalogerConfig(),
|
||||
Python: python.DefaultCatalogerConfig(),
|
||||
Java: java.DefaultArchiveCatalogerConfig(),
|
||||
Javascript: javascript.DefaultCatalogerConfig(),
|
||||
ExcludeBinaryOverlapByOwnership: true,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,23 +58,14 @@ func parseDotnetPortableExecutable(_ file.Resolver, _ *generic.Environment, f fi
|
||||
func buildDotNetPackage(versionResources map[string]string, f file.LocationReadCloser) (dnpkg pkg.Package, err error) {
|
||||
name := findName(versionResources)
|
||||
if name == "" {
|
||||
return dnpkg, fmt.Errorf("unable to find FileDescription, or ProductName in PE file: %s", f.RealPath)
|
||||
return dnpkg, fmt.Errorf("unable to find PE name in file: %s", f.RealPath)
|
||||
}
|
||||
|
||||
version := findVersion(versionResources)
|
||||
if strings.TrimSpace(version) == "" {
|
||||
return dnpkg, fmt.Errorf("unable to find FileVersion in PE file: %s", f.RealPath)
|
||||
if version == "" {
|
||||
return dnpkg, fmt.Errorf("unable to find PE version in file: %s", f.RealPath)
|
||||
}
|
||||
|
||||
purl := packageurl.NewPackageURL(
|
||||
packageurl.TypeNuget, // See explanation in syft/pkg/cataloger/dotnet/package.go as to why this was chosen.
|
||||
"",
|
||||
name,
|
||||
version,
|
||||
nil,
|
||||
"",
|
||||
).ToString()
|
||||
|
||||
metadata := pkg.DotnetPortableExecutableEntry{
|
||||
AssemblyVersion: versionResources["Assembly Version"],
|
||||
LegalCopyright: versionResources["LegalCopyright"],
|
||||
@@ -91,7 +82,7 @@ func buildDotNetPackage(versionResources map[string]string, f file.LocationReadC
|
||||
Locations: file.NewLocationSet(f.Location.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation)),
|
||||
Type: pkg.DotnetPkg,
|
||||
Language: pkg.Dotnet,
|
||||
PURL: purl,
|
||||
PURL: portableExecutablePackageURL(name, version),
|
||||
Metadata: metadata,
|
||||
}
|
||||
|
||||
@@ -100,30 +91,128 @@ func buildDotNetPackage(versionResources map[string]string, f file.LocationReadC
|
||||
return dnpkg, nil
|
||||
}
|
||||
|
||||
func findVersion(versionResources map[string]string) string {
|
||||
for _, key := range []string{"FileVersion"} {
|
||||
if version, ok := versionResources[key]; ok {
|
||||
if strings.TrimSpace(version) == "" {
|
||||
continue
|
||||
}
|
||||
fields := strings.Fields(version)
|
||||
if len(fields) > 0 {
|
||||
return fields[0]
|
||||
}
|
||||
func portableExecutablePackageURL(name, version string) string {
|
||||
return packageurl.NewPackageURL(
|
||||
packageurl.TypeNuget, // See explanation in syft/pkg/cataloger/dotnet/package.go as to why this was chosen.
|
||||
"",
|
||||
name,
|
||||
version,
|
||||
nil,
|
||||
"",
|
||||
).ToString()
|
||||
}
|
||||
|
||||
func extractVersion(version string) string {
|
||||
version = strings.TrimSpace(version)
|
||||
|
||||
out := ""
|
||||
|
||||
// some example versions are: "1, 0, 0, 0", "Release 73" or "4.7.4076.0 built by: NET472REL1LAST_B"
|
||||
// so try to split it and take the first parts that look numeric
|
||||
for i, f := range strings.Fields(version) {
|
||||
// if the output already has a number but the current segment does not have a number,
|
||||
// return what we found for the version
|
||||
if containsNumber(out) && !containsNumber(f) {
|
||||
return out
|
||||
}
|
||||
|
||||
if i == 0 {
|
||||
out = f
|
||||
} else {
|
||||
out += " " + f
|
||||
}
|
||||
}
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
func findVersion(versionResources map[string]string) string {
|
||||
productVersion := extractVersion(versionResources["ProductVersion"])
|
||||
fileVersion := extractVersion(versionResources["FileVersion"])
|
||||
|
||||
if productVersion == "" {
|
||||
return fileVersion
|
||||
}
|
||||
|
||||
productVersionDetail := punctuationCount(productVersion)
|
||||
fileVersionDetail := punctuationCount(fileVersion)
|
||||
|
||||
if containsNumber(productVersion) && productVersionDetail >= fileVersionDetail {
|
||||
return productVersion
|
||||
}
|
||||
|
||||
if containsNumber(fileVersion) && fileVersionDetail > 0 {
|
||||
return fileVersion
|
||||
}
|
||||
|
||||
if containsNumber(productVersion) {
|
||||
return productVersion
|
||||
}
|
||||
|
||||
if containsNumber(fileVersion) {
|
||||
return fileVersion
|
||||
}
|
||||
|
||||
return productVersion
|
||||
}
|
||||
|
||||
func containsNumber(s string) bool {
|
||||
return numberRegex.MatchString(s)
|
||||
}
|
||||
|
||||
func punctuationCount(s string) int {
|
||||
return len(versionPunctuationRegex.FindAllString(s, -1))
|
||||
}
|
||||
|
||||
var (
|
||||
// spaceRegex includes nbsp (#160) considered to be a space character
|
||||
spaceRegex = regexp.MustCompile(`[\s\xa0]+`)
|
||||
numberRegex = regexp.MustCompile(`\d`)
|
||||
versionPunctuationRegex = regexp.MustCompile(`[.,]+`)
|
||||
)
|
||||
|
||||
func findName(versionResources map[string]string) string {
|
||||
// PE files found in the wild _not_ authored by Microsoft seem to use ProductName as a clear
|
||||
// identifier of the software
|
||||
nameFields := []string{"ProductName", "FileDescription", "InternalName", "OriginalFilename"}
|
||||
|
||||
if isMicrosoft(versionResources) {
|
||||
// Microsoft seems to be consistent using the FileDescription, with a few that are blank and have
|
||||
// fallbacks to ProductName last, as this is often something very broad like "Microsoft Windows"
|
||||
nameFields = []string{"FileDescription", "InternalName", "OriginalFilename", "ProductName"}
|
||||
}
|
||||
|
||||
for _, field := range nameFields {
|
||||
value := spaceNormalize(versionResources[field])
|
||||
if value == "" {
|
||||
continue
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
func findName(versionResources map[string]string) string {
|
||||
for _, key := range []string{"FileDescription", "ProductName"} {
|
||||
if name, ok := versionResources[key]; ok {
|
||||
if strings.TrimSpace(name) == "" {
|
||||
continue
|
||||
}
|
||||
trimmed := strings.TrimSpace(name)
|
||||
return regexp.MustCompile(`[^a-zA-Z0-9.]+`).ReplaceAllString(trimmed, "")
|
||||
}
|
||||
// normalizes a string to a trimmed version with all contigous whitespace collapsed to a single space character
|
||||
func spaceNormalize(value string) string {
|
||||
value = strings.TrimSpace(value)
|
||||
if value == "" {
|
||||
return ""
|
||||
}
|
||||
return ""
|
||||
// ensure valid utf8 text
|
||||
value = strings.ToValidUTF8(value, "")
|
||||
// consolidate all space characters
|
||||
value = spaceRegex.ReplaceAllString(value, " ")
|
||||
// remove other non-space, non-printable characters
|
||||
value = regexp.MustCompile(`[\x00-\x1f]`).ReplaceAllString(value, "")
|
||||
// consolidate all space characters again in case other non-printables were in-between
|
||||
value = spaceRegex.ReplaceAllString(value, " ")
|
||||
// finally, remove any remaining surrounding whitespace
|
||||
value = strings.TrimSpace(value)
|
||||
return value
|
||||
}
|
||||
|
||||
func isMicrosoft(versionResources map[string]string) bool {
|
||||
return strings.Contains(strings.ToLower(versionResources["CompanyName"]), "microsoft") ||
|
||||
strings.Contains(strings.ToLower(versionResources["ProductName"]), "microsoft")
|
||||
}
|
||||
|
||||
@@ -32,12 +32,8 @@ func TestParseDotnetPortableExecutable(t *testing.T) {
|
||||
"Assembly Version": "3.14.2.11",
|
||||
},
|
||||
expectedPackage: pkg.Package{
|
||||
Name: "ActiveDirectoryAuthenticationLibrary",
|
||||
Version: "3.14.40721.0918",
|
||||
Locations: file.NewLocationSet(file.NewLocation("").WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation)),
|
||||
Type: pkg.DotnetPkg,
|
||||
Language: pkg.Dotnet,
|
||||
PURL: "pkg:nuget/ActiveDirectoryAuthenticationLibrary@3.14.40721.0918",
|
||||
Name: "Active Directory Authentication Library",
|
||||
Version: "3.14.40721.0918",
|
||||
Metadata: pkg.DotnetPortableExecutableEntry{
|
||||
AssemblyVersion: "3.14.2.11",
|
||||
LegalCopyright: "Copyright (c) Microsoft Corporation. All rights reserved.",
|
||||
@@ -52,7 +48,7 @@ func TestParseDotnetPortableExecutable(t *testing.T) {
|
||||
name: "dotnet package with malformed field and extended version",
|
||||
versionResources: map[string]string{
|
||||
"CompanyName": "Microsoft Corporation",
|
||||
"FileDescription": "äbFileVersion",
|
||||
"FileDescription": "äbFile\xa0\xa1Versi on",
|
||||
"FileVersion": "4.6.25512.01 built by: dlab-DDVSOWINAGE016. Commit Hash: d0d5c7b49271cadb6d97de26d8e623e98abdc8db",
|
||||
"InternalName": "äbFileVersion",
|
||||
"LegalCopyright": "© Microsoft Corporation. All rights reserved.",
|
||||
@@ -61,13 +57,9 @@ func TestParseDotnetPortableExecutable(t *testing.T) {
|
||||
"ProductVersion": "4.6.25512.01 built by: dlab-DDVSOWINAGE016. Commit Hash: d0d5c7b49271cadb6d97de26d8e623e98abdc8db",
|
||||
},
|
||||
expectedPackage: pkg.Package{
|
||||
Name: "bFileVersion",
|
||||
Name: "äbFileVersi on",
|
||||
Version: "4.6.25512.01",
|
||||
Locations: file.NewLocationSet(
|
||||
file.NewLocation("").WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation)),
|
||||
Type: pkg.DotnetPkg,
|
||||
Language: pkg.Dotnet,
|
||||
PURL: "pkg:nuget/bFileVersion@4.6.25512.01",
|
||||
PURL: "pkg:nuget/%C3%A4bFileVersi%20on@4.6.25512.01",
|
||||
Metadata: pkg.DotnetPortableExecutableEntry{
|
||||
LegalCopyright: "© Microsoft Corporation. All rights reserved.",
|
||||
InternalName: "äb\x01FileVersion",
|
||||
@@ -77,16 +69,208 @@ func TestParseDotnetPortableExecutable(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "System.Data.Linq.dll",
|
||||
versionResources: map[string]string{
|
||||
"CompanyName": "Microsoft Corporation",
|
||||
"FileDescription": "System.Data.Linq.dll",
|
||||
"FileVersion": "4.7.3190.0 built by: NET472REL1LAST_C",
|
||||
"InternalName": "System.Data.Linq.dll",
|
||||
"LegalCopyright": "© Microsoft Corporation. All rights reserved.",
|
||||
"OriginalFilename": "System.Data.Linq.dll",
|
||||
"ProductName": "Microsoft® .NET Framework",
|
||||
"ProductVersion": "4.7.3190.0",
|
||||
},
|
||||
expectedPackage: pkg.Package{
|
||||
Name: "System.Data.Linq.dll",
|
||||
Version: "4.7.3190.0",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "curl",
|
||||
versionResources: map[string]string{
|
||||
"CompanyName": "curl, https://curl.se/",
|
||||
"FileDescription": "The curl executable",
|
||||
"FileVersion": "8.4.0",
|
||||
"InternalName": "curl",
|
||||
"LegalCopyright": "© Daniel Stenberg, <daniel@haxx.se>.",
|
||||
"OriginalFilename": "curl.exe",
|
||||
"ProductName": "The curl executable",
|
||||
"ProductVersion": "8.4.0",
|
||||
},
|
||||
expectedPackage: pkg.Package{
|
||||
Name: "The curl executable",
|
||||
Version: "8.4.0",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Prometheus",
|
||||
versionResources: map[string]string{
|
||||
"AssemblyVersion": "8.0.0.0",
|
||||
"CompanyName": "",
|
||||
"FileDescription": "",
|
||||
"FileVersion": "8.0.1",
|
||||
"InternalName": "Prometheus.AspNetCore.dll",
|
||||
"OriginalFilename": "Prometheus.AspNetCore.dll",
|
||||
"ProductName": "",
|
||||
"ProductVersion": "8.0.1",
|
||||
},
|
||||
expectedPackage: pkg.Package{
|
||||
Name: "Prometheus.AspNetCore.dll",
|
||||
Version: "8.0.1",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Hidden Input",
|
||||
versionResources: map[string]string{
|
||||
"FileDescription": "Reads from stdin without leaking info to the terminal and outputs back to stdout",
|
||||
"FileVersion": "1, 0, 0, 0",
|
||||
"InternalName": "hiddeninput",
|
||||
"LegalCopyright": "Jordi Boggiano - 2012",
|
||||
"OriginalFilename": "hiddeninput.exe",
|
||||
"ProductName": "Hidden Input",
|
||||
"ProductVersion": "1, 0, 0, 0",
|
||||
},
|
||||
expectedPackage: pkg.Package{
|
||||
Name: "Hidden Input",
|
||||
Version: "1, 0, 0, 0",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "SQLite3",
|
||||
versionResources: map[string]string{
|
||||
"CompanyName": "SQLite Development Team",
|
||||
"FileDescription": "SQLite is a software library that implements a self-contained, serverless, zero-configuration, transactional SQL database engine.",
|
||||
"FileVersion": "3.23.2",
|
||||
"InternalName": "sqlite3",
|
||||
"LegalCopyright": "http://www.sqlite.org/copyright.html",
|
||||
"ProductName": "SQLite",
|
||||
"ProductVersion": "3.23.2",
|
||||
},
|
||||
expectedPackage: pkg.Package{
|
||||
Name: "SQLite",
|
||||
Version: "3.23.2",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Brave Browser",
|
||||
versionResources: map[string]string{
|
||||
"CompanyName": "Brave Software, Inc.",
|
||||
"FileDescription": "Brave Browser",
|
||||
"FileVersion": "80.1.7.92",
|
||||
"InternalName": "chrome_exe",
|
||||
"LegalCopyright": "Copyright 2016 The Brave Authors. All rights reserved.",
|
||||
"OriginalFilename": "chrome.exe",
|
||||
"ProductName": "Brave Browser",
|
||||
"ProductVersion": "80.1.7.92",
|
||||
},
|
||||
expectedPackage: pkg.Package{
|
||||
Name: "Brave Browser",
|
||||
Version: "80.1.7.92",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Better product version",
|
||||
versionResources: map[string]string{
|
||||
"FileDescription": "Better version",
|
||||
"FileVersion": "80.1.7",
|
||||
"ProductVersion": "80.1.7.92",
|
||||
},
|
||||
expectedPackage: pkg.Package{
|
||||
Name: "Better version",
|
||||
Version: "80.1.7.92",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Better file version",
|
||||
versionResources: map[string]string{
|
||||
"FileDescription": "Better version",
|
||||
"FileVersion": "80.1.7.92",
|
||||
"ProductVersion": "80.1.7",
|
||||
},
|
||||
expectedPackage: pkg.Package{
|
||||
Name: "Better version",
|
||||
Version: "80.1.7.92",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
location := file.NewLocation("")
|
||||
f := file.LocationReadCloser{
|
||||
Location: file.NewLocation(""),
|
||||
Location: location,
|
||||
}
|
||||
got, err := buildDotNetPackage(tc.versionResources, f)
|
||||
assert.NoErrorf(t, err, "failed to build package from version resources: %+v", tc.versionResources)
|
||||
|
||||
// ignore certain metadata
|
||||
if tc.expectedPackage.Metadata == nil {
|
||||
got.Metadata = nil
|
||||
}
|
||||
// set known defaults
|
||||
if tc.expectedPackage.Type == "" {
|
||||
tc.expectedPackage.Type = pkg.DotnetPkg
|
||||
}
|
||||
if tc.expectedPackage.Language == "" {
|
||||
tc.expectedPackage.Language = pkg.Dotnet
|
||||
}
|
||||
if tc.expectedPackage.PURL == "" {
|
||||
tc.expectedPackage.PURL = portableExecutablePackageURL(tc.expectedPackage.Name, tc.expectedPackage.Version)
|
||||
}
|
||||
tc.expectedPackage.Locations = file.NewLocationSet(location.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation))
|
||||
|
||||
pkgtest.AssertPackagesEqual(t, tc.expectedPackage, got)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_extractVersion(t *testing.T) {
|
||||
tests := []struct {
|
||||
input string
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
input: "1, 0, 0, 0",
|
||||
expected: "1, 0, 0, 0",
|
||||
},
|
||||
{
|
||||
input: "Release 73",
|
||||
expected: "Release 73",
|
||||
},
|
||||
{
|
||||
input: "4.7.4076.0 built by: NET472REL1LAST_B",
|
||||
expected: "4.7.4076.0",
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.input, func(t *testing.T) {
|
||||
got := extractVersion(test.input)
|
||||
assert.Equal(t, test.expected, got)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_spaceNormalize(t *testing.T) {
|
||||
tests := []struct {
|
||||
input string
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
expected: "some spaces apart",
|
||||
input: " some spaces\n\t\t \n\rapart\n",
|
||||
},
|
||||
{
|
||||
expected: "söme ¡nvalid characters",
|
||||
input: "\rsöme \u0001¡nvalid\t characters\n",
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.expected, func(t *testing.T) {
|
||||
got := spaceNormalize(test.input)
|
||||
assert.Equal(t, test.expected, got)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ import (
|
||||
"github.com/go-git/go-git/v5/storage/memory"
|
||||
"github.com/scylladb/go-set/strset"
|
||||
|
||||
"github.com/anchore/syft/internal/bus"
|
||||
"github.com/anchore/syft/internal/licenses"
|
||||
"github.com/anchore/syft/internal/log"
|
||||
"github.com/anchore/syft/syft/event/monitor"
|
||||
@@ -31,7 +32,6 @@ import (
|
||||
type goLicenses struct {
|
||||
opts CatalogerConfig
|
||||
localModCacheResolver file.WritableResolver
|
||||
progress *monitor.CatalogerTask
|
||||
lowerLicenseFileNames *strset.Set
|
||||
}
|
||||
|
||||
@@ -39,11 +39,6 @@ func newGoLicenses(opts CatalogerConfig) goLicenses {
|
||||
return goLicenses{
|
||||
opts: opts,
|
||||
localModCacheResolver: modCacheResolver(opts.LocalModCacheDir),
|
||||
progress: &monitor.CatalogerTask{
|
||||
SubStatus: true,
|
||||
RemoveOnCompletion: true,
|
||||
Title: "Downloading go mod",
|
||||
},
|
||||
lowerLicenseFileNames: strset.New(lowercaseLicenseFiles()...),
|
||||
}
|
||||
}
|
||||
@@ -123,7 +118,16 @@ func (c *goLicenses) getLicensesFromRemote(moduleName, moduleVersion string) ([]
|
||||
|
||||
proxies := remotesForModule(c.opts.Proxies, c.opts.NoProxy, moduleName)
|
||||
|
||||
fsys, err := getModule(c.progress, proxies, moduleName, moduleVersion)
|
||||
prog := bus.StartCatalogerTask(monitor.GenericTask{
|
||||
Title: monitor.Title{
|
||||
Default: "Download go mod",
|
||||
WhileRunning: "Downloading go mod",
|
||||
OnSuccess: "Downloaded go mod",
|
||||
},
|
||||
HideOnSuccess: true,
|
||||
}, -1, "")
|
||||
|
||||
fsys, err := getModule(prog, proxies, moduleName, moduleVersion)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -206,7 +210,7 @@ func processCaps(s string) string {
|
||||
})
|
||||
}
|
||||
|
||||
func getModule(progress *monitor.CatalogerTask, proxies []string, moduleName, moduleVersion string) (fsys fs.FS, err error) {
|
||||
func getModule(progress *monitor.CatalogerTaskProgress, proxies []string, moduleName, moduleVersion string) (fsys fs.FS, err error) {
|
||||
for _, proxy := range proxies {
|
||||
u, _ := url.Parse(proxy)
|
||||
if proxy == "direct" {
|
||||
@@ -218,7 +222,7 @@ func getModule(progress *monitor.CatalogerTask, proxies []string, moduleName, mo
|
||||
fsys, err = getModuleProxy(progress, proxy, moduleName, moduleVersion)
|
||||
case "file":
|
||||
p := filepath.Join(u.Path, moduleName, "@v", moduleVersion)
|
||||
progress.SetValue(fmt.Sprintf("file: %s", p))
|
||||
progress.AtomicStage.Set(fmt.Sprintf("file: %s", p))
|
||||
fsys = os.DirFS(p)
|
||||
}
|
||||
if fsys != nil {
|
||||
@@ -228,9 +232,9 @@ func getModule(progress *monitor.CatalogerTask, proxies []string, moduleName, mo
|
||||
return
|
||||
}
|
||||
|
||||
func getModuleProxy(progress *monitor.CatalogerTask, proxy string, moduleName string, moduleVersion string) (out fs.FS, _ error) {
|
||||
func getModuleProxy(progress *monitor.CatalogerTaskProgress, proxy string, moduleName string, moduleVersion string) (out fs.FS, _ error) {
|
||||
u := fmt.Sprintf("%s/%s/@v/%s.zip", proxy, moduleName, moduleVersion)
|
||||
progress.SetValue(u)
|
||||
progress.AtomicStage.Set(u)
|
||||
|
||||
// get the module zip
|
||||
resp, err := http.Get(u) //nolint:gosec
|
||||
@@ -241,7 +245,7 @@ func getModuleProxy(progress *monitor.CatalogerTask, proxy string, moduleName st
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
u = fmt.Sprintf("%s/%s/@v/%s.zip", proxy, strings.ToLower(moduleName), moduleVersion)
|
||||
progress.SetValue(u)
|
||||
progress.AtomicStage.Set(u)
|
||||
|
||||
// try lowercasing it; some packages have mixed casing that really messes up the proxy
|
||||
resp, err = http.Get(u) //nolint:gosec
|
||||
@@ -284,14 +288,14 @@ func findVersionPath(f fs.FS, dir string) string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func getModuleRepository(progress *monitor.CatalogerTask, moduleName string, moduleVersion string) (fs.FS, error) {
|
||||
func getModuleRepository(progress *monitor.CatalogerTaskProgress, moduleName string, moduleVersion string) (fs.FS, error) {
|
||||
repoName := moduleName
|
||||
parts := strings.Split(moduleName, "/")
|
||||
if len(parts) > 2 {
|
||||
repoName = fmt.Sprintf("%s/%s/%s", parts[0], parts[1], parts[2])
|
||||
}
|
||||
|
||||
progress.SetValue(fmt.Sprintf("git: %s", repoName))
|
||||
progress.AtomicStage.Set(fmt.Sprintf("git: %s", repoName))
|
||||
|
||||
f := memfs.New()
|
||||
buf := &bytes.Buffer{}
|
||||
|
||||
@@ -63,6 +63,9 @@ func parseStackLock(_ file.Resolver, _ *generic.Environment, reader file.Locatio
|
||||
}
|
||||
|
||||
for _, pack := range lockFile.Packages {
|
||||
if pack.Completed.Hackage == "" {
|
||||
continue
|
||||
}
|
||||
pkgName, pkgVersion, pkgHash := parseStackPackageEncoding(pack.Completed.Hackage)
|
||||
pkgs = append(
|
||||
pkgs,
|
||||
@@ -80,13 +83,20 @@ func parseStackLock(_ file.Resolver, _ *generic.Environment, reader file.Locatio
|
||||
|
||||
return pkgs, nil, nil
|
||||
}
|
||||
|
||||
func parseStackPackageEncoding(pkgEncoding string) (name, version, hash string) {
|
||||
lastDashIdx := strings.LastIndex(pkgEncoding, "-")
|
||||
if lastDashIdx == -1 {
|
||||
name = pkgEncoding
|
||||
return
|
||||
}
|
||||
name = pkgEncoding[:lastDashIdx]
|
||||
remainingEncoding := pkgEncoding[lastDashIdx+1:]
|
||||
encodingSplits := strings.Split(remainingEncoding, "@")
|
||||
version = encodingSplits[0]
|
||||
startHash, endHash := strings.Index(encodingSplits[1], ":")+1, strings.Index(encodingSplits[1], ",")
|
||||
hash = encodingSplits[1][startHash:endHash]
|
||||
if len(encodingSplits) > 1 {
|
||||
startHash, endHash := strings.Index(encodingSplits[1], ":")+1, strings.Index(encodingSplits[1], ",")
|
||||
hash = encodingSplits[1][startHash:endHash]
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -67,6 +67,19 @@ packages:
|
||||
sha256: 557c438345de19f82bf01d676100da2a191ef06f624e7a4b90b09ac17cbb52a5
|
||||
original:
|
||||
hackage: ptr-0.16.8.2@sha256:708ebb95117f2872d2c5a554eb6804cf1126e86abe793b2673f913f14e5eb1ac,3959
|
||||
- completed:
|
||||
commit: a5847301404583e16d55cd4d051b8e605d704fbc
|
||||
git: https://github.com/runtimeverification/haskell-backend.git
|
||||
name: kore
|
||||
pantry-tree:
|
||||
sha256: 30a502eda589be5af735b1b59760ce3e0235c0cae8961978a46b3564dd8db32b
|
||||
size: 44685
|
||||
subdir: kore
|
||||
version: 0.60.0.0
|
||||
original:
|
||||
commit: a5847301404583e16d55cd4d051b8e605d704fbc
|
||||
git: https://github.com/runtimeverification/haskell-backend.git
|
||||
subdir: kore
|
||||
snapshots:
|
||||
- completed:
|
||||
size: 618951
|
||||
|
||||
@@ -3,15 +3,9 @@ package java
|
||||
import (
|
||||
"crypto"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/vifraa/gopom"
|
||||
|
||||
intFile "github.com/anchore/syft/internal/file"
|
||||
"github.com/anchore/syft/internal/licenses"
|
||||
@@ -263,19 +257,13 @@ func findLicenseFromJavaMetadata(name string, manifest *pkg.JavaManifest, versio
|
||||
if gID := groupIDFromJavaMetadata(name, pkg.JavaArchive{Manifest: manifest}); gID != "" {
|
||||
groupID = gID
|
||||
}
|
||||
pomLicenses, err := recursivelyFindLicensesFromParentPom(groupID, name, version, j.cfg)
|
||||
if err != nil {
|
||||
log.Tracef("unable to get parent pom from Maven central: %v", err)
|
||||
}
|
||||
pomLicenses := recursivelyFindLicensesFromParentPom(groupID, name, version, j.cfg)
|
||||
|
||||
if len(pomLicenses) == 0 {
|
||||
// Try removing the last part of the groupId, as sometimes it duplicates the artifactId
|
||||
packages := strings.Split(groupID, ".")
|
||||
groupID = strings.Join(packages[:len(packages)-1], ".")
|
||||
pomLicenses, err = recursivelyFindLicensesFromParentPom(groupID, name, version, j.cfg)
|
||||
if err != nil {
|
||||
log.Tracef("unable to get parent pom from Maven central: %v", err)
|
||||
}
|
||||
pomLicenses = recursivelyFindLicensesFromParentPom(groupID, name, version, j.cfg)
|
||||
}
|
||||
|
||||
if len(pomLicenses) > 0 {
|
||||
@@ -320,8 +308,18 @@ func (j *archiveParser) guessMainPackageNameAndVersionFromPomInfo() (name, versi
|
||||
if version == "" && pomProjectObject != nil {
|
||||
version = pomProjectObject.Version
|
||||
}
|
||||
if pomProjectObject != nil && j.cfg.UseNetwork {
|
||||
findPomLicenses(pomProjectObject, j.cfg)
|
||||
if j.cfg.UseNetwork {
|
||||
if pomProjectObject == nil {
|
||||
// If we have no pom.xml, check maven central using pom.properties
|
||||
parentLicenses := recursivelyFindLicensesFromParentPom(pomPropertiesObject.GroupID, pomPropertiesObject.ArtifactID, pomPropertiesObject.Version, j.cfg)
|
||||
if len(parentLicenses) > 0 {
|
||||
for _, licenseName := range parentLicenses {
|
||||
licenses = append(licenses, pkg.NewLicenseFromFields(licenseName, "", nil))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
findPomLicenses(pomProjectObject, j.cfg)
|
||||
}
|
||||
}
|
||||
|
||||
if pomProjectObject != nil {
|
||||
@@ -341,16 +339,12 @@ func artifactIDMatchesFilename(artifactID, fileName string) bool {
|
||||
func findPomLicenses(pomProjectObject *parsedPomProject, cfg ArchiveCatalogerConfig) {
|
||||
// If we don't have any licenses until now, and if we have a parent Pom, then we'll check the parent pom in maven central for licenses.
|
||||
if pomProjectObject != nil && pomProjectObject.Parent != nil && len(pomProjectObject.Licenses) == 0 {
|
||||
parentLicenses, err := recursivelyFindLicensesFromParentPom(
|
||||
parentLicenses := recursivelyFindLicensesFromParentPom(
|
||||
pomProjectObject.Parent.GroupID,
|
||||
pomProjectObject.Parent.ArtifactID,
|
||||
pomProjectObject.Parent.Version,
|
||||
cfg)
|
||||
if err != nil {
|
||||
// We don't want to abort here as the parent pom might not exist in Maven Central, we'll just log the error
|
||||
log.Tracef("unable to get parent pom from Maven central: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
if len(parentLicenses) > 0 {
|
||||
for _, licenseName := range parentLicenses {
|
||||
pomProjectObject.Licenses = append(pomProjectObject.Licenses, pkg.NewLicenseFromFields(licenseName, "", nil))
|
||||
@@ -359,96 +353,6 @@ func findPomLicenses(pomProjectObject *parsedPomProject, cfg ArchiveCatalogerCon
|
||||
}
|
||||
}
|
||||
|
||||
func formatMavenPomURL(groupID, artifactID, version, mavenBaseURL string) (requestURL string, err error) {
|
||||
// groupID needs to go from maven.org -> maven/org
|
||||
urlPath := strings.Split(groupID, ".")
|
||||
artifactPom := fmt.Sprintf("%s-%s.pom", artifactID, version)
|
||||
urlPath = append(urlPath, artifactID, version, artifactPom)
|
||||
|
||||
// ex:"https://repo1.maven.org/maven2/groupID/artifactID/artifactPom
|
||||
requestURL, err = url.JoinPath(mavenBaseURL, urlPath...)
|
||||
if err != nil {
|
||||
return requestURL, fmt.Errorf("could not construct maven url: %w", err)
|
||||
}
|
||||
return requestURL, err
|
||||
}
|
||||
|
||||
func recursivelyFindLicensesFromParentPom(groupID, artifactID, version string, cfg ArchiveCatalogerConfig) ([]string, error) {
|
||||
var licenses []string
|
||||
// As there can be nested parent poms, we'll recursively check for licenses until we reach the max depth
|
||||
for i := 0; i < cfg.MaxParentRecursiveDepth; i++ {
|
||||
parentPom, err := getPomFromMavenRepo(groupID, artifactID, version, cfg.MavenBaseURL)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
parentLicenses := parseLicensesFromPom(parentPom)
|
||||
if len(parentLicenses) > 0 || parentPom == nil || parentPom.Parent == nil {
|
||||
licenses = parentLicenses
|
||||
break
|
||||
}
|
||||
|
||||
groupID = *parentPom.Parent.GroupID
|
||||
artifactID = *parentPom.Parent.ArtifactID
|
||||
version = *parentPom.Parent.Version
|
||||
}
|
||||
|
||||
return licenses, nil
|
||||
}
|
||||
|
||||
func getPomFromMavenRepo(groupID, artifactID, version, mavenBaseURL string) (*gopom.Project, error) {
|
||||
requestURL, err := formatMavenPomURL(groupID, artifactID, version, mavenBaseURL)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
log.Tracef("trying to fetch parent pom from Maven central %s", requestURL)
|
||||
|
||||
mavenRequest, err := http.NewRequest(http.MethodGet, requestURL, nil)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to format request for Maven central: %w", err)
|
||||
}
|
||||
|
||||
httpClient := &http.Client{
|
||||
Timeout: time.Second * 10,
|
||||
}
|
||||
|
||||
resp, err := httpClient.Do(mavenRequest)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to get pom from Maven central: %w", err)
|
||||
}
|
||||
defer func() {
|
||||
if err := resp.Body.Close(); err != nil {
|
||||
log.Errorf("unable to close body: %+v", err)
|
||||
}
|
||||
}()
|
||||
|
||||
bytes, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to parse pom from Maven central: %w", err)
|
||||
}
|
||||
|
||||
pom, err := decodePomXML(strings.NewReader(string(bytes)))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to parse pom from Maven central: %w", err)
|
||||
}
|
||||
|
||||
return &pom, nil
|
||||
}
|
||||
|
||||
func parseLicensesFromPom(pom *gopom.Project) []string {
|
||||
var licenses []string
|
||||
if pom != nil && pom.Licenses != nil {
|
||||
for _, license := range *pom.Licenses {
|
||||
if license.Name != nil {
|
||||
licenses = append(licenses, *license.Name)
|
||||
} else if license.URL != nil {
|
||||
licenses = append(licenses, *license.URL)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return licenses
|
||||
}
|
||||
|
||||
// discoverPkgsFromAllMavenFiles parses Maven POM properties/xml for a given
|
||||
// parent package, returning all listed Java packages found for each pom
|
||||
// properties discovered and potentially updating the given parentPkg with new
|
||||
@@ -693,10 +597,22 @@ func newPackageFromMavenData(pomProperties pkg.JavaPomProperties, parsedPomProje
|
||||
|
||||
var pkgPomProject *pkg.JavaPomProject
|
||||
licenses := make([]pkg.License, 0)
|
||||
if parsedPomProject != nil {
|
||||
if cfg.UseNetwork {
|
||||
|
||||
if cfg.UseNetwork {
|
||||
if parsedPomProject == nil {
|
||||
// If we have no pom.xml, check maven central using pom.properties
|
||||
parentLicenses := recursivelyFindLicensesFromParentPom(pomProperties.GroupID, pomProperties.ArtifactID, pomProperties.Version, cfg)
|
||||
if len(parentLicenses) > 0 {
|
||||
for _, licenseName := range parentLicenses {
|
||||
licenses = append(licenses, pkg.NewLicenseFromFields(licenseName, "", nil))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
findPomLicenses(parsedPomProject, cfg)
|
||||
}
|
||||
}
|
||||
|
||||
if parsedPomProject != nil {
|
||||
pkgPomProject = parsedPomProject.JavaPomProject
|
||||
licenses = append(licenses, parsedPomProject.Licenses...)
|
||||
}
|
||||
|
||||
@@ -31,9 +31,11 @@ func NewArchiveCataloger(cfg ArchiveCatalogerConfig) *generic.Cataloger {
|
||||
|
||||
// NewPomCataloger returns a cataloger capable of parsing dependencies from a pom.xml file.
|
||||
// Pom files list dependencies that maybe not be locally installed yet.
|
||||
func NewPomCataloger() pkg.Cataloger {
|
||||
func NewPomCataloger(cfg ArchiveCatalogerConfig) pkg.Cataloger {
|
||||
gap := newGenericArchiveParserAdapter(cfg)
|
||||
|
||||
return generic.NewCataloger("java-pom-cataloger").
|
||||
WithParserByGlobs(parserPomXML, "**/pom.xml")
|
||||
WithParserByGlobs(gap.parserPomXML, "**/pom.xml")
|
||||
}
|
||||
|
||||
// NewGradleLockfileCataloger returns a cataloger capable of parsing dependencies from a gradle.lockfile file.
|
||||
|
||||
@@ -89,7 +89,15 @@ func Test_POMCataloger_Globs(t *testing.T) {
|
||||
pkgtest.NewCatalogTester().
|
||||
FromDirectory(t, test.fixture).
|
||||
ExpectsResolverContentQueries(test.expected).
|
||||
TestCataloger(t, NewPomCataloger())
|
||||
TestCataloger(t,
|
||||
NewPomCataloger(
|
||||
ArchiveCatalogerConfig{
|
||||
ArchiveSearchConfig: cataloging.ArchiveSearchConfig{
|
||||
IncludeIndexedArchives: true,
|
||||
IncludeUnindexedArchives: true,
|
||||
},
|
||||
},
|
||||
))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,10 +13,7 @@ type ArchiveCatalogerConfig struct {
|
||||
|
||||
func DefaultArchiveCatalogerConfig() ArchiveCatalogerConfig {
|
||||
return ArchiveCatalogerConfig{
|
||||
ArchiveSearchConfig: cataloging.ArchiveSearchConfig{
|
||||
IncludeIndexedArchives: true,
|
||||
IncludeUnindexedArchives: false,
|
||||
},
|
||||
ArchiveSearchConfig: cataloging.DefaultArchiveSearchConfig(),
|
||||
UseNetwork: false,
|
||||
MavenBaseURL: mavenBaseURL,
|
||||
MaxParentRecursiveDepth: 5,
|
||||
|
||||
@@ -0,0 +1,133 @@
|
||||
package java
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/vifraa/gopom"
|
||||
|
||||
"github.com/anchore/syft/internal/log"
|
||||
)
|
||||
|
||||
func formatMavenPomURL(groupID, artifactID, version, mavenBaseURL string) (requestURL string, err error) {
|
||||
// groupID needs to go from maven.org -> maven/org
|
||||
urlPath := strings.Split(groupID, ".")
|
||||
artifactPom := fmt.Sprintf("%s-%s.pom", artifactID, version)
|
||||
urlPath = append(urlPath, artifactID, version, artifactPom)
|
||||
|
||||
// ex:"https://repo1.maven.org/maven2/groupID/artifactID/artifactPom
|
||||
requestURL, err = url.JoinPath(mavenBaseURL, urlPath...)
|
||||
if err != nil {
|
||||
return requestURL, fmt.Errorf("could not construct maven url: %w", err)
|
||||
}
|
||||
return requestURL, err
|
||||
}
|
||||
|
||||
// An artifact can have its version defined in a parent's DependencyManagement section
|
||||
func recursivelyFindVersionFromParentPom(groupID, artifactID, parentGroupID, parentArtifactID, parentVersion string, cfg ArchiveCatalogerConfig) string {
|
||||
// As there can be nested parent poms, we'll recursively check for the version until we reach the max depth
|
||||
for i := 0; i < cfg.MaxParentRecursiveDepth; i++ {
|
||||
parentPom, err := getPomFromMavenRepo(parentGroupID, parentArtifactID, parentVersion, cfg.MavenBaseURL)
|
||||
if err != nil {
|
||||
// We don't want to abort here as the parent pom might not exist in Maven Central, we'll just log the error
|
||||
log.Tracef("unable to get parent pom from Maven central: %v", err)
|
||||
break
|
||||
}
|
||||
if parentPom != nil && parentPom.DependencyManagement != nil {
|
||||
for _, dependency := range *parentPom.DependencyManagement.Dependencies {
|
||||
if groupID == *dependency.GroupID && artifactID == *dependency.ArtifactID && dependency.Version != nil {
|
||||
return *dependency.Version
|
||||
}
|
||||
}
|
||||
}
|
||||
if parentPom == nil || parentPom.Parent == nil {
|
||||
break
|
||||
}
|
||||
parentGroupID = *parentPom.Parent.GroupID
|
||||
parentArtifactID = *parentPom.Parent.ArtifactID
|
||||
parentVersion = *parentPom.Parent.Version
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func recursivelyFindLicensesFromParentPom(groupID, artifactID, version string, cfg ArchiveCatalogerConfig) []string {
|
||||
var licenses []string
|
||||
// As there can be nested parent poms, we'll recursively check for licenses until we reach the max depth
|
||||
for i := 0; i < cfg.MaxParentRecursiveDepth; i++ {
|
||||
parentPom, err := getPomFromMavenRepo(groupID, artifactID, version, cfg.MavenBaseURL)
|
||||
if err != nil {
|
||||
// We don't want to abort here as the parent pom might not exist in Maven Central, we'll just log the error
|
||||
log.Tracef("unable to get parent pom from Maven central: %v", err)
|
||||
return []string{}
|
||||
}
|
||||
parentLicenses := parseLicensesFromPom(parentPom)
|
||||
if len(parentLicenses) > 0 || parentPom == nil || parentPom.Parent == nil {
|
||||
licenses = parentLicenses
|
||||
break
|
||||
}
|
||||
|
||||
groupID = *parentPom.Parent.GroupID
|
||||
artifactID = *parentPom.Parent.ArtifactID
|
||||
version = *parentPom.Parent.Version
|
||||
}
|
||||
|
||||
return licenses
|
||||
}
|
||||
|
||||
func getPomFromMavenRepo(groupID, artifactID, version, mavenBaseURL string) (*gopom.Project, error) {
|
||||
requestURL, err := formatMavenPomURL(groupID, artifactID, version, mavenBaseURL)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
log.Tracef("trying to fetch parent pom from Maven central %s", requestURL)
|
||||
|
||||
mavenRequest, err := http.NewRequest(http.MethodGet, requestURL, nil)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to format request for Maven central: %w", err)
|
||||
}
|
||||
|
||||
httpClient := &http.Client{
|
||||
Timeout: time.Second * 10,
|
||||
}
|
||||
|
||||
resp, err := httpClient.Do(mavenRequest)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to get pom from Maven central: %w", err)
|
||||
}
|
||||
defer func() {
|
||||
if err := resp.Body.Close(); err != nil {
|
||||
log.Errorf("unable to close body: %+v", err)
|
||||
}
|
||||
}()
|
||||
|
||||
bytes, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to parse pom from Maven central: %w", err)
|
||||
}
|
||||
|
||||
pom, err := decodePomXML(strings.NewReader(string(bytes)))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to parse pom from Maven central: %w", err)
|
||||
}
|
||||
|
||||
return &pom, nil
|
||||
}
|
||||
|
||||
func parseLicensesFromPom(pom *gopom.Project) []string {
|
||||
var licenses []string
|
||||
if pom != nil && pom.Licenses != nil {
|
||||
for _, license := range *pom.Licenses {
|
||||
if license.Name != nil {
|
||||
licenses = append(licenses, *license.Name)
|
||||
} else if license.URL != nil {
|
||||
licenses = append(licenses, *license.URL)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return licenses
|
||||
}
|
||||
@@ -153,6 +153,22 @@ func extractNameFromApacheMavenBundlePlugin(manifest *pkg.JavaManifest) string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func extractNameFromArchiveFilename(a archiveFilename) string {
|
||||
if strings.Contains(a.name, ".") {
|
||||
// special case: this *might* be a group id + artifact id. By convention artifact ids do not have "." in them;
|
||||
// however, there are some specific exceptions like with the artifacts under
|
||||
// https://repo1.maven.org/maven2/org/eclipse/platform/
|
||||
if strings.HasPrefix(a.name, "org.eclipse.") {
|
||||
return a.name
|
||||
}
|
||||
|
||||
fields := strings.Split(a.name, ".")
|
||||
return fields[len(fields)-1]
|
||||
}
|
||||
|
||||
return a.name
|
||||
}
|
||||
|
||||
func selectName(manifest *pkg.JavaManifest, filenameObj archiveFilename) string {
|
||||
name := extractNameFromApacheMavenBundlePlugin(manifest)
|
||||
if name != "" {
|
||||
@@ -160,13 +176,9 @@ func selectName(manifest *pkg.JavaManifest, filenameObj archiveFilename) string
|
||||
}
|
||||
|
||||
// the filename tends to be the next-best reference for the package name
|
||||
if filenameObj.name != "" {
|
||||
if strings.Contains(filenameObj.name, ".") {
|
||||
// special case: this *might* be a group id + artifact id. By convention artifact ids do not have "." in them.
|
||||
fields := strings.Split(filenameObj.name, ".")
|
||||
return fields[len(fields)-1]
|
||||
}
|
||||
return filenameObj.name
|
||||
name = extractNameFromArchiveFilename(filenameObj)
|
||||
if name != "" {
|
||||
return name
|
||||
}
|
||||
|
||||
// remaining fields in the manifest is a bit of a free-for-all depending on the build tooling used and package maintainer preferences
|
||||
|
||||
@@ -209,6 +209,16 @@ func TestSelectName(t *testing.T) {
|
||||
archive: newJavaArchiveFilename("/something/com.atlassian.gadgets.atlassian-gadgets-api.jar"),
|
||||
expected: "atlassian-gadgets-api",
|
||||
},
|
||||
{
|
||||
desc: "Skip stripping groupId prefix from archive filename for org.eclipse",
|
||||
manifest: pkg.JavaManifest{
|
||||
Main: map[string]string{
|
||||
"Automatic-Module-Name": "org.eclipse.ant.core",
|
||||
},
|
||||
},
|
||||
archive: newJavaArchiveFilename("/something/org.eclipse.ant.core-3.7.0.jar"),
|
||||
expected: "org.eclipse.ant.core",
|
||||
},
|
||||
{
|
||||
// example: pkg:maven/com.google.oauth-client/google-oauth-client@1.25.0
|
||||
desc: "skip Apache Maven Bundle Plugin logic if symbolic name is same as vendor id",
|
||||
|
||||
@@ -24,7 +24,7 @@ const pomXMLGlob = "*pom.xml"
|
||||
|
||||
var propertyMatcher = regexp.MustCompile("[$][{][^}]+[}]")
|
||||
|
||||
func parserPomXML(_ file.Resolver, _ *generic.Environment, reader file.LocationReadCloser) ([]pkg.Package, []artifact.Relationship, error) {
|
||||
func (gap genericArchiveParserAdapter) parserPomXML(_ file.Resolver, _ *generic.Environment, reader file.LocationReadCloser) ([]pkg.Package, []artifact.Relationship, error) {
|
||||
pom, err := decodePomXML(reader)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
@@ -36,6 +36,7 @@ func parserPomXML(_ file.Resolver, _ *generic.Environment, reader file.LocationR
|
||||
p := newPackageFromPom(
|
||||
pom,
|
||||
dep,
|
||||
gap.cfg,
|
||||
reader.Location.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation),
|
||||
)
|
||||
if p.Name == "" {
|
||||
@@ -97,7 +98,7 @@ func newPomProject(path string, p gopom.Project, location file.Location) *parsed
|
||||
}
|
||||
}
|
||||
|
||||
func newPackageFromPom(pom gopom.Project, dep gopom.Dependency, locations ...file.Location) pkg.Package {
|
||||
func newPackageFromPom(pom gopom.Project, dep gopom.Dependency, cfg ArchiveCatalogerConfig, locations ...file.Location) pkg.Package {
|
||||
m := pkg.JavaArchive{
|
||||
PomProperties: &pkg.JavaPomProperties{
|
||||
GroupID: resolveProperty(pom, dep.GroupID, "groupId"),
|
||||
@@ -109,10 +110,32 @@ func newPackageFromPom(pom gopom.Project, dep gopom.Dependency, locations ...fil
|
||||
name := safeString(dep.ArtifactID)
|
||||
version := resolveProperty(pom, dep.Version, "version")
|
||||
|
||||
licenses := make([]pkg.License, 0)
|
||||
if cfg.UseNetwork {
|
||||
if version == "" {
|
||||
// If we have no version then let's try to get it from a parent pom DependencyManagement section
|
||||
version = recursivelyFindVersionFromParentPom(*dep.GroupID, *dep.ArtifactID, *pom.Parent.GroupID, *pom.Parent.ArtifactID, *pom.Parent.Version, cfg)
|
||||
}
|
||||
if version != "" {
|
||||
parentLicenses := recursivelyFindLicensesFromParentPom(
|
||||
m.PomProperties.GroupID,
|
||||
m.PomProperties.ArtifactID,
|
||||
version,
|
||||
cfg)
|
||||
|
||||
if len(parentLicenses) > 0 {
|
||||
for _, licenseName := range parentLicenses {
|
||||
licenses = append(licenses, pkg.NewLicenseFromFields(licenseName, "", nil))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
p := pkg.Package{
|
||||
Name: name,
|
||||
Version: version,
|
||||
Locations: file.NewLocationSet(locations...),
|
||||
Licenses: pkg.NewLicenseSet(licenses...),
|
||||
PURL: packageURL(name, version, m),
|
||||
Language: pkg.Java,
|
||||
Type: pkg.JavaPkg, // TODO: should we differentiate between packages from jar/war/zip versus packages from a pom.xml that were not installed yet?
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/vifraa/gopom"
|
||||
|
||||
"github.com/anchore/syft/syft/cataloging"
|
||||
"github.com/anchore/syft/syft/file"
|
||||
"github.com/anchore/syft/syft/license"
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
@@ -61,7 +62,15 @@ func Test_parserPomXML(t *testing.T) {
|
||||
for i := range test.expected {
|
||||
test.expected[i].Locations.Add(file.NewLocation(test.input))
|
||||
}
|
||||
pkgtest.TestFileParser(t, test.input, parserPomXML, test.expected, nil)
|
||||
|
||||
gap := newGenericArchiveParserAdapter(ArchiveCatalogerConfig{
|
||||
ArchiveSearchConfig: cataloging.ArchiveSearchConfig{
|
||||
IncludeIndexedArchives: true,
|
||||
IncludeUnindexedArchives: true,
|
||||
},
|
||||
})
|
||||
|
||||
pkgtest.TestFileParser(t, test.input, gap.parserPomXML, test.expected, nil)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -276,7 +285,14 @@ func Test_parseCommonsTextPomXMLProject(t *testing.T) {
|
||||
for i := range test.expected {
|
||||
test.expected[i].Locations.Add(file.NewLocation(test.input))
|
||||
}
|
||||
pkgtest.TestFileParser(t, test.input, parserPomXML, test.expected, nil)
|
||||
|
||||
gap := newGenericArchiveParserAdapter(ArchiveCatalogerConfig{
|
||||
ArchiveSearchConfig: cataloging.ArchiveSearchConfig{
|
||||
IncludeIndexedArchives: true,
|
||||
IncludeUnindexedArchives: true,
|
||||
},
|
||||
})
|
||||
pkgtest.TestFileParser(t, test.input, gap.parserPomXML, test.expected, nil)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,9 +15,10 @@ func NewPackageCataloger() pkg.Cataloger {
|
||||
}
|
||||
|
||||
// NewLockCataloger returns a new cataloger object for NPM (and NPM-adjacent, such as yarn) lock files.
|
||||
func NewLockCataloger() pkg.Cataloger {
|
||||
func NewLockCataloger(cfg CatalogerConfig) pkg.Cataloger {
|
||||
yarnLockAdapter := newGenericYarnLockAdapter(cfg)
|
||||
return generic.NewCataloger("javascript-lock-cataloger").
|
||||
WithParserByGlobs(parsePackageLock, "**/package-lock.json").
|
||||
WithParserByGlobs(parseYarnLock, "**/yarn.lock").
|
||||
WithParserByGlobs(yarnLockAdapter.parseYarnLock, "**/yarn.lock").
|
||||
WithParserByGlobs(parsePnpmLock, "**/pnpm-lock.yaml")
|
||||
}
|
||||
|
||||
@@ -132,7 +132,7 @@ func Test_JavascriptCataloger(t *testing.T) {
|
||||
pkgtest.NewCatalogTester().
|
||||
FromDirectory(t, "test-fixtures/pkg-lock").
|
||||
Expects(expectedPkgs, nil).
|
||||
TestCataloger(t, NewLockCataloger())
|
||||
TestCataloger(t, NewLockCataloger(CatalogerConfig{}))
|
||||
|
||||
}
|
||||
|
||||
@@ -183,7 +183,7 @@ func Test_LockCataloger_Globs(t *testing.T) {
|
||||
pkgtest.NewCatalogTester().
|
||||
FromDirectory(t, test.fixture).
|
||||
ExpectsResolverContentQueries(test.expected).
|
||||
TestCataloger(t, NewLockCataloger())
|
||||
TestCataloger(t, NewLockCataloger(CatalogerConfig{}))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
package javascript
|
||||
|
||||
const npmBaseURL = "https://registry.npmjs.org"
|
||||
|
||||
type CatalogerConfig struct {
|
||||
SearchRemoteLicenses bool `json:"search-remote-licenses" yaml:"search-remote-licenses" mapstructure:"search-remote-licenses"`
|
||||
NPMBaseURL string `json:"npm-base-url" yaml:"npm-base-url" mapstructure:"npm-base-url"`
|
||||
}
|
||||
|
||||
func DefaultCatalogerConfig() CatalogerConfig {
|
||||
return CatalogerConfig{
|
||||
SearchRemoteLicenses: false,
|
||||
NPMBaseURL: npmBaseURL,
|
||||
}
|
||||
}
|
||||
|
||||
func (j CatalogerConfig) WithSearchRemoteLicenses(input bool) CatalogerConfig {
|
||||
j.SearchRemoteLicenses = input
|
||||
return j
|
||||
}
|
||||
|
||||
func (j CatalogerConfig) WithNpmBaseURL(input string) CatalogerConfig {
|
||||
if input != "" {
|
||||
j.NPMBaseURL = input
|
||||
}
|
||||
return j
|
||||
}
|
||||
@@ -2,9 +2,13 @@ package javascript
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"path"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/anchore/packageurl-go"
|
||||
"github.com/anchore/syft/internal/log"
|
||||
@@ -106,13 +110,27 @@ func newPnpmPackage(resolver file.Resolver, location file.Location, name, versio
|
||||
)
|
||||
}
|
||||
|
||||
func newYarnLockPackage(resolver file.Resolver, location file.Location, name, version string) pkg.Package {
|
||||
func newYarnLockPackage(cfg CatalogerConfig, resolver file.Resolver, location file.Location, name, version string) pkg.Package {
|
||||
var licenseSet pkg.LicenseSet
|
||||
|
||||
if cfg.SearchRemoteLicenses {
|
||||
license, err := getLicenseFromNpmRegistry(cfg.NPMBaseURL, name, version)
|
||||
if err == nil && license != "" {
|
||||
licenses := pkg.NewLicensesFromValues(license)
|
||||
licenseSet = pkg.NewLicenseSet(licenses...)
|
||||
}
|
||||
if err != nil {
|
||||
log.Warnf("unable to extract licenses from javascript yarn.lock for package %s:%s: %+v", name, version, err)
|
||||
}
|
||||
}
|
||||
|
||||
return finalizeLockPkg(
|
||||
resolver,
|
||||
location,
|
||||
pkg.Package{
|
||||
Name: name,
|
||||
Version: version,
|
||||
Licenses: licenseSet,
|
||||
Locations: file.NewLocationSet(location.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation)),
|
||||
PURL: packageURL(name, version),
|
||||
Language: pkg.JavaScript,
|
||||
@@ -121,6 +139,63 @@ func newYarnLockPackage(resolver file.Resolver, location file.Location, name, ve
|
||||
)
|
||||
}
|
||||
|
||||
func formatNpmRegistryURL(baseURL, packageName, version string) (requestURL string, err error) {
|
||||
urlPath := []string{packageName, version}
|
||||
requestURL, err = url.JoinPath(baseURL, urlPath...)
|
||||
if err != nil {
|
||||
return requestURL, fmt.Errorf("unable to format npm request for pkg:version %s%s; %w", packageName, version, err)
|
||||
}
|
||||
return requestURL, nil
|
||||
}
|
||||
|
||||
func getLicenseFromNpmRegistry(basURL, packageName, version string) (string, error) {
|
||||
// "https://registry.npmjs.org/%s/%s", packageName, version
|
||||
requestURL, err := formatNpmRegistryURL(basURL, packageName, version)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("unable to format npm request for pkg:version %s%s; %w", packageName, version, err)
|
||||
}
|
||||
log.Tracef("trying to fetch remote package %s", requestURL)
|
||||
|
||||
npmRequest, err := http.NewRequest(http.MethodGet, requestURL, nil)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("unable to format remote request: %w", err)
|
||||
}
|
||||
|
||||
httpClient := &http.Client{
|
||||
Timeout: time.Second * 10,
|
||||
}
|
||||
|
||||
resp, err := httpClient.Do(npmRequest)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("unable to get package from npm registry: %w", err)
|
||||
}
|
||||
defer func() {
|
||||
if err := resp.Body.Close(); err != nil {
|
||||
log.Errorf("unable to close body: %+v", err)
|
||||
}
|
||||
}()
|
||||
|
||||
bytes, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("unable to parse package from npm registry: %w", err)
|
||||
}
|
||||
|
||||
dec := json.NewDecoder(strings.NewReader(string(bytes)))
|
||||
|
||||
// Read "license" from the response
|
||||
var license struct {
|
||||
License string `json:"license"`
|
||||
}
|
||||
|
||||
if err := dec.Decode(&license); err != nil {
|
||||
return "", fmt.Errorf("unable to parse license from npm registry: %w", err)
|
||||
}
|
||||
|
||||
log.Tracef("Retrieved License: %s", license.License)
|
||||
|
||||
return license.License, nil
|
||||
}
|
||||
|
||||
func finalizeLockPkg(resolver file.Resolver, location file.Location, p pkg.Package) pkg.Package {
|
||||
licenseCandidate := addLicenses(p.Name, resolver, location)
|
||||
p.Licenses.Add(pkg.NewLicensesFromLocation(location, licenseCandidate...)...)
|
||||
|
||||
@@ -13,9 +13,6 @@ import (
|
||||
"github.com/anchore/syft/syft/pkg/cataloger/generic"
|
||||
)
|
||||
|
||||
// integrity check
|
||||
var _ generic.Parser = parseYarnLock
|
||||
|
||||
var (
|
||||
// packageNameExp matches the name of the dependency in yarn.lock
|
||||
// including scope/namespace prefix if found.
|
||||
@@ -43,7 +40,17 @@ const (
|
||||
noVersion = ""
|
||||
)
|
||||
|
||||
func parseYarnLock(resolver file.Resolver, _ *generic.Environment, reader file.LocationReadCloser) ([]pkg.Package, []artifact.Relationship, error) {
|
||||
type genericYarnLockAdapter struct {
|
||||
cfg CatalogerConfig
|
||||
}
|
||||
|
||||
func newGenericYarnLockAdapter(cfg CatalogerConfig) genericYarnLockAdapter {
|
||||
return genericYarnLockAdapter{
|
||||
cfg: cfg,
|
||||
}
|
||||
}
|
||||
|
||||
func (a genericYarnLockAdapter) parseYarnLock(resolver file.Resolver, _ *generic.Environment, reader file.LocationReadCloser) ([]pkg.Package, []artifact.Relationship, error) {
|
||||
// in the case we find yarn.lock files in the node_modules directories, skip those
|
||||
// as the whole purpose of the lock file is for the specific dependencies of the project
|
||||
if pathContainsNodeModulesDirectory(reader.Path()) {
|
||||
@@ -62,7 +69,7 @@ func parseYarnLock(resolver file.Resolver, _ *generic.Environment, reader file.L
|
||||
if packageName := findPackageName(line); packageName != noPackage {
|
||||
// When we find a new package, check if we have unsaved identifiers
|
||||
if currentPackage != noPackage && currentVersion != noVersion && !parsedPackages.Has(currentPackage+"@"+currentVersion) {
|
||||
pkgs = append(pkgs, newYarnLockPackage(resolver, reader.Location, currentPackage, currentVersion))
|
||||
pkgs = append(pkgs, newYarnLockPackage(a.cfg, resolver, reader.Location, currentPackage, currentVersion))
|
||||
parsedPackages.Add(currentPackage + "@" + currentVersion)
|
||||
}
|
||||
|
||||
@@ -70,7 +77,7 @@ func parseYarnLock(resolver file.Resolver, _ *generic.Environment, reader file.L
|
||||
} else if version := findPackageVersion(line); version != noVersion {
|
||||
currentVersion = version
|
||||
} else if packageName, version := findPackageAndVersion(line); packageName != noPackage && version != noVersion && !parsedPackages.Has(packageName+"@"+version) {
|
||||
pkgs = append(pkgs, newYarnLockPackage(resolver, reader.Location, packageName, version))
|
||||
pkgs = append(pkgs, newYarnLockPackage(a.cfg, resolver, reader.Location, packageName, version))
|
||||
parsedPackages.Add(packageName + "@" + version)
|
||||
|
||||
// Cleanup to indicate no unsaved identifiers
|
||||
@@ -81,7 +88,7 @@ func parseYarnLock(resolver file.Resolver, _ *generic.Environment, reader file.L
|
||||
|
||||
// check if we have valid unsaved data after end-of-file has reached
|
||||
if currentPackage != noPackage && currentVersion != noVersion && !parsedPackages.Has(currentPackage+"@"+currentVersion) {
|
||||
pkgs = append(pkgs, newYarnLockPackage(resolver, reader.Location, currentPackage, currentVersion))
|
||||
pkgs = append(pkgs, newYarnLockPackage(a.cfg, resolver, reader.Location, currentPackage, currentVersion))
|
||||
parsedPackages.Add(currentPackage + "@" + currentVersion)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
package javascript
|
||||
|
||||
import (
|
||||
"io"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
@@ -91,8 +95,8 @@ func TestParseYarnBerry(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
pkgtest.TestFileParser(t, fixture, parseYarnLock, expectedPkgs, expectedRelationships)
|
||||
|
||||
adapter := newGenericYarnLockAdapter(CatalogerConfig{})
|
||||
pkgtest.TestFileParser(t, fixture, adapter.parseYarnLock, expectedPkgs, expectedRelationships)
|
||||
}
|
||||
|
||||
func TestParseYarnLock(t *testing.T) {
|
||||
@@ -177,8 +181,62 @@ func TestParseYarnLock(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
pkgtest.TestFileParser(t, fixture, parseYarnLock, expectedPkgs, expectedRelationships)
|
||||
adapter := newGenericYarnLockAdapter(CatalogerConfig{})
|
||||
pkgtest.TestFileParser(t, fixture, adapter.parseYarnLock, expectedPkgs, expectedRelationships)
|
||||
}
|
||||
|
||||
type handlerPath struct {
|
||||
path string
|
||||
handler func(w http.ResponseWriter, r *http.Request)
|
||||
}
|
||||
|
||||
func TestSearchYarnForLicenses(t *testing.T) {
|
||||
fixture := "test-fixtures/yarn-remote/yarn.lock"
|
||||
locations := file.NewLocationSet(file.NewLocation(fixture))
|
||||
mux, url, teardown := setup()
|
||||
defer teardown()
|
||||
tests := []struct {
|
||||
name string
|
||||
fixture string
|
||||
config CatalogerConfig
|
||||
requestHandlers []handlerPath
|
||||
expectedPackages []pkg.Package
|
||||
}{
|
||||
{
|
||||
name: "search remote licenses returns the expected licenses when search is set to true",
|
||||
config: CatalogerConfig{SearchRemoteLicenses: true},
|
||||
requestHandlers: []handlerPath{
|
||||
{
|
||||
// https://registry.yarnpkg.com/@babel/code-frame/7.10.4
|
||||
path: "/@babel/code-frame/7.10.4",
|
||||
handler: generateMockNPMHandler("test-fixtures/yarn-remote/registry_response.json"),
|
||||
},
|
||||
},
|
||||
expectedPackages: []pkg.Package{
|
||||
{
|
||||
Name: "@babel/code-frame",
|
||||
Version: "7.10.4",
|
||||
Locations: locations,
|
||||
PURL: "pkg:npm/%40babel/code-frame@7.10.4",
|
||||
Licenses: pkg.NewLicenseSet(pkg.NewLicense("MIT")),
|
||||
Language: pkg.JavaScript,
|
||||
Type: pkg.NpmPkg,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
// set up the mock server
|
||||
for _, handler := range tc.requestHandlers {
|
||||
mux.HandleFunc(handler.path, handler.handler)
|
||||
}
|
||||
tc.config.NPMBaseURL = url
|
||||
adapter := newGenericYarnLockAdapter(tc.config)
|
||||
pkgtest.TestFileParser(t, fixture, adapter.parseYarnLock, tc.expectedPackages, nil)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseYarnFindPackageNames(t *testing.T) {
|
||||
@@ -336,3 +394,40 @@ func TestParseYarnFindPackageVersions(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func generateMockNPMHandler(responseFixture string) func(w http.ResponseWriter, r *http.Request) {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
// Copy the file's content to the response writer
|
||||
file, err := os.Open(responseFixture)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
_, err = io.Copy(w, file)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// setup sets up a test HTTP server for mocking requests to maven central.
|
||||
// The returned url is injected into the Config so the client uses the test server.
|
||||
// Tests should register handlers on mux to simulate the expected request/response structure
|
||||
func setup() (mux *http.ServeMux, serverURL string, teardown func()) {
|
||||
// mux is the HTTP request multiplexer used with the test server.
|
||||
mux = http.NewServeMux()
|
||||
|
||||
// We want to ensure that tests catch mistakes where the endpoint URL is
|
||||
// specified as absolute rather than relative. It only makes a difference
|
||||
// when there's a non-empty base URL path. So, use that. See issue #752.
|
||||
apiHandler := http.NewServeMux()
|
||||
apiHandler.Handle("/", mux)
|
||||
// server is a test HTTP server used to provide mock API responses.
|
||||
server := httptest.NewServer(apiHandler)
|
||||
|
||||
return mux, server.URL, server.Close
|
||||
}
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
{
|
||||
"name": "@babel/code-frame",
|
||||
"version": "7.10.4",
|
||||
"description": "Generate errors that contain a code frame that point to source locations.",
|
||||
"author": {
|
||||
"name": "Sebastian McKenzie",
|
||||
"email": "sebmck@gmail.com"
|
||||
},
|
||||
"homepage": "https://babeljs.io/",
|
||||
"license": "MIT",
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/babel/babel.git",
|
||||
"directory": "packages/babel-code-frame"
|
||||
},
|
||||
"main": "lib/index.js",
|
||||
"dependencies": {
|
||||
"@babel/highlight": "^7.10.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"chalk": "^2.0.0",
|
||||
"strip-ansi": "^4.0.0"
|
||||
},
|
||||
"gitHead": "7fd40d86a0d03ff0e9c3ea16b29689945433d4df",
|
||||
"bugs": {
|
||||
"url": "https://github.com/babel/babel/issues"
|
||||
},
|
||||
"_id": "@babel/code-frame@7.10.4",
|
||||
"_nodeVersion": "14.4.0",
|
||||
"_npmVersion": "lerna/3.19.0/node@v14.4.0+x64 (darwin)",
|
||||
"dist": {
|
||||
"integrity": "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==",
|
||||
"shasum": "168da1a36e90da68ae8d49c0f1b48c7c6249213a",
|
||||
"tarball": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz",
|
||||
"fileCount": 4,
|
||||
"unpackedSize": 7723,
|
||||
"npm-signature": "-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJe+zovCRA9TVsSAnZWagAAe8cQAKMtKF7FJx92Re+ol+4B\no0f3yGdzxWUhl8B+e8eXgjYcetMe1MZpG1oQF5ocYo45mZ+ASWMzfp1caT1p\nqt3F5rtADrL9int8ti7ICrWkIGQ3ccnrTxmtx1y9NRGANeARYjlB538xg0xy\n2Gin+2NchK2gxkxeX0nPH7LOcLlJpXecv1p2BK8gFZfabhM4fKfcMSSeljUp\ngzBGU/0CQp3++KsFAS/GMtgo6ZLw7wnHn0IVtDbwhA6A7hpDZar1Q5xsleui\nUTFIJCegGBx9exO1z0fYLGjOuvOdB5790fQnGsspbVTMwpImWpjspmuH1kWI\nTtk1ocnUnvEu1wNK2FMspUeKHNmOi5Jr6bkdGTxecXV4W/p9oEoPe3tHItL5\nbG9gNxY4IUkHeL93D86w9DtgaYtFSCYD6+sY7mQQQdhBrilR06AugBtQG3jP\nFpEsOLSn8vhYOQKv18CN//xaJM/uar40NTfZcQTn4VLXjUsuR4W+3eAv+qb+\nSKEpf8YAhgXJR5EFG1m3m4VHCp40SM1oSibh3/Ib74VZmlF/aq0VcPDs9tD2\no/MibYbQcP01cYxzpfObPXRczTH8TSl3scslcf7aVcLuhbyJtw8gblKnmXjo\njNaZrKjGKrpKRYStMBbCt8ILkL+OZTcDJcihy1x0v4oOWT43lrHnPntOAg7D\nqQbp\r\n=RhVa\r\n-----END PGP SIGNATURE-----\r\n",
|
||||
"signatures": [
|
||||
{
|
||||
"keyid": "SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA",
|
||||
"sig": "MEUCIQDSjBYOah3mnIxnAjEKv638MySMCxhZ0J9pexriecmdogIgAOaTRZg3UeVxrs8Khzr78+n4T+10hMn2Z9DRR7k5qEM="
|
||||
}
|
||||
]
|
||||
},
|
||||
"maintainers": [
|
||||
{
|
||||
"email": "daniel@tschinder.de",
|
||||
"name": "danez"
|
||||
},
|
||||
{
|
||||
"email": "bng412@gmail.com",
|
||||
"name": "existentialism"
|
||||
},
|
||||
{
|
||||
"email": "hi@henryzoo.com",
|
||||
"name": "hzoo"
|
||||
},
|
||||
{
|
||||
"email": "i@jhuang.me",
|
||||
"name": "jlhwung"
|
||||
},
|
||||
{
|
||||
"email": "loganfsmyth@gmail.com",
|
||||
"name": "loganfsmyth"
|
||||
},
|
||||
{
|
||||
"email": "nicolo.ribaudo@gmail.com",
|
||||
"name": "nicolo-ribaudo"
|
||||
}
|
||||
],
|
||||
"_npmUser": {
|
||||
"name": "jlhwung",
|
||||
"email": "i@jhuang.me"
|
||||
},
|
||||
"directories": {},
|
||||
"_npmOperationalInternal": {
|
||||
"host": "s3://npm-registry-packages",
|
||||
"tmp": "tmp/code-frame_7.10.4_1593522734690_0.6416145193889038"
|
||||
},
|
||||
"_hasShrinkwrap": false
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
|
||||
# yarn lockfile v1
|
||||
|
||||
|
||||
"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.10.4":
|
||||
version "7.10.4"
|
||||
resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.10.4.tgz#168da1a36e90da68ae8d49c0f1b48c7c6249213a"
|
||||
integrity sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==
|
||||
dependencies:
|
||||
"@babel/highlight" "^7.10.4"
|
||||
@@ -4,6 +4,8 @@ import (
|
||||
"fmt"
|
||||
|
||||
"github.com/anchore/packageurl-go"
|
||||
"github.com/anchore/syft/internal/licenses"
|
||||
"github.com/anchore/syft/internal/log"
|
||||
"github.com/anchore/syft/syft/file"
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
)
|
||||
@@ -55,13 +57,42 @@ func newPackageForRequirementsWithMetadata(name, version string, metadata pkg.Py
|
||||
return p
|
||||
}
|
||||
|
||||
func newPackageForPackage(m parsedData, sources ...file.Location) pkg.Package {
|
||||
func newPackageForPackage(resolver file.Resolver, m parsedData, sources ...file.Location) pkg.Package {
|
||||
var licenseSet pkg.LicenseSet
|
||||
|
||||
switch {
|
||||
case m.LicenseExpression != "":
|
||||
licenseSet = pkg.NewLicenseSet(pkg.NewLicensesFromLocation(m.LicenseLocation, m.LicenseExpression)...)
|
||||
case m.Licenses != "":
|
||||
licenseSet = pkg.NewLicenseSet(pkg.NewLicensesFromLocation(m.LicenseLocation, m.Licenses)...)
|
||||
case m.LicenseLocation.Path() != "":
|
||||
// If we have a license file then resolve and parse it
|
||||
found, err := resolver.FilesByPath(m.LicenseLocation.Path())
|
||||
if err != nil {
|
||||
log.WithFields("error", err).Tracef("unable to resolve python license path %s", m.LicenseLocation.Path())
|
||||
}
|
||||
if len(found) > 0 {
|
||||
metadataContents, err := resolver.FileContentsByLocation(found[0])
|
||||
if err == nil {
|
||||
parsed, err := licenses.Parse(metadataContents, m.LicenseLocation)
|
||||
if err != nil {
|
||||
log.WithFields("error", err).Tracef("unable to parse a license from the file in %s", m.LicenseLocation.Path())
|
||||
}
|
||||
if len(parsed) > 0 {
|
||||
licenseSet = pkg.NewLicenseSet(parsed...)
|
||||
}
|
||||
} else {
|
||||
log.WithFields("error", err).Tracef("unable to read file contents at %s", m.LicenseLocation.Path())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
p := pkg.Package{
|
||||
Name: m.Name,
|
||||
Version: m.Version,
|
||||
PURL: packageURL(m.Name, m.Version, &m.PythonPackage),
|
||||
Locations: file.NewLocationSet(sources...),
|
||||
Licenses: pkg.NewLicenseSet(pkg.NewLicensesFromLocation(m.LicenseLocation, m.Licenses)...),
|
||||
Licenses: licenseSet,
|
||||
Language: pkg.Python,
|
||||
Type: pkg.PythonPkg,
|
||||
Metadata: m.PythonPackage,
|
||||
|
||||
@@ -32,7 +32,7 @@ func parseWheelOrEgg(resolver file.Resolver, _ *generic.Environment, reader file
|
||||
return nil, nil, nil
|
||||
}
|
||||
|
||||
pkgs := []pkg.Package{newPackageForPackage(*pd, sources...)}
|
||||
pkgs := []pkg.Package{newPackageForPackage(resolver, *pd, sources...)}
|
||||
|
||||
return pkgs, nil, nil
|
||||
}
|
||||
|
||||
@@ -17,6 +17,8 @@ import (
|
||||
|
||||
type parsedData struct {
|
||||
Licenses string `mapstructure:"License"`
|
||||
LicenseFile string `mapstructure:"LicenseFile"`
|
||||
LicenseExpression string `mapstructure:"LicenseExpression"`
|
||||
LicenseLocation file.Location
|
||||
pkg.PythonPackage `mapstructure:",squash"`
|
||||
}
|
||||
@@ -80,8 +82,10 @@ func parseWheelOrEggMetadata(path string, reader io.Reader) (parsedData, error)
|
||||
// add additional metadata not stored in the egg/wheel metadata file
|
||||
|
||||
pd.SitePackagesRootPath = determineSitePackagesRootPath(path)
|
||||
if pd.Licenses != "" {
|
||||
if pd.Licenses != "" || pd.LicenseExpression != "" {
|
||||
pd.LicenseLocation = file.NewLocation(path)
|
||||
} else if pd.LicenseFile != "" {
|
||||
pd.LicenseLocation = file.NewLocation(filepath.Join(filepath.Dir(path), pd.LicenseFile))
|
||||
}
|
||||
|
||||
return pd, nil
|
||||
|
||||
@@ -19,6 +19,8 @@ func TestParseWheelEggMetadata(t *testing.T) {
|
||||
Fixture: "test-fixtures/egg-info/PKG-INFO",
|
||||
ExpectedMetadata: parsedData{
|
||||
"Apache 2.0",
|
||||
"",
|
||||
"",
|
||||
file.NewLocation("test-fixtures/egg-info/PKG-INFO"),
|
||||
pkg.PythonPackage{
|
||||
Name: "requests",
|
||||
@@ -34,6 +36,8 @@ func TestParseWheelEggMetadata(t *testing.T) {
|
||||
Fixture: "test-fixtures/dist-info/METADATA",
|
||||
ExpectedMetadata: parsedData{
|
||||
"BSD License",
|
||||
"",
|
||||
"",
|
||||
file.NewLocation("test-fixtures/dist-info/METADATA"),
|
||||
pkg.PythonPackage{
|
||||
Name: "Pygments",
|
||||
@@ -134,6 +138,8 @@ func TestParseWheelEggMetadataInvalid(t *testing.T) {
|
||||
{
|
||||
Fixture: "test-fixtures/egg-info/PKG-INFO-INVALID",
|
||||
ExpectedMetadata: parsedData{
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
file.Location{},
|
||||
pkg.PythonPackage{
|
||||
|
||||
+30
-25
@@ -21,7 +21,7 @@ type Collection struct {
|
||||
|
||||
// NewCollection returns a new empty Collection
|
||||
func NewCollection(pkgs ...Package) *Collection {
|
||||
catalog := Collection{
|
||||
c := Collection{
|
||||
byID: make(map[artifact.ID]Package),
|
||||
idsByName: make(map[string]orderedIDSet),
|
||||
idsByType: make(map[Type]orderedIDSet),
|
||||
@@ -29,10 +29,10 @@ func NewCollection(pkgs ...Package) *Collection {
|
||||
}
|
||||
|
||||
for _, p := range pkgs {
|
||||
catalog.Add(p)
|
||||
c.Add(p)
|
||||
}
|
||||
|
||||
return &catalog
|
||||
return &c
|
||||
}
|
||||
|
||||
// PackageCount returns the total number of packages that have been added.
|
||||
@@ -97,32 +97,37 @@ func (c *Collection) packages(ids []artifact.ID) (result []Package) {
|
||||
return result
|
||||
}
|
||||
|
||||
// Add n packages to the catalog.
|
||||
// Add n packages to the collection.
|
||||
func (c *Collection) Add(pkgs ...Package) {
|
||||
for _, p := range pkgs {
|
||||
c.add(p)
|
||||
}
|
||||
}
|
||||
|
||||
// Add a package to the Collection.
|
||||
func (c *Collection) add(p Package) {
|
||||
c.lock.Lock()
|
||||
defer c.lock.Unlock()
|
||||
|
||||
for _, p := range pkgs {
|
||||
id := p.ID()
|
||||
if id == "" {
|
||||
log.Warnf("found package with empty ID while adding to the catalog: %+v", p)
|
||||
p.SetID()
|
||||
id = p.ID()
|
||||
}
|
||||
|
||||
if existing, exists := c.byID[id]; exists {
|
||||
// there is already a package with this fingerprint merge the existing record with the new one
|
||||
if err := existing.merge(p); err != nil {
|
||||
log.Warnf("failed to merge packages: %+v", err)
|
||||
} else {
|
||||
c.byID[id] = existing
|
||||
c.addPathsToIndex(p)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
c.addToIndex(p)
|
||||
id := p.ID()
|
||||
if id == "" {
|
||||
log.Warnf("found package with empty ID while adding to the collection: %+v", p)
|
||||
p.SetID()
|
||||
id = p.ID()
|
||||
}
|
||||
|
||||
if existing, exists := c.byID[id]; exists {
|
||||
// there is already a package with this fingerprint merge the existing record with the new one
|
||||
if err := existing.merge(p); err != nil {
|
||||
log.Warnf("failed to merge packages: %+v", err)
|
||||
} else {
|
||||
c.byID[id] = existing
|
||||
c.addPathsToIndex(p)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
c.addToIndex(p)
|
||||
}
|
||||
|
||||
func (c *Collection) addToIndex(p Package) {
|
||||
@@ -242,7 +247,7 @@ func (c *Collection) Enumerate(types ...Type) <-chan Package {
|
||||
defer close(channel)
|
||||
|
||||
if c == nil {
|
||||
// we should allow enumerating from a catalog that was never created (which will result in no packages enumerated)
|
||||
// we should allow enumerating from a collection that was never created (which will result in no packages enumerated)
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -189,7 +189,7 @@ func (s FileSource) FileResolver(_ Scope) (file.Resolver, error) {
|
||||
return fs.SkipDir
|
||||
}
|
||||
|
||||
if path.Base(p) != path.Base(s.config.Path) {
|
||||
if filepath.Base(p) != filepath.Base(s.config.Path) {
|
||||
// we're in the root directory, but this is not the file we want to scan...
|
||||
// we should selectively skip this file (not the directory we're in).
|
||||
return fileresolver.ErrSkipPath
|
||||
|
||||
+605
-163
@@ -17,8 +17,14 @@ func TestJavaPURLs(t *testing.T) {
|
||||
if p.Type != pkg.JavaPkg && p.Type != pkg.JenkinsPluginPkg {
|
||||
continue
|
||||
}
|
||||
key := fmt.Sprintf("%s@%s", p.Name, p.Version)
|
||||
found[key] = p.PURL
|
||||
|
||||
if metadata, ok := p.Metadata.(pkg.JavaArchive); ok {
|
||||
if _, ok := noAssertion[metadata.VirtualPath]; ok {
|
||||
continue
|
||||
}
|
||||
|
||||
found[metadata.VirtualPath] = p.PURL
|
||||
}
|
||||
}
|
||||
for key, expectedPURL := range expectedPURLs {
|
||||
purl := found[key]
|
||||
@@ -30,168 +36,604 @@ func TestJavaPURLs(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// This is for artifacts that either don't have a known groupid/artifactid
|
||||
// since they aren't available on a known maven repository, or where syft is currently
|
||||
// generating the incorrect PURL
|
||||
var noAssertion = map[string]string{
|
||||
// These are not known to exist on any public maven repo, so no real PURL should be asserted
|
||||
"/packages/jruby-stdlib-9.1.15.0.jar:META-INF/jruby.home/lib/ruby/stdlib/jopenssl.jar": "pkg:maven/jopenssl/jopenssl",
|
||||
"/packages/jruby-stdlib-9.1.15.0.jar:META-INF/jruby.home/lib/ruby/stdlib/json/ext/generator.jar": "pkg:maven/generator/generator",
|
||||
"/packages/jruby-stdlib-9.1.15.0.jar:META-INF/jruby.home/lib/ruby/stdlib/json/ext/parser.jar": "pkg:maven/parser/parser",
|
||||
"/packages/jruby-stdlib-9.1.15.0.jar:META-INF/jruby.home/lib/ruby/stdlib/psych.jar": "pkg:maven/psych/psych",
|
||||
"/packages/jruby-stdlib-9.1.15.0.jar:META-INF/jruby.home/lib/ruby/stdlib/racc/cparse-jruby.jar": "pkg:maven/cparse-jruby/cparse-jruby",
|
||||
"/packages/jruby-stdlib-9.1.15.0.jar:META-INF/jruby.home/lib/ruby/stdlib/readline.jar": "pkg:maven/readline/readline",
|
||||
"/packages/org.eclipse.ant.core-3.7.0.jar:lib/antsupportlib.jar": "pkg:maven/antsupportlib/antsupportlib",
|
||||
"/packages/TwilioNotifier.hpi:WEB-INF/lib/sdk-3.0.jar": "pkg:maven/sdk/sdk@3.0",
|
||||
|
||||
// syft generates incorrect purls
|
||||
"/packages/kafka_2.13-3.2.2.jar": "pkg:maven/org.apache.kafka/kafka_2.13@3.2.2",
|
||||
"/packages/akka-actor_2.13-2.6.6.jar": "pkg:maven/com.typesafe.akka/akka-actor_2.13@2.6.6",
|
||||
"/packages/akka-management-cluster-bootstrap_2.13-1.2.0.jar": "pkg:maven/com.lightbend.akka.management/akka-management-cluster-bootstrap_2.13@1.2.0",
|
||||
"/packages/hudson.war:WEB-INF/lib/asm-2.2.3.jar": "pkg:maven/asm/asm@2.2.3",
|
||||
"/packages/hudson.war:WEB-INF/lib/asm-commons-2.2.3.jar": "pkg:maven/asm/asm-commons@2.2.3",
|
||||
"/packages/hudson.war:WEB-INF/lib/asm-tree-2.2.3.jar": "pkg:maven/asm/asm-tree@2.2.3",
|
||||
"/packages/hudson.war:WEB-INF/slave.jar": "pkg:maven/org.jvnet.hudson.main/remoting@1.390",
|
||||
"/packages/hudson.war:WEB-INF/lib/xpp3_min-1.1.4c.jar": "pkg:maven/xpp3_min/xpp3_min@1.1.4c",
|
||||
"/packages/hudson.war:WEB-INF/lib/xpp3-1.1.4c.jar": "pkg:maven/xpp3/xpp3@1.1.4c",
|
||||
"/packages/hudson.war:WEB-INF/hudson-cli.jar": "pkg:maven/org.jvnet.hudson.main/hudson-cli@1.390",
|
||||
"/packages/hudson.war:WEB-INF/lib/dom4j-1.6.1-hudson-3.jar": "pkg:maven/org.jvnet.hudson.dom4j/dom4j@1.6.1-hudson-3",
|
||||
"/packages/xpp3_min-1.1.4c.jar": "pkg:maven/xpp3/xpp3_min@1.1.4c",
|
||||
|
||||
// syft generates an unstable purl
|
||||
"/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-auth": "pkg:maven/org.apache.dubbo/dubbo-auth@3.1.4",
|
||||
"/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-cluster": "pkg:maven/org.apache.dubbo/dubbo-cluster@3.1.4",
|
||||
"/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-common": "pkg:maven/org.apache.dubbo/dubbo-common@3.1.4",
|
||||
"/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-compatible": "pkg:maven/org.apache.dubbo/dubbo-compatible@3.1.4",
|
||||
"/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-config-api": "pkg:maven/org.apache.dubbo/dubbo-config-api@3.1.4",
|
||||
"/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-config-spring": "pkg:maven/org.apache.dubbo/dubbo-config-spring@3.1.4",
|
||||
"/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-configcenter-apollo": "pkg:maven/org.apache.dubbo/dubbo-configcenter-apollo@3.1.4",
|
||||
"/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-configcenter-nacos": "pkg:maven/org.apache.dubbo/dubbo-configcenter-nacos@3.1.4",
|
||||
"/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-configcenter-zookeeper": "pkg:maven/org.apache.dubbo/dubbo-configcenter-zookeeper@3.1.4",
|
||||
"/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-container-api": "pkg:maven/org.apache.dubbo/dubbo-container-api@3.1.4",
|
||||
"/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-container-spring": "pkg:maven/org.apache.dubbo/dubbo-container-spring@3.1.4",
|
||||
"/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-filter-cache": "pkg:maven/org.apache.dubbo/dubbo-filter-cache@3.1.4",
|
||||
"/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-filter-validation": "pkg:maven/org.apache.dubbo/dubbo-filter-validation@3.1.4",
|
||||
"/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-kubernetes": "pkg:maven/org.apache.dubbo/dubbo-kubernetes@3.1.4",
|
||||
"/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-metadata-api": "pkg:maven/org.apache.dubbo/dubbo-metadata-api@3.1.4",
|
||||
"/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-metadata-definition-protobuf": "pkg:maven/org.apache.dubbo/dubbo-metadata-definition-protobuf@3.1.4",
|
||||
"/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-metadata-report-nacos": "pkg:maven/org.apache.dubbo/dubbo-metadata-report-nacos@3.1.4",
|
||||
"/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-metadata-report-redis": "pkg:maven/org.apache.dubbo/dubbo-metadata-report-redis@3.1.4",
|
||||
"/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-metadata-report-zookeeper": "pkg:maven/org.apache.dubbo/dubbo-metadata-report-zookeeper@3.1.4",
|
||||
"/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-metrics-api": "pkg:maven/org.apache.dubbo/dubbo-metrics-api@3.1.4",
|
||||
"/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-metrics-prometheus": "pkg:maven/org.apache.dubbo/dubbo-metrics-prometheus@3.1.4",
|
||||
"/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-monitor-api": "pkg:maven/org.apache.dubbo/dubbo-monitor-api@3.1.4",
|
||||
"/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-monitor-default": "pkg:maven/org.apache.dubbo/dubbo-monitor-default@3.1.4",
|
||||
"/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-qos": "pkg:maven/org.apache.dubbo/dubbo-qos@3.1.4",
|
||||
"/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-reactive": "pkg:maven/org.apache.dubbo/dubbo-reactive@3.1.4",
|
||||
"/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-registry-api": "pkg:maven/org.apache.dubbo/dubbo-registry-api@3.1.4",
|
||||
"/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-registry-multicast": "pkg:maven/org.apache.dubbo/dubbo-registry-multicast@3.1.4",
|
||||
"/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-registry-multiple": "pkg:maven/org.apache.dubbo/dubbo-registry-multiple@3.1.4",
|
||||
"/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-registry-nacos": "pkg:maven/org.apache.dubbo/dubbo-registry-nacos@3.1.4",
|
||||
"/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-registry-zookeeper": "pkg:maven/org.apache.dubbo/dubbo-registry-zookeeper@3.1.4",
|
||||
"/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-remoting-api": "pkg:maven/org.apache.dubbo/dubbo-remoting-api@3.1.4",
|
||||
"/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-remoting-http": "pkg:maven/org.apache.dubbo/dubbo-remoting-http@3.1.4",
|
||||
"/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-remoting-netty": "pkg:maven/org.apache.dubbo/dubbo-remoting-netty@3.1.4",
|
||||
"/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-remoting-netty4": "pkg:maven/org.apache.dubbo/dubbo-remoting-netty4@3.1.4",
|
||||
"/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-remoting-zookeeper": "pkg:maven/org.apache.dubbo/dubbo-remoting-zookeeper@3.1.4",
|
||||
"/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-remoting-zookeeper-curator5": "pkg:maven/org.apache.dubbo/dubbo-remoting-zookeeper-curator5@3.1.4",
|
||||
"/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-rpc-api": "pkg:maven/org.apache.dubbo/dubbo-rpc-api@3.1.4",
|
||||
"/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-rpc-dubbo": "pkg:maven/org.apache.dubbo/dubbo-rpc-dubbo@3.1.4",
|
||||
"/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-rpc-grpc": "pkg:maven/org.apache.dubbo/dubbo-rpc-grpc@3.1.4",
|
||||
"/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-rpc-injvm": "pkg:maven/org.apache.dubbo/dubbo-rpc-injvm@3.1.4",
|
||||
"/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-rpc-rest": "pkg:maven/org.apache.dubbo/dubbo-rpc-rest@3.1.4",
|
||||
"/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-rpc-triple": "pkg:maven/org.apache.dubbo/dubbo-rpc-triple@3.1.4",
|
||||
"/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-serialization-api": "pkg:maven/org.apache.dubbo/dubbo-serialization-api@3.1.4",
|
||||
"/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-serialization-fastjson2": "pkg:maven/org.apache.dubbo/dubbo-serialization-fastjson2@3.1.4",
|
||||
"/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-serialization-hessian2": "pkg:maven/org.apache.dubbo/dubbo-serialization-hessian2@3.1.4",
|
||||
"/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-serialization-jdk": "pkg:maven/org.apache.dubbo/dubbo-serialization-jdk@3.1.4",
|
||||
"/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-xds": "pkg:maven/org.apache.dubbo/dubbo-xds@3.1.4",
|
||||
"/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo": "pkg:maven/org.apache.dubbo/dubbo@3.1.4",
|
||||
"/packages/dubbo-3.1.4.jar": "pkg:maven/org.apache.dubbo/dubbo@3.1.4",
|
||||
}
|
||||
|
||||
// Constructed by:
|
||||
// syft anchore/test_images:java-56d52bc -o template -t /tmp/test.templ | grep 'pkg:maven' | sort | uniq >> test/integration/java_purl_test.go
|
||||
// where the template is:
|
||||
/*
|
||||
{{ range .Artifacts}}"{{.Name}}@{{.Version}}":"{{.PURL}}",
|
||||
{{ end }}
|
||||
*/
|
||||
// syft anchore/test_images:java-1abc58f -o json | jq -r '.artifacts.[] | [.metadata.virtualPath, .purl, ""] | @csv' | grep 'pkg:maven' | sort | uniq >> /tmp/java_artifacts_mapping.txt
|
||||
// The map was then hand-edited for correctness by comparing to Maven Central.
|
||||
var expectedPURLs = map[string]string{
|
||||
"TwilioNotifier@0.2.1": "pkg:maven/com.twilio.jenkins/TwilioNotifier@0.2.1",
|
||||
"access-modifier-annotation@1.0": "pkg:maven/org.kohsuke/access-modifier-annotation@1.0",
|
||||
"acegi-security@1.0.5": "pkg:maven/org.acegisecurity/acegi-security@1.0.5",
|
||||
"activation@1.1.1-hudson-1": "pkg:maven/org.jvnet.hudson/activation@1.1.1-hudson-1",
|
||||
"akuma@1.2": "pkg:maven/com.sun.akuma/akuma@1.2",
|
||||
"animal-sniffer-annotation@1.0": "pkg:maven/org.jvnet/animal-sniffer-annotation@1.0",
|
||||
"annotation-indexer@1.2": "pkg:maven/org.jvnet.hudson/annotation-indexer@1.2",
|
||||
"annotations@13.0": "pkg:maven/org.jetbrains/annotations@13.0",
|
||||
"ant-launcher@1.8.0": "pkg:maven/org.apache.ant/ant-launcher@1.8.0",
|
||||
"ant@1.8.0": "pkg:maven/org.apache.ant/ant@1.8.0",
|
||||
"antlr@2.7.6": "pkg:maven/antlr/antlr@2.7.6",
|
||||
"aopalliance@1.0": "pkg:maven/aopalliance/aopalliance@1.0",
|
||||
"args4j@2.0.16": "pkg:maven/args4j/args4j@2.0.16",
|
||||
"asm-commons@2.2.3": "pkg:maven/asm-commons/asm-commons@2.2.3",
|
||||
"asm-tree@2.2.3": "pkg:maven/asm-tree/asm-tree@2.2.3",
|
||||
"asm@2.2.3": "pkg:maven/asm/asm@2.2.3",
|
||||
"avalon-framework@4.1.3": "pkg:maven/avalon-framework/avalon-framework@4.1.3",
|
||||
"bridge-method-annotation@1.2": "pkg:maven/com.infradna.tool/bridge-method-annotation@1.2",
|
||||
"classworlds@1.1": "pkg:maven/org.codehaus.classworlds/classworlds@1.1",
|
||||
"cli@1.390": "pkg:maven/org.jvnet.hudson.main/cli@1.390",
|
||||
"commons-beanutils@1.8.0": "pkg:maven/commons-beanutils/commons-beanutils@1.8.0",
|
||||
"commons-codec@1.2": "pkg:maven/commons-codec/commons-codec@1.2",
|
||||
"commons-codec@1.4": "pkg:maven/commons-codec/commons-codec@1.4",
|
||||
"commons-collections@3.2": "pkg:maven/commons-collections/commons-collections@3.2",
|
||||
"commons-digester@1.7": "pkg:maven/commons-digester/commons-digester@1.7",
|
||||
"commons-discovery@0.4": "pkg:maven/commons-discovery/commons-discovery@0.4",
|
||||
"commons-fileupload@1.2.1": "pkg:maven/commons-fileupload/commons-fileupload@1.2.1",
|
||||
"commons-httpclient@3.1": "pkg:maven/org.apache/commons-httpclient@3.1",
|
||||
"commons-httpclient@3.1-rc1": "pkg:maven/commons-httpclient/commons-httpclient@3.1-rc1",
|
||||
"commons-io@1.4": "pkg:maven/commons-io/commons-io@1.4",
|
||||
"commons-jelly-tags-define@1.0.1-hudson-20071021": "pkg:maven/org.jvnet.hudson/commons-jelly-tags-define@1.0.1-hudson-20071021",
|
||||
"commons-jelly-tags-fmt@1.0": "pkg:maven/commons-jelly-tags-fmt/commons-jelly-tags-fmt@1.0",
|
||||
"commons-jelly-tags-xml@1.1": "pkg:maven/commons-jelly-tags-xml/commons-jelly-tags-xml@1.1",
|
||||
"commons-jelly@1.1-hudson-20100305": "pkg:maven/org.jvnet.hudson/commons-jelly@1.1-hudson-20100305",
|
||||
"commons-jexl@1.1-hudson-20090508": "pkg:maven/org.jvnet.hudson/commons-jexl@1.1-hudson-20090508",
|
||||
"commons-lang@2.4": "pkg:maven/commons-lang/commons-lang@2.4",
|
||||
"commons-lang@2.5": "pkg:maven/commons-lang/commons-lang@2.5",
|
||||
"commons-logging@1.0.4": "pkg:maven/commons-logging/commons-logging@1.0.4", // see https://mvnrepository.com/artifact/commons-logging/commons-logging/1.0.4
|
||||
"commons-logging@1.1": "pkg:maven/commons-logging/commons-logging@1.1", // see https://mvnrepository.com/artifact/commons-logging/commons-logging/1.1
|
||||
"commons-logging@1.1.1": "pkg:maven/commons-logging/commons-logging@1.1.1", // see https://mvnrepository.com/artifact/commons-logging/commons-logging/1.1.1
|
||||
"commons-pool@1.3": "pkg:maven/commons-pool/commons-pool@1.3",
|
||||
"crypto-util@1.0": "pkg:maven/org.jvnet.hudson/crypto-util@1.0",
|
||||
"cvs@1.2": "pkg:maven/org.jvnet.hudson.plugins/cvs@1.2",
|
||||
"dom4j@1.6.1-hudson-3": "pkg:maven/dom4j/dom4j@1.6.1-hudson-3",
|
||||
"doxia-sink-api@1.0-alpha-10": "pkg:maven/org.apache.maven.doxia/doxia-sink-api@1.0-alpha-10",
|
||||
"easymock@2.4": "pkg:maven/org.easymock/easymock@2.4",
|
||||
"embedded_su4j@1.1": "pkg:maven/com.sun.solaris/embedded_su4j@1.1",
|
||||
"example-java-app-gradle@0.1.0": "pkg:maven/example-java-app-gradle/example-java-app-gradle@0.1.0",
|
||||
"ezmorph@1.0.3": "pkg:maven/net.sf.ezmorph/ezmorph@1.0.3",
|
||||
"graph-layouter@1.0": "pkg:maven/org.kohsuke/graph-layouter@1.0",
|
||||
"groovy-all@1.6.0": "pkg:maven/groovy-all/groovy-all@1.6.0",
|
||||
"gson@2.8.6": "pkg:maven/com.google.code.gson/gson@2.8.6",
|
||||
"guava@r06": "pkg:maven/com.google.guava/guava@r06",
|
||||
"httpclient@4.1.1": "pkg:maven/org.apache.httpcomponents/httpclient@4.1.1",
|
||||
"httpcore@4.1": "pkg:maven/org.apache.httpcomponents/httpcore@4.1",
|
||||
"hudson-cli@": "pkg:maven/hudson-cli/hudson-cli",
|
||||
"hudson-core@1.390": "pkg:maven/org.jvnet.hudson.main/hudson-core@1.390",
|
||||
"hudson-war@1.390": "pkg:maven/org.jvnet.hudson.main/hudson-war@1.390",
|
||||
"j-interop@2.0.5": "pkg:maven/j-interop/j-interop@2.0.5",
|
||||
"j-interopdeps@2.0.5": "pkg:maven/j-interopdeps/j-interopdeps@2.0.5",
|
||||
"jaxen@1.1-beta-11": "pkg:maven/org.jaxen/jaxen@1.1-beta-11",
|
||||
"jcaptcha-all@1.0-RC6": "pkg:maven/jcaptcha-all/jcaptcha-all@1.0-RC6",
|
||||
"jcifs@1.3.14-kohsuke-1": "pkg:maven/org.samba.jcifs/jcifs@1.3.14-kohsuke-1",
|
||||
"jcommon@1.0.12": "pkg:maven/jfree/jcommon@1.0.12",
|
||||
"jfreechart@1.0.9": "pkg:maven/jfreechart/jfreechart@1.0.9",
|
||||
"jinterop-proxy@1.1": "pkg:maven/org.kohsuke.jinterop/jinterop-proxy@1.1",
|
||||
"jinterop-wmi@1.0": "pkg:maven/org.jvnet.hudson/jinterop-wmi@1.0",
|
||||
"jline@0.9.94": "pkg:maven/jline/jline@0.9.94",
|
||||
"jmdns@3.1.6-hudson-2": "pkg:maven/com.strangeberry.jmdns.tools.Main/jmdns@3.1.6-hudson-2",
|
||||
"jna-posix@1.0.3": "pkg:maven/org.jruby.ext.posix/jna-posix@1.0.3",
|
||||
"jna@3.2.4": "pkg:maven/com.sun.jna/jna@3.2.4",
|
||||
"jsch@0.1.27": "pkg:maven/jsch/jsch@0.1.27",
|
||||
"json-lib@2.1-rev6": "pkg:maven/json-lib/json-lib@2.1-rev6",
|
||||
"json@20200518": "pkg:maven/org.json/json@20200518",
|
||||
"jstl@1.1.0": "pkg:maven/com.sun/jstl@1.1.0",
|
||||
"jtidy@4aug2000r7-dev-hudson-1": "pkg:maven/jtidy/jtidy@4aug2000r7-dev-hudson-1",
|
||||
"junit@4.13.1": "pkg:maven/junit/junit@4.13.1",
|
||||
"kotlin-stdlib-common@1.3.70": "pkg:maven/kotlin-stdlib-common/kotlin-stdlib-common@1.3.70",
|
||||
"kotlin-stdlib@1.3.70": "pkg:maven/kotlin-stdlib/kotlin-stdlib@1.3.70",
|
||||
"libpam4j@1.2": "pkg:maven/org.jvnet.libpam4j/libpam4j@1.2",
|
||||
"libzfs@0.5": "pkg:maven/org.jvnet.libzfs/libzfs@0.5",
|
||||
"localizer@1.10": "pkg:maven/org.jvnet.localizer/localizer@1.10",
|
||||
"log4j@1.2.9": "pkg:maven/log4j/log4j@1.2.9",
|
||||
"logkit@1.0.1": "pkg:maven/logkit/logkit@1.0.1",
|
||||
"mail@1.4": "pkg:maven/com.sun/mail@1.4",
|
||||
"maven-agent@1.390": "pkg:maven/org.jvnet.hudson.main/maven-agent@1.390",
|
||||
"maven-artifact-manager@2.0.9": "pkg:maven/org.apache.maven/maven-artifact-manager@2.0.9",
|
||||
"maven-artifact@2.0.9": "pkg:maven/org.apache.maven/maven-artifact@2.0.9",
|
||||
"maven-core@2.0.9": "pkg:maven/org.apache.maven/maven-core@2.0.9",
|
||||
"maven-embedder@2.0.4": "pkg:maven/org.apache.maven/maven-embedder@2.0.4",
|
||||
"maven-embedder@2.0.4-hudson-1": "pkg:maven/org.jvnet.hudson/maven-embedder@2.0.4-hudson-1",
|
||||
"maven-error-diagnostics@2.0.9": "pkg:maven/org.apache.maven/maven-error-diagnostics@2.0.9",
|
||||
"maven-interceptor@1.390": "pkg:maven/org.jvnet.hudson.main/maven-interceptor@1.390",
|
||||
"maven-model@2.0.9": "pkg:maven/org.apache.maven/maven-model@2.0.9",
|
||||
"maven-monitor@2.0.9": "pkg:maven/org.apache.maven/maven-monitor@2.0.9",
|
||||
"maven-plugin-api@2.0.9": "pkg:maven/org.apache.maven/maven-plugin-api@2.0.9",
|
||||
"maven-plugin-descriptor@2.0.9": "pkg:maven/org.apache.maven/maven-plugin-descriptor@2.0.9",
|
||||
"maven-plugin-parameter-documenter@2.0.9": "pkg:maven/org.apache.maven/maven-plugin-parameter-documenter@2.0.9",
|
||||
"maven-plugin-registry@2.0.9": "pkg:maven/org.apache.maven/maven-plugin-registry@2.0.9",
|
||||
"maven-plugin@1.390": "pkg:maven/org.jvnet.hudson.main/maven-plugin@1.390",
|
||||
"maven-profile@2.0.9": "pkg:maven/org.apache.maven/maven-profile@2.0.9",
|
||||
"maven-project@2.0.9": "pkg:maven/org.apache.maven/maven-project@2.0.9",
|
||||
"maven-reporting-api@2.0.9": "pkg:maven/org.apache.maven.reporting/maven-reporting-api@2.0.9",
|
||||
"maven-repository-metadata@2.0.9": "pkg:maven/org.apache.maven/maven-repository-metadata@2.0.9",
|
||||
"maven-settings@2.0.9": "pkg:maven/org.apache.maven/maven-settings@2.0.9",
|
||||
"maven2.1-interceptor@1.2": "pkg:maven/org.jvnet.hudson/maven2.1-interceptor@1.2",
|
||||
"memory-monitor@1.3": "pkg:maven/org.jvnet.hudson/memory-monitor@1.3",
|
||||
"nomad@0.7.4": "pkg:maven/org.jenkins-ci.plugins/nomad@0.7.4",
|
||||
"okhttp@4.5.0": "pkg:maven/com.squareup.okhttp3/okhttp@4.5.0",
|
||||
"okio@2.5.0": "pkg:maven/com.squareup.okio/okio@2.5.0",
|
||||
"oro@2.0.8": "pkg:maven/org.apache.oro/oro@2.0.8",
|
||||
"plexus-container-default@1.0-alpha-9-stable-1": "pkg:maven/org.codehaus.plexus/plexus-container-default@1.0-alpha-9-stable-1",
|
||||
"plexus-interactivity-api@1.0-alpha-4": "pkg:maven/org.codehaus.plexus/plexus-interactivity-api@1.0-alpha-4",
|
||||
"plexus-utils@1.5.1": "pkg:maven/org.codehaus.plexus/plexus-utils@1.5.1",
|
||||
"remoting@1.390": "pkg:maven/org.jvnet.hudson.main/remoting@1.390",
|
||||
"robust-http-client@1.1": "pkg:maven/org.jvnet.robust-http-client/robust-http-client@1.1",
|
||||
"sdk@3.0": "pkg:maven/sdk/sdk@3.0",
|
||||
"sezpoz@1.7": "pkg:maven/net.java.sezpoz/sezpoz@1.7",
|
||||
"slave@": "pkg:maven/slave/slave",
|
||||
"slide-webdavlib@2.1": "pkg:maven/slide-webdavlib/slide-webdavlib@2.1",
|
||||
"spring-aop@2.5": "pkg:maven/org.springframework/spring-aop@2.5",
|
||||
"spring-beans@2.5": "pkg:maven/org.springframework/spring-beans@2.5",
|
||||
"spring-context@2.5": "pkg:maven/org.springframework/spring-context@2.5",
|
||||
"spring-core@2.5": "pkg:maven/org.springframework/spring-core@2.5",
|
||||
"spring-dao@1.2.9": "pkg:maven/org.springframework/spring-dao@1.2.9",
|
||||
"spring-jdbc@1.2.9": "pkg:maven/org.springframework/spring-jdbc@1.2.9",
|
||||
"spring-web@2.5": "pkg:maven/org.springframework/spring-web@2.5",
|
||||
"ssh-slaves@0.14": "pkg:maven/org.jvnet.hudson.plugins/ssh-slaves@0.14",
|
||||
"stapler-adjunct-timeline@1.2": "pkg:maven/org.kohsuke.stapler/stapler-adjunct-timeline@1.2",
|
||||
"stapler-jelly@1.155": "pkg:maven/org.kohsuke.stapler/stapler-jelly@1.155",
|
||||
"stapler@1.155": "pkg:maven/org.kohsuke.stapler/stapler@1.155",
|
||||
"stax-api@1.0.1": "pkg:maven/stax-api/stax-api@1.0.1",
|
||||
"subversion@1.20": "pkg:maven/org.jvnet.hudson.plugins/subversion@1.20",
|
||||
"svnkit@1.3.4-hudson-2": "pkg:maven/svnkit/svnkit@1.3.4-hudson-2",
|
||||
"task-reactor@1.2": "pkg:maven/org.jvnet.hudson/task-reactor@1.2",
|
||||
"tiger-types@1.3": "pkg:maven/org.jvnet/tiger-types@1.3",
|
||||
"trilead-putty-extension@1.0": "pkg:maven/org.kohsuke/trilead-putty-extension@1.0",
|
||||
"trilead-ssh2@build212-hudson-5": "pkg:maven/org.jvnet.hudson/trilead-ssh2@build212-hudson-5",
|
||||
"txw2@20070624": "pkg:maven/txw2/txw2@20070624",
|
||||
"wagon-file@1.0-beta-2": "pkg:maven/org.apache.maven.wagon/wagon-file@1.0-beta-2",
|
||||
"wagon-http-lightweight@1.0-beta-2": "pkg:maven/org.apache.maven.wagon/wagon-http-lightweight@1.0-beta-2",
|
||||
"wagon-http-shared@1.0-beta-2": "pkg:maven/org.apache.maven.wagon/wagon-http-shared@1.0-beta-2",
|
||||
"wagon-provider-api@1.0-beta-2": "pkg:maven/org.apache.maven.wagon/wagon-provider-api@1.0-beta-2",
|
||||
"wagon-ssh-common@1.0-beta-2": "pkg:maven/org.apache.maven.wagon/wagon-ssh-common@1.0-beta-2",
|
||||
"wagon-ssh-external@1.0-beta-2": "pkg:maven/org.apache.maven.wagon/wagon-ssh-external@1.0-beta-2",
|
||||
"wagon-ssh@1.0-beta-2": "pkg:maven/org.apache.maven.wagon/wagon-ssh@1.0-beta-2",
|
||||
"wagon-webdav@1.0-beta-2-hudson-1": "pkg:maven/org.jvnet.hudson/wagon-webdav@1.0-beta-2-hudson-1",
|
||||
"windows-remote-command@1.0": "pkg:maven/org.jvnet.hudson/windows-remote-command@1.0",
|
||||
"winp@1.14": "pkg:maven/org.jvnet.winp/winp@1.14",
|
||||
"winstone@0.9.10-hudson-24": "pkg:maven/org.jvnet.hudson.winstone/winstone@0.9.10-hudson-24",
|
||||
"wstx-asl@3.2.7": "pkg:maven/wstx-asl/wstx-asl@3.2.7",
|
||||
"xml-im-exporter@1.1": "pkg:maven/xml-im-exporter/xml-im-exporter@1.1",
|
||||
"xpp3@1.1.4c": "pkg:maven/xpp3/xpp3@1.1.4c",
|
||||
"xpp3_min@1.1.4c": "pkg:maven/xpp3_min/xpp3_min@1.1.4c",
|
||||
"xstream@1.3.1-hudson-8": "pkg:maven/org.jvnet.hudson/xstream@1.3.1-hudson-8",
|
||||
"/packages/activemq-client-5.18.2.jar": "pkg:maven/org.apache.activemq/activemq-client@5.18.2",
|
||||
"/packages/activemq-protobuf-1.1.jar": "pkg:maven/org.apache.activemq.protobuf/activemq-protobuf@1.1",
|
||||
// "/packages/akka-actor_2.13-2.6.6.jar": "pkg:maven/com.typesafe.akka/akka-actor_2.13@2.6.6",
|
||||
// "/packages/akka-management-cluster-bootstrap_2.13-1.2.0.jar": "pkg:maven/com.lightbend.akka.management/akka-management-cluster-bootstrap_2.13@1.2.0",
|
||||
"/packages/ant-1.10.3.jar": "pkg:maven/org.apache.ant/ant@1.10.3",
|
||||
"/packages/apache-chainsaw-2.1.0.jar": "pkg:maven/log4j/apache-chainsaw@2.1.0",
|
||||
"/packages/apache-log4j-extras-1.1.jar": "pkg:maven/log4j/apache-log4j-extras@1.1",
|
||||
"/packages/apoc-4.4.0.11.jar": "pkg:maven/org.neo4j.procedure/apoc@4.4.0.11",
|
||||
"/packages/bc-fips-1.0.2.3.jar": "pkg:maven/org.bouncycastle/bc-fips@1.0.2.3",
|
||||
"/packages/camel-core-3.1.0.jar": "pkg:maven/org.apache.camel/camel-core@3.1.0",
|
||||
"/packages/cassandra-all-4.1.1.jar": "pkg:maven/org.apache.cassandra/cassandra-all@4.1.1",
|
||||
"/packages/commons-logging-1.1.1.jar": "pkg:maven/commons-logging/commons-logging@1.1.1",
|
||||
"/packages/commons-vfs-1.0.jar": "pkg:maven/commons-vfs/commons-vfs@1.0",
|
||||
"/packages/cxf-rt-transports-http-2.7.3.jar": "pkg:maven/org.apache.cxf/cxf-rt-transports-http@2.7.3",
|
||||
"/packages/dubbo-3.1.4.jar:com.alibaba:hessian-lite": "pkg:maven/com.alibaba/hessian-lite@3.2.13",
|
||||
// "/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-auth": "pkg:maven/org.apache.dubbo/dubbo-auth@3.1.4",
|
||||
// "/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-cluster": "pkg:maven/org.apache.dubbo/dubbo-cluster@3.1.4",
|
||||
// "/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-common": "pkg:maven/org.apache.dubbo/dubbo-common@3.1.4",
|
||||
// "/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-compatible": "pkg:maven/org.apache.dubbo/dubbo-compatible@3.1.4",
|
||||
// "/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-config-api": "pkg:maven/org.apache.dubbo/dubbo-config-api@3.1.4",
|
||||
// "/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-config-spring": "pkg:maven/org.apache.dubbo/dubbo-config-spring@3.1.4",
|
||||
// "/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-configcenter-apollo": "pkg:maven/org.apache.dubbo/dubbo-configcenter-apollo@3.1.4",
|
||||
// "/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-configcenter-nacos": "pkg:maven/org.apache.dubbo/dubbo-configcenter-nacos@3.1.4",
|
||||
// "/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-configcenter-zookeeper": "pkg:maven/org.apache.dubbo/dubbo-configcenter-zookeeper@3.1.4",
|
||||
// "/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-container-api": "pkg:maven/org.apache.dubbo/dubbo-container-api@3.1.4",
|
||||
// "/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-container-spring": "pkg:maven/org.apache.dubbo/dubbo-container-spring@3.1.4",
|
||||
// "/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-filter-cache": "pkg:maven/org.apache.dubbo/dubbo-filter-cache@3.1.4",
|
||||
// "/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-filter-validation": "pkg:maven/org.apache.dubbo/dubbo-filter-validation@3.1.4",
|
||||
// "/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-kubernetes": "pkg:maven/org.apache.dubbo/dubbo-kubernetes@3.1.4",
|
||||
// "/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-metadata-api": "pkg:maven/org.apache.dubbo/dubbo-metadata-api@3.1.4",
|
||||
// "/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-metadata-definition-protobuf": "pkg:maven/org.apache.dubbo/dubbo-metadata-definition-protobuf@3.1.4",
|
||||
// "/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-metadata-report-nacos": "pkg:maven/org.apache.dubbo/dubbo-metadata-report-nacos@3.1.4",
|
||||
// "/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-metadata-report-redis": "pkg:maven/org.apache.dubbo/dubbo-metadata-report-redis@3.1.4",
|
||||
// "/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-metadata-report-zookeeper": "pkg:maven/org.apache.dubbo/dubbo-metadata-report-zookeeper@3.1.4",
|
||||
// "/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-metrics-api": "pkg:maven/org.apache.dubbo/dubbo-metrics-api@3.1.4",
|
||||
// "/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-metrics-prometheus": "pkg:maven/org.apache.dubbo/dubbo-metrics-prometheus@3.1.4",
|
||||
// "/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-monitor-api": "pkg:maven/org.apache.dubbo/dubbo-monitor-api@3.1.4",
|
||||
// "/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-monitor-default": "pkg:maven/org.apache.dubbo/dubbo-monitor-default@3.1.4",
|
||||
// "/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-qos": "pkg:maven/org.apache.dubbo/dubbo-qos@3.1.4",
|
||||
// "/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-reactive": "pkg:maven/org.apache.dubbo/dubbo-reactive@3.1.4",
|
||||
// "/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-registry-api": "pkg:maven/org.apache.dubbo/dubbo-registry-api@3.1.4",
|
||||
// "/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-registry-multicast": "pkg:maven/org.apache.dubbo/dubbo-registry-multicast@3.1.4",
|
||||
// "/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-registry-multiple": "pkg:maven/org.apache.dubbo/dubbo-registry-multiple@3.1.4",
|
||||
// "/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-registry-nacos": "pkg:maven/org.apache.dubbo/dubbo-registry-nacos@3.1.4",
|
||||
// "/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-registry-zookeeper": "pkg:maven/org.apache.dubbo/dubbo-registry-zookeeper@3.1.4",
|
||||
// "/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-remoting-api": "pkg:maven/org.apache.dubbo/dubbo-remoting-api@3.1.4",
|
||||
// "/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-remoting-http": "pkg:maven/org.apache.dubbo/dubbo-remoting-http@3.1.4",
|
||||
// "/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-remoting-netty": "pkg:maven/org.apache.dubbo/dubbo-remoting-netty@3.1.4",
|
||||
// "/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-remoting-netty4": "pkg:maven/org.apache.dubbo/dubbo-remoting-netty4@3.1.4",
|
||||
// "/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-remoting-zookeeper": "pkg:maven/org.apache.dubbo/dubbo-remoting-zookeeper@3.1.4",
|
||||
// "/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-remoting-zookeeper-curator5": "pkg:maven/org.apache.dubbo/dubbo-remoting-zookeeper-curator5@3.1.4",
|
||||
// "/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-rpc-api": "pkg:maven/org.apache.dubbo/dubbo-rpc-api@3.1.4",
|
||||
// "/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-rpc-dubbo": "pkg:maven/org.apache.dubbo/dubbo-rpc-dubbo@3.1.4",
|
||||
// "/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-rpc-grpc": "pkg:maven/org.apache.dubbo/dubbo-rpc-grpc@3.1.4",
|
||||
// "/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-rpc-injvm": "pkg:maven/org.apache.dubbo/dubbo-rpc-injvm@3.1.4",
|
||||
// "/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-rpc-rest": "pkg:maven/org.apache.dubbo/dubbo-rpc-rest@3.1.4",
|
||||
// "/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-rpc-triple": "pkg:maven/org.apache.dubbo/dubbo-rpc-triple@3.1.4",
|
||||
// "/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-serialization-api": "pkg:maven/org.apache.dubbo/dubbo-serialization-api@3.1.4",
|
||||
// "/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-serialization-fastjson2": "pkg:maven/org.apache.dubbo/dubbo-serialization-fastjson2@3.1.4",
|
||||
// "/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-serialization-hessian2": "pkg:maven/org.apache.dubbo/dubbo-serialization-hessian2@3.1.4",
|
||||
// "/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-serialization-jdk": "pkg:maven/org.apache.dubbo/dubbo-serialization-jdk@3.1.4",
|
||||
// "/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo-xds": "pkg:maven/org.apache.dubbo/dubbo-xds@3.1.4",
|
||||
// "/packages/dubbo-3.1.4.jar:org.apache.dubbo:dubbo": "pkg:maven/org.apache.dubbo/dubbo@3.1.4",
|
||||
// "/packages/dubbo-3.1.4.jar": "pkg:maven/org.apache.dubbo/dubbo@3.1.4",
|
||||
"/packages/elasticsearch-8.10.2.jar": "pkg:maven/org.elasticsearch/elasticsearch@8.10.2",
|
||||
"/packages/elasticsearch-rest-client-sniffer-7.17.11.jar": "pkg:maven/org.elasticsearch.client/elasticsearch-rest-client-sniffer@7.17.11",
|
||||
"/packages/example-java-app-gradle-0.1.0.ear": "pkg:maven/example-java-app-gradle/example-java-app-gradle@0.1.0",
|
||||
"/packages/geode-core-1.14.3.jar": "pkg:maven/org.apache.geode/geode-core@1.14.3",
|
||||
"/packages/github-api-1.118.jar": "pkg:maven/org.kohsuke/github-api@1.118",
|
||||
"/packages/google-oauth-client-1.25.0.jar": "pkg:maven/com.google.oauth-client/google-oauth-client@1.25.0",
|
||||
"/packages/graphql-java-20.0.jar:com.google.guava:guava": "pkg:maven/com.google.guava/guava@31.0.1-jre",
|
||||
"/packages/graphql-java-20.0.jar:org.antlr:antlr4-runtime": "pkg:maven/org.antlr/antlr4-runtime@4.9.3",
|
||||
"/packages/graphql-java-20.0.jar": "pkg:maven/com.graphql-java/graphql-java@20.0",
|
||||
"/packages/guava-29.0-jre.jar": "pkg:maven/com.google.guava/guava@29.0-jre",
|
||||
"/packages/hadoop-common-3.3.2.jar": "pkg:maven/org.apache.hadoop/hadoop-common@3.3.2",
|
||||
"/packages/hazelcast-5.2.4.jar:com.fasterxml.jackson.core:jackson-core": "pkg:maven/com.fasterxml.jackson.core/jackson-core@2.15.2",
|
||||
"/packages/hazelcast-5.2.4.jar:com.fasterxml.jackson.jr:jackson-jr-annotation-support": "pkg:maven/com.fasterxml.jackson.jr/jackson-jr-annotation-support@2.15.2",
|
||||
"/packages/hazelcast-5.2.4.jar:com.fasterxml.jackson.jr:jackson-jr-objects": "pkg:maven/com.fasterxml.jackson.jr/jackson-jr-objects@2.15.2",
|
||||
"/packages/hazelcast-5.2.4.jar:com.github.erosb:everit-json-schema": "pkg:maven/com.github.erosb/everit-json-schema@1.14.2",
|
||||
"/packages/hazelcast-5.2.4.jar:com.zaxxer:HikariCP": "pkg:maven/com.zaxxer/HikariCP@4.0.3",
|
||||
"/packages/hazelcast-5.2.4.jar:io.github.classgraph:classgraph": "pkg:maven/io.github.classgraph/classgraph@4.8.149",
|
||||
"/packages/hazelcast-5.2.4.jar:org.json:json": "pkg:maven/org.json/json@20230227",
|
||||
"/packages/hazelcast-5.2.4.jar:org.snakeyaml:snakeyaml-engine": "pkg:maven/org.snakeyaml/snakeyaml-engine@2.3",
|
||||
"/packages/hazelcast-5.2.4.jar": "pkg:maven/com.hazelcast/hazelcast@5.2.4",
|
||||
"/packages/hibernate-validator-6.1.3.Final.jar": "pkg:maven/org.hibernate.validator/hibernate-validator@6.1.3.Final",
|
||||
"/packages/http2-common-11.0.16.jar": "pkg:maven/org.eclipse.jetty.http2/http2-common@11.0.16",
|
||||
"/packages/hudson.war:WEB-INF/hudson-cli.jar:args4j:args4j": "pkg:maven/args4j/args4j@2.0.16",
|
||||
"/packages/hudson.war:WEB-INF/hudson-cli.jar:org.jvnet:animal-sniffer-annotation": "pkg:maven/org.jvnet/animal-sniffer-annotation@1.0",
|
||||
"/packages/hudson.war:WEB-INF/hudson-cli.jar:org.jvnet.hudson.main:remoting": "pkg:maven/org.jvnet.hudson.main/remoting@1.390",
|
||||
"/packages/hudson.war:WEB-INF/hudson-cli.jar:org.jvnet.localizer:localizer": "pkg:maven/org.jvnet.localizer/localizer@1.10",
|
||||
// "/packages/hudson.war:WEB-INF/hudson-cli.jar": "pkg:maven/org.jvnet.hudson.main/hudson-cli@1.390",
|
||||
"/packages/hudson.war:WEB-INF/lib/access-modifier-annotation-1.0.jar": "pkg:maven/org.kohsuke/access-modifier-annotation@1.0",
|
||||
"/packages/hudson.war:WEB-INF/lib/acegi-security-1.0.5.jar": "pkg:maven/org.acegisecurity/acegi-security@1.0.5",
|
||||
"/packages/hudson.war:WEB-INF/lib/activation-1.1.1-hudson-1.jar": "pkg:maven/org.jvnet.hudson/activation@1.1.1-hudson-1",
|
||||
"/packages/hudson.war:WEB-INF/lib/akuma-1.2.jar": "pkg:maven/com.sun.akuma/akuma@1.2",
|
||||
"/packages/hudson.war:WEB-INF/lib/annotation-indexer-1.2.jar": "pkg:maven/org.jvnet.hudson/annotation-indexer@1.2",
|
||||
"/packages/hudson.war:WEB-INF/lib/ant-1.8.0.jar": "pkg:maven/org.apache.ant/ant@1.8.0",
|
||||
"/packages/hudson.war:WEB-INF/lib/ant-launcher-1.8.0.jar": "pkg:maven/org.apache.ant/ant-launcher@1.8.0",
|
||||
"/packages/hudson.war:WEB-INF/lib/antlr-2.7.6.jar": "pkg:maven/antlr/antlr@2.7.6",
|
||||
"/packages/hudson.war:WEB-INF/lib/aopalliance-1.0.jar": "pkg:maven/aopalliance/aopalliance@1.0",
|
||||
"/packages/hudson.war:WEB-INF/lib/args4j-2.0.16.jar": "pkg:maven/args4j/args4j@2.0.16",
|
||||
// "/packages/hudson.war:WEB-INF/lib/asm-2.2.3.jar": "pkg:maven/asm/asm@2.2.3",
|
||||
// "/packages/hudson.war:WEB-INF/lib/asm-commons-2.2.3.jar": "pkg:maven/asm/asm-commons@2.2.3",
|
||||
// "/packages/hudson.war:WEB-INF/lib/asm-tree-2.2.3.jar": "pkg:maven/asm/asm-tree@2.2.3",
|
||||
"/packages/hudson.war:WEB-INF/lib/avalon-framework-4.1.3.jar": "pkg:maven/avalon-framework/avalon-framework@4.1.3",
|
||||
"/packages/hudson.war:WEB-INF/lib/bridge-method-annotation-1.2.jar": "pkg:maven/com.infradna.tool/bridge-method-annotation@1.2",
|
||||
"/packages/hudson.war:WEB-INF/lib/cli-1.390.jar": "pkg:maven/org.jvnet.hudson.main/cli@1.390",
|
||||
"/packages/hudson.war:WEB-INF/lib/commons-beanutils-1.8.0.jar": "pkg:maven/commons-beanutils/commons-beanutils@1.8.0",
|
||||
"/packages/hudson.war:WEB-INF/lib/commons-codec-1.4.jar": "pkg:maven/commons-codec/commons-codec@1.4",
|
||||
"/packages/hudson.war:WEB-INF/lib/commons-collections-3.2.jar": "pkg:maven/commons-collections/commons-collections@3.2",
|
||||
"/packages/hudson.war:WEB-INF/lib/commons-digester-1.7.jar": "pkg:maven/commons-digester/commons-digester@1.7",
|
||||
"/packages/hudson.war:WEB-INF/lib/commons-discovery-0.4.jar": "pkg:maven/commons-discovery/commons-discovery@0.4",
|
||||
"/packages/hudson.war:WEB-INF/lib/commons-fileupload-1.2.1.jar": "pkg:maven/commons-fileupload/commons-fileupload@1.2.1",
|
||||
"/packages/hudson.war:WEB-INF/lib/commons-io-1.4.jar": "pkg:maven/commons-io/commons-io@1.4",
|
||||
"/packages/hudson.war:WEB-INF/lib/commons-jelly-1.1-hudson-20100305.jar": "pkg:maven/org.jvnet.hudson/commons-jelly@1.1-hudson-20100305",
|
||||
"/packages/hudson.war:WEB-INF/lib/commons-jelly-tags-define-1.0.1-hudson-20071021.jar": "pkg:maven/org.jvnet.hudson/commons-jelly-tags-define@1.0.1-hudson-20071021",
|
||||
"/packages/hudson.war:WEB-INF/lib/commons-jelly-tags-fmt-1.0.jar": "pkg:maven/commons-jelly/commons-jelly-tags-fmt@1.0",
|
||||
"/packages/hudson.war:WEB-INF/lib/commons-jelly-tags-xml-1.1.jar": "pkg:maven/commons-jelly/commons-jelly-tags-xml@1.1",
|
||||
"/packages/hudson.war:WEB-INF/lib/commons-jexl-1.1-hudson-20090508.jar": "pkg:maven/org.jvnet.hudson/commons-jexl@1.1-hudson-20090508",
|
||||
"/packages/hudson.war:WEB-INF/lib/commons-lang-2.4.jar": "pkg:maven/commons-lang/commons-lang@2.4",
|
||||
"/packages/hudson.war:WEB-INF/lib/commons-logging-1.1.jar": "pkg:maven/commons-logging/commons-logging@1.1",
|
||||
"/packages/hudson.war:WEB-INF/lib/commons-pool-1.3.jar": "pkg:maven/commons-pool/commons-pool@1.3",
|
||||
"/packages/hudson.war:WEB-INF/lib/crypto-util-1.0.jar": "pkg:maven/org.jvnet.hudson/crypto-util@1.0",
|
||||
// "/packages/hudson.war:WEB-INF/lib/dom4j-1.6.1-hudson-3.jar": "pkg:maven/org.jvnet.hudson.dom4j/dom4j@1.6.1-hudson-3",
|
||||
"/packages/hudson.war:WEB-INF/lib/embedded_su4j-1.1.jar": "pkg:maven/com.sun.solaris/embedded_su4j@1.1",
|
||||
"/packages/hudson.war:WEB-INF/lib/ezmorph-1.0.3.jar": "pkg:maven/net.sf.ezmorph/ezmorph@1.0.3",
|
||||
"/packages/hudson.war:WEB-INF/lib/graph-layouter-1.0.jar": "pkg:maven/org.kohsuke/graph-layouter@1.0",
|
||||
"/packages/hudson.war:WEB-INF/lib/groovy-all-1.6.0.jar": "pkg:maven/org.codehaus.groovy/groovy-all@1.6.0",
|
||||
"/packages/hudson.war:WEB-INF/lib/guava-r06.jar": "pkg:maven/com.google.guava/guava@r06",
|
||||
"/packages/hudson.war:WEB-INF/lib/hudson-core-1.390.jar": "pkg:maven/org.jvnet.hudson.main/hudson-core@1.390",
|
||||
"/packages/hudson.war:WEB-INF/lib/j-interop-2.0.5.jar": "pkg:maven/j-interop/j-interop@2.0.5",
|
||||
"/packages/hudson.war:WEB-INF/lib/j-interopdeps-2.0.5.jar": "pkg:maven/j-interopdeps/j-interopdeps@2.0.5",
|
||||
"/packages/hudson.war:WEB-INF/lib/jaxen-1.1-beta-11.jar": "pkg:maven/org.jaxen/jaxen@1.1-beta-11",
|
||||
"/packages/hudson.war:WEB-INF/lib/jcaptcha-all-1.0-RC6.jar": "pkg:maven/jcaptcha-all/jcaptcha-all@1.0-RC6",
|
||||
"/packages/hudson.war:WEB-INF/lib/jcifs-1.3.14-kohsuke-1.jar": "pkg:maven/org.samba.jcifs/jcifs@1.3.14-kohsuke-1",
|
||||
"/packages/hudson.war:WEB-INF/lib/jcommon-1.0.12.jar": "pkg:maven/jfree/jcommon@1.0.12",
|
||||
"/packages/hudson.war:WEB-INF/lib/jfreechart-1.0.9.jar": "pkg:maven/jfreechart/jfreechart@1.0.9",
|
||||
"/packages/hudson.war:WEB-INF/lib/jinterop-proxy-1.1.jar": "pkg:maven/org.kohsuke.jinterop/jinterop-proxy@1.1",
|
||||
"/packages/hudson.war:WEB-INF/lib/jinterop-wmi-1.0.jar": "pkg:maven/org.jvnet.hudson/jinterop-wmi@1.0",
|
||||
"/packages/hudson.war:WEB-INF/lib/jline-0.9.94.jar": "pkg:maven/jline/jline@0.9.94",
|
||||
"/packages/hudson.war:WEB-INF/lib/jmdns-3.1.6-hudson-2.jar": "pkg:maven/com.strangeberry.jmdns.tools.Main/jmdns@3.1.6-hudson-2",
|
||||
"/packages/hudson.war:WEB-INF/lib/jna-3.2.4.jar": "pkg:maven/com.sun.jna/jna@3.2.4",
|
||||
"/packages/hudson.war:WEB-INF/lib/jna-posix-1.0.3.jar": "pkg:maven/org.jruby.ext.posix/jna-posix@1.0.3",
|
||||
"/packages/hudson.war:WEB-INF/lib/json-lib-2.1-rev6.jar": "pkg:maven/json-lib/json-lib@2.1-rev6",
|
||||
"/packages/hudson.war:WEB-INF/lib/jstl-1.1.0.jar": "pkg:maven/com.sun/jstl@1.1.0",
|
||||
"/packages/hudson.war:WEB-INF/lib/jtidy-4aug2000r7-dev-hudson-1.jar": "pkg:maven/jtidy/jtidy@4aug2000r7-dev-hudson-1",
|
||||
"/packages/hudson.war:WEB-INF/lib/libpam4j-1.2.jar": "pkg:maven/org.jvnet.libpam4j/libpam4j@1.2",
|
||||
"/packages/hudson.war:WEB-INF/lib/libzfs-0.5.jar": "pkg:maven/org.jvnet.libzfs/libzfs@0.5",
|
||||
"/packages/hudson.war:WEB-INF/lib/localizer-1.10.jar": "pkg:maven/org.jvnet.localizer/localizer@1.10",
|
||||
"/packages/hudson.war:WEB-INF/lib/log4j-1.2.9.jar": "pkg:maven/log4j/log4j@1.2.9",
|
||||
"/packages/hudson.war:WEB-INF/lib/logkit-1.0.1.jar": "pkg:maven/logkit/logkit@1.0.1",
|
||||
"/packages/hudson.war:WEB-INF/lib/mail-1.4.jar": "pkg:maven/com.sun/mail@1.4",
|
||||
"/packages/hudson.war:WEB-INF/lib/memory-monitor-1.3.jar": "pkg:maven/org.jvnet.hudson/memory-monitor@1.3",
|
||||
"/packages/hudson.war:WEB-INF/lib/oro-2.0.8.jar": "pkg:maven/org.apache.oro/oro@2.0.8",
|
||||
"/packages/hudson.war:WEB-INF/lib/remoting-1.390.jar:args4j:args4j": "pkg:maven/args4j/args4j@2.0.16",
|
||||
"/packages/hudson.war:WEB-INF/lib/remoting-1.390.jar": "pkg:maven/org.jvnet.hudson.main/remoting@1.390",
|
||||
"/packages/hudson.war:WEB-INF/lib/robust-http-client-1.1.jar": "pkg:maven/org.jvnet.robust-http-client/robust-http-client@1.1",
|
||||
"/packages/hudson.war:WEB-INF/lib/sezpoz-1.7.jar": "pkg:maven/net.java.sezpoz/sezpoz@1.7",
|
||||
"/packages/hudson.war:WEB-INF/lib/spring-aop-2.5.jar": "pkg:maven/org.springframework/spring-aop@2.5",
|
||||
"/packages/hudson.war:WEB-INF/lib/spring-beans-2.5.jar": "pkg:maven/org.springframework/spring-beans@2.5",
|
||||
"/packages/hudson.war:WEB-INF/lib/spring-context-2.5.jar": "pkg:maven/org.springframework/spring-context@2.5",
|
||||
"/packages/hudson.war:WEB-INF/lib/spring-core-2.5.jar": "pkg:maven/org.springframework/spring-core@2.5",
|
||||
"/packages/hudson.war:WEB-INF/lib/spring-dao-1.2.9.jar": "pkg:maven/org.springframework/spring-dao@1.2.9",
|
||||
"/packages/hudson.war:WEB-INF/lib/spring-jdbc-1.2.9.jar": "pkg:maven/org.springframework/spring-jdbc@1.2.9",
|
||||
"/packages/hudson.war:WEB-INF/lib/spring-web-2.5.jar": "pkg:maven/org.springframework/spring-web@2.5",
|
||||
"/packages/hudson.war:WEB-INF/lib/stapler-1.155.jar": "pkg:maven/org.kohsuke.stapler/stapler@1.155",
|
||||
"/packages/hudson.war:WEB-INF/lib/stapler-adjunct-timeline-1.2.jar": "pkg:maven/org.kohsuke.stapler/stapler-adjunct-timeline@1.2",
|
||||
"/packages/hudson.war:WEB-INF/lib/stapler-jelly-1.155.jar": "pkg:maven/org.kohsuke.stapler/stapler-jelly@1.155",
|
||||
"/packages/hudson.war:WEB-INF/lib/stax-api-1.0.1.jar": "pkg:maven/stax-api/stax-api@1.0.1",
|
||||
"/packages/hudson.war:WEB-INF/lib/task-reactor-1.2.jar": "pkg:maven/org.jvnet.hudson/task-reactor@1.2",
|
||||
"/packages/hudson.war:WEB-INF/lib/tiger-types-1.3.jar": "pkg:maven/org.jvnet/tiger-types@1.3",
|
||||
"/packages/hudson.war:WEB-INF/lib/trilead-putty-extension-1.0.jar": "pkg:maven/org.kohsuke/trilead-putty-extension@1.0",
|
||||
"/packages/hudson.war:WEB-INF/lib/trilead-ssh2-build212-hudson-5.jar": "pkg:maven/org.jvnet.hudson/trilead-ssh2@build212-hudson-5",
|
||||
"/packages/hudson.war:WEB-INF/lib/txw2-20070624.jar": "pkg:maven/txw2/txw2@20070624",
|
||||
"/packages/hudson.war:WEB-INF/lib/windows-remote-command-1.0.jar": "pkg:maven/org.jvnet.hudson/windows-remote-command@1.0",
|
||||
"/packages/hudson.war:WEB-INF/lib/winp-1.14.jar": "pkg:maven/org.jvnet.winp/winp@1.14",
|
||||
"/packages/hudson.war:WEB-INF/lib/wstx-asl-3.2.7.jar": "pkg:maven/wstx-asl/wstx-asl@3.2.7",
|
||||
// "/packages/hudson.war:WEB-INF/lib/xpp3_min-1.1.4c.jar": "pkg:maven/xpp3_min/xpp3_min@1.1.4c",
|
||||
// "/packages/hudson.war:WEB-INF/lib/xpp3-1.1.4c.jar": "pkg:maven/xpp3/xpp3@1.1.4c",
|
||||
"/packages/hudson.war:WEB-INF/lib/xstream-1.3.1-hudson-8.jar": "pkg:maven/org.jvnet.hudson/xstream@1.3.1-hudson-8",
|
||||
"/packages/hudson.war:WEB-INF/plugins/cvs.hpi": "pkg:maven/org.jvnet.hudson.plugins/cvs@1.2",
|
||||
"/packages/hudson.war:WEB-INF/plugins/maven-plugin.hpi:WEB-INF/lib/avalon-framework-4.1.3.jar": "pkg:maven/avalon-framework/avalon-framework@4.1.3",
|
||||
"/packages/hudson.war:WEB-INF/plugins/maven-plugin.hpi:WEB-INF/lib/classworlds-1.1.jar": "pkg:maven/org.codehaus.classworlds/classworlds@1.1",
|
||||
"/packages/hudson.war:WEB-INF/plugins/maven-plugin.hpi:WEB-INF/lib/commons-codec-1.4.jar": "pkg:maven/commons-codec/commons-codec@1.4",
|
||||
"/packages/hudson.war:WEB-INF/plugins/maven-plugin.hpi:WEB-INF/lib/commons-httpclient-3.1-rc1.jar": "pkg:maven/commons-httpclient/commons-httpclient@3.1-rc1",
|
||||
"/packages/hudson.war:WEB-INF/plugins/maven-plugin.hpi:WEB-INF/lib/commons-logging-1.1.jar": "pkg:maven/commons-logging/commons-logging@1.1",
|
||||
"/packages/hudson.war:WEB-INF/plugins/maven-plugin.hpi:WEB-INF/lib/doxia-sink-api-1.0-alpha-10.jar": "pkg:maven/org.apache.maven.doxia/doxia-sink-api@1.0-alpha-10",
|
||||
"/packages/hudson.war:WEB-INF/plugins/maven-plugin.hpi:WEB-INF/lib/jsch-0.1.27.jar": "pkg:maven/jsch/jsch@0.1.27",
|
||||
"/packages/hudson.war:WEB-INF/plugins/maven-plugin.hpi:WEB-INF/lib/log4j-1.2.9.jar": "pkg:maven/log4j/log4j@1.2.9",
|
||||
"/packages/hudson.war:WEB-INF/plugins/maven-plugin.hpi:WEB-INF/lib/logkit-1.0.1.jar": "pkg:maven/logkit/logkit@1.0.1",
|
||||
"/packages/hudson.war:WEB-INF/plugins/maven-plugin.hpi:WEB-INF/lib/maven-agent-1.390.jar": "pkg:maven/org.jvnet.hudson.main/maven-agent@1.390",
|
||||
"/packages/hudson.war:WEB-INF/plugins/maven-plugin.hpi:WEB-INF/lib/maven-artifact-2.0.9.jar": "pkg:maven/org.apache.maven/maven-artifact@2.0.9",
|
||||
"/packages/hudson.war:WEB-INF/plugins/maven-plugin.hpi:WEB-INF/lib/maven-artifact-manager-2.0.9.jar": "pkg:maven/org.apache.maven/maven-artifact-manager@2.0.9",
|
||||
"/packages/hudson.war:WEB-INF/plugins/maven-plugin.hpi:WEB-INF/lib/maven-core-2.0.9.jar": "pkg:maven/org.apache.maven/maven-core@2.0.9",
|
||||
"/packages/hudson.war:WEB-INF/plugins/maven-plugin.hpi:WEB-INF/lib/maven-embedder-2.0.4-hudson-1.jar": "pkg:maven/org.jvnet.hudson/maven-embedder@2.0.4-hudson-1",
|
||||
"/packages/hudson.war:WEB-INF/plugins/maven-plugin.hpi:WEB-INF/lib/maven-embedder-2.0.4.jar": "pkg:maven/org.apache.maven/maven-embedder@2.0.4",
|
||||
"/packages/hudson.war:WEB-INF/plugins/maven-plugin.hpi:WEB-INF/lib/maven-error-diagnostics-2.0.9.jar": "pkg:maven/org.apache.maven/maven-error-diagnostics@2.0.9",
|
||||
"/packages/hudson.war:WEB-INF/plugins/maven-plugin.hpi:WEB-INF/lib/maven-interceptor-1.390.jar": "pkg:maven/org.jvnet.hudson.main/maven-interceptor@1.390",
|
||||
"/packages/hudson.war:WEB-INF/plugins/maven-plugin.hpi:WEB-INF/lib/maven-model-2.0.9.jar": "pkg:maven/org.apache.maven/maven-model@2.0.9",
|
||||
"/packages/hudson.war:WEB-INF/plugins/maven-plugin.hpi:WEB-INF/lib/maven-monitor-2.0.9.jar": "pkg:maven/org.apache.maven/maven-monitor@2.0.9",
|
||||
"/packages/hudson.war:WEB-INF/plugins/maven-plugin.hpi:WEB-INF/lib/maven-plugin-api-2.0.9.jar": "pkg:maven/org.apache.maven/maven-plugin-api@2.0.9",
|
||||
"/packages/hudson.war:WEB-INF/plugins/maven-plugin.hpi:WEB-INF/lib/maven-plugin-descriptor-2.0.9.jar": "pkg:maven/org.apache.maven/maven-plugin-descriptor@2.0.9",
|
||||
"/packages/hudson.war:WEB-INF/plugins/maven-plugin.hpi:WEB-INF/lib/maven-plugin-parameter-documenter-2.0.9.jar": "pkg:maven/org.apache.maven/maven-plugin-parameter-documenter@2.0.9",
|
||||
"/packages/hudson.war:WEB-INF/plugins/maven-plugin.hpi:WEB-INF/lib/maven-plugin-registry-2.0.9.jar": "pkg:maven/org.apache.maven/maven-plugin-registry@2.0.9",
|
||||
"/packages/hudson.war:WEB-INF/plugins/maven-plugin.hpi:WEB-INF/lib/maven-profile-2.0.9.jar": "pkg:maven/org.apache.maven/maven-profile@2.0.9",
|
||||
"/packages/hudson.war:WEB-INF/plugins/maven-plugin.hpi:WEB-INF/lib/maven-project-2.0.9.jar": "pkg:maven/org.apache.maven/maven-project@2.0.9",
|
||||
"/packages/hudson.war:WEB-INF/plugins/maven-plugin.hpi:WEB-INF/lib/maven-reporting-api-2.0.9.jar": "pkg:maven/org.apache.maven.reporting/maven-reporting-api@2.0.9",
|
||||
"/packages/hudson.war:WEB-INF/plugins/maven-plugin.hpi:WEB-INF/lib/maven-repository-metadata-2.0.9.jar": "pkg:maven/org.apache.maven/maven-repository-metadata@2.0.9",
|
||||
"/packages/hudson.war:WEB-INF/plugins/maven-plugin.hpi:WEB-INF/lib/maven-settings-2.0.9.jar": "pkg:maven/org.apache.maven/maven-settings@2.0.9",
|
||||
"/packages/hudson.war:WEB-INF/plugins/maven-plugin.hpi:WEB-INF/lib/maven2.1-interceptor-1.2.jar": "pkg:maven/org.jvnet.hudson/maven2.1-interceptor@1.2",
|
||||
"/packages/hudson.war:WEB-INF/plugins/maven-plugin.hpi:WEB-INF/lib/plexus-container-default-1.0-alpha-9-stable-1.jar": "pkg:maven/org.codehaus.plexus/plexus-container-default@1.0-alpha-9-stable-1",
|
||||
"/packages/hudson.war:WEB-INF/plugins/maven-plugin.hpi:WEB-INF/lib/plexus-interactivity-api-1.0-alpha-4.jar": "pkg:maven/org.codehaus.plexus/plexus-interactivity-api@1.0-alpha-4",
|
||||
"/packages/hudson.war:WEB-INF/plugins/maven-plugin.hpi:WEB-INF/lib/plexus-utils-1.5.1.jar": "pkg:maven/org.codehaus.plexus/plexus-utils@1.5.1",
|
||||
"/packages/hudson.war:WEB-INF/plugins/maven-plugin.hpi:WEB-INF/lib/slide-webdavlib-2.1.jar": "pkg:maven/slide-webdavlib/slide-webdavlib@2.1",
|
||||
"/packages/hudson.war:WEB-INF/plugins/maven-plugin.hpi:WEB-INF/lib/wagon-file-1.0-beta-2.jar": "pkg:maven/org.apache.maven.wagon/wagon-file@1.0-beta-2",
|
||||
"/packages/hudson.war:WEB-INF/plugins/maven-plugin.hpi:WEB-INF/lib/wagon-http-lightweight-1.0-beta-2.jar": "pkg:maven/org.apache.maven.wagon/wagon-http-lightweight@1.0-beta-2",
|
||||
"/packages/hudson.war:WEB-INF/plugins/maven-plugin.hpi:WEB-INF/lib/wagon-http-shared-1.0-beta-2.jar": "pkg:maven/org.apache.maven.wagon/wagon-http-shared@1.0-beta-2",
|
||||
"/packages/hudson.war:WEB-INF/plugins/maven-plugin.hpi:WEB-INF/lib/wagon-provider-api-1.0-beta-2.jar": "pkg:maven/org.apache.maven.wagon/wagon-provider-api@1.0-beta-2",
|
||||
"/packages/hudson.war:WEB-INF/plugins/maven-plugin.hpi:WEB-INF/lib/wagon-ssh-1.0-beta-2.jar": "pkg:maven/org.apache.maven.wagon/wagon-ssh@1.0-beta-2",
|
||||
"/packages/hudson.war:WEB-INF/plugins/maven-plugin.hpi:WEB-INF/lib/wagon-ssh-common-1.0-beta-2.jar": "pkg:maven/org.apache.maven.wagon/wagon-ssh-common@1.0-beta-2",
|
||||
"/packages/hudson.war:WEB-INF/plugins/maven-plugin.hpi:WEB-INF/lib/wagon-ssh-external-1.0-beta-2.jar": "pkg:maven/org.apache.maven.wagon/wagon-ssh-external@1.0-beta-2",
|
||||
"/packages/hudson.war:WEB-INF/plugins/maven-plugin.hpi:WEB-INF/lib/wagon-webdav-1.0-beta-2-hudson-1.jar": "pkg:maven/org.jvnet.hudson/wagon-webdav@1.0-beta-2-hudson-1",
|
||||
"/packages/hudson.war:WEB-INF/plugins/maven-plugin.hpi:WEB-INF/lib/xml-im-exporter-1.1.jar": "pkg:maven/xml-im-exporter/xml-im-exporter@1.1",
|
||||
"/packages/hudson.war:WEB-INF/plugins/maven-plugin.hpi": "pkg:maven/org.jvnet.hudson.main/maven-plugin@1.390",
|
||||
"/packages/hudson.war:WEB-INF/plugins/ssh-slaves.hpi": "pkg:maven/org.jvnet.hudson.plugins/ssh-slaves@0.14",
|
||||
"/packages/hudson.war:WEB-INF/plugins/subversion.hpi:WEB-INF/lib/svnkit-1.3.4-hudson-2.jar": "pkg:maven/svnkit/svnkit@1.3.4-hudson-2",
|
||||
"/packages/hudson.war:WEB-INF/plugins/subversion.hpi": "pkg:maven/org.jvnet.hudson.plugins/subversion@1.20",
|
||||
"/packages/hudson.war:WEB-INF/remoting.jar:args4j:args4j": "pkg:maven/args4j/args4j@2.0.16",
|
||||
"/packages/hudson.war:WEB-INF/remoting.jar": "pkg:maven/org.jvnet.hudson.main/remoting@1.390",
|
||||
"/packages/hudson.war:WEB-INF/slave.jar:args4j:args4j": "pkg:maven/args4j/args4j@2.0.16",
|
||||
"/packages/hudson.war:WEB-INF/slave.jar:org.jvnet.hudson.main:remoting": "pkg:maven/org.jvnet.hudson.main/remoting@1.390",
|
||||
// "/packages/hudson.war:WEB-INF/slave.jar": "pkg:maven/org.jvnet.hudson.main/remoting@1.390",
|
||||
"/packages/hudson.war:winstone.jar": "pkg:maven/org.jvnet.hudson.winstone/winstone@0.9.10-hudson-24",
|
||||
"/packages/hudson.war": "pkg:maven/org.jvnet.hudson.main/hudson-war@1.390",
|
||||
"/packages/infinispan-core-11.0.4.Final.jar": "pkg:maven/org.infinispan/infinispan-core@11.0.4.Final",
|
||||
"/packages/jeecg-boot-common-3.6.0.jar": "pkg:maven/org.jeecgframework.boot/jeecg-boot-common@3.6.0",
|
||||
"/packages/jetty-client-9.4.31.v20200723.jar": "pkg:maven/org.eclipse.jetty/jetty-client@9.4.31.v20200723",
|
||||
"/packages/jetty-server-12.0.0.alpha3.jar": "pkg:maven/org.eclipse.jetty/jetty-server@12.0.0.alpha3",
|
||||
"/packages/jetty-setuid-java-1.0.4.jar": "pkg:maven/org.eclipse.jetty.toolchain.setuid/jetty-setuid-java@1.0.4",
|
||||
"/packages/jmdns-3.4.1.jar": "pkg:maven/javax.jmdns/jmdns@3.4.1",
|
||||
"/packages/jruby-stdlib-9.1.15.0.jar:META-INF/jruby.home/lib/ruby/stdlib/jopenssl.jar:rubygems:jruby-openssl": "pkg:maven/rubygems/jruby-openssl@0.9.21",
|
||||
"/packages/jruby-stdlib-9.1.15.0.jar:META-INF/jruby.home/lib/ruby/stdlib/org/bouncycastle/bcpkix-jdk15on/1.56/bcpkix-jdk15on-1.56.jar": "pkg:maven/org.bouncycastle/bcpkix-jdk15on@1.56",
|
||||
"/packages/jruby-stdlib-9.1.15.0.jar:META-INF/jruby.home/lib/ruby/stdlib/org/bouncycastle/bcprov-jdk15on/1.56/bcprov-jdk15on-1.56.jar": "pkg:maven/org.bouncycastle/bcprov-jdk15on@1.56",
|
||||
"/packages/jruby-stdlib-9.1.15.0.jar:META-INF/jruby.home/lib/ruby/stdlib/org/yaml/snakeyaml/1.18/snakeyaml-1.18.jar": "pkg:maven/org.yaml/snakeyaml@1.18",
|
||||
"/packages/jruby-stdlib-9.1.15.0.jar:META-INF/jruby.home/lib/ruby/stdlib/readline.jar:jline:jline": "pkg:maven/jline/jline@2.11",
|
||||
"/packages/jruby-stdlib-9.1.15.0.jar:META-INF/jruby.home/lib/ruby/stdlib/readline.jar:rubygems:jruby-readline": "pkg:maven/rubygems/jruby-readline@1.2.0",
|
||||
"/packages/jruby-stdlib-9.1.15.0.jar": "pkg:maven/org.jruby/jruby-stdlib@9.1.15.0",
|
||||
"/packages/jsch-0.1.55.jar": "pkg:maven/com.jcraft/jsch@0.1.55",
|
||||
"/packages/junit-4.13.1.jar": "pkg:maven/junit/junit@4.13.1",
|
||||
// "/packages/kafka_2.13-3.2.2.jar": "pkg:maven/org.apache.kafka/kafka_2.13@3.2.2",
|
||||
"/packages/keycloak-core-22.0.2.jar": "pkg:maven/org.keycloak/keycloak-core@22.0.2",
|
||||
"/packages/log4j-1.2.16.jar": "pkg:maven/log4j/log4j@1.2.16",
|
||||
"/packages/log4j-core-2.17.0.jar": "pkg:maven/org.apache.logging.log4j/log4j-core@2.17.0",
|
||||
"/packages/log4j-over-slf4j-1.7.36.jar": "pkg:maven/org.slf4j/log4j-over-slf4j@1.7.36",
|
||||
"/packages/manager-pojo-1.8.0.jar": "pkg:maven/org.apache.inlong/manager-pojo@1.8.0",
|
||||
"/packages/maven-shared-utils-3.2.1.jar": "pkg:maven/org.apache.maven.shared/maven-shared-utils@3.2.1",
|
||||
"/packages/mesos-1.7.1.jar": "pkg:maven/org.apache.mesos/mesos@1.7.1",
|
||||
"/packages/minio-8.3.8.jar": "pkg:maven/io.minio/minio@8.3.8",
|
||||
"/packages/ms-mcms-5.3.1.jar": "pkg:maven/net.mingsoft/ms-mcms@5.3.1",
|
||||
"/packages/my-app-1.jar:com.fasterxml:classmate": "pkg:maven/com.fasterxml/classmate@1.5.1",
|
||||
"/packages/my-app-1.jar:com.fasterxml.jackson.core:jackson-annotations": "pkg:maven/com.fasterxml.jackson.core/jackson-annotations@2.13.2",
|
||||
"/packages/my-app-1.jar:com.fasterxml.jackson.core:jackson-core": "pkg:maven/com.fasterxml.jackson.core/jackson-core@2.13.2",
|
||||
"/packages/my-app-1.jar:com.fasterxml.jackson.core:jackson-databind": "pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.13.0",
|
||||
"/packages/my-app-1.jar:com.google.errorprone:error_prone_annotations": "pkg:maven/com.google.errorprone/error_prone_annotations@2.0.18",
|
||||
"/packages/my-app-1.jar:com.google.guava:guava": "pkg:maven/com.google.guava/guava@23.0",
|
||||
"/packages/my-app-1.jar:com.google.j2objc:j2objc-annotations": "pkg:maven/com.google.j2objc/j2objc-annotations@1.1",
|
||||
"/packages/my-app-1.jar:com.hazelcast:hazelcast-kubernetes": "pkg:maven/com.hazelcast/hazelcast-kubernetes@1.5.4",
|
||||
"/packages/my-app-1.jar:com.hierynomus:asn-one": "pkg:maven/com.hierynomus/asn-one@0.5.0",
|
||||
"/packages/my-app-1.jar:com.typesafe.netty:netty-reactive-streams": "pkg:maven/com.typesafe.netty/netty-reactive-streams@2.0.5",
|
||||
"/packages/my-app-1.jar:commons-beanutils:commons-beanutils": "pkg:maven/commons-beanutils/commons-beanutils@1.9.2",
|
||||
"/packages/my-app-1.jar:commons-collections:commons-collections": "pkg:maven/commons-collections/commons-collections@3.2.2",
|
||||
"/packages/my-app-1.jar:commons-digester:commons-digester": "pkg:maven/commons-digester/commons-digester@1.8.1",
|
||||
"/packages/my-app-1.jar:commons-io:commons-io": "pkg:maven/commons-io/commons-io@2.8.0",
|
||||
"/packages/my-app-1.jar:commons-logging:commons-logging": "pkg:maven/commons-logging/commons-logging@1.2",
|
||||
"/packages/my-app-1.jar:commons-validator:commons-validator": "pkg:maven/commons-validator/commons-validator@1.5.1",
|
||||
"/packages/my-app-1.jar:io.netty:netty-buffer": "pkg:maven/io.netty/netty-buffer@4.1.52.Final",
|
||||
"/packages/my-app-1.jar:io.netty:netty-codec-dns": "pkg:maven/io.netty/netty-codec-dns@4.1.63.Final",
|
||||
"/packages/my-app-1.jar:io.netty:netty-codec-http": "pkg:maven/io.netty/netty-codec-http@4.1.63.Final",
|
||||
"/packages/my-app-1.jar:io.netty:netty-codec-socks": "pkg:maven/io.netty/netty-codec-socks@4.1.63.Final",
|
||||
"/packages/my-app-1.jar:io.netty:netty-codec": "pkg:maven/io.netty/netty-codec@4.1.52.Final",
|
||||
"/packages/my-app-1.jar:io.netty:netty-common": "pkg:maven/io.netty/netty-common@4.1.52.Final",
|
||||
"/packages/my-app-1.jar:io.netty:netty-handler-proxy": "pkg:maven/io.netty/netty-handler-proxy@4.1.63.Final",
|
||||
"/packages/my-app-1.jar:io.netty:netty-handler": "pkg:maven/io.netty/netty-handler@4.1.52.Final",
|
||||
"/packages/my-app-1.jar:io.netty:netty-resolver-dns-native-macos": "pkg:maven/io.netty/netty-resolver-dns-native-macos@4.1.63.Final",
|
||||
"/packages/my-app-1.jar:io.netty:netty-resolver-dns": "pkg:maven/io.netty/netty-resolver-dns@4.1.63.Final",
|
||||
"/packages/my-app-1.jar:io.netty:netty-resolver": "pkg:maven/io.netty/netty-resolver@4.1.52.Final",
|
||||
"/packages/my-app-1.jar:io.netty:netty-transport-native-epoll": "pkg:maven/io.netty/netty-transport-native-epoll@4.1.63.Final",
|
||||
"/packages/my-app-1.jar:io.netty:netty-transport-native-unix-common": "pkg:maven/io.netty/netty-transport-native-unix-common@4.1.63.Final",
|
||||
"/packages/my-app-1.jar:io.netty:netty-transport": "pkg:maven/io.netty/netty-transport@4.1.52.Final",
|
||||
"/packages/my-app-1.jar:io.prometheus:simpleclient_common": "pkg:maven/io.prometheus/simpleclient_common@0.9.0",
|
||||
"/packages/my-app-1.jar:io.prometheus:simpleclient": "pkg:maven/io.prometheus/simpleclient@0.9.0",
|
||||
"/packages/my-app-1.jar:io.vavr:vavr-match": "pkg:maven/io.vavr/vavr-match@0.10.2",
|
||||
"/packages/my-app-1.jar:io.vavr:vavr": "pkg:maven/io.vavr/vavr@0.10.2",
|
||||
"/packages/my-app-1.jar:jakarta.validation:jakarta.validation-api": "pkg:maven/jakarta.validation/jakarta.validation-api@2.0.2",
|
||||
"/packages/my-app-1.jar:javax.servlet:javax.servlet-api": "pkg:maven/javax.servlet/javax.servlet-api@3.1.0",
|
||||
"/packages/my-app-1.jar:org.apache.activemq.protobuf:activemq-protobuf": "pkg:maven/org.apache.activemq.protobuf/activemq-protobuf@1.1",
|
||||
"/packages/my-app-1.jar:org.apache.commons:commons-compress": "pkg:maven/org.apache.commons/commons-compress@1.21",
|
||||
"/packages/my-app-1.jar:org.apache.commons:commons-lang3": "pkg:maven/org.apache.commons/commons-lang3@3.10",
|
||||
"/packages/my-app-1.jar:org.apache.maven.shared:maven-shared-utils": "pkg:maven/org.apache.maven.shared/maven-shared-utils@3.3.4",
|
||||
"/packages/my-app-1.jar:org.codehaus.mojo:animal-sniffer-annotations": "pkg:maven/org.codehaus.mojo/animal-sniffer-annotations@1.14",
|
||||
"/packages/my-app-1.jar:org.eclipse.jetty:jetty-client": "pkg:maven/org.eclipse.jetty/jetty-client@9.4.43.v20210629",
|
||||
"/packages/my-app-1.jar:org.eclipse.jetty:jetty-http": "pkg:maven/org.eclipse.jetty/jetty-http@9.4.43.v20210629",
|
||||
"/packages/my-app-1.jar:org.eclipse.jetty:jetty-io": "pkg:maven/org.eclipse.jetty/jetty-io@9.4.43.v20210629",
|
||||
"/packages/my-app-1.jar:org.eclipse.jetty:jetty-server": "pkg:maven/org.eclipse.jetty/jetty-server@9.1.0.M0",
|
||||
"/packages/my-app-1.jar:org.eclipse.jetty:jetty-util": "pkg:maven/org.eclipse.jetty/jetty-util@9.4.43.v20210629",
|
||||
"/packages/my-app-1.jar:org.eclipse.jetty.http2:http2-common": "pkg:maven/org.eclipse.jetty.http2/http2-common@9.4.43.v20210629",
|
||||
"/packages/my-app-1.jar:org.eclipse.jetty.http2:http2-hpack": "pkg:maven/org.eclipse.jetty.http2/http2-hpack@9.4.43.v20210629",
|
||||
"/packages/my-app-1.jar:org.eclipse.jetty.toolchain.setuid:jetty-setuid-java": "pkg:maven/org.eclipse.jetty.toolchain.setuid/jetty-setuid-java@1.0.4",
|
||||
"/packages/my-app-1.jar:org.everit.json:org.everit.json.schema": "pkg:maven/org.everit.json/org.everit.json.schema@1.5.1",
|
||||
"/packages/my-app-1.jar:org.hibernate.validator:hibernate-validator": "pkg:maven/org.hibernate.validator/hibernate-validator@6.2.4.Final",
|
||||
"/packages/my-app-1.jar:org.jboss.logging:jboss-logging": "pkg:maven/org.jboss.logging/jboss-logging@3.4.1.Final",
|
||||
"/packages/my-app-1.jar:org.jctools:jctools-core": "pkg:maven/org.jctools/jctools-core@3.1.0",
|
||||
"/packages/my-app-1.jar:org.jetbrains:annotations": "pkg:maven/org.jetbrains/annotations@13.0",
|
||||
"/packages/my-app-1.jar:org.json:json": "pkg:maven/org.json/json@20160810",
|
||||
"/packages/my-app-1.jar:org.kohsuke:github-api": "pkg:maven/org.kohsuke/github-api@1.301",
|
||||
"/packages/my-app-1.jar:org.slf4j:log4j-over-slf4j": "pkg:maven/org.slf4j/log4j-over-slf4j@1.7.33",
|
||||
"/packages/my-app-1.jar:org.slf4j:slf4j-api": "pkg:maven/org.slf4j/slf4j-api@1.7.33",
|
||||
"/packages/my-app-1.jar:org.sonarsource.analyzer-commons:sonar-analyzer-test-commons": "pkg:maven/org.sonarsource.analyzer-commons/sonar-analyzer-test-commons@1.14.1.690",
|
||||
"/packages/my-app-1.jar:org.sonarsource.php:php-checks": "pkg:maven/org.sonarsource.php/php-checks@3.17.0.7439",
|
||||
"/packages/my-app-1.jar:org.sonarsource.php:php-frontend": "pkg:maven/org.sonarsource.php/php-frontend@3.17.0.7439",
|
||||
"/packages/my-app-1.jar:org.sonarsource.python:python-checks": "pkg:maven/org.sonarsource.python/python-checks@3.4.1.8066",
|
||||
"/packages/my-app-1.jar:org.sonarsource.python:python-frontend": "pkg:maven/org.sonarsource.python/python-frontend@3.4.1.8066",
|
||||
"/packages/my-app-1.jar:org.sonarsource.sslr:sslr-core": "pkg:maven/org.sonarsource.sslr/sslr-core@1.24.0.633",
|
||||
"/packages/my-app-1.jar": "pkg:maven/com.mycompany.app/my-app@1",
|
||||
"/packages/netty-reactive-streams-2.0.6.jar": "pkg:maven/com.typesafe.netty/netty-reactive-streams@2.0.6",
|
||||
"/packages/nifi-utils-1.12.0.jar": "pkg:maven/org.apache.nifi/nifi-utils@1.12.0",
|
||||
"/packages/nomad.hpi:WEB-INF/lib/annotations-13.0.jar": "pkg:maven/org.jetbrains/annotations@13.0",
|
||||
"/packages/nomad.hpi:WEB-INF/lib/gson-2.8.6.jar": "pkg:maven/com.google.code.gson/gson@2.8.6",
|
||||
"/packages/nomad.hpi:WEB-INF/lib/json-20200518.jar": "pkg:maven/org.json/json@20200518",
|
||||
"/packages/nomad.hpi:WEB-INF/lib/kotlin-stdlib-1.3.70.jar": "pkg:maven/kotlin-stdlib/kotlin-stdlib@1.3.70",
|
||||
"/packages/nomad.hpi:WEB-INF/lib/kotlin-stdlib-common-1.3.70.jar": "pkg:maven/kotlin-stdlib-common/kotlin-stdlib-common@1.3.70",
|
||||
"/packages/nomad.hpi:WEB-INF/lib/nomad.jar": "pkg:maven/org.jenkins-ci.plugins/nomad@0.7.4",
|
||||
"/packages/nomad.hpi:WEB-INF/lib/okhttp-4.5.0.jar": "pkg:maven/com.squareup.okhttp3/okhttp@4.5.0",
|
||||
"/packages/nomad.hpi:WEB-INF/lib/okio-2.5.0.jar": "pkg:maven/com.squareup.okio/okio@2.5.0",
|
||||
"/packages/nomad.hpi": "pkg:maven/org.jenkins-ci.plugins/nomad@0.7.4",
|
||||
"/packages/openmeetings-util-4.0.9.jar": "pkg:maven/org.apache.openmeetings/openmeetings-util@4.0.9",
|
||||
"/packages/org.eclipse.ant.core-3.7.0.jar": "pkg:maven/org.eclipse.platform/org.eclipse.ant.core@3.7.0",
|
||||
"/packages/org.eclipse.osgi-3.18.0.jar": "pkg:maven/org.eclipse.platform/org.eclipse.osgi@3.18.0",
|
||||
"/packages/org.everit.json.schema-1.5.1.jar": "pkg:maven/org.everit.json/org.everit.json.schema@1.5.1",
|
||||
"/packages/original-my-app-1.jar:com.fasterxml:classmate": "pkg:maven/com.fasterxml/classmate@1.5.1",
|
||||
"/packages/original-my-app-1.jar:com.fasterxml.jackson.core:jackson-annotations": "pkg:maven/com.fasterxml.jackson.core/jackson-annotations@2.13.2",
|
||||
"/packages/original-my-app-1.jar:com.fasterxml.jackson.core:jackson-core": "pkg:maven/com.fasterxml.jackson.core/jackson-core@2.13.2",
|
||||
"/packages/original-my-app-1.jar:com.fasterxml.jackson.core:jackson-databind": "pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.13.0",
|
||||
"/packages/original-my-app-1.jar:com.google.errorprone:error_prone_annotations": "pkg:maven/com.google.errorprone/error_prone_annotations@2.0.18",
|
||||
"/packages/original-my-app-1.jar:com.google.guava:guava": "pkg:maven/com.google.guava/guava@23.0",
|
||||
"/packages/original-my-app-1.jar:com.google.j2objc:j2objc-annotations": "pkg:maven/com.google.j2objc/j2objc-annotations@1.1",
|
||||
"/packages/original-my-app-1.jar:com.hazelcast:hazelcast-kubernetes": "pkg:maven/com.hazelcast/hazelcast-kubernetes@1.5.4",
|
||||
"/packages/original-my-app-1.jar:com.hierynomus:asn-one": "pkg:maven/com.hierynomus/asn-one@0.5.0",
|
||||
"/packages/original-my-app-1.jar:com.typesafe.netty:netty-reactive-streams": "pkg:maven/com.typesafe.netty/netty-reactive-streams@2.0.5",
|
||||
"/packages/original-my-app-1.jar:commons-beanutils:commons-beanutils": "pkg:maven/commons-beanutils/commons-beanutils@1.9.2",
|
||||
"/packages/original-my-app-1.jar:commons-collections:commons-collections": "pkg:maven/commons-collections/commons-collections@3.2.2",
|
||||
"/packages/original-my-app-1.jar:commons-digester:commons-digester": "pkg:maven/commons-digester/commons-digester@1.8.1",
|
||||
"/packages/original-my-app-1.jar:commons-io:commons-io": "pkg:maven/commons-io/commons-io@2.8.0",
|
||||
"/packages/original-my-app-1.jar:commons-logging:commons-logging": "pkg:maven/commons-logging/commons-logging@1.2",
|
||||
"/packages/original-my-app-1.jar:commons-validator:commons-validator": "pkg:maven/commons-validator/commons-validator@1.5.1",
|
||||
"/packages/original-my-app-1.jar:io.netty:netty-buffer": "pkg:maven/io.netty/netty-buffer@4.1.52.Final",
|
||||
"/packages/original-my-app-1.jar:io.netty:netty-codec-dns": "pkg:maven/io.netty/netty-codec-dns@4.1.63.Final",
|
||||
"/packages/original-my-app-1.jar:io.netty:netty-codec-http": "pkg:maven/io.netty/netty-codec-http@4.1.63.Final",
|
||||
"/packages/original-my-app-1.jar:io.netty:netty-codec-socks": "pkg:maven/io.netty/netty-codec-socks@4.1.63.Final",
|
||||
"/packages/original-my-app-1.jar:io.netty:netty-codec": "pkg:maven/io.netty/netty-codec@4.1.52.Final",
|
||||
"/packages/original-my-app-1.jar:io.netty:netty-common": "pkg:maven/io.netty/netty-common@4.1.52.Final",
|
||||
"/packages/original-my-app-1.jar:io.netty:netty-handler-proxy": "pkg:maven/io.netty/netty-handler-proxy@4.1.63.Final",
|
||||
"/packages/original-my-app-1.jar:io.netty:netty-handler": "pkg:maven/io.netty/netty-handler@4.1.52.Final",
|
||||
"/packages/original-my-app-1.jar:io.netty:netty-resolver-dns-native-macos": "pkg:maven/io.netty/netty-resolver-dns-native-macos@4.1.63.Final",
|
||||
"/packages/original-my-app-1.jar:io.netty:netty-resolver-dns": "pkg:maven/io.netty/netty-resolver-dns@4.1.63.Final",
|
||||
"/packages/original-my-app-1.jar:io.netty:netty-resolver": "pkg:maven/io.netty/netty-resolver@4.1.52.Final",
|
||||
"/packages/original-my-app-1.jar:io.netty:netty-transport-native-epoll": "pkg:maven/io.netty/netty-transport-native-epoll@4.1.63.Final",
|
||||
"/packages/original-my-app-1.jar:io.netty:netty-transport-native-unix-common": "pkg:maven/io.netty/netty-transport-native-unix-common@4.1.63.Final",
|
||||
"/packages/original-my-app-1.jar:io.netty:netty-transport": "pkg:maven/io.netty/netty-transport@4.1.52.Final",
|
||||
"/packages/original-my-app-1.jar:io.prometheus:simpleclient_common": "pkg:maven/io.prometheus/simpleclient_common@0.9.0",
|
||||
"/packages/original-my-app-1.jar:io.prometheus:simpleclient": "pkg:maven/io.prometheus/simpleclient@0.9.0",
|
||||
"/packages/original-my-app-1.jar:io.vavr:vavr-match": "pkg:maven/io.vavr/vavr-match@0.10.2",
|
||||
"/packages/original-my-app-1.jar:io.vavr:vavr": "pkg:maven/io.vavr/vavr@0.10.2",
|
||||
"/packages/original-my-app-1.jar:jakarta.validation:jakarta.validation-api": "pkg:maven/jakarta.validation/jakarta.validation-api@2.0.2",
|
||||
"/packages/original-my-app-1.jar:javax.servlet:javax.servlet-api": "pkg:maven/javax.servlet/javax.servlet-api@3.1.0",
|
||||
"/packages/original-my-app-1.jar:org.apache.activemq.protobuf:activemq-protobuf": "pkg:maven/org.apache.activemq.protobuf/activemq-protobuf@1.1",
|
||||
"/packages/original-my-app-1.jar:org.apache.commons:commons-compress": "pkg:maven/org.apache.commons/commons-compress@1.21",
|
||||
"/packages/original-my-app-1.jar:org.apache.commons:commons-lang3": "pkg:maven/org.apache.commons/commons-lang3@3.10",
|
||||
"/packages/original-my-app-1.jar:org.apache.maven.shared:maven-shared-utils": "pkg:maven/org.apache.maven.shared/maven-shared-utils@3.3.4",
|
||||
"/packages/original-my-app-1.jar:org.codehaus.mojo:animal-sniffer-annotations": "pkg:maven/org.codehaus.mojo/animal-sniffer-annotations@1.14",
|
||||
"/packages/original-my-app-1.jar:org.eclipse.jetty:jetty-client": "pkg:maven/org.eclipse.jetty/jetty-client@9.4.43.v20210629",
|
||||
"/packages/original-my-app-1.jar:org.eclipse.jetty:jetty-http": "pkg:maven/org.eclipse.jetty/jetty-http@9.4.43.v20210629",
|
||||
"/packages/original-my-app-1.jar:org.eclipse.jetty:jetty-io": "pkg:maven/org.eclipse.jetty/jetty-io@9.4.43.v20210629",
|
||||
"/packages/original-my-app-1.jar:org.eclipse.jetty:jetty-server": "pkg:maven/org.eclipse.jetty/jetty-server@9.1.0.M0",
|
||||
"/packages/original-my-app-1.jar:org.eclipse.jetty:jetty-util": "pkg:maven/org.eclipse.jetty/jetty-util@9.4.43.v20210629",
|
||||
"/packages/original-my-app-1.jar:org.eclipse.jetty.http2:http2-common": "pkg:maven/org.eclipse.jetty.http2/http2-common@9.4.43.v20210629",
|
||||
"/packages/original-my-app-1.jar:org.eclipse.jetty.http2:http2-hpack": "pkg:maven/org.eclipse.jetty.http2/http2-hpack@9.4.43.v20210629",
|
||||
"/packages/original-my-app-1.jar:org.eclipse.jetty.toolchain.setuid:jetty-setuid-java": "pkg:maven/org.eclipse.jetty.toolchain.setuid/jetty-setuid-java@1.0.4",
|
||||
"/packages/original-my-app-1.jar:org.everit.json:org.everit.json.schema": "pkg:maven/org.everit.json/org.everit.json.schema@1.5.1",
|
||||
"/packages/original-my-app-1.jar:org.hibernate.validator:hibernate-validator": "pkg:maven/org.hibernate.validator/hibernate-validator@6.2.4.Final",
|
||||
"/packages/original-my-app-1.jar:org.jboss.logging:jboss-logging": "pkg:maven/org.jboss.logging/jboss-logging@3.4.1.Final",
|
||||
"/packages/original-my-app-1.jar:org.jctools:jctools-core": "pkg:maven/org.jctools/jctools-core@3.1.0",
|
||||
"/packages/original-my-app-1.jar:org.jetbrains:annotations": "pkg:maven/org.jetbrains/annotations@13.0",
|
||||
"/packages/original-my-app-1.jar:org.json:json": "pkg:maven/org.json/json@20160810",
|
||||
"/packages/original-my-app-1.jar:org.kohsuke:github-api": "pkg:maven/org.kohsuke/github-api@1.301",
|
||||
"/packages/original-my-app-1.jar:org.slf4j:log4j-over-slf4j": "pkg:maven/org.slf4j/log4j-over-slf4j@1.7.33",
|
||||
"/packages/original-my-app-1.jar:org.slf4j:slf4j-api": "pkg:maven/org.slf4j/slf4j-api@1.7.33",
|
||||
"/packages/original-my-app-1.jar:org.sonarsource.analyzer-commons:sonar-analyzer-test-commons": "pkg:maven/org.sonarsource.analyzer-commons/sonar-analyzer-test-commons@1.14.1.690",
|
||||
"/packages/original-my-app-1.jar:org.sonarsource.php:php-checks": "pkg:maven/org.sonarsource.php/php-checks@3.17.0.7439",
|
||||
"/packages/original-my-app-1.jar:org.sonarsource.php:php-frontend": "pkg:maven/org.sonarsource.php/php-frontend@3.17.0.7439",
|
||||
"/packages/original-my-app-1.jar:org.sonarsource.python:python-checks": "pkg:maven/org.sonarsource.python/python-checks@3.4.1.8066",
|
||||
"/packages/original-my-app-1.jar:org.sonarsource.python:python-frontend": "pkg:maven/org.sonarsource.python/python-frontend@3.4.1.8066",
|
||||
"/packages/original-my-app-1.jar:org.sonarsource.sslr:sslr-core": "pkg:maven/org.sonarsource.sslr/sslr-core@1.24.0.633",
|
||||
"/packages/original-my-app-1.jar": "pkg:maven/com.mycompany.app/my-app@1",
|
||||
"/packages/php-frontend-3.9.0.6331.jar": "pkg:maven/org.sonarsource.php/php-frontend@3.9.0.6331",
|
||||
"/packages/postgresql-42.5.0.jar": "pkg:maven/org.postgresql/postgresql@42.5.0",
|
||||
"/packages/protobuf-java-3.21.6.jar": "pkg:maven/com.google.protobuf/protobuf-java@3.21.6",
|
||||
"/packages/python-frontend-3.24.0.10784.jar": "pkg:maven/org.sonarsource.python/python-frontend@3.24.0.10784",
|
||||
"/packages/ratpack-core-1.8.2.jar": "pkg:maven/io.ratpack/ratpack-core@1.8.2",
|
||||
"/packages/reactor-netty-core-1.0.35.jar": "pkg:maven/io.projectreactor.netty/reactor-netty-core@1.0.35",
|
||||
"/packages/reactor-netty-http-1.1.9.jar": "pkg:maven/io.projectreactor.netty/reactor-netty-http@1.1.9",
|
||||
"/packages/reactor-netty-incubator-quic-0.1.3.jar": "pkg:maven/io.projectreactor.netty.incubator/reactor-netty-incubator-quic@0.1.3",
|
||||
"/packages/resilience4j-prometheus-0.17.0.jar": "pkg:maven/io.github.resilience4j.prometheus/resilience4j-prometheus@0.17.0",
|
||||
"/packages/shiro-core-1.9.1.jar": "pkg:maven/org.apache.shiro/shiro-core@1.9.1",
|
||||
"/packages/solr-core-8.8.1.jar": "pkg:maven/org.apache.solr/solr-core@8.8.1",
|
||||
"/packages/spring-amqp-2.4.17.jar": "pkg:maven/org.springframework.amqp/spring-amqp@2.4.17",
|
||||
"/packages/spring-analytics-2.0.0.RELEASE.jar": "pkg:maven/org.springframework.analytics/spring-analytics@2.0.0.RELEASE",
|
||||
"/packages/spring-asm-3.0.7.RELEASE.jar": "pkg:maven/org.springframework/spring-asm@3.0.7.RELEASE",
|
||||
"/packages/spring-batch-core-4.2.1.RELEASE.jar": "pkg:maven/org.springframework.batch/spring-batch-core@4.2.1.RELEASE",
|
||||
"/packages/spring-boot-3.1.2.jar": "pkg:maven/org.springframework.boot/spring-boot@3.1.2",
|
||||
"/packages/spring-cloud-app-broker-core-1.6.1.jar": "pkg:maven/org.springframework.cloud/spring-cloud-app-broker-core@1.6.1",
|
||||
"/packages/spring-cql-1.5.11.RELEASE.jar": "pkg:maven/org.springframework.data/spring-cql@1.5.11.RELEASE",
|
||||
"/packages/spring-credhub-core-1.0.1.RELEASE.jar": "pkg:maven/org.springframework.credhub/spring-credhub-core@1.0.1.RELEASE",
|
||||
"/packages/spring-flex-1.0.3.RELEASE.jar": "pkg:maven/org.springframework.flex/spring-flex@1.0.3.RELEASE",
|
||||
"/packages/spring-graphql-1.2.2.jar": "pkg:maven/org.springframework.graphql/spring-graphql@1.2.2",
|
||||
"/packages/spring-hateoas-2.1.0.jar": "pkg:maven/org.springframework.hateoas/spring-hateoas@2.1.0",
|
||||
"/packages/spring-integration-amqp-6.0.5.jar": "pkg:maven/org.springframework.integration/spring-integration-amqp@6.0.5",
|
||||
"/packages/spring-kafka-3.0.9.jar": "pkg:maven/org.springframework.kafka/spring-kafka@3.0.9",
|
||||
"/packages/spring-security-core-6.0.2.jar": "pkg:maven/org.springframework.security/spring-security-core@6.0.2",
|
||||
"/packages/spring-security-kerberos-core-1.0.1.RELEASE.jar": "pkg:maven/org.springframework.security.kerberos/spring-security-kerberos-core@1.0.1.RELEASE",
|
||||
"/packages/spring-security-oauth-2.5.1.RELEASE.jar": "pkg:maven/org.springframework.security.oauth/spring-security-oauth@2.5.1.RELEASE",
|
||||
"/packages/spring-security-oauth2-autoconfigure-2.5.9.jar": "pkg:maven/org.springframework.security.oauth.boot/spring-security-oauth2-autoconfigure@2.5.9",
|
||||
"/packages/spring-security-saml2-core-1.0.10.RELEASE.jar": "pkg:maven/org.springframework.security.extensions/spring-security-saml2-core@1.0.10.RELEASE",
|
||||
"/packages/spring-session-core-3.0.0.jar": "pkg:maven/org.springframework.session/spring-session-core@3.0.0",
|
||||
"/packages/spring-social-core-1.1.2.RELEASE.jar": "pkg:maven/org.springframework.social/spring-social-core@1.1.2.RELEASE",
|
||||
"/packages/spring-vault-core-3.0.1.jar": "pkg:maven/org.springframework.vault/spring-vault-core@3.0.1",
|
||||
"/packages/spring-webmvc-3.1.4.RELEASE.jar": "pkg:maven/org.springframework/spring-webmvc@3.1.4.RELEASE",
|
||||
"/packages/spring-xml-3.0.3.RELEASE.jar": "pkg:maven/org.springframework.ws/spring-xml@3.0.3.RELEASE",
|
||||
"/packages/storm-core-1.2.2.jar:cheshire:cheshire": "pkg:maven/cheshire/cheshire@5.3.1",
|
||||
"/packages/storm-core-1.2.2.jar:clj-time:clj-time": "pkg:maven/clj-time/clj-time@0.8.0",
|
||||
"/packages/storm-core-1.2.2.jar:clout:clout": "pkg:maven/clout/clout@1.2.0",
|
||||
"/packages/storm-core-1.2.2.jar:com.fasterxml.jackson.core:jackson-core": "pkg:maven/com.fasterxml.jackson.core/jackson-core@2.9.4",
|
||||
"/packages/storm-core-1.2.2.jar:com.fasterxml.jackson.dataformat:jackson-dataformat-smile": "pkg:maven/com.fasterxml.jackson.dataformat/jackson-dataformat-smile@2.9.4",
|
||||
"/packages/storm-core-1.2.2.jar:com.google.guava:guava": "pkg:maven/com.google.guava/guava@16.0.1",
|
||||
"/packages/storm-core-1.2.2.jar:com.twitter:carbonite": "pkg:maven/com.twitter/carbonite@1.5.0",
|
||||
"/packages/storm-core-1.2.2.jar:commons-codec:commons-codec": "pkg:maven/commons-codec/commons-codec@1.6",
|
||||
"/packages/storm-core-1.2.2.jar:commons-collections:commons-collections": "pkg:maven/commons-collections/commons-collections@3.2.2",
|
||||
"/packages/storm-core-1.2.2.jar:commons-fileupload:commons-fileupload": "pkg:maven/commons-fileupload/commons-fileupload@1.3.2",
|
||||
"/packages/storm-core-1.2.2.jar:commons-io:commons-io": "pkg:maven/commons-io/commons-io@2.5",
|
||||
"/packages/storm-core-1.2.2.jar:commons-lang:commons-lang": "pkg:maven/commons-lang/commons-lang@2.5",
|
||||
"/packages/storm-core-1.2.2.jar:compojure:compojure": "pkg:maven/compojure/compojure@1.1.9",
|
||||
"/packages/storm-core-1.2.2.jar:hiccup:hiccup": "pkg:maven/hiccup/hiccup@0.3.6",
|
||||
"/packages/storm-core-1.2.2.jar:io.netty:netty": "pkg:maven/io.netty/netty@3.9.9.Final",
|
||||
"/packages/storm-core-1.2.2.jar:joda-time:joda-time": "pkg:maven/joda-time/joda-time@2.3",
|
||||
"/packages/storm-core-1.2.2.jar:metrics-clojure:metrics-clojure": "pkg:maven/metrics-clojure/metrics-clojure@2.5.1",
|
||||
"/packages/storm-core-1.2.2.jar:ns-tracker:ns-tracker": "pkg:maven/ns-tracker/ns-tracker@0.2.2",
|
||||
"/packages/storm-core-1.2.2.jar:org.apache.commons:commons-compress": "pkg:maven/org.apache.commons/commons-compress@1.4.1",
|
||||
"/packages/storm-core-1.2.2.jar:org.apache.commons:commons-exec": "pkg:maven/org.apache.commons/commons-exec@1.1",
|
||||
"/packages/storm-core-1.2.2.jar:org.apache.curator:curator-client": "pkg:maven/org.apache.curator/curator-client@4.0.1",
|
||||
"/packages/storm-core-1.2.2.jar:org.apache.curator:curator-framework": "pkg:maven/org.apache.curator/curator-framework@4.0.1",
|
||||
"/packages/storm-core-1.2.2.jar:org.apache.curator:curator-recipes": "pkg:maven/org.apache.curator/curator-recipes@4.0.1",
|
||||
"/packages/storm-core-1.2.2.jar:org.apache.hadoop:hadoop-auth": "pkg:maven/org.apache.hadoop/hadoop-auth@2.6.1",
|
||||
"/packages/storm-core-1.2.2.jar:org.apache.httpcomponents:httpclient": "pkg:maven/org.apache.httpcomponents/httpclient@4.3.3",
|
||||
"/packages/storm-core-1.2.2.jar:org.apache.httpcomponents:httpcore": "pkg:maven/org.apache.httpcomponents/httpcore@4.4.1",
|
||||
"/packages/storm-core-1.2.2.jar:org.clojure:java.jmx": "pkg:maven/org.clojure/java.jmx@0.3.1",
|
||||
"/packages/storm-core-1.2.2.jar:org.clojure:math.numeric-tower": "pkg:maven/org.clojure/math.numeric-tower@0.0.1",
|
||||
"/packages/storm-core-1.2.2.jar:org.clojure:tools.cli": "pkg:maven/org.clojure/tools.cli@0.2.4",
|
||||
"/packages/storm-core-1.2.2.jar:org.clojure:tools.logging": "pkg:maven/org.clojure/tools.logging@0.2.3",
|
||||
"/packages/storm-core-1.2.2.jar:org.clojure:tools.macro": "pkg:maven/org.clojure/tools.macro@0.1.0",
|
||||
"/packages/storm-core-1.2.2.jar:org.clojure:tools.namespace": "pkg:maven/org.clojure/tools.namespace@0.2.4",
|
||||
"/packages/storm-core-1.2.2.jar:org.eclipse.jetty:jetty-client": "pkg:maven/org.eclipse.jetty/jetty-client@7.6.13.v20130916",
|
||||
"/packages/storm-core-1.2.2.jar:org.eclipse.jetty:jetty-continuation": "pkg:maven/org.eclipse.jetty/jetty-continuation@7.6.13.v20130916",
|
||||
"/packages/storm-core-1.2.2.jar:org.eclipse.jetty:jetty-http": "pkg:maven/org.eclipse.jetty/jetty-http@7.6.13.v20130916",
|
||||
"/packages/storm-core-1.2.2.jar:org.eclipse.jetty:jetty-io": "pkg:maven/org.eclipse.jetty/jetty-io@7.6.13.v20130916",
|
||||
"/packages/storm-core-1.2.2.jar:org.eclipse.jetty:jetty-security": "pkg:maven/org.eclipse.jetty/jetty-security@7.6.13.v20130916",
|
||||
"/packages/storm-core-1.2.2.jar:org.eclipse.jetty:jetty-server": "pkg:maven/org.eclipse.jetty/jetty-server@7.6.13.v20130916",
|
||||
"/packages/storm-core-1.2.2.jar:org.eclipse.jetty:jetty-servlet": "pkg:maven/org.eclipse.jetty/jetty-servlet@7.6.13.v20130916",
|
||||
"/packages/storm-core-1.2.2.jar:org.eclipse.jetty:jetty-servlets": "pkg:maven/org.eclipse.jetty/jetty-servlets@7.6.13.v20130916",
|
||||
"/packages/storm-core-1.2.2.jar:org.eclipse.jetty:jetty-util": "pkg:maven/org.eclipse.jetty/jetty-util@7.6.13.v20130916",
|
||||
"/packages/storm-core-1.2.2.jar:org.jgrapht:jgrapht-core": "pkg:maven/org.jgrapht/jgrapht-core@0.9.0",
|
||||
"/packages/storm-core-1.2.2.jar:org.yaml:snakeyaml": "pkg:maven/org.yaml/snakeyaml@1.11",
|
||||
"/packages/storm-core-1.2.2.jar:ring:ring-codec": "pkg:maven/ring/ring-codec@1.0.0",
|
||||
"/packages/storm-core-1.2.2.jar:ring:ring-core": "pkg:maven/ring/ring-core@1.3.1",
|
||||
"/packages/storm-core-1.2.2.jar:ring:ring-devel": "pkg:maven/ring/ring-devel@1.3.1",
|
||||
"/packages/storm-core-1.2.2.jar:ring:ring-jetty-adapter": "pkg:maven/ring/ring-jetty-adapter@1.3.1",
|
||||
"/packages/storm-core-1.2.2.jar:ring:ring-json": "pkg:maven/ring/ring-json@0.3.1",
|
||||
"/packages/storm-core-1.2.2.jar:ring:ring-servlet": "pkg:maven/ring/ring-servlet@1.3.1",
|
||||
"/packages/storm-core-1.2.2.jar": "pkg:maven/org.apache.storm/storm-core@1.2.2",
|
||||
"/packages/tapestry-core-5.8.1.jar": "pkg:maven/org.apache.tapestry/tapestry-core@5.8.1",
|
||||
"/packages/tika-core-1.26.jar": "pkg:maven/org.apache.tika/tika-core@1.26",
|
||||
"/packages/tomcat-catalina-11.0.0-M1.jar": "pkg:maven/org.apache.tomcat/tomcat-catalina@11.0.0-M1",
|
||||
"/packages/tomcat-embed-core-11.0.0-M7.jar": "pkg:maven/org.apache.tomcat.embed/tomcat-embed-core@11.0.0-M7",
|
||||
"/packages/TwilioNotifier.hpi:WEB-INF/lib/commons-codec-1.2.jar": "pkg:maven/commons-codec/commons-codec@1.2",
|
||||
"/packages/TwilioNotifier.hpi:WEB-INF/lib/commons-httpclient-3.1.jar": "pkg:maven/org.apache/commons-httpclient@3.1",
|
||||
"/packages/TwilioNotifier.hpi:WEB-INF/lib/commons-logging-1.0.4.jar": "pkg:maven/commons-logging/commons-logging@1.0.4",
|
||||
"/packages/TwilioNotifier.hpi:WEB-INF/lib/log4j-1.2.9.jar": "pkg:maven/log4j/log4j@1.2.9",
|
||||
"/packages/TwilioNotifier.hpi:WEB-INF/lib/sdk-3.0.jar:commons-codec:commons-codec": "pkg:maven/commons-codec/commons-codec@1.4",
|
||||
"/packages/TwilioNotifier.hpi:WEB-INF/lib/sdk-3.0.jar:commons-lang:commons-lang": "pkg:maven/commons-lang/commons-lang@2.5",
|
||||
"/packages/TwilioNotifier.hpi:WEB-INF/lib/sdk-3.0.jar:commons-logging:commons-logging": "pkg:maven/commons-logging/commons-logging@1.1.1",
|
||||
"/packages/TwilioNotifier.hpi:WEB-INF/lib/sdk-3.0.jar:org.apache.httpcomponents:httpclient": "pkg:maven/org.apache.httpcomponents/httpclient@4.1.1",
|
||||
"/packages/TwilioNotifier.hpi:WEB-INF/lib/sdk-3.0.jar:org.apache.httpcomponents:httpcore": "pkg:maven/org.apache.httpcomponents/httpcore@4.1",
|
||||
"/packages/TwilioNotifier.hpi:WEB-INF/lib/sdk-3.0.jar:org.easymock:easymock": "pkg:maven/org.easymock/easymock@2.4",
|
||||
"/packages/TwilioNotifier.hpi": "pkg:maven/com.twilio.jenkins/TwilioNotifier@0.2.1",
|
||||
"/packages/undertow-core-2.3.4.Final.jar": "pkg:maven/io.undertow/undertow-core@2.3.4.Final",
|
||||
"/packages/vaadin-client-8.11.3.jar": "pkg:maven/com.vaadin/vaadin-client@8.11.3",
|
||||
"/packages/velocity-1.7.jar": "pkg:maven/org.apache.velocity/velocity@1.7",
|
||||
"/packages/vertx-web-4.3.7.jar": "pkg:maven/io.vertx/vertx-web@4.3.7",
|
||||
"/packages/wicket-core-9.2.0.jar": "pkg:maven/org.apache.wicket/wicket-core@9.2.0",
|
||||
"/packages/xalan-2.7.2.jar": "pkg:maven/xalan/xalan@2.7.2",
|
||||
"/packages/xmlpull-1.1.3.1.jar": "pkg:maven/xmlpull/xmlpull@1.1.3.1",
|
||||
// "/packages/xpp3_min-1.1.4c.jar": "pkg:maven/xpp3/xpp3_min@1.1.4c",
|
||||
"/packages/xstream-1.4.11.1.jar": "pkg:maven/com.thoughtworks.xstream/xstream@1.4.11.1",
|
||||
"/packages/xstream-1.4.19.jar": "pkg:maven/com.thoughtworks.xstream/xstream@1.4.19",
|
||||
"/packages/xwiki-commons-xml-15.1.jar": "pkg:maven/org.xwiki.commons/xwiki-commons-xml@15.1",
|
||||
"/packages/xwiki-platform-oldcore-15.3.jar": "pkg:maven/org.xwiki.platform/xwiki-platform-oldcore@15.3",
|
||||
"/packages/zookeeper-3.7.1.jar": "pkg:maven/org.apache.zookeeper/zookeeper@3.7.1",
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user