mirror of
https://github.com/anchore/syft.git
synced 2026-02-12 10:36:45 +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().
|
Dotnet: dotnet.DefaultCatalogerConfig().
|
||||||
WithDepPackagesMustHaveDLL(cfg.Dotnet.DepPackagesMustHaveDLL).
|
WithDepPackagesMustHaveDLL(cfg.Dotnet.DepPackagesMustHaveDLL).
|
||||||
WithDepPackagesMustClaimDLL(cfg.Dotnet.DepPackagesMustClaimDLL).
|
WithDepPackagesMustClaimDLL(cfg.Dotnet.DepPackagesMustClaimDLL).
|
||||||
|
WithPropagateDLLClaimsToParents(cfg.Dotnet.PropagateDLLClaimsToParents).
|
||||||
WithRelaxDLLClaimsWhenBundlingDetected(cfg.Dotnet.RelaxDLLClaimsWhenBundlingDetected),
|
WithRelaxDLLClaimsWhenBundlingDetected(cfg.Dotnet.RelaxDLLClaimsWhenBundlingDetected),
|
||||||
Golang: golang.DefaultCatalogerConfig().
|
Golang: golang.DefaultCatalogerConfig().
|
||||||
WithSearchLocalModCacheLicenses(*multiLevelOption(false, enrichmentEnabled(cfg.Enrich, task.Go, task.Golang), cfg.Golang.SearchLocalModCacheLicenses)).
|
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"`
|
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"`
|
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)
|
} = (*dotnetConfig)(nil)
|
||||||
|
|
||||||
func (o *dotnetConfig) DescribeFields(descriptions clio.FieldDescriptionSet) {
|
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.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)`)
|
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)`)
|
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{
|
return dotnetConfig{
|
||||||
DepPackagesMustHaveDLL: def.DepPackagesMustHaveDLL,
|
DepPackagesMustHaveDLL: def.DepPackagesMustHaveDLL,
|
||||||
DepPackagesMustClaimDLL: def.DepPackagesMustClaimDLL,
|
DepPackagesMustClaimDLL: def.DepPackagesMustClaimDLL,
|
||||||
|
PropagateDLLClaimsToParents: def.PropagateDLLClaimsToParents,
|
||||||
RelaxDLLClaimsWhenBundlingDetected: def.RelaxDLLClaimsWhenBundlingDetected,
|
RelaxDLLClaimsWhenBundlingDetected: def.RelaxDLLClaimsWhenBundlingDetected,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,8 +2,9 @@ package licenses
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestSetContextLicenseScanner(t *testing.T) {
|
func TestSetContextLicenseScanner(t *testing.T) {
|
||||||
|
|||||||
@ -1,9 +1,9 @@
|
|||||||
package dotnet
|
package dotnet
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"strings"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/scylladb/go-set/strset"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
|
||||||
"github.com/anchore/syft/syft/artifact"
|
"github.com/anchore/syft/syft/artifact"
|
||||||
@ -119,6 +119,10 @@ func TestCataloger(t *testing.T) {
|
|||||||
}
|
}
|
||||||
net8AppExpectedDepPkgs = append(net8AppExpectedDepPkgs, net8AppExpectedDepPkgsWithoutUnpairedDlls...)
|
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)
|
// app binaries (always dlls)
|
||||||
net8AppBinaryOnlyPkgs := []string{
|
net8AppBinaryOnlyPkgs := []string{
|
||||||
"Humanizer @ 2.14.1.48190 (/app/Humanizer.dll)",
|
"Humanizer @ 2.14.1.48190 (/app/Humanizer.dll)",
|
||||||
@ -280,11 +284,17 @@ func TestCataloger(t *testing.T) {
|
|||||||
net8AppDepOnlyRelationships = append(net8AppDepOnlyRelationships, net8AppDepOnlyRelationshipsWithoutHumanizer...)
|
net8AppDepOnlyRelationships = append(net8AppDepOnlyRelationships, net8AppDepOnlyRelationshipsWithoutHumanizer...)
|
||||||
net8AppDepOnlyRelationships = append(net8AppDepOnlyRelationships, humanizerToAppDepsRelationship)
|
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
|
var net8AppExpectedDepRelationships []string
|
||||||
net8AppExpectedDepRelationships = append(net8AppExpectedDepRelationships, net8AppDepOnlyRelationships...)
|
net8AppExpectedDepRelationships = append(net8AppExpectedDepRelationships, net8AppDepOnlyRelationships...)
|
||||||
|
|
||||||
var net8AppExpectedDepSelfContainedPkgs []string
|
var net8AppExpectedDepSelfContainedPkgs []string
|
||||||
net8AppExpectedDepSelfContainedPkgs = append(net8AppExpectedDepSelfContainedPkgs, net8AppExpectedDepPkgsWithoutUnpairedDlls...)
|
net8AppExpectedDepSelfContainedPkgs = append(net8AppExpectedDepSelfContainedPkgs, net8AppExpectedDepPkgs...)
|
||||||
net8AppExpectedDepSelfContainedPkgs = append(net8AppExpectedDepSelfContainedPkgs,
|
net8AppExpectedDepSelfContainedPkgs = append(net8AppExpectedDepSelfContainedPkgs,
|
||||||
// add the CLR runtime packages...
|
// add the CLR runtime packages...
|
||||||
"runtimepack.Microsoft.NETCore.App.Runtime.win-x64 @ 8.0.14 (/app/dotnetapp.deps.json)",
|
"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
|
var net8AppExpectedDepSelfContainedRelationships []string
|
||||||
net8AppExpectedDepSelfContainedRelationships = append(net8AppExpectedDepSelfContainedRelationships, net8AppDepOnlyRelationshipsWithoutHumanizer...)
|
net8AppExpectedDepSelfContainedRelationships = append(net8AppExpectedDepSelfContainedRelationships, net8AppDepOnlyRelationships...)
|
||||||
net8AppExpectedDepSelfContainedRelationships = append(net8AppExpectedDepSelfContainedRelationships,
|
net8AppExpectedDepSelfContainedRelationships = append(net8AppExpectedDepSelfContainedRelationships,
|
||||||
// add the CLR runtime relationships...
|
// 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)",
|
"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,
|
assertion: assertAllDepEntriesWithoutExecutables,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "combined cataloger",
|
name: "combined cataloger",
|
||||||
fixture: "image-net8-app",
|
fixture: "image-net8-app",
|
||||||
cataloger: NewDotnetDepsBinaryCataloger(DefaultCatalogerConfig()),
|
cataloger: NewDotnetDepsBinaryCataloger(DefaultCatalogerConfig()),
|
||||||
|
expectedPkgs: net8AppExpectedDepPkgs,
|
||||||
// if we don't care about DLL claims in the deps.json, then this is right
|
expectedRels: net8AppDepOnlyRelationships,
|
||||||
//expectedPkgs: net8AppExpectedDepPkgs,
|
assertion: assertAlmostAllDepEntriesWithExecutables, // important! this is what makes this case different from the previous one... dep entries have attached executables
|
||||||
//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 (with runtime)",
|
name: "combined cataloger (with runtime)",
|
||||||
fixture: "image-net8-app-with-runtime",
|
fixture: "image-net8-app-with-runtime",
|
||||||
cataloger: NewDotnetDepsBinaryCataloger(DefaultCatalogerConfig()),
|
cataloger: NewDotnetDepsBinaryCataloger(DefaultCatalogerConfig()),
|
||||||
expectedPkgs: func() []string {
|
expectedPkgs: net8AppExpectedDepPkgsWithRuntime,
|
||||||
pkgs := net8AppExpectedDepPkgsWithoutUnpairedDlls
|
expectedRels: net8AppDepOnlyRelationshipsWithRuntime,
|
||||||
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)")
|
assertion: assertAccurateNetRuntimePackage,
|
||||||
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, no deps.json anywhere)",
|
name: "combined cataloger (with runtime, no deps.json anywhere)",
|
||||||
@ -923,11 +917,7 @@ func TestCataloger(t *testing.T) {
|
|||||||
fixture: "image-net8-app-self-contained",
|
fixture: "image-net8-app-self-contained",
|
||||||
cataloger: NewDotnetDepsCataloger(),
|
cataloger: NewDotnetDepsCataloger(),
|
||||||
expectedPkgs: net8AppExpectedDepsSelfContainedPkgs,
|
expectedPkgs: net8AppExpectedDepsSelfContainedPkgs,
|
||||||
expectedRels: func() []string {
|
expectedRels: net8AppExpectedDepSelfContainedRelationships,
|
||||||
x := net8AppExpectedDepSelfContainedRelationships
|
|
||||||
x = append(x, humanizerToAppDepsRelationship)
|
|
||||||
return x
|
|
||||||
}(),
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "combined cataloger (self-contained)",
|
name: "combined cataloger (self-contained)",
|
||||||
@ -935,13 +925,8 @@ func TestCataloger(t *testing.T) {
|
|||||||
cataloger: NewDotnetDepsBinaryCataloger(DefaultCatalogerConfig()),
|
cataloger: NewDotnetDepsBinaryCataloger(DefaultCatalogerConfig()),
|
||||||
// we care about DLL claims in the deps.json, so the main application inherits all relationships to/from humarizer
|
// we care about DLL claims in the deps.json, so the main application inherits all relationships to/from humarizer
|
||||||
expectedPkgs: net8AppExpectedDepSelfContainedPkgs,
|
expectedPkgs: net8AppExpectedDepSelfContainedPkgs,
|
||||||
expectedRels: func() []string {
|
expectedRels: net8AppExpectedDepSelfContainedRelationships,
|
||||||
x := replaceAll(net8AppExpectedDepSelfContainedRelationships, "Humanizer @ 2.14.1", "dotnetapp @ 1.0.0")
|
assertion: assertAccurateNetRuntimePackage,
|
||||||
// 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,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "pe cataloger (self-contained)",
|
name: "pe cataloger (self-contained)",
|
||||||
@ -1004,6 +989,8 @@ func TestCataloger(t *testing.T) {
|
|||||||
fixture: "image-net2-app",
|
fixture: "image-net2-app",
|
||||||
cataloger: NewDotnetDepsBinaryCataloger(DefaultCatalogerConfig()),
|
cataloger: NewDotnetDepsBinaryCataloger(DefaultCatalogerConfig()),
|
||||||
expectedPkgs: []string{
|
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 @ 2.10.0 (/app/helloworld.deps.json)",
|
||||||
"Serilog.Sinks.Console @ 4.0.1 (/app/helloworld.deps.json)",
|
"Serilog.Sinks.Console @ 4.0.1 (/app/helloworld.deps.json)",
|
||||||
"helloworld @ 1.0.0 (/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
|
"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{
|
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] 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 @ 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)",
|
"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.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,
|
assertion: assertAccurateNetRuntimePackage,
|
||||||
},
|
},
|
||||||
@ -1037,6 +1027,25 @@ func TestCataloger(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestDotnetDepsCataloger_regressions(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 {
|
cases := []struct {
|
||||||
name string
|
name string
|
||||||
fixture 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",
|
fixture: "image-net8-compile-target",
|
||||||
cataloger: NewDotnetDepsBinaryCataloger(DefaultCatalogerConfig()),
|
cataloger: NewDotnetDepsBinaryCataloger(DefaultCatalogerConfig()),
|
||||||
assertion: func(t *testing.T, pkgs []pkg.Package, relationships []artifact.Relationship) {
|
assertion: assertPackages(
|
||||||
// ensure we find the DotNetNuke.Core package (which is using the compile target reference)
|
[]string{
|
||||||
for _, p := range pkgs {
|
"DotNetNuke.Core", // uses a compile target reference in the deps.json
|
||||||
if p.Name == "DotNetNuke.Core" {
|
"Umbraco.Cms", // this is the parent of other packages which do have DLLs included (even though it does not have any DLLs)
|
||||||
return
|
},
|
||||||
}
|
[]string{
|
||||||
}
|
"StyleCop.Analyzers", // this is a development tool
|
||||||
t.Error("expected to find DotNetNuke.Core package")
|
"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 {
|
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)
|
t.Fatalf("expected to find package %s", name)
|
||||||
return pkg.Package{}
|
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
|
// 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"`
|
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
|
// 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.
|
// 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"`
|
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
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c CatalogerConfig) WithPropagateDLLClaimsToParents(propagate bool) CatalogerConfig {
|
||||||
|
c.PropagateDLLClaimsToParents = propagate
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
func DefaultCatalogerConfig() CatalogerConfig {
|
func DefaultCatalogerConfig() CatalogerConfig {
|
||||||
return CatalogerConfig{
|
return CatalogerConfig{
|
||||||
DepPackagesMustHaveDLL: false,
|
DepPackagesMustHaveDLL: false,
|
||||||
DepPackagesMustClaimDLL: true,
|
DepPackagesMustClaimDLL: true,
|
||||||
|
PropagateDLLClaimsToParents: true,
|
||||||
RelaxDLLClaimsWhenBundlingDetected: true,
|
RelaxDLLClaimsWhenBundlingDetected: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -111,7 +111,7 @@ func (c depsBinaryCataloger) Catalog(_ context.Context, resolver file.Resolver)
|
|||||||
runtimePkgs = append(runtimePkgs, &rtp)
|
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 _, root := range roots {
|
||||||
for _, runtimePkg := range runtimePkgs {
|
for _, runtimePkg := range runtimePkgs {
|
||||||
relationships = append(relationships, artifact.Relationship{
|
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`)
|
var runtimeDLLPathPattern = regexp.MustCompile(`/Microsoft\.NETCore\.App/(?P<version>\d+\.\d+\.\d+)/[^/]+\.dll`)
|
||||||
@ -267,15 +268,14 @@ func packagesFromLogicalDepsJSON(doc logicalDepsJSON, config CatalogerConfig) (*
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
lp := doc.PackagesByNameVersion[nameVersion]
|
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...
|
// could not find a paired DLL and the user required this...
|
||||||
skippedDepPkgs[nameVersion] = lp
|
skippedDepPkgs[nameVersion] = lp
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
claimsDLLs := len(lp.RuntimePathsByRelativeDLLPath) > 0 || len(lp.ResourcePathsByRelativeDLLPath) > 0 || len(lp.CompilePathsByRelativeDLLPath) > 0 || len(lp.NativePaths.List()) > 0
|
// 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.DepPackagesMustClaimDLL && !claimsDLLs {
|
|
||||||
if config.RelaxDLLClaimsWhenBundlingDetected && !doc.BundlingDetected || !config.RelaxDLLClaimsWhenBundlingDetected {
|
if config.RelaxDLLClaimsWhenBundlingDetected && !doc.BundlingDetected || !config.RelaxDLLClaimsWhenBundlingDetected {
|
||||||
// could not find a runtime or resource path and the user required this...
|
// 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)
|
// and there is no evidence of a bundler in the dependencies (e.g. ILRepack)
|
||||||
|
|||||||
@ -84,6 +84,12 @@ type logicalDepsJSONPackage struct {
|
|||||||
Targets *depsTarget
|
Targets *depsTarget
|
||||||
Library *depsLibrary
|
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
|
// 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".
|
// to the target path as described in the deps.json target entry under "runtime".
|
||||||
RuntimePathsByRelativeDLLPath map[string]string
|
RuntimePathsByRelativeDLLPath map[string]string
|
||||||
@ -107,6 +113,34 @@ type logicalDepsJSONPackage struct {
|
|||||||
Executables []logicalPE
|
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 {
|
type logicalDepsJSON struct {
|
||||||
Location file.Location
|
Location file.Location
|
||||||
RuntimeTarget runtimeTarget
|
RuntimeTarget runtimeTarget
|
||||||
@ -199,6 +233,8 @@ func getLogicalDepsJSON(deps depsJSON) logicalDepsJSON {
|
|||||||
if !bundlingDetected && knownBundlers.Has(name) {
|
if !bundlingDetected && knownBundlers.Has(name) {
|
||||||
bundlingDetected = true
|
bundlingDetected = true
|
||||||
}
|
}
|
||||||
|
p.anyChildClaimsDLLs = searchForDLLClaims(packageMap, p.dependencyNameVersions()...)
|
||||||
|
p.anyChildHasDLLs = searchForDLLEvidence(packageMap, p.dependencyNameVersions()...)
|
||||||
packages[p.NameVersion] = *p
|
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>.+)`)
|
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.
|
// 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
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func createNameAndVersion(name, version string) (nameVersion string) {
|
func createNameAndVersion(name, version string) string {
|
||||||
nameVersion = fmt.Sprintf("%s/%s", name, version)
|
return fmt.Sprintf("%s/%s", name, version)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func packageURL(m pkg.DotnetDepsEntry) string {
|
func packageURL(m pkg.DotnetDepsEntry) string {
|
||||||
|
|||||||
@ -6,8 +6,7 @@ COPY src/helloworld.csproj .
|
|||||||
RUN dotnet restore -r $RUNTIME
|
RUN dotnet restore -r $RUNTIME
|
||||||
|
|
||||||
COPY src/*.cs .
|
COPY src/*.cs .
|
||||||
|
RUN dotnet publish -c Release -r $RUNTIME --self-contained false -o /app
|
||||||
RUN dotnet publish -c Release --no-restore -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
|
# 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
|
# 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 System;
|
||||||
|
using Microsoft.AspNetCore.Builder;
|
||||||
|
using Microsoft.Extensions.Hosting;
|
||||||
|
|
||||||
namespace HelloWorld
|
namespace HelloWorld
|
||||||
{
|
{
|
||||||
@ -6,7 +8,22 @@ namespace HelloWorld
|
|||||||
{
|
{
|
||||||
public static void Main(string[] args)
|
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>
|
<ItemGroup>
|
||||||
<PackageReference Include="DotNetNuke.Core" Version="9.9.1"/>
|
<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="jQuery" Version="3.4.1" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.Razor" Version="2.2.0" />
|
<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">
|
<PackageReference Include="Microsoft.ChakraCore" Version="1.11.24">
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
|
|
||||||
|
<!-- Nuget.CommandLine is a command line tool for managing NuGet packages -->
|
||||||
<PackageReference Include="Nuget.CommandLine" Version="6.3.1">
|
<PackageReference Include="Nuget.CommandLine" Version="6.3.1">
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
|
|
||||||
|
<!-- Umbraco.Cms has dependencies with software, but itself has no DLLs -->
|
||||||
<PackageReference Include="Umbraco.Cms" Version="11.3.0" />
|
<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>
|
</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>
|
</Project>
|
||||||
Loading…
x
Reference in New Issue
Block a user