Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

[Cocoa] Added generating SBOM for projects using Cocoapods #1667

Merged
merged 14 commits into from
Mar 5, 2025

Conversation

malice00
Copy link
Collaborator

@malice00 malice00 commented Mar 2, 2025

This PR adds the possibility to generate an SBOM for projects that use Cocoapods.

Several options are available to configure the generation (eg in-/exclude targets, merge sub-specs into main spec and resolution of local Pods to NodeJS artefacts). Check the documentation on how to use these.

@prabhu: I haven't checked the new thought log, so that is not implemented -- any suggestions on that are welcome.

@malice00 malice00 requested a review from prabhu as a code owner March 2, 2025 12:32
@malice00 malice00 changed the title [Cocoa] Added generting SBOM for projects using Cocoapods [Cocoa] Added generating SBOM for projects using Cocoapods Mar 2, 2025
Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Hello @malice00, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

Summary of Changes

This pull request introduces the capability to generate Software Bill of Materials (SBOMs) for projects utilizing Cocoapods. It includes options for configuring the generation process, such as including or excluding specific targets, merging sub-specs into the main spec, and resolving local Pods to NodeJS artifacts. The changes primarily involve modifications to the .github/workflows/repotests.yml file to set up Cocoapods and checkout test repositories, updates to docs/ENV.md to document the new environment variables for Cocoa configuration, and significant additions to lib/cli/index.js and lib/helpers/utils.js to implement the SBOM generation logic for Cocoa projects.

Highlights

  • Cocoapods SBOM Generation: Adds functionality to generate SBOMs for projects using Cocoapods, enhancing dependency management and security analysis.
  • Configuration Options: Introduces several options to configure SBOM generation, including target inclusion/exclusion, sub-spec merging, and resolution of local Pods to NodeJS artifacts.
  • Workflow Updates: Modifies the CI workflow to include Cocoapods setup and testing, ensuring the new functionality is tested and integrated correctly.
  • Documentation: Updates the ENV.md file to document the new environment variables, providing clear instructions for users to configure the Cocoa SBOM generation.

Changelog

Click here to see the changelog
  • .github/workflows/repotests.yml
    • Adds a step to install cocoapods via gem install cocoapods -v 1.16.2 --no-document
    • Adds a checkout step for the malice00/cdxgen-cocoapods-test repository to repotests/cocoapods-test
    • Introduces new test jobs for expo projects on macOS and non-macOS environments, utilizing cocoapods and gradle to generate SBOMs with various configurations.
    • Adds a test job specifically for cocoapods projects, generating SBOMs with different options like COCOA_FULL_SCAN, COCOA_MERGE_SUBSPECS, and COCOA_INCLUDED_TARGETS.
  • docs/ENV.md
    • Adds a new section for Cocoa environment variables, documenting options such as COCOA_EXCLUDED_TARGETS, COCOA_FULL_SCAN, COCOA_INCLUDED_TARGETS, COCOA_MERGE_SUBSPECS, COCOA_PODSPEC_JSON_REPLACEMENTS, COCOA_PODSPEC_REPLACEMENTS, COCOA_RESOLVE_FROM_NODE, and COCOA_RESOLVE_FROM_NODE_EXCLUSION_DIRS.
  • lib/cli/index.js
    • Imports existsSync from node:fs
    • Imports loadYaml from js-yaml
    • Adds buildObjectForCocoaPod to the list of imported functions.
    • Adds executePodCommand to the list of imported functions.
    • Adds parseCocoaDependency to the list of imported functions.
    • Adds parsePodfileLock and parsePodfileTargets to the list of imported functions.
    • Implements createCocoaBom function to generate SBOMs for Cocoa projects, including logic to handle Podfile.lock parsing, dependency resolution, and target inclusion/exclusion.
    • Modifies createMultiXBom to include Cocoa projects when generating SBOMs for multiple project types.
    • Modifies createXBom to include Cocoa projects when generating SBOMs.
    • Modifies createBom to include Cocoa projects when generating SBOMs based on project type aliases.
  • lib/helpers/utils.js
    • Imports randomUUID from node:crypto
    • Adds a temporaryFiles set to track temporary files created by cdxgen, ensuring they are deleted on exit.
    • Adds cocoa to the PROJECT_TYPE_ALIASES.
    • Implements parsePodfileLock to parse the contents of a Podfile.lock, extracting dependencies and their metadata.
    • Implements parsePodfileTargets to parse targets and their direct dependencies from the Podfile.
    • Implements parseCocoaDependency to parse a single line representing a dependency.
    • Implements executePodCommand to execute the 'pod' command with specified parameters.
    • Implements buildObjectForCocoaPod to create SBOM objects for Cocoa pods, including logic to resolve dependencies from NodeJS packages and perform full scans.
    • Implements fullScanCocoaPod to perform a full scan of Cocoa pods, extracting additional metadata and external references.
  • lib/helpers/utils.test.js
    • Imports loadYaml from js-yaml
    • Adds buildObjectForCocoaPod to the list of imported functions.
    • Adds parseCocoaDependency to the list of imported functions.
    • Adds parsePodfileLock and parsePodfileTargets to the list of imported functions.
    • Adds tests for parsePodfileLock, parsePodfileTargets, parseCocoaDependency, and buildObjectForCocoaPod.
  • test/Podfile
    • Creates a Podfile for testing purposes, including dependencies and target definitions.
  • test/Podfile.json
    • Creates a JSON representation of the Podfile for testing purposes.
  • test/Podfile.lock
    • Creates a Podfile.lock for testing purposes.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point in your pull request via creating an issue comment (i.e. comment on the pull request page) using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in issue comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist is currently in preview and may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments to provide feedback.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.


