@freshguard/freshguard-core 0.13.2 → 0.15.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.
Files changed (196) hide show
  1. package/CHANGELOG.md +15 -1
  2. package/README.md +74 -1
  3. package/SKILL.md +229 -0
  4. package/dist/cli/index.d.ts +13 -0
  5. package/dist/cli/index.d.ts.map +1 -1
  6. package/dist/cli/index.js +74 -1
  7. package/dist/cli/index.js.map +1 -1
  8. package/dist/connectors/azure-sql.d.ts +121 -0
  9. package/dist/connectors/azure-sql.d.ts.map +1 -0
  10. package/dist/connectors/azure-sql.js +489 -0
  11. package/dist/connectors/azure-sql.js.map +1 -0
  12. package/dist/connectors/base-connector.d.ts +139 -0
  13. package/dist/connectors/base-connector.d.ts.map +1 -1
  14. package/dist/connectors/base-connector.js +160 -3
  15. package/dist/connectors/base-connector.js.map +1 -1
  16. package/dist/connectors/bigquery.d.ts +100 -0
  17. package/dist/connectors/bigquery.d.ts.map +1 -1
  18. package/dist/connectors/bigquery.js +143 -2
  19. package/dist/connectors/bigquery.js.map +1 -1
  20. package/dist/connectors/duckdb.d.ts +96 -0
  21. package/dist/connectors/duckdb.d.ts.map +1 -1
  22. package/dist/connectors/duckdb.js +144 -7
  23. package/dist/connectors/duckdb.js.map +1 -1
  24. package/dist/connectors/index.d.ts +28 -0
  25. package/dist/connectors/index.d.ts.map +1 -1
  26. package/dist/connectors/index.js +28 -0
  27. package/dist/connectors/index.js.map +1 -1
  28. package/dist/connectors/mssql.d.ts +119 -0
  29. package/dist/connectors/mssql.d.ts.map +1 -0
  30. package/dist/connectors/mssql.js +483 -0
  31. package/dist/connectors/mssql.js.map +1 -0
  32. package/dist/connectors/mysql.d.ts +85 -0
  33. package/dist/connectors/mysql.d.ts.map +1 -1
  34. package/dist/connectors/mysql.js +118 -3
  35. package/dist/connectors/mysql.js.map +1 -1
  36. package/dist/connectors/postgres.d.ts +85 -0
  37. package/dist/connectors/postgres.d.ts.map +1 -1
  38. package/dist/connectors/postgres.js +113 -6
  39. package/dist/connectors/postgres.js.map +1 -1
  40. package/dist/connectors/redshift.d.ts +90 -0
  41. package/dist/connectors/redshift.d.ts.map +1 -1
  42. package/dist/connectors/redshift.js +131 -7
  43. package/dist/connectors/redshift.js.map +1 -1
  44. package/dist/connectors/snowflake.d.ts +108 -0
  45. package/dist/connectors/snowflake.d.ts.map +1 -1
  46. package/dist/connectors/snowflake.js +137 -3
  47. package/dist/connectors/snowflake.js.map +1 -1
  48. package/dist/connectors/synapse.d.ts +123 -0
  49. package/dist/connectors/synapse.d.ts.map +1 -0
  50. package/dist/connectors/synapse.js +495 -0
  51. package/dist/connectors/synapse.js.map +1 -0
  52. package/dist/db/index.d.ts +25 -0
  53. package/dist/db/index.d.ts.map +1 -1
  54. package/dist/db/index.js +23 -0
  55. package/dist/db/index.js.map +1 -1
  56. package/dist/db/migrate.d.ts +23 -0
  57. package/dist/db/migrate.d.ts.map +1 -1
  58. package/dist/db/migrate.js +38 -0
  59. package/dist/db/migrate.js.map +1 -1
  60. package/dist/db/schema.d.ts +11 -0
  61. package/dist/db/schema.d.ts.map +1 -1
  62. package/dist/db/schema.js +70 -0
  63. package/dist/db/schema.js.map +1 -1
  64. package/dist/errors/debug-factory.d.ts +38 -0
  65. package/dist/errors/debug-factory.d.ts.map +1 -1
  66. package/dist/errors/debug-factory.js +40 -0
  67. package/dist/errors/debug-factory.js.map +1 -1
  68. package/dist/errors/index.d.ts +59 -0
  69. package/dist/errors/index.d.ts.map +1 -1
  70. package/dist/errors/index.js +110 -7
  71. package/dist/errors/index.js.map +1 -1
  72. package/dist/index.d.ts +32 -1
  73. package/dist/index.d.ts.map +1 -1
  74. package/dist/index.js +37 -1
  75. package/dist/index.js.map +1 -1
  76. package/dist/metadata/duckdb-storage.d.ts +3 -0
  77. package/dist/metadata/duckdb-storage.d.ts.map +1 -1
  78. package/dist/metadata/duckdb-storage.js +6 -0
  79. package/dist/metadata/duckdb-storage.js.map +1 -1
  80. package/dist/metadata/factory.d.ts +30 -0
  81. package/dist/metadata/factory.d.ts.map +1 -1
  82. package/dist/metadata/factory.js +31 -0
  83. package/dist/metadata/factory.js.map +1 -1
  84. package/dist/metadata/index.d.ts +26 -0
  85. package/dist/metadata/index.d.ts.map +1 -1
  86. package/dist/metadata/index.js +26 -0
  87. package/dist/metadata/index.js.map +1 -1
  88. package/dist/metadata/interface.d.ts +33 -0
  89. package/dist/metadata/interface.d.ts.map +1 -1
  90. package/dist/metadata/interface.js +3 -0
  91. package/dist/metadata/interface.js.map +1 -1
  92. package/dist/metadata/postgresql-storage.d.ts +3 -0
  93. package/dist/metadata/postgresql-storage.d.ts.map +1 -1
  94. package/dist/metadata/postgresql-storage.js +12 -2
  95. package/dist/metadata/postgresql-storage.js.map +1 -1
  96. package/dist/metadata/schema-config.d.ts +53 -0
  97. package/dist/metadata/schema-config.d.ts.map +1 -1
  98. package/dist/metadata/schema-config.js +64 -0
  99. package/dist/metadata/schema-config.js.map +1 -1
  100. package/dist/metadata/types.d.ts +3 -0
  101. package/dist/metadata/types.d.ts.map +1 -1
  102. package/dist/metadata/types.js +3 -0
  103. package/dist/metadata/types.js.map +1 -1
  104. package/dist/monitor/baseline-calculator.d.ts +56 -0
  105. package/dist/monitor/baseline-calculator.d.ts.map +1 -1
  106. package/dist/monitor/baseline-calculator.js +72 -0
  107. package/dist/monitor/baseline-calculator.js.map +1 -1
  108. package/dist/monitor/baseline-config.d.ts +77 -0
  109. package/dist/monitor/baseline-config.d.ts.map +1 -1
  110. package/dist/monitor/baseline-config.js +79 -1
  111. package/dist/monitor/baseline-config.js.map +1 -1
  112. package/dist/monitor/freshness.d.ts +40 -0
  113. package/dist/monitor/freshness.d.ts.map +1 -1
  114. package/dist/monitor/freshness.js +82 -3
  115. package/dist/monitor/freshness.js.map +1 -1
  116. package/dist/monitor/index.d.ts +29 -0
  117. package/dist/monitor/index.d.ts.map +1 -1
  118. package/dist/monitor/index.js +29 -0
  119. package/dist/monitor/index.js.map +1 -1
  120. package/dist/monitor/schema-baseline.d.ts +45 -0
  121. package/dist/monitor/schema-baseline.d.ts.map +1 -1
  122. package/dist/monitor/schema-baseline.js +63 -5
  123. package/dist/monitor/schema-baseline.js.map +1 -1
  124. package/dist/monitor/schema-changes.d.ts +45 -0
  125. package/dist/monitor/schema-changes.d.ts.map +1 -1
  126. package/dist/monitor/schema-changes.js +85 -0
  127. package/dist/monitor/schema-changes.js.map +1 -1
  128. package/dist/monitor/volume.d.ts +43 -0
  129. package/dist/monitor/volume.d.ts.map +1 -1
  130. package/dist/monitor/volume.js +89 -0
  131. package/dist/monitor/volume.js.map +1 -1
  132. package/dist/observability/logger.d.ts +91 -0
  133. package/dist/observability/logger.d.ts.map +1 -1
  134. package/dist/observability/logger.js +108 -0
  135. package/dist/observability/logger.js.map +1 -1
  136. package/dist/observability/metrics.d.ts +140 -0
  137. package/dist/observability/metrics.d.ts.map +1 -1
  138. package/dist/observability/metrics.js +184 -7
  139. package/dist/observability/metrics.js.map +1 -1
  140. package/dist/resilience/circuit-breaker.d.ts +112 -2
  141. package/dist/resilience/circuit-breaker.d.ts.map +1 -1
  142. package/dist/resilience/circuit-breaker.js +140 -6
  143. package/dist/resilience/circuit-breaker.js.map +1 -1
  144. package/dist/resilience/index.d.ts +9 -0
  145. package/dist/resilience/index.d.ts.map +1 -1
  146. package/dist/resilience/index.js +13 -0
  147. package/dist/resilience/index.js.map +1 -1
  148. package/dist/resilience/retry-policy.d.ts +105 -0
  149. package/dist/resilience/retry-policy.d.ts.map +1 -1
  150. package/dist/resilience/retry-policy.js +158 -7
  151. package/dist/resilience/retry-policy.js.map +1 -1
  152. package/dist/resilience/timeout-manager.d.ts +137 -0
  153. package/dist/resilience/timeout-manager.d.ts.map +1 -1
  154. package/dist/resilience/timeout-manager.js +151 -4
  155. package/dist/resilience/timeout-manager.js.map +1 -1
  156. package/dist/security/query-analyzer.d.ts +124 -0
  157. package/dist/security/query-analyzer.d.ts.map +1 -1
  158. package/dist/security/query-analyzer.js +150 -9
  159. package/dist/security/query-analyzer.js.map +1 -1
  160. package/dist/security/schema-cache.d.ts +152 -0
  161. package/dist/security/schema-cache.d.ts.map +1 -1
  162. package/dist/security/schema-cache.js +144 -12
  163. package/dist/security/schema-cache.js.map +1 -1
  164. package/dist/types/connector.d.ts +68 -1
  165. package/dist/types/connector.d.ts.map +1 -1
  166. package/dist/types/connector.js +38 -15
  167. package/dist/types/connector.js.map +1 -1
  168. package/dist/types/driver-results.d.ts +28 -0
  169. package/dist/types/driver-results.d.ts.map +1 -1
  170. package/dist/types/driver-results.js +12 -0
  171. package/dist/types/driver-results.js.map +1 -1
  172. package/dist/types.d.ts +113 -1
  173. package/dist/types.d.ts.map +1 -1
  174. package/dist/types.js +8 -0
  175. package/dist/types.js.map +1 -1
  176. package/dist/validation/index.d.ts +8 -0
  177. package/dist/validation/index.d.ts.map +1 -1
  178. package/dist/validation/index.js +12 -0
  179. package/dist/validation/index.js.map +1 -1
  180. package/dist/validation/runtime-validator.d.ts +98 -0
  181. package/dist/validation/runtime-validator.d.ts.map +1 -1
  182. package/dist/validation/runtime-validator.js +114 -1
  183. package/dist/validation/runtime-validator.js.map +1 -1
  184. package/dist/validation/sanitizers.d.ts +59 -0
  185. package/dist/validation/sanitizers.d.ts.map +1 -1
  186. package/dist/validation/sanitizers.js +104 -20
  187. package/dist/validation/sanitizers.js.map +1 -1
  188. package/dist/validation/schemas.d.ts +73 -0
  189. package/dist/validation/schemas.d.ts.map +1 -1
  190. package/dist/validation/schemas.js +132 -5
  191. package/dist/validation/schemas.js.map +1 -1
  192. package/dist/validators/index.d.ts +54 -0
  193. package/dist/validators/index.d.ts.map +1 -1
  194. package/dist/validators/index.js +93 -2
  195. package/dist/validators/index.js.map +1 -1
  196. package/package.json +6 -2
