itglue-mcp 1.0.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 (79) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +382 -0
  3. package/dist/index.d.ts +7 -0
  4. package/dist/index.d.ts.map +1 -0
  5. package/dist/index.js +513 -0
  6. package/dist/index.js.map +1 -0
  7. package/dist/lib/api-client.d.ts +76 -0
  8. package/dist/lib/api-client.d.ts.map +1 -0
  9. package/dist/lib/api-client.js +189 -0
  10. package/dist/lib/api-client.js.map +1 -0
  11. package/dist/lib/audit-logger.d.ts +51 -0
  12. package/dist/lib/audit-logger.d.ts.map +1 -0
  13. package/dist/lib/audit-logger.js +119 -0
  14. package/dist/lib/audit-logger.js.map +1 -0
  15. package/dist/lib/cache.d.ts +52 -0
  16. package/dist/lib/cache.d.ts.map +1 -0
  17. package/dist/lib/cache.js +115 -0
  18. package/dist/lib/cache.js.map +1 -0
  19. package/dist/lib/error-handler.d.ts +25 -0
  20. package/dist/lib/error-handler.d.ts.map +1 -0
  21. package/dist/lib/error-handler.js +99 -0
  22. package/dist/lib/error-handler.js.map +1 -0
  23. package/dist/lib/rate-limiter.d.ts +45 -0
  24. package/dist/lib/rate-limiter.d.ts.map +1 -0
  25. package/dist/lib/rate-limiter.js +124 -0
  26. package/dist/lib/rate-limiter.js.map +1 -0
  27. package/dist/tools/auxiliary/audit/compliance-check.d.ts +54 -0
  28. package/dist/tools/auxiliary/audit/compliance-check.d.ts.map +1 -0
  29. package/dist/tools/auxiliary/audit/compliance-check.js +303 -0
  30. package/dist/tools/auxiliary/audit/compliance-check.js.map +1 -0
  31. package/dist/tools/auxiliary/health/health-check.d.ts +36 -0
  32. package/dist/tools/auxiliary/health/health-check.d.ts.map +1 -0
  33. package/dist/tools/auxiliary/health/health-check.js +287 -0
  34. package/dist/tools/auxiliary/health/health-check.js.map +1 -0
  35. package/dist/tools/auxiliary/reporting/organization-report.d.ts +41 -0
  36. package/dist/tools/auxiliary/reporting/organization-report.d.ts.map +1 -0
  37. package/dist/tools/auxiliary/reporting/organization-report.js +297 -0
  38. package/dist/tools/auxiliary/reporting/organization-report.js.map +1 -0
  39. package/dist/tools/auxiliary/staleness/staleness-detector.d.ts +82 -0
  40. package/dist/tools/auxiliary/staleness/staleness-detector.d.ts.map +1 -0
  41. package/dist/tools/auxiliary/staleness/staleness-detector.js +238 -0
  42. package/dist/tools/auxiliary/staleness/staleness-detector.js.map +1 -0
  43. package/dist/tools/auxiliary/validation/data-validator.d.ts +46 -0
  44. package/dist/tools/auxiliary/validation/data-validator.d.ts.map +1 -0
  45. package/dist/tools/auxiliary/validation/data-validator.js +296 -0
  46. package/dist/tools/auxiliary/validation/data-validator.js.map +1 -0
  47. package/dist/tools/configurations.d.ts +48 -0
  48. package/dist/tools/configurations.d.ts.map +1 -0
  49. package/dist/tools/configurations.js +89 -0
  50. package/dist/tools/configurations.js.map +1 -0
  51. package/dist/tools/documents.d.ts +42 -0
  52. package/dist/tools/documents.d.ts.map +1 -0
  53. package/dist/tools/documents.js +79 -0
  54. package/dist/tools/documents.js.map +1 -0
  55. package/dist/tools/flexible-assets.d.ts +79 -0
  56. package/dist/tools/flexible-assets.d.ts.map +1 -0
  57. package/dist/tools/flexible-assets.js +136 -0
  58. package/dist/tools/flexible-assets.js.map +1 -0
  59. package/dist/tools/organizations.d.ts +68 -0
  60. package/dist/tools/organizations.d.ts.map +1 -0
  61. package/dist/tools/organizations.js +123 -0
  62. package/dist/tools/organizations.js.map +1 -0
  63. package/dist/tools/passwords.d.ts +86 -0
  64. package/dist/tools/passwords.d.ts.map +1 -0
  65. package/dist/tools/passwords.js +165 -0
  66. package/dist/tools/passwords.js.map +1 -0
  67. package/dist/tools/search.d.ts +34 -0
  68. package/dist/tools/search.d.ts.map +1 -0
  69. package/dist/tools/search.js +79 -0
  70. package/dist/tools/search.js.map +1 -0
  71. package/dist/types/itglue.d.ts +129 -0
  72. package/dist/types/itglue.d.ts.map +1 -0
  73. package/dist/types/itglue.js +10 -0
  74. package/dist/types/itglue.js.map +1 -0
  75. package/dist/types/mcp.d.ts +33 -0
  76. package/dist/types/mcp.d.ts.map +1 -0
  77. package/dist/types/mcp.js +11 -0
  78. package/dist/types/mcp.js.map +1 -0
  79. package/package.json +64 -0
