apsa 1.2.0__tar.gz → 1.3.0__tar.gz
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.
- {apsa-1.2.0 → apsa-1.3.0}/.agents/skills/apsa/SKILL.md +5 -3
- {apsa-1.2.0/src/mobile_audit/data → apsa-1.3.0/.agents}/skills/mobile-audit/SKILL.md +5 -3
- {apsa-1.2.0/src/mobile_audit/data → apsa-1.3.0/.agents}/skills/quaygate/SKILL.md +5 -3
- apsa-1.3.0/.github/workflows/dependency-evaluation.yml +47 -0
- apsa-1.3.0/.github/workflows/dependency-oracle.yml +77 -0
- apsa-1.3.0/.github/workflows/fpfn-evaluation.yml +43 -0
- {apsa-1.2.0 → apsa-1.3.0}/.github/workflows/hardening-replay.yml +1 -1
- {apsa-1.2.0 → apsa-1.3.0}/Makefile +3 -3
- {apsa-1.2.0 → apsa-1.3.0}/PKG-INFO +75 -9
- {apsa-1.2.0 → apsa-1.3.0}/README.ko.md +63 -7
- {apsa-1.2.0 → apsa-1.3.0}/README.md +74 -8
- {apsa-1.2.0 → apsa-1.3.0}/RELEASE_READINESS.md +36 -0
- apsa-1.3.0/benchmarks/DEPENDENCY_RESULTS.ko.md +158 -0
- apsa-1.3.0/benchmarks/DEPENDENCY_RESULTS.md +182 -0
- apsa-1.3.0/benchmarks/FPFN_RESULTS.ko.md +88 -0
- apsa-1.3.0/benchmarks/FPFN_RESULTS.md +100 -0
- {apsa-1.2.0 → apsa-1.3.0}/benchmarks/competitive.py +7 -1
- apsa-1.3.0/benchmarks/dependency_cases.json +114 -0
- apsa-1.3.0/benchmarks/dependency_eval.py +187 -0
- apsa-1.3.0/benchmarks/dependency_locks/element-x.lockfile +704 -0
- apsa-1.3.0/benchmarks/dependency_locks/fossify-calculator.lockfile +404 -0
- apsa-1.3.0/benchmarks/dependency_locks/fossify-gallery.lockfile +484 -0
- apsa-1.3.0/benchmarks/dependency_locks/home-assistant.lockfile +705 -0
- apsa-1.3.0/benchmarks/dependency_locks/mihon.lockfile +583 -0
- apsa-1.3.0/benchmarks/dependency_locks/nextcloud.lockfile +734 -0
- apsa-1.3.0/benchmarks/dependency_locks/nowinandroid.lockfile +613 -0
- apsa-1.3.0/benchmarks/dependency_locks/pocket-casts.lockfile +618 -0
- apsa-1.3.0/benchmarks/dependency_locks/wikipedia.lockfile +624 -0
- apsa-1.3.0/benchmarks/dependency_oracle.py +176 -0
- apsa-1.3.0/benchmarks/dependency_truth.json +9874 -0
- apsa-1.3.0/benchmarks/dependency_truth_holdout2.json +9459 -0
- apsa-1.3.0/benchmarks/dependency_truth_holdout3.json +6935 -0
- apsa-1.3.0/benchmarks/fpfn_eval.py +189 -0
- apsa-1.3.0/benchmarks/fpfn_truth.json +273 -0
- apsa-1.3.0/benchmarks/fpfn_truth_amendments.json +17 -0
- apsa-1.3.0/benchmarks/results/2026-10-09-dependency-development-rerun.json +18341 -0
- apsa-1.3.0/benchmarks/results/2026-10-09-dependency-final-head.json +18337 -0
- apsa-1.3.0/benchmarks/results/2026-10-09-dependency-first-holdout1.json +6092 -0
- apsa-1.3.0/benchmarks/results/2026-10-09-dependency-first-holdout2.json +13271 -0
- apsa-1.3.0/benchmarks/results/2026-10-09-dependency-first-holdout3.json +18095 -0
- apsa-1.3.0/benchmarks/results/2026-10-09-dependency-frozen-replay.json +5360 -0
- apsa-1.3.0/benchmarks/results/2026-10-09-dependency-review-rerun.json +18337 -0
- apsa-1.3.0/benchmarks/results/2026-10-09-fpfn-first.json +911 -0
- apsa-1.3.0/benchmarks/results/2026-10-09-parser-fresh-repos.json +43 -0
- apsa-1.3.0/benchmarks/results/2026-10-09-release-130-harnesses.json +225 -0
- apsa-1.3.0/docs/DEVICE_EVIDENCE.md +31 -0
- {apsa-1.2.0 → apsa-1.3.0}/docs/INTEGRATION.md +1 -1
- apsa-1.3.0/docs/NEXT_ANALYSIS.md +271 -0
- {apsa-1.2.0 → apsa-1.3.0}/docs/OWASP_COVERAGE.md +1 -1
- {apsa-1.2.0 → apsa-1.3.0}/docs/ROADMAP.md +3 -2
- {apsa-1.2.0 → apsa-1.3.0}/docs/SUPPORTED_MATRIX.md +10 -9
- {apsa-1.2.0 → apsa-1.3.0}/docs/ci-example.yml +1 -1
- {apsa-1.2.0 → apsa-1.3.0}/pyproject.toml +1 -1
- {apsa-1.2.0 → apsa-1.3.0}/quaygate/__init__.py +1 -1
- {apsa-1.2.0 → apsa-1.3.0}/src/mobile_audit/audit.py +73 -10
- {apsa-1.2.0 → apsa-1.3.0}/src/mobile_audit/binary_analysis.py +153 -3
- {apsa-1.2.0 → apsa-1.3.0}/src/mobile_audit/cli.py +14 -0
- {apsa-1.2.0 → apsa-1.3.0}/src/mobile_audit/core.py +1 -1
- {apsa-1.2.0 → apsa-1.3.0}/src/mobile_audit/data/skills/apsa/SKILL.md +5 -3
- {apsa-1.2.0/.agents → apsa-1.3.0/src/mobile_audit/data}/skills/mobile-audit/SKILL.md +5 -3
- {apsa-1.2.0/.agents → apsa-1.3.0/src/mobile_audit/data}/skills/quaygate/SKILL.md +5 -3
- {apsa-1.2.0 → apsa-1.3.0}/src/mobile_audit/inputs.py +133 -3
- {apsa-1.2.0 → apsa-1.3.0}/src/mobile_audit/intel.py +152 -12
- {apsa-1.2.0 → apsa-1.3.0}/src/mobile_audit/objc_analysis.py +11 -2
- {apsa-1.2.0 → apsa-1.3.0}/src/mobile_audit/parser_compat.py +150 -0
- {apsa-1.2.0 → apsa-1.3.0}/src/mobile_audit/runtime.py +6 -0
- {apsa-1.2.0 → apsa-1.3.0}/src/mobile_audit/skills.py +3 -0
- {apsa-1.2.0 → apsa-1.3.0}/src/mobile_audit/source_analysis.py +5 -1
- apsa-1.3.0/src/mobile_audit/source_context.py +694 -0
- apsa-1.3.0/tests/fixtures/skills/apsa-1.3.0.md +52 -0
- apsa-1.3.0/tests/fixtures/skills/mobile-audit-1.3.0.md +52 -0
- apsa-1.3.0/tests/fixtures/skills/quaygate-1.3.0.md +52 -0
- apsa-1.3.0/tests/test_dependency_evidence.py +728 -0
- apsa-1.3.0/tests/test_intel_history.py +154 -0
- apsa-1.3.0/tests/test_parser_depth.py +373 -0
- {apsa-1.2.0 → apsa-1.3.0}/uv.lock +1 -1
- apsa-1.2.0/docs/NEXT_ANALYSIS.md +0 -128
- apsa-1.2.0/src/mobile_audit/source_context.py +0 -269
- {apsa-1.2.0 → apsa-1.3.0}/.github/workflows/benchmark-evidence.yml +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/.github/workflows/ci.yml +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/.github/workflows/competitive-benchmark.yml +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/.github/workflows/generated-aab.yml +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/.github/workflows/next-holdout.yml +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/.github/workflows/public-evidence.yml +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/.github/workflows/real-world-benchmark.yml +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/.github/workflows/release.yml +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/DESIGN.md +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/LICENSE +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/NAMING.md +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/PRODUCT_REQUIREMENTS.md +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/THIRD_PARTY_NOTICES.md +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/apsa/__init__.py +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/apsa/__main__.py +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/apsa/cli.py +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/benchmarks/COMPETITIVE.md +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/benchmarks/COMPETITIVE_RESULTS.ko.md +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/benchmarks/COMPETITIVE_RESULTS.md +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/benchmarks/COVERAGE_RESULTS.ko.md +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/benchmarks/COVERAGE_RESULTS.md +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/benchmarks/HARDENING_RESULTS.ko.md +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/benchmarks/HARDENING_RESULTS.md +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/benchmarks/NEXT_RESULTS.ko.md +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/benchmarks/NEXT_RESULTS.md +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/benchmarks/README.md +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/benchmarks/REAL_WORLD.ko.md +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/benchmarks/REAL_WORLD.md +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/benchmarks/REAL_WORLD_RESULTS.ko.md +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/benchmarks/REAL_WORLD_RESULTS.md +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/benchmarks/__init__.py +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/benchmarks/cases/java/bridge-fixed.java +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/benchmarks/cases/java/bridge-vulnerable.java +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/benchmarks/cases/java/cross-function-irrelevant.java +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/benchmarks/cases/java/documentation-irrelevant.java +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/benchmarks/cases/java/host-fixed.java +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/benchmarks/cases/java/host-vulnerable.java +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/benchmarks/cases/java/intent-fixed.java +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/benchmarks/cases/java/intent-vulnerable.java +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/benchmarks/cases/java/other-client-irrelevant.java +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/benchmarks/cases/java/post-validation-mutation.java +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/benchmarks/cases/java/ssl-fixed.java +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/benchmarks/cases/java/ssl-vulnerable.java +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/benchmarks/cases/kotlin/documentation-irrelevant.kt +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/benchmarks/cases/kotlin/navigation-fixed.kt +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/benchmarks/cases/kotlin/navigation-vulnerable.kt +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/benchmarks/cases/kotlin/query-fixed.kt +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/benchmarks/cases/kotlin/query-vulnerable.kt +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/benchmarks/cases/kotlin/ssl-fixed.kt +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/benchmarks/cases/kotlin/ssl-vulnerable.kt +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/benchmarks/cases/kotlin/unrelated-shadow.kt +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/benchmarks/cases/swift/documentation-irrelevant.swift +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/benchmarks/cases/swift/navigation-fixed.swift +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/benchmarks/cases/swift/navigation-vulnerable.swift +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/benchmarks/cases/swift/query-javascript-fixed.swift +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/benchmarks/cases/swift/query-javascript-vulnerable.swift +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/benchmarks/cases/swift/unrelated-shadow.swift +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/benchmarks/cases/swift/url-fixed.swift +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/benchmarks/cases/swift/url-vulnerable.swift +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/benchmarks/competitive_cases.py +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/benchmarks/corpus.json +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/benchmarks/coverage_replay.py +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/benchmarks/hardening_replay.py +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/benchmarks/ios_branch_cases.json +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/benchmarks/next_holdout.py +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/benchmarks/next_replay.py +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/benchmarks/next_truth.json +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/benchmarks/primary/CVE-2025-31200.json +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/benchmarks/primary/CVE-2025-31201.json +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/benchmarks/primary/CVE-2025-43300.json +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/benchmarks/real_world.py +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/benchmarks/real_world_advisories.json +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/benchmarks/real_world_cases.json +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/benchmarks/real_world_swift_advisory.json +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/benchmarks/results/2026-10-09-candidate-mobsf.json +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/benchmarks/results/2026-10-09-coverage-evidence.json +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/benchmarks/results/2026-10-09-hardening-evidence.json +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/benchmarks/results/2026-10-09-initial-candidate-mobsf.json +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/benchmarks/results/2026-10-09-initial-released-baseline.json +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/benchmarks/results/2026-10-09-next-evidence.json +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/benchmarks/results/2026-10-09-next-first-holdout.json +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/benchmarks/results/2026-10-09-next-first-replay.json +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/benchmarks/results/2026-10-09-next-generated-aab-verified.json +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/benchmarks/results/2026-10-09-next-generated-aab.json +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/benchmarks/results/2026-10-09-next-holdout-rerun.json +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/benchmarks/results/2026-10-09-next-replay-rerun.json +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/benchmarks/results/2026-10-09-public-coverage-extension.json +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/benchmarks/results/2026-10-09-public-evidence.json +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/benchmarks/results/2026-10-09-public-real-world-hardened.json +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/benchmarks/results/2026-10-09-public-real-world-initial.json +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/benchmarks/results/2026-10-09-released-baseline.json +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/benchmarks/reviews/2026-10-09-coverage-architecture.md +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/benchmarks/reviews/2026-10-09-coverage-code.md +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/benchmarks/reviews/2026-10-09-hardening-architecture.md +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/benchmarks/reviews/2026-10-09-hardening-code.md +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/benchmarks/reviews/2026-10-09-next-runtime-architecture.md +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/benchmarks/reviews/2026-10-09-next-runtime-code.json +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/benchmarks/reviews/2026-10-09-next-runtime-code.md +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/benchmarks/run.py +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/docs/MODEL_WORKFLOWS.md +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/docs/OPERATIONS.md +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/docs/PUBLISHING.md +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/docs/THREAT_MODEL.md +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/docs/legacy/MOBILE_AUDIT_1_0_READINESS.md +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/docs/legacy/QUAYGATE_0_9.md +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/examples/scenario.android.json +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/quaygate/__main__.py +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/quaygate/adb.py +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/quaygate/apk.py +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/quaygate/appchecks.py +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/quaygate/apps.py +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/quaygate/arsc.py +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/quaygate/axml.py +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/quaygate/cert.py +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/quaygate/checks.py +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/quaygate/cli.py +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/quaygate/dex.py +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/quaygate/dexcode.py +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/quaygate/elf.py +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/quaygate/indicators.py +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/quaygate/ipa.py +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/quaygate/legacy_cli.py +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/quaygate/network_security.py +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/quaygate/report.py +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/requirements-release.txt +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/scripts/licenses.py +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/scripts/release-check.sh +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/scripts/release.py +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/scripts/verify_aab.py +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/src/mobile_audit/__init__.py +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/src/mobile_audit/__main__.py +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/src/mobile_audit/_job_worker.py +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/src/mobile_audit/_parser_worker.py +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/src/mobile_audit/aab_manifest.py +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/src/mobile_audit/baselines.py +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/src/mobile_audit/data/demo/AndroidManifest.xml +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/src/mobile_audit/data/demo/Demo.swift +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/src/mobile_audit/data/demo/Info.plist +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/src/mobile_audit/data/demo/MainActivity.kt +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/src/mobile_audit/data/demo/build.gradle.kts +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/src/mobile_audit/data/rules.json +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/src/mobile_audit/data/structural-rules.json +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/src/mobile_audit/engine.py +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/src/mobile_audit/input_snapshot.py +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/src/mobile_audit/ios_embedded.py +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/src/mobile_audit/ios_ranges.py +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/src/mobile_audit/jobs.py +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/src/mobile_audit/mcp_server.py +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/src/mobile_audit/model_context.py +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/src/mobile_audit/output.py +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/src/mobile_audit/parser_sandbox.py +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/src/mobile_audit/policy.py +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/src/mobile_audit/processes.py +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/src/mobile_audit/quaygate_analysis.py +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/src/mobile_audit/rules.py +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/src/mobile_audit/selection.py +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/src/mobile_audit/store.py +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/src/mobile_audit/tools.py +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/src/mobile_audit/tui.py +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/src/mobile_audit/watch.py +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/tests/__init__.py +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/tests/conftest.py +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/tests/fixtures/ANDROGUARD-LICENCE +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/tests/fixtures/README.md +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/tests/fixtures/Test-debug.apk +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/tests/fixtures/binary_analysis/README.md +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/tests/fixtures/binary_analysis/build.py +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/tests/fixtures/binary_analysis/safe/Calls.java +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/tests/fixtures/binary_analysis/safe.apk +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/tests/fixtures/binary_analysis/unsafe/Calls.java +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/tests/fixtures/binary_analysis/unsafe.apk +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/tests/fixtures/runtime/README.md +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/tests/fixtures/runtime/android/AndroidManifest.xml +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/tests/fixtures/runtime/android/MainActivity.java +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/tests/fixtures/runtime/build.py +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/tests/fixtures/runtime/ios/Main.swift +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/tests/fixtures/runtime/verify.py +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/tests/fixtures/skills/apsa-1.0.3.md +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/tests/fixtures/skills/apsa-1.0.6.md +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/tests/fixtures/skills/apsa-1.1.0.md +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/tests/fixtures/skills/apsa-1.2.0.md +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/tests/fixtures/skills/mobile-audit-1.0.1.md +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/tests/fixtures/skills/mobile-audit-1.0.2.md +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/tests/fixtures/skills/mobile-audit-1.0.3.md +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/tests/fixtures/skills/mobile-audit-1.0.6.md +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/tests/fixtures/skills/mobile-audit-1.1.0.md +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/tests/fixtures/skills/mobile-audit-1.2.0.md +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/tests/fixtures/skills/quaygate-1.0.1.md +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/tests/fixtures/skills/quaygate-1.0.2.md +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/tests/fixtures/skills/quaygate-1.0.3.md +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/tests/fixtures/skills/quaygate-1.0.6.md +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/tests/fixtures/skills/quaygate-1.1.0.md +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/tests/fixtures/skills/quaygate-1.2.0.md +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/tests/helpers.py +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/tests/test_apk_checks.py +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/tests/test_apps.py +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/tests/test_arsc.py +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/tests/test_audit.py +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/tests/test_axml.py +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/tests/test_benchmark.py +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/tests/test_binary_analysis.py +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/tests/test_cert.py +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/tests/test_competitive.py +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/tests/test_coverage_extension.py +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/tests/test_device_checks.py +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/tests/test_dex.py +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/tests/test_dexcode.py +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/tests/test_elf.py +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/tests/test_evidence106.py +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/tests/test_foundations.py +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/tests/test_intel.py +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/tests/test_intel_product.py +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/tests/test_interfaces.py +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/tests/test_ipa.py +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/tests/test_jobs.py +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/tests/test_network_security.py +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/tests/test_next_hardening.py +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/tests/test_policy.py +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/tests/test_product_review.py +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/tests/test_real_world.py +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/tests/test_real_world_hardening.py +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/tests/test_release_hardening.py +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/tests/test_report_cli.py +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/tests/test_review3_regressions.py +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/tests/test_runtime.py +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/tests/test_security_primitives.py +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/tests/test_source_analysis.py +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/tests/test_unified.py +0 -0
- {apsa-1.2.0 → apsa-1.3.0}/tests/test_workflows11.py +0 -0
|
@@ -15,7 +15,7 @@ For a local audit, run `scan TARGET`. Source folders, APK, AAB and IPA are accep
|
|
|
15
15
|
|
|
16
16
|
Use `scan TARGET --background` or MCP `audit_start` for long scans. Keep the returned job ID; poll `jobs status ID` / `jobs_status`, and use the corresponding cancel tool when requested. A completed job supplies a report ID. Failed, cancelled and interrupted jobs do not establish a successful audit. Closing the TUI or MCP client does not itself cancel persistent jobs.
|
|
17
17
|
|
|
18
|
-
CLI analysis runs locally and does not upload app source or builds. Online OSV queries send dependency names and versions. MCP context sends finding metadata to the invoking client, which may forward it to a hosted model. Follow the user's model/data policy; local analysis is separate from whether the product is open source.
|
|
18
|
+
CLI analysis runs locally and does not upload app source or builds. Online OSV queries send dependency names and versions, including Gradle catalog aliases used in shipped configurations and release-runtime lockfile coordinates from any module (private group IDs too). One online run queries at most 100 packages: those without a recent OSV result first, declared packages and non-Gradle manifests before transitive Gradle lockfile coordinates. The rest without such a result stay not-run and the audit incomplete; repeated runs advance through them. MCP context sends finding metadata to the invoking client, which may forward it to a hosted model. Follow the user's model/data policy; local analysis is separate from whether the product is open source.
|
|
19
19
|
|
|
20
20
|
Read exact finding evidence with `reports get REPORT_ID --finding FINDING_ID`, or MCP `reports_get`. Use `reports list` to resolve saved IDs. Keep app defects, included dependency CVEs and device/OS CVEs separate. Never infer device patch status from targetSdk/minSdk. Distinguish candidate, configuration-confirmed, version-affected and runtime-confirmed; a package match does not establish reachability or reproduction. Not-run, inconclusive and empty results do not establish safety.
|
|
21
21
|
|
|
@@ -43,8 +43,10 @@ Model report context is bounded and paginated. After resolving latest once, use
|
|
|
43
43
|
|
|
44
44
|
Portable team baselines require explicit authorized approved_by and approval_reference metadata. Export with reports export --format baseline or MCP reports_export_baseline, then pin its returned SHA-256 in independently reviewed CI configuration. Evaluate with --baseline-file/--baseline-sha256 or MCP baseline_path/baseline_sha256; do not derive the expected hash from an untrusted artifact in CI. The hash proves integrity against the approved value, not approver identity or a digital signature. scan --policy with --out writes a separate .decision.json; --decision-out selects another path. The decision includes policy/report hashes, approval provenance and waiver details.
|
|
45
45
|
|
|
46
|
-
AST coverage reports recognized/analyzed/skipped/bodyless function declarations; errors and unsupported syntax can hide additional functions. Local exports retain per-file inventory.source_analysis metadata. Kotlin open identifiers and Swift nonisolated(unsafe) variable compatibility keep files partial and original evidence offsets. For Apple mobile device-info JSON, os_product=ipados explicitly selects iPadOS; default ios does not match iPadOS-only ranges. Apple custom ranges require CNA identity plus matching official bulletin branch/reference. Outside-published-affected-range does not prove patching; older CVE cache entries without identity need refetching.
|
|
46
|
+
AST coverage reports recognized/analyzed/skipped/bodyless function declarations; errors and unsupported syntax can hide additional functions. Local exports retain per-file inventory.source_analysis metadata. Kotlin open identifiers and Swift nonisolated(unsafe) variable compatibility keep files partial and original evidence offsets. For Apple mobile device-info JSON, os_product=ipados explicitly selects iPadOS; default ios does not match iPadOS-only ranges. Apple custom ranges require CNA identity plus matching official bulletin branch/reference. Outside-published-affected-range does not prove patching; older CVE cache entries without identity need refetching. Android device-info may add soc_manufacturer, soc_model and vendor_security_patch; chipset and kernel bulletin entries use the older of the platform and vendor patch levels, and chipset_vendor match/mismatch is recorded beside the patch-level state without replacing it. `intel backfill --source android --since YYYY-MM` fetches an explicit bounded month range; Apple history is not backfilled.
|
|
47
47
|
|
|
48
|
-
|
|
48
|
+
Gradle catalog aliases referenced from shipped dependency configurations become declared candidates; unreferenced, test and build-tooling aliases stay unresolved usage. Application-module gradle.lockfile runtime coordinates are exact, so their matches are version-affected; other modules' lockfile coordinates stay declared candidates. A declared candidate is superseded (not-applicable) only when every shipping application that reaches it resolved the package; partial inputs keep every candidate, and with unparsed project references only an application's own declarations can be superseded. Lockfile-resolved findings get a new identity, so baselines and waivers need re-approval.
|
|
49
|
+
|
|
50
|
+
AAB analysis decodes the base and feature-module AAPT2 protobuf manifests and reads module DEX with module provenance. Feature components and deep links carry their module and declared delivery; identity and application flags come only from the base manifest. Resource merging and the installed split set remain unverified; bundle audits stay partial. IPA embedded framework, extension and dylib metadata retain separate roles and hashes without replacing the main identity. CodeDirectory page and entitlement hashes are recomputed for BINARY-IOS-CODE-INTEGRITY: a mismatch is modified, while encrypted or unsigned executables stay not-run or unverifiable. The CMS signature, certificate chain, team and provisioning are not authenticated, so signature_verified stays false. Native code paths remain unverified. Objective-C .m has bounded CST navigation/weak-digest candidates, always partial. NS_ENUM-family macros and one branch per preprocessor conditional are adapted; a function overlapping a normalized conditional is skipped as uncertain. .mm, other macros, dispatch and interprocedural flow remain unsupported.
|
|
49
51
|
|
|
50
52
|
The parser reports inventory.parser_isolation. APSA_PARSER_SANDBOX=auto uses system Seatbelt/bubblewrap when an input-free activation probe succeeds and otherwise records unavailable with the reason; required refuses unavailable isolation; off reports resource-limits-only. Once the parser has launched under isolation, a failure never retries unsandboxed. Availability in doctor is not activation evidence. Only a successful worker launch records enforced isolation.
|
|
@@ -15,7 +15,7 @@ For a local audit, run `scan TARGET`. Source folders, APK, AAB and IPA are accep
|
|
|
15
15
|
|
|
16
16
|
Use `scan TARGET --background` or MCP `audit_start` for long scans. Keep the returned job ID; poll `jobs status ID` / `jobs_status`, and use the corresponding cancel tool when requested. A completed job supplies a report ID. Failed, cancelled and interrupted jobs do not establish a successful audit. Closing the TUI or MCP client does not itself cancel persistent jobs.
|
|
17
17
|
|
|
18
|
-
CLI analysis runs locally and does not upload app source or builds. Online OSV queries send dependency names and versions. MCP context sends finding metadata to the invoking client, which may forward it to a hosted model. Follow the user's model/data policy; local analysis is separate from whether the product is open source.
|
|
18
|
+
CLI analysis runs locally and does not upload app source or builds. Online OSV queries send dependency names and versions, including Gradle catalog aliases used in shipped configurations and release-runtime lockfile coordinates from any module (private group IDs too). One online run queries at most 100 packages: those without a recent OSV result first, declared packages and non-Gradle manifests before transitive Gradle lockfile coordinates. The rest without such a result stay not-run and the audit incomplete; repeated runs advance through them. MCP context sends finding metadata to the invoking client, which may forward it to a hosted model. Follow the user's model/data policy; local analysis is separate from whether the product is open source.
|
|
19
19
|
|
|
20
20
|
Read exact finding evidence with `reports get REPORT_ID --finding FINDING_ID`, or MCP `reports_get`. Use `reports list` to resolve saved IDs. Keep app defects, included dependency CVEs and device/OS CVEs separate. Never infer device patch status from targetSdk/minSdk. Distinguish candidate, configuration-confirmed, version-affected and runtime-confirmed; a package match does not establish reachability or reproduction. Not-run, inconclusive and empty results do not establish safety.
|
|
21
21
|
|
|
@@ -43,8 +43,10 @@ Model report context is bounded and paginated. After resolving latest once, use
|
|
|
43
43
|
|
|
44
44
|
Portable team baselines require explicit authorized approved_by and approval_reference metadata. Export with reports export --format baseline or MCP reports_export_baseline, then pin its returned SHA-256 in independently reviewed CI configuration. Evaluate with --baseline-file/--baseline-sha256 or MCP baseline_path/baseline_sha256; do not derive the expected hash from an untrusted artifact in CI. The hash proves integrity against the approved value, not approver identity or a digital signature. scan --policy with --out writes a separate .decision.json; --decision-out selects another path. The decision includes policy/report hashes, approval provenance and waiver details.
|
|
45
45
|
|
|
46
|
-
AST coverage reports recognized/analyzed/skipped/bodyless function declarations; errors and unsupported syntax can hide additional functions. Local exports retain per-file inventory.source_analysis metadata. Kotlin open identifiers and Swift nonisolated(unsafe) variable compatibility keep files partial and original evidence offsets. For Apple mobile device-info JSON, os_product=ipados explicitly selects iPadOS; default ios does not match iPadOS-only ranges. Apple custom ranges require CNA identity plus matching official bulletin branch/reference. Outside-published-affected-range does not prove patching; older CVE cache entries without identity need refetching.
|
|
46
|
+
AST coverage reports recognized/analyzed/skipped/bodyless function declarations; errors and unsupported syntax can hide additional functions. Local exports retain per-file inventory.source_analysis metadata. Kotlin open identifiers and Swift nonisolated(unsafe) variable compatibility keep files partial and original evidence offsets. For Apple mobile device-info JSON, os_product=ipados explicitly selects iPadOS; default ios does not match iPadOS-only ranges. Apple custom ranges require CNA identity plus matching official bulletin branch/reference. Outside-published-affected-range does not prove patching; older CVE cache entries without identity need refetching. Android device-info may add soc_manufacturer, soc_model and vendor_security_patch; chipset and kernel bulletin entries use the older of the platform and vendor patch levels, and chipset_vendor match/mismatch is recorded beside the patch-level state without replacing it. `intel backfill --source android --since YYYY-MM` fetches an explicit bounded month range; Apple history is not backfilled.
|
|
47
47
|
|
|
48
|
-
|
|
48
|
+
Gradle catalog aliases referenced from shipped dependency configurations become declared candidates; unreferenced, test and build-tooling aliases stay unresolved usage. Application-module gradle.lockfile runtime coordinates are exact, so their matches are version-affected; other modules' lockfile coordinates stay declared candidates. A declared candidate is superseded (not-applicable) only when every shipping application that reaches it resolved the package; partial inputs keep every candidate, and with unparsed project references only an application's own declarations can be superseded. Lockfile-resolved findings get a new identity, so baselines and waivers need re-approval.
|
|
49
|
+
|
|
50
|
+
AAB analysis decodes the base and feature-module AAPT2 protobuf manifests and reads module DEX with module provenance. Feature components and deep links carry their module and declared delivery; identity and application flags come only from the base manifest. Resource merging and the installed split set remain unverified; bundle audits stay partial. IPA embedded framework, extension and dylib metadata retain separate roles and hashes without replacing the main identity. CodeDirectory page and entitlement hashes are recomputed for BINARY-IOS-CODE-INTEGRITY: a mismatch is modified, while encrypted or unsigned executables stay not-run or unverifiable. The CMS signature, certificate chain, team and provisioning are not authenticated, so signature_verified stays false. Native code paths remain unverified. Objective-C .m has bounded CST navigation/weak-digest candidates, always partial. NS_ENUM-family macros and one branch per preprocessor conditional are adapted; a function overlapping a normalized conditional is skipped as uncertain. .mm, other macros, dispatch and interprocedural flow remain unsupported.
|
|
49
51
|
|
|
50
52
|
The parser reports inventory.parser_isolation. APSA_PARSER_SANDBOX=auto uses system Seatbelt/bubblewrap when an input-free activation probe succeeds and otherwise records unavailable with the reason; required refuses unavailable isolation; off reports resource-limits-only. Once the parser has launched under isolation, a failure never retries unsandboxed. Availability in doctor is not activation evidence. Only a successful worker launch records enforced isolation.
|
|
@@ -15,7 +15,7 @@ For a local audit, run `scan TARGET`. Source folders, APK, AAB and IPA are accep
|
|
|
15
15
|
|
|
16
16
|
Use `scan TARGET --background` or MCP `audit_start` for long scans. Keep the returned job ID; poll `jobs status ID` / `jobs_status`, and use the corresponding cancel tool when requested. A completed job supplies a report ID. Failed, cancelled and interrupted jobs do not establish a successful audit. Closing the TUI or MCP client does not itself cancel persistent jobs.
|
|
17
17
|
|
|
18
|
-
CLI analysis runs locally and does not upload app source or builds. Online OSV queries send dependency names and versions. MCP context sends finding metadata to the invoking client, which may forward it to a hosted model. Follow the user's model/data policy; local analysis is separate from whether the product is open source.
|
|
18
|
+
CLI analysis runs locally and does not upload app source or builds. Online OSV queries send dependency names and versions, including Gradle catalog aliases used in shipped configurations and release-runtime lockfile coordinates from any module (private group IDs too). One online run queries at most 100 packages: those without a recent OSV result first, declared packages and non-Gradle manifests before transitive Gradle lockfile coordinates. The rest without such a result stay not-run and the audit incomplete; repeated runs advance through them. MCP context sends finding metadata to the invoking client, which may forward it to a hosted model. Follow the user's model/data policy; local analysis is separate from whether the product is open source.
|
|
19
19
|
|
|
20
20
|
Read exact finding evidence with `reports get REPORT_ID --finding FINDING_ID`, or MCP `reports_get`. Use `reports list` to resolve saved IDs. Keep app defects, included dependency CVEs and device/OS CVEs separate. Never infer device patch status from targetSdk/minSdk. Distinguish candidate, configuration-confirmed, version-affected and runtime-confirmed; a package match does not establish reachability or reproduction. Not-run, inconclusive and empty results do not establish safety.
|
|
21
21
|
|
|
@@ -43,8 +43,10 @@ Model report context is bounded and paginated. After resolving latest once, use
|
|
|
43
43
|
|
|
44
44
|
Portable team baselines require explicit authorized approved_by and approval_reference metadata. Export with reports export --format baseline or MCP reports_export_baseline, then pin its returned SHA-256 in independently reviewed CI configuration. Evaluate with --baseline-file/--baseline-sha256 or MCP baseline_path/baseline_sha256; do not derive the expected hash from an untrusted artifact in CI. The hash proves integrity against the approved value, not approver identity or a digital signature. scan --policy with --out writes a separate .decision.json; --decision-out selects another path. The decision includes policy/report hashes, approval provenance and waiver details.
|
|
45
45
|
|
|
46
|
-
AST coverage reports recognized/analyzed/skipped/bodyless function declarations; errors and unsupported syntax can hide additional functions. Local exports retain per-file inventory.source_analysis metadata. Kotlin open identifiers and Swift nonisolated(unsafe) variable compatibility keep files partial and original evidence offsets. For Apple mobile device-info JSON, os_product=ipados explicitly selects iPadOS; default ios does not match iPadOS-only ranges. Apple custom ranges require CNA identity plus matching official bulletin branch/reference. Outside-published-affected-range does not prove patching; older CVE cache entries without identity need refetching.
|
|
46
|
+
AST coverage reports recognized/analyzed/skipped/bodyless function declarations; errors and unsupported syntax can hide additional functions. Local exports retain per-file inventory.source_analysis metadata. Kotlin open identifiers and Swift nonisolated(unsafe) variable compatibility keep files partial and original evidence offsets. For Apple mobile device-info JSON, os_product=ipados explicitly selects iPadOS; default ios does not match iPadOS-only ranges. Apple custom ranges require CNA identity plus matching official bulletin branch/reference. Outside-published-affected-range does not prove patching; older CVE cache entries without identity need refetching. Android device-info may add soc_manufacturer, soc_model and vendor_security_patch; chipset and kernel bulletin entries use the older of the platform and vendor patch levels, and chipset_vendor match/mismatch is recorded beside the patch-level state without replacing it. `intel backfill --source android --since YYYY-MM` fetches an explicit bounded month range; Apple history is not backfilled.
|
|
47
47
|
|
|
48
|
-
|
|
48
|
+
Gradle catalog aliases referenced from shipped dependency configurations become declared candidates; unreferenced, test and build-tooling aliases stay unresolved usage. Application-module gradle.lockfile runtime coordinates are exact, so their matches are version-affected; other modules' lockfile coordinates stay declared candidates. A declared candidate is superseded (not-applicable) only when every shipping application that reaches it resolved the package; partial inputs keep every candidate, and with unparsed project references only an application's own declarations can be superseded. Lockfile-resolved findings get a new identity, so baselines and waivers need re-approval.
|
|
49
|
+
|
|
50
|
+
AAB analysis decodes the base and feature-module AAPT2 protobuf manifests and reads module DEX with module provenance. Feature components and deep links carry their module and declared delivery; identity and application flags come only from the base manifest. Resource merging and the installed split set remain unverified; bundle audits stay partial. IPA embedded framework, extension and dylib metadata retain separate roles and hashes without replacing the main identity. CodeDirectory page and entitlement hashes are recomputed for BINARY-IOS-CODE-INTEGRITY: a mismatch is modified, while encrypted or unsigned executables stay not-run or unverifiable. The CMS signature, certificate chain, team and provisioning are not authenticated, so signature_verified stays false. Native code paths remain unverified. Objective-C .m has bounded CST navigation/weak-digest candidates, always partial. NS_ENUM-family macros and one branch per preprocessor conditional are adapted; a function overlapping a normalized conditional is skipped as uncertain. .mm, other macros, dispatch and interprocedural flow remain unsupported.
|
|
49
51
|
|
|
50
52
|
The parser reports inventory.parser_isolation. APSA_PARSER_SANDBOX=auto uses system Seatbelt/bubblewrap when an input-free activation probe succeeds and otherwise records unavailable with the reason; required refuses unavailable isolation; off reports resource-limits-only. Once the parser has launched under isolation, a failure never retries unsandboxed. Availability in doctor is not activation evidence. Only a successful worker launch records enforced isolation.
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
name: Catalog usage and lockfile evidence against the Gradle oracle
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: ["dev/dependency-evidence", "dev/evidence-depth"]
|
|
6
|
+
paths: ["src/**", "benchmarks/dependency_eval.py", "benchmarks/dependency_truth*.json", "benchmarks/dependency_locks/**", ".github/workflows/dependency-evaluation.yml"]
|
|
7
|
+
workflow_dispatch:
|
|
8
|
+
|
|
9
|
+
permissions:
|
|
10
|
+
contents: read
|
|
11
|
+
actions: read
|
|
12
|
+
|
|
13
|
+
jobs:
|
|
14
|
+
evaluate:
|
|
15
|
+
runs-on: ubuntu-24.04
|
|
16
|
+
timeout-minutes: 30
|
|
17
|
+
steps:
|
|
18
|
+
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0
|
|
19
|
+
with:
|
|
20
|
+
persist-credentials: false
|
|
21
|
+
- uses: astral-sh/setup-uv@c18668ad3cf93ea998bef934396af7bb5c839dc7
|
|
22
|
+
with:
|
|
23
|
+
version: "0.12.1"
|
|
24
|
+
python-version: "3.12.13"
|
|
25
|
+
enable-cache: false
|
|
26
|
+
- run: uv sync --locked --extra dev
|
|
27
|
+
- name: Download the frozen oracle source archives
|
|
28
|
+
env:
|
|
29
|
+
GH_TOKEN: ${{ github.token }}
|
|
30
|
+
run: |
|
|
31
|
+
for RUN_ID in $(python3 -c 'import glob, json; print(" ".join(sorted({str(json.load(open(p))["oracle_run"]) for p in glob.glob("benchmarks/dependency_truth*.json")})))'); do
|
|
32
|
+
gh run download "$RUN_ID" --repo "$GITHUB_REPOSITORY" --pattern 'dependency-oracle-*' --dir "$RUNNER_TEMP/oracle/$RUN_ID"
|
|
33
|
+
done
|
|
34
|
+
- name: Scan pinned sources with APSA only; no Gradle or upstream code runs
|
|
35
|
+
env:
|
|
36
|
+
APSA_PARSER_LOCK_DIR: ${{ runner.temp }}/dependency-parser-locks
|
|
37
|
+
run: |
|
|
38
|
+
uv run --locked python -m benchmarks.dependency_eval \
|
|
39
|
+
--archives "$RUNNER_TEMP/oracle" --work "$RUNNER_TEMP/eval-work" \
|
|
40
|
+
--out "$RUNNER_TEMP/dependency-evidence/results.json"
|
|
41
|
+
- uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02
|
|
42
|
+
if: always()
|
|
43
|
+
with:
|
|
44
|
+
name: dependency-evidence-evaluation
|
|
45
|
+
path: ${{ runner.temp }}/dependency-evidence
|
|
46
|
+
retention-days: 90
|
|
47
|
+
if-no-files-found: error
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
name: Gradle dependency resolution oracle
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: ["dev/dependency-evidence"]
|
|
6
|
+
paths: ["benchmarks/dependency_cases.json", "benchmarks/dependency_oracle.py", ".github/workflows/dependency-oracle.yml"]
|
|
7
|
+
workflow_dispatch:
|
|
8
|
+
|
|
9
|
+
permissions:
|
|
10
|
+
contents: read
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
oracle:
|
|
14
|
+
name: Resolve ${{ matrix.case }} with Gradle
|
|
15
|
+
runs-on: ubuntu-24.04
|
|
16
|
+
timeout-minutes: 40
|
|
17
|
+
strategy:
|
|
18
|
+
fail-fast: false
|
|
19
|
+
matrix:
|
|
20
|
+
include:
|
|
21
|
+
- case: owncloud
|
|
22
|
+
java: "21"
|
|
23
|
+
- case: nextcloud
|
|
24
|
+
java: "21"
|
|
25
|
+
- case: home-assistant
|
|
26
|
+
java: "21"
|
|
27
|
+
- case: signal
|
|
28
|
+
java: "21"
|
|
29
|
+
- case: amaze
|
|
30
|
+
java: "21"
|
|
31
|
+
steps:
|
|
32
|
+
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0
|
|
33
|
+
with:
|
|
34
|
+
persist-credentials: false
|
|
35
|
+
path: apsa
|
|
36
|
+
- uses: actions/setup-java@de7274f081f381c8f8158605e0321c36c376e2e6 # v6.0.1
|
|
37
|
+
with:
|
|
38
|
+
distribution: temurin
|
|
39
|
+
java-version: ${{ matrix.java }}
|
|
40
|
+
- name: Fetch the pinned public source archive
|
|
41
|
+
id: fetch
|
|
42
|
+
working-directory: apsa
|
|
43
|
+
run: |
|
|
44
|
+
SHA="$(python3 -I benchmarks/dependency_oracle.py prepare --case "${{ matrix.case }}" --work "$RUNNER_TEMP/oracle")"
|
|
45
|
+
echo "sha256=$SHA" >> "$GITHUB_OUTPUT"
|
|
46
|
+
- name: Let Gradle resolve and lock every configuration of the app module
|
|
47
|
+
run: |
|
|
48
|
+
cat > "$RUNNER_TEMP/lock-all.gradle" <<'GRADLE'
|
|
49
|
+
// Isolated-projects compatible (Gradle 8.8+): lock every configuration of every project.
|
|
50
|
+
gradle.lifecycle.beforeProject { project ->
|
|
51
|
+
project.dependencyLocking { lockAllConfigurations() }
|
|
52
|
+
}
|
|
53
|
+
GRADLE
|
|
54
|
+
cd "$(find "$RUNNER_TEMP/oracle/source" -mindepth 1 -maxdepth 1 -type d)"
|
|
55
|
+
grep -h distributionUrl gradle/wrapper/gradle-wrapper.properties
|
|
56
|
+
MODULE="$(python3 -c 'import json,sys; print(next(c["module"] for c in json.load(open(sys.argv[1]))["cases"] if c["id"] == sys.argv[2]))' "$GITHUB_WORKSPACE/apsa/benchmarks/dependency_cases.json" "${{ matrix.case }}")"
|
|
57
|
+
rm -f "$(echo "${MODULE#:}" | tr : /)/gradle.lockfile"
|
|
58
|
+
./gradlew --no-daemon --init-script "$RUNNER_TEMP/lock-all.gradle" \
|
|
59
|
+
"$MODULE:dependencies" --write-locks > "$RUNNER_TEMP/oracle/${{ matrix.case }}.dependencies.txt" 2>&1 \
|
|
60
|
+
|| { tail -80 "$RUNNER_TEMP/oracle/${{ matrix.case }}.dependencies.txt"; exit 1; }
|
|
61
|
+
java -version 2>&1 | head -1 > "$RUNNER_TEMP/oracle/${{ matrix.case }}.java.txt"
|
|
62
|
+
./gradlew --no-daemon --version >> "$RUNNER_TEMP/oracle/${{ matrix.case }}.java.txt"
|
|
63
|
+
- name: Record the resolved oracle without running APSA
|
|
64
|
+
working-directory: apsa
|
|
65
|
+
run: python3 -I benchmarks/dependency_oracle.py record --case "${{ matrix.case }}" --work "$RUNNER_TEMP/oracle" --expected-sha256 "${{ steps.fetch.outputs.sha256 }}"
|
|
66
|
+
- uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02
|
|
67
|
+
if: always()
|
|
68
|
+
with:
|
|
69
|
+
name: dependency-oracle-${{ matrix.case }}
|
|
70
|
+
path: |
|
|
71
|
+
${{ runner.temp }}/oracle/*.zip
|
|
72
|
+
${{ runner.temp }}/oracle/*.json
|
|
73
|
+
${{ runner.temp }}/oracle/*.lockfile
|
|
74
|
+
${{ runner.temp }}/oracle/*.txt
|
|
75
|
+
retention-days: 90
|
|
76
|
+
if-no-files-found: error
|
|
77
|
+
# APSA is not installed or executed here; upstream Gradle build logic runs on this disposable runner without secrets.
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
name: Independent vulnerable and fixed source pairs
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: ["dev/evidence-depth"]
|
|
6
|
+
paths: ["src/**", "benchmarks/fpfn_eval.py", "benchmarks/fpfn_truth*.json", ".github/workflows/fpfn-evaluation.yml"]
|
|
7
|
+
workflow_dispatch:
|
|
8
|
+
|
|
9
|
+
permissions:
|
|
10
|
+
contents: read
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
evaluate:
|
|
14
|
+
runs-on: ubuntu-24.04
|
|
15
|
+
timeout-minutes: 90
|
|
16
|
+
steps:
|
|
17
|
+
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0
|
|
18
|
+
with:
|
|
19
|
+
persist-credentials: false
|
|
20
|
+
- uses: astral-sh/setup-uv@c18668ad3cf93ea998bef934396af7bb5c839dc7
|
|
21
|
+
with:
|
|
22
|
+
version: "0.12.1"
|
|
23
|
+
python-version: "3.12.13"
|
|
24
|
+
enable-cache: false
|
|
25
|
+
- run: uv sync --locked --extra dev
|
|
26
|
+
- name: Scan each pinned vulnerable and fixed commit with APSA only
|
|
27
|
+
run: |
|
|
28
|
+
uv run --locked python -m benchmarks.fpfn_eval \
|
|
29
|
+
--work "$RUNNER_TEMP/fpfn-work" --out "$RUNNER_TEMP/fpfn/results.json"
|
|
30
|
+
- name: Keep the captured public archives and reports
|
|
31
|
+
if: always()
|
|
32
|
+
run: |
|
|
33
|
+
mkdir -p "$RUNNER_TEMP/fpfn/captures"
|
|
34
|
+
cd "$RUNNER_TEMP/fpfn-work" 2>/dev/null && find . \( -name source.zip -o -name report.json \) -print0 \
|
|
35
|
+
| xargs -0 -I{} cp --parents {} "$RUNNER_TEMP/fpfn/captures/" || true
|
|
36
|
+
- uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02
|
|
37
|
+
if: always()
|
|
38
|
+
with:
|
|
39
|
+
name: independent-fpfn-pairs
|
|
40
|
+
path: ${{ runner.temp }}/fpfn
|
|
41
|
+
retention-days: 90
|
|
42
|
+
if-no-files-found: error
|
|
43
|
+
# Only APSA executes. No upstream app build, backend, device, private data or publishing.
|
|
@@ -11,9 +11,9 @@ install-skill:
|
|
|
11
11
|
|
|
12
12
|
test:
|
|
13
13
|
$(UV_RUN) pytest -q
|
|
14
|
-
$(UV_RUN) ruff check apsa src benchmarks scripts quaygate/cli.py tests/test_audit.py tests/test_benchmark.py tests/test_binary_analysis.py tests/test_foundations.py tests/test_intel.py tests/test_intel_product.py tests/test_interfaces.py tests/test_jobs.py tests/test_policy.py tests/test_runtime.py tests/test_source_analysis.py tests/test_unified.py tests/test_product_review.py tests/test_release_hardening.py tests/test_evidence106.py tests/test_workflows11.py tests/test_real_world_hardening.py tests/test_coverage_extension.py tests/test_next_hardening.py
|
|
15
|
-
$(UV_RUN) ruff format --check apsa src benchmarks scripts quaygate/cli.py tests/test_audit.py tests/test_benchmark.py tests/test_binary_analysis.py tests/test_foundations.py tests/test_intel.py tests/test_intel_product.py tests/test_interfaces.py tests/test_jobs.py tests/test_policy.py tests/test_runtime.py tests/test_source_analysis.py tests/test_unified.py tests/test_product_review.py tests/test_release_hardening.py tests/test_evidence106.py tests/test_workflows11.py tests/test_real_world_hardening.py tests/test_coverage_extension.py tests/test_next_hardening.py
|
|
16
|
-
$(UV_RUN) pyright apsa src benchmarks scripts quaygate/cli.py tests/test_audit.py tests/test_benchmark.py tests/test_binary_analysis.py tests/test_foundations.py tests/test_intel.py tests/test_intel_product.py tests/test_interfaces.py tests/test_jobs.py tests/test_policy.py tests/test_runtime.py tests/test_source_analysis.py tests/test_unified.py tests/test_product_review.py tests/test_release_hardening.py tests/test_evidence106.py tests/test_workflows11.py tests/test_real_world_hardening.py tests/test_coverage_extension.py tests/test_next_hardening.py
|
|
14
|
+
$(UV_RUN) ruff check apsa src benchmarks scripts quaygate/cli.py tests/test_audit.py tests/test_benchmark.py tests/test_binary_analysis.py tests/test_foundations.py tests/test_intel.py tests/test_intel_product.py tests/test_interfaces.py tests/test_jobs.py tests/test_policy.py tests/test_runtime.py tests/test_source_analysis.py tests/test_unified.py tests/test_product_review.py tests/test_release_hardening.py tests/test_evidence106.py tests/test_workflows11.py tests/test_real_world_hardening.py tests/test_coverage_extension.py tests/test_next_hardening.py tests/test_dependency_evidence.py tests/test_parser_depth.py tests/test_intel_history.py
|
|
15
|
+
$(UV_RUN) ruff format --check apsa src benchmarks scripts quaygate/cli.py tests/test_audit.py tests/test_benchmark.py tests/test_binary_analysis.py tests/test_foundations.py tests/test_intel.py tests/test_intel_product.py tests/test_interfaces.py tests/test_jobs.py tests/test_policy.py tests/test_runtime.py tests/test_source_analysis.py tests/test_unified.py tests/test_product_review.py tests/test_release_hardening.py tests/test_evidence106.py tests/test_workflows11.py tests/test_real_world_hardening.py tests/test_coverage_extension.py tests/test_next_hardening.py tests/test_dependency_evidence.py tests/test_parser_depth.py tests/test_intel_history.py
|
|
16
|
+
$(UV_RUN) pyright apsa src benchmarks scripts quaygate/cli.py tests/test_audit.py tests/test_benchmark.py tests/test_binary_analysis.py tests/test_foundations.py tests/test_intel.py tests/test_intel_product.py tests/test_interfaces.py tests/test_jobs.py tests/test_policy.py tests/test_runtime.py tests/test_source_analysis.py tests/test_unified.py tests/test_product_review.py tests/test_release_hardening.py tests/test_evidence106.py tests/test_workflows11.py tests/test_real_world_hardening.py tests/test_coverage_extension.py tests/test_next_hardening.py tests/test_dependency_evidence.py tests/test_parser_depth.py tests/test_intel_history.py
|
|
17
17
|
|
|
18
18
|
benchmark:
|
|
19
19
|
$(UV_RUN) python benchmarks/run.py
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: apsa
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.3.0
|
|
4
4
|
Summary: APSA (앱사): evidence-first security audits for Android and iOS
|
|
5
5
|
Project-URL: Homepage, https://github.com/ictechgy/apsa
|
|
6
6
|
Project-URL: Repository, https://github.com/ictechgy/apsa
|
|
@@ -69,14 +69,69 @@ CVE matches until build usage or resolved versions are supplied. New rules
|
|
|
69
69
|
`OBJC-CRYPTO-WEAK-HASH`, `OBJC-WEBVIEW-UNTRUSTED-REQUEST`) can add findings
|
|
70
70
|
relative to existing 1.1 baselines.
|
|
71
71
|
|
|
72
|
+
APSA 1.3 links Gradle version-catalog aliases to the shipped dependency
|
|
73
|
+
configurations that use them and reads application-module `gradle.lockfile`
|
|
74
|
+
coordinates as resolved versions. It also decodes AAB feature-module manifests,
|
|
75
|
+
recomputes Mach-O CodeDirectory page and entitlement hashes without
|
|
76
|
+
authenticating the signature, adapts more Swift and Objective-C syntax, and can
|
|
77
|
+
backfill an explicit range of Android security bulletins with SoC vendor and
|
|
78
|
+
vendor patch-level context. See the
|
|
79
|
+
[dependency evidence results](https://github.com/ictechgy/apsa/blob/main/benchmarks/DEPENDENCY_RESULTS.md),
|
|
80
|
+
the [independent source pairs](https://github.com/ictechgy/apsa/blob/main/benchmarks/FPFN_RESULTS.md)
|
|
81
|
+
and [analysis scope and limits](https://github.com/ictechgy/apsa/blob/main/docs/NEXT_ANALYSIS.md).
|
|
82
|
+
|
|
83
|
+
**Upgrading from 1.2.**
|
|
84
|
+
|
|
85
|
+
- Catalog aliases referenced from shipped configurations become `declared`
|
|
86
|
+
candidates and can receive CVE matches again; unreferenced, test-only and
|
|
87
|
+
build-tooling aliases stay unresolved. Application-module lockfile coordinates
|
|
88
|
+
are exact, so their matches are `version-affected`, and the default policy
|
|
89
|
+
fails on high and critical ones; other modules' lockfile coordinates stay
|
|
90
|
+
`declared` candidates. A declared candidate that every shipping application
|
|
91
|
+
resolved is superseded and leaves CVE correlation. Partial inputs keep every
|
|
92
|
+
candidate, and with unparsed project references only an application's own
|
|
93
|
+
declarations can be superseded.
|
|
94
|
+
- Lockfile assumptions: APSA does not check that dependency locking is enabled
|
|
95
|
+
or that the lockfile is current, and it merges the release runtime classpaths
|
|
96
|
+
of every application module (flavors and wear, TV or automotive apps).
|
|
97
|
+
`--source-module` scans only that module's directory, so a root version
|
|
98
|
+
catalog and library-module declarations outside it are not read.
|
|
99
|
+
- Baselines and waivers: a lockfile-resolved finding has a new location
|
|
100
|
+
(`gradle.lockfile`) and status, so `only_new` treats it as new and waivers for
|
|
101
|
+
the old finding ID no longer match. Re-approve baselines after upgrading.
|
|
102
|
+
- `--online` sends catalog aliases used in shipped configurations and the
|
|
103
|
+
release-runtime lockfile coordinates of every module, transitive ones and
|
|
104
|
+
private group IDs included, to OSV; there is no exclusion list. One run
|
|
105
|
+
queries at most 100 packages: those without an OSV result from the last day
|
|
106
|
+
first, and among them build-file declarations before lockfile coordinates in
|
|
107
|
+
lockfile order. Measured application lockfiles hold 179–412 shipped
|
|
108
|
+
coordinates, so a single run leaves the rest `not-run`: a required
|
|
109
|
+
`DEPENDENCY-CVE` rule cannot pass, the online audit is incomplete and the
|
|
110
|
+
default `fail_on_partial` policy exits 3. Repeated runs within a day advance
|
|
111
|
+
through the remainder, and a package with an OSV result from the last day
|
|
112
|
+
counts as checked. Unresolved catalog aliases and ecosystems OSV does not
|
|
113
|
+
support are reported as online errors on every run, so they keep the online
|
|
114
|
+
audit incomplete however many runs follow.
|
|
115
|
+
- IPA reports gain `BINARY-IOS-CODE-INTEGRITY`. Consistent hashes do not prove
|
|
116
|
+
authenticity, because a modified binary that was re-signed is consistent. A
|
|
117
|
+
mismatch adds a warning, not a finding; App Store encrypted and unsigned
|
|
118
|
+
executables stay `not-run`.
|
|
119
|
+
- `intel sync` refreshes only the recent Android bulletin window; use
|
|
120
|
+
`intel backfill` for older months. Records cached by 1.2 derive their vendor
|
|
121
|
+
scope from the component name; entries outside chipset and kernel sections use
|
|
122
|
+
the platform patch level only. AAB feature-module installation stays unknown.
|
|
123
|
+
- Adapted Swift and Objective-C files stay partial, and an Objective-C function
|
|
124
|
+
overlapping a normalized preprocessor conditional is skipped as uncertain.
|
|
125
|
+
Unmodified 1.2 skills upgrade with `apsa skill install`.
|
|
126
|
+
|
|
72
127
|
## What it checks
|
|
73
128
|
|
|
74
129
|
| Area | Available checks |
|
|
75
130
|
| --- | --- |
|
|
76
|
-
| Source code | Java/Kotlin/Swift AST analysis; bounded Objective-C `.m` candidates; WebView and deep-link patterns; Manifest, Info.plist, storage, and dependency inspection |
|
|
77
|
-
| Android builds | DEX calls and constant flow; AAB base
|
|
78
|
-
| iOS builds | Mach-O headers, including embedded framework/extension metadata; limited entitlement/configuration checks (embedded XML entitlements, ATS exceptions, provisioning indicators); PIE, canary, and string evidence |
|
|
79
|
-
| Public intelligence | Apple/Android advisories, CVE, CISA KEV, OWASP guidance, and OSV dependency correlation |
|
|
131
|
+
| Source code | Java/Kotlin/Swift AST analysis; bounded Objective-C `.m` candidates; WebView and deep-link patterns; Manifest, Info.plist, storage, and dependency inspection, including Gradle catalog usage and application lockfiles |
|
|
132
|
+
| Android builds | DEX calls and constant flow; AAB base and feature-module manifests and module DEX (always partial); resources and network configuration; exported components/providers; signing-block and v1 certificate evidence; ELF hardening |
|
|
133
|
+
| iOS builds | Mach-O headers, including embedded framework/extension metadata; CodeDirectory page and entitlement hash integrity (not signature authentication); limited entitlement/configuration checks (embedded XML entitlements, ATS exceptions, provisioning indicators); PIE, canary, and string evidence |
|
|
134
|
+
| Public intelligence | Apple/Android advisories with bounded Android bulletin backfill, CVE, CISA KEV, OWASP guidance, and OSV dependency correlation |
|
|
80
135
|
| Reports and CI | SQLite history, comparison and reassessment, JSON/Markdown/SARIF export, coverage requirements, and expiring waivers |
|
|
81
136
|
| Runtime | Prepared scenarios for owned Android test apps and iOS simulator apps; physical iOS devices are unsupported |
|
|
82
137
|
| Model integration | stdio MCP tools/resources and packaged skills, without a required model provider or LLM API key |
|
|
@@ -92,7 +147,7 @@ Install **uv** on **macOS or Linux**. APSA targets **CPython 3.11 and 3.12**; no
|
|
|
92
147
|
Install the published package from [PyPI](https://pypi.org/project/apsa/):
|
|
93
148
|
|
|
94
149
|
```sh
|
|
95
|
-
uv tool install --python 3.12 apsa==1.
|
|
150
|
+
uv tool install --python 3.12 apsa==1.3.0
|
|
96
151
|
apsa --version
|
|
97
152
|
apsa doctor --json
|
|
98
153
|
apsa demo --out ./apsa-demo
|
|
@@ -139,8 +194,9 @@ A default `scan` reads local files and cached intelligence without uploading sou
|
|
|
139
194
|
| `apsa scan TARGET` | Uses local inputs and cached intelligence |
|
|
140
195
|
| `apsa intel sync` | Fetches public vulnerability sources |
|
|
141
196
|
| `apsa intel watch` | Polls public sources and reassesses saved inventories; does not reread app files or implicitly query OSV |
|
|
142
|
-
| `apsa
|
|
143
|
-
| `apsa
|
|
197
|
+
| `apsa intel backfill --source android --since YYYY-MM` | Fetches an explicit, bounded range of monthly Android security bulletins |
|
|
198
|
+
| `apsa scan TARGET --online` | Sends discovered dependency names and versions to OSV, including Gradle catalog aliases used in shipped configurations and release-runtime lockfile coordinates of every module; at most 100 packages per run, unchecked build-file declarations first |
|
|
199
|
+
| `apsa intel watch --online` | Also sends saved dependency names and versions to OSV, with the same budget |
|
|
144
200
|
|
|
145
201
|
```sh
|
|
146
202
|
apsa intel sync
|
|
@@ -259,7 +315,9 @@ A reproducible [APSA/MobSF comparison](benchmarks/COMPETITIVE.md) and its
|
|
|
259
315
|
[recorded results](benchmarks/COMPETITIVE_RESULTS.md) use freshly generated
|
|
260
316
|
synthetic source projects and APKs. They measure development candidates
|
|
261
317
|
recorded before APSA 1.2.0, not the published package; these results are not
|
|
262
|
-
production accuracy estimates.
|
|
318
|
+
production accuracy estimates. A rerun on the APSA 1.3.0 release runtime with
|
|
319
|
+
newly generated inputs reproduced the candidate figures (see
|
|
320
|
+
[RELEASE_READINESS.md](https://github.com/ictechgy/apsa/blob/main/RELEASE_READINESS.md)).
|
|
263
321
|
|
|
264
322
|
A separate [public-source and CVE evaluation](benchmarks/REAL_WORLD.md) records
|
|
265
323
|
[initial results](benchmarks/REAL_WORLD_RESULTS.md) on six pinned app source
|
|
@@ -281,4 +339,12 @@ covers AAB/IPA metadata, Objective-C, parser isolation and two independently
|
|
|
281
339
|
labeled public sources. It records selected CVE boundary agreement, unresolved
|
|
282
340
|
catalog usage and remaining parser gaps separately.
|
|
283
341
|
|
|
342
|
+
The [dependency evidence evaluation](benchmarks/DEPENDENCY_RESULTS.md) compares
|
|
343
|
+
APSA's Gradle catalog usage and lockfile coordinates with Gradle's own
|
|
344
|
+
resolution on three frozen holdouts of public apps, keeping first blind results
|
|
345
|
+
separate from reruns after the truth was seen. The
|
|
346
|
+
[independent source pairs](benchmarks/FPFN_RESULTS.md) score vulnerable and
|
|
347
|
+
fixed commits of public projects against truth frozen before scanning. Both are
|
|
348
|
+
narrow samples, not general accuracy estimates.
|
|
349
|
+
|
|
284
350
|
The source is publicly available on [GitHub](https://github.com/ictechgy/apsa). [LICENSE](https://github.com/ictechgy/apsa/blob/main/LICENSE) preserves the original Quaygate MIT notice. This publication does not declare an additional license for the combined product.
|
|
@@ -31,14 +31,61 @@ version catalog에만 선언된 의존성은 빌드 사용 근거나 해결 버
|
|
|
31
31
|
`OBJC-CRYPTO-WEAK-HASH`, `OBJC-WEBVIEW-UNTRUSTED-REQUEST`)은 기존 1.1 기준선 대비
|
|
32
32
|
새 발견 항목을 추가할 수 있습니다.
|
|
33
33
|
|
|
34
|
+
APSA 1.3은 Gradle version catalog alias를 실제로 사용하는 출하 의존성 구성과
|
|
35
|
+
연결하고, application 모듈의 `gradle.lockfile` 좌표를 해결된 버전으로 읽습니다.
|
|
36
|
+
AAB feature 모듈 매니페스트를 해석하고, 서명을 인증하지 않은 채 Mach-O
|
|
37
|
+
CodeDirectory의 페이지·entitlement 해시를 다시 계산하며, 더 많은 Swift·Objective-C
|
|
38
|
+
구문을 호환 처리합니다. 지정한 기간의 Android 보안 공지를 SoC 제조사·vendor 패치
|
|
39
|
+
수준 정보와 함께 소급 수집할 수 있습니다.
|
|
40
|
+
[의존성 근거 결과](https://github.com/ictechgy/apsa/blob/main/benchmarks/DEPENDENCY_RESULTS.ko.md),
|
|
41
|
+
[독립 취약·수정 소스 쌍](https://github.com/ictechgy/apsa/blob/main/benchmarks/FPFN_RESULTS.ko.md),
|
|
42
|
+
[분석 범위와 한계](https://github.com/ictechgy/apsa/blob/main/docs/NEXT_ANALYSIS.md)를 참고하세요.
|
|
43
|
+
|
|
44
|
+
**1.2에서 업그레이드할 때.**
|
|
45
|
+
|
|
46
|
+
- 출하 구성에서 참조하는 catalog alias는 `declared` 후보가 되어 다시 CVE를 대조할 수
|
|
47
|
+
있습니다. 참조되지 않거나 테스트·빌드 도구용인 alias는 미확인으로 남습니다.
|
|
48
|
+
application 모듈 lockfile 좌표는 정확한 버전이므로 대조 결과가 `version-affected`가
|
|
49
|
+
되며, 기본 정책은 high·critical 항목에서 실패합니다. 다른 모듈의 lockfile 좌표는
|
|
50
|
+
`declared` 후보로 남습니다. 모든 출하 앱이 해결한 선언 후보는 대체(superseded)되어 CVE
|
|
51
|
+
대조에서 빠집니다. 부분 입력에서는 모든 후보를 유지하며, 해석하지 못한 project 참조가
|
|
52
|
+
있으면 application 자신의 선언만 대체될 수 있습니다.
|
|
53
|
+
- lockfile 전제: APSA는 dependency locking 활성화나 lockfile 최신 여부를 확인하지 않으며,
|
|
54
|
+
모든 application 모듈(flavor, wear·TV·automotive 앱 포함)의 release runtime classpath를
|
|
55
|
+
합칩니다. `--source-module`은 해당 모듈 폴더만 검사하므로 그 밖의 루트 version catalog와
|
|
56
|
+
library 모듈 선언은 읽지 않습니다.
|
|
57
|
+
- 기준선·예외: lockfile로 해결된 발견 항목은 위치(`gradle.lockfile`)와 상태가 바뀌므로
|
|
58
|
+
`only_new`는 새 항목으로 보고, 이전 발견 ID에 대한 예외는 더 이상 일치하지 않습니다.
|
|
59
|
+
업그레이드 후 기준선을 다시 승인하세요.
|
|
60
|
+
- `--online`은 출하 구성에서 쓰는 catalog alias와 모든 모듈 lockfile의 release runtime
|
|
61
|
+
좌표(전이 좌표·비공개 group ID 포함)를 OSV에 보내며 제외 목록은 없습니다. 한 번에 최대
|
|
62
|
+
100개 패키지를 조회하며, 최근 하루 안의 OSV 결과가 없는 패키지를 먼저, 그중에서는 빌드
|
|
63
|
+
파일 선언을 lockfile 좌표보다 먼저 조회합니다. 측정한 application lockfile은 출하 좌표가
|
|
64
|
+
179~412개였으므로 한 번의 실행으로는 나머지가 `not-run`으로 남아, 필수 `DEPENDENCY-CVE`
|
|
65
|
+
규칙은 통과할 수 없고 온라인 감사는 불완전하며 기본 `fail_on_partial` 정책은 종료 코드 3을
|
|
66
|
+
반환합니다. 하루 안에 반복 실행하면 남은 패키지를 이어서 조회하며, 최근 하루 안의 OSV
|
|
67
|
+
결과가 있는 패키지는 검사된 것으로 봅니다. 미확인 catalog alias와 OSV가 지원하지 않는
|
|
68
|
+
생태계는 매 실행마다 온라인 오류로 보고되므로, 반복 실행해도 온라인 감사는 불완전하게
|
|
69
|
+
남습니다.
|
|
70
|
+
- IPA 보고서에 `BINARY-IOS-CODE-INTEGRITY`가 추가됩니다. 해시가 일치해도 진위를 증명하지
|
|
71
|
+
않습니다. 수정 후 다시 서명한 바이너리도 일치하기 때문입니다. 불일치는 발견 항목이 아닌
|
|
72
|
+
경고를 추가하며, App Store 암호화·서명 없는 실행 파일은 `not-run`입니다.
|
|
73
|
+
- `intel sync`는 최근 Android 공지 범위만 갱신하므로 이전 달은 `intel backfill`을
|
|
74
|
+
사용하세요. 1.2가 캐시한 공지는 컴포넌트 이름에서 vendor 범위를 도출하며, 칩셋·커널
|
|
75
|
+
절이 아닌 항목은 플랫폼 패치 수준만 사용합니다. AAB feature 모듈의 설치 여부는 알 수
|
|
76
|
+
없습니다.
|
|
77
|
+
- 호환 처리한 Swift·Objective-C 파일은 부분 분석으로 남고, 정규화한 전처리 조건부와
|
|
78
|
+
겹치는 Objective-C 함수는 불확실로 분석에서 제외합니다. 수정하지 않은 1.2 스킬은
|
|
79
|
+
`apsa skill install`로 업그레이드됩니다.
|
|
80
|
+
|
|
34
81
|
## 검사 범위
|
|
35
82
|
|
|
36
83
|
| 영역 | 제공하는 검사 |
|
|
37
84
|
| --- | --- |
|
|
38
|
-
| 소스 코드 | Java·Kotlin·Swift AST 분석, 제한된 Objective-C `.m` 후보, WebView·딥링크 패턴, Manifest·Info.plist·저장소·의존성 검사 |
|
|
39
|
-
| Android 빌드 | DEX 호출·상수 흐름, AAB base
|
|
40
|
-
| iOS 빌드 | 내장 framework·확장 메타데이터를 포함한 Mach-O 헤더, 제한적인 entitlement·설정 검사(내장 XML entitlement, ATS 예외, provisioning 지표), PIE·카나리·문자열 근거 |
|
|
41
|
-
| 공개 취약점 정보 | Apple·Android
|
|
85
|
+
| 소스 코드 | Java·Kotlin·Swift AST 분석, 제한된 Objective-C `.m` 후보, WebView·딥링크 패턴, Manifest·Info.plist·저장소·의존성 검사(Gradle catalog 사용 근거·application lockfile 포함) |
|
|
86
|
+
| Android 빌드 | DEX 호출·상수 흐름, AAB base·feature 모듈 매니페스트와 모듈 DEX(항상 부분 감사), 리소스·네트워크 설정, exported 컴포넌트·provider, 서명 블록·v1 인증서 근거, ELF 하드닝 |
|
|
87
|
+
| iOS 빌드 | 내장 framework·확장 메타데이터를 포함한 Mach-O 헤더, CodeDirectory 페이지·entitlement 해시 무결성(서명 인증 아님), 제한적인 entitlement·설정 검사(내장 XML entitlement, ATS 예외, provisioning 지표), PIE·카나리·문자열 근거 |
|
|
88
|
+
| 공개 취약점 정보 | Apple·Android 공지(지정 기간의 Android 공지 소급 수집 포함), CVE, CISA KEV, OWASP 가이드, OSV 의존성 대조 |
|
|
42
89
|
| 보고서와 CI | SQLite 이력, 비교·재평가, JSON·Markdown·SARIF 내보내기, 필수 검사 범위, 만료일이 있는 예외 |
|
|
43
90
|
| 런타임 | 소유한 Android 테스트 앱과 iOS 시뮬레이터 앱의 준비된 시나리오. 실제 iOS 기기는 미지원 |
|
|
44
91
|
| 모델 연결 | stdio MCP 도구·리소스와 패키지 스킬. 특정 모델 제공자나 LLM API 키는 필수가 아님 |
|
|
@@ -54,7 +101,7 @@ OWASP 매핑은 관련 검사를 설명합니다. APSA는 MASVS 준수를 인증
|
|
|
54
101
|
[PyPI](https://pypi.org/project/apsa/)에서 배포 패키지를 설치합니다.
|
|
55
102
|
|
|
56
103
|
```sh
|
|
57
|
-
uv tool install --python 3.12 apsa==1.
|
|
104
|
+
uv tool install --python 3.12 apsa==1.3.0
|
|
58
105
|
apsa --version
|
|
59
106
|
apsa doctor --json
|
|
60
107
|
apsa demo --out ./apsa-demo
|
|
@@ -101,8 +148,9 @@ apsa tui
|
|
|
101
148
|
| `apsa scan TARGET` | 로컬 입력과 캐시 사용 |
|
|
102
149
|
| `apsa intel sync` | 공개 취약점 정보 수집 |
|
|
103
150
|
| `apsa intel watch` | 공개 피드를 폴링하고 저장된 인벤토리를 재평가. 앱 파일을 다시 읽거나 OSV를 자동 조회하지 않음 |
|
|
104
|
-
| `apsa
|
|
105
|
-
| `apsa
|
|
151
|
+
| `apsa intel backfill --source android --since YYYY-MM` | 지정한 제한된 기간의 월별 Android 보안 공지를 수집 |
|
|
152
|
+
| `apsa scan TARGET --online` | 발견한 의존성 이름·버전을 OSV에 전송. 출하 구성에서 쓰는 Gradle catalog alias와 모든 모듈 lockfile의 release runtime 좌표를 포함하며 한 번에 최대 100개 패키지, 미검사 빌드 파일 선언 우선 |
|
|
153
|
+
| `apsa intel watch --online` | 저장된 의존성 이름·버전도 같은 한도로 OSV에 전송 |
|
|
106
154
|
|
|
107
155
|
```sh
|
|
108
156
|
apsa intel sync
|
|
@@ -220,6 +268,8 @@ make release RELEASE_OUT=dist/apsa-local-release
|
|
|
220
268
|
새로 생성한 합성 소스 프로젝트와 APK를 사용하는 [APSA/MobSF 비교](benchmarks/COMPETITIVE.md)(영문)와
|
|
221
269
|
[측정 결과](benchmarks/COMPETITIVE_RESULTS.ko.md)를 제공합니다. APSA 1.2.0 배포 전의
|
|
222
270
|
개발 후보를 측정한 결과이며 배포 패키지의 측정이나 운영 앱의 정확도를 나타내지 않습니다.
|
|
271
|
+
APSA 1.3.0 릴리스 런타임에서 새로 생성한 입력으로 다시 실행해 후보 수치를 재현했습니다
|
|
272
|
+
([RELEASE_READINESS.md](https://github.com/ictechgy/apsa/blob/main/RELEASE_READINESS.md)).
|
|
223
273
|
|
|
224
274
|
별도의 [공개 소스·CVE 평가](benchmarks/REAL_WORLD.ko.md)와
|
|
225
275
|
[최초 결과](benchmarks/REAL_WORLD_RESULTS.ko.md)는 커밋을 고정한 앱 소스 6개,
|
|
@@ -240,4 +290,10 @@ make release RELEASE_OUT=dist/apsa-local-release
|
|
|
240
290
|
Objective-C, 파서 격리와 독립 라벨의 새 공개 소스 2개를 다룹니다.
|
|
241
291
|
선택한 CVE 경계 일치, catalog 사용 미확인과 남은 구문 누락을 별도로 기록합니다.
|
|
242
292
|
|
|
293
|
+
[의존성 근거 평가](benchmarks/DEPENDENCY_RESULTS.ko.md)는 APSA의 Gradle catalog 사용 근거와
|
|
294
|
+
lockfile 좌표를 공개 앱 holdout 3개에서 Gradle 자체 해석과 비교하며, 최초 블라인드 결과와
|
|
295
|
+
정답을 본 뒤의 재실행을 구분합니다. [독립 취약·수정 소스 쌍](benchmarks/FPFN_RESULTS.ko.md)은
|
|
296
|
+
공개 프로젝트의 취약·수정 커밋을 스캔 전에 고정한 정답으로 채점합니다. 둘 다 좁은 표본이며
|
|
297
|
+
일반적인 정확도 추정이 아닙니다.
|
|
298
|
+
|
|
243
299
|
소스는 [GitHub](https://github.com/ictechgy/apsa)에 공개되어 있습니다. [LICENSE](https://github.com/ictechgy/apsa/blob/main/LICENSE)는 원래 Quaygate의 MIT 고지를 보존합니다. 이번 공개는 통합 제품에 추가 라이선스를 선언하지 않습니다.
|