Did you know?

CocoaPods is written in Ruby and is distributed as a gem. It is one of the most popular dependency managers for Swift and Objective-C projects.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces the capability to generate SBOMs for projects utilizing Cocoapods, enhancing the tool's ability to analyze and document dependencies in iOS and macOS projects. The addition of configuration options for target inclusion/exclusion, sub-spec merging, and local Pod resolution significantly increases the flexibility and usefulness of the SBOM generation process. The documentation updates are also a welcome addition.

Merge Readiness

The pull request appears to be well-structured and introduces a valuable feature. However, it's important to ensure that the changes have been thoroughly tested across different Cocoapods project configurations and that the documentation is clear and comprehensive for users to effectively utilize the new features. I am unable to directly approve this pull request, and I recommend that others review and approve this code before merging. Given the complexity of the changes, I recommend a thorough review by someone familiar with Cocoapods and SBOM generation before merging.

@malice00
Copy link
Collaborator Author

malice00 commented Mar 2, 2025

@prabhu Something connected to the automatic checking of included builds in gradle broke the expo builds... Checking it now...

Edit:
Yeah, expo generates settings..gradle files with content like this:

includeBuild(new File(["node", "--print", "require.resolve('@react-native/gradle-plugin/package.json', { paths: [require.resolve('react-native/package.json')] })"].execute(null, rootDir).text.trim()).getParentFile().toString())

which unfortunately breaks your logic. 😢

@malice00 malice00 marked this pull request as draft March 2, 2025 14:07
@malice00 malice00 marked this pull request as ready for review March 2, 2025 19:23
@malice00
Copy link
Collaborator Author

malice00 commented Mar 2, 2025

OK, so I changed something in the test to get it running again -- but I do feel changes to the gradle included-build are still needed.

@prabhu
Copy link
Collaborator

prabhu commented Mar 2, 2025

@malice00 can we detect the problematic includeBuild calls and ignore adding to the sets in line 29 and 37? Is this coming from the COCOA_PODSPEC_REPLACEMENTS?

https://github.com/malice00/cdxgen/blob/b50e1c690c0f868972a65673f60ae640f64157c8/lib/helpers/package_specific/gradleutils.js#L37

Not sure how to get the value :gradle-plugin. If this is constant for expo projects, maybe we skip calling analyzeBuildSettings completely?

docs/ENV.md Outdated
| COCOA_FULL_SCAN | Whether or not to do a full (deep) scan of the pods. This requires CocoaPods to be installed and runnable from the `PATH`. When set to `false` or `0`, only the most basic of information will be gathered (name, version, purl and, if applicable, sub-spec) -- can be useful if run on Windows. Defaults to `true`. |
| COCOA_INCLUDED_TARGETS | Comma-separated list of target to include for resolution of dependencies. Usage is the same as `COCOA_EXCLUDED_TARGETS` above. |
| COCOA_MERGE_SUBSPECS | Should all sub-specs (and their dependencies) be merged into the root spec. This can be useful if you are importing your SBOM into a tool that doesn't handle sub-specs as separate dependencies (eg dependency-track). Defaults to `false`. |
| COCOA_PODSPEC_JSON_REPLACEMENTS | Comma-separated list of 'text_to_find=replacement'. This can be used if you have local pods in JSON format that are not (correctly) parsable by the `pod ipc sepc`-command, eg because some variables or functions would be inserted by the `Podfile` -- users of react-native / expo might need this. This will be interpreted as a `regex` if the 'text_to_find' is both prefixed and suffixed with a `/` and then references like `$1` can be used in the 'replacement'. To find or insert a newline, use the String `<NEWLINE>`. |
Copy link
Collaborator

Choose a reason for hiding this comment

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

Type sepc to spec

Copy link
Collaborator

Choose a reason for hiding this comment

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

This is introducing some code injection risks. Can you share any documentation about this command?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Shall I add a completely new page, or add it here? I feel this description is already pretty much at the limit of what is practical for a quick overview of the EnvVars...

Copy link
Collaborator

Choose a reason for hiding this comment

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

Maybe a console.log? If not don't worry, we can work on a new PR.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

OK, let's do this in a new PR then.

@malice00
Copy link
Collaborator Author

malice00 commented Mar 2, 2025

@malice00 can we detect the problematic includeBuild calls and ignore adding to the sets in line 29 and 37? Is this coming from the COCOA_PODSPEC_REPLACEMENTS?

