Skip to content

Conversation

@HI-JIN2
Copy link
Member

@HI-JIN2 HI-JIN2 commented Jan 26, 2026

Summary

Describe your changes

Issue

  • Resolves #

To reviewers

- FileUtils.mkdir_p로 안전한 디렉토리 생성
- Base64 형식 검증 및 에러 처리 추가
- 서비스 계정 JSON 파일에 0600 권한 설정으로 보안 강화
- 중복된 환경 변수 설정 단계 제거
- AAB 아티팩트 경로를 명확한 release 경로로 변경
- sleep 3 대신 폴링 방식으로 GitHub Release 생성 확인
- jq 명령어 존재 여부 체크 추가
- curl --show-error 옵션으로 에러 노출 방지
- RELEASE_NOTES.txt 빈 파일 체크
- 최소 길이(10자) 검증 추가
- Play Store 정책 위반 가능성 경고
- release-notes/ 디렉토리 추가 및 가이드 문서화
- YAML 기반 버전별 릴리즈 노트 관리 (한국어/영어)
- Fastlane 워크플로우에 수동 릴리즈 배포 기능 추가
- deploy_release lane 추가: YAML 파싱 및 다국어 Play Store 배포
- 워크플로우 입력 필드 확장 (version, track 파라미터)
- 샘플 v3.2.0 릴리즈 노트 포함
- google-services.json 명시적 추가
- Keystore 파일 주석 명확화
- 불필요한 주석 제거 및 정리
- CI/CD 시스템 도입 관련 내용 포함
- 한국어/영어 다국어 지원
- YAML 형식으로 버전별 관리
@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @HI-JIN2, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

이 PR은 Fastlane을 활용하여 Android 애플리케이션의 CI/CD 파이프라인을 구축하고 자동화된 빌드 및 배포 시스템을 도입하는 것을 목표로 합니다. 개발 환경 설정, Google 서비스 파일 관리, 다양한 빌드 유형 생성, 그리고 Google Play Store로의 배포 과정을 효율적으로 처리할 수 있도록 Fastlane 스크립트와 관련 설정 파일들이 추가되었습니다. 또한, 프로젝트의 문서화를 강화하기 위해 상세한 개발자 가이드와 다국어 릴리즈 노트 관리 시스템을 함께 구축했습니다.

Highlights

  • Fastlane CI/CD 시스템 도입: Android 앱의 빌드 및 배포 프로세스를 자동화하기 위한 Fastlane 설정 파일들이 추가되었습니다.
  • .gitignore 파일 업데이트: 빌드 아티팩트, Fastlane 관련 파일, Ruby 관련 파일 등을 적절히 무시하도록 .gitignore 파일이 수정되었습니다.
  • 개발자 가이드 문서 추가: 프로젝트의 개발 환경 설정, 빌드/테스트 명령어, 코드 컨벤션 등을 상세히 설명하는 AGENTS.md 파일이 새로 추가되었습니다.
  • README.md 개선: Fastlane CI/CD 사용법에 대한 안내와 함께 오타가 수정되었습니다.
  • 다국어 릴리즈 노트 시스템 구축: YAML 기반의 다국어 릴리즈 노트 관리 시스템이 도입되었으며, 관련 가이드 문서와 예시 파일이 추가되었습니다.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Ignored Files
  • Ignored by pattern: .github/workflows/** (2)
    • .github/workflows/fastlane.yml
    • .github/workflows/release_tag.yml
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces Fastlane to automate the build and deployment process, significantly enhancing the CI/CD pipeline with features like QA/production environment separation, APK/AAB artifact creation, and Play Store distribution. While the automation is well-structured, there are critical security concerns regarding the handling of sensitive data such as API keys and service account JSONs. Specifically, secrets are being written to files with insecure, world-readable permissions, and a hardcoded path in /tmp is used for sensitive credentials, which is vulnerable to race conditions and collisions on shared build infrastructure. Additionally, there are minor suggestions to improve code maintainability.

/build
# Local configuration file (sdk path, etc)
local.properties
app/src/main/res/values/kakao_string.xml
Copy link
Contributor

Choose a reason for hiding this comment

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

critical

이 파일은 이전에 APP_KEY를 포함하고 있다는 주석과 함께 gitignore 처리되고 있었습니다. .gitignore에서 이 파일을 제거하면 민감한 정보가 저장소에 커밋될 위험이 있습니다. 이 파일에 민감한 데이터가 포함되어 있는지 확인하고, 만약 그렇다면 다시 .gitignore에 추가해야 합니다. 키 관리는 다른 키들처럼 local.properties를 사용하고 buildConfigField를 통해 접근하는 방식을 권장합니다.

Comment on lines +187 to +188
version_name = sh("grep 'versionName' app/build.gradle.kts | head -1 | sed 's/.*versionName = \"\\(.*\\)\".*/\\1/'", log: false).strip
version_code = sh("grep 'versionCode' app/build.gradle.kts | head -1 | sed 's/.*versionCode = \\([0-9]*\\).*/\\1/'", log: false).strip
Copy link
Contributor

Choose a reason for hiding this comment

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

high

grepsed를 사용하여 버전 정보를 추출하는 방식은 app/build.gradle.kts 파일의 형식이 변경(예: 공백 추가)되면 깨지기 쉽습니다. 더 안정적인 방법은 버전 정보를 출력하는 전용 Gradle 태스크를 사용하거나, fastlane-plugin-gradle_properties_reader 또는 fastlane-plugin-android_versioning과 같은 fastlane 플러그인을 사용하는 것입니다.

예를 들어, build.gradle.kts에 다음과 같은 태스크를 추가할 수 있습니다:

task("printVersionName") {
    doLast {
        println(android.defaultConfig.versionName)
    }
}

그리고 fastlane에서 다음과 같이 호출할 수 있습니다:

version_name = sh("./gradlew -q printVersionName").strip

이렇게 하면 로직이 파일의 특정 형식에 종속되지 않게 됩니다.

Comment on lines +15 to +35
sh("touch local.properties")

# 환경 변수에서 값 읽어오기 (GitHub Actions에서 설정됨)
dev_base_url = ENV["DEV_BASE_URL"] || ""
prod_base_url = ENV["PROD_BASE_URL"] || ""
kakao_key = ENV["KAKAO_NATIVE_APP_KEY"] || ""
naver_maps_id = ENV["NAVER_MAPS_CLIENT_ID"] || ""
posthog_api_key = ENV["POSTHOG_API_KEY"] || ""
posthog_host = ENV["POSTHOG_HOST"] || ""

base_url = environment == "production" ? prod_base_url : dev_base_url

# local.properties에 값 추가
File.open("local.properties", "a") do |f|
f.puts("DEV_BASE_URL=\"#{dev_base_url}\"")
f.puts("PROD_BASE_URL=\"#{prod_base_url}\"")
f.puts("KAKAO_NATIVE_APP_KEY=#{kakao_key}")
f.puts("NAVER_MAPS_CLIENT_ID=#{naver_maps_id}")
f.puts("POSTHOG_API_KEY=#{posthog_api_key}")
f.puts("POSTHOG_HOST=#{posthog_host}")
end
Copy link
Contributor

Choose a reason for hiding this comment

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

security-medium medium

The script creates local.properties using sh("touch local.properties"), which typically results in world-readable permissions (0644) based on the system's umask. Sensitive information such as API keys and base URLs are then written to this file, allowing unauthorized local users or processes to access these secrets on shared build infrastructure. Additionally, the base_url local variable is assigned but not used, which can be removed for clarity.

Comment on lines +140 to +142
service_account_path = "/tmp/google-play-service-account.json"
File.write(service_account_path, ENV["GOOGLE_PLAY_SERVICE_ACCOUNT_JSON"])
File.chmod(0600, service_account_path)
Copy link
Contributor

Choose a reason for hiding this comment

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

security-medium medium

The script uses a hardcoded path in /tmp (/tmp/google-play-service-account.json) to store sensitive service account credentials. This can lead to collisions between concurrent builds on the same host. Furthermore, the file is created with default permissions before File.chmod is called, creating a race condition where the secret is briefly world-readable by other users or processes on the system (CWE-377, CWE-379).

require 'base64'
begin
decoded_content = Base64.strict_decode64(google_service)
File.write("app/google-services.json", decoded_content)
Copy link
Contributor

Choose a reason for hiding this comment

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

security-medium medium

The file app/google-services.json is created with default system permissions (typically 0644), making it world-readable. This file contains sensitive configuration data. It should be created with restricted permissions (e.g., 0600) to prevent unauthorized access on shared systems.

Comment on lines +136 to +137
- Project overview: `README.md`.
- Project overview: `README.md`; troubleshooting: `.github/TROUBLESHOOTING.md`.
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

이 섹션에는 README.md를 가리키는 라인이 중복되어 있습니다. 가독성을 위해 하나를 제거하는 것이 좋겠습니다.

Suggested change
- Project overview: `README.md`.
- Project overview: `README.md`; troubleshooting: `.github/TROUBLESHOOTING.md`.
- Project overview: `README.md`; troubleshooting: `.github/TROUBLESHOOTING.md`

# Appfile for fastlane
# 앱 정보 설정

json_key_file("") # Google Play Service Account JSON 키 경로 (선택사항)
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

json_key_file을 빈 문자열로 설정하는 것은 혼란을 줄 수 있습니다. Fastfile에서 upload_to_play_store 액션에 JSON 키가 환경 변수로부터 직접 제공되므로 이 라인은 필수는 아니며, 혼동을 피하기 위해 제거하거나 명확한 주석으로 교체하는 것이 좋습니다.

# Google Play Service Account JSON 키는 Fastfile에서 환경 변수를 통해 관리됩니다.

Comment on lines +243 to +245
elsif release_notes_content.length < 10
UI.error("❌ RELEASE_NOTES.txt 내용이 너무 짧습니다. 최소 10자 이상 필요합니다.")
release_notes_path = nil
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

릴리즈 노트 길이가 최소 10자 이상이어야 한다는 검사는 다소 임의적으로 보입니다. 빈 릴리즈 노트를 방지하는 것은 좋지만, "버그 수정"과 같이 짧지만 유효한 노트가 거부될 수 있습니다. 이 검사가 Google Play Store의 엄격한 요구사항이 아니라면, 이 임계값을 낮추거나 설정 가능한 매개변수로 만드는 것을 고려해 보세요.

Comment on lines +320 to +328
if ko_notes.nil? || ko_notes.strip.empty?
UI.error("❌ 한국어 릴리즈 노트가 비어있습니다.")
ko_notes = "버그 수정 및 성능 개선"
end

if en_notes.nil? || en_notes.strip.empty?
UI.error("❌ 영어 릴리즈 노트가 비어있습니다.")
en_notes = "Bug fixes and performance improvements"
end
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

한국어 및 영어 대체 릴리즈 노트가 레인 로직 내에 하드코딩되어 있습니다(여기 와 아래의 rescue 블록). 이를 파일 상단에 상수로 정의하면 유지보수성이 향상될 것입니다. 이렇게 하면 필요할 때 더 쉽게 찾고 업데이트할 수 있습니다.

예시:

DEFAULT_KO_RELEASE_NOTES = "버그 수정 및 성능 개선"
DEFAULT_EN_RELEASE_NOTES = "Bug fixes and performance improvements"

# ... 레인 내부 ...
if ko_notes.nil? || ko_notes.strip.empty?
  UI.error("❌ 한국어 릴리즈 노트가 비어있습니다.")
  ko_notes = DEFAULT_KO_RELEASE_NOTES
end

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.

2 participants