Skip to content

[feature](fe) Prepare encrypted Iceberg HMS metadata reads - #70192

Merged
hello-stephen merged 4 commits into
apache:masterfrom
Gabriel39:dev/iceberg-encrypted-metadata
Nov 5, 2026
Merged

hello-stephen merged 4 commits into
apache:masterfrom
Gabriel39:dev/iceberg-encrypted-metadata

Conversation

@Gabriel39

@Gabriel39 Gabriel39 commented Nov 4, 2026 •

Copy link
Copy Markdown
Contributor

What problem does this PR solve?

Related PR: #70159

The authenticated Iceberg FileIO wrapper inherits typed defaults that reject encrypted data, delete, manifest and manifest-list descriptors before the SDK encryption delegate can handle them. Forward all four descriptors inside the authentication scope, preserving their key metadata and manifest-list key IDs.

This also provides the reproducible encrypted HMS metadata fixture needed for the read roadmap:

  • Disposable Moto KMS, a separate HMS and a dedicated MinIO bucket in the standard Iceberg stack. Reference Iceberg 1.12.0 artifacts are isolated, checksum pinned and readable by the non-root fixture user on both fresh downloads and cache hits.
  • Real v3 encrypted Parquet, manifests and manifest lists, with two snapshots and distinct file key metadata. Both the SDK generic reader and Spark SQL verify historical rows [1, 2] and [1, 2, 3, 4].
  • Actual metadata-planning failures for missing KMS, injected AWS invalid-credential/access-denied responses, and authenticated-decryption failure with different KMS-wrapped key material. The injected responses test propagation; they do not claim live AWS IAM validation.
  • SQL regression verifies plaintext results and 48 encrypted admission rejections across SELECT, COUNT, DESC and system tables, caching on/off, count pushdown on/off and repeated reads. Required fixtures fail the enabled suite if unavailable. There is no additional test-mode switch.

The existing plugin already packages AWS KMS dependencies; this PR verifies that closure rather than adding a second dependency. Encrypted SQL execution remains blocked by the existing admission guard. Native encrypted file execution is subsequent work.

Validation

  • Reproduced the original reference-jar permission failure in the Spark 4.0.0 container. After the fix, the actual fixture compiles as the default non-root Spark user with freshly downloaded pinned jars, repaired mode-0600 cached jars, and mode-0644 cached jars owned by another user. Both cache checks used an unavailable download source; the already-readable shared cache retained its permissions and ownership without metadata changes. Shell syntax and diff checks passed.
  • Before the fix, all three encrypted descriptor tests failed at the inherited FileIO defaults. After the fix, the focused 16-test suite passed.
  • Full connector reactor package: 1,913 passed, 14 existing skips, zero failures/errors.
  • Full FE build and FE Checkstyle passed.
  • test_iceberg_encrypted_hms_metadata: generated results using the standard runner, then normal comparisons passed twice, including the final fixture source. Each run executed 48 expected encrypted rejections and verified plaintext rows/counts.
  • Real encrypted fixture verification passed with the SDK, Spark SQL and all four KMS/key failure checks.
  • Reproduced the external-CI endpoint failure: its unanchored hms_port substitution also rewrites the encrypted-fixture port, causing the suite to query the wrong metastore and report a missing database. Renamed the regression key to iceberg_encryption_metastore_port in both configuration entry points, the suite and the fixture documentation; the Docker mapping is unchanged. Verified the exact substitution with both legacy port values on both configurations, then passed the full enabled suite after applying it: 1 suite, 0 failures, 0 skips, including all 48 expected rejections and SDK/Spark/KMS/plaintext checks. This config-only rerun reused existing local FE/BE binaries.

Release note

Preserve SDK encryption metadata through authenticated Iceberg FileIO. Encrypted SQL execution remains guarded.

Check List (For Author)

  • Test
    • Regression test
    • Unit Test
    • Manual test (full FE build and isolated external stack)
  • Behavior changed:
    • Yes. Typed FileIO forwarding preserves SDK encryption descriptors.
  • Does this need documentation?
    • Yes. Connector contract and fixture instructions are included.

Check List (For Reviewer who merge this PR)

  • Confirm the release note
  • Confirm test cases
  • Confirm document
  • Add branch pick label

### What problem does this PR solve?

Related PR: apache#70159

Problem Summary: The authentication FileIO wrapper inherits typed defaults that reject encrypted descriptors before the Iceberg SDK delegate can decrypt them. Forward data, delete, manifest and manifest-list descriptors inside the authentication scope. Add reproducible v3 encrypted HMS samples backed by disposable KMS and MinIO services, verified independently with Iceberg SDK and Spark SQL across two snapshots.

### Release note

Preserve Iceberg encryption metadata through authenticated FileIO. Encrypted SQL execution remains protected by the existing admission guard.

### Check List (For Author)

- Test: Connector reactor package: 1,913 passed, 14 existing skips; full FE build and Checkstyle passed; encrypted HMS SQL regression passed with 48 rejection assertions and plaintext row/count comparisons.
- Behavior changed: Yes, typed FileIO descriptors preserve SDK encryption metadata.
- Does this need documentation: Yes, connector contract and fixture instructions updated in this commit.
@hello-stephen

Copy link
Copy Markdown
Contributor

Thank you for your contribution to Apache Doris.
Don't know what should be done next? See How to process your PR.

Please clearly describe your PR:

  1. What problem was fixed (it's best to include specific error reporting information). How it was fixed.
  2. Which behaviors were modified. What was the previous behavior, what is it now, why was it modified, and what possible impacts might there be.
  3. What features were added. Why was this function added?
  4. Which code was refactored and why was this part of the code refactored?
  5. Which functions were optimized and what is the difference before and after the optimization?

@Gabriel39

Copy link
Copy Markdown
Contributor Author

run buildall

@Gabriel39

Copy link
Copy Markdown
Contributor Author

/review

@hello-stephen

Copy link
Copy Markdown
Contributor
TPC-H: Total hot run time: 28859 ms
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/tpch-tools
Tpch sf100 test result on commit 5436f1ba7fc24800b319ca00661caeb8e2895c07, data reload: false

------ Round 1 ----------------------------------
============================================
q1	17591	5166	5090	5090
q2	2143	309	254	254
q3	10220	1389	836	836
q4	4679	464	335	335
q5	7466	801	540	540
q6	183	187	155	155
q7	749	808	603	603
q8	9257	1360	1097	1097
q9	5469	4178	4160	4160
q10	6809	1297	1020	1020
q11	442	251	232	232
q12	640	401	283	283
q13	18088	3702	3032	3032
q14	272	267	249	249
q15	q16	729	729	653	653
q17	1199	747	578	578
q18	6962	6164	6116	6116
q19	1099	963	614	614
q20	381	335	228	228
q21	5328	2506	2526	2506
q22	386	324	278	278
Total cold run time: 100092 ms
Total hot run time: 28859 ms

----- Round 2, with runtime_filter_mode=off -----
============================================
q1	6028	5964	6182	5964
q2	767	640	677	640
q3	5636	5736	5412	5412
q4	2023	2171	1627	1627
q5	5679	5933	5588	5588
q6	240	186	142	142
q7	2209	1980	1798	1798
q8	2994	2735	2719	2719
q9	8016	7508	7443	7443
q10	3637	3567	3184	3184
q11	603	417	390	390
q12	673	686	510	510
q13	3354	3653	3016	3016
q14	285	289	264	264
q15	q16	672	698	642	642
q17	7681	7050	6944	6944
q18	12966	12092	12831	12092
q19	935	838	835	835
q20	2128	2235	1909	1909
q21	5722	4738	4924	4738
q22	487	469	413	413
Total cold run time: 72735 ms
Total hot run time: 66270 ms

@hello-stephen

Copy link
Copy Markdown
Contributor
TPC-DS: Total hot run time: 151373 ms
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/tpcds-tools
TPC-DS sf100 test result on commit 5436f1ba7fc24800b319ca00661caeb8e2895c07, data reload: false

query5	4299	556	443	443
query6	433	204	191	191
query7	4805	442	247	247
query8	318	172	157	157
query9	8800	3179	3187	3179
query10	471	299	255	255
query11	6011	3861	3575	3575
query12	142	93	89	89
query13	1257	479	331	331
query14	6059	3866	3621	3621
query14_1	3414	3382	3457	3382
query15	208	196	179	179
query16	934	439	409	409
query17	853	648	538	538
query18	2413	422	317	317
query19	203	161	141	141
query20	87	86	84	84
query21	214	136	109	109
query22	13010	13041	12789	12789
query23	13370	12688	12429	12429
query23_1	12574	12649	12628	12628
query24	7387	822	480	480
query24_1	491	478	475	475
query25	542	420	362	362
query26	1302	257	144	144
query27	2769	440	274	274
query28	4660	2013	2029	2013
query29	1579	613	454	454
query30	304	230	189	189
query31	996	938	820	820
query32	146	90	92	90
query33	534	292	242	242
query34	964	849	496	496
query35	728	752	641	641
query36	827	821	699	699
query37	131	102	90	90
query38	1790	1738	1650	1650
query39	791	805	745	745
query39_1	732	732	743	732
query40	220	115	105	105
query41	72	68	69	68
query42	91	84	83	83
query43	339	359	308	308
query44	1309	693	703	693
query45	178	184	164	164
query46	832	978	580	580
query47	2999	2857	2799	2799
query48	301	310	221	221
query49	625	417	294	294
query50	671	270	214	214
query51	10466	10431	10499	10431
query52	79	80	65	65
query53	187	208	158	158
query54	224	190	171	171
query55	70	63	62	62
query56	235	222	206	206
query57	1660	1600	1594	1594
query58	290	263	251	251
query59	2163	2208	2016	2016
query60	279	241	227	227
query61	147	138	146	138
query62	382	334	289	289
query63	187	159	156	156
query64	2725	996	736	736
query65	3340	3283	3265	3265
query66	1803	414	293	293
query67	20212	20242	20184	20184
query68	3248	1002	628	628
query69	397	296	249	249
query70	831	777	739	739
query71	304	221	216	216
query72	2834	2616	2292	2292
query73	535	533	293	293
query74	4642	4501	4350	4350
query75	2342	2276	1908	1908
query76	2403	1021	584	584
query77	338	368	269	269
query78	9752	9689	9236	9236
query79	964	902	530	530
query80	786	414	324	324
query81	573	318	274	274
query82	577	141	110	110
query83	310	196	182	182
query84	310	123	99	99
query85	881	423	373	373
query86	348	232	228	228
query87	1966	1976	1797	1797
query88	3749	2774	2753	2753
query89	323	278	239	239
query90	1785	173	166	166
query91	168	153	130	130
query92	104	90	87	87
query93	982	982	577	577
query94	505	303	279	279
query95	578	327	301	301
query96	682	478	243	243
query97	2449	2446	2322	2322
query98	163	155	146	146
query99	771	765	648	648
Total cold run time: 235036 ms
Total hot run time: 151373 ms

@hello-stephen

Copy link
Copy Markdown
Contributor
ClickBench: Total hot run time: 24.33 s
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/clickbench-tools
ClickBench test result on commit 5436f1ba7fc24800b319ca00661caeb8e2895c07, data reload: false

query1	0.01	0.01	0.01
query2	0.09	0.05	0.05
query3	0.26	0.09	0.08
query4	1.61	0.10	0.10
query5	0.24	0.24	0.24
query6	1.17	0.68	0.67
query7	0.04	0.01	0.00
query8	0.06	0.04	0.03
query9	0.40	0.36	0.35
query10	0.55	0.60	0.58
query11	0.20	0.14	0.15
query12	0.19	0.15	0.15
query13	0.48	0.48	0.49
query14	1.04	1.04	0.99
query15	0.62	0.61	0.61
query16	0.36	0.35	0.35
query17	1.12	1.14	1.16
query18	0.21	0.18	0.20
query19	2.11	1.94	2.05
query20	0.02	0.02	0.01
query21	15.48	0.20	0.13
query22	4.77	0.05	0.06
query23	16.31	0.33	0.12
query24	2.63	0.50	0.48
query25	0.10	0.07	0.05
query26	1.27	0.22	0.15
query27	0.06	0.05	0.05
query28	4.15	0.82	0.36
query29	12.48	4.18	3.28
query30	0.29	0.13	0.10
query31	2.77	0.56	0.33
query32	3.22	0.60	0.50
query33	3.23	3.23	3.19
query34	15.46	3.99	3.34
query35	3.37	3.37	3.34
query36	0.55	0.45	0.42
query37	0.08	0.06	0.06
query38	0.05	0.03	0.03
query39	0.04	0.03	0.03
query40	0.18	0.15	0.13
query41	0.09	0.04	0.03
query42	0.04	0.03	0.03
query43	0.04	0.03	0.04
Total cold run time: 97.44 s
Total hot run time: 24.33 s

@github-actions

github-actions Bot commented Nov 4, 2026

Copy link
Copy Markdown
Contributor

Codex automated review failed and did not complete.

Error: Selected model is at capacity. Please try a different model.
Workflow run: https://github.com/apache/doris/actions/runs/41799370713

Please inspect the workflow logs and rerun the review after the underlying issue is resolved.

### What problem does this PR solve?

Related PR: apache#70192

Problem Summary: Reference jars downloaded through mktemp retained owner-only
permissions, preventing the non-root Spark fixture from compiling on a fresh
Linux setup. Set readable permissions after checksum verification and before
atomic publication, and repair valid cached artifacts on reuse.

### Release note

None

### Check List (For Author)

- Test: Reproduced the original Permission denied failure in the Spark 4.0.0 container; verified fixture compilation as its default non-root user after clean downloads and after repairing cached mode-0600 jars with an unavailable download source. Shell syntax and diff checks passed.
- Behavior changed: Yes. Verified reference jars are readable by the fixture container on fresh downloads and cache hits.
- Does this need documentation: No. This restores the documented fixture startup behavior.
@Gabriel39

Copy link
Copy Markdown
Contributor Author

run buildall

@Gabriel39

Copy link
Copy Markdown
Contributor Author

/review

### What problem does this PR solve?

Related PR: apache#70192

Problem Summary: Unconditionally changing cached jar permissions rejects valid
readable artifacts owned by another user. Inspect the target other-read bit
before repairing permissions so Spark can reuse shared caches without requiring
ownership, while restrictive caches are still repaired.

### Release note

None

### Check List (For Author)

- Test: Reproduced the cache ownership failure. Verified actual fixture compilation as the default non-root Spark user with fresh downloads, repaired mode-0600 caches, and root-owned mode-0644 caches. Cache checks used an unavailable source; shared cache metadata remained unchanged. Shell syntax and diff checks passed.
- Behavior changed: Yes. Already-readable shared caches no longer require ownership to be reused.
- Does this need documentation: No. This restores the documented fixture startup behavior.
@Gabriel39

Copy link
Copy Markdown
Contributor Author

run buildall

@Gabriel39

Copy link
Copy Markdown
Contributor Author

/review

@hello-stephen

Copy link
Copy Markdown
Contributor
TPC-H: Total hot run time: 28853 ms
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/tpch-tools
Tpch sf100 test result on commit 7e8fa587a222dbdf9bb39a70b58f37257e253ae9, data reload: false

------ Round 1 ----------------------------------
============================================
q1	17583	5233	5074	5074
q2	2135	300	250	250
q3	10283	1383	831	831
q4	4670	460	333	333
q5	7421	789	540	540
q6	177	187	155	155
q7	743	794	602	602
q8	9250	1317	1097	1097
q9	5444	4174	4183	4174
q10	6822	1297	1032	1032
q11	426	250	229	229
q12	651	409	291	291
q13	18060	3593	3020	3020
q14	275	269	248	248
q15	q16	708	707	666	666
q17	1180	741	571	571
q18	6983	6169	6121	6121
q19	1095	956	610	610
q20	393	338	225	225
q21	5218	2515	2515	2515
q22	395	340	269	269
Total cold run time: 99912 ms
Total hot run time: 28853 ms

----- Round 2, with runtime_filter_mode=off -----
============================================
q1	6049	5946	5923	5923
q2	689	598	546	546
q3	5569	5719	5243	5243
q4	2311	2211	1576	1576
q5	5716	5811	5616	5616
q6	243	185	143	143
q7	2187	1998	1775	1775
q8	2920	2621	2566	2566
q9	7497	7495	7508	7495
q10	3588	3597	3130	3130
q11	566	400	388	388
q12	659	653	523	523
q13	3285	3558	3031	3031
q14	287	283	260	260
q15	q16	660	666	606	606
q17	7699	7047	6860	6860
q18	12964	12226	12885	12226
q19	921	836	822	822
q20	2167	2166	1910	1910
q21	5686	4564	4668	4564
q22	484	435	386	386
Total cold run time: 72147 ms
Total hot run time: 65589 ms

@hello-stephen

Copy link
Copy Markdown
Contributor
TPC-DS: Total hot run time: 151523 ms
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/tpcds-tools
TPC-DS sf100 test result on commit 7e8fa587a222dbdf9bb39a70b58f37257e253ae9, data reload: false

query5	4335	587	445	445
query6	424	207	190	190
query7	4804	442	241	241
query8	316	162	151	151
query9	8777	3175	3182	3175
query10	479	310	262	262
query11	5856	3852	3563	3563
query12	148	91	88	88
query13	1260	415	329	329
query14	6093	3932	3607	3607
query14_1	3462	3366	3440	3366
query15	204	206	186	186
query16	934	397	405	397
query17	866	650	541	541
query18	2425	424	320	320
query19	207	163	146	146
query20	83	86	81	81
query21	206	136	113	113
query22	13029	13023	12788	12788
query23	13555	12790	12506	12506
query23_1	12505	12601	12544	12544
query24	7376	839	476	476
query24_1	485	488	483	483
query25	541	432	371	371
query26	1267	259	143	143
query27	2756	444	278	278
query28	4642	2032	2070	2032
query29	1575	611	458	458
query30	303	223	187	187
query31	1006	936	808	808
query32	135	89	93	89
query33	533	299	248	248
query34	975	869	507	507
query35	725	768	695	695
query36	815	810	738	738
query37	130	95	82	82
query38	1776	1749	1679	1679
query39	797	791	756	756
query39_1	742	723	737	723
query40	224	117	101	101
query41	72	69	67	67
query42	85	83	81	81
query43	346	362	310	310
query44	1302	710	700	700
query45	177	180	173	173
query46	842	978	573	573
query47	2962	2701	2799	2701
query48	297	341	220	220
query49	573	397	293	293
query50	684	274	221	221
query51	10818	10445	10550	10445
query52	78	79	68	68
query53	195	210	149	149
query54	232	188	183	183
query55	68	65	59	59
query56	219	217	225	217
query57	1642	1608	1589	1589
query58	287	281	260	260
query59	2171	2208	2036	2036
query60	288	246	222	222
query61	149	148	149	148
query62	388	338	283	283
query63	186	162	161	161
query64	2743	949	774	774
query65	3327	3259	3257	3257
query66	1777	412	325	325
query67	20227	20552	20070	20070
query68	3007	1002	611	611
query69	374	287	236	236
query70	848	781	766	766
query71	290	225	213	213
query72	2739	2599	2244	2244
query73	540	526	293	293
query74	4599	4527	4343	4343
query75	2336	2279	1932	1932
query76	2306	1014	588	588
query77	344	381	280	280
query78	9956	9779	9229	9229
query79	1024	848	531	531
query80	1248	413	333	333
query81	592	321	274	274
query82	627	126	104	104
query83	301	199	185	185
query84	313	127	101	101
query85	856	438	364	364
query86	402	236	233	233
query87	1989	1943	1820	1820
query88	3795	2790	2760	2760
query89	330	287	242	242
query90	1909	167	159	159
query91	162	152	139	139
query92	103	86	79	79
query93	1017	1016	581	581
query94	628	305	265	265
query95	559	332	373	332
query96	680	493	236	236
query97	2454	2443	2343	2343
query98	160	155	149	149
query99	773	765	646	646
Total cold run time: 236419 ms
Total hot run time: 151523 ms

@hello-stephen

Copy link
Copy Markdown
Contributor
ClickBench: Total hot run time: 24.31 s
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/clickbench-tools
ClickBench test result on commit 7e8fa587a222dbdf9bb39a70b58f37257e253ae9, data reload: false

query1	0.01	0.01	0.00
query2	0.10	0.05	0.05
query3	0.25	0.10	0.09
query4	1.61	0.11	0.10
query5	0.23	0.24	0.23
query6	1.17	0.67	0.67
query7	0.04	0.01	0.01
query8	0.05	0.04	0.04
query9	0.40	0.35	0.35
query10	0.57	0.59	0.62
query11	0.21	0.15	0.14
query12	0.18	0.15	0.15
query13	0.51	0.49	0.49
query14	1.03	1.02	1.02
query15	0.65	0.62	0.61
query16	0.35	0.35	0.36
query17	1.11	1.12	1.09
query18	0.20	0.19	0.19
query19	2.00	2.08	2.06
query20	0.02	0.01	0.01
query21	15.48	0.18	0.14
query22	4.94	0.05	0.06
query23	16.28	0.31	0.13
query24	3.17	0.64	0.35
query25	0.11	0.05	0.07
query26	1.35	0.23	0.16
query27	0.06	0.03	0.04
query28	3.24	0.78	0.37
query29	12.45	4.13	3.21
query30	0.28	0.13	0.10
query31	2.77	0.56	0.33
query32	3.22	0.60	0.50
query33	3.20	3.17	3.23
query34	15.47	4.03	3.39
query35	3.35	3.34	3.33
query36	0.57	0.45	0.42
query37	0.09	0.07	0.06
query38	0.05	0.04	0.04
query39	0.03	0.03	0.04
query40	0.16	0.15	0.14
query41	0.09	0.03	0.02
query42	0.03	0.03	0.02
query43	0.05	0.03	0.03
Total cold run time: 97.13 s
Total hot run time: 24.31 s

@github-actions

github-actions Bot commented Nov 4, 2026

Copy link
Copy Markdown
Contributor

Codex automated review failed and did not complete.

Error: Selected model is at capacity. Please try a different model.
Workflow run: https://github.com/apache/doris/actions/runs/41811512901

Please inspect the workflow logs and rerun the review after the underlying issue is resolved.

@Gabriel39

Copy link
Copy Markdown
Contributor Author

Local pipeline review — ✅ PASS

schema: doris-repo-review/v1
status: PASS
pr: apache/doris#70192
commit: 7e8fa587a222dbdf9bb39a70b58f37257e253ae9
base: 0eb5131db62cd7939788508377fc148df6ac1ef1
reviewed_at: 2026-11-04T19:05+08:00
reviewer: Gabriel39
model: gpt-6-astra
effort: xhigh
findings: {blocker: 0, major: 0, minor: 0, nit: 0}
rounds: 1
converged: true

Notes for maintainers

  • docker/thirdparties/docker-compose/iceberg/encryption/prepare-jars.sh:39 and :53: the previously reported fixture jar-readability issue is fixed for fresh downloads and private caches; readable shared caches avoid chmod.
  • fe/fe-connector/fe-connector-iceberg/src/main/java/org/apache/doris/connector/iceberg/IcebergAuthenticatedFileIO.java:100: all four typed descriptors retain SDK encryption metadata inside authentication. Encrypted SQL execution remains guarded.
  • Static review of all 17 changed files; no build or test was run during this review. Nine prior dismissals were re-confirmed.

Reviewed locally with the doris-repo-review pipeline. Repository policy may accept this receipt for the matching commit; it is not a human Apache approval.

924060929
924060929 previously approved these changes Nov 4, 2026

@924060929 924060929 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Iceberg encrypted reads require typed file descriptors to preserve key metadata and manifest-list key IDs. This PR forwards all four descriptor types through the existing authentication scope and adds an isolated HMS/KMS fixture; encrypted SQL execution remains blocked by the existing admission checks.

Independent static review of the 17 changed files and affected FE callers found no blocking P0/P1/P2 issues. The fix belongs in the shared FileIO decorator, preserves descriptor semantics, and does not bypass admission for cached reads, COUNT pushdown, or metadata tables. Resource ownership and production wire protocols are unchanged.

Approve for the reviewed FE scope at 7e8fa58. No builds or tests were run during this review. The supplied snapshot shows compilation and Checkstyle success, while P0, FE UT, and external regression remain pending. This recommendation does not establish merge readiness.

Automated FE-focused static review (gpt-6.1-sol, high). No build or tests were run.

@hello-stephen

Copy link
Copy Markdown
Contributor

FE UT Coverage Report

Increment line coverage `` 🎉
Increment coverage report
Complete coverage report

### What problem does this PR solve?

Related PR: apache#70192

Problem Summary: The external regression setup rewrites hms_port with an
unanchored substitution that also matches iceberg_encryption_hms_port. The
suite then connects to the default Hive metastore instead of its isolated
encrypted-metadata fixture and fails with a missing database. Rename the
regression key to iceberg_encryption_metastore_port in both configurations,
the suite and the fixture documentation. Preserve the Docker port mapping.

### Release note

None

### Check List (For Author)

- Test: Reproduced the original substitution failure. Verified both configuration files with legacy HMS replacements of 9083 and 9183. Ran the full enabled encrypted-HMS suite after the same substitution: 1 suite passed, 0 failures, 0 skips, including plaintext checks, 48 encrypted admission rejections, SDK/Spark snapshots and all four KMS/key failure checks. Reused existing local FE/BE binaries; no production source changes. Diff checks passed.
- Behavior changed: No. Correct the regression fixture endpoint selection.
- Does this need documentation: Yes. The fixture configuration mapping is updated.
@Gabriel39

Copy link
Copy Markdown
Contributor Author

run buildall

@Gabriel39

Copy link
Copy Markdown
Contributor Author

/review

@github-actions

github-actions Bot commented Nov 4, 2026

Copy link
Copy Markdown
Contributor

Codex automated review failed and did not complete.

Error: Selected model is at capacity. Please try a different model.
Workflow run: https://github.com/apache/doris/actions/runs/41825672197

Please inspect the workflow logs and rerun the review after the underlying issue is resolved.

@hello-stephen

Copy link
Copy Markdown
Contributor
TPC-H: Total hot run time: 28238 ms
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/tpch-tools
Tpch sf100 test result on commit 3ac88c57dc3c60c0881976b4f4d14254ded8c210, data reload: false

------ Round 1 ----------------------------------
============================================
q1	17587	5180	5032	5032
q2	2141	303	250	250
q3	10258	1367	816	816
q4	4674	472	342	342
q5	7439	815	527	527
q6	183	185	150	150
q7	750	800	605	605
q8	9260	1327	1060	1060
q9	5456	4210	4163	4163
q10	6836	1285	1041	1041
q11	418	242	224	224
q12	651	387	284	284
q13	18083	3540	2996	2996
q14	278	265	244	244
q15	q16	709	716	671	671
q17	1179	758	573	573
q18	6974	6177	6105	6105
q19	1104	956	563	563
q20	371	328	221	221
q21	4371	2123	2250	2123
q22	339	289	248	248
Total cold run time: 99061 ms
Total hot run time: 28238 ms

----- Round 2, with runtime_filter_mode=off -----
============================================
q1	5571	5548	5570	5548
q2	680	563	541	541
q3	5186	5358	4907	4907
q4	1976	2160	1516	1516
q5	5229	5126	5307	5126
q6	253	211	153	153
q7	2348	2059	1875	1875
q8	3036	2675	2668	2668
q9	8147	7916	7977	7916
q10	3761	3804	3239	3239
q11	603	442	406	406
q12	689	688	530	530
q13	3534	3800	3328	3328
q14	312	316	304	304
q15	q16	685	752	646	646
q17	8323	7159	6811	6811
q18	13011	12207	12848	12207
q19	888	752	752	752
q20	2142	2131	1928	1928
q21	5498	4526	4634	4526
q22	512	455	402	402
Total cold run time: 72384 ms
Total hot run time: 65329 ms

@hello-stephen

Copy link
Copy Markdown
Contributor
TPC-DS: Total hot run time: 150584 ms
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/tpcds-tools
TPC-DS sf100 test result on commit 3ac88c57dc3c60c0881976b4f4d14254ded8c210, data reload: false

query5	4303	574	449	449
query6	418	219	189	189
query7	4800	447	252	252
query8	327	165	148	148
query9	8793	3166	3152	3152
query10	474	312	257	257
query11	5979	3838	3558	3558
query12	159	90	85	85
query13	1251	431	317	317
query14	6147	3913	3628	3628
query14_1	3400	3402	3410	3402
query15	204	200	181	181
query16	939	386	426	386
query17	848	659	550	550
query18	2415	429	317	317
query19	198	171	136	136
query20	83	85	80	80
query21	207	129	106	106
query22	12917	13139	12780	12780
query23	13433	12719	12460	12460
query23_1	12513	12525	12520	12520
query24	7387	814	470	470
query24_1	494	481	482	481
query25	551	423	358	358
query26	1265	260	139	139
query27	2788	435	272	272
query28	4632	2032	2032	2032
query29	1578	605	456	456
query30	300	223	192	192
query31	1021	955	816	816
query32	141	92	88	88
query33	535	343	230	230
query34	933	840	507	507
query35	732	745	638	638
query36	811	782	718	718
query37	124	90	80	80
query38	1776	1724	1663	1663
query39	786	787	740	740
query39_1	723	719	734	719
query40	217	106	90	90
query41	65	61	63	61
query42	82	83	81	81
query43	342	367	309	309
query44	1309	695	695	695
query45	175	175	166	166
query46	831	965	560	560
query47	3022	2857	2721	2721
query48	291	297	217	217
query49	577	391	283	283
query50	658	270	213	213
query51	10664	10512	10486	10486
query52	75	76	71	71
query53	191	211	148	148
query54	247	204	185	185
query55	71	66	64	64
query56	232	210	224	210
query57	1655	1632	1621	1621
query58	283	257	250	250
query59	2147	2186	1939	1939
query60	290	238	221	221
query61	153	146	146	146
query62	386	334	276	276
query63	184	159	156	156
query64	2744	914	740	740
query65	3314	3245	3252	3245
query66	1777	419	297	297
query67	20194	20335	19803	19803
query68	2997	990	624	624
query69	390	285	245	245
query70	848	774	762	762
query71	292	231	202	202
query72	2706	2535	2283	2283
query73	519	522	284	284
query74	4624	4513	4329	4329
query75	2323	2292	1877	1877
query76	2325	1020	588	588
query77	324	385	254	254
query78	9676	9687	9121	9121
query79	1053	842	535	535
query80	519	398	338	338
query81	515	319	275	275
query82	563	131	103	103
query83	301	200	183	183
query84	313	119	98	98
query85	808	409	359	359
query86	317	237	232	232
query87	1985	1938	1843	1843
query88	3726	2754	2742	2742
query89	326	273	238	238
query90	1892	160	162	160
query91	156	148	127	127
query92	96	85	93	85
query93	998	992	587	587
query94	440	308	267	267
query95	580	384	328	328
query96	683	485	235	235
query97	2458	2467	2323	2323
query98	160	156	146	146
query99	767	763	653	653
Total cold run time: 233987 ms
Total hot run time: 150584 ms

@hello-stephen

Copy link
Copy Markdown
Contributor
ClickBench: Total hot run time: 24.21 s
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/clickbench-tools
ClickBench test result on commit 3ac88c57dc3c60c0881976b4f4d14254ded8c210, data reload: false

query1	0.01	0.01	0.01
query2	0.09	0.05	0.05
query3	0.26	0.09	0.08
query4	1.60	0.10	0.09
query5	0.22	0.24	0.25
query6	1.17	0.68	0.67
query7	0.04	0.00	0.00
query8	0.06	0.04	0.03
query9	0.39	0.34	0.35
query10	0.57	0.59	0.56
query11	0.20	0.14	0.13
query12	0.18	0.14	0.14
query13	0.49	0.49	0.50
query14	1.03	1.01	1.00
query15	0.62	0.60	0.63
query16	0.35	0.35	0.34
query17	1.16	1.09	1.11
query18	0.21	0.17	0.19
query19	2.07	1.93	2.01
query20	0.02	0.02	0.01
query21	15.48	0.19	0.14
query22	4.82	0.06	0.05
query23	16.28	0.31	0.12
query24	2.75	0.68	0.41
query25	0.11	0.09	0.04
query26	1.67	0.21	0.16
query27	0.05	0.04	0.06
query28	3.88	0.84	0.37
query29	12.50	4.13	3.24
query30	0.28	0.13	0.09
query31	2.77	0.55	0.32
query32	3.22	0.60	0.51
query33	3.15	3.22	3.32
query34	15.27	3.96	3.40
query35	3.33	3.33	3.34
query36	0.57	0.46	0.45
query37	0.10	0.06	0.06
query38	0.05	0.04	0.03
query39	0.04	0.03	0.03
query40	0.17	0.15	0.14
query41	0.09	0.03	0.03
query42	0.03	0.03	0.03
query43	0.04	0.03	0.04
Total cold run time: 97.39 s
Total hot run time: 24.21 s

@hello-stephen

Copy link
Copy Markdown
Contributor

FE UT Coverage Report

Increment line coverage `` 🎉
Increment coverage report
Complete coverage report

@924060929 924060929 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Iceberg encrypted reads require typed descriptors to retain key metadata and manifest-list key IDs. This PR forwards all four descriptor types through the shared authenticated FileIO decorator and adds an isolated HMS/KMS fixture. Existing admission checks still reject encrypted SQL before manifest planning and BE task generation.

Independent static review of all 17 changed files and affected FE callers found no blocking P0/P1/P2 issues. The fix is placed at the shared abstraction, preserves authentication and descriptor semantics, and leaves resource ownership and production protocols unchanged. The increment since the previously reviewed commit only renames the fixture metastore configuration key consistently across both configurations, the suite, and documentation.

APPROVE for the FE scope at 3ac88c5. No builds or tests were run during this review. The supplied head snapshot reports compilation, Checkstyle, FE UT, P0, and external regression success; FE coverage failed and automated AI review remains incomplete. This recommendation does not establish merge readiness.

Automated FE-focused static review (gpt-6.1-sol, high). No build or tests were run.

@hello-stephen
hello-stephen merged commit 315c2e0 into apache:master Nov 5, 2026
42 of 44 checks passed
Gabriel39 added a commit that referenced this pull request Nov 5, 2026
### What problem does this PR solve?

Related PRs: #70159, #70192

Prepare the file metadata and diagnostic protection required for native
Iceberg encrypted reads. Data files and each delete file need
independent binary keys and AAD. Generated Thrift strings and JSON
diagnostics must not expose those values.

- Define `TFileEncryptionInfo` directly in `PlanNodes.thrift`, alongside
its data/delete consumers. The optional carrier contains a payload
version, binary file key and exact AAD bytes; malformed payloads are
rejected. There is no separate encryption IDL file.
- Assume FE and BE are deployed together. This PR adds no encryption
heartbeat fields, receiver capability negotiation, capability
persistence or downgrade/replay handling.
- Validate assigned fragment parameters/ranges and every lazy split
response. FE and BE uniformly reject encrypted execution with
`READ_UNAVAILABLE` before readers, caches or metadata COUNT shortcuts. A
denied final split batch stops producers and remains an error on
repeated fetches.
- Keep the BE file-encryption validator inside
`file_scan_range_utils.h`, alongside its only production caller, with no
separate validator header.
- Redact generated Java/C++ strings, nested output, ThriftDebugString,
Gson and Thrift JSON diagnostics. Binary/Compact retain the real
payload. The generation transform targets only the secret carrier inside
`PlanNodes_types.cpp`, leaves other plan diagnostics unchanged, is
idempotent and fails on compiler-shape drift. FE, regression-framework
and C++ generation use the same protection.
- Keep encrypted SQL reads disabled until native decryption and
authenticated, confidential transport for both fragment dispatch and
lazy split responses are implemented. The Iceberg option cannot bypass
these requirements.

The read and wire contracts document this scope. File-key extraction and
native decryption are subsequent roadmap work.

### Validation

- Full FE build and FE Checkstyle passed with Maven build cache
disabled.
- Official focused FE tests: 55 passed (10 protocol tests and 45 FE
tests), zero failures/errors/skips. Covers independent data/delete keys,
diagnostics, malformed payloads, plain scans, direct/lazy dispatch and
terminal last-batch retries.
- SQL normal comparisons passed: the wire guard suite executed 80
expected rejections with plaintext rows/counts; the existing D1
admission suite executed 96 expected rejections with plaintext
comparisons. Covers v2/v3, actual lazy planning, COUNT pushdown,
repeated queries, malformed versions and key lengths. Existing generated
result files remain valid and unchanged.
- Compiled the actual regenerated `PlanNodes_types.cpp` with the
existing C++ contract suite: 4 tests passed. Generator self-tests: 4
passed, including idempotence, compiler drift and preservation of other
plan diagnostics. Regression-framework generation also passed with the
pinned Thrift compiler.
- Clang-format 16, clang-tidy and BE build hygiene passed on affected
files. Packaged heartbeat classes no longer contain either removed field
or the removed backend state class.
- The updated guard expectations failed against the old implementation,
then passed after simplification.
- Reproduced all three `PluginDrivenScanNodePartitionBatchTest`
failures: its fixture omitted the required `scan_range`, so lazy
dispatch validation dereferenced a missing range. Completed the fixture
with the same plaintext file-scan envelope used by production and
neighboring streaming tests, preserving split identities and all
existing assertions. The official expanded FE run then passed 383 tests
across 46 classes, with zero failures/errors/skips, including all nine
partition-batch tests, plugin scan, split
producer/consumer/assignment/compaction/concurrency, and encryption
protocol/guard coverage. FE Checkstyle passed with zero violations. This
follow-up changes only the unit-test fixture.

- Inlined the unchanged BE validator and documented build-time redaction
versus runtime wire/diagnostic serialization. Four standalone ASAN C++
contract tests passed against freshly regenerated `PlanNodes` code, and
all four Python generator tests passed. Three relevant BE test
translation units passed syntax checks using the existing ASAN compile
database. Clang-format 16, clang-tidy and header hygiene passed. Python
transform logic and Thrift field definitions are unchanged.

The SQL tests use the updated FE and an existing ASAN BE. Native
encrypted SQL interoperability is outside this protocol-preparation
stage. Full BE ASAN unit execution was not rerun in this update: the
earlier attempt stopped in the unchanged baseline
`vparquet_writer_test.cpp` because its `WriteInfo` initializer still
uses removed path members. The standalone C++ tests do not replace a
full ASAN run.

### Release note

Prepare per-file Iceberg encryption metadata and redacted diagnostics.
Encrypted SQL reads remain disabled.

### Check List (For Author)

- Test
    - [x] Regression test
    - [x] Unit Test
    - [x] Manual test (full FE build and local external stack)
- Behavior changed:
- [x] Yes. Encrypted file payloads are validated and uniformly rejected
until execution is implemented.
- Does this need documentation?
    - [x] Yes. Read and wire contracts are included.

### Check List (For Reviewer who merge this PR)

- [ ] Confirm the release note
- [ ] Confirm test cases
- [ ] Confirm document
- [ ] Add branch pick label
Gabriel39 added a commit to Gabriel39/incubator-doris that referenced this pull request Nov 5, 2026
…anning

### Background

Iceberg decrypts encrypted manifests before native scan planning. Doris already has a per-file encryption Thrift descriptor, but the Iceberg planner does not populate its key and AAD fields.

### What problem does this PR solve?

Issue Number: apache#70245
Related PR: apache#70192 (metadata planning and fixture), apache#70213 (file-key wire contract)
PR Type: Feature

Problem Summary:

Extract each data file's StandardKeyMetadata into every scan split so native readers can receive the correct file key and AAD. Preserve plaintext files and reject malformed metadata without exposing binary payloads. Also fix the encrypted metadata fixture's first reset after KMS restart: retained HMS tables previously caused purge to fail while reading manifests encrypted with the lost key.

### Details

- **Change map:** 220 production lines changed, 280 test lines, 29 documentation lines and 2 Checkstyle configuration lines; no generated files. Production changes add a bounded SDK metadata bridge, an immutable per-file carrier and split population; tests cover SDK interoperability and split ownership, plus a real fixture restart; documentation describes the stage boundary and lifecycle test.
- **Scope:** Parquet data-file key transport. Encrypted SQL admission remains disabled; encrypted deletes and native reader integration are subsequent stages. Reject independently encrypted deletes in merge-on-read and native position_deletes metadata-table planning until delete decryption is integrated.
- **Design:** Validate metadata size and encoded field lengths before the SDK codec can allocate. Parse one immutable snapshot, reuse the carrier only within a file, and copy mutable Thrift buffers for each split. Null per-file metadata remains plaintext. Errors contain static classifications without codec causes.
- **COUNT guard:** Both metadata COUNT algorithms fall back to normal per-file ranges when any live data file carries key metadata. Manifest totals do not certify per-file encryption absence, so the aggregate path now validates all live file metadata in O(files) with bounded retained heap, without reading data files. Encrypted delete files also prevent position-delete netting from bypassing the guard.
- **Usage:** No new configuration. Existing encrypted-read admission and BE dispatch guards remain in place.
- **Default behavior:** Encrypted SQL remains rejected. Plaintext ranges retain their previous wire shape.
- **Compatibility:** Reuses existing optional Thrift fields and the Iceberg SDK's StandardKeyMetadata v1 codec; no protocol or plugin SPI change.
- **Behavior change:** Native scan splits now carry per-file encryption parameters; the test fixture can reset retained tables after its KMS loses keys. Encrypted SQL admission is unchanged.
- **Fixture fix:** Drop only the two dedicated fixture HMS entries without purge, then delete and verify their fixed object prefixes. Cleanup therefore needs no old KMS key and leaves no orphan objects in those prefixes. The restart regression retains HMS/storage, restarts KMS/fixture, and requires the first reset to succeed without retrying it.

### Testing

- Locally: 286 FE tests across scan planning/ranges, SDK encrypted metadata I/O, admission and the new adapter; zero failures. Final adapter/split rerun: 5 tests, zero failures.
- Review-fix validation: both reported holes reproduced in two failing tests, then 280 focused FE tests passed with zero failures/errors. Coverage includes both COUNT algorithms with the cache enabled/disabled, position/equality delete rejection, native position_deletes and netted COUNT. Existing plaintext COUNT behavior remains covered.
- Locally: Maven reactor validation / FE Checkstyle passed, including the review fixes.
- Before the fix: the first fixture reset after restarting the disposable KMS returned HTTP 500.
- After the fix: the committed lifecycle regression passed; SDK and Spark both read historical snapshots `[1,2]` and `[1,2,3,4]`, with two file keys and encrypted manifests/manifest lists. Missing KMS, invalid credentials, denied access and wrong keys remained rejected.
- Shell syntax and diff whitespace checks passed. Full encrypted Doris SQL is intentionally unavailable at this stage.

### Release note

None. This prepares file-key transport while encrypted query execution remains disabled, and makes the external regression fixture restartable.

### Check List (For Author)

- Behavior changed: Yes (see Details: per-file transport and fixture reset)
- Does this need documentation: No user-facing feature enablement; internal contract and fixture instructions updated.
- Pre-submission status: Ready

### AI Disclosure

- Tool: Codex (GPT-6)
- Generated: Code, tests and this description.
- Human review: Pending maintainer review; agent self-review completed.
Gabriel39 added a commit that referenced this pull request Nov 5, 2026
…70246)

### Background

Iceberg decrypts encrypted manifests before native scan planning. Doris
already has a per-file encryption Thrift descriptor, but the Iceberg
planner does not populate its key and AAD fields.

### What problem does this PR solve?

Issue Number: #70245
Related PR: #70192 (metadata planning and fixture), #70213 (file-key
wire contract)
PR Type: Feature

Problem Summary:

Extract each data file's StandardKeyMetadata into every scan split so
native readers can receive the correct file key and AAD. Preserve
plaintext files and reject malformed metadata without exposing binary
payloads. Reject mixed-file metadata COUNT during bounded validation so
unsupported encryption cannot trigger eager full-table task and range
allocation before dispatch fails. Also fix the encrypted metadata
fixture's first reset after KMS restart: retained HMS tables previously
caused purge to fail while reading manifests encrypted with the lost
key.

### Details

- **Change map:** 238 production lines changed, 325 test lines, 38
documentation lines and 2 Checkstyle configuration lines; no generated
files. Production changes add a bounded SDK metadata bridge, an
immutable per-file carrier and split population; tests cover SDK
interoperability, split ownership, bounded COUNT rejection and a real
fixture restart.
- **Scope:** Parquet data-file key transport. Encrypted SQL admission
remains disabled; encrypted deletes and native reader integration are
subsequent stages. Reject independently encrypted deletes in
merge-on-read and native position_deletes metadata-table planning until
delete decryption is integrated.
- **Design:** Validate metadata size and encoded field lengths before
the SDK codec can allocate. Parse one immutable snapshot, reuse the
carrier only within a file, and copy mutable Thrift buffers for each
split. Null per-file metadata remains plaintext. Errors contain static
classifications without codec causes.
- **COUNT guard:** Both metadata COUNT algorithms validate live file
metadata in O(files) with bounded retained heap, without reading data
files. A per-file encryption marker rejects immediately with
`COUNT_READ_UNAVAILABLE`, including when the table has no encryption
declaration. Returning to ordinary scan planning would retain all tasks
and splits after COUNT scheduling had disabled streaming. Deterministic
rejection bypasses the manifest cache retry; actual cache failures
retain the SDK retry. Encrypted delete files also prevent
position-delete netting from bypassing the guard.
- **Usage:** No new configuration. Existing encrypted-read admission and
BE dispatch guards remain in place.
- **Default behavior:** Encrypted SQL remains rejected. Plaintext ranges
retain their previous wire shape.
- **Compatibility:** Reuses existing optional Thrift fields and the
Iceberg SDK's StandardKeyMetadata v1 codec; no protocol or plugin SPI
change.
- **Behavior change:** Native scan splits now carry per-file encryption
parameters; the test fixture can reset retained tables after its KMS
loses keys. Encrypted SQL admission is unchanged.
- **Fixture fix:** Drop only the two dedicated fixture HMS entries
without purge, then delete and verify their fixed object prefixes.
Cleanup therefore needs no old KMS key and leaves no orphan objects in
those prefixes. The restart regression retains HMS/storage, restarts
KMS/fixture, and requires the first reset to succeed without retrying
it.

### Testing

- Final local verification: **295 FE tests, zero
failures/errors/skips**, covering `IcebergScanPlanProviderTest`,
`IcebergScanRangeTest`, `IcebergFileEncryptionTest`,
`IcebergEncryptionReadTest` and `IcebergEncryptedMetadataIOTest`. Maven
reactor validation and FE Checkstyle passed.
- Red/green proof: the initial four-case COUNT matrix failed before the
fix. The final eight-case matrix passes across SDK/cache,
present/missing manifest row aggregates and manifest concurrency 1/8. A
batch threshold of 1 proves ordinary scanning would stream while COUNT
stays synchronous; assertions verify early rejection, no second SDK
planning pass, SDK iterable closure, no cache-failure accounting, and
stopping before the tail manifest in serial mode.
- Existing plaintext COUNT collapse, delete handling and both real
cache-failure SDK retries pass. Final verification uses
`-XX:ActiveProcessorCount=2 -XX:TieredStopAtLevel=1`, matching the FE
unit-test JVM setting. A diagnostic run without the processor cap hit
three existing cancellation-test fixture-count assertions caused by
automatic manifest merging; those test implementations were not changed.
- Previously verified, unchanged fixture lifecycle: the first reset
after a disposable KMS restart failed before the fixture fix and passes
afterward. SDK and Spark read historical snapshots `[1,2]` and
`[1,2,3,4]`; missing KMS, invalid credentials, denied access and wrong
keys remain rejected.
- Diff whitespace checks passed. Encrypted Doris SQL execution remains
unavailable at this stage; this update validates the planner guard
rather than enabling encrypted execution.

### Release note

None. This prepares file-key transport while encrypted query execution
remains disabled, and makes the external regression fixture restartable.

### Check List (For Author)

- Behavior changed: Yes (see Details: per-file transport and fixture
reset)
- Does this need documentation: No user-facing feature enablement;
internal contract and fixture instructions updated.
- Pre-submission status: Ready

### AI Disclosure

- Tool: Codex (GPT-6)
- Generated: Code, tests and this description.
- Human review: Pending maintainer review; agent self-review completed.
yiguolei pushed a commit that referenced this pull request Nov 6, 2026
### Background

Doris has per-file Iceberg encryption parameters and a native Parquet
reader, but that reader cannot consume encrypted footers or pages.
Parquet modular encryption authenticates each module with file AAD and
row-group, physical-column and data-page ordinals.

### What problem does this PR solve?

Issue Number: #70245
Related PR: #70087 (PME dependency build), #70192 (Iceberg metadata
reads), #70213 (file-key wire contract), #70246 (per-file key
extraction)
PR Type: Feature

Problem Summary:

Add the physical reader needed to read AES_GCM_V1 Parquet files with
encrypted footers and footer-key columns. Authenticate and decrypt
modules through parquet-cpp before passing bytes into the existing
native metadata and value decoders. Java/Iceberg interoperability,
bounded parsing and cache isolation require changes beyond the crypto
wrapper. Enforce the native container budget independently of unverified
serialized element types, so malformed authenticated metadata cannot
undercount its allocation cost. Encrypted SQL admission remains closed
while index, delete-file and final scan integration are completed
separately.

### Details

- **Change map:** 1300 production lines changed, 1420 test/generator
lines, 57 generated result lines, 81 documentation lines, 9 scanner
configuration lines and 4 small synthetic binary fixtures/twins/copies
(about 10 KB total). Production changes comprise module crypto/parsing,
footer ownership, native page/column plumbing and sequential scan
guards. The native column factory now takes four arguments through a
creation context and explicit read options, with separate complex-type
helpers and one scalar initialization path. Tests cover independent
Java/Iceberg interoperability, validation/authentication boundaries and
real S3 SQL scans.
- **Scope:** AES_GCM_V1 encrypted footers, encrypted page headers,
dictionary pages and Data Page V1/V2; 128/192/256-bit footer keys;
scalar and nested physical decoding. AES_GCM_CTR_V1, plaintext-footer
encryption and separate column keys are explicitly unsupported.
- **Design:** Keep physical decoding in format_v2. The crypto wrapper
uses parquet-cpp AES and module-AAD helpers, retains an immutable
SecureString file key, and creates mutable decryptors per physical
column reader. Track ciphertext disk sizes separately from decrypted
compressed sizes and count only data pages in AAD ordinals. Authenticate
metadata before accepting Parquet Java's zero-filled serialization
padding. Bound encrypted modules and decompressed pages to 64 MiB and
impose Thrift container, recursion and aggregate allocation limits
before decoding. Bypass shared decrypted metadata/page/condition caches
and index/dictionary/bloom pruning for the sequential stage. Recursive
column construction shares immutable file/row-group inputs by reference,
while keeping in_collection local to each node and mutable decryptors
local to each physical leaf. Pass cache policy directly instead of
creating a temporary RuntimeState to override it.
- **Metadata budget:** Generated Thrift readers use statically declared
C++ vector elements without validating the serialized element type.
Charge each list/set element and both sides of each map entry at the
largest reachable native element size. This is a conservative budget;
very large primitive/string lists may reach the limit sooner. No schema
mirror or generated source change is needed.
- **Scratch reclamation:** Include decrypted page capacity and active
bytes in the existing scalar scratch policy. A page that grows to 32 MiB
can relinquish its unused capacity after ordinary small batches, while
release waits for a page boundary so live payload and V2 level views
stay valid. The existing idle thresholds remain unchanged. Page activity
is tracked separately from vector size, preserving initialized bytes for
same-size reuse without an additional full-page initialization.
- **GCC unity builds:** Keep the shared secure-key implementation type
in a named namespace. The externally linked PImpl types must not contain
an anonymous-namespace type when this source is included by a unity
translation unit.
- **Usage:** Controlled physical-reader callers can supply the existing
TFileEncryptionInfo as an optional constructor parameter. No new engine
configuration, Thrift field, capability negotiation or user SQL entry is
added. Encrypted indexes and delete-file integration remain follow-up
work.
- **Default behavior:** Existing plaintext callers retain default
parameters and their existing cache/pruning paths. FE encrypted-table
admission and BE scan dispatch guards remain closed.
- **Compatibility:** Reuses the existing descriptor. PME requires the
internal headers and actual encryption implementation from the
previously enabled third-party build; older prebuilt bundles compile and
explicitly report PME_DEPENDENCY_UNAVAILABLE. No storage format or
dependency version changes.
- **Behavior change:** The native physical reader can decrypt the
supported layout when explicitly given file parameters; encrypted files
without keys and unsupported layouts fail explicitly. This PR does not
enable encrypted SQL queries.

### Testing

- Latest full local ASAN BE build through `build.sh --be -j 6` passed,
including the GLIBC_2.17 compatibility gate.
- Latest final run: 249 focused ASAN tests passed across ten
Parquet/native-decoder, page-cache and existing
file-encryption/scan-range guard suites, including all 24 encryption
tests. Used `run-be-ut.sh` with a local CMake test-source filter;
production libraries were built normally. This is not the full BE
unit-test suite.
- Decrypted-page scratch red/green coverage: the new real-reader test
fails before the repair because a 32 MiB page is absent from retained
scratch accounting. After the fix, Page V1/V2 x UNCOMPRESSED/SNAPPY all
preserve active page data and NULL values, defer release while page
views remain live, and reduce retained scratch to at most 4 MiB after
small-page transitions. SNAPPY cases assert that decompression actually
runs.
- GCC 15.1 unity compilation: a syntax check that includes the actual
production source reproduces both subobject-linkage errors before the
fix and passes after it. This is a focused compiler check, not a full
GCC release build.
- Allocation-budget red/green coverage: the new real-parser regression
fails on the old implementation and passes after the fix for
byte-labeled LIST/SET/MAP containers. It uses sub-MiB inputs and
skippable unknown fields to validate cumulative accounting without
allocating large native vectors. The MAP threshold detects accounting
for only one side of an entry. Existing Java/Arrow fixtures cover
successful normal metadata decoding.
- Factory refactor coverage: all four collection/offset-index
combinations read the selected middle-page rows after the temporary
creation context is destroyed. Explicit page-cache policy is verified
cold/warm with no RuntimeState and with both session settings, including
opposing settings. Both new tests also pass twice in one process.
Existing nested projection and INT96 timezone tests continue to pass.
- Positive physical-reader coverage: dictionary/plain encoding, Data
Page V1/V2, three AES key sizes, multiple pages and row groups,
null/empty nested shapes, levels-only reads and the ParquetReader block
interface. The checked-in Iceberg 1.12.0 Java sample is compared
field-by-field with the independent parquet-cpp reader.
- Boundary coverage: descriptor fields, unsupported ciphers/plaintext
footers/column keys, AAD policy and authentication,
module/row/column/page AAD binding, ordinal/length limits,
tampering/truncation, another key after cache warmup, independent
decryptor state and avoiding encrypted index reads. Errors do not expose
keys or AAD.
- Added `test_iceberg_encryption_native_reader`: on a local cluster with
a freshly built PR ASAN BE and an existing compatible FE, generation and
a separate normal comparison run both passed; the normal comparison also
passed against the refactored BE. Each run checks 21 expected errors and
seven positive result sets/aggregates across page-cache and
COUNT-pushdown settings. A plaintext first file allows schema discovery;
actual mixed-file SELECT/COUNT must still reject the later encrypted
file with MISSING_KEY. Repeated failures and a truncated input preserve
subsequent plaintext nested values/counts. The suite needs standard
MinIO, without KMS or a new encryption-specific test flag, and deletes
its unique bucket/objects. This SQL regression was verified earlier on
the PR and was not rerun for the metadata-budget, GCC linkage or
scratch-reclamation updates.
- Before implementation, the SQL missing-key assertion fails on the old
BE with Invalid Parquet v2 footer magic. The initial missing-key unit
contract also failed before implementation.
- Positive crypto tests use PME rebuilt with the Doris toolchain.
Original prebuilt dependencies previously passed four explicit
dependency/metadata contracts and rejected decryption.
- Gitleaks 8.30.0 reproduced the reported three fixture false positives;
the complete PR commit history, including the budget fix, has zero
findings. The exact-path/exact-value exception still detects a different
value in that file and all three original occurrences outside that path.
- Fixture generator compilation, clang-format 16, changed-line
clang-tidy, build hygiene and source whitespace checks passed. SQL
results are runner-generated; SQL binary copies byte-match their BE
originals.
- Additional diagnostic: repeating the whole selection in one process
passes the first round, then two unchanged cold-cache profile tests fail
second-round counter assertions because the global page cache is already
warm (UnknownMtimeUsesPageCacheForImmutableFile and
DictionaryPruningPublishesColdAndWarmNativePageProfile). The standard
single-round selection passes; new cases use independent cache
identities and pass repeated execution.
- Full BE CI and positive encrypted SQL end-to-end validation are not
claimed; encrypted SQL admission remains intentionally gated.

### Notes for Reviewers

Start with parquet_crypto, then encrypted footer parsing and native
page_reader. The direct format_common include fixes a pre-existing
unity-neighbor include dependency exposed by adding a source file. The
fixture README includes its generator, public synthetic parameters and
test matrix. CI scans the full PR commit range; the Gitleaks exception
requires both the exact native test path and one of the two documented
public fixture values.

### Release note

None. This prepares the native encrypted Parquet reader; encrypted SQL
admission remains disabled.

### Check List (For Author)

- Behavior changed: Yes (see Details).
- Does this need documentation: No user-facing enablement; fixture and
stage limitations documented alongside the tests.
- Pre-submission status: Ready; full CI pending.

### AI Disclosure

- Tool: Codex (GPT-6).
- Generated: Code, tests, synthetic fixture generator and this
description.
- Human review: Pending maintainer review; agent self-review completed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants