Packages
mob_dev
0.5.9
0.6.23
0.6.22
0.6.21
0.6.20
0.6.19
0.6.18
0.6.17
0.6.16
0.6.15
0.6.14
0.6.13
0.6.12
0.6.11
0.6.10
0.6.9
0.6.8
0.6.7
0.6.6
0.6.5
0.6.4
0.6.3
0.6.2
0.6.1
0.6.0
0.5.17
0.5.16
0.5.15
0.5.14
0.5.13
0.5.12
0.5.11
0.5.10
0.5.9
0.5.8
0.5.7
0.5.6
0.5.5
0.5.4
0.5.3
0.5.2
0.5.1
0.5.0
0.4.0
0.3.37
0.3.35
0.3.34
0.3.33
0.3.28
0.3.26
0.3.23
0.3.21
0.3.19
0.3.18
0.3.17
0.3.16
0.3.15
0.3.14
0.3.13
0.3.12
0.3.11
0.3.10
0.3.9
0.3.8
0.3.7
0.3.6
0.3.5
0.3.4
0.3.3
0.3.2
0.3.1
0.3.0
0.2.18
0.2.17
0.2.15
0.2.14
0.2.13
0.2.12
0.2.11
0.2.10
0.2.9
0.2.8
0.2.7
0.2.6
0.2.5
0.2.4
0.2.3
0.2.2
0.2.1
0.2.0
0.1.0
Development tooling for the Mob mobile framework
Current section
Files
Jump to
Current section
Files
lib/mob_dev/security_scan/layers/swift_deps.ex
defmodule MobDev.SecurityScan.Layers.SwiftDeps do
@moduledoc """
Audits iOS dependencies via `osv-scanner` recursively over the
`ios/` directory.
## What gets scanned
`osv-scanner` understands:
* `Package.resolved` — Swift Package Manager (when SwiftPM is used)
* `Podfile.lock` — CocoaPods
Mob's iOS template does not depend on either by default — the iOS
bridge is built with raw `.m` / `.swift` files plus the bundled OTP
static libs (libcrypto.a, libbeam.a, etc.). Those static libs are
audited by the `:bundled_runtime` layer; this layer only covers
*application-level* iOS dependencies.
In a stock Mob app this layer typically reports `:not_applicable`,
which is the correct signal — there's no iOS dependency manifest
to audit because the app pulls nothing from CocoaPods/SwiftPM.
"""
@behaviour MobDev.SecurityScan.Layer
alias MobDev.SecurityScan.{LayerResult, OsvScanner}
@impl true
def name, do: :swift_deps
@impl true
def run(opts) do
project_root = Keyword.get(opts, :project_root, File.cwd!())
ios_dir = Path.join(project_root, "ios")
cond do
not File.dir?(ios_dir) ->
%LayerResult{
name: :swift_deps,
status: :not_applicable,
notes: ["no ios/ directory at #{ios_dir}"]
}
not has_swift_manifest?(ios_dir) ->
%LayerResult{
name: :swift_deps,
status: :not_applicable,
notes: [
"no Package.resolved or Podfile.lock under #{ios_dir}",
"Mob iOS apps typically have neither — bundled OpenSSL/SQLite are audited by :bundled_runtime"
]
}
true ->
run_scan(ios_dir, opts)
end
end
defp has_swift_manifest?(ios_dir) do
paths = [
Path.join([ios_dir, "Package.resolved"]),
Path.join([ios_dir, "**/Package.resolved"]),
Path.join([ios_dir, "Podfile.lock"]),
Path.join([ios_dir, "**/Podfile.lock"])
]
Enum.any?(paths, &(Path.wildcard(&1) != []))
end
defp run_scan(ios_dir, opts) do
osv_scan = Keyword.get(opts, :osv_scan_fn, &OsvScanner.scan/3)
case osv_scan.({:directory, ios_dir}, :swift_deps, []) do
{:ok, findings} ->
%LayerResult{
name: :swift_deps,
status: :ok,
findings: findings,
tools_used: ["osv-scanner"],
notes: ["osv-scanner: #{length(findings)} finding(s) under #{ios_dir}"]
}
{:error, :not_installed} ->
%LayerResult{
name: :swift_deps,
status: :tool_missing,
notes: ["osv-scanner not installed — install: brew install osv-scanner"]
}
{:error, {:scan_failed, reason}} ->
%LayerResult{
name: :swift_deps,
status: :error,
tools_used: ["osv-scanner"],
error: "osv-scanner failed: #{reason}"
}
{:error, {:not_found, path}} ->
%LayerResult{
name: :swift_deps,
status: :not_applicable,
notes: ["target path missing: #{path}"]
}
end
end
end