Skip to content

Commit

Permalink
Improvements to csproj target framework detection (#1289)
Browse files Browse the repository at this point in the history
* Capture root namespaces and description for csproj

Signed-off-by: Prabhu Subramanian <[email protected]>

* Capture root namespaces and description for csproj

Signed-off-by: Prabhu Subramanian <[email protected]>

* Capture target frameworks from more properties

Signed-off-by: Prabhu Subramanian <[email protected]>

* Add bazel to container images

Signed-off-by: Prabhu Subramanian <[email protected]>

* Support for Bazel args

Signed-off-by: Prabhu Subramanian <[email protected]>

* Support for Bazel args

Signed-off-by: Prabhu Subramanian <[email protected]>

* Tweaks

Signed-off-by: Prabhu Subramanian <[email protected]>

---------

Signed-off-by: Prabhu Subramanian <[email protected]>
  • Loading branch information
prabhu authored Aug 4, 2024
1 parent f9d8c75 commit 1c4bb9b
Show file tree
Hide file tree
Showing 14 changed files with 228 additions and 40 deletions.
2 changes: 1 addition & 1 deletion bin/cdxgen.js
Original file line number Diff line number Diff line change
Expand Up @@ -278,7 +278,7 @@ const args = yargs(hideBin(process.argv))
.option("feature-flags", {
description: "Experimental feature flags to enable. Advanced users only.",
hidden: true,
choices: ["safe-pip-install"],
choices: ["safe-pip-install", "suggest-build-tools"],
})
.completion("completion", "Generate bash/zsh completion")
.array("type")
Expand Down
3 changes: 3 additions & 0 deletions ci/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,9 @@ RUN set -e; \
&& curl -L -O https://github.com/clojure/brew-install/releases/latest/download/linux-install.sh \
&& chmod +x linux-install.sh \
&& sudo ./linux-install.sh \
&& curl -L --output /usr/local/bin/bazel https://github.com/bazelbuild/bazelisk/releases/latest/download/bazelisk-linux-${GOBIN_VERSION} \
&& chmod +x /usr/local/bin/bazel \
&& bazel --version \
&& useradd -ms /bin/bash cyclonedx \
&& npm install --unsafe-perm -g node-gyp @microsoft/rush --omit=dev \
&& npx node-gyp install \
Expand Down
3 changes: 3 additions & 0 deletions ci/Dockerfile-deno
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,9 @@ RUN set -e; \
&& curl -L -O https://github.com/clojure/brew-install/releases/latest/download/linux-install.sh \
&& chmod +x linux-install.sh \
&& sudo ./linux-install.sh \
&& curl -L --output /usr/local/bin/bazel https://github.com/bazelbuild/bazelisk/releases/latest/download/bazelisk-linux-${GOBIN_VERSION} \
&& chmod +x /usr/local/bin/bazel \
&& bazel --version \
&& useradd -ms /bin/bash cyclonedx \
&& pecl channel-update pecl.php.net \
&& pecl install timezonedb \
Expand Down
2 changes: 1 addition & 1 deletion deno.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@cyclonedx/cdxgen",
"version": "10.9.0",
"version": "10.9.1",
"exports": "./index.js",
"compilerOptions": {
"allowJs": true,
Expand Down
1 change: 1 addition & 0 deletions docs/ENV.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ The following environment variables are available to configure the bom generatio
| PREFER_MAVEN_DEPS_TREE | Use maven `dependency:tree` command instead of the cyclonedx maven plugin |
| MAVEN_CENTRAL_URL | Specify URL of Maven Central for metadata fetching (e.g. when private repo is used) |
| ANDROID_MAVEN_URL | Specify URL of Android Maven Repository for metadata fetching (e.g. when private repo is used) |
| BAZEL_ARGS | Additional arguments for Bazel command. Eg: --bazelrc=bazelrc.remote |
| BAZEL_TARGET | Bazel target to build. Default :all (Eg: //java-maven) |
| BAZEL_STRIP_MAVEN_PREFIX | Strip Maven group prefix (e.g. useful when private repo is used, defaults to `/maven2/`) |
| BAZEL_USE_ACTION_GRAPH | SBOM for specific Bazel target, uses `bazel aquery 'outputs(".*.jar", deps(<BAZEL_TARGET>))'` (defaults to `false`) |
Expand Down
91 changes: 67 additions & 24 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -1529,7 +1529,6 @@ export async function createJavaBom(path, options) {
) {
parentComponent = bomJsonObj.metadata.component;
options.parentComponent = parentComponent;
pkgList = [];
}
if (bomJsonObj.components) {
// Inject evidence into the components. #994
Expand Down Expand Up @@ -1944,7 +1943,11 @@ export async function createJavaBom(path, options) {

// Bazel
// Look for the BUILD file only in the root directory
const bazelFiles = getAllFiles(path, "BUILD", options);
const bazelFiles = getAllFiles(
path,
`${options.multiProject ? "**/" : ""}BUILD*`,
options,
);
if (
bazelFiles?.length &&
!options.projectType?.includes("maven") &&
Expand All @@ -1959,9 +1962,18 @@ export async function createJavaBom(path, options) {
for (const f of bazelFiles) {
const basePath = dirname(f);
// Invoke bazel build first
const bazelTarget = process.env.BAZEL_TARGET || ":all";
console.log("Executing", BAZEL_CMD, "build", bazelTarget, "in", basePath);
let result = spawnSync(BAZEL_CMD, ["build", bazelTarget], {
const bazelTarget = process.env.BAZEL_TARGET || "//...";
let bArgs = [
...(process.env?.BAZEL_ARGS?.split(" ") || []),
"build",
bazelTarget,
];
// Automatically load any bazelrc file
if (!process.env.BAZEL_ARGS && existsSync(join(basePath, ".bazelrc"))) {
bArgs = ["--bazelrc=.bazelrc", "build", bazelTarget];
}
console.log("Executing", BAZEL_CMD, bArgs.join(" "), "in", basePath);
let result = spawnSync(BAZEL_CMD, bArgs, {
cwd: basePath,
shell: true,
encoding: "utf-8",
Expand All @@ -1978,16 +1990,23 @@ export async function createJavaBom(path, options) {
options.failOnError && process.exit(1);
} else {
const target = process.env.BAZEL_TARGET || "//...";
let query;
let query = [...(process.env?.BAZEL_ARGS?.split(" ") || [])];
let bazelParser;
// Automatically load any bazelrc file
if (!process.env.BAZEL_ARGS && existsSync(join(basePath, ".bazelrc"))) {
query = ["--bazelrc=.bazelrc"];
}
if (["true", "1"].includes(process.env.BAZEL_USE_ACTION_GRAPH)) {
query = ["aquery", `outputs('.*.jar',deps(${target}))`];
query = query.concat(["aquery", `outputs('.*.jar',deps(${target}))`]);
bazelParser = parseBazelActionGraph;
} else {
query = ["aquery", "--output=textproto", "--skyframe_state"];
query = query.concat([
"aquery",
"--output=textproto",
"--skyframe_state",
]);
bazelParser = parseBazelSkyframe;
}

console.log("Executing", BAZEL_CMD, `${query.join(" ")} in`, basePath);
result = spawnSync(BAZEL_CMD, query, {
cwd: basePath,
Expand Down Expand Up @@ -2067,8 +2086,12 @@ export async function createJavaBom(path, options) {
options,
);

if (sbtProjects?.length) {
let pkgList = [];
if (
sbtProjects?.length &&
!options.projectType?.includes("bazel") &&
!options.projectType?.includes("gradle") &&
!options.projectType?.includes("maven")
) {
// If the project use sbt lock files
if (sbtLockFiles?.length) {
for (const f of sbtLockFiles) {
Expand Down Expand Up @@ -4920,6 +4943,32 @@ export async function createCsharpBom(path, options) {
`${options.multiProject ? "**/" : ""}*.nupkg`,
options,
);
// Support for detecting and suggesting build tools for this project
// We parse all the .csproj files to collect the target framework strings
if (isFeatureEnabled(options, "suggest-build-tools")) {
const targetFrameworks = new Set();
for (const f of csProjFiles) {
const csProjData = readFileSync(f, { encoding: "utf-8" });
const retMap = parseCsProjData(csProjData, f, {});
if (retMap?.parentComponent?.properties) {
const parentProperties = retMap.parentComponent.properties;
retMap.parentComponent.properties
.filter(
(p) =>
p.name === "cdx:dotnet:target_framework" && p.value.trim().length,
)
.forEach((p) => {
const frameworkValues = p.value
.split(";")
.filter((v) => v.trim().length && !v.startsWith("$("))
.forEach((v) => {
targetFrameworks.add(v);
});
});
}
}
console.log("Target frameworks found:", Array.from(targetFrameworks));
}
// Support for automatic restore for .Net projects
if (
options.installDeps &&
Expand Down Expand Up @@ -4969,9 +5018,11 @@ export async function createCsharpBom(path, options) {
console.log(
"Authenticate with any private registries such as Azure Artifacts feed before running cdxgen.",
);
console.log(
"Alternatively, try using the unofficial `ghcr.io/appthreat/cdxgen-dotnet6:v10` container image, which bundles nuget (mono) and a range of dotnet SDKs.",
);
if (process.env?.CDXGEN_IN_CONTAINER !== "true") {
console.log(
"Alternatively, try using the unofficial `ghcr.io/appthreat/cdxgen-dotnet6:v10` container image, which bundles nuget (mono) and a range of dotnet SDKs.",
);
}
}
console.log(result.stdout, result.stderr);
options.failOnError && process.exit(1);
Expand Down Expand Up @@ -5097,10 +5148,6 @@ export async function createCsharpBom(path, options) {
console.log(`Parsing ${f}`);
}
pkgData = readFileSync(f, { encoding: "utf-8" });
// Remove byte order mark
if (pkgData.charCodeAt(0) === 0xfeff) {
pkgData = pkgData.slice(1);
}
const dlist = parseCsPkgData(pkgData, f);
if (dlist?.length) {
pkgList = pkgList.concat(dlist);
Expand Down Expand Up @@ -5147,13 +5194,9 @@ export async function createCsharpBom(path, options) {
if (DEBUG_MODE) {
console.log(`Parsing ${f}`);
}
let csProjData = readFileSync(f, { encoding: "utf-8" });
// Remove byte order mark
if (csProjData.charCodeAt(0) === 0xfeff) {
csProjData = csProjData.slice(1);
}
const csProjData = readFileSync(f, { encoding: "utf-8" });
const retMap = parseCsProjData(csProjData, f, pkgNameVersions);
if (retMap?.parentComponent) {
if (retMap?.parentComponent?.purl) {
// If there are multiple project files, track the parent components using nested components
if (csProjFiles.length > 1) {
if (!parentComponent.components) {
Expand Down
2 changes: 1 addition & 1 deletion jsr.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@cyclonedx/cdxgen",
"version": "10.9.0",
"version": "10.9.1",
"exports": "./index.js",
"include": ["*.js", "bin/**", "data/**", "types/**"],
"exclude": ["test/", "docs/", "contrib/", "ci/", "tools_config/"]
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@cyclonedx/cdxgen",
"version": "10.9.0",
"version": "10.9.1",
"description": "Creates CycloneDX Software Bill of Materials (SBOM) from source or container image",
"homepage": "http://github.com/cyclonedx/cdxgen",
"author": "Prabhu Subramanian <[email protected]>",
Expand Down
38 changes: 38 additions & 0 deletions test/data/Logging.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<?xml version="1.0" encoding="utf-8"?>
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>$(TargetFrameworks);</TargetFrameworks>
<Description>Sample OData extensions for OData v8</Description>
<RootNamespace>Sample.OData</RootNamespace>
<Nullable>enable</Nullable>
</PropertyGroup>

<PropertyGroup>
<PackageReadmeFile>README.md</PackageReadmeFile>
<PackageDescription>Includes latest versions of Seedwork packages and versions of packages used by Seedwork. Includes project validation's checks. Includes mechanism to attach Seedwork locally</PackageDescription>
<PackageTags>MSBuild Tasks Seedwork</PackageTags>
<DevelopmentDependency>true</DevelopmentDependency>
<IncludeBuildOutput>false</IncludeBuildOutput>
</PropertyGroup>

<ItemGroup>
<InternalsVisibleTo Include="Sample.Web" />
<InternalsVisibleTo Include="Sample.Web.ServiceBus" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="Serilog" />
<PackageReference Include="Serilog.Sinks.ApplicationInsights" />
<PackageReference Include="Serilog.Sinks.ElasticSearch" />
<PackageReference Include="Serilog.Sinks.Trace" />
<PackageReference Include="Serilog.Sinks.Console" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\Sample.Configuration\Sample.Configuration.csproj" />
<ProjectReference Include="..\Sample.DependencyInjection.Netcore\Sample.DependencyInjection.Netcore.csproj" />
<ProjectReference Include="..\Sample.Contracts\Sample.Contracts.csproj" />
</ItemGroup>

</Project>
6 changes: 3 additions & 3 deletions types/evinser.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export function prepareDB(options: any): Promise<{
changed<K extends keyof any>(key: K, dirty: boolean): void;
changed(): false | string[];
previous(): Partial<any>;
previous<K extends string | number | symbol>(key: K): any | undefined;
previous<K extends string | number | symbol>(key: K): any;
save(options?: import("sequelize").SaveOptions<any>): Promise<any>;
reload(options?: import("sequelize").FindOptions<any>): Promise<any>;
validate(options?: import("sequelize/types/instance-validator.js").ValidationOptions): Promise<void>;
Expand Down Expand Up @@ -213,7 +213,7 @@ export function prepareDB(options: any): Promise<{
changed<K extends keyof any>(key: K, dirty: boolean): void;
changed(): false | string[];
previous(): Partial<any>;
previous<K extends string | number | symbol>(key: K): any | undefined;
previous<K extends string | number | symbol>(key: K): any;
save(options?: import("sequelize").SaveOptions<any>): Promise<any>;
reload(options?: import("sequelize").FindOptions<any>): Promise<any>;
validate(options?: import("sequelize/types/instance-validator.js").ValidationOptions): Promise<void>;
Expand Down Expand Up @@ -396,7 +396,7 @@ export function prepareDB(options: any): Promise<{
changed<K extends keyof any>(key: K, dirty: boolean): void;
changed(): false | string[];
previous(): Partial<any>;
previous<K extends string | number | symbol>(key: K): any | undefined;
previous<K extends string | number | symbol>(key: K): any;
save(options?: import("sequelize").SaveOptions<any>): Promise<any>;
reload(options?: import("sequelize").FindOptions<any>): Promise<any>;
validate(options?: import("sequelize/types/instance-validator.js").ValidationOptions): Promise<void>;
Expand Down
2 changes: 1 addition & 1 deletion types/index.d.ts.map

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 1c4bb9b

Please sign in to comment.