Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Filters and config files support #634

Merged
merged 5 commits into from
Oct 13, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .github/workflows/repotests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -144,9 +144,17 @@ jobs:
with:
repository: 'appthreat/blint'
path: 'repotests/blint'
- uses: actions/checkout@v4
with:
repository: 'hoolicorp/java-sec-code'
path: 'repotests/java-sec-code'
- uses: dtolnay/rust-toolchain@stable
- name: repotests
run: |
bin/cdxgen.js -p -t java repotests/java-sec-code -o bomresults/bom-java-sec-code.json
bin/cdxgen.js -p -t java repotests/java-sec-code -o bomresults/bom-java-sec-code.json --required-only
bin/cdxgen.js -p -t java repotests/java-sec-code -o bomresults/bom-java-sec-code.json --filter postgres --filter json
bin/cdxgen.js -p -t java repotests/java-sec-code -o bomresults/bom-java-sec-code.json --only spring
bin/cdxgen.js -p -r -t java repotests/shiftleft-java-example -o bomresults/bom-java.json --generate-key-and-sign
node bin/evinse.js -i bomresults/bom-java.json -o bomresults/bom-java.evinse.json -l java --with-data-flow -p repotests/shiftleft-java-example
SBOM_SIGN_ALGORITHM=RS512 SBOM_SIGN_PRIVATE_KEY=bomresults/private.key SBOM_SIGN_PUBLIC_KEY=bomresults/public.key bin/cdxgen.js -p -r -t github repotests/shiftleft-java-example -o bomresults/bom-github.json
Expand Down
15 changes: 14 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ import { createBom, submitBom } from "npm:@cyclonedx/cdxgen@^9.0.1";

```text
$ cdxgen -h
Options:
-o, --output Output file for bom.xml or bom.json. Default bom.
json
-t, --type Project type
Expand All @@ -149,7 +150,9 @@ $ cdxgen -h
d or the project name and version together
--parent-project-id Dependency track parent project id
--required-only Include only the packages with required scope on
the SBOM. [boolean]
the SBOM. Would set compositions.aggregate to inc
omplete unless --no-auto-compositions is passed.
[boolean]
--fail-on-error Fail if any dependency extractor fails. [boolean]
--no-babel Do not use babel to perform usage analysis for Ja
vaScript/TypeScript projects. [boolean]
Expand All @@ -166,11 +169,21 @@ $ cdxgen -h
--validate Validate the generated SBOM using json schema. De
faults to true. Pass --no-validate to disable.
[boolean] [default: true]
--evidence Generate SBOM with evidence for supported languag
es. WIP [boolean] [default: false]
--usages-slices-file Path for the usages slice file created by atom.
--data-flow-slices-file Path for the data-flow slice file created by atom
.
--spec-version CycloneDX Specification version to use. Defaults
to 1.5 [default: 1.5]
--filter Filter components containining this word in purl.
Multiple values allowed. [array]
--only Include components only containining this word in
purl. Useful to generate BOM with first party co
mponents alone. Multiple values allowed. [array]
--auto-compositions Automatically set compositions when the BOM was f
iltered. Defaults to true
[boolean] [default: true]
-h, --help Show help [boolean]
-v, --version Show version number [boolean]
```
Expand Down
82 changes: 57 additions & 25 deletions bin/cdxgen.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,29 @@ import { fileURLToPath } from "node:url";
import globalAgent from "global-agent";
import process from "node:process";
import { printTable, printDependencyTree } from "../display.js";
import { findUpSync } from "find-up";
import { load as _load } from "js-yaml";
import { postProcess } from "../postgen.js";

// Support for config files
const configPath = findUpSync([
".cdxgenrc",
".cdxgen.json",
".cdxgen.yml",
".cdxgen.yaml"
]);
let config = {};
if (configPath) {
try {
if (configPath.endsWith(".yml") || configPath.endsWith(".yaml")) {
config = _load(fs.readFileSync(configPath, "utf-8"));
} else {
config = JSON.parse(fs.readFileSync(configPath, "utf-8"));
}
} catch (e) {
console.log("Invalid config file", configPath);
}
}