@@ -1,22 +1,67 @@
1
+ /**
2
+ * Schema baseline management for schema change monitoring
3
+ * Handles storage, retrieval and comparison of database schema baselines
4
+ *
5
+ * Security features:
6
+ * - Input validation to prevent SQL injection
7
+ * - Safe schema comparison algorithms
8
+ * - Sanitized error messages
9
+ *
10
+ * @module @freshguard/freshguard-core/monitor/schema-baseline
11
+ * @license MIT
12
+ */
1
13
  import type { SchemaBaseline, SchemaChanges } from '../types.js';
2
14
  import type { TableSchema } from '../types/connector.js';
3
15
  import type { MetadataStorage } from '../metadata/interface.js';
16
+ /**
17
+ * Manager for schema baseline operations
18
+ */
4
19
  export declare class SchemaBaselineManager {
20
+ /**
21
+ * Store a new schema baseline
22
+ */
5
23
  storeBaseline(metadataStorage: MetadataStorage, ruleId: string, tableName: string, schema: TableSchema, adaptationReason?: string): Promise<void>;
24
+ /**
25
+ * Get existing schema baseline for a rule
26
+ */
6
27
  getBaseline(metadataStorage: MetadataStorage, ruleId: string): Promise<SchemaBaseline | null>;
28
+ /**
29
+ * Update existing baseline with new schema
30
+ */
7
31
  updateBaseline(metadataStorage: MetadataStorage, ruleId: string, newSchema: TableSchema, adaptationReason: string): Promise<void>;
32
+ /**
33
+ * Generate consistent hash for schema comparison
34
+ */
8
35
  private generateSchemaHash;
9
36
  }
