Skip to content

Commit 608d6fa

Browse files
authored
feat: rust analysis support (#411)
* feat: rust analysis support * fix: use a proper toml parser * fix: remove duplicate functions * fix: update after review * fix: revert accidental changes to package-lock.json * fix: broken sboms * feat: include path dependencies in SBOM with repository_url=local qualifier --------- Signed-off-by: Adva Oren <aoren@redhat.com>
1 parent cb4ae28 commit 608d6fa

File tree

98 files changed

+4401
-9
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

98 files changed

+4401
-9
lines changed

CONTRIBUTING.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ The OpenAPI specification is located in the [`trustify-da-api-spec`](https://git
4242
which will provide data that we can send to the _Backend_ using _analysis.js_. See the
4343
[Adding a Provider](#adding-a-provider) section.
4444
* [java_maven.js](src/providers/java_maven.js) is the provider for the _Java_ _Maven_ ecosystem.
45+
* [rust_cargo.js](src/providers/rust_cargo.js) is the provider for the _Rust_ _Cargo_ ecosystem.
4546

4647
#### Types
4748

README.md

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ let imageAnalysisWithArch = await client.imageAnalysis(['httpd:2.4.49^^amd64'])
4949
The client automatically detects your project's license with intelligent fallback:
5050
</p>
5151
<ul>
52-
<li><strong>Manifest-first:</strong> For ecosystems with license support (Maven, JavaScript), reads from manifest file (<code>pom.xml</code>, <code>package.json</code>)</li>
52+
<li><strong>Manifest-first:</strong> For ecosystems with license support (Maven, JavaScript, Rust Cargo), reads from manifest file (<code>pom.xml</code>, <code>package.json</code>, <code>Cargo.toml</code>)</li>
5353
<li><strong>LICENSE file fallback:</strong> If no license in manifest, or for ecosystems without license support (Gradle, Go, Python), automatically reads from <code>LICENSE</code>, <code>LICENSE.md</code>, or <code>LICENSE.txt</code></li>
5454
<li><strong>SBOM integration:</strong> Detected licenses are included in generated SBOMs for all ecosystems</li>
5555
<li><strong>SPDX support:</strong> Automatically detects common licenses (Apache-2.0, MIT, GPL, BSD) from LICENSE file content</li>
@@ -196,14 +196,15 @@ $ trustify-da-javascript-client license /path/to/package.json
196196
<li><a href="https://go.dev/">Golang</a> - <a href="https://go.dev/blog/using-go-modules/">Go Modules</a></li>
197197
<li><a href="https://www.python.org/">Python</a> - <a href="https://pypi.org/project/pip/">pip Installer</a></li>
198198
<li><a href="https://gradle.org/">Gradle (Groovy and Kotlin DSL)</a> - <a href="https://gradle.org/install/">Gradle Installation</a></li>
199+
<li><a href="https://www.rust-lang.org/">Rust</a> - <a href="https://doc.rust-lang.org/cargo/">Cargo</a></li>
199200
</ul>
200201

201202
<h3>License Detection</h3>
202203
<p>
203204
The client automatically detects your project's license with intelligent fallback:
204205
</p>
205206
<ul>
206-
<li><strong>Manifest-first:</strong> For ecosystems with license support (Maven, JavaScript), reads from manifest file (<code>pom.xml</code>, <code>package.json</code>)</li>
207+
<li><strong>Manifest-first:</strong> For ecosystems with license support (Maven, JavaScript, Rust Cargo), reads from manifest file (<code>pom.xml</code>, <code>package.json</code>, <code>Cargo.toml</code>)</li>
207208
<li><strong>LICENSE file fallback:</strong> If no license in manifest, or for ecosystems without license support (Gradle, Go, Python), automatically reads from <code>LICENSE</code>, <code>LICENSE.md</code>, or <code>LICENSE.txt</code></li>
208209
<li><strong>SBOM integration:</strong> Detected licenses are included in generated SBOMs for all ecosystems</li>
209210
<li><strong>SPDX support:</strong> Automatically detects common licenses (Apache-2.0, MIT, GPL, BSD) from LICENSE file content</li>
@@ -334,7 +335,21 @@ test {
334335
}
335336
```
336337

337-
All of the 5 above examples are valid for marking a package to be ignored
338+
<em>Rust Cargo</em> users can add a comment with <code># trustify-da-ignore</code> (or <code># exhortignore</code>) in <em>Cargo.toml</em> next to the dependency to be ignored. This works for inline declarations, table-based declarations, and workspace-level dependency sections:
339+
340+
```toml
341+
[dependencies]
342+
serde = "1.0" # trustify-da-ignore
343+
tokio = { version = "1.35", features = ["full"] }
344+
345+
[dependencies.regex] # trustify-da-ignore
346+
version = "1.10"
347+
348+
[workspace.dependencies]
349+
log = "0.4" # trustify-da-ignore
350+
```
351+
352+
All of the 6 above examples are valid for marking a package to be ignored
338353
</li>
339354

340355
</ul>
@@ -366,6 +381,7 @@ let options = {
366381
'TRUSTIFY_DA_PYTHON_PATH' : '/path/to/python',
367382
'TRUSTIFY_DA_PIP_PATH' : '/path/to/pip',
368383
'TRUSTIFY_DA_GRADLE_PATH' : '/path/to/gradle',
384+
'TRUSTIFY_DA_CARGO_PATH' : '/path/to/cargo',
369385
// Configure proxy for all requests
370386
'TRUSTIFY_DA_PROXY_URL': 'http://proxy.example.com:8080'
371387
}
@@ -411,7 +427,7 @@ The proxy URL should be in the format: `http://host:port` or `https://host:port`
411427

412428
<h4>License resolution and dependency license compliance</h4>
413429
<p>
414-
The client can resolve the <strong>project license</strong> from the manifest (e.g. <code>package.json</code> <code>license</code>, <code>pom.xml</code> <code>&lt;licenses&gt;</code>) and from a <code>LICENSE</code> or <code>LICENSE.md</code> file in the project, and report when they differ. For <strong>component analysis</strong>, you can optionally run a license check: the client fetches dependency licenses from the backend (by purl) and reports dependencies whose licenses are incompatible with the project license. See <a href="docs/license-resolution-and-compliance.md">License resolution and compliance</a> for design and behavior. To disable the check on component analysis, set <code>TRUSTIFY_DA_LICENSE_CHECK=false</code> or pass <code>licenseCheck: false</code> in the options.
430+
The client can resolve the <strong>project license</strong> from the manifest (e.g. <code>package.json</code> <code>license</code>, <code>pom.xml</code> <code>&lt;licenses&gt;</code>, <code>Cargo.toml</code> <code>license</code>) and from a <code>LICENSE</code> or <code>LICENSE.md</code> file in the project, and report when they differ. For <strong>component analysis</strong>, you can optionally run a license check: the client fetches dependency licenses from the backend (by purl) and reports dependencies whose licenses are incompatible with the project license. See <a href="docs/license-resolution-and-compliance.md">License resolution and compliance</a> for design and behavior. To disable the check on component analysis, set <code>TRUSTIFY_DA_LICENSE_CHECK=false</code> or pass <code>licenseCheck: false</code> in the options.
415431
</p>
416432

417433
<h4>Customizing Executables</h4>
@@ -487,6 +503,11 @@ following keys for setting custom paths for the said executables.
487503
<td><em>gradle</em></td>
488504
<td>TRUSTIFY_DA_PREFER_GRADLEW</td>
489505
</tr>
506+
<tr>
507+
<td><a href="https://www.rust-lang.org/">Rust Cargo</a></td>
508+
<td><em>cargo</em></td>
509+
<td>TRUSTIFY_DA_CARGO_PATH</td>
510+
</tr>
490511
</table>
491512

492513
#### Match Manifest Versions Feature

docs/license-resolution-and-compliance.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,15 @@ The client looks for your project’s license with **automatic fallback**:
2020
1. **Primary: Manifest file** — Reads the license field from:
2121
- `package.json`: `license` field
2222
- `pom.xml`: `<licenses><license><name>` element
23+
- `Cargo.toml`: `license` field under `[package]` or `[workspace.package]`
2324
- `build.gradle` / `build.gradle.kts`: No standard license field (falls back to LICENSE file)
2425
- `go.mod`: No standard license field (falls back to LICENSE file)
2526
- `requirements.txt`: No standard license field (falls back to LICENSE file)
2627

2728
2. **Fallback: LICENSE file** — If no license is found in the manifest, searches for `LICENSE`, `LICENSE.md`, or `LICENSE.txt` in the same directory as your manifest
2829

2930
**How the fallback works:**
30-
- **Ecosystems with manifest license support** (Maven, JavaScript): Uses manifest license if present, otherwise falls back to LICENSE file
31+
- **Ecosystems with manifest license support** (Maven, JavaScript, Rust Cargo): Uses manifest license if present, otherwise falls back to LICENSE file
3132
- **Ecosystems without manifest license support** (Gradle, Go, Python): Automatically reads from LICENSE file
3233
- **SPDX detection**: Common licenses (Apache-2.0, MIT, GPL-2.0/3.0, LGPL-2.1/3.0, AGPL-3.0, BSD-2-Clause/3-Clause) are automatically detected from LICENSE file content
3334

@@ -167,5 +168,5 @@ Project license information is automatically included in generated SBOMs (Cyclon
167168
**LICENSE file fallback in SBOMs:**
168169
- **All ecosystems** now include license information in the SBOM when available
169170
- **Gradle, Go, Python projects**: Even though these ecosystems don’t have manifest license fields, the SBOM will include the license from your LICENSE file
170-
- **Maven, JavaScript projects**: The SBOM uses the manifest license, or falls back to LICENSE file if not specified in manifest
171+
- **Maven, JavaScript, Rust Cargo projects**: The SBOM uses the manifest license, or falls back to LICENSE file if not specified in manifest
171172
- If neither manifest nor LICENSE file contains a license, the SBOM root component will have no `licenses` field

package-lock.json

Lines changed: 13 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@
5656
"https-proxy-agent": "^7.0.6",
5757
"node-fetch": "^3.3.2",
5858
"packageurl-js": "~1.0.2",
59+
"smol-toml": "^1.6.0",
5960
"tree-sitter-requirements": "github:Strum355/tree-sitter-requirements#d0261ee76b84253997fe70d7d397e78c006c3801",
6061
"web-tree-sitter": "^0.26.6",
6162
"yargs": "^18.0.0"

src/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ export default { componentAnalysis, stackAnalysis, imageAnalysis, validateToken
1515

1616
/**
1717
* @typedef {{
18+
* TRUSTIFY_DA_CARGO_PATH?: string | undefined,
1819
* TRUSTIFY_DA_DOCKER_PATH?: string | undefined,
1920
* TRUSTIFY_DA_GO_MVS_LOGIC_ENABLED?: string | undefined,
2021
* TRUSTIFY_DA_GO_PATH?: string | undefined,

src/provider.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import Javascript_npm from './providers/javascript_npm.js';
88
import Javascript_pnpm from './providers/javascript_pnpm.js';
99
import Javascript_yarn from './providers/javascript_yarn.js';
1010
import pythonPipProvider from './providers/python_pip.js'
11+
import rustCargoProvider from './providers/rust_cargo.js'
1112

1213
/** @typedef {{ecosystem: string, contentType: string, content: string}} Provided */
1314
/** @typedef {{isSupported: function(string): boolean, validateLockFile: function(string): void, provideComponent: function(string, {}): Provided | Promise<Provided>, provideStack: function(string, {}): Provided | Promise<Provided>, readLicenseFromManifest: function(string): string | null}} Provider */
@@ -24,7 +25,8 @@ export const availableProviders = [
2425
new Javascript_pnpm(),
2526
new Javascript_yarn(),
2627
golangGomodulesProvider,
27-
pythonPipProvider]
28+
pythonPipProvider,
29+
rustCargoProvider]
2830

2931
/**
3032
* Match a provider by manifest type only (no lock file check). Used for license reading.

0 commit comments

Comments
 (0)