source_map_tauri/tauri_config/
effective.rs1use anyhow::Result;
2use serde_json::{json, Value};
3
4use crate::{
5 config::{normalize_path, ResolvedConfig},
6 discovery::RepoDiscovery,
7 ids::document_id,
8 model::ArtifactDoc,
9 security::apply_artifact_security,
10};
11
12pub fn extract_effective_capabilities(
13 config: &ResolvedConfig,
14 discovery: &RepoDiscovery,
15) -> Result<Vec<ArtifactDoc>> {
16 let mut windows = Vec::new();
17 for path in &discovery.tauri_configs {
18 let text = std::fs::read_to_string(path)?;
19 let value: serde_json::Value = serde_json::from_str(&text)?;
20 if let Some(items) = value
21 .get("app")
22 .and_then(|item| item.get("windows"))
23 .and_then(serde_json::Value::as_array)
24 {
25 for item in items {
26 if let Some(label) = item.get("label").and_then(serde_json::Value::as_str) {
27 windows.push(label.to_owned());
28 } else {
29 windows.push("main".to_owned());
30 }
31 }
32 }
33 }
34
35 let mut docs = Vec::new();
36 for window in windows {
37 let mut permissions = Vec::new();
38 let mut capability_ids = Vec::new();
39 for path in &discovery.capability_files {
40 let text = std::fs::read_to_string(path)?;
41 let value: serde_json::Value =
42 serde_json::from_str(&text).unwrap_or_else(|_| json!({}));
43 let matches_window = value
44 .get("windows")
45 .and_then(serde_json::Value::as_array)
46 .map(|items| {
47 items
48 .iter()
49 .any(|item| item.as_str() == Some(window.as_str()))
50 })
51 .unwrap_or(false);
52 if matches_window {
53 if let Some(identifier) =
54 value.get("identifier").and_then(serde_json::Value::as_str)
55 {
56 capability_ids.push(identifier.to_owned());
57 }
58 if let Some(items) = value
59 .get("permissions")
60 .and_then(serde_json::Value::as_array)
61 {
62 permissions.extend(
63 items
64 .iter()
65 .filter_map(|item| item.as_str())
66 .map(str::to_owned),
67 );
68 }
69 }
70 }
71 let source_path = discovery
72 .capability_files
73 .first()
74 .map(|path| normalize_path(&config.root, path))
75 .unwrap_or_else(|| "src-tauri/capabilities".to_owned());
76 let mut doc = ArtifactDoc {
77 id: document_id(
78 &config.repo,
79 "tauri_capability_effective",
80 Some(&source_path),
81 Some(1),
82 Some(&window),
83 ),
84 repo: config.repo.clone(),
85 kind: "tauri_capability_effective".to_owned(),
86 side: Some("config".to_owned()),
87 language: Some("json".to_owned()),
88 name: Some(window.clone()),
89 display_name: Some(window.clone()),
90 source_path: Some(source_path),
91 line_start: Some(1),
92 line_end: Some(1),
93 column_start: None,
94 column_end: None,
95 package_name: None,
96 comments: Vec::new(),
97 tags: vec!["capability".to_owned()],
98 related_symbols: Vec::new(),
99 related_tests: Vec::new(),
100 risk_level: "medium".to_owned(),
101 risk_reasons: vec!["multiple capabilities merge for window".to_owned()],
102 contains_phi: false,
103 has_related_tests: false,
104 updated_at: chrono::Utc::now().to_rfc3339(),
105 data: Default::default(),
106 };
107 doc.data
108 .insert("window_label".to_owned(), Value::String(window));
109 doc.data.insert(
110 "capability_ids".to_owned(),
111 Value::Array(capability_ids.into_iter().map(Value::String).collect()),
112 );
113 doc.data.insert(
114 "permissions".to_owned(),
115 Value::Array(permissions.iter().cloned().map(Value::String).collect()),
116 );
117 doc.data.insert(
118 "plugin_permissions".to_owned(),
119 Value::Array(
120 permissions
121 .iter()
122 .filter(|item| item.contains(':'))
123 .cloned()
124 .map(Value::String)
125 .collect(),
126 ),
127 );
128 doc.data
129 .insert("merged_capabilities".to_owned(), Value::Bool(true));
130 doc.data
131 .insert("remote_capability".to_owned(), Value::Bool(false));
132 apply_artifact_security(&mut doc);
133 docs.push(doc);
134 }
135 Ok(docs)
136}