Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 32 additions & 3 deletions .github/workflows/gradle-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,6 @@ name: 🧪 Unit Tests

on:
push:

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 Medium - All branch pushes now run credentialed coverage jobs

Removing the push branch filter makes this workflow execute its coverage paths for every branch push, not just the protected main branch. A user who can push a branch can therefore change the workflow on that branch and use the newly reachable id-token: write job or the Codecov step's repository token to exfiltrate credentials or mint a trusted OIDC identity, whereas the former main-only trigger prevented non-main branch workflows from reaching them. This expands the privileged workflow trust boundary to unprotected branches.

Suggested change
push:
push:
branches:
- main

More info - Reply on this comment to give feedback or ignore the issue.

branches:
- main
pull_request:

permissions:
contents: read
Expand Down Expand Up @@ -83,6 +80,14 @@ jobs:
working-directory: ./
run: chmod +x gradlew && ./gradlew clean && make cov

- name: Upload LCOV coverage report
if: ${{ !cancelled() && matrix.java-version == '21' }}
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: coverage-java-${{ matrix.java-version }}-${{ matrix.distribution }}
path: agent_api/build/jacoco/test/lcov.info
if-no-files-found: error

- name: Upload coverage report to Codecov
if: matrix.java-version == '21' # Only upload coverage for Java 21
uses: codecov/codecov-action@b9fd7d16f6d7d1b5d2bec1a2887e65ceed900238 # v4
Expand All @@ -91,3 +96,27 @@ jobs:
files: ./agent_api/build/jacoco/test/jacocoTestReport.xml
token: ${{ secrets.CODECOV_TOKEN }}
verbose: true

upload-coverage:
needs: test-and-coverage
if: github.event_name == 'push'
runs-on: ubuntu-latest
permissions:
id-token: write
contents: read
steps:
- name: Download LCOV artifacts
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
path: coverage-reports
pattern: coverage-java-*
merge-multiple: false

- name: Upload coverage to Aikido
uses: AikidoSec/code-coverage-github-action@660c7844f246c44570d9c035f5b51ffe7f266a79 # v1.0.0
with:
lcov-file-paths: |
coverage-reports/coverage-java-21-adopt/lcov.info
coverage-reports/coverage-java-21-corretto/lcov.info
coverage-reports/coverage-java-21-oracle/lcov.info
fail-on-error: false
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ test:
AIKIDO_LOG_LEVEL="error" AIKIDO_TOKEN="token" ./gradlew test

cov:
AIKIDO_LOG_LEVEL="error" AIKIDO_TOKEN="token" ./gradlew test --rerun-tasks -PcoverageRun jacocoTestReport jacocoTestCoverageVerification
AIKIDO_LOG_LEVEL="error" AIKIDO_TOKEN="token" ./gradlew test --rerun-tasks -PcoverageRun jacocoTestReport jacocoToLcov jacocoTestCoverageVerification


# Automatic versioning for releases :
Expand Down
50 changes: 50 additions & 0 deletions agent_api/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,56 @@ jacocoTestReport {
dependsOn test
}

def jacocoReportFile = layout.buildDirectory.file('jacoco/test/jacocoTestReport.xml')
def lcovReportFile = layout.buildDirectory.file('jacoco/test/lcov.info')

tasks.register('jacocoToLcov') {
group = 'verification'
description = 'Converts JaCoCo XML coverage report to LCOV format'
dependsOn jacocoTestReport
inputs.file(jacocoReportFile)
outputs.file(lcovReportFile)

doLast {
def reportFile = jacocoReportFile.get().asFile
if (!reportFile.exists()) {
throw new GradleException("JaCoCo report not found: ${reportFile}")
}

def parser = new groovy.xml.XmlSlurper(false, false, true)
parser.setFeature('http://xml.org/sax/features/external-general-entities', false)
parser.setFeature('http://xml.org/sax/features/external-parameter-entities', false)
parser.setFeature('http://apache.org/xml/features/nonvalidating/load-external-dtd', false)
def xml = parser.parse(reportFile)
def sourceRoots = sourceSets.main.java.srcDirs

def out = lcovReportFile.get().asFile
out.parentFile.mkdirs()
out.withWriter('UTF-8') { writer ->
writer.println('TN:')
xml.package.each { packageNode ->
Comment thread
hansott marked this conversation as resolved.
packageNode.sourcefile.each { sourceFile ->
def relativePath = "${packageNode.@name.text()}/${sourceFile.@name.text()}"
def path = relativePath
for (root in sourceRoots) {
def candidate = new File(root, relativePath)
if (candidate.exists()) {
path = candidate.path
break
}
}
writer.println("SF:${path}")
sourceFile.line.each { line ->
def hits = line.@ci.text().toInteger() > 0 ? 1 : 0
writer.println("DA:${line.@nr.text()},${hits}")
}
writer.println('end_of_record')
}
}
}
}
}

jacocoTestCoverageVerification {
classDirectories.setFrom(jacocoClassDirectories)
violationRules {
Expand Down
Loading