let url = import.meta.url;
if (!url.startsWith("file://")) {
Expand All @@ -22,6 +45,7 @@ import yargs from "yargs";
import { hideBin } from "yargs/helpers";

const args = yargs(hideBin(process.argv))
.env("CDXGEN")
.option("output", {
alias: "o",
description: "Output file for bom.xml or bom.json. Default bom.json"
Expand Down Expand Up @@ -77,7 +101,8 @@ const args = yargs(hideBin(process.argv))
})
.option("required-only", {
type: "boolean",
description: "Include only the packages with required scope on the SBOM."
description:
"Include only the packages with required scope on the SBOM. Would set compositions.aggregate to incomplete unless --no-auto-compositions is passed."
})
.option("fail-on-error", {
type: "boolean",
Expand Down Expand Up @@ -132,6 +157,28 @@ const args = yargs(hideBin(process.argv))
description: "CycloneDX Specification version to use. Defaults to 1.5",
default: 1.5
})
.option("filter", {
description:
"Filter components containining this word in purl. Multiple values allowed."
})
.option("only", {
description:
"Include components only containining this word in purl. Useful to generate BOM with first party components alone. Multiple values allowed."
})
.array("filter")
.array("only")
.option("auto-compositions", {
type: "boolean",
default: true,
description:
"Automatically set compositions when the BOM was filtered. Defaults to true"
})
.example([
["$0 -t java .", "Generate a Java SBOM for the current directory"],
["$0 --server", "Run cdxgen as a server"]
])
.epilogue("for documentation, visit https://cyclonedx.github.io/cdxgen")
.config(config)
.scriptName("cdxgen")
.version()
.alias("v", "version")
Expand Down Expand Up @@ -177,32 +224,14 @@ if (process.argv[1].includes("obom") && !args.type) {
}

/**
* projectType: python, nodejs, java, golang
* multiProject: Boolean to indicate monorepo or multi-module projects
* Command line options
*/
const options = {
const options = Object.assign({}, args, {
projectType: args.type,
multiProject: args.recurse,
output: args.output,
resolveClass: args.resolveClass,
installDeps: args.installDeps,
requiredOnly: args.requiredOnly,
failOnError: args.failOnError,
noBabel: args.noBabel || args.babel === false,
deep: args.deep,
generateKeyAndSign: args.generateKeyAndSign,
project: args.projectId,
projectName: args.projectName,
projectGroup: args.projectGroup,
projectVersion: args.projectVersion,
server: args.server,
serverHost: args.serverHost,
serverPort: args.serverPort,
specVersion: args.specVersion,
evidence: args.evidence,
usagesSlicesFile: args.usagesSlicesFile,
dataFlowSlicesFile: args.dataFlowSlicesFile
};
project: args.projectId
});

/**
* Check for node >= 20 permissions
Expand Down Expand Up @@ -243,7 +272,7 @@ const checkPermissions = (filePath) => {
// Start SBOM server
if (args.server) {
const serverModule = await import("../server.js");
return await serverModule.start(options);
return serverModule.start(options);
}
// Check if cdxgen has the required permissions
if (!checkPermissions(filePath)) {
Expand All @@ -253,7 +282,10 @@ const checkPermissions = (filePath) => {
if (!options.usagesSlicesFile) {
options.usagesSlicesFile = `${options.projectName}-usages.json`;
}
const bomNSData = (await createBom(filePath, options)) || {};
let bomNSData = (await createBom(filePath, options)) || {};
if (options.requiredOnly || options["filter"] || options["only"]) {
bomNSData = postProcess(bomNSData, options);
}
if (!args.output) {
args.output = "bom.json";
}
Expand Down
24 changes: 24 additions & 0 deletions bin/evinse.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,28 @@ import process from "node:process";
import { analyzeProject, createEvinseFile, prepareDB } from "../evinser.js";
import { validateBom } from "../validator.js";
import { printCallStack, printOccurrences, printServices } from "../display.js";
import { findUpSync } from "find-up";
import { load as _load } from "js-yaml";

// Support for config files
const configPath = findUpSync([
".cdxgenrc",
".cdxgen.json",
".cdxgen.yml",
".cdxgen.yaml"
]);
let config = {};
if (configPath) {
try {
if (configPath.endsWith(".yml") || configPath.endsWith(".yaml")) {
config = _load(fs.readFileSync(configPath, "utf-8"));
} else {
config = JSON.parse(fs.readFileSync(configPath, "utf-8"));
}
} catch (e) {
console.log("Invalid config file", configPath);
}
}

const isWin = _platform() === "win32";
const isMac = _platform() === "darwin";
Expand All @@ -28,6 +50,7 @@ if (!process.env.ATOM_DB && !fs.existsSync(ATOM_DB)) {
}
}
const args = yargs(hideBin(process.argv))
.env("EVINSE")
.option("input", {
alias: "i",
description: "Input SBOM file. Default bom.json",
Expand Down Expand Up @@ -88,6 +111,7 @@ const args = yargs(hideBin(process.argv))
type: "boolean",
description: "Print the evidences as table"
})
.config(config)
.scriptName("evinse")
.version()
.help("h").argv;
Expand Down
93 changes: 93 additions & 0 deletions docs/ADVANCED.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,98 @@
# Advanced Usage

## Filtering components

cdxgen can filter the components and the dependency tree before writing to a BOM json file. Three kinds of filters are allowed:

### Required only filter

Pass `--required-only` to only store components with the `scope` attribute set to `required`. These are usually considered direct dependencies.

```shell
cdxgen -t java -o /tmp/bom.json -p --required-only
```

Languages supported:

- Java with Maven
- Node.js
- Go
- Php

### Purl filter

Use `--filter` to filter components containing the string in the purl.

```shell
cdxgen -t java -o /tmp/bom.json -p --filter org.springframework
```

### Include only filter

Use `--only` to include only those components containing the string in the purl. This can be used to generate BOM with "first party" components only.

```shell
cdxgen -t java -o /tmp/bom.json -p --only org.springframework
```

## Automatic compositions

When using any filters, cdxgen would automatically set the [compositions.aggregate](https://cyclonedx.org/docs/1.5/json/#compositions_items_aggregate) property to "incomplete" or "incomplete_first_party_only".

To disable this behavior, pass `--no-auto-compositions`.

## Configuration files

Tired of passing command line arguments to cdxgen?

JSON format

- .cdxgenrc
- .cdxgen.json

YAML format

- .cdxgen.yml
- .cdxgen.yaml

Examples:

```json
{
"type": "java",
"print": true,
"output": "bom.json"
}
```

```yaml
# Java type
type: java
# Print the BOM as table and tree
print: true
# Set the output file
output: bom.json
# Only include these components in the BOM
only: org.springframework
```

### Environment variables

All command line arguments can also be passed as environment variables using the "CDXGEN\_" prefix.

```shell
export CDXGEN_TYPE=java
export CDXGEN_PROJECT_NAME=foo
```

Environment variables override values from the configuration files.

### Config value ordering

- Command-line arguments
- Environment variables
- Configuration files (JSON first, followed by yaml)

## Evinse Mode / SaaSBOM

Evinse (Evinse Verification Is Nearly SBOM Evidence) is a new command with cdxgen to generate component evidence and SaaSBOM for supported languages. The tool is powered by [atom](https://github.com/AppThreat/atom).
Expand Down
16 changes: 15 additions & 1 deletion docs/CLI.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ import { createBom, submitBom } from "npm:@cyclonedx/cdxgen@^9.0.1";

```text
$ cdxgen -h

Options:
-o, --output Output file for bom.xml or bom.json. Default bom.
json
-t, --type Project type
Expand All @@ -86,7 +88,9 @@ $ cdxgen -h
d or the project name and version together
--parent-project-id Dependency track parent project id
--required-only Include only the packages with required scope on
the SBOM. [boolean]
the SBOM. Would set compositions.aggregate to inc
omplete unless --no-auto-compositions is passed.
[boolean]
--fail-on-error Fail if any dependency extractor fails. [boolean]
--no-babel Do not use babel to perform usage analysis for Ja
vaScript/TypeScript projects. [boolean]
Expand All @@ -103,11 +107,21 @@ $ cdxgen -h
--validate Validate the generated SBOM using json schema. De
faults to true. Pass --no-validate to disable.
[boolean] [default: true]
--evidence Generate SBOM with evidence for supported languag
es. WIP [boolean] [default: false]
--usages-slices-file Path for the usages slice file created by atom.
--data-flow-slices-file Path for the data-flow slice file created by atom
.
--spec-version CycloneDX Specification version to use. Defaults
to 1.5 [default: 1.5]
--filter Filter components containining this word in purl.
Multiple values allowed. [array]
--only Include components only containining this word in
purl. Useful to generate BOM with first party co
mponents alone. Multiple values allowed. [array]
--auto-compositions Automatically set compositions when the BOM was f
iltered. Defaults to true
[boolean] [default: true]
-h, --help Show help [boolean]
-v, --version Show version number [boolean]
```
Expand Down
Loading
Loading