1use super::empty_finding_summary;
2use super::sarif::SarifReport;
3use super::types::{
4 ContextPolicy, PolicyAudit, PolicyFile, PolicyProfile, ShieldPolicy, SuppressionSummary,
5};
6use crate::analyzer::{
7 AgentExtensionKind, ArtifactClassification, ArtifactIdentitySource, StructuralValidity,
8};
9use crate::artifact_graph::ArtifactGraph;
10use crate::findings::{ArtifactKind, Finding, FindingSummary, PackageVerdictReport, Verdict};
11use chrono::{DateTime, Utc};
12use serde::{Deserialize, Serialize};
13
14#[derive(Debug, Clone, Serialize, Deserialize)]
15pub struct JsonReport {
16 pub skill_name: String,
17 pub skill_path: String,
18 pub extension_kind: AgentExtensionKind,
19 pub classification: ArtifactClassification,
20 #[serde(skip_serializing_if = "Option::is_none")]
21 pub package_id: Option<String>,
22 pub identity_source: ArtifactIdentitySource,
23 pub structural_validity: StructuralValidity,
24 pub heuristic_score: u8,
25 pub timestamp: DateTime<Utc>,
26 pub findings: Vec<Finding>,
27 #[serde(default)]
28 pub primary_findings: Vec<Finding>,
29 #[serde(default)]
30 pub supporting_findings: Vec<Finding>,
31 pub summary: FindingSummary,
32 #[serde(default = "empty_finding_summary")]
33 pub primary_summary: FindingSummary,
34 #[serde(default = "empty_finding_summary")]
35 pub supporting_summary: FindingSummary,
36 pub verdict: Verdict,
37 pub verdict_report: PackageVerdictReport,
38 pub artifact_graph: ArtifactGraph,
39 pub policies: Vec<ShieldPolicy>,
40 pub context_policies: Vec<ContextPolicy>,
41 #[serde(skip_serializing_if = "Option::is_none")]
42 pub profile: Option<PolicyProfile>,
43 #[serde(default)]
44 pub suppression_summary: SuppressionSummary,
45 #[serde(default)]
46 pub policy_audit: PolicyAudit,
47}
48
49pub struct PolicyGenerator {
50 skill_name: String,
51 skill_path: String,
52 primary_artifact_kind: ArtifactKind,
53 extension_kind: AgentExtensionKind,
54 classification: ArtifactClassification,
55 package_id: Option<String>,
56 identity_source: ArtifactIdentitySource,
57 structural_validity: StructuralValidity,
58 heuristic_score: u8,
59 findings: Vec<Finding>,
60 artifact_graph: ArtifactGraph,
61 profile: Option<PolicyProfile>,
62 policy: Option<PolicyFile>,
63 suppression_summary: SuppressionSummary,
64 policy_audit: PolicyAudit,
65 verdict_report: Option<PackageVerdictReport>,
68}
69
70impl PolicyGenerator {
71 #[must_use]
73 pub fn skill_name(&self) -> &str {
74 &self.skill_name
75 }
76
77 #[must_use]
79 pub fn skill_path(&self) -> &str {
80 &self.skill_path
81 }
82
83 #[must_use]
85 pub fn primary_artifact_kind(&self) -> ArtifactKind {
86 self.primary_artifact_kind
87 }
88
89 #[must_use]
91 pub fn extension_kind(&self) -> AgentExtensionKind {
92 self.extension_kind
93 }
94
95 #[must_use]
97 pub fn classification(&self) -> ArtifactClassification {
98 self.classification
99 }
100
101 #[must_use]
103 pub fn package_id(&self) -> Option<&str> {
104 self.package_id.as_deref()
105 }
106
107 #[must_use]
109 pub fn identity_source(&self) -> ArtifactIdentitySource {
110 self.identity_source
111 }
112
113 #[must_use]
115 pub fn structural_validity(&self) -> StructuralValidity {
116 self.structural_validity
117 }
118
119 #[must_use]
121 pub fn heuristic_score(&self) -> u8 {
122 self.heuristic_score
123 }
124
125 #[must_use]
127 pub fn findings(&self) -> &[Finding] {
128 &self.findings
129 }
130
131 #[must_use]
133 pub fn artifact_graph(&self) -> &ArtifactGraph {
134 &self.artifact_graph
135 }
136
137 #[must_use]
139 pub fn profile(&self) -> Option<PolicyProfile> {
140 self.profile
141 }
142
143 #[must_use]
145 pub fn policy(&self) -> Option<&PolicyFile> {
146 self.policy.as_ref()
147 }
148
149 #[must_use]
151 pub fn suppression_summary(&self) -> &SuppressionSummary {
152 &self.suppression_summary
153 }
154
155 #[must_use]
157 pub fn policy_audit(&self) -> &PolicyAudit {
158 &self.policy_audit
159 }
160
161 #[must_use]
163 pub fn verdict_report(&self) -> Option<&PackageVerdictReport> {
164 self.verdict_report.as_ref()
165 }
166
167 pub fn new(
168 skill_name: impl Into<String>,
169 skill_path: impl Into<String>,
170 findings: Vec<Finding>,
171 artifact_graph: ArtifactGraph,
172 ) -> Self {
173 Self {
174 skill_name: skill_name.into(),
175 skill_path: skill_path.into(),
176 primary_artifact_kind: ArtifactKind::SkillDocument,
177 extension_kind: AgentExtensionKind::Skill,
178 classification: ArtifactClassification::ConfirmedSkill,
179 package_id: None,
180 identity_source: ArtifactIdentitySource::ExplicitName,
181 structural_validity: StructuralValidity::Confirmed,
182 heuristic_score: 0,
183 findings,
184 artifact_graph,
185 profile: None,
186 policy: None,
187 suppression_summary: SuppressionSummary::default(),
188 policy_audit: PolicyAudit::default(),
189 verdict_report: None,
190 }
191 }
192
193 #[must_use]
194 pub fn with_primary_artifact_kind(mut self, artifact_kind: ArtifactKind) -> Self {
195 self.primary_artifact_kind = artifact_kind;
196 self
197 }
198
199 #[must_use]
200 pub fn with_profile(mut self, profile: PolicyProfile) -> Self {
201 self.profile = Some(profile);
202 self
203 }
204
205 #[must_use]
206 pub fn with_extension_kind(mut self, extension_kind: AgentExtensionKind) -> Self {
207 self.extension_kind = extension_kind;
208 self
209 }
210
211 #[must_use]
212 pub fn with_classification(mut self, classification: ArtifactClassification) -> Self {
213 self.classification = classification;
214 self
215 }
216
217 #[must_use]
218 pub fn with_package_id(mut self, package_id: Option<String>) -> Self {
219 self.package_id = package_id;
220 self
221 }
222
223 #[must_use]
224 pub fn with_identity_source(mut self, identity_source: ArtifactIdentitySource) -> Self {
225 self.identity_source = identity_source;
226 self
227 }
228
229 #[must_use]
230 pub fn with_structural_validity(mut self, structural_validity: StructuralValidity) -> Self {
231 self.structural_validity = structural_validity;
232 self
233 }
234
235 #[must_use]
236 pub fn with_heuristic_score(mut self, heuristic_score: u8) -> Self {
237 self.heuristic_score = heuristic_score;
238 self
239 }
240
241 #[must_use]
242 pub fn with_policy(mut self, policy: PolicyFile) -> Self {
243 self.policy = Some(policy);
244 self
245 }
246
247 #[must_use]
248 pub fn with_suppression_summary(mut self, suppression_summary: SuppressionSummary) -> Self {
249 self.suppression_summary = suppression_summary;
250 self
251 }
252
253 #[must_use]
254 pub fn with_policy_audit(mut self, policy_audit: PolicyAudit) -> Self {
255 self.policy_audit = policy_audit;
256 self
257 }
258
259 #[must_use]
260 pub fn with_verdict_report(mut self, verdict_report: PackageVerdictReport) -> Self {
261 self.verdict_report = Some(verdict_report);
262 self
263 }
264
265 pub fn generate_shield_md(&self) -> String {
266 super::serializers::generate_shield_md(self)
267 }
268
269 pub fn generate_json(&self) -> JsonReport {
270 super::serializers::generate_json(self)
271 }
272
273 pub fn generate_sarif(&self) -> SarifReport {
274 super::serializers::generate_sarif(self)
275 }
276}