From 2a2a54b948ddd90c9523b3a1bf059dd8d33c8758 Mon Sep 17 00:00:00 2001 From: Ariel De Los Santos Date: Tue, 25 Jun 2024 13:04:45 -0400 Subject: [PATCH] feat(#305172): add MobSF security scan on android build staging and prod --- build/azure-pipelines.yml | 30 ++++++ build/stage-build-security-android.yml | 43 ++++++++ build/steps-build-android.yml | 6 ++ build/templates/mobsf-android-scan.yml | 141 +++++++++++++++++++++++++ build/variables.yml | 6 ++ src/cli/CHANGELOG.md | 2 + 6 files changed, 228 insertions(+) create mode 100644 build/stage-build-security-android.yml create mode 100644 build/templates/mobsf-android-scan.yml diff --git a/build/azure-pipelines.yml b/build/azure-pipelines.yml index f576a1b..4cfbdef 100644 --- a/build/azure-pipelines.yml +++ b/build/azure-pipelines.yml @@ -106,6 +106,21 @@ stages: applicationEnvironment: Staging deploymentEnvironment: TestFlight +# MOBSF SECURITY SCAN STAGING +- stage: Security_Scan_Build_Staging + dependsOn: Build_Staging + jobs: + - template: stage-build-security-android.yml + parameters: + applicationEnvironment: Staging + androidKeyStoreFile: $(InternalKeystore) + androidVariableGroup: 'ApplicationTemplate.Distribution.Internal.Android' + firebaseJsonFile: $(InternalFirebaseJson) + firebaseOptionsDartFile: $(InternalFirebaseOptionsDart) + androidKeyPropertiesFile: $(InternalKeyProperties) + googleServicesJsonFile: $(InternalGoogleServicesJson) + enableSecurityScan: true + - stage: Build_Production dependsOn: Build_Staging condition: and(succeeded(), eq(variables['IsPullRequestBuild'], 'false')) @@ -138,6 +153,21 @@ stages: appCenterServiceConnectionName: $(AppCenterServiceConnection) appCenterDistributionGroup: $(AppCenterDistributionGroup) +# MOBSF SECURITY SCAN PRODUCTION +- stage: Security_Scan_Build_Production + dependsOn: Build_Production + jobs: + - template: stage-build-security-android.yml + parameters: + applicationEnvironment: Production + androidKeyStoreFile: $(GooglePlayKeystore) + androidKeyPropertiesFile: $(GooglePlayKeyProperties) + androidVariableGroup: 'ApplicationTemplate.Distribution.GooglePlay' + firebaseJsonFile: $(FirebaseJson) + firebaseOptionsDartFile: $(FirebaseOptionsDart) + googleServicesJsonFile: $(GoogleServicesJson) + enableSecurityScan: true + - stage: AppStore condition: and(succeeded(), eq(variables['IsPullRequestBuild'], 'false')) dependsOn: Build_Production diff --git a/build/stage-build-security-android.yml b/build/stage-build-security-android.yml new file mode 100644 index 0000000..2a1fda6 --- /dev/null +++ b/build/stage-build-security-android.yml @@ -0,0 +1,43 @@ +parameters: +- name: applicationEnvironment + type: string + default: '' +- name: androidKeyStoreFile + type: string + default: '' +- name: androidVariableGroup + type: string + default: '' +- name: artifactName + type: string + default: '' +- name: pathToSrc + type: string + default: '$(Build.SourcesDirectory)/src' +- name: androidKeyPropertiesFile + type: string + default: '' +- name: projectName + type: string + default: '$(ProjectName)' +- name: firebaseJsonFile + type: string +- name: firebaseOptionsDartFile + type: string +- name: googleServicesJsonFile + type: string +- name: enableSecurityScan + type: boolean + default: false + +jobs: + - job: OnLinux_Android_SecurityScan + condition: eq(${{parameters.enableSecurityScan}}, true) + dependsOn: [] + pool: + vmImage: $(ubuntuHostedAgentImage) + steps: + - template: templates/mobsf-android-scan.yml + parameters: + mobSfApiKey: '8181' + artifactName: '$(AndroidArtifactName)_${{ parameters.applicationEnvironment }}' \ No newline at end of file diff --git a/build/steps-build-android.yml b/build/steps-build-android.yml index 30600cc..84ae85c 100644 --- a/build/steps-build-android.yml +++ b/build/steps-build-android.yml @@ -14,6 +14,12 @@ parameters: type: string - name: googleServicesJsonFile type: string +- name: artifactName + type: string + default: '' +- name: applicationEnvironment + type: string + default: '' steps: #-if false diff --git a/build/templates/mobsf-android-scan.yml b/build/templates/mobsf-android-scan.yml new file mode 100644 index 0000000..da14beb --- /dev/null +++ b/build/templates/mobsf-android-scan.yml @@ -0,0 +1,141 @@ +parameters: +- name: mobSfApiKey + type: string + default: '8181' +- name: artifactName + type: string + default: '' + +steps: +- task: DownloadPipelineArtifact@1 + inputs: + buildType: 'current' + downloadType: 'single' + artifactName: "${{parameters.artifactName}}" + downloadPath: '$(System.ArtifactsDirectory)' + condition: succeeded() + +- task: DockerInstaller@0 + displayName: 'Install Docker' + inputs: + dockerVersion: $(DockerVersion) + condition: succeeded() + +- script: docker pull opensecurity/mobile-security-framework-mobsf:latest + displayName: 'Pull MobSF Docker Image' + condition: succeeded() + +- script: docker run -d -it --rm -e MOBSF_API_KEY='${{parameters.mobSfApiKey}}' -e DATA_UPLOAD_MAX_MEMORY_SIZE=209715200 -p 8000:8000 opensecurity/mobile-security-framework-mobsf:latest + displayName: 'Run MobSF Docker Image' + condition: succeeded() + +- script: ls -R "$(System.ArtifactsDirectory)" + displayName: 'List Downloaded Artifacts' + +- task: PowerShell@2 + displayName: 'Upload Android file to MobSF' + inputs: + targetType: 'inline' + script: | + $file = "$(System.ArtifactsDirectory)/app-release.$(aabFileExtension)" + Write-Host "Uploading file $file to MobSF..." + + # Check if the server is up and running + $serverIsRunning = $false + $retryCount = 0 + while (-not $serverIsRunning -and $retryCount -lt 10) { + $response = curl --url http://127.0.0.1:8000/api/v1/scans -H "Authorization: ${{parameters.mobSfApiKey}}" + if ($response.StatusCode -eq 200) { + Write-Host "MobSF server is up and running" + $serverIsRunning = $true + } else { + Write-Host "Waiting for the MobSF server to start..." + $retryCount++ + Start-Sleep -Seconds 5 + } + } + + $uploadResponse = curl -X POST -F "file=@$file;type=application/octet-stream" http://127.0.0.1:8000/api/v1/upload -H "Authorization: ${{parameters.mobSfApiKey}}" + $uploadResponseJson = $uploadResponse | ConvertFrom-Json + $hash = $uploadResponseJson.hash + echo "##vso[task.setvariable variable=fileHash]$hash" + Write-Host "Uploaded file hash: $hash" + Write-Host "Android file uploaded to MobSF" + condition: succeeded() + +- task: PowerShell@2 + displayName: 'Run MobSF Scan' + inputs: + targetType: 'inline' + script: | + Write-Host "MobSF Scan started" + $hash = "$(fileHash)" + $scanUrl = "http://127.0.0.1:8000/api/v1/scan" + Write-Host "Scanning Uploaded file hash: $hash" + $headers = @{ + "Authorization" = ${{parameters.mobSfApiKey}} + } + $scanBody = @{ + "scan_type" = "$(aabFileExtension)" + "hash" = $hash # use the hash from the upload response + } + $response = Invoke-RestMethod -Uri $scanUrl -Method Post -Headers $headers -Body $scanBody + Write-Host "Scan completed" + condition: succeeded() + +- task: PowerShell@2 + displayName: 'Download MobSF PDF report' + inputs: + targetType: 'inline' + script: | + Write-Host "Downloading MobSF PDF report..." + $hash = "$(fileHash)" + Write-Host "File hash: $hash" + $reportUrl = "http://127.0.0.1:8000/api/v1/download_pdf" + $headers = @{ + "Authorization" = "${{parameters.mobSfApiKey}}" + } + $reportBody = @{ + "hash" = $hash # use the hash from the upload response + } + $directoryPath = "${{parameters.artifactName}}/Android" + if (!(Test-Path -Path $directoryPath)) { + New-Item -ItemType Directory -Path $directoryPath | Out-Null + } + $pdfFilePath = "$directoryPath/report.pdf" + Invoke-WebRequest -Uri $reportUrl -Method Post -Headers $headers -Body $reportBody -OutFile $pdfFilePath + Write-Host "PDF report downloaded to $pdfFilePath" + condition: succeeded() + +- task: PowerShell@2 + displayName: 'Download MobSF Json report' + inputs: + targetType: 'inline' + script: | + Write-Host "Downloading MobSF Json report..." + $hash = "$(fileHash)" + Write-Host "File hash: $hash" + $reportUrl = "http://127.0.0.1:8000/api/v1/report_json" + $headers = @{ + "Authorization" = "${{parameters.mobSfApiKey}}" + } + $reportBody = @{ + "hash" = $hash # use the hash from the upload response + } + $reportResponse = Invoke-RestMethod -Uri $reportUrl -Method Post -Headers $headers -Body $reportBody + Write-Host "Response: $reportResponse" + $jsonFilePath = "${{parameters.artifactName}}/Android/Report.json" + $reportResponse | ConvertTo-Json | Out-File -FilePath $jsonFilePath + Write-Host "JSON report downloaded to $jsonFilePath" + condition: succeeded() + +- task: PublishBuildArtifacts@1 + displayName: 'Publish Artifact' + inputs: + PathtoPublish: '${{parameters.artifactName}}/Android' + ArtifactName: ${{parameters.artifactName}}_Security_Reports + publishLocation: 'Container' + +- task: PostBuildCleanup@3 + displayName: 'Post-Build Cleanup: Cleanup files to keep build server clean!' + condition: always() \ No newline at end of file diff --git a/build/variables.yml b/build/variables.yml index 32800f4..fc1d22e 100644 --- a/build/variables.yml +++ b/build/variables.yml @@ -32,6 +32,8 @@ InternalKeyProperties: com.nventive.internal.flutterapptemplate.key.properties # This is the internal key properties used for internal builds. GooglePlayKeystore: com.nventive.flutterapptemplate.jks # This is the official keystore used for Google Play. GooglePlayKeyProperties: com.nventive.flutterapptemplate.key.properties # This is the official key properties used for Google Play. + aabFileExtension: aab # This is the file extension for Android App Bundles. + apkFileExtension: apk # This is the file extension for Android APKs. # iOS. InternalProvisioningProfile: com.nventive.internal.flutterapptemplate.mobileprovision # This is the internal provisioning profile for internal builds. InternalExportOptions: com.nventive.internal.flutterapptemplate.exportOptions.plist # This is the export options file for internal builds. @@ -69,9 +71,13 @@ # Flutter version. FlutterVersion: '3.22.1' + # Docker version. + DockerVersion: '25.0.5' + # Virtual machine images. windowsHostedAgentImage: 'windows-2022' macOSHostedAgentImage: 'macOS-13' + ubuntuHostedAgentImage: 'ubuntu-latest' # Name of the folder where the artefacts will be placed. Variable used in build and release phases. # We make seperate folders so that releases can each download only the folder they need. diff --git a/src/cli/CHANGELOG.md b/src/cli/CHANGELOG.md index e62ab3a..1b16160 100644 --- a/src/cli/CHANGELOG.md +++ b/src/cli/CHANGELOG.md @@ -4,6 +4,8 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) Prefix your items with `(Template)` if the change is about the template and not the resulting application. +## 0.19.5 +- Configured MobSF security scan on Android for Stanging and Production builds ## 0.19.3 - Fix CI/CD artifact name for iOS.