| 131 | |
| 132 | impl SkillValidator for DefaultSkillValidator { |
| 133 | fn validate(&self, skill: &Skill) -> Result<(), SkillValidationError> { |
| 134 | // 1. Name validation |
| 135 | if skill.name.is_empty() || skill.name.len() > self.max_name_len { |
| 136 | return Err(SkillValidationError { |
| 137 | kind: ValidationErrorKind::InvalidName, |
| 138 | message: format!( |
| 139 | "Name must be 1-{} characters, got {}", |
| 140 | self.max_name_len, |
| 141 | skill.name.len() |
| 142 | ), |
| 143 | }); |
| 144 | } |
| 145 | |
| 146 | if !Self::is_kebab_case(&skill.name) { |
| 147 | return Err(SkillValidationError { |
| 148 | kind: ValidationErrorKind::InvalidName, |
| 149 | message: format!( |
| 150 | "Name '{}' is not valid kebab-case (lowercase alphanumeric and hyphens only)", |
| 151 | skill.name |
| 152 | ), |
| 153 | }); |
| 154 | } |
| 155 | |
| 156 | // 2. Reserved name protection |
| 157 | if self.reserved_names.contains(&skill.name) { |
| 158 | return Err(SkillValidationError { |
| 159 | kind: ValidationErrorKind::ReservedName, |
| 160 | message: format!( |
| 161 | "Name '{}' is reserved for a built-in skill and cannot be overwritten", |
| 162 | skill.name |
| 163 | ), |
| 164 | }); |
| 165 | } |
| 166 | |
| 167 | // 3. Content size limit |
| 168 | if skill.content.len() > self.max_content_bytes { |
| 169 | return Err(SkillValidationError { |
| 170 | kind: ValidationErrorKind::ContentTooLarge, |
| 171 | message: format!( |
| 172 | "Content is {} bytes, max allowed is {} bytes", |
| 173 | skill.content.len(), |
| 174 | self.max_content_bytes |
| 175 | ), |
| 176 | }); |
| 177 | } |
| 178 | |
| 179 | // 4. Dangerous tool detection |
| 180 | if let Some(ref allowed) = skill.allowed_tools { |
| 181 | for pattern in &self.dangerous_tool_patterns { |
| 182 | if allowed.contains(pattern.as_str()) { |
| 183 | return Err(SkillValidationError { |
| 184 | kind: ValidationErrorKind::DangerousTools, |
| 185 | message: format!( |
| 186 | "Skill requests dangerous tool permission '{}'. Use specific patterns instead of wildcards.", |
| 187 | pattern |
| 188 | ), |
| 189 | }); |
| 190 | } |