mcp-server-db2i 1.0.0 → 1.2.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 (40) hide show
  1. package/README.md +142 -7
  2. package/dist/config.d.ts +95 -1
  3. package/dist/config.d.ts.map +1 -1
  4. package/dist/config.js +136 -5
  5. package/dist/config.js.map +1 -1
  6. package/dist/db/connection.d.ts +0 -13
  7. package/dist/db/connection.d.ts.map +1 -1
  8. package/dist/db/connection.js +15 -32
  9. package/dist/db/connection.js.map +1 -1
  10. package/dist/db/queries.d.ts +22 -0
  11. package/dist/db/queries.d.ts.map +1 -1
  12. package/dist/db/queries.js +42 -35
  13. package/dist/db/queries.js.map +1 -1
  14. package/dist/index.js +43 -136
  15. package/dist/index.js.map +1 -1
  16. package/dist/server.d.ts +39 -0
  17. package/dist/server.d.ts.map +1 -0
  18. package/dist/server.js +133 -0
  19. package/dist/server.js.map +1 -0
  20. package/dist/tools/metadata.d.ts +51 -194
  21. package/dist/tools/metadata.d.ts.map +1 -1
  22. package/dist/tools/metadata.js +35 -167
  23. package/dist/tools/metadata.js.map +1 -1
  24. package/dist/tools/query.d.ts +8 -21
  25. package/dist/tools/query.d.ts.map +1 -1
  26. package/dist/tools/query.js +18 -24
  27. package/dist/tools/query.js.map +1 -1
  28. package/dist/utils/logger.d.ts +48 -0
  29. package/dist/utils/logger.d.ts.map +1 -0
  30. package/dist/utils/logger.js +124 -0
  31. package/dist/utils/logger.js.map +1 -0
  32. package/dist/utils/rateLimiter.d.ts +90 -0
  33. package/dist/utils/rateLimiter.d.ts.map +1 -0
  34. package/dist/utils/rateLimiter.js +215 -0
  35. package/dist/utils/rateLimiter.js.map +1 -0
  36. package/dist/utils/security/sqlSecurityValidator.d.ts +101 -0
  37. package/dist/utils/security/sqlSecurityValidator.d.ts.map +1 -0
  38. package/dist/utils/security/sqlSecurityValidator.js +312 -0
  39. package/dist/utils/security/sqlSecurityValidator.js.map +1 -0
  40. package/package.json +17 -3
