5. CI/CD & Build Pipeline

CI/CD Pipeline Health

Build Automation80 / 100
Automated Testing in CI/CD0 / 100
Code Signing Security50 / 100
Deployment Process40 / 100

5.1 Build Configuration

Status: ⚠️Warning

Findings:

  • No explicit Flutter version pinning: codemagic.yaml uses flutter: fvm but no .fvmrc file existed in repository to pin specific version
  • Flutter version managed through Codemagic environment groups (github_credentials) rather than repository-level configuration
  • SDK constraint allows Flutter 3.x but no explicit version specified in codebase
  • CocoaPods version set to default (not pinned to specific version like 1.15.2)
  • Deprecated dependencies may block Flutter framework upgrades
  • Fixed commit dependencies complicate upgrade process
  • No version lock file to ensure reproducible builds across environments
  • Build number calculation uses PROJECT_BUILD_NUMBER + 14000 offset (not automatic store API lookup)

Evidence:

  • codemagic.yaml (revision f8e2a6965abf2ddb2d41ad724ff7f930013b4965):
  • flutter: fvm (uses FVM but no version specified)
  • cocoapods: default (not pinned to specific version)
  • Environment groups: github_credentials (not flutter_stg/flutter_prd)
  • No .fvmrc file in repository at that revision
  • pubspec.yaml SDK constraint: >=3.0.0 <4.0.0 (allows any 3.x version)
  • Deprecated packages (moor, device_info, etc.) may have compatibility issues with newer Flutter versions
  • Flutter version depends on Codemagic group configuration (not visible in repository)
  • Build scripts use $(($PROJECT_BUILD_NUMBER + 14000)) for version code calculation

Risk Level: Medium Risk

Recommendation:

  • Immediate actions:
  • Add .fvmrc file to pin Flutter version in repository
  • Pin CocoaPods version explicitly (e.g., 1.15.2)
  • Document Flutter version in README or build documentation
  • Ensure Codemagic groups use same Flutter version as .fvmrc
  • Short-term:
  • Plan incremental upgrades (e.g., current → latest 3.x → 4.0 when stable) aligned with dependency migrations
  • Test Flutter upgrades in staging environment before production
  • Resolve deprecated dependencies before major Flutter upgrades
  • Use FVM to manage multiple Flutter versions during transition
  • Use automatic build number from store APIs instead of offset calculation

5.2 Code Signing & Certificates

Status: Fail

Findings:

  • Critical: Sensitive signing credentials stored directly in repository
  • Android keystore file (tinq4u.keystore.jks) in android-src-files/
  • Private keys (private_key.pepk, deployment_cert.der, upload_cert.der) in repository
  • Google Play service account JSON with embedded private key in repository
  • Apple Sign In private keys (.p8 files) in repository
  • Android signing configuration:
  • Uses encrypted environment variables (FCI_KEYSTORE, FCI_KEYSTORE_PASSWORD, FCI_KEY_PASSWORD, FCI_KEY_ALIAS)
  • Creates key.properties file dynamically from environment variables during build
  • Both staging and production workflows include Android signing setup
  • Hardcoded path to service account in android/fastlane/Appfile
  • iOS signing configuration:
  • Uses App Store Connect credentials from environment variables (not Codemagic integration)
  • Credentials: APP_STORE_CONNECT_ID, APP_STORE_CONNECT_PASSWORD, APP_STORE_CONNECT_PRIVATE_KEY, etc.
  • Uses app-store-connect fetch-signing-files to fetch certificates and profiles
  • Keychain setup and certificate management in build scripts
  • Build number management:
  • Uses PROJECT_BUILD_NUMBER + 14000 offset calculation (not automatic store API lookup)
  • Version name extracted from Git tag (e.g., prod_1.2.31.2.3)
  • Potential for build number conflicts if not managed carefully
  • Certificate management issues:
  • No centralized certificate management
  • Certificates and keys stored in multiple locations
  • Sensitive files in repository despite encrypted variables in CI/CD

Evidence:

  • codemagic.yaml (revision f8e2a6965abf2ddb2d41ad724ff7f930013b4965):
  • Android signing: Encrypted environment variables for keystore credentials
  • Script set_key_properties: Creates key.properties from encrypted variables
  • iOS signing: Environment variables for App Store Connect credentials
  • Scripts: setup_keychain, setup_certificates, add_certificates, setup_provisioning_profiles
  • Build number: $(($PROJECT_BUILD_NUMBER + 14000))
  • android-src-files/tinq4u.keystore.jks: Android signing keystore in repository
  • android-src-files/private_key.pepk: Private key file in repository
  • android-src-files/deployment_cert.der: Deployment certificate in repository
  • android-src-files/upload_cert.der: Upload certificate in repository
  • android-src-files/fastlane-serivce-account.json: Google Play service account with private key
  • apple-src-files/Signin-with-apple-AuthKey_63ZBT4A89B.p8: Apple Sign In private key
  • apple-src-files/ApplePushServices.certSigningRequest: Certificate signing request
  • src-assets/AuthKey_9BWX5U9947.p8: Additional Apple private key
  • android/fastlane/Appfile line 1: Hardcoded path: json_key_file("/Users/markedeer/FlutterApps/tinq4u.flutter.app/android-src-files/fastlane-serivce-account.json")
  • android/app/build.gradle lines 32-36: References key.properties for signing config

Risk Level: Critical Risk

Recommendation:

  • Immediate actions:
  • Remove all sensitive signing files from repository (after backing up to secure location)
  • Move signing credentials to Codemagic secrets management or secure cloud storage
  • Add sensitive directories to .gitignore: android-src-files/, apple-src-files/, src-assets/
  • Short-term:
  • Consider using Codemagic's App Store Connect integration instead of environment variables

5.3 Automated Testing in CI/CD

Status: Fail

Findings:

  • No automated tests in CI/CD pipeline: codemagic.yaml does not include test execution steps
  • Builds can succeed even with broken code
  • Missing quality gates in build process

Evidence:

  • codemagic.yaml (revision f8e2a6965abf2ddb2d41ad724ff7f930013b4965):
  • Workflow scripts (tinq4u-prod, tinq4u-staging) do not include flutter test commands
  • No test execution steps in build scripts
  • No test failure gates in build pipeline
  • Scripts focus on dependency setup, signing, and building only
  • No linting or static analysis steps visible

Risk Level: High Risk

Recommendation:

  • Immediate actions:
  • Add test execution steps to Codemagic workflows
  • Run unit tests, widget tests, and golden tests before building
  • Fail builds if critical tests fail
  • Short-term:
  • Run integration tests against staging environment in CI/CD
  • Add linting and static analysis steps

5.4 Deployment Process

Status: ⚠️Warning

Findings:

  • Separate tag-based deployment: Uses different Git tag patterns for staging and production (staging_* vs prod_*)
  • Suboptimal tag management: Separate tags make it difficult to track which version is in staging vs production
  • No clear promotion path: No mechanism to promote same artifact from staging to production
  • Tag-based versioning: Version name extracted from tag (e.g., prod_1.2.3 → version 1.2.3)
  • Build number offset: Uses PROJECT_BUILD_NUMBER + 14000 calculation instead of automatic store API lookup
  • GitFlow workflow: Makes it hard to track pending changes and current state
  • Multiple long-lived branches: Create complexity and merge conflicts
  • Difficult to identify deployed code: Hard to determine what code is currently deployed in each environment
  • Unused CI/CD pipeline files: jenkins/pipeline.groovy exists but project uses Codemagic
  • Dead code in repository: Jenkins pipeline configuration is no longer used
  • Workflow naming: Uses tinq4u-prod and tinq4u-staging workflow names

Evidence:

  • codemagic.yaml (revision f8e2a6965abf2ddb2d41ad724ff7f930013b4965):
  • Separate workflows: tinq4u-prod and tinq4u-staging
  • Tag patterns: prod_* for production, staging_* for staging
  • Version extraction from tag: IN="$FCI_TAG"; arrIN=(${IN//_/ }); VERSION_NAME=${arrIN[1]}
  • Build number: $(($PROJECT_BUILD_NUMBER + 14000))
  • Separate bundle IDs for staging (nl.tinq4u.tinq4u-app-staging) and production (nl.tinq4u.tinq4u-app)
  • Different entry points: lib/main.dart (staging) vs lib/main_prod.dart (production)
  • GitFlow branching model in use (based on audit finding)
  • jenkins/pipeline.groovy contains placeholder pipeline code (not actively used)
  • No references to Jenkins in codebase or documentation
  • Project uses Codemagic for CI/CD (evident from codemagic.yaml)

Risk Level: Medium Risk

Recommendation:

  • Immediate actions:
  • Migrate from GitFlow to trunk-based development workflow
  • Implement single tag approach: tag once, deploy to staging, then promote same tag to production after approval
  • Finish and merge all hanging changes from feature branches
  • Clean up unused CI/CD files (remove jenkins/ directory)
  • Short-term:
  • Implement deployment promotion pipeline: staging → production using same build artifact
  • Simplify branching: main/master as primary branch, short-lived feature branches
  • Add deployment notifications