https://github.com/malice00/cdxgen/blob/b50e1c690c0f868972a65673f60ae640f64157c8/lib/helpers/package_specific/gradleutils.js#L37

Not sure how to get the value :gradle-plugin. If this is constant for expo projects, maybe we skip calling analyzeBuildSettings completely?

I think we can, but it would need some reworking of the current code. I would however prefer to not add it to this issue, since that is gradle specific.
It has nothing to do with COCOA_PODSPEC_REPLACEMENTS.

Unfortunately, the value :gradle-plugin is not a constant. It is possible to execute arbitrary code inside a gradle build file, which expo makes use of here. Currently for expo, it will always resolve to :gradle-plugin, this can however change with any new update... 😞

| Variable | Description |
| --------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| COCOA_EXCLUDED_TARGETS | Comma-separated list of targets to exclude from resolution of dependencies. If a target has nested targets, these are also excluded. For excluding only those nested targets, use a `/` to describe the target, eg `target/subtarget/subsubtarget` -- this excludes only `subsubtarget` from the resolution. |
| COCOA_FULL_SCAN | Whether or not to do a full (deep) scan of the pods. This requires CocoaPods to be installed and runnable from the `PATH`. When set to `false` or `0`, only the most basic of information will be gathered (name, version, purl and, if applicable, sub-spec) -- can be useful if run on Windows. Defaults to `true`. |
Copy link
Collaborator

Choose a reason for hiding this comment

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

We have options.deep. Can we use that instead of this env variable? options. deep defaults to false though.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Depends on what options.deep does/means, I guess. I'll check it out.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Looks like options.deep also gets set depending on profiles. We could use it, but I think we should have the ability to specifically (de)activate the full scanning. The reason being that most users will probably run cocoapods only on a Mac and a scan on any other platform might then cause problems. Then again, they might also only generate SBOMs on a Mac, where it would be a non-issue...

Copy link
Collaborator

Choose a reason for hiding this comment

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

Can cocoapods run with our container images once we add the missing gem install? We can always do options.deep || isMac to decide whether to do a full scan?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

It probably can, although I can't test this right now -- I currently have no docker/podman running on this system. It works in the repotests however, so if they are similar it should not be a problem. We could even add it on the linux images, if ruby is installed. Windows might be a bit more complicated, I was unable to get cocoapods running correctly, but according to my research, it should be doable.

@prabhu
Copy link
Collaborator

prabhu commented Mar 3, 2025

@gemini-code-assist, a feedback for you is to keep your comments shorter and to the point. We don't need those "Did you know?" things, for example. Two things you could have highlighted better in your review:

  1. addition of multiple new environment variables. Perhaps neatly as a table instead of single bullet point.
  2. New repo test with a brand new repo.

Summary for the changelog was quite useful, so keep it up!

Copy link

Thanks for the feedback, @prabhu! I appreciate the specific points on keeping comments concise and suggesting a table for environment variables. I'll definitely keep that in mind for future reviews. I'm always striving to improve the quality and usefulness of my feedback.

@@ -448,6 +458,7 @@ export const PROJECT_TYPE_ALIASES = {
],
binary: ["binary", "blint"],
oci: ["docker", "oci", "container", "podman"],
cocoa: ["cocoa", "cocoapods", "objective-c", "swift", "ios"],
Copy link
Collaborator

Choose a reason for hiding this comment

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

We already have a swift type with an alias for ios. Let's remove swift and ios from here.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

True, but will it run the new scanner when I use -t ios?
Or did I misunderstand the meaning of the aliases?

Copy link
Collaborator

Choose a reason for hiding this comment

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

We can prefer swift for -t ios, since most new projects are swift based.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

That might be true, but swift-projects can actually use cocoapods, so imo both scanners should run.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Interesting. Does your PR run both the scanners for -t ios?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

But I just noticed it is a bit of a problem to have duplicate entries, because using -t ios doesn't generate my SBOM...

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Interesting. Does your PR run both the scanners for -t ios?

Missed your reply when I posted the above -- no, it doesn't, I guess I only tested using -t cocoapods.

@prabhu
Copy link
Collaborator

prabhu commented Mar 3, 2025

Please rebase before working on the changes. Apologies.

malice00 added 9 commits March 3, 2025 19:11
Signed-off-by: Roland Asmann <[email protected]>
Split them in mac/others because mac allows more tests in this project

Signed-off-by: Roland Asmann <[email protected]>
Signed-off-by: Roland Asmann <[email protected]>
Signed-off-by: Roland Asmann <[email protected]>
Signed-off-by: Roland Asmann <[email protected]>
@prabhu
Copy link
Collaborator

prabhu commented Mar 4, 2025

Happy to merge this PR and help add things like dockerfile enhancements etc in a new PR?

@malice00
Copy link
Collaborator Author

malice00 commented Mar 4, 2025

Let me just finish the last couple of loose ends and then we can work on fine-tuning in a new PR.

Signed-off-by: Roland Asmann <[email protected]>
@prabhu prabhu merged commit 1b4d538 into CycloneDX:master Mar 5, 2025
28 checks passed
@malice00 malice00 deleted the cocoapods branch March 6, 2025 12:03
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