gradle / gradle-build-action

Execute your Gradle build and trigger dependency submission
https://github.com/marketplace/actions/gradle-build-action
MIT License
671 stars 97 forks source link

dependency graph submission seems unsuccessful as cannot be found by dependency review action #960

Closed uli-f closed 9 months ago

uli-f commented 10 months ago

Hi,

I set up the gradle-build-action so that it generates and submits the dependency graph to the github dependency submission api:

- name: 👩🏻‍🍳 Setup gradle
  uses: gradle/gradle-build-action@v2
  with:
    dependency-graph: generate-and-submit

There are three executions of gradle in my CI (build and test, javadoc, generate cyclonedx sbom) so gradle generates a dependency graph for each of these tree runs.

When looking at the post operation of the gradle-build-action in my builds I can see the following if the CI workflow gets triggered by a PR:

Post job cleanup.
In final post-action step, saving state and writing summary
Cache is read-only: will not save state for use in subsequent builds.
Writing job summary
Uploading dependency graph files: dependency-graph-reports/ci_pipeline-build_test_sbom_javadoc-1.json,dependency-graph-reports/ci_pipeline-build_test_sbom_javadoc-2.json,dependency-graph-reports/ci_pipeline-build_test_sbom_javadoc.json
Starting artifact upload
For more detailed logs during the artifact upload process, enable step-debugging: https://docs.github.com/actions/monitoring-and-troubleshooting-workflows/enabling-debug-logging#enabling-step-debug-logging
Artifact name is valid!
Container for artifact "dependency-graph" successfully created. Starting upload of file(s)
Total size of all the files uploaded is 23964 bytes
File upload process has finished. Finalizing the artifact upload
Artifact has been finalized. All files have been successfully uploaded!

The raw size of all the files that were specified for upload is 275964 bytes
The size of all the files that were uploaded is 23964 bytes. This takes into account any gzip compression used to reduce the upload size, time and storage

Note: The size of downloaded zips can differ significantly from the reported size. For more information see: https://github.com/actions/upload-artifact#zipped-artifact-downloads 

Notice: Submitted dependency-graph-reports/ci_pipeline-build_test_sbom_javadoc-1.json: The snapshot was accepted, but it is not for the default branch. It will not update dependency results for the repository.
Notice: Submitted dependency-graph-reports/ci_pipeline-build_test_sbom_javadoc-2.json: The snapshot was accepted, but it is not for the default branch. It will not update dependency results for the repository.
Notice: Submitted dependency-graph-reports/ci_pipeline-build_test_sbom_javadoc.json: The snapshot was accepted, but it is not for the default branch. It will not update dependency results for the repository.

Looking at the last three lines of that output it seems that the dependency results have not been updated.

The dependency review action is set up in a different yml file following your example in the README.md:

name: "Dependency review"

on:
  pull_request:
    branches: [ main ]
# remove default permissions from the token
permissions: {}

jobs:
  dependency_review:
    name: Dependency review
    runs-on: ubuntu-latest
    permissions:
      actions: read
      contents: read
      pull-requests: write

    steps:
      - name: 🥽 PR dependency review
        uses: actions/dependency-review-action@v3
        with:
          comment-summary-in-pr: 'always'
          # Enable retrying the action every 10 seconds while waiting for dependency submission actions to complete.
          retry-on-snapshot-warnings: true
          # Maximum amount of seconds to retry the action while waiting for dependency submission actions to complete.
          retry-on-snapshot-warnings-timeout: 300

However, the dependency review action cannot find the snapshot though even minutes after the CI workflow finished:

Run actions/dependency-review-action@v3
  with:
    comment-summary-in-pr: always
    retry-on-snapshot-warnings: true
    retry-on-snapshot-warnings-timeout: 300
    repo-token: ***
No snapshots were found for the head SHA 82ef38589abd4553abfcb95d6dc120fbdf166567.
Retrying in 10 seconds...
No snapshots were found for the head SHA 82ef38589abd4553abfcb95d6dc120fbdf166567.
Retrying in 10 seconds...

I'd appreciate any help to get the dependency graph successfully submitted for PRs so that it can be picked up by the dependency review action.

DuncanCasteleyn commented 10 months ago

Hi

I work for an organization were we recently had a meeting to buy GitHub Advanced security and this action was part of the meeting, you can't run this task parallel in a different action.

You will need to run the build that submits the graph before the review action, the submissions needs to be done already before you run the review action. This is limitation of that action, you should create an issue with them for not documenting this.