@@ -0,0 +1,99 @@
1
+ /**
2
+ * Error Handler for ITGlue API Errors
3
+ * Transforms API errors into user-friendly messages
4
+ */
5
+ export class ITGlueAPIError extends Error {
6
+ statusCode;
7
+ isRetryable;
8
+ details;
9
+ constructor(message, statusCode, isRetryable = false, details) {
10
+ super(message);
11
+ this.name = 'ITGlueAPIError';
12
+ this.statusCode = statusCode;
13
+ this.isRetryable = isRetryable;
14
+ this.details = details;
15
+ // Maintains proper stack trace
16
+ Error.captureStackTrace(this, this.constructor);
17
+ }
18
+ }
19
+ /**
20
+ * Transform Axios error into ITGlueAPIError
21
+ */
22
+ export function handleApiError(error) {
23
+ if (error instanceof ITGlueAPIError) {
24
+ return error;
25
+ }
26
+ // Handle Axios errors
27
+ if (isAxiosError(error)) {
28
+ const statusCode = error.response?.status || 0;
29
+ const responseData = error.response?.data;
30
+ // Extract error details from ITGlue response
31
+ let message = 'An unknown error occurred';
32
+ let details;
33
+ if (responseData && Array.isArray(responseData.errors) && responseData.errors.length > 0) {
34
+ const firstError = responseData.errors[0];
35
+ message = firstError.title || message;
36
+ details = firstError.detail;
37
+ }
38
+ switch (statusCode) {
39
+ case 401:
40
+ return new ITGlueAPIError('Authentication failed. Please check your ITGLUE_API_KEY environment variable.', 401, false, details || 'Invalid or missing API key');
41
+ case 403:
42
+ return new ITGlueAPIError('Access denied. Your API key does not have permission to access this resource.', 403, false, details);
43
+ case 404:
44
+ return new ITGlueAPIError('Resource not found. The requested resource does not exist or you do not have access to it.', 404, false, details);
45
+ case 422:
46
+ return new ITGlueAPIError('Invalid request parameters.', 422, false, details || 'Check your request parameters');
47
+ case 429:
48
+ const retryAfter = error.response?.headers['retry-after'];
49
+ return new ITGlueAPIError('Rate limit exceeded. The request will be automatically retried.', 429, true, retryAfter ? `Retry after ${retryAfter} seconds` : undefined);
50
+ case 500:
51
+ case 502:
52
+ case 503:
53
+ case 504:
54
+ return new ITGlueAPIError('ITGlue server error. The request will be automatically retried.', statusCode, true, details);
55
+ default:
56
+ if (statusCode >= 500) {
57
+ return new ITGlueAPIError('ITGlue server error. The request will be automatically retried.', statusCode, true, details);
58
+ }
59
+ return new ITGlueAPIError(message || `Request failed with status ${statusCode}`, statusCode, false, details);
60
+ }
61
+ }
62
+ // Handle network errors
63
+ if (error instanceof Error) {
64
+ if (error.message.includes('ENOTFOUND') || error.message.includes('ECONNREFUSED')) {
65
+ return new ITGlueAPIError('Network error: Unable to connect to ITGlue API. Check your internet connection and ITGLUE_REGION setting.', 0, true, error.message);
66
+ }
67
+ if (error.message.includes('ETIMEDOUT')) {
68
+ return new ITGlueAPIError('Request timeout: ITGlue API did not respond in time.', 0, true, error.message);
69
+ }
70
+ return new ITGlueAPIError('Request failed: ' + error.message, 0, false, error.message);
71
+ }
72
+ return new ITGlueAPIError('An unknown error occurred', 0, false);
73
+ }
74
+ /**
75
+ * Type guard for Axios errors
76
+ */
77
+ function isAxiosError(error) {
78
+ return (typeof error === 'object' &&
79
+ error !== null &&
80
+ 'isAxiosError' in error &&
81
+ error.isAxiosError === true);
82
+ }
83
+ /**
84
+ * Format error for MCP tool response
85
+ */
86
+ export function formatErrorResponse(error) {
87
+ let errorMessage = `Error: ${error.message}`;
88
+ if (error.details) {
89
+ errorMessage += `\n\nDetails: ${error.details}`;
90
+ }
91
+ if (error.statusCode) {
92
+ errorMessage += `\n\nStatus Code: ${error.statusCode}`;
93
+ }
94
+ return {
95
+ content: [{ type: 'text', text: errorMessage }],
96
+ isError: true,
97
+ };
98
+ }
99
+ //# sourceMappingURL=error-handler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"error-handler.js","sourceRoot":"","sources":["../../src/lib/error-handler.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,MAAM,OAAO,cAAe,SAAQ,KAAK;IACvB,UAAU,CAAS;IACnB,WAAW,CAAU;IACrB,OAAO,CAAU;IAEjC,YAAY,OAAe,EAAE,UAAkB,EAAE,WAAW,GAAG,KAAK,EAAE,OAAgB;QACpF,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,gBAAgB,CAAC;QAC7B,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;QAC7B,IAAI,CAAC,WAAW,GAAG,WAAW,CAAC;QAC/B,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QAEvB,+BAA+B;QAC/B,KAAK,CAAC,iBAAiB,CAAC,IAAI,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC;IAClD,CAAC;CACF;AAED;;GAEG;AACH,MAAM,UAAU,cAAc,CAAC,KAAc;IAC3C,IAAI,KAAK,YAAY,cAAc,EAAE,CAAC;QACpC,OAAO,KAAK,CAAC;IACf,CAAC;IAED,sBAAsB;IACtB,IAAI,YAAY,CAAC,KAAK,CAAC,EAAE,CAAC;QACxB,MAAM,UAAU,GAAG,KAAK,CAAC,QAAQ,EAAE,MAAM,IAAI,CAAC,CAAC;QAC/C,MAAM,YAAY,GAAG,KAAK,CAAC,QAAQ,EAAE,IAAuC,CAAC;QAE7E,6CAA6C;QAC7C,IAAI,OAAO,GAAG,2BAA2B,CAAC;QAC1C,IAAI,OAA2B,CAAC;QAEhC,IAAI,YAAY,IAAI,KAAK,CAAC,OAAO,CAAC,YAAY,CAAC,MAAM,CAAC,IAAI,YAAY,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACzF,MAAM,UAAU,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;YAC1C,OAAO,GAAG,UAAU,CAAC,KAAK,IAAI,OAAO,CAAC;YACtC,OAAO,GAAG,UAAU,CAAC,MAAM,CAAC;QAC9B,CAAC;QAED,QAAQ,UAAU,EAAE,CAAC;YACnB,KAAK,GAAG;gBACN,OAAO,IAAI,cAAc,CACvB,+EAA+E,EAC/E,GAAG,EACH,KAAK,EACL,OAAO,IAAI,4BAA4B,CACxC,CAAC;YAEJ,KAAK,GAAG;gBACN,OAAO,IAAI,cAAc,CACvB,+EAA+E,EAC/E,GAAG,EACH,KAAK,EACL,OAAO,CACR,CAAC;YAEJ,KAAK,GAAG;gBACN,OAAO,IAAI,cAAc,CACvB,4FAA4F,EAC5F,GAAG,EACH,KAAK,EACL,OAAO,CACR,CAAC;YAEJ,KAAK,GAAG;gBACN,OAAO,IAAI,cAAc,CACvB,6BAA6B,EAC7B,GAAG,EACH,KAAK,EACL,OAAO,IAAI,+BAA+B,CAC3C,CAAC;YAEJ,KAAK,GAAG;gBACN,MAAM,UAAU,GAAG,KAAK,CAAC,QAAQ,EAAE,OAAO,CAAC,aAAa,CAAC,CAAC;gBAC1D,OAAO,IAAI,cAAc,CACvB,iEAAiE,EACjE,GAAG,EACH,IAAI,EACJ,UAAU,CAAC,CAAC,CAAC,eAAe,UAAU,UAAU,CAAC,CAAC,CAAC,SAAS,CAC7D,CAAC;YAEJ,KAAK,GAAG,CAAC;YACT,KAAK,GAAG,CAAC;YACT,KAAK,GAAG,CAAC;YACT,KAAK,GAAG;gBACN,OAAO,IAAI,cAAc,CACvB,iEAAiE,EACjE,UAAU,EACV,IAAI,EACJ,OAAO,CACR,CAAC;YAEJ;gBACE,IAAI,UAAU,IAAI,GAAG,EAAE,CAAC;oBACtB,OAAO,IAAI,cAAc,CACvB,iEAAiE,EACjE,UAAU,EACV,IAAI,EACJ,OAAO,CACR,CAAC;gBACJ,CAAC;gBAED,OAAO,IAAI,cAAc,CACvB,OAAO,IAAI,8BAA8B,UAAU,EAAE,EACrD,UAAU,EACV,KAAK,EACL,OAAO,CACR,CAAC;QACN,CAAC;IACH,CAAC;IAED,wBAAwB;IACxB,IAAI,KAAK,YAAY,KAAK,EAAE,CAAC;QAC3B,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAC,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAC,EAAE,CAAC;YAClF,OAAO,IAAI,cAAc,CACvB,2GAA2G,EAC3G,CAAC,EACD,IAAI,EACJ,KAAK,CAAC,OAAO,CACd,CAAC;QACJ,CAAC;QAED,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC;YACxC,OAAO,IAAI,cAAc,CACvB,sDAAsD,EACtD,CAAC,EACD,IAAI,EACJ,KAAK,CAAC,OAAO,CACd,CAAC;QACJ,CAAC;QAED,OAAO,IAAI,cAAc,CAAC,kBAAkB,GAAG,KAAK,CAAC,OAAO,EAAE,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;IACzF,CAAC;IAED,OAAO,IAAI,cAAc,CAAC,2BAA2B,EAAE,CAAC,EAAE,KAAK,CAAC,CAAC;AACnE,CAAC;AAED;;GAEG;AACH,SAAS,YAAY,CAAC,KAAc;IAClC,OAAO,CACL,OAAO,KAAK,KAAK,QAAQ;QACzB,KAAK,KAAK,IAAI;QACd,cAAc,IAAI,KAAK;QACtB,KAAa,CAAC,YAAY,KAAK,IAAI,CACrC,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,mBAAmB,CAAC,KAAqB;IAIvD,IAAI,YAAY,GAAG,UAAU,KAAK,CAAC,OAAO,EAAE,CAAC;IAE7C,IAAI,KAAK,CAAC,OAAO,EAAE,CAAC;QAClB,YAAY,IAAI,gBAAgB,KAAK,CAAC,OAAO,EAAE,CAAC;IAClD,CAAC;IAED,IAAI,KAAK,CAAC,UAAU,EAAE,CAAC;QACrB,YAAY,IAAI,oBAAoB,KAAK,CAAC,UAAU,EAAE,CAAC;IACzD,CAAC;IAED,OAAO;QACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,YAAY,EAAE,CAAC;QAC/C,OAAO,EAAE,IAAI;KACd,CAAC;AACJ,CAAC"}
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Queue-Based Rate Limiter
3
+ * Ensures we stay within ITGlue's rate limits (3000 req/5min = 10 req/sec)
4
+ * Conservative limit: 8 req/sec with 20% safety margin
5
+ */
6
+ import { AuditLogger } from './audit-logger.js';
7
+ export declare class RateLimiter {
8
+ private readonly requestsPerSecond;
9
+ private readonly requestQueue;
10
+ private readonly requestTimes;
11
+ private isProcessing;
12
+ private readonly logger;
13
+ constructor(requestsPerSecond?: number, logger?: AuditLogger);
14
+ /**
15
+ * Enqueue a request to be executed with rate limiting
16
+ */
17
+ enqueue<T>(fn: () => Promise<T>): Promise<T>;
18
+ /**
19
+ * Process queued requests with rate limiting
20
+ */
21
+ private processQueue;
22
+ /**
23
+ * Wait until a request slot is available
24
+ * Uses sliding window algorithm
25
+ */
26
+ private waitForSlot;
27
+ /**
28
+ * Sleep for specified milliseconds
29
+ */
30
+ private sleep;
31
+ /**
32
+ * Get current rate limiting stats
33
+ */
34
+ getStats(): {
35
+ queueSize: number;
36
+ requestsInLastSecond: number;
37
+ maxRequestsPerSecond: number;
38
+ utilization: number;
39
+ };
40
+ /**
41
+ * Clear the queue (useful for testing or shutdown)
42
+ */
43
+ clear(): void;
44
+ }
45
+ //# sourceMappingURL=rate-limiter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rate-limiter.d.ts","sourceRoot":"","sources":["../../src/lib/rate-limiter.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAQhD,qBAAa,WAAW;IACtB,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAS;IAC3C,OAAO,CAAC,QAAQ,CAAC,YAAY,CAA4B;IACzD,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAgB;IAC7C,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAc;gBAEzB,iBAAiB,SAAI,EAAE,MAAM,CAAC,EAAE,WAAW;IAKvD;;OAEG;IACG,OAAO,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IAgBlD;;OAEG;YACW,YAAY;IAgC1B;;;OAGG;YACW,WAAW;IA6BzB;;OAEG;IACH,OAAO,CAAC,KAAK;IAIb;;OAEG;IACH,QAAQ;;;;;;IAaR;;OAEG;IACH,KAAK,IAAI,IAAI;CAYd"}
@@ -0,0 +1,124 @@
1
+ /**
2
+ * Queue-Based Rate Limiter
3
+ * Ensures we stay within ITGlue's rate limits (3000 req/5min = 10 req/sec)
4
+ * Conservative limit: 8 req/sec with 20% safety margin
5
+ */
6
+ import { AuditLogger } from './audit-logger.js';
7
+ export class RateLimiter {
8
+ requestsPerSecond;
9
+ requestQueue = [];
10
+ requestTimes = []; // Track request times in last second
11
+ isProcessing = false;
12
+ logger;
13
+ constructor(requestsPerSecond = 8, logger) {
14
+ this.requestsPerSecond = requestsPerSecond;
15
+ this.logger = logger || new AuditLogger();
16
+ }
17
+ /**
18
+ * Enqueue a request to be executed with rate limiting
19
+ */
20
+ async enqueue(fn) {
21
+ return new Promise((resolve, reject) => {
22
+ this.requestQueue.push({ fn, resolve, reject });
23
+ if (this.requestQueue.length > 1) {
24
+ this.logger.debug('Request queued', {
25
+ queueSize: this.requestQueue.length,
26
+ });
27
+ }
28
+ if (!this.isProcessing) {
29
+ this.processQueue();
30
+ }
31
+ });
32
+ }
33
+ /**
34
+ * Process queued requests with rate limiting
35
+ */
36
+ async processQueue() {
37
+ if (this.isProcessing) {
38
+ return;
39
+ }
40
+ this.isProcessing = true;
41
+ while (this.requestQueue.length > 0) {
42
+ // Wait for available slot
43
+ await this.waitForSlot();
44
+ const request = this.requestQueue.shift();
45
+ if (!request) {
46
+ break;
47
+ }
48
+ // Track request time
49
+ const now = Date.now();
50
+ this.requestTimes.push(now);
51
+ // Execute request
52
+ try {
53
+ const result = await request.fn();
54
+ request.resolve(result);
55
+ }
56
+ catch (error) {
57
+ request.reject(error);
58
+ }
59
+ }
60
+ this.isProcessing = false;
61
+ }
62
+ /**
63
+ * Wait until a request slot is available
64
+ * Uses sliding window algorithm
65
+ */
66
+ async waitForSlot() {
67
+ const now = Date.now();
68
+ const oneSecondAgo = now - 1000;
69
+ // Remove requests older than 1 second
70
+ while (this.requestTimes.length > 0 && this.requestTimes[0] < oneSecondAgo) {
71
+ this.requestTimes.shift();
72
+ }
73
+ // If we're at the limit, wait
74
+ if (this.requestTimes.length >= this.requestsPerSecond) {
75
+ const oldestRequestTime = this.requestTimes[0];
76
+ const waitTime = oldestRequestTime + 1000 - now;
77
+ if (waitTime > 0) {
78
+ this.logger.debug('Rate limit throttling', {
79
+ waitTimeMs: waitTime,
80
+ currentRate: this.requestTimes.length,
81
+ maxRate: this.requestsPerSecond,
82
+ });
83
+ await this.sleep(waitTime);
84
+ // Recursively check again after waiting
85
+ return this.waitForSlot();
86
+ }
87
+ }
88
+ }
89
+ /**
90
+ * Sleep for specified milliseconds
91
+ */
92
+ sleep(ms) {
93
+ return new Promise(resolve => setTimeout(resolve, ms));
94
+ }
95
+ /**
96
+ * Get current rate limiting stats
97
+ */
98
+ getStats() {
99
+ const now = Date.now();
100
+ const oneSecondAgo = now - 1000;
101
+ const recentRequests = this.requestTimes.filter(time => time > oneSecondAgo);
102
+ return {
103
+ queueSize: this.requestQueue.length,
104
+ requestsInLastSecond: recentRequests.length,
105
+ maxRequestsPerSecond: this.requestsPerSecond,
106
+ utilization: (recentRequests.length / this.requestsPerSecond) * 100,
107
+ };
108
+ }
109
+ /**
110
+ * Clear the queue (useful for testing or shutdown)
111
+ */
112
+ clear() {
113
+ // Reject all pending requests
114
+ while (this.requestQueue.length > 0) {
115
+ const request = this.requestQueue.shift();
116
+ if (request) {
117
+ request.reject(new Error('Rate limiter cleared'));
118
+ }
119
+ }
120
+ this.requestTimes.length = 0;
121
+ this.isProcessing = false;
122
+ }
123
+ }
124
+ //# sourceMappingURL=rate-limiter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rate-limiter.js","sourceRoot":"","sources":["../../src/lib/rate-limiter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Compliance Check Tools
3
+ * Verify ITGlue data meets organizational compliance standards
4
+ */
5
+ import { z } from 'zod';
6
+ import type { APIClient } from '../../../lib/api-client.js';
7
+ export declare const ComplianceCheckSchema: z.ZodObject<{
8
+ organization_id: z.ZodString;
9
+ checks: z.ZodDefault<z.ZodArray<z.ZodEnum<["passwords", "configurations", "documentation", "warranties"]>, "many">>;
10
+ }, "strip", z.ZodTypeAny, {
11
+ organization_id: string;
12
+ checks: ("configurations" | "passwords" | "documentation" | "warranties")[];
13
+ }, {
14
+ organization_id: string;
15
+ checks?: ("configurations" | "passwords" | "documentation" | "warranties")[] | undefined;
16
+ }>;
17
+ export type ComplianceCheckArgs = z.infer<typeof ComplianceCheckSchema>;
18
+ interface ComplianceIssue {
19
+ severity: 'low' | 'medium' | 'high' | 'critical';
20
+ category: string;
21
+ issue: string;
22
+ resource_type: string;
23
+ resource_id?: string;
24
+ recommendation: string;
25
+ }
26
+ /**
27
+ * Perform comprehensive compliance checks on ITGlue data
28
+ */
29
+ export declare function performComplianceCheck(client: APIClient, args: ComplianceCheckArgs): Promise<{
30
+ content: Array<{
31
+ type: "text";
32
+ text: string;
33
+ }>;
34
+ isError: true;
35
+ } | {
36
+ content: {
37
+ type: "text";
38
+ text: string;
39
+ }[];
40
+ data: {
41
+ organization_id: string;
42
+ checks_performed: ("configurations" | "passwords" | "documentation" | "warranties")[];
43
+ total_issues: number;
44
+ issues_by_severity: {
45
+ critical: number;
46
+ high: number;
47
+ medium: number;
48
+ low: number;
49
+ };
50
+ issues: ComplianceIssue[];
51
+ };
52
+ }>;
53
+ export {};
54
+ //# sourceMappingURL=compliance-check.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compliance-check.d.ts","sourceRoot":"","sources":["../../../../src/tools/auxiliary/audit/compliance-check.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,4BAA4B,CAAC;AAI5D,eAAO,MAAM,qBAAqB;;;;;;;;;EAMhC,CAAC;AAEH,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAExE,UAAU,eAAe;IACvB,QAAQ,EAAE,KAAK,GAAG,QAAQ,GAAG,MAAM,GAAG,UAAU,CAAC;IACjD,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,MAAM,CAAC;CACxB;AAED;;GAEG;AACH,wBAAsB,sBAAsB,CAAC,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;GAkDxF"}
@@ -0,0 +1,303 @@
1
+ /**
2
+ * Compliance Check Tools
3
+ * Verify ITGlue data meets organizational compliance standards
4
+ */
5
+ import { z } from 'zod';
6
+ import { handleApiError, formatErrorResponse } from '../../../lib/error-handler.js';
7
+ export const ComplianceCheckSchema = z.object({
8
+ organization_id: z.string().describe('Organization ID to check compliance for'),
9
+ checks: z
10
+ .array(z.enum(['passwords', 'configurations', 'documentation', 'warranties']))
11
+ .default(['passwords', 'configurations', 'documentation'])
12
+ .describe('Compliance checks to perform'),
13
+ });
14
+ /**
15
+ * Perform comprehensive compliance checks on ITGlue data
16
+ */
17
+ export async function performComplianceCheck(client, args) {
18
+ try {
19
+ const issues = [];
20
+ const checks = args.checks;
21
+ // Password compliance checks
22
+ if (checks.includes('passwords')) {
23
+ const passwordIssues = await checkPasswordCompliance(client, args.organization_id);
24
+ issues.push(...passwordIssues);
25
+ }
26
+ // Configuration compliance checks
27
+ if (checks.includes('configurations')) {
28
+ const configIssues = await checkConfigurationCompliance(client, args.organization_id);
29
+ issues.push(...configIssues);
30
+ }
31
+ // Documentation compliance checks
32
+ if (checks.includes('documentation')) {
33
+ const docIssues = await checkDocumentationCompliance(client, args.organization_id);
34
+ issues.push(...docIssues);
35
+ }
36
+ // Warranty compliance checks
37
+ if (checks.includes('warranties')) {
38
+ const warrantyIssues = await checkWarrantyCompliance(client, args.organization_id);
39
+ issues.push(...warrantyIssues);
40
+ }
41
+ const resultText = formatComplianceReport(issues, args.organization_id, checks);
42
+ return {
43
+ content: [{ type: 'text', text: resultText }],
44
+ data: {
45
+ organization_id: args.organization_id,
46
+ checks_performed: checks,
47
+ total_issues: issues.length,
48
+ issues_by_severity: {
49
+ critical: issues.filter(i => i.severity === 'critical').length,
50
+ high: issues.filter(i => i.severity === 'high').length,
51
+ medium: issues.filter(i => i.severity === 'medium').length,
52
+ low: issues.filter(i => i.severity === 'low').length,
53
+ },
54
+ issues,
55
+ },
56
+ };
57
+ }
58
+ catch (error) {
59
+ const apiError = handleApiError(error);
60
+ return formatErrorResponse(apiError);
61
+ }
62
+ }
63
+ /**
64
+ * Check password-related compliance issues
65
+ */
66
+ async function checkPasswordCompliance(client, organizationId) {
67
+ const issues = [];
68
+ try {
69
+ const response = await client.get('/passwords', {
70
+ 'filter[organization_id]': organizationId,
71
+ 'page[size]': 100,
72
+ }, {
73
+ skipCache: true,
74
+ organizationId,
75
+ });
76
+ const passwords = Array.isArray(response.data) ? response.data : [response.data];
77
+ for (const pwd of passwords) {
78
+ // Check for missing category
79
+ if (!pwd.attributes['password-category-id'] && !pwd.attributes['password-category-name']) {
80
+ issues.push({
81
+ severity: 'medium',
82
+ category: 'Password Management',
83
+ issue: `Password "${pwd.attributes.name}" has no category assigned`,
84
+ resource_type: 'password',
85
+ resource_id: pwd.id,
86
+ recommendation: 'Assign a password category for better organization and compliance tracking',
87
+ });
88
+ }
89
+ // Check for missing username
90
+ if (!pwd.attributes.username) {
91
+ issues.push({
92
+ severity: 'low',
93
+ category: 'Password Management',
94
+ issue: `Password "${pwd.attributes.name}" has no username`,
95
+ resource_type: 'password',
96
+ resource_id: pwd.id,
97
+ recommendation: 'Add username for complete credential documentation',
98
+ });
99
+ }
100
+ // Check for very old passwords (>365 days without update)
101
+ const updatedAt = new Date(pwd.attributes['updated-at']);
102
+ const daysSinceUpdate = Math.floor((Date.now() - updatedAt.getTime()) / (1000 * 60 * 60 * 24));
103
+ if (daysSinceUpdate > 365) {
104
+ issues.push({
105
+ severity: 'high',
106
+ category: 'Password Management',
107
+ issue: `Password "${pwd.attributes.name}" not updated in ${daysSinceUpdate} days`,
108
+ resource_type: 'password',
109
+ resource_id: pwd.id,
110
+ recommendation: 'Review and update password, verify it is still current and secure',
111
+ });
112
+ }
113
+ }
114
+ }
115
+ catch (error) {
116
+ // If passwords can't be fetched, note it but don't fail the whole check
117
+ issues.push({
118
+ severity: 'high',
119
+ category: 'Password Management',
120
+ issue: 'Unable to fetch passwords for compliance check',
121
+ resource_type: 'password',
122
+ recommendation: 'Verify API permissions include password access',
123
+ });
124
+ }
125
+ return issues;
126
+ }
127
+ /**
128
+ * Check configuration-related compliance issues
129
+ */
130
+ async function checkConfigurationCompliance(client, organizationId) {
131
+ const issues = [];
132
+ try {
133
+ const response = await client.get('/configurations', {
134
+ 'filter[organization_id]': organizationId,
135
+ 'page[size]': 100,
136
+ }, {
137
+ cacheTTL: 60,
138
+ organizationId,
139
+ });
140
+ const configs = Array.isArray(response.data) ? response.data : [response.data];
141
+ for (const config of configs) {
142
+ // Check for missing serial number on physical assets
143
+ const isPhysical = ['Server', 'Workstation', 'Laptop', 'Desktop'].some(type => config.attributes['configuration-type-name']?.includes(type));
144
+ if (isPhysical && !config.attributes['serial-number']) {
145
+ issues.push({
146
+ severity: 'medium',
147
+ category: 'Asset Management',
148
+ issue: `Configuration "${config.attributes.name}" missing serial number`,
149
+ resource_type: 'configuration',
150
+ resource_id: config.id,
151
+ recommendation: 'Add serial number for asset tracking and warranty management',
152
+ });
153
+ }
154
+ // Check for missing manufacturer/model
155
+ if (isPhysical && (!config.attributes['manufacturer-name'] || !config.attributes['model-number'])) {
156
+ issues.push({
157
+ severity: 'low',
158
+ category: 'Asset Management',
159
+ issue: `Configuration "${config.attributes.name}" missing manufacturer or model information`,
160
+ resource_type: 'configuration',
161
+ resource_id: config.id,
162
+ recommendation: 'Add manufacturer and model for accurate asset documentation',
163
+ });
164
+ }
165
+ }
166
+ }
167
+ catch (error) {
168
+ issues.push({
169
+ severity: 'high',
170
+ category: 'Asset Management',
171
+ issue: 'Unable to fetch configurations for compliance check',
172
+ resource_type: 'configuration',
173
+ recommendation: 'Verify API permissions and connectivity',
174
+ });
175
+ }
176
+ return issues;
177
+ }
178
+ /**
179
+ * Check documentation-related compliance issues
180
+ */
181
+ async function checkDocumentationCompliance(client, organizationId) {
182
+ const issues = [];
183
+ try {
184
+ const response = await client.get('/documents', {
185
+ 'filter[organization_id]': organizationId,
186
+ 'page[size]': 10,
187
+ }, {
188
+ cacheTTL: 60,
189
+ organizationId,
190
+ });
191
+ const documents = Array.isArray(response.data) ? response.data : [response.data];
192
+ if (documents.length === 0) {
193
+ issues.push({
194
+ severity: 'medium',
195
+ category: 'Documentation',
196
+ issue: 'No documents found for organization',
197
+ resource_type: 'document',
198
+ recommendation: 'Upload essential documentation (network diagrams, SOPs, vendor contacts)',
199
+ });
200
+ }
201
+ }
202
+ catch (error) {
203
+ // Non-critical if documents can't be checked
204
+ }
205
+ return issues;
206
+ }
207
+ /**
208
+ * Check warranty-related compliance issues
209
+ */
210
+ async function checkWarrantyCompliance(client, organizationId) {
211
+ const issues = [];
212
+ try {
213
+ const response = await client.get('/configurations', {
214
+ 'filter[organization_id]': organizationId,
215
+ 'page[size]': 100,
216
+ }, {
217
+ cacheTTL: 60,
218
+ organizationId,
219
+ });
220
+ const configs = Array.isArray(response.data) ? response.data : [response.data];
221
+ for (const config of configs) {
222
+ const warrantyExpires = config.attributes['warranty-expires-at'];
223
+ if (warrantyExpires) {
224
+ const expiryDate = new Date(warrantyExpires);
225
+ const daysUntilExpiry = Math.floor((expiryDate.getTime() - Date.now()) / (1000 * 60 * 60 * 24));
226
+ if (daysUntilExpiry < 0) {
227
+ issues.push({
228
+ severity: 'medium',
229
+ category: 'Warranty Management',
230
+ issue: `Configuration "${config.attributes.name}" warranty expired ${Math.abs(daysUntilExpiry)} days ago`,
231
+ resource_type: 'configuration',
232
+ resource_id: config.id,
233
+ recommendation: 'Review asset status and consider renewal or replacement',
234
+ });
235
+ }
236
+ else if (daysUntilExpiry <= 90) {
237
+ issues.push({
238
+ severity: 'low',
239
+ category: 'Warranty Management',
240
+ issue: `Configuration "${config.attributes.name}" warranty expires in ${daysUntilExpiry} days`,
241
+ resource_type: 'configuration',
242
+ resource_id: config.id,
243
+ recommendation: 'Plan for warranty renewal or replacement',
244
+ });
245
+ }
246
+ }
247
+ }
248
+ }
249
+ catch (error) {
250
+ // Non-critical
251
+ }
252
+ return issues;
253
+ }
254
+ /**
255
+ * Format compliance report
256
+ */
257
+ function formatComplianceReport(issues, organizationId, checks) {
258
+ const lines = [
259
+ `# Compliance Check Report`,
260
+ `**Organization ID**: ${organizationId}`,
261
+ `**Checks Performed**: ${checks.join(', ')}`,
262
+ `**Total Issues Found**: ${issues.length}`,
263
+ '',
264
+ ];
265
+ if (issues.length === 0) {
266
+ lines.push('✅ **No compliance issues found!**');
267
+ lines.push('');
268
+ lines.push('All checked areas meet compliance standards.');
269
+ return lines.join('\n');
270
+ }
271
+ // Group by severity
272
+ const bySeverity = {
273
+ critical: issues.filter(i => i.severity === 'critical'),
274
+ high: issues.filter(i => i.severity === 'high'),
275
+ medium: issues.filter(i => i.severity === 'medium'),
276
+ low: issues.filter(i => i.severity === 'low'),
277
+ };
278
+ lines.push('## Issues by Severity');
279
+ lines.push('');
280
+ lines.push(`- 🔴 **Critical**: ${bySeverity.critical.length}`);
281
+ lines.push(`- 🟠 **High**: ${bySeverity.high.length}`);
282
+ lines.push(`- 🟡 **Medium**: ${bySeverity.medium.length}`);
283
+ lines.push(`- 🟢 **Low**: ${bySeverity.low.length}`);
284
+ lines.push('');
285
+ // Detail each severity level
286
+ for (const [severity, severityIssues] of Object.entries(bySeverity)) {
287
+ if (severityIssues.length === 0)
288
+ continue;
289
+ const emoji = { critical: '🔴', high: '🟠', medium: '🟡', low: '🟢' }[severity];
290
+ lines.push(`## ${emoji} ${severity.toUpperCase()} Priority Issues`);
291
+ lines.push('');
292
+ for (const issue of severityIssues) {
293
+ lines.push(`### ${issue.category}: ${issue.issue}`);
294
+ if (issue.resource_id) {
295
+ lines.push(`**Resource**: ${issue.resource_type} (ID: ${issue.resource_id})`);
296
+ }
297
+ lines.push(`**Recommendation**: ${issue.recommendation}`);
298
+ lines.push('');
299
+ }
300
+ }
301
+ return lines.join('\n');
302
+ }
303
+ //# sourceMappingURL=compliance-check.js.map