source-map-tauri 0.3.0

Static Tauri app scanner that emits Meilisearch-ready NDJSON
Documentation
use std::collections::{BTreeMap, BTreeSet};

use anyhow::Result;
use serde_json::Value;

use crate::{
    ids::document_id,
    model::{ArtifactDoc, EdgeDoc, WarningDoc},
};

fn edge(
    repo: &str,
    edge_type: &str,
    from: &ArtifactDoc,
    to: &ArtifactDoc,
    reason: &str,
    confidence: f32,
) -> EdgeDoc {
    EdgeDoc {
        id: document_id(
            repo,
            "edge",
            from.source_path.as_deref(),
            from.line_start,
            Some(&format!("{edge_type}:{}:{}", from.id, to.id)),
        ),
        repo: repo.to_owned(),
        kind: "edge".to_owned(),
        edge_type: edge_type.to_owned(),
        from_id: from.id.clone(),
        from_kind: from.kind.clone(),
        from_name: from.name.clone(),
        to_id: to.id.clone(),
        to_kind: to.kind.clone(),
        to_name: to.name.clone(),
        confidence,
        reason: reason.to_owned(),
        source_path: from.source_path.clone(),
        line_start: from.line_start,
        risk_level: from.risk_level.clone(),
        updated_at: chrono::Utc::now().to_rfc3339(),
    }
}

fn warning(
    repo: &str,
    warning_type: &str,
    message: String,
    related: Option<&ArtifactDoc>,
    risk_level: &str,
) -> WarningDoc {
    WarningDoc {
        id: document_id(
            repo,
            "warning",
            related.and_then(|item| item.source_path.as_deref()),
            related.and_then(|item| item.line_start),
            Some(warning_type),
        ),
        repo: repo.to_owned(),
        kind: "warning".to_owned(),
        warning_type: warning_type.to_owned(),
        severity: if risk_level == "critical" {
            "error"
        } else {
            "warning"
        }
        .to_owned(),
        message,
        source_path: related.and_then(|item| item.source_path.clone()),
        line_start: related.and_then(|item| item.line_start),
        related_id: related.map(|item| item.id.clone()),
        risk_level: risk_level.to_owned(),
        remediation: None,
        updated_at: chrono::Utc::now().to_rfc3339(),
    }
}

pub fn link_all(
    artifacts: &mut [ArtifactDoc],
    warnings: &mut Vec<WarningDoc>,
) -> Result<Vec<EdgeDoc>> {
    let mut edges = Vec::new();
    let mut by_name: BTreeMap<String, Vec<usize>> = BTreeMap::new();
    let mut by_invoke: BTreeMap<String, usize> = BTreeMap::new();
    let mut by_kind: BTreeMap<String, Vec<usize>> = BTreeMap::new();

    for (index, artifact) in artifacts.iter().enumerate() {
        if let Some(name) = &artifact.name {
            by_name.entry(name.clone()).or_default().push(index);
        }
        if let Some(invoke_key) = artifact.data.get("invoke_key").and_then(Value::as_str) {
            by_invoke.insert(invoke_key.to_owned(), index);
        }
        by_kind
            .entry(artifact.kind.clone())
            .or_default()
            .push(index);
    }

    let mut test_links: BTreeMap<usize, BTreeSet<String>> = BTreeMap::new();

    for artifact in artifacts.iter() {
        if artifact.kind == "frontend_hook_use" {
            if let Some(name) = artifact.data.get("hook_def_name").and_then(Value::as_str) {
                if let Some(target_index) =
                    by_kind.get("frontend_hook_def").and_then(|candidates| {
                        candidates
                            .iter()
                            .copied()
                            .find(|candidate| artifacts[*candidate].name.as_deref() == Some(name))
                    })
                {
                    edges.push(edge(
                        &artifact.repo,
                        "uses_hook",
                        artifact,
                        &artifacts[target_index],
                        "hook callsite name matches hook definition",
                        0.95,
                    ));
                }
            }
        }

        if artifact.kind == "tauri_invoke" {
            if let Some(invoke_key) = artifact.data.get("invoke_key").and_then(Value::as_str) {
                if let Some(target_index) = by_invoke
                    .get(invoke_key)
                    .copied()
                    .filter(|candidate| artifacts[*candidate].kind == "tauri_plugin_command")
                    .or_else(|| {
                        let name = artifact.data.get("command_name").and_then(Value::as_str)?;
                        by_kind.get("tauri_command").and_then(|candidates| {
                            candidates.iter().copied().find(|candidate| {
                                artifacts[*candidate].name.as_deref() == Some(name)
                            })
                        })
                    })
                {
                    let edge_type = if artifacts[target_index].kind == "tauri_plugin_command" {
                        "invokes_plugin_command"
                    } else {
                        "invokes"
                    };
                    edges.push(edge(
                        &artifact.repo,
                        edge_type,
                        artifact,
                        &artifacts[target_index],
                        "invoke key matches command registration",
                        0.98,
                    ));
                }
            }
        }

        if artifact.kind == "tauri_plugin_binding" {
            if let Some(invoke_key) = artifact.data.get("invoke_key").and_then(Value::as_str) {
                if let Some(target_index) = by_invoke
                    .get(invoke_key)
                    .copied()
                    .filter(|candidate| artifacts[*candidate].kind == "tauri_plugin_command")
                {
                    edges.push(edge(
                        &artifact.repo,
                        "invokes_plugin_command",
                        artifact,
                        &artifacts[target_index],
                        "plugin binding invoke key matches plugin command",
                        0.99,
                    ));
                }
            }
        }

        if artifact.kind == "tauri_capability" {
            let capability_permissions = artifact
                .data
                .get("permissions")
                .and_then(Value::as_array)
                .cloned()
                .unwrap_or_default();
            for permission in capability_permissions.iter().filter_map(Value::as_str) {
                if let Some(target_index) = by_kind.get("tauri_permission").and_then(|candidates| {
                    candidates.iter().copied().find(|candidate| {
                        artifacts[*candidate]
                            .name
                            .as_deref()
                            .map(|name| {
                                name == permission || name.ends_with(&format!(":{permission}"))
                            })
                            .unwrap_or(false)
                    })
                }) {
                    edges.push(edge(
                        &artifact.repo,
                        "capability_grants_permission",
                        artifact,
                        &artifacts[target_index],
                        "capability permissions include permission identifier",
                        0.9,
                    ));
                }
            }
        }

        if artifact.kind == "frontend_test" {
            let imports = artifact
                .data
                .get("imports")
                .and_then(Value::as_array)
                .cloned()
                .unwrap_or_default();
            let mocked_commands = artifact
                .data
                .get("mocked_commands")
                .and_then(Value::as_array)
                .cloned()
                .unwrap_or_default();
            for import in imports.iter().filter_map(Value::as_str) {
                if let Some(candidates) = by_name.get(import) {
                    for target_index in candidates {
                        test_links
                            .entry(*target_index)
                            .or_default()
                            .insert(artifact.source_path.clone().unwrap_or_default());
                        edges.push(edge(
                            &artifact.repo,
                            "tested_by",
                            &artifacts[*target_index],
                            artifact,
                            "frontend test imports symbol",
                            0.9,
                        ));
                    }
                }
            }
            for command in mocked_commands.iter().filter_map(Value::as_str) {
                if let Some(target_index) = by_invoke.get(command).copied() {
                    test_links
                        .entry(target_index)
                        .or_default()
                        .insert(artifact.source_path.clone().unwrap_or_default());
                    edges.push(edge(
                        &artifact.repo,
                        "mocked_by",
                        &artifacts[target_index],
                        artifact,
                        "frontend test mocks invoke key",
                        0.95,
                    ));
                }
            }
        }

        if artifact.kind == "rust_test" {
            let targets = artifact
                .data
                .get("targets")
                .and_then(Value::as_array)
                .cloned()
                .unwrap_or_default();
            for target in targets.iter().filter_map(Value::as_str) {
                if let Some(candidates) = by_name.get(target) {
                    for target_index in candidates {
                        test_links
                            .entry(*target_index)
                            .or_default()
                            .insert(artifact.source_path.clone().unwrap_or_default());
                        edges.push(edge(
                            &artifact.repo,
                            "tested_by",
                            &artifacts[*target_index],
                            artifact,
                            "rust test target name matches artifact name",
                            0.85,
                        ));
                    }
                }
            }
        }
    }

    for (index, related_tests) in test_links {
        let artifact = &mut artifacts[index];
        artifact.related_tests = related_tests.into_iter().collect();
        artifact.has_related_tests = !artifact.related_tests.is_empty();
    }

    let warning_exists = |warning_type: &str, related_id: &str, warnings: &[WarningDoc]| {
        warnings.iter().any(|item| {
            item.warning_type == warning_type && item.related_id.as_deref() == Some(related_id)
        })
    };

    for artifact in artifacts.iter() {
        if (artifact.kind == "tauri_command" || artifact.kind == "tauri_plugin_command")
            && artifact.risk_level != "low"
            && artifact.related_tests.is_empty()
        {
            warnings.push(warning(
                &artifact.repo,
                "missing_related_test",
                format!(
                    "{} is high-risk and has no related tests",
                    artifact.name.clone().unwrap_or_default()
                ),
                Some(artifact),
                &artifact.risk_level,
            ));
        }

        if artifact.kind == "tauri_plugin_command" {
            let plugin_name = artifact.data.get("plugin_name").and_then(Value::as_str);
            let command_name = artifact.name.as_deref().unwrap_or_default();
            let has_permission = artifacts.iter().any(|candidate| {
                candidate.kind == "tauri_permission"
                    && candidate.data.get("plugin_name").and_then(Value::as_str) == plugin_name
                    && candidate
                        .data
                        .get("commands_allow")
                        .and_then(Value::as_array)
                        .map(|items| items.iter().any(|item| item.as_str() == Some(command_name)))
                        .unwrap_or(false)
            });
            if !has_permission
                && !warning_exists(
                    "plugin_command_without_permission_evidence",
                    &artifact.id,
                    warnings,
                )
            {
                warnings.push(warning(
                    &artifact.repo,
                    "plugin_command_without_permission_evidence",
                    format!(
                        "{} has no permission evidence",
                        artifact.name.clone().unwrap_or_default()
                    ),
                    Some(artifact),
                    &artifact.risk_level,
                ));
            }
        }

        if artifact.kind == "tauri_command"
            && !warning_exists(
                "command_without_permission_evidence",
                &artifact.id,
                warnings,
            )
        {
            warnings.push(warning(
                &artifact.repo,
                "command_without_permission_evidence",
                format!(
                    "{} has no permission evidence",
                    artifact.name.clone().unwrap_or_default()
                ),
                Some(artifact),
                &artifact.risk_level,
            ));
        }
    }

    Ok(edges)
}