uli-f commented 10 months ago

Thank you @DuncanCasteleyn for taking the time to comment, much appreciated.

Just to clarify: The workflow to execute actions/dependency-review-action@v3 has two parameters that configure it to check every 10 seconds if the snapshots are available for up to 5 minutes:

 # Enable retrying the action every 10 seconds while waiting for dependency submission actions to complete.
retry-on-snapshot-warnings: true
# Maximum amount of seconds to retry the action while waiting for dependency submission actions to complete.
retry-on-snapshot-warnings-timeout: 300

This follows the example given in the dependency action documenation.

DuncanCasteleyn commented 10 months ago

Oh, that's good to know. Strange that they told us something different during the meeting and it was just 1 week ago they should know how their own actions work.

In any case did you try a checkout on your actual head of the branch instead of the pull requests merged state for the gradle build action? to clarify what i mean is this https://github.com/actions/checkout?tab=readme-ov-file#checkout-pull-request-head-commit-instead-of-merge-commit it might make no difference but worth a try to figure out what might be happening, if this resolves it this might be a bug with the action or dependency graph API.

uli-f commented 10 months ago

@DuncanCasteleyn Thanks again for your comment. I submitted a ticket to github support but haven't received a reply yet. I'll update here if I am able to get this resolved...

tspascoal commented 10 months ago

Hi @uli-f

Have you tried to use generate value in the dependency-graph parameter and then at the end of those 3 jobs running the action with download-and-submit prior to running the dependency review action?

See

I've tried it just now (with a single build, but no reason why it wouldn't work it multiple according to gradle action docs)

