fix(security): unbekannte Requirement-ID sperrt das Divi-Tool

Deklariert ein Tool über DeclaresRequirements eine ID, die keine Divi-Fähigkeit ist, wird der Aufruf mit divi_incompatible (423) gesperrt, statt ungesperrt zu laufen.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Jan-Niclas Loosen
2026-11-06 11:30:05 +01:00
co-authored by Claude Opus 5.5
parent 234fd1edac
commit 691231f776
4 changed files with 85 additions and 11 deletions
+21 -2
View File
@@ -17,8 +17,8 @@ final class FeatureSets
{
/**
* The capabilities $ability declares for $input: its own diviFeatures() (the Divi tools) or the IDs a core tool
* names through DeclaresRequirements (lit/content-create with divi). Anything else declares none; an ID that is no
* DiviFeature is ignored (the core may name capabilities of other integrations).
* names through DeclaresRequirements (lit/content-create with divi). Anything else declares none. Every declared
* ID is a Divi ID; one that is no DiviFeature is skipped here but locks the call (unknownIds(), fail closed).
*
* @param array<string, mixed> $input
* @return list<DiviFeature>
@@ -44,6 +44,25 @@ final class FeatureSets
return self::merge($features);
}
/**
* The IDs a core tool declares for $input that are no DiviFeature. Such a call cannot be judged, so
* DiviFeatureGate refuses it instead of letting it run unlocked.
*
* @param array<string, mixed> $input
* @return list<string>
*/
public static function unknownIds(Ability $ability, array $input): array
{
if ($ability instanceof RequiresDiviFeatures || ! $ability instanceof DeclaresRequirements) {
return [];
}
return array_values(array_filter(
$ability->requirements($input),
static fn (string $id): bool => DiviFeature::tryFrom($id) === null
));
}
/**
* @param list<DiviFeature> ...$lists
* @return list<DiviFeature> Every capability once, in the order of first appearance.