Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 40 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,43 @@
## 2.0.0

Plugin-based command knowledge base.

### Added

- Plugin architecture for command knowledge: knowledge is now contributed by
`CommandKnowledgePlugin`s, one per domain. Twelve built-in plugins ship by
default (`filesystem`, `archive`, `shell`, `environment`, `process`, `system`,
`network`, `container`, `packageManager`, `dartFlutter`, `git`, `windows`),
composed via `defaultKnowledgePlugins`. Register your own with
`CommandKnowledgeBase(plugins: [...])` or replace the built-ins entirely with
`includeDefaults: false`.
- Declarative `CommandKnowledge` entries with rich fields: `category`,
`platforms`, `description`, `baseCapabilities`, `baseRisk`, `subcommands`,
`argumentRules`, `wrapper` and an optional `refine` function hook. Argument
rules use composable `ArgumentMatch`es (`ExactFlag`, `PrefixFlag`,
`TokenPresent`, `ArgRegex`, `ArgPredicate`).
- `CommandKnowledgeBase.analyze()` returning a `CommandKnowledgeResult`
(capabilities, an aggregated `SecurityLevel` risk hint, the matched entry and
explanatory notes), plus `knowledgeFor()` and `allKnowledge`.
- `CommandAnalysis.knowledgeRisk`: the highest knowledge-base risk hint across a
command's invocations (advisory metadata).
- Opt-in `KnowledgeRiskDetector` that surfaces elevated knowledge-base risk
(e.g. a force push) as `knowledge-risk` security findings. Not part of
`SecurityAnalyzer.defaultDetectors`, so default verdicts are unchanged.
- Broader command coverage: Dart/Flutter sub-commands, archive/compression
tools, cloud CLIs (`gh`, `aws`, `gcloud`, `az`, `kubectl`), more `git`
sub-commands, additional package managers and Windows-specific tools.

### Changed (breaking)

- `CommandKnowledgeBase` is now composed from plugins. The
`extraExecutableCapabilities` constructor parameter and the static
`wrapperCommands` set have been removed; supply a `CommandKnowledgePlugin`
(e.g. `ListKnowledgePlugin`) and per-entry `WrapperSpec`s instead.
- Sub-command matching now uses the first non-flag argument rather than the
first argument, so leading global flags (e.g. `git --no-pager push`) no longer
hide the sub-command.

## 1.0.0

Initial release.
Expand Down
17 changes: 17 additions & 0 deletions lib/command_shield.dart
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,22 @@ export 'src/ast/command_node.dart';
export 'src/capabilities/capability.dart';
export 'src/capabilities/capability_detector.dart';
export 'src/capabilities/command_knowledge_base.dart';
export 'src/capabilities/knowledge/command_knowledge.dart';
export 'src/capabilities/knowledge/command_knowledge_plugin.dart';
export 'src/capabilities/knowledge/command_knowledge_result.dart';
export 'src/capabilities/knowledge/plugins/archive_knowledge.dart';
export 'src/capabilities/knowledge/plugins/container_knowledge.dart';
export 'src/capabilities/knowledge/plugins/dart_flutter_knowledge.dart';
export 'src/capabilities/knowledge/plugins/default_plugins.dart';
export 'src/capabilities/knowledge/plugins/environment_knowledge.dart';
export 'src/capabilities/knowledge/plugins/filesystem_knowledge.dart';
export 'src/capabilities/knowledge/plugins/git_knowledge.dart';
export 'src/capabilities/knowledge/plugins/network_knowledge.dart';
export 'src/capabilities/knowledge/plugins/package_manager_knowledge.dart';
export 'src/capabilities/knowledge/plugins/process_knowledge.dart';
export 'src/capabilities/knowledge/plugins/shell_knowledge.dart';
export 'src/capabilities/knowledge/plugins/system_config_knowledge.dart';
export 'src/capabilities/knowledge/plugins/windows_knowledge.dart';
export 'src/classification/effect.dart';
export 'src/classification/effect_classifier.dart';
export 'src/command_shield.dart';
Expand Down Expand Up @@ -56,6 +72,7 @@ export 'src/security/detectors/command_substitution_detector.dart';
export 'src/security/detectors/dangerous_operator_detector.dart';
export 'src/security/detectors/destructive_command_detector.dart';
export 'src/security/detectors/env_expansion_detector.dart';
export 'src/security/detectors/knowledge_risk_detector.dart';
export 'src/security/detectors/path_traversal_detector.dart';
export 'src/security/detectors/privilege_escalation_detector.dart';
export 'src/security/detectors/remote_exec_detector.dart';
Expand Down
20 changes: 19 additions & 1 deletion lib/src/analysis/analyzer.dart
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import '../capabilities/capability.dart';
import '../capabilities/capability_detector.dart';
import '../capabilities/command_knowledge_base.dart';
import '../classification/effect.dart';
import '../classification/effect_classifier.dart';
import '../normalization/normalizer.dart';
import '../parser/parse_result.dart';
import '../security/security_analyzer.dart';
import '../security/security_detector.dart';
import '../security/security_level.dart';
import 'command_analysis.dart';

/// Orchestrates the post-parse stages of the pipeline:
Expand All @@ -20,14 +22,20 @@ final class Analyzer {
CapabilityDetector? capabilityDetector,
EffectClassifier? effectClassifier,
SecurityAnalyzer? securityAnalyzer,
CommandKnowledgeBase? knowledgeBase,
}) : _normalizer = normalizer ?? Normalizer.standard(),
_knowledgeBase = knowledgeBase ?? CommandKnowledgeBase.standard(),
_capabilityDetector =
capabilityDetector ??
CapabilityDetector(normalizer: normalizer ?? Normalizer.standard()),
CapabilityDetector(
normalizer: normalizer ?? Normalizer.standard(),
knowledgeBase: knowledgeBase,
),
_effectClassifier = effectClassifier ?? const EffectClassifier(),
_securityAnalyzer = securityAnalyzer ?? SecurityAnalyzer();

final Normalizer _normalizer;
final CommandKnowledgeBase _knowledgeBase;
final CapabilityDetector _capabilityDetector;
final EffectClassifier _effectClassifier;
final SecurityAnalyzer _securityAnalyzer;
Expand All @@ -49,6 +57,15 @@ final class Analyzer {
? <CommandEffect>{}
: _effectClassifier.classify(capabilities);

var knowledgeRisk = SecurityLevel.safe;
for (final inv in parseResult.invocations) {
if (inv.executable.isEmpty) continue;
final exe = _normalizer.normalize(inv.executable);
knowledgeRisk = knowledgeRisk.max(
_knowledgeBase.analyze(exe, inv.arguments).risk,
);
}

final report = _securityAnalyzer.analyze(
SecurityContext(
raw: parseResult.raw,
Expand All @@ -68,6 +85,7 @@ final class Analyzer {
effects: Set<CommandEffect>.unmodifiable(effects),
securityLevel: report.level,
findings: report.findings,
knowledgeRisk: knowledgeRisk,
);
}
}
8 changes: 8 additions & 0 deletions lib/src/analysis/command_analysis.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import 'package:meta/meta.dart' show immutable;

import '../ast/command_node.dart';
import '../capabilities/capability.dart';
import '../capabilities/command_knowledge_base.dart';
import '../classification/effect.dart';
import '../parser/parse_diagnostic.dart';
import '../security/security_finding.dart';
Expand All @@ -27,6 +28,7 @@ final class CommandAnalysis {
required this.effects,
required this.securityLevel,
required this.findings,
this.knowledgeRisk = SecurityLevel.safe,
});

/// The original command string.
Expand All @@ -53,6 +55,12 @@ final class CommandAnalysis {
/// The overall security severity.
final SecurityLevel securityLevel;

/// The highest risk hint contributed by the command knowledge base across all
/// invocations (for example, a force push). This is advisory metadata derived
/// from the [CommandKnowledgeBase] and does **not** affect [securityLevel]
/// unless a `KnowledgeRiskDetector` is explicitly enabled.
final SecurityLevel knowledgeRisk;

/// The aggregated security findings, sorted by descending severity.
final List<SecurityFinding> findings;

Expand Down
Loading