If there is only one build , then we can optimize this a bit to save one job on pushes (by having either generate or generate-and-submit depending if it's a PR or not and running the second job only on PRs)

name: Run Gradle Build

on:
  push:
    branches: [ "main", "development" ]
  pull_request:
    branches: [ "main", "development" ]

jobs:
  build:

    runs-on: ubuntu-latest

    steps:
      - name: Checkout
        uses: actions/checkout@v3
      - name: Set up JDK 11
        uses: actions/setup-java@v3
        with:
          java-version: '11'
          distribution: 'temurin'

      - name: Set up Gradle Build Action
        uses: gradle/gradle-build-action@v2
        with:
          dependency-graph: generate
          cache-disabled: true

      - name: Build and test with Gradle
        run: ./gradlew build

  submit-and-review:
      runs-on: ubuntu

      steps:

      - name: Set up Gradle Build Action
        uses: gradle/gradle-build-action@v2
        with:
          dependency-graph: download-and-submit
          cache-disabled: true

      - name: 'Dependency Review'
        if: github.event_name == 'pull_request'
        uses: actions/dependency-review-action@v3        
tspascoal commented 10 months ago

@uli-f Update, I've misread your issue (I assume there were 3 different jobs doing the build. So this might be even simpler)

name: Run Gradle Build

on:
  push:
    branches: [ "main", "development" ]
  pull_request:
    branches: [ "main", "development" ]

jobs:
  build:

    runs-on: ubuntu-latest

    steps:
      - name: Checkout
        uses: actions/checkout@v3
      - name: Set up JDK 11
        uses: actions/setup-java@v3
        with:
          java-version: '11'
          distribution: 'temurin'

      - name: Set up Gradle Build Action
        uses: gradle/gradle-build-action@v2
        with:
          dependency-graph: generate-and-submit
          cache-disabled: true

      - name: Build and test with Gradle
        run: ./gradlew build

  dependency-review:
      runs-on: ubuntu
      if: github.event_name == 'pull_request'

      steps:

      - name: Set up Gradle Build Action
        uses: gradle/gradle-build-action@v2
        with:
          dependency-graph: download-and-submit
          cache-disabled: true

      - name: 'Dependency Review'
        uses: actions/dependency-review-action@v3        

I have not tried it with more than submission, I will if I can find an example with more than one submission

Update: I have tried with a double build (synthetic example though)

- name: Build and test with Gradle
        run: ./gradlew build

      - name: clean
        run: ./gradlew clean        

      - name: Build and test with Gradle
        run: ./gradlew build

and it works as well

Notice: Submitted dependency-graph-reports/run_gradle_build-build-2.json: The snapshot was accepted, but it is not for the default branch. It will not update dependency results for the repository.
Notice: Submitted dependency-graph-reports/run_gradle_build-build.json: The snapshot was accepted, but it is not for the default branch. It will not update dependency results for the repository.

Only after doing all of this, I've noticed this technique is describe in integrating-the-dependency-review-action the link you pointed to, is about running in pull request that with pull requests from forks? Is that your scenario?

uli-f commented 10 months ago

Thank you for your comments @tspascoal.

Yes, I have a single job calling gradle three times for different reasons (build and test, javadoc, generate sbom).

My scenario isn't running PRs from forks, but having a workflow that can run

on:
  pull request

which includes PRs opened by dependabot. My understanding is that PRs opened by dependabot run with limited permissions comparable to PRs from forks.

Looking at the dependency-review job of your example above:

dependency-review:
      runs-on: ubuntu
      if: github.event_name == 'pull_request'

      steps:

      - name: Set up Gradle Build Action
        uses: gradle/gradle-build-action@v2
        with:
          dependency-graph: download-and-submit
          cache-disabled: true

      - name: 'Dependency Review'
        uses: actions/dependency-review-action@v3       

my understanding is that the dependency-review action diffs the dependency-graph of two revisions of my repo. The dependency-review job above is only run if the workflow was triggered by a PR. So what revision would the dependency graph of the PR be compared to? In other words, I don't see the dependency-review action being run for main to generate a baseline dependency graph.

tspascoal commented 10 months ago

Thank you for your comments @tspascoal.

Yes, I have a single job calling gradle three times for different reasons (build and test, javadoc, generate sbom).

My scenario isn't running PRs from forks, but having a workflow that can run

on:
  pull request

which includes PRs opened by dependabot. My understanding is that PRs opened by dependabot run with limited permissions comparable to PRs from forks.

Both dependabot and PR from forks will run with limited permissions (read only), but I also don't think it makes sense to run dependency review on dependabot alerts, since dependabot is going to fix potential vulnerabilities and not add them. :)

So if it's about dependabot, just put a condition to avoid dependency review to run if it's a dependabot PR

something like this

       - name: 'Dependency Review'
         if: github.event_name == 'pull_request && github.actor != 'dependabot[bot]'
         uses: actions/dependency-review-action@v3      

See About Dependabot and GitHub Actions

Looking at the dependency-review job of your example above:

dependency-review:
      runs-on: ubuntu
      if: github.event_name == 'pull_request'

      steps:

      - name: Set up Gradle Build Action
        uses: gradle/gradle-build-action@v2
        with:
          dependency-graph: download-and-submit
          cache-disabled: true

      - name: 'Dependency Review'
        uses: actions/dependency-review-action@v3       

my understanding is that the dependency-review action diffs the dependency-graph of two revisions of my repo. The dependency-review job above is only run if the workflow was triggered by a PR. So what revision would the dependency graph of the PR be compared to? In other words, I don't see the dependency-review action being run for main to generate a baseline dependency graph.

There are 2 steps. One is submitting the dependencies and that is done by the gradle action. That needs to be done both on default branch and on PRs.

And then on PRs the dependency review will run run, based on those two "diffs"

So the dependency submission is used to feed information to the dependency graph (, this will allow you to see both the graph, generate the SBOM (from the UI or using GH api) or for dependabot to generate alerts. (the alerts are generated from the default branch).

The dependency review, is used on the PR process to prevent (or warn) the introduction of version that have know vulnerabilities.

They are orthogonal. BUT dependency review might need the submission process for some package managers (like graddle) to be aware of the graph.

If the dependencies from running javadoc and generate sbom don't really matter you can also disable it's generation by using the environment variable GITHUB_DEPENDENCY_GRAPH_ENABLED: false to the gradle step that is doing javadoc and generate sbom (I assume you have 3 separate steps)

So it seems (based on my limited view of your requirements) this is what you want I believe

name: Run Gradle Build

on:
  push:
    branches: [ "main", "development" ]
  pull_request:
    branches: [ "main", "development" ]

jobs:
  build:

    runs-on: ubuntu-latest

    steps:
      - name: Checkout
        uses: actions/checkout@v3
      - name: Set up JDK 11
        uses: actions/setup-java@v3
        with:
          java-version: '11'
          distribution: 'temurin'

      - name: Set up Gradle Build Action
        uses: gradle/gradle-build-action@v2
        with:
          dependency-graph: generate-and-submit
          cache-disabled: true

      - name: Build and test with Gradle
        run: ./gradlew build

      - name: javadoc
        run: ./gradlew WHATEVER
        env:
          GITHUB_DEPENDENCY_GRAPH_ENABLED: false        

      - name: javadoc
        run: ./gradlew WHATEVER
        env:
          GITHUB_DEPENDENCY_GRAPH_ENABLED: false

  submit-and-review:
      runs-on: ubuntu-latest
      if: github.event_name == 'pull_request && github.actor != 'dependabot[bot]'
      needs: build

      steps:

      - name: 'Dependency Review'
        if: github.event_name == 'pull_request'
        uses: actions/dependency-review-action@v3        
uli-f commented 9 months ago

Thanks a million @tspascoal and sorry for my very delayed reply.

Both dependabot and PR from forks will run with limited permissions (read only), but I also don't think it makes sense to run dependency review on dependabot alerts, since dependabot is going to fix potential vulnerabilities and not add them. :)

So if it's about dependabot, just put a condition to avoid dependency review to run if it's a dependabot PR

something like this

       - name: 'Dependency Review'
         if: github.event_name == 'pull_request && github.actor != 'dependabot[bot]'
         uses: actions/dependency-review-action@v3      

That makes a lot of sense and I did exactly as you suggested. (There might be a single quote missing after pull_request, just in case anyone is coming across your solution and does a copy and paste).

There are 2 steps. One is submitting the dependencies and that is done by the gradle action. That needs to be done both on default branch and on PRs.

And then on PRs the dependency review will run run, based on those two "diffs"

So the dependency submission is used to feed information to the dependency graph (, this will allow you to see both the graph, generate the SBOM (from the UI or using GH api) or for dependabot to generate alerts. (the alerts are generated from the default branch).

The dependency review, is used on the PR process to prevent (or warn) the introduction of version that have know vulnerabilities.

They are orthogonal. BUT dependency review might need the submission process for some package managers (like graddle) to be aware of the graph.

Again, very helpful information, made it easy for me to fully understand the idea and mechanism behind dependency graph and dependency review.

If the dependencies from running javadoc and generate sbom don't really matter you can also disable it's generation by using the environment variable GITHUB_DEPENDENCY_GRAPH_ENABLED: false to the gradle step that is doing javadoc and generate sbom (I assume you have 3 separate steps)

Much appreciated, was exactly what I needed to reduce my depdency graph output to the gradle run that executes the build.

name: Run Gradle Build

on:
  push:
    branches: [ "main", "development" ]
  pull_request:
    branches: [ "main", "development" ]

jobs:
  build:

    runs-on: ubuntu-latest

    steps:
      - name: Checkout
        uses: actions/checkout@v3
      - name: Set up JDK 11
        uses: actions/setup-java@v3
        with:
          java-version: '11'
          distribution: 'temurin'

      - name: Set up Gradle Build Action
        uses: gradle/gradle-build-action@v2
        with:
          dependency-graph: generate-and-submit
          cache-disabled: true

      - name: Build and test with Gradle
        run: ./gradlew build

      - name: javadoc
        run: ./gradlew WHATEVER
        env:
          GITHUB_DEPENDENCY_GRAPH_ENABLED: false        

      - name: javadoc
        run: ./gradlew WHATEVER
        env:
          GITHUB_DEPENDENCY_GRAPH_ENABLED: false

  submit-and-review:
      runs-on: ubuntu-latest
      if: github.event_name == 'pull_request && github.actor != 'dependabot[bot]'
      needs: build

      steps:

      - name: 'Dependency Review'
        if: github.event_name == 'pull_request'
        uses: actions/dependency-review-action@v3        

I basically copied this workflow and it did exactly what I want 😃

tspascoal commented 9 months ago

@uli-f I will leave up to you to decided if you want cache enabled or not. I disabled because it made my POC faster :)

Glad that things are working for you now

Pil0tXia commented 5 months ago

Hi everyone,

I have a question regarding the final outcome of the workflow file that you discussed and reached a consensus on. According to the documentation on integrating dependency-submission and dependency-review-action with pull requests from public forked repositories, it seems that dependency-submission cannot submit the dependency graph in a workflow triggered by a pull request. This means that the dependency-review-action cannot access the changes made to the dependencies in the pull request.

I'm currently working on this issue mentioned in this PR, and I wanted to ask if the reason the workflow file discussed in this issue is able to run successfully is because it is running in a private repository?

Thank you for your help and clarification.