package/README.md CHANGED
@@ -20,9 +20,11 @@ A [Model Context Protocol (MCP)](https://modelcontextprotocol.io/) server for IB
20
20
  | `list_tables` | List tables in a schema (with optional filter) |
21
21
  | `describe_table` | Get detailed column information |
22
22
  | `list_views` | List views in a schema (with optional filter) |
23
- | `list_indexes` | List indexes for a table |
23
+ | `list_indexes` | List SQL indexes for a table |
24
24
  | `get_table_constraints` | Get primary keys, foreign keys, unique constraints |
25
25
 
26
+ > **Note:** `list_indexes` and `get_table_constraints` query the `QSYS2` SQL catalog views and only return SQL-defined objects. Legacy DDS Logical Files and Physical File constraints are not included. This is standard DB2 for i behavior.
27
+
26
28
  ### Filter Syntax
27
29
 
28
30
  The list tools support pattern matching:
@@ -70,11 +72,26 @@ DB2I_HOSTNAME=your-ibm-i-host.com
70
72
  DB2I_USERNAME=your-username
71
73
  DB2I_PASSWORD=your-password
72
74
 
73
- # Optional
75
+ # Optional - Database
74
76
  DB2I_PORT=446 # Default: 446
75
77
  DB2I_DATABASE=*LOCAL # Default: *LOCAL
76
78
  DB2I_SCHEMA=your-default-schema # Default schema for all tools (can be overridden per-call)
77
79
  DB2I_JDBC_OPTIONS=naming=system;date format=iso
80
+
81
+ # Optional - Logging
82
+ LOG_LEVEL=info # debug, info, warn, error, fatal (default: info)
83
+ NODE_ENV=production # production = JSON logs, development = pretty logs
84
+ LOG_PRETTY=true # Override: force pretty (true) or JSON (false) logs
85
+ LOG_COLORS=true # Override: force colors on/off (auto-detected by default)
86
+
87
+ # Optional - Rate Limiting
88
+ RATE_LIMIT_WINDOW_MS=900000 # Time window in ms (default: 900000 = 15 minutes)
89
+ RATE_LIMIT_MAX_REQUESTS=100 # Max requests per window (default: 100)
90
+ RATE_LIMIT_ENABLED=true # Set to 'false' to disable (default: true)
91
+
92
+ # Optional - Query Limits
93
+ QUERY_DEFAULT_LIMIT=1000 # Default rows returned (default: 1000)
94
+ QUERY_MAX_LIMIT=10000 # Maximum rows allowed (default: 10000)
78
95
  ```
79
96
 
80
97
  ### Environment Variables
@@ -82,12 +99,25 @@ DB2I_JDBC_OPTIONS=naming=system;date format=iso
82
99
  | Variable | Required | Default | Description |
83
100
  |----------|----------|---------|-------------|
84
101
  | `DB2I_HOSTNAME` | Yes | - | IBM i hostname or IP address |
85
- | `DB2I_USERNAME` | Yes | - | IBM i user profile |
86
- | `DB2I_PASSWORD` | Yes | - | User password |
102
+ | `DB2I_USERNAME` | Yes* | - | IBM i user profile |
103
+ | `DB2I_PASSWORD` | Yes* | - | User password |
104
+ | `DB2I_USERNAME_FILE` | No | - | Path to file containing username (overrides `DB2I_USERNAME`) |
105
+ | `DB2I_PASSWORD_FILE` | No | - | Path to file containing password (overrides `DB2I_PASSWORD`) |
87
106
  | `DB2I_PORT` | No | `446` | JDBC port (446 is standard for IBM i) |
88
107
  | `DB2I_DATABASE` | No | `*LOCAL` | Database name |
89
108
  | `DB2I_SCHEMA` | No | - | Default schema/library for tools. If set, you don't need to specify schema in each tool call. |
90
109
  | `DB2I_JDBC_OPTIONS` | No | - | Additional JDBC options (semicolon-separated) |
110
+ | `LOG_LEVEL` | No | `info` | Log level: `debug`, `info`, `warn`, `error`, `fatal` |
111
+ | `NODE_ENV` | No | - | Set to `production` for JSON logs, otherwise pretty-printed |
112
+ | `LOG_PRETTY` | No | - | Override log format: `true` = pretty, `false` = JSON |
113
+ | `LOG_COLORS` | No | auto | Override colors: `true`/`false` (auto-detects TTY by default) |
114
+ | `RATE_LIMIT_WINDOW_MS` | No | `900000` | Rate limit time window in milliseconds (15 min) |
115
+ | `RATE_LIMIT_MAX_REQUESTS` | No | `100` | Maximum requests allowed per window |
116
+ | `RATE_LIMIT_ENABLED` | No | `true` | Set to `false` or `0` to disable rate limiting |
117
+ | `QUERY_DEFAULT_LIMIT` | No | `1000` | Default number of rows returned by queries |
118
+ | `QUERY_MAX_LIMIT` | No | `10000` | Maximum rows allowed (caps user-provided limits) |
119
+
120
+ *Either the environment variable or the corresponding `*_FILE` variable must be set. File-based secrets take priority when both are provided.
91
121
 
92
122
  ### JDBC Options
93
123
 
@@ -223,20 +253,124 @@ npm run build
223
253
 
224
254
  # Run production build
225
255
  npm start
256
+
257
+ # Run tests
258
+ npm test
259
+
260
+ # Run tests in watch mode
261
+ npm run test:watch
262
+
263
+ # Lint code
264
+ npm run lint
265
+
266
+ # Lint and fix
267
+ npm run lint:fix
268
+
269
+ # Type check
270
+ npm run typecheck
226
271
  ```
227
272
 
228
273
  ## Security
229
274
 
230
275
  - **Read-only access**: Only SELECT statements are permitted
231
- - **No credentials in code**: All sensitive data via environment variables
232
- - **Query validation**: Dangerous SQL keywords are blocked
233
- - **Result limiting**: Default limit of 1000 rows prevents large result sets
276
+ - **No credentials in code**: All sensitive data via environment variables or file-based secrets
277
+ - **Query validation**: AST-based SQL parsing plus regex validation blocks dangerous operations
278
+ - **Result limiting**: Default limit of 1000 rows, configurable max limit (default: 10000)
279
+ - **Rate limiting**: Configurable request throttling to prevent abuse (100 req/15 min default)
280
+ - **Structured logging**: Automatic redaction of sensitive fields like passwords
281
+
282
+ ### Rate Limiting
283
+
284
+ The server includes built-in rate limiting to protect the IBM i database from excessive queries:
285
+
286
+ - **Default**: 100 requests per 15-minute window
287
+ - **Scope**: Per server instance (for stdio transport, this effectively means per-client since each MCP client spawns its own server process)
288
+ - **Configurable**: Adjust via `RATE_LIMIT_*` environment variables or disable entirely
289
+
290
+ When the rate limit is exceeded, queries return an error with `waitTimeSeconds` indicating when to retry.
291
+
292
+ ### Credential Management
293
+
294
+ The server supports multiple methods for providing credentials, listed from most to least secure:
295
+
296
+ #### Option 1: Docker Secrets (Recommended for Production)
297
+
298
+ Docker secrets provide the most secure credential management. Secrets are mounted as files and never exposed in environment variables or process listings.
299
+
300
+ 1. Create secret files:
301
+
302
+ ```bash
303
+ mkdir -p ./secrets
304
+ echo "your-username" > ./secrets/db2i_username.txt
305
+ echo "your-password" > ./secrets/db2i_password.txt
306
+ chmod 600 ./secrets/*.txt
307
+ ```
308
+
309
+ 2. Configure docker-compose.yml to use secrets:
310
+
311
+ ```yaml
312
+ services:
313
+ mcp-server-db2i:
314
+ # ... other config ...
315
+ environment:
316
+ - DB2I_HOSTNAME=${DB2I_HOSTNAME}
317
+ - DB2I_USERNAME_FILE=/run/secrets/db2i_username
318
+ - DB2I_PASSWORD_FILE=/run/secrets/db2i_password
319
+ secrets:
320
+ - db2i_username
321
+ - db2i_password
322
+
323
+ secrets:
324
+ db2i_username:
325
+ file: ./secrets/db2i_username.txt
326
+ db2i_password:
327
+ file: ./secrets/db2i_password.txt
328
+ ```
329
+
330
+ For Docker Swarm or Kubernetes, use their native secret management instead of file-based secrets.
331
+
332
+ #### Option 2: External Secret Management
333
+
334
+ For enterprise deployments, integrate with secret management systems:
335
+
336
+ - **HashiCorp Vault**: Inject secrets at runtime
337
+ - **AWS Secrets Manager**: Use IAM roles for access
338
+ - **Azure Key Vault**: Integrate with managed identities
339
+
340
+ These systems can populate the `*_FILE` environment variables or inject secrets directly.
341
+
342
+ #### Option 3: Environment Variables (Development Only)
343
+
344
+ Plain environment variables are convenient for development but expose credentials through:
345
+ - `docker inspect` output
346
+ - Process listings (`ps aux`)
347
+ - Shell history
348
+ - Log files
349
+
350
+ ```bash
351
+ # .env file (ensure it's in .gitignore)
352
+ DB2I_USERNAME=your-username
353
+ DB2I_PASSWORD=your-password
354
+ ```
355
+
356
+ **Warning**: Never commit `.env` files or credentials to version control.
357
+
358
+ ### File-Based Secret Variables
359
+
360
+ | Variable | Description |
361
+ |----------|-------------|
362
+ | `DB2I_USERNAME_FILE` | Path to file containing username (takes priority over `DB2I_USERNAME`) |
363
+ | `DB2I_PASSWORD_FILE` | Path to file containing password (takes priority over `DB2I_PASSWORD`) |
234
364
 
235
365
  ## Compatibility
236
366
 
237
367
  - IBM i V7R3 and later (V7R5 recommended)
238
368
  - Works with any IBM i system accessible via JDBC over TCP/IP
239
369
 
370
+ ## Related Projects
371
+
372
+ - **[IBM ibmi-mcp-server](https://github.com/IBM/ibmi-mcp-server)** - IBM's official MCP server for IBM i systems. Offers YAML-based SQL tool definitions, AI agent frameworks, and production deployment options. Requires [Mapepire](https://mapepire-ibmi.github.io/) to be installed on your IBM i system, but if you can manage that prerequisite, it's worth checking out for more advanced use cases.
373
+
240
374
  ## Contributing
241
375
 
242
376
  Contributions are welcome! Please feel free to submit a Pull Request.
@@ -250,3 +384,4 @@ MIT License - see [LICENSE](LICENSE) for details.
250
384
  - [node-jt400](https://www.npmjs.com/package/node-jt400) - JT400 JDBC driver wrapper for Node.js
251
385
  - [Model Context Protocol](https://modelcontextprotocol.io/) - The protocol specification
252
386
  - [@modelcontextprotocol/sdk](https://github.com/modelcontextprotocol/typescript-sdk) - Official TypeScript SDK
387
+ - [IBM ibmi-mcp-server](https://github.com/IBM/ibmi-mcp-server) - SQL security validation patterns inspired by their approach to AST-based query validation
package/dist/config.d.ts CHANGED
@@ -1,6 +1,9 @@
1
1
  /**
2
2
  * Configuration module for IBM DB2i MCP Server
3
3
  * Handles environment variables and JDBC connection options
4
+ *
5
+ * Supports file-based secrets (e.g., Docker secrets) via *_FILE environment variables.
6
+ * File-based secrets take priority over plain environment variables.
4
7
  */
5
8
  export interface DB2iConfig {
6
9
  hostname: string;
@@ -12,7 +15,48 @@ export interface DB2iConfig {
12
15
  jdbcOptions: Record<string, string>;
13
16
  }
14
17
  /**
15
- * Load configuration from environment variables
18
+ * Valid log levels for the application
19
+ */
20
+ export type LogLevel = 'debug' | 'info' | 'warn' | 'error' | 'fatal';
21
+ /**
22
+ * Get the configured log level from environment
23
+ * Defaults to 'info' if not set or invalid
24
+ */
25
+ export declare function getLogLevel(): LogLevel;
26
+ /**
27
+ * Read a secret value from a file.
28
+ * Docker secrets are typically mounted at /run/secrets/<secret_name>
29
+ *
30
+ * @param filePath - Path to the file containing the secret
31
+ * @returns The secret value with leading/trailing whitespace trimmed
32
+ * @throws Error if file cannot be read
33
+ */
34
+ export declare function readSecretFromFile(filePath: string): string;
35
+ /**
36
+ * Get a secret value from either a file or environment variable.
37
+ * File-based secrets take priority (more secure).
38
+ *
39
+ * @param envVar - Name of the environment variable containing the value
40
+ * @param fileEnvVar - Name of the environment variable containing the file path
41
+ * @returns The secret value, or undefined if neither is set
42
+ */
43
+ export declare function getSecret(envVar: string, fileEnvVar: string): string | undefined;
44
+ /**
45
+ * Validate hostname format.
46
+ * Accepts valid hostnames (RFC 1123) and IPv4 addresses.
47
+ *
48
+ * @param hostname - The hostname or IP address to validate
49
+ * @returns true if the hostname format is valid, false otherwise
50
+ */
51
+ export declare function validateHostname(hostname: string): boolean;
52
+ /**
53
+ * Load configuration from environment variables.
54
+ *
55
+ * Supports file-based secrets for sensitive values (recommended for production):
56
+ * - DB2I_PASSWORD_FILE: Path to file containing password (e.g., Docker secret)
57
+ * - DB2I_USERNAME_FILE: Path to file containing username (optional)
58
+ *
59
+ * File-based secrets take priority over plain environment variables.
16
60
  */
17
61
  export declare function loadConfig(): DB2iConfig;
18
62
  /**
@@ -28,4 +72,54 @@ export declare function buildConnectionConfig(config: DB2iConfig): {
28
72
  * Get the default schema from config
29
73
  */
30
74
  export declare function getDefaultSchema(config: DB2iConfig): string | undefined;
75
+ /**
76
+ * Rate limit configuration interface
77
+ */
78
+ export interface RateLimitConfig {
79
+ /** Time window in milliseconds (default: 900000 = 15 minutes) */
80
+ windowMs: number;
81
+ /** Maximum requests allowed per window (default: 100) */
82
+ maxRequests: number;
83
+ /** Whether rate limiting is enabled (default: true) */
84
+ enabled: boolean;
85
+ }
86
+ /**
87
+ * Default rate limit configuration values
88
+ *
89
+ * Environment variables:
90
+ * - RATE_LIMIT_WINDOW_MS: Time window in milliseconds (default: 900000)
91
+ * - RATE_LIMIT_MAX_REQUESTS: Max requests per window (default: 100)
92
+ * - RATE_LIMIT_ENABLED: Set to 'false' or '0' to disable (default: true)
93
+ */
94
+ export declare const DEFAULT_RATE_LIMIT: RateLimitConfig;
95
+ /**
96
+ * Query limit configuration interface
97
+ */
98
+ export interface QueryLimitConfig {
99
+ /** Default number of rows to return (default: 1000) */
100
+ defaultLimit: number;
101
+ /** Maximum number of rows allowed (default: 10000) */
102
+ maxLimit: number;
103
+ }
104
+ /**
105
+ * Default query limit configuration values
106
+ *
107
+ * Environment variables:
108
+ * - QUERY_DEFAULT_LIMIT: Default rows to return (default: 1000)
109
+ * - QUERY_MAX_LIMIT: Maximum rows allowed, caps user-provided limits (default: 10000)
110
+ */
111
+ export declare const DEFAULT_QUERY_LIMIT: QueryLimitConfig;
112
+ /**
113
+ * Get query limit configuration from environment variables
114
+ */
115
+ export declare function getQueryLimitConfig(): QueryLimitConfig;
116
+ /**
117
+ * Apply query limit constraints.
118
+ * Returns the effective limit, capped to maxLimit.
119
+ *
120
+ * @param requestedLimit - The limit requested by the user (or undefined for default)
121
+ * @param config - Query limit configuration
122
+ * @returns The effective limit to use
123
+ */
124
+ export declare function applyQueryLimit(requestedLimit: number | undefined, config?: QueryLimitConfig): number;
31
125
  //# sourceMappingURL=config.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,WAAW,UAAU;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACrC;AA6BD;;GAEG;AACH,wBAAgB,UAAU,IAAI,UAAU,CAwBvC;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,UAAU,GAAG;IACzD,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC;CACvB,CA4BA;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,GAAG,SAAS,CAEvE"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,MAAM,WAAW,UAAU;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACrC;AAED;;GAEG;AACH,MAAM,MAAM,QAAQ,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,OAAO,CAAC;AAErE;;;GAGG;AACH,wBAAgB,WAAW,IAAI,QAAQ,CAStC;AAED;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAK3D;AAED;;;;;;;GAOG;AACH,wBAAgB,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAMhF;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAwB1D;AA6BD;;;;;;;;GAQG;AACH,wBAAgB,UAAU,IAAI,UAAU,CAiCvC;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,UAAU,GAAG;IACzD,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC;CACvB,CA4BA;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,GAAG,SAAS,CAEvE;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,iEAAiE;IACjE,QAAQ,EAAE,MAAM,CAAC;IACjB,yDAAyD;IACzD,WAAW,EAAE,MAAM,CAAC;IACpB,uDAAuD;IACvD,OAAO,EAAE,OAAO,CAAC;CAClB;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,kBAAkB,EAAE,eAIhC,CAAC;AAEF;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,uDAAuD;IACvD,YAAY,EAAE,MAAM,CAAC;IACrB,sDAAsD;IACtD,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;;;;;GAMG;AACH,eAAO,MAAM,mBAAmB,EAAE,gBAGjC,CAAC;AAEF;;GAEG;AACH,wBAAgB,mBAAmB,IAAI,gBAAgB,CAQtD;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAC7B,cAAc,EAAE,MAAM,GAAG,SAAS,EAClC,MAAM,GAAE,gBAAwC,GAC/C,MAAM,CAGR"}
package/dist/config.js CHANGED
@@ -1,7 +1,82 @@
1
1
  /**
2
2
  * Configuration module for IBM DB2i MCP Server
3
3
  * Handles environment variables and JDBC connection options
4
+ *
5
+ * Supports file-based secrets (e.g., Docker secrets) via *_FILE environment variables.
6
+ * File-based secrets take priority over plain environment variables.
4
7
  */
8
+ import { readFileSync, existsSync } from 'node:fs';
9
+ /**
10
+ * Get the configured log level from environment
11
+ * Defaults to 'info' if not set or invalid
12
+ */
13
+ export function getLogLevel() {
14
+ const level = process.env.LOG_LEVEL?.toLowerCase();
15
+ const validLevels = ['debug', 'info', 'warn', 'error', 'fatal'];
16
+ if (level && validLevels.includes(level)) {
17
+ return level;
18
+ }
19
+ return 'info';
20
+ }
21
+ /**
22
+ * Read a secret value from a file.
23
+ * Docker secrets are typically mounted at /run/secrets/<secret_name>
24
+ *
25
+ * @param filePath - Path to the file containing the secret
26
+ * @returns The secret value with leading/trailing whitespace trimmed
27
+ * @throws Error if file cannot be read
28
+ */
29
+ export function readSecretFromFile(filePath) {
30
+ if (!existsSync(filePath)) {
31
+ throw new Error(`Secret file not found: ${filePath}`);
32
+ }
33
+ return readFileSync(filePath, 'utf8').trim();
34
+ }
35
+ /**
36
+ * Get a secret value from either a file or environment variable.
37
+ * File-based secrets take priority (more secure).
38
+ *
39
+ * @param envVar - Name of the environment variable containing the value
40
+ * @param fileEnvVar - Name of the environment variable containing the file path
41
+ * @returns The secret value, or undefined if neither is set
42
+ */
43
+ export function getSecret(envVar, fileEnvVar) {
44
+ const filePath = process.env[fileEnvVar];
45
+ if (filePath) {
46
+ return readSecretFromFile(filePath);
47
+ }
48
+ return process.env[envVar];
49
+ }
50
+ /**
51
+ * Validate hostname format.
52
+ * Accepts valid hostnames (RFC 1123) and IPv4 addresses.
53
+ *
54
+ * @param hostname - The hostname or IP address to validate
55
+ * @returns true if the hostname format is valid, false otherwise
56
+ */
57
+ export function validateHostname(hostname) {
58
+ const trimmed = hostname.trim();
59
+ if (!trimmed)
60
+ return false;
61
+ // IPv4 pattern: four octets separated by dots
62
+ const ipv4Pattern = /^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/;
63
+ const ipv4Match = trimmed.match(ipv4Pattern);
64
+ if (ipv4Match) {
65
+ // Validate each octet is 0-255
66
+ return ipv4Match.slice(1).every((octet) => {
67
+ const num = parseInt(octet, 10);
68
+ return num >= 0 && num <= 255;
69
+ });
70
+ }
71
+ // Hostname pattern (RFC 1123):
72
+ // - Labels separated by dots
73
+ // - Each label: 1-63 chars, alphanumeric or hyphen, cannot start/end with hyphen
74
+ // - Total length up to 253 chars
75
+ if (trimmed.length > 253)
76
+ return false;
77
+ const hostnamePattern = /^[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(\.[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/;
78
+ return hostnamePattern.test(trimmed);
79
+ }
5
80
  /**
6
81
  * Parse JDBC options from a semicolon-separated string
7
82
  * Format: "key1=value1;key2=value2"
@@ -26,20 +101,29 @@ function parseJdbcOptions(optionsString) {
26
101
  return options;
27
102
  }
28
103
  /**
29
- * Load configuration from environment variables
104
+ * Load configuration from environment variables.
105
+ *
106
+ * Supports file-based secrets for sensitive values (recommended for production):
107
+ * - DB2I_PASSWORD_FILE: Path to file containing password (e.g., Docker secret)
108
+ * - DB2I_USERNAME_FILE: Path to file containing username (optional)
109
+ *
110
+ * File-based secrets take priority over plain environment variables.
30
111
  */
31
112
  export function loadConfig() {
32
113
  const hostname = process.env.DB2I_HOSTNAME;
33
- const username = process.env.DB2I_USERNAME;
34
- const password = process.env.DB2I_PASSWORD;
114
+ const username = getSecret('DB2I_USERNAME', 'DB2I_USERNAME_FILE');
115
+ const password = getSecret('DB2I_PASSWORD', 'DB2I_PASSWORD_FILE');
35
116
  if (!hostname) {
36
117
  throw new Error('DB2I_HOSTNAME environment variable is required');
37
118
  }
119
+ if (!validateHostname(hostname)) {
120
+ throw new Error(`Invalid DB2I_HOSTNAME format: "${hostname}". Must be a valid hostname or IPv4 address.`);
121
+ }
38
122
  if (!username) {
39
- throw new Error('DB2I_USERNAME environment variable is required');
123
+ throw new Error('DB2I_USERNAME environment variable is required (or DB2I_USERNAME_FILE for file-based secret)');
40
124
  }
41
125
  if (!password) {
42
- throw new Error('DB2I_PASSWORD environment variable is required');
126
+ throw new Error('DB2I_PASSWORD environment variable is required (or DB2I_PASSWORD_FILE for file-based secret)');
43
127
  }
44
128
  return {
45
129
  hostname,
@@ -80,4 +164,51 @@ export function buildConnectionConfig(config) {
80
164
  export function getDefaultSchema(config) {
81
165
  return config.schema || undefined;
82
166
  }
167
+ /**
168
+ * Default rate limit configuration values
169
+ *
170
+ * Environment variables:
171
+ * - RATE_LIMIT_WINDOW_MS: Time window in milliseconds (default: 900000)
172
+ * - RATE_LIMIT_MAX_REQUESTS: Max requests per window (default: 100)
173
+ * - RATE_LIMIT_ENABLED: Set to 'false' or '0' to disable (default: true)
174
+ */
175
+ export const DEFAULT_RATE_LIMIT = {
176
+ windowMs: 15 * 60 * 1000, // 15 minutes
177
+ maxRequests: 100,
178
+ enabled: true,
179
+ };
180
+ /**
181
+ * Default query limit configuration values
182
+ *
183
+ * Environment variables:
184
+ * - QUERY_DEFAULT_LIMIT: Default rows to return (default: 1000)
185
+ * - QUERY_MAX_LIMIT: Maximum rows allowed, caps user-provided limits (default: 10000)
186
+ */
187
+ export const DEFAULT_QUERY_LIMIT = {
188
+ defaultLimit: 1000,
189
+ maxLimit: 10000,
190
+ };
191
+ /**
192
+ * Get query limit configuration from environment variables
193
+ */
194
+ export function getQueryLimitConfig() {
195
+ const defaultLimit = parseInt(process.env.QUERY_DEFAULT_LIMIT || '1000', 10);
196
+ const maxLimit = parseInt(process.env.QUERY_MAX_LIMIT || '10000', 10);
197
+ return {
198
+ defaultLimit: Math.max(1, defaultLimit),
199
+ maxLimit: Math.max(1, maxLimit),
200
+ };
201
+ }
202
+ /**
203
+ * Apply query limit constraints.
204
+ * Returns the effective limit, capped to maxLimit.
205
+ *
206
+ * @param requestedLimit - The limit requested by the user (or undefined for default)
207
+ * @param config - Query limit configuration
208
+ * @returns The effective limit to use
209
+ */
210
+ export function applyQueryLimit(requestedLimit, config = getQueryLimitConfig()) {
211
+ const limit = requestedLimit ?? config.defaultLimit;
212
+ return Math.min(Math.max(1, limit), config.maxLimit);
213
+ }
83
214
  //# sourceMappingURL=config.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
@@ -1,7 +1,6 @@
1
1
  /**
2
2
  * JDBC Connection Manager for IBM DB2i using node-jt400
3
3
  */
4
- import { pool } from 'node-jt400';
5
4
  import type { DB2iConfig } from '../config.js';
6
5
  export interface QueryResult {
7
6
  rows: Record<string, unknown>[];
@@ -19,24 +18,12 @@ export interface QueryResult {
19
18
  * Initialize the connection pool
20
19
  */
21
20
  export declare function initializePool(config: DB2iConfig): void;
22
- /**
23
- * Get the connection pool instance
24
- */
25
- export declare function getPool(): ReturnType<typeof pool>;
26
21
  /**
27
22
  * Execute a query and return results
28
23
  */
29
24
  export declare function executeQuery(sql: string, params?: unknown[]): Promise<QueryResult>;
30
- /**
31
- * Execute a query with metadata about columns
32
- */
33
- export declare function executeQueryWithMetadata(sql: string, params?: unknown[]): Promise<QueryResult>;
34
25
  /**
35
26
  * Test the database connection
36
27
  */
37
28
  export declare function testConnection(): Promise<boolean>;
38
- /**
39
- * Close the connection pool
40
- */
41
- export declare function closePool(): Promise<void>;
42
29
  //# sourceMappingURL=connection.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"connection.d.ts","sourceRoot":"","sources":["../../src/db/connection.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAElC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAG/C,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC;IAChC,QAAQ,CAAC,EAAE;QACT,WAAW,EAAE,MAAM,CAAC;QACpB,OAAO,EAAE,KAAK,CAAC;YACb,IAAI,EAAE,MAAM,CAAC;YACb,IAAI,EAAE,MAAM,CAAC;YACb,SAAS,EAAE,MAAM,CAAC;YAClB,KAAK,EAAE,MAAM,CAAC;SACf,CAAC,CAAC;KACJ,CAAC;CACH;AAID;;GAEG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,UAAU,GAAG,IAAI,CAGvD;AAED;;GAEG;AACH,wBAAgB,OAAO,IAAI,UAAU,CAAC,OAAO,IAAI,CAAC,CAKjD;AAkBD;;GAEG;AACH,wBAAsB,YAAY,CAChC,GAAG,EAAE,MAAM,EACX,MAAM,GAAE,OAAO,EAAO,GACrB,OAAO,CAAC,WAAW,CAAC,CActB;AAED;;GAEG;AACH,wBAAsB,wBAAwB,CAC5C,GAAG,EAAE,MAAM,EACX,MAAM,GAAE,OAAO,EAAO,GACrB,OAAO,CAAC,WAAW,CAAC,CActB;AAED;;GAEG;AACH,wBAAsB,cAAc,IAAI,OAAO,CAAC,OAAO,CAAC,CAOvD;AAED;;GAEG;AACH,wBAAsB,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC,CAK/C"}
1
+ {"version":3,"file":"connection.d.ts","sourceRoot":"","sources":["../../src/db/connection.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAM/C,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC;IAChC,QAAQ,CAAC,EAAE;QACT,WAAW,EAAE,MAAM,CAAC;QACpB,OAAO,EAAE,KAAK,CAAC;YACb,IAAI,EAAE,MAAM,CAAC;YACb,IAAI,EAAE,MAAM,CAAC;YACb,SAAS,EAAE,MAAM,CAAC;YAClB,KAAK,EAAE,MAAM,CAAC;SACf,CAAC,CAAC;KACJ,CAAC;CACH;AAID;;GAEG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,UAAU,GAAG,IAAI,CAKvD;AA4BD;;GAEG;AACH,wBAAsB,YAAY,CAChC,GAAG,EAAE,MAAM,EACX,MAAM,GAAE,OAAO,EAAO,GACrB,OAAO,CAAC,WAAW,CAAC,CAgBtB;AAED;;GAEG;AACH,wBAAsB,cAAc,IAAI,OAAO,CAAC,OAAO,CAAC,CAUvD"}
@@ -3,18 +3,22 @@
3
3
  */
4
4
  import { pool } from 'node-jt400';
5
5
  import { buildConnectionConfig } from '../config.js';
6
+ import { createChildLogger } from '../utils/logger.js';
7
+ const log = createChildLogger({ component: 'database' });
6
8
  let connectionPool = null;
7
9
  /**
8
10
  * Initialize the connection pool
9
11
  */
10
12
  export function initializePool(config) {
13
+ log.debug({ hostname: config.hostname, port: config.port }, 'Initializing connection pool');
11
14
  const connectionConfig = buildConnectionConfig(config);
12
15
  connectionPool = pool(connectionConfig);
16
+ log.info({ hostname: config.hostname }, 'Connection pool created');
13
17
  }
14
18
  /**
15
- * Get the connection pool instance
19
+ * Get the connection pool instance (internal use only)
16
20
  */
17
- export function getPool() {
21
+ function getPool() {
18
22
  if (!connectionPool) {
19
23
  throw new Error('Connection pool not initialized. Call initializePool first.');
20
24
  }
@@ -45,31 +49,16 @@ function toParams(params) {
45
49
  export async function executeQuery(sql, params = []) {
46
50
  const db = getPool();
47
51
  try {
52
+ log.debug({ sql: sql.substring(0, 200), paramCount: params.length }, 'Executing query');
48
53
  const typedParams = toParams(params);
49
54
  const results = await db.query(sql, typedParams);
50
- return {
51
- rows: results,
52
- };
53
- }
54
- catch (error) {
55
- const message = error instanceof Error ? error.message : 'Unknown database error';
56
- throw new Error(`Database query failed: ${message}`);
57
- }
58
- }
59
- /**
60
- * Execute a query with metadata about columns
61
- */
62
- export async function executeQueryWithMetadata(sql, params = []) {
63
- const db = getPool();
64
- try {
65
- const typedParams = toParams(params);
66
- const results = await db.query(sql, typedParams);
67
- return {
68
- rows: results,
69
- };
55
+ const rows = results;
56
+ log.debug({ rowCount: rows.length }, 'Query completed');
57
+ return { rows };
70
58
  }
71
59
  catch (error) {
72
60
  const message = error instanceof Error ? error.message : 'Unknown database error';
61
+ log.debug({ err: error, sql: sql.substring(0, 200) }, 'Database query failed');
73
62
  throw new Error(`Database query failed: ${message}`);
74
63
  }
75
64
  }
@@ -78,20 +67,14 @@ export async function executeQueryWithMetadata(sql, params = []) {
78
67
  */
79
68
  export async function testConnection() {
80
69
  try {
70
+ log.debug('Testing database connection');
81
71
  await executeQuery('SELECT 1 FROM SYSIBM.SYSDUMMY1');
72
+ log.debug('Connection test successful');
82
73
  return true;
83
74
  }
84
- catch {
75
+ catch (error) {
76
+ log.warn({ err: error }, 'Connection test failed');
85
77
  return false;
86
78
  }
87
79
  }
88
- /**
89
- * Close the connection pool
90
- */
91
- export async function closePool() {
92
- if (connectionPool) {
93
- // node-jt400 pool doesn't have explicit close, but we can clear the reference
94
- connectionPool = null;
95
- }
96
- }
97
80
  //# sourceMappingURL=connection.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"connection.js","sourceRoot":"","sources":["../../src/db/connection.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"connection.js","sourceRoot":"","sources":["../../src/db/connection.ts"],"names":[],"mappings":"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"}