Skip to content

[ANE-2235] Fix PNPM v9 lockfile parsing issues with package names/versions #1531

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

Open
wants to merge 51 commits into
base: master
Choose a base branch
from

Conversation

ryanlink
Copy link
Contributor

@ryanlink ryanlink commented Apr 11, 2025

Overview

This PR fixes issues with PNPM v9 lockfile parsing, specifically addressing problems with incorrect package name and version handling.

Acceptance criteria

  1. When analyzing a project with a PNPM v9 lockfile:

    • Locators should be correctly formatted as npm+package-name$version
    • There should be no malformed locators like [email protected]
  2. Dependencies with special formats should be correctly handled:

    • Packages with namespaced references (e.g., @pnpm/[email protected]) should appear as npm+hosted-git-info$1.0.0
    • Packages where the version string contains another package name (e.g., [email protected]) should appear as npm+safe-execa$0.1.2
  3. Link references should be properly processed:

    • Workspace links (e.g., link:../cli-meta) should not result in malformed locators
    • No errors should be thrown when processing link references
  4. The FOSSA CLI should successfully build and run all PNPM-related unit tests

  5. When analyzing the PNPM repository itself (or any large project using PNPM v9), all dependencies should be properly resolved with correctly formatted locators

Testing plan

Tested with a real PNPM v9 lockfile from the PNPM repository itself, which demonstrated correct dependency resolution with properly formatted FOSSA locators. Also tested against a v9 lockfile @vishal-thenge provided from a prospect.

Risks

Observation

While testing the new PNPM-v9 lock-file parser I ran FOSSA analysis on the full pnpm repo.
Analysis succeeded, but the CLI emitted warnings such as:

[WARN] [PNPM v9] Could not find package metadata for linked dependency.
    Importer Key: .
    Dependency Name: @pnpm/catalogs.types
    Version Ref (Link): link:../../catalogs/types

Similar warnings appear for @pnpm/config, @pnpm/logger, and other internal workspace links.

Why this happens

  • PNPM lockfiles record workspace packages with the link: protocol.
  • Those linked packages do not have corresponding entries in the packages: map of the lockfile, so our parser can’t pull the usual version/integrity metadata.
  • When we detect link: but find no metadata block, we currently log a warning.

Impact

  • FOSSA still scans each workspace package (it finds the package.json on disk), so license analysis succeeds.
  • However, the dependency graph it uploads is missing the explicit edges + version pins for these internal packages. That can affect SBOM completeness and reachability analysis.

Proposed follow-ups (post-merge)

  1. Enhance generateCandidateSnapshotKeysV9 to treat link: refs as first-class nodes:
    • Use the on-disk package.json for name/version.
    • Synthesize a pseudo snapshot key (e.g., link:@pnpm/logger@workspace).

  2. Downgrade the current warning to DEBUG once we have a resolution path, to avoid noise.

This isn’t a blocker for merging—overall parsing logic works—but we should track the enhancement so that SBOMs include internal workspace dependencies with accurate version pins.

Metrics

References

ANE-2235: Support pnpm@9 and pnpm-lockfile v9

