Repository navigation
Expand file tree
/
Copy pathbuild.gradle.kts
More file actions
232 lines (226 loc) · 12.5 KB
/
Copy pathbuild.gradle.kts
File metadata and controls
232 lines (226 loc) · 12.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
// AGP 9.3.2·Firebase App Distribution 5.3.0 이 buildscript classpath 로 끌어오는 전이 의존성 중
// 보안 권고 영향권인 것들의 하한(#975~#985·#2132). 루트 classpath 는 plugins 블록 처리 시점에
// 리졸브가 끝나 아래 본문 훅으로는 늦고, buildscript 블록에서는 버전 카탈로그 accessor 를 쓸 수 없다
// — libs.versions.toml 의 같은 이름 버전과 값을 맞춰 유지할 것.
buildscript {
dependencies {
constraints {
listOf("bcprov-jdk18on", "bcpkix-jdk18on", "bcutil-jdk18on").forEach { artifact ->
add("classpath", "org.bouncycastle:$artifact:1.85") {
because("GHSA-9pwp-9qqc-pr26·GHSA-qp49-qgx5-5m26 — 1.85 미만 취약 — #2132")
}
}
add("classpath", "org.apache.commons:commons-lang3:3.18.0") {
because("GHSA-j288-q9x7-2f5v — 3.18.0 미만 취약 — #981")
}
add("classpath", "org.bitbucket.b_c:jose4j:0.9.6") {
because("GHSA-3677-xxcr-wjqv — 0.9.6 미만 취약 — #982")
}
add("classpath", "org.jdom:jdom2:2.0.6.1") {
because("GHSA-2363-cqg2-863c — 2.0.6.1 미만 취약 — #985")
}
// 보안 하한이 아니라 카탈로그 정렬(#1656). AGP 9.3.2 의 analytics-library·sdklib·repository 와
// KGP 2.4.10 의 kotlin-compiler-runner 가 플러그인 클래스패스에 coroutines 1.9.0(과 그 BOM)을
// 얹는다 — 누가 강제로 내리는 게 아니라 이 클래스패스에 버전 카탈로그가 닿지 않아서다. 모듈
// 클래스패스는 이미 카탈로그대로 1.11.0 이라, 여기만 끌어올려 「선언 = 해석」을 한 의도로 맞춘다.
// require 시맨틱이라 AGP 가 나중에 더 높은 버전을 선언하면 그쪽이 이긴다.
// libs.versions.toml 의 kotlinxCoroutines 와 값을 맞춰 유지할 것.
add("classpath", "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.11.0") {
because("카탈로그 선언(1.11.0)과 AGP·KGP 전이 1.9.0 의 불일치 — #1656")
}
}
// netty 는 grpc-netty 가 끌어오는 모듈이 10개가 넘고 서로 같은 버전이어야 해 BOM 으로 정렬한다
// (GHSA-558v-64gr-wgg4 등 33건, #975~#980). 이 BOM 을 아래 본문의 allprojects 하한에 platform()
// 으로 함께 걸면 AGP 의 android-reverse-meta-data usage 가 platform 변형을 못 찾아 리졸브가 깨진다.
// 그래서 루트 classpath 는 이 BOM 이 맡고, AGP 가 만드는 UTP 설정 경유분은 아래 securityFloors 의
// 평범한 constraint 가 맡는다(#1058).
add("classpath", platform("io.netty:netty-bom:4.1.137.Final"))
}
}
// Top-level build file where you can add configuration options common to all sub-projects/modules.
plugins {
id("afternote.kover")
alias(libs.plugins.android.application) apply false
alias(libs.plugins.kotlin.compose) apply false
alias(libs.plugins.android.library) apply false
alias(libs.plugins.jetbrains.kotlin.jvm) apply false
alias(libs.plugins.hilt.android) apply false
alias(libs.plugins.ksp) apply false
alias(libs.plugins.kotlin.serialization) apply false
alias(libs.plugins.google.services) apply false
alias(libs.plugins.firebase.app.distribution) apply false
alias(libs.plugins.firebase.crashlytics) apply false
}
// 빌드·테스트 클래스패스의 보안 하한(#975~#985·#1058·#1072·#1262·#2132). 상류가 취약 버전을 물고 있고 상류
// 최신판도 아직 패치 버전 미만이라 constraint 로 올린다 — Robolectric 4.15.1(bcprov 1.80)·AGP
// 9.3.2(bcprov 1.79·commons-lang3 3.16.0·jose4j 0.9.5·jdom2 2.0.6)·Firebase App Distribution 5.3.0
// 과 AGP UTP 설정(netty — unified-test-platform-core 가 4.1.93, -host-emulator-control 이 4.1.110)
// ·AGP androidLintTool 과 UTP(httpclient 4.5.6)·ktlint CLI(logback 1.3.16)·Compose Accessibility Test
// Framework(protobuf-javalite 3.19.1)·Kakao SDK 2.23.2(okhttp 4.9.2→okio 2.8.0). androidLintTool·UTP
// 처럼 AGP 가 뒤늦게 만드는 configuration 까지 잡도록
// configureEach 로 걸고, require 시맨틱이라 상류가 하한 이상을 선언하게 되면 그쪽이 이긴다. okhttp 는
// production 런타임, protobuf-javalite 는 androidTest 런타임에만 있고 나머지는 빌드 도구 경유라
// release APK 에 없다(releaseRuntimeClasspath 실측). build-logic 은 별도 빌드라
// build-logic/build.gradle.kts 가 같은 하한을 선언한다.
data class SecurityFloor(
val module: String,
val version: String,
val because: String,
)
val securityFloors =
listOf("bcprov-jdk18on", "bcpkix-jdk18on", "bcutil-jdk18on").map { artifact ->
SecurityFloor(
module = "org.bouncycastle:$artifact",
version = libs.versions.bouncycastle.get(),
because = "GHSA-9pwp-9qqc-pr26·GHSA-qp49-qgx5-5m26 — 1.85 미만 취약 — #2132",
)
} +
listOf(
"netty-buffer",
"netty-codec",
"netty-codec-http",
"netty-codec-http2",
"netty-codec-socks",
"netty-common",
"netty-handler",
"netty-handler-proxy",
"netty-resolver",
"netty-transport",
"netty-transport-native-unix-common",
).map { artifact ->
SecurityFloor(
module = "io.netty:$artifact",
version = libs.versions.netty.get(),
because = "GHSA-558v-64gr-wgg4 등 33건 — AGP UTP 경유 4.1.110·4.1.93 잔존 — #1058",
)
} +
listOf(
SecurityFloor(
module = "org.apache.commons:commons-lang3",
version = libs.versions.commonsLang3.get(),
because = "GHSA-j288-q9x7-2f5v — 3.18.0 미만 취약 — #981",
),
SecurityFloor(
module = "org.bitbucket.b_c:jose4j",
version = libs.versions.jose4j.get(),
because = "GHSA-3677-xxcr-wjqv — 0.9.6 미만 취약 — #982",
),
SecurityFloor(
module = "org.jdom:jdom2",
version = libs.versions.jdom2.get(),
because = "GHSA-2363-cqg2-863c — 2.0.6.1 미만 취약 — #985",
),
SecurityFloor(
module = "org.apache.httpcomponents:httpclient",
version = libs.versions.httpclient.get(),
because = "GHSA-7r82-7xv7-xcpj — 4.5.13 미만 취약 — #1072",
),
SecurityFloor(
module = "com.google.protobuf:protobuf-javalite",
version = libs.versions.protobufJavalite.get(),
because =
"GHSA-4gg5-vx3j-xwc7·GHSA-735f-pc8j-v9w8 — " +
"Accessibility Test Framework 4.1.1 경유 3.19.1 잔존 — #1262",
),
SecurityFloor(
module = "com.google.guava:guava",
version = libs.versions.guavaAndroid.get(),
because = "GHSA-7g45-4rm6-3mm3·GHSA-5mg8-w23w-74h3: 접근성 테스트의 31.0.1-android 취약, #2219",
),
SecurityFloor(
module = "org.jsoup:jsoup",
version = libs.versions.jsoup.get(),
because = "GHSA-pmhh-3w7g-xqp8·GHSA-gp7f-rwcx-9369·GHSA-65r4-943x-97jj: jsoup 1.23.1 미만 취약, #2219·#2302",
),
) +
// baselineprofile 테스트 모듈의 디코더만 올린다. constraint 는 새 런타임 의존성을 추가하지 않는다.
listOf("wire-runtime", "wire-runtime-jvm").map { artifact ->
SecurityFloor(
module = "com.squareup.wire:$artifact",
version = libs.versions.wire.get(),
because = "GHSA-9rm7-3qhh-h2mc: benchmark 1.5.0-rc02 경유 6.4.0 취약, #2219",
)
} +
// logback-core 만 취약하지만 classic 은 core 와 같은 버전이라야 동작해 함께 올린다.
listOf("logback-core", "logback-classic").map { artifact ->
SecurityFloor(
module = "ch.qos.logback:$artifact",
version = libs.versions.logback.get(),
because = "GHSA-jhq6-gfmj-v8fx 등 3건 — 1.5.34 미만 취약 — #1072",
)
} +
// okio 2.8.0(GHSA-w33c-445m-f8w7)이 Kakao SDK 경유 okhttp 4.9.2 로 딸려 온다. okhttp 4.9.x 는
// okio 2.x API 를 쓰므로 okio 만 3.x 로 올리면 런타임이 깨진다. 그래서 okio 가 아니라 okhttp 를
// 카탈로그 버전으로 정렬해 okio 를 함께 끌어올린다 — :app 최종 조합이 이미 그 짝(okhttp 5.4.0 +
// okio-jvm 3.17.0)이라, 카탈로그 okhttp 를 직접 의존하지 않는 feature 모듈의 컴파일 클래스패스만
// 뒤처져 있던 것을 맞추는 셈이다. logging-interceptor 는 okhttp 와 같은 버전이라야 한다.
listOf("okhttp", "logging-interceptor").map { artifact ->
SecurityFloor(
module = "com.squareup.okhttp3:$artifact",
version = libs.versions.okhttp.get(),
because = "GHSA-w33c-445m-f8w7 — okhttp 4.9.2 가 물고 오는 okio 2.8.0 취약 — #1072",
)
}
fun Project.securityFloorConstraintSet() =
securityFloors.map { floor ->
dependencies.constraints.create("${floor.module}:${floor.version}") {
because(floor.because)
}
}
allprojects {
// Gradle 9 는 declarable 이 아닌 configuration(compileClasspath 등)에 constraint 선언을 금지한다.
// 전용 declarable configuration 에 담아 모든 resolvable configuration 이 extend 하게 한다.
val floor =
configurations.create("securityFloors") {
isCanBeResolved = false
isCanBeConsumed = false
securityFloorConstraintSet().forEach { dependencyConstraints.add(it) }
}
configurations.configureEach {
if (name != floor.name && isCanBeResolved) extendsFrom(floor)
}
}
// buildscript 컨테이너에는 configuration 을 추가할 수 없어 declarable 인 classpath 에 constraint 를
// 직접 단다. 루트 자신의 classpath 는 최상단 buildscript 블록이 담당한다(여기 시점엔 리졸브 완료라 불가).
subprojects {
buildscript.configurations.named("classpath") {
securityFloorConstraintSet().forEach { dependencyConstraints.add(it) }
}
}
// 커버리지 규약(kover 적용·리포트 필터·«ci» 변형)은 afternote.kover convention plugin 이 모듈마다
// 스스로 건다. 루트에 남는 것은 «무엇을 합칠지» 뿐이다 — 예전에는 여기서 subprojects 를
// configuration time 에 열거해 남의 프로젝트의 pluginManager·extensions 를 직접 조작했고,
// 이 저장소에서 모듈 공통 설정이 convention plugin 밖에 있는 유일한 자리이자 Gradle
// project isolation 의 첫 걸림돌이었다(#918 — #864 승인 리뷰의 유예분).
//
// 모듈이 늘면 여기 한 줄과 그 모듈 plugins 블록의 afternote.kover 가 함께 늘어야 한다. 둘이
// 어긋나면 커버리지에서 조용히 빠지므로 build-logic 의 KoverAggregationTest 가 일치를 검사한다.
dependencies {
kover(project(":app"))
kover(project(":core:common"))
kover(project(":core:data"))
kover(project(":core:datastore"))
kover(project(":core:domain"))
kover(project(":core:model"))
kover(project(":core:network"))
kover(project(":core:ui"))
kover(project(":feature:afternote:data"))
kover(project(":feature:afternote:domain"))
kover(project(":feature:afternote:presentation"))
kover(project(":feature:home:presentation"))
kover(project(":feature:mindrecord:data"))
kover(project(":feature:mindrecord:domain"))
kover(project(":feature:mindrecord:presentation"))
kover(project(":feature:onboarding:data"))
kover(project(":feature:onboarding:presentation"))
kover(project(":feature:receiver:data"))
kover(project(":feature:receiver:domain"))
kover(project(":feature:receiver:presentation"))
kover(project(":feature:setting:data"))
kover(project(":feature:setting:domain"))
kover(project(":feature:setting:presentation"))
kover(project(":feature:timeletter:data"))
kover(project(":feature:timeletter:domain"))
kover(project(":feature:timeletter:presentation"))
kover(project(":feature:timeletter:res"))
}