1
0

DefaultPoliciesSeeder.php 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. <?php
  2. declare(strict_types=1);
  3. use Phinx\Seed\AbstractSeed;
  4. /**
  5. * Seeds three baseline policies — paranoid (most aggressive), moderate
  6. * (balanced), strict (highest signal-to-noise) — with thresholds across all
  7. * five default categories.
  8. *
  9. * Naming nuance: "strict" here means "strictly only block when confidence is
  10. * high" (high threshold = fewer entries) while "paranoid" means "block at the
  11. * slightest hint" (low threshold = many entries). This mirrors operator usage
  12. * where "strict" describes the inclusion bar, not the resulting blocklist size.
  13. *
  14. * Idempotent: skips policies and threshold rows that already exist.
  15. */
  16. final class DefaultPoliciesSeeder extends AbstractSeed
  17. {
  18. /**
  19. * @return array<class-string<\Phinx\Seed\AbstractSeed>>
  20. */
  21. public function getDependencies(): array
  22. {
  23. return ['DefaultCategoriesSeeder'];
  24. }
  25. public function run(): void
  26. {
  27. $policiesSpec = [
  28. 'strict' => [
  29. 'description' => 'Conservative: block only IPs with strong signal across categories.',
  30. 'thresholds' => [
  31. 'brute_force' => '2.5000',
  32. 'spam' => '2.5000',
  33. 'scanner' => '2.5000',
  34. 'malware_c2' => '2.5000',
  35. 'web_attack' => '2.5000',
  36. ],
  37. ],
  38. 'moderate' => [
  39. 'description' => 'Balanced: block IPs with moderate accumulated abuse signal.',
  40. 'thresholds' => [
  41. 'brute_force' => '1.0000',
  42. 'spam' => '1.0000',
  43. 'scanner' => '1.0000',
  44. 'malware_c2' => '1.0000',
  45. 'web_attack' => '1.0000',
  46. ],
  47. ],
  48. 'paranoid' => [
  49. 'description' => 'Aggressive: block on faint signal; expect more false positives.',
  50. 'thresholds' => [
  51. 'brute_force' => '0.3000',
  52. 'spam' => '0.3000',
  53. 'scanner' => '0.3000',
  54. 'malware_c2' => '0.3000',
  55. 'web_attack' => '0.3000',
  56. ],
  57. ],
  58. ];
  59. $existingPolicies = $this->fetchAll('SELECT id, name FROM policies');
  60. $policyByName = [];
  61. foreach ($existingPolicies as $row) {
  62. $policyByName[$row['name']] = (int) $row['id'];
  63. }
  64. $insertPolicies = [];
  65. foreach ($policiesSpec as $name => $spec) {
  66. if (isset($policyByName[$name])) {
  67. continue;
  68. }
  69. $insertPolicies[] = [
  70. 'name' => $name,
  71. 'description' => $spec['description'],
  72. 'include_manual_blocks' => 1,
  73. ];
  74. }
  75. if ($insertPolicies !== []) {
  76. $this->table('policies')->insert($insertPolicies)->save();
  77. }
  78. // Re-fetch to include newly inserted policies.
  79. $allPolicies = $this->fetchAll('SELECT id, name FROM policies');
  80. $policyByName = [];
  81. foreach ($allPolicies as $row) {
  82. $policyByName[$row['name']] = (int) $row['id'];
  83. }
  84. $allCategories = $this->fetchAll('SELECT id, slug FROM categories');
  85. $categoryBySlug = [];
  86. foreach ($allCategories as $row) {
  87. $categoryBySlug[$row['slug']] = (int) $row['id'];
  88. }
  89. $existingThresholds = $this->fetchAll('SELECT policy_id, category_id FROM policy_category_thresholds');
  90. $existingPairs = [];
  91. foreach ($existingThresholds as $row) {
  92. $existingPairs[(int) $row['policy_id'] . ':' . (int) $row['category_id']] = true;
  93. }
  94. $thresholdRows = [];
  95. foreach ($policiesSpec as $name => $spec) {
  96. if (!isset($policyByName[$name])) {
  97. continue;
  98. }
  99. $policyId = $policyByName[$name];
  100. foreach ($spec['thresholds'] as $slug => $threshold) {
  101. if (!isset($categoryBySlug[$slug])) {
  102. continue;
  103. }
  104. $categoryId = $categoryBySlug[$slug];
  105. $key = $policyId . ':' . $categoryId;
  106. if (isset($existingPairs[$key])) {
  107. continue;
  108. }
  109. $thresholdRows[] = [
  110. 'policy_id' => $policyId,
  111. 'category_id' => $categoryId,
  112. 'threshold' => $threshold,
  113. ];
  114. }
  115. }
  116. if ($thresholdRows !== []) {
  117. $this->table('policy_category_thresholds')->insert($thresholdRows)->save();
  118. }
  119. }
  120. }