Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
12d22a3
Fix release pipeline
meladRaouf Feb 19, 2025
2287bec
Capitalize build-environment and environment values in pipeline and r…
meladRaouf Feb 19, 2025
1c0aeb1
[MS-883] Fix forming RealmQuery from SubjectQuery's moduleId/attendantId
BurningAXE Feb 19, 2025
707c22f
Merge pull request #1109 from Simprints/fix-release-cicd
meladRaouf Feb 19, 2025
f31fbce
Merge pull request #1110 from Simprints/MS-883-SubjectQuery-type-in-R…
BurningAXE Feb 19, 2025
3117e4d
[MS-852] Add explicit class type to tokenized fields returned to CoSync
BurningAXE Feb 19, 2025
a204eac
[MS-852] Probe tokenization state of Raw values only
BurningAXE Feb 19, 2025
0184805
Merge pull request #1111 from Simprints/MS-852-CoSync-add-explicit-cl…
meladRaouf Feb 20, 2025
d31316b
MS-886 Run licence check only on the first opening of capture screen
luhmirin-s Feb 20, 2025
064db0f
Merge pull request #1112 from Simprints/hotfix/MS-886-unnecessary-lic…
luhmirin-s Feb 24, 2025
6f77dba
[MS-887] Refactor the filtering logic for `CommCare EnrolmentRecordCr…
meladRaouf Feb 24, 2025
a8fd21e
Merge pull request #1113 from Simprints/bugfix/MS-887-commcare-id
meladRaouf Feb 24, 2025
215b140
MS-885 Do not add verification success flag when threshold is not ena…
luhmirin-s Feb 24, 2025
64598b3
Merge pull request #1114 from Simprints/hotfix/MS-885-success-flag
luhmirin-s Feb 24, 2025
8186f4a
MS-882 Download privacy notice in the default language if current is …
luhmirin-s Feb 24, 2025
d5ef245
MS-882 Remove unnecessary suspend keyword
luhmirin-s Feb 24, 2025
8fcedb0
Merge pull request #1115 from Simprints/hotfix/MS-882-default-notice
luhmirin-s Feb 24, 2025
3c5a15f
[MS-894] Add a custom CoSync deserializer that accounts for past vers…
BurningAXE Feb 24, 2025
498b94b
Merge pull request #1116 from Simprints/MS-894-CoSync-enrolments-made…
BurningAXE Feb 25, 2025
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
18 changes: 4 additions & 14 deletions .github/workflows/pipeline-deploy-to-internal.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,9 @@ jobs:
build-internal-aab:
uses: ./.github/workflows/reusable-build-apk.yml
secrets: inherit
needs: get-version
with:
build-environment: internal
build-environment: Internal
version-name: ${{ needs.get-version.outputs.version-name }}

run-app-sweep:
Expand All @@ -28,21 +29,10 @@ jobs:

deploy-internal-build:
uses: ./.github/workflows/reusable-promote-artifact.yml
secrets: inherit
with:
deployment-track: internal
upload-artifact: ${{ needs.build-internal-aab.outputs.build-artifact }}
mapping-file: ${{ needs.build-internal-aab.outputs.optional-mapping-file }}
needs:
- build-internal-aab
- run-app-sweep

deploy-alpha-build:
uses: ./.github/workflows/reusable-promote-artifact.yml
with:
deployment-track: alpha
deployment-track: Internal
upload-artifact: ${{ needs.build-internal-aab.outputs.build-artifact }}
mapping-file: ${{ needs.build-internal-aab.outputs.optional-mapping-file }}
needs:
- build-internal-aab
- run-app-sweep
- deploy-internal-build
5 changes: 3 additions & 2 deletions .github/workflows/pipeline-deploy-to-staging.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,9 @@ jobs:
build-staging-apk:
uses: ./.github/workflows/reusable-build-apk.yml
secrets: inherit
needs: get-version
with:
build-environment: staging
build-environment: Staging
version-name: ${{ needs.get-version.outputs.version-name }}

deploy-to-firebase:
Expand All @@ -23,5 +24,5 @@ jobs:
needs:
- build-staging-apk
with:
build-environment: staging
build-environment: Staging
upload-artifact: ${{ needs.build-staging-apk.outputs.build-artifact }}
2 changes: 1 addition & 1 deletion .github/workflows/reusable-app-sweep.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ jobs:
name: App Sweep Security Scan
runs-on: ubuntu-latest
timeout-minutes: ${{ fromJSON(vars.JOB_TIMEOUT_MINUTES) }}
environment: internal
environment: Internal

steps:
- name: Download AAB artifact
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ jobs:
console_url="$(echo "$output" | grep -o 'https://console\.firebase\.google\.com[^[:space:]]*')"

# Expose console_url as a step output using $GITHUB_OUTPUT
echo "console_url=$console_url" >> "$GITHUB_OUTPUT"
echo "console_url=$console_url" >> $GITHUB_OUTPUT

- name: Distribution Summary
run: |
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/reusable-get-version-name.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ jobs:
run: |
if [ "${{ inputs.version-source }}" = "branch" ]; then
last_part="${GITHUB_REF_NAME##*/}"
echo "version-name=$last_part" >> "$GITHUB_OUTPUT"
echo "version-name=$last_part" >> $GITHUB_OUTPUT
elif [ "${{ inputs.version-source }}" = "internal" ]; then
VERSION_NAME=$(grep 'set("VERSION_NAME"' build-logic/build_properties.gradle.kts \
| sed -E 's/.*set\("VERSION_NAME",[[:space:]]*"([^"]+)".*/\1/')
Expand Down
72 changes: 42 additions & 30 deletions .github/workflows/reusable-promote-artifact.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,35 +46,47 @@ jobs:

- name: Set vars
run: |
if [ "${{inputs.deployment-track}}" == "Internal" ]; then
STATUS="completed"
USER_FRACTION=1.0
TRACK="qa"
elif [ "${{inputs.deployment-track}}" == "Alpha" ]; then
STATUS="completed"
USER_FRACTION=1.0
TRACK="alpha"
elif [ "${{inputs.deployment-track}}" == "Prod-25-Percent-Rollout" ]; then
STATUS="inProgress"
USER_FRACTION=0.25
TRACK="production"
elif [ "${{inputs.deployment-track}}" == "Prod-50-Percent-Rollout" ]; then
STATUS="inProgress"
USER_FRACTION=0.5
TRACK="production"
elif [ "${{inputs.deployment-track}}" == "Prod-100-Percent-Rollout" ]; then
STATUS="completed"
USER_FRACTION=1.0
TRACK="production"
if [ "${{ inputs.deployment-track }}" == "Internal" ]; then
echo "STATUS=completed" >> $GITHUB_ENV
echo "USER_FRACTION=1.0" >> $GITHUB_ENV
echo "TRACK=internal" >> $GITHUB_ENV
elif [ "${{ inputs.deployment-track }}" == "Alpha" ]; then
echo "STATUS=completed" >> $GITHUB_ENV
echo "USER_FRACTION=1.0" >> $GITHUB_ENV
echo "TRACK=alpha" >> $GITHUB_ENV
elif [ "${{ inputs.deployment-track }}" == "Prod-25-Percent-Rollout" ]; then
echo "STATUS=inProgress" >> $GITHUB_ENV
echo "USER_FRACTION=0.25" >> $GITHUB_ENV
echo "TRACK=production" >> $GITHUB_ENV
elif [ "${{ inputs.deployment-track }}" == "Prod-50-Percent-Rollout" ]; then
echo "STATUS=inProgress" >> $GITHUB_ENV
echo "USER_FRACTION=0.5" >> $GITHUB_ENV
echo "TRACK=production" >> $GITHUB_ENV
elif [ "${{ inputs.deployment-track }}" == "Prod-100-Percent-Rollout" ]; then
echo "STATUS=completed" >> $GITHUB_ENV
echo "USER_FRACTION=1.0" >> $GITHUB_ENV
echo "TRACK=production" >> $GITHUB_ENV
fi

- name: Publish app to track
uses: r0adkll/upload-google-play@v1
with:
serviceAccountJsonPlainText: ${{secrets.GOOGLE_API_KEY_JSON}}
packageName: com.simprints.id
releaseFiles: ${{ inputs.upload-artifact }}
track: $TRACK
status: $STATUS
userFraction: $USER_FRACTION
mappingFile: ${{ inputs.mapping-file }}

- name: Publish app (Completed Release)
if: env.STATUS == 'completed'
uses: r0adkll/upload-google-play@v1
with:
serviceAccountJsonPlainText: ${{ secrets.GOOGLE_API_KEY_JSON }}
packageName: com.simprints.id
releaseFiles: ${{ inputs.upload-artifact }}
track: ${{ env.TRACK }}
mappingFile: ${{ inputs.mapping-file }}

- name: Publish app (Rollout Release)
if: env.STATUS == 'inProgress'
uses: r0adkll/upload-google-play@v1
with:
serviceAccountJsonPlainText: ${{ secrets.GOOGLE_API_KEY_JSON }}
packageName: com.simprints.id
releaseFiles: ${{ inputs.upload-artifact }}
track: ${{ env.TRACK }}
status: ${{ env.STATUS }}
userFraction: ${{ env.USER_FRACTION }}
mappingFile: ${{ inputs.mapping-file }}
9 changes: 8 additions & 1 deletion .github/workflows/reusable-sonar-scan.yml
Original file line number Diff line number Diff line change
Expand Up @@ -69,4 +69,11 @@ jobs:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
./gradlew sonar -Dsonar.qualitygate.wait=true -Dsonar.qualitygate.timeout=3600 --info
# Check if the event is a pull request
if [ "${{ github.event_name }}" == "pull_request" ]; then
# Run SonarQube scan without branch name param as sonarqube will detect PR branch
./gradlew sonar -Dsonar.qualitygate.wait=true -Dsonar.qualitygate.timeout=3600 --info
else
# Run SonarQube scan with branch name param
./gradlew sonar -Dsonar.qualitygate.wait=true -Dsonar.qualitygate.timeout=3600 -Dsonar.branch.name=${{ github.ref_name }} --info
fi
2 changes: 1 addition & 1 deletion build-logic/build_properties.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ extra.apply {
* Dev version >= 2024.2.2 is required for float quality thresholds
* Dev version >= 2024.3.0 is required to receive configuration ID
*/
set("VERSION_NAME", "2024.3.0")
set("VERSION_NAME", "2025.1.0")

/**
* Build type. The version code describes which build type was used for the build.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ import com.simprints.face.capture.usecases.SaveFaceImageUseCase
import com.simprints.face.capture.usecases.SimpleCaptureEventReporter
import com.simprints.face.infra.biosdkresolver.ResolveFaceBioSdkUseCase
import com.simprints.infra.authstore.AuthStore
import com.simprints.infra.config.store.models.experimental
import com.simprints.infra.config.sync.ConfigManager
import com.simprints.infra.license.LicenseRepository
import com.simprints.infra.license.LicenseStatus
Expand Down Expand Up @@ -56,6 +55,7 @@ internal class FaceCaptureViewModel @Inject constructor(
// Updated in live feedback screen
var attemptNumber: Int = 0
var samplesToCapture = 1
var initialised = false

var shouldCheckCameraPermissions = AtomicBoolean(true)

Expand Down Expand Up @@ -90,6 +90,11 @@ internal class FaceCaptureViewModel @Inject constructor(
}

fun initFaceBioSdk(activity: Activity) = viewModelScope.launch {
if (initialised) {
Simber.i("Face bio SDK already initialised", tag = FACE_CAPTURE)
return@launch
}

Simber.i("Starting face capture flow", tag = FACE_CAPTURE)

val licenseVendor = Vendor.RankOne
Expand Down Expand Up @@ -124,10 +129,9 @@ internal class FaceCaptureViewModel @Inject constructor(
saveLicenseCheckEvent(licenseVendor, licenseStatus)
}

fun setupAutoCapture() =
viewModelScope.launch {
_isAutoCaptureEnabled.postValue(isUsingAutoCapture())
}
fun setupAutoCapture() = viewModelScope.launch {
_isAutoCaptureEnabled.postValue(isUsingAutoCapture())
}

private suspend fun initialize(
activity: Activity,
Expand All @@ -139,6 +143,7 @@ internal class FaceCaptureViewModel @Inject constructor(
// This is should reported as an error
return LicenseStatus.ERROR
}
initialised = true
return LicenseStatus.VALID
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import com.simprints.face.capture.usecases.SimpleCaptureEventReporter
import com.simprints.face.infra.basebiosdk.initialization.FaceBioSdkInitializer
import com.simprints.infra.authstore.AuthStore
import com.simprints.infra.config.store.models.FaceConfiguration.ImageSavingStrategy
import com.simprints.infra.config.store.models.experimental
import com.simprints.infra.config.sync.ConfigManager
import com.simprints.infra.license.LicenseRepository
import com.simprints.infra.license.LicenseStatus
Expand Down Expand Up @@ -161,7 +160,7 @@ class FaceCaptureViewModelTest {
}

@Test
fun `test initFaceBioSdk should initialize faceBioSdk`() {
fun `test initFaceBioSdk should initialize faceBioSdk only once`() {
// Given
val license = "license"
every { faceBioSdkInitializer.tryInitWithLicense(any(), license) } returns true
Expand All @@ -173,8 +172,11 @@ class FaceCaptureViewModelTest {

// When
viewModel.initFaceBioSdk(mockk())
viewModel.initFaceBioSdk(mockk())
viewModel.initFaceBioSdk(mockk())

// Then
coVerify { faceBioSdkInitializer.tryInitWithLicense(any(), license) }
coVerify(exactly = 1) { faceBioSdkInitializer.tryInitWithLicense(any(), license) }
assertThat(licenseStatusSlot.captured).isEqualTo(LicenseStatus.VALID)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,8 @@ internal class LibSimprintsResponseMapper @Inject constructor() {
guid = response.matchResult.guid,
),
)
putBoolean(Constants.SIMPRINTS_VERIFICATION_SUCCESS, response.matchResult.verificationSuccess == true)
response.matchResult.verificationSuccess
?.let { putBoolean(Constants.SIMPRINTS_VERIFICATION_SUCCESS, it) }
}

else -> putString(
Expand All @@ -83,7 +84,7 @@ internal class LibSimprintsResponseMapper @Inject constructor() {
guid = response.matchResult.guid,
confidence = response.matchResult.confidenceScore.toFloat(),
confidenceBand = ConfidenceBand.valueOf(response.matchResult.matchConfidence.name),
isSuccess = response.matchResult.verificationSuccess == true,
isSuccess = response.matchResult.verificationSuccess,
).toJson(),
)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
package com.simprints.feature.clientapi.usecases

import com.fasterxml.jackson.databind.module.SimpleModule
import com.simprints.core.domain.tokenization.TokenizableString
import com.simprints.core.domain.tokenization.serialization.TokenizationClassNameDeserializer
import com.simprints.core.domain.tokenization.serialization.TokenizationClassNameSerializer
import com.simprints.core.tools.json.JsonHelper
import com.simprints.core.tools.utils.EncodingUtils
import com.simprints.infra.config.store.models.canCoSyncAllData
Expand Down Expand Up @@ -34,7 +38,7 @@ internal class GetEnrolmentCreationEventForSubjectUseCase @Inject constructor(
?.fromSubjectToEnrolmentCreationEvent()
?: return null

return jsonHelper.toJson(CoSyncEnrolmentRecordEvents(listOf(recordCreationEvent)))
return jsonHelper.toJson(CoSyncEnrolmentRecordEvents(listOf(recordCreationEvent)), coSyncSerializationModule)
}

private fun Subject.fromSubjectToEnrolmentCreationEvent() = EnrolmentRecordCreationEvent(
Expand All @@ -44,4 +48,11 @@ internal class GetEnrolmentCreationEventForSubjectUseCase @Inject constructor(
attendantId,
EnrolmentRecordCreationEvent.buildBiometricReferences(fingerprintSamples, faceSamples, encoder),
)

companion object {
val coSyncSerializationModule = SimpleModule().apply {
addSerializer(TokenizableString::class.java, TokenizationClassNameSerializer())
addDeserializer(TokenizableString::class.java, TokenizationClassNameDeserializer())
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ class LibSimprintsResponseMapperTest {
assertThat(extraVerification?.tier).isEqualTo(LegacyTier.TIER_1)
assertThat(extraVerification?.getConfidence()).isEqualTo(50)
assertThat(extras.getBoolean(Constants.SIMPRINTS_BIOMETRICS_COMPLETE_CHECK)).isTrue()
assertThat(extras.getBoolean(Constants.SIMPRINTS_VERIFICATION_SUCCESS)).isFalse() // Default value
assertThat(extras.keySet()).doesNotContain(Constants.SIMPRINTS_VERIFICATION_SUCCESS)
}

@Test
Expand All @@ -179,6 +179,7 @@ class LibSimprintsResponseMapperTest {
assertThat(extraVerification?.tier).isEqualTo(LegacyTier.TIER_1)
assertThat(extraVerification?.getConfidence()).isEqualTo(50)
assertThat(extras.getBoolean(Constants.SIMPRINTS_BIOMETRICS_COMPLETE_CHECK)).isTrue()
assertThat(extras.keySet()).contains(Constants.SIMPRINTS_VERIFICATION_SUCCESS)
assertThat(extras.getBoolean(Constants.SIMPRINTS_VERIFICATION_SUCCESS)).isEqualTo(false)
}

Expand All @@ -204,7 +205,6 @@ class LibSimprintsResponseMapperTest {
assertThat(extraVerification?.guid).isEqualTo("guid")
assertThat(extraVerification?.tier).isEqualTo(LegacyTier.TIER_1)
assertThat(extraVerification?.getConfidence()).isEqualTo(50)
// assertThat(extraVerification?.isSuccess).isTrue()
assertThat(extras.getBoolean(Constants.SIMPRINTS_BIOMETRICS_COMPLETE_CHECK)).isTrue()
assertThat(extras.getBoolean(Constants.SIMPRINTS_VERIFICATION_SUCCESS)).isTrue()
}
Expand Down Expand Up @@ -235,6 +235,32 @@ class LibSimprintsResponseMapperTest {
assertThat(extras.getBoolean(Constants.SIMPRINTS_BIOMETRICS_COMPLETE_CHECK)).isTrue()
}

@Test
fun `correctly maps verify response without success after LibSimprints refactoring`() {
val extras = mapper(
ActionResponse.VerifyActionResponse(
actionIdentifier = VerifyActionFactory
.getIdentifier()
.copy(contractVersion = VersionsList.INITIAL_REWORK),
sessionId = "sessionId",
matchResult = AppMatchResult(
guid = "guid",
confidenceScore = 50,
matchConfidence = AppMatchConfidence.HIGH,
verificationSuccess = null,
),
),
)

assertThat(extras.getString(Constants.SIMPRINTS_SESSION_ID)).isEqualTo("sessionId")
assertThat(extras.getString(Constants.SIMPRINTS_VERIFICATION)).isEqualTo(
"""
{"guid":"guid","confidenceBand":"HIGH","confidence":50}
""".trimIndent(),
)
assertThat(extras.getBoolean(Constants.SIMPRINTS_BIOMETRICS_COMPLETE_CHECK)).isTrue()
}

@Test
fun `correctly maps exit form response`() {
val extras = mapper(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ class GetEnrolmentCreationEventForSubjectUseCaseTest {
val result = useCase("projectId", "subjectId")

coVerify { enrolmentRecordRepository.load(any()) }
coVerify { jsonHelper.toJson(any()) }
coVerify { jsonHelper.toJson(any(), any()) }
assertThat(result).isNotNull()
}
}
Loading