Skip to content

Commit 3691727

Browse files
authored
release: 0.1.0-dev.4 (#15)
* fix(secrets): include keys detection * fix(rules): secure random detection * test(rules): add test for random secure * refactor: fix naming of visitor * feat: improve analysis report handling * refactor: improve report handling * refactor: improve config parsing * refactor: proper class declaration * chore: check todos * chore: raise version * refactor: add rule registering * feat: implict current folder for analysis * chore: update CHANGELOG * style: formatting * style: formatting * style: formatting * chore: add .pubignore
1 parent e55bb85 commit 3691727

File tree

21 files changed

+448
-73
lines changed

21 files changed

+448
-73
lines changed

.pubignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
docs/
2+
resources/
3+
.github/

CHANGELOG.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,28 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## [0.1.0-dev.4] - 2025-10-08
9+
10+
### Added
11+
- Implicit current folder analysis - users can now run analysis without specifying a target directory ([issue #6](https://github.com/yardexx/dart_shield/issues/6))
12+
- Rule registry system for better rule management and organization
13+
- Improved analysis report handling with better error reporting and progress tracking ([issue #9](https://github.com/yardexx/dart_shield/issues/9))
14+
15+
### Changed
16+
- Enhanced configuration parsing for better flexibility
17+
- Improved report handling and project report structure
18+
- Refactored class declarations for better code organization
19+
- Updated visitor naming for consistency
20+
21+
### Fixed
22+
- Secure random detection in crypto rules
23+
- Hardcoded secrets detection now includes key detection
24+
- Various rule detection improvements
25+
26+
### Tests
27+
- Added comprehensive tests for secure random rule
28+
- Enhanced test coverage for configuration parsing
29+
830
## [0.1.0-dev.3] - 2024-08-31
931

1032
### Added

README.md

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -73,16 +73,17 @@ dart_shield init -f
7373
dart_shield init --force
7474
```
7575

76-
To analyze your Dart code for potential security flaws, run the following command,
77-
specifying the directory:
76+
To analyze your Dart code for potential security flaws, run the following command:
7877

7978
```bash
79+
# Analyze current directory (default)
80+
dart_shield analyze
81+
82+
# Or explicitly specify a directory
8083
dart_shield analyze .
84+
dart_shield analyze lib
8185
```
8286

83-
> **Note:** The . at the end of the command specifies the directory to be analyzed and must always
84-
> be included. The command does not automatically add it.
85-
8687
This command analyzes your Dart code based on the configuration in the shield_options.yaml file.
8788
If the configuration file is not found, the command will fail.
8889

assets/shield_secrets.yaml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
# TODO: Bundle this using native assets feature stable: https://github.com/dart-lang/sdk/issues/53562
1+
# Workaround: This file is duplicated in lib/assets/shield_secrets_dart.dart
2+
# because Dart doesn't support native assets yet.
3+
# See: https://github.com/dart-lang/sdk/issues/53562
4+
# TODO: Use native assets when Dart SDK supports it
25
shield_patterns:
36
version: 0.1.0-dev.1
47
secrets:

lib/assets/shield_secrets_dart.dart

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1-
// Copy of [shield_secrets.dart] because Dart doesn't support assets.
2-
// TODO: Remove this file once Dart supports assets: https://github.com/dart-lang/sdk/issues/53562
1+
// Copy of [shield_secrets.yaml] because Dart doesn't support native assets yet.
2+
// This is a workaround until Dart SDK adds native asset support.
3+
// See: https://github.com/dart-lang/sdk/issues/53562
4+
// TODO: Remove this file and use native assets when Dart SDK supports it
35

46
const String shieldSecretsSource = r'''
57
shield_patterns:

lib/src/cli/commands/analyze.dart

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ class AnalyzeCommand extends ShieldCommand {
4747
final progress = logger.progress('Creating workspace');
4848

4949
final workspace = Workspace(
50-
analyzedPaths: argResults.rest,
50+
analyzedPaths: argResults.rest.isEmpty ? ['.'] : argResults.rest,
5151
rootFolder: Directory.current.path,
5252
);
5353

@@ -68,6 +68,15 @@ class AnalyzeCommand extends ShieldCommand {
6868
) async {
6969
final progress = logger.progress('Analyzing project');
7070
final report = await _analyzer.analyzeFromCli(workspace, config);
71+
72+
// Log skipped files if any
73+
if (report.skippedFiles.isNotEmpty) {
74+
logger.warn('Could not analyze ${report.skippedFiles.length} file(s):');
75+
for (final file in report.skippedFiles) {
76+
logger.warn(' - $file');
77+
}
78+
}
79+
7180
progress.complete('Project analyzed.');
7281
return report;
7382
}

lib/src/cli/commands/shield_command.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ abstract class ShieldCommand extends Command<int> {
2424
}
2525

2626
bool get targetsExist {
27+
if (argResults.rest.isEmpty) return true; // Default to current directory
2728
return argResults.rest.length == 1 &&
2829
Directory(argResults.rest.first).existsSync();
2930
}

lib/src/security_analyzer/configuration/lint_rule_converter.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import 'package:dart_shield/src/security_analyzer/rules/enums/enums.dart';
22
import 'package:dart_shield/src/security_analyzer/rules/rule/rule.dart';
3-
import 'package:dart_shield/src/security_analyzer/rules/rule_creator.dart';
3+
import 'package:dart_shield/src/security_analyzer/rules/rule_registry.dart';
44
import 'package:json_annotation/json_annotation.dart';
55

66
class LintRuleConverter implements JsonConverter<LintRule, String> {
@@ -9,7 +9,7 @@ class LintRuleConverter implements JsonConverter<LintRule, String> {
99
// Todo: Implement file exclusion
1010
@override
1111
LintRule fromJson(String name) {
12-
final rule = RuleCreator.createRule(
12+
final rule = RuleRegistry.createRule(
1313
id: RuleId.fromYamlName(name),
1414
excludes: [],
1515
);

lib/src/security_analyzer/configuration/shield_config.dart

Lines changed: 41 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -32,35 +32,62 @@ class ShieldConfig {
3232
}
3333

3434
factory ShieldConfig.fromFile(String path) {
35-
final content = File(path).readAsStringSync();
36-
final dartMap = yamlToDartMap(loadYaml(content)) as Map<String, dynamic>;
37-
return ShieldConfig.fromYaml(dartMap);
35+
try {
36+
final content = File(path).readAsStringSync();
37+
final dartMap = yamlToDartMap(loadYaml(content)) as Map<String, dynamic>;
38+
return ShieldConfig.fromYaml(dartMap);
39+
} on FileSystemException catch (e) {
40+
throw InvalidConfigurationException(
41+
'Could not read config file at $path: ${e.message}',
42+
);
43+
} on YamlException catch (e) {
44+
throw InvalidConfigurationException(
45+
'Invalid YAML in config file at $path: ${e.message}',
46+
);
47+
} catch (e) {
48+
throw InvalidConfigurationException(
49+
'Invalid configuration structure in $path: $e',
50+
);
51+
}
3852
}
3953

4054
// Verifies the validity of the configuration
4155
void _verifyValidity() {
4256
// Ensure no experimental rules are in the main rules list
43-
if (rules.any((rule) => rule.status == RuleStatus.experimental)) {
44-
throw const InvalidConfigurationException(
45-
'Rules with status experimental are not allowed in the rules list',
57+
final experimentalInMainRules =
58+
rules.where((rule) => rule.status == RuleStatus.experimental).toList();
59+
if (experimentalInMainRules.isNotEmpty) {
60+
final ruleNames =
61+
experimentalInMainRules.map((rule) => rule.id.name).join(', ');
62+
throw InvalidConfigurationException(
63+
'Found experimental rule(s) in the "rules" list: $ruleNames. '
64+
'Move these to "experimental-rules" list.',
4665
);
4766
}
4867

4968
// Ensure experimental rules are only allowed if the experimental flag is
5069
// enabled
5170
if (!enableExperimental && experimentalRules.isNotEmpty) {
52-
throw const InvalidConfigurationException(
53-
'Experimental rules are not allowed when the experimental flag is '
54-
'disabled',
71+
final ruleNames =
72+
experimentalRules.map((rule) => rule.id.name).join(', ');
73+
throw InvalidConfigurationException(
74+
'Found experimental rule(s) in "experimental-rules" list: $ruleNames, '
75+
'but "enable-experimental" is set to false. '
76+
'Set "enable-experimental" to true to use these rules.',
5577
);
5678
}
5779

5880
// Ensure only experimental rules are in the experimental rules list
59-
if (experimentalRules
60-
.any((rule) => rule.status != RuleStatus.experimental)) {
61-
throw const InvalidConfigurationException(
62-
'Only rules with status experimental are allowed in the experimental '
63-
'rules list',
81+
final nonExperimentalInExperimentalRules = experimentalRules
82+
.where((rule) => rule.status != RuleStatus.experimental)
83+
.toList();
84+
if (nonExperimentalInExperimentalRules.isNotEmpty) {
85+
final ruleNames = nonExperimentalInExperimentalRules
86+
.map((rule) => rule.id.name)
87+
.join(', ');
88+
throw InvalidConfigurationException(
89+
'Found non-experimental rule(s) in "experimental-rules" list: '
90+
'$ruleNames. Move these to the "rules" list.',
6491
);
6592
}
6693
}

lib/src/security_analyzer/report/analysis_report/project_report.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ class ProjectReport {
55
ProjectReport({
66
required this.path,
77
required this.fileReports,
8+
this.skippedFiles = const [],
89
});
910

1011
factory ProjectReport.empty(String path) {
@@ -16,6 +17,7 @@ class ProjectReport {
1617

1718
final String path;
1819
final List<FileReport> fileReports;
20+
List<String> skippedFiles;
1921

2022
int get criticalCount =>
2123
fileReports.map((report) => report.criticalCount).sum;

0 commit comments

Comments
 (0)