37
+ /**
38
+ * Schema comparison utility
39
+ */
10
40
  export declare class SchemaComparer {
41
+ /**
42
+ * Compare two schemas and detect changes
43
+ */
11
44
  compareSchemas(baseline: TableSchema, current: TableSchema, config?: {
12
45
  trackTypes?: boolean;
13
46
  trackNullability?: boolean;
14
47
  trackedColumns?: string[];
15
48
  monitoringMode?: 'full' | 'partial';
16
49
  }): SchemaChanges;
50
+ /**
51
+ * Normalize database type names for comparison
52
+ */
17
53
  private normalizeType;
54
+ /**
55
+ * Determine impact level for type changes
56
+ */
18
57
  private determineTypeChangeImpact;
58
+ /**
59
+ * Calculate overall severity based on changes
60
+ */
19
61
  private calculateSeverity;
62
+ /**
63
+ * Generate human-readable summary
64
+ */
20
65
  private generateSummary;
21
66
  }
22
67
  //# sourceMappingURL=schema-baseline.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"schema-baseline.d.ts","sourceRoot":"","sources":["../../src/monitor/schema-baseline.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAgB,MAAM,aAAa,CAAC;AAC/E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACzD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAOhE,qBAAa,qBAAqB;IAI1B,aAAa,CACjB,eAAe,EAAE,eAAe,EAChC,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,WAAW,EACnB,gBAAgB,CAAC,EAAE,MAAM,GACxB,OAAO,CAAC,IAAI,CAAC;IAyCV,WAAW,CAAC,eAAe,EAAE,eAAe,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC;IAwB7F,cAAc,CAClB,eAAe,EAAE,eAAe,EAChC,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,WAAW,EACtB,gBAAgB,EAAE,MAAM,GACvB,OAAO,CAAC,IAAI,CAAC;IAehB,OAAO,CAAC,kBAAkB;CAW3B;AAKD,qBAAa,cAAc;IAIzB,cAAc,CACZ,QAAQ,EAAE,WAAW,EACrB,OAAO,EAAE,WAAW,EACpB,MAAM,GAAE;QACN,UAAU,CAAC,EAAE,OAAO,CAAC;QACrB,gBAAgB,CAAC,EAAE,OAAO,CAAC;QAC3B,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;QAC1B,cAAc,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;KAChC,GACL,aAAa;IAsGhB,OAAO,CAAC,aAAa;IAYrB,OAAO,CAAC,yBAAyB;IA0CjC,OAAO,CAAC,iBAAiB;IAqBzB,OAAO,CAAC,eAAe;CA6BxB"}
1
+ {"version":3,"file":"schema-baseline.d.ts","sourceRoot":"","sources":["../../src/monitor/schema-baseline.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAgB,MAAM,aAAa,CAAC;AAC/E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACzD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAIhE;;GAEG;AACH,qBAAa,qBAAqB;IAChC;;OAEG;IACG,aAAa,CACjB,eAAe,EAAE,eAAe,EAChC,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,WAAW,EACnB,gBAAgB,CAAC,EAAE,MAAM,GACxB,OAAO,CAAC,IAAI,CAAC;IAsChB;;OAEG;IACG,WAAW,CAAC,eAAe,EAAE,eAAe,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC;IAqBnG;;OAEG;IACG,cAAc,CAClB,eAAe,EAAE,eAAe,EAChC,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,WAAW,EACtB,gBAAgB,EAAE,MAAM,GACvB,OAAO,CAAC,IAAI,CAAC;IAYhB;;OAEG;IACH,OAAO,CAAC,kBAAkB;CAW3B;AAED;;GAEG;AACH,qBAAa,cAAc;IACzB;;OAEG;IACH,cAAc,CACZ,QAAQ,EAAE,WAAW,EACrB,OAAO,EAAE,WAAW,EACpB,MAAM,GAAE;QACN,UAAU,CAAC,EAAE,OAAO,CAAC;QACrB,gBAAgB,CAAC,EAAE,OAAO,CAAC;QAC3B,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;QAC1B,cAAc,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;KAChC,GACL,aAAa;IAmGhB;;OAEG;IACH,OAAO,CAAC,aAAa;IASrB;;OAEG;IACH,OAAO,CAAC,yBAAyB;IAuCjC;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAkBzB;;OAEG;IACH,OAAO,CAAC,eAAe;CA6BxB"}
@@ -1,6 +1,24 @@
1
+ /**
2
+ * Schema baseline management for schema change monitoring
3
+ * Handles storage, retrieval and comparison of database schema baselines
4
+ *
5
+ * Security features:
6
+ * - Input validation to prevent SQL injection
7
+ * - Safe schema comparison algorithms
8
+ * - Sanitized error messages
9
+ *
10
+ * @module @freshguard/freshguard-core/monitor/schema-baseline
11
+ * @license MIT
12
+ */
1
13
  import { ConfigurationError, MetadataStorageError } from '../errors/index.js';
2
14
  import { createHash } from 'crypto';
15
+ /**
16
+ * Manager for schema baseline operations
17
+ */
3
18
  export class SchemaBaselineManager {
19
+ /**
20
+ * Store a new schema baseline
21
+ */
4
22
  async storeBaseline(metadataStorage, ruleId, tableName, schema, adaptationReason) {
5
23
  if (!metadataStorage) {
6
24
  throw new ConfigurationError('Metadata storage is required for schema baseline management');
@@ -29,6 +47,9 @@ export class SchemaBaselineManager {
29
47
  throw new MetadataStorageError('Failed to store schema baseline', 'schema_baseline_storage', undefined, error instanceof Error ? error : undefined);
30
48
  }
31
49
  }
50
+ /**
51
+ * Get existing schema baseline for a rule
52
+ */
32
53
  async getBaseline(metadataStorage, ruleId) {
33
54
  if (!metadataStorage) {
34
55
  throw new ConfigurationError('Metadata storage is required for schema baseline management');
@@ -43,6 +64,9 @@ export class SchemaBaselineManager {
43
64
  throw new MetadataStorageError('Failed to retrieve schema baseline', 'schema_baseline_retrieval', undefined, error instanceof Error ? error : undefined);
44
65
  }
45
66
  }
67
+ /**
68
+ * Update existing baseline with new schema
69
+ */
46
70
  async updateBaseline(metadataStorage, ruleId, newSchema, adaptationReason) {
47
71
  if (!metadataStorage) {
48
72
  throw new ConfigurationError('Metadata storage is required for schema baseline management');
@@ -52,32 +76,45 @@ export class SchemaBaselineManager {
52
76
  }
53
77
  await this.storeBaseline(metadataStorage, ruleId, newSchema.table, newSchema, adaptationReason);
54
78
  }
79
+ /**
80
+ * Generate consistent hash for schema comparison
81
+ */
55
82
  generateSchemaHash(schema) {
83
+ // Create deterministic string representation of schema
56
84
  const normalizedColumns = schema.columns
57
- .slice()
58
- .sort((a, b) => a.name.localeCompare(b.name))
85
+ .slice() // Create copy to avoid mutation
86
+ .sort((a, b) => a.name.localeCompare(b.name)) // Sort by name for consistency
59
87
  .map(col => `${col.name}:${col.type.toLowerCase()}:${col.nullable ? 'null' : 'notnull'}`)
60
88
  .join('|');
61
89
  const schemaString = `${schema.table}:${normalizedColumns}`;
62
90
  return createHash('sha256').update(schemaString).digest('hex');
63
91
  }
64
92
  }
93
+ /**
94
+ * Schema comparison utility
95
+ */
65
96
  export class SchemaComparer {
97
+ /**
98
+ * Compare two schemas and detect changes
99
+ */
66
100
  compareSchemas(baseline, current, config = {}) {
67
101
  if (!baseline || !current) {
68
102
  throw new ConfigurationError('Both baseline and current schemas are required for comparison');
69
103
  }
70
- const trackTypes = config.trackTypes !== false;
71
- const trackNullability = config.trackNullability === true;
104
+ const trackTypes = config.trackTypes !== false; // Default: true
105
+ const trackNullability = config.trackNullability === true; // Default: false
72
106
  const monitoringMode = config.monitoringMode ?? 'full';
107
+ // Create column maps for efficient lookup
73
108
  const baselineColumns = new Map(baseline.columns.map(col => [col.name, col]));
74
109
  const currentColumns = new Map(current.columns.map(col => [col.name, col]));
75
110
  const addedColumns = [];
76
111
  const removedColumns = [];
77
112
  const modifiedColumns = [];
113
+ // If partial mode, filter to only tracked columns
78
114
  const columnsToCheck = monitoringMode === 'partial' && config.trackedColumns
79
115
  ? config.trackedColumns
80
116
  : Array.from(new Set([...baselineColumns.keys(), ...currentColumns.keys()]));
117
+ // Check for added columns
81
118
  for (const [columnName, column] of currentColumns) {
82
119
  if (!columnsToCheck.includes(columnName))
83
120
  continue;
@@ -90,11 +127,13 @@ export class SchemaComparer {
90
127
  });
91
128
  }
92
129
  }
130
+ // Check for removed columns and modifications
93
131
  for (const [columnName, baselineColumn] of baselineColumns) {
94
132
  if (!columnsToCheck.includes(columnName))
95
133
  continue;
96
134
  const currentColumn = currentColumns.get(columnName);
97
135
  if (!currentColumn) {
136
+ // Column was removed
98
137
  removedColumns.push({
99
138
  columnName,
100
139
  changeType: 'removed',
@@ -103,6 +142,7 @@ export class SchemaComparer {
103
142
  });
104
143
  }
105
144
  else if (trackTypes || trackNullability) {
145
+ // Check for type or nullability changes
106
146
  const changes = [];
107
147
  if (trackTypes && this.normalizeType(baselineColumn.type) !== this.normalizeType(currentColumn.type)) {
108
148
  changes.push({
@@ -119,15 +159,18 @@ export class SchemaComparer {
119
159
  changeType: 'nullability_changed',
120
160
  oldValue: baselineColumn.nullable ? 'NULL' : 'NOT NULL',
121
161
  newValue: currentColumn.nullable ? 'NULL' : 'NOT NULL',
122
- impact: currentColumn.nullable ? 'safe' : 'breaking'
162
+ impact: currentColumn.nullable ? 'safe' : 'breaking' // Adding NOT NULL is breaking
123
163
  });
124
164
  }
125
165
  modifiedColumns.push(...changes);
126
166
  }
127
167
  }
168
+ // Calculate summary
128
169
  const changeCount = addedColumns.length + removedColumns.length + modifiedColumns.length;
129
170
  const hasChanges = changeCount > 0;
171
+ // Determine severity based on impact
130
172
  const severity = this.calculateSeverity(addedColumns, removedColumns, modifiedColumns);
173
+ // Generate summary message
131
174
  const summary = this.generateSummary(addedColumns, removedColumns, modifiedColumns);
132
175
  return {
133
176
  hasChanges,
@@ -139,6 +182,9 @@ export class SchemaComparer {
139
182
  severity
140
183
  };
141
184
  }
185
+ /**
186
+ * Normalize database type names for comparison
187
+ */
142
188
  normalizeType(type) {
143
189
  return type.toLowerCase()
144
190
  .replace(/varchar\(\d+\)/g, 'varchar')
@@ -147,9 +193,13 @@ export class SchemaComparer {
147
193
  .replace(/numeric\(\d+,?\d*\)/g, 'numeric')
148
194
  .trim();
149
195
  }
196
+ /**
197
+ * Determine impact level for type changes
198
+ */
150
199
  determineTypeChangeImpact(oldType, newType) {
151
200
  const normalizedOld = this.normalizeType(oldType);
152
201
  const normalizedNew = this.normalizeType(newType);
202
+ // Safe expansions (usually backwards compatible)
153
203
  const safeChanges = [
154
204
  ['varchar', 'text'],
155
205
  ['int', 'bigint'],
@@ -165,6 +215,7 @@ export class SchemaComparer {
165
215
  return 'safe';
166
216
  }
167
217
  }
218
+ // Warning changes (might be compatible but risky)
168
219
  const warningChanges = [
169
220
  ['bigint', 'int'],
170
221
  ['numeric', 'int'],
@@ -175,8 +226,12 @@ export class SchemaComparer {
175
226
  return 'warning';
176
227
  }
177
228
  }
229
+ // Everything else is potentially breaking
178
230
  return 'breaking';
179
231
  }
232
+ /**
233
+ * Calculate overall severity based on changes
234
+ */
180
235
  calculateSeverity(addedColumns, removedColumns, modifiedColumns) {
181
236
  const allChanges = [...addedColumns, ...removedColumns, ...modifiedColumns];
182
237
  if (allChanges.some(change => change.impact === 'breaking')) {
@@ -187,6 +242,9 @@ export class SchemaComparer {
187
242
  }
188
243
  return 'low';
189
244
  }
245
+ /**
246
+ * Generate human-readable summary
247
+ */
190
248
  generateSummary(addedColumns, removedColumns, modifiedColumns) {
191
249
  const parts = [];
192
250
  if (addedColumns.length > 0) {
@@ -1 +1 @@
1
- {"version":3,"file":"schema-baseline.js","sourceRoot":"","sources":["../../src/monitor/schema-baseline.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"schema-baseline.js","sourceRoot":"","sources":["../../src/monitor/schema-baseline.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,50 @@
1
+ /**
2
+ * Schema change monitoring algorithm
3
+ * Detects database schema changes and alerts based on configuration
4
+ *
5
+ * Security features:
6
+ * - Input validation to prevent SQL injection
7
+ * - Error sanitization to prevent information disclosure
8
+ * - Timeout protection against long-running queries
9
+ * - Safe parameter validation
10
+ *
11
+ * @module @freshguard/freshguard-core/monitor/schema-changes
12
+ * @license MIT
13
+ */
1
14
  import type { CheckResult, MonitoringRule, FreshGuardConfig } from '../types.js';
2
15
  import type { Connector } from '../types/connector.js';
3
16
  import type { MetadataStorage } from '../metadata/interface.js';
17
+ /**
18
+ * Detect schema changes by comparing the current table schema against a stored
19
+ * baseline. Returns `'alert'` when columns are added, removed, or modified.
20
+ *
21
+ * On the first run (no baseline), stores the current schema and returns `'ok'`.
22
+ * Subsequent runs compare against that baseline. The `adaptationMode` in
23
+ * `rule.schemaChangeConfig` controls whether safe changes auto-update the baseline.
24
+ *
25
+ * Requires metadata storage to persist schema baselines.
26
+ *
27
+ * @param connector - Database connector instance
28
+ * @param rule - Monitoring rule with `ruleType: 'schema_change'` and optional `schemaChangeConfig`
29
+ * @param metadataStorage - Metadata storage for schema baseline persistence
30
+ * @param config - Optional configuration including debug settings and timeouts
31
+ * @returns CheckResult with `status` and `schemaChanges` containing added/removed/modified columns
32
+ * @throws {ConfigurationError} If the rule is missing required schema change fields
33
+ * @throws {QueryError} If the schema query fails
34
+ * @throws {TimeoutError} If the query exceeds the configured timeout
35
+ *
36
+ * @example
37
+ * ```typescript
38
+ * import { checkSchemaChanges, createMetadataStorage, PostgresConnector } from '@freshguard/freshguard-core';
39
+ *
40
+ * const connector = new PostgresConnector({ host: 'localhost', database: 'mydb', username: 'user', password: 'pass', ssl: true });
41
+ * const storage = await createMetadataStorage();
42
+ * const rule = { id: 'r1', sourceId: 's1', name: 'Users Schema', tableName: 'users', ruleType: 'schema_change' as const, checkIntervalMinutes: 60, isActive: true, schemaChangeConfig: { adaptationMode: 'manual' as const, monitoringMode: 'full' as const }, createdAt: new Date(), updatedAt: new Date() };
43
+ * const result = await checkSchemaChanges(connector, rule, storage);
44
+ * if (result.schemaChanges?.hasChanges) { console.log(result.schemaChanges.summary); }
45
+ * ```
46
+ *
47
+ * @since 0.10.0
48
+ */
4
49
  export declare function checkSchemaChanges(connector: Connector, rule: MonitoringRule, metadataStorage?: MetadataStorage, config?: FreshGuardConfig): Promise<CheckResult>;
5
50
  //# sourceMappingURL=schema-changes.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"schema-changes.d.ts","sourceRoot":"","sources":["../../src/monitor/schema-changes.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,WAAW,EAAE,cAAc,EAAE,gBAAgB,EAA8B,MAAM,aAAa,CAAC;AAC7G,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AA4ChE,wBAAsB,kBAAkB,CACtC,SAAS,EAAE,SAAS,EACpB,IAAI,EAAE,cAAc,EACpB,eAAe,CAAC,EAAE,eAAe,EACjC,MAAM,CAAC,EAAE,gBAAgB,GACxB,OAAO,CAAC,WAAW,CAAC,CAqOtB"}
1
+ {"version":3,"file":"schema-changes.d.ts","sourceRoot":"","sources":["../../src/monitor/schema-changes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,cAAc,EAAE,gBAAgB,EAA8B,MAAM,aAAa,CAAC;AAC7G,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAYhE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,wBAAsB,kBAAkB,CACtC,SAAS,EAAE,SAAS,EACpB,IAAI,EAAE,cAAc,EACpB,eAAe,CAAC,EAAE,eAAe,EACjC,MAAM,CAAC,EAAE,gBAAgB,GACxB,OAAO,CAAC,WAAW,CAAC,CAqOtB"}
@@ -1,13 +1,59 @@
1
+ /**
2
+ * Schema change monitoring algorithm
3
+ * Detects database schema changes and alerts based on configuration
4
+ *
5
+ * Security features:
6
+ * - Input validation to prevent SQL injection
7
+ * - Error sanitization to prevent information disclosure
8
+ * - Timeout protection against long-running queries
9
+ * - Safe parameter validation
10
+ *
11
+ * @module @freshguard/freshguard-core/monitor/schema-changes
12
+ * @license MIT
13
+ */
1
14
  import { validateTableName } from '../validators/index.js';
2
15
  import { QueryError, TimeoutError, ConfigurationError, ErrorHandler } from '../errors/index.js';
3
16
  import { DebugErrorFactory, mergeDebugConfig } from '../errors/debug-factory.js';
4
17
  import { SchemaBaselineManager, SchemaComparer } from './schema-baseline.js';
18
+ /**
19
+ * Detect schema changes by comparing the current table schema against a stored
20
+ * baseline. Returns `'alert'` when columns are added, removed, or modified.
21
+ *
22
+ * On the first run (no baseline), stores the current schema and returns `'ok'`.
23
+ * Subsequent runs compare against that baseline. The `adaptationMode` in
24
+ * `rule.schemaChangeConfig` controls whether safe changes auto-update the baseline.
25
+ *
26
+ * Requires metadata storage to persist schema baselines.
27
+ *
28
+ * @param connector - Database connector instance
29
+ * @param rule - Monitoring rule with `ruleType: 'schema_change'` and optional `schemaChangeConfig`
30
+ * @param metadataStorage - Metadata storage for schema baseline persistence
31
+ * @param config - Optional configuration including debug settings and timeouts
32
+ * @returns CheckResult with `status` and `schemaChanges` containing added/removed/modified columns
33
+ * @throws {ConfigurationError} If the rule is missing required schema change fields
34
+ * @throws {QueryError} If the schema query fails
35
+ * @throws {TimeoutError} If the query exceeds the configured timeout
36
+ *
37
+ * @example
38
+ * ```typescript
39
+ * import { checkSchemaChanges, createMetadataStorage, PostgresConnector } from '@freshguard/freshguard-core';
40
+ *
41
+ * const connector = new PostgresConnector({ host: 'localhost', database: 'mydb', username: 'user', password: 'pass', ssl: true });
42
+ * const storage = await createMetadataStorage();
43
+ * const rule = { id: 'r1', sourceId: 's1', name: 'Users Schema', tableName: 'users', ruleType: 'schema_change' as const, checkIntervalMinutes: 60, isActive: true, schemaChangeConfig: { adaptationMode: 'manual' as const, monitoringMode: 'full' as const }, createdAt: new Date(), updatedAt: new Date() };
44
+ * const result = await checkSchemaChanges(connector, rule, storage);
45
+ * if (result.schemaChanges?.hasChanges) { console.log(result.schemaChanges.summary); }
46
+ * ```
47
+ *
48
+ * @since 0.10.0
49
+ */
5
50
  export async function checkSchemaChanges(connector, rule, metadataStorage, config) {
6
51
  const startTime = Date.now();
7
52
  const debugConfig = mergeDebugConfig(config?.debug);
8
53
  const debugFactory = new DebugErrorFactory(debugConfig);
9
54
  const debugId = `fg-schema-${Date.now().toString(36)}-${Math.random().toString(36).substr(2, 5)}`;
10
55
  try {
56
+ // Log debug info at start
11
57
  if (debugConfig.enabled) {
12
58
  console.log(`[DEBUG-${debugId}] Starting schema change check:`, {
13
59
  table: rule.tableName,
@@ -15,23 +61,29 @@ export async function checkSchemaChanges(connector, rule, metadataStorage, confi
15
61
  timestamp: new Date().toISOString()
16
62
  });
17
63
  }
64
+ // Validate input parameters for security
18
65
  validateSchemaChangeRule(rule);
19
66
  validateTableName(rule.tableName);
67
+ // Initialize managers
20
68
  const baselineManager = new SchemaBaselineManager();
21
69
  const schemaComparer = new SchemaComparer();
70
+ // Get configuration with defaults
22
71
  const schemaConfig = rule.schemaChangeConfig ?? {};
23
72
  const adaptationMode = schemaConfig.adaptationMode ?? 'manual';
24
73
  const monitoringMode = schemaConfig.monitoringMode ?? 'full';
25
74
  const trackTypes = schemaConfig.trackedColumns?.trackTypes !== false;
26
75
  const trackNullability = schemaConfig.trackedColumns?.trackNullability === true;
76
+ // Execute schema introspection with timeout protection
27
77
  const currentSchema = await executeWithTimeout(() => executeSchemaQuery(connector, rule.tableName, debugConfig, debugFactory), config?.timeoutMs ?? 30000, 'Schema introspection query timeout');
28
78
  if (!currentSchema) {
29
79
  throw new QueryError('Failed to retrieve current schema', 'schema_query', rule.tableName);
30
80
  }
81
+ // Get existing baseline if available
31
82
  let baseline = null;
32
83
  if (metadataStorage) {
33
84
  baseline = await baselineManager.getBaseline(metadataStorage, rule.id);
34
85
  }
86
+ // Handle first run - capture baseline and return OK
35
87
  if (!baseline) {
36
88
  if (debugConfig.enabled) {
37
89
  console.log(`[DEBUG-${debugId}] No baseline found, capturing initial schema`);
@@ -70,18 +122,21 @@ export async function checkSchemaChanges(connector, rule, metadataStorage, confi
70
122
  }
71
123
  });
72
124
  }
125
+ // Compare current schema with baseline
73
126
  const schemaChanges = schemaComparer.compareSchemas(baseline.schema, currentSchema, {
74
127
  trackTypes,
75
128
  trackNullability,
76
129
  trackedColumns: schemaConfig.trackedColumns?.columns,
77
130
  monitoringMode
78
131
  });
132
+ // Determine if we should alert or adapt
79
133
  let shouldAlert = schemaChanges.hasChanges;
80
134
  let shouldUpdateBaseline = false;
81
135
  let adaptationReason = '';
82
136
  if (schemaChanges.hasChanges) {
83
137
  switch (adaptationMode) {
84
138
  case 'auto': {
139
+ // Auto-adapt to safe changes only
85
140
  const hasSafeChangesOnly = [...schemaChanges.addedColumns, ...schemaChanges.modifiedColumns]
86
141
  .every(change => change.impact === 'safe') && schemaChanges.removedColumns.length === 0;
87
142
  if (hasSafeChangesOnly) {
@@ -92,22 +147,27 @@ export async function checkSchemaChanges(connector, rule, metadataStorage, confi
92
147
  break;
93
148
  }
94
149
  case 'alert_only':
150
+ // Always alert, never update baseline
95
151
  shouldAlert = true;
96
152
  shouldUpdateBaseline = false;
97
153
  break;
98
154
  case 'manual':
99
155
  default:
156
+ // Alert on changes, require manual baseline update
100
157
  shouldAlert = true;
101
158
  shouldUpdateBaseline = false;
102
159
  break;
103
160
  }
104
161
  }
162
+ // Update baseline if needed
105
163
  if (shouldUpdateBaseline && metadataStorage) {
106
164
  await baselineManager.updateBaseline(metadataStorage, rule.id, currentSchema, adaptationReason);
107
165
  }
166
+ // Determine status
108
167
  const status = shouldAlert ? 'alert' : 'ok';
109
168
  const executedAt = new Date();
110
169
  const executionDurationMs = Date.now() - startTime;
170
+ // Save execution result
111
171
  await saveExecutionResult(metadataStorage, {
112
172
  ruleId: rule.id,
113
173
  status,
@@ -133,9 +193,11 @@ export async function checkSchemaChanges(connector, rule, metadataStorage, confi
133
193
  });
134
194
  }
135
195
  catch (error) {
196
+ // Use secure error handling to prevent information disclosure
136
197
  const userMessage = ErrorHandler.getUserMessage(error);
137
198
  const executedAt = new Date();
138
199
  const executionDurationMs = Date.now() - startTime;
200
+ // Log debug error information
139
201
  if (debugConfig.enabled) {
140
202
  console.error(`[DEBUG-${debugId}] Schema change check failed:`, {
141
203
  table: rule.tableName,
@@ -154,18 +216,23 @@ export async function checkSchemaChanges(connector, rule, metadataStorage, confi
154
216
  error: userMessage
155
217
  }, debugConfig);
156
218
  }
219
+ // Create result with debug information
157
220
  const result = createSecureCheckResult('failed', {
158
221
  error: userMessage,
159
222
  executionDurationMs,
160
223
  executedAt,
161
224
  debugId
162
225
  });
226
+ // Add debug information if available
163
227
  if (debugConfig.enabled && error instanceof Error && 'debug' in error) {
164
228
  result.debug = error.debug;
165
229
  }
166
230
  return result;
167
231
  }
168
232
  }
233
+ /**
234
+ * Save execution result to metadata storage with error handling
235
+ */
169
236
  async function saveExecutionResult(metadataStorage, execution, debugConfig) {
170
237
  if (!metadataStorage)
171
238
  return;
@@ -193,6 +260,9 @@ async function saveExecutionResult(metadataStorage, execution, debugConfig) {
193
260
  }
194
261
  }
195
262
  }
263
+ /**
264
+ * Validate monitoring rule parameters for security
265
+ */
196
266
  function validateSchemaChangeRule(rule) {
197
267
  if (!rule) {
198
268
  throw new ConfigurationError('Monitoring rule is required');
@@ -203,9 +273,11 @@ function validateSchemaChangeRule(rule) {
203
273
  if (rule.tableName.length > 256) {
204
274
  throw new ConfigurationError('Table name too long (max 256 characters)');
205
275
  }
276
+ // Validate rule type matches
206
277
  if (rule.ruleType !== 'schema_change') {
207
278
  throw new ConfigurationError('Rule type must be "schema_change" for schema change checks');
208
279
  }
280
+ // Validate schema change configuration if provided
209
281
  const config = rule.schemaChangeConfig;
210
282
  if (config) {
211
283
  if (config.adaptationMode && !['auto', 'manual', 'alert_only'].includes(config.adaptationMode)) {
@@ -222,6 +294,9 @@ function validateSchemaChangeRule(rule) {
222
294
  }
223
295
  }
224
296
  }
297
+ /**
298
+ * Execute schema introspection using connector methods with proper error handling
299
+ */
225
300
  async function executeSchemaQuery(connector, tableName, debugConfig, debugFactory) {
226
301
  const startTime = performance.now();
227
302
  const queryContext = {
@@ -231,6 +306,7 @@ async function executeSchemaQuery(connector, tableName, debugConfig, debugFactor
231
306
  operation: 'schema_query'
232
307
  };
233
308
  try {
309
+ // Log connector operation in debug mode
234
310
  if (debugConfig.enabled) {
235
311
  console.log(`[DEBUG] Executing schema introspection via connector:`, {
236
312
  table: tableName,
@@ -241,6 +317,7 @@ async function executeSchemaQuery(connector, tableName, debugConfig, debugFactor
241
317
  }
242
318
  const schema = await connector.getTableSchema(tableName);
243
319
  queryContext.duration = performance.now() - startTime;
320
+ // Validate schema result
244
321
  if (!schema || typeof schema !== 'object') {
245
322
  throw debugFactory.createQueryError('Invalid schema returned from connector', undefined, queryContext);
246
323
  }
@@ -250,6 +327,7 @@ async function executeSchemaQuery(connector, tableName, debugConfig, debugFactor
250
327
  if (!Array.isArray(schema.columns) || schema.columns.length === 0) {
251
328
  throw debugFactory.createQueryError('Schema missing or empty columns array', undefined, queryContext);
252
329
  }
330
+ // Validate each column
253
331
  for (const column of schema.columns) {
254
332
  if (!column.name || typeof column.name !== 'string') {
255
333
  throw debugFactory.createQueryError('Invalid column name in schema', undefined, queryContext);
@@ -265,9 +343,13 @@ async function executeSchemaQuery(connector, tableName, debugConfig, debugFactor
265
343
  }
266
344
  catch (error) {
267
345
  queryContext.duration = performance.now() - startTime;
346
+ // Create enhanced error with debug context
268
347
  throw debugFactory.createQueryError('Failed to execute schema introspection via connector', error instanceof Error ? error : undefined, queryContext);
269
348
  }
270
349
  }
350
+ /**
351
+ * Execute operation with timeout protection
352
+ */
271
353
  async function executeWithTimeout(operation, timeoutMs, timeoutMessage) {
272
354
  return new Promise((resolve, reject) => {
273
355
  const timer = setTimeout(() => {
@@ -279,6 +361,9 @@ async function executeWithTimeout(operation, timeoutMs, timeoutMessage) {
279
361
  .finally(() => clearTimeout(timer));
280
362
  });
281
363
  }
364
+ /**
365
+ * Create secure check result with consistent structure
366
+ */
282
367
  function createSecureCheckResult(status, data) {
283
368
  return {
284
369
  status,