Setting/#485 Github Action와 Fastlane을 통한 자동 배포 - #486
Hidden character warning
Conversation
WalkthroughGitHub Actions가 ChangesFastlane 자동 배포
Estimated code review effort: 4 (Complex) | ~45 minutes Sequence Diagram(s)sequenceDiagram
participant GitHub as GitHub Actions
participant Fastlane
participant TestFlight
participant AppStore as App Store Connect
participant Discord
GitHub->>Fastlane: develop 병합 시 upload_testflight 실행
Fastlane->>TestFlight: 빌드 번호 조회 및 앱 업로드
Fastlane->>Discord: 결과 알림 전송
GitHub->>Fastlane: main 병합 시 release_app_store 실행
Fastlane->>AppStore: 앱 제출 및 자동 출시
Fastlane->>Discord: 결과 알림 전송
Possibly related issues
Suggested reviewers: Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 8
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.github/workflows/fastlane_ci.yml:
- Around line 10-14: Serialize the fastlane deployment job by adding a shared
GitHub Actions concurrency group for the TestFlight and App Store lanes, and
explicitly configure the pending-run cancellation policy so queued deployments
are not unintentionally discarded. Anchor the group to the deployment workflow
or shared environment rather than the individual PR, ensuring merged PR
deployments receive unique build numbers.
- Around line 30-34: Update the “Install dependencies” and “Output Fastlane
environment” steps in the workflow to set working-directory to ByeBoo-iOS, so
both bundle commands execute from the directory containing the Gemfile and
Fastfile.
- Line 18: Update the checkout action version in the workflow from
actions/checkout@v3 to actions/checkout@v4 or a newer supported release, leaving
the surrounding workflow configuration unchanged.
In `@ByeBoo-iOS/fastlane/Fastfile`:
- Around line 114-117: Update the release_app_store flow to call
notify_discord_success immediately after upload_to_app_store completes
successfully, using a message that clearly indicates App Store review submission
succeeded rather than release completion. Preserve the existing
notify_discord_failure handling for errors.
- Line 80: Update the notify_discord_success call in the TestFlight upload
success path to pass only the single argument accepted by
notify_discord_success, while preserving the existing success message behavior
and avoiding the rescue failure-notification path.
- Line 63: Update the deployment lane call from the undefined
`iprepare_ci_and_signing` helper to the correctly defined CI and signing
preparation helper, preserving the existing TestFlight deployment flow.
- Around line 103-114: upload_to_app_store 호출의 인자 목록과 submission_information 블록을
닫는 괄호를 추가한 뒤 rescue 절이 메서드 호출 바깥에서 파싱되도록 정렬을 수정하십시오. upload_to_app_store의 기존 옵션과
rescue 처리 흐름은 그대로 유지하십시오.
- Around line 34-39: Update notify_discord_failure so the Discord payload is
built with a JSON serializer rather than interpolated JSON, preserving the lane
name and sanitized error message content. Invoke curl through Fastlane sh with
separate arguments instead of constructing one shell command string, ensuring
shell metacharacters and quotes in both payload data and the Discord URL are not
interpreted by the shell.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: b0ef0ba8-ee3c-47ac-9f3a-c1d5dbc7bd5a
📒 Files selected for processing (2)
.github/workflows/fastlane_ci.ymlByeBoo-iOS/fastlane/Fastfile
| jobs: | ||
| fastlane: | ||
| name: Run Fastlane | ||
| runs-on: macos-latest | ||
| if: github.event.pull_request.merged == true |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟠 Major | 🏗️ Heavy lift
배포 작업을 직렬화하거나 빌드 번호를 원자적으로 할당하십시오.
동시에 두 PR이 병합되면 두 작업이 latest_testflight_build_number를 같은 값으로 읽을 수 있습니다. 두 작업은 같은 다음 빌드 번호를 업로드하려고 시도합니다. 한 작업은 중복 빌드 번호 때문에 실패합니다.
TestFlight와 App Store 레인 전체에 공유되는 배포 조정 방식을 추가하십시오. GitHub Actions concurrency를 사용할 경우, 대기 중인 배포가 취소될 수 있는 정책도 명시적으로 처리하십시오.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.github/workflows/fastlane_ci.yml around lines 10 - 14, Serialize the
fastlane deployment job by adding a shared GitHub Actions concurrency group for
the TestFlight and App Store lanes, and explicitly configure the pending-run
cancellation policy so queued deployments are not unintentionally discarded.
Anchor the group to the deployment workflow or shared environment rather than
the individual PR, ensuring merged PR deployments receive unique build numbers.
|
|
||
| steps: | ||
| - name: Checkout repository | ||
| uses: actions/checkout@v3 |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# v3 액션 런타임을 확인합니다.
curl -fsSL https://raw.githubusercontent.com/actions/checkout/v3/action.yml |
rg -n 'using:|node'Repository: 36-APPJAM-HEARTZ/BYEBOO-iOS
Length of output: 185
🌐 Web query:
GitHub Actions Node 16 runner deprecation actions/checkout v3 node16
💡 Result:
GitHub Actions support for Node 16 reached its end-of-life (EOL) and has been fully removed from the Actions runner environment [1]. The deprecation timeline and key points are as follows: 1. End of Life Date: Node 16 was officially removed from the GitHub Actions runner environment on November 12, 2024 [1]. 2. Context for actions/checkout: While actions/checkout@v3 was originally built to run on Node 16, it is now obsolete [2][3]. Because Node 16 is no longer supported, workflows continuing to use actions/checkout@v3 or any other action requiring Node 16 will fail on GitHub-hosted runners [1]. 3. Recommended Action: You should update all workflows to use the latest versions of actions (e.g., actions/checkout@v4), which are designed to run on Node 20 or newer [1][4]. If you are currently experiencing issues with workflows running on older versions, it is because the necessary runtime (Node 16) is no longer available in the environment [1][5]. Setting environment variables like ACTIONS_ALLOW_USE_UNSECURE_NODE_VERSION=true, which were used during the transition period to temporarily extend Node 16 usage, are no longer effective because the Node 16 binaries have been removed from the runners entirely [1][6][7].
Citations:
- 1: https://github.blog/changelog/2024-09-25-end-of-life-for-actions-node16/
- 2: https://github.com/marketplace/actions/checkout?version=v3.6.0
- 3: actions/checkout@6fbf6d4
- 4: Node 16 deprecation actions/setup-node#850
- 5: [Ubuntu 20 and 22] Node.js version 16 will be removed on November 18,2024. actions/runner-images#10896
- 6: checkout@v3 using node20 instead of node16 actions/checkout#1809
- 7: https://github.blog/changelog/2024-05-17-updated-dates-for-actions-runner-using-node20-instead-of-node16-by-default/
actions/checkout@v4 이상으로 업데이트하십시오.
actions/checkout@v3는 node16 런타임에 의존하므로 현재 GitHub Actions runner에서 실행에 실패합니다. 안정성 이슈를 방지하려면 actions/checkout@v4 이상을 사용하십시오.
🧰 Tools
🪛 actionlint (1.7.12)
[error] 18-18: the runner of "actions/checkout@v3" action is too old to run on GitHub Actions. update the action's version to fix this issue
(action)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.github/workflows/fastlane_ci.yml at line 18, Update the checkout action
version in the workflow from actions/checkout@v3 to actions/checkout@v4 or a
newer supported release, leaving the surrounding workflow configuration
unchanged.
Source: Linters/SAST tools
| - name: Install dependencies | ||
| run: bundle install | ||
|
|
||
| - name: Output Fastlane environment | ||
| run: bundle exec fastlane env |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Fastlane과 Bundler 설정 파일의 실제 위치를 확인합니다.
fd -H -t f '^(Gemfile|Fastfile)$' .Repository: 36-APPJAM-HEARTZ/BYEBOO-iOS
Length of output: 217
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf 'Workflow file:\n'
sed -n '1,140p' .github/workflows/fastlane_ci.yml
printf '\nRoot listing relevant entries:\n'
git ls-files | sed -n '1,200p' | grep -E '(^|/)(Gemfile|Fastfile|\.fastlane|bundle|fastlane|README|\.github/workflows/fastlane_ci.yml)$' || trueRepository: 36-APPJAM-HEARTZ/BYEBOO-iOS
Length of output: 2556
.github/workflows/fastlane_ci.yml의 Fastlane 명령에 working-directory: ByeBoo-iOS를 추가하세요.
저장소 루트에는 Gemfile이나 Fastfile이 없습니다. 현재 bundle install과 bundle exec fastlane ... 명령이 루트에서 실행되므로 실행 단계에서 실패합니다.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.github/workflows/fastlane_ci.yml around lines 30 - 34, Update the “Install
dependencies” and “Output Fastlane environment” steps in the workflow to set
working-directory to ByeBoo-iOS, so both bundle commands execute from the
directory containing the Gemfile and Fastfile.
| def notify_discord_failure(lane_name, error_message) | ||
| sh( | ||
| "curl -H 'Content-Type: application/json' " + | ||
| "-d '{\"content\": \"🤔🌀 **#{lane_name}** 실패\\n```#{error_message.to_s.gsub('"', "'").gsub("\n", " ")}```\"}' " + | ||
| "#{ENV['DISCORD_URL']}" | ||
| ) |
There was a problem hiding this comment.
🔒 Security & Privacy | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== file excerpt =="
sed -n '1,120p' ByeBoo-iOS/fastlane/Fastfile
echo
echo "== relevant notify_discord_* usages =="
rg -n "notify_discord|DISCORD_URL|upload_testflight|release_app_store" ByeBoo-iOS/fastlane/Fastfile
echo
echo "== fastlane/Gemfile versions =="
for f in ByeBoo-iOS/Gemfile ByeBoo-iOS/fastlane/Gemfile Gemfile ByeBoo-iOS/fastlane/Gemfile; do
if [ -f "$f" ]; then
echo "--- $f"
rg -n "fastlane|ruby" "$f" || true
fi
done
echo
echo "== local shell command construction behavior probe =="
python3 - <<'PY'
import shlex
msg = "abc' && curl -e \"injected\" # comment"
cmd = "curl -H 'Content-Type: application/json' -d '{\"content\": \"🤔🌀 **lane_name** 실패\\n```" + msg + "```\"}' DISCORD_URL"
print("constructed:")
print(cmd)
print("parsed by shlex:")
try:
for i, token in enumerate(shlex.split(cmd, posix=True), 1):
print(f"{i}: {token!r}")
except Exception as e:
print(f"shlex error: {type(e).__name__}: {e}")
PYRepository: 36-APPJAM-HEARTZ/BYEBOO-iOS
Length of output: 3967
🌐 Web query:
Ruby Fastlane sh command string interpolation shell injection safe passing arguments
💡 Result:
To securely pass arguments to the Fastlane sh action and avoid command injection vulnerabilities, you should always pass arguments as separate array elements rather than constructing a single shell-interpolated string [1][2][3]. When you provide multiple arguments (e.g., sh('git', 'log', '-2', "--grep='DEV'")), Fastlane passes these arguments directly to Ruby's Open3.popen2e (or similar system call methods like Kernel#spawn), bypassing the shell interpreter entirely [2][4][5]. This ensures that special characters in your arguments are treated as literal data rather than shell metacharacters [2]. ### Recommended Approach Avoid shell interpolation entirely: # Insecure (vulnerable to injection) sh("git --grep='#{user_input}'") # Secure (arguments passed as separate elements) sh('git', 'log', '-2', "--grep=#{user_input}") By using the second approach, sh does not invoke a shell interpreter to parse the string, effectively preventing malicious users from injecting arbitrary shell commands [2][5]. ### Key Takeaways 1. Separate Arguments: Always pass arguments as a list to sh (e.g., sh('command', 'arg1', 'arg2')) instead of a single string [3][4]. 2. Avoid Shell Interpolation: If you must use a single string, you are responsible for manually escaping input using Ruby's Shellwords.shellescape method, but this is significantly more error-prone than simply using the variadic argument list [3]. 3. Logging: Be aware that sh will log the command it executes. If you are passing sensitive information (like passwords) as arguments, consider using environment variables to avoid leaking sensitive data in your logs [6]. 4. Internal Implementation: Internally, Fastlane uses the passed arguments to execute the process directly. While Fastlane's shell_command_from_args helper attempts to reconstruct a command string for logging purposes, the actual execution path (via Open3.popen2e) is what provides the security against injection [4][5].
Citations:
- 1: [install_xcode_plugin] hardening sh() to properly handle repo URL fastlane/fastlane#29811
- 2: Why does Fastlane `sh` command add escape characters? fastlane/fastlane#21676
- 3: https://docs.fastlane.tools/advanced/actions/
- 4: https://github.com/fastlane/fastlane/blob/master/fastlane/lib/fastlane/helper/sh_helper.rb
- 5: https://github.com/fastlane/fastlane/blob/cd88359fa9b6772f91a31a290f8f3c790a716dc0/fastlane/lib/fastlane/helper/sh_helper.rb
- 6: https://stackoverflow.com/questions/58093548/hiding-sensitive-ruby-shell-commands
oler_?
?
오류 메시지를 쉘 명령어에서 안전한 인수로 전달하십시오.
notify_discord_failure는 error_message를 쉘 문자열에 보간합니다. '가 포함된 메시지는 명령어를 깨뜨리고, 쉘 특수 문자가 들어갈 수 있으니 제어가 필요합니다. JSON을 안전하게 직렬화하고, Fastlane sh('curl', ...)처럼 인자 배열으로 전달해 쉘 해석을 피하십시오.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@ByeBoo-iOS/fastlane/Fastfile` around lines 34 - 39, Update
notify_discord_failure so the Discord payload is built with a JSON serializer
rather than interpolated JSON, preserving the lane name and sanitized error
message content. Invoke curl through Fastlane sh with separate arguments instead
of constructing one shell command string, ensuring shell metacharacters and
quotes in both payload data and the Discord URL are not interpreted by the
shell.
| ) | ||
| upload_to_testflight | ||
| begin | ||
| iprepare_ci_and_signing |
There was a problem hiding this comment.
🎯 Functional Correctness | 🔴 Critical | ⚡ Quick win
정의된 헬퍼 이름을 호출하십시오.
iprepare_ci_and_signing은 정의되지 않았습니다. 이 호출은 NoMethodError를 발생시키고 TestFlight 배포를 시작하지 못하게 합니다.
수정 예시
- iprepare_ci_and_signing
+ prepare_ci_and_signing📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| iprepare_ci_and_signing | |
| prepare_ci_and_signing |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@ByeBoo-iOS/fastlane/Fastfile` at line 63, Update the deployment lane call
from the undefined `iprepare_ci_and_signing` helper to the correctly defined CI
and signing preparation helper, preserving the existing TestFlight deployment
flow.
| skip_waiting_for_build_processing: true | ||
| ) | ||
|
|
||
| notify_discord_success("TestFlight 업로드", build_number) |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
성공 알림 헬퍼의 인수 개수를 맞추십시오.
notify_discord_success는 Line 26에서 인수 하나만 받습니다. 이 호출은 업로드 성공 후 ArgumentError를 발생시키고 rescue 경로에서 실패 알림을 전송합니다.
수정 예시
- notify_discord_success("TestFlight 업로드", build_number)
+ notify_discord_success("TestFlight 업로드")📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| notify_discord_success("TestFlight 업로드", build_number) | |
| notify_discord_success("TestFlight 업로드") |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@ByeBoo-iOS/fastlane/Fastfile` at line 80, Update the notify_discord_success
call in the TestFlight upload success path to pass only the single argument
accepted by notify_discord_success, while preserving the existing success
message behavior and avoiding the rescue failure-notification path.
| upload_to_app_store( | ||
| skip_screenshots: true, | ||
| skip_metadata: true, | ||
| force: true, | ||
| submit_for_review: true, # 자동으로 심사 제출 | ||
| automatic_release: true, # 심사 통과 후 자동 출시 | ||
| precheck_include_in_app_purchases: false, | ||
| submission_information: { | ||
| add_id_info_uses_idfa: false, # admob 추가 시 true로 변경 | ||
| export_compliance_uses_encryption: false | ||
| } | ||
| rescue => e |
There was a problem hiding this comment.
🩺 Stability & Availability | 🔴 Critical | ⚡ Quick win
upload_to_app_store 호출을 닫으십시오.
Line 103의 upload_to_app_store(에 대응하는 )가 없습니다. Ruby 파서는 Line 114의 rescue에서 중단됩니다. 이 Fastfile은 두 배포 레인을 모두 실행할 수 없습니다.
수정 예시
submission_information: {
add_id_info_uses_idfa: false,
export_compliance_uses_encryption: false
}
+ )
rescue => e📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| upload_to_app_store( | |
| skip_screenshots: true, | |
| skip_metadata: true, | |
| force: true, | |
| submit_for_review: true, # 자동으로 심사 제출 | |
| automatic_release: true, # 심사 통과 후 자동 출시 | |
| precheck_include_in_app_purchases: false, | |
| submission_information: { | |
| add_id_info_uses_idfa: false, # admob 추가 시 true로 변경 | |
| export_compliance_uses_encryption: false | |
| } | |
| rescue => e | |
| upload_to_app_store( | |
| skip_screenshots: true, | |
| skip_metadata: true, | |
| force: true, | |
| submit_for_review: true, # 자동으로 심사 제출 | |
| automatic_release: true, # 심사 통과 후 자동 출시 | |
| precheck_include_in_app_purchases: false, | |
| submission_information: { | |
| add_id_info_uses_idfa: false, # admob 추가 시 true로 변경 | |
| export_compliance_uses_encryption: false | |
| } | |
| ) | |
| rescue => e |
🧰 Tools
🪛 RuboCop (1.88.2)
[fatal] 114-114: unexpected token kRESCUE
(Using Ruby 2.7 parser; configure using TargetRubyVersion parameter, under AllCops)
(Lint/Syntax)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@ByeBoo-iOS/fastlane/Fastfile` around lines 103 - 114, upload_to_app_store 호출의
인자 목록과 submission_information 블록을 닫는 괄호를 추가한 뒤 rescue 절이 메서드 호출 바깥에서 파싱되도록 정렬을
수정하십시오. upload_to_app_store의 기존 옵션과 rescue 처리 흐름은 그대로 유지하십시오.
Source: Linters/SAST tools
| rescue => e | ||
| notify_discord_failure("App Store 배포", e.message) | ||
| raise e | ||
| end |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
App Store 제출 성공 알림을 추가하십시오.
release_app_store는 실패 알림만 전송합니다. upload_to_app_store가 성공한 뒤 notify_discord_success를 호출하십시오. 알림 메시지는 실제 출시 완료가 아니라 심사 제출 성공임을 표시해야 합니다.
🧰 Tools
🪛 RuboCop (1.88.2)
[fatal] 114-114: unexpected token kRESCUE
(Using Ruby 2.7 parser; configure using TargetRubyVersion parameter, under AllCops)
(Lint/Syntax)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@ByeBoo-iOS/fastlane/Fastfile` around lines 114 - 117, Update the
release_app_store flow to call notify_discord_success immediately after
upload_to_app_store completes successfully, using a message that clearly
indicates App Store review submission succeeded rather than release completion.
Preserve the existing notify_discord_failure handling for errors.
🔗 연결된 이슈
📄 작업 내용
📚 참고자료
참고 링크
Summary by CodeRabbit
새 기능
개선 사항