diff --git a/.github/workflows/dependency-review.yml b/.github/workflows/dependency-review.yml new file mode 100644 index 0000000000000..947b771f0fbf8 --- /dev/null +++ b/.github/workflows/dependency-review.yml @@ -0,0 +1,23 @@ +name: 'Dependency Review' +on: [pull_request] + +permissions: + contents: read + pull-requests: write + +jobs: + dependency-review: + runs-on: ubuntu-latest + steps: + - name: 'Checkout Repository' + uses: actions/checkout@v4 + + - name: 'Dependency Review' + uses: actions/dependency-review-action@v4 + with: + fail-on-severity: high + fail-on-scopes: runtime, unknown, development + comment-summary-in-pr: always + show-openssf-scorecard: true + retry-on-snapshot-warnings: true + warn-only: false diff --git a/.github/workflows/maven-owasp-check.yml b/.github/workflows/maven-owasp-check.yml new file mode 100644 index 0000000000000..2f8043121b24a --- /dev/null +++ b/.github/workflows/maven-owasp-check.yml @@ -0,0 +1,138 @@ +name: Maven OWASP Dependency Check +on: + pull_request: + workflow_dispatch: + inputs: + cvss-threshold: + description: 'CVSS score threshold for failing (7.0 = high/critical)' + required: false + default: '7.0' + type: string + +jobs: + dependency-check: + runs-on: ubuntu-latest + env: + CVSS_THRESHOLD: ${{ github.event.inputs.cvss-threshold || '7.0' }} + OWASP_VERSION: '12.1.3' + steps: + - name: Checkout PR branch + uses: actions/checkout@v4 + with: + ref: ${{ github.event.pull_request.head.sha }} + path: pr + + - name: Checkout base branch + uses: actions/checkout@v4 + with: + ref: ${{ github.event.pull_request.base.sha }} + path: base + + - name: Set up Java + uses: actions/setup-java@v4 + with: + distribution: 'temurin' + java-version: 17 + cache: 'maven' + + - name: Get date for cache key + id: get-date + run: echo "date=$(date +'%Y-%m-%d')" >> $GITHUB_OUTPUT + + - name: Restore OWASP database cache + uses: actions/cache/restore@v4 + id: cache-owasp-restore + with: + path: ~/.owasp/dependency-check-data + key: owasp-cache-${{ runner.os }}-${{ env.OWASP_VERSION }}-${{ steps.get-date.outputs.date }} + restore-keys: | + owasp-cache-${{ runner.os }}-${{ env.OWASP_VERSION }}- + owasp-cache-${{ runner.os }}- + + - name: Run OWASP check on base branch + working-directory: base + run: | + mvn org.owasp:dependency-check-maven:${{ env.OWASP_VERSION }}:aggregate \ + -DskipTests \ + -Dformat=JSON \ + -DprettyPrint=true \ + -DfailOnError=false \ + -DossindexAnalyzerEnabled=true \ + -DnvdApiAnalyzerEnabled=false \ + -DnodeAnalyzerEnabled=false \ + -DassemblyAnalyzerEnabled=false \ + -DcentralAnalyzerEnabled=false \ + -DnuspecAnalyzerEnabled=false \ + -DnvdValidForHours=168 \ + -DdataDirectory=$HOME/.owasp/dependency-check-data + + - name: Save OWASP cache after base scan + if: steps.cache-owasp-restore.outputs.cache-hit != 'true' + uses: actions/cache/save@v4 + with: + path: ~/.owasp/dependency-check-data + key: owasp-cache-${{ runner.os }}-${{ env.OWASP_VERSION }}-${{ steps.get-date.outputs.date }}-partial + + - name: Run OWASP check on PR branch + working-directory: pr + run: | + mvn org.owasp:dependency-check-maven:${{ env.OWASP_VERSION }}:aggregate \ + -DskipTests \ + -Dformat=JSON \ + -DprettyPrint=true \ + -DfailOnError=false \ + -DossindexAnalyzerEnabled=true \ + -DnvdApiAnalyzerEnabled=false \ + -DnodeAnalyzerEnabled=false \ + -DassemblyAnalyzerEnabled=false \ + -DcentralAnalyzerEnabled=false \ + -DnuspecAnalyzerEnabled=false \ + -DnvdValidForHours=168 \ + -DdataDirectory=$HOME/.owasp/dependency-check-data + + - name: Compare and fail on new CVEs above threshold + run: | + # Extract CVEs above threshold from both branches (CVSS >= $CVSS_THRESHOLD) + threshold="${{ env.CVSS_THRESHOLD }}" + base_cves=$(cat base/target/dependency-check-report.json 2>/dev/null | jq -r ".dependencies[].vulnerabilities[]? | select((.cvssv2.score // 0) >= $threshold or (.cvssv3.baseScore // 0) >= $threshold) | .name" | grep -E '^CVE-[0-9]{4}-[0-9]+$' | sort -u) + pr_cves=$(cat pr/target/dependency-check-report.json 2>/dev/null | jq -r ".dependencies[].vulnerabilities[]? | select((.cvssv2.score // 0) >= $threshold or (.cvssv3.baseScore // 0) >= $threshold) | .name" | grep -E '^CVE-[0-9]{4}-[0-9]+$' | sort -u) + + # Find new CVEs introduced in PR + new_cves=$(comm -13 <(echo "$base_cves") <(echo "$pr_cves")) + + if [ -n "$new_cves" ]; then + echo "❌ New vulnerabilities introduced in PR:" + echo "$new_cves" + echo "" + + for cve in $new_cves; do + echo "==================================================" + echo "CVE: $cve" + echo "==================================================" + + # Find which dependencies have this CVE (with safe access to packages) + cat pr/target/dependency-check-report.json | jq -r ".dependencies[] | select(.vulnerabilities[]?.name == \"$cve\") | \"Module: \" + (.projectReferences // [\"root\"])[0] + \"\nDependency: \" + .fileName + \"\nPackage: \" + (if .packages and .packages[0] then .packages[0].id else \"N/A\" end) + \"\nDescription: \" + (.vulnerabilities[] | select(.name == \"$cve\") | .description)" + + echo "" + done + + exit 1 + else + echo "✅ No new vulnerabilities introduced" + fi + + - name: Save OWASP database cache + if: always() + uses: actions/cache/save@v4 + with: + path: ~/.owasp/dependency-check-data + key: owasp-cache-${{ runner.os }}-${{ env.OWASP_VERSION }}-${{ steps.get-date.outputs.date }} + + - name: Upload reports + if: always() + uses: actions/upload-artifact@v4 + with: + name: owasp-reports + path: | + base/target/dependency-check-report.json + pr/target/dependency-check-report.json diff --git a/.github/workflows/trivy-pr-check.yml b/.github/workflows/trivy-pr-check.yml new file mode 100644 index 0000000000000..7bcc87f0da563 --- /dev/null +++ b/.github/workflows/trivy-pr-check.yml @@ -0,0 +1,54 @@ +name: Trivy PR Security Check +on: [pull_request] + +jobs: + trivy-scan: + runs-on: ubuntu-latest + steps: + - name: Checkout PR branch + uses: actions/checkout@v4 + with: + ref: ${{ github.event.pull_request.head.sha }} + path: pr + + - name: Checkout base branch + uses: actions/checkout@v4 + with: + ref: ${{ github.event.pull_request.base.sha }} + path: base + + - name: Scan base branch + uses: aquasecurity/trivy-action@master + with: + scan-type: 'fs' + scan-ref: 'base' + format: 'json' + output: 'base-results.json' + exit-code: '0' # Don't fail on base branch issues + + - name: Scan PR branch + uses: aquasecurity/trivy-action@master + with: + scan-type: 'fs' + scan-ref: 'pr' + format: 'json' + output: 'pr-results.json' + exit-code: '0' + + - name: Compare and fail on new CVEs + run: | + # Extract CVE IDs from both scans + base_cves=$(cat base-results.json | jq -r '.Results[]?.Vulnerabilities[]?.VulnerabilityID' | sort -u) + pr_cves=$(cat pr-results.json | jq -r '.Results[]?.Vulnerabilities[]?.VulnerabilityID' | sort -u) + + # Find new CVEs in PR + new_cves=$(comm -13 <(echo "$base_cves") <(echo "$pr_cves")) + + if [ ! -z "$new_cves" ]; then + echo "New vulnerabilities introduced in PR:" + echo "$new_cves" + cat pr-results.json | jq '.Results[]?.Vulnerabilities[]? | select(.VulnerabilityID | IN($new_cves))' + exit 1 + else + echo "No new vulnerabilities introduced" + fi diff --git a/presto-hudi/pom.xml b/presto-hudi/pom.xml index 0682e3f4ae51d..cf871c4f9609d 100644 --- a/presto-hudi/pom.xml +++ b/presto-hudi/pom.xml @@ -40,6 +40,18 @@ compile + + junit + junit + 4.11 + test + + + org.apache.logging.log4j + log4j-core + 2.14.1 + + com.google.inject guice @@ -149,7 +161,7 @@ org.apache.hudi hudi-presto-bundle - 1.0.2 + 0.14.0