Checklist

  • I added tests for this PR's change (or explained in the PR description why tests don't make sense).
  • If this PR introduced a user-visible change, I added documentation into docs/.
  • If this PR added docs, I added links as appropriate to the user manual's ToC in docs/README.ms and gave consideration to how discoverable or not my documentation is.
  • If this change is externally visible, I updated Changelog.md. If this PR did not mark a release, I added my changes into an ## Unreleased section at the top.
  • If I made changes to .fossa.yml or fossa-deps.{json.yml}, I updated docs/references/files/*.schema.json AND I have updated example files used by fossa init command. You may also need to update these if you have added/removed new dependency type (e.g. pip) or analysis target type (e.g. poetry).
  • If I made changes to a subcommand's options, I updated docs/references/subcommands/<subcommand>.md.

@ryanlink ryanlink requested a review from a team as a code owner April 11, 2025 04:23
@ryanlink ryanlink requested a review from spatten April 11, 2025 04:23
@ryanlink ryanlink marked this pull request as draft April 11, 2025 04:42
@ryanlink ryanlink removed the request for review from spatten April 11, 2025 04:43
@ryanlink ryanlink force-pushed the pnpm-9-lockfile-fix branch from ccc9f49 to e8d9005 Compare April 11, 2025 14:28
@ryanlink ryanlink force-pushed the pnpm-9-lockfile-fix branch from 9ae886c to 67fd875 Compare April 11, 2025 16:59
@ryanlink ryanlink force-pushed the pnpm-9-lockfile-fix branch from 67975e7 to 6202d62 Compare May 9, 2025 15:36
ryanlink added 3 commits May 9, 2025 16:10
…key handling, version cleanup, error handling, and docs; unify graph logic; polish v9 support
…rld lockfile structure and parser behavior. Mark non-representative tests as pending.
@ryanlink ryanlink force-pushed the pnpm-9-lockfile-fix branch from 9c5d12f to ffbfa47 Compare May 12, 2025 19:58
…nit, last) in PnpmLock.hs. Use safe alternatives (listToMaybe, take, drop) for all list indexing and manipulation. Also, replace run . evalGrapher with runIdentity . evalGrapher for legacy pnpm lockfile parsing. Code is now hlint clean and fourmolu formatted.
@ryanlink ryanlink force-pushed the pnpm-9-lockfile-fix branch from 82c517e to 965c4c5 Compare May 13, 2025 19:41
ryanlink and others added 3 commits May 13, 2025 14:47
…ts, and shadowed/unused bindings in PnpmLock.hs; fix guard syntax; ensure fourmolu and hlint clean.
…(resolveDependencySnapshots, getPkgNameVersionForV9Snapshots, shouldApplySymConstraint). Fixes build errors from previous cleanup.
Copy link
Contributor

@csasarak csasarak left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've left some comments. In general:

  • You spent a lot of time understanding the lockfile format, we don't want to lose that information so I need you to add commentary relating the code to the parts of the file. This is especially critical since as far as I know there isn't a spec for PNPM lock files. We don't want to throw away understanding.
  • This PR seems to remove a lot of commentary on the pnpm lock format without any replacement. Please go through and explain why it was removed or bring them back to the relevant spots. A previous dev spent a lot of time understanding and writing that stuff so future devs wouldn't have to - throwing it away is unacceptable.
  • I'd strongly recommend writing a half-page to a page of prose describing the format you're trying to match and what makes it different from previous versions of pnpm. I think it might clarify a lot of this or you may identify areas where pre-existing code would be able to do the job.
  • When I was looking into this issue, it seemed like it would likely be simple to implement but the hard part of the job would be understanding what the right solution is. Based on this PR, I still have no idea what the right solution is and we need to prove that we do understand it.
  • With the commentary that does exist in this PR, a lot of it I'm not clear on how it's supposed to help me. In particular, I wouldn't reference previous versions of the code in commentary unless it's to describe how the current implementation might be surprising. Also, don't compare things to master since ideally this PR will someday be on master!

Please don't try to submit code changes to this PR in response to my review. Let's go through all the comments and discuss next steps for each of them together with @zlav and myself.

Changelog.md Outdated
@@ -1,5 +1,9 @@
# FOSSA CLI Changelog

## Unreleased
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This warrants a release. Make it 3.10.9.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

<img width="796" alt="image" src="https://github.com/user-attachments/assets/d1461506-d3e7-42da-b9be-2b53a87f79f1" />

Please [email](mailto:[email protected]) FOSSA support if you are affected by this limitation.
As of [PR #1531](https://github.com/fossas/fossa-cli/pull/1531), pnpm v9 and v10 and their associated v9 lockfiles are supported by FOSSA CLI. If you encounter any issues, please [email](mailto:[email protected]) FOSSA support.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we typically recommend support.fossa.com. Is there a reason to use the email here?

I would say "as of version" rather than "as of PR." PR isn't going to mean anything to some of our customers.

Also, I would just focus on the lockfile versions we support. If pnpm 10 uses lockfile v9 then the pnpm 10 detail isn't really relevant IMO. It will also come to imply in the future that we don't support pnpm > 11 which may not be true if they also use pnpm v9.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

@@ -736,6 +738,7 @@ test-suite unit-tests
, hspec-hedgehog ^>=0.1
, hspec-megaparsec ^>=2.2
, HUnit ^>=1.6.0
, QuickCheck ^>=2.15.0.1
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We use hedgehog for property based testing in this repo, not QuickCheck. Please alter this PR to use QuickCheck or justify why we should use both systems.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I must have tried this transiently in PnpmLockSpec.hs, but it's no longer being used. Removing

@@ -194,7 +215,7 @@ instance FromJSON ProjectMapDepMetadata where

data PackageData = PackageData
{ isDev :: Bool
, name :: Maybe Text -- only provided when non-registry resolver is used
, name :: Maybe Text
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you explain why this comment is no longer relevant? No need to include it in code, an explanation here is fine.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure why that was removed, can reinstate.

A more accurate, albeit slightly less concise, comment might be:
-- | The canonical package name. More consistently present for non-registry resolved dependencies (git, file), but can appear for registry ones too.
Or, if we want to keep it very brief:
-- | Optional: The canonical package name, especially for non-registry packages.

let finalIsDev = maybe isCtxDev isDev maybePkgData
pure $ createDepSimple NodeJSType canonicalDepName (Just versionFromSnapKey) finalIsDev

-- Define processImporterEntries here, after resolveSnapshotDependency
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Irrelevant comment.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will remove.

pure $ createDepSimple NodeJSType canonicalDepName (Just versionFromSnapKey) finalIsDev

-- Define processImporterEntries here, after resolveSnapshotDependency
let processImporterEntries entries isDepDevFlag =
Copy link
Contributor

@csasarak csasarak May 15, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Above here you explicitly write a type for a function but here you do not. In general we do like to add explicit types even for local definitions. At the very least, try to make code close together consistent.

Hint: If you wrote processImporterEntries :: _ on its own line above the function head the language server should help you.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adding type signature

-- Define processImporterEntries here, after resolveSnapshotDependency
let processImporterEntries entries isDepDevFlag =
for_ entries $ \(canonicalName, ProjectMapDepMetadata{depVersion = resolvedRefStr}) -> do
if "catalog:" `Text.isPrefixOf` resolvedRefStr
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would strongly recommend using parser combinators from MegaParsec throughout here. It's much easier to read and keep track of. At minimum, some more commentary clarifying which branches match to which patterns in the lockfile format would be really helpful.

As it is, this code is complex enough that there's a strong likelihood a reviewer (me) will miss something without the additional information.

This may be a "me" thing, but when I start seeing lots of nesting like this it's usually a strong indication that there's something wrong with the way I've chosen to organize the code.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

refactored this whole section

withoutSymConstraint = fst . Text.breakOn "_"
removePrefixes v
| "@" `Text.isInfixOf` v && Text.count "@" v > 1 =
let parts = Text.splitOn "@" v
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Couldn't you just splitOn and pattern match to know if its infix or there are more than 1 "@"?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

removed

checkGraphLegacy pnpmLockV6WithWorkspace pnpmLockV6WithWorkspaceGraphSpec
checkGraphLegacy pnpmLockV6 pnpmLockV6GraphSpec

-- v9 format - START V9 CHANGES
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
-- v9 format - START V9 CHANGES
-- v9 format

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

@ryanlink
Copy link
Contributor Author

@csasarak Thanks for the thorough review. I'm actually revamping the parser again as I realized the few unresolved deps I mentioned led me to a bunch of deps we didn't parse from the lockfile; there are many package names in the lockfile containing the string pkg but the current parser only output npm+pkg$5.12.0.

I definitely didn't intend to remove commentary. That appears to be a consequence of vibe-coding without a specific instruction to retain it, which is unfortunate. I'll restore as much as I can and add comments where needed on new logic.

I'm going to address your comments individually and propose changes in-comment before making any changes to the code, but I will likely push a new commit by tomorrow that will address the missing dependencies. cc @zlav hope that's OK!

@csasarak
Copy link
Contributor

I suspect that this PR is more complicated than it needs to be - in particular AIs seem to like reinventing rather than integrating with what already exists.

I'd like to strongly reiterate my suggestion to write a short prose document explaining what's wrong with the current parser (outside this PR) and what the new one needs to do. The reason I recommend waiting on adding new code is because I'm not confident that this PR will be incrementally improvable to get to a solution we'll accept.

@ryanlink
Copy link
Contributor Author

Agreed. I'll re-approach it with more attention to using pre-existing code, retaining commentary, and adding only appropriate comments. I don't know why I didn't think of this before, but I can reverse-engineer https://github.com/pnpm/pnpm/blob/main/lockfile/fs/src/lockfileFormatConverters.ts and https://github.com/pnpm/pnpm/blob/main/lockfile/fs/src/write.ts to make this code a lot cleaner.

Here's a prose-and-bullets doc explaining what we know about changes to the v9 lockfile format from v6.

@csasarak I respect your request not to make edits without individually reviewing them with you and @zlav, but I believe that, given your helpful and specific comments, I can do a much better job on this before submitting for review again. Do you mind if I take what you've written and run with it, with the goal of retaining as much pre-existing code and commentary as possible?

@csasarak
Copy link
Contributor

csasarak commented May 16, 2025

I can reverse-engineer https://github.com/pnpm/pnpm/blob/main/lockfile/fs/src/lockfileFormatConverters.ts and https://github.com/pnpm/pnpm/blob/main/lockfile/fs/src/write.ts to make this code a lot cleaner.

I would be careful with this, as a direct translation won't always result in code that's a good use of the target language. It's not a bad approach to understanding the problem though.

Cards on the table: a lot of my comments and initial thoughts are aimed at finding out what your level of understanding is about the changes you're doing here and how PNPM lockfile v9 works. This isn't meant to be condescending: a huge amount of the work any SE does is understanding problems even if it ultimately gets distilled down into code. Some of this may just be my bias, but one concern I have with LLMs is that it seems easy to get something that appears right behaviorally, but skip over the parts of the process that actually demonstrate that the solution is the correct one in a logical sense. That last bit can seem extraneous, but it's critical when we have to fix a bug or make enhancements later.

When I took my first stab at this a while back and then decided to write it up as a ticket for later, it wasn't because I was expecting to have to write a ton of code and that's time consuming. It's because I knew that it would take me time to learn enough that I could be comfortable releasing what I'd written and calling it PNPM v9 support.

@csasarak I respect your request not to make edits without individually reviewing them with you and @zlav, but I believe that, given your helpful and specific comments, I can do a much better job on this before submitting for review again.

My goal here was to make sure you understood each comment and got some guidance on how to address each one so you don't waste your time. I want to stress that this is just the first round of review: addressing what I've written here (either by doing it or by explaining why you won't) is necessary but not sufficient to get this merged.

If you think that you have what you need to move forward and that's the most effective way to proceed then that's fine - I didn't mean to lay down a hard injunction.

with the goal of retaining as much pre-existing code and commentary as possible?

Retaining the old code/commentary isn't necessarily the goal. Feel free to change it if it makes sense - the real goal should be for these new changes to be as understandable as the old version.

If you need something more from me or I can offer more support, please let me know!

ryanlink and others added 5 commits May 19, 2025 15:22
…arious helper functions, renamed graph building functions: main dispatcher is now 'dispatchPnpmGraphBuilder', legacy logic is 'buildGraph'; added/reinstated commentary, removed unused QuickCheck dependency. TODO: resolve test build errors under fused-effects
…t key parsing, full recursive snapshot walk, and correct transitive dependency resolution. Cleans up imports, unifies traversal logic, adds warnings for missing keys, and ensures output matches expected dependency counts. Passes hlint and fourmolu.
…pliance; refactored getGraphIO in test/Pnpm/PnpmLockSpec.hs to use expectationFailure instead of error, improving test safety and hlint compliance; ensured all formatting and linting checks pass for both test and lockfile modules; staged src/Strategy/Node/Pnpm/PnpmLock.hs as part of the relevant PNPM lockfile/test improvements.
…notation, update comments, and remove outdated TODOs. Restore v3 deprecation note. No functional changes.
Copy link

qodo-merge-pro bot commented May 20, 2025

CI Feedback 🧐

(Feedback updated until commit 83e2774)

A test triggered by this PR failed. Here is an AI-generated analysis of the failure:

Action: Linux-build

Failed stage: Build and Unit Test [❌]

Failed test name: Pnpm.PnpmLock, can work with v9.0 format, with real-world pnpm repo lockfile, buildGraph with v9 format, should include dependencies of root package as direct

Failure summary:

The action failed because the unit test "Pnpm.PnpmLock, can work with v9.0 format, with real-world
pnpm repo lockfile, buildGraph with v9 format, should include dependencies of root package as
direct" failed. The test expected a specific list of dependencies but received a different list. The
error message indicates that the actual list of dependencies is not a permutation of the expected
list, suggesting an issue with how the code processes pnpm v9.0 format lockfiles.

Relevant error logs:
1:  ##[group]Runner Image Provisioner
2:  Hosted Compute Agent
...

278:  �[36;1mecho "components=$(for c in ${components//,/ }; do echo -n ' --component' $c; done)" >> $GITHUB_OUTPUT�[0m
279:  �[36;1mecho "downgrade=" >> $GITHUB_OUTPUT�[0m
280:  shell: bash --noprofile --norc -e -o pipefail {0}
281:  env:
282:  targets: 
283:  components: 
284:  ##[endgroup]
285:  ##[group]Run : set $CARGO_HOME
286:  �[36;1m: set $CARGO_HOME�[0m
287:  �[36;1mecho CARGO_HOME=${CARGO_HOME:-"$HOME/.cargo"} >> $GITHUB_ENV�[0m
288:  shell: bash --noprofile --norc -e -o pipefail {0}
289:  ##[endgroup]
290:  ##[group]Run : install rustup if needed
291:  �[36;1m: install rustup if needed�[0m
292:  �[36;1mif ! command -v rustup &>/dev/null; then�[0m
293:  �[36;1m  curl --proto '=https' --tlsv1.2 --retry 10 --retry-connrefused --location --silent --show-error --fail https://sh.rustup.rs | sh -s -- --default-toolchain none -y�[0m
294:  �[36;1m  echo "$CARGO_HOME/bin" >> $GITHUB_PATH�[0m
295:  �[36;1mfi�[0m
296:  shell: bash --noprofile --norc -e -o pipefail {0}
297:  env:
298:  CARGO_HOME: /github/home/.cargo
299:  ##[endgroup]
300:  info: downloading installer
301:  error: $HOME differs from euid-obtained home directory: you may be using sudo
302:  error: $HOME directory: /github/home
303:  error: euid-obtained home directory: /root
304:  info: profile set to 'default'
...

373:  �[36;1mif [ -z "${CARGO_REGISTRIES_CRATES_IO_PROTOCOL+set}" -o -f "/home/runner/work/_temp"/.implicit_cargo_registries_crates_io_protocol ]; then�[0m
374:  �[36;1m  if rustc +stable --version --verbose | grep -q '^release: 1\.6[89]\.'; then�[0m
375:  �[36;1m    touch "/home/runner/work/_temp"/.implicit_cargo_registries_crates_io_protocol || true�[0m
376:  �[36;1m    echo CARGO_REGISTRIES_CRATES_IO_PROTOCOL=sparse >> $GITHUB_ENV�[0m
377:  �[36;1m  elif rustc +stable --version --verbose | grep -q '^release: 1\.6[67]\.'; then�[0m
378:  �[36;1m    touch "/home/runner/work/_temp"/.implicit_cargo_registries_crates_io_protocol || true�[0m
379:  �[36;1m    echo CARGO_REGISTRIES_CRATES_IO_PROTOCOL=git >> $GITHUB_ENV�[0m
380:  �[36;1m  fi�[0m
381:  �[36;1mfi�[0m
382:  shell: bash --noprofile --norc -e -o pipefail {0}
383:  env:
384:  CARGO_HOME: /github/home/.cargo
385:  CARGO_INCREMENTAL: 0
386:  CARGO_TERM_COLOR: always
387:  ##[endgroup]
388:  ##[group]Run : work around spurious network errors in curl 8.0
389:  �[36;1m: work around spurious network errors in curl 8.0�[0m
390:  �[36;1m# https://rust-lang.zulipchat.com/#narrow/stream/246057-t-cargo/topic/timeout.20investigation�[0m
...

425:  ##[group]Run set -eu
426:  �[36;1mset -eu�[0m
427:  �[36;1mif ! command -v bash >/dev/null; then�[0m
428:  �[36;1m  if grep -Eq '^ID=alpine' /etc/os-release; then�[0m
429:  �[36;1m    printf '::group::Install packages required for install-action (bash)\n'�[0m
430:  �[36;1m    # NB: sync with apk_install in main.sh�[0m
431:  �[36;1m    if command -v sudo >/dev/null; then�[0m
432:  �[36;1m      sudo apk --no-cache add bash�[0m
433:  �[36;1m    elif command -v doas >/dev/null; then�[0m
434:  �[36;1m      doas apk --no-cache add bash�[0m
435:  �[36;1m    else�[0m
436:  �[36;1m      apk --no-cache add bash�[0m
437:  �[36;1m    fi�[0m
438:  �[36;1m    printf '::endgroup::\n'�[0m
439:  �[36;1m  else�[0m
440:  �[36;1m    printf '::error::install-action requires bash\n'�[0m
441:  �[36;1m    exit 1�[0m
...

527:  Received 500023815 of 504218119 (99.2%), 79.1 MBs/sec
528:  Received 504218119 of 504218119 (100.0%), 74.4 MBs/sec
529:  Cache Size: ~481 MB (504218119 B)
530:  [command]/usr/bin/tar -xf /__w/_temp/e9af029e-96b2-4824-a20c-ca32681f0746/cache.tgz -P -C /__w/fossa-cli/fossa-cli -z
531:  Cache restored successfully
532:  Restored from cache key "ubuntu-latest-build-all-Linux-x64-1cc4a42b-1dad9a9f" full match: true.
533:  ##[group]Run ghc --version || echo "no ghc"
534:  �[36;1mghc --version || echo "no ghc"�[0m
535:  �[36;1mcabal --version || echo "no cabal"�[0m
536:  �[36;1mghcup --version || echo "no ghcup"�[0m
537:  shell: bash --noprofile --norc -e -o pipefail {0}
538:  env:
539:  CARGO_HOME: /github/home/.cargo
540:  CARGO_INCREMENTAL: 0
541:  CARGO_TERM_COLOR: always
542:  CACHE_ON_FAILURE: false
543:  ##[endgroup]
544:  The Glorious Glasgow Haskell Compilation System, version 9.8.2
545:  cabal-install version 3.10.3.0
546:  compiled using version 3.10.3.0 of the Cabal library 
547:  The GHCup Haskell installer, version 0.1.50.1
548:  ##[group]Run cargo build ${RUST_FEATURES:+--features $RUST_FEATURES} --release
549:  �[36;1mcargo build ${RUST_FEATURES:+--features $RUST_FEATURES} --release�[0m
550:  shell: bash --noprofile --norc -e -o pipefail {0}
551:  env:
552:  CARGO_HOME: /github/home/.cargo
553:  CARGO_INCREMENTAL: 0
554:  CARGO_TERM_COLOR: always
555:  CACHE_ON_FAILURE: false
556:  RUST_FEATURES: jemalloc
557:  ##[endgroup]
558:  �[1m�[32m    Updating�[0m crates.io index
559:  �[1m�[32m   Compiling�[0m berkeleydb v1.0.0 (/__w/fossa-cli/fossa-cli/extlib/berkeleydb)
560:  �[1m�[32m   Compiling�[0m millhone v0.4.0 (/__w/fossa-cli/fossa-cli/extlib/millhone)
561:  �[1m�[32m   Compiling�[0m diagnose v1.0.0 (/__w/fossa-cli/fossa-cli/tools/diagnose)
562:  �[1m�[32m    Finished�[0m `release` profile [optimized] target(s) in 1m 43s
563:  ##[group]Run cargo nextest run --release
564:  �[36;1mcargo nextest run --release�[0m
565:  shell: bash --noprofile --norc -e -o pipefail {0}
566:  env:
567:  CARGO_HOME: /github/home/.cargo
568:  CARGO_INCREMENTAL: 0
569:  CARGO_TERM_COLOR: always
570:  CACHE_ON_FAILURE: false
571:  ##[endgroup]
...

614:  �[32;1m        PASS�[0m [   0.005s] �[35;1mmillhone�[0m �[36mextract::tests�[0m�[36m::�[0m�[34;1mtext_location_complicated�[0m
615:  �[32;1m        PASS�[0m [   0.005s] �[35;1mmillhone�[0m �[36mextract::tests�[0m�[36m::�[0m�[34;1mtext_location_simple�[0m
616:  �[32;1m        PASS�[0m [   0.004s] �[35;1mmillhone�[0m �[36mextract::tests�[0m�[36m::�[0m�[34;1munknown_on_missing_ext�[0m
617:  �[32;1m        PASS�[0m [   0.004s] �[35;1mmillhone�[0m �[36mextract::tests�[0m�[36m::�[0m�[34;1munsupported_on_invalid_ext�[0m
618:  �[32;1m        PASS�[0m [   0.008s] �[35;1mmillhone::bin/millhone�[0m �[36mcmd::analyze_container::tests�[0m�[36m::�[0m�[34;1mit_finds_nested_jars�[0m
619:  �[32;1m        PASS�[0m [   0.025s] �[35;1mmillhone::bin/millhone�[0m �[36mcmd::analyze_container::tests�[0m�[36m::�[0m�[34;1mit_finds_expected_output�[0m
620:  ────────────
621:  �[32;1m     Summary�[0m [   0.374s] �[1m41�[0m tests run: �[1m41�[0m �[32;1mpassed�[0m, �[1m0�[0m �[33;1mskipped�[0m
622:  ##[group]Run cargo run --release --bin diagnose -- walk --trace-spans none --trace-level info
623:  �[36;1mcargo run --release --bin diagnose -- walk --trace-spans none --trace-level info�[0m
624:  shell: bash --noprofile --norc -e -o pipefail {0}
625:  env:
626:  CARGO_HOME: /github/home/.cargo
627:  CARGO_INCREMENTAL: 0
628:  CARGO_TERM_COLOR: always
629:  CACHE_ON_FAILURE: false
630:  ##[endgroup]
631:  �[1m�[32m   Compiling�[0m diagnose v1.0.0 (/__w/fossa-cli/fossa-cli/tools/diagnose)
632:  �[1m�[32m    Finished�[0m `release` profile [optimized] target(s) in 39.30s
633:  �[1m�[32m     Running�[0m `target/release/diagnose walk --trace-spans none --trace-level info`
634:  �[2m2025-05-20T18:29:10.946902Z�[0m �[32m INFO�[0m �[1mmain�[0m�[1m{�[0m�[3mroot�[0m�[2m=�[0m"/__w/fossa-cli/fossa-cli"�[1m}�[0m�[2m:�[0m �[2mdiagnose::cmd::walk�[0m�[2m:�[0m inspecting root: /__w/fossa-cli/fossa-cli
635:  �[2m2025-05-20T18:29:11.051420Z�[0m �[32m INFO�[0m �[1mmain�[0m�[1m{�[0m�[3mroot�[0m�[2m=�[0m"/__w/fossa-cli/fossa-cli" �[3mroot_device_id�[0m�[2m=�[0m2065�[1m}�[0m�[2m:�[0m �[2mdiagnose::cmd::walk�[0m�[2m:�[0m entries inside '/__w/fossa-cli/fossa-cli' inspected: 8583
636:  �[2m2025-05-20T18:29:11.051438Z�[0m �[32m INFO�[0m �[1mmain�[0m�[1m{�[0m�[3mroot�[0m�[2m=�[0m"/__w/fossa-cli/fossa-cli" �[3mroot_device_id�[0m�[2m=�[0m2065�[1m}�[0m�[2m:�[0m �[2mdiagnose::cmd::walk�[0m�[2m:�[0m directories: 1013; files: 7570
637:  �[2m2025-05-20T18:29:11.051441Z�[0m �[32m INFO�[0m �[1mmain�[0m�[1m{�[0m�[3mroot�[0m�[2m=�[0m"/__w/fossa-cli/fossa-cli" �[3mroot_device_id�[0m�[2m=�[0m2065�[1m}�[0m�[2m:�[0m �[2mdiagnose::cmd::walk�[0m�[2m:�[0m deepest level: 11 ('/__w/fossa-cli/fossa-cli/target/release/build/tikv-jemalloc-sys-03975aa2a0e63c05/out/build/msvc/projects/vc2017/test_threads/test_threads.vcxproj')
638:  ##[group]Run git config --global --add safe.directory "$GITHUB_WORKSPACE"
639:  �[36;1mgit config --global --add safe.directory "$GITHUB_WORKSPACE"�[0m
640:  shell: bash --noprofile --norc -e -o pipefail {0}
641:  env:
642:  CARGO_HOME: /github/home/.cargo
643:  CARGO_INCREMENTAL: 0
644:  CARGO_TERM_COLOR: always
645:  CACHE_ON_FAILURE: false
646:  ##[endgroup]
647:  ##[group]Run git status --porcelain
648:  �[36;1mgit status --porcelain�[0m
649:  �[36;1mecho "parent_commit=$(git rev-parse HEAD^)" >> $GITHUB_ENV�[0m
650:  shell: bash --noprofile --norc -e -o pipefail {0}
651:  env:
652:  CARGO_HOME: /github/home/.cargo
653:  CARGO_INCREMENTAL: 0
654:  CARGO_TERM_COLOR: always
655:  CACHE_ON_FAILURE: false
656:  ##[endgroup]
657:  ##[group]Run ./.github/workflows/scripts/compute_cache_key.sh Linux cabal.project.ci.linux
658:  �[36;1m./.github/workflows/scripts/compute_cache_key.sh Linux cabal.project.ci.linux�[0m
659:  shell: bash --noprofile --norc -e -o pipefail {0}
660:  env:
661:  CARGO_HOME: /github/home/.cargo
662:  CARGO_INCREMENTAL: 0
663:  CARGO_TERM_COLOR: always
664:  CACHE_ON_FAILURE: false
665:  parent_commit: 3e95966398c2d350db2b8fb6f0f4482d7d833b81
...

1291:  ##[group]Run actions/cache@v4
1292:  with:
1293:  path: ~/.local/state/cabal
1294:  key: Linux-9.8.2-cabal-cache-bff2880936a24d232c9f62f53efc669e580cc9a053e47a9ff850b01cc49d2927
1295:  restore-keys: Linux-9.8.2-cabal-cache-
1296:  Linux-9.8.2-
1297:  
1298:  enableCrossOsArchive: false
1299:  fail-on-cache-miss: false
1300:  lookup-only: false
1301:  save-always: false
1302:  env:
1303:  CARGO_HOME: /github/home/.cargo
1304:  CARGO_INCREMENTAL: 0
1305:  CARGO_TERM_COLOR: always
1306:  CACHE_ON_FAILURE: false
1307:  parent_commit: 3e95966398c2d350db2b8fb6f0f4482d7d833b81
...

1319:  with:
1320:  path: /home/runner/work/fossa-cli/fossa-cli/dist-newstyle
1321:  key: Linux-9.8.2-dist-newstyle-83e2774b10a4ccc1224392cb5481e39a87ad7b47
1322:  restore-keys: Linux-9.8.2-dist-newstyle-3e95966398c2d350db2b8fb6f0f4482d7d833b81
1323:  Linux-9.8.2-dist-newstyle-
1324:  Linux-9.8.2-
1325:  
1326:  enableCrossOsArchive: false
1327:  fail-on-cache-miss: false
1328:  lookup-only: false
1329:  save-always: false
1330:  env:
1331:  CARGO_HOME: /github/home/.cargo
1332:  CARGO_INCREMENTAL: 0
1333:  CARGO_TERM_COLOR: always
1334:  CACHE_ON_FAILURE: false
1335:  parent_commit: 3e95966398c2d350db2b8fb6f0f4482d7d833b81
...

1342:  Received 293601280 of 454351256 (64.6%), 69.9 MBs/sec
1343:  Received 402653184 of 454351256 (88.6%), 75.7 MBs/sec
1344:  Received 454351256 of 454351256 (100.0%), 76.3 MBs/sec
1345:  Cache Size: ~433 MB (454351256 B)
1346:  [command]/usr/bin/tar -xf /__w/_temp/a5de5401-943c-4b1f-a370-94403200f259/cache.tgz -P -C /__w/fossa-cli/fossa-cli -z
1347:  Cache restored successfully
1348:  Cache restored from key: Linux-9.8.2-dist-newstyle-3e95966398c2d350db2b8fb6f0f4482d7d833b81
1349:  ##[group]Run mkdir vendor-bins
1350:  �[36;1mmkdir vendor-bins�[0m
1351:  �[36;1m./vendor_download.sh�[0m
1352:  shell: bash --noprofile --norc -e -o pipefail {0}
1353:  env:
1354:  CARGO_HOME: /github/home/.cargo
1355:  CARGO_INCREMENTAL: 0
1356:  CARGO_TERM_COLOR: always
1357:  CACHE_ON_FAILURE: false
1358:  parent_commit: 3e95966398c2d350db2b8fb6f0f4482d7d833b81
...

1389:  -rwxr-xr-x    1 root     root       24.9M May 20 18:30 index.gob.xz
1390:  -rwxr-xr-x    1 root     root        3.3M May 20 18:30 lernie
1391:  -rwxr-xr-x    1 root     root        8.0M May 20 18:30 themis-cli
1392:  Checking binary versions
1393:  circe: circe 1.0.0
1394:  lernie: lernie v0.3.1
1395:  2025/05/20 18:30:39 maxprocs: Leaving GOMAXPROCS=4: CPU quota undefined
1396:  themis-cli: Version: 1.0.37
1397:  ##[group]Run ./.github/workflows/scripts/build.sh Linux cabal.project.ci.linux
1398:  �[36;1m./.github/workflows/scripts/build.sh Linux cabal.project.ci.linux�[0m
1399:  shell: bash --noprofile --norc -e -o pipefail {0}
1400:  env:
1401:  CARGO_HOME: /github/home/.cargo
1402:  CARGO_INCREMENTAL: 0
1403:  CARGO_TERM_COLOR: always
1404:  CACHE_ON_FAILURE: false
1405:  parent_commit: 3e95966398c2d350db2b8fb6f0f4482d7d833b81
...

1412:  + git config --global --add safe.directory /__w/fossa-cli/fossa-cli
1413:  + echo '{- 15145005220 -}'
1414:  + cabal update
1415:  Downloading the latest package list from hackage.haskell.org
1416:  Package list of hackage.haskell.org is up to date.
1417:  The index-state is set to 2025-05-20T18:21:05Z.
1418:  + cabal build '--project-file=cabal.project.ci.linux' all
1419:  Resolving dependencies...
1420:  Build profile: -w ghc-9.8.2 -O2
1421:  In order, the following will be built (use -v for more details):
1422:  - spectrometer-0.1.0.0 (lib) (file target/release/millhone changed)
1423:  - spectrometer-0.1.0.0 (test:unit-tests) (dependency rebuilt)
1424:  - spectrometer-0.1.0.0 (test:integration-tests) (dependency rebuilt)
1425:  - spectrometer-0.1.0.0 (exe:fossa) (dependency rebuilt)
1426:  ./spectrometer.cabal has been changed. Re-configuring with most recently used
1427:  options. If this fails, please run configure manually.
1428:  Configuring library for spectrometer-0.1.0.0..
1429:  Preprocessing library for spectrometer-0.1.0.0..
1430:  Building library for spectrometer-0.1.0.0..
1431:  [166 of 358] Compiling Strategy.Node.Pnpm.PnpmLock ( src/Strategy/Node/Pnpm/PnpmLock.hs, /__w/fossa-cli/fossa-cli/dist-newstyle/build/x86_64-linux/ghc-9.8.2/spectrometer-0.1.0.0/opt/build/Strategy/Node/Pnpm/PnpmLock.o, /__w/fossa-cli/fossa-cli/dist-newstyle/build/x86_64-linux/ghc-9.8.2/spectrometer-0.1.0.0/opt/build/Strategy/Node/Pnpm/PnpmLock.dyn_o ) [Source file changed]
1432:  [188 of 358] Compiling App.Version.TH   ( src/App/Version/TH.hs, /__w/fossa-cli/fossa-cli/dist-newstyle/build/x86_64-linux/ghc-9.8.2/spectrometer-0.1.0.0/opt/build/App/Version/TH.o, /__w/fossa-cli/fossa-cli/dist-newstyle/build/x86_64-linux/ghc-9.8.2/spectrometer-0.1.0.0/opt/build/App/Version/TH.dyn_o ) [/__w/fossa-cli/fossa-cli/.git/index changed]
1433:  [189 of 358] Compiling App.Version      ( src/App/Version.hs, /__w/fossa-cli/fossa-cli/dist-newstyle/build/x86_64-linux/ghc-9.8.2/spectrometer-0.1.0.0/opt/build/App/Version.o, /__w/fossa-cli/fossa-cli/dist-newstyle/build/x86_64-linux/ghc-9.8.2/spectrometer-0.1.0.0/opt/build/App/Version.dyn_o ) [Source file changed]
1434:  [190 of 358] Compiling App.Fossa.Analyze.Record ( src/App/Fossa/Analyze/Record.hs, /__w/fossa-cli/fossa-cli/dist-newstyle/build/x86_64-linux/ghc-9.8.2/spectrometer-0.1.0.0/opt/build/App/Fossa/Analyze/Record.o, /__w/fossa-cli/fossa-cli/dist-newstyle/build/x86_64-linux/ghc-9.8.2/spectrometer-0.1.0.0/opt/build/App/Fossa/Analyze/Record.dyn_o ) [App.Version changed]
1435:  [201 of 358] Compiling App.Fossa.EmbeddedBinary ( src/App/Fossa/EmbeddedBinary.hs, /__w/fossa-cli/fossa-cli/dist-newstyle/build/x86_64-linux/ghc-9.8.2/spectrometer-0.1.0.0/opt/build/App/Fossa/EmbeddedBinary.o, /__w/fossa-cli/fossa-cli/dist-newstyle/build/x86_64-linux/ghc-9.8.2/spectrometer-0.1.0.0/opt/build/App/Fossa/EmbeddedBinary.dyn_o ) [target/release/berkeleydb changed]
1436:  [224 of 358] Compiling App.Fossa.Analyze.Debug ( src/App/Fossa/Analyze/Debug.hs, /__w/fossa-cli/fossa-cli/dist-newstyle/build/x86_64-linux/ghc-9.8.2/spectrometer-0.1.0.0/opt/build/App/Fossa/Analyze/Debug.o, /__w/fossa-cli/fossa-cli/dist-newstyle/build/x86_64-linux/ghc-9.8.2/spectrometer-0.1.0.0/opt/build/App/Fossa/Analyze/Debug.dyn_o ) [App.Version changed]
1437:  [334 of 358] Compiling App.Fossa.Analyze.ScanSummary ( src/App/Fossa/Analyze/ScanSummary.hs, /__w/fossa-cli/fossa-cli/dist-newstyle/build/x86_64-linux/ghc-9.8.2/spectrometer-0.1.0.0/opt/build/App/Fossa/Analyze/ScanSummary.o, /__w/fossa-cli/fossa-cli/dist-newstyle/build/x86_64-linux/ghc-9.8.2/spectrometer-0.1.0.0/opt/build/App/Fossa/Analyze/ScanSummary.dyn_o ) [App.Version changed]
1438:  [358 of 358] Compiling App.Fossa.Main   ( src/App/Fossa/Main.hs, /__w/fossa-cli/fossa-cli/dist-newstyle/build/x86_64-linux/ghc-9.8.2/spectrometer-0.1.0.0/opt/build/App/Fossa/Main.o, /__w/fossa-cli/fossa-cli/dist-newstyle/build/x86_64-linux/ghc-9.8.2/spectrometer-0.1.0.0/opt/build/App/Fossa/Main.dyn_o ) [App.Version changed]
1439:  ./spectrometer.cabal has been changed. Re-configuring with most recently used
1440:  options. If this fails, please run configure manually.
1441:  ./spectrometer.cabal has been changed. Re-configuring with most recently used
1442:  options. If this fails, please run configure manually.
1443:  ./spectrometer.cabal has been changed. Re-configuring with most recently used
1444:  options. If this fails, please run configure manually.
1445:  Configuring test suite 'unit-tests' for spectrometer-0.1.0.0..
1446:  Configuring test suite 'integration-tests' for spectrometer-0.1.0.0..
1447:  Configuring executable 'fossa' for spectrometer-0.1.0.0..
1448:  Preprocessing executable 'fossa' for spectrometer-0.1.0.0..
1449:  Building executable 'fossa' for spectrometer-0.1.0.0..
1450:  Preprocessing test suite 'integration-tests' for spectrometer-0.1.0.0..
1451:  Building test suite 'integration-tests' for spectrometer-0.1.0.0..
1452:  [1 of 1] Compiling Main             ( app/fossa/Main.hs, /__w/fossa-cli/fossa-cli/dist-newstyle/build/x86_64-linux/ghc-9.8.2/spectrometer-0.1.0.0/x/fossa/opt/build/fossa/fossa-tmp/Main.o ) [App.Fossa.Main changed]
1453:  Preprocessing test suite 'unit-tests' for spectrometer-0.1.0.0..
1454:  Building test suite 'unit-tests' for spectrometer-0.1.0.0..
1455:  [2 of 2] Linking /__w/fossa-cli/fossa-cli/dist-newstyle/build/x86_64-linux/ghc-9.8.2/spectrometer-0.1.0.0/x/fossa/opt/build/fossa/fossa [Objects changed]
1456:  [26 of 26] Linking /__w/fossa-cli/fossa-cli/dist-newstyle/build/x86_64-linux/ghc-9.8.2/spectrometer-0.1.0.0/t/integration-tests/opt/build/integration-tests/integration-tests [Library changed]
1457:  [ 73 of 171] Compiling Pnpm.PnpmLockSpec ( test/Pnpm/PnpmLockSpec.hs, /__w/fossa-cli/fossa-cli/dist-newstyle/build/x86_64-linux/ghc-9.8.2/spectrometer-0.1.0.0/t/unit-tests/opt/build/unit-tests/unit-tests-tmp/Pnpm/PnpmLockSpec.o ) [Strategy.Node.Pnpm.PnpmLock changed]
1458:  test/Pnpm/PnpmLockSpec.hs:76:14: warning: [GHC-63394] [-Wx-partial]
1459:  In the use of ‘head’
1460:  (imported from Prelude, but defined in GHC.List):
1461:  "This is a partial function, it throws an error on empty lists. Use pattern matching or Data.List.uncons instead. Consider refactoring to use Data.List.NonEmpty."
1462:  |
...

1470:  - spectrometer-0.1.0.0 (test:unit-tests) (ephemeral targets)
1471:  Preprocessing test suite 'unit-tests' for spectrometer-0.1.0.0..
1472:  Building test suite 'unit-tests' for spectrometer-0.1.0.0..
1473:  Running 1 test suites...
1474:  Test suite unit-tests: RUNNING...
1475:  AdjacencyMap
1476:  splitGraph
1477:  should correctly split trivial acyclic graphs [�[32m✔�[0m]
1478:  should correctly split a graph with mutual children [�[32m✔�[0m]
1479:  should reject cyclic graphs [�[32m✔�[0m]
1480:  AlpineLinux.Parser
1481:  installedPackagesDatabaseParser
1482:  parses empty files [�[32m✔�[0m]
1483:  parses the example database [�[32m✔�[0m]
1484:  trims the returned strings [�[32m✔�[0m]
1485:  parses an error if the package name is missing [�[32m✔�[0m]
1486:  parses an error if the package architecture is missing [�[32m✔�[0m]
1487:  parses an error if the package architecture is missing [�[32m✔�[0m]
1488:  Android.Util
...

1560:  https://github.com/fossas/fossa-cli/blob/pnpm-9-lockfile-fix/docs/references/files/fossa-deps.md should be reachable [�[33m‐�[0m]
1561:  �[33m      # PENDING: No reason given�[0m
1562:  https://github.com/fossas/fossa-cli/blob/pnpm-9-lockfile-fix/docs/references/subcommands/analyze.md#what-are-the-default-path-filters should be reachable [�[33m‐�[0m]
1563:  �[33m      # PENDING: No reason given�[0m
1564:  https://github.com/fossas/fossa-cli/blob/pnpm-9-lockfile-fix/docs/references/subcommands/container.md#ignore-default-filters should be reachable [�[33m‐�[0m]
1565:  �[33m      # PENDING: No reason given�[0m
1566:  App.Fossa.Analyze
1567:  Discovery function list
1568:  should be length 35 [�[32m✔�[0m]
1569:  App.Fossa.Analyze.Upload
1570:  uploadSuccessfulAnalysis
1571:  uploads analysis and git contributors [�[32m✔�[0m]
1572:  {"branch":"testBranch","id":"testLocator+testProject$testRevision","project":"testProject","projectId":"testLocator+testProject","revision":"testRevision","url":"https://app.fossa.com/account/saml/42?next=/projects/testLocator%252btestProject/refs/branch/testBranch/testRevision"}    renders JSON output when requested [�[32m✔�[0m]
1573:  performs reachability upload, if organization supports reachability [�[32m✔�[0m]
1574:  aborts when uploading to a monorepo [�[32m✔�[0m]
1575:  continues if fetching the project fails [�[32m✔�[0m]
1576:  continues if fetching contributors fails [�[32m✔�[0m]
1577:  continues if uploading contributors fails [�[32m✔�[0m]
1578:  uploads to S3 and to /api/builds/custom_with_first_party_licenses if there are licenses [�[32m✔�[0m]
...

1583:  App.Fossa.API.BuildLink
1584:  BuildLink
1585:  SAML URL builder
1586:  should render simple locators [�[32m✔�[0m]
1587:  should render git@ locators [�[32m✔�[0m]
1588:  should render full url correctly [�[32m✔�[0m]
1589:  Standard URL Builder
1590:  should render simple links [�[32m✔�[0m]
1591:  Fossa URL Builder
1592:  should render from API info [�[32m✔�[0m]
1593:  App.Fossa.API.BuildWait
1594:  BuildWait
1595:  waitForScanCompletion
1596:  should return when the build is complete [�[32m✔�[0m]
1597:  should retry periodically if the build is not complete [�[32m✔�[0m]
1598:  should die if the build fails [�[32m✔�[0m]
1599:  should cancel when the timeout expires [�[32m✔�[0m]
1600:  waitForIssues
1601:  should return when the issues are avilable [�[32m✔�[0m]
1602:  should return when the issues diffs are available [�[32m✔�[0m]
1603:  should retry periodically if the issues are not available [�[32m✔�[0m]
1604:  should cancel when the timeout expires [�[32m✔�[0m]
1605:  waitForBuild
1606:  should return when the build is complete [�[32m✔�[0m]
1607:  should retry periodically if the build is not complete [�[32m✔�[0m]
1608:  should die if the build fails [�[32m✔�[0m]
1609:  should cancel when the timeout expires [�[32m✔�[0m]
1610:  waitForReportReadiness
1611:  should return when the dependency cache are ready [�[32m✔�[0m]
1612:  should retry periodically if the revision's dependency cache is in waiting state [�[32m✔�[0m]
1613:  should cancel when the timeout expires [�[32m✔�[0m]
1614:  App.Fossa.ApiUtils
1615:  retrievePolicyId
1616:  should fail when the policy title does not exist [�[32m✔�[0m]
1617:  should fail when the policy type does not match [�[32m✔�[0m]
1618:  should fail when there are multiple policies with the same name [�[32m✔�[0m]
1619:  should return Nothing [�[32m✔�[0m]
1620:  should successfully retrieve policy id [�[32m✔�[0m]
1621:  retrieveTeamIdsWithMaybe
1622:  should return Nothing if the team names is Nothing [�[32m✔�[0m]
1623:  should successfully retrieve all team ids [�[32m✔�[0m]
1624:  retrieveTeamIds
1625:  should fail if not all team names exist in org [�[32m✔�[0m]
1626:  should successfully retrieve all team ids [�[32m✔�[0m]
...

1634:  App.Fossa.BinaryDeps.Jar
1635:  handle JAR with multiple pom.xml
1636:  parses the jar correctly [�[32m✔�[0m]
1637:  handle JAR with one pom.xml
1638:  parses the jar correctly [�[32m✔�[0m]
1639:  handle JAR without pom.xml
1640:  parses the jar correctly [�[32m✔�[0m]
1641:  App.Fossa.Circe
1642:  Circe binary
1643:  should be extractable [�[32m✔�[0m]
1644:  should run with --version argument [�[32m✔�[0m]
1645:  App.Fossa.Config.Analyze
1646:  loadConfig
1647:  should load from the configured base dir [�[32m✔�[0m]
1648:  5 labels are the max
1649:  should fail when labels exceed 5 [�[32m✔�[0m]
1650:  App.Fossa.Config.ReleaseGroup.Create
1651:  mergeOpts
1652:  should use values from create opts when both create opts and config values are present [�[32m✔�[0m]
1653:  should use values from config when create opts values are empty [�[32m✔�[0m]
1654:  should fail when no title is provided [�[32m✔�[0m]
1655:  should fail when no release is provided [�[32m✔�[0m]
1656:  should fail when no projects are provided [�[32m✔�[0m]
1657:  App.Fossa.Config.Test
1658:  loadConfig
1659:  should load from the configured base dir [�[32m✔�[0m]
1660:  App.Fossa.Configuration.Configuration
1661:  config file parser
1662:  parses a full config file in the default location [�[32m✔�[0m]
1663:  parses a full config file with the `yaml` extension in the default location [�[32m✔�[0m]
1664:  parses a full config file in a specified location [�[32m✔�[0m]
1665:  always returns failure for a bad file [�[32m✔�[0m]
1666:  returns Nothing for missing default file [�[32m✔�[0m]
...

1672:  by default telemetry sink set to nothing, if api key is not provided [�[32m✔�[0m]
1673:  by default telemetry sink set to full telemetry [�[32m✔�[0m]
1674:  command opts
1675:  should set sink to nothing, when off scope is provided via command opts [�[32m✔�[0m]
1676:  should set sink to endpoint, when full scope is provided via command opts [�[32m✔�[0m]
1677:  should set sink to file, when debug option is provided via command line [�[32m✔�[0m]
1678:  environment variables
1679:  should set sink to nothing, when off scope is provided via environment variables [�[32m✔�[0m]
1680:  should set sink to endpoint, when full scope is provided via environment variables [�[32m✔�[0m]
1681:  should set sink to file, when debug option is provided via environment variable [�[32m✔�[0m]
1682:  configuration file
1683:  should set sink to nothing, when off scope is provided via configuration file [�[32m✔�[0m]
1684:  should set sink to endpoint, when full scope is provided via configuration file [�[32m✔�[0m]
1685:  App.Fossa.Container.AnalyzeNative
1686:  parseDockerEngineSource
1687:  should fail if docker engine is not accessible [�[32m✔�[0m]
1688:  should fail if text lacks tag signifier  [�[32m✔�[0m]
1689:  should fail if image's size cannot be retrieved [�[32m✔�[0m]
1690:  should parse image source if image size can be inferred via docker api [�[32m✔�[0m]
...

1693:  should analyze application dependencies [�[32m✔�[0m]
1694:  should apply tool exclusion filter [�[32m✔�[0m]
1695:  should apply project exclusion filter [�[32m✔�[0m]
1696:  should analyze all targets, if default filter is disabled [�[32m✔�[0m]
1697:  should apply path exclusion filter [�[32m✔�[0m]
1698:  Jars in Containers
1699:  Reads and merges the layers correctly [�[32m✔�[0m]
1700:  Each layer should have the expected number of JAR observations [�[32m✔�[0m]
1701:  Discovers non-system/non-JIC dependencies [�[32m✔�[0m]
1702:  Nested Jars in Containers
1703:  Reads and merges the layers correctly [�[32m✔�[0m]
1704:  Each layer should have the expected number of JAR observations [�[32m✔�[0m]
1705:  App.Fossa.Container.AnalyzeNativeUpload
1706:  Native Container Upload
1707:  should upload native container upload, when org supports native container scanning [�[32m✔�[0m]
1708:  should fail uploading native container scan, when org does not supports native container scanning [�[32m✔�[0m]
1709:  {"branch":"master","id":"testLocator+testProject$testRevision","project":"testProject","revision":"testRevision","url":"https://app.fossa.com/account/saml/42?next=/projects/testLocator%252btestProject/refs/branch/master/testRevision"}    should render JSON when requested [�[32m✔�[0m]
1710:  App.Fossa.FirstPartyScan
1711:  runFirstPartyScan
1712:  should fail if the organization does not support first party scans and you force it on [�[32m✔�[0m]
1713:  should not run if the organization does not support first-party scans and it is not forced on [�[32m✔�[0m]
...

1719:  should upload matchData if the org does not default to full-file uploads [�[32m✔�[0m]
1720:  should skip scanning manual deps [�[32m✔�[0m]
1721:  should find notice files [�[32m✔�[0m]
1722:  App.Fossa.Init
1723:  .fossa.yml
1724:  should write valid .fossa.yml.example file [�[32m✔�[0m]
1725:  fossa-deps.yml
1726:  should write valid fossa-deps file [�[32m✔�[0m]
1727:  App.Fossa.Lernie
1728:  lernieMessagesToLernieResults
1729:  should create a proper LernieResults [�[32m✔�[0m]
1730:  should deal properly with two of the same license found in one file [�[32m✔�[0m]
1731:  addLernieMessage
1732:  should add a match to matches [�[32m✔�[0m]
1733:  should add a warning to warnings [�[32m✔�[0m]
1734:  should add an error to errors [�[32m✔�[0m]
1735:  grepOptionsToLernieConfig
...

1756:  should upload with the fullFiles flag if the org requires full files [�[32m✔�[0m]
1757:  App.Fossa.ManualDeps
1758:  fossa-deps json parser
1759:  should parse json correctly [�[32m✔�[0m]
1760:  fossa-deps labeled
1761:  should successfully parse all possible inputs [�[32m✔�[0m]
1762:  should extract nested labels with orgId [�[32m✔�[0m]
1763:  should extract nested labels without orgId [�[32m✔�[0m]
1764:  fossa-deps yaml parser
1765:  should successfully parse all possible inputs [�[32m✔�[0m]
1766:  should report an unsupported type [�[32m✔�[0m]
1767:  should report license used on referenced deps [�[32m✔�[0m]
1768:  reference dependency
1769:  should parse linux reference dependency [�[32m✔�[0m]
1770:  should parse rpm reference dependency with epoch [�[32m✔�[0m]
1771:  should fail when linux reference dependency of deb or apk contains epoch [�[32m✔�[0m]
1772:  should fail when linux reference dependency does not include arch information [�[32m✔�[0m]
1773:  should fail when linux reference dependency does not include os information [�[32m✔�[0m]
1774:  should fail when linux reference dependency uses not supported os [�[32m✔�[0m]
1775:  should fail when managed reference dependency provides os information [�[32m✔�[0m]
1776:  should fail when linux reference dependency of deb or apk contains epoch [�[32m✔�[0m]
1777:  remote dependency
1778:  should fail when remote dependency has empty name or only whitespace [�[32m✔�[0m]
1779:  should fail when remote dependency has empty version or only whitespace [�[32m✔�[0m]
1780:  should fail when remote dependency has empty url or only whitespace [�[32m✔�[0m]
1781:  custom dependency
1782:  should fail when custom dependency has empty name or only whitespace [�[32m✔�[0m]
1783:  should fail when custom dependency has empty version or only whitespace [�[32m✔�[0m]
1784:  should fail when custom dependency has empty license or only whitespace [�[32m✔�[0m]
1785:  vendor dependency
1786:  should fail when vendor dependency has empty name or only whitespace [�[32m✔�[0m]
1787:  should fail when vendor dependency has empty path or only whitespace [�[32m✔�[0m]
1788:  should fail when vendor dependency has version with not supported character [�[32m✔�[0m]
1789:  locator dependency
1790:  should fail when locator dependency is empty [�[32m✔�[0m]
1791:  getScanCfg
1792:  should fail if you try to force a license scan but the FOSSA server does not support it [�[32m✔�[0m]
1793:  should do a license scan if requested and FOSSA supports it [�[32m✔�[0m]
...

1820:  should perform path dependency scan and upload, if path dependency is not already analyzed [�[32m✔�[0m]
1821:  should not perform path dependency scan and upload, if path dependency is already analyzed [�[32m✔�[0m]
1822:  includeAll [--include-unused-deps]
1823:  should not perform enrichment for non-production path deps [�[32m✔�[0m]
1824:  should perform enrichment for non-production path deps, when flag is included [�[32m✔�[0m]
1825:  fullFile
1826:  should upload with fullFile, if org requires fullfile [�[32m✔�[0m]
1827:  should upload with matchData, if org does not requires fullfile [�[32m✔�[0m]
1828:  forceRescan
1829:  should not retrieve analyzed versions, if forceRescan is true [�[32m✔�[0m]
1830:  should retrieve analyzed versions, if forceRescan is false [�[32m✔�[0m]
1831:  App.Fossa.PreflightChecks
1832:  preflight checks
1833:  should pass all checks for test command [�[32m✔�[0m]
1834:  should pass all check for report command [�[32m✔�[0m]
1835:  should fail full access token check for report command [�[32m✔�[0m]
1836:  should pass all custom upload permission checks for analyze command [�[32m✔�[0m]
1837:  should pass all checks while skipping permission checks for analyze command [�[32m✔�[0m]
1838:  should fail edit project check for analyze command [�[32m✔�[0m]
1839:  should fail create project check for analyze command [�[32m✔�[0m]
1840:  should fail create team project check for analyze command [�[32m✔�[0m]
1841:  should fail create project only for team check for analyze command [�[32m✔�[0m]
1842:  should fail edit release group check for analyze command [�[32m✔�[0m]
1843:  should fail create team projects for release group check for analyze command [�[32m✔�[0m]
1844:  App.Fossa.Project.Edit
1845:  Edit Project
1846:  should fail when a project does not have a latest revision [�[32m✔�[0m]
1847:  Project `custom+123/example-locator` has been updated successfully.
1848:  should successfully execute with ProjectIdentifier ProjectLocator [�[32m✔�[0m]
1849:  Project `custom+123/example-locator` has been updated successfully.
1850:  should successfully execute with ProjectIdentifier ProjectId [�[32m✔�[0m]
1851:  App.Fossa.ProjectInference
1852:  linesWithoutCR
1853:  should remove CR from lines if present [�[32m✔�[0m]
1854:  should remove CR from lines [�[32m✔�[0m]
1855:  App.Fossa.ReleaseGroup.AddProjects
1856:  constructUpdateRequest
1857:  should successfully create an UpdateReleaseRequest [�[32m✔�[0m]
1858:  Add Release Group Projects
1859:  should fail if release group does not exist when updating a release [�[32m✔�[0m]
1860:  should fail to update the release [�[32m✔�[0m]
1861:  Projects were added to release group release id: 2
1862:  View the updated release at: https://app.fossa.com/projects/group/1/releases/2
1863:  should successfully to update the release [�[32m✔�[0m]
1864:  App.Fossa.ReleaseGroup.Common
1865:  Delete Release Group
1866:  should fail when there are multiple release groups that match the input title [�[32m✔�[0m]
1867:  should return Nothing when release group title is not in the list of release groups [�[32m✔�[0m]
1868:  should return the release group id [�[32m✔�[0m]
1869:  Delete Release Group
1870:  should fail when there are multiple release groups that match the input release title [�[32m✔�[0m]
1871:  should fail when there are no releases that match the input release title [�[32m✔�[0m]
1872:  should return the release group release id [�[32m✔�[0m]
1873:  App.Fossa.ReleaseGroup.Create
1874:  Create Release Group
1875:  should fail when a release group with the same name already exists [�[32m✔�[0m]
1876:  Created release group with id: 1
1877:  View the created release group at: https://app.fossa.com/projects/group/1
1878:  should create release group [�[32m✔�[0m]
1879:  App.Fossa.ReleaseGroup.CreateRelease
1880:  Create Release Group Release
1881:  should fail if release group does not exist when creating a release [�[32m✔�[0m]
1882:  should fail to create a release group release [�[32m✔�[0m]
1883:  Created release group release with id: 2
1884:  View the created release group release at: https://app.fossa.com/projects/group/1/releases/2
1885:  should successfully create a release group release [�[32m✔�[0m]
1886:  App.Fossa.ReleaseGroup.Delete
1887:  Delete Release Group
1888:  should fail when the release group to delete does not exist when deleting a release group [�[32m✔�[0m]
1889:  should fail to delete release group [�[32m✔�[0m]
1890:  Release group `example-title` has been deleted
1891:  should delete release group [�[32m✔�[0m]
1892:  App.Fossa.ReleaseGroup.DeleteRelease
1893:  Delete Release Group Release
1894:  should fail if release group does not exist when deleting a release [�[32m✔�[0m]
1895:  should fail when there is only one release [�[32m✔�[0m]
1896:  should fail to delete release group release [�[32m✔�[0m]
1897:  Release `example-release-title` has been deleted
1898:  should delete release group release [�[32m✔�[0m]
1899:  App.Fossa.Report
1900:  Report
1901:  Custom build
1902:  should timeout if build-completion doesn't complete [�[32m✔�[0m]
1903:  should timeout if issue-generation doesn't complete [�[32m✔�[0m]
1904:  {"TestReport": "TestReportData"}      should fetch a report when the build and issues are ready [�[32m✔�[0m]
1905:  should die if fetching the build fails [�[32m✔�[0m]
1906:  should die if fetching issues fails [�[32m✔�[0m]
1907:  should die if fetching the report fails [�[32m✔�[0m]
1908:  Every value of ReportOutputJson can be parsed from a string matching its Show instance
1909:  Parses "csv" [�[32m✔�[0m]
1910:  Parses "cyclonedx-json" [�[32m✔�[0m]
1911:  Parses "cyclonedx-xml" [�[32m✔�[0m]
1912:  Parses "html" [�[32m✔�[0m]
1913:  Parses "json" [�[32m✔�[0m]
1914:  Parses "markdown" [�[32m✔�[0m]
1915:  Parses "text" [�[32m✔�[0m]
1916:  Parses "spdx" [�[32m✔�[0m]
1917:  Parses "spdx-json" [�[32m✔�[0m]
1918:  SBOM build
1919:  should timeout if build-completion doesn't complete [�[32m✔�[0m]
1920:  should timeout if issue-generation doesn't complete [�[32m✔�[0m]
1921:  {"TestReport": "TestReportData"}      should fetch a report when the build and issues are ready [�[32m✔�[0m]
1922:  should die if fetching the build fails [�[32m✔�[0m]
1923:  should die if fetching issues fails [�[32m✔�[0m]
1924:  should die if fetching the report fails [�[32m✔�[0m]
1925:  Every value of ReportOutputJson can be parsed from a string matching its Show instance
...

2001:  multi line file
2002:  fingerprints raw correctly [�[32m✔�[0m]
2003:  fingerprints comment stripped correctly [�[32m✔�[0m]
2004:  multi line file with comment
2005:  fingerprints raw correctly [�[32m✔�[0m]
2006:  fingerprints comment stripped correctly [�[32m✔�[0m]
2007:  multi line file with comment (windows)
2008:  fingerprints raw correctly [�[32m✔�[0m]
2009:  fingerprints comment stripped correctly [�[32m✔�[0m]
2010:  App.Fossa.VSI.IAT.Resolve
2011:  resolveUserDefined
2012:  returns Nothing if there are no deps [�[32m✔�[0m]
2013:  returns all user defined dependencies that are found [�[32m✔�[0m]
2014:  resolveRevision
2015:  ignores non-top-level locators [�[32m✔�[0m]
2016:  returns Nothing if there is an error [�[32m✔�[0m]
2017:  resolves dependencies for top-level locators [�[32m✔�[0m]
...

2108:  conanToVendoredDep
2109:  should transforms conan to vendor dep, when dep has location [�[32m✔�[0m]
2110:  should not transforms conan to vendor dep, when dep does not have location [�[32m✔�[0m]
2111:  locatorToArchiveDep
2112:  should transforms archive locator to vendor dep [�[32m✔�[0m]
2113:  should not transforms non-archive locator to vendor dep [�[32m✔�[0m]
2114:  findArchiveTwin
2115:  should find archive sibling for given conan dependency [�[32m✔�[0m]
2116:  should not find archive sibling for inequivalent conan dependency (dep name differs) [�[32m✔�[0m]
2117:  should not find archive sibling for inequivalent conan dependency (location differs) [�[32m✔�[0m]
2118:  enrich
2119:  should transform conan dependency into archive dependency [�[32m✔�[0m]
2120:  should preserve dependency environment [�[32m✔�[0m]
2121:  should preserve dependency edges [�[32m✔�[0m]
2122:  should return supplied graph if there are no conan dependencies in the graph [�[32m✔�[0m]
2123:  should fail if there are conan dependencies without dependency locations [�[32m✔�[0m]
2124:  Conan.Version
...

2206:  should read content of file in tarball [�[32m✔�[0m]
2207:  should read content of symbolic link's target in tarball [�[32m✔�[0m]
2208:  should read content of file in tarball when root has no name [�[32m✔�[0m]
2209:  listDir
2210:  should list directories and files [�[32m✔�[0m]
2211:  should list directories and files when root has no name [�[32m✔�[0m]
2212:  resolveFile
2213:  should resolve file [�[32m✔�[0m]
2214:  should resolve file when root has no name [�[32m✔�[0m]
2215:  resolveDir
2216:  should resolve directory [�[32m✔�[0m]
2217:  should resolve directory when root has no name [�[32m✔�[0m]
2218:  Control.Carrier.Diagnostics
2219:  logWithExit_
2220:  exits on success [�[32m✔�[0m]
2221:  exits on failure [�[32m✔�[0m]
2222:  Control.Carrier.Telemetry
2223:  withTelemetry
2224:  exits on success [�[32m✔�[0m]
2225:  exits on failure [�[32m✔�[0m]
2226:  Control.Timeout
2227:  timeout'
2228:  Should set the flag after the alloted time [�[32m✔�[0m]
2229:  shouldCancelRightNow
2230:  should return true when the mvar is not empty [�[32m✔�[0m]
2231:  should return false when the mvar is empty [�[32m✔�[0m]
2232:  checkForCancel
2233:  should throw a fatal error after the alloted time [�[32m✔�[0m]
2234:  Dart.PubDeps
...

2280:  should return false when dir does not exists [�[32m✔�[0m]
2281:  lookupFileRef
2282:  should return Nothing when querying dir [�[32m✔�[0m]
2283:  should return Nothing when querying non existent entry [�[32m✔�[0m]
2284:  should return reference of file [�[32m✔�[0m]
2285:  doesFileExist
2286:  should return true when file exists [�[32m✔�[0m]
2287:  should return false when file does not exists [�[32m✔�[0m]
2288:  resolveSymLinkRef
2289:  should resolve to parent directory, when ./ is prefixed in target path [�[32m✔�[0m]
2290:  should resolve to grand parent directory, when ../ is prefixed in target path [�[32m✔�[0m]
2291:  should resolve when multiple ../ ./ prefix are consecutively used [�[32m✔�[0m]
2292:  should resolve to absolute path when / is prefixed in target path [�[32m✔�[0m]
2293:  Data.RpmDbHeaderBlob
2294:  RPM header blob parsing
2295:  headerBlob parsing errors
2296:  Should report failure when parsing nonexistent index count [�[32m✔�[0m]
2297:  Should report failure when parsing nonexistent data length [�[32m✔�[0m]
2298:  Should report too small index lengths [�[32m✔�[0m]
...

2324:  calculates length of two int32 [�[32m✔�[0m]
2325:  calculates length of an int16 [�[32m✔�[0m]
2326:  calculates length of an int8 [�[32m✔�[0m]
2327:  read package data
2328:  Reads big-endian bdb package: ubi8 Which [�[32m✔�[0m]
2329:  Reads little-endian bdb package: centos5 Vim [�[32m✔�[0m]
2330:  Reads ndb package: suse15 libncurses6 [�[32m✔�[0m]
2331:  Reads package blob with a v3 header centos6-devtools gpg pubkey [�[32m✔�[0m]
2332:  Discovery.Archive
2333:  extract zip archive to a temporary location
2334:  should have extracted the correct contents [�[32m✔�[0m]
2335:  should have cleaned up the temporary directory [�[32m✔�[0m]
2336:  extract tar archive to a temporary location
2337:  should have extracted the correct contents [�[32m✔�[0m]
2338:  should have cleaned up the temporary directory [�[32m✔�[0m]
2339:  should not thrown an error when working with empty tar file [�[32m✔�[0m]
2340:  extract tar.gz archive to a temporary location
2341:  should have extracted the correct contents [�[32m✔�[0m]
2342:  should have cleaned up the temporary directory [�[32m✔�[0m]
2343:  extract tar.xz archive to a temporary location
2344:  should have extracted the correct contents [�[32m✔�[0m]
2345:  should have cleaned up the temporary directory [�[32m✔�[0m]
2346:  extract tar.bz2 archive to a temporary location
2347:  should have extracted the correct contents [�[32m✔�[0m]
2348:  should have cleaned up the temporary directory [�[32m✔�[0m]
2349:  extract el7 (xz) rpm to a temporary location
2350:  should have extracted the correct contents [�[32m✔�[0m]
2351:  extract fc35 (zstd) rpm to a temporary location
2352:  should have extracted the correct contents [�[32m✔�[0m]
2353:  Archive unpack failures
2354:  Succeeds with a warning on archive unpack failure [�[32m✔�[0m]
2355:  Discovery.Filters
...

2390:  ignores excluded paths [�[32m✔�[0m]
2391:  Dpkg.Dpkg
2392:  Container Dpkg Parser
2393:  parses a single simple entry [�[32m✔�[0m]
2394:  parses a single realistic entry [�[32m✔�[0m]
2395:  parses two entries [�[32m✔�[0m]
2396:  parses var/lib/dpkg/status [�[32m✔�[0m]
2397:  Effect.Exec
2398:  IO-based handler
2399:  should return Left, and not throw an exception, when a command is not found [�[32m✔�[0m]
2400:  Command selection
2401:  should choose the first successful command [�[32m✔�[0m]
2402:  Command selection with override
2403:  should choose the first successful command [�[32m✔�[0m]
2404:  Command selection with no working option
2405:  should respond with an error [�[32m✔�[0m]
2406:  Effect.Logger
...

2488:  produces the expected output [�[32m✔�[0m]
2489:  works end to end [�[32m✔�[0m]
2490:  Go.GoListPackages
2491:  Graphing deps with go list -json -deps all
2492:  Graphs modules based on package dependencies [�[32m✔�[0m]
2493:  Graphs module deps when there are multiple main modules [�[32m✔�[0m]
2494:  Go.Gomod
2495:  buildGraph
2496:  constructs a trivial graph and performs overrides [�[32m✔�[0m]
2497:  renders different kinds of versions correctly [�[32m✔�[0m]
2498:  does not include locally replaced modules [�[32m✔�[0m]
2499:  gomod parser
2500:  parses a trivial example [�[32m✔�[0m]
2501:  parses each edge case [�[32m✔�[0m]
2502:  parses different kinds of module versions [�[32m✔�[0m]
2503:  parses without failure when retract statements are included [�[32m✔�[0m]
2504:  parses without failure when retract statements are included with comments [�[32m✔�[0m]
2505:  Go.GopkgLock
...

2796:  reads a file and extracts the correct license [�[32m✔�[0m]
2797:  reads a file with multiple licenses [�[32m✔�[0m]
2798:  constructs an accurate graph [�[32m✔�[0m]
2799:  NuGet.PackageReference
2800:  Package Reference parser
2801:  reads a file and constructs an accurate list of item groups [�[32m✔�[0m]
2802:  constructs an accurate graph [�[32m✔�[0m]
2803:  NuGet.PackagesConfig
2804:  packages.config analyzer
2805:  reads a file and constructs an accurate graph [�[32m✔�[0m]
2806:  constructs an accurate graph [�[32m✔�[0m]
2807:  NuGet.Paket
2808:  paket lock analyzer
2809:  produces the expected output [�[32m✔�[0m]
2810:  paket lock parser
2811:  parses error messages into an empty list [�[32m✔�[0m]
2812:  NuGet.ProjectAssetsJson
...

3123:  dependenciesOf
3124:  should upload reachability units and content [�[32m✔�[0m]
3125:  RPM.SpecFile
3126:  rpm specfile parser
3127:  should list all BuildRequires and Requires [�[32m✔�[0m]
3128:  line parser
3129:  should parse single lines correctly [�[32m✔�[0m]
3130:  rpm dependency grapher
3131:  should produce flat RuntimeRequires [�[32m✔�[0m]
3132:  Ruby.BundleShow
3133:  bundle show analyzer
3134:  produces the expected output [�[32m✔�[0m]
3135:  bundle show parser
3136:  parses ideal bundle show output [�[32m✔�[0m]
3137:  parses complex bundle show output [�[32m✔�[0m]
3138:  parses error messages into an empty list [�[32m✔�[0m]
3139:  Ruby.GemfileLock
3140:  gemfile lock analyzer
3141:  produces the expected output [�[32m✔�[0m]
3142:  gemfile lock parser
3143:  parses error messages into an empty list [�[32m✔�[0m]
3144:  Ruby.Parse
...

3264:  should parse empty list [�[32m✔�[0m]
3265:  should parse list of text [�[32m✔�[0m]
3266:  should parse list of dictionary types [�[32m✔�[0m]
3267:  should parse list of mixed types [�[32m✔�[0m]
3268:  parseAsciiDict
3269:  should parse empty dictionary [�[32m✔�[0m]
3270:  should parse dictionary with key, and value of text [�[32m✔�[0m]
3271:  should parse dictionary with key, and value of list [�[32m✔�[0m]
3272:  should parse dictionary with key, and value of dict [�[32m✔�[0m]
3273:  should parse dictionary with multiple keys, and multiple value types [�[32m✔�[0m]
3274:  parseAsciiValue
3275:  should parse any ascii value type [�[32m✔�[0m]
3276:  parsePbxProj
3277:  should parse pbxproj.project [�[32m✔�[0m]
3278:  should parse pbxproj.project with just record fields [�[32m✔�[0m]
3279:  should fail when provided with non utf-8 encoding [�[32m✔�[0m]
3280:  System.Args
...

3314:  LinkResolver
3315:  Should work for supported locators [�[32m✔�[0m]
3316:  PortalResolver
3317:  Should work for supported locators [�[32m✔�[0m]
3318:  ExecResolver
3319:  Should work for supported locators [�[32m✔�[0m]
3320:  PatchResolver
3321:  Should work for supported locators [�[32m✔�[0m]
3322:  resolveLocatorToPackage
3323:  Should prefer the tarball to the git resolver in cases where a locator would match both [�[32m✔�[0m]
3324:  Failures:
3325:  �[36m  test/GraphUtil.hs:66:57: �[0m
3326:  1) Pnpm.PnpmLock, can work with v9.0 format, with real-world pnpm repo lockfile, buildGraph with v9 format, should include dependencies of root package as direct
3327:  �[31m       Actual list is not a permutation of expected list!�[0m
3328:  �[31m         expected elements: [Dependency {dependencyType = NodeJSType, dependencyName = "@babel/core", dependencyVersion = Just (CEq "7.26.10"), dependencyLocations = [], dependencyEnvironments = fromList [EnvDevelopment], dependencyTags = fromList []}, Dependency {dependencyType = NodeJSType, dependencyName = "@babel/preset-typescript", dependencyVersion = Just (CEq "7.26.0"), dependencyLocations = [], dependencyEnvironments = fromList [EnvDevelopment], dependencyTags = fromList []}, Dependency {dependencyType = NodeJSType, dependencyName = "@babel/types", dependencyVersion = Just (CEq "7.26.10"), dependencyLocations = [], dependencyEnvironments = fromList [EnvDevelopment], dependencyTags = fromList []}, Dependency {dependencyType = NodeJSType, dependencyName = "@changesets/cli", dependencyVersion = Just (CEq "2.28.1"), dependencyLocations = [], dependencyEnvironments = fromList [EnvDevelopment], dependencyTags = fromList []}, Dependency {dependencyType = NodeJSType, dependencyName = "@commitlint/cli", dependencyVersion = Just (CEq "17.8.1"), dependencyLocations = [], dependencyEnvironments = fromList [EnvDevelopment], dependencyTags = fromList []}, Dependency {dependencyType = NodeJSType, dependencyName = "@commitlint/config-conventional", dependencyVersion = Just (CEq "17.8.1"), dependencyLocations = [], dependencyEnvironments = fromList [EnvDevelopment], dependencyTags = fromList []}, Dependency {dependencyType = NodeJSType, dependencyName = "@commitlint/prompt-cli", dependencyVersion = Just (CEq "17.8.1"), dependencyLocations = [], dependencyEnvironments = fromList [EnvDevelopment], dependencyTags = fromList []}, Dependency {dependencyType = NodeJSType, dependencyName = "@eslint/eslintrc", dependencyVersion = Just (CEq "3.1.0"), dependencyLocations = [], dependencyEnvironments = fromList [EnvProduction], dependencyTags = fromList []}, Dependency {dependencyType = NodeJSType, dependencyName = "@eslint/js", dependencyVersion = Just (CEq "9.9.1"), dependencyLocations = [], dependencyEnvironments = fromList [EnvProduction], dependencyTags = fromList []}, Dependency {dependencyType = NodeJSType, dependencyName = "@gwhitney/detect-indent", dependencyVersion = Just (CEq "7.0.1"), dependencyLocations = [], dependencyEnvironments = fromList [EnvProduction], dependencyTags = fromList []}, Dependency {dependencyType = NodeJSType, dependencyName = "@pnpm/builder.policy", dependencyVersion = Just (CEq "3.0.1"), dependencyLocations = [], dependencyEnvironments = fromList [EnvProduction], dependencyTags = fromList []}, Dependency {dependencyType = NodeJSType, dependencyName = "@pnpm/byline", dependencyVersion = Just (CEq "1.0.0"), dependencyLocations = [], dependencyEnvironments = fromList [EnvDevelopment], dependencyTags = fromList []}, Dependency {dependencyType = NodeJSType, dependencyName = "@pnpm/colorize-semver-diff", dependencyVersion = Just (CEq "1.0.1"), dependencyLocations = [], dependencyEnvironments = fromList [EnvProduction], dependencyTags = fromList []}, Dependency {dependencyType = NodeJSType, dependencyName = "@pnpm/config.env-replace", dependencyVersion = Just (CEq "3.0.1"), dependencyLocations = [], dependencyEnvironments = fromList [EnvProduction], dependencyTags = fromList []}, Dependency {dependencyType = NodeJSType, dependencyName = "@pnpm/exec", dependencyVersion = Just (CEq "2.0.0"), dependencyLocations = [], dependencyEnvironments = fromList [EnvProduction], dependencyTags = fromList []}, Dependency {dependencyType = NodeJSType, dependencyName = "@pnpm/fs.packlist", dependencyVersion = Just (CEq "2.0.0"), dependencyLocations = [], dependencyEnvironments = fromList [EnvProduction], dependencyTags = fromList []}, Dependency {dependencyType = NodeJSType, dependencyName = "@pnpm/log.group", dependencyVersion = Just (CEq "3.0.1"), dependencyLocations = [], dependencyEnvironments = fromList [EnvProduction], dependencyTags = fromList []}, Dependency {dependencyType = NodeJSType, dependencyName = "@pnpm/logger", dependencyVersion = Just (CEq "1000.0.0"), dependencyLocations = [], dependencyEnvironments = fromList [EnvProduction], dependencyTags = fromList []}, Dependency {dependencyType = NodeJSType, dependencyName = "@pnpm/logger", dependencyVersion = Just (CEq "1000.0.0"), dependencyLocations = [], dependencyEnvironments = fromList [EnvDevelopment], dependencyTags = fromList []}, Dependency {dependencyType = NodeJSType, dependencyName = "@pnpm/meta-updater", dependencyVersion = Just (CEq "2.0.5"), dependencyLocations = [], dependencyEnvironments = fromList [EnvProduction], dependencyTags = fromList []}, Dependency {dependencyType = NodeJSType, dependencyName = "@pnpm/meta-updater", dependencyVersion = Just (CEq "2.0.5"), dependencyLocations = [], dependencyEnvironments = fromList [EnvDevelopment], dependencyTags = fromList []}, Dependency {dependencyType = NodeJSType, dependencyName = "@pnpm/network.agent", dependencyVersion = Just (CEq "2.0.2"), dependencyLocations = [], dependencyEnvironments = fromList [EnvProduction], dependencyTags = fromList []}, Dependency {dependencyType = NodeJSType, dependencyName = "@pnpm/network.agent", dependencyVersion = Just (CEq "2.0.2"), dependencyLocations = [], dependencyEnvironments = fromList [EnvDevelopment], dependencyTags = fromList []}, Dependency {dependencyType = NodeJSType, dependencyName = "@pnpm/nopt", dependencyVersion = Just (CEq "0.2.1"), dependencyLocations = [], dependencyEnvironments = fromList [EnvProduction], dependencyTags = fromList []}, Dependency {dependencyType = NodeJSType, dependencyName = "@pnpm/nopt", dependencyVersion = Just (CEq "0.2.1"), dependencyLocations = [], dependencyEnvironments = fromList [EnvDevelopment], dependencyTags = fromList []}, Dependency {dependencyType = NodeJSType, dependencyName = "@pnpm/npm-conf", dependencyVersion = Just (CEq "3.0.0"), dependencyLocations = [], dependencyEnvironments = fromList [EnvProduction], dependencyTags = fromList []}, Dependency {dependencyType = NodeJSType, dependencyName = "@pnpm/npm-lifecycle", dependencyVersion = Just (CEq "1000.0.2"), dependencyLocations = [], dependencyEnvironments = fromList [EnvProduction], dependencyTags = fromList []}, Dependency {dependencyType = NodeJSType, dependencyName = "@pnpm/npm-package-arg", dependencyVersion = Just (CEq "1.0.0"), dependencyLocations = [], dependencyEnvironments = fromList [EnvProduction], dependencyTags = fromList []}, Dependency {dependencyType = NodeJSType, dependencyName = "@pnpm/os.env.path-extender", dependencyVersion = Just (CEq "2.0.2"), dependencyLocations = [], dependencyEnvironments = fromList [EnvProduction], dependencyTags = fromList []}, Dependency {dependencyType = NodeJSType, dependencyName = "@pnpm/patch-package", dependencyVersion = Just (CEq "0.0.1"), dependencyLocations = [], dependencyEnvironments = fromList [EnvProduction], dependencyTags = fromList []}, Dependency {dependencyType = NodeJSType, dependencyName = "@pnpm/registry-mock", dependencyVersion = Just (CEq "4.3.0"), dependencyLocations = [], dependencyEnvironments = fromList [EnvProduction], dependencyTags = fromList []}, Dependency {dependencyType = NodeJSType, dependencyName = "@pnpm/registry-mock", dependencyVersion = Just (CEq "4.3.0"), dependencyLocations = [], dependencyEnvironments = fromList [EnvDevelopment], dependencyTags = fromList []}, Dependency {dependencyType = NodeJSType, dependencyName = "@pnpm/semver-diff", dependencyVersion = Just (CEq "1.1.0"), dependencyLocations = [], dependencyEnvironments = fromList [EnvProduction], dependencyTags = fromList []}, Dependency {dependencyType = NodeJSType, dependencyName = "@pnpm/tabtab", dependencyVersion = Just (CEq "0.5.4"), dependencyLocations = [], dependencyEnvironments = fromList [EnvProduction], dependencyTags = fromList []}, Dependency {dependencyType = NodeJSType, dependencyName = "@pnpm/tabtab", dependencyVersion = Just (CEq "0.5.4"), dependencyLocations = [], dependencyEnvironments = fromList [EnvDevelopment], dependencyTags = fromList []}, Dependency {dependencyType = NodeJSType, dependencyName = "@pnpm/tgz-fixtures", dependencyVersion = Just (CEq "0.0.0"), dependencyLocations = [], dependencyEnvironments = fromList [EnvDevelopment], dependencyTags = fromList []}, Dependency {dependencyType = NodeJSType, dependencyName = "@pnpm/util.lex-comparator", dependencyVersion = Just (CEq "3.0.1"), dependencyLocations = [], dependencyEnvironments = fromList [EnvProduction], dependencyTags = fromList []}, Dependency {dependencyType = NodeJSType, dependencyName = "@pnpm/workspace.find-packages", dependencyVersion = Just (CEq "1000.0.15"), dependencyLocations = [], dependencyEnvironments = fromList [EnvProduction], dependencyTags = fromList []}, Dependency {dependencyType = NodeJSType, dependencyName = "@pnpm/workspace.read-manifest", dependencyVersion = Just (CEq "1000.1.1"), dependencyLocations = [], dependencyEnvironments = fromList [EnvProduction], dependencyTags = fromList []}, Dependency {dependencyType = NodeJSType, dependencyName = "@reflink/reflink", dependencyVersion = Just (CEq "0.1.18"), dependencyLocations = [], dependencyEnvironments = fromList [EnvProduction], dependencyTags = fromList []}, Dependency {dependencyType = NodeJSType, dependencyName = "@rushstack/worker-pool", dependencyVersion = Just (CEq "0.4.9"), dependencyLocations = [], dependencyEnvironments = fromList [EnvProduction], dependencyTags = fromList []}, Dependency {dependencyType = NodeJSType, dependencyName = "@types/adm-zip", dependencyVersion = Just (CEq "0.5.7"), dependencyLocations = [], dependencyEnvironments = fromList [EnvDevelopment], dependencyTags = fromList []}, Dependency {dependencyType = NodeJSType, dependencyName = "@types/archy", dependencyVersion = Just (CEq "0.0.33"), dependencyLocations = [], dependencyEnvironments = fromList [EnvDevelopment], dependencyTags = fromList []}, Dependency {dependencyType = NodeJSType, dependencyName = "@types/cross-spawn", dependencyVersion = Just (CEq "6.0.6"), dependencyLocations = [], dependencyEnvironments = fromList [EnvDevelopment], dependencyTags = fromList []}, Dependency {dependencyType = NodeJSType, dependencyName = "@types/fs-extra", dependencyVersion = Just (CEq "9.0.13"), dependencyLocations = [], dependencyEnvironments = fromList [EnvDevelopment], dependencyTags = fromList []}, Dependency {dependencyType = NodeJSType, dependencyName = "@types/graceful-fs", dependencyVersion = Just (CEq "4.1.9"), dependencyLocations = [], dependencyEnvironments = fromList [EnvDevelopment], dependencyTags = fromList []}, Dependency {dependencyType = NodeJSType, dependencyName = "@types/hosted-git-info", dependencyVersion = Just (CEq "3.0.5"), dependencyLocations = [], dependencyEnvironments = fromList [EnvDevelopment], dependencyTags = fromList []}, Dependency {dependencyType = NodeJSType, dependencyName = "@types/ini", dependencyVersion = Just (CEq "1.3.31"), dependencyLocations = [], dependencyEnvironments = fromList [EnvDevelopment], dependencyTags = fromList []}, Dependency {dependencyType = NodeJSType, dependencyName = "@types/is-gzip", dependencyVersion = Just (CEq "2.0.0"), dependencyLocations = [], dependencyEnvironments = fromList [EnvDevelopment], dependencyTags = fromList []}, Dependency {dependencyType = NodeJSType, dependencyName = "@types/is-windows", dependencyVersion = Just (CEq "1.0.2"), dependencyLocations = [], dependencyEnvironments = fromList [EnvDevelopment], dependencyTags = fromList []}, Dependency {dependencyType = NodeJSType, dependencyName = "@types/isexe", dependencyVersion = Just (CEq "2.0.2"), dependencyLocations = [], dependencyEnvironments = fromList [EnvDevelopment], dependencyTags = fromList []}, Dependency {dependencyType = NodeJSType, dependencyName = "@types/jest", dependencyVersion = Just (CEq "29.5.14"), dependencyLocations = [], dependencyEnvironments = fromList [EnvDevelopment], dependencyTags = fromList []}, Dependency {dependencyType = NodeJSType, dependencyName = "@types/js-yaml", dependencyVersion = Just (CEq "4.0.9"), dependencyLocations = [], dependencyEnvironments = fromList [EnvDevelopment], dependencyTags = fromList []}, Dependency {dependencyType = NodeJSType, dependencyName = "@types/lodash.kebabcase", dependencyVersion = Just (CEq "4.1.9"), dependencyLocations = [], dependencyEnvironments = fromList [EnvDevelopment], dependencyTags = fromList []}, Dependency {dependencyType = NodeJSType, dependencyName = "@types/lodash.throttle", dependencyVersion = Just (CEq "4.1.7"), dependencyLocations = [], dependencyEnvironments = fromList [EnvDevelopment], dependencyTags = fromList []}, Dependency {dependencyType = NodeJSType, dependencyName = "@types/micromatch", dependencyVersion = Just (CEq "4.0.9"), dependencyLocations = [], dependencyEnvironments = fromList [EnvDevelopment], dependencyTags = fromList []}, Dependency {dependencyType = NodeJSType, dependencyName = "@types/node", dependencyVersion = Just (CEq "18.19.34"), dependencyLocations = [], dependencyEnvironments = fromList [EnvDevelopment], dependencyTags = fromList []}, Dependency {dependencyType = NodeJSType, dependencyName = "@types/normalize-package-data", dependencyVersion = Just (CEq "2.4.4"), dependencyLocations = [], dependencyEnvironments = fromList [EnvDevelopment], dependencyTags = fromList []}, Dependency {dependencyType = NodeJSType, dependencyName = "@types/normalize-path", dependencyVersion = Just (CEq "3.0.2"), dependencyLocations = [], dependencyEnvironments = fromList [EnvProduction], dependencyTags = fromList []}, Dependency {dependencyType = NodeJSType, dependencyName = "@types/normalize-path", dependencyVersion = Just (CEq "3.0.2"), dependencyLocations = [], dependencyEnvironments = fromList [EnvDevelopment], dependencyTags = fromList []}, Dependency {dependencyType = NodeJSType, dependencyName = "@types/object-hash", dependencyVersion = Just (CEq "3.0.6"), dependencyLocations = [], dependencyEnvironments = fromList [EnvDevelopment], dependencyTags = fromList []}, Dependency {dependencyType = NodeJSType, dependencyName = "@types/parse-json", dependencyVersion = Just (CEq "4.0.2"), dependencyLocations = [], dependencyEnvironments = fromList [EnvDevelopment], dependencyTags = fromList []}, Dependency {dependencyType = NodeJSType, dependencyName = "@types/pnpm__byline", dependencyVersion = Just (CEq "4.2.36"), dependencyLocations = [], dependencyEnvironments = fromList [EnvProduction], dependencyTags = fromList []}, Dependency {dependencyType = NodeJSType, dependencyName = "@types/proxyquire", dependencyVersion = Just (CEq "1.3.31"), dependencyLocations = [], dependencyEnvironments = fromList [EnvDevelopment], dependencyTags = fromList []}, Dependency {dependencyType = NodeJSType, dependencyName = "@types/ramda", dependencyVersion = Just (CEq "0.29.12"), dependencyLocations = [], dependencyEnvironments = fromList [EnvDevelopment], dependencyTags = fromL...

…legacy helpers for clarity, update comments, and ensure all formatting/linting/tests pass. No functional changes.
@ryanlink ryanlink force-pushed the pnpm-9-lockfile-fix branch 3 times, most recently from 484f47f to 4857360 Compare May 20, 2025 18:08
…actor legacy logic; ensure correct name/version assignment
@ryanlink ryanlink force-pushed the pnpm-9-lockfile-fix branch from 4857360 to 83e2774 Compare May 20, 2025 18:23
ryanlink and others added 7 commits June 10, 2025 16:15
…linking

Improves pnpm lockfile parsing to support v9+ formats, which introduce a 'snapshots' section for the dependency graph. This change adds logic to correctly resolve local workspace packages referenced via 'link:', normalizing paths to ensure consistent lookups in the 'packages' and 'snapshots' maps. Extensive diagnostic logging has been included to aid in debugging complex resolution scenarios. The legacy v5/v6 parsing logic has been preserved and now operates alongside the new v9+ parser, dispatched based on the 'lockFileVersion'.
…riants, alias/@@ handling, npm: prefix stripping, better logging.

Highlights:\n• generateCandidateSnapshotKeysV9: expand normalization rules (npm:, @@ alias, peer suffix combinations).\n• lookupSnapshotV9 warns on missing snapshot but no longer fails.\n• No behavioural changes for pre-v9 lockfiles.\n• Keeps synthetic workspace root logic intact.
…ck & mixed dep tests

Changes:\n• PnpmLockSpec.hs: added buildGraphFrom helper.\n• Added inline v9 fixture with link dependency and registry dep to validate UserType fallback and direct promotion.\n• Subset assertions switched to shouldSatisfy.\nAll unit tests green (1200 examples, 0 failures).
Changes:\n• PnpmLockSpec.hs: repl. head/last split with Text.breakOnEnd and safe fallback, clearing -Wpartial.\n• Fourmolu + hlint run; no production code touched.\nAll unit tests pass (1202 examples).
@ryanlink ryanlink requested review from csasarak and a team June 13, 2025 20:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants