mirror of
https://github.com/anchore/syft.git
synced 2025-11-17 08:23:15 +01:00
Consider DLL claims for dependencies of .NET packages from deps.json (#3822)
* consider child dll claims for .NET packages from deps.json Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com> * make dll claim propagation configurable Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com> --------- Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
This commit is contained in:
parent
2dd9d583af
commit
df18edf905
@ -170,6 +170,7 @@ func (cfg Catalog) ToPackagesConfig() pkgcataloging.Config {
|
||||
Dotnet: dotnet.DefaultCatalogerConfig().
|
||||
WithDepPackagesMustHaveDLL(cfg.Dotnet.DepPackagesMustHaveDLL).
|
||||
WithDepPackagesMustClaimDLL(cfg.Dotnet.DepPackagesMustClaimDLL).
|
||||
WithPropagateDLLClaimsToParents(cfg.Dotnet.PropagateDLLClaimsToParents).
|
||||
WithRelaxDLLClaimsWhenBundlingDetected(cfg.Dotnet.RelaxDLLClaimsWhenBundlingDetected),
|
||||
Golang: golang.DefaultCatalogerConfig().
|
||||
WithSearchLocalModCacheLicenses(*multiLevelOption(false, enrichmentEnabled(cfg.Enrich, task.Go, task.Golang), cfg.Golang.SearchLocalModCacheLicenses)).
|
||||
|
||||
@ -10,6 +10,8 @@ type dotnetConfig struct {
|
||||
|
||||
DepPackagesMustClaimDLL bool `mapstructure:"dep-packages-must-claim-dll" json:"dep-packages-must-claim-dll" yaml:"dep-packages-must-claim-dll"`
|
||||
|
||||
PropagateDLLClaimsToParents bool `mapstructure:"propagate-dll-claims-to-parents" json:"propagate-dll-claims-to-parents" yaml:"propagate-dll-claims-to-parents"`
|
||||
|
||||
RelaxDLLClaimsWhenBundlingDetected bool `mapstructure:"relax-dll-claims-when-bundling-detected" json:"relax-dll-claims-when-bundling-detected" yaml:"relax-dll-claims-when-bundling-detected"`
|
||||
}
|
||||
|
||||
@ -18,8 +20,9 @@ var _ interface {
|
||||
} = (*dotnetConfig)(nil)
|
||||
|
||||
func (o *dotnetConfig) DescribeFields(descriptions clio.FieldDescriptionSet) {
|
||||
descriptions.Add(&o.DepPackagesMustHaveDLL, `only keep dep.json packages which an executable on disk can be found for`)
|
||||
descriptions.Add(&o.DepPackagesMustClaimDLL, `only keep dep.json packages which have a runtime/resource DLL claimed in the deps.json targets section (but not necessarily found on disk)`)
|
||||
descriptions.Add(&o.DepPackagesMustHaveDLL, `only keep dep.json packages which an executable on disk is found. The package is also included if a DLL is found for any child package, even if the package itself does not have a DLL.`)
|
||||
descriptions.Add(&o.DepPackagesMustClaimDLL, `only keep dep.json packages which have a runtime/resource DLL claimed in the deps.json targets section (but not necessarily found on disk). The package is also included if any child package claims a DLL, even if the package itself does not claim a DLL.`)
|
||||
descriptions.Add(&o.PropagateDLLClaimsToParents, `treat DLL claims or on-disk evidence for child packages as DLL claims or on-disk evidence for any parent package`)
|
||||
descriptions.Add(&o.RelaxDLLClaimsWhenBundlingDetected, `show all packages from the deps.json if bundling tooling is present as a dependency (e.g. ILRepack)`)
|
||||
}
|
||||
|
||||
@ -28,6 +31,7 @@ func defaultDotnetConfig() dotnetConfig {
|
||||
return dotnetConfig{
|
||||
DepPackagesMustHaveDLL: def.DepPackagesMustHaveDLL,
|
||||
DepPackagesMustClaimDLL: def.DepPackagesMustClaimDLL,
|
||||
PropagateDLLClaimsToParents: def.PropagateDLLClaimsToParents,
|
||||
RelaxDLLClaimsWhenBundlingDetected: def.RelaxDLLClaimsWhenBundlingDetected,
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,8 +2,9 @@ package licenses
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/stretchr/testify/require"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestSetContextLicenseScanner(t *testing.T) {
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
package dotnet
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/scylladb/go-set/strset"
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/anchore/syft/syft/artifact"
|
||||
@ -119,6 +119,10 @@ func TestCataloger(t *testing.T) {
|
||||
}
|
||||
net8AppExpectedDepPkgs = append(net8AppExpectedDepPkgs, net8AppExpectedDepPkgsWithoutUnpairedDlls...)
|
||||
|
||||
var net8AppExpectedDepPkgsWithRuntime []string
|
||||
net8AppExpectedDepPkgsWithRuntime = append(net8AppExpectedDepPkgsWithRuntime, net8AppExpectedDepPkgs...)
|
||||
net8AppExpectedDepPkgsWithRuntime = append(net8AppExpectedDepPkgsWithRuntime, "Microsoft.NETCore.App.Runtime.linux-x64 @ 8.0.14 (/usr/share/dotnet/shared/Microsoft.NETCore.App/8.0.14/Microsoft.NETCore.App.deps.json)")
|
||||
|
||||
// app binaries (always dlls)
|
||||
net8AppBinaryOnlyPkgs := []string{
|
||||
"Humanizer @ 2.14.1.48190 (/app/Humanizer.dll)",
|
||||
@ -280,11 +284,17 @@ func TestCataloger(t *testing.T) {
|
||||
net8AppDepOnlyRelationships = append(net8AppDepOnlyRelationships, net8AppDepOnlyRelationshipsWithoutHumanizer...)
|
||||
net8AppDepOnlyRelationships = append(net8AppDepOnlyRelationships, humanizerToAppDepsRelationship)
|
||||
|
||||
var net8AppDepOnlyRelationshipsWithRuntime []string
|
||||
net8AppDepOnlyRelationshipsWithRuntime = append(net8AppDepOnlyRelationshipsWithRuntime, net8AppDepOnlyRelationships...)
|
||||
net8AppDepOnlyRelationshipsWithRuntime = append(net8AppDepOnlyRelationshipsWithRuntime,
|
||||
"Microsoft.NETCore.App.Runtime.linux-x64 @ 8.0.14 (/usr/share/dotnet/shared/Microsoft.NETCore.App/8.0.14/Microsoft.NETCore.App.deps.json) [dependency-of] dotnetapp @ 1.0.0 (/app/dotnetapp.deps.json)",
|
||||
)
|
||||
|
||||
var net8AppExpectedDepRelationships []string
|
||||
net8AppExpectedDepRelationships = append(net8AppExpectedDepRelationships, net8AppDepOnlyRelationships...)
|
||||
|
||||
var net8AppExpectedDepSelfContainedPkgs []string
|
||||
net8AppExpectedDepSelfContainedPkgs = append(net8AppExpectedDepSelfContainedPkgs, net8AppExpectedDepPkgsWithoutUnpairedDlls...)
|
||||
net8AppExpectedDepSelfContainedPkgs = append(net8AppExpectedDepSelfContainedPkgs, net8AppExpectedDepPkgs...)
|
||||
net8AppExpectedDepSelfContainedPkgs = append(net8AppExpectedDepSelfContainedPkgs,
|
||||
// add the CLR runtime packages...
|
||||
"runtimepack.Microsoft.NETCore.App.Runtime.win-x64 @ 8.0.14 (/app/dotnetapp.deps.json)",
|
||||
@ -298,7 +308,7 @@ func TestCataloger(t *testing.T) {
|
||||
)
|
||||
|
||||
var net8AppExpectedDepSelfContainedRelationships []string
|
||||
net8AppExpectedDepSelfContainedRelationships = append(net8AppExpectedDepSelfContainedRelationships, net8AppDepOnlyRelationshipsWithoutHumanizer...)
|
||||
net8AppExpectedDepSelfContainedRelationships = append(net8AppExpectedDepSelfContainedRelationships, net8AppDepOnlyRelationships...)
|
||||
net8AppExpectedDepSelfContainedRelationships = append(net8AppExpectedDepSelfContainedRelationships,
|
||||
// add the CLR runtime relationships...
|
||||
"runtimepack.Microsoft.NETCore.App.Runtime.win-x64 @ 8.0.14 (/app/dotnetapp.deps.json) [dependency-of] dotnetapp @ 1.0.0 (/app/dotnetapp.deps.json)",
|
||||
@ -706,36 +716,20 @@ func TestCataloger(t *testing.T) {
|
||||
assertion: assertAllDepEntriesWithoutExecutables,
|
||||
},
|
||||
{
|
||||
name: "combined cataloger",
|
||||
fixture: "image-net8-app",
|
||||
cataloger: NewDotnetDepsBinaryCataloger(DefaultCatalogerConfig()),
|
||||
|
||||
// if we don't care about DLL claims in the deps.json, then this is right
|
||||
//expectedPkgs: net8AppExpectedDepPkgs,
|
||||
//expectedRels: net8AppExpectedDepRelationships,
|
||||
|
||||
// we care about DLL claims in the deps.json, so the main application inherits all relationships to/from humanizer
|
||||
expectedPkgs: net8AppExpectedDepPkgsWithoutUnpairedDlls,
|
||||
expectedRels: replaceAll(net8AppDepOnlyRelationshipsWithoutHumanizer, "Humanizer @ 2.14.1", "dotnetapp @ 1.0.0"),
|
||||
|
||||
assertion: assertAlmostAllDepEntriesWithExecutables, // important! this is what makes this case different from the previous one... dep entries have attached executables
|
||||
name: "combined cataloger",
|
||||
fixture: "image-net8-app",
|
||||
cataloger: NewDotnetDepsBinaryCataloger(DefaultCatalogerConfig()),
|
||||
expectedPkgs: net8AppExpectedDepPkgs,
|
||||
expectedRels: net8AppDepOnlyRelationships,
|
||||
assertion: assertAlmostAllDepEntriesWithExecutables, // important! this is what makes this case different from the previous one... dep entries have attached executables
|
||||
},
|
||||
{
|
||||
name: "combined cataloger (with runtime)",
|
||||
fixture: "image-net8-app-with-runtime",
|
||||
cataloger: NewDotnetDepsBinaryCataloger(DefaultCatalogerConfig()),
|
||||
expectedPkgs: func() []string {
|
||||
pkgs := net8AppExpectedDepPkgsWithoutUnpairedDlls
|
||||
pkgs = append(pkgs, "Microsoft.NETCore.App.Runtime.linux-x64 @ 8.0.14 (/usr/share/dotnet/shared/Microsoft.NETCore.App/8.0.14/Microsoft.NETCore.App.deps.json)")
|
||||
return pkgs
|
||||
}(),
|
||||
expectedRels: func() []string {
|
||||
x := replaceAll(net8AppDepOnlyRelationshipsWithoutHumanizer, "Humanizer @ 2.14.1", "dotnetapp @ 1.0.0")
|
||||
// the main application should also have a relationship to the runtime package
|
||||
x = append(x, "Microsoft.NETCore.App.Runtime.linux-x64 @ 8.0.14 (/usr/share/dotnet/shared/Microsoft.NETCore.App/8.0.14/Microsoft.NETCore.App.deps.json) [dependency-of] dotnetapp @ 1.0.0 (/app/dotnetapp.deps.json)")
|
||||
return x
|
||||
}(),
|
||||
assertion: assertAccurateNetRuntimePackage,
|
||||
name: "combined cataloger (with runtime)",
|
||||
fixture: "image-net8-app-with-runtime",
|
||||
cataloger: NewDotnetDepsBinaryCataloger(DefaultCatalogerConfig()),
|
||||
expectedPkgs: net8AppExpectedDepPkgsWithRuntime,
|
||||
expectedRels: net8AppDepOnlyRelationshipsWithRuntime,
|
||||
assertion: assertAccurateNetRuntimePackage,
|
||||
},
|
||||
{
|
||||
name: "combined cataloger (with runtime, no deps.json anywhere)",
|
||||
@ -923,11 +917,7 @@ func TestCataloger(t *testing.T) {
|
||||
fixture: "image-net8-app-self-contained",
|
||||
cataloger: NewDotnetDepsCataloger(),
|
||||
expectedPkgs: net8AppExpectedDepsSelfContainedPkgs,
|
||||
expectedRels: func() []string {
|
||||
x := net8AppExpectedDepSelfContainedRelationships
|
||||
x = append(x, humanizerToAppDepsRelationship)
|
||||
return x
|
||||
}(),
|
||||
expectedRels: net8AppExpectedDepSelfContainedRelationships,
|
||||
},
|
||||
{
|
||||
name: "combined cataloger (self-contained)",
|
||||
@ -935,13 +925,8 @@ func TestCataloger(t *testing.T) {
|
||||
cataloger: NewDotnetDepsBinaryCataloger(DefaultCatalogerConfig()),
|
||||
// we care about DLL claims in the deps.json, so the main application inherits all relationships to/from humarizer
|
||||
expectedPkgs: net8AppExpectedDepSelfContainedPkgs,
|
||||
expectedRels: func() []string {
|
||||
x := replaceAll(net8AppExpectedDepSelfContainedRelationships, "Humanizer @ 2.14.1", "dotnetapp @ 1.0.0")
|
||||
// the main application also has a dependency on the runtime package
|
||||
x = append(x, "runtimepack.Microsoft.NETCore.App.Runtime.win-x64 @ 8.0.14 (/app/dotnetapp.deps.json) [dependency-of] dotnetapp @ 1.0.0 (/app/dotnetapp.deps.json)")
|
||||
return x
|
||||
}(),
|
||||
assertion: assertAccurateNetRuntimePackage,
|
||||
expectedRels: net8AppExpectedDepSelfContainedRelationships,
|
||||
assertion: assertAccurateNetRuntimePackage,
|
||||
},
|
||||
{
|
||||
name: "pe cataloger (self-contained)",
|
||||
@ -1004,6 +989,8 @@ func TestCataloger(t *testing.T) {
|
||||
fixture: "image-net2-app",
|
||||
cataloger: NewDotnetDepsBinaryCataloger(DefaultCatalogerConfig()),
|
||||
expectedPkgs: []string{
|
||||
"Microsoft.NETCore.App @ 2.2.8 (/usr/share/dotnet/shared/Microsoft.NETCore.App/2.2.8/Microsoft.NETCore.App.deps.json)",
|
||||
"Microsoft.NETCore.DotNetHostPolicy @ 2.2.8 (/usr/share/dotnet/shared/Microsoft.NETCore.App/2.2.8/Microsoft.NETCore.App.deps.json)",
|
||||
"Serilog @ 2.10.0 (/app/helloworld.deps.json)",
|
||||
"Serilog.Sinks.Console @ 4.0.1 (/app/helloworld.deps.json)",
|
||||
"helloworld @ 1.0.0 (/app/helloworld.deps.json)",
|
||||
@ -1011,10 +998,13 @@ func TestCataloger(t *testing.T) {
|
||||
"runtime.linux-x64.Microsoft.NETCore.DotNetHostPolicy @ 2.2.8 (/usr/share/dotnet/shared/Microsoft.NETCore.App/2.2.8/Microsoft.NETCore.App.deps.json)", // a compile target reference
|
||||
},
|
||||
expectedRels: []string{
|
||||
"Microsoft.NETCore.DotNetHostPolicy @ 2.2.8 (/usr/share/dotnet/shared/Microsoft.NETCore.App/2.2.8/Microsoft.NETCore.App.deps.json) [dependency-of] Microsoft.NETCore.App @ 2.2.8 (/usr/share/dotnet/shared/Microsoft.NETCore.App/2.2.8/Microsoft.NETCore.App.deps.json)",
|
||||
"Serilog @ 2.10.0 (/app/helloworld.deps.json) [dependency-of] Serilog.Sinks.Console @ 4.0.1 (/app/helloworld.deps.json)",
|
||||
"Serilog @ 2.10.0 (/app/helloworld.deps.json) [dependency-of] helloworld @ 1.0.0 (/app/helloworld.deps.json)",
|
||||
"Serilog.Sinks.Console @ 4.0.1 (/app/helloworld.deps.json) [dependency-of] helloworld @ 1.0.0 (/app/helloworld.deps.json)",
|
||||
"runtime.linux-x64.Microsoft.NETCore.App @ 2.2.8 (/usr/share/dotnet/shared/Microsoft.NETCore.App/2.2.8/Microsoft.NETCore.App.deps.json) [dependency-of] Microsoft.NETCore.App @ 2.2.8 (/usr/share/dotnet/shared/Microsoft.NETCore.App/2.2.8/Microsoft.NETCore.App.deps.json)",
|
||||
"runtime.linux-x64.Microsoft.NETCore.App @ 2.2.8 (/usr/share/dotnet/shared/Microsoft.NETCore.App/2.2.8/Microsoft.NETCore.App.deps.json) [dependency-of] helloworld @ 1.0.0 (/app/helloworld.deps.json)",
|
||||
"runtime.linux-x64.Microsoft.NETCore.DotNetHostPolicy @ 2.2.8 (/usr/share/dotnet/shared/Microsoft.NETCore.App/2.2.8/Microsoft.NETCore.App.deps.json) [dependency-of] Microsoft.NETCore.DotNetHostPolicy @ 2.2.8 (/usr/share/dotnet/shared/Microsoft.NETCore.App/2.2.8/Microsoft.NETCore.App.deps.json)",
|
||||
},
|
||||
assertion: assertAccurateNetRuntimePackage,
|
||||
},
|
||||
@ -1037,6 +1027,25 @@ func TestCataloger(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestDotnetDepsCataloger_regressions(t *testing.T) {
|
||||
|
||||
assertPackages := func(mustHave []string, mustNotHave []string) func(t *testing.T, pkgs []pkg.Package, relationships []artifact.Relationship) {
|
||||
expected := strset.New(mustHave...)
|
||||
notExpected := strset.New(mustNotHave...)
|
||||
return func(t *testing.T, pkgs []pkg.Package, relationships []artifact.Relationship) {
|
||||
|
||||
for _, p := range pkgs {
|
||||
expected.Remove(p.Name)
|
||||
if notExpected.Has(p.Name) {
|
||||
t.Errorf("unexpected package: %s", p.Name)
|
||||
}
|
||||
}
|
||||
if expected.IsEmpty() {
|
||||
return
|
||||
}
|
||||
t.Errorf("missing packages: %s", expected.List())
|
||||
}
|
||||
}
|
||||
|
||||
cases := []struct {
|
||||
name string
|
||||
fixture string
|
||||
@ -1074,18 +1083,56 @@ func TestDotnetDepsCataloger_regressions(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "compile target reference",
|
||||
name: "indirect packages references",
|
||||
fixture: "image-net8-compile-target",
|
||||
cataloger: NewDotnetDepsBinaryCataloger(DefaultCatalogerConfig()),
|
||||
assertion: func(t *testing.T, pkgs []pkg.Package, relationships []artifact.Relationship) {
|
||||
// ensure we find the DotNetNuke.Core package (which is using the compile target reference)
|
||||
for _, p := range pkgs {
|
||||
if p.Name == "DotNetNuke.Core" {
|
||||
return
|
||||
}
|
||||
}
|
||||
t.Error("expected to find DotNetNuke.Core package")
|
||||
},
|
||||
assertion: assertPackages(
|
||||
[]string{
|
||||
"DotNetNuke.Core", // uses a compile target reference in the deps.json
|
||||
"Umbraco.Cms", // this is the parent of other packages which do have DLLs included (even though it does not have any DLLs)
|
||||
},
|
||||
[]string{
|
||||
"StyleCop.Analyzers", // this is a development tool
|
||||
"Microsoft.NET.Test.Sdk", // this is a development tool
|
||||
"jQuery", // has no DLLs but has javascript assets
|
||||
},
|
||||
),
|
||||
},
|
||||
{
|
||||
name: "not propagating claims",
|
||||
fixture: "image-net8-compile-target",
|
||||
cataloger: NewDotnetDepsBinaryCataloger(DefaultCatalogerConfig().WithPropagateDLLClaimsToParents(false)),
|
||||
assertion: assertPackages(
|
||||
[]string{
|
||||
"DotNetNuke.Core", // uses a compile target reference in the deps.json
|
||||
|
||||
},
|
||||
[]string{
|
||||
"Umbraco.Cms", // this is the parent of other packages which do have DLLs included (even though it does not have any DLLs)
|
||||
"StyleCop.Analyzers", // this is a development tool
|
||||
"Microsoft.NET.Test.Sdk", // this is a development tool under the debug configuration (we build the release configuration)
|
||||
"jQuery", // has no DLLs but has javascript assets -- this is bad behavior (as we want to detect this)
|
||||
},
|
||||
),
|
||||
},
|
||||
{
|
||||
name: "not requiring claims finds jquery",
|
||||
fixture: "image-net8-compile-target",
|
||||
cataloger: NewDotnetDepsBinaryCataloger(CatalogerConfig{
|
||||
DepPackagesMustHaveDLL: false,
|
||||
DepPackagesMustClaimDLL: false,
|
||||
PropagateDLLClaimsToParents: false,
|
||||
RelaxDLLClaimsWhenBundlingDetected: false,
|
||||
}),
|
||||
assertion: assertPackages(
|
||||
[]string{
|
||||
"jQuery", // has no DLLs but has javascript assets
|
||||
"StyleCop.Analyzers", // this is a development tool -- this is bad behavior (since we should not detect this), but cannot be helped
|
||||
},
|
||||
[]string{
|
||||
"Microsoft.NET.Test.Sdk", // this is a development tool under the debug configuration (we build the release configuration)
|
||||
},
|
||||
),
|
||||
},
|
||||
}
|
||||
for _, tt := range cases {
|
||||
@ -1475,11 +1522,3 @@ func extractMatchingPackage(t *testing.T, name string, pkgs []pkg.Package) pkg.P
|
||||
t.Fatalf("expected to find package %s", name)
|
||||
return pkg.Package{}
|
||||
}
|
||||
|
||||
func replaceAll(ss []string, find, replace string) []string {
|
||||
var results []string
|
||||
for _, s := range ss {
|
||||
results = append(results, strings.ReplaceAll(s, find, replace))
|
||||
}
|
||||
return results
|
||||
}
|
||||
|
||||
@ -8,6 +8,9 @@ type CatalogerConfig struct {
|
||||
// This does not require such claimed DLLs to exist on disk. The behavior of this
|
||||
DepPackagesMustClaimDLL bool `mapstructure:"dep-packages-must-claim-dll" json:"dep-packages-must-claim-dll" yaml:"dep-packages-must-claim-dll"`
|
||||
|
||||
// PropagateDLLClaimsToParents allows for deps.json packages to be included if any child (transitive) package claims a DLL. This applies to both the claims configuration and evidence-on-disk configurations.
|
||||
PropagateDLLClaimsToParents bool `mapstructure:"propagate-dll-claims-to-parents" json:"propagate-dll-claims-to-parents" yaml:"propagate-dll-claims-to-parents"`
|
||||
|
||||
// RelaxDLLClaimsWhenBundlingDetected will look for indications of IL bundle tooling via deps.json package names
|
||||
// and, if found (and this config option is enabled), will relax the DepPackagesMustClaimDLL value to `false` only in those cases.
|
||||
RelaxDLLClaimsWhenBundlingDetected bool `mapstructure:"relax-dll-claims-when-bundling-detected" json:"relax-dll-claims-when-bundling-detected" yaml:"relax-dll-claims-when-bundling-detected"`
|
||||
@ -28,10 +31,16 @@ func (c CatalogerConfig) WithRelaxDLLClaimsWhenBundlingDetected(relax bool) Cata
|
||||
return c
|
||||
}
|
||||
|
||||
func (c CatalogerConfig) WithPropagateDLLClaimsToParents(propagate bool) CatalogerConfig {
|
||||
c.PropagateDLLClaimsToParents = propagate
|
||||
return c
|
||||
}
|
||||
|
||||
func DefaultCatalogerConfig() CatalogerConfig {
|
||||
return CatalogerConfig{
|
||||
DepPackagesMustHaveDLL: false,
|
||||
DepPackagesMustClaimDLL: true,
|
||||
PropagateDLLClaimsToParents: true,
|
||||
RelaxDLLClaimsWhenBundlingDetected: true,
|
||||
}
|
||||
}
|
||||
|
||||
@ -111,7 +111,7 @@ func (c depsBinaryCataloger) Catalog(_ context.Context, resolver file.Resolver)
|
||||
runtimePkgs = append(runtimePkgs, &rtp)
|
||||
}
|
||||
|
||||
// create a relationship from every runtime package to every root package
|
||||
// create a relationship from every runtime package to every root package...
|
||||
for _, root := range roots {
|
||||
for _, runtimePkg := range runtimePkgs {
|
||||
relationships = append(relationships, artifact.Relationship{
|
||||
@ -122,7 +122,8 @@ func (c depsBinaryCataloger) Catalog(_ context.Context, resolver file.Resolver)
|
||||
}
|
||||
}
|
||||
|
||||
return pkgs, relationships, unknowns
|
||||
// in the process of creating root-to-runtime relationships, we may have created duplicate relationships. Use the relationship index to deduplicate.
|
||||
return pkgs, relationship.NewIndex(relationships...).All(), unknowns
|
||||
}
|
||||
|
||||
var runtimeDLLPathPattern = regexp.MustCompile(`/Microsoft\.NETCore\.App/(?P<version>\d+\.\d+\.\d+)/[^/]+\.dll`)
|
||||
@ -267,15 +268,14 @@ func packagesFromLogicalDepsJSON(doc logicalDepsJSON, config CatalogerConfig) (*
|
||||
continue
|
||||
}
|
||||
lp := doc.PackagesByNameVersion[nameVersion]
|
||||
if config.DepPackagesMustHaveDLL && len(lp.Executables) == 0 {
|
||||
if config.DepPackagesMustHaveDLL && !lp.FoundDLLs(config.PropagateDLLClaimsToParents) {
|
||||
// could not find a paired DLL and the user required this...
|
||||
skippedDepPkgs[nameVersion] = lp
|
||||
continue
|
||||
}
|
||||
|
||||
claimsDLLs := len(lp.RuntimePathsByRelativeDLLPath) > 0 || len(lp.ResourcePathsByRelativeDLLPath) > 0 || len(lp.CompilePathsByRelativeDLLPath) > 0 || len(lp.NativePaths.List()) > 0
|
||||
|
||||
if config.DepPackagesMustClaimDLL && !claimsDLLs {
|
||||
// check to see if we should skip this package because it does not claim a DLL (or has not dependency that claims a DLL)
|
||||
if config.DepPackagesMustClaimDLL && !lp.ClaimsDLLs(config.PropagateDLLClaimsToParents) {
|
||||
if config.RelaxDLLClaimsWhenBundlingDetected && !doc.BundlingDetected || !config.RelaxDLLClaimsWhenBundlingDetected {
|
||||
// could not find a runtime or resource path and the user required this...
|
||||
// and there is no evidence of a bundler in the dependencies (e.g. ILRepack)
|
||||
|
||||
@ -84,6 +84,12 @@ type logicalDepsJSONPackage struct {
|
||||
Targets *depsTarget
|
||||
Library *depsLibrary
|
||||
|
||||
// anyChildClaimsDLLs is a flag that indicates if any of the children of this package claim a DLL associated with them in the deps.json.
|
||||
anyChildClaimsDLLs bool
|
||||
|
||||
// anyChildHasDLLs is a flag that indicates if any of the children of this package have a DLL associated with them (found on disk).
|
||||
anyChildHasDLLs bool
|
||||
|
||||
// RuntimePathsByRelativeDLLPath is a map of the relative path to the DLL relative to the deps.json file
|
||||
// to the target path as described in the deps.json target entry under "runtime".
|
||||
RuntimePathsByRelativeDLLPath map[string]string
|
||||
@ -107,6 +113,34 @@ type logicalDepsJSONPackage struct {
|
||||
Executables []logicalPE
|
||||
}
|
||||
|
||||
func (l *logicalDepsJSONPackage) dependencyNameVersions() []string {
|
||||
if l.Targets == nil {
|
||||
return nil
|
||||
}
|
||||
var results []string
|
||||
for name, version := range l.Targets.Dependencies {
|
||||
results = append(results, createNameAndVersion(name, version))
|
||||
}
|
||||
return results
|
||||
}
|
||||
|
||||
// ClaimsDLLs indicates if this package has any DLLs associated with it (directly or indirectly with a dependency).
|
||||
func (l *logicalDepsJSONPackage) ClaimsDLLs(includeChildren bool) bool {
|
||||
selfClaim := len(l.RuntimePathsByRelativeDLLPath) > 0 || len(l.ResourcePathsByRelativeDLLPath) > 0 || len(l.CompilePathsByRelativeDLLPath) > 0 || len(l.NativePaths.List()) > 0
|
||||
if !includeChildren {
|
||||
return selfClaim
|
||||
}
|
||||
return selfClaim || l.anyChildClaimsDLLs
|
||||
}
|
||||
|
||||
func (l *logicalDepsJSONPackage) FoundDLLs(includeChildren bool) bool {
|
||||
selfClaim := len(l.Executables) > 0
|
||||
if !includeChildren {
|
||||
return selfClaim
|
||||
}
|
||||
return selfClaim || l.anyChildHasDLLs
|
||||
}
|
||||
|
||||
type logicalDepsJSON struct {
|
||||
Location file.Location
|
||||
RuntimeTarget runtimeTarget
|
||||
@ -199,6 +233,8 @@ func getLogicalDepsJSON(deps depsJSON) logicalDepsJSON {
|
||||
if !bundlingDetected && knownBundlers.Has(name) {
|
||||
bundlingDetected = true
|
||||
}
|
||||
p.anyChildClaimsDLLs = searchForDLLClaims(packageMap, p.dependencyNameVersions()...)
|
||||
p.anyChildHasDLLs = searchForDLLEvidence(packageMap, p.dependencyNameVersions()...)
|
||||
packages[p.NameVersion] = *p
|
||||
}
|
||||
|
||||
@ -211,6 +247,47 @@ func getLogicalDepsJSON(deps depsJSON) logicalDepsJSON {
|
||||
}
|
||||
}
|
||||
|
||||
type visitorFunc func(p *logicalDepsJSONPackage) bool
|
||||
|
||||
// searchForDLLEvidence recursively searches for executables found for any of the given nameVersions and children recursively.
|
||||
func searchForDLLEvidence(packageMap map[string]*logicalDepsJSONPackage, nameVersions ...string) bool {
|
||||
return traverseDependencies(packageMap, func(p *logicalDepsJSONPackage) bool {
|
||||
return p.FoundDLLs(true)
|
||||
}, nameVersions...)
|
||||
}
|
||||
|
||||
// searchForDLLClaims recursively searches for DLL claims in the deps.json for any of the given nameVersions and children recursively.
|
||||
func searchForDLLClaims(packageMap map[string]*logicalDepsJSONPackage, nameVersions ...string) bool {
|
||||
return traverseDependencies(packageMap, func(p *logicalDepsJSONPackage) bool {
|
||||
return p.ClaimsDLLs(true)
|
||||
}, nameVersions...)
|
||||
}
|
||||
|
||||
func traverseDependencies(packageMap map[string]*logicalDepsJSONPackage, visitor visitorFunc, nameVersions ...string) bool {
|
||||
if len(nameVersions) == 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
for _, nameVersion := range nameVersions {
|
||||
if p, ok := packageMap[nameVersion]; ok {
|
||||
if visitor(p) {
|
||||
return true
|
||||
}
|
||||
|
||||
var children []string
|
||||
for name, version := range p.Targets.Dependencies {
|
||||
children = append(children, createNameAndVersion(name, version))
|
||||
}
|
||||
|
||||
if traverseDependencies(packageMap, visitor, children...) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
var libPathPattern = regexp.MustCompile(`^(?:runtimes/[^/]+/)?lib/net[^/]+/(?P<targetPath>.+)`)
|
||||
|
||||
// trimLibPrefix removes prefixes like "lib/net6.0/" or "runtimes/linux-arm/lib/netcoreapp2.2/" from a path.
|
||||
|
||||
@ -196,9 +196,8 @@ func extractNameAndVersion(nameVersion string) (name, version string) {
|
||||
return
|
||||
}
|
||||
|
||||
func createNameAndVersion(name, version string) (nameVersion string) {
|
||||
nameVersion = fmt.Sprintf("%s/%s", name, version)
|
||||
return
|
||||
func createNameAndVersion(name, version string) string {
|
||||
return fmt.Sprintf("%s/%s", name, version)
|
||||
}
|
||||
|
||||
func packageURL(m pkg.DotnetDepsEntry) string {
|
||||
|
||||
@ -6,8 +6,7 @@ COPY src/helloworld.csproj .
|
||||
RUN dotnet restore -r $RUNTIME
|
||||
|
||||
COPY src/*.cs .
|
||||
|
||||
RUN dotnet publish -c Release --no-restore -o /app
|
||||
RUN dotnet publish -c Release -r $RUNTIME --self-contained false -o /app
|
||||
|
||||
# note: we're not using a runtime here to make testing easier... so you cannot run this container and expect it to work
|
||||
# we do this to keep the test assertions small since the don't want to include the several other runtime packages
|
||||
|
||||
@ -1,4 +1,6 @@
|
||||
using System;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
|
||||
namespace HelloWorld
|
||||
{
|
||||
@ -6,7 +8,22 @@ namespace HelloWorld
|
||||
{
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
Console.WriteLine("Hello World!");
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
var app = builder.Build();
|
||||
|
||||
// configure the HTTP request pipeline
|
||||
if (!app.Environment.IsDevelopment())
|
||||
{
|
||||
app.UseExceptionHandler("/Error");
|
||||
}
|
||||
|
||||
// enable serving static files (including jQuery)
|
||||
app.UseStaticFiles();
|
||||
|
||||
app.MapGet("/", () => "Hello World!");
|
||||
|
||||
Console.WriteLine("Application starting...");
|
||||
app.Run();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -8,17 +8,51 @@
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="DotNetNuke.Core" Version="9.9.1"/>
|
||||
|
||||
<!-- jQuery wraps the javascript library, so no DLLs -->
|
||||
<PackageReference Include="jQuery" Version="3.4.1" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.Razor" Version="2.2.0" />
|
||||
|
||||
<!-- ChakraCore is an open source Javascript engine with a C API -->
|
||||
<PackageReference Include="Microsoft.ChakraCore" Version="1.11.24">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
|
||||
<!-- Nuget.CommandLine is a command line tool for managing NuGet packages -->
|
||||
<PackageReference Include="Nuget.CommandLine" Version="6.3.1">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
|
||||
<!-- Umbraco.Cms has dependencies with software, but itself has no DLLs -->
|
||||
<PackageReference Include="Umbraco.Cms" Version="11.3.0" />
|
||||
|
||||
<!-- For code analysis/style checking, only needed during development -->
|
||||
<PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.435" PrivateAssets="All" />
|
||||
|
||||
<!-- For unit testing, only needed during development -->
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" Condition="'$(Configuration)' == 'Debug'" PrivateAssets="All" />
|
||||
|
||||
</ItemGroup>
|
||||
|
||||
<!-- create directories if they don't exist -->
|
||||
<Target Name="CreateWwwroot" BeforeTargets="PrepareForPublish">
|
||||
<MakeDir Directories="$(PublishDir)wwwroot\lib\jquery" />
|
||||
</Target>
|
||||
|
||||
<!-- explicitly copy jQuery files during publish phase -->
|
||||
<Target Name="CopyJQueryToPublishOutput" AfterTargets="CreateWwwroot" BeforeTargets="ComputeFilesToPublish">
|
||||
<ItemGroup>
|
||||
<!-- find jQuery files in the packages folder -->
|
||||
<JQueryFiles Include="$(NuGetPackageRoot)\jquery\3.4.1\Content\Scripts\*.js" />
|
||||
|
||||
<!-- add these to the publish output -->
|
||||
<ResolvedFileToPublish Include="@(JQueryFiles)">
|
||||
<RelativePath>wwwroot\lib\jquery\%(Filename)%(Extension)</RelativePath>
|
||||
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
|
||||
</ResolvedFileToPublish>
|
||||
</ItemGroup>
|
||||
</Target>
|
||||
|
||||
</Project>
|
||||
Loading…
x
Reference in New Issue
Block a user