| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133 |
- <?php
- declare(strict_types=1);
- use Phinx\Seed\AbstractSeed;
- /**
- * Seeds three baseline policies — paranoid (most aggressive), moderate
- * (balanced), strict (highest signal-to-noise) — with thresholds across all
- * five default categories.
- *
- * Naming nuance: "strict" here means "strictly only block when confidence is
- * high" (high threshold = fewer entries) while "paranoid" means "block at the
- * slightest hint" (low threshold = many entries). This mirrors operator usage
- * where "strict" describes the inclusion bar, not the resulting blocklist size.
- *
- * Idempotent: skips policies and threshold rows that already exist.
- */
- final class DefaultPoliciesSeeder extends AbstractSeed
- {
- /**
- * @return array<class-string<\Phinx\Seed\AbstractSeed>>
- */
- public function getDependencies(): array
- {
- return ['DefaultCategoriesSeeder'];
- }
- public function run(): void
- {
- $policiesSpec = [
- 'strict' => [
- 'description' => 'Conservative: block only IPs with strong signal across categories.',
- 'thresholds' => [
- 'brute_force' => '2.5000',
- 'spam' => '2.5000',
- 'scanner' => '2.5000',
- 'malware_c2' => '2.5000',
- 'web_attack' => '2.5000',
- ],
- ],
- 'moderate' => [
- 'description' => 'Balanced: block IPs with moderate accumulated abuse signal.',
- 'thresholds' => [
- 'brute_force' => '1.0000',
- 'spam' => '1.0000',
- 'scanner' => '1.0000',
- 'malware_c2' => '1.0000',
- 'web_attack' => '1.0000',
- ],
- ],
- 'paranoid' => [
- 'description' => 'Aggressive: block on faint signal; expect more false positives.',
- 'thresholds' => [
- 'brute_force' => '0.3000',
- 'spam' => '0.3000',
- 'scanner' => '0.3000',
- 'malware_c2' => '0.3000',
- 'web_attack' => '0.3000',
- ],
- ],
- ];
- $existingPolicies = $this->fetchAll('SELECT id, name FROM policies');
- $policyByName = [];
- foreach ($existingPolicies as $row) {
- $policyByName[$row['name']] = (int) $row['id'];
- }
- $insertPolicies = [];
- foreach ($policiesSpec as $name => $spec) {
- if (isset($policyByName[$name])) {
- continue;
- }
- $insertPolicies[] = [
- 'name' => $name,
- 'description' => $spec['description'],
- 'include_manual_blocks' => 1,
- ];
- }
- if ($insertPolicies !== []) {
- $this->table('policies')->insert($insertPolicies)->save();
- }
- // Re-fetch to include newly inserted policies.
- $allPolicies = $this->fetchAll('SELECT id, name FROM policies');
- $policyByName = [];
- foreach ($allPolicies as $row) {
- $policyByName[$row['name']] = (int) $row['id'];
- }
- $allCategories = $this->fetchAll('SELECT id, slug FROM categories');
- $categoryBySlug = [];
- foreach ($allCategories as $row) {
- $categoryBySlug[$row['slug']] = (int) $row['id'];
- }
- $existingThresholds = $this->fetchAll('SELECT policy_id, category_id FROM policy_category_thresholds');
- $existingPairs = [];
- foreach ($existingThresholds as $row) {
- $existingPairs[(int) $row['policy_id'] . ':' . (int) $row['category_id']] = true;
- }
- $thresholdRows = [];
- foreach ($policiesSpec as $name => $spec) {
- if (!isset($policyByName[$name])) {
- continue;
- }
- $policyId = $policyByName[$name];
- foreach ($spec['thresholds'] as $slug => $threshold) {
- if (!isset($categoryBySlug[$slug])) {
- continue;
- }
- $categoryId = $categoryBySlug[$slug];
- $key = $policyId . ':' . $categoryId;
- if (isset($existingPairs[$key])) {
- continue;
- }
- $thresholdRows[] = [
- 'policy_id' => $policyId,
- 'category_id' => $categoryId,
- 'threshold' => $threshold,
- ];
- }
- }
- if ($thresholdRows !== []) {
- $this->table('policy_category_thresholds')->insert($thresholdRows)->save();
- }
- }
- }
|