From 2bae0e350c2504241d19690e0540514b73bb84a3 Mon Sep 17 00:00:00 2001 From: Rinjae Date: Thu, 13 Aug 2026 17:53:14 +0900 Subject: [PATCH] =?UTF-8?q?OWASP=20Dependency-Check=20=ED=86=B5=ED=95=A9?= =?UTF-8?q?=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Jenkinsfile.security: 라이브러리 취약점 검사용 파이프라인 작성 (SAST/SCA 병행) - dependency-check-classpath.gradle: 스캔 대상 의존성 jar 분리 로직 작성 - dependency-check-suppressions.xml: 오탐 억제 규칙 파일 추가 --- Jenkinsfile.security | 501 +++++++++++++++++++++++++++ ci/dependency-check-classpath.gradle | 58 ++++ ci/dependency-check-suppressions.xml | 31 ++ 3 files changed, 590 insertions(+) create mode 100644 Jenkinsfile.security create mode 100644 ci/dependency-check-classpath.gradle create mode 100644 ci/dependency-check-suppressions.xml diff --git a/Jenkinsfile.security b/Jenkinsfile.security new file mode 100644 index 0000000..63f8c06 --- /dev/null +++ b/Jenkinsfile.security @@ -0,0 +1,501 @@ +// 보안 검사 통합 파이프라인 — OWASP Dependency-Check(SCA) + SonarQube(SAST). +// +// 두 검사는 보는 대상이 다르다. 하나만 돌리면 절반만 본다. +// SonarQube : 우리가 쓴 코드의 결함 (SQL Injection, XSS, 하드코딩 시크릿 …) +// Dependency-Check : 우리가 쓰는 라이브러리의 알려진 취약점 (CVE) +// +// 전제 (Jenkins 쪽 설정 이름이 다르면 environment 블록만 고치면 된다) +// 1) Manage Jenkins > System > SonarQube servers 에 서버 등록 (이름: SONAR_ENV_NAME) +// 2) Manage Jenkins > Tools > SonarQube Scanner 에 스캐너 등록 (없으면 PATH 탐색) +// 3) 노드에 Dependency-Check CLI 설치 (DC_HOME) — 설치 방법은 17-보안 가이드 문서 참고 +// 4) NVD API Key 를 Secret text credential 로 등록 (기본 ID: nvd-api-key) +// 키가 없으면 NVD 갱신이 극심하게 느려진다(수 시간). 폐쇄망은 UPDATE_NVD=false 로 운영. +// 5) Quality Gate 대기를 쓰려면 SonarQube 에 /sonarqube-webhook/ 웹훅 등록 +// +// JDK 분리: 빌드는 JDK 8, 스캐너/Dependency-Check 실행은 JDK 17. +// (SonarScanner CLI 5.x 는 JRE 17 필수, Dependency-Check 9.x 이상은 JRE 11 이상 필수) +pipeline { + agent { label 'djb-vm' } + + triggers { + // 코드 변경 감지 + pollSCM('H/30 * * * *') + // 코드가 그대로여도 새 CVE 는 계속 공개된다 → 야간 정기 재검사 + cron('H 3 * * *') + } + + options { + timestamps() + disableConcurrentBuilds() + buildDiscarder(logRotator(numToKeepStr: '20')) + } + + parameters { + booleanParam( + name: 'RUN_DEPENDENCY_CHECK', + defaultValue: true, + description: 'OWASP Dependency-Check(SCA) 실행' + ) + booleanParam( + name: 'RUN_SONAR', + defaultValue: true, + description: 'SonarQube 정적 분석(SAST) 실행' + ) + booleanParam( + name: 'RUN_TESTS', + defaultValue: false, + description: '단위 테스트를 함께 실행해 JUnit 결과를 Sonar 로 전송한다(분석 시간 증가).' + ) + booleanParam( + name: 'UPDATE_NVD', + defaultValue: true, + description: 'NVD 취약점 DB 갱신. 폐쇄망(외부 인터넷 불가)이면 반드시 끈다 — 캐시된 DB 로만 검사한다.' + ) + string( + name: 'FAIL_ON_CVSS', + defaultValue: '11', + description: '이 CVSS 점수 이상이면 검사 실패로 표시. 11 = 실패시키지 않음(리포트만). 예: 7 = High 이상' + ) + booleanParam( + name: 'FAIL_BUILD_ON_FINDING', + defaultValue: false, + description: 'FAIL_ON_CVSS 위반 시 빌드를 FAILURE 로 만든다. 끄면 UNSTABLE 로만 표시.' + ) + booleanParam( + name: 'SCAN_JS', + defaultValue: true, + description: '정적 JS 라이브러리(static/js, static/plugins)도 RetireJS 로 검사. 폐쇄망에서 오류나면 끈다.' + ) + } + + environment { + // --- Jenkins 설정 이름 (환경에 맞게 수정) --- + SONAR_ENV_NAME = 'SonarQube-Community' + SONAR_SCANNER_TOOL = '' + // NVD API Key 를 담은 Secret text credential ID. 없으면 키 없이 진행한다(느림). + NVD_API_KEY_CRED = 'nvd-api-key' + + // --- 툴체인 --- + JAVA_HOME = '/apps/opts/jdk8' // gradle 컴파일용 (프로젝트는 Java 8) + JAVA_HOME_SCANNER = '/apps/opts/jdk17' // sonar-scanner / dependency-check 실행용 + GRADLE_HOME = '/apps/opts/gradle-8.7' + GRADLE_USER_HOME = '/apps/opts/gradle-home' + PATH = "/apps/opts/jdk8/bin:/apps/opts/gradle-8.7/bin:/apps/opts/bin:${env.PATH}" + GIT_SSH_COMMAND = 'ssh -o StrictHostKeyChecking=accept-new' + + // --- Dependency-Check --- + // CLI 설치 경로. 비어 있거나 없으면 Jenkins Tools 등록분 > PATH 순으로 탐색한다. + DC_HOME = '/apps/opts/dependency-check' + // NVD 캐시(H2 DB). 워크스페이스 밖에 두어야 빌드마다 1GB 이상을 다시 받지 않는다. + // 여러 Job 이 공유하므로 disableConcurrentBuilds 를 켠 채로 쓴다. + DC_DATA = '/apps/opts/dependency-check-data' + DC_TOOL_NAME = '' + DC_REPORT_DIR = 'build/reports/dependency-check' + } + + stages { + stage('Checkout') { + steps { + checkout scm + } + } + + // eapim-portal 은 elink-portal-common / elink-online-core-jpa 를 subproject 로 참조한다. + // 이 둘이 없으면 컴파일도 의존성 해석도 불가능하다. + stage('Checkout dependencies') { + steps { + sh ''' + set -eu + cd "$WORKSPACE/.." + + if [ ! -d elink-portal-common/.git ]; then + rm -rf elink-portal-common + git clone --depth=1 --branch master \ + ssh://git@172.30.1.50:2222/djb-eapim/elink-portal-common.git \ + elink-portal-common + else + git -C elink-portal-common fetch --depth=1 origin master + git -C elink-portal-common reset --hard origin/master + git -C elink-portal-common clean -fdx + fi + + mkdir -p eapim-online + if [ ! -d eapim-online/elink-online-core-jpa/.git ]; then + rm -rf eapim-online/elink-online-core-jpa + git clone --depth=1 --branch master \ + ssh://git@172.30.1.50:2222/djb-eapim/elink-online-core-jpa.git \ + eapim-online/elink-online-core-jpa + else + git -C eapim-online/elink-online-core-jpa fetch --depth=1 origin master + git -C eapim-online/elink-online-core-jpa reset --hard origin/master + git -C eapim-online/elink-online-core-jpa clean -fdx + fi + ''' + } + } + + stage('Verify toolchain') { + steps { + sh ''' + set -eu + echo "--- build JDK ---" + java -version + gradle --version + + echo "--- scanner/dependency-check JDK ---" + if [ ! -x "$JAVA_HOME_SCANNER/bin/java" ]; then + echo "JDK 17 이 없다: $JAVA_HOME_SCANNER" + echo "SonarScanner 는 JRE 17, Dependency-Check 는 JRE 11 이상을 요구한다." + exit 1 + fi + "$JAVA_HOME_SCANNER/bin/java" -version + ''' + } + } + + // build/generated 잔여 산출물이 남으면 MapStruct Impl / QueryDSL Q클래스가 + // 중복 생성되어 컴파일이 깨진다. clean 이 파일 잠금 등으로 실패하는 경우가 있어 + // 생성 소스 디렉터리는 별도로 먼저 지운다. + stage('Compile') { + steps { + sh ''' + set -eu + rm -rf build/generated build/classes + gradle clean classes testClasses --no-daemon + ''' + } + } + + stage('Test') { + when { expression { return params.RUN_TESTS } } + steps { + sh 'gradle test --no-daemon' + } + post { + always { + junit allowEmptyResults: true, testResults: 'build/test-results/test/*.xml' + } + } + } + + // 배포본에 실리는 것과 같은 목록(runtimeClasspath)만 모은다. + // 이게 없으면 Dependency-Check 가 스캔할 jar 가 없어 "취약점 0건" 이라는 거짓 안심을 준다. + stage('Export dependency jars') { + when { expression { return params.RUN_DEPENDENCY_CHECK } } + steps { + sh 'gradle -I ci/dependency-check-classpath.gradle exportDependencyJars --no-daemon' + sh ''' + set -eu + COUNT=$(find build/dependency-check/libs -name '*.jar' -type f | wc -l | tr -d ' ') + echo "scan target jars: $COUNT" + if [ "$COUNT" -eq 0 ]; then + echo "수집된 jar 가 0개다. 의존성 해석이 실패했는지 확인할 것." + exit 1 + fi + ''' + } + } + + stage('OWASP Dependency-Check') { + when { expression { return params.RUN_DEPENDENCY_CHECK } } + steps { + script { + // CLI 위치 결정: DC_HOME > Jenkins Tools 등록분 > PATH + def dcHome = null + if (env.DC_HOME?.trim() && fileExists("${env.DC_HOME}/bin/dependency-check.sh")) { + dcHome = env.DC_HOME.trim() + echo "Dependency-Check: ${dcHome} (DC_HOME)" + } else { + def candidates = env.DC_TOOL_NAME?.trim() + ? [env.DC_TOOL_NAME.trim()] + : ['dependency-check', 'Dependency-Check', 'OWASP Dependency-Check', 'dependency-check-cli'] + for (name in candidates) { + try { + dcHome = tool name: name, + type: 'org.jenkinsci.plugins.DependencyCheck.tools.DependencyCheckInstallation' + echo "Dependency-Check tool: '${name}' -> ${dcHome}" + break + } catch (ignored) { + // 등록되지 않은 이름은 건너뛴다 + } + } + if (dcHome == null) { + echo 'Jenkins Tools 에 등록된 Dependency-Check 가 없다. PATH 의 dependency-check.sh 로 진행한다.' + } + } + + // NVD API Key credential 이 있는지 먼저 확인한다. + // (없는 credential 로 withCredentials 를 감싸면 파이프라인 자체가 죽는다) + def hasNvdKey = true + try { + withCredentials([string(credentialsId: env.NVD_API_KEY_CRED, variable: 'NVD_PROBE')]) { + // 존재 확인만 한다 + } + } catch (ignored) { + hasNvdKey = false + } + + if (!hasNvdKey) { + echo "NVD API Key credential('${env.NVD_API_KEY_CRED}') 이 없다. 키 없이 진행한다." + echo 'NVD 갱신이 매우 느려진다(수 시간). https://nvd.nist.gov/developers/request-an-api-key 에서 발급 권장.' + } + + def dcScript = ''' + set -eu + + # Dependency-Check 는 JRE 11 이상 필요 (빌드용 JDK 8 과 분리) + export JAVA_HOME="$JAVA_HOME_SCANNER" + export PATH="$JAVA_HOME/bin:$PATH" + + mkdir -p "$DC_DATA" "$DC_REPORT_DIR" + + if [ -n "${DC_RESOLVED_HOME:-}" ] && [ -x "$DC_RESOLVED_HOME/bin/dependency-check.sh" ]; then + DC="$DC_RESOLVED_HOME/bin/dependency-check.sh" + elif command -v dependency-check.sh >/dev/null 2>&1; then + DC="$(command -v dependency-check.sh)" + else + echo "dependency-check.sh 를 찾지 못했다." + echo "노드에 CLI 를 설치하고 DC_HOME 을 맞추거나, Manage Jenkins > Tools 에 등록할 것." + exit 1 + fi + echo "dependency-check: $DC" + + ARGS="" + + # 폐쇄망/오프라인: 캐시된 NVD DB 로만 검사한다. + if [ "${UPDATE_NVD_FLAG}" != "true" ]; then + ARGS="$ARGS --noupdate" + if [ ! -d "$DC_DATA" ] || [ -z "$(ls -A "$DC_DATA" 2>/dev/null)" ]; then + echo "NVD 캐시가 비어 있는데 갱신이 꺼져 있다: $DC_DATA" + echo "인터넷 되는 곳에서 1회 적재한 data 디렉터리를 복사해 둘 것." + exit 1 + fi + fi + + if [ -n "${NVD_API_KEY:-}" ]; then + ARGS="$ARGS --nvdApiKey ${NVD_API_KEY}" + fi + + # OSS Index 분석기는 외부 서비스(ossindex.sonatype.org)를 호출한다. + # 갱신을 끈 환경(=외부 통신 불가)에서는 같이 끈다. + if [ "${UPDATE_NVD_FLAG}" != "true" ]; then + ARGS="$ARGS --disableOssIndex" + fi + + # 자바 프로젝트에 불필요한 분석기 — 실행 시간만 늘린다. + ARGS="$ARGS --disableAssembly --disableNodeAudit --disableNodeJS" + + SCAN_ARGS="--scan build/dependency-check/libs" + if [ "${SCAN_JS_FLAG}" = "true" ]; then + # 번들된 JS 라이브러리(jQuery, summernote 등)의 알려진 취약점 — RetireJS + [ -d src/main/resources/static/js ] && SCAN_ARGS="$SCAN_ARGS --scan src/main/resources/static/js" + [ -d src/main/resources/static/plugins ] && SCAN_ARGS="$SCAN_ARGS --scan src/main/resources/static/plugins" + else + ARGS="$ARGS --disableRetireJS" + fi + + SUPPRESSION="" + if [ -f ci/dependency-check-suppressions.xml ]; then + SUPPRESSION="--suppression ci/dependency-check-suppressions.xml" + fi + + # 토큰/키가 콘솔에 남지 않도록 실행 명령 자체는 출력하지 않는다. + set +x + "$DC" \ + --project "DJB eAPIM Portal" \ + $SCAN_ARGS \ + --out "$DC_REPORT_DIR" \ + --format HTML --format XML --format JSON \ + --data "$DC_DATA" \ + --failOnCVSS "${FAIL_ON_CVSS_VALUE}" \ + $SUPPRESSION \ + $ARGS + ''' + + def dcEnv = [ + "DC_RESOLVED_HOME=${dcHome ?: ''}", + "UPDATE_NVD_FLAG=${params.UPDATE_NVD}", + "SCAN_JS_FLAG=${params.SCAN_JS}", + "FAIL_ON_CVSS_VALUE=${params.FAIL_ON_CVSS}" + ] + + // 정책: 기본은 UNSTABLE 로만 표시하고 뒤의 Sonar 분석까지 마친다. + // FAIL_BUILD_ON_FINDING 을 켜면 임계치 위반이 빌드 실패가 된다. + def onFinding = params.FAIL_BUILD_ON_FINDING ? 'FAILURE' : 'UNSTABLE' + catchError(buildResult: onFinding, stageResult: 'FAILURE') { + withEnv(dcEnv) { + if (hasNvdKey) { + withCredentials([string(credentialsId: env.NVD_API_KEY_CRED, variable: 'NVD_API_KEY')]) { + sh dcScript + } + } else { + sh dcScript + } + } + } + } + } + post { + always { + archiveArtifacts allowEmptyArchive: true, + artifacts: 'build/reports/dependency-check/dependency-check-report.*' + script { + // OWASP Dependency-Check 플러그인이 설치돼 있으면 추이 그래프/경고를 남긴다. + // 없어도 리포트는 위에서 아카이브되므로 실패로 보지 않는다. + try { + dependencyCheckPublisher pattern: 'build/reports/dependency-check/dependency-check-report.xml' + } catch (ignored) { + echo 'OWASP Dependency-Check 플러그인 미설치 — 아카이브된 HTML 리포트로 확인할 것.' + } + } + } + } + } + + // sonar.java.libraries 용 클래스패스 덤프. + // 없으면 타입 해석이 안 돼 보안 룰 다수가 침묵하므로 실패 시 UNSTABLE 로만 넘기고 분석은 계속한다. + stage('Export analysis classpath') { + when { expression { return params.RUN_SONAR } } + steps { + catchError(buildResult: 'UNSTABLE', stageResult: 'FAILURE') { + sh 'gradle -I ci/sonar-classpath.gradle exportSonarClasspath --no-daemon' + } + } + } + + stage('SonarQube analysis') { + when { expression { return params.RUN_SONAR } } + steps { + script { + // 스캐너 위치 결정: 지정 이름 > 흔한 등록 이름 후보 > PATH 의 sonar-scanner + def candidates = env.SONAR_SCANNER_TOOL?.trim() + ? [env.SONAR_SCANNER_TOOL.trim()] + : ['SonarScanner', 'SonarQube Scanner', 'sonar-scanner', 'SonarScanner CLI', 'sonarqube-scanner'] + + def scannerHome = null + for (name in candidates) { + try { + scannerHome = tool name: name, type: 'hudson.plugins.sonar.SonarRunnerInstallation' + echo "SonarScanner tool: '${name}' -> ${scannerHome}" + break + } catch (ignored) { + // 등록되지 않은 이름은 건너뛴다 + } + } + + if (scannerHome == null) { + echo 'Jenkins Tools 에 등록된 SonarQube Scanner 를 찾지 못했다. PATH 의 sonar-scanner 로 진행한다.' + echo '(Manage Jenkins > Tools 에 등록한 뒤 environment 의 SONAR_SCANNER_TOOL 에 그 이름을 넣으면 확실하다.)' + } + + withSonarQubeEnv(env.SONAR_ENV_NAME) { + withEnv(["SONAR_SCANNER_HOME=${scannerHome ?: ''}"]) { + sh ''' + set -eu + + # 스캐너는 JDK 17 로 실행한다 (빌드용 JDK 8 과 분리) + export JAVA_HOME="$JAVA_HOME_SCANNER" + export PATH="$JAVA_HOME/bin:$PATH" + + # 토큰은 커맨드라인(-Dsonar.token)에 노출시키지 않고 환경변수로만 넘긴다. + if [ -z "${SONAR_TOKEN:-}" ] && [ -n "${SONAR_AUTH_TOKEN:-}" ]; then + export SONAR_TOKEN="$SONAR_AUTH_TOKEN" + fi + + LIBS="" + if [ -f build/sonar/java-libraries.txt ]; then + LIBS=$(cat build/sonar/java-libraries.txt) + else + echo "WARN: build/sonar/java-libraries.txt 없음 - 타입 해석 정확도 저하" + fi + + TEST_LIBS="" + if [ -f build/sonar/java-test-libraries.txt ]; then + TEST_LIBS=$(cat build/sonar/java-test-libraries.txt) + fi + + JUNIT_ARG="" + if [ -d build/test-results/test ]; then + JUNIT_ARG="-Dsonar.junit.reportPaths=build/test-results/test" + fi + + # SonarQube 에 Dependency-Check 플러그인이 설치돼 있으면 CVE 결과도 함께 올린다. + # 플러그인이 없으면 스캐너가 모르는 속성으로 무시한다(경고만). + DC_ARG="" + if [ -f "$DC_REPORT_DIR/dependency-check-report.json" ]; then + DC_ARG="-Dsonar.dependencyCheck.jsonReportPath=$DC_REPORT_DIR/dependency-check-report.json" + if [ -f "$DC_REPORT_DIR/dependency-check-report.html" ]; then + DC_ARG="$DC_ARG -Dsonar.dependencyCheck.htmlReportPath=$DC_REPORT_DIR/dependency-check-report.html" + fi + fi + + if [ -n "${SONAR_SCANNER_HOME:-}" ] && [ -x "$SONAR_SCANNER_HOME/bin/sonar-scanner" ]; then + SCANNER="$SONAR_SCANNER_HOME/bin/sonar-scanner" + elif command -v sonar-scanner >/dev/null 2>&1; then + SCANNER="$(command -v sonar-scanner)" + else + echo "sonar-scanner 실행 파일을 찾지 못했다." + echo "Manage Jenkins > Tools > SonarQube Scanner 에 등록하거나 노드 PATH 에 설치할 것." + exit 1 + fi + echo "scanner: $SCANNER" + + "$SCANNER" \ + -Dsonar.projectVersion="${BUILD_NUMBER}" \ + -Dsonar.java.libraries="$LIBS" \ + -Dsonar.java.test.libraries="$TEST_LIBS" \ + $JUNIT_ARG \ + $DC_ARG + ''' + } + } + } + } + } + + // SonarQube 웹훅으로 게이트 결과를 받아 판정한다. + // 정책: 게이트 실패는 UNSTABLE 로만 표시하고 빌드는 실패시키지 않는다. + stage('Quality Gate') { + when { expression { return params.RUN_SONAR } } + steps { + script { + def qg = null + try { + timeout(time: 15, unit: 'MINUTES') { + qg = waitForQualityGate abortPipeline: false + } + } catch (err) { + unstable("Quality Gate 결과 대기 실패/타임아웃: ${err}") + return + } + + if (qg == null) { + unstable('Quality Gate 결과를 받지 못했다. SonarQube 웹훅 설정을 확인할 것.') + } else if (qg.status != 'OK') { + unstable("Quality Gate ${qg.status}") + } else { + echo 'Quality Gate OK' + } + } + } + } + } + + post { + always { + archiveArtifacts allowEmptyArchive: true, artifacts: '.scannerwork/report-task.txt' + script { + def report = '.scannerwork/report-task.txt' + if (fileExists(report)) { + def url = readFile(report).readLines().find { it.startsWith('dashboardUrl=') } + if (url) { + echo "SonarQube: ${url.substring('dashboardUrl='.length())}" + } + } + if (fileExists('build/reports/dependency-check/dependency-check-report.html')) { + echo "Dependency-Check 리포트: ${env.BUILD_URL}artifact/build/reports/dependency-check/dependency-check-report.html" + } + } + } + } +} diff --git a/ci/dependency-check-classpath.gradle b/ci/dependency-check-classpath.gradle new file mode 100644 index 0000000..8560ca2 --- /dev/null +++ b/ci/dependency-check-classpath.gradle @@ -0,0 +1,58 @@ +// OWASP Dependency-Check 가 스캔할 서드파티 jar 를 한 디렉터리로 모은다. +// +// build.gradle 을 건드리지 않기 위해 init script(-I) 로만 주입한다. +// gradle -I ci/dependency-check-classpath.gradle exportDependencyJars --no-daemon +// +// 출력: +// build/dependency-check/libs/*.jar runtimeClasspath 의 외부 의존 jar (원본 파일명 유지) +// build/dependency-check/jars.txt 수집 목록(경로 1줄씩) — 진단용 +// +// 왜 디렉터리로 모으는가 +// Dependency-Check CLI 는 --scan <경로> 로 파일/디렉터리를 받는다. Gradle 캐시를 통째로 스캔하면 +// 이 프로젝트가 쓰지 않는 버전까지 잡히고, 프로젝트 디렉터리만 스캔하면 의존 jar 가 아예 안 잡힌다. +// 실제 배포본에 실리는 것과 같은 목록(runtimeClasspath)만 모아야 결과가 배포 산출물과 일치한다. +// +// 파일명을 유지해야 하는 이유 +// Dependency-Check 는 jar 안의 POM/MANIFEST 외에 파일명에서도 CPE(제품/버전)를 추론한다. +// 이름을 바꾸면 탐지 정확도가 떨어진다. + +rootProject { project -> + project.plugins.withId('java') { + project.tasks.register('exportDependencyJars') { + group = 'verification' + description = 'Dependency-Check 스캔용 런타임 의존 jar 를 build/dependency-check/libs 에 모은다' + + doLast { + def outRoot = new File(project.layout.buildDirectory.get().asFile, 'dependency-check') + def outDir = new File(outRoot, 'libs') + project.delete(outDir) + outDir.mkdirs() + + // 컴포지트/서브프로젝트의 build 디렉터리 산출물(우리가 만든 jar)은 제외한다. + // 자체 코드는 SonarQube 가 보는 영역이고, SCA 대상은 외부 라이브러리다. + def buildDirs = project.allprojects.collect { + it.layout.buildDirectory.get().asFile.absolutePath + } + def isOwnArtifact = { File f -> + buildDirs.any { f.absolutePath.startsWith(it + File.separator) } + } + + def jars = project.configurations.runtimeClasspath.files + .findAll { it.isFile() && it.name.endsWith('.jar') && !isOwnArtifact(it) } + .unique() + .sort { it.name } + + project.copy { + from jars + into outDir + } + + new File(outRoot, 'jars.txt').text = + jars.collect { it.absolutePath }.join(System.lineSeparator()) + System.lineSeparator() + + def totalMb = (jars.sum { it.length() } ?: 0L) / (1024 * 1024) + logger.lifecycle("dependency-check scan target: ${jars.size()} jars, ${totalMb as int} MB -> ${outDir}") + } + } + } +} diff --git a/ci/dependency-check-suppressions.xml b/ci/dependency-check-suppressions.xml new file mode 100644 index 0000000..e70259b --- /dev/null +++ b/ci/dependency-check-suppressions.xml @@ -0,0 +1,31 @@ + + + + + + +