Skip to content

Commit

Permalink
Use SPDX package relationships to filter out the project added a de…
Browse files Browse the repository at this point in the history
…pendency (#1383)

* Filter out project from package list

* Update SPDX text parser to capture relationships and fix issue with optional fields

* Update changelog

* Remove described packages for SPDX v2.2
  • Loading branch information
ejortega authored Apr 10, 2024
1 parent 287edc4 commit 3959a5e
Show file tree
Hide file tree
Showing 3 changed files with 226 additions and 34 deletions.
20 changes: 11 additions & 9 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
### Fixed

- Improve parsing of non-UTF-8 encoded pom.xml files
- `SPDX` parsing adding the described package as a dependency
- `SPDX` parsing certain text files with optional package fields

## 6.2.0 - 2024-03-19

Expand Down Expand Up @@ -57,7 +59,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
### Changed

- Renamed multiple CLI arguments to avoid the term `lockfile` in places where
manifests are also accepted
manifests are also accepted
- Renamed `lockfiles` key in `phylum status --json` output to `dependency_files`

## 5.9.0 - 2023-12-05
Expand Down Expand Up @@ -99,7 +101,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
### Changed

- Automatic manifest resolution with `init`, `parse`, `analyze`, and `status`
will no longer return manifests in subdirectories of other manifests
will no longer return manifests in subdirectories of other manifests

### Fixed

Expand Down Expand Up @@ -339,7 +341,7 @@ before, the existing project ID will be re-linked.
### Fixed

- Fix parser lockfile consistency by @cd-work (#882)
- Add deno.window lib reference to extension\_api.ts by @kylewillmon (#890)
- Add deno.window lib reference to extension_api.ts by @kylewillmon (#890)

## 4.1.0 - 2022-12-20

Expand Down Expand Up @@ -375,7 +377,7 @@ before, the existing project ID will be re-linked.
- `phylum auth set-token` by @kylewillmon (#786)
- Add `--lockfile-type` option to `phylum analyze` by @cd-work (#798)
- Add `phylum init` subcommand by @cd-work (#801)
- Add lockfile path and type to .phylum\_project by @cd-work (#806)
- Add lockfile path and type to .phylum_project by @cd-work (#806)
- Add `unsandboxed_run` manifest permission by @cd-work (#777)
- Add group member management subcommands by @cd-work (#809)

Expand Down Expand Up @@ -492,7 +494,7 @@ before, the existing project ID will be re-linked.

### Fixed

- Fix PHYLUM\_API\_KEY overwriting config token by @cd-work in #631
- Fix PHYLUM_API_KEY overwriting config token by @cd-work in #631
- Fix parsing gradle lockfile without classpath by @cd-work in #627
- Fix link dependencies in yarn parser by @cd-work in #621

Expand Down Expand Up @@ -565,7 +567,7 @@ before, the existing project ID will be re-linked.
- Ignore certs everywhere when requested by @kylewillmon (#389)
- Remove Web UI link from analyze output by @cd-work (#397)
- Don't use streaming parsers by @kylewillmon (#401)
- Bump phylum\_types version by @kylewillmon (#409)
- Bump phylum_types version by @kylewillmon (#409)

## 3.4.0 - 2022-05-19

Expand All @@ -589,7 +591,7 @@ before, the existing project ID will be re-linked.
### Fixed

- Fix non-frozen Pipfile suffix by @cd-work (#366)
- Use new endpoint for ping by @kylewillmon (#369)
- Use new endpoint for ping by @kylewillmon (#369)

## 3.2.0 - 2022-05-06

Expand Down Expand Up @@ -665,7 +667,7 @@ before, the existing project ID will be re-linked.

- Continue install/upgrade even if quarantine flag isn't found by @kylewillmon (#249)
- Replace Language/Type with Ecosystem by @cd-work (#248)
- Use git\_version for version numbers by @kylewillmon (#243)
- Use git_version for version numbers by @kylewillmon (#243)
- Use Ecosystem in `phylum package` output by @cd-work (#255)
- Add support for new npm package-lock format by @cd-work (#242)

Expand Down Expand Up @@ -696,7 +698,7 @@ before, the existing project ID will be re-linked.

- Bring Oauth Support to CLI by @DanielJoyce (#118)
- Better error handling by @DanielJoyce (#145)
- Swap out static\_init module for lazy\_static by @DanielJoyce (#146)
- Swap out static_init module for lazy_static by @DanielJoyce (#146)
- Gather files from static builder by @louislang (#147)
- Adding release script by @eeclfrei (#150)
- Updates for recent api changes by @eeclfrei (#160)
Expand Down
95 changes: 78 additions & 17 deletions lockfile/src/parsers/spdx.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,78 @@
use nom::branch::alt;
use nom::bytes::complete::{tag, take_until, take_while};
use nom::bytes::complete::{tag, take_till, take_until, take_while};
use nom::character::complete::{line_ending, multispace0, not_line_ending, space0};
use nom::combinator::{eof, map_opt, opt, recognize};
use nom::error::{context, VerboseError, VerboseErrorKind};
use nom::multi::{many1, many_till};
use nom::sequence::{delimited, tuple};
use nom::multi::{many0, many1, many_till};
use nom::sequence::{delimited, preceded, tuple};
use nom::Err as NomErr;

use crate::parsers::{take_till_blank_line, take_till_line_end, IResult};
use crate::spdx::{ExternalRefs, PackageInformation, ReferenceCategory};
use crate::spdx::{ExternalRefs, PackageInformation, ReferenceCategory, Relationship, SpdxInfo};

pub(crate) fn parse(input: &str) -> IResult<&str, Vec<PackageInformation>> {
let (i, pkgs_info) = many1(package)(input)?;
Ok((i, pkgs_info))
pub(crate) fn parse(input: &str) -> IResult<&str, SpdxInfo> {
let (_, relationships) = parse_relationships(input)?;
let (_, document_describes) = parse_document_describes(input)?;
let (i, spdx_id) = parse_spdx_id(input)?;
let (i, packages) = many1(package)(i)?;

Ok((i, SpdxInfo { spdx_id: spdx_id.into(), document_describes, packages, relationships }))
}

fn parse_spdx_id(input: &str) -> IResult<&str, &str> {
let (i, _) = skip_until_tag(input, "SPDXID:")?;
let (i, spdx_id) = take_till_line_end(i)?;
Ok((i, spdx_id.trim()))
}

fn parse_document_describes(input: &str) -> IResult<&str, Vec<String>> {
let (i, describes) = opt(preceded(
take_until("DocumentDescribes:"),
take_till(|c| c == '\n' || c == '\r'),
))(input)?;

let describes_list = if let Some(describes_str) = describes {
describes_str
.trim_start_matches("DocumentDescribes:")
.trim()
.split(',')
.map(str::trim)
.filter(|s| !s.is_empty())
.map(String::from)
.collect()
} else {
Vec::new()
};

Ok((i, describes_list))
}

fn skip_until_tag<'a>(input: &'a str, line_tag: &'a str) -> IResult<&'a str, ()> {
let (i, _) = take_until(line_tag)(input)?;
let (i, _) = tag(line_tag)(i)?;
Ok((i, ()))
}

fn parse_relationships(input: &str) -> IResult<&str, Vec<Relationship>> {
many0(parse_relationship)(input)
}

fn parse_relationship(input: &str) -> IResult<&str, Relationship> {
let (i, _) = skip_until_tag(input, "Relationship:")?;
let (i, rel) = recognize(ws(take_till_line_end))(i)?;

let parts: Vec<&str> = rel.split_whitespace().collect();
if parts.len() == 3 {
Ok((i, Relationship {
spdx_element_id: Some(parts[0].to_string()),
relationship_type: Some(parts[1].to_string()),
related_spdx_element: Some(parts[2].to_string()),
}))
} else {
let kind = VerboseErrorKind::Context("Invalid relationship format");
let error = VerboseError { errors: vec![(input, kind)] };
Err(NomErr::Failure(error))
}
}

fn package_name(input: &str) -> IResult<&str, &str> {
Expand Down Expand Up @@ -41,44 +101,45 @@ fn parse_package(input: &str) -> IResult<&str, PackageInformation> {
fn package_info(input: &str) -> IResult<&str, PackageInformation> {
let (i, _) = package_name(input)?;

// PackageName is required
// PackageName is required.
let (i, _) = tag("PackageName:")(i)?;

let (i, name) = recognize(ws(take_till_line_end))(i)?;

// SPDXID is required
// SPDXID is required.
let (i, _) = tag("SPDXID:")(i)?;
let (tail, _) = recognize(ws(take_till_line_end))(i)?;
let (tail, spdx_id) = recognize(ws(take_till_line_end))(i)?;

// PackageVersion is optional
// PackageVersion is optional.
// Version can be obtained from PURL if present, so we don't return an error
// here
// here.
let (i, has_version) = opt(tag("PackageVersion:"))(tail)?;
let (i, v) = recognize(ws(take_till_line_end))(i)?;
let version = has_version.map(|_| v.trim().to_string());

// Update input
// Update input.
let i = match version {
Some(_) => i,
None => tail,
};

// PackageDownloadLocation is required
let (i, _) = tag("PackageDownloadLocation:")(i)?;
// PackageDownloadLocation is required.
let (i, _) = skip_until_tag(i, "PackageDownloadLocation:")?;
let (i, download_location) = recognize(ws(take_till_line_end))(i)?;

// Look for external references
// Look for external references.
let (i, next_input) = extern_ref(i)?;
let (_, external_ref) = opt(recognize(ws(take_till_line_end)))(i)?;

// Package name
// Package name.
let name = name.trim();

if let Some(external_ref) = external_ref {
let (_, external_ref) = parse_external_refs(external_ref)?;

Ok((next_input, PackageInformation {
name: name.into(),
spdx_id: spdx_id.trim().into(),
version_info: version,
download_location: download_location.into(),
external_refs: vec![external_ref],
Expand Down
Loading

0 comments on commit 3959a5e

Please sign in to comment.