--- title: "Gradle Working With Files — Reproducible Archives (sec:reproducible_archives)" source_type: official-doc url: https://docs.gradle.org/current/userguide/working_with_files.html#sec:reproducible_archives archive_url: vendor: Gradle related_branches: [feature-build-release-supply-chain-contract] related_projects: [] tags: [official-doc, ci-cd, gradle, reproducible-builds, supply-chain] created: 2026-06-15 --- # Gradle Working With Files — Reproducible Archives (sec:reproducible_archives) > Layer: `raw/` — 공식 문서 원문 발췌·출처 기록. > 검증된 요약은 `/ingest` 후 `wiki/concepts/`에 `source-summary-template` 형식으로 별도 작성. 원본은 raw에 영구 보관. ## Parent / 활용 branch | Branch | 이 자료가 정당화하는 결정 | |---|---| | [[raw/branch-notes/feature-build-release-supply-chain-contract]] | Decision D10 — `preserveFileTimestamps=false` / `reproducibleFileOrder=true` 의 Gradle 공식 API 명세: 각 property 가 무엇을 하며, `tasks.withType().configureEach {}` 패턴으로 전역 적용하는 방법 | ## 출처 / Source - 원본 URL: https://docs.gradle.org/current/userguide/working_with_files.html#sec:reproducible_archives - 보조 URL (DSL reference): https://docs.gradle.org/current/dsl/org.gradle.api.tasks.bundling.AbstractArchiveTask.html - 보조 URL (Javadoc): https://docs.gradle.org/current/javadoc/org/gradle/api/tasks/bundling/AbstractArchiveTask.html - 아카이브 URL: (미등록) - 저자 / 조직: Gradle (https://gradle.org) - 발행일: (Gradle 공식 문서 — 버전 릴리즈마다 갱신) - 마지막 확인일: 2026-06-15 ## 왜 저장했는지 / Why archived `feature-build-release-supply-chain-contract` 의 D10 결정 (`preserveFileTimestamps=false`, `reproducibleFileOrder=true` 를 `AbstractArchiveTask` 에 적용) 은 `UNSUPPORTED_DECISION` 으로 라벨되어 있었다. 본 자료는 두 property 의 공식 API 명세와 전역 적용 DSL 예시를 제공하며, D10 을 `official-vendor-doc` 강도로 승격하는 근거다. ## 핵심 인용 / Key quotes (verbatim) > [§preserveFileTimestamps, DSL reference / Javadoc] "Specifies whether file timestamps should be preserved in the archive. If `false` this ensures that archive entries have the same time for builds between different machines, Java versions and operating systems." > [§reproducibleFileOrder, DSL reference / Javadoc] "Specifies whether to enforce a reproducible file order when reading files from directories. Gradle will then walk the directories on disk which are part of this archive in a reproducible order independent of file systems and operating systems. This helps Gradle reliably produce byte-for-byte reproducible archives." > [§sec:reproducible_archives, Kotlin DSL code example] > ```kotlin > tasks.withType().configureEach { > preserveFileTimestamps = false > reproducibleFileOrder = true > } > ``` > [§sec:reproducible_archives, Groovy DSL code example] > ```groovy > tasks.withType(AbstractArchiveTask) { > preserveFileTimestamps = false > reproducibleFileOrder = true > } > ``` ## Claims Extracted / 추출된 주장 > 이 자료가 **직접 말하는 것만** claim 으로 분리한다. 내 프로젝트에 적용한 결론은 여기 쓰지 않는다. | Claim ID | Claim (이 자료가 직접 말하는 것) | Evidence quote | Strength | Applies to | Does not prove | |---|---|---|---|---|---| | GRADLE-RA-C1 | `preserveFileTimestamps=false` 로 설정하면 archive entry 타임스탬프가 기계·JVM 버전·OS 와 무관하게 동일해진다 | [§preserveFileTimestamps] "If `false` this ensures that archive entries have the same time for builds between different machines, Java versions and operating systems." | `official-vendor-doc` | Gradle `AbstractArchiveTask` 를 상속한 모든 archive task (Zip, Jar, Tar, War, Ear 포함) | 특정 timestamp 값이 무엇인지 (1980-01-01 0:00 등) 는 본 인용이 직접 명시하지 않음; 다른 비결정성 요소(클래스파일 내 날짜, JDK 자체 출력물) 는 별도 제거 필요 | | GRADLE-RA-C2 | `reproducibleFileOrder=true` 로 설정하면 Gradle 이 디렉터리를 OS·파일시스템과 무관한 순서로 탐색하여 byte-for-byte reproducible archive 를 생성할 수 있다 | [§reproducibleFileOrder] "Gradle will then walk the directories on disk which are part of this archive in a reproducible order independent of file systems and operating systems. This helps Gradle reliably produce byte-for-byte reproducible archives." | `official-vendor-doc` | Gradle `AbstractArchiveTask` 를 상속한 모든 archive task | "helps produce" 표현 — 다른 비결정성 원인(타임스탬프, 컴파일 출력 등)이 함께 제거되어야 실제 byte-for-byte 재현 가능. 본 property 단독으로는 충분조건 아님 | | GRADLE-RA-C3 | `tasks.withType().configureEach {}` 블록으로 두 property 를 전역 일괄 적용하는 것이 Gradle 공식 권장 패턴이다 | [§sec:reproducible_archives, Kotlin DSL] `tasks.withType().configureEach { preserveFileTimestamps = false; reproducibleFileOrder = true }` | `official-vendor-doc` | Gradle build scripts (Kotlin DSL / Groovy DSL 모두) | 특정 Gradle 버전 최소 요구사항은 본 인용에서 명시되지 않음; `configureEach` vs 직접 호출 차이(lazy vs eager)는 본 claim 범위 밖 | ## Usage Boundaries / 적용 경계 - 이 자료가 직접 증명하는 것: - `GRADLE-RA-C1`: `preserveFileTimestamps=false` 가 빌드 환경(기계/JVM/OS) 간 archive entry 타임스탬프를 통일한다 - `GRADLE-RA-C2`: `reproducibleFileOrder=true` 가 파일시스템 순서 의존성을 제거하여 byte-for-byte reproducible archive 에 기여한다 - `GRADLE-RA-C3`: `tasks.withType().configureEach {}` 가 두 property 전역 적용 패턴임을 공식 문서가 보여준다 - 이 자료가 증명하지 않는 것: - 두 property 만 설정하면 완전한 reproducible build 가 보장된다는 것 (C2의 "helps" 표현 — 타임스탬프 entropy, JDK 버전 고정, 컴파일러 출력 결정론 등 추가 조건 필요) - 특정 Gradle 버전에서 이 property 가 도입된 시점 - CI 환경(GitHub Actions 등) 에서의 실제 적용 검증 - 내 프로젝트에 적용하려면 추가 확인이 필요한 것: - ca-skeleton 의 `build.gradle.kts` 에 `tasks.withType().configureEach {}` 블록 실제 적용 후 동일 commit 2회 빌드 → artifact SHA-256 비교 (`Claims To Verify` 항목) - JDK 버전 고정 (`.tool-versions` 또는 `gradle/wrapper/`) 병행 여부 — D10 에서 함께 명시된 조건 ## 메모 / Notes - C2 의 "helps Gradle reliably produce byte-for-byte reproducible archives" 는 충분조건이 아닌 기여 표현. D10 의 "동일 commit 2회 build → artifact hash 일치" 테스트 계약은 이 두 property + JDK pin 조합의 실증으로 보완해야 한다. - DSL reference 와 Javadoc 두 출처가 동일 verbatim 을 반환 — 설명이 단일 소스에서 생성된 것으로 보임. - D10 의 Supporting Claims 를 `GRADLE-RA-C1`, `GRADLE-RA-C2`, `GRADLE-RA-C3` 로 갱신하면 `UNSUPPORTED_DECISION` 라벨 제거 가능. ## Related / 관련 - 같은 주제 Gradle 공식 문서: [[raw/official-docs/supply-chain-gradle-vs-maven-dependency-locking]] (dependency locking) - 이 자료를 인용한 wiki 요약: (생성 시 추가)