@probelabs/visor 0.1.153 → 0.1.154-ee
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.
- package/dist/index.js +2023 -88
- package/dist/providers/mcp-custom-sse-server.d.ts.map +1 -1
- package/dist/scheduler/schedule-tool.d.ts.map +1 -1
- package/dist/sdk/{check-provider-registry-OEPUY5P6.mjs → check-provider-registry-PK3OTEX6.mjs} +7 -7
- package/dist/sdk/{check-provider-registry-ZOGNKTC3.mjs → check-provider-registry-PZ6K7G4G.mjs} +7 -7
- package/dist/sdk/{chunk-CPYQDJ27.mjs → chunk-AS6LIEO4.mjs} +3 -3
- package/dist/sdk/{chunk-Y3XWPKFP.mjs → chunk-GQ7H7E4Y.mjs} +2 -2
- package/dist/sdk/{chunk-Y3XWPKFP.mjs.map → chunk-GQ7H7E4Y.mjs.map} +1 -1
- package/dist/sdk/{chunk-KBX4OIXL.mjs → chunk-ILIWDV37.mjs} +2 -2
- package/dist/sdk/{chunk-U7KB66AN.mjs → chunk-LIRIQICI.mjs} +56 -36
- package/dist/sdk/chunk-LIRIQICI.mjs.map +1 -0
- package/dist/sdk/{chunk-DNDS7R3N.mjs → chunk-NZADFXHE.mjs} +7 -1
- package/dist/sdk/chunk-NZADFXHE.mjs.map +1 -0
- package/dist/sdk/{chunk-ZCUGMT7X.mjs → chunk-SPCGI24K.mjs} +3 -3
- package/dist/sdk/{chunk-EYQWEVZF.mjs → chunk-WPF7PJ64.mjs} +55 -35
- package/dist/sdk/chunk-WPF7PJ64.mjs.map +1 -0
- package/dist/sdk/{config-SW3VO4DQ.mjs → config-CWHZO5AL.mjs} +2 -2
- package/dist/sdk/{failure-condition-evaluator-R3UE4PE7.mjs → failure-condition-evaluator-LYFZMQ6Y.mjs} +3 -3
- package/dist/sdk/{github-frontend-6KZSVSPC.mjs → github-frontend-XKPAYXOT.mjs} +3 -3
- package/dist/sdk/{host-A5HS6F6G.mjs → host-6DJCOUJE.mjs} +2 -2
- package/dist/sdk/{host-YBJOWFT4.mjs → host-7Y25DDOR.mjs} +2 -2
- package/dist/sdk/knex-store-CRORFJE6.mjs +527 -0
- package/dist/sdk/knex-store-CRORFJE6.mjs.map +1 -0
- package/dist/sdk/loader-NJCF7DUS.mjs +89 -0
- package/dist/sdk/loader-NJCF7DUS.mjs.map +1 -0
- package/dist/sdk/opa-policy-engine-S2S2ULEI.mjs +655 -0
- package/dist/sdk/opa-policy-engine-S2S2ULEI.mjs.map +1 -0
- package/dist/sdk/{routing-MMEOAH34.mjs → routing-L224WQSY.mjs} +4 -4
- package/dist/sdk/{schedule-tool-NMCFABHK.mjs → schedule-tool-HRFONU5J.mjs} +7 -7
- package/dist/sdk/{schedule-tool-NYRLSV4F.mjs → schedule-tool-KZ36XTW4.mjs} +7 -7
- package/dist/sdk/{schedule-tool-handler-2TFSBZ2O.mjs → schedule-tool-handler-2V4EJEQT.mjs} +7 -7
- package/dist/sdk/{schedule-tool-handler-DRVRLVGD.mjs → schedule-tool-handler-KXZC4ZOR.mjs} +7 -7
- package/dist/sdk/sdk.js +1677 -277
- package/dist/sdk/sdk.js.map +1 -1
- package/dist/sdk/sdk.mjs +6 -6
- package/dist/sdk/{trace-helpers-JJLVZ2RJ.mjs → trace-helpers-AWTAWKRA.mjs} +2 -2
- package/dist/sdk/validator-XTZJZZJH.mjs +134 -0
- package/dist/sdk/validator-XTZJZZJH.mjs.map +1 -0
- package/dist/sdk/{workflow-check-provider-GIW4WECT.mjs → workflow-check-provider-HGFTX64I.mjs} +7 -7
- package/dist/sdk/{workflow-check-provider-UQMMFLSK.mjs → workflow-check-provider-TXAEY7OU.mjs} +7 -7
- package/dist/sdk/{workflow-registry-MHUSKSD6.mjs → workflow-registry-NGV3SESX.mjs} +2 -2
- package/dist/slack/schedule-tool-handler.d.ts.map +1 -1
- package/dist/workflow-registry.d.ts.map +1 -1
- package/package.json +2 -2
- package/dist/output/traces/run-2026-03-04T13-24-27-240Z.ndjson +0 -138
- package/dist/output/traces/run-2026-03-04T13-25-12-321Z.ndjson +0 -2197
- package/dist/sdk/check-provider-registry-CSIZGIKC.mjs +0 -29
- package/dist/sdk/chunk-DNDS7R3N.mjs.map +0 -1
- package/dist/sdk/chunk-EYQWEVZF.mjs.map +0 -1
- package/dist/sdk/chunk-NYK7WDGH.mjs +0 -43754
- package/dist/sdk/chunk-NYK7WDGH.mjs.map +0 -1
- package/dist/sdk/chunk-SMR5N5MG.mjs +0 -443
- package/dist/sdk/chunk-SMR5N5MG.mjs.map +0 -1
- package/dist/sdk/chunk-U7KB66AN.mjs.map +0 -1
- package/dist/sdk/chunk-VBN45DBR.mjs +0 -1502
- package/dist/sdk/chunk-WG7P66MJ.mjs +0 -739
- package/dist/sdk/chunk-WG7P66MJ.mjs.map +0 -1
- package/dist/sdk/chunk-ZCUGMT7X.mjs.map +0 -1
- package/dist/sdk/failure-condition-evaluator-Y32S6DB2.mjs +0 -17
- package/dist/sdk/github-frontend-6SIR7QWX.mjs +0 -1368
- package/dist/sdk/github-frontend-6SIR7QWX.mjs.map +0 -1
- package/dist/sdk/routing-U63OJMZQ.mjs +0 -25
- package/dist/sdk/schedule-tool-74VMD77T.mjs +0 -35
- package/dist/sdk/schedule-tool-handler-EOQBRZSD.mjs +0 -39
- package/dist/sdk/schedule-tool-handler-EOQBRZSD.mjs.map +0 -1
- package/dist/sdk/trace-helpers-2BIVADUK.mjs +0 -25
- package/dist/sdk/trace-helpers-2BIVADUK.mjs.map +0 -1
- package/dist/sdk/trace-helpers-JJLVZ2RJ.mjs.map +0 -1
- package/dist/sdk/workflow-check-provider-4NHVFLMQ.mjs +0 -29
- package/dist/sdk/workflow-check-provider-4NHVFLMQ.mjs.map +0 -1
- package/dist/sdk/workflow-check-provider-GIW4WECT.mjs.map +0 -1
- package/dist/sdk/workflow-check-provider-UQMMFLSK.mjs.map +0 -1
- package/dist/sdk/workflow-registry-MHUSKSD6.mjs.map +0 -1
- package/dist/traces/run-2026-03-04T13-24-27-240Z.ndjson +0 -138
- package/dist/traces/run-2026-03-04T13-25-12-321Z.ndjson +0 -2197
- /package/dist/sdk/{check-provider-registry-CSIZGIKC.mjs.map → check-provider-registry-PK3OTEX6.mjs.map} +0 -0
- /package/dist/sdk/{check-provider-registry-OEPUY5P6.mjs.map → check-provider-registry-PZ6K7G4G.mjs.map} +0 -0
- /package/dist/sdk/{chunk-CPYQDJ27.mjs.map → chunk-AS6LIEO4.mjs.map} +0 -0
- /package/dist/sdk/{chunk-KBX4OIXL.mjs.map → chunk-ILIWDV37.mjs.map} +0 -0
- /package/dist/sdk/{chunk-VBN45DBR.mjs.map → chunk-SPCGI24K.mjs.map} +0 -0
- /package/dist/sdk/{check-provider-registry-ZOGNKTC3.mjs.map → config-CWHZO5AL.mjs.map} +0 -0
- /package/dist/sdk/{config-SW3VO4DQ.mjs.map → failure-condition-evaluator-LYFZMQ6Y.mjs.map} +0 -0
- /package/dist/sdk/{github-frontend-6KZSVSPC.mjs.map → github-frontend-XKPAYXOT.mjs.map} +0 -0
- /package/dist/sdk/{host-A5HS6F6G.mjs.map → host-6DJCOUJE.mjs.map} +0 -0
- /package/dist/sdk/{host-YBJOWFT4.mjs.map → host-7Y25DDOR.mjs.map} +0 -0
- /package/dist/sdk/{failure-condition-evaluator-R3UE4PE7.mjs.map → routing-L224WQSY.mjs.map} +0 -0
- /package/dist/sdk/{failure-condition-evaluator-Y32S6DB2.mjs.map → schedule-tool-HRFONU5J.mjs.map} +0 -0
- /package/dist/sdk/{routing-MMEOAH34.mjs.map → schedule-tool-KZ36XTW4.mjs.map} +0 -0
- /package/dist/sdk/{routing-U63OJMZQ.mjs.map → schedule-tool-handler-2V4EJEQT.mjs.map} +0 -0
- /package/dist/sdk/{schedule-tool-74VMD77T.mjs.map → schedule-tool-handler-KXZC4ZOR.mjs.map} +0 -0
- /package/dist/sdk/{schedule-tool-NMCFABHK.mjs.map → trace-helpers-AWTAWKRA.mjs.map} +0 -0
- /package/dist/sdk/{schedule-tool-NYRLSV4F.mjs.map → workflow-check-provider-HGFTX64I.mjs.map} +0 -0
- /package/dist/sdk/{schedule-tool-handler-2TFSBZ2O.mjs.map → workflow-check-provider-TXAEY7OU.mjs.map} +0 -0
- /package/dist/sdk/{schedule-tool-handler-DRVRLVGD.mjs.map → workflow-registry-NGV3SESX.mjs.map} +0 -0
package/dist/index.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
process.env.VISOR_VERSION = '0.1.
|
|
3
|
-
process.env.PROBE_VERSION = '0.6.0-
|
|
4
|
-
process.env.VISOR_COMMIT_SHA = '
|
|
5
|
-
process.env.VISOR_COMMIT_SHORT = '
|
|
2
|
+
process.env.VISOR_VERSION = '0.1.154';
|
|
3
|
+
process.env.PROBE_VERSION = '0.6.0-rc271';
|
|
4
|
+
process.env.VISOR_COMMIT_SHA = '1ceb9f8073c3ec36e82c277d3e4bfcbf3320ba3b';
|
|
5
|
+
process.env.VISOR_COMMIT_SHORT = '1ceb9f8';
|
|
6
6
|
/******/ (() => { // webpackBootstrap
|
|
7
7
|
/******/ var __webpack_modules__ = ({
|
|
8
8
|
|
|
@@ -161210,7 +161210,7 @@ async function handleDumpPolicyInput(checkId, argv) {
|
|
|
161210
161210
|
let PolicyInputBuilder;
|
|
161211
161211
|
try {
|
|
161212
161212
|
// @ts-ignore — enterprise/ may not exist in OSS builds (caught at runtime)
|
|
161213
|
-
const mod = await Promise.resolve().then(() => __importStar(__nccwpck_require__(
|
|
161213
|
+
const mod = await Promise.resolve().then(() => __importStar(__nccwpck_require__(17117)));
|
|
161214
161214
|
PolicyInputBuilder = mod.PolicyInputBuilder;
|
|
161215
161215
|
}
|
|
161216
161216
|
catch {
|
|
@@ -167084,6 +167084,1810 @@ class DependencyResolver {
|
|
|
167084
167084
|
exports.DependencyResolver = DependencyResolver;
|
|
167085
167085
|
|
|
167086
167086
|
|
|
167087
|
+
/***/ }),
|
|
167088
|
+
|
|
167089
|
+
/***/ 50069:
|
|
167090
|
+
/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) {
|
|
167091
|
+
|
|
167092
|
+
"use strict";
|
|
167093
|
+
|
|
167094
|
+
/**
|
|
167095
|
+
* Copyright (c) ProbeLabs. All rights reserved.
|
|
167096
|
+
* Licensed under the Elastic License 2.0; you may not use this file except
|
|
167097
|
+
* in compliance with the Elastic License 2.0.
|
|
167098
|
+
*/
|
|
167099
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
167100
|
+
if (k2 === undefined) k2 = k;
|
|
167101
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
167102
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
167103
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
167104
|
+
}
|
|
167105
|
+
Object.defineProperty(o, k2, desc);
|
|
167106
|
+
}) : (function(o, m, k, k2) {
|
|
167107
|
+
if (k2 === undefined) k2 = k;
|
|
167108
|
+
o[k2] = m[k];
|
|
167109
|
+
}));
|
|
167110
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
167111
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
167112
|
+
}) : function(o, v) {
|
|
167113
|
+
o["default"] = v;
|
|
167114
|
+
});
|
|
167115
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
167116
|
+
var ownKeys = function(o) {
|
|
167117
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
167118
|
+
var ar = [];
|
|
167119
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
167120
|
+
return ar;
|
|
167121
|
+
};
|
|
167122
|
+
return ownKeys(o);
|
|
167123
|
+
};
|
|
167124
|
+
return function (mod) {
|
|
167125
|
+
if (mod && mod.__esModule) return mod;
|
|
167126
|
+
var result = {};
|
|
167127
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
167128
|
+
__setModuleDefault(result, mod);
|
|
167129
|
+
return result;
|
|
167130
|
+
};
|
|
167131
|
+
})();
|
|
167132
|
+
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
167133
|
+
exports.LicenseValidator = void 0;
|
|
167134
|
+
const crypto = __importStar(__nccwpck_require__(76982));
|
|
167135
|
+
const fs = __importStar(__nccwpck_require__(79896));
|
|
167136
|
+
const path = __importStar(__nccwpck_require__(16928));
|
|
167137
|
+
class LicenseValidator {
|
|
167138
|
+
/** Ed25519 public key for license verification (PEM format). */
|
|
167139
|
+
static PUBLIC_KEY = '-----BEGIN PUBLIC KEY-----\n' +
|
|
167140
|
+
'MCowBQYDK2VwAyEAI/Zd08EFmgIdrDm/HXd0l3/5GBt7R1PrdvhdmEXhJlU=\n' +
|
|
167141
|
+
'-----END PUBLIC KEY-----\n';
|
|
167142
|
+
cache = null;
|
|
167143
|
+
static CACHE_TTL = 5 * 60 * 1000; // 5 minutes
|
|
167144
|
+
static GRACE_PERIOD = 72 * 3600 * 1000; // 72 hours after expiry
|
|
167145
|
+
/**
|
|
167146
|
+
* Load and validate license from environment or file.
|
|
167147
|
+
*
|
|
167148
|
+
* Resolution order:
|
|
167149
|
+
* 1. VISOR_LICENSE env var (JWT string)
|
|
167150
|
+
* 2. VISOR_LICENSE_FILE env var (path to file)
|
|
167151
|
+
* 3. .visor-license in project root (cwd)
|
|
167152
|
+
* 4. .visor-license in ~/.config/visor/
|
|
167153
|
+
*/
|
|
167154
|
+
async loadAndValidate() {
|
|
167155
|
+
// Return cached result if still fresh
|
|
167156
|
+
if (this.cache && Date.now() - this.cache.validatedAt < LicenseValidator.CACHE_TTL) {
|
|
167157
|
+
return this.cache.payload;
|
|
167158
|
+
}
|
|
167159
|
+
const token = this.resolveToken();
|
|
167160
|
+
if (!token)
|
|
167161
|
+
return null;
|
|
167162
|
+
const payload = this.verifyAndDecode(token);
|
|
167163
|
+
if (!payload)
|
|
167164
|
+
return null;
|
|
167165
|
+
this.cache = { payload, validatedAt: Date.now() };
|
|
167166
|
+
return payload;
|
|
167167
|
+
}
|
|
167168
|
+
/** Check if a specific feature is licensed */
|
|
167169
|
+
hasFeature(feature) {
|
|
167170
|
+
if (!this.cache)
|
|
167171
|
+
return false;
|
|
167172
|
+
return this.cache.payload.features.includes(feature);
|
|
167173
|
+
}
|
|
167174
|
+
/** Check if license is valid (with grace period) */
|
|
167175
|
+
isValid() {
|
|
167176
|
+
if (!this.cache)
|
|
167177
|
+
return false;
|
|
167178
|
+
const now = Date.now();
|
|
167179
|
+
const expiryMs = this.cache.payload.exp * 1000;
|
|
167180
|
+
return now < expiryMs + LicenseValidator.GRACE_PERIOD;
|
|
167181
|
+
}
|
|
167182
|
+
/** Check if the license is within its grace period (expired but still valid) */
|
|
167183
|
+
isInGracePeriod() {
|
|
167184
|
+
if (!this.cache)
|
|
167185
|
+
return false;
|
|
167186
|
+
const now = Date.now();
|
|
167187
|
+
const expiryMs = this.cache.payload.exp * 1000;
|
|
167188
|
+
return now >= expiryMs && now < expiryMs + LicenseValidator.GRACE_PERIOD;
|
|
167189
|
+
}
|
|
167190
|
+
resolveToken() {
|
|
167191
|
+
// 1. Direct env var
|
|
167192
|
+
if (process.env.VISOR_LICENSE) {
|
|
167193
|
+
return process.env.VISOR_LICENSE.trim();
|
|
167194
|
+
}
|
|
167195
|
+
// 2. File path from env (validate against path traversal)
|
|
167196
|
+
if (process.env.VISOR_LICENSE_FILE) {
|
|
167197
|
+
// path.resolve() produces an absolute path with all '..' segments resolved,
|
|
167198
|
+
// so a separate resolved.includes('..') check is unnecessary.
|
|
167199
|
+
const resolved = path.resolve(process.env.VISOR_LICENSE_FILE);
|
|
167200
|
+
const home = process.env.HOME || process.env.USERPROFILE || '';
|
|
167201
|
+
const allowedPrefixes = [path.normalize(process.cwd())];
|
|
167202
|
+
if (home)
|
|
167203
|
+
allowedPrefixes.push(path.normalize(path.join(home, '.config', 'visor')));
|
|
167204
|
+
// Resolve symlinks so an attacker cannot create a symlink inside an
|
|
167205
|
+
// allowed prefix that points to an arbitrary file outside it.
|
|
167206
|
+
let realPath;
|
|
167207
|
+
try {
|
|
167208
|
+
realPath = fs.realpathSync(resolved);
|
|
167209
|
+
}
|
|
167210
|
+
catch {
|
|
167211
|
+
return null; // File doesn't exist or isn't accessible
|
|
167212
|
+
}
|
|
167213
|
+
const isSafe = allowedPrefixes.some(prefix => realPath === prefix || realPath.startsWith(prefix + path.sep));
|
|
167214
|
+
if (!isSafe)
|
|
167215
|
+
return null;
|
|
167216
|
+
return this.readFile(realPath);
|
|
167217
|
+
}
|
|
167218
|
+
// 3. .visor-license in cwd
|
|
167219
|
+
const cwdPath = path.join(process.cwd(), '.visor-license');
|
|
167220
|
+
const cwdToken = this.readFile(cwdPath);
|
|
167221
|
+
if (cwdToken)
|
|
167222
|
+
return cwdToken;
|
|
167223
|
+
// 4. ~/.config/visor/.visor-license
|
|
167224
|
+
const home = process.env.HOME || process.env.USERPROFILE || '';
|
|
167225
|
+
if (home) {
|
|
167226
|
+
const configPath = path.join(home, '.config', 'visor', '.visor-license');
|
|
167227
|
+
const configToken = this.readFile(configPath);
|
|
167228
|
+
if (configToken)
|
|
167229
|
+
return configToken;
|
|
167230
|
+
}
|
|
167231
|
+
return null;
|
|
167232
|
+
}
|
|
167233
|
+
readFile(filePath) {
|
|
167234
|
+
try {
|
|
167235
|
+
return fs.readFileSync(filePath, 'utf-8').trim();
|
|
167236
|
+
}
|
|
167237
|
+
catch {
|
|
167238
|
+
return null;
|
|
167239
|
+
}
|
|
167240
|
+
}
|
|
167241
|
+
verifyAndDecode(token) {
|
|
167242
|
+
try {
|
|
167243
|
+
const parts = token.split('.');
|
|
167244
|
+
if (parts.length !== 3)
|
|
167245
|
+
return null;
|
|
167246
|
+
const [headerB64, payloadB64, signatureB64] = parts;
|
|
167247
|
+
// Decode header to verify algorithm
|
|
167248
|
+
const header = JSON.parse(Buffer.from(headerB64, 'base64url').toString());
|
|
167249
|
+
if (header.alg !== 'EdDSA')
|
|
167250
|
+
return null;
|
|
167251
|
+
// Verify signature
|
|
167252
|
+
const data = `${headerB64}.${payloadB64}`;
|
|
167253
|
+
const signature = Buffer.from(signatureB64, 'base64url');
|
|
167254
|
+
const publicKey = crypto.createPublicKey(LicenseValidator.PUBLIC_KEY);
|
|
167255
|
+
// Validate that the loaded public key is actually Ed25519 (OID 1.3.101.112).
|
|
167256
|
+
// This prevents algorithm-confusion attacks if the embedded key were ever
|
|
167257
|
+
// swapped to a different type.
|
|
167258
|
+
if (publicKey.asymmetricKeyType !== 'ed25519') {
|
|
167259
|
+
return null;
|
|
167260
|
+
}
|
|
167261
|
+
// Ed25519 verification: algorithm must be null because EdDSA performs its
|
|
167262
|
+
// own internal hashing (SHA-512) — passing a digest algorithm here would
|
|
167263
|
+
// cause Node.js to throw. The key type is validated above.
|
|
167264
|
+
const isValid = crypto.verify(null, Buffer.from(data), publicKey, signature);
|
|
167265
|
+
if (!isValid)
|
|
167266
|
+
return null;
|
|
167267
|
+
// Decode payload
|
|
167268
|
+
const payload = JSON.parse(Buffer.from(payloadB64, 'base64url').toString());
|
|
167269
|
+
// Validate required fields
|
|
167270
|
+
if (!payload.org ||
|
|
167271
|
+
!Array.isArray(payload.features) ||
|
|
167272
|
+
typeof payload.exp !== 'number' ||
|
|
167273
|
+
typeof payload.iat !== 'number' ||
|
|
167274
|
+
!payload.sub) {
|
|
167275
|
+
return null;
|
|
167276
|
+
}
|
|
167277
|
+
// Check expiry (with grace period)
|
|
167278
|
+
const now = Date.now();
|
|
167279
|
+
const expiryMs = payload.exp * 1000;
|
|
167280
|
+
if (now >= expiryMs + LicenseValidator.GRACE_PERIOD) {
|
|
167281
|
+
return null;
|
|
167282
|
+
}
|
|
167283
|
+
return payload;
|
|
167284
|
+
}
|
|
167285
|
+
catch {
|
|
167286
|
+
return null;
|
|
167287
|
+
}
|
|
167288
|
+
}
|
|
167289
|
+
}
|
|
167290
|
+
exports.LicenseValidator = LicenseValidator;
|
|
167291
|
+
|
|
167292
|
+
|
|
167293
|
+
/***/ }),
|
|
167294
|
+
|
|
167295
|
+
/***/ 87068:
|
|
167296
|
+
/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) {
|
|
167297
|
+
|
|
167298
|
+
"use strict";
|
|
167299
|
+
|
|
167300
|
+
/**
|
|
167301
|
+
* Copyright (c) ProbeLabs. All rights reserved.
|
|
167302
|
+
* Licensed under the Elastic License 2.0; you may not use this file except
|
|
167303
|
+
* in compliance with the Elastic License 2.0.
|
|
167304
|
+
*/
|
|
167305
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
167306
|
+
if (k2 === undefined) k2 = k;
|
|
167307
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
167308
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
167309
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
167310
|
+
}
|
|
167311
|
+
Object.defineProperty(o, k2, desc);
|
|
167312
|
+
}) : (function(o, m, k, k2) {
|
|
167313
|
+
if (k2 === undefined) k2 = k;
|
|
167314
|
+
o[k2] = m[k];
|
|
167315
|
+
}));
|
|
167316
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
167317
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
167318
|
+
}) : function(o, v) {
|
|
167319
|
+
o["default"] = v;
|
|
167320
|
+
});
|
|
167321
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
167322
|
+
var ownKeys = function(o) {
|
|
167323
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
167324
|
+
var ar = [];
|
|
167325
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
167326
|
+
return ar;
|
|
167327
|
+
};
|
|
167328
|
+
return ownKeys(o);
|
|
167329
|
+
};
|
|
167330
|
+
return function (mod) {
|
|
167331
|
+
if (mod && mod.__esModule) return mod;
|
|
167332
|
+
var result = {};
|
|
167333
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
167334
|
+
__setModuleDefault(result, mod);
|
|
167335
|
+
return result;
|
|
167336
|
+
};
|
|
167337
|
+
})();
|
|
167338
|
+
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
167339
|
+
exports.loadEnterprisePolicyEngine = loadEnterprisePolicyEngine;
|
|
167340
|
+
exports.loadEnterpriseStoreBackend = loadEnterpriseStoreBackend;
|
|
167341
|
+
const default_engine_1 = __nccwpck_require__(93866);
|
|
167342
|
+
/**
|
|
167343
|
+
* Load the enterprise policy engine if licensed, otherwise return the default no-op engine.
|
|
167344
|
+
*
|
|
167345
|
+
* This is the sole import boundary between OSS and enterprise code. Core code
|
|
167346
|
+
* must only import from this module (via dynamic `await import()`), never from
|
|
167347
|
+
* individual enterprise submodules.
|
|
167348
|
+
*/
|
|
167349
|
+
async function loadEnterprisePolicyEngine(config) {
|
|
167350
|
+
try {
|
|
167351
|
+
const { LicenseValidator } = await Promise.resolve().then(() => __importStar(__nccwpck_require__(50069)));
|
|
167352
|
+
const validator = new LicenseValidator();
|
|
167353
|
+
const license = await validator.loadAndValidate();
|
|
167354
|
+
if (!license || !validator.hasFeature('policy')) {
|
|
167355
|
+
return new default_engine_1.DefaultPolicyEngine();
|
|
167356
|
+
}
|
|
167357
|
+
if (validator.isInGracePeriod()) {
|
|
167358
|
+
// eslint-disable-next-line no-console
|
|
167359
|
+
console.warn('[visor:enterprise] License has expired but is within the 72-hour grace period. ' +
|
|
167360
|
+
'Please renew your license.');
|
|
167361
|
+
}
|
|
167362
|
+
const { OpaPolicyEngine } = await Promise.resolve().then(() => __importStar(__nccwpck_require__(39530)));
|
|
167363
|
+
const engine = new OpaPolicyEngine(config);
|
|
167364
|
+
await engine.initialize(config);
|
|
167365
|
+
return engine;
|
|
167366
|
+
}
|
|
167367
|
+
catch (err) {
|
|
167368
|
+
// Enterprise code not available or initialization failed
|
|
167369
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
167370
|
+
try {
|
|
167371
|
+
const { logger } = __nccwpck_require__(86999);
|
|
167372
|
+
logger.warn(`[PolicyEngine] Enterprise policy init failed, falling back to default: ${msg}`);
|
|
167373
|
+
}
|
|
167374
|
+
catch {
|
|
167375
|
+
// silent
|
|
167376
|
+
}
|
|
167377
|
+
return new default_engine_1.DefaultPolicyEngine();
|
|
167378
|
+
}
|
|
167379
|
+
}
|
|
167380
|
+
/**
|
|
167381
|
+
* Load the enterprise schedule store backend if licensed.
|
|
167382
|
+
*
|
|
167383
|
+
* @param driver Database driver ('postgresql', 'mysql', or 'mssql')
|
|
167384
|
+
* @param storageConfig Storage configuration with connection details
|
|
167385
|
+
* @param haConfig Optional HA configuration
|
|
167386
|
+
* @throws Error if enterprise license is not available or missing 'scheduler-sql' feature
|
|
167387
|
+
*/
|
|
167388
|
+
async function loadEnterpriseStoreBackend(driver, storageConfig, haConfig) {
|
|
167389
|
+
const { LicenseValidator } = await Promise.resolve().then(() => __importStar(__nccwpck_require__(50069)));
|
|
167390
|
+
const validator = new LicenseValidator();
|
|
167391
|
+
const license = await validator.loadAndValidate();
|
|
167392
|
+
if (!license || !validator.hasFeature('scheduler-sql')) {
|
|
167393
|
+
throw new Error(`The ${driver} schedule storage driver requires a Visor Enterprise license ` +
|
|
167394
|
+
`with the 'scheduler-sql' feature. Please upgrade or use driver: 'sqlite' (default).`);
|
|
167395
|
+
}
|
|
167396
|
+
if (validator.isInGracePeriod()) {
|
|
167397
|
+
// eslint-disable-next-line no-console
|
|
167398
|
+
console.warn('[visor:enterprise] License has expired but is within the 72-hour grace period. ' +
|
|
167399
|
+
'Please renew your license.');
|
|
167400
|
+
}
|
|
167401
|
+
const { KnexStoreBackend } = await Promise.resolve().then(() => __importStar(__nccwpck_require__(63737)));
|
|
167402
|
+
return new KnexStoreBackend(driver, storageConfig, haConfig);
|
|
167403
|
+
}
|
|
167404
|
+
|
|
167405
|
+
|
|
167406
|
+
/***/ }),
|
|
167407
|
+
|
|
167408
|
+
/***/ 628:
|
|
167409
|
+
/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) {
|
|
167410
|
+
|
|
167411
|
+
"use strict";
|
|
167412
|
+
|
|
167413
|
+
/**
|
|
167414
|
+
* Copyright (c) ProbeLabs. All rights reserved.
|
|
167415
|
+
* Licensed under the Elastic License 2.0; you may not use this file except
|
|
167416
|
+
* in compliance with the Elastic License 2.0.
|
|
167417
|
+
*/
|
|
167418
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
167419
|
+
if (k2 === undefined) k2 = k;
|
|
167420
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
167421
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
167422
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
167423
|
+
}
|
|
167424
|
+
Object.defineProperty(o, k2, desc);
|
|
167425
|
+
}) : (function(o, m, k, k2) {
|
|
167426
|
+
if (k2 === undefined) k2 = k;
|
|
167427
|
+
o[k2] = m[k];
|
|
167428
|
+
}));
|
|
167429
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
167430
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
167431
|
+
}) : function(o, v) {
|
|
167432
|
+
o["default"] = v;
|
|
167433
|
+
});
|
|
167434
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
167435
|
+
var ownKeys = function(o) {
|
|
167436
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
167437
|
+
var ar = [];
|
|
167438
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
167439
|
+
return ar;
|
|
167440
|
+
};
|
|
167441
|
+
return ownKeys(o);
|
|
167442
|
+
};
|
|
167443
|
+
return function (mod) {
|
|
167444
|
+
if (mod && mod.__esModule) return mod;
|
|
167445
|
+
var result = {};
|
|
167446
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
167447
|
+
__setModuleDefault(result, mod);
|
|
167448
|
+
return result;
|
|
167449
|
+
};
|
|
167450
|
+
})();
|
|
167451
|
+
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
167452
|
+
exports.OpaCompiler = void 0;
|
|
167453
|
+
const fs = __importStar(__nccwpck_require__(79896));
|
|
167454
|
+
const path = __importStar(__nccwpck_require__(16928));
|
|
167455
|
+
const os = __importStar(__nccwpck_require__(70857));
|
|
167456
|
+
const crypto = __importStar(__nccwpck_require__(76982));
|
|
167457
|
+
const child_process_1 = __nccwpck_require__(35317);
|
|
167458
|
+
/**
|
|
167459
|
+
* OPA Rego Compiler - compiles .rego policy files to WASM bundles using the `opa` CLI.
|
|
167460
|
+
*
|
|
167461
|
+
* Handles:
|
|
167462
|
+
* - Resolving input paths to WASM bytes (direct .wasm, directory with policy.wasm, or .rego files)
|
|
167463
|
+
* - Compiling .rego files to WASM via `opa build`
|
|
167464
|
+
* - Caching compiled bundles based on content hashes
|
|
167465
|
+
* - Extracting policy.wasm from OPA tar.gz bundles
|
|
167466
|
+
*
|
|
167467
|
+
* Requires:
|
|
167468
|
+
* - `opa` CLI on PATH (only when auto-compiling .rego files)
|
|
167469
|
+
*/
|
|
167470
|
+
class OpaCompiler {
|
|
167471
|
+
static CACHE_DIR = path.join(os.tmpdir(), 'visor-opa-cache');
|
|
167472
|
+
/**
|
|
167473
|
+
* Resolve the input paths to WASM bytes.
|
|
167474
|
+
*
|
|
167475
|
+
* Strategy:
|
|
167476
|
+
* 1. If any path is a .wasm file, read it directly
|
|
167477
|
+
* 2. If a directory contains policy.wasm, read it
|
|
167478
|
+
* 3. Otherwise, collect all .rego files and auto-compile via `opa build`
|
|
167479
|
+
*/
|
|
167480
|
+
async resolveWasmBytes(paths) {
|
|
167481
|
+
// Collect .rego files and check for existing .wasm
|
|
167482
|
+
const regoFiles = [];
|
|
167483
|
+
for (const p of paths) {
|
|
167484
|
+
const resolved = path.resolve(p);
|
|
167485
|
+
// Reject paths containing '..' after resolution (path traversal)
|
|
167486
|
+
if (path.normalize(resolved).includes('..')) {
|
|
167487
|
+
throw new Error(`Policy path contains traversal sequences: ${p}`);
|
|
167488
|
+
}
|
|
167489
|
+
// Direct .wasm file
|
|
167490
|
+
if (resolved.endsWith('.wasm') && fs.existsSync(resolved)) {
|
|
167491
|
+
return fs.readFileSync(resolved);
|
|
167492
|
+
}
|
|
167493
|
+
if (!fs.existsSync(resolved))
|
|
167494
|
+
continue;
|
|
167495
|
+
const stat = fs.statSync(resolved);
|
|
167496
|
+
if (stat.isDirectory()) {
|
|
167497
|
+
// Check for pre-compiled policy.wasm in directory
|
|
167498
|
+
const wasmCandidate = path.join(resolved, 'policy.wasm');
|
|
167499
|
+
if (fs.existsSync(wasmCandidate)) {
|
|
167500
|
+
return fs.readFileSync(wasmCandidate);
|
|
167501
|
+
}
|
|
167502
|
+
// Collect all .rego files from directory
|
|
167503
|
+
const files = fs.readdirSync(resolved);
|
|
167504
|
+
for (const f of files) {
|
|
167505
|
+
if (f.endsWith('.rego')) {
|
|
167506
|
+
regoFiles.push(path.join(resolved, f));
|
|
167507
|
+
}
|
|
167508
|
+
}
|
|
167509
|
+
}
|
|
167510
|
+
else if (resolved.endsWith('.rego')) {
|
|
167511
|
+
regoFiles.push(resolved);
|
|
167512
|
+
}
|
|
167513
|
+
}
|
|
167514
|
+
if (regoFiles.length === 0) {
|
|
167515
|
+
throw new Error(`OPA WASM evaluator: no .wasm bundle or .rego files found in: ${paths.join(', ')}`);
|
|
167516
|
+
}
|
|
167517
|
+
// Auto-compile .rego -> .wasm
|
|
167518
|
+
return this.compileRego(regoFiles);
|
|
167519
|
+
}
|
|
167520
|
+
/**
|
|
167521
|
+
* Auto-compile .rego files to a WASM bundle using the `opa` CLI.
|
|
167522
|
+
*
|
|
167523
|
+
* Caches the compiled bundle based on a content hash of all input .rego files
|
|
167524
|
+
* so subsequent runs skip compilation if policies haven't changed.
|
|
167525
|
+
*/
|
|
167526
|
+
compileRego(regoFiles) {
|
|
167527
|
+
// Check that `opa` CLI is available
|
|
167528
|
+
try {
|
|
167529
|
+
(0, child_process_1.execFileSync)('opa', ['version'], { stdio: 'pipe' });
|
|
167530
|
+
}
|
|
167531
|
+
catch {
|
|
167532
|
+
throw new Error('OPA CLI (`opa`) not found on PATH. Install it from https://www.openpolicyagent.org/docs/latest/#running-opa\n' +
|
|
167533
|
+
'Or pre-compile your .rego files: opa build -t wasm -e visor -o bundle.tar.gz ' +
|
|
167534
|
+
regoFiles.join(' '));
|
|
167535
|
+
}
|
|
167536
|
+
// Compute content hash for cache key
|
|
167537
|
+
const hash = crypto.createHash('sha256');
|
|
167538
|
+
for (const f of regoFiles.sort()) {
|
|
167539
|
+
hash.update(fs.readFileSync(f));
|
|
167540
|
+
hash.update(f); // include filename for disambiguation
|
|
167541
|
+
}
|
|
167542
|
+
const cacheKey = hash.digest('hex').slice(0, 16);
|
|
167543
|
+
const cacheDir = OpaCompiler.CACHE_DIR;
|
|
167544
|
+
const cachedWasm = path.join(cacheDir, `${cacheKey}.wasm`);
|
|
167545
|
+
// Return cached bundle if still valid
|
|
167546
|
+
if (fs.existsSync(cachedWasm)) {
|
|
167547
|
+
return fs.readFileSync(cachedWasm);
|
|
167548
|
+
}
|
|
167549
|
+
// Compile to WASM via opa build
|
|
167550
|
+
fs.mkdirSync(cacheDir, { recursive: true });
|
|
167551
|
+
const bundleTar = path.join(cacheDir, `${cacheKey}-bundle.tar.gz`);
|
|
167552
|
+
try {
|
|
167553
|
+
const args = [
|
|
167554
|
+
'build',
|
|
167555
|
+
'-t',
|
|
167556
|
+
'wasm',
|
|
167557
|
+
'-e',
|
|
167558
|
+
'visor', // entrypoint: the visor package tree
|
|
167559
|
+
'-o',
|
|
167560
|
+
bundleTar,
|
|
167561
|
+
...regoFiles,
|
|
167562
|
+
];
|
|
167563
|
+
(0, child_process_1.execFileSync)('opa', args, {
|
|
167564
|
+
stdio: 'pipe',
|
|
167565
|
+
timeout: 30000,
|
|
167566
|
+
});
|
|
167567
|
+
}
|
|
167568
|
+
catch (err) {
|
|
167569
|
+
const stderr = err?.stderr?.toString() || '';
|
|
167570
|
+
throw new Error(`Failed to compile .rego files to WASM:\n${stderr}\n` +
|
|
167571
|
+
'Ensure your .rego files are valid and the `opa` CLI is installed.');
|
|
167572
|
+
}
|
|
167573
|
+
// Extract policy.wasm from the tar.gz bundle
|
|
167574
|
+
// OPA bundles are tar.gz with /policy.wasm inside
|
|
167575
|
+
try {
|
|
167576
|
+
(0, child_process_1.execFileSync)('tar', ['-xzf', bundleTar, '-C', cacheDir, '/policy.wasm'], {
|
|
167577
|
+
stdio: 'pipe',
|
|
167578
|
+
});
|
|
167579
|
+
const extractedWasm = path.join(cacheDir, 'policy.wasm');
|
|
167580
|
+
if (fs.existsSync(extractedWasm)) {
|
|
167581
|
+
// Move to cache-key named file
|
|
167582
|
+
fs.renameSync(extractedWasm, cachedWasm);
|
|
167583
|
+
}
|
|
167584
|
+
}
|
|
167585
|
+
catch {
|
|
167586
|
+
// Some tar implementations don't like leading /
|
|
167587
|
+
try {
|
|
167588
|
+
(0, child_process_1.execFileSync)('tar', ['-xzf', bundleTar, '-C', cacheDir, 'policy.wasm'], {
|
|
167589
|
+
stdio: 'pipe',
|
|
167590
|
+
});
|
|
167591
|
+
const extractedWasm = path.join(cacheDir, 'policy.wasm');
|
|
167592
|
+
if (fs.existsSync(extractedWasm)) {
|
|
167593
|
+
fs.renameSync(extractedWasm, cachedWasm);
|
|
167594
|
+
}
|
|
167595
|
+
}
|
|
167596
|
+
catch (err2) {
|
|
167597
|
+
throw new Error(`Failed to extract policy.wasm from OPA bundle: ${err2?.message || err2}`);
|
|
167598
|
+
}
|
|
167599
|
+
}
|
|
167600
|
+
// Clean up tar
|
|
167601
|
+
try {
|
|
167602
|
+
fs.unlinkSync(bundleTar);
|
|
167603
|
+
}
|
|
167604
|
+
catch { }
|
|
167605
|
+
if (!fs.existsSync(cachedWasm)) {
|
|
167606
|
+
throw new Error('OPA build succeeded but policy.wasm was not found in the bundle');
|
|
167607
|
+
}
|
|
167608
|
+
return fs.readFileSync(cachedWasm);
|
|
167609
|
+
}
|
|
167610
|
+
}
|
|
167611
|
+
exports.OpaCompiler = OpaCompiler;
|
|
167612
|
+
|
|
167613
|
+
|
|
167614
|
+
/***/ }),
|
|
167615
|
+
|
|
167616
|
+
/***/ 44693:
|
|
167617
|
+
/***/ ((__unused_webpack_module, exports) => {
|
|
167618
|
+
|
|
167619
|
+
"use strict";
|
|
167620
|
+
|
|
167621
|
+
/**
|
|
167622
|
+
* Copyright (c) ProbeLabs. All rights reserved.
|
|
167623
|
+
* Licensed under the Elastic License 2.0; you may not use this file except
|
|
167624
|
+
* in compliance with the Elastic License 2.0.
|
|
167625
|
+
*/
|
|
167626
|
+
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
167627
|
+
exports.OpaHttpEvaluator = void 0;
|
|
167628
|
+
/**
|
|
167629
|
+
* OPA HTTP Evaluator - evaluates policies via an external OPA server's REST API.
|
|
167630
|
+
*
|
|
167631
|
+
* Uses the built-in `fetch` API (Node 18+), so no extra dependencies are needed.
|
|
167632
|
+
*/
|
|
167633
|
+
class OpaHttpEvaluator {
|
|
167634
|
+
baseUrl;
|
|
167635
|
+
timeout;
|
|
167636
|
+
constructor(baseUrl, timeout = 5000) {
|
|
167637
|
+
// Validate URL format and protocol
|
|
167638
|
+
let parsed;
|
|
167639
|
+
try {
|
|
167640
|
+
parsed = new URL(baseUrl);
|
|
167641
|
+
}
|
|
167642
|
+
catch {
|
|
167643
|
+
throw new Error(`OPA HTTP evaluator: invalid URL: ${baseUrl}`);
|
|
167644
|
+
}
|
|
167645
|
+
if (!['http:', 'https:'].includes(parsed.protocol)) {
|
|
167646
|
+
throw new Error(`OPA HTTP evaluator: url must use http:// or https:// protocol, got: ${baseUrl}`);
|
|
167647
|
+
}
|
|
167648
|
+
// Block cloud metadata, loopback, link-local, and private network addresses
|
|
167649
|
+
const hostname = parsed.hostname;
|
|
167650
|
+
if (this.isBlockedHostname(hostname)) {
|
|
167651
|
+
throw new Error(`OPA HTTP evaluator: url must not point to internal, loopback, or private network addresses`);
|
|
167652
|
+
}
|
|
167653
|
+
// Normalize: strip trailing slash
|
|
167654
|
+
this.baseUrl = baseUrl.replace(/\/+$/, '');
|
|
167655
|
+
this.timeout = timeout;
|
|
167656
|
+
}
|
|
167657
|
+
/**
|
|
167658
|
+
* Check if a hostname is blocked due to SSRF concerns.
|
|
167659
|
+
*
|
|
167660
|
+
* Blocks:
|
|
167661
|
+
* - Loopback addresses (127.x.x.x, localhost, 0.0.0.0, ::1)
|
|
167662
|
+
* - Link-local addresses (169.254.x.x)
|
|
167663
|
+
* - Private networks (10.x.x.x, 172.16-31.x.x, 192.168.x.x)
|
|
167664
|
+
* - IPv6 unique local addresses (fd00::/8)
|
|
167665
|
+
* - Cloud metadata services (*.internal)
|
|
167666
|
+
*/
|
|
167667
|
+
isBlockedHostname(hostname) {
|
|
167668
|
+
if (!hostname)
|
|
167669
|
+
return true; // block empty hostnames
|
|
167670
|
+
// Normalize hostname: lowercase and remove brackets for IPv6
|
|
167671
|
+
const normalized = hostname.toLowerCase().replace(/^\[|\]$/g, '');
|
|
167672
|
+
// Block .internal domains (cloud metadata services)
|
|
167673
|
+
if (normalized === 'metadata.google.internal' || normalized.endsWith('.internal')) {
|
|
167674
|
+
return true;
|
|
167675
|
+
}
|
|
167676
|
+
// Block localhost variants
|
|
167677
|
+
if (normalized === 'localhost' || normalized === 'localhost.localdomain') {
|
|
167678
|
+
return true;
|
|
167679
|
+
}
|
|
167680
|
+
// Block IPv6 loopback
|
|
167681
|
+
if (normalized === '::1' || normalized === '0:0:0:0:0:0:0:1') {
|
|
167682
|
+
return true;
|
|
167683
|
+
}
|
|
167684
|
+
// Check IPv4 patterns
|
|
167685
|
+
const ipv4Pattern = /^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/;
|
|
167686
|
+
const ipv4Match = normalized.match(ipv4Pattern);
|
|
167687
|
+
if (ipv4Match) {
|
|
167688
|
+
const octets = ipv4Match.slice(1, 5).map(Number);
|
|
167689
|
+
// Validate octets are in range [0, 255]
|
|
167690
|
+
if (octets.some(octet => octet > 255)) {
|
|
167691
|
+
return false;
|
|
167692
|
+
}
|
|
167693
|
+
const [a, b] = octets;
|
|
167694
|
+
// Block loopback: 127.0.0.0/8
|
|
167695
|
+
if (a === 127) {
|
|
167696
|
+
return true;
|
|
167697
|
+
}
|
|
167698
|
+
// Block 0.0.0.0/8 (this host)
|
|
167699
|
+
if (a === 0) {
|
|
167700
|
+
return true;
|
|
167701
|
+
}
|
|
167702
|
+
// Block link-local: 169.254.0.0/16
|
|
167703
|
+
if (a === 169 && b === 254) {
|
|
167704
|
+
return true;
|
|
167705
|
+
}
|
|
167706
|
+
// Block private networks
|
|
167707
|
+
// 10.0.0.0/8
|
|
167708
|
+
if (a === 10) {
|
|
167709
|
+
return true;
|
|
167710
|
+
}
|
|
167711
|
+
// 172.16.0.0/12 (172.16.x.x through 172.31.x.x)
|
|
167712
|
+
if (a === 172 && b >= 16 && b <= 31) {
|
|
167713
|
+
return true;
|
|
167714
|
+
}
|
|
167715
|
+
// 192.168.0.0/16
|
|
167716
|
+
if (a === 192 && b === 168) {
|
|
167717
|
+
return true;
|
|
167718
|
+
}
|
|
167719
|
+
}
|
|
167720
|
+
// Check IPv6 patterns
|
|
167721
|
+
// Block unique local addresses: fd00::/8
|
|
167722
|
+
if (normalized.startsWith('fd') || normalized.startsWith('fc')) {
|
|
167723
|
+
return true;
|
|
167724
|
+
}
|
|
167725
|
+
// Block link-local: fe80::/10
|
|
167726
|
+
if (normalized.startsWith('fe80:')) {
|
|
167727
|
+
return true;
|
|
167728
|
+
}
|
|
167729
|
+
return false;
|
|
167730
|
+
}
|
|
167731
|
+
/**
|
|
167732
|
+
* Evaluate a policy rule against an input document via OPA REST API.
|
|
167733
|
+
*
|
|
167734
|
+
* @param input - The input document to evaluate
|
|
167735
|
+
* @param rulePath - OPA rule path (e.g., 'visor/check/execute')
|
|
167736
|
+
* @returns The result object from OPA, or undefined on error
|
|
167737
|
+
*/
|
|
167738
|
+
async evaluate(input, rulePath) {
|
|
167739
|
+
// OPA Data API: POST /v1/data/<path>
|
|
167740
|
+
const encodedPath = rulePath
|
|
167741
|
+
.split('/')
|
|
167742
|
+
.map(s => encodeURIComponent(s))
|
|
167743
|
+
.join('/');
|
|
167744
|
+
const url = `${this.baseUrl}/v1/data/${encodedPath}`;
|
|
167745
|
+
const controller = new AbortController();
|
|
167746
|
+
const timer = setTimeout(() => controller.abort(), this.timeout);
|
|
167747
|
+
try {
|
|
167748
|
+
const response = await fetch(url, {
|
|
167749
|
+
method: 'POST',
|
|
167750
|
+
headers: { 'Content-Type': 'application/json' },
|
|
167751
|
+
body: JSON.stringify({ input }),
|
|
167752
|
+
signal: controller.signal,
|
|
167753
|
+
});
|
|
167754
|
+
if (!response.ok) {
|
|
167755
|
+
throw new Error(`OPA HTTP ${response.status}: ${response.statusText}`);
|
|
167756
|
+
}
|
|
167757
|
+
let body;
|
|
167758
|
+
try {
|
|
167759
|
+
body = await response.json();
|
|
167760
|
+
}
|
|
167761
|
+
catch (jsonErr) {
|
|
167762
|
+
throw new Error(`OPA HTTP evaluator: failed to parse JSON response: ${jsonErr instanceof Error ? jsonErr.message : String(jsonErr)}`);
|
|
167763
|
+
}
|
|
167764
|
+
// OPA returns { result: { ... } }
|
|
167765
|
+
return body?.result;
|
|
167766
|
+
}
|
|
167767
|
+
finally {
|
|
167768
|
+
clearTimeout(timer);
|
|
167769
|
+
}
|
|
167770
|
+
}
|
|
167771
|
+
async shutdown() {
|
|
167772
|
+
// No persistent connections to close
|
|
167773
|
+
}
|
|
167774
|
+
}
|
|
167775
|
+
exports.OpaHttpEvaluator = OpaHttpEvaluator;
|
|
167776
|
+
|
|
167777
|
+
|
|
167778
|
+
/***/ }),
|
|
167779
|
+
|
|
167780
|
+
/***/ 39530:
|
|
167781
|
+
/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
|
|
167782
|
+
|
|
167783
|
+
"use strict";
|
|
167784
|
+
|
|
167785
|
+
/**
|
|
167786
|
+
* Copyright (c) ProbeLabs. All rights reserved.
|
|
167787
|
+
* Licensed under the Elastic License 2.0; you may not use this file except
|
|
167788
|
+
* in compliance with the Elastic License 2.0.
|
|
167789
|
+
*/
|
|
167790
|
+
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
167791
|
+
exports.OpaPolicyEngine = void 0;
|
|
167792
|
+
const opa_wasm_evaluator_1 = __nccwpck_require__(8613);
|
|
167793
|
+
const opa_http_evaluator_1 = __nccwpck_require__(44693);
|
|
167794
|
+
const policy_input_builder_1 = __nccwpck_require__(17117);
|
|
167795
|
+
/**
|
|
167796
|
+
* Enterprise OPA Policy Engine.
|
|
167797
|
+
*
|
|
167798
|
+
* Wraps both WASM (local) and HTTP (remote) OPA evaluators behind the
|
|
167799
|
+
* OSS PolicyEngine interface. All OPA input building and role resolution
|
|
167800
|
+
* is handled internally — the OSS call sites pass only plain types.
|
|
167801
|
+
*/
|
|
167802
|
+
class OpaPolicyEngine {
|
|
167803
|
+
evaluator = null;
|
|
167804
|
+
fallback;
|
|
167805
|
+
timeout;
|
|
167806
|
+
config;
|
|
167807
|
+
inputBuilder = null;
|
|
167808
|
+
logger = null;
|
|
167809
|
+
constructor(config) {
|
|
167810
|
+
this.config = config;
|
|
167811
|
+
this.fallback = config.fallback || 'deny';
|
|
167812
|
+
this.timeout = config.timeout || 5000;
|
|
167813
|
+
}
|
|
167814
|
+
async initialize(config) {
|
|
167815
|
+
// Resolve logger once at initialization
|
|
167816
|
+
try {
|
|
167817
|
+
this.logger = (__nccwpck_require__(86999).logger);
|
|
167818
|
+
}
|
|
167819
|
+
catch {
|
|
167820
|
+
// logger not available in this context
|
|
167821
|
+
}
|
|
167822
|
+
// Build actor/repo context from environment (available at engine init time)
|
|
167823
|
+
const actor = {
|
|
167824
|
+
authorAssociation: process.env.VISOR_AUTHOR_ASSOCIATION,
|
|
167825
|
+
login: process.env.VISOR_AUTHOR_LOGIN || process.env.GITHUB_ACTOR,
|
|
167826
|
+
isLocalMode: !process.env.GITHUB_ACTIONS,
|
|
167827
|
+
};
|
|
167828
|
+
const repo = {
|
|
167829
|
+
owner: process.env.GITHUB_REPOSITORY_OWNER,
|
|
167830
|
+
name: process.env.GITHUB_REPOSITORY?.split('/')[1],
|
|
167831
|
+
branch: process.env.GITHUB_HEAD_REF,
|
|
167832
|
+
baseBranch: process.env.GITHUB_BASE_REF,
|
|
167833
|
+
event: process.env.GITHUB_EVENT_NAME,
|
|
167834
|
+
};
|
|
167835
|
+
const prNum = process.env.GITHUB_PR_NUMBER
|
|
167836
|
+
? parseInt(process.env.GITHUB_PR_NUMBER, 10)
|
|
167837
|
+
: undefined;
|
|
167838
|
+
const pullRequest = {
|
|
167839
|
+
number: prNum !== undefined && Number.isFinite(prNum) ? prNum : undefined,
|
|
167840
|
+
};
|
|
167841
|
+
this.inputBuilder = new policy_input_builder_1.PolicyInputBuilder(config, actor, repo, pullRequest);
|
|
167842
|
+
if (config.engine === 'local') {
|
|
167843
|
+
if (!config.rules) {
|
|
167844
|
+
throw new Error('OPA local mode requires `policy.rules` path to .wasm or .rego files');
|
|
167845
|
+
}
|
|
167846
|
+
const wasm = new opa_wasm_evaluator_1.OpaWasmEvaluator();
|
|
167847
|
+
await wasm.initialize(config.rules);
|
|
167848
|
+
if (config.data) {
|
|
167849
|
+
wasm.loadData(config.data);
|
|
167850
|
+
}
|
|
167851
|
+
this.evaluator = wasm;
|
|
167852
|
+
}
|
|
167853
|
+
else if (config.engine === 'remote') {
|
|
167854
|
+
if (!config.url) {
|
|
167855
|
+
throw new Error('OPA remote mode requires `policy.url` pointing to OPA server');
|
|
167856
|
+
}
|
|
167857
|
+
this.evaluator = new opa_http_evaluator_1.OpaHttpEvaluator(config.url, this.timeout);
|
|
167858
|
+
}
|
|
167859
|
+
else {
|
|
167860
|
+
this.evaluator = null;
|
|
167861
|
+
}
|
|
167862
|
+
}
|
|
167863
|
+
/**
|
|
167864
|
+
* Update actor/repo/PR context (e.g., after PR info becomes available).
|
|
167865
|
+
* Called by the enterprise loader when engine context is enriched.
|
|
167866
|
+
*/
|
|
167867
|
+
setActorContext(actor, repo, pullRequest) {
|
|
167868
|
+
this.inputBuilder = new policy_input_builder_1.PolicyInputBuilder(this.config, actor, repo, pullRequest);
|
|
167869
|
+
}
|
|
167870
|
+
async evaluateCheckExecution(checkId, checkConfig) {
|
|
167871
|
+
if (!this.evaluator || !this.inputBuilder)
|
|
167872
|
+
return { allowed: true };
|
|
167873
|
+
const cfg = checkConfig && typeof checkConfig === 'object'
|
|
167874
|
+
? checkConfig
|
|
167875
|
+
: {};
|
|
167876
|
+
const policyOverride = cfg.policy;
|
|
167877
|
+
const input = this.inputBuilder.forCheckExecution({
|
|
167878
|
+
id: checkId,
|
|
167879
|
+
type: cfg.type || 'ai',
|
|
167880
|
+
group: cfg.group,
|
|
167881
|
+
tags: cfg.tags,
|
|
167882
|
+
criticality: cfg.criticality,
|
|
167883
|
+
sandbox: cfg.sandbox,
|
|
167884
|
+
policy: policyOverride,
|
|
167885
|
+
});
|
|
167886
|
+
return this.doEvaluate(input, this.resolveRulePath('check.execute', policyOverride?.rule));
|
|
167887
|
+
}
|
|
167888
|
+
async evaluateToolInvocation(serverName, methodName, transport) {
|
|
167889
|
+
if (!this.evaluator || !this.inputBuilder)
|
|
167890
|
+
return { allowed: true };
|
|
167891
|
+
const input = this.inputBuilder.forToolInvocation(serverName, methodName, transport);
|
|
167892
|
+
return this.doEvaluate(input, 'visor/tool/invoke');
|
|
167893
|
+
}
|
|
167894
|
+
async evaluateCapabilities(checkId, capabilities) {
|
|
167895
|
+
if (!this.evaluator || !this.inputBuilder)
|
|
167896
|
+
return { allowed: true };
|
|
167897
|
+
const input = this.inputBuilder.forCapabilityResolve(checkId, capabilities);
|
|
167898
|
+
return this.doEvaluate(input, 'visor/capability/resolve');
|
|
167899
|
+
}
|
|
167900
|
+
async shutdown() {
|
|
167901
|
+
if (this.evaluator && 'shutdown' in this.evaluator) {
|
|
167902
|
+
await this.evaluator.shutdown();
|
|
167903
|
+
}
|
|
167904
|
+
this.evaluator = null;
|
|
167905
|
+
this.inputBuilder = null;
|
|
167906
|
+
}
|
|
167907
|
+
resolveRulePath(defaultScope, override) {
|
|
167908
|
+
if (override) {
|
|
167909
|
+
return override.startsWith('visor/') ? override : `visor/${override}`;
|
|
167910
|
+
}
|
|
167911
|
+
return `visor/${defaultScope.replace(/\./g, '/')}`;
|
|
167912
|
+
}
|
|
167913
|
+
async doEvaluate(input, rulePath) {
|
|
167914
|
+
try {
|
|
167915
|
+
this.logger?.debug(`[PolicyEngine] Evaluating ${rulePath}`, JSON.stringify(input));
|
|
167916
|
+
let timer;
|
|
167917
|
+
const timeoutPromise = new Promise((_resolve, reject) => {
|
|
167918
|
+
timer = setTimeout(() => reject(new Error('policy evaluation timeout')), this.timeout);
|
|
167919
|
+
});
|
|
167920
|
+
try {
|
|
167921
|
+
const result = await Promise.race([this.rawEvaluate(input, rulePath), timeoutPromise]);
|
|
167922
|
+
const decision = this.parseDecision(result);
|
|
167923
|
+
// In warn mode, override denied decisions to allowed but flag as warn
|
|
167924
|
+
if (!decision.allowed && this.fallback === 'warn') {
|
|
167925
|
+
decision.allowed = true;
|
|
167926
|
+
decision.warn = true;
|
|
167927
|
+
decision.reason = `audit: ${decision.reason || 'policy denied'}`;
|
|
167928
|
+
}
|
|
167929
|
+
this.logger?.debug(`[PolicyEngine] Decision for ${rulePath}: allowed=${decision.allowed}, warn=${decision.warn || false}, reason=${decision.reason || 'none'}`);
|
|
167930
|
+
return decision;
|
|
167931
|
+
}
|
|
167932
|
+
finally {
|
|
167933
|
+
if (timer)
|
|
167934
|
+
clearTimeout(timer);
|
|
167935
|
+
}
|
|
167936
|
+
}
|
|
167937
|
+
catch (err) {
|
|
167938
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
167939
|
+
this.logger?.warn(`[PolicyEngine] Evaluation failed for ${rulePath}: ${msg}`);
|
|
167940
|
+
return {
|
|
167941
|
+
allowed: this.fallback === 'allow' || this.fallback === 'warn',
|
|
167942
|
+
warn: this.fallback === 'warn' ? true : undefined,
|
|
167943
|
+
reason: `policy evaluation failed, fallback=${this.fallback}`,
|
|
167944
|
+
};
|
|
167945
|
+
}
|
|
167946
|
+
}
|
|
167947
|
+
async rawEvaluate(input, rulePath) {
|
|
167948
|
+
if (this.evaluator instanceof opa_wasm_evaluator_1.OpaWasmEvaluator) {
|
|
167949
|
+
const result = await this.evaluator.evaluate(input);
|
|
167950
|
+
// WASM compiled with `-e visor` entrypoint returns the full visor package tree.
|
|
167951
|
+
// Navigate to the specific rule subtree using rulePath segments.
|
|
167952
|
+
// e.g., 'visor/check/execute' → result.check.execute
|
|
167953
|
+
return this.navigateWasmResult(result, rulePath);
|
|
167954
|
+
}
|
|
167955
|
+
return this.evaluator.evaluate(input, rulePath);
|
|
167956
|
+
}
|
|
167957
|
+
/**
|
|
167958
|
+
* Navigate nested OPA WASM result tree to reach the specific rule's output.
|
|
167959
|
+
* The WASM entrypoint `-e visor` means the result root IS the visor package,
|
|
167960
|
+
* so we strip the `visor/` prefix and walk the remaining segments.
|
|
167961
|
+
*/
|
|
167962
|
+
navigateWasmResult(result, rulePath) {
|
|
167963
|
+
if (!result || typeof result !== 'object')
|
|
167964
|
+
return result;
|
|
167965
|
+
// Strip the 'visor/' prefix (matches our compilation entrypoint)
|
|
167966
|
+
const segments = rulePath.replace(/^visor\//, '').split('/');
|
|
167967
|
+
let current = result;
|
|
167968
|
+
for (const seg of segments) {
|
|
167969
|
+
if (current && typeof current === 'object' && seg in current) {
|
|
167970
|
+
current = current[seg];
|
|
167971
|
+
}
|
|
167972
|
+
else {
|
|
167973
|
+
return undefined; // path not found in result tree
|
|
167974
|
+
}
|
|
167975
|
+
}
|
|
167976
|
+
return current;
|
|
167977
|
+
}
|
|
167978
|
+
parseDecision(result) {
|
|
167979
|
+
if (result === undefined || result === null) {
|
|
167980
|
+
return {
|
|
167981
|
+
allowed: this.fallback === 'allow' || this.fallback === 'warn',
|
|
167982
|
+
warn: this.fallback === 'warn' ? true : undefined,
|
|
167983
|
+
reason: this.fallback === 'warn' ? 'audit: no policy result' : 'no policy result',
|
|
167984
|
+
};
|
|
167985
|
+
}
|
|
167986
|
+
const allowed = result.allowed !== false;
|
|
167987
|
+
const decision = {
|
|
167988
|
+
allowed,
|
|
167989
|
+
reason: result.reason,
|
|
167990
|
+
};
|
|
167991
|
+
if (result.capabilities) {
|
|
167992
|
+
decision.capabilities = result.capabilities;
|
|
167993
|
+
}
|
|
167994
|
+
return decision;
|
|
167995
|
+
}
|
|
167996
|
+
}
|
|
167997
|
+
exports.OpaPolicyEngine = OpaPolicyEngine;
|
|
167998
|
+
|
|
167999
|
+
|
|
168000
|
+
/***/ }),
|
|
168001
|
+
|
|
168002
|
+
/***/ 8613:
|
|
168003
|
+
/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) {
|
|
168004
|
+
|
|
168005
|
+
"use strict";
|
|
168006
|
+
|
|
168007
|
+
/**
|
|
168008
|
+
* Copyright (c) ProbeLabs. All rights reserved.
|
|
168009
|
+
* Licensed under the Elastic License 2.0; you may not use this file except
|
|
168010
|
+
* in compliance with the Elastic License 2.0.
|
|
168011
|
+
*/
|
|
168012
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
168013
|
+
if (k2 === undefined) k2 = k;
|
|
168014
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
168015
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
168016
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
168017
|
+
}
|
|
168018
|
+
Object.defineProperty(o, k2, desc);
|
|
168019
|
+
}) : (function(o, m, k, k2) {
|
|
168020
|
+
if (k2 === undefined) k2 = k;
|
|
168021
|
+
o[k2] = m[k];
|
|
168022
|
+
}));
|
|
168023
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
168024
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
168025
|
+
}) : function(o, v) {
|
|
168026
|
+
o["default"] = v;
|
|
168027
|
+
});
|
|
168028
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
168029
|
+
var ownKeys = function(o) {
|
|
168030
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
168031
|
+
var ar = [];
|
|
168032
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
168033
|
+
return ar;
|
|
168034
|
+
};
|
|
168035
|
+
return ownKeys(o);
|
|
168036
|
+
};
|
|
168037
|
+
return function (mod) {
|
|
168038
|
+
if (mod && mod.__esModule) return mod;
|
|
168039
|
+
var result = {};
|
|
168040
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
168041
|
+
__setModuleDefault(result, mod);
|
|
168042
|
+
return result;
|
|
168043
|
+
};
|
|
168044
|
+
})();
|
|
168045
|
+
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
168046
|
+
exports.OpaWasmEvaluator = void 0;
|
|
168047
|
+
const fs = __importStar(__nccwpck_require__(79896));
|
|
168048
|
+
const path = __importStar(__nccwpck_require__(16928));
|
|
168049
|
+
const opa_compiler_1 = __nccwpck_require__(628);
|
|
168050
|
+
/**
|
|
168051
|
+
* OPA WASM Evaluator - loads and evaluates OPA policies locally.
|
|
168052
|
+
*
|
|
168053
|
+
* Supports three input formats:
|
|
168054
|
+
* 1. Pre-compiled `.wasm` bundle — loaded directly (fastest startup)
|
|
168055
|
+
* 2. `.rego` files or directory — auto-compiled to WASM via `opa build` CLI
|
|
168056
|
+
* 3. Directory with `policy.wasm` inside — loaded directly
|
|
168057
|
+
*
|
|
168058
|
+
* Compilation and caching of .rego files is delegated to {@link OpaCompiler}.
|
|
168059
|
+
*
|
|
168060
|
+
* Requires:
|
|
168061
|
+
* - `@open-policy-agent/opa-wasm` npm package (optional dep)
|
|
168062
|
+
* - `opa` CLI on PATH (only when auto-compiling .rego files)
|
|
168063
|
+
*/
|
|
168064
|
+
class OpaWasmEvaluator {
|
|
168065
|
+
policy = null;
|
|
168066
|
+
dataDocument = {};
|
|
168067
|
+
compiler = new opa_compiler_1.OpaCompiler();
|
|
168068
|
+
async initialize(rulesPath) {
|
|
168069
|
+
const paths = Array.isArray(rulesPath) ? rulesPath : [rulesPath];
|
|
168070
|
+
const wasmBytes = await this.compiler.resolveWasmBytes(paths);
|
|
168071
|
+
try {
|
|
168072
|
+
// Use createRequire to load the optional dep at runtime without ncc bundling it.
|
|
168073
|
+
// `new Function('id', 'return require(id)')` fails in ncc bundles because
|
|
168074
|
+
// `require` is not in the `new Function` scope. `createRequire` works correctly
|
|
168075
|
+
// because it creates a real Node.js require rooted at the given path.
|
|
168076
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
168077
|
+
const { createRequire } = __nccwpck_require__(73339);
|
|
168078
|
+
const runtimeRequire = createRequire(__filename);
|
|
168079
|
+
const opaWasm = runtimeRequire('@open-policy-agent/opa-wasm');
|
|
168080
|
+
const loadPolicy = opaWasm.loadPolicy || opaWasm.default?.loadPolicy;
|
|
168081
|
+
if (!loadPolicy) {
|
|
168082
|
+
throw new Error('loadPolicy not found in @open-policy-agent/opa-wasm');
|
|
168083
|
+
}
|
|
168084
|
+
this.policy = await loadPolicy(wasmBytes);
|
|
168085
|
+
}
|
|
168086
|
+
catch (err) {
|
|
168087
|
+
if (err?.code === 'MODULE_NOT_FOUND' || err?.code === 'ERR_MODULE_NOT_FOUND') {
|
|
168088
|
+
throw new Error('OPA WASM evaluator requires @open-policy-agent/opa-wasm. ' +
|
|
168089
|
+
'Install it with: npm install @open-policy-agent/opa-wasm');
|
|
168090
|
+
}
|
|
168091
|
+
throw err;
|
|
168092
|
+
}
|
|
168093
|
+
}
|
|
168094
|
+
/**
|
|
168095
|
+
* Load external data from a JSON file to use as the OPA data document.
|
|
168096
|
+
* The loaded data will be passed to `policy.setData()` during evaluation,
|
|
168097
|
+
* making it available in Rego via `data.<key>`.
|
|
168098
|
+
*/
|
|
168099
|
+
loadData(dataPath) {
|
|
168100
|
+
const resolved = path.resolve(dataPath);
|
|
168101
|
+
if (path.normalize(resolved).includes('..')) {
|
|
168102
|
+
throw new Error(`Data path contains traversal sequences: ${dataPath}`);
|
|
168103
|
+
}
|
|
168104
|
+
if (!fs.existsSync(resolved)) {
|
|
168105
|
+
throw new Error(`OPA data file not found: ${resolved}`);
|
|
168106
|
+
}
|
|
168107
|
+
const stat = fs.statSync(resolved);
|
|
168108
|
+
if (stat.size > 10 * 1024 * 1024) {
|
|
168109
|
+
throw new Error(`OPA data file exceeds 10MB limit: ${resolved} (${stat.size} bytes)`);
|
|
168110
|
+
}
|
|
168111
|
+
const raw = fs.readFileSync(resolved, 'utf-8');
|
|
168112
|
+
try {
|
|
168113
|
+
const parsed = JSON.parse(raw);
|
|
168114
|
+
if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) {
|
|
168115
|
+
throw new Error('OPA data file must contain a JSON object (not an array or primitive)');
|
|
168116
|
+
}
|
|
168117
|
+
this.dataDocument = parsed;
|
|
168118
|
+
}
|
|
168119
|
+
catch (err) {
|
|
168120
|
+
if (err.message.startsWith('OPA data file must')) {
|
|
168121
|
+
throw err;
|
|
168122
|
+
}
|
|
168123
|
+
throw new Error(`Failed to parse OPA data file ${resolved}: ${err.message}`);
|
|
168124
|
+
}
|
|
168125
|
+
}
|
|
168126
|
+
async evaluate(input) {
|
|
168127
|
+
if (!this.policy) {
|
|
168128
|
+
throw new Error('OPA WASM evaluator not initialized');
|
|
168129
|
+
}
|
|
168130
|
+
this.policy.setData(this.dataDocument);
|
|
168131
|
+
const resultSet = this.policy.evaluate(input);
|
|
168132
|
+
if (Array.isArray(resultSet) && resultSet.length > 0) {
|
|
168133
|
+
return resultSet[0].result;
|
|
168134
|
+
}
|
|
168135
|
+
return undefined;
|
|
168136
|
+
}
|
|
168137
|
+
async shutdown() {
|
|
168138
|
+
if (this.policy) {
|
|
168139
|
+
// opa-wasm policy objects may have a close/free method for WASM cleanup
|
|
168140
|
+
if (typeof this.policy.close === 'function') {
|
|
168141
|
+
try {
|
|
168142
|
+
this.policy.close();
|
|
168143
|
+
}
|
|
168144
|
+
catch { }
|
|
168145
|
+
}
|
|
168146
|
+
else if (typeof this.policy.free === 'function') {
|
|
168147
|
+
try {
|
|
168148
|
+
this.policy.free();
|
|
168149
|
+
}
|
|
168150
|
+
catch { }
|
|
168151
|
+
}
|
|
168152
|
+
}
|
|
168153
|
+
this.policy = null;
|
|
168154
|
+
}
|
|
168155
|
+
}
|
|
168156
|
+
exports.OpaWasmEvaluator = OpaWasmEvaluator;
|
|
168157
|
+
|
|
168158
|
+
|
|
168159
|
+
/***/ }),
|
|
168160
|
+
|
|
168161
|
+
/***/ 17117:
|
|
168162
|
+
/***/ ((__unused_webpack_module, exports) => {
|
|
168163
|
+
|
|
168164
|
+
"use strict";
|
|
168165
|
+
|
|
168166
|
+
/**
|
|
168167
|
+
* Copyright (c) ProbeLabs. All rights reserved.
|
|
168168
|
+
* Licensed under the Elastic License 2.0; you may not use this file except
|
|
168169
|
+
* in compliance with the Elastic License 2.0.
|
|
168170
|
+
*/
|
|
168171
|
+
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
168172
|
+
exports.PolicyInputBuilder = void 0;
|
|
168173
|
+
/**
|
|
168174
|
+
* Builds OPA-compatible input documents from engine context.
|
|
168175
|
+
*
|
|
168176
|
+
* Resolves actor roles from the `policy.roles` config section by matching
|
|
168177
|
+
* the actor's authorAssociation and login against role definitions.
|
|
168178
|
+
*/
|
|
168179
|
+
class PolicyInputBuilder {
|
|
168180
|
+
roles;
|
|
168181
|
+
actor;
|
|
168182
|
+
repository;
|
|
168183
|
+
pullRequest;
|
|
168184
|
+
constructor(policyConfig, actor, repository, pullRequest) {
|
|
168185
|
+
this.roles = policyConfig.roles || {};
|
|
168186
|
+
this.actor = actor;
|
|
168187
|
+
this.repository = repository;
|
|
168188
|
+
this.pullRequest = pullRequest;
|
|
168189
|
+
}
|
|
168190
|
+
/** Resolve which roles apply to the current actor. */
|
|
168191
|
+
resolveRoles() {
|
|
168192
|
+
const matched = [];
|
|
168193
|
+
for (const [roleName, roleConfig] of Object.entries(this.roles)) {
|
|
168194
|
+
let identityMatch = false;
|
|
168195
|
+
if (roleConfig.author_association &&
|
|
168196
|
+
this.actor.authorAssociation &&
|
|
168197
|
+
roleConfig.author_association.includes(this.actor.authorAssociation)) {
|
|
168198
|
+
identityMatch = true;
|
|
168199
|
+
}
|
|
168200
|
+
if (!identityMatch &&
|
|
168201
|
+
roleConfig.users &&
|
|
168202
|
+
this.actor.login &&
|
|
168203
|
+
roleConfig.users.includes(this.actor.login)) {
|
|
168204
|
+
identityMatch = true;
|
|
168205
|
+
}
|
|
168206
|
+
// Slack user ID match
|
|
168207
|
+
if (!identityMatch &&
|
|
168208
|
+
roleConfig.slack_users &&
|
|
168209
|
+
this.actor.slack?.userId &&
|
|
168210
|
+
roleConfig.slack_users.includes(this.actor.slack.userId)) {
|
|
168211
|
+
identityMatch = true;
|
|
168212
|
+
}
|
|
168213
|
+
// Email match (case-insensitive)
|
|
168214
|
+
if (!identityMatch && roleConfig.emails && this.actor.slack?.email) {
|
|
168215
|
+
const actorEmail = this.actor.slack.email.toLowerCase();
|
|
168216
|
+
if (roleConfig.emails.some(e => e.toLowerCase() === actorEmail)) {
|
|
168217
|
+
identityMatch = true;
|
|
168218
|
+
}
|
|
168219
|
+
}
|
|
168220
|
+
// Note: teams-based role resolution requires GitHub API access (read:org scope)
|
|
168221
|
+
// and is not yet implemented. If configured, the role will not match via teams.
|
|
168222
|
+
if (!identityMatch)
|
|
168223
|
+
continue;
|
|
168224
|
+
// slack_channels gate: if set, the role only applies when triggered from one of these channels
|
|
168225
|
+
if (roleConfig.slack_channels && roleConfig.slack_channels.length > 0) {
|
|
168226
|
+
if (!this.actor.slack?.channelId ||
|
|
168227
|
+
!roleConfig.slack_channels.includes(this.actor.slack.channelId)) {
|
|
168228
|
+
continue;
|
|
168229
|
+
}
|
|
168230
|
+
}
|
|
168231
|
+
matched.push(roleName);
|
|
168232
|
+
}
|
|
168233
|
+
return matched;
|
|
168234
|
+
}
|
|
168235
|
+
buildActor() {
|
|
168236
|
+
return {
|
|
168237
|
+
authorAssociation: this.actor.authorAssociation,
|
|
168238
|
+
login: this.actor.login,
|
|
168239
|
+
roles: this.resolveRoles(),
|
|
168240
|
+
isLocalMode: this.actor.isLocalMode,
|
|
168241
|
+
...(this.actor.slack && { slack: this.actor.slack }),
|
|
168242
|
+
};
|
|
168243
|
+
}
|
|
168244
|
+
forCheckExecution(check) {
|
|
168245
|
+
return {
|
|
168246
|
+
scope: 'check.execute',
|
|
168247
|
+
check: {
|
|
168248
|
+
id: check.id,
|
|
168249
|
+
type: check.type,
|
|
168250
|
+
group: check.group,
|
|
168251
|
+
tags: check.tags,
|
|
168252
|
+
criticality: check.criticality,
|
|
168253
|
+
sandbox: check.sandbox,
|
|
168254
|
+
policy: check.policy,
|
|
168255
|
+
},
|
|
168256
|
+
actor: this.buildActor(),
|
|
168257
|
+
repository: this.repository,
|
|
168258
|
+
pullRequest: this.pullRequest,
|
|
168259
|
+
};
|
|
168260
|
+
}
|
|
168261
|
+
forToolInvocation(serverName, methodName, transport) {
|
|
168262
|
+
return {
|
|
168263
|
+
scope: 'tool.invoke',
|
|
168264
|
+
tool: { serverName, methodName, transport },
|
|
168265
|
+
actor: this.buildActor(),
|
|
168266
|
+
repository: this.repository,
|
|
168267
|
+
pullRequest: this.pullRequest,
|
|
168268
|
+
};
|
|
168269
|
+
}
|
|
168270
|
+
forCapabilityResolve(checkId, capabilities) {
|
|
168271
|
+
return {
|
|
168272
|
+
scope: 'capability.resolve',
|
|
168273
|
+
check: { id: checkId, type: 'ai' },
|
|
168274
|
+
capability: capabilities,
|
|
168275
|
+
actor: this.buildActor(),
|
|
168276
|
+
repository: this.repository,
|
|
168277
|
+
pullRequest: this.pullRequest,
|
|
168278
|
+
};
|
|
168279
|
+
}
|
|
168280
|
+
}
|
|
168281
|
+
exports.PolicyInputBuilder = PolicyInputBuilder;
|
|
168282
|
+
|
|
168283
|
+
|
|
168284
|
+
/***/ }),
|
|
168285
|
+
|
|
168286
|
+
/***/ 63737:
|
|
168287
|
+
/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) {
|
|
168288
|
+
|
|
168289
|
+
"use strict";
|
|
168290
|
+
|
|
168291
|
+
/**
|
|
168292
|
+
* Copyright (c) ProbeLabs. All rights reserved.
|
|
168293
|
+
* Licensed under the Elastic License 2.0; you may not use this file except
|
|
168294
|
+
* in compliance with the Elastic License 2.0.
|
|
168295
|
+
*/
|
|
168296
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
168297
|
+
if (k2 === undefined) k2 = k;
|
|
168298
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
168299
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
168300
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
168301
|
+
}
|
|
168302
|
+
Object.defineProperty(o, k2, desc);
|
|
168303
|
+
}) : (function(o, m, k, k2) {
|
|
168304
|
+
if (k2 === undefined) k2 = k;
|
|
168305
|
+
o[k2] = m[k];
|
|
168306
|
+
}));
|
|
168307
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
168308
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
168309
|
+
}) : function(o, v) {
|
|
168310
|
+
o["default"] = v;
|
|
168311
|
+
});
|
|
168312
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
168313
|
+
var ownKeys = function(o) {
|
|
168314
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
168315
|
+
var ar = [];
|
|
168316
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
168317
|
+
return ar;
|
|
168318
|
+
};
|
|
168319
|
+
return ownKeys(o);
|
|
168320
|
+
};
|
|
168321
|
+
return function (mod) {
|
|
168322
|
+
if (mod && mod.__esModule) return mod;
|
|
168323
|
+
var result = {};
|
|
168324
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
168325
|
+
__setModuleDefault(result, mod);
|
|
168326
|
+
return result;
|
|
168327
|
+
};
|
|
168328
|
+
})();
|
|
168329
|
+
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
168330
|
+
exports.KnexStoreBackend = void 0;
|
|
168331
|
+
/**
|
|
168332
|
+
* Knex-backed schedule store for PostgreSQL, MySQL, and MSSQL (Enterprise)
|
|
168333
|
+
*
|
|
168334
|
+
* Uses Knex query builder for database-agnostic SQL. Same schema as SQLite backend
|
|
168335
|
+
* but with real distributed locking via row-level claims (claimed_by/claimed_at/lock_token).
|
|
168336
|
+
*/
|
|
168337
|
+
const fs = __importStar(__nccwpck_require__(79896));
|
|
168338
|
+
const path = __importStar(__nccwpck_require__(16928));
|
|
168339
|
+
const uuid_1 = __nccwpck_require__(31914);
|
|
168340
|
+
const logger_1 = __nccwpck_require__(86999);
|
|
168341
|
+
function toNum(val) {
|
|
168342
|
+
if (val === null || val === undefined)
|
|
168343
|
+
return undefined;
|
|
168344
|
+
return typeof val === 'string' ? parseInt(val, 10) : val;
|
|
168345
|
+
}
|
|
168346
|
+
function safeJsonParse(value) {
|
|
168347
|
+
if (!value)
|
|
168348
|
+
return undefined;
|
|
168349
|
+
try {
|
|
168350
|
+
return JSON.parse(value);
|
|
168351
|
+
}
|
|
168352
|
+
catch {
|
|
168353
|
+
return undefined;
|
|
168354
|
+
}
|
|
168355
|
+
}
|
|
168356
|
+
function fromTriggerRow(row) {
|
|
168357
|
+
return {
|
|
168358
|
+
id: row.id,
|
|
168359
|
+
creatorId: row.creator_id,
|
|
168360
|
+
creatorContext: row.creator_context ?? undefined,
|
|
168361
|
+
creatorName: row.creator_name ?? undefined,
|
|
168362
|
+
description: row.description ?? undefined,
|
|
168363
|
+
channels: safeJsonParse(row.channels),
|
|
168364
|
+
fromUsers: safeJsonParse(row.from_users),
|
|
168365
|
+
fromBots: row.from_bots === true || row.from_bots === 1,
|
|
168366
|
+
contains: safeJsonParse(row.contains),
|
|
168367
|
+
matchPattern: row.match_pattern ?? undefined,
|
|
168368
|
+
threads: row.threads,
|
|
168369
|
+
workflow: row.workflow,
|
|
168370
|
+
inputs: safeJsonParse(row.inputs),
|
|
168371
|
+
outputContext: safeJsonParse(row.output_context),
|
|
168372
|
+
status: row.status,
|
|
168373
|
+
enabled: row.enabled === true || row.enabled === 1,
|
|
168374
|
+
createdAt: toNum(row.created_at),
|
|
168375
|
+
};
|
|
168376
|
+
}
|
|
168377
|
+
function toTriggerInsertRow(trigger) {
|
|
168378
|
+
return {
|
|
168379
|
+
id: trigger.id,
|
|
168380
|
+
creator_id: trigger.creatorId,
|
|
168381
|
+
creator_context: trigger.creatorContext ?? null,
|
|
168382
|
+
creator_name: trigger.creatorName ?? null,
|
|
168383
|
+
description: trigger.description ?? null,
|
|
168384
|
+
channels: trigger.channels ? JSON.stringify(trigger.channels) : null,
|
|
168385
|
+
from_users: trigger.fromUsers ? JSON.stringify(trigger.fromUsers) : null,
|
|
168386
|
+
from_bots: trigger.fromBots,
|
|
168387
|
+
contains: trigger.contains ? JSON.stringify(trigger.contains) : null,
|
|
168388
|
+
match_pattern: trigger.matchPattern ?? null,
|
|
168389
|
+
threads: trigger.threads,
|
|
168390
|
+
workflow: trigger.workflow,
|
|
168391
|
+
inputs: trigger.inputs ? JSON.stringify(trigger.inputs) : null,
|
|
168392
|
+
output_context: trigger.outputContext ? JSON.stringify(trigger.outputContext) : null,
|
|
168393
|
+
status: trigger.status,
|
|
168394
|
+
enabled: trigger.enabled,
|
|
168395
|
+
created_at: trigger.createdAt,
|
|
168396
|
+
};
|
|
168397
|
+
}
|
|
168398
|
+
function fromDbRow(row) {
|
|
168399
|
+
return {
|
|
168400
|
+
id: row.id,
|
|
168401
|
+
creatorId: row.creator_id,
|
|
168402
|
+
creatorContext: row.creator_context ?? undefined,
|
|
168403
|
+
creatorName: row.creator_name ?? undefined,
|
|
168404
|
+
timezone: row.timezone,
|
|
168405
|
+
schedule: row.schedule_expr,
|
|
168406
|
+
runAt: toNum(row.run_at),
|
|
168407
|
+
isRecurring: row.is_recurring === true || row.is_recurring === 1,
|
|
168408
|
+
originalExpression: row.original_expression,
|
|
168409
|
+
workflow: row.workflow ?? undefined,
|
|
168410
|
+
workflowInputs: safeJsonParse(row.workflow_inputs),
|
|
168411
|
+
outputContext: safeJsonParse(row.output_context),
|
|
168412
|
+
status: row.status,
|
|
168413
|
+
createdAt: toNum(row.created_at),
|
|
168414
|
+
lastRunAt: toNum(row.last_run_at),
|
|
168415
|
+
nextRunAt: toNum(row.next_run_at),
|
|
168416
|
+
runCount: row.run_count,
|
|
168417
|
+
failureCount: row.failure_count,
|
|
168418
|
+
lastError: row.last_error ?? undefined,
|
|
168419
|
+
previousResponse: row.previous_response ?? undefined,
|
|
168420
|
+
};
|
|
168421
|
+
}
|
|
168422
|
+
function toInsertRow(schedule) {
|
|
168423
|
+
return {
|
|
168424
|
+
id: schedule.id,
|
|
168425
|
+
creator_id: schedule.creatorId,
|
|
168426
|
+
creator_context: schedule.creatorContext ?? null,
|
|
168427
|
+
creator_name: schedule.creatorName ?? null,
|
|
168428
|
+
timezone: schedule.timezone,
|
|
168429
|
+
schedule_expr: schedule.schedule,
|
|
168430
|
+
run_at: schedule.runAt ?? null,
|
|
168431
|
+
is_recurring: schedule.isRecurring,
|
|
168432
|
+
original_expression: schedule.originalExpression,
|
|
168433
|
+
workflow: schedule.workflow ?? null,
|
|
168434
|
+
workflow_inputs: schedule.workflowInputs ? JSON.stringify(schedule.workflowInputs) : null,
|
|
168435
|
+
output_context: schedule.outputContext ? JSON.stringify(schedule.outputContext) : null,
|
|
168436
|
+
status: schedule.status,
|
|
168437
|
+
created_at: schedule.createdAt,
|
|
168438
|
+
last_run_at: schedule.lastRunAt ?? null,
|
|
168439
|
+
next_run_at: schedule.nextRunAt ?? null,
|
|
168440
|
+
run_count: schedule.runCount,
|
|
168441
|
+
failure_count: schedule.failureCount,
|
|
168442
|
+
last_error: schedule.lastError ?? null,
|
|
168443
|
+
previous_response: schedule.previousResponse ?? null,
|
|
168444
|
+
};
|
|
168445
|
+
}
|
|
168446
|
+
/**
|
|
168447
|
+
* Enterprise Knex-backed store for PostgreSQL, MySQL, and MSSQL
|
|
168448
|
+
*/
|
|
168449
|
+
class KnexStoreBackend {
|
|
168450
|
+
knex = null;
|
|
168451
|
+
driver;
|
|
168452
|
+
connection;
|
|
168453
|
+
constructor(driver, storageConfig, _haConfig) {
|
|
168454
|
+
this.driver = driver;
|
|
168455
|
+
this.connection = (storageConfig.connection || {});
|
|
168456
|
+
}
|
|
168457
|
+
async initialize() {
|
|
168458
|
+
// Load knex dynamically
|
|
168459
|
+
const { createRequire } = __nccwpck_require__(73339);
|
|
168460
|
+
const runtimeRequire = createRequire(__filename);
|
|
168461
|
+
let knexFactory;
|
|
168462
|
+
try {
|
|
168463
|
+
knexFactory = runtimeRequire('knex');
|
|
168464
|
+
}
|
|
168465
|
+
catch (err) {
|
|
168466
|
+
const code = err?.code;
|
|
168467
|
+
if (code === 'MODULE_NOT_FOUND' || code === 'ERR_MODULE_NOT_FOUND') {
|
|
168468
|
+
throw new Error('knex is required for PostgreSQL/MySQL/MSSQL schedule storage. ' +
|
|
168469
|
+
'Install it with: npm install knex');
|
|
168470
|
+
}
|
|
168471
|
+
throw err;
|
|
168472
|
+
}
|
|
168473
|
+
const clientMap = {
|
|
168474
|
+
postgresql: 'pg',
|
|
168475
|
+
mysql: 'mysql2',
|
|
168476
|
+
mssql: 'tedious',
|
|
168477
|
+
};
|
|
168478
|
+
const client = clientMap[this.driver];
|
|
168479
|
+
// Build connection config
|
|
168480
|
+
let connection;
|
|
168481
|
+
if (this.connection.connection_string) {
|
|
168482
|
+
connection = this.connection.connection_string;
|
|
168483
|
+
}
|
|
168484
|
+
else if (this.driver === 'mssql') {
|
|
168485
|
+
connection = this.buildMssqlConnection();
|
|
168486
|
+
}
|
|
168487
|
+
else {
|
|
168488
|
+
connection = this.buildStandardConnection();
|
|
168489
|
+
}
|
|
168490
|
+
this.knex = knexFactory({
|
|
168491
|
+
client,
|
|
168492
|
+
connection,
|
|
168493
|
+
pool: {
|
|
168494
|
+
min: this.connection.pool?.min ?? 0,
|
|
168495
|
+
max: this.connection.pool?.max ?? 10,
|
|
168496
|
+
},
|
|
168497
|
+
});
|
|
168498
|
+
// Run schema migration
|
|
168499
|
+
await this.migrateSchema();
|
|
168500
|
+
logger_1.logger.info(`[KnexStore] Initialized (${this.driver})`);
|
|
168501
|
+
}
|
|
168502
|
+
buildStandardConnection() {
|
|
168503
|
+
return {
|
|
168504
|
+
host: this.connection.host || 'localhost',
|
|
168505
|
+
port: this.connection.port,
|
|
168506
|
+
database: this.connection.database || 'visor',
|
|
168507
|
+
user: this.connection.user,
|
|
168508
|
+
password: this.connection.password,
|
|
168509
|
+
ssl: this.resolveSslConfig(),
|
|
168510
|
+
};
|
|
168511
|
+
}
|
|
168512
|
+
buildMssqlConnection() {
|
|
168513
|
+
const ssl = this.connection.ssl;
|
|
168514
|
+
const sslEnabled = ssl === true || (typeof ssl === 'object' && ssl.enabled !== false);
|
|
168515
|
+
return {
|
|
168516
|
+
server: this.connection.host || 'localhost',
|
|
168517
|
+
port: this.connection.port,
|
|
168518
|
+
database: this.connection.database || 'visor',
|
|
168519
|
+
user: this.connection.user,
|
|
168520
|
+
password: this.connection.password,
|
|
168521
|
+
options: {
|
|
168522
|
+
encrypt: sslEnabled,
|
|
168523
|
+
trustServerCertificate: typeof ssl === 'object' ? ssl.reject_unauthorized === false : !sslEnabled,
|
|
168524
|
+
},
|
|
168525
|
+
};
|
|
168526
|
+
}
|
|
168527
|
+
resolveSslConfig() {
|
|
168528
|
+
const ssl = this.connection.ssl;
|
|
168529
|
+
if (ssl === false || ssl === undefined)
|
|
168530
|
+
return false;
|
|
168531
|
+
if (ssl === true)
|
|
168532
|
+
return { rejectUnauthorized: true };
|
|
168533
|
+
// Object config
|
|
168534
|
+
if (ssl.enabled === false)
|
|
168535
|
+
return false;
|
|
168536
|
+
const result = {
|
|
168537
|
+
rejectUnauthorized: ssl.reject_unauthorized !== false,
|
|
168538
|
+
};
|
|
168539
|
+
if (ssl.ca) {
|
|
168540
|
+
const caPath = this.validateSslPath(ssl.ca, 'CA certificate');
|
|
168541
|
+
result.ca = fs.readFileSync(caPath, 'utf8');
|
|
168542
|
+
}
|
|
168543
|
+
if (ssl.cert) {
|
|
168544
|
+
const certPath = this.validateSslPath(ssl.cert, 'client certificate');
|
|
168545
|
+
result.cert = fs.readFileSync(certPath, 'utf8');
|
|
168546
|
+
}
|
|
168547
|
+
if (ssl.key) {
|
|
168548
|
+
const keyPath = this.validateSslPath(ssl.key, 'client key');
|
|
168549
|
+
result.key = fs.readFileSync(keyPath, 'utf8');
|
|
168550
|
+
}
|
|
168551
|
+
return result;
|
|
168552
|
+
}
|
|
168553
|
+
validateSslPath(filePath, label) {
|
|
168554
|
+
const resolved = path.resolve(filePath);
|
|
168555
|
+
if (resolved !== path.normalize(resolved)) {
|
|
168556
|
+
throw new Error(`SSL ${label} path contains invalid sequences: ${filePath}`);
|
|
168557
|
+
}
|
|
168558
|
+
if (!fs.existsSync(resolved)) {
|
|
168559
|
+
throw new Error(`SSL ${label} not found: ${filePath}`);
|
|
168560
|
+
}
|
|
168561
|
+
return resolved;
|
|
168562
|
+
}
|
|
168563
|
+
async shutdown() {
|
|
168564
|
+
if (this.knex) {
|
|
168565
|
+
await this.knex.destroy();
|
|
168566
|
+
this.knex = null;
|
|
168567
|
+
}
|
|
168568
|
+
}
|
|
168569
|
+
async migrateSchema() {
|
|
168570
|
+
const knex = this.getKnex();
|
|
168571
|
+
const exists = await knex.schema.hasTable('schedules');
|
|
168572
|
+
if (!exists) {
|
|
168573
|
+
await knex.schema.createTable('schedules', table => {
|
|
168574
|
+
table.string('id', 36).primary();
|
|
168575
|
+
table.string('creator_id', 255).notNullable().index();
|
|
168576
|
+
table.string('creator_context', 255);
|
|
168577
|
+
table.string('creator_name', 255);
|
|
168578
|
+
table.string('timezone', 64).notNullable().defaultTo('UTC');
|
|
168579
|
+
table.string('schedule_expr', 255);
|
|
168580
|
+
table.bigInteger('run_at');
|
|
168581
|
+
table.boolean('is_recurring').notNullable();
|
|
168582
|
+
table.text('original_expression');
|
|
168583
|
+
table.string('workflow', 255);
|
|
168584
|
+
table.text('workflow_inputs');
|
|
168585
|
+
table.text('output_context');
|
|
168586
|
+
table.string('status', 20).notNullable().index();
|
|
168587
|
+
table.bigInteger('created_at').notNullable();
|
|
168588
|
+
table.bigInteger('last_run_at');
|
|
168589
|
+
table.bigInteger('next_run_at');
|
|
168590
|
+
table.integer('run_count').notNullable().defaultTo(0);
|
|
168591
|
+
table.integer('failure_count').notNullable().defaultTo(0);
|
|
168592
|
+
table.text('last_error');
|
|
168593
|
+
table.text('previous_response');
|
|
168594
|
+
table.index(['status', 'next_run_at']);
|
|
168595
|
+
});
|
|
168596
|
+
}
|
|
168597
|
+
// Create message_triggers table
|
|
168598
|
+
const triggersExist = await knex.schema.hasTable('message_triggers');
|
|
168599
|
+
if (!triggersExist) {
|
|
168600
|
+
await knex.schema.createTable('message_triggers', table => {
|
|
168601
|
+
table.string('id', 36).primary();
|
|
168602
|
+
table.string('creator_id', 255).notNullable().index();
|
|
168603
|
+
table.string('creator_context', 255);
|
|
168604
|
+
table.string('creator_name', 255);
|
|
168605
|
+
table.text('description');
|
|
168606
|
+
table.text('channels'); // JSON array
|
|
168607
|
+
table.text('from_users'); // JSON array
|
|
168608
|
+
table.boolean('from_bots').notNullable().defaultTo(false);
|
|
168609
|
+
table.text('contains'); // JSON array
|
|
168610
|
+
table.text('match_pattern');
|
|
168611
|
+
table.string('threads', 20).notNullable().defaultTo('any');
|
|
168612
|
+
table.string('workflow', 255).notNullable();
|
|
168613
|
+
table.text('inputs'); // JSON
|
|
168614
|
+
table.text('output_context'); // JSON
|
|
168615
|
+
table.string('status', 20).notNullable().defaultTo('active').index();
|
|
168616
|
+
table.boolean('enabled').notNullable().defaultTo(true);
|
|
168617
|
+
table.bigInteger('created_at').notNullable();
|
|
168618
|
+
});
|
|
168619
|
+
}
|
|
168620
|
+
// Create scheduler_locks table for distributed locking
|
|
168621
|
+
const locksExist = await knex.schema.hasTable('scheduler_locks');
|
|
168622
|
+
if (!locksExist) {
|
|
168623
|
+
await knex.schema.createTable('scheduler_locks', table => {
|
|
168624
|
+
table.string('lock_id', 255).primary();
|
|
168625
|
+
table.string('node_id', 255).notNullable();
|
|
168626
|
+
table.string('lock_token', 36).notNullable();
|
|
168627
|
+
table.bigInteger('acquired_at').notNullable();
|
|
168628
|
+
table.bigInteger('expires_at').notNullable();
|
|
168629
|
+
});
|
|
168630
|
+
}
|
|
168631
|
+
}
|
|
168632
|
+
getKnex() {
|
|
168633
|
+
if (!this.knex) {
|
|
168634
|
+
throw new Error('[KnexStore] Not initialized. Call initialize() first.');
|
|
168635
|
+
}
|
|
168636
|
+
return this.knex;
|
|
168637
|
+
}
|
|
168638
|
+
// --- CRUD ---
|
|
168639
|
+
async create(schedule) {
|
|
168640
|
+
const knex = this.getKnex();
|
|
168641
|
+
const newSchedule = {
|
|
168642
|
+
...schedule,
|
|
168643
|
+
id: (0, uuid_1.v4)(),
|
|
168644
|
+
createdAt: Date.now(),
|
|
168645
|
+
runCount: 0,
|
|
168646
|
+
failureCount: 0,
|
|
168647
|
+
status: 'active',
|
|
168648
|
+
};
|
|
168649
|
+
await knex('schedules').insert(toInsertRow(newSchedule));
|
|
168650
|
+
logger_1.logger.info(`[KnexStore] Created schedule ${newSchedule.id} for user ${newSchedule.creatorId}`);
|
|
168651
|
+
return newSchedule;
|
|
168652
|
+
}
|
|
168653
|
+
async importSchedule(schedule) {
|
|
168654
|
+
const knex = this.getKnex();
|
|
168655
|
+
const existing = await knex('schedules').where('id', schedule.id).first();
|
|
168656
|
+
if (existing)
|
|
168657
|
+
return; // Already imported (idempotent)
|
|
168658
|
+
await knex('schedules').insert(toInsertRow(schedule));
|
|
168659
|
+
}
|
|
168660
|
+
async get(id) {
|
|
168661
|
+
const knex = this.getKnex();
|
|
168662
|
+
const row = await knex('schedules').where('id', id).first();
|
|
168663
|
+
return row ? fromDbRow(row) : undefined;
|
|
168664
|
+
}
|
|
168665
|
+
async update(id, patch) {
|
|
168666
|
+
const knex = this.getKnex();
|
|
168667
|
+
const existing = await knex('schedules').where('id', id).first();
|
|
168668
|
+
if (!existing)
|
|
168669
|
+
return undefined;
|
|
168670
|
+
const current = fromDbRow(existing);
|
|
168671
|
+
const updated = { ...current, ...patch, id: current.id };
|
|
168672
|
+
const row = toInsertRow(updated);
|
|
168673
|
+
// Remove id from update (PK cannot change)
|
|
168674
|
+
delete row.id;
|
|
168675
|
+
await knex('schedules').where('id', id).update(row);
|
|
168676
|
+
return updated;
|
|
168677
|
+
}
|
|
168678
|
+
async delete(id) {
|
|
168679
|
+
const knex = this.getKnex();
|
|
168680
|
+
const deleted = await knex('schedules').where('id', id).del();
|
|
168681
|
+
if (deleted > 0) {
|
|
168682
|
+
logger_1.logger.info(`[KnexStore] Deleted schedule ${id}`);
|
|
168683
|
+
return true;
|
|
168684
|
+
}
|
|
168685
|
+
return false;
|
|
168686
|
+
}
|
|
168687
|
+
// --- Queries ---
|
|
168688
|
+
async getByCreator(creatorId) {
|
|
168689
|
+
const knex = this.getKnex();
|
|
168690
|
+
const rows = await knex('schedules').where('creator_id', creatorId);
|
|
168691
|
+
return rows.map((r) => fromDbRow(r));
|
|
168692
|
+
}
|
|
168693
|
+
async getActiveSchedules() {
|
|
168694
|
+
const knex = this.getKnex();
|
|
168695
|
+
const rows = await knex('schedules').where('status', 'active');
|
|
168696
|
+
return rows.map((r) => fromDbRow(r));
|
|
168697
|
+
}
|
|
168698
|
+
async getDueSchedules(now) {
|
|
168699
|
+
const ts = now ?? Date.now();
|
|
168700
|
+
const knex = this.getKnex();
|
|
168701
|
+
// MSSQL uses 1/0 for booleans
|
|
168702
|
+
const bFalse = this.driver === 'mssql' ? 0 : false;
|
|
168703
|
+
const bTrue = this.driver === 'mssql' ? 1 : true;
|
|
168704
|
+
const rows = await knex('schedules')
|
|
168705
|
+
.where('status', 'active')
|
|
168706
|
+
.andWhere(function () {
|
|
168707
|
+
this.where(function () {
|
|
168708
|
+
this.where('is_recurring', bFalse)
|
|
168709
|
+
.whereNotNull('run_at')
|
|
168710
|
+
.where('run_at', '<=', ts);
|
|
168711
|
+
}).orWhere(function () {
|
|
168712
|
+
this.where('is_recurring', bTrue)
|
|
168713
|
+
.whereNotNull('next_run_at')
|
|
168714
|
+
.where('next_run_at', '<=', ts);
|
|
168715
|
+
});
|
|
168716
|
+
});
|
|
168717
|
+
return rows.map((r) => fromDbRow(r));
|
|
168718
|
+
}
|
|
168719
|
+
async findByWorkflow(creatorId, workflowName) {
|
|
168720
|
+
const knex = this.getKnex();
|
|
168721
|
+
const escaped = workflowName.toLowerCase().replace(/[%_\\]/g, '\\$&');
|
|
168722
|
+
const pattern = `%${escaped}%`;
|
|
168723
|
+
const rows = await knex('schedules')
|
|
168724
|
+
.where('creator_id', creatorId)
|
|
168725
|
+
.where('status', 'active')
|
|
168726
|
+
.whereRaw("LOWER(workflow) LIKE ? ESCAPE '\\'", [pattern]);
|
|
168727
|
+
return rows.map((r) => fromDbRow(r));
|
|
168728
|
+
}
|
|
168729
|
+
async getAll() {
|
|
168730
|
+
const knex = this.getKnex();
|
|
168731
|
+
const rows = await knex('schedules');
|
|
168732
|
+
return rows.map((r) => fromDbRow(r));
|
|
168733
|
+
}
|
|
168734
|
+
async getStats() {
|
|
168735
|
+
const knex = this.getKnex();
|
|
168736
|
+
// MSSQL uses 1/0 for booleans; PostgreSQL/MySQL accept both true/1
|
|
168737
|
+
const boolTrue = this.driver === 'mssql' ? '1' : 'true';
|
|
168738
|
+
const boolFalse = this.driver === 'mssql' ? '0' : 'false';
|
|
168739
|
+
const result = await knex('schedules')
|
|
168740
|
+
.select(knex.raw('COUNT(*) as total'), knex.raw("SUM(CASE WHEN status = 'active' THEN 1 ELSE 0 END) as active"), knex.raw("SUM(CASE WHEN status = 'paused' THEN 1 ELSE 0 END) as paused"), knex.raw("SUM(CASE WHEN status = 'completed' THEN 1 ELSE 0 END) as completed"), knex.raw("SUM(CASE WHEN status = 'failed' THEN 1 ELSE 0 END) as failed"), knex.raw(`SUM(CASE WHEN is_recurring = ${boolTrue} THEN 1 ELSE 0 END) as recurring`), knex.raw(`SUM(CASE WHEN is_recurring = ${boolFalse} THEN 1 ELSE 0 END) as one_time`))
|
|
168741
|
+
.first();
|
|
168742
|
+
return {
|
|
168743
|
+
total: Number(result.total) || 0,
|
|
168744
|
+
active: Number(result.active) || 0,
|
|
168745
|
+
paused: Number(result.paused) || 0,
|
|
168746
|
+
completed: Number(result.completed) || 0,
|
|
168747
|
+
failed: Number(result.failed) || 0,
|
|
168748
|
+
recurring: Number(result.recurring) || 0,
|
|
168749
|
+
oneTime: Number(result.one_time) || 0,
|
|
168750
|
+
};
|
|
168751
|
+
}
|
|
168752
|
+
async validateLimits(creatorId, isRecurring, limits) {
|
|
168753
|
+
const knex = this.getKnex();
|
|
168754
|
+
if (limits.maxGlobal) {
|
|
168755
|
+
const result = await knex('schedules').count('* as cnt').first();
|
|
168756
|
+
if (Number(result?.cnt) >= limits.maxGlobal) {
|
|
168757
|
+
throw new Error(`Global schedule limit reached (${limits.maxGlobal})`);
|
|
168758
|
+
}
|
|
168759
|
+
}
|
|
168760
|
+
if (limits.maxPerUser) {
|
|
168761
|
+
const result = await knex('schedules')
|
|
168762
|
+
.where('creator_id', creatorId)
|
|
168763
|
+
.count('* as cnt')
|
|
168764
|
+
.first();
|
|
168765
|
+
if (Number(result?.cnt) >= limits.maxPerUser) {
|
|
168766
|
+
throw new Error(`You have reached the maximum number of schedules (${limits.maxPerUser})`);
|
|
168767
|
+
}
|
|
168768
|
+
}
|
|
168769
|
+
if (isRecurring && limits.maxRecurringPerUser) {
|
|
168770
|
+
const bTrue = this.driver === 'mssql' ? 1 : true;
|
|
168771
|
+
const result = await knex('schedules')
|
|
168772
|
+
.where('creator_id', creatorId)
|
|
168773
|
+
.where('is_recurring', bTrue)
|
|
168774
|
+
.count('* as cnt')
|
|
168775
|
+
.first();
|
|
168776
|
+
if (Number(result?.cnt) >= limits.maxRecurringPerUser) {
|
|
168777
|
+
throw new Error(`You have reached the maximum number of recurring schedules (${limits.maxRecurringPerUser})`);
|
|
168778
|
+
}
|
|
168779
|
+
}
|
|
168780
|
+
}
|
|
168781
|
+
// --- HA Distributed Locking (via scheduler_locks table) ---
|
|
168782
|
+
async tryAcquireLock(lockId, nodeId, ttlSeconds) {
|
|
168783
|
+
const knex = this.getKnex();
|
|
168784
|
+
const now = Date.now();
|
|
168785
|
+
const expiresAt = now + ttlSeconds * 1000;
|
|
168786
|
+
const token = (0, uuid_1.v4)();
|
|
168787
|
+
// Step 1: Try to claim an existing expired lock
|
|
168788
|
+
const updated = await knex('scheduler_locks')
|
|
168789
|
+
.where('lock_id', lockId)
|
|
168790
|
+
.where('expires_at', '<', now)
|
|
168791
|
+
.update({
|
|
168792
|
+
node_id: nodeId,
|
|
168793
|
+
lock_token: token,
|
|
168794
|
+
acquired_at: now,
|
|
168795
|
+
expires_at: expiresAt,
|
|
168796
|
+
});
|
|
168797
|
+
if (updated > 0)
|
|
168798
|
+
return token;
|
|
168799
|
+
// Step 2: Try to INSERT a new lock row
|
|
168800
|
+
try {
|
|
168801
|
+
await knex('scheduler_locks').insert({
|
|
168802
|
+
lock_id: lockId,
|
|
168803
|
+
node_id: nodeId,
|
|
168804
|
+
lock_token: token,
|
|
168805
|
+
acquired_at: now,
|
|
168806
|
+
expires_at: expiresAt,
|
|
168807
|
+
});
|
|
168808
|
+
return token;
|
|
168809
|
+
}
|
|
168810
|
+
catch {
|
|
168811
|
+
// Unique constraint violation — another node holds the lock
|
|
168812
|
+
return null;
|
|
168813
|
+
}
|
|
168814
|
+
}
|
|
168815
|
+
async releaseLock(lockId, lockToken) {
|
|
168816
|
+
const knex = this.getKnex();
|
|
168817
|
+
await knex('scheduler_locks').where('lock_id', lockId).where('lock_token', lockToken).del();
|
|
168818
|
+
}
|
|
168819
|
+
async renewLock(lockId, lockToken, ttlSeconds) {
|
|
168820
|
+
const knex = this.getKnex();
|
|
168821
|
+
const now = Date.now();
|
|
168822
|
+
const expiresAt = now + ttlSeconds * 1000;
|
|
168823
|
+
const updated = await knex('scheduler_locks')
|
|
168824
|
+
.where('lock_id', lockId)
|
|
168825
|
+
.where('lock_token', lockToken)
|
|
168826
|
+
.update({ acquired_at: now, expires_at: expiresAt });
|
|
168827
|
+
return updated > 0;
|
|
168828
|
+
}
|
|
168829
|
+
async flush() {
|
|
168830
|
+
// No-op for server-based backends
|
|
168831
|
+
}
|
|
168832
|
+
// --- Message Trigger CRUD ---
|
|
168833
|
+
async createTrigger(trigger) {
|
|
168834
|
+
const knex = this.getKnex();
|
|
168835
|
+
const newTrigger = {
|
|
168836
|
+
...trigger,
|
|
168837
|
+
id: (0, uuid_1.v4)(),
|
|
168838
|
+
createdAt: Date.now(),
|
|
168839
|
+
};
|
|
168840
|
+
await knex('message_triggers').insert(toTriggerInsertRow(newTrigger));
|
|
168841
|
+
logger_1.logger.info(`[KnexStore] Created trigger ${newTrigger.id} for user ${newTrigger.creatorId}`);
|
|
168842
|
+
return newTrigger;
|
|
168843
|
+
}
|
|
168844
|
+
async getTrigger(id) {
|
|
168845
|
+
const knex = this.getKnex();
|
|
168846
|
+
const row = await knex('message_triggers').where('id', id).first();
|
|
168847
|
+
return row ? fromTriggerRow(row) : undefined;
|
|
168848
|
+
}
|
|
168849
|
+
async updateTrigger(id, patch) {
|
|
168850
|
+
const knex = this.getKnex();
|
|
168851
|
+
const existing = await knex('message_triggers').where('id', id).first();
|
|
168852
|
+
if (!existing)
|
|
168853
|
+
return undefined;
|
|
168854
|
+
const current = fromTriggerRow(existing);
|
|
168855
|
+
const updated = {
|
|
168856
|
+
...current,
|
|
168857
|
+
...patch,
|
|
168858
|
+
id: current.id,
|
|
168859
|
+
createdAt: current.createdAt,
|
|
168860
|
+
};
|
|
168861
|
+
const row = toTriggerInsertRow(updated);
|
|
168862
|
+
delete row.id;
|
|
168863
|
+
await knex('message_triggers').where('id', id).update(row);
|
|
168864
|
+
return updated;
|
|
168865
|
+
}
|
|
168866
|
+
async deleteTrigger(id) {
|
|
168867
|
+
const knex = this.getKnex();
|
|
168868
|
+
const deleted = await knex('message_triggers').where('id', id).del();
|
|
168869
|
+
if (deleted > 0) {
|
|
168870
|
+
logger_1.logger.info(`[KnexStore] Deleted trigger ${id}`);
|
|
168871
|
+
return true;
|
|
168872
|
+
}
|
|
168873
|
+
return false;
|
|
168874
|
+
}
|
|
168875
|
+
async getTriggersByCreator(creatorId) {
|
|
168876
|
+
const knex = this.getKnex();
|
|
168877
|
+
const rows = await knex('message_triggers').where('creator_id', creatorId);
|
|
168878
|
+
return rows.map((r) => fromTriggerRow(r));
|
|
168879
|
+
}
|
|
168880
|
+
async getActiveTriggers() {
|
|
168881
|
+
const knex = this.getKnex();
|
|
168882
|
+
const rows = await knex('message_triggers')
|
|
168883
|
+
.where('status', 'active')
|
|
168884
|
+
.where('enabled', this.driver === 'mssql' ? 1 : true);
|
|
168885
|
+
return rows.map((r) => fromTriggerRow(r));
|
|
168886
|
+
}
|
|
168887
|
+
}
|
|
168888
|
+
exports.KnexStoreBackend = KnexStoreBackend;
|
|
168889
|
+
|
|
168890
|
+
|
|
167087
168891
|
/***/ }),
|
|
167088
168892
|
|
|
167089
168893
|
/***/ 83864:
|
|
@@ -178087,6 +179891,35 @@ class OutputFormatters {
|
|
|
178087
179891
|
exports.OutputFormatters = OutputFormatters;
|
|
178088
179892
|
|
|
178089
179893
|
|
|
179894
|
+
/***/ }),
|
|
179895
|
+
|
|
179896
|
+
/***/ 93866:
|
|
179897
|
+
/***/ ((__unused_webpack_module, exports) => {
|
|
179898
|
+
|
|
179899
|
+
"use strict";
|
|
179900
|
+
|
|
179901
|
+
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
179902
|
+
exports.DefaultPolicyEngine = void 0;
|
|
179903
|
+
/**
|
|
179904
|
+
* Default (no-op) policy engine — always allows everything.
|
|
179905
|
+
* Used when no enterprise license is present or policy is disabled.
|
|
179906
|
+
*/
|
|
179907
|
+
class DefaultPolicyEngine {
|
|
179908
|
+
async initialize(_config) { }
|
|
179909
|
+
async evaluateCheckExecution(_checkId, _checkConfig) {
|
|
179910
|
+
return { allowed: true };
|
|
179911
|
+
}
|
|
179912
|
+
async evaluateToolInvocation(_serverName, _methodName, _transport) {
|
|
179913
|
+
return { allowed: true };
|
|
179914
|
+
}
|
|
179915
|
+
async evaluateCapabilities(_checkId, _capabilities) {
|
|
179916
|
+
return { allowed: true };
|
|
179917
|
+
}
|
|
179918
|
+
async shutdown() { }
|
|
179919
|
+
}
|
|
179920
|
+
exports.DefaultPolicyEngine = DefaultPolicyEngine;
|
|
179921
|
+
|
|
179922
|
+
|
|
178090
179923
|
/***/ }),
|
|
178091
179924
|
|
|
178092
179925
|
/***/ 96611:
|
|
@@ -188256,6 +190089,15 @@ class CustomToolsSSEServer {
|
|
|
188256
190089
|
original_expression: args.original_expression,
|
|
188257
190090
|
// For cancel/pause/resume
|
|
188258
190091
|
schedule_id: args.schedule_id,
|
|
190092
|
+
// For trigger actions
|
|
190093
|
+
trigger_channels: args.trigger_channels,
|
|
190094
|
+
trigger_from: args.trigger_from,
|
|
190095
|
+
trigger_from_bots: args.trigger_from_bots,
|
|
190096
|
+
trigger_contains: args.trigger_contains,
|
|
190097
|
+
trigger_match: args.trigger_match,
|
|
190098
|
+
trigger_threads: args.trigger_threads,
|
|
190099
|
+
trigger_description: args.trigger_description,
|
|
190100
|
+
trigger_id: args.trigger_id,
|
|
188259
190101
|
};
|
|
188260
190102
|
const scheduleResult = await (0, schedule_tool_1.handleScheduleAction)(scheduleArgs, scheduleContext);
|
|
188261
190103
|
result = scheduleResult.success
|
|
@@ -194160,19 +196002,13 @@ function formatTrigger(trigger) {
|
|
|
194160
196002
|
* Handle create_trigger action
|
|
194161
196003
|
*/
|
|
194162
196004
|
async function handleCreateTrigger(args, context, store) {
|
|
194163
|
-
//
|
|
194164
|
-
|
|
194165
|
-
return {
|
|
194166
|
-
success: false,
|
|
194167
|
-
message: 'Missing workflow',
|
|
194168
|
-
error: 'Please specify the workflow to run when the trigger fires.',
|
|
194169
|
-
};
|
|
194170
|
-
}
|
|
196005
|
+
// Default workflow to "default" if not specified
|
|
196006
|
+
const workflow = args.workflow || 'default';
|
|
194171
196007
|
// Validate workflow exists if we have available workflows
|
|
194172
|
-
if (context.availableWorkflows && !context.availableWorkflows.includes(
|
|
196008
|
+
if (context.availableWorkflows && !context.availableWorkflows.includes(workflow)) {
|
|
194173
196009
|
return {
|
|
194174
196010
|
success: false,
|
|
194175
|
-
message: `Workflow "${
|
|
196011
|
+
message: `Workflow "${workflow}" not found`,
|
|
194176
196012
|
error: `Available workflows: ${context.availableWorkflows.slice(0, 5).join(', ')}${context.availableWorkflows.length > 5 ? '...' : ''}`,
|
|
194177
196013
|
};
|
|
194178
196014
|
}
|
|
@@ -194188,7 +196024,7 @@ async function handleCreateTrigger(args, context, store) {
|
|
|
194188
196024
|
};
|
|
194189
196025
|
}
|
|
194190
196026
|
// Check permissions for the workflow
|
|
194191
|
-
const permissionCheck = checkSchedulePermissions(context,
|
|
196027
|
+
const permissionCheck = checkSchedulePermissions(context, workflow);
|
|
194192
196028
|
if (!permissionCheck.allowed) {
|
|
194193
196029
|
return {
|
|
194194
196030
|
success: false,
|
|
@@ -194208,12 +196044,12 @@ async function handleCreateTrigger(args, context, store) {
|
|
|
194208
196044
|
contains: args.trigger_contains,
|
|
194209
196045
|
matchPattern: args.trigger_match,
|
|
194210
196046
|
threads: args.trigger_threads ?? 'any',
|
|
194211
|
-
workflow:
|
|
196047
|
+
workflow: workflow,
|
|
194212
196048
|
inputs: args.workflow_inputs,
|
|
194213
196049
|
status: 'active',
|
|
194214
196050
|
enabled: true,
|
|
194215
196051
|
});
|
|
194216
|
-
logger_1.logger.info(`[ScheduleTool] Created message trigger ${trigger.id} for user ${context.userId}: workflow="${
|
|
196052
|
+
logger_1.logger.info(`[ScheduleTool] Created message trigger ${trigger.id} for user ${context.userId}: workflow="${workflow}"`);
|
|
194217
196053
|
return {
|
|
194218
196054
|
success: true,
|
|
194219
196055
|
message: `**Message trigger created!**
|
|
@@ -194346,12 +196182,17 @@ function getScheduleToolDefinition() {
|
|
|
194346
196182
|
|
|
194347
196183
|
YOU (the AI) must extract and structure all scheduling parameters. Do NOT pass natural language time expressions - convert them to cron or ISO timestamps.
|
|
194348
196184
|
|
|
194349
|
-
CRITICAL WORKFLOW RULE:
|
|
196185
|
+
CRITICAL WORKFLOW RULE (for 'create' action only):
|
|
194350
196186
|
- To schedule a WORKFLOW, the user MUST use a '%' prefix (e.g., "schedule %my-workflow daily").
|
|
194351
196187
|
- If the '%' prefix is present, extract the word following it as the 'workflow' parameter (without the '%').
|
|
194352
196188
|
- If the '%' prefix is NOT present, the request is a simple text reminder. The ENTIRE user request (excluding the schedule expression) MUST be placed in the 'reminder_text' parameter.
|
|
194353
196189
|
- DO NOT guess or infer a workflow name from a user's request without the '%' prefix.
|
|
194354
196190
|
|
|
196191
|
+
WORKFLOW RULE FOR TRIGGERS (create_trigger action):
|
|
196192
|
+
- Triggers ALWAYS require a workflow. The '%' prefix rule does NOT apply to triggers.
|
|
196193
|
+
- If the user specifies a workflow name (with or without '%'), use it directly.
|
|
196194
|
+
- If the user does NOT specify a workflow name, use "default" as the workflow name.
|
|
196195
|
+
|
|
194355
196196
|
ACTIONS:
|
|
194356
196197
|
- create: Schedule a new reminder or workflow
|
|
194357
196198
|
- list: Show user's active schedules
|
|
@@ -194364,7 +196205,7 @@ Slack messages in specific channels. Use the create_trigger, list_triggers, dele
|
|
|
194364
196205
|
actions for this. Message triggers fire workflows based on message content, channel, sender, and thread scope.
|
|
194365
196206
|
|
|
194366
196207
|
TRIGGER ACTIONS:
|
|
194367
|
-
- create_trigger: Create a new message trigger (requires
|
|
196208
|
+
- create_trigger: Create a new message trigger (requires at least one filter; workflow defaults to "default" if not specified). Supports filtering by user IDs (trigger_from), channels, keywords, regex, and thread scope.
|
|
194368
196209
|
- list_triggers: Show user's message triggers
|
|
194369
196210
|
- delete_trigger: Remove a trigger by ID
|
|
194370
196211
|
- update_trigger: Enable/disable a trigger by ID
|
|
@@ -194464,6 +196305,9 @@ User: "watch #cicd for messages containing 'failed' and run %handle-cicd"
|
|
|
194464
196305
|
User: "trigger on each of my messages in this channel and run %auto-reply" (user ID is U3P2L4XNE)
|
|
194465
196306
|
→ { "action": "create_trigger", "trigger_channels": ["C09V810NY6R"], "trigger_from": ["U3P2L4XNE"], "workflow": "auto-reply" }
|
|
194466
196307
|
|
|
196308
|
+
User: "trigger on each message in this channel" (no workflow specified — use "default")
|
|
196309
|
+
→ { "action": "create_trigger", "trigger_channels": ["C09V810NY6R"], "workflow": "default" }
|
|
196310
|
+
|
|
194467
196311
|
User: "list my message triggers"
|
|
194468
196312
|
→ { "action": "list_triggers" }
|
|
194469
196313
|
|
|
@@ -194497,7 +196341,7 @@ User: "disable trigger abc123"
|
|
|
194497
196341
|
},
|
|
194498
196342
|
workflow: {
|
|
194499
196343
|
type: 'string',
|
|
194500
|
-
description: 'For create: workflow ID to run. ONLY populate this if the user used the % prefix (e.g., "%my-workflow"). Extract the name without the % symbol. If no % prefix, use reminder_text instead.',
|
|
196344
|
+
description: 'For create: workflow ID to run. ONLY populate this if the user used the % prefix (e.g., "%my-workflow"). Extract the name without the % symbol. If no % prefix, use reminder_text instead. For create_trigger: workflow is REQUIRED — use the workflow name the user specified (% prefix optional), or "default" if not specified.',
|
|
194501
196345
|
},
|
|
194502
196346
|
workflow_inputs: {
|
|
194503
196347
|
type: 'object',
|
|
@@ -198079,6 +199923,15 @@ async function executeScheduleTool(args, slackContext, slackClient, availableWor
|
|
|
198079
199923
|
original_expression: args.original_expression,
|
|
198080
199924
|
// For cancel/pause/resume
|
|
198081
199925
|
schedule_id: args.schedule_id,
|
|
199926
|
+
// For trigger actions
|
|
199927
|
+
trigger_channels: args.trigger_channels,
|
|
199928
|
+
trigger_from: args.trigger_from,
|
|
199929
|
+
trigger_from_bots: args.trigger_from_bots,
|
|
199930
|
+
trigger_contains: args.trigger_contains,
|
|
199931
|
+
trigger_match: args.trigger_match,
|
|
199932
|
+
trigger_threads: args.trigger_threads,
|
|
199933
|
+
trigger_description: args.trigger_description,
|
|
199934
|
+
trigger_id: args.trigger_id,
|
|
198082
199935
|
};
|
|
198083
199936
|
// If AI didn't provide target, default to current Slack context
|
|
198084
199937
|
if (!toolArgs.target_type && slackContext.channel) {
|
|
@@ -199751,7 +201604,7 @@ class StateMachineExecutionEngine {
|
|
|
199751
201604
|
try {
|
|
199752
201605
|
logger_1.logger.debug(`[PolicyEngine] Loading enterprise policy engine (engine=${configWithTagFilter.policy.engine})`);
|
|
199753
201606
|
// @ts-ignore — enterprise/ may not exist in OSS builds (caught at runtime)
|
|
199754
|
-
const { loadEnterprisePolicyEngine } = await Promise.resolve().then(() => __importStar(__nccwpck_require__(
|
|
201607
|
+
const { loadEnterprisePolicyEngine } = await Promise.resolve().then(() => __importStar(__nccwpck_require__(87068)));
|
|
199755
201608
|
context.policyEngine = await loadEnterprisePolicyEngine(configWithTagFilter.policy);
|
|
199756
201609
|
logger_1.logger.debug(`[PolicyEngine] Initialized: ${context.policyEngine?.constructor?.name || 'unknown'}`);
|
|
199757
201610
|
}
|
|
@@ -210025,7 +211878,7 @@ async function initTelemetry(opts = {}) {
|
|
|
210025
211878
|
const path = __nccwpck_require__(16928);
|
|
210026
211879
|
const outDir = opts.file?.dir ||
|
|
210027
211880
|
process.env.VISOR_TRACE_DIR ||
|
|
210028
|
-
|
|
211881
|
+
path.join(process.cwd(), 'output', 'traces');
|
|
210029
211882
|
fs.mkdirSync(outDir, { recursive: true });
|
|
210030
211883
|
const ts = new Date().toISOString().replace(/[:.]/g, '-');
|
|
210031
211884
|
process.env.VISOR_FALLBACK_TRACE_FILE = path.join(outDir, `run-${ts}.ndjson`);
|
|
@@ -210230,7 +212083,7 @@ async function shutdownTelemetry() {
|
|
|
210230
212083
|
if (process.env.VISOR_TRACE_REPORT === 'true') {
|
|
210231
212084
|
const fs = __nccwpck_require__(79896);
|
|
210232
212085
|
const path = __nccwpck_require__(16928);
|
|
210233
|
-
const outDir = process.env.VISOR_TRACE_DIR ||
|
|
212086
|
+
const outDir = process.env.VISOR_TRACE_DIR || path.join(process.cwd(), 'output', 'traces');
|
|
210234
212087
|
if (!fs.existsSync(outDir))
|
|
210235
212088
|
fs.mkdirSync(outDir, { recursive: true });
|
|
210236
212089
|
const ts = new Date().toISOString().replace(/[:.]/g, '-');
|
|
@@ -210729,7 +212582,7 @@ function __getOrCreateNdjsonPath() {
|
|
|
210729
212582
|
fs.mkdirSync(dir, { recursive: true });
|
|
210730
212583
|
return __ndjsonPath;
|
|
210731
212584
|
}
|
|
210732
|
-
const outDir = process.env.VISOR_TRACE_DIR ||
|
|
212585
|
+
const outDir = process.env.VISOR_TRACE_DIR || path.join(process.cwd(), 'output', 'traces');
|
|
210733
212586
|
if (!fs.existsSync(outDir))
|
|
210734
212587
|
fs.mkdirSync(outDir, { recursive: true });
|
|
210735
212588
|
if (!__ndjsonPath) {
|
|
@@ -224465,6 +226318,12 @@ class WorkflowRegistry {
|
|
|
224465
226318
|
message: 'Input parameter schema is recommended',
|
|
224466
226319
|
});
|
|
224467
226320
|
}
|
|
226321
|
+
if (input.schema?.type === 'array' && !input.schema.items) {
|
|
226322
|
+
warnings.push({
|
|
226323
|
+
path: `inputs[${i}].schema`,
|
|
226324
|
+
message: 'Array schema should define "items" (e.g. items: { type: string }). Some LLM providers (Gemini) reject array schemas without items.',
|
|
226325
|
+
});
|
|
226326
|
+
}
|
|
224468
226327
|
}
|
|
224469
226328
|
}
|
|
224470
226329
|
// Validate output parameters
|
|
@@ -224683,22 +226542,6 @@ class WorkflowRegistry {
|
|
|
224683
226542
|
exports.WorkflowRegistry = WorkflowRegistry;
|
|
224684
226543
|
|
|
224685
226544
|
|
|
224686
|
-
/***/ }),
|
|
224687
|
-
|
|
224688
|
-
/***/ 7065:
|
|
224689
|
-
/***/ ((module) => {
|
|
224690
|
-
|
|
224691
|
-
module.exports = eval("require")("./enterprise/loader");
|
|
224692
|
-
|
|
224693
|
-
|
|
224694
|
-
/***/ }),
|
|
224695
|
-
|
|
224696
|
-
/***/ 71370:
|
|
224697
|
-
/***/ ((module) => {
|
|
224698
|
-
|
|
224699
|
-
module.exports = eval("require")("./enterprise/policy/policy-input-builder");
|
|
224700
|
-
|
|
224701
|
-
|
|
224702
226545
|
/***/ }),
|
|
224703
226546
|
|
|
224704
226547
|
/***/ 18327:
|
|
@@ -355804,9 +357647,10 @@ You are working with a workspace. Available paths: ${workspaceDesc}
|
|
|
355804
357647
|
}
|
|
355805
357648
|
if (completionAttempted && this.completionPrompt && !options._completionPromptProcessed) {
|
|
355806
357649
|
if (this.debug) {
|
|
355807
|
-
console.log("[DEBUG] Running completion prompt
|
|
357650
|
+
console.log("[DEBUG] Running completion prompt as continuation of current session...");
|
|
355808
357651
|
}
|
|
355809
357652
|
try {
|
|
357653
|
+
const originalResult = finalResult;
|
|
355810
357654
|
if (this.tracer) {
|
|
355811
357655
|
this.tracer.recordEvent("completion_prompt.started", {
|
|
355812
357656
|
"completion_prompt.original_result_length": finalResult?.length || 0
|
|
@@ -355819,24 +357663,66 @@ Here is the result to review:
|
|
|
355819
357663
|
${finalResult}
|
|
355820
357664
|
</result>
|
|
355821
357665
|
|
|
355822
|
-
|
|
355823
|
-
|
|
355824
|
-
|
|
355825
|
-
|
|
355826
|
-
|
|
355827
|
-
|
|
355828
|
-
|
|
355829
|
-
|
|
355830
|
-
|
|
357666
|
+
Double-check your response based on the criteria above. If everything looks good, respond with your previous answer exactly as-is using attempt_completion. If something needs to be fixed or is missing, do it now, then respond with the COMPLETE updated answer (everything you did in total, not just the fix) using attempt_completion.`;
|
|
357667
|
+
currentMessages.push({ role: "user", content: completionPromptMessage });
|
|
357668
|
+
completionResult = null;
|
|
357669
|
+
completionAttempted = false;
|
|
357670
|
+
const completionMaxIterations = 5;
|
|
357671
|
+
const completionStreamOptions = {
|
|
357672
|
+
model: this.provider ? this.provider(this.model) : this.model,
|
|
357673
|
+
messages: this.prepareMessagesWithImages(currentMessages),
|
|
357674
|
+
tools: tools2,
|
|
357675
|
+
stopWhen: (0, import_ai4.stepCountIs)(completionMaxIterations),
|
|
357676
|
+
maxTokens: maxResponseTokens,
|
|
357677
|
+
temperature: 0.3,
|
|
357678
|
+
onStepFinish: ({ toolResults, text, finishReason, usage }) => {
|
|
357679
|
+
if (usage) {
|
|
357680
|
+
this.tokenCounter.recordUsage(usage);
|
|
357681
|
+
}
|
|
357682
|
+
if (options.onStream && text) {
|
|
357683
|
+
options.onStream(text);
|
|
357684
|
+
}
|
|
357685
|
+
if (this.debug) {
|
|
357686
|
+
console.log(`[DEBUG] Completion prompt step finished (reason: ${finishReason}, tools: ${toolResults?.length || 0})`);
|
|
357687
|
+
}
|
|
357688
|
+
}
|
|
357689
|
+
};
|
|
357690
|
+
const providerOpts = this._buildThinkingProviderOptions(maxResponseTokens);
|
|
357691
|
+
if (providerOpts) {
|
|
357692
|
+
completionStreamOptions.providerOptions = providerOpts;
|
|
357693
|
+
}
|
|
357694
|
+
const cpResult = await this.streamTextWithRetryAndFallback(completionStreamOptions);
|
|
357695
|
+
const cpFinalText = await cpResult.text;
|
|
357696
|
+
const cpUsage = await cpResult.usage;
|
|
357697
|
+
if (cpUsage) {
|
|
357698
|
+
this.tokenCounter.recordUsage(cpUsage, cpResult.experimental_providerMetadata);
|
|
357699
|
+
}
|
|
357700
|
+
const cpMessages = await cpResult.response?.messages;
|
|
357701
|
+
if (cpMessages) {
|
|
357702
|
+
for (const msg of cpMessages) {
|
|
357703
|
+
currentMessages.push(msg);
|
|
357704
|
+
}
|
|
357705
|
+
}
|
|
357706
|
+
if (completionResult) {
|
|
357707
|
+
finalResult = completionResult;
|
|
357708
|
+
completionAttempted = true;
|
|
357709
|
+
} else if (cpFinalText && cpFinalText.trim().length > 0) {
|
|
357710
|
+
finalResult = cpFinalText;
|
|
357711
|
+
completionAttempted = true;
|
|
357712
|
+
} else {
|
|
357713
|
+
finalResult = originalResult;
|
|
357714
|
+
completionAttempted = true;
|
|
357715
|
+
if (this.debug) {
|
|
357716
|
+
console.log("[DEBUG] Completion prompt returned empty result, keeping original.");
|
|
357717
|
+
}
|
|
355831
357718
|
}
|
|
355832
|
-
this._extractedRawBlocks = savedExtractedBlocks;
|
|
355833
|
-
finalResult = completionResult2;
|
|
355834
357719
|
if (this.debug) {
|
|
355835
|
-
console.log(`[DEBUG] Completion prompt finished.
|
|
357720
|
+
console.log(`[DEBUG] Completion prompt finished. Final result length: ${finalResult?.length || 0}`);
|
|
355836
357721
|
}
|
|
355837
357722
|
if (this.tracer) {
|
|
355838
357723
|
this.tracer.recordEvent("completion_prompt.completed", {
|
|
355839
|
-
"completion_prompt.final_result_length": finalResult?.length || 0
|
|
357724
|
+
"completion_prompt.final_result_length": finalResult?.length || 0,
|
|
357725
|
+
"completion_prompt.used_original": finalResult === originalResult
|
|
355840
357726
|
});
|
|
355841
357727
|
}
|
|
355842
357728
|
} catch (error2) {
|
|
@@ -357594,6 +359480,17 @@ function parseDelegatedTargets(rawResponse) {
|
|
|
357594
359480
|
}
|
|
357595
359481
|
return normalizeTargets(fallbackTargetsFromText(trimmed));
|
|
357596
359482
|
}
|
|
359483
|
+
function splitTargetSuffix(target) {
|
|
359484
|
+
const searchStart = target.length > 2 && target[1] === ":" && /[a-zA-Z]/.test(target[0]) ? 2 : 0;
|
|
359485
|
+
const colonIdx = target.indexOf(":", searchStart);
|
|
359486
|
+
const hashIdx = target.indexOf("#");
|
|
359487
|
+
if (colonIdx !== -1 && (hashIdx === -1 || colonIdx < hashIdx)) {
|
|
359488
|
+
return { filePart: target.substring(0, colonIdx), suffix: target.substring(colonIdx) };
|
|
359489
|
+
} else if (hashIdx !== -1) {
|
|
359490
|
+
return { filePart: target.substring(0, hashIdx), suffix: target.substring(hashIdx) };
|
|
359491
|
+
}
|
|
359492
|
+
return { filePart: target, suffix: "" };
|
|
359493
|
+
}
|
|
357597
359494
|
function buildSearchDelegateTask({ searchQuery, searchPath, exact, language, allowTests }) {
|
|
357598
359495
|
return [
|
|
357599
359496
|
"You are a code-search subagent. Your job is to find ALL relevant code locations for the given query.",
|
|
@@ -357622,7 +359519,7 @@ function buildSearchDelegateTask({ searchQuery, searchPath, exact, language, all
|
|
|
357622
359519
|
"Deduplicate targets. Do NOT explain or answer - ONLY return the JSON targets."
|
|
357623
359520
|
].join("\n");
|
|
357624
359521
|
}
|
|
357625
|
-
var import_ai5, CODE_SEARCH_SCHEMA, searchTool, queryTool, extractTool, delegateTool, analyzeAllTool;
|
|
359522
|
+
var import_ai5, import_fs11, CODE_SEARCH_SCHEMA, searchTool, queryTool, extractTool, delegateTool, analyzeAllTool;
|
|
357626
359523
|
var init_vercel = __esm({
|
|
357627
359524
|
"src/tools/vercel.js"() {
|
|
357628
359525
|
"use strict";
|
|
@@ -357633,6 +359530,7 @@ var init_vercel = __esm({
|
|
|
357633
359530
|
init_delegate();
|
|
357634
359531
|
init_analyzeAll();
|
|
357635
359532
|
init_common2();
|
|
359533
|
+
import_fs11 = __nccwpck_require__(79896);
|
|
357636
359534
|
init_error_types();
|
|
357637
359535
|
init_hashline();
|
|
357638
359536
|
CODE_SEARCH_SCHEMA = {
|
|
@@ -357758,10 +359656,47 @@ var init_vercel = __esm({
|
|
|
357758
359656
|
}
|
|
357759
359657
|
return fallbackResult;
|
|
357760
359658
|
}
|
|
359659
|
+
const delegateBase = options.allowedFolders?.[0] || options.cwd || ".";
|
|
357761
359660
|
const resolutionBase = searchPaths[0] || options.cwd || ".";
|
|
357762
|
-
const resolvedTargets = targets.map((target) => resolveTargetPath(target,
|
|
359661
|
+
const resolvedTargets = targets.map((target) => resolveTargetPath(target, delegateBase));
|
|
359662
|
+
const validatedTargets = [];
|
|
359663
|
+
for (const target of resolvedTargets) {
|
|
359664
|
+
const { filePart, suffix } = splitTargetSuffix(target);
|
|
359665
|
+
if ((0, import_fs11.existsSync)(filePart)) {
|
|
359666
|
+
validatedTargets.push(target);
|
|
359667
|
+
continue;
|
|
359668
|
+
}
|
|
359669
|
+
let fixed = false;
|
|
359670
|
+
const parts = filePart.split("/").filter(Boolean);
|
|
359671
|
+
for (let i5 = 0; i5 < parts.length - 1; i5++) {
|
|
359672
|
+
if (parts[i5] === parts[i5 + 1]) {
|
|
359673
|
+
const candidate = "/" + [...parts.slice(0, i5), ...parts.slice(i5 + 1)].join("/");
|
|
359674
|
+
if ((0, import_fs11.existsSync)(candidate)) {
|
|
359675
|
+
validatedTargets.push(candidate + suffix);
|
|
359676
|
+
if (debug) console.error(`[search-delegate] Fixed doubled path segment: ${filePart} \u2192 ${candidate}`);
|
|
359677
|
+
fixed = true;
|
|
359678
|
+
break;
|
|
359679
|
+
}
|
|
359680
|
+
}
|
|
359681
|
+
}
|
|
359682
|
+
if (fixed) continue;
|
|
359683
|
+
for (const altBase of [resolutionBase, options.cwd].filter(Boolean)) {
|
|
359684
|
+
if (altBase === delegateBase) continue;
|
|
359685
|
+
const altResolved = resolveTargetPath(target, altBase);
|
|
359686
|
+
const { filePart: altFile } = splitTargetSuffix(altResolved);
|
|
359687
|
+
if ((0, import_fs11.existsSync)(altFile)) {
|
|
359688
|
+
validatedTargets.push(altResolved);
|
|
359689
|
+
if (debug) console.error(`[search-delegate] Resolved with alt base: ${filePart} \u2192 ${altFile}`);
|
|
359690
|
+
fixed = true;
|
|
359691
|
+
break;
|
|
359692
|
+
}
|
|
359693
|
+
}
|
|
359694
|
+
if (fixed) continue;
|
|
359695
|
+
if (debug) console.error(`[search-delegate] Warning: target may not exist: ${filePart}`);
|
|
359696
|
+
validatedTargets.push(target);
|
|
359697
|
+
}
|
|
357763
359698
|
const extractOptions = {
|
|
357764
|
-
files:
|
|
359699
|
+
files: validatedTargets,
|
|
357765
359700
|
cwd: resolutionBase,
|
|
357766
359701
|
allowTests: allow_tests ?? true
|
|
357767
359702
|
};
|
|
@@ -358314,7 +360249,7 @@ Example: <edit><file_path>${file_path}</file_path><symbol>${allMatches[0].qualif
|
|
|
358314
360249
|
Example: <extract><targets>${file_path}#${symbol15}</targets></extract>`;
|
|
358315
360250
|
}
|
|
358316
360251
|
}
|
|
358317
|
-
const content = await
|
|
360252
|
+
const content = await import_fs12.promises.readFile(resolvedPath2, "utf-8");
|
|
358318
360253
|
const lines = content.split("\n");
|
|
358319
360254
|
if (position) {
|
|
358320
360255
|
const refIndent = detectBaseIndent(symbolInfo.code);
|
|
@@ -358325,7 +360260,7 @@ Example: <extract><targets>${file_path}#${symbol15}</targets></extract>`;
|
|
|
358325
360260
|
} else {
|
|
358326
360261
|
lines.splice(symbolInfo.startLine - 1, 0, ...newLines, "");
|
|
358327
360262
|
}
|
|
358328
|
-
await
|
|
360263
|
+
await import_fs12.promises.writeFile(resolvedPath2, lines.join("\n"), "utf-8");
|
|
358329
360264
|
if (fileTracker) {
|
|
358330
360265
|
const updated = await findSymbol(resolvedPath2, symbol15, cwd || process.cwd());
|
|
358331
360266
|
if (updated) {
|
|
@@ -358343,7 +360278,7 @@ Example: <extract><targets>${file_path}#${symbol15}</targets></extract>`;
|
|
|
358343
360278
|
const reindented = reindent(new_string, originalIndent);
|
|
358344
360279
|
const newLines = reindented.split("\n");
|
|
358345
360280
|
lines.splice(symbolInfo.startLine - 1, symbolInfo.endLine - symbolInfo.startLine + 1, ...newLines);
|
|
358346
|
-
await
|
|
360281
|
+
await import_fs12.promises.writeFile(resolvedPath2, lines.join("\n"), "utf-8");
|
|
358347
360282
|
if (fileTracker) {
|
|
358348
360283
|
const updated = await findSymbol(resolvedPath2, symbol15, cwd || process.cwd());
|
|
358349
360284
|
if (updated) {
|
|
@@ -358398,7 +360333,7 @@ async function handleLineEdit({ resolvedPath: resolvedPath2, file_path, start_li
|
|
|
358398
360333
|
if (position !== void 0 && position !== null && position !== "before" && position !== "after") {
|
|
358399
360334
|
return 'Error editing file: Invalid position - must be "before" or "after". Use position="before" to insert before the line, or position="after" to insert after it.';
|
|
358400
360335
|
}
|
|
358401
|
-
const content = await
|
|
360336
|
+
const content = await import_fs12.promises.readFile(resolvedPath2, "utf-8");
|
|
358402
360337
|
const fileLines = content.split("\n");
|
|
358403
360338
|
if (startLine > fileLines.length) {
|
|
358404
360339
|
return `Error editing file: Line ${startLine} is beyond file length (${fileLines.length} lines). Use 'extract' to read the current file content.`;
|
|
@@ -358427,20 +360362,20 @@ async function handleLineEdit({ resolvedPath: resolvedPath2, file_path, start_li
|
|
|
358427
360362
|
const newLines = cleaned === "" ? [] : cleaned.split("\n");
|
|
358428
360363
|
if (position === "after") {
|
|
358429
360364
|
fileLines.splice(startLine, 0, ...newLines);
|
|
358430
|
-
await
|
|
360365
|
+
await import_fs12.promises.writeFile(resolvedPath2, fileLines.join("\n"), "utf-8");
|
|
358431
360366
|
if (fileTracker) await fileTracker.trackFileAfterWrite(resolvedPath2);
|
|
358432
360367
|
const action = `${newLines.length} line${newLines.length !== 1 ? "s" : ""} inserted after line ${startLine}`;
|
|
358433
360368
|
return buildLineEditResponse(file_path, startLine, startLine, newLines.length, fileLines, startLine, action, modifications);
|
|
358434
360369
|
} else if (position === "before") {
|
|
358435
360370
|
fileLines.splice(startLine - 1, 0, ...newLines);
|
|
358436
|
-
await
|
|
360371
|
+
await import_fs12.promises.writeFile(resolvedPath2, fileLines.join("\n"), "utf-8");
|
|
358437
360372
|
if (fileTracker) await fileTracker.trackFileAfterWrite(resolvedPath2);
|
|
358438
360373
|
const action = `${newLines.length} line${newLines.length !== 1 ? "s" : ""} inserted before line ${startLine}`;
|
|
358439
360374
|
return buildLineEditResponse(file_path, startLine, startLine, newLines.length, fileLines, startLine - 1, action, modifications);
|
|
358440
360375
|
} else {
|
|
358441
360376
|
const replacedCount = endLine - startLine + 1;
|
|
358442
360377
|
fileLines.splice(startLine - 1, replacedCount, ...newLines);
|
|
358443
|
-
await
|
|
360378
|
+
await import_fs12.promises.writeFile(resolvedPath2, fileLines.join("\n"), "utf-8");
|
|
358444
360379
|
if (fileTracker) await fileTracker.trackFileAfterWrite(resolvedPath2);
|
|
358445
360380
|
let action;
|
|
358446
360381
|
if (newLines.length === 0) {
|
|
@@ -358453,14 +360388,14 @@ async function handleLineEdit({ resolvedPath: resolvedPath2, file_path, start_li
|
|
|
358453
360388
|
return buildLineEditResponse(file_path, startLine, endLine, newLines.length, fileLines, startLine - 1, action, modifications);
|
|
358454
360389
|
}
|
|
358455
360390
|
}
|
|
358456
|
-
var import_ai6,
|
|
360391
|
+
var import_ai6, import_fs12, import_path16, import_fs13, editTool, createTool, multiEditTool, editSchema, createSchema, multiEditSchema, editDescription, createDescription, multiEditDescription, editToolDefinition, createToolDefinition, multiEditToolDefinition;
|
|
358457
360392
|
var init_edit = __esm({
|
|
358458
360393
|
"src/tools/edit.js"() {
|
|
358459
360394
|
"use strict";
|
|
358460
360395
|
import_ai6 = __nccwpck_require__(86619);
|
|
358461
|
-
import_fs11 = __nccwpck_require__(79896);
|
|
358462
|
-
import_path16 = __nccwpck_require__(16928);
|
|
358463
360396
|
import_fs12 = __nccwpck_require__(79896);
|
|
360397
|
+
import_path16 = __nccwpck_require__(16928);
|
|
360398
|
+
import_fs13 = __nccwpck_require__(79896);
|
|
358464
360399
|
init_path_validation();
|
|
358465
360400
|
init_fuzzyMatch();
|
|
358466
360401
|
init_symbolEdit();
|
|
@@ -358544,7 +360479,7 @@ Parameters:
|
|
|
358544
360479
|
const relativePath = toRelativePath(resolvedPath2, workspaceRoot);
|
|
358545
360480
|
return `Error editing file: Permission denied - ${relativePath} is outside allowed directories. Use a file path within the project workspace.`;
|
|
358546
360481
|
}
|
|
358547
|
-
if (!(0,
|
|
360482
|
+
if (!(0, import_fs13.existsSync)(resolvedPath2)) {
|
|
358548
360483
|
return `Error editing file: File not found - ${file_path}. Verify the path is correct and the file exists. Use 'search' to find files by name, or 'create' to make a new file.`;
|
|
358549
360484
|
}
|
|
358550
360485
|
if (options.fileTracker && !options.fileTracker.isFileSeen(resolvedPath2)) {
|
|
@@ -358574,7 +360509,7 @@ Example: <extract><targets>${displayPath}</targets></extract>`;
|
|
|
358574
360509
|
Example: <extract><targets>${displayPath}</targets></extract>`;
|
|
358575
360510
|
}
|
|
358576
360511
|
}
|
|
358577
|
-
const content = await
|
|
360512
|
+
const content = await import_fs12.promises.readFile(resolvedPath2, "utf-8");
|
|
358578
360513
|
let matchTarget = old_string;
|
|
358579
360514
|
let matchStrategy = "exact";
|
|
358580
360515
|
if (!content.includes(old_string)) {
|
|
@@ -358606,7 +360541,7 @@ Example: <extract><targets>${displayPath}</targets></extract>`;
|
|
|
358606
360541
|
if (newContent === content) {
|
|
358607
360542
|
return `Error editing file: No changes made - the replacement result is identical to the original. Verify that old_string and new_string are actually different. If fuzzy matching was used, the matched text may already equal new_string.`;
|
|
358608
360543
|
}
|
|
358609
|
-
await
|
|
360544
|
+
await import_fs12.promises.writeFile(resolvedPath2, newContent, "utf-8");
|
|
358610
360545
|
if (options.fileTracker) {
|
|
358611
360546
|
await options.fileTracker.trackFileAfterWrite(resolvedPath2);
|
|
358612
360547
|
options.fileTracker.recordTextEdit(resolvedPath2);
|
|
@@ -358677,13 +360612,13 @@ Important:
|
|
|
358677
360612
|
const relativePath = toRelativePath(resolvedPath2, workspaceRoot);
|
|
358678
360613
|
return `Error creating file: Permission denied - ${relativePath} is outside allowed directories. Use a file path within the project workspace.`;
|
|
358679
360614
|
}
|
|
358680
|
-
if ((0,
|
|
360615
|
+
if ((0, import_fs13.existsSync)(resolvedPath2) && !overwrite) {
|
|
358681
360616
|
return `Error creating file: File already exists - ${file_path}. Use overwrite: true to replace it.`;
|
|
358682
360617
|
}
|
|
358683
|
-
const existed = (0,
|
|
360618
|
+
const existed = (0, import_fs13.existsSync)(resolvedPath2);
|
|
358684
360619
|
const dir = (0, import_path16.dirname)(resolvedPath2);
|
|
358685
|
-
await
|
|
358686
|
-
await
|
|
360620
|
+
await import_fs12.promises.mkdir(dir, { recursive: true });
|
|
360621
|
+
await import_fs12.promises.writeFile(resolvedPath2, content, "utf-8");
|
|
358687
360622
|
if (options.fileTracker) await options.fileTracker.trackFileAfterWrite(resolvedPath2);
|
|
358688
360623
|
const action = existed && overwrite ? "overwrote" : "created";
|
|
358689
360624
|
const bytes = Buffer.byteLength(content, "utf-8");
|
|
@@ -359325,10 +361260,10 @@ async function listFilesByLevel(options) {
|
|
|
359325
361260
|
maxFiles = 100,
|
|
359326
361261
|
respectGitignore = true
|
|
359327
361262
|
} = options;
|
|
359328
|
-
if (!
|
|
361263
|
+
if (!import_fs14.default.existsSync(directory)) {
|
|
359329
361264
|
throw new Error(`Directory does not exist: ${directory}`);
|
|
359330
361265
|
}
|
|
359331
|
-
const gitDirExists =
|
|
361266
|
+
const gitDirExists = import_fs14.default.existsSync(import_path17.default.join(directory, ".git"));
|
|
359332
361267
|
if (gitDirExists && respectGitignore) {
|
|
359333
361268
|
try {
|
|
359334
361269
|
return await listFilesUsingGit(directory, maxFiles);
|
|
@@ -359359,7 +361294,7 @@ async function listFilesByLevelManually(directory, maxFiles, respectGitignore) {
|
|
|
359359
361294
|
while (queue.length > 0 && result.length < maxFiles) {
|
|
359360
361295
|
const { dir, level } = queue.shift();
|
|
359361
361296
|
try {
|
|
359362
|
-
const entries =
|
|
361297
|
+
const entries = import_fs14.default.readdirSync(dir, { withFileTypes: true });
|
|
359363
361298
|
const files = entries.filter((entry) => {
|
|
359364
361299
|
const fullPath = import_path17.default.join(dir, entry.name);
|
|
359365
361300
|
return getEntryTypeSync(entry, fullPath).isFile;
|
|
@@ -359390,11 +361325,11 @@ async function listFilesByLevelManually(directory, maxFiles, respectGitignore) {
|
|
|
359390
361325
|
}
|
|
359391
361326
|
function loadGitignorePatterns(directory) {
|
|
359392
361327
|
const gitignorePath = import_path17.default.join(directory, ".gitignore");
|
|
359393
|
-
if (!
|
|
361328
|
+
if (!import_fs14.default.existsSync(gitignorePath)) {
|
|
359394
361329
|
return [];
|
|
359395
361330
|
}
|
|
359396
361331
|
try {
|
|
359397
|
-
const content =
|
|
361332
|
+
const content = import_fs14.default.readFileSync(gitignorePath, "utf8");
|
|
359398
361333
|
return content.split("\n").map((line) => line.trim()).filter((line) => line && !line.startsWith("#"));
|
|
359399
361334
|
} catch (error2) {
|
|
359400
361335
|
console.error(`Warning: Could not read .gitignore: ${error2.message}`);
|
|
@@ -359412,11 +361347,11 @@ function shouldIgnore(filePath, ignorePatterns) {
|
|
|
359412
361347
|
}
|
|
359413
361348
|
return false;
|
|
359414
361349
|
}
|
|
359415
|
-
var
|
|
361350
|
+
var import_fs14, import_path17, import_util12, import_child_process10, execAsync3;
|
|
359416
361351
|
var init_file_lister = __esm({
|
|
359417
361352
|
"src/utils/file-lister.js"() {
|
|
359418
361353
|
"use strict";
|
|
359419
|
-
|
|
361354
|
+
import_fs14 = __toESM(__nccwpck_require__(79896), 1);
|
|
359420
361355
|
import_path17 = __toESM(__nccwpck_require__(16928), 1);
|
|
359421
361356
|
import_util12 = __nccwpck_require__(39023);
|
|
359422
361357
|
import_child_process10 = __nccwpck_require__(35317);
|
|
@@ -359435,11 +361370,11 @@ function initializeSimpleTelemetryFromOptions(options) {
|
|
|
359435
361370
|
});
|
|
359436
361371
|
return telemetry;
|
|
359437
361372
|
}
|
|
359438
|
-
var
|
|
361373
|
+
var import_fs15, import_path18, SimpleTelemetry, SimpleAppTracer;
|
|
359439
361374
|
var init_simpleTelemetry = __esm({
|
|
359440
361375
|
"src/agent/simpleTelemetry.js"() {
|
|
359441
361376
|
"use strict";
|
|
359442
|
-
|
|
361377
|
+
import_fs15 = __nccwpck_require__(79896);
|
|
359443
361378
|
import_path18 = __nccwpck_require__(16928);
|
|
359444
361379
|
SimpleTelemetry = class {
|
|
359445
361380
|
constructor(options = {}) {
|
|
@@ -359455,10 +361390,10 @@ var init_simpleTelemetry = __esm({
|
|
|
359455
361390
|
initializeFileExporter() {
|
|
359456
361391
|
try {
|
|
359457
361392
|
const dir = (0, import_path18.dirname)(this.filePath);
|
|
359458
|
-
if (!(0,
|
|
359459
|
-
(0,
|
|
361393
|
+
if (!(0, import_fs15.existsSync)(dir)) {
|
|
361394
|
+
(0, import_fs15.mkdirSync)(dir, { recursive: true });
|
|
359460
361395
|
}
|
|
359461
|
-
this.stream = (0,
|
|
361396
|
+
this.stream = (0, import_fs15.createWriteStream)(this.filePath, { flags: "a" });
|
|
359462
361397
|
this.stream.on("error", (error2) => {
|
|
359463
361398
|
console.error(`[SimpleTelemetry] Stream error: ${error2.message}`);
|
|
359464
361399
|
});
|
|
@@ -395235,7 +397170,7 @@ module.exports = /*#__PURE__*/JSON.parse('{"100":"Continue","101":"Switching Pro
|
|
|
395235
397170
|
/***/ ((module) => {
|
|
395236
397171
|
|
|
395237
397172
|
"use strict";
|
|
395238
|
-
module.exports = /*#__PURE__*/JSON.parse('{"name":"@probelabs/visor","version":"0.1.
|
|
397173
|
+
module.exports = /*#__PURE__*/JSON.parse('{"name":"@probelabs/visor","version":"0.1.42","main":"dist/index.js","bin":{"visor":"./dist/index.js"},"exports":{".":{"require":"./dist/index.js","import":"./dist/index.js"},"./sdk":{"types":"./dist/sdk/sdk.d.ts","import":"./dist/sdk/sdk.mjs","require":"./dist/sdk/sdk.js"},"./cli":{"require":"./dist/index.js"}},"files":["dist/","defaults/","action.yml","README.md","LICENSE"],"publishConfig":{"access":"public","registry":"https://registry.npmjs.org/"},"scripts":{"build:cli":"ncc build src/index.ts -o dist && cp -r defaults dist/ && cp -r output dist/ && cp -r docs dist/ && cp -r examples dist/ && cp -r src/debug-visualizer/ui dist/debug-visualizer/ && node scripts/inject-version.js && echo \'#!/usr/bin/env node\' | cat - dist/index.js > temp && mv temp dist/index.js && chmod +x dist/index.js","build:sdk":"tsup src/sdk.ts --dts --sourcemap --format esm,cjs --out-dir dist/sdk","build":"./scripts/build-oss.sh","build:ee":"npm run build:cli && npm run build:sdk","test":"jest && npm run test:yaml","test:unit":"jest","prepublishOnly":"npm run build","test:watch":"jest --watch","test:coverage":"jest --coverage","test:ee":"jest --testPathPatterns=\'tests/ee\' --testPathIgnorePatterns=\'/node_modules/\' --no-coverage","test:manual:bash":"RUN_MANUAL_TESTS=true jest tests/manual/bash-config-manual.test.ts","lint":"eslint src tests --ext .ts","lint:fix":"eslint src tests --ext .ts --fix","format":"prettier --write src tests","format:check":"prettier --check src tests","clean":"","clean:traces":"node scripts/clean-traces.js","prebuild":"npm run clean && node scripts/generate-config-schema.js","pretest":"npm run clean:traces && node scripts/generate-config-schema.js && npm run build:cli","pretest:unit":"npm run clean:traces && node scripts/generate-config-schema.js && npm run build:cli","test:with-build":"npm run build:cli && jest","test:yaml":"node dist/index.js test --progress compact","test:yaml:parallel":"node dist/index.js test --progress compact --max-parallel 4","prepare":"husky","pre-commit":"lint-staged","deploy:site":"cd site && npx wrangler pages deploy . --project-name=visor-site --commit-dirty=true","deploy:worker":"npx wrangler deploy","deploy":"npm run deploy:site && npm run deploy:worker","publish:ee":"./scripts/publish-ee.sh","release":"./scripts/release.sh","release:patch":"./scripts/release.sh patch","release:minor":"./scripts/release.sh minor","release:major":"./scripts/release.sh major","release:prerelease":"./scripts/release.sh prerelease","docs:validate":"node scripts/validate-readme-links.js","workshop:setup":"npm install -D reveal-md@6.1.2","workshop:serve":"cd workshop && reveal-md slides.md -w","workshop:export":"reveal-md workshop/slides.md --static workshop/build","workshop:pdf":"reveal-md workshop/slides.md --print workshop/Visor-Workshop.pdf --print-size letter","workshop:pdf:ci":"reveal-md workshop/slides.md --print workshop/Visor-Workshop.pdf --print-size letter --puppeteer-launch-args=\\"--no-sandbox --disable-dev-shm-usage\\"","workshop:pdf:a4":"reveal-md workshop/slides.md --print workshop/Visor-Workshop-A4.pdf --print-size A4","workshop:build":"npm run workshop:export && npm run workshop:pdf","simulate:issue":"TS_NODE_TRANSPILE_ONLY=1 ts-node scripts/simulate-gh-run.ts --event issues --action opened --debug","simulate:comment":"TS_NODE_TRANSPILE_ONLY=1 ts-node scripts/simulate-gh-run.ts --event issue_comment --action created --debug"},"keywords":["code-review","ai","github-action","cli","pr-review","visor"],"author":"Probe Labs","license":"MIT","description":"AI workflow engine for code review, assistants, and automation — orchestrate checks, MCP tools, and AI providers with YAML-driven pipelines","repository":{"type":"git","url":"git+https://github.com/probelabs/visor.git"},"bugs":{"url":"https://github.com/probelabs/visor/issues"},"homepage":"https://github.com/probelabs/visor#readme","dependencies":{"@actions/core":"^1.11.1","@apidevtools/swagger-parser":"^12.1.0","@modelcontextprotocol/sdk":"^1.25.3","@nyariv/sandboxjs":"github:probelabs/SandboxJS#f1c13b8eee98734a8ea024061eada4aa9a9ff2e9","@octokit/action":"^8.0.2","@octokit/auth-app":"^8.1.0","@octokit/core":"^7.0.3","@octokit/rest":"^22.0.0","@opentelemetry/api":"^1.9.0","@opentelemetry/core":"^1.30.1","@opentelemetry/exporter-trace-otlp-grpc":"^0.203.0","@opentelemetry/exporter-trace-otlp-http":"^0.203.0","@opentelemetry/instrumentation":"^0.203.0","@opentelemetry/resources":"^1.30.1","@opentelemetry/sdk-metrics":"^1.30.1","@opentelemetry/sdk-node":"^0.203.0","@opentelemetry/sdk-trace-base":"^1.30.1","@opentelemetry/semantic-conventions":"^1.30.1","@probelabs/probe":"^0.6.0-rc271","@types/commander":"^2.12.0","@types/uuid":"^10.0.0","acorn":"^8.16.0","acorn-walk":"^8.3.5","ajv":"^8.17.1","ajv-formats":"^3.0.1","better-sqlite3":"^11.0.0","blessed":"^0.1.81","cli-table3":"^0.6.5","commander":"^14.0.0","deepmerge":"^4.3.1","dotenv":"^17.2.3","ignore":"^7.0.5","js-yaml":"^4.1.0","jsonpath-plus":"^10.4.0","liquidjs":"^10.21.1","minimatch":"^10.2.2","node-cron":"^3.0.3","open":"^9.1.0","simple-git":"^3.28.0","uuid":"^11.1.0","ws":"^8.18.3"},"optionalDependencies":{"@anthropic/claude-code-sdk":"npm:null@*","@open-policy-agent/opa-wasm":"^1.10.0","knex":"^3.1.0","mysql2":"^3.11.0","pg":"^8.13.0","tedious":"^19.0.0"},"devDependencies":{"@eslint/js":"^9.34.0","@kie/act-js":"^2.6.2","@kie/mock-github":"^2.0.1","@swc/core":"^1.13.2","@swc/jest":"^0.2.37","@types/better-sqlite3":"^7.6.0","@types/blessed":"^0.1.27","@types/jest":"^30.0.0","@types/js-yaml":"^4.0.9","@types/node":"^24.3.0","@types/node-cron":"^3.0.11","@types/ws":"^8.18.1","@typescript-eslint/eslint-plugin":"^8.42.0","@typescript-eslint/parser":"^8.42.0","@vercel/ncc":"^0.38.4","eslint":"^9.34.0","eslint-config-prettier":"^10.1.8","eslint-plugin-prettier":"^5.5.4","husky":"^9.1.7","jest":"^30.1.3","lint-staged":"^16.1.6","prettier":"^3.6.2","reveal-md":"^6.1.2","ts-json-schema-generator":"^1.5.1","ts-node":"^10.9.2","tsup":"^8.5.0","typescript":"^5.9.2","wrangler":"^3.0.0"},"peerDependenciesMeta":{"@anthropic/claude-code-sdk":{"optional":true}},"directories":{"test":"tests"},"lint-staged":{"src/**/*.{ts,js}":["eslint --fix","prettier --write"],"tests/**/*.{ts,js}":["eslint --fix","prettier --write"],"*.{json,md,yml,yaml}":["prettier --write"]}}');
|
|
395239
397174
|
|
|
395240
397175
|
/***/ })
|
|
395241
397176
|
|