Skip to content

Add support for relationship attribute in DependencySubmission payload #12768

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

Merged
merged 18 commits into from
Aug 8, 2025

Conversation

phillmv
Copy link
Member

@phillmv phillmv commented Aug 1, 2025

What are you trying to accomplish?

Per https://github.com/github/dependency-graph/issues/7121,

[for those of you who do not work at GitHub, the above link describes an effort we're undergoing to refactor technical debt and start using dependabot-core to parse dependencies for our dependency graph service.]

This PR is a follow up on #12734 . Now that we can generate payloads, the next step is to fill out the remaining attributes that the Dependency Submission API expects.

This PR then:

  • Adds Dependency#direct? as a bit of state we can track when parsing dependencies
  • Ensures this gets submitted in the payload

Anything you want to highlight for special attention from reviewers?

In order to get here there was a meandering path. The first step involved realizing that the DependencySet class squashes all of the Dependencies it has parsed and combines them into a flat list; this means that we could not produce an accurate list of the lockfile's dependencies because the overlapping ones would be assigned to the gemfile.

In order to get around this now associate dependencies directly with their DependencyFile via a new association DependencyFile#dependencies.

In order to start tracking whether a dependency is direct or transitive, we need to keep track of this within the Dependency class. At first we tried adding requirements objects to direct dependencies parsed from the lockfile but this caused weird test failures deep within Dependabot, so we skipped that. We eventually settled on adding a new Dependency#direct? method that either mimics top_level? or can be set directly via ivar on initialize.

How will you know you've accomplished your goal?

All tests pass & we deploy it and see it send requests to our API.

Checklist

  • I have run the complete test suite to ensure all tests and linters pass.
    • YES but some of the e2e tests are failing. I see they're failing on other unrelated recently merged PRs so it feels safe for now – it doesn't make sense why these changes would impact npm parsing.
  • I have thoroughly tested my code changes to ensure they work as expected, including adding additional tests for new functionality.
  • I have written clear and descriptive commit messages.
  • I have provided a detailed description of the changes in the pull request, including the problem it addresses, how it fixes the problem, and any relevant details about the implementation.
  • I have ensured that the code is well-documented and easy to understand.

@github-actions github-actions bot added the L: ruby:bundler RubyGems via bundler label Aug 1, 2025
@brrygrdn brrygrdn force-pushed the brrygrdn/experiment-dependency-submission branch from aa28e82 to 8782ea9 Compare August 4, 2025 11:31
Base automatically changed from brrygrdn/experiment-dependency-submission to main August 4, 2025 15:40
phillmv added 3 commits August 4, 2025 18:15
…? Could we use it to track transitive dependencies?
This commit:
- backs out previous WIP that added `dependency_file` to
  `Dependabot::Dependency`
- introduces `Dependabot::DependencyFile#dependencies` list

Now, for the bundler ecosystem at least, DependencyFiles included in
DependencySnapshots will be aware of their Dependabot::Dependency
objects – and DependencySubmission payloads can accurately reflect the
contents of the specified manifests.
@brrygrdn brrygrdn force-pushed the phillmv/experiment-dependency-submission-with-dep-files branch from 2e98f11 to f02ba8a Compare August 4, 2025 17:15
@brrygrdn brrygrdn self-assigned this Aug 4, 2025
@brrygrdn brrygrdn force-pushed the phillmv/experiment-dependency-submission-with-dep-files branch from 36eed25 to 5c56412 Compare August 5, 2025 13:42
@brrygrdn brrygrdn force-pushed the phillmv/experiment-dependency-submission-with-dep-files branch from 5c56412 to ea7d193 Compare August 5, 2025 14:00
In order to create DependencySubmission payloads, we must keep track of
dependencies on a per-DependencyFile level, and those dependency objects
must know whether they are direct dependencies (`#top_level?`) and
whether they are usined in `production?`.

First we tried faking `Dependency#requirements` objects but this broke
a number of tests; somewhere deep within Dependabot there is an
assumption that lockfiles do not produce dependencies with requirements.

Instead of trying to fix the tests, here is a different approach:
- Instead of faking `requirements` objects, we instead directly supply
  the `top_level?` boolean at instantiation, i.e. before, top_level was
  a synonym for `requirements.any?` and now it is not.

Hopefully this turns out to be a simpler modification going forward.
Copy link
Contributor

@brrygrdn brrygrdn left a comment

Choose a reason for hiding this comment

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

👍🏻 On this approach, I'm nervous about changing the contract of top_level? but I also don't love having two methods meaning slightly different things in different contexts.

phillmv and others added 8 commits August 6, 2025 15:57
Instead of overriding `top_level?`, which on inspection is a leaky
abstraction – it's often used elsewhere as a synonym for "has
requirements" – here we introduce our own method that only means "this
dependency has a direct relationship".
@phillmv phillmv changed the title Adds support for relationship attribute in DependencySubmission payload Add support for relationship attribute in DependencySubmission payload Aug 7, 2025
@phillmv phillmv marked this pull request as ready for review August 7, 2025 15:40
@phillmv phillmv requested a review from a team as a code owner August 7, 2025 15:40
Copy link
Contributor

@brrygrdn brrygrdn left a comment

Choose a reason for hiding this comment

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

I lack the real power of approval, but this LGTM

Comment on lines +136 to +137
gemfile = payload[:manifests].fetch("/Gemfile")
expect(gemfile[:name]).to eq("/Gemfile")
Copy link
Contributor

@brrygrdn brrygrdn Aug 7, 2025

Choose a reason for hiding this comment

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

I was going to ask why we were adding a / here, but on checking the API docs, this is just an arbitrary name. Comparing with a real world payload, I note people doing esoteric things like:

project-a/pom.xml > project-a

expect(capybara[:scope]).to eq("development")
# the lockfile should be reporting 4 direct dependencies and 24 indirect ones
expect(lockfile[:resolved].values.count { |dep| dep[:relationship] == "direct" }).to eq(4)
expect(lockfile[:resolved].values.count { |dep| dep[:relationship] == "indirect" }).to eq(24)
Copy link
Contributor

Choose a reason for hiding this comment

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

🎉

@brrygrdn
Copy link
Contributor

brrygrdn commented Aug 7, 2025

Huh, I do not lack the real power of approval 😅 - I'll set it to neutral until a :dependabot:-er has a chance to review

Copy link
Contributor

@brrygrdn brrygrdn left a comment

Choose a reason for hiding this comment

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

I approve in a non-binding way

@brrygrdn brrygrdn self-requested a review August 7, 2025 15:56
Copy link
Member

@jakecoffman jakecoffman left a comment

Choose a reason for hiding this comment

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

LGTM

We've been kind of... working around DependencySet for a while. If you think introducing a new data structure that doesn't smoosh dependencies into a set would be easier, feel free and we can work that back into Dependabot's update code at some point.

@brrygrdn
Copy link
Contributor

brrygrdn commented Aug 8, 2025

We've been kind of... working around DependencySet for a while. If you think introducing a new data structure that doesn't smoosh dependencies into a set would be easier, feel free and we can work that back into Dependabot's update code at some point.

IIRC @phillmv and I talked about this lightly where we'd ideally replace DependencySet with a method that smooshed the right subset of dependencies from the DependencyFiles into a big list - but building both in parallel allows us to maybe do that as a feature flag on the long tail of this work?

@phillmv phillmv merged commit 1980e12 into main Aug 8, 2025
178 of 180 checks passed
@phillmv phillmv deleted the phillmv/experiment-dependency-submission-with-dep-files branch August 8, 2025 16:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
L: ruby:bundler RubyGems via bundler
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants