Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 49 additions & 0 deletions .github/workflows/distribute_internal.yml
Original file line number Diff line number Diff line change
Expand Up @@ -149,3 +149,52 @@ jobs:
MATCH_PASSWORD: ${{ secrets.MATCH_PASSWORD }}
APPSTORE_API_KEY: ${{ secrets.APPSTORE_API_KEY }}
run: bundle exec fastlane distribute_to_firebase

ios_testflight:
needs: determine_platforms
if: ${{ needs.determine_platforms.outputs.run_ios == 'true' }}
runs-on: macos-15 # Requires xcode 15 or later
timeout-minutes: 30
steps:
- name: Connect Bot
uses: webfactory/ssh-agent@v0.9.1
with:
ssh-private-key: ${{ secrets.BOT_SSH_PRIVATE_KEY }}

- name: "Git Checkout"
uses: actions/checkout@v6
with:
fetch-depth: 0

- uses: maxim-lobanov/setup-xcode@v1
with:
xcode-version: '26.3'

- name: "Install Flutter"
uses: subosito/flutter-action@v2
with:
flutter-version: ${{ env.FLUTTER_VERSION }}
channel: stable
cache-key: flutter-:os:-:channel:-:version:-:arch:-:hash:-${{ hashFiles('**/pubspec.lock') }}

- name: "Disable Swift Package Manager"
run: flutter config --no-enable-swift-package-manager

- name: "Install Tools"
run: flutter pub global activate melos

- name: "Bootstrap Workspace"
run: melos bootstrap

- name: Setup Ruby
uses: ruby/setup-ruby@v1
with:
bundler-cache: true
working-directory: sample_app/ios

- name: Distribute to TestFlight Internal
working-directory: sample_app/ios
env:
MATCH_PASSWORD: ${{ secrets.MATCH_PASSWORD }}
APPSTORE_API_KEY: ${{ secrets.APPSTORE_API_KEY }}
Comment on lines +159 to +199
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.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

FILE=".github/workflows/distribute_internal.yml"
echo "== File existence =="
ls -l "$FILE"

echo "== Show lines 130-230 =="
nl -ba "$FILE" | sed -n '130,230p'

echo "== Find all actions/checkout usages =="
rg -n "uses:\s*actions/checkout" "$FILE" || true

echo "== Show any persist-credentials settings =="
rg -n "persist-credentials" "$FILE" || true

echo "== Show all uses lines in the workflow (limited to within distribute_internal.yml) =="
rg -n "^\s*uses:\s*" "$FILE" | head -n 200

Repository: GetStream/stream-chat-flutter

Length of output: 271


🏁 Script executed:

#!/bin/bash
set -euo pipefail

FILE=".github/workflows/distribute_internal.yml"
nl -ba "$FILE" | sed -n '150,210p'

Repository: GetStream/stream-chat-flutter

Length of output: 116


🏁 Script executed:

#!/bin/bash
set -euo pipefail

FILE=".github/workflows/distribute_internal.yml"
echo "== File existence =="
ls -l "$FILE"

echo "== Match actions/checkout usages =="
rg -n "uses:\s*actions/checkout" "$FILE" || true

echo "== Match persist-credentials settings =="
rg -n "persist-credentials" "$FILE" || true

echo "== Match all uses: lines (first 200) =="
rg -n "^\s*uses:\s*" "$FILE" | head -n 200 || true

echo "== Show file excerpt (lines 140-220) using awk =="
awk 'NR>=140 && NR<=220 {printf "%5d %s\n", NR, $0}' "$FILE" | sed -n '1,200p'

Repository: GetStream/stream-chat-flutter

Length of output: 3350


Pin GitHub Actions to SHAs and prevent checkout token persistence

In the ios_testflight job, actions/checkout@v6 is used without persist-credentials: false, and multiple third-party actions use mutable version tags (webfactory/ssh-agent@v0.9.1, maxim-lobanov/setup-xcode@v1, subosito/flutter-action@v2, ruby/setup-ruby@v1). Pin each uses: to a full commit SHA, and set persist-credentials: false on the Git Checkout step.

🧰 Tools
🪛 zizmor (1.25.2)

[warning] 164-167: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false

(artipacked)


[error] 160-160: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)

(unpinned-uses)


[error] 165-165: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)

(unpinned-uses)


[error] 169-169: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)

(unpinned-uses)


[error] 174-174: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)

(unpinned-uses)


[error] 190-190: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)

(unpinned-uses)

🤖 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/distribute_internal.yml around lines 159 - 199, Update the
workflow steps to pin third‑party actions to immutable commit SHAs (replace
uses: webfactory/ssh-agent@v0.9.1, maxim-lobanov/setup-xcode@v1,
subosito/flutter-action@v2, ruby/setup-ruby@v1, etc. with their corresponding
full commit SHAs) and set persist-credentials: false on the "Git Checkout" step
(the step titled "Git Checkout" that uses actions/checkout@v6) so the checkout
token is not persisted to subsequent steps.

run: bundle exec fastlane distribute_to_testflight_internal
26 changes: 26 additions & 0 deletions sample_app/ios/fastlane/Fastfile
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,32 @@ platform :ios do
)
end

desc "Build and distribute app to TestFlight Internal Testers with auto-incrementing build number"
# Usage: bundle exec fastlane ios distribute_to_testflight_internal
lane :distribute_to_testflight_internal do
match_me

current_build_number = latest_testflight_build_number(
api_key: appstore_api_key,
app_identifier: app_identifier
)

build_number = (current_build_number || 0).to_i + 1
build_ipa(export_method: "app-store", build_number: build_number)

upload_dsyms_to_crashlytics

upload_to_testflight(
api_key: appstore_api_key,
distribute_external: false,
notify_external_testers: false,
ipa: "#{root_path}/build/ios/ipa/ChatSample.ipa",
groups: ['Internal Testers'],
changelog: 'Lots of amazing new features to test out!',
skip_waiting_for_build_processing: true,
)
Comment thread
coderabbitai[bot] marked this conversation as resolved.
end

desc "Upload iOS dSYMs from the most recent `flutter build ipa` to Firebase Crashlytics"
private_lane :upload_dsyms_to_crashlytics do
dsym_zip = zip(
Expand Down
2 changes: 1 addition & 1 deletion sample_app/pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name: sample_app
description: A new Flutter project.
publish_to: "none"
version: 2.2.0
version: 9.24.0

# Note: The environment configuration and dependency versions are managed by Melos.
#
Expand Down
20 changes: 20 additions & 0 deletions tools/generate_version.dart
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,24 @@ Future<void> main() async {
await versionFile.writeAsString(updatedContent);

print('✓ Successfully updated version to $version in $versionFilePath');

var cleanedVersion = version;
if (cleanedVersion.contains('-')) {
cleanedVersion = cleanedVersion.split('-').first;

print('Cleaned version for app: $cleanedVersion');
}

// Update the version in the sample_app pubspec.yaml
final sampleAppPubspecPath = p.join(rootDir, 'sample_app', 'pubspec.yaml');
final sampleAppPubspec = File(sampleAppPubspecPath).readAsStringSync();
final updatedSampleAppPubspec = sampleAppPubspec.replaceFirst(
RegExp('version: .+'),
'version: $cleanedVersion',
);

await File(sampleAppPubspecPath).writeAsString(updatedSampleAppPubspec);

print(
'✓ Successfully updated version to $cleanedVersion in $sampleAppPubspecPath');
}
Loading