From 6aea1cef2a8b3d66c70bf3e026b03154e5b774cb Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jaroslav=20Novotn=C3=BD?=
<62177414+yardexx@users.noreply.github.com>
Date: Mon, 26 Jan 2026 09:50:53 +0100
Subject: [PATCH 1/9] feat: new architecture (#22)
* feat: introduce analyzer interface and domain models
* feat: implement code analyzer with plugin infrastructure
* feat: add security rules
* feat: implement configuration management
* feat: add core analyzer engine and runner
* feat: implement reporters
* refactor: migrate CLI commands to new architecture
* refactor: update main entry point
* refactor: remove legacy security_analyzer module
* chore: update dependencies and example configuration
* chore: remove obsolete test files
* docs: add project context and architecture documentation
* refactor(core): cleanup ShieldRunner and reporter selection
* feat(analyzer): implement code scanning and issue mapping
* fix(analyzer): update analyzer result DTO structure
* feat(secrets): implement advanced secret scanning with Gitleaks rules (#18)
* feat(core): implement structured error handling system
* fix(analyzer): fix secret scanner keyword matching case sensitivity
* test: add unit tests for core/config/rules and E2E integration test
* feat!: replace gitbook with docs.page (#19)
* feat!: replace gitbook with docs.page
* docs: basic structure
* docs: basic structure
* docs: basic structure
* docs: basic structure
* docs: basic structure
* docs: basic structure
* docs: basic structure
* docs: basic structure
* docs: basic structure
* docs: basic structure
* docs: basic structure
* docs: basic structure
* docs: basic structure
* docs: basic structure
* docs: basic structure
* docs: basic structure
* docs: basic structure
* docs: basic structure
* docs: basic structure
* docs: basic structure
* docs: basic structure
* docs: basic structure
* docs: basic structure
* docs: basic structure
* docs: basic structure
* docs: basic structure
* docs: basic structure
* docs: basic structure
* docs: basic structure
* docs: basic structure
* feat: stability improvements (#20)
* chore: add test dependencies for analysis rules
Add analyzer_testing and test_reflective_loader packages to enable
proper unit testing of analysis rules using the official Dart testing
framework.
* test: add unit tests for all 5 analysis rules
Add comprehensive unit tests for security rules using analyzer_testing:
- prefer_https_over_http: 11 tests
- avoid_hardcoded_urls: 10 tests
- avoid_weak_hashing: 8 tests
- prefer_secure_random: 7 tests
- avoid_hardcoded_secrets: 11 tests
Total: 47 new tests covering positive and negative cases.
* ci: add tests and code coverage to CI pipeline
- Add dart test step to run unit tests on every PR
- Add coverage generation and upload to Codecov
- Add separate integration test job
- Configure codecov.yml with coverage thresholds (70% project, 80% patch)
* docs: fix configuration documentation inconsistency
Update README and example to correctly document analysis_options.yaml
as the configuration file with dart_shield: key, replacing incorrect
references to shield_options.yaml.
- Add coverage badge to README
- Simplify configuration documentation
- Update example/analysis_options.yaml to use correct format
* feat: add severity metadata and filtering to rules
- Create rule_metadata.dart with severity levels and OWASP/CWE refs
- Map rule IDs to proper severity (high/medium/low/info)
- Add --min-severity flag to analyze command for filtering
- Update shield_runner to filter results by minimum severity
Severity assignments:
- avoid_hardcoded_secrets: high (CWE-798)
- prefer_https_over_http: high (CWE-319)
- avoid_weak_hashing: medium (CWE-328)
- prefer_secure_random: medium (CWE-330)
- avoid_hardcoded_urls: low (CWE-547)
* chore: update ignore files and clean up tracked files
- Add pubspec.lock to .gitignore (not needed for packages)
- Add internal docs to .gitignore (GEMINI.md, ROADMAP.md, etc.)
- Update .pubignore with test/, tool/, codecov.yml, docs.json
- Remove pubspec.lock files from git tracking
- Remove internal planning documents from git tracking
* style: apply dart format to codebase
Run dart format to ensure consistent code style across the project.
* ci: raise Dart SDK version
* style: formatting
* style: formatting
* ci: update test suite
---
.github/workflows/dart.yml | 20 +-
.gitignore | 16 +-
.pubignore | 13 +
README.md | 66 +-
assets/shield_secrets.yaml | 28 -
codecov.yml | 18 +
docs.json | 157 ++
docs/.gitbook/assets/1.png | Bin 189594 -> 0 bytes
docs/.gitbook/assets/2.png | Bin 242756 -> 0 bytes
docs/.gitbook/assets/3.png | Bin 240885 -> 0 bytes
docs/.gitbook/assets/4.png | Bin 174596 -> 0 bytes
docs/.gitbook/assets/image.png | Bin 37215 -> 0 bytes
docs/.gitignore | 0
docs/README.md | 44 -
docs/SUMMARY.md | 23 -
.../img => docs/assets}/shield-logo.svg | 0
docs/assets/title-image.png | Bin 0 -> 798724 bytes
docs/basics/commands.md | 2 -
docs/basics/configuration.md | 2 -
docs/basics/reports.md | 2 -
docs/basics/rules.md | 2 -
docs/beyond-the-basics/introduction.md | 13 -
docs/beyond-the-basics/sast-basics.md | 58 -
docs/cli/analyze.mdx | 56 +
docs/cli/index.mdx | 83 +
docs/cli/init.mdx | 40 +
docs/community-and-development/changelog.md | 6 -
.../community-and-development/contribution.md | 6 -
docs/community-and-development/license.md | 6 -
docs/community-and-development/road-map.md | 6 -
docs/guides/background/architecture.mdx | 22 +
docs/guides/background/sast-basics.mdx | 16 +
.../community-and-development/changelog.mdx | 8 +
.../community-and-development/license.mdx | 38 +
docs/guides/configuration/ignoring.mdx | 48 +
docs/guides/configuration/options.mdx | 58 +
docs/guides/getting-started/quick-start.mdx | 46 +
docs/index.mdx | 15 +
docs/quickstart.md | 92 -
docs/rulebook/RULE_TEMPLATE.mdx | 54 +
.../cryptography/avoid-weak-hashing.mdx | 85 +
.../cryptography/prefer-secure-random.mdx | 79 +
docs/rulebook/index.mdx | 45 +
.../rulebook/network/avoid-hardcoded-urls.mdx | 75 +
.../network/prefer-https-over-http.mdx | 67 +
.../secrets/avoid-hardcoded-secrets.mdx | 75 +
example/analysis_options.yaml | 8 +
example/lib/vulnerabilities.dart | 27 +-
example/pubspec.yaml | 2 +-
example/shield_options.yaml | 38 -
lib/assets/assets.dart | 1 -
lib/assets/shield_secrets_dart.dart | 31 -
lib/main.dart | 3 +
lib/src/analyzers/analyzer.dart | 7 +
lib/src/analyzers/code/code_analyzer.dart | 96 +
.../analyzers/code/plugin/shield_plugin.dart | 15 +
.../cryptography/avoid_weak_hashing.dart | 83 +
.../cryptography/prefer_secure_random.dart | 63 +
.../rules/network/avoid_harcoded_urls.dart | 52 +
.../rules/network/prefer_https_over_http.dart | 77 +
.../analyzers/code/rules/rule_metadata.dart | 77 +
lib/src/analyzers/code/rules/rules.dart | 14 +
.../secrets/avoid_hardcoded_secrets.dart | 109 +
.../code/rules/secrets/rule_provider.dart | 69 +
.../code/rules/secrets/secret_rule.dart | 61 +
.../code/rules/secrets/secret_rules.dart | 31 +
lib/src/analyzers/utils/analyzer_result.dart | 98 +
.../analyzers/utils/diagnostic_mapper.dart | 33 +
lib/src/analyzers/utils/dto_mapper.dart | 48 +
lib/src/analyzers/utils/shannon_entropy.dart | 34 +
lib/src/cli/cli.dart | 1 -
lib/src/cli/command_runner.dart | 9 +-
lib/src/cli/commands/analyze.dart | 91 -
lib/src/cli/commands/analyze_command.dart | 56 +
lib/src/cli/commands/commands.dart | 2 -
lib/src/cli/commands/init.dart | 55 -
lib/src/cli/commands/init_command.dart | 55 +
lib/src/configuration/config_manager.dart | 83 +
lib/src/configuration/shield_config.dart | 59 +
lib/src/configuration/shield_config.g.dart | 30 +
lib/src/core/analyzer_engine.dart | 13 +
lib/src/core/analyzer_factory.dart | 49 +
lib/src/core/shield_run_config.dart | 32 +
lib/src/core/shield_runner.dart | 104 +
lib/src/domain/analysis_issue.dart | 27 +
lib/src/domain/analyzer_result.dart | 39 +
lib/src/domain/exceptions.dart | 39 +
lib/src/domain/issue_context.dart | 23 +
lib/src/generated/fallback_rules.dart | 2371 +++++++++++++++++
lib/src/reporters/console_reporter.dart | 83 +
lib/src/reporters/json_reporter.dart | 45 +
lib/src/reporters/reporter.dart | 7 +
.../configuration/configuration.dart | 1 -
.../configuration/glob_converter.dart | 16 -
.../configuration/lint_rule_converter.dart | 28 -
.../configuration/rule_config.dart | 52 -
.../configuration/shield_config.dart | 104 -
.../configuration/shield_config.g.dart | 24 -
.../exceptions/exceptions.dart | 1 -
.../invalid_configuration_exception.dart | 5 -
lib/src/security_analyzer/extensions.dart | 71 -
.../report/analysis_report/file_report.dart | 50 -
.../analysis_report/project_report.dart | 35 -
lib/src/security_analyzer/report/report.dart | 3 -
.../report/reporters/console_report.dart | 84 -
.../report/reporters/issue_reporter.dart | 7 -
.../report/reporters/reporters.dart | 1 -
.../security_analyzer/rules/enums/enums.dart | 3 -
.../rules/enums/rule_id.dart | 29 -
.../rules/enums/rule_status.dart | 1 -
.../rules/enums/severity.dart | 12 -
.../rules/models/matching_pattern.dart | 19 -
.../rules/models/matching_pattern.g.dart | 13 -
.../rules/models/models.dart | 2 -
.../rules/models/shield_secrets.dart | 45 -
.../rules/models/shield_secrets.g.dart | 18 -
.../rules/rule/error_node_collector.dart | 6 -
.../rules/rule/lint_issue.dart | 38 -
.../rules/rule/lint_rule.dart | 74 -
.../security_analyzer/rules/rule/rule.dart | 3 -
.../rules/rule_registry.dart | 57 -
lib/src/security_analyzer/rules/rules.dart | 2 -
.../rules_list/avoid_hardcoded_secrets.dart | 43 -
.../rules_list/avoid_hardcoded_urls.dart | 36 -
.../rules_list/crypto/avoid_weak_hashing.dart | 73 -
.../rules/rules_list/crypto/crypto.dart | 2 -
.../crypto/prefer_secure_random.dart | 50 -
.../rules_list/prefer_https_over_http.dart | 57 -
.../rules/rules_list/rules_list.dart | 4 -
.../security_analyzer/security_analyzer.dart | 104 -
.../security_analyzer/utils/suppression.dart | 67 -
lib/src/security_analyzer/workspace.dart | 36 -
lib/src/utils/path.dart | 25 +
lib/src/utils/utils.dart | 1 -
lib/src/utils/yaml.dart | 18 -
pubspec.yaml | 13 +-
rules.json | 2366 ++++++++++++++++
test/fixtures/configs/complete_config.yaml | 14 -
test/fixtures/configs/config_examples.dart | 50 -
test/fixtures/configs/invalid_config.yaml | 10 -
test/fixtures/configs/minimal_config.yaml | 4 -
test/fixtures/configs/yaml_inputs.dart | 42 -
test/fixtures/dart_files/mixed_code.dart | 61 -
test/fixtures/dart_files/secure_code.dart | 48 -
.../dart_files/suppression_example.dart | 26 -
test/fixtures/dart_files/vulnerable_code.dart | 116 -
test/helpers/test_analyzer.dart | 230 --
.../cryptography/avoid_weak_hashing_test.dart | 138 +
.../prefer_secure_random_test.dart | 109 +
.../network/avoid_hardcoded_urls_test.dart | 124 +
.../network/prefer_https_over_http_test.dart | 141 +
.../secrets/avoid_hardcoded_secrets_test.dart | 145 +
.../code/rules/secrets/secret_rule_test.dart | 60 +
.../analyzers/utils/shannon_entropy_test.dart | 44 +
.../src/configuration/shield_config_test.dart | 68 +
test/src/core/analyzer_factory_test.dart | 63 +
test/tool/utils/regex_sanitizer_test.dart | 45 +
.../configuration/glob_converter_test.dart | 26 -
.../lint_rule_converter_test.dart | 101 -
.../configuration/shield_config_test.dart | 77 -
.../rules/enums/rule_id_test.dart | 118 -
.../rules/enums/rule_status_test.dart | 56 -
.../rules/enums/severity_test.dart | 84 -
.../rules/models/lint_issue_test.dart | 226 --
.../rules/models/matching_pattern_test.dart | 154 --
.../rules/models/shield_secrets_test.dart | 200 --
.../rules/rule_registry_test.dart | 194 --
.../crypto/prefer_secure_random_test.dart | 239 --
.../utils/suppression_test.dart | 231 --
.../security_analyzer/workspace_test.dart | 280 --
test/unit/utils/yaml_test.dart | 105 -
tool/generate_rules.dart | 95 +
tool/utils/regex_sanitizer.dart | 98 +
173 files changed, 8781 insertions(+), 4580 deletions(-)
delete mode 100644 assets/shield_secrets.yaml
create mode 100644 codecov.yml
create mode 100644 docs.json
delete mode 100644 docs/.gitbook/assets/1.png
delete mode 100644 docs/.gitbook/assets/2.png
delete mode 100644 docs/.gitbook/assets/3.png
delete mode 100644 docs/.gitbook/assets/4.png
delete mode 100644 docs/.gitbook/assets/image.png
delete mode 100644 docs/.gitignore
delete mode 100644 docs/README.md
delete mode 100644 docs/SUMMARY.md
rename {resources/img => docs/assets}/shield-logo.svg (100%)
create mode 100644 docs/assets/title-image.png
delete mode 100644 docs/basics/commands.md
delete mode 100644 docs/basics/configuration.md
delete mode 100644 docs/basics/reports.md
delete mode 100644 docs/basics/rules.md
delete mode 100644 docs/beyond-the-basics/introduction.md
delete mode 100644 docs/beyond-the-basics/sast-basics.md
create mode 100644 docs/cli/analyze.mdx
create mode 100644 docs/cli/index.mdx
create mode 100644 docs/cli/init.mdx
delete mode 100644 docs/community-and-development/changelog.md
delete mode 100644 docs/community-and-development/contribution.md
delete mode 100644 docs/community-and-development/license.md
delete mode 100644 docs/community-and-development/road-map.md
create mode 100644 docs/guides/background/architecture.mdx
create mode 100644 docs/guides/background/sast-basics.mdx
create mode 100644 docs/guides/community-and-development/changelog.mdx
create mode 100644 docs/guides/community-and-development/license.mdx
create mode 100644 docs/guides/configuration/ignoring.mdx
create mode 100644 docs/guides/configuration/options.mdx
create mode 100644 docs/guides/getting-started/quick-start.mdx
create mode 100644 docs/index.mdx
delete mode 100644 docs/quickstart.md
create mode 100644 docs/rulebook/RULE_TEMPLATE.mdx
create mode 100644 docs/rulebook/cryptography/avoid-weak-hashing.mdx
create mode 100644 docs/rulebook/cryptography/prefer-secure-random.mdx
create mode 100644 docs/rulebook/index.mdx
create mode 100644 docs/rulebook/network/avoid-hardcoded-urls.mdx
create mode 100644 docs/rulebook/network/prefer-https-over-http.mdx
create mode 100644 docs/rulebook/secrets/avoid-hardcoded-secrets.mdx
delete mode 100644 example/shield_options.yaml
delete mode 100644 lib/assets/assets.dart
delete mode 100644 lib/assets/shield_secrets_dart.dart
create mode 100644 lib/main.dart
create mode 100644 lib/src/analyzers/analyzer.dart
create mode 100644 lib/src/analyzers/code/code_analyzer.dart
create mode 100644 lib/src/analyzers/code/plugin/shield_plugin.dart
create mode 100644 lib/src/analyzers/code/rules/cryptography/avoid_weak_hashing.dart
create mode 100644 lib/src/analyzers/code/rules/cryptography/prefer_secure_random.dart
create mode 100644 lib/src/analyzers/code/rules/network/avoid_harcoded_urls.dart
create mode 100644 lib/src/analyzers/code/rules/network/prefer_https_over_http.dart
create mode 100644 lib/src/analyzers/code/rules/rule_metadata.dart
create mode 100644 lib/src/analyzers/code/rules/rules.dart
create mode 100644 lib/src/analyzers/code/rules/secrets/avoid_hardcoded_secrets.dart
create mode 100644 lib/src/analyzers/code/rules/secrets/rule_provider.dart
create mode 100644 lib/src/analyzers/code/rules/secrets/secret_rule.dart
create mode 100644 lib/src/analyzers/code/rules/secrets/secret_rules.dart
create mode 100644 lib/src/analyzers/utils/analyzer_result.dart
create mode 100644 lib/src/analyzers/utils/diagnostic_mapper.dart
create mode 100644 lib/src/analyzers/utils/dto_mapper.dart
create mode 100644 lib/src/analyzers/utils/shannon_entropy.dart
delete mode 100644 lib/src/cli/cli.dart
delete mode 100644 lib/src/cli/commands/analyze.dart
create mode 100644 lib/src/cli/commands/analyze_command.dart
delete mode 100644 lib/src/cli/commands/commands.dart
delete mode 100644 lib/src/cli/commands/init.dart
create mode 100644 lib/src/cli/commands/init_command.dart
create mode 100644 lib/src/configuration/config_manager.dart
create mode 100644 lib/src/configuration/shield_config.dart
create mode 100644 lib/src/configuration/shield_config.g.dart
create mode 100644 lib/src/core/analyzer_engine.dart
create mode 100644 lib/src/core/analyzer_factory.dart
create mode 100644 lib/src/core/shield_run_config.dart
create mode 100644 lib/src/core/shield_runner.dart
create mode 100644 lib/src/domain/analysis_issue.dart
create mode 100644 lib/src/domain/analyzer_result.dart
create mode 100644 lib/src/domain/exceptions.dart
create mode 100644 lib/src/domain/issue_context.dart
create mode 100644 lib/src/generated/fallback_rules.dart
create mode 100644 lib/src/reporters/console_reporter.dart
create mode 100644 lib/src/reporters/json_reporter.dart
create mode 100644 lib/src/reporters/reporter.dart
delete mode 100644 lib/src/security_analyzer/configuration/configuration.dart
delete mode 100644 lib/src/security_analyzer/configuration/glob_converter.dart
delete mode 100644 lib/src/security_analyzer/configuration/lint_rule_converter.dart
delete mode 100644 lib/src/security_analyzer/configuration/rule_config.dart
delete mode 100644 lib/src/security_analyzer/configuration/shield_config.dart
delete mode 100644 lib/src/security_analyzer/configuration/shield_config.g.dart
delete mode 100644 lib/src/security_analyzer/exceptions/exceptions.dart
delete mode 100644 lib/src/security_analyzer/exceptions/invalid_configuration_exception.dart
delete mode 100644 lib/src/security_analyzer/extensions.dart
delete mode 100644 lib/src/security_analyzer/report/analysis_report/file_report.dart
delete mode 100644 lib/src/security_analyzer/report/analysis_report/project_report.dart
delete mode 100644 lib/src/security_analyzer/report/report.dart
delete mode 100644 lib/src/security_analyzer/report/reporters/console_report.dart
delete mode 100644 lib/src/security_analyzer/report/reporters/issue_reporter.dart
delete mode 100644 lib/src/security_analyzer/report/reporters/reporters.dart
delete mode 100644 lib/src/security_analyzer/rules/enums/enums.dart
delete mode 100644 lib/src/security_analyzer/rules/enums/rule_id.dart
delete mode 100644 lib/src/security_analyzer/rules/enums/rule_status.dart
delete mode 100644 lib/src/security_analyzer/rules/enums/severity.dart
delete mode 100644 lib/src/security_analyzer/rules/models/matching_pattern.dart
delete mode 100644 lib/src/security_analyzer/rules/models/matching_pattern.g.dart
delete mode 100644 lib/src/security_analyzer/rules/models/models.dart
delete mode 100644 lib/src/security_analyzer/rules/models/shield_secrets.dart
delete mode 100644 lib/src/security_analyzer/rules/models/shield_secrets.g.dart
delete mode 100644 lib/src/security_analyzer/rules/rule/error_node_collector.dart
delete mode 100644 lib/src/security_analyzer/rules/rule/lint_issue.dart
delete mode 100644 lib/src/security_analyzer/rules/rule/lint_rule.dart
delete mode 100644 lib/src/security_analyzer/rules/rule/rule.dart
delete mode 100644 lib/src/security_analyzer/rules/rule_registry.dart
delete mode 100644 lib/src/security_analyzer/rules/rules.dart
delete mode 100644 lib/src/security_analyzer/rules/rules_list/avoid_hardcoded_secrets.dart
delete mode 100644 lib/src/security_analyzer/rules/rules_list/avoid_hardcoded_urls.dart
delete mode 100644 lib/src/security_analyzer/rules/rules_list/crypto/avoid_weak_hashing.dart
delete mode 100644 lib/src/security_analyzer/rules/rules_list/crypto/crypto.dart
delete mode 100644 lib/src/security_analyzer/rules/rules_list/crypto/prefer_secure_random.dart
delete mode 100644 lib/src/security_analyzer/rules/rules_list/prefer_https_over_http.dart
delete mode 100644 lib/src/security_analyzer/rules/rules_list/rules_list.dart
delete mode 100644 lib/src/security_analyzer/security_analyzer.dart
delete mode 100644 lib/src/security_analyzer/utils/suppression.dart
delete mode 100644 lib/src/security_analyzer/workspace.dart
create mode 100644 lib/src/utils/path.dart
delete mode 100644 lib/src/utils/utils.dart
delete mode 100644 lib/src/utils/yaml.dart
create mode 100644 rules.json
delete mode 100644 test/fixtures/configs/complete_config.yaml
delete mode 100644 test/fixtures/configs/config_examples.dart
delete mode 100644 test/fixtures/configs/invalid_config.yaml
delete mode 100644 test/fixtures/configs/minimal_config.yaml
delete mode 100644 test/fixtures/configs/yaml_inputs.dart
delete mode 100644 test/fixtures/dart_files/mixed_code.dart
delete mode 100644 test/fixtures/dart_files/secure_code.dart
delete mode 100644 test/fixtures/dart_files/suppression_example.dart
delete mode 100644 test/fixtures/dart_files/vulnerable_code.dart
delete mode 100644 test/helpers/test_analyzer.dart
create mode 100644 test/src/analyzers/code/rules/cryptography/avoid_weak_hashing_test.dart
create mode 100644 test/src/analyzers/code/rules/cryptography/prefer_secure_random_test.dart
create mode 100644 test/src/analyzers/code/rules/network/avoid_hardcoded_urls_test.dart
create mode 100644 test/src/analyzers/code/rules/network/prefer_https_over_http_test.dart
create mode 100644 test/src/analyzers/code/rules/secrets/avoid_hardcoded_secrets_test.dart
create mode 100644 test/src/analyzers/code/rules/secrets/secret_rule_test.dart
create mode 100644 test/src/analyzers/utils/shannon_entropy_test.dart
create mode 100644 test/src/configuration/shield_config_test.dart
create mode 100644 test/src/core/analyzer_factory_test.dart
create mode 100644 test/tool/utils/regex_sanitizer_test.dart
delete mode 100644 test/unit/security_analyzer/configuration/glob_converter_test.dart
delete mode 100644 test/unit/security_analyzer/configuration/lint_rule_converter_test.dart
delete mode 100644 test/unit/security_analyzer/configuration/shield_config_test.dart
delete mode 100644 test/unit/security_analyzer/rules/enums/rule_id_test.dart
delete mode 100644 test/unit/security_analyzer/rules/enums/rule_status_test.dart
delete mode 100644 test/unit/security_analyzer/rules/enums/severity_test.dart
delete mode 100644 test/unit/security_analyzer/rules/models/lint_issue_test.dart
delete mode 100644 test/unit/security_analyzer/rules/models/matching_pattern_test.dart
delete mode 100644 test/unit/security_analyzer/rules/models/shield_secrets_test.dart
delete mode 100644 test/unit/security_analyzer/rules/rule_registry_test.dart
delete mode 100644 test/unit/security_analyzer/rules/rules_list/crypto/prefer_secure_random_test.dart
delete mode 100644 test/unit/security_analyzer/utils/suppression_test.dart
delete mode 100644 test/unit/security_analyzer/workspace_test.dart
delete mode 100644 test/unit/utils/yaml_test.dart
create mode 100644 tool/generate_rules.dart
create mode 100644 tool/utils/regex_sanitizer.dart
diff --git a/.github/workflows/dart.yml b/.github/workflows/dart.yml
index 242cbff..7fab192 100644
--- a/.github/workflows/dart.yml
+++ b/.github/workflows/dart.yml
@@ -17,7 +17,7 @@ jobs:
- uses: actions/checkout@v5
- uses: dart-lang/setup-dart@v1.6.5
with:
- sdk: '3.9.0'
+ sdk: '3.10.0'
- name: โ Install Dependencies
run: dart pub get
@@ -28,5 +28,23 @@ jobs:
- name: ๐ Analyze
run: dart analyze --fatal-infos --fatal-warnings .
+ - name: ๐งช Run Tests
+ run: dart test --coverage=coverage
+
+ - name: ๐ Generate Coverage Report
+ run: |
+ dart pub global activate coverage
+ dart pub global run coverage:format_coverage \
+ --lcov \
+ --in=coverage \
+ --out=coverage/lcov.info \
+ --report-on=lib
+
+ - name: ๐ Upload Coverage
+ uses: codecov/codecov-action@v4
+ with:
+ files: coverage/lcov.info
+ fail_ci_if_error: false
+
- name: ๐ Run Pana
run: dart pub global activate pana && dart pub global run pana
diff --git a/.gitignore b/.gitignore
index 6646d44..52632d5 100644
--- a/.gitignore
+++ b/.gitignore
@@ -11,8 +11,20 @@ pubspec.lock
coverage/
.test_runner.dart
-# Android studio and IntelliJ
-.idea
+# IDEs and Editors
+.idea/
+.vscode/
+*.swp
+*.bak
+
+# macOS
+.DS_Store
+
+# Project
+.gemini/
+GEMINI.md
+ROADMAP.md
+RULES_CATEGORIZATION.md
# Custom
code_examples/
\ No newline at end of file
diff --git a/.pubignore b/.pubignore
index efb994d..383be22 100644
--- a/.pubignore
+++ b/.pubignore
@@ -1,2 +1,15 @@
+# Documentation (hosted separately)
docs/
+docs.json
+
+# GitHub files
.github/
+
+# CI/CD configuration
+codecov.yml
+
+# Tests (not needed for package consumers)
+test/
+
+# Internal tooling
+tool/
diff --git a/README.md b/README.md
index bbf1f1c..30f79b0 100644
--- a/README.md
+++ b/README.md
@@ -10,6 +10,7 @@
Dart-based security-focused code analyzer which analyzes your Dart code for potential security flaws.
+
@@ -63,12 +64,8 @@ To initialize `dart_shield` in your project, run the following command:
dart_shield init
```
-This command creates a `shield_options.yaml` file in the root of your project. This file contains
-the configuration for `dart_shield`, which will be used during the analysis (similar to
-`analysis_options.yaml`).
-
-If a shield_options.yaml file already exists in your project and you want to recreate it, use the
-`-f` or `--force` flag:
+This command updates your `analysis_options.yaml` file to include the `dart_shield` configuration.
+If the `dart_shield` section already exists and you want to recreate it, use the `-f` or `--force` flag:
```bash
dart_shield init -f
@@ -87,51 +84,30 @@ dart_shield analyze .
dart_shield analyze lib
```
-This command analyzes your Dart code based on the configuration in the shield_options.yaml file.
-If the configuration file is not found, the command will fail.
+This command analyzes your Dart code for security issues.
# Configuration
-The `shield_options.yaml` file contains configuration options, primarily rules, for `dart_shield`.
-The configuration is similar to the `analysis_options.yaml` file, making it familiar to those who
-have
-used Dart analysis tools.
+Configuration is done through your `analysis_options.yaml` file using the `dart_shield` key.
+This approach follows Dart conventions and keeps all analysis configuration in one place.
-Example of the `shield_options.yaml` file:
+Example configuration in `analysis_options.yaml`:
```yaml
-# This is a sample configuration file for dart_shield.
-# โ ๏ธ Configuration file must be named `shield_options.yaml` and placed in the root of the project.
-
-# shield_options.yaml is file with structure similar to analysis_options.yaml and it defines the
-# rules that dart_shield will use to analyze your code.
-
-# The `shield` key is required.
-shield:
-
- # List of excluded files or directories from being analyzed
- exclude:
- # Exclude a file using path (path begins at the root of the project):
- - 'lib/ignored.dart'
- # Globs are also supported
- - '**.g.dart'
-
- # List of rules that dart_shield will use to analyze your code
- rules:
- - prefer_https_over_http
- - avoid_hardcoded_secrets
-
- # Some rules need more fine-tuning and are marked as experimental.
- # You can enable them by setting `enable_experimental` to `true`.
- enable_experimental: true
-
- # List of experimental rules that dart_shield will use to analyze your code
- # โ ๏ธ Experimental rules are subject to change and may not be as stable as regular rules.
- # โ ๏ธ Using "experimental_rules" without setting "enable_experimental" to "true" will cause an error.
- experimental_rules:
- - avoid_hardcoded_urls
- - avoid_weak_hashing
- - prefer_secure_random
+# Enable dart_shield as an analyzer plugin
+analyzer:
+ plugins:
+ - dart_shield
+
+# dart_shield configuration
+dart_shield:
+ analyzers:
+ code: true # Enable code analysis
+
+ # Future options:
+ # exclude:
+ # - 'lib/generated/**'
+ # - '**.g.dart'
```
# Rules
diff --git a/assets/shield_secrets.yaml b/assets/shield_secrets.yaml
deleted file mode 100644
index bc0382e..0000000
--- a/assets/shield_secrets.yaml
+++ /dev/null
@@ -1,28 +0,0 @@
-# Workaround: This file is duplicated in lib/assets/shield_secrets_dart.dart
-# because Dart doesn't support native assets yet.
-# See: https://github.com/dart-lang/sdk/issues/53562
-# TODO: Use native assets when Dart SDK supports it
-shield_patterns:
- version: 0.1.0-dev.1
- secrets:
- - name: 'Gitlab Personal Access Token'
- pattern: 'glpat-[0-9a-zA-Z_\-]{20}'
- - name: 'GitHub Personal Access Token'
- pattern: 'ghp_[0-9a-zA-Z]{36}'
- - name: 'GitHub OAuth Token'
- pattern: 'gho_[0-9a-zA-Z]{36}'
- - name: 'GitHub App Token'
- pattern: '(ghu|ghs)_[0-9a-zA-Z]{36}'
- - name: 'AWS Access Token'
- pattern: 'AKIA[0-9A-Z]{16}'
- - name: 'Stripe Live API Key'
- pattern: 'sk_live_[0-9a-zA-Z]{24}'
- - name: 'Google API Key'
- pattern: 'AIza[0-9A-Za-z\\-_]{35}'
- - name: 'Google Cloud Platform Service Account Key'
- pattern: '\"type\": \"service_account\"'
- - name: 'URL with password'
- pattern: '[a-zA-Z]{3,10}:\/\/[^$][^:@\/\n]{3,20}:[^$][^:@\n\/]{3,40}@.{1,100}'
- keys:
- - name: 'RSA Private Key'
- pattern: '-----BEGIN'
\ No newline at end of file
diff --git a/codecov.yml b/codecov.yml
new file mode 100644
index 0000000..f52cb8b
--- /dev/null
+++ b/codecov.yml
@@ -0,0 +1,18 @@
+coverage:
+ precision: 2
+ round: down
+ range: "60...100"
+
+ status:
+ project:
+ default:
+ target: 70%
+ threshold: 5%
+ patch:
+ default:
+ target: 80%
+
+ignore:
+ - "**/*.g.dart"
+ - "lib/src/generated/**"
+ - "test/**"
diff --git a/docs.json b/docs.json
new file mode 100644
index 0000000..779bbc1
--- /dev/null
+++ b/docs.json
@@ -0,0 +1,157 @@
+{
+ "name": "dart_shield",
+ "description": "Open-source, dart-first security library for building secure applications.",
+ "theme": {
+ "defaultTheme": "dark",
+ "primary": "#5FC9F8",
+ "primaryDark": "#04599C"
+ },
+ "content": {
+ "automaticallyInferNextPrevious": false
+ },
+ "favicon": "/assets/shield-logo.svg",
+ "logo": {
+ "light": "/assets/shield-logo.svg",
+ "dark": "/assets/shield-logo.svg"
+ },
+ "tabs": [
+ {
+ "id": "guides",
+ "title": "Guides",
+ "href": "/"
+ },
+ {
+ "id": "cli",
+ "title": "CLI",
+ "href": "/cli/index"
+ },
+ {
+ "id": "rulebook",
+ "title": "Rulebook",
+ "href": "/rulebook/index"
+ }
+ ],
+ "sidebar": [
+ {
+ "tab": "guides",
+ "group": "Getting Started",
+ "pages": [
+ {
+ "title": "Introduction",
+ "href": "/"
+ },
+ {
+ "title": "Quick Start",
+ "href": "/guides/getting-started/quick-start"
+ }
+ ]
+ },
+ {
+ "tab": "guides",
+ "group": "Configuration",
+ "pages": [
+ {
+ "title": "Options",
+ "href": "/guides/configuration/options"
+ },
+ {
+ "title": "Ignoring Rules",
+ "href": "/guides/configuration/ignoring"
+ }
+ ]
+ },
+ {
+ "tab": "guides",
+ "group": "Background",
+ "pages": [
+ {
+ "title": "SAST Basics",
+ "href": "/guides/background/sast-basics"
+ },
+ {
+ "title": "Architecture",
+ "href": "/guides/background/architecture"
+ }
+ ]
+ },
+ {
+ "tab": "guides",
+ "group": "Community",
+ "pages": [
+ {
+ "title": "Changelog",
+ "href": "/guides/community-and-development/changelog"
+ },
+ {
+ "title": "License",
+ "href": "/guides/community-and-development/license"
+ }
+ ]
+ },
+ {
+ "tab": "cli",
+ "group": "Reference",
+ "pages": [
+ {
+ "title": "Overview",
+ "href": "/cli/index"
+ },
+ {
+ "title": "init",
+ "href": "/cli/init"
+ },
+ {
+ "title": "analyze",
+ "href": "/cli/analyze"
+ }
+ ]
+ },
+ {
+ "tab": "rulebook",
+ "pages": [
+ {
+ "title": "Overview",
+ "href": "/rulebook/index"
+ }
+ ]
+ },
+ {
+ "tab": "rulebook",
+ "group": "Cryptography",
+ "pages": [
+ {
+ "title": "Avoid Weak Hashing",
+ "href": "/rulebook/cryptography/avoid-weak-hashing"
+ },
+ {
+ "title": "Prefer Secure Random",
+ "href": "/rulebook/cryptography/prefer-secure-random"
+ }
+ ]
+ },
+ {
+ "tab": "rulebook",
+ "group": "Network",
+ "pages": [
+ {
+ "title": "Prefer HTTPS over HTTP",
+ "href": "/rulebook/network/prefer-https-over-http"
+ },
+ {
+ "title": "Avoid Hardcoded URLs",
+ "href": "/rulebook/network/avoid-hardcoded-urls"
+ }
+ ]
+ },
+ {
+ "tab": "rulebook",
+ "group": "Secrets",
+ "pages": [
+ {
+ "title": "Avoid Hardcoded Secrets",
+ "href": "/rulebook/secrets/avoid-hardcoded-secrets"
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/docs/.gitbook/assets/1.png b/docs/.gitbook/assets/1.png
deleted file mode 100644
index 2dadf07d57d290c8e8ec3081587b436023df2330..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001
literal 189594
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%0DCvDt)_i@Y;7PJBD5
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