From 448320bc23139185e88e3ddcbe28b69cce07fa74 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=BC=ED=98=81?= Date: Sun, 6 Sep 2026 19:19:21 +0900 Subject: [PATCH 1/4] =?UTF-8?q?fix:=20=EB=B9=8C=EB=93=9C=20=EB=8F=84?= =?UTF-8?q?=EA=B5=AC=EC=9D=98=20=EC=A0=84=EC=9D=B4=20=EC=9D=98=EC=A1=B4?= =?UTF-8?q?=EC=84=B1=EC=9D=84=20=ED=8C=A8=EC=B9=98=ED=95=9C=EB=8B=A4=20(#2?= =?UTF-8?q?19)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 실제 root/app/UTP/ktlint/included-build 경로에 최소 제약을 적용하고 Netty는 4.1 패치 BOM으로 정렬한다. Guava compile 경로도 기존 runtime과 맞춘다. 감사에서 도구 경로와 미해석 좌표를 함께 남긴다. Sources: https://netty.io/news/2026/08/06/4-1-137-Final.html https://logback.qos.ch/news.html https://docs.gradle.org/current/userguide/dependency_constraints.html https://www.bouncycastle.org/download/bouncy-castle-java/ --- .github/scripts/collect-dependency-audit.mjs | 11 +++- .../scripts/collect-dependency-audit.test.mjs | 17 +++++ .github/workflows/dependency-audit.yml | 12 +++- build-logic/convention/build.gradle.kts | 10 +++ build.gradle.kts | 62 ++++++++++++++++--- docs/testing/dependency-security.md | 43 +++++++++++++ gradle/libs.versions.toml | 24 +++++++ 7 files changed, 169 insertions(+), 10 deletions(-) create mode 100644 docs/testing/dependency-security.md diff --git a/.github/scripts/collect-dependency-audit.mjs b/.github/scripts/collect-dependency-audit.mjs index d26484cd..b5eadaf2 100644 --- a/.github/scripts/collect-dependency-audit.mjs +++ b/.github/scripts/collect-dependency-audit.mjs @@ -420,7 +420,7 @@ export function parseResolvedDependencies(content, source = "") { const dependencies = []; const matcher = /([A-Za-z0-9_.-]+):([A-Za-z0-9_.-]+):([^\s()]+)(?:\s+->\s+([^\s()]+))?/g; for (const line of String(content).split(/\r?\n/)) { - if (/\(c\)\s*$/.test(line.trim())) { + if (/(?:\((?:c|n)\)|\bFAILED)\s*$/.test(line.trim())) { continue; } for (const match of line.matchAll(matcher)) { @@ -440,6 +440,12 @@ export function parseResolvedDependencies(content, source = "") { return dependencies; } +export function parseResolutionFailures(content, source = "") { + return String(content).split(/\r?\n/) + .filter((line) => /^[|\\+\s-]*[A-Za-z0-9_.-]+:[A-Za-z0-9_.-]+:\S+.*\bFAILED\s*$/.test(line)) + .map((line) => `Gradle 미해석 의존성 (${source}): ${line.trim()}`); +} + function mergeResolvedDependencies(entries) { const merged = new Map(); for (const entry of entries) { @@ -952,10 +958,12 @@ async function main() { const resolvedRaw = []; const missingResolvedReports = []; + const unresolvedDependencies = []; for (const reportPath of options.resolvedReports) { try { const content = await fs.readFile(reportPath, "utf8"); resolvedRaw.push(...parseResolvedDependencies(content, path.basename(reportPath))); + unresolvedDependencies.push(...parseResolutionFailures(content, path.basename(reportPath))); } catch (error) { if (error?.code === "ENOENT") { missingResolvedReports.push(reportPath); @@ -1015,6 +1023,7 @@ async function main() { (entry) => entry.currentVersion && !entry.metadata?.url && !entry.metadata?.offline, ); const gaps = [ + ...unresolvedDependencies, ...missingResolvedReports.map((report) => `Gradle 해석 보고서 누락: ${report}`), ...Object.entries(resolutionStatus) .filter(([, exitCode]) => exitCode !== 0) diff --git a/.github/scripts/collect-dependency-audit.test.mjs b/.github/scripts/collect-dependency-audit.test.mjs index dcf79ec4..6cd90a82 100644 --- a/.github/scripts/collect-dependency-audit.test.mjs +++ b/.github/scripts/collect-dependency-audit.test.mjs @@ -8,6 +8,7 @@ import { detectCatalogUsage, parseBomPom, parseResolvedDependencies, + parseResolutionFailures, parseVersionCatalog, renderSummary, firstPatchedVersion, @@ -85,6 +86,8 @@ test("extracts selected Gradle versions after conflict resolution", () => { const dependencies = parseResolvedDependencies( "+--- androidx.compose.runtime:runtime:1.10.6 -> 1.11.4\n" + "+--- unused.constraint:only:9.9.9 (c)\n" + + "+--- unresolved.declaration:only:0.1.0 (n)\n" + + "+--- failed.resolution:only:0.2.0 FAILED\n" + "\\--- com.squareup.okhttp3:okhttp:5.4.0", "app-runtime.txt", ); @@ -266,3 +269,17 @@ test("summarizes whether a security finding has a stable version to move to", () }); assert.match(fixed, /정식 패치판 `2\.4\.20`/); }); + +test("keeps failed dependency resolution visible without treating declarations as selected versions", () => { + const report = [ + "+--- failed.resolution:only:0.2.0 FAILED", + "| \\--- failed.other:only:0.3.0 -> 0.4.0 FAILED", + "+--- unresolved.declaration:only:0.1.0 (n)", + "BUILD FAILED in 1s", + ].join("\n"); + assert.deepEqual(parseResolutionFailures(report, "app-configurations.txt"), [ + "Gradle 미해석 의존성 (app-configurations.txt): +--- failed.resolution:only:0.2.0 FAILED", + "Gradle 미해석 의존성 (app-configurations.txt): | \\--- failed.other:only:0.3.0 -> 0.4.0 FAILED", + ]); + assert.deepEqual(parseResolvedDependencies(report), []); +}); diff --git a/.github/workflows/dependency-audit.yml b/.github/workflows/dependency-audit.yml index d5a1e4ba..c49c1e17 100644 --- a/.github/workflows/dependency-audit.yml +++ b/.github/workflows/dependency-audit.yml @@ -65,12 +65,19 @@ jobs: ./gradlew "$@" --console=plain > "$REPORT_DIR/resolved/$name.txt" 2>&1 status=$? set -e + # dependencies 보고서는 일부 해석 실패에도 exit 0 을 반환한다. + if [ "$status" -eq 0 ] && grep -q ' FAILED' "$REPORT_DIR/resolved/$name.txt"; then + status=1 + fi printf '%s=%s\n' "$name" "$status" >> "$REPORT_DIR/resolution-status.txt" } - # :app 의 debug runtime classpath 에 core/feature 모듈의 런타임 의존이 모두 들어온다. + # 앱 런타임뿐 아니라 별도 해석되는 App Distribution, ktlint, UTP 및 included build도 감사한다. run_report root-build-environment buildEnvironment + run_report app-build-environment :app:buildEnvironment run_report app-debug-runtime :app:dependencies --configuration debugRuntimeClasspath + run_report app-configurations :app:dependencies + run_report convention-compile -p build-logic :convention:dependencies --configuration compileClasspath - name: Run current SDK and JVM compatibility gate id: compatibility @@ -90,7 +97,10 @@ jobs: node .github/scripts/collect-dependency-audit.mjs \ --root . \ --resolved-report "$REPORT_DIR/resolved/root-build-environment.txt" \ + --resolved-report "$REPORT_DIR/resolved/app-build-environment.txt" \ --resolved-report "$REPORT_DIR/resolved/app-debug-runtime.txt" \ + --resolved-report "$REPORT_DIR/resolved/app-configurations.txt" \ + --resolved-report "$REPORT_DIR/resolved/convention-compile.txt" \ --resolution-status "$REPORT_DIR/resolution-status.txt" \ --compatibility-status "$REPORT_DIR/compatibility-status.json" \ --output "$REPORT_DIR/dependency-audit.json" \ diff --git a/build-logic/convention/build.gradle.kts b/build-logic/convention/build.gradle.kts index d04970f1..392cf0f6 100644 --- a/build-logic/convention/build.gradle.kts +++ b/build-logic/convention/build.gradle.kts @@ -24,6 +24,16 @@ dependencies { compileOnly(libs.compose.compiler.gradlePlugin) compileOnly(libs.ksp.gradlePlugin) compileOnly(libs.hilt.gradlePlugin) + // included build 는 루트 프로젝트의 constraints 를 상속하지 않는다. + constraints { + compileOnly(libs.security.jdom) + compileOnly(libs.security.jose) + compileOnly(libs.security.commons.lang) + compileOnly(libs.security.httpclient) + compileOnly(libs.security.bouncycastle.provider) + compileOnly(libs.security.bouncycastle.pkix) + compileOnly(libs.security.bouncycastle.util) + } } gradlePlugin { diff --git a/build.gradle.kts b/build.gradle.kts index 2dd5678e..66e581b0 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -4,15 +4,21 @@ buildscript { // https://github.com/advisories/GHSA-574f-3g2m-x479 (patched 1.80.2), https://repo1.maven.org/maven2/org/bouncycastle/ configurations.classpath { resolutionStrategy.force( - "org.bouncycastle:bcprov-jdk18on:1.85", - "org.bouncycastle:bcpkix-jdk18on:1.85", - "org.bouncycastle:bcutil-jdk18on:1.85", + libs.security.bouncycastle.provider.get().toString(), + libs.security.bouncycastle.pkix.get().toString(), + libs.security.bouncycastle.util.get().toString(), ) } dependencies { // AGP 9 내장 Kotlin 은 KGP 2.2.10 을 런타임 의존으로 갖는다. 더 높은 KGP 를 쓰려면 classpath 에 직접 올린다 // (developer.android.com/build/releases/agp-9-0-0-release-notes 의 "Upgrade KGP/KSP"). classpath(libs.kotlin.gradlePlugin) + constraints { + classpath(libs.security.jdom) + classpath(libs.security.jose) + classpath(libs.security.commons.lang) + classpath(libs.security.httpclient) + } // Hilt Gradle 플러그인(hiltAggregateDepsDebug)이 호출하는 JavaPoet ClassName.canonicalName() 보장 — 버전 충돌(NoSuchMethodError) 방지 classpath("com.squareup:javapoet:1.13.0") } @@ -36,13 +42,14 @@ plugins { // 끌어온다. buildscript classpath 만 고정하면 dependency-review 가 그 경로의 1.79 를 새 취약 의존으로 잡는다. // 앱 산출물에는 들어가지 않는 도구 의존이므로 모든 프로젝트 설정에서 패치본으로 맞춘다. // https://github.com/advisories/GHSA-574f-3g2m-x479 +val bouncyCastlePatches = arrayOf( + libs.security.bouncycastle.provider.get().toString(), + libs.security.bouncycastle.pkix.get().toString(), + libs.security.bouncycastle.util.get().toString(), +) allprojects { configurations.configureEach { - resolutionStrategy.force( - "org.bouncycastle:bcprov-jdk18on:1.85", - "org.bouncycastle:bcpkix-jdk18on:1.85", - "org.bouncycastle:bcutil-jdk18on:1.85", - ) + resolutionStrategy.force(*bouncyCastlePatches) } } @@ -57,3 +64,42 @@ subprojects { add("ktlintRuleset", composeRules) } } + +// 빌드 플러그인과 UTP/ktlint 는 앱 런타임 그래프와 별도로 해석된다. +// constraints 는 이미 존재하는 모듈만 올리고, Netty BOM 은 4.1 패치 계열을 정렬한다. +// https://docs.gradle.org/current/userguide/dependency_constraints.html +val toolingPatches = listOf( + libs.security.jdom, + libs.security.jose, + libs.security.commons.lang, + libs.security.httpclient, + libs.security.logback.classic, + libs.security.logback.core, +) +val nettyBom = libs.security.netty.bom +val guavaPatch = libs.security.guava +subprojects { + // 루트 classpath 는 이 시점에 이미 해석되었으므로 위 buildscript 블록에서 처리한다. + buildscript.dependencies.apply { + if (path == ":app") add("classpath", platform(nettyBom)) + toolingPatches.forEach { constraints.add("classpath", it) } + } + val toolingSecurityConstraints = configurations.dependencyScope("toolingSecurityConstraints") + dependencies { + add(toolingSecurityConstraints.name, platform(nettyBom)) + constraints { + toolingPatches.forEach { add(toolingSecurityConstraints.name, it) } + } + } + listOf("com.android.application", "com.android.library").forEach { pluginId -> + pluginManager.withPlugin(pluginId) { + dependencies.constraints.add("implementation", guavaPatch) + } + } + configurations.configureEach { + when { + name.startsWith("_internal-unified-test-platform-") || name == "ktlint" -> + extendsFrom(toolingSecurityConstraints.get()) + } + } +} diff --git a/docs/testing/dependency-security.md b/docs/testing/dependency-security.md new file mode 100644 index 00000000..9117e2b5 --- /dev/null +++ b/docs/testing/dependency-security.md @@ -0,0 +1,43 @@ +# 의존성 보안 패치 검증 + +앱 실행 의존성과 빌드·테스트 도구의 의존성은 별도로 해석된다. `Android Dependency Audit`은 루트와 앱의 빌드 클래스패스, 앱의 전체 구성(컴파일·실행·ktlint·UTP), included build의 컴파일 구성을 함께 수집한다. 기존 debug 실행 그래프도 별도 파일로 유지하여 비교할 수 있다. 선언 전용 `(n)` 항목은 실제 선택 버전으로 세지 않고, 해석 실패는 감사의 미확인 항목으로 남긴다. + +## 현재 적용한 최소 버전 + +`gradle/libs.versions.toml`의 `security-*` 별칭은 기존 전이 의존성에 대한 최소 제약이다. 기존 Bouncy Castle 강제 정렬은 유지하며 값은 같은 카탈로그에서 읽는다. 나머지 제약은 상위 버전 선택을 막지 않고 앱에 도구 라이브러리를 추가하지 않는다. Netty는 BOM으로 같은 4.1 패치 계열을 맞춘다. + +| 좌표 | 최소 버전 | 적용 경로·근거 | +| --- | --- | --- | +| `io.netty:netty-bom` | `4.1.137.Final` | App Distribution·UTP. [공식 패치 릴리스](https://netty.io/news/2026/08/06/4-1-137-Final.html) | +| `org.jdom:jdom2` | `2.0.6.1` | AGP Jetifier. [릴리스 안내](https://www.jdom.org/news/) | +| `org.bitbucket.b_c:jose4j` | `0.9.6` | AGP bundletool. [공식 수정](https://bitbucket.org/b_c/jose4j/commits/19a90a64c47bb07c4aa5462f1316d5c293d81fcf) | +| `org.apache.commons:commons-lang3` | `3.18.0` | AGP·UTP. [릴리스 기록](https://commons.apache.org/proper/commons-lang/changes.html) | +| `org.apache.httpcomponents:httpclient` | `4.5.14` | UTP의 구버전 요청을 기존 빌드 도구 버전과 정렬. [공식 배포 기록](https://archive.apache.org/dist/httpcomponents/httpclient/RELEASE_NOTES-4.5.x.txt) | +| `com.google.guava:guava` | `32.1.3-android` | 앱 컴파일 의존성을 기존 실행 버전과 정렬. [릴리스 기록](https://github.com/google/guava/releases/tag/v32.1.3) | +| `ch.qos.logback:logback-classic`, `ch.qos.logback:logback-core` | `1.6.3` | ktlint 도구에만 적용. [릴리스·호환성 안내](https://logback.qos.ch/news.html) | +| `org.bouncycastle:bcprov-jdk18on` | `1.85.2` | 기존 루트·UTP 패치를 included build에도 적용하고 provider 패치를 반영. [공식 릴리스](https://www.bouncycastle.org/download/bouncy-castle-java/) | +| `org.bouncycastle:bcpkix-jdk18on`, `org.bouncycastle:bcutil-jdk18on` | `1.85` | provider 전용 1.85.2 패치에는 새 pkix/util 배포가 없으므로 기존 배포 버전 유지. [공식 릴리스](https://www.bouncycastle.org/resources/new-release-bouncy-castle-java-1-85/) | + +Logback 1.3은 유지보수가 종료되어 1.6 계열로 옮겼다. ktlint가 호출하는 Logger/Level API와 실제 ktlint 실행을 확인한다. 이 도구는 JDK 21에서 실행하며 앱의 JVM 11 설정을 바꾸지 않는다. [Logback 요구 사항](https://logback.qos.ch/dependencies.html) + +## 재검증 + +JDK 21에서 다음을 실행한다. `:app:dependencies`에서 UTP 및 ktlint의 선택 버전도 확인한다. 버전 변경 후 빌드·lint·단위 테스트와 UTP 연결 테스트를 함께 실행해야 한다. + +```sh +./gradlew buildEnvironment :app:buildEnvironment :app:dependencies --max-workers=2 +./gradlew -p build-logic :convention:dependencies --configuration compileClasspath +./gradlew assembleDebug testDebugUnitTest lintDebug ktlintCheck --max-workers=2 +ANDROID_SERIAL=<전용-에뮬레이터> ./gradlew :app:connectedDebugAndroidTest \ + -Pandroid.testInstrumentationRunnerArguments.class=com.example.slowclock.ExampleInstrumentedTest,com.example.slowclock.AlarmCommandIdentityTest \ + --max-workers=2 +node --test .github/scripts/*.test.mjs +``` + +연결 테스트는 폐기 가능한 에뮬레이터에서 수행한다. 이 검증은 실제 App Distribution 업로드나 운영 서비스 호출을 포함하지 않는다. 배포 시 서비스 인증·권한 검증은 [배포 절차](../release/distribution.md)를 따른다. + +## 남아 있는 경계 + +2026-09-06 기준 `org.jetbrains.kotlin:kotlin-gradle-plugin:2.4.10`의 GHSA-r937-wjx7-w2jp는 경보를 유지한다. [공식 수정](https://github.com/JetBrains/kotlin/commit/bf51df665b458fda7c3eaf436c4d88dc119d7ec6)은 KAPT 증분 캐시 역직렬화 경로이며 현재 프로젝트는 KSP를 사용하고 KAPT 플러그인·작업을 사용하지 않는다. 패치가 포함된 2.4.20은 아직 시험판이므로, 안정 버전 공개 후 Kotlin·Compose compiler를 함께 갱신하고 전체 호환성 검증을 다시 수행한다. 이 판단을 전체 빌드 도구의 안전 보장이나 경보 해제로 확대하지 않는다. [Kotlin 공식 릴리스](https://github.com/JetBrains/kotlin/releases) + +npm의 Functions 실행 의존성과 Firestore 테스트 도구는 각각의 lockfile과 테스트로 별도 검증한다. GitHub 경보 수는 기본 브랜치의 의존성 snapshot이 반영된 후 다시 확인한다. diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 947df2cd..eda14ad5 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -34,7 +34,31 @@ kotlinxSerialization = "1.11.0" mockk = "1.14.11" kotlinxCoroutinesTest = "1.11.0" +# 기존 도구의 전이 의존성에 적용하는 최소 패치 버전. 상위 버전 선택은 막지 않는다. +securityJdom = "2.0.6.1" +securityJose = "0.9.6" +securityCommonsLang = "3.18.0" +securityHttpclient = "4.5.14" +securityGuava = "32.1.3-android" +securityNetty = "4.1.137.Final" +securityLogback = "1.6.3" +securityBouncyCastle = "1.85" +# 1.85.2 는 provider 만 배포된 패치다. pkix/util 최신 배포는 1.85. +securityBouncyCastleProvider = "1.85.2" + [libraries] +security-jdom = { module = "org.jdom:jdom2", version.ref = "securityJdom" } +security-jose = { module = "org.bitbucket.b_c:jose4j", version.ref = "securityJose" } +security-commons-lang = { module = "org.apache.commons:commons-lang3", version.ref = "securityCommonsLang" } +security-httpclient = { module = "org.apache.httpcomponents:httpclient", version.ref = "securityHttpclient" } +security-guava = { module = "com.google.guava:guava", version.ref = "securityGuava" } +security-netty-bom = { module = "io.netty:netty-bom", version.ref = "securityNetty" } +security-logback-classic = { module = "ch.qos.logback:logback-classic", version.ref = "securityLogback" } +security-logback-core = { module = "ch.qos.logback:logback-core", version.ref = "securityLogback" } +security-bouncycastle-provider = { module = "org.bouncycastle:bcprov-jdk18on", version.ref = "securityBouncyCastleProvider" } +security-bouncycastle-pkix = { module = "org.bouncycastle:bcpkix-jdk18on", version.ref = "securityBouncyCastle" } +security-bouncycastle-util = { module = "org.bouncycastle:bcutil-jdk18on", version.ref = "securityBouncyCastle" } + androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" } junit = { group = "junit", name = "junit", version.ref = "junit" } mockk = { group = "io.mockk", name = "mockk", version.ref = "mockk" } From eed3bed4401f024f1d5f777536a93c61e9ae82e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=BC=ED=98=81?= Date: Sun, 13 Sep 2026 16:35:02 +0900 Subject: [PATCH 2/4] =?UTF-8?q?fix:=20Kotlin=20=EC=95=88=EC=A0=95=20?= =?UTF-8?q?=ED=8C=A8=EC=B9=98=EB=A1=9C=20=EB=B9=8C=EB=93=9C=20=EC=BA=90?= =?UTF-8?q?=EC=8B=9C=20=EC=B7=A8=EC=95=BD=EC=A0=90=EC=9D=84=20=ED=95=B4?= =?UTF-8?q?=EC=86=8C=ED=95=9C=EB=8B=A4=20(#219)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sources: https://github.com/JetBrains/kotlin/releases/tag/v2.4.20 https://kotlinlang.org/docs/gradle-configure-project.html --- docs/testing/dependency-security.md | 2 +- gradle/libs.versions.toml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/testing/dependency-security.md b/docs/testing/dependency-security.md index 9117e2b5..7c2f1be5 100644 --- a/docs/testing/dependency-security.md +++ b/docs/testing/dependency-security.md @@ -38,6 +38,6 @@ node --test .github/scripts/*.test.mjs ## 남아 있는 경계 -2026-09-06 기준 `org.jetbrains.kotlin:kotlin-gradle-plugin:2.4.10`의 GHSA-r937-wjx7-w2jp는 경보를 유지한다. [공식 수정](https://github.com/JetBrains/kotlin/commit/bf51df665b458fda7c3eaf436c4d88dc119d7ec6)은 KAPT 증분 캐시 역직렬화 경로이며 현재 프로젝트는 KSP를 사용하고 KAPT 플러그인·작업을 사용하지 않는다. 패치가 포함된 2.4.20은 아직 시험판이므로, 안정 버전 공개 후 Kotlin·Compose compiler를 함께 갱신하고 전체 호환성 검증을 다시 수행한다. 이 판단을 전체 빌드 도구의 안전 보장이나 경보 해제로 확대하지 않는다. [Kotlin 공식 릴리스](https://github.com/JetBrains/kotlin/releases) +2026-09-13에 안정판 `org.jetbrains.kotlin:kotlin-gradle-plugin:2.4.20`과 같은 버전의 Compose compiler·serialization 플러그인을 함께 적용했다. GHSA-r937-wjx7-w2jp의 KAPT 캐시 수정이 포함된 안정판으로 갱신하며, 기존 KSP 사용은 유지한다. [공식 릴리스](https://github.com/JetBrains/kotlin/releases/tag/v2.4.20), [Gradle·AGP 호환성](https://kotlinlang.org/docs/gradle-configure-project.html). npm의 Functions 실행 의존성과 Firestore 테스트 도구는 각각의 lockfile과 테스트로 별도 검증한다. GitHub 경보 수는 기본 브랜치의 의존성 snapshot이 반영된 후 다시 확인한다. diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index eda14ad5..8ec60483 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,8 +1,8 @@ [versions] # AGP 9.1.1 은 Gradle 9.3.1 이상, JDK 17 이상. Kotlin 은 AGP 내장(built-in Kotlin)이라 kotlin-android 플러그인을 쓰지 않는다. -# KGP 2.4.10 의 완전 지원 범위는 Gradle 7.6.3~9.5.0, AGP 8.5.2~9.1.0 (kotlinlang.org/docs/gradle-configure-project.html) +# KGP 2.4.20 의 완전 지원 범위는 Gradle 7.6.3~9.7.0, AGP 8.5.2~9.3.1 (kotlinlang.org/docs/gradle-configure-project.html) agp = "9.1.1" -kotlin = "2.4.10" +kotlin = "2.4.20" coreKtx = "1.19.0" junit = "4.13.2" junitVersion = "1.3.0" From e4d17a9f7c51af53c52b0aea11996e8f4b72e7ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=BC=ED=98=81?= Date: Sun, 13 Sep 2026 16:39:47 +0900 Subject: [PATCH 3/4] =?UTF-8?q?fix:=20Kotlin=20=ED=8C=A8=EC=B9=98=ED=8C=90?= =?UTF-8?q?=EC=9D=84=20=EC=A7=80=EC=9B=90=ED=95=98=EB=8A=94=20CodeQL?= =?UTF-8?q?=EB=A1=9C=20=EA=B0=B1=EC=8B=A0=ED=95=9C=EB=8B=A4=20(#219)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Source: https://github.com/github/codeql-action/releases/tag/v4.38.0 https://codeql.github.com/docs/codeql-overview/supported-languages-and-frameworks/ --- .github/workflows/codeql.yml | 12 ++++++------ docs/testing/dependency-security.md | 2 ++ 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 5daa3f4c..f7cc6ce0 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -137,14 +137,14 @@ jobs: persist-credentials: false - name: Initialize CodeQL - uses: github/codeql-action/init@cdf488f595d80d6e07e03d4674febd5ab45fa938 # v4.37.9 + uses: github/codeql-action/init@b96794f015dfd88f77b49b1c93e0fa7110f94c63 # v4.38.0 with: languages: actions build-mode: none - name: Analyze and upload CodeQL results id: analyze - uses: github/codeql-action/analyze@cdf488f595d80d6e07e03d4674febd5ab45fa938 # v4.37.9 + uses: github/codeql-action/analyze@b96794f015dfd88f77b49b1c93e0fa7110f94c63 # v4.38.0 with: category: /language:actions @@ -174,14 +174,14 @@ jobs: persist-credentials: false - name: Initialize CodeQL - uses: github/codeql-action/init@cdf488f595d80d6e07e03d4674febd5ab45fa938 # v4.37.9 + uses: github/codeql-action/init@b96794f015dfd88f77b49b1c93e0fa7110f94c63 # v4.38.0 with: languages: javascript-typescript build-mode: none - name: Analyze and upload CodeQL results id: analyze - uses: github/codeql-action/analyze@cdf488f595d80d6e07e03d4674febd5ab45fa938 # v4.37.9 + uses: github/codeql-action/analyze@b96794f015dfd88f77b49b1c93e0fa7110f94c63 # v4.38.0 with: category: /language:javascript-typescript @@ -231,7 +231,7 @@ jobs: uses: ./.github/actions/setup-ci-config - name: Initialize CodeQL - uses: github/codeql-action/init@cdf488f595d80d6e07e03d4674febd5ab45fa938 # v4.37.9 + uses: github/codeql-action/init@b96794f015dfd88f77b49b1c93e0fa7110f94c63 # v4.38.0 with: languages: java-kotlin build-mode: manual @@ -249,7 +249,7 @@ jobs: - name: Analyze and upload CodeQL results id: analyze - uses: github/codeql-action/analyze@cdf488f595d80d6e07e03d4674febd5ab45fa938 # v4.37.9 + uses: github/codeql-action/analyze@b96794f015dfd88f77b49b1c93e0fa7110f94c63 # v4.38.0 with: category: /language:java-kotlin diff --git a/docs/testing/dependency-security.md b/docs/testing/dependency-security.md index 7c2f1be5..10e831cd 100644 --- a/docs/testing/dependency-security.md +++ b/docs/testing/dependency-security.md @@ -41,3 +41,5 @@ node --test .github/scripts/*.test.mjs 2026-09-13에 안정판 `org.jetbrains.kotlin:kotlin-gradle-plugin:2.4.20`과 같은 버전의 Compose compiler·serialization 플러그인을 함께 적용했다. GHSA-r937-wjx7-w2jp의 KAPT 캐시 수정이 포함된 안정판으로 갱신하며, 기존 KSP 사용은 유지한다. [공식 릴리스](https://github.com/JetBrains/kotlin/releases/tag/v2.4.20), [Gradle·AGP 호환성](https://kotlinlang.org/docs/gradle-configure-project.html). npm의 Functions 실행 의존성과 Firestore 테스트 도구는 각각의 lockfile과 테스트로 별도 검증한다. GitHub 경보 수는 기본 브랜치의 의존성 snapshot이 반영된 후 다시 확인한다. + +Kotlin 2.4.20 분석을 위해 CodeQL Action도 v4.38.0 (CLI 2.27.0)으로 갱신했다. 이전 CLI 2.26.4는 해당 컴파일러를 거부한다. [Action 릴리스](https://github.com/github/codeql-action/releases/tag/v4.38.0), [지원 Kotlin 범위](https://codeql.github.com/docs/codeql-overview/supported-languages-and-frameworks/). From 52f565cd7c9a8e691b3a46ec233f14bb6aab66b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=BC=ED=98=81?= Date: Sun, 13 Sep 2026 16:47:29 +0900 Subject: [PATCH 4/4] =?UTF-8?q?fix:=20CodeQL=20=EB=AF=B8=EC=A7=80=EC=9B=90?= =?UTF-8?q?=20Kotlin=20=ED=8C=A8=EC=B9=98=EB=A5=BC=20=ED=9B=84=EC=86=8D?= =?UTF-8?q?=EC=9C=BC=EB=A1=9C=20=EB=B6=84=EB=A6=AC=ED=95=9C=EB=8B=A4=20(#2?= =?UTF-8?q?29)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Evidence: https://github.com/1hyok/SlowClock/actions/runs/34745788351 --- docs/testing/dependency-security.md | 11 ++++++++--- gradle/libs.versions.toml | 4 ++-- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/docs/testing/dependency-security.md b/docs/testing/dependency-security.md index 10e831cd..14847187 100644 --- a/docs/testing/dependency-security.md +++ b/docs/testing/dependency-security.md @@ -38,8 +38,13 @@ node --test .github/scripts/*.test.mjs ## 남아 있는 경계 -2026-09-13에 안정판 `org.jetbrains.kotlin:kotlin-gradle-plugin:2.4.20`과 같은 버전의 Compose compiler·serialization 플러그인을 함께 적용했다. GHSA-r937-wjx7-w2jp의 KAPT 캐시 수정이 포함된 안정판으로 갱신하며, 기존 KSP 사용은 유지한다. [공식 릴리스](https://github.com/JetBrains/kotlin/releases/tag/v2.4.20), [Gradle·AGP 호환성](https://kotlinlang.org/docs/gradle-configure-project.html). +2026-09-13 기준 `org.jetbrains.kotlin:kotlin-gradle-plugin:2.4.10`의 GHSA-r937-wjx7-w2jp는 유지한다. 수정 안정판 2.4.20은 배포되었고 로컬 빌드·단위 테스트 322개·lint·스크린샷 검증은 통과했으나, CodeQL CLI 2.26.4와 최신 2.27.0 모두 `Kotlin version 2.4.20 is too recent`로 실제 소스 추출에 실패했다. 공식 지원표와 실행 결과가 달라, 보안 분석을 유지하기 위해 Kotlin·Compose compiler·serialization을 기존 2.4.10에 둔다. CodeQL Action은 v4.38.0으로 갱신했다. 지원되는 추출기 배포 후 세 플러그인을 함께 갱신하고 실제 Kotlin 분석까지 검증한다. -npm의 Functions 실행 의존성과 Firestore 테스트 도구는 각각의 lockfile과 테스트로 별도 검증한다. GitHub 경보 수는 기본 브랜치의 의존성 snapshot이 반영된 후 다시 확인한다. +- [안정판 릴리스](https://github.com/JetBrains/kotlin/releases/tag/v2.4.20) +- [실패한 최신 CodeQL 실행](https://github.com/1hyok/SlowClock/actions/runs/34745788351) +- [CodeQL Action 릴리스](https://github.com/github/codeql-action/releases/tag/v4.38.0) +- [공식 지원표](https://codeql.github.com/docs/codeql-overview/supported-languages-and-frameworks/) -Kotlin 2.4.20 분석을 위해 CodeQL Action도 v4.38.0 (CLI 2.27.0)으로 갱신했다. 이전 CLI 2.26.4는 해당 컴파일러를 거부한다. [Action 릴리스](https://github.com/github/codeql-action/releases/tag/v4.38.0), [지원 Kotlin 범위](https://codeql.github.com/docs/codeql-overview/supported-languages-and-frameworks/). +해당 취약점은 KAPT 캐시 역직렬화 경로이며 현재 프로젝트는 KSP를 사용한다. 이 사실을 경고 해제나 전체 빌드 도구의 안전 보장으로 확대하지 않는다. [공식 수정](https://github.com/JetBrains/kotlin/commit/bf51df665b458fda7c3eaf436c4d88dc119d7ec6). + +npm의 Functions 실행 의존성과 Firestore 테스트 도구는 #225에서 별도 검증한다. GitHub 경고 감소는 기본 브랜치 snapshot 반영 후 확인한다. diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 8ec60483..eda14ad5 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,8 +1,8 @@ [versions] # AGP 9.1.1 은 Gradle 9.3.1 이상, JDK 17 이상. Kotlin 은 AGP 내장(built-in Kotlin)이라 kotlin-android 플러그인을 쓰지 않는다. -# KGP 2.4.20 의 완전 지원 범위는 Gradle 7.6.3~9.7.0, AGP 8.5.2~9.3.1 (kotlinlang.org/docs/gradle-configure-project.html) +# KGP 2.4.10 의 완전 지원 범위는 Gradle 7.6.3~9.5.0, AGP 8.5.2~9.1.0 (kotlinlang.org/docs/gradle-configure-project.html) agp = "9.1.1" -kotlin = "2.4.20" +kotlin = "2.4.10" coreKtx = "1.19.0" junit = "4.13.2" junitVersion = "1.3.0"