@dailephd/my-dev-kit-lab 0.3.4 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -287
- package/dist/scripts/security/validate.js +210 -70
- package/dist/src/audits/codeRot/detectors/architectureDriftDetector.js +5 -2
- package/dist/src/audits/codeRot/detectors/securityValidationAssumptionRotDetector.js +5 -2
- package/dist/src/mobile/android/advancedSecurity/backupConfiguration/analyzeBackupConfiguration.js +300 -0
- package/dist/src/mobile/android/advancedSecurity/backupConfiguration/checkResult.js +41 -0
- package/dist/src/mobile/android/advancedSecurity/backupConfiguration/index.js +8 -0
- package/dist/src/mobile/android/advancedSecurity/backupConfiguration/manifestEvidence.js +102 -0
- package/dist/src/mobile/android/advancedSecurity/backupConfiguration/parseBackupRules.js +110 -0
- package/dist/src/mobile/android/advancedSecurity/backupConfiguration/types.js +27 -0
- package/dist/src/mobile/android/advancedSecurity/candidateEvidence.js +50 -0
- package/dist/src/mobile/android/advancedSecurity/clipboard/analyzeClipboardSecurity.js +166 -0
- package/dist/src/mobile/android/advancedSecurity/clipboard/checkResult.js +74 -0
- package/dist/src/mobile/android/advancedSecurity/clipboard/collectClipboardEvidence.js +82 -0
- package/dist/src/mobile/android/advancedSecurity/clipboard/index.js +1 -0
- package/dist/src/mobile/android/advancedSecurity/clipboard/types.js +1 -0
- package/dist/src/mobile/android/advancedSecurity/externalTools/androidLint/checkResult.js +255 -0
- package/dist/src/mobile/android/advancedSecurity/externalTools/androidLint/index.js +1 -0
- package/dist/src/mobile/android/advancedSecurity/externalTools/androidLint/parseLintSarif.js +37 -0
- package/dist/src/mobile/android/advancedSecurity/externalTools/androidLint/parseLintXml.js +36 -0
- package/dist/src/mobile/android/advancedSecurity/externalTools/artifacts.js +95 -0
- package/dist/src/mobile/android/advancedSecurity/externalTools/boundedOutput.js +33 -0
- package/dist/src/mobile/android/advancedSecurity/externalTools/dependencyCheck/checkResult.js +173 -0
- package/dist/src/mobile/android/advancedSecurity/externalTools/dependencyCheck/command.js +33 -0
- package/dist/src/mobile/android/advancedSecurity/externalTools/dependencyCheck/index.js +1 -0
- package/dist/src/mobile/android/advancedSecurity/externalTools/dependencyCheck/parseDependencyCheckJson.js +133 -0
- package/dist/src/mobile/android/advancedSecurity/externalTools/discoverExecutable.js +13 -0
- package/dist/src/mobile/android/advancedSecurity/externalTools/index.js +8 -0
- package/dist/src/mobile/android/advancedSecurity/externalTools/minimalEnvironment.js +26 -0
- package/dist/src/mobile/android/advancedSecurity/externalTools/mutation.js +77 -0
- package/dist/src/mobile/android/advancedSecurity/externalTools/osv/checkResult.js +161 -0
- package/dist/src/mobile/android/advancedSecurity/externalTools/osv/command.js +25 -0
- package/dist/src/mobile/android/advancedSecurity/externalTools/osv/index.js +1 -0
- package/dist/src/mobile/android/advancedSecurity/externalTools/osv/parseOsvJson.js +136 -0
- package/dist/src/mobile/android/advancedSecurity/externalTools/runBoundedExternalTool.js +51 -0
- package/dist/src/mobile/android/advancedSecurity/externalTools/runRequestedAndroidExternalTools.js +54 -0
- package/dist/src/mobile/android/advancedSecurity/externalTools/semgrep/checkResult.js +170 -0
- package/dist/src/mobile/android/advancedSecurity/externalTools/semgrep/command.js +28 -0
- package/dist/src/mobile/android/advancedSecurity/externalTools/semgrep/index.js +2 -0
- package/dist/src/mobile/android/advancedSecurity/externalTools/semgrep/parseSemgrepJson.js +141 -0
- package/dist/src/mobile/android/advancedSecurity/externalTools/semgrep/rules.js +105 -0
- package/dist/src/mobile/android/advancedSecurity/externalTools/types.js +107 -0
- package/dist/src/mobile/android/advancedSecurity/fileProvider/checkResult.js +188 -0
- package/dist/src/mobile/android/advancedSecurity/fileProvider/index.js +1 -0
- package/dist/src/mobile/android/advancedSecurity/firebaseGoogle/analyzeFirebaseGoogleServices.js +197 -0
- package/dist/src/mobile/android/advancedSecurity/firebaseGoogle/checkResult.js +77 -0
- package/dist/src/mobile/android/advancedSecurity/firebaseGoogle/collectFirebaseServiceEvidence.js +193 -0
- package/dist/src/mobile/android/advancedSecurity/firebaseGoogle/discoverFirebaseArtifacts.js +128 -0
- package/dist/src/mobile/android/advancedSecurity/firebaseGoogle/index.js +1 -0
- package/dist/src/mobile/android/advancedSecurity/firebaseGoogle/parseDatabaseRules.js +55 -0
- package/dist/src/mobile/android/advancedSecurity/firebaseGoogle/parseFirebaseConfig.js +75 -0
- package/dist/src/mobile/android/advancedSecurity/firebaseGoogle/parseFirestoreStorageRules.js +88 -0
- package/dist/src/mobile/android/advancedSecurity/firebaseGoogle/parseGoogleServicesConfig.js +55 -0
- package/dist/src/mobile/android/advancedSecurity/firebaseGoogle/types.js +6 -0
- package/dist/src/mobile/android/advancedSecurity/networkSecurity/analyzeNetworkSecurity.js +394 -0
- package/dist/src/mobile/android/advancedSecurity/networkSecurity/checkResult.js +47 -0
- package/dist/src/mobile/android/advancedSecurity/networkSecurity/deriveEffectiveNetworkPolicy.js +52 -0
- package/dist/src/mobile/android/advancedSecurity/networkSecurity/index.js +14 -0
- package/dist/src/mobile/android/advancedSecurity/networkSecurity/manifestEvidence.js +109 -0
- package/dist/src/mobile/android/advancedSecurity/networkSecurity/parseNetworkSecurityConfig.js +186 -0
- package/dist/src/mobile/android/advancedSecurity/networkSecurity/types.js +1 -0
- package/dist/src/mobile/android/advancedSecurity/ordering.js +44 -0
- package/dist/src/mobile/android/advancedSecurity/redaction.js +54 -0
- package/dist/src/mobile/android/advancedSecurity/releaseConfiguration/analyzeReleaseConfiguration.js +221 -0
- package/dist/src/mobile/android/advancedSecurity/releaseConfiguration/checkResult.js +39 -0
- package/dist/src/mobile/android/advancedSecurity/releaseConfiguration/index.js +7 -0
- package/dist/src/mobile/android/advancedSecurity/releaseConfiguration/manifestEvidence.js +19 -0
- package/dist/src/mobile/android/advancedSecurity/resourceReference.js +69 -0
- package/dist/src/mobile/android/advancedSecurity/resourceResolution.js +118 -0
- package/dist/src/mobile/android/advancedSecurity/ruleIds.js +141 -0
- package/dist/src/mobile/android/advancedSecurity/secretCandidates/analyzeSecretCandidates.js +116 -0
- package/dist/src/mobile/android/advancedSecurity/secretCandidates/checkResult.js +80 -0
- package/dist/src/mobile/android/advancedSecurity/secretCandidates/discoverSecretSourceFiles.js +152 -0
- package/dist/src/mobile/android/advancedSecurity/secretCandidates/index.js +9 -0
- package/dist/src/mobile/android/advancedSecurity/secretCandidates/matchSecretCandidates.js +136 -0
- package/dist/src/mobile/android/advancedSecurity/secretCandidates/suppressValue.js +61 -0
- package/dist/src/mobile/android/advancedSecurity/secretCandidates/types.js +11 -0
- package/dist/src/mobile/android/advancedSecurity/sensitiveCategories.js +34 -0
- package/dist/src/mobile/android/advancedSecurity/sensitiveData/classifyDirectExpression.js +99 -0
- package/dist/src/mobile/android/advancedSecurity/sensitiveData/classifySensitiveIdentifier.js +111 -0
- package/dist/src/mobile/android/advancedSecurity/sensitiveData/index.js +3 -0
- package/dist/src/mobile/android/advancedSecurity/sensitiveData/localSourceContext.js +90 -0
- package/dist/src/mobile/android/advancedSecurity/sensitiveData/splitArguments.js +59 -0
- package/dist/src/mobile/android/advancedSecurity/sensitiveLogging/analyzeSensitiveLogging.js +117 -0
- package/dist/src/mobile/android/advancedSecurity/sensitiveLogging/checkResult.js +74 -0
- package/dist/src/mobile/android/advancedSecurity/sensitiveLogging/collectLoggingEvidence.js +87 -0
- package/dist/src/mobile/android/advancedSecurity/sensitiveLogging/index.js +1 -0
- package/dist/src/mobile/android/advancedSecurity/sensitiveLogging/types.js +1 -0
- package/dist/src/mobile/android/advancedSecurity/sensitiveStorage/analyzeSensitiveStorage.js +182 -0
- package/dist/src/mobile/android/advancedSecurity/sensitiveStorage/checkResult.js +74 -0
- package/dist/src/mobile/android/advancedSecurity/sensitiveStorage/collectStorageEvidence.js +109 -0
- package/dist/src/mobile/android/advancedSecurity/sensitiveStorage/index.js +1 -0
- package/dist/src/mobile/android/advancedSecurity/sensitiveStorage/types.js +4 -0
- package/dist/src/mobile/android/advancedSecurity/signingConfiguration/analyzeSigningConfiguration.js +270 -0
- package/dist/src/mobile/android/advancedSecurity/signingConfiguration/checkResult.js +119 -0
- package/dist/src/mobile/android/advancedSecurity/signingConfiguration/discoverKeystoreCandidates.js +55 -0
- package/dist/src/mobile/android/advancedSecurity/signingConfiguration/extractSigningConfigurations.js +81 -0
- package/dist/src/mobile/android/advancedSecurity/signingConfiguration/index.js +8 -0
- package/dist/src/mobile/android/advancedSecurity/signingConfiguration/types.js +20 -0
- package/dist/src/mobile/android/advancedSecurity/sourceLocation.js +15 -0
- package/dist/src/mobile/android/advancedSecurity/webview/checkResult.js +210 -0
- package/dist/src/mobile/android/advancedSecurity/webview/index.js +1 -0
- package/dist/src/mobile/android/audit/androidFinding.js +68 -0
- package/dist/src/mobile/android/audit/checkResultBuilder.js +97 -0
- package/dist/src/mobile/android/audit/deepLinkAudit.js +183 -0
- package/dist/src/mobile/android/audit/exportedComponentAudit.js +183 -0
- package/dist/src/mobile/android/audit/intentFilterAudit.js +128 -0
- package/dist/src/mobile/android/audit/permissionAudit.js +142 -0
- package/dist/src/mobile/android/detect/androidTargetDetection.js +18 -0
- package/dist/src/mobile/android/detect/buildFileEvidence.js +36 -0
- package/dist/src/mobile/android/detect/classify.js +150 -0
- package/dist/src/mobile/android/detect/detectAndroidProject.js +252 -0
- package/dist/src/mobile/android/detect/settingsModules.js +60 -0
- package/dist/src/mobile/android/detect/sourceEvidence.js +92 -0
- package/dist/src/mobile/android/detect/traversal.js +79 -0
- package/dist/src/mobile/android/detect/versionCatalogEvidence.js +37 -0
- package/dist/src/mobile/android/detection.js +28 -0
- package/dist/src/mobile/android/gradle/gradleMetadataCheckResult.js +120 -0
- package/dist/src/mobile/android/gradle/moduleMetadataExtractor.js +243 -0
- package/dist/src/mobile/android/gradle/pluginVersionExtractor.js +40 -0
- package/dist/src/mobile/android/gradle/readAndroidGradleMetadata.js +210 -0
- package/dist/src/mobile/android/gradle/releaseMetadataSummary.js +64 -0
- package/dist/src/mobile/android/gradle/settingsMetadata.js +20 -0
- package/dist/src/mobile/android/gradle/types.js +1 -0
- package/dist/src/mobile/android/gradle/validate/executor.js +9 -0
- package/dist/src/mobile/android/gradle/validate/operationCheckResult.js +99 -0
- package/dist/src/mobile/android/gradle/validate/operations.js +68 -0
- package/dist/src/mobile/android/gradle/validate/planner.js +49 -0
- package/dist/src/mobile/android/gradle/validate/runOptionalGradleValidation.js +113 -0
- package/dist/src/mobile/android/gradle/validate/targetMutation.js +45 -0
- package/dist/src/mobile/android/gradle/validate/taskListParser.js +24 -0
- package/dist/src/mobile/android/gradle/versionCatalogMetadata.js +94 -0
- package/dist/src/mobile/android/gradle/wrapperMetadata.js +32 -0
- package/dist/src/mobile/android/manifest/parseAndroidManifest.js +364 -0
- package/dist/src/mobile/android/manifest/types.js +29 -0
- package/dist/src/mobile/android/manifest/xml/parseXml.js +329 -0
- package/dist/src/mobile/android/profile.js +29 -0
- package/dist/src/mobile/android/report/model.js +135 -0
- package/dist/src/mobile/android/report/renderAndroidReport.js +286 -0
- package/dist/src/mobile/android/report/writeAndroidReportFiles.js +23 -0
- package/dist/src/mobile/android/targetMetadata.js +27 -0
- package/dist/src/mobile/android/validate/androidVerdict.js +248 -0
- package/dist/src/mobile/android/validate/detectionAndImmutabilityCheckResults.js +177 -0
- package/dist/src/mobile/android/validate/playReadinessChecklist.js +145 -0
- package/dist/src/mobile/android/validate/validateAndroidTarget.js +315 -0
- package/dist/src/mobile/android/validation/checkResult.js +58 -0
- package/dist/src/mobile/android/validation/result.js +25 -0
- package/dist/src/mobile/index.js +42 -0
- package/dist/src/mobile/types.js +27 -0
- package/dist/src/securityValidation/attackScenarios/attackProfile.js +2 -0
- package/dist/src/securityValidation/attackScenarios/profiles/androidProfile.js +20 -0
- package/dist/src/securityValidation/commandRunner.js +10 -1
- package/dist/src/securityValidation/validate/cliOptions.js +92 -2
- package/package.json +2 -1
- package/tests/fixtures/android/advanced-security-fixtures/backup-configuration/module-a/src/debug/res/xml/ambiguous_backup_rules.xml +4 -0
- package/tests/fixtures/android/advanced-security-fixtures/backup-configuration/module-a/src/main/res/xml/ambiguous_backup_rules.xml +4 -0
- package/tests/fixtures/android/advanced-security-fixtures/backup-configuration/module-a/src/main/res/xml/backup_rules.xml +5 -0
- package/tests/fixtures/android/advanced-security-fixtures/backup-configuration/module-a/src/main/res/xml/broad_backup_rules.xml +4 -0
- package/tests/fixtures/android/advanced-security-fixtures/backup-configuration/module-a/src/main/res/xml/data_extraction_rules.xml +10 -0
- package/tests/fixtures/android/advanced-security-fixtures/backup-configuration/module-a/src/main/res/xml/unsupported_domain_rules.xml +4 -0
- package/tests/fixtures/android/advanced-security-fixtures/backup-configuration/module-b/src/main/res/xml/malformed_backup_rules.xml +4 -0
- package/tests/fixtures/android/advanced-security-fixtures/backup-configuration/module-b/src/main/res/xml/unsupported_root.xml +4 -0
- package/tests/fixtures/android/advanced-security-fixtures/network-security/module-a/src/debug/res/xml/ambiguous_config.xml +4 -0
- package/tests/fixtures/android/advanced-security-fixtures/network-security/module-a/src/main/res/xml/ambiguous_config.xml +4 -0
- package/tests/fixtures/android/advanced-security-fixtures/network-security/module-a/src/main/res/xml/base_cleartext_false.xml +8 -0
- package/tests/fixtures/android/advanced-security-fixtures/network-security/module-a/src/main/res/xml/broad_and_duplicate_domains.xml +8 -0
- package/tests/fixtures/android/advanced-security-fixtures/network-security/module-a/src/main/res/xml/empty_domain.xml +6 -0
- package/tests/fixtures/android/advanced-security-fixtures/network-security/module-a/src/main/res/xml/malformed_pin.xml +11 -0
- package/tests/fixtures/android/advanced-security-fixtures/network-security/module-a/src/main/res/xml/network_security_config.xml +26 -0
- package/tests/fixtures/android/advanced-security-fixtures/network-security/module-b/src/main/res/xml/malformed_network_security_config.xml +6 -0
- package/tests/fixtures/android/advanced-security-fixtures/network-security/module-b/src/main/res/xml/unsupported_root.xml +4 -0
- package/tests/fixtures/android/advanced-security-fixtures/release-configuration/groovy-release-debuggable-dynamic.gradle +7 -0
- package/tests/fixtures/android/advanced-security-fixtures/release-configuration/groovy-release-debuggable-false.gradle +9 -0
- package/tests/fixtures/android/advanced-security-fixtures/release-configuration/groovy-release-debuggable-true.gradle +13 -0
- package/tests/fixtures/android/advanced-security-fixtures/release-configuration/kotlin-release-debuggable-false.gradle.kts +7 -0
- package/tests/fixtures/android/advanced-security-fixtures/release-configuration/kotlin-release-debuggable-true.gradle.kts +10 -0
- package/tests/fixtures/android/advanced-security-fixtures/release-configuration/missing-release-build-type.gradle.kts +7 -0
- package/tests/fixtures/android/advanced-security-fixtures/resource-resolution/module-a/src/debug/res/xml/network_security_config.xml +8 -0
- package/tests/fixtures/android/advanced-security-fixtures/resource-resolution/module-a/src/main/res/xml/backup_rules.xml +4 -0
- package/tests/fixtures/android/advanced-security-fixtures/resource-resolution/module-a/src/main/res/xml/network_security_config.xml +8 -0
- package/tests/fixtures/android/advanced-security-fixtures/resource-resolution/module-b/src/main/res/xml/malformed_network_security_config.xml +7 -0
- package/tests/fixtures/android/advanced-security-fixtures/secret-candidates/SampleActivity.java +8 -0
- package/tests/fixtures/android/advanced-security-fixtures/secret-candidates/SampleActivity.kt +9 -0
- package/tests/fixtures/android/advanced-security-fixtures/secret-candidates/build.gradle +11 -0
- package/tests/fixtures/android/advanced-security-fixtures/secret-candidates/build.gradle.kts +11 -0
- package/tests/fixtures/android/advanced-security-fixtures/secret-candidates/google-services.json +16 -0
- package/tests/fixtures/android/advanced-security-fixtures/secret-candidates/local.properties +3 -0
- package/tests/fixtures/android/advanced-security-fixtures/secret-candidates-bounds/module/binary.properties +0 -0
- package/tests/fixtures/android/advanced-security-fixtures/secret-candidates-bounds/module/oversized.json +1 -0
- package/tests/fixtures/android/advanced-security-fixtures/signing-configuration/app/fake-release-keystore.jks +1 -0
- package/tests/fixtures/android/advanced-security-fixtures/signing-configuration/build/generated-fake.keystore +1 -0
- package/tests/fixtures/android/compose-app/app/build.gradle.kts +21 -0
- package/tests/fixtures/android/compose-app/app/src/main/AndroidManifest.xml +22 -0
- package/tests/fixtures/android/compose-app/app/src/main/java/com/example/composeapp/MainActivity.kt +11 -0
- package/tests/fixtures/android/compose-app/build.gradle.kts +4 -0
- package/tests/fixtures/android/compose-app/gradle/wrapper/gradle-wrapper.properties +4 -0
- package/tests/fixtures/android/compose-app/settings.gradle.kts +2 -0
- package/tests/fixtures/android/gradle-metadata-fixtures/catalog-only-plugin/build.gradle.kts +3 -0
- package/tests/fixtures/android/gradle-metadata-fixtures/catalog-only-plugin/gradle/libs.versions.toml +5 -0
- package/tests/fixtures/android/gradle-metadata-fixtures/comment-safety.gradle.kts +21 -0
- package/tests/fixtures/android/gradle-metadata-fixtures/dynamic-values.gradle.kts +17 -0
- package/tests/fixtures/android/gradle-metadata-fixtures/groovy-literal.gradle +23 -0
- package/tests/fixtures/android/gradle-metadata-fixtures/wrapper-malformed.properties +4 -0
- package/tests/fixtures/android/gradle-metadata-fixtures/wrapper-missing-url.properties +3 -0
- package/tests/fixtures/android/gradle-metadata-fixtures/wrapper-with-checksum.properties +5 -0
- package/tests/fixtures/android/java-app/app/build.gradle +16 -0
- package/tests/fixtures/android/java-app/app/src/main/AndroidManifest.xml +19 -0
- package/tests/fixtures/android/java-app/app/src/main/java/com/example/javaapp/MainActivity.java +4 -0
- package/tests/fixtures/android/java-app/build.gradle +3 -0
- package/tests/fixtures/android/java-app/gradle/wrapper/gradle-wrapper.properties +4 -0
- package/tests/fixtures/android/java-app/settings.gradle +2 -0
- package/tests/fixtures/android/library/build.gradle.kts +3 -0
- package/tests/fixtures/android/library/gradle/wrapper/gradle-wrapper.properties +4 -0
- package/tests/fixtures/android/library/mylibrary/build.gradle.kts +13 -0
- package/tests/fixtures/android/library/mylibrary/src/main/AndroidManifest.xml +2 -0
- package/tests/fixtures/android/library/settings.gradle.kts +2 -0
- package/tests/fixtures/android/manifest-audit-fixtures/incomplete-intent-filter.xml +14 -0
- package/tests/fixtures/android/manifest-audit-fixtures/malformed-exported.xml +10 -0
- package/tests/fixtures/android/manifest-audit-fixtures/malformed.xml +5 -0
- package/tests/fixtures/android/manifest-audit-fixtures/missing-application.xml +7 -0
- package/tests/fixtures/android/manifest-audit-fixtures/missing-component-name.xml +11 -0
- package/tests/fixtures/android/manifest-audit-fixtures/permission-coverage.xml +29 -0
- package/tests/fixtures/android/manifest-audit-fixtures/risky-components.xml +62 -0
- package/tests/fixtures/android/manifest-audit-fixtures/risky-deep-links.xml +45 -0
- package/tests/fixtures/android/manifest-audit-fixtures/unresolved-placeholder.xml +14 -0
- package/tests/fixtures/android/manifest-audit-fixtures/unusual-namespace-prefix.xml +11 -0
- package/tests/fixtures/android/multi-module/app/build.gradle.kts +22 -0
- package/tests/fixtures/android/multi-module/app/src/androidTest/java/com/example/multimodule/app/ExampleInstrumentedTest.kt +3 -0
- package/tests/fixtures/android/multi-module/app/src/main/AndroidManifest.xml +11 -0
- package/tests/fixtures/android/multi-module/app/src/test/java/com/example/multimodule/app/ExampleUnitTest.kt +3 -0
- package/tests/fixtures/android/multi-module/build.gradle.kts +5 -0
- package/tests/fixtures/android/multi-module/core/build.gradle.kts +14 -0
- package/tests/fixtures/android/multi-module/core/src/main/AndroidManifest.xml +2 -0
- package/tests/fixtures/android/multi-module/feature-login/build.gradle.kts +18 -0
- package/tests/fixtures/android/multi-module/feature-login/src/main/AndroidManifest.xml +2 -0
- package/tests/fixtures/android/multi-module/gradle/libs.versions.toml +8 -0
- package/tests/fixtures/android/multi-module/gradle/wrapper/gradle-wrapper.properties +4 -0
- package/tests/fixtures/android/multi-module/settings.gradle.kts +4 -0
- package/tests/fixtures/android/non-android-gradle/build.gradle.kts +3 -0
- package/tests/fixtures/android/non-android-gradle/core/build.gradle.kts +3 -0
- package/tests/fixtures/android/non-android-gradle/core/src/main/java/com/example/core/Core.java +4 -0
- package/tests/fixtures/android/non-android-gradle/gradle/wrapper/gradle-wrapper.properties +4 -0
- package/tests/fixtures/android/non-android-gradle/settings.gradle.kts +2 -0
- package/tests/fixtures/android/partial/app/build.gradle.kts +7 -0
- package/tests/fixtures/android/partial/settings.gradle.kts +2 -0
- package/tests/fixtures/android/xml-view-app/app/build.gradle.kts +17 -0
- package/tests/fixtures/android/xml-view-app/app/src/main/AndroidManifest.xml +31 -0
- package/tests/fixtures/android/xml-view-app/app/src/main/kotlin/com/example/xmlviewapp/MainActivity.kt +7 -0
- package/tests/fixtures/android/xml-view-app/app/src/main/res/layout/activity_main.xml +4 -0
- package/tests/fixtures/android/xml-view-app/build.gradle.kts +4 -0
- package/tests/fixtures/android/xml-view-app/gradle/wrapper/gradle-wrapper.properties +4 -0
- package/tests/fixtures/android/xml-view-app/settings.gradle.kts +2 -0
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
// ---------------------------------------------------------------------------
|
|
2
|
+
// v0.4.0 Batch 2 — bounded gradle/libs.versions.toml plugin-alias evidence.
|
|
3
|
+
//
|
|
4
|
+
// This is deliberately not a general TOML parser: it only line-scans the
|
|
5
|
+
// `[plugins]`/`[libraries]` sections for aliases whose declared id/module
|
|
6
|
+
// statically mentions an Android/Kotlin-Android/Compose plugin or library.
|
|
7
|
+
// Anything else in the catalog (bundles, rich versions, references) is left
|
|
8
|
+
// unresolved, matching the "bounded evidence only" requirement for this
|
|
9
|
+
// batch — a full catalog resolver belongs to a later batch if ever needed.
|
|
10
|
+
// ---------------------------------------------------------------------------
|
|
11
|
+
const ALIAS_LINE_PATTERN = /^([A-Za-z0-9_-]+)\s*=\s*(\{.*\}|".*")\s*$/;
|
|
12
|
+
export function extractVersionCatalogEvidence(text) {
|
|
13
|
+
const androidPluginAliasEvidence = [];
|
|
14
|
+
const kotlinAndroidPluginAliasEvidence = [];
|
|
15
|
+
const composeAliasEvidence = [];
|
|
16
|
+
for (const rawLine of text.split(/\r?\n/)) {
|
|
17
|
+
const line = rawLine.trim();
|
|
18
|
+
const match = line.match(ALIAS_LINE_PATTERN);
|
|
19
|
+
if (!match)
|
|
20
|
+
continue;
|
|
21
|
+
const [, alias, body] = match;
|
|
22
|
+
if (body.includes("com.android.application") || body.includes("com.android.library")) {
|
|
23
|
+
androidPluginAliasEvidence.push(alias);
|
|
24
|
+
}
|
|
25
|
+
if (body.includes("org.jetbrains.kotlin.android")) {
|
|
26
|
+
kotlinAndroidPluginAliasEvidence.push(alias);
|
|
27
|
+
}
|
|
28
|
+
if (/compose/i.test(body) || /androidx\.compose/i.test(body)) {
|
|
29
|
+
composeAliasEvidence.push(alias);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
return {
|
|
33
|
+
androidPluginAliasEvidence: androidPluginAliasEvidence.sort((a, b) => a.localeCompare(b)),
|
|
34
|
+
kotlinAndroidPluginAliasEvidence: kotlinAndroidPluginAliasEvidence.sort((a, b) => a.localeCompare(b)),
|
|
35
|
+
composeAliasEvidence: composeAliasEvidence.sort((a, b) => a.localeCompare(b)),
|
|
36
|
+
};
|
|
37
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
// ---------------------------------------------------------------------------
|
|
2
|
+
// v0.4.0 Batch 1 — Android detection result contract.
|
|
3
|
+
// v0.4.0 Batch 2 — narrow inherited-contract correction: ANDROID_PROJECT_KINDS
|
|
4
|
+
// widened (additive) from {application, library, unknown} to also cover
|
|
5
|
+
// project-level outcomes ("multi-module", "mixed", "partial", "non-android")
|
|
6
|
+
// required by Batch 2 classification (see agents.txt Batch 2 section 7.8).
|
|
7
|
+
// The original three values are preserved unchanged and remain the only
|
|
8
|
+
// values a single AndroidModuleDetection.kind can take in practice, so no
|
|
9
|
+
// existing consumer or test is broken by the widening. AndroidModuleDetection
|
|
10
|
+
// also gained optional confidence/evidence fields so per-module
|
|
11
|
+
// classification results (Batch 2 section 7.7) can be evidence-backed
|
|
12
|
+
// without a second module-result type.
|
|
13
|
+
//
|
|
14
|
+
// This is the normalized shape a future detection batch will populate. This
|
|
15
|
+
// batch defines the contract only; no detection algorithm exists yet.
|
|
16
|
+
// "uncertain"/"unknown" outcomes must never be normalized into a positive
|
|
17
|
+
// detection — callers must check `detected` explicitly.
|
|
18
|
+
// ---------------------------------------------------------------------------
|
|
19
|
+
export const ANDROID_PROJECT_KINDS = [
|
|
20
|
+
"application",
|
|
21
|
+
"library",
|
|
22
|
+
"unknown",
|
|
23
|
+
"multi-module",
|
|
24
|
+
"mixed",
|
|
25
|
+
"partial",
|
|
26
|
+
"non-android",
|
|
27
|
+
];
|
|
28
|
+
export const ANDROID_UI_TOOLKITS = ["compose", "xml-view", "mixed", "uncertain"];
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
// ---------------------------------------------------------------------------
|
|
2
|
+
// v0.4.0 Batch 4 — static Gradle metadata check-result construction
|
|
3
|
+
// (agents.txt Batch 4 section 7.16).
|
|
4
|
+
//
|
|
5
|
+
// Status policy:
|
|
6
|
+
// - non-Android target -> "unsupported" (optional)
|
|
7
|
+
// - Android detected but no module build -> "inconclusive" (required)
|
|
8
|
+
// file could be read
|
|
9
|
+
// - Android detected but no metadata field -> "inconclusive" (required)
|
|
10
|
+
// could be resolved from any module
|
|
11
|
+
// - usable evidence resolved -> "passed"
|
|
12
|
+
// Unresolved dynamic values and metadata conflicts are represented as
|
|
13
|
+
// warnings/evidence — they never fail this check on their own, matching the
|
|
14
|
+
// "validation evidence, not automatic vulnerability" framing used throughout
|
|
15
|
+
// this batch. There is no reachable "malformed"/"error" path for plain-text
|
|
16
|
+
// Gradle files the way there is for XML: readAndroidGradleMetadata treats an
|
|
17
|
+
// unreadable file the same as an absent one, and all paths inspected here
|
|
18
|
+
// come from the already target-contained Batch 2 detection result.
|
|
19
|
+
// ---------------------------------------------------------------------------
|
|
20
|
+
const CHECK_ID = "android-gradle-metadata";
|
|
21
|
+
export function buildAndroidGradleMetadataCheckResult(detection, gradle) {
|
|
22
|
+
const sourcePaths = [...gradle.settingsFiles, ...gradle.rootBuildFiles, ...gradle.moduleBuildFiles].sort((a, b) => a.localeCompare(b));
|
|
23
|
+
const evidence = [];
|
|
24
|
+
if (gradle.wrapper.versionEvidence)
|
|
25
|
+
evidence.push(`Gradle wrapper version: ${gradle.wrapper.versionEvidence}`);
|
|
26
|
+
if (gradle.pluginEvidence.androidGradlePluginVersion)
|
|
27
|
+
evidence.push(`Android Gradle Plugin version: ${gradle.pluginEvidence.androidGradlePluginVersion}`);
|
|
28
|
+
if (gradle.pluginEvidence.kotlinAndroidPluginVersion)
|
|
29
|
+
evidence.push(`Kotlin Android plugin version: ${gradle.pluginEvidence.kotlinAndroidPluginVersion}`);
|
|
30
|
+
for (const module of gradle.modules) {
|
|
31
|
+
if (module.namespace || module.applicationId) {
|
|
32
|
+
evidence.push(`${module.path}: namespace=${module.namespace ?? "(none)"} applicationId=${module.applicationId ?? "(none)"}`);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
const warnings = [...gradle.parseWarnings];
|
|
36
|
+
if (gradle.conflicts && gradle.conflicts.length > 0) {
|
|
37
|
+
warnings.push(...gradle.conflicts.map((c) => c.note));
|
|
38
|
+
}
|
|
39
|
+
if (detection.projectKind === "non-android") {
|
|
40
|
+
return {
|
|
41
|
+
id: CHECK_ID,
|
|
42
|
+
category: "android-gradle",
|
|
43
|
+
title: "Android Gradle metadata extraction",
|
|
44
|
+
status: "unsupported",
|
|
45
|
+
requirementLevel: "optional",
|
|
46
|
+
ran: false,
|
|
47
|
+
skipped: true,
|
|
48
|
+
skipInfo: {
|
|
49
|
+
checkId: CHECK_ID,
|
|
50
|
+
reason: "Target was not detected as an Android project.",
|
|
51
|
+
requirementLevel: "optional",
|
|
52
|
+
missingCapability: "android-detection",
|
|
53
|
+
verdictImpact: "does not apply to a non-Android target",
|
|
54
|
+
recommendedNextAction: "Re-run against an Android Gradle project, or verify project detection.",
|
|
55
|
+
},
|
|
56
|
+
evidence: [],
|
|
57
|
+
findings: [],
|
|
58
|
+
warnings: [],
|
|
59
|
+
errors: [],
|
|
60
|
+
sourcePaths: [],
|
|
61
|
+
confidence: "unknown",
|
|
62
|
+
environmentRequirements: [],
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
const hasModuleBuildFile = gradle.moduleBuildFiles.length > 0;
|
|
66
|
+
const hasAnyResolvedModuleMetadata = gradle.modules.some((m) => m.namespace || m.applicationId || m.minSdk || m.targetSdk || m.compileSdk || m.versionName || m.versionCode);
|
|
67
|
+
if (!hasModuleBuildFile) {
|
|
68
|
+
return {
|
|
69
|
+
id: CHECK_ID,
|
|
70
|
+
category: "android-gradle",
|
|
71
|
+
title: "Android Gradle metadata extraction",
|
|
72
|
+
status: "inconclusive",
|
|
73
|
+
requirementLevel: "required",
|
|
74
|
+
ran: true,
|
|
75
|
+
skipped: false,
|
|
76
|
+
evidence,
|
|
77
|
+
findings: [],
|
|
78
|
+
warnings: [...warnings, "No module build.gradle(.kts) file could be read for metadata extraction."],
|
|
79
|
+
errors: [],
|
|
80
|
+
sourcePaths,
|
|
81
|
+
confidence: "unknown",
|
|
82
|
+
environmentRequirements: [],
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
if (!hasAnyResolvedModuleMetadata) {
|
|
86
|
+
return {
|
|
87
|
+
id: CHECK_ID,
|
|
88
|
+
category: "android-gradle",
|
|
89
|
+
title: "Android Gradle metadata extraction",
|
|
90
|
+
status: "inconclusive",
|
|
91
|
+
requirementLevel: "required",
|
|
92
|
+
ran: true,
|
|
93
|
+
skipped: false,
|
|
94
|
+
evidence,
|
|
95
|
+
findings: [],
|
|
96
|
+
warnings: [...warnings, "Module build file(s) were read but no static metadata field could be resolved."],
|
|
97
|
+
errors: [],
|
|
98
|
+
sourcePaths,
|
|
99
|
+
confidence: gradle.metadataConfidence,
|
|
100
|
+
environmentRequirements: [],
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
const confidence = gradle.metadataConfidence;
|
|
104
|
+
return {
|
|
105
|
+
id: CHECK_ID,
|
|
106
|
+
category: "android-gradle",
|
|
107
|
+
title: "Android Gradle metadata extraction",
|
|
108
|
+
status: "passed",
|
|
109
|
+
requirementLevel: "required",
|
|
110
|
+
ran: true,
|
|
111
|
+
skipped: false,
|
|
112
|
+
evidence,
|
|
113
|
+
findings: [],
|
|
114
|
+
warnings,
|
|
115
|
+
errors: [],
|
|
116
|
+
sourcePaths,
|
|
117
|
+
confidence,
|
|
118
|
+
environmentRequirements: [],
|
|
119
|
+
};
|
|
120
|
+
}
|
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
import { extractBuildFileEvidence } from "../detect/buildFileEvidence.js";
|
|
2
|
+
// ---------------------------------------------------------------------------
|
|
3
|
+
// v0.4.0 Batch 4 — bounded literal metadata extraction from a single module
|
|
4
|
+
// build.gradle(.kts) file's text.
|
|
5
|
+
//
|
|
6
|
+
// Reuses Batch 2's extractBuildFileEvidence for plugin/Compose boolean
|
|
7
|
+
// evidence (already covers namespace/applicationId at a basic level) and
|
|
8
|
+
// adds the additional literal fields Batch 4 needs (version/SDK fields,
|
|
9
|
+
// build-type names) plus raw/unresolved-expression preservation for every
|
|
10
|
+
// field, using the same generic "try a literal, else capture a bounded raw
|
|
11
|
+
// excerpt" strategy for each key. Comments are stripped first so a
|
|
12
|
+
// commented-out assignment never becomes active metadata (ANDROID-B4-05).
|
|
13
|
+
// ---------------------------------------------------------------------------
|
|
14
|
+
// v0.4.1 Batch 4 — exported (was module-private) so the new signing-
|
|
15
|
+
// configuration module can reuse the exact same comment-stripping/literal-
|
|
16
|
+
// extraction/brace-matching technique instead of a second implementation.
|
|
17
|
+
export function stripComments(text) {
|
|
18
|
+
// Replaces comment characters with spaces (not empty string) so any
|
|
19
|
+
// surviving line/column-independent offsets are not shifted — this batch
|
|
20
|
+
// does not track per-field locations, but keeping length stable is cheap
|
|
21
|
+
// and avoids accidentally joining tokens across a removed comment.
|
|
22
|
+
return text
|
|
23
|
+
.replace(/\/\*[\s\S]*?\*\//g, (match) => match.replace(/[^\n]/g, " "))
|
|
24
|
+
.replace(/\/\/[^\n]*/g, (match) => " ".repeat(match.length));
|
|
25
|
+
}
|
|
26
|
+
const STRING_OR_INT = `(?:'([^']*)'|"([^"]*)"|(-?\\d+))`;
|
|
27
|
+
export function extractLiteral(text, keyAlternatives) {
|
|
28
|
+
const keyPattern = keyAlternatives.map((k) => k.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")).join("|");
|
|
29
|
+
// Anchored to the start of a line (allowing leading indentation) so a key
|
|
30
|
+
// name that merely appears as a word inside an unrelated string literal —
|
|
31
|
+
// e.g. `val note = "the applicationId field below is the real one"` — is
|
|
32
|
+
// never mistaken for a real assignment (ANDROID-B4-05). Genuine Gradle
|
|
33
|
+
// property assignments always begin a statement/line.
|
|
34
|
+
const literalPattern = new RegExp(`^[ \\t]*(?:${keyPattern})\\b\\s*[=]?\\s*${STRING_OR_INT}`, "m");
|
|
35
|
+
const literalMatch = text.match(literalPattern);
|
|
36
|
+
if (literalMatch) {
|
|
37
|
+
const value = literalMatch[1] ?? literalMatch[2] ?? literalMatch[3];
|
|
38
|
+
return { value };
|
|
39
|
+
}
|
|
40
|
+
const rawPattern = new RegExp(`^[ \\t]*(?:${keyPattern})\\b\\s*[=]?\\s*([^\\n]{1,120})`, "m");
|
|
41
|
+
const rawMatch = text.match(rawPattern);
|
|
42
|
+
if (rawMatch) {
|
|
43
|
+
const raw = rawMatch[1].trim();
|
|
44
|
+
// A raw excerpt that is itself just a bare literal (already handled
|
|
45
|
+
// above) or empty is not meaningfully "dynamic" — only report genuinely
|
|
46
|
+
// unresolved expressions.
|
|
47
|
+
if (raw.length > 0)
|
|
48
|
+
return { raw };
|
|
49
|
+
}
|
|
50
|
+
return {};
|
|
51
|
+
}
|
|
52
|
+
// Returns the inner text of the first `<blockKeyword> { ... }` block found,
|
|
53
|
+
// bounded by brace-depth matching (not a full parser). Shared by
|
|
54
|
+
// findNamedBlockEntries (names only) and extractNamedSubBlocks (v0.4.1
|
|
55
|
+
// Batch 3 — names plus each entry's own block content).
|
|
56
|
+
export function findBlockBody(text, blockKeyword) {
|
|
57
|
+
const blockStart = text.search(new RegExp(`\\b${blockKeyword}\\s*\\{`));
|
|
58
|
+
if (blockStart === -1)
|
|
59
|
+
return undefined;
|
|
60
|
+
const openBraceIndex = text.indexOf("{", blockStart);
|
|
61
|
+
return sliceBlockAt(text, openBraceIndex);
|
|
62
|
+
}
|
|
63
|
+
// Given the index of an opening `{`, returns the text between it and its
|
|
64
|
+
// matching `}` (brace-depth bounded), or undefined if unterminated.
|
|
65
|
+
export function sliceBlockAt(text, openBraceIndex) {
|
|
66
|
+
if (text[openBraceIndex] !== "{")
|
|
67
|
+
return undefined;
|
|
68
|
+
let depth = 0;
|
|
69
|
+
for (let i = openBraceIndex; i < text.length; i++) {
|
|
70
|
+
if (text[i] === "{")
|
|
71
|
+
depth += 1;
|
|
72
|
+
else if (text[i] === "}") {
|
|
73
|
+
depth -= 1;
|
|
74
|
+
if (depth === 0)
|
|
75
|
+
return text.slice(openBraceIndex + 1, i);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return undefined;
|
|
79
|
+
}
|
|
80
|
+
// Finds the top-level named entries inside a `<blockKeyword> { ... }` block
|
|
81
|
+
// (e.g. `buildTypes { debug { ... } release { ... } }` or
|
|
82
|
+
// `sourceSets { main { ... } androidTest { ... } }`), supporting both the
|
|
83
|
+
// bare-identifier Groovy/Kotlin-DSL form and the Kotlin DSL
|
|
84
|
+
// getByName/create/named(...) form. Bounded by brace-depth matching, not a
|
|
85
|
+
// full parser — nested unrelated blocks inside are not descended into for
|
|
86
|
+
// name extraction beyond the immediate children.
|
|
87
|
+
function findNamedBlockEntries(text, blockKeyword) {
|
|
88
|
+
const block = findBlockBody(text, blockKeyword);
|
|
89
|
+
if (block === undefined)
|
|
90
|
+
return [];
|
|
91
|
+
const names = new Set();
|
|
92
|
+
for (const match of block.matchAll(/\b([A-Za-z_][A-Za-z0-9_]*)\s*\{/g)) {
|
|
93
|
+
names.add(match[1]);
|
|
94
|
+
}
|
|
95
|
+
for (const match of block.matchAll(/\b(?:getByName|create|named)\(\s*["']([\w-]+)["']/g)) {
|
|
96
|
+
names.add(match[1]);
|
|
97
|
+
}
|
|
98
|
+
return [...names].sort((a, b) => a.localeCompare(b));
|
|
99
|
+
}
|
|
100
|
+
// v0.4.1 Batch 3 — like findNamedBlockEntries, but also returns each named
|
|
101
|
+
// entry's own block content so per-build-type literal fields (debuggable,
|
|
102
|
+
// minifyEnabled, etc.) can be extracted. Reuses the exact same bounded
|
|
103
|
+
// brace-matching technique and the same two name-pattern forms — not a
|
|
104
|
+
// second parser, just returning more of what was already being scanned.
|
|
105
|
+
export function extractNamedSubBlocks(text, blockKeyword) {
|
|
106
|
+
const block = findBlockBody(text, blockKeyword);
|
|
107
|
+
if (block === undefined)
|
|
108
|
+
return [];
|
|
109
|
+
const results = [];
|
|
110
|
+
const seen = new Set();
|
|
111
|
+
for (const match of block.matchAll(/\b([A-Za-z_][A-Za-z0-9_]*)\s*\{/g)) {
|
|
112
|
+
const name = match[1];
|
|
113
|
+
if (seen.has(name))
|
|
114
|
+
continue;
|
|
115
|
+
const openBraceIndex = match.index + match[0].length - 1;
|
|
116
|
+
const content = sliceBlockAt(block, openBraceIndex);
|
|
117
|
+
if (content !== undefined) {
|
|
118
|
+
results.push({ name, content });
|
|
119
|
+
seen.add(name);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
for (const match of block.matchAll(/\b(?:getByName|create|named)\(\s*["']([\w-]+)["']\s*\)\s*\{/g)) {
|
|
123
|
+
const name = match[1];
|
|
124
|
+
if (seen.has(name))
|
|
125
|
+
continue;
|
|
126
|
+
const openBraceIndex = match.index + match[0].length - 1;
|
|
127
|
+
const content = sliceBlockAt(block, openBraceIndex);
|
|
128
|
+
if (content !== undefined) {
|
|
129
|
+
results.push({ name, content });
|
|
130
|
+
seen.add(name);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
return results.sort((a, b) => a.name.localeCompare(b.name));
|
|
134
|
+
}
|
|
135
|
+
const BOOLEAN_TOKEN = `(true|false)`;
|
|
136
|
+
// v0.4.1 Batch 3 — boolean-literal counterpart to extractLiteral (which only
|
|
137
|
+
// matches quoted-string/integer literals — Gradle boolean assignments like
|
|
138
|
+
// `debuggable true` or `isMinifyEnabled = true` are bare tokens, not quoted).
|
|
139
|
+
// Same anchoring/fallback strategy as extractLiteral for consistency.
|
|
140
|
+
export function extractBooleanLiteral(text, keyAlternatives) {
|
|
141
|
+
const keyPattern = keyAlternatives.map((k) => k.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")).join("|");
|
|
142
|
+
const literalPattern = new RegExp(`^[ \\t]*(?:${keyPattern})\\b\\s*[=(]?\\s*${BOOLEAN_TOKEN}\\)?`, "m");
|
|
143
|
+
const literalMatch = text.match(literalPattern);
|
|
144
|
+
if (literalMatch) {
|
|
145
|
+
return { value: literalMatch[1] === "true" };
|
|
146
|
+
}
|
|
147
|
+
const rawPattern = new RegExp(`^[ \\t]*(?:${keyPattern})\\b\\s*[=(]?\\s*([^\\n]{1,120})`, "m");
|
|
148
|
+
const rawMatch = text.match(rawPattern);
|
|
149
|
+
if (rawMatch) {
|
|
150
|
+
const raw = rawMatch[1].trim();
|
|
151
|
+
if (raw.length > 0)
|
|
152
|
+
return { raw };
|
|
153
|
+
}
|
|
154
|
+
return {};
|
|
155
|
+
}
|
|
156
|
+
function booleanLiteralState(result) {
|
|
157
|
+
if (result.value !== undefined)
|
|
158
|
+
return result.value ? "literal-true" : "literal-false";
|
|
159
|
+
if (result.raw !== undefined)
|
|
160
|
+
return "dynamic";
|
|
161
|
+
return "missing";
|
|
162
|
+
}
|
|
163
|
+
// v0.4.1 Batch 3 — builds bounded literal evidence for one named build-type
|
|
164
|
+
// block. Never evaluates Gradle; signingConfig/matchingFallbacks/initWith
|
|
165
|
+
// are always reference expressions, so only a bounded raw excerpt is kept.
|
|
166
|
+
function buildBuildTypeInfo(name, content) {
|
|
167
|
+
const debuggable = extractBooleanLiteral(content, ["debuggable", "isDebuggable"]);
|
|
168
|
+
const minifyEnabled = extractBooleanLiteral(content, ["minifyEnabled", "isMinifyEnabled"]);
|
|
169
|
+
const shrinkResources = extractBooleanLiteral(content, ["shrinkResources", "isShrinkResources"]);
|
|
170
|
+
const signingConfig = extractLiteral(content, ["signingConfig"]);
|
|
171
|
+
const matchingFallbacks = extractLiteral(content, ["matchingFallbacks"]);
|
|
172
|
+
const initWith = extractLiteral(content, ["initWith"]);
|
|
173
|
+
return {
|
|
174
|
+
name,
|
|
175
|
+
debuggable: debuggable.value,
|
|
176
|
+
debuggableRaw: debuggable.raw,
|
|
177
|
+
debuggableState: booleanLiteralState(debuggable),
|
|
178
|
+
minifyEnabled: minifyEnabled.value,
|
|
179
|
+
minifyEnabledRaw: minifyEnabled.raw,
|
|
180
|
+
minifyEnabledState: booleanLiteralState(minifyEnabled),
|
|
181
|
+
shrinkResources: shrinkResources.value,
|
|
182
|
+
shrinkResourcesRaw: shrinkResources.raw,
|
|
183
|
+
shrinkResourcesState: booleanLiteralState(shrinkResources),
|
|
184
|
+
signingConfigRef: signingConfig.value ?? signingConfig.raw,
|
|
185
|
+
matchingFallbacksRaw: matchingFallbacks.value ?? matchingFallbacks.raw,
|
|
186
|
+
initWithRaw: initWith.value ?? initWith.raw,
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
// Extracts bounded static metadata for one module's build file text. `path`
|
|
190
|
+
// is intentionally omitted from the returned info — the caller (the
|
|
191
|
+
// aggregator, which already knows the module path from detection) attaches
|
|
192
|
+
// it, keeping this function pure with respect to filesystem/module identity.
|
|
193
|
+
export function extractModuleGradleMetadata(rawText) {
|
|
194
|
+
const text = stripComments(rawText);
|
|
195
|
+
const evidence = extractBuildFileEvidence(text);
|
|
196
|
+
const unsupportedExpressions = [];
|
|
197
|
+
const namespace = extractLiteral(text, ["namespace"]);
|
|
198
|
+
const applicationId = extractLiteral(text, ["applicationId"]);
|
|
199
|
+
const versionCode = extractLiteral(text, ["versionCode"]);
|
|
200
|
+
const versionName = extractLiteral(text, ["versionName"]);
|
|
201
|
+
const minSdk = extractLiteral(text, ["minSdk", "minSdkVersion"]);
|
|
202
|
+
const targetSdk = extractLiteral(text, ["targetSdk", "targetSdkVersion"]);
|
|
203
|
+
const compileSdk = extractLiteral(text, ["compileSdk", "compileSdkVersion"]);
|
|
204
|
+
for (const [field, result] of [
|
|
205
|
+
["namespace", namespace],
|
|
206
|
+
["applicationId", applicationId],
|
|
207
|
+
["versionCode", versionCode],
|
|
208
|
+
["versionName", versionName],
|
|
209
|
+
["minSdk", minSdk],
|
|
210
|
+
["targetSdk", targetSdk],
|
|
211
|
+
["compileSdk", compileSdk],
|
|
212
|
+
]) {
|
|
213
|
+
if (result.raw) {
|
|
214
|
+
unsupportedExpressions.push(`${field}: ${result.raw}`);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
return {
|
|
218
|
+
info: {
|
|
219
|
+
isApplication: evidence.androidApplicationPlugin || undefined,
|
|
220
|
+
isLibrary: evidence.androidLibraryPlugin || undefined,
|
|
221
|
+
namespace: namespace.value ?? evidence.namespace,
|
|
222
|
+
namespaceRaw: namespace.raw,
|
|
223
|
+
applicationId: applicationId.value ?? evidence.applicationId,
|
|
224
|
+
applicationIdRaw: applicationId.raw,
|
|
225
|
+
versionCode: versionCode.value,
|
|
226
|
+
versionCodeRaw: versionCode.raw,
|
|
227
|
+
versionName: versionName.value,
|
|
228
|
+
versionNameRaw: versionName.raw,
|
|
229
|
+
minSdk: minSdk.value,
|
|
230
|
+
minSdkRaw: minSdk.raw,
|
|
231
|
+
targetSdk: targetSdk.value,
|
|
232
|
+
targetSdkRaw: targetSdk.raw,
|
|
233
|
+
compileSdk: compileSdk.value,
|
|
234
|
+
compileSdkRaw: compileSdk.raw,
|
|
235
|
+
buildTypes: findNamedBlockEntries(text, "buildTypes"),
|
|
236
|
+
buildTypeDetails: extractNamedSubBlocks(text, "buildTypes").map(({ name, content }) => buildBuildTypeInfo(name, content)),
|
|
237
|
+
composeEnabled: evidence.composeBuildFeatureEvidence || evidence.composeDependencyEvidence || undefined,
|
|
238
|
+
sourceSetEvidence: findNamedBlockEntries(text, "sourceSets").map((name) => `declared sourceSet: ${name}`),
|
|
239
|
+
testSourceSetEvidence: [],
|
|
240
|
+
unsupportedExpressions,
|
|
241
|
+
},
|
|
242
|
+
};
|
|
243
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { accessorSuffixToCatalogAlias, resolveCatalogVersion } from "./versionCatalogMetadata.js";
|
|
2
|
+
function extractDirectIdVersion(text, pluginId) {
|
|
3
|
+
const escaped = pluginId.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
4
|
+
const pattern = new RegExp(`id\\s*\\(?\\s*['"]${escaped}['"]\\s*\\)?\\s*version\\s*['"]([^'"]+)['"]`);
|
|
5
|
+
return text.match(pattern)?.[1];
|
|
6
|
+
}
|
|
7
|
+
function extractClasspathVersion(text, groupArtifact) {
|
|
8
|
+
const escaped = groupArtifact.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
9
|
+
const pattern = new RegExp(`classpath\\s*['"]${escaped}:([^'"]+)['"]`);
|
|
10
|
+
return text.match(pattern)?.[1];
|
|
11
|
+
}
|
|
12
|
+
function extractCatalogAliasVersion(text, pluginId, catalog) {
|
|
13
|
+
if (!catalog)
|
|
14
|
+
return undefined;
|
|
15
|
+
for (const match of text.matchAll(/alias\(\s*libs\.plugins\.([\w.]+)\s*\)/g)) {
|
|
16
|
+
const alias = accessorSuffixToCatalogAlias(match[1]);
|
|
17
|
+
const entry = catalog.plugins[alias];
|
|
18
|
+
if (entry?.id === pluginId) {
|
|
19
|
+
return resolveCatalogVersion(catalog, entry);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
return undefined;
|
|
23
|
+
}
|
|
24
|
+
// Resolves a plugin's version from root/module build-file text plus an
|
|
25
|
+
// optional parsed version catalog. `classpathGroupArtifact` is only relevant
|
|
26
|
+
// for the Android Gradle Plugin's legacy buildscript-classpath form.
|
|
27
|
+
export function resolvePluginVersion(text, pluginId, catalog, classpathGroupArtifact) {
|
|
28
|
+
const direct = extractDirectIdVersion(text, pluginId);
|
|
29
|
+
if (direct)
|
|
30
|
+
return { version: direct };
|
|
31
|
+
if (classpathGroupArtifact) {
|
|
32
|
+
const classpath = extractClasspathVersion(text, classpathGroupArtifact);
|
|
33
|
+
if (classpath)
|
|
34
|
+
return { version: classpath };
|
|
35
|
+
}
|
|
36
|
+
const catalogVersion = extractCatalogAliasVersion(text, pluginId, catalog);
|
|
37
|
+
if (catalogVersion)
|
|
38
|
+
return { version: catalogVersion };
|
|
39
|
+
return {};
|
|
40
|
+
}
|