@microsoft/sentinel-cli 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +2728 -413
- package/package.json +6 -1
package/dist/index.js
CHANGED
|
@@ -44,7 +44,7 @@ var require_correlationService = __commonJS({
|
|
|
44
44
|
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
45
45
|
exports2.CorrelationService = void 0;
|
|
46
46
|
var crypto_1 = require("crypto");
|
|
47
|
-
var
|
|
47
|
+
var CorrelationService17 = class {
|
|
48
48
|
/**
|
|
49
49
|
* Creates a new correlation context with a unique ID for request tracking.
|
|
50
50
|
* @returns A UUID string to be used as a correlation ID in API requests and telemetry.
|
|
@@ -61,7 +61,7 @@ var require_correlationService = __commonJS({
|
|
|
61
61
|
return response?.headers?.["x-ms-correlation-request-id"];
|
|
62
62
|
}
|
|
63
63
|
};
|
|
64
|
-
exports2.CorrelationService =
|
|
64
|
+
exports2.CorrelationService = CorrelationService17;
|
|
65
65
|
}
|
|
66
66
|
});
|
|
67
67
|
|
|
@@ -159,6 +159,7 @@ var require_requestService = __commonJS({
|
|
|
159
159
|
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
160
160
|
exports2.RequestService = exports2.DEFAULT_RETRY_OPTIONS = void 0;
|
|
161
161
|
exports2.extractErrorInfo = extractErrorInfo;
|
|
162
|
+
var https_1 = __importDefault(require("https"));
|
|
162
163
|
var axios_1 = __importDefault(require("axios"));
|
|
163
164
|
var correlationService_1 = require_correlationService();
|
|
164
165
|
var httpConstants_1 = require_httpConstants();
|
|
@@ -185,13 +186,19 @@ var require_requestService = __commonJS({
|
|
|
185
186
|
baseDelayMs: 1e3,
|
|
186
187
|
maxDelayMs: 3e4,
|
|
187
188
|
retryableStatusCodes: Object.freeze([429, 500, 502, 503, 504]),
|
|
188
|
-
retryableErrors: Object.freeze(["ECONNRESET", "ETIMEDOUT", "ENOTFOUND", "ECONNABORTED"])
|
|
189
|
+
retryableErrors: Object.freeze(["ECONNRESET", "ETIMEDOUT", "ENOTFOUND", "ECONNABORTED"]),
|
|
190
|
+
retryableErrorMessages: Object.freeze([
|
|
191
|
+
"socket disconnected",
|
|
192
|
+
"socket hang up",
|
|
193
|
+
"client network socket disconnected"
|
|
194
|
+
])
|
|
189
195
|
});
|
|
190
|
-
var
|
|
196
|
+
var HTTPS_AGENT = new https_1.default.Agent({ keepAlive: false });
|
|
197
|
+
var RequestService5 = class {
|
|
191
198
|
telemetry;
|
|
192
199
|
headerBuilder;
|
|
193
|
-
constructor(
|
|
194
|
-
this.telemetry =
|
|
200
|
+
constructor(telemetry2, headerBuilder) {
|
|
201
|
+
this.telemetry = telemetry2;
|
|
195
202
|
this.headerBuilder = headerBuilder;
|
|
196
203
|
}
|
|
197
204
|
async get(options) {
|
|
@@ -273,7 +280,12 @@ var require_requestService = __commonJS({
|
|
|
273
280
|
mainSpan.addAttributes({ success: "true" });
|
|
274
281
|
return result;
|
|
275
282
|
} catch (error) {
|
|
276
|
-
|
|
283
|
+
const decision = this.shouldRetry(error, retryOptions ?? {});
|
|
284
|
+
if (attempt < clampedMaxRetries && decision.retry) {
|
|
285
|
+
mainSpan.addAttributes({
|
|
286
|
+
[`retry.${attempt}.reason`]: decision.reason ?? "",
|
|
287
|
+
[`retry.${attempt}.detail`]: decision.detail ?? ""
|
|
288
|
+
});
|
|
277
289
|
await this.sleep(this.calculateRetryDelay(attempt, clampedBaseDelayMs, clampedMaxDelayMs));
|
|
278
290
|
continue;
|
|
279
291
|
}
|
|
@@ -350,7 +362,8 @@ var require_requestService = __commonJS({
|
|
|
350
362
|
url,
|
|
351
363
|
method: options?.method?.toLowerCase() || "get",
|
|
352
364
|
headers: { ...options?.headers },
|
|
353
|
-
data: options?.body
|
|
365
|
+
data: options?.body,
|
|
366
|
+
httpsAgent: HTTPS_AGENT
|
|
354
367
|
};
|
|
355
368
|
if (timeoutMs !== void 0) {
|
|
356
369
|
axiosConfig.timeout = timeoutMs;
|
|
@@ -402,15 +415,24 @@ var require_requestService = __commonJS({
|
|
|
402
415
|
shouldRetry(error, retryOptions) {
|
|
403
416
|
const retryableStatusCodes = retryOptions.retryableStatusCodes ?? exports2.DEFAULT_RETRY_OPTIONS.retryableStatusCodes;
|
|
404
417
|
const retryableErrors = retryOptions.retryableErrors ?? exports2.DEFAULT_RETRY_OPTIONS.retryableErrors;
|
|
418
|
+
const retryableErrorMessages = retryOptions.retryableErrorMessages ?? exports2.DEFAULT_RETRY_OPTIONS.retryableErrorMessages;
|
|
405
419
|
const httpError = error;
|
|
406
420
|
if (typeof httpError?.statusCode === "number") {
|
|
407
|
-
return retryableStatusCodes.includes(httpError.statusCode);
|
|
421
|
+
return retryableStatusCodes.includes(httpError.statusCode) ? { retry: true, reason: "statusCode", detail: String(httpError.statusCode) } : { retry: false };
|
|
408
422
|
}
|
|
409
423
|
const codedError = error;
|
|
410
|
-
if (codedError?.code) {
|
|
411
|
-
return
|
|
424
|
+
if (codedError?.code && retryableErrors.includes(codedError.code)) {
|
|
425
|
+
return { retry: true, reason: "errorCode", detail: codedError.code };
|
|
412
426
|
}
|
|
413
|
-
|
|
427
|
+
const errorMessage = error?.message;
|
|
428
|
+
if (typeof errorMessage === "string" && errorMessage.length > 0) {
|
|
429
|
+
const lowerMessage = errorMessage.toLowerCase();
|
|
430
|
+
const matchedPattern = retryableErrorMessages.find((pattern) => lowerMessage.includes(pattern.toLowerCase()));
|
|
431
|
+
if (matchedPattern) {
|
|
432
|
+
return { retry: true, reason: "errorMessage", detail: matchedPattern };
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
return { retry: false };
|
|
414
436
|
}
|
|
415
437
|
/**
|
|
416
438
|
* Exponential backoff with 10% random jitter.
|
|
@@ -423,7 +445,7 @@ var require_requestService = __commonJS({
|
|
|
423
445
|
return Math.min(exponentialDelay + jitter, maxDelayMs);
|
|
424
446
|
}
|
|
425
447
|
sleep(ms) {
|
|
426
|
-
return new Promise((
|
|
448
|
+
return new Promise((resolve2) => setTimeout(resolve2, ms));
|
|
427
449
|
}
|
|
428
450
|
// -------------------------------------------------------------------------
|
|
429
451
|
// URL helpers
|
|
@@ -439,7 +461,7 @@ var require_requestService = __commonJS({
|
|
|
439
461
|
return urlObj.toString();
|
|
440
462
|
}
|
|
441
463
|
};
|
|
442
|
-
exports2.RequestService =
|
|
464
|
+
exports2.RequestService = RequestService5;
|
|
443
465
|
function getPathFromUrl(url) {
|
|
444
466
|
const urlObject = new URL(url);
|
|
445
467
|
return urlObject.pathname;
|
|
@@ -466,7 +488,7 @@ var require_client = __commonJS({
|
|
|
466
488
|
o[k2] = m[k];
|
|
467
489
|
}));
|
|
468
490
|
var __exportStar = exports2 && exports2.__exportStar || function(m, exports3) {
|
|
469
|
-
for (var
|
|
491
|
+
for (var p4 in m) if (p4 !== "default" && !Object.prototype.hasOwnProperty.call(exports3, p4)) __createBinding(exports3, m, p4);
|
|
470
492
|
};
|
|
471
493
|
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
472
494
|
__exportStar(require_requestService(), exports2);
|
|
@@ -484,7 +506,13 @@ var require_jobEventNames = __commonJS({
|
|
|
484
506
|
LOAD_JOBS: "JobsPanel.Load.Jobs",
|
|
485
507
|
CREATE_JOB: "Jobs.Create.Job",
|
|
486
508
|
GET_JOB: "Jobs.Get.Job",
|
|
487
|
-
DELETE_JOB: "Jobs.Delete.Job"
|
|
509
|
+
DELETE_JOB: "Jobs.Delete.Job",
|
|
510
|
+
DISABLE_JOB: "Jobs.Disable.Job",
|
|
511
|
+
ENABLE_JOB: "Jobs.Enable.Job",
|
|
512
|
+
LIST_JOB_RUNS: "Jobs.List.Runs",
|
|
513
|
+
GET_JOB_RUN: "Jobs.Get.Run",
|
|
514
|
+
START_JOB_RUN: "Jobs.Start.Run",
|
|
515
|
+
CANCEL_JOB_RUN: "Jobs.Cancel.Run"
|
|
488
516
|
};
|
|
489
517
|
}
|
|
490
518
|
});
|
|
@@ -522,7 +550,7 @@ var require_constants = __commonJS({
|
|
|
522
550
|
o[k2] = m[k];
|
|
523
551
|
}));
|
|
524
552
|
var __exportStar = exports2 && exports2.__exportStar || function(m, exports3) {
|
|
525
|
-
for (var
|
|
553
|
+
for (var p4 in m) if (p4 !== "default" && !Object.prototype.hasOwnProperty.call(exports3, p4)) __createBinding(exports3, m, p4);
|
|
526
554
|
};
|
|
527
555
|
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
528
556
|
exports2.FulfillmentStatus = exports2.PackageManifestIdValues = exports2.PackageManifestTypes = exports2.CANCEL_DEPLOYMENT_REQUEST_TYPE = exports2.NEW_DEPLOYMENT_REQUEST_TYPE = void 0;
|
|
@@ -557,26 +585,26 @@ var require_region = __commonJS({
|
|
|
557
585
|
init_cjs_shims();
|
|
558
586
|
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
559
587
|
exports2.Region = void 0;
|
|
560
|
-
var
|
|
561
|
-
(function(
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
})(
|
|
588
|
+
var Region14;
|
|
589
|
+
(function(Region15) {
|
|
590
|
+
Region15["NorwayEast"] = "norwayeast";
|
|
591
|
+
Region15["EastUS2EUAP"] = "eastus2euap";
|
|
592
|
+
Region15["AustraliaEast"] = "australiaeast";
|
|
593
|
+
Region15["CanadaCentral"] = "canadacentral";
|
|
594
|
+
Region15["CentralUS"] = "centralus";
|
|
595
|
+
Region15["EastUS"] = "eastus";
|
|
596
|
+
Region15["EastUS2"] = "eastus2";
|
|
597
|
+
Region15["FranceCentral"] = "francecentral";
|
|
598
|
+
Region15["JapanEast"] = "japaneast";
|
|
599
|
+
Region15["NorthEurope"] = "northeurope";
|
|
600
|
+
Region15["SouthCentralUS"] = "southcentralus";
|
|
601
|
+
Region15["UKSouth"] = "uksouth";
|
|
602
|
+
Region15["WestEurope"] = "westeurope";
|
|
603
|
+
Region15["WestUS"] = "westus";
|
|
604
|
+
Region15["WestUS2"] = "westus2";
|
|
605
|
+
Region15["Global"] = "global";
|
|
606
|
+
Region15["Dev"] = "dev";
|
|
607
|
+
})(Region14 || (exports2.Region = Region14 = {}));
|
|
580
608
|
}
|
|
581
609
|
});
|
|
582
610
|
|
|
@@ -587,10 +615,10 @@ var require_securityPlatformEnvironment = __commonJS({
|
|
|
587
615
|
init_cjs_shims();
|
|
588
616
|
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
589
617
|
exports2.SecurityPlatformEnvironment = void 0;
|
|
590
|
-
var
|
|
591
|
-
(function(
|
|
592
|
-
|
|
593
|
-
})(
|
|
618
|
+
var SecurityPlatformEnvironment21;
|
|
619
|
+
(function(SecurityPlatformEnvironment22) {
|
|
620
|
+
SecurityPlatformEnvironment22["Production"] = "production";
|
|
621
|
+
})(SecurityPlatformEnvironment21 || (exports2.SecurityPlatformEnvironment = SecurityPlatformEnvironment21 = {}));
|
|
594
622
|
}
|
|
595
623
|
});
|
|
596
624
|
|
|
@@ -611,6 +639,8 @@ var require_production = __commonJS({
|
|
|
611
639
|
gatewayAuthResourceUri: "73c2949e-da2d-457a-9607-fcc665198967/.default",
|
|
612
640
|
gatewayEndpoint: "https://api.securityplatform.microsoft.com/",
|
|
613
641
|
aadClientId: DeviceCodeApplicationId,
|
|
642
|
+
armEndpoint: "https://management.azure.com",
|
|
643
|
+
armScope: "https://management.azure.com/.default",
|
|
614
644
|
regions: {
|
|
615
645
|
[region_1.Region.NorwayEast]: buildRegionConfig(region_1.Region.NorwayEast),
|
|
616
646
|
[region_1.Region.EastUS2EUAP]: buildRegionConfig(region_1.Region.EastUS2EUAP),
|
|
@@ -663,7 +693,7 @@ var require_configs = __commonJS({
|
|
|
663
693
|
o[k2] = m[k];
|
|
664
694
|
}));
|
|
665
695
|
var __exportStar = exports2 && exports2.__exportStar || function(m, exports3) {
|
|
666
|
-
for (var
|
|
696
|
+
for (var p4 in m) if (p4 !== "default" && !Object.prototype.hasOwnProperty.call(exports3, p4)) __createBinding(exports3, m, p4);
|
|
667
697
|
};
|
|
668
698
|
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
669
699
|
__exportStar(require_production(), exports2);
|
|
@@ -692,9 +722,9 @@ var require_api_env = __commonJS({
|
|
|
692
722
|
"use strict";
|
|
693
723
|
init_cjs_shims();
|
|
694
724
|
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
695
|
-
exports2.getApiEnv =
|
|
725
|
+
exports2.getApiEnv = getApiEnv21;
|
|
696
726
|
var helper_1 = require_helper();
|
|
697
|
-
function
|
|
727
|
+
function getApiEnv21(env) {
|
|
698
728
|
return (0, helper_1.getEnvironmentConfig)(env);
|
|
699
729
|
}
|
|
700
730
|
}
|
|
@@ -728,7 +758,7 @@ var require_environments = __commonJS({
|
|
|
728
758
|
o[k2] = m[k];
|
|
729
759
|
}));
|
|
730
760
|
var __exportStar = exports2 && exports2.__exportStar || function(m, exports3) {
|
|
731
|
-
for (var
|
|
761
|
+
for (var p4 in m) if (p4 !== "default" && !Object.prototype.hasOwnProperty.call(exports3, p4)) __createBinding(exports3, m, p4);
|
|
732
762
|
};
|
|
733
763
|
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
734
764
|
__exportStar(require_configs(), exports2);
|
|
@@ -788,11 +818,11 @@ var require_common = __commonJS({
|
|
|
788
818
|
init_cjs_shims();
|
|
789
819
|
var __awaiter = exports2 && exports2.__awaiter || function(thisArg, _arguments, P, generator) {
|
|
790
820
|
function adopt(value) {
|
|
791
|
-
return value instanceof P ? value : new P(function(
|
|
792
|
-
|
|
821
|
+
return value instanceof P ? value : new P(function(resolve2) {
|
|
822
|
+
resolve2(value);
|
|
793
823
|
});
|
|
794
824
|
}
|
|
795
|
-
return new (P || (P = Promise))(function(
|
|
825
|
+
return new (P || (P = Promise))(function(resolve2, reject) {
|
|
796
826
|
function fulfilled(value) {
|
|
797
827
|
try {
|
|
798
828
|
step(generator.next(value));
|
|
@@ -808,7 +838,7 @@ var require_common = __commonJS({
|
|
|
808
838
|
}
|
|
809
839
|
}
|
|
810
840
|
function step(result) {
|
|
811
|
-
result.done ?
|
|
841
|
+
result.done ? resolve2(result.value) : adopt(result.value).then(fulfilled, rejected);
|
|
812
842
|
}
|
|
813
843
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
814
844
|
});
|
|
@@ -907,11 +937,11 @@ var require_api = __commonJS({
|
|
|
907
937
|
init_cjs_shims();
|
|
908
938
|
var __awaiter = exports2 && exports2.__awaiter || function(thisArg, _arguments, P, generator) {
|
|
909
939
|
function adopt(value) {
|
|
910
|
-
return value instanceof P ? value : new P(function(
|
|
911
|
-
|
|
940
|
+
return value instanceof P ? value : new P(function(resolve2) {
|
|
941
|
+
resolve2(value);
|
|
912
942
|
});
|
|
913
943
|
}
|
|
914
|
-
return new (P || (P = Promise))(function(
|
|
944
|
+
return new (P || (P = Promise))(function(resolve2, reject) {
|
|
915
945
|
function fulfilled(value) {
|
|
916
946
|
try {
|
|
917
947
|
step(generator.next(value));
|
|
@@ -927,7 +957,7 @@ var require_api = __commonJS({
|
|
|
927
957
|
}
|
|
928
958
|
}
|
|
929
959
|
function step(result) {
|
|
930
|
-
result.done ?
|
|
960
|
+
result.done ? resolve2(result.value) : adopt(result.value).then(fulfilled, rejected);
|
|
931
961
|
}
|
|
932
962
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
933
963
|
});
|
|
@@ -2372,7 +2402,7 @@ var require_dist = __commonJS({
|
|
|
2372
2402
|
o[k2] = m[k];
|
|
2373
2403
|
}));
|
|
2374
2404
|
var __exportStar = exports2 && exports2.__exportStar || function(m, exports3) {
|
|
2375
|
-
for (var
|
|
2405
|
+
for (var p4 in m) if (p4 !== "default" && !Object.prototype.hasOwnProperty.call(exports3, p4)) __createBinding(exports3, m, p4);
|
|
2376
2406
|
};
|
|
2377
2407
|
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
2378
2408
|
__exportStar(require_api(), exports2);
|
|
@@ -2659,7 +2689,7 @@ var require_factories = __commonJS({
|
|
|
2659
2689
|
o[k2] = m[k];
|
|
2660
2690
|
}));
|
|
2661
2691
|
var __exportStar = exports2 && exports2.__exportStar || function(m, exports3) {
|
|
2662
|
-
for (var
|
|
2692
|
+
for (var p4 in m) if (p4 !== "default" && !Object.prototype.hasOwnProperty.call(exports3, p4)) __createBinding(exports3, m, p4);
|
|
2663
2693
|
};
|
|
2664
2694
|
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
2665
2695
|
__exportStar(require_jobPayloadFactory(), exports2);
|
|
@@ -2766,7 +2796,7 @@ var require_jobs = __commonJS({
|
|
|
2766
2796
|
o[k2] = m[k];
|
|
2767
2797
|
}));
|
|
2768
2798
|
var __exportStar = exports2 && exports2.__exportStar || function(m, exports3) {
|
|
2769
|
-
for (var
|
|
2799
|
+
for (var p4 in m) if (p4 !== "default" && !Object.prototype.hasOwnProperty.call(exports3, p4)) __createBinding(exports3, m, p4);
|
|
2770
2800
|
};
|
|
2771
2801
|
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
2772
2802
|
__exportStar(require_analyticsJobDefinition(), exports2);
|
|
@@ -2808,7 +2838,7 @@ var require_lake = __commonJS({
|
|
|
2808
2838
|
o[k2] = m[k];
|
|
2809
2839
|
}));
|
|
2810
2840
|
var __exportStar = exports2 && exports2.__exportStar || function(m, exports3) {
|
|
2811
|
-
for (var
|
|
2841
|
+
for (var p4 in m) if (p4 !== "default" && !Object.prototype.hasOwnProperty.call(exports3, p4)) __createBinding(exports3, m, p4);
|
|
2812
2842
|
};
|
|
2813
2843
|
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
2814
2844
|
__exportStar(require_database(), exports2);
|
|
@@ -2891,7 +2921,7 @@ var require_models = __commonJS({
|
|
|
2891
2921
|
o[k2] = m[k];
|
|
2892
2922
|
}));
|
|
2893
2923
|
var __exportStar = exports2 && exports2.__exportStar || function(m, exports3) {
|
|
2894
|
-
for (var
|
|
2924
|
+
for (var p4 in m) if (p4 !== "default" && !Object.prototype.hasOwnProperty.call(exports3, p4)) __createBinding(exports3, m, p4);
|
|
2895
2925
|
};
|
|
2896
2926
|
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
2897
2927
|
__exportStar(require_jobs(), exports2);
|
|
@@ -2902,6 +2932,133 @@ var require_models = __commonJS({
|
|
|
2902
2932
|
}
|
|
2903
2933
|
});
|
|
2904
2934
|
|
|
2935
|
+
// ../../packages/common/dist/src/services/tenant/types.js
|
|
2936
|
+
var require_types = __commonJS({
|
|
2937
|
+
"../../packages/common/dist/src/services/tenant/types.js"(exports2) {
|
|
2938
|
+
"use strict";
|
|
2939
|
+
init_cjs_shims();
|
|
2940
|
+
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
2941
|
+
}
|
|
2942
|
+
});
|
|
2943
|
+
|
|
2944
|
+
// ../../packages/common/dist/src/services/tenant/tenantApiClient.js
|
|
2945
|
+
var require_tenantApiClient = __commonJS({
|
|
2946
|
+
"../../packages/common/dist/src/services/tenant/tenantApiClient.js"(exports2) {
|
|
2947
|
+
"use strict";
|
|
2948
|
+
init_cjs_shims();
|
|
2949
|
+
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
2950
|
+
exports2.TenantApiClient = void 0;
|
|
2951
|
+
var DEFAULT_ARM_ENDPOINT = "https://management.azure.com";
|
|
2952
|
+
var ARM_API_VERSION = "2020-01-01";
|
|
2953
|
+
var MAX_PAGES = 20;
|
|
2954
|
+
var TENANT_LIST_EVENT = "TenantApiClient.fetchAllTenants";
|
|
2955
|
+
var TenantApiClient2 = class {
|
|
2956
|
+
requestService;
|
|
2957
|
+
tenantsUrl;
|
|
2958
|
+
trustedOrigin;
|
|
2959
|
+
constructor(options) {
|
|
2960
|
+
this.requestService = options.requestService;
|
|
2961
|
+
const armEndpoint = options.armEndpoint ?? DEFAULT_ARM_ENDPOINT;
|
|
2962
|
+
this.tenantsUrl = new URL("/tenants", armEndpoint).toString();
|
|
2963
|
+
this.trustedOrigin = new URL(armEndpoint).origin;
|
|
2964
|
+
}
|
|
2965
|
+
/**
|
|
2966
|
+
* Fetches all tenants accessible to the authenticated user from ARM,
|
|
2967
|
+
* following pagination links until exhausted or the page limit is reached.
|
|
2968
|
+
*
|
|
2969
|
+
* @param accessToken - A valid ARM bearer access token.
|
|
2970
|
+
* @returns An array of {@link ArmTenant} objects.
|
|
2971
|
+
*/
|
|
2972
|
+
async fetchAllTenants(accessToken) {
|
|
2973
|
+
const allTenants = [];
|
|
2974
|
+
let nextUrl = this.tenantsUrl;
|
|
2975
|
+
let params = { "api-version": ARM_API_VERSION };
|
|
2976
|
+
let pageCount = 0;
|
|
2977
|
+
while (nextUrl && pageCount < MAX_PAGES) {
|
|
2978
|
+
pageCount++;
|
|
2979
|
+
const page = await this.requestService.get({
|
|
2980
|
+
url: nextUrl,
|
|
2981
|
+
eventName: TENANT_LIST_EVENT,
|
|
2982
|
+
params,
|
|
2983
|
+
token: accessToken
|
|
2984
|
+
});
|
|
2985
|
+
if (Array.isArray(page.value)) {
|
|
2986
|
+
allTenants.push(...page.value.map(mapArmTenant));
|
|
2987
|
+
}
|
|
2988
|
+
if (page.nextLink) {
|
|
2989
|
+
this.validateNextLink(page.nextLink);
|
|
2990
|
+
nextUrl = page.nextLink;
|
|
2991
|
+
params = {};
|
|
2992
|
+
} else {
|
|
2993
|
+
nextUrl = void 0;
|
|
2994
|
+
}
|
|
2995
|
+
}
|
|
2996
|
+
if (nextUrl) {
|
|
2997
|
+
throw new Error(`Tenant list is incomplete: maximum page limit of ${MAX_PAGES} reached.`);
|
|
2998
|
+
}
|
|
2999
|
+
return allTenants;
|
|
3000
|
+
}
|
|
3001
|
+
/**
|
|
3002
|
+
* Validates that a pagination URL returned by the ARM API originates from
|
|
3003
|
+
* the trusted ARM endpoint and targets the /tenants path, preventing SSRF
|
|
3004
|
+
* and bearer-token exfiltration to other origins or endpoints.
|
|
3005
|
+
*/
|
|
3006
|
+
validateNextLink(nextLink) {
|
|
3007
|
+
let parsedUrl;
|
|
3008
|
+
try {
|
|
3009
|
+
parsedUrl = new URL(nextLink);
|
|
3010
|
+
} catch {
|
|
3011
|
+
throw new Error(`Invalid nextLink URL: ${nextLink}`);
|
|
3012
|
+
}
|
|
3013
|
+
if (parsedUrl.origin !== this.trustedOrigin) {
|
|
3014
|
+
throw new Error(`Untrusted nextLink origin: expected ${this.trustedOrigin}, got ${parsedUrl.origin}`);
|
|
3015
|
+
}
|
|
3016
|
+
if (parsedUrl.pathname !== "/tenants" && !parsedUrl.pathname.startsWith("/tenants/")) {
|
|
3017
|
+
throw new Error(`Untrusted nextLink path detected: ${parsedUrl.pathname}`);
|
|
3018
|
+
}
|
|
3019
|
+
}
|
|
3020
|
+
};
|
|
3021
|
+
exports2.TenantApiClient = TenantApiClient2;
|
|
3022
|
+
function mapArmTenant(raw) {
|
|
3023
|
+
return {
|
|
3024
|
+
id: raw.id,
|
|
3025
|
+
tenantId: raw.tenantId,
|
|
3026
|
+
displayName: raw.displayName ?? "Unknown Tenant",
|
|
3027
|
+
defaultDomain: raw.defaultDomain ?? "",
|
|
3028
|
+
tenantType: raw.tenantType ?? "AAD",
|
|
3029
|
+
tenantCategory: raw.tenantCategory
|
|
3030
|
+
};
|
|
3031
|
+
}
|
|
3032
|
+
}
|
|
3033
|
+
});
|
|
3034
|
+
|
|
3035
|
+
// ../../packages/common/dist/src/services/tenant/index.js
|
|
3036
|
+
var require_tenant = __commonJS({
|
|
3037
|
+
"../../packages/common/dist/src/services/tenant/index.js"(exports2) {
|
|
3038
|
+
"use strict";
|
|
3039
|
+
init_cjs_shims();
|
|
3040
|
+
var __createBinding = exports2 && exports2.__createBinding || (Object.create ? (function(o, m, k, k2) {
|
|
3041
|
+
if (k2 === void 0) k2 = k;
|
|
3042
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
3043
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
3044
|
+
desc = { enumerable: true, get: function() {
|
|
3045
|
+
return m[k];
|
|
3046
|
+
} };
|
|
3047
|
+
}
|
|
3048
|
+
Object.defineProperty(o, k2, desc);
|
|
3049
|
+
}) : (function(o, m, k, k2) {
|
|
3050
|
+
if (k2 === void 0) k2 = k;
|
|
3051
|
+
o[k2] = m[k];
|
|
3052
|
+
}));
|
|
3053
|
+
var __exportStar = exports2 && exports2.__exportStar || function(m, exports3) {
|
|
3054
|
+
for (var p4 in m) if (p4 !== "default" && !Object.prototype.hasOwnProperty.call(exports3, p4)) __createBinding(exports3, m, p4);
|
|
3055
|
+
};
|
|
3056
|
+
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
3057
|
+
__exportStar(require_types(), exports2);
|
|
3058
|
+
__exportStar(require_tenantApiClient(), exports2);
|
|
3059
|
+
}
|
|
3060
|
+
});
|
|
3061
|
+
|
|
2905
3062
|
// ../../packages/common/dist/src/services/jobs/jobApiClient.js
|
|
2906
3063
|
var require_jobApiClient = __commonJS({
|
|
2907
3064
|
"../../packages/common/dist/src/services/jobs/jobApiClient.js"(exports2) {
|
|
@@ -2965,6 +3122,111 @@ var require_jobApiClient = __commonJS({
|
|
|
2965
3122
|
requestId
|
|
2966
3123
|
});
|
|
2967
3124
|
}
|
|
3125
|
+
async disableJob(jobName, token, requestId) {
|
|
3126
|
+
if (!jobName?.trim()) {
|
|
3127
|
+
throw new Error("Job name is required");
|
|
3128
|
+
}
|
|
3129
|
+
const current = await this.getJob(jobName, token, requestId);
|
|
3130
|
+
const updated = { ...current, jobDefinition: { ...current.jobDefinition, isDisabled: true } };
|
|
3131
|
+
return this.requestService.put({
|
|
3132
|
+
url: this.jobUrl(jobName),
|
|
3133
|
+
params: { "api-version": API_VERSION },
|
|
3134
|
+
eventName: jobEventNames_1.JobApiEvents.DISABLE_JOB,
|
|
3135
|
+
body: JSON.stringify(updated),
|
|
3136
|
+
token,
|
|
3137
|
+
requestId
|
|
3138
|
+
});
|
|
3139
|
+
}
|
|
3140
|
+
async enableJob(jobName, token, requestId) {
|
|
3141
|
+
if (!jobName?.trim()) {
|
|
3142
|
+
throw new Error("Job name is required");
|
|
3143
|
+
}
|
|
3144
|
+
const current = await this.getJob(jobName, token, requestId);
|
|
3145
|
+
const updated = { ...current, jobDefinition: { ...current.jobDefinition, isDisabled: false } };
|
|
3146
|
+
return this.requestService.put({
|
|
3147
|
+
url: this.jobUrl(jobName),
|
|
3148
|
+
params: { "api-version": API_VERSION },
|
|
3149
|
+
eventName: jobEventNames_1.JobApiEvents.ENABLE_JOB,
|
|
3150
|
+
body: JSON.stringify(updated),
|
|
3151
|
+
token,
|
|
3152
|
+
requestId
|
|
3153
|
+
});
|
|
3154
|
+
}
|
|
3155
|
+
jobRunsUrl(jobName) {
|
|
3156
|
+
return `${this.jobUrl(jobName)}/runs`;
|
|
3157
|
+
}
|
|
3158
|
+
jobRunUrl(jobName, runId) {
|
|
3159
|
+
return `${this.jobRunsUrl(jobName)}/${encodeURIComponent(runId)}`;
|
|
3160
|
+
}
|
|
3161
|
+
async listJobRuns(jobName, token, requestId) {
|
|
3162
|
+
if (!jobName?.trim()) {
|
|
3163
|
+
throw new Error("Job name is required");
|
|
3164
|
+
}
|
|
3165
|
+
const runs = [];
|
|
3166
|
+
let continuationToken = void 0;
|
|
3167
|
+
do {
|
|
3168
|
+
const params = { "api-version": API_VERSION };
|
|
3169
|
+
if (continuationToken !== null && continuationToken !== void 0) {
|
|
3170
|
+
params.continuationToken = continuationToken;
|
|
3171
|
+
}
|
|
3172
|
+
const data = await this.requestService.get({
|
|
3173
|
+
url: this.jobRunsUrl(jobName),
|
|
3174
|
+
params,
|
|
3175
|
+
eventName: jobEventNames_1.JobApiEvents.LIST_JOB_RUNS,
|
|
3176
|
+
token,
|
|
3177
|
+
requestId
|
|
3178
|
+
});
|
|
3179
|
+
if (data?.results) {
|
|
3180
|
+
runs.push(...data.results);
|
|
3181
|
+
}
|
|
3182
|
+
continuationToken = data?.continuationToken ?? null;
|
|
3183
|
+
} while (continuationToken !== null);
|
|
3184
|
+
return runs;
|
|
3185
|
+
}
|
|
3186
|
+
async getJobRun(jobName, runId, token, requestId) {
|
|
3187
|
+
if (!jobName?.trim()) {
|
|
3188
|
+
throw new Error("Job name is required");
|
|
3189
|
+
}
|
|
3190
|
+
if (!runId?.trim()) {
|
|
3191
|
+
throw new Error("Run ID is required");
|
|
3192
|
+
}
|
|
3193
|
+
return this.requestService.get({
|
|
3194
|
+
url: this.jobRunUrl(jobName, runId),
|
|
3195
|
+
params: { "api-version": API_VERSION },
|
|
3196
|
+
eventName: jobEventNames_1.JobApiEvents.GET_JOB_RUN,
|
|
3197
|
+
token,
|
|
3198
|
+
requestId
|
|
3199
|
+
});
|
|
3200
|
+
}
|
|
3201
|
+
async startJobRun(jobName, token, requestId) {
|
|
3202
|
+
if (!jobName?.trim()) {
|
|
3203
|
+
throw new Error("Job name is required");
|
|
3204
|
+
}
|
|
3205
|
+
return this.requestService.post({
|
|
3206
|
+
url: `${this.jobUrl(jobName)}:runNow`,
|
|
3207
|
+
params: { "api-version": API_VERSION },
|
|
3208
|
+
eventName: jobEventNames_1.JobApiEvents.START_JOB_RUN,
|
|
3209
|
+
body: JSON.stringify({}),
|
|
3210
|
+
token,
|
|
3211
|
+
requestId
|
|
3212
|
+
});
|
|
3213
|
+
}
|
|
3214
|
+
async cancelJobRun(jobName, runId, token, requestId) {
|
|
3215
|
+
if (!jobName?.trim()) {
|
|
3216
|
+
throw new Error("Job name is required");
|
|
3217
|
+
}
|
|
3218
|
+
if (!runId?.trim()) {
|
|
3219
|
+
throw new Error("Run ID is required");
|
|
3220
|
+
}
|
|
3221
|
+
return this.requestService.post({
|
|
3222
|
+
url: `${this.jobRunUrl(jobName, runId)}:cancel`,
|
|
3223
|
+
params: { "api-version": API_VERSION },
|
|
3224
|
+
eventName: jobEventNames_1.JobApiEvents.CANCEL_JOB_RUN,
|
|
3225
|
+
body: JSON.stringify({}),
|
|
3226
|
+
token,
|
|
3227
|
+
requestId
|
|
3228
|
+
});
|
|
3229
|
+
}
|
|
2968
3230
|
async listJobs(token, requestId) {
|
|
2969
3231
|
const jobs = [];
|
|
2970
3232
|
let continuationToken = void 0;
|
|
@@ -3221,7 +3483,7 @@ var require_common2 = __commonJS({
|
|
|
3221
3483
|
function isNothing(subject) {
|
|
3222
3484
|
return typeof subject === "undefined" || subject === null;
|
|
3223
3485
|
}
|
|
3224
|
-
function
|
|
3486
|
+
function isObject2(subject) {
|
|
3225
3487
|
return typeof subject === "object" && subject !== null;
|
|
3226
3488
|
}
|
|
3227
3489
|
function toArray(sequence) {
|
|
@@ -3251,7 +3513,7 @@ var require_common2 = __commonJS({
|
|
|
3251
3513
|
return number === 0 && Number.NEGATIVE_INFINITY === 1 / number;
|
|
3252
3514
|
}
|
|
3253
3515
|
module2.exports.isNothing = isNothing;
|
|
3254
|
-
module2.exports.isObject =
|
|
3516
|
+
module2.exports.isObject = isObject2;
|
|
3255
3517
|
module2.exports.toArray = toArray;
|
|
3256
3518
|
module2.exports.repeat = repeat;
|
|
3257
3519
|
module2.exports.isNegativeZero = isNegativeZero;
|
|
@@ -6079,10 +6341,10 @@ var require_notebookUtils = __commonJS({
|
|
|
6079
6341
|
exports2.getJupyterNotebook = getJupyterNotebook;
|
|
6080
6342
|
exports2.removeCellOutput = removeCellOutput;
|
|
6081
6343
|
exports2.notebookToBase64 = notebookToBase64;
|
|
6082
|
-
var
|
|
6344
|
+
var fs7 = __importStar(require("fs/promises"));
|
|
6083
6345
|
async function getJupyterNotebook(filePath) {
|
|
6084
6346
|
try {
|
|
6085
|
-
const notebookFile = await
|
|
6347
|
+
const notebookFile = await fs7.readFile(filePath, "utf-8");
|
|
6086
6348
|
return JSON.parse(notebookFile);
|
|
6087
6349
|
} catch (error) {
|
|
6088
6350
|
throw new Error(`Failed to read or parse the notebook file: ${error}`);
|
|
@@ -6160,18 +6422,18 @@ var require_secureExchangeManifestUtils = __commonJS({
|
|
|
6160
6422
|
})();
|
|
6161
6423
|
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
6162
6424
|
exports2.updateSecureExchangeManifest = updateSecureExchangeManifest;
|
|
6163
|
-
var
|
|
6425
|
+
var fs7 = __importStar(require("fs-extra"));
|
|
6164
6426
|
var yaml = __importStar(require("yaml"));
|
|
6165
6427
|
async function updateSecureExchangeManifest(manifestEntries, secureExchangeManifestPath) {
|
|
6166
6428
|
if (manifestEntries.length > 0) {
|
|
6167
|
-
const existingYaml = await
|
|
6429
|
+
const existingYaml = await fs7.readFile(secureExchangeManifestPath, "utf-8");
|
|
6168
6430
|
const parsedYaml = existingYaml ? yaml.parse(existingYaml) || [] : [];
|
|
6169
6431
|
const newEntries = manifestEntries.filter((newEntry) => !parsedYaml.some((existingEntry) => existingEntry.id === newEntry.id && existingEntry.type === newEntry.type));
|
|
6170
6432
|
if (newEntries.length === 0) {
|
|
6171
6433
|
return;
|
|
6172
6434
|
}
|
|
6173
6435
|
const updatedYaml = [...parsedYaml, ...newEntries];
|
|
6174
|
-
await
|
|
6436
|
+
await fs7.writeFile(secureExchangeManifestPath, yaml.stringify(updatedYaml), "utf-8");
|
|
6175
6437
|
}
|
|
6176
6438
|
}
|
|
6177
6439
|
}
|
|
@@ -6787,8 +7049,8 @@ var require_zipDirectory = __commonJS({
|
|
|
6787
7049
|
try {
|
|
6788
7050
|
const output = fs_1.default.createWriteStream(outPath);
|
|
6789
7051
|
const archive = (0, archiver_1.default)("zip", { zlib: { level: 9 } });
|
|
6790
|
-
return new Promise((
|
|
6791
|
-
output.on("close",
|
|
7052
|
+
return new Promise((resolve2, reject) => {
|
|
7053
|
+
output.on("close", resolve2);
|
|
6792
7054
|
output.on("error", reject);
|
|
6793
7055
|
archive.on("error", reject);
|
|
6794
7056
|
archive.pipe(output);
|
|
@@ -6865,8 +7127,8 @@ var require_manifestProcessorService = __commonJS({
|
|
|
6865
7127
|
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
6866
7128
|
exports2.ManifestProcessorService = void 0;
|
|
6867
7129
|
var crypto_1 = require("crypto");
|
|
6868
|
-
var
|
|
6869
|
-
var
|
|
7130
|
+
var fs7 = __importStar(require("fs-extra"));
|
|
7131
|
+
var path8 = __importStar(require("path"));
|
|
6870
7132
|
var yaml = __importStar(require("yaml"));
|
|
6871
7133
|
var constants_1 = require_constants();
|
|
6872
7134
|
var buildScheduledJobArtifacts_1 = require_buildScheduledJobArtifacts();
|
|
@@ -6889,17 +7151,17 @@ var require_manifestProcessorService = __commonJS({
|
|
|
6889
7151
|
};
|
|
6890
7152
|
}
|
|
6891
7153
|
async buildZipPackage(manifestPath) {
|
|
6892
|
-
const manifestDir =
|
|
6893
|
-
const tempPackageDir =
|
|
7154
|
+
const manifestDir = path8.dirname(path8.resolve(manifestPath));
|
|
7155
|
+
const tempPackageDir = path8.join(manifestDir, ".packaging-temp");
|
|
6894
7156
|
try {
|
|
6895
|
-
await
|
|
6896
|
-
await
|
|
7157
|
+
await fs7.rm(tempPackageDir, { recursive: true, force: true });
|
|
7158
|
+
await fs7.mkdir(tempPackageDir, { recursive: true });
|
|
6897
7159
|
const manifest = await (0, manifestParser_1.parseManifest)(manifestPath);
|
|
6898
|
-
const discoveredFiles = await (0, discoverFiles_1.discoverFiles)(manifest.includePaths,
|
|
7160
|
+
const discoveredFiles = await (0, discoverFiles_1.discoverFiles)(manifest.includePaths, path8.dirname(path8.resolve(manifestPath)));
|
|
6899
7161
|
console.log("Discovered files:", JSON.stringify(discoveredFiles, null, 2));
|
|
6900
7162
|
(0, manifestValidator_1.validateSingleScAgent)(discoveredFiles);
|
|
6901
|
-
const secureExchangeManifestPath =
|
|
6902
|
-
await
|
|
7163
|
+
const secureExchangeManifestPath = path8.join(tempPackageDir, "PackageManifest.yaml");
|
|
7164
|
+
await fs7.writeFile(secureExchangeManifestPath, "");
|
|
6903
7165
|
console.log("Empty PackageManifest.yaml created at:", secureExchangeManifestPath);
|
|
6904
7166
|
await (0, processMainTemplate_1.processMainTemplate)(discoveredFiles, tempPackageDir, secureExchangeManifestPath);
|
|
6905
7167
|
console.log("mainTemplate.json processed and added to PackageManifest.yaml");
|
|
@@ -6909,8 +7171,8 @@ var require_manifestProcessorService = __commonJS({
|
|
|
6909
7171
|
console.log("SC Agents processed and PackageManifest.yaml updated.");
|
|
6910
7172
|
await (0, refactorManifest_1.finalizeManifest)(secureExchangeManifestPath, tempPackageDir);
|
|
6911
7173
|
const zipName = `${manifest.packageName}.zip`;
|
|
6912
|
-
const manifestDir2 =
|
|
6913
|
-
const outputZipPath =
|
|
7174
|
+
const manifestDir2 = path8.dirname(path8.resolve(manifestPath));
|
|
7175
|
+
const outputZipPath = path8.join(manifestDir2, zipName);
|
|
6914
7176
|
await (0, zipDirectory_1.zipDirectory)(tempPackageDir, outputZipPath);
|
|
6915
7177
|
console.log("Package zipped at:", outputZipPath);
|
|
6916
7178
|
return outputZipPath;
|
|
@@ -6922,21 +7184,21 @@ var require_manifestProcessorService = __commonJS({
|
|
|
6922
7184
|
}
|
|
6923
7185
|
} finally {
|
|
6924
7186
|
try {
|
|
6925
|
-
await
|
|
7187
|
+
await fs7.rm(tempPackageDir, { recursive: true, force: true });
|
|
6926
7188
|
} catch (err) {
|
|
6927
7189
|
console.warn("Please clean the temp directory as Failed to clean up temp directory:", err);
|
|
6928
7190
|
}
|
|
6929
7191
|
}
|
|
6930
7192
|
}
|
|
6931
7193
|
async validateManifest(manifestPath) {
|
|
6932
|
-
const manifestDir =
|
|
6933
|
-
const tempPackageDir =
|
|
7194
|
+
const manifestDir = path8.dirname(path8.resolve(manifestPath));
|
|
7195
|
+
const tempPackageDir = path8.join(manifestDir, ".packaging-temp");
|
|
6934
7196
|
let parsed;
|
|
6935
7197
|
try {
|
|
6936
|
-
await
|
|
6937
|
-
const content = await
|
|
7198
|
+
await fs7.rm(tempPackageDir, { recursive: true, force: true });
|
|
7199
|
+
const content = await fs7.readFile(manifestPath, "utf8");
|
|
6938
7200
|
parsed = yaml.parse(content);
|
|
6939
|
-
const discoveredFiles = await (0, discoverFiles_1.discoverFiles)(parsed.includePaths,
|
|
7201
|
+
const discoveredFiles = await (0, discoverFiles_1.discoverFiles)(parsed.includePaths, path8.dirname(path8.resolve(manifestPath)));
|
|
6940
7202
|
(0, manifestValidator_1.validateSingleScAgent)(discoveredFiles);
|
|
6941
7203
|
const yamlType = parsed.yamlType;
|
|
6942
7204
|
if (!yamlType) {
|
|
@@ -6946,8 +7208,8 @@ var require_manifestProcessorService = __commonJS({
|
|
|
6946
7208
|
if (!validator) {
|
|
6947
7209
|
throw new Error(`No validator found for yamlType '${yamlType}'`);
|
|
6948
7210
|
}
|
|
6949
|
-
const absPath =
|
|
6950
|
-
const manifestDir2 =
|
|
7211
|
+
const absPath = path8.resolve(manifestPath);
|
|
7212
|
+
const manifestDir2 = path8.dirname(absPath);
|
|
6951
7213
|
await validator(parsed, manifestDir2);
|
|
6952
7214
|
} catch (err) {
|
|
6953
7215
|
if (err instanceof Error) {
|
|
@@ -6957,30 +7219,30 @@ var require_manifestProcessorService = __commonJS({
|
|
|
6957
7219
|
}
|
|
6958
7220
|
} finally {
|
|
6959
7221
|
try {
|
|
6960
|
-
await
|
|
7222
|
+
await fs7.rm(tempPackageDir, { recursive: true, force: true });
|
|
6961
7223
|
} catch (err) {
|
|
6962
7224
|
console.warn("Please clean the temp directory as Failed to clean up temp directory:", err);
|
|
6963
7225
|
}
|
|
6964
7226
|
}
|
|
6965
7227
|
}
|
|
6966
7228
|
async buildSideLoadRequest(manifestPath) {
|
|
6967
|
-
const manifestDir =
|
|
6968
|
-
const tempPackageDir =
|
|
6969
|
-
const sentinelLakeDir =
|
|
7229
|
+
const manifestDir = path8.dirname(path8.resolve(manifestPath));
|
|
7230
|
+
const tempPackageDir = path8.join(manifestDir, ".packaging-temp");
|
|
7231
|
+
const sentinelLakeDir = path8.join(tempPackageDir, constants_1.PackageManifestIdValues.SentinelLakeId);
|
|
6970
7232
|
const deploymentId = (0, crypto_1.randomUUID)();
|
|
6971
7233
|
try {
|
|
6972
|
-
await
|
|
7234
|
+
await fs7.rm(tempPackageDir, { recursive: true, force: true });
|
|
6973
7235
|
const manifest = await (0, manifestParser_1.parseManifest)(manifestPath);
|
|
6974
|
-
const discoveredFiles = await (0, discoverFiles_1.discoverFiles)(manifest.includePaths,
|
|
7236
|
+
const discoveredFiles = await (0, discoverFiles_1.discoverFiles)(manifest.includePaths, path8.dirname(path8.resolve(manifestPath)));
|
|
6975
7237
|
console.log("Discovered files:", JSON.stringify(discoveredFiles, null, 2));
|
|
6976
|
-
await
|
|
7238
|
+
await fs7.mkdir(tempPackageDir, { recursive: true });
|
|
6977
7239
|
await (0, buildScheduledJobArtifacts_1.processScheduledJobs)(discoveredFiles, tempPackageDir, "");
|
|
6978
|
-
const jobDirs = await
|
|
7240
|
+
const jobDirs = await fs7.readdir(sentinelLakeDir);
|
|
6979
7241
|
const artifacts = [];
|
|
6980
7242
|
for (const dir of jobDirs) {
|
|
6981
|
-
const deploymentJsonPath =
|
|
6982
|
-
if (await
|
|
6983
|
-
const jsonContent = await
|
|
7243
|
+
const deploymentJsonPath = path8.join(sentinelLakeDir, dir, "deployment.json");
|
|
7244
|
+
if (await fs7.pathExists(deploymentJsonPath)) {
|
|
7245
|
+
const jsonContent = await fs7.readFile(deploymentJsonPath, "utf8");
|
|
6984
7246
|
const escapedJson = JSON.stringify(JSON.parse(jsonContent));
|
|
6985
7247
|
artifacts.push({
|
|
6986
7248
|
name: "deployment.yaml",
|
|
@@ -7003,7 +7265,7 @@ var require_manifestProcessorService = __commonJS({
|
|
|
7003
7265
|
console.error("Error building side-load request:", error);
|
|
7004
7266
|
throw error;
|
|
7005
7267
|
} finally {
|
|
7006
|
-
await
|
|
7268
|
+
await fs7.remove(tempPackageDir);
|
|
7007
7269
|
}
|
|
7008
7270
|
}
|
|
7009
7271
|
};
|
|
@@ -7257,9 +7519,10 @@ var require_services = __commonJS({
|
|
|
7257
7519
|
o[k2] = m[k];
|
|
7258
7520
|
}));
|
|
7259
7521
|
var __exportStar = exports2 && exports2.__exportStar || function(m, exports3) {
|
|
7260
|
-
for (var
|
|
7522
|
+
for (var p4 in m) if (p4 !== "default" && !Object.prototype.hasOwnProperty.call(exports3, p4)) __createBinding(exports3, m, p4);
|
|
7261
7523
|
};
|
|
7262
7524
|
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
7525
|
+
__exportStar(require_tenant(), exports2);
|
|
7263
7526
|
__exportStar(require_httpConstants(), exports2);
|
|
7264
7527
|
__exportStar(require_jobs2(), exports2);
|
|
7265
7528
|
__exportStar(require_lake2(), exports2);
|
|
@@ -7291,13 +7554,68 @@ var require_errors = __commonJS({
|
|
|
7291
7554
|
o[k2] = m[k];
|
|
7292
7555
|
}));
|
|
7293
7556
|
var __exportStar = exports2 && exports2.__exportStar || function(m, exports3) {
|
|
7294
|
-
for (var
|
|
7557
|
+
for (var p4 in m) if (p4 !== "default" && !Object.prototype.hasOwnProperty.call(exports3, p4)) __createBinding(exports3, m, p4);
|
|
7295
7558
|
};
|
|
7296
7559
|
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
7297
7560
|
__exportStar(require_errorTypes(), exports2);
|
|
7298
7561
|
}
|
|
7299
7562
|
});
|
|
7300
7563
|
|
|
7564
|
+
// ../../packages/common/dist/src/telemetry/types.js
|
|
7565
|
+
var require_types2 = __commonJS({
|
|
7566
|
+
"../../packages/common/dist/src/telemetry/types.js"(exports2) {
|
|
7567
|
+
"use strict";
|
|
7568
|
+
init_cjs_shims();
|
|
7569
|
+
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
7570
|
+
}
|
|
7571
|
+
});
|
|
7572
|
+
|
|
7573
|
+
// ../../packages/common/dist/src/telemetry/index.js
|
|
7574
|
+
var require_telemetry = __commonJS({
|
|
7575
|
+
"../../packages/common/dist/src/telemetry/index.js"(exports2) {
|
|
7576
|
+
"use strict";
|
|
7577
|
+
init_cjs_shims();
|
|
7578
|
+
var __createBinding = exports2 && exports2.__createBinding || (Object.create ? (function(o, m, k, k2) {
|
|
7579
|
+
if (k2 === void 0) k2 = k;
|
|
7580
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
7581
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
7582
|
+
desc = { enumerable: true, get: function() {
|
|
7583
|
+
return m[k];
|
|
7584
|
+
} };
|
|
7585
|
+
}
|
|
7586
|
+
Object.defineProperty(o, k2, desc);
|
|
7587
|
+
}) : (function(o, m, k, k2) {
|
|
7588
|
+
if (k2 === void 0) k2 = k;
|
|
7589
|
+
o[k2] = m[k];
|
|
7590
|
+
}));
|
|
7591
|
+
var __exportStar = exports2 && exports2.__exportStar || function(m, exports3) {
|
|
7592
|
+
for (var p4 in m) if (p4 !== "default" && !Object.prototype.hasOwnProperty.call(exports3, p4)) __createBinding(exports3, m, p4);
|
|
7593
|
+
};
|
|
7594
|
+
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
7595
|
+
__exportStar(require_types2(), exports2);
|
|
7596
|
+
}
|
|
7597
|
+
});
|
|
7598
|
+
|
|
7599
|
+
// ../../packages/common/dist/src/utils/decodeBase64Notebook.js
|
|
7600
|
+
var require_decodeBase64Notebook = __commonJS({
|
|
7601
|
+
"../../packages/common/dist/src/utils/decodeBase64Notebook.js"(exports2) {
|
|
7602
|
+
"use strict";
|
|
7603
|
+
init_cjs_shims();
|
|
7604
|
+
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
7605
|
+
exports2.decodeBase64Notebook = decodeBase64Notebook3;
|
|
7606
|
+
var BASE64_RE = /^[A-Za-z0-9+/\r\n]*={0,2}$/;
|
|
7607
|
+
function decodeBase64Notebook3(encoded, label) {
|
|
7608
|
+
if (!encoded?.trim()) {
|
|
7609
|
+
throw new Error(`${label} has no notebook content to decode.`);
|
|
7610
|
+
}
|
|
7611
|
+
if (!BASE64_RE.test(encoded.trim())) {
|
|
7612
|
+
throw new Error(`${label} has an invalid base64-encoded notebook.`);
|
|
7613
|
+
}
|
|
7614
|
+
return Buffer.from(encoded, "base64").toString("utf-8");
|
|
7615
|
+
}
|
|
7616
|
+
}
|
|
7617
|
+
});
|
|
7618
|
+
|
|
7301
7619
|
// ../../packages/common/dist/src/utils/pathUtils.js
|
|
7302
7620
|
var require_pathUtils = __commonJS({
|
|
7303
7621
|
"../../packages/common/dist/src/utils/pathUtils.js"(exports2) {
|
|
@@ -7309,8 +7627,49 @@ var require_pathUtils = __commonJS({
|
|
|
7309
7627
|
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
7310
7628
|
exports2.resolvePath = resolvePath2;
|
|
7311
7629
|
var path_1 = __importDefault(require("path"));
|
|
7312
|
-
function resolvePath2(
|
|
7313
|
-
return path_1.default.resolve(
|
|
7630
|
+
function resolvePath2(p4) {
|
|
7631
|
+
return path_1.default.resolve(p4);
|
|
7632
|
+
}
|
|
7633
|
+
}
|
|
7634
|
+
});
|
|
7635
|
+
|
|
7636
|
+
// ../../packages/common/dist/src/utils/tokenUtils.js
|
|
7637
|
+
var require_tokenUtils = __commonJS({
|
|
7638
|
+
"../../packages/common/dist/src/utils/tokenUtils.js"(exports2) {
|
|
7639
|
+
"use strict";
|
|
7640
|
+
init_cjs_shims();
|
|
7641
|
+
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
7642
|
+
exports2.extractTenantId = extractTenantId2;
|
|
7643
|
+
var TOKEN_PARSING = {
|
|
7644
|
+
SEPARATOR: ".",
|
|
7645
|
+
BASE64_HYPHEN_REPLACEMENT: "+",
|
|
7646
|
+
BASE64_UNDERSCORE_REPLACEMENT: "/",
|
|
7647
|
+
BASE64_HYPHEN_PATTERN: /-/g,
|
|
7648
|
+
BASE64_UNDERSCORE_PATTERN: /_/g,
|
|
7649
|
+
BASE64_ENCODING: "base64",
|
|
7650
|
+
TENANT_ID_CLAIM: "tid",
|
|
7651
|
+
TOKEN_PARTS_LENGTH: 3,
|
|
7652
|
+
PAYLOAD_INDEX: 1
|
|
7653
|
+
};
|
|
7654
|
+
function extractTenantId2(accessToken) {
|
|
7655
|
+
try {
|
|
7656
|
+
const tokenParts = accessToken.split(TOKEN_PARSING.SEPARATOR);
|
|
7657
|
+
if (tokenParts.length !== TOKEN_PARSING.TOKEN_PARTS_LENGTH) {
|
|
7658
|
+
return void 0;
|
|
7659
|
+
}
|
|
7660
|
+
let base64Url = tokenParts[TOKEN_PARSING.PAYLOAD_INDEX].replace(TOKEN_PARSING.BASE64_HYPHEN_PATTERN, TOKEN_PARSING.BASE64_HYPHEN_REPLACEMENT).replace(TOKEN_PARSING.BASE64_UNDERSCORE_PATTERN, TOKEN_PARSING.BASE64_UNDERSCORE_REPLACEMENT);
|
|
7661
|
+
while (base64Url.length % 4 !== 0) {
|
|
7662
|
+
base64Url += "=";
|
|
7663
|
+
}
|
|
7664
|
+
const payload = JSON.parse(Buffer.from(base64Url, TOKEN_PARSING.BASE64_ENCODING).toString());
|
|
7665
|
+
if (typeof payload === "object" && payload !== null) {
|
|
7666
|
+
const tenantId = payload[TOKEN_PARSING.TENANT_ID_CLAIM];
|
|
7667
|
+
return typeof tenantId === "string" ? tenantId : void 0;
|
|
7668
|
+
}
|
|
7669
|
+
return void 0;
|
|
7670
|
+
} catch {
|
|
7671
|
+
return void 0;
|
|
7672
|
+
}
|
|
7314
7673
|
}
|
|
7315
7674
|
}
|
|
7316
7675
|
});
|
|
@@ -7334,12 +7693,14 @@ var require_utils = __commonJS({
|
|
|
7334
7693
|
o[k2] = m[k];
|
|
7335
7694
|
}));
|
|
7336
7695
|
var __exportStar = exports2 && exports2.__exportStar || function(m, exports3) {
|
|
7337
|
-
for (var
|
|
7696
|
+
for (var p4 in m) if (p4 !== "default" && !Object.prototype.hasOwnProperty.call(exports3, p4)) __createBinding(exports3, m, p4);
|
|
7338
7697
|
};
|
|
7339
7698
|
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
7340
7699
|
__exportStar(require_correlationService(), exports2);
|
|
7700
|
+
__exportStar(require_decodeBase64Notebook(), exports2);
|
|
7341
7701
|
__exportStar(require_pathUtils(), exports2);
|
|
7342
7702
|
__exportStar(require_jobPayloadUtils(), exports2);
|
|
7703
|
+
__exportStar(require_tokenUtils(), exports2);
|
|
7343
7704
|
}
|
|
7344
7705
|
});
|
|
7345
7706
|
|
|
@@ -7362,7 +7723,7 @@ var require_src = __commonJS({
|
|
|
7362
7723
|
o[k2] = m[k];
|
|
7363
7724
|
}));
|
|
7364
7725
|
var __exportStar = exports2 && exports2.__exportStar || function(m, exports3) {
|
|
7365
|
-
for (var
|
|
7726
|
+
for (var p4 in m) if (p4 !== "default" && !Object.prototype.hasOwnProperty.call(exports3, p4)) __createBinding(exports3, m, p4);
|
|
7366
7727
|
};
|
|
7367
7728
|
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
7368
7729
|
__exportStar(require_client(), exports2);
|
|
@@ -7372,6 +7733,7 @@ var require_src = __commonJS({
|
|
|
7372
7733
|
__exportStar(require_models(), exports2);
|
|
7373
7734
|
__exportStar(require_services(), exports2);
|
|
7374
7735
|
__exportStar(require_errors(), exports2);
|
|
7736
|
+
__exportStar(require_telemetry(), exports2);
|
|
7375
7737
|
__exportStar(require_utils(), exports2);
|
|
7376
7738
|
}
|
|
7377
7739
|
});
|
|
@@ -7415,103 +7777,1029 @@ function addCreateZipCommand(packageCommand) {
|
|
|
7415
7777
|
});
|
|
7416
7778
|
}
|
|
7417
7779
|
|
|
7418
|
-
// src/commands/
|
|
7780
|
+
// src/commands/jobs/jobDefinitionCreate.ts
|
|
7419
7781
|
init_cjs_shims();
|
|
7420
|
-
var import_common9 = __toESM(require_src());
|
|
7421
7782
|
|
|
7422
|
-
// src/actions/
|
|
7783
|
+
// src/actions/jobs/index.ts
|
|
7423
7784
|
init_cjs_shims();
|
|
7424
7785
|
|
|
7425
|
-
// src/actions/
|
|
7786
|
+
// src/actions/jobs/listJobs.ts
|
|
7426
7787
|
init_cjs_shims();
|
|
7427
7788
|
var import_common3 = __toESM(require_src());
|
|
7428
|
-
async function
|
|
7789
|
+
async function listJobs(jobService, accessToken) {
|
|
7429
7790
|
const requestId = import_common3.CorrelationService.createCorrelationContext();
|
|
7430
|
-
console.info("Fetching
|
|
7431
|
-
return
|
|
7791
|
+
console.info("Fetching jobs...");
|
|
7792
|
+
return jobService.listJobs(accessToken, requestId);
|
|
7432
7793
|
}
|
|
7433
7794
|
|
|
7434
|
-
// src/actions/
|
|
7795
|
+
// src/actions/jobs/getJob.ts
|
|
7435
7796
|
init_cjs_shims();
|
|
7436
7797
|
var import_common4 = __toESM(require_src());
|
|
7437
|
-
async function
|
|
7798
|
+
async function getJob(jobService, accessToken, jobName) {
|
|
7438
7799
|
const requestId = import_common4.CorrelationService.createCorrelationContext();
|
|
7439
|
-
|
|
7440
|
-
|
|
7441
|
-
return tableService.listTables(accessToken, requestId, database);
|
|
7800
|
+
console.info(`Fetching job "${jobName}"...`);
|
|
7801
|
+
return jobService.getJob(jobName, accessToken, requestId);
|
|
7442
7802
|
}
|
|
7443
7803
|
|
|
7444
|
-
// src/
|
|
7804
|
+
// src/actions/jobs/deleteJob.ts
|
|
7445
7805
|
init_cjs_shims();
|
|
7806
|
+
var import_common5 = __toESM(require_src());
|
|
7807
|
+
async function deleteJob(jobService, accessToken, jobName) {
|
|
7808
|
+
const requestId = import_common5.CorrelationService.createCorrelationContext();
|
|
7809
|
+
console.info(`Deleting job "${jobName}"...`);
|
|
7810
|
+
return jobService.deleteJob(jobName, accessToken, requestId);
|
|
7811
|
+
}
|
|
7446
7812
|
|
|
7447
|
-
// src/
|
|
7813
|
+
// src/actions/jobs/disableJob.ts
|
|
7448
7814
|
init_cjs_shims();
|
|
7449
|
-
var
|
|
7450
|
-
|
|
7451
|
-
|
|
7452
|
-
}
|
|
7453
|
-
|
|
7454
|
-
|
|
7455
|
-
}
|
|
7456
|
-
};
|
|
7815
|
+
var import_common6 = __toESM(require_src());
|
|
7816
|
+
async function disableJob(jobService, accessToken, jobName) {
|
|
7817
|
+
const requestId = import_common6.CorrelationService.createCorrelationContext();
|
|
7818
|
+
console.info(`Disabling job "${jobName}"...`);
|
|
7819
|
+
return jobService.disableJob(jobName, accessToken, requestId);
|
|
7820
|
+
}
|
|
7457
7821
|
|
|
7458
|
-
// src/
|
|
7822
|
+
// src/actions/jobs/enableJob.ts
|
|
7459
7823
|
init_cjs_shims();
|
|
7460
|
-
var
|
|
7461
|
-
|
|
7462
|
-
|
|
7463
|
-
}
|
|
7464
|
-
|
|
7465
|
-
|
|
7466
|
-
}
|
|
7467
|
-
};
|
|
7824
|
+
var import_common7 = __toESM(require_src());
|
|
7825
|
+
async function enableJob(jobService, accessToken, jobName) {
|
|
7826
|
+
const requestId = import_common7.CorrelationService.createCorrelationContext();
|
|
7827
|
+
console.info(`Enabling job "${jobName}"...`);
|
|
7828
|
+
return jobService.enableJob(jobName, accessToken, requestId);
|
|
7829
|
+
}
|
|
7468
7830
|
|
|
7469
|
-
// src/
|
|
7831
|
+
// src/actions/jobs/downloadJob.ts
|
|
7470
7832
|
init_cjs_shims();
|
|
7471
|
-
var
|
|
7472
|
-
var
|
|
7473
|
-
|
|
7474
|
-
|
|
7475
|
-
|
|
7476
|
-
|
|
7477
|
-
|
|
7478
|
-
|
|
7479
|
-
}
|
|
7480
|
-
|
|
7481
|
-
|
|
7482
|
-
|
|
7483
|
-
|
|
7484
|
-
|
|
7485
|
-
}
|
|
7486
|
-
return void 0;
|
|
7833
|
+
var import_fs = __toESM(require("fs"));
|
|
7834
|
+
var import_path = __toESM(require("path"));
|
|
7835
|
+
var import_common8 = __toESM(require_src());
|
|
7836
|
+
async function downloadJob(jobService, accessToken, jobName, outputPath) {
|
|
7837
|
+
const requestId = import_common8.CorrelationService.createCorrelationContext();
|
|
7838
|
+
console.info(`Fetching job "${jobName}"...`);
|
|
7839
|
+
const job = await jobService.getJob(jobName, accessToken, requestId);
|
|
7840
|
+
const inlineScript = job.jobDefinition.inlineScript;
|
|
7841
|
+
const decoded = (0, import_common8.decodeBase64Notebook)(inlineScript, `job "${jobName}"`);
|
|
7842
|
+
const sanitizedJobName = import_path.default.basename(jobName).replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
7843
|
+
const resolvedPath = import_path.default.resolve(outputPath ?? import_path.default.join(process.cwd(), `${sanitizedJobName}.ipynb`));
|
|
7844
|
+
await import_fs.default.promises.mkdir(import_path.default.dirname(resolvedPath), { recursive: true });
|
|
7845
|
+
await import_fs.default.promises.writeFile(resolvedPath, decoded, "utf-8");
|
|
7846
|
+
return resolvedPath;
|
|
7487
7847
|
}
|
|
7488
|
-
|
|
7489
|
-
|
|
7490
|
-
|
|
7491
|
-
|
|
7492
|
-
|
|
7493
|
-
|
|
7494
|
-
|
|
7495
|
-
|
|
7496
|
-
process.exit(1);
|
|
7497
|
-
}
|
|
7498
|
-
return match;
|
|
7848
|
+
|
|
7849
|
+
// src/actions/jobs/listJobRuns.ts
|
|
7850
|
+
init_cjs_shims();
|
|
7851
|
+
var import_common9 = __toESM(require_src());
|
|
7852
|
+
async function listJobRuns(jobService, accessToken, jobName) {
|
|
7853
|
+
const requestId = import_common9.CorrelationService.createCorrelationContext();
|
|
7854
|
+
console.info(`Fetching runs for job "${jobName}"...`);
|
|
7855
|
+
return jobService.listJobRuns(jobName, accessToken, requestId);
|
|
7499
7856
|
}
|
|
7500
|
-
|
|
7501
|
-
|
|
7502
|
-
|
|
7503
|
-
|
|
7504
|
-
|
|
7505
|
-
|
|
7506
|
-
|
|
7857
|
+
|
|
7858
|
+
// src/actions/jobs/getJobRun.ts
|
|
7859
|
+
init_cjs_shims();
|
|
7860
|
+
var import_common10 = __toESM(require_src());
|
|
7861
|
+
async function getJobRun(jobService, accessToken, jobName, runId) {
|
|
7862
|
+
const requestId = import_common10.CorrelationService.createCorrelationContext();
|
|
7863
|
+
console.info(`Fetching run "${runId}" for job "${jobName}"...`);
|
|
7864
|
+
return jobService.getJobRun(jobName, runId, accessToken, requestId);
|
|
7865
|
+
}
|
|
7866
|
+
|
|
7867
|
+
// src/actions/jobs/startJobRun.ts
|
|
7868
|
+
init_cjs_shims();
|
|
7869
|
+
var import_common11 = __toESM(require_src());
|
|
7870
|
+
async function startJobRun(jobService, accessToken, jobName) {
|
|
7871
|
+
const requestId = import_common11.CorrelationService.createCorrelationContext();
|
|
7872
|
+
console.info(`Starting run for job "${jobName}"...`);
|
|
7873
|
+
return jobService.startJobRun(jobName, accessToken, requestId);
|
|
7874
|
+
}
|
|
7875
|
+
|
|
7876
|
+
// src/actions/jobs/cancelJobRun.ts
|
|
7877
|
+
init_cjs_shims();
|
|
7878
|
+
var import_common12 = __toESM(require_src());
|
|
7879
|
+
async function cancelJobRun(jobService, accessToken, jobName, runId) {
|
|
7880
|
+
const requestId = import_common12.CorrelationService.createCorrelationContext();
|
|
7881
|
+
console.info(`Cancelling run "${runId}" for job "${jobName}"...`);
|
|
7882
|
+
return jobService.cancelJobRun(jobName, runId, accessToken, requestId);
|
|
7883
|
+
}
|
|
7884
|
+
|
|
7885
|
+
// src/actions/jobs/downloadJobRunNotebook.ts
|
|
7886
|
+
init_cjs_shims();
|
|
7887
|
+
var import_fs2 = __toESM(require("fs"));
|
|
7888
|
+
var import_path2 = __toESM(require("path"));
|
|
7889
|
+
var import_common13 = __toESM(require_src());
|
|
7890
|
+
async function downloadJobRunNotebook(jobService, accessToken, jobName, runId, outputPath) {
|
|
7891
|
+
const requestId = import_common13.CorrelationService.createCorrelationContext();
|
|
7892
|
+
console.info(`Fetching run "${runId}" for job "${jobName}"...`);
|
|
7893
|
+
const run = await jobService.getJobRun(jobName, runId, accessToken, requestId);
|
|
7894
|
+
const scriptSnapshot = run.scriptSnapshot;
|
|
7895
|
+
const decoded = (0, import_common13.decodeBase64Notebook)(scriptSnapshot, `run "${runId}" for job "${jobName}"`);
|
|
7896
|
+
const sanitizedJobName = import_path2.default.basename(jobName).replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
7897
|
+
const sanitizedRunId = import_path2.default.basename(runId).replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
7898
|
+
const defaultFileName = `${sanitizedJobName}_${sanitizedRunId}.ipynb`;
|
|
7899
|
+
const resolvedPath = import_path2.default.resolve(outputPath ?? import_path2.default.join(process.cwd(), defaultFileName));
|
|
7900
|
+
await import_fs2.default.promises.mkdir(import_path2.default.dirname(resolvedPath), { recursive: true });
|
|
7901
|
+
await import_fs2.default.promises.writeFile(resolvedPath, decoded, "utf-8");
|
|
7902
|
+
return resolvedPath;
|
|
7903
|
+
}
|
|
7904
|
+
|
|
7905
|
+
// src/actions/jobs/createJobDefinition.ts
|
|
7906
|
+
init_cjs_shims();
|
|
7907
|
+
var p2 = __toESM(require("@clack/prompts"));
|
|
7908
|
+
var path3 = __toESM(require("path"));
|
|
7909
|
+
|
|
7910
|
+
// src/utils/validator/jobDefinitionValidator.ts
|
|
7911
|
+
init_cjs_shims();
|
|
7912
|
+
var import_zod = require("zod");
|
|
7913
|
+
var ISO_DATE_PATTERN = /^\d{4}-\d{2}-\d{2}(T\d{2}:\d{2}(:\d{2}(\.\d+)?)?(Z|[+-]\d{2}:\d{2})?)?$/;
|
|
7914
|
+
var JOB_TYPES = ["Notebook", "GraphNotebook", "Kql"];
|
|
7915
|
+
var NODE_SIZES = ["small", "medium", "large"];
|
|
7916
|
+
var REPEAT_FREQUENCIES = ["minutes", "hours", "days", "weeks", "months"];
|
|
7917
|
+
var INTERVAL_BOUNDS = {
|
|
7918
|
+
minutes: { min: 15, max: 720 },
|
|
7919
|
+
hours: { min: 1, max: 72 }
|
|
7920
|
+
};
|
|
7921
|
+
var FIXED_INTERVAL_FREQUENCIES = new Set(
|
|
7922
|
+
REPEAT_FREQUENCIES.filter((f) => !(f in INTERVAL_BOUNDS))
|
|
7923
|
+
);
|
|
7924
|
+
var JOB_NAME_PATTERN = /^[a-zA-Z0-9 _-]+$/;
|
|
7925
|
+
var JOB_NAME_PATTERN_MESSAGE = "Job name may only contain letters, numbers, spaces, hyphens, or underscores";
|
|
7926
|
+
var VALID_WEEK_DAYS = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"];
|
|
7927
|
+
function isValidISODate(value) {
|
|
7928
|
+
if (!ISO_DATE_PATTERN.test(value)) {
|
|
7929
|
+
return false;
|
|
7930
|
+
}
|
|
7931
|
+
return !isNaN(new Date(value).getTime());
|
|
7932
|
+
}
|
|
7933
|
+
var timeTableSchema = import_zod.z.object({
|
|
7934
|
+
weekDays: import_zod.z.array(import_zod.z.enum(VALID_WEEK_DAYS)).optional(),
|
|
7935
|
+
monthDays: import_zod.z.array(import_zod.z.number().int().min(1).max(31)).optional()
|
|
7936
|
+
}).optional();
|
|
7937
|
+
var scheduleConfigSchema = import_zod.z.object({
|
|
7938
|
+
isEnabled: import_zod.z.boolean(),
|
|
7939
|
+
repeatFrequency: import_zod.z.enum(REPEAT_FREQUENCIES).optional(),
|
|
7940
|
+
interval: import_zod.z.number().int().positive().optional(),
|
|
7941
|
+
startTime: import_zod.z.string().optional(),
|
|
7942
|
+
endTime: import_zod.z.string().optional(),
|
|
7943
|
+
timeTable: timeTableSchema
|
|
7944
|
+
});
|
|
7945
|
+
var jobDefinitionValidator = import_zod.z.object({
|
|
7946
|
+
jobName: import_zod.z.string().min(1, "Job name is required").regex(JOB_NAME_PATTERN, JOB_NAME_PATTERN_MESSAGE),
|
|
7947
|
+
jobPath: import_zod.z.string().min(1, "Job path is required"),
|
|
7948
|
+
jobType: import_zod.z.enum(JOB_TYPES).optional(),
|
|
7949
|
+
jobDescription: import_zod.z.string().optional(),
|
|
7950
|
+
computeInfo: import_zod.z.object({
|
|
7951
|
+
nodeSize: import_zod.z.enum(NODE_SIZES)
|
|
7952
|
+
}).optional(),
|
|
7953
|
+
scheduleConfig: scheduleConfigSchema.optional(),
|
|
7954
|
+
inputTables: import_zod.z.array(import_zod.z.string()).optional(),
|
|
7955
|
+
outputTables: import_zod.z.array(import_zod.z.string()).optional(),
|
|
7956
|
+
runtimeArgs: import_zod.z.array(import_zod.z.string()).optional(),
|
|
7957
|
+
isDisabled: import_zod.z.boolean().optional()
|
|
7958
|
+
}).refine(
|
|
7959
|
+
(data) => {
|
|
7960
|
+
const jobType = data.jobType ?? "Notebook";
|
|
7961
|
+
if (jobType === "Kql") {
|
|
7962
|
+
return true;
|
|
7963
|
+
}
|
|
7964
|
+
return data.jobPath.toLowerCase().endsWith(".ipynb");
|
|
7965
|
+
},
|
|
7966
|
+
{ message: "Job path must be a Python notebook (.ipynb) file", path: ["jobPath"] }
|
|
7967
|
+
).refine(
|
|
7968
|
+
(data) => {
|
|
7969
|
+
if (data.scheduleConfig?.isEnabled) {
|
|
7970
|
+
return !!data.scheduleConfig.repeatFrequency;
|
|
7971
|
+
}
|
|
7972
|
+
return true;
|
|
7973
|
+
},
|
|
7974
|
+
{ message: "repeatFrequency is required for scheduled jobs", path: ["scheduleConfig", "repeatFrequency"] }
|
|
7975
|
+
).refine(
|
|
7976
|
+
(data) => {
|
|
7977
|
+
const sc = data.scheduleConfig;
|
|
7978
|
+
if (!sc?.isEnabled || !sc.repeatFrequency) {
|
|
7979
|
+
return true;
|
|
7980
|
+
}
|
|
7981
|
+
return sc.interval !== void 0;
|
|
7982
|
+
},
|
|
7983
|
+
{ message: "Interval is required for scheduled jobs", path: ["scheduleConfig", "interval"] }
|
|
7984
|
+
).refine(
|
|
7985
|
+
(data) => {
|
|
7986
|
+
const sc = data.scheduleConfig;
|
|
7987
|
+
if (!sc?.isEnabled || sc.interval === void 0 || !sc.repeatFrequency) {
|
|
7988
|
+
return true;
|
|
7989
|
+
}
|
|
7990
|
+
const bounds = INTERVAL_BOUNDS[sc.repeatFrequency];
|
|
7991
|
+
if (bounds) {
|
|
7992
|
+
return sc.interval >= bounds.min && sc.interval <= bounds.max;
|
|
7993
|
+
}
|
|
7994
|
+
if (FIXED_INTERVAL_FREQUENCIES.has(sc.repeatFrequency)) {
|
|
7995
|
+
return sc.interval === 1;
|
|
7996
|
+
}
|
|
7997
|
+
return true;
|
|
7998
|
+
},
|
|
7999
|
+
{
|
|
8000
|
+
message: "Schedule interval is out of range for the selected frequency",
|
|
8001
|
+
path: ["scheduleConfig", "interval"]
|
|
8002
|
+
}
|
|
8003
|
+
).refine(
|
|
8004
|
+
(data) => {
|
|
8005
|
+
const sc = data.scheduleConfig;
|
|
8006
|
+
if (!sc?.isEnabled || !sc.startTime) {
|
|
8007
|
+
return true;
|
|
8008
|
+
}
|
|
8009
|
+
return isValidISODate(sc.startTime);
|
|
8010
|
+
},
|
|
8011
|
+
{ message: "Start time must be a valid ISO 8601 date", path: ["scheduleConfig", "startTime"] }
|
|
8012
|
+
).refine(
|
|
8013
|
+
(data) => {
|
|
8014
|
+
const sc = data.scheduleConfig;
|
|
8015
|
+
if (!sc?.isEnabled || !sc.endTime) {
|
|
8016
|
+
return true;
|
|
8017
|
+
}
|
|
8018
|
+
return isValidISODate(sc.endTime);
|
|
8019
|
+
},
|
|
8020
|
+
{ message: "End time must be a valid ISO 8601 date", path: ["scheduleConfig", "endTime"] }
|
|
8021
|
+
).refine(
|
|
8022
|
+
(data) => {
|
|
8023
|
+
const sc = data.scheduleConfig;
|
|
8024
|
+
if (!sc?.isEnabled || !sc.startTime || !sc.endTime) {
|
|
8025
|
+
return true;
|
|
8026
|
+
}
|
|
8027
|
+
const start = new Date(sc.startTime);
|
|
8028
|
+
const end = new Date(sc.endTime);
|
|
8029
|
+
if (isNaN(start.getTime()) || isNaN(end.getTime())) {
|
|
8030
|
+
return true;
|
|
8031
|
+
}
|
|
8032
|
+
return end > start;
|
|
8033
|
+
},
|
|
8034
|
+
{ message: "End time must be after start time", path: ["scheduleConfig", "endTime"] }
|
|
8035
|
+
).refine(
|
|
8036
|
+
(data) => {
|
|
8037
|
+
const sc = data.scheduleConfig;
|
|
8038
|
+
if (!sc?.isEnabled || sc.repeatFrequency !== "weeks") {
|
|
8039
|
+
return true;
|
|
8040
|
+
}
|
|
8041
|
+
const days = sc.timeTable?.weekDays;
|
|
8042
|
+
return Array.isArray(days) && days.length > 0;
|
|
8043
|
+
},
|
|
8044
|
+
{ message: "At least one day of the week is required for weekly schedule", path: ["scheduleConfig", "timeTable"] }
|
|
8045
|
+
).refine(
|
|
8046
|
+
(data) => {
|
|
8047
|
+
const sc = data.scheduleConfig;
|
|
8048
|
+
if (!sc?.isEnabled || sc.repeatFrequency !== "months") {
|
|
8049
|
+
return true;
|
|
8050
|
+
}
|
|
8051
|
+
const days = sc.timeTable?.monthDays;
|
|
8052
|
+
return Array.isArray(days) && days.length > 0;
|
|
8053
|
+
},
|
|
8054
|
+
{
|
|
8055
|
+
message: "At least one day of the month is required for monthly schedule",
|
|
8056
|
+
path: ["scheduleConfig", "timeTable", "monthDays"]
|
|
8057
|
+
}
|
|
8058
|
+
);
|
|
8059
|
+
|
|
8060
|
+
// src/actions/jobs/promptHelpers.ts
|
|
8061
|
+
init_cjs_shims();
|
|
8062
|
+
var fs3 = __toESM(require("fs"));
|
|
8063
|
+
var p = __toESM(require("@clack/prompts"));
|
|
8064
|
+
var DEFAULT_NODE_SIZE = "large";
|
|
8065
|
+
var NODE_SIZE_OPTIONS = NODE_SIZES.map((size) => ({
|
|
8066
|
+
value: size,
|
|
8067
|
+
label: size === DEFAULT_NODE_SIZE ? `${capitalize(size)} (default)` : capitalize(size)
|
|
8068
|
+
}));
|
|
8069
|
+
var FREQUENCY_OPTIONS = REPEAT_FREQUENCIES.map((freq) => ({
|
|
8070
|
+
value: freq,
|
|
8071
|
+
label: capitalize(freq)
|
|
8072
|
+
}));
|
|
8073
|
+
var CONFIGURABLE_INTERVAL_FREQUENCIES = new Set(
|
|
8074
|
+
Object.keys(INTERVAL_BOUNDS)
|
|
8075
|
+
);
|
|
8076
|
+
var WEEKDAY_OPTIONS = [
|
|
8077
|
+
{ value: "Monday", label: "Monday" },
|
|
8078
|
+
{ value: "Tuesday", label: "Tuesday" },
|
|
8079
|
+
{ value: "Wednesday", label: "Wednesday" },
|
|
8080
|
+
{ value: "Thursday", label: "Thursday" },
|
|
8081
|
+
{ value: "Friday", label: "Friday" },
|
|
8082
|
+
{ value: "Saturday", label: "Saturday" },
|
|
8083
|
+
{ value: "Sunday", label: "Sunday" }
|
|
8084
|
+
];
|
|
8085
|
+
function capitalize(s) {
|
|
8086
|
+
return s.charAt(0).toUpperCase() + s.slice(1);
|
|
8087
|
+
}
|
|
8088
|
+
function handleCancel(value) {
|
|
8089
|
+
if (p.isCancel(value)) {
|
|
8090
|
+
p.cancel("Operation cancelled.");
|
|
8091
|
+
process.exit(0);
|
|
8092
|
+
}
|
|
8093
|
+
}
|
|
8094
|
+
async function promptIfMissing(flagValue, promptFn) {
|
|
8095
|
+
if (flagValue !== void 0) {
|
|
8096
|
+
return flagValue;
|
|
8097
|
+
}
|
|
8098
|
+
const result = await promptFn();
|
|
8099
|
+
handleCancel(result);
|
|
8100
|
+
return result;
|
|
8101
|
+
}
|
|
8102
|
+
function validateInterval(frequency) {
|
|
8103
|
+
return (v) => {
|
|
8104
|
+
if (!v || v.trim() === "") {
|
|
8105
|
+
return "Interval is required";
|
|
8106
|
+
}
|
|
8107
|
+
const trimmed = v.trim();
|
|
8108
|
+
if (!/^\d+$/.test(trimmed)) {
|
|
8109
|
+
return "Please enter a whole number";
|
|
8110
|
+
}
|
|
8111
|
+
const n = parseInt(trimmed, 10);
|
|
8112
|
+
const bounds = INTERVAL_BOUNDS[frequency];
|
|
8113
|
+
if (bounds) {
|
|
8114
|
+
if (n < bounds.min) {
|
|
8115
|
+
return `Minimum value is ${bounds.min} ${frequency}`;
|
|
8116
|
+
}
|
|
8117
|
+
if (n > bounds.max) {
|
|
8118
|
+
return `Maximum value is ${bounds.max} ${frequency}`;
|
|
8119
|
+
}
|
|
8120
|
+
} else if (FIXED_INTERVAL_FREQUENCIES.has(frequency)) {
|
|
8121
|
+
if (n !== 1) {
|
|
8122
|
+
return `Interval must be 1 for ${frequency}`;
|
|
8123
|
+
}
|
|
8124
|
+
}
|
|
8125
|
+
return void 0;
|
|
8126
|
+
};
|
|
8127
|
+
}
|
|
8128
|
+
function validateJobPath(v) {
|
|
8129
|
+
if (!v) {
|
|
8130
|
+
return "Job path is required";
|
|
8131
|
+
}
|
|
8132
|
+
if (!v.toLowerCase().endsWith(".ipynb")) {
|
|
8133
|
+
return "Job path must be a Python notebook (.ipynb) file";
|
|
8134
|
+
}
|
|
8135
|
+
if (!fs3.existsSync(v)) {
|
|
8136
|
+
return `File not found at "${v}". Please provide a valid path to an existing .ipynb file`;
|
|
8137
|
+
}
|
|
8138
|
+
return void 0;
|
|
8139
|
+
}
|
|
8140
|
+
function validateISODate(v) {
|
|
8141
|
+
if (!v) {
|
|
8142
|
+
return "Date/time is required";
|
|
8143
|
+
}
|
|
8144
|
+
const iso8601Pattern = /^\d{4}-\d{2}-\d{2}(T\d{2}:\d{2}(:\d{2}(\.\d+)?)?(Z|[+-]\d{2}:\d{2})?)?$/;
|
|
8145
|
+
if (!iso8601Pattern.test(v)) {
|
|
8146
|
+
return "Must be a valid ISO 8601 date (e.g. 2026-01-01T09:00:00Z)";
|
|
8147
|
+
}
|
|
8148
|
+
const d = new Date(v);
|
|
8149
|
+
if (isNaN(d.getTime())) {
|
|
8150
|
+
return "Must be a valid ISO 8601 date (e.g. 2026-01-01T09:00:00Z)";
|
|
8151
|
+
}
|
|
8152
|
+
return void 0;
|
|
8153
|
+
}
|
|
8154
|
+
function validateEndTimeAfterStart(startTime, endTime) {
|
|
8155
|
+
if (!endTime) {
|
|
8156
|
+
return "End time is required";
|
|
8157
|
+
}
|
|
8158
|
+
const start = new Date(startTime);
|
|
8159
|
+
const end = new Date(endTime);
|
|
8160
|
+
if (isNaN(start.getTime()) || isNaN(end.getTime())) {
|
|
8161
|
+
return "Please enter valid date and time values";
|
|
8162
|
+
}
|
|
8163
|
+
if (end <= start) {
|
|
8164
|
+
return "End time must be after start time";
|
|
8165
|
+
}
|
|
8166
|
+
return void 0;
|
|
8167
|
+
}
|
|
8168
|
+
function validateJobName(v) {
|
|
8169
|
+
if (!v) {
|
|
8170
|
+
return "Job name is required";
|
|
8171
|
+
}
|
|
8172
|
+
if (!JOB_NAME_PATTERN.test(v)) {
|
|
8173
|
+
return JOB_NAME_PATTERN_MESSAGE;
|
|
8174
|
+
}
|
|
8175
|
+
return void 0;
|
|
8176
|
+
}
|
|
8177
|
+
function validateEndTime(startTime) {
|
|
8178
|
+
return (v) => {
|
|
8179
|
+
const isoErr = validateISODate(v);
|
|
8180
|
+
if (isoErr) {
|
|
8181
|
+
return isoErr;
|
|
8182
|
+
}
|
|
8183
|
+
return validateEndTimeAfterStart(startTime, v);
|
|
8184
|
+
};
|
|
8185
|
+
}
|
|
8186
|
+
|
|
8187
|
+
// src/utils/yaml/yamlIO.ts
|
|
8188
|
+
init_cjs_shims();
|
|
8189
|
+
var fs4 = __toESM(require("fs"));
|
|
8190
|
+
var YAML = __toESM(require("yaml"));
|
|
8191
|
+
function readJobDefinitionYaml(filePath) {
|
|
8192
|
+
if (!fs4.existsSync(filePath)) {
|
|
8193
|
+
throw new Error(`File not found: ${filePath}`);
|
|
8194
|
+
}
|
|
8195
|
+
let raw;
|
|
8196
|
+
try {
|
|
8197
|
+
const content = fs4.readFileSync(filePath, "utf-8");
|
|
8198
|
+
raw = YAML.parse(content);
|
|
8199
|
+
} catch (err) {
|
|
8200
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
8201
|
+
throw new Error(`Failed to read/parse YAML: ${message}`);
|
|
8202
|
+
}
|
|
8203
|
+
const result = jobDefinitionValidator.safeParse(raw);
|
|
8204
|
+
if (result.success) {
|
|
8205
|
+
return result.data;
|
|
8206
|
+
}
|
|
8207
|
+
const issues = result.error.issues.map((i) => `${i.path.join(".")}: ${i.message}`);
|
|
8208
|
+
throw new Error(`Validation failed:
|
|
8209
|
+
${issues.join("\n")}`);
|
|
8210
|
+
}
|
|
8211
|
+
function writeJobDefinitionYaml(filePath, config) {
|
|
8212
|
+
const result = jobDefinitionValidator.safeParse(config);
|
|
8213
|
+
if (!result.success) {
|
|
8214
|
+
const issues = result.error.issues.map((i) => `${i.path.join(".")}: ${i.message}`);
|
|
8215
|
+
return { success: false, issues };
|
|
8216
|
+
}
|
|
8217
|
+
try {
|
|
8218
|
+
const yamlContent = YAML.stringify(result.data, { lineWidth: 0 });
|
|
8219
|
+
fs4.writeFileSync(filePath, yamlContent, "utf-8");
|
|
8220
|
+
return { success: true, issues: [] };
|
|
8221
|
+
} catch (err) {
|
|
8222
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
8223
|
+
return { success: false, issues: [`Failed to write file "${filePath}": ${message}`] };
|
|
8224
|
+
}
|
|
8225
|
+
}
|
|
8226
|
+
|
|
8227
|
+
// src/actions/jobs/createJobDefinition.ts
|
|
8228
|
+
function sanitizeFileName(fileName) {
|
|
8229
|
+
return fileName.replace(/[<>:"/\\|?*]/g, "_").replace(/\s+/g, "_");
|
|
8230
|
+
}
|
|
8231
|
+
function fail(message) {
|
|
8232
|
+
throw new Error(message);
|
|
8233
|
+
}
|
|
8234
|
+
async function collectJobDetails(jobNameArg, options) {
|
|
8235
|
+
const jobName = await promptIfMissing(
|
|
8236
|
+
jobNameArg,
|
|
8237
|
+
() => p2.text({
|
|
8238
|
+
message: "Job name:",
|
|
8239
|
+
validate: validateJobName
|
|
8240
|
+
})
|
|
8241
|
+
);
|
|
8242
|
+
if (jobNameArg !== void 0) {
|
|
8243
|
+
const nameError = validateJobName(jobName);
|
|
8244
|
+
if (nameError) {
|
|
8245
|
+
fail(nameError);
|
|
8246
|
+
}
|
|
8247
|
+
}
|
|
8248
|
+
const jobDescription = await promptIfMissing(
|
|
8249
|
+
options.description,
|
|
8250
|
+
() => p2.text({ message: "Description (optional):", defaultValue: "" })
|
|
8251
|
+
);
|
|
8252
|
+
const jobPath = await promptIfMissing(
|
|
8253
|
+
options.notebook,
|
|
8254
|
+
() => p2.text({
|
|
8255
|
+
message: "Job path (.ipynb):",
|
|
8256
|
+
placeholder: "path/to/notebook.ipynb",
|
|
8257
|
+
validate: validateJobPath
|
|
8258
|
+
})
|
|
8259
|
+
);
|
|
8260
|
+
if (options.notebook !== void 0) {
|
|
8261
|
+
const pathError = validateJobPath(jobPath);
|
|
8262
|
+
if (pathError) {
|
|
8263
|
+
fail(pathError);
|
|
8264
|
+
}
|
|
8265
|
+
}
|
|
8266
|
+
return { jobName, jobDescription, jobPath };
|
|
8267
|
+
}
|
|
8268
|
+
async function collectCompute(options) {
|
|
8269
|
+
if (options.cluster) {
|
|
8270
|
+
const normalized = options.cluster.toLowerCase();
|
|
8271
|
+
if (!NODE_SIZES.includes(normalized)) {
|
|
8272
|
+
fail(`Invalid cluster size "${options.cluster}". Must be one of: ${NODE_SIZES.join(", ")}`);
|
|
8273
|
+
}
|
|
8274
|
+
return normalized;
|
|
8275
|
+
}
|
|
8276
|
+
const result = await p2.select({
|
|
8277
|
+
message: "Cluster size:",
|
|
8278
|
+
options: NODE_SIZE_OPTIONS,
|
|
8279
|
+
initialValue: DEFAULT_NODE_SIZE
|
|
8280
|
+
});
|
|
8281
|
+
handleCancel(result);
|
|
8282
|
+
return result;
|
|
8283
|
+
}
|
|
8284
|
+
async function collectSchedule(options) {
|
|
8285
|
+
let wantsSchedule = !!options.schedule;
|
|
8286
|
+
if (!wantsSchedule) {
|
|
8287
|
+
const result = await p2.confirm({ message: "Schedule this job?", initialValue: true });
|
|
8288
|
+
handleCancel(result);
|
|
8289
|
+
wantsSchedule = result;
|
|
8290
|
+
}
|
|
8291
|
+
if (!wantsSchedule) {
|
|
8292
|
+
return { isEnabled: false };
|
|
8293
|
+
}
|
|
8294
|
+
const repeatFrequency = await promptIfMissing(
|
|
8295
|
+
options.schedule,
|
|
8296
|
+
() => p2.select({ message: "Repeat frequency:", options: FREQUENCY_OPTIONS })
|
|
8297
|
+
);
|
|
8298
|
+
if (options.schedule && !REPEAT_FREQUENCIES.includes(repeatFrequency)) {
|
|
8299
|
+
fail(`Invalid schedule frequency "${options.schedule}". Must be one of: ${REPEAT_FREQUENCIES.join(", ")}`);
|
|
8300
|
+
}
|
|
8301
|
+
let interval = 1;
|
|
8302
|
+
if (CONFIGURABLE_INTERVAL_FREQUENCIES.has(repeatFrequency)) {
|
|
8303
|
+
const intervalStr = await promptIfMissing(
|
|
8304
|
+
options.interval,
|
|
8305
|
+
() => p2.text({
|
|
8306
|
+
message: `Interval (${repeatFrequency}):`,
|
|
8307
|
+
defaultValue: repeatFrequency === "minutes" ? "15" : "1",
|
|
8308
|
+
validate: validateInterval(repeatFrequency)
|
|
8309
|
+
})
|
|
7507
8310
|
);
|
|
7508
|
-
|
|
8311
|
+
if (options.interval) {
|
|
8312
|
+
const intervalError = validateInterval(repeatFrequency)(intervalStr);
|
|
8313
|
+
if (intervalError) {
|
|
8314
|
+
fail(intervalError);
|
|
8315
|
+
}
|
|
8316
|
+
}
|
|
8317
|
+
interval = Number(intervalStr);
|
|
7509
8318
|
}
|
|
7510
|
-
|
|
8319
|
+
let timeTable;
|
|
8320
|
+
if (repeatFrequency === "weeks") {
|
|
8321
|
+
const result = await p2.multiselect({
|
|
8322
|
+
message: "Which days of the week?",
|
|
8323
|
+
options: [...WEEKDAY_OPTIONS],
|
|
8324
|
+
required: true
|
|
8325
|
+
});
|
|
8326
|
+
handleCancel(result);
|
|
8327
|
+
timeTable = { weekDays: result };
|
|
8328
|
+
}
|
|
8329
|
+
const startTime = await promptIfMissing(
|
|
8330
|
+
options.startTime,
|
|
8331
|
+
() => p2.text({
|
|
8332
|
+
message: "Start time (ISO 8601):",
|
|
8333
|
+
defaultValue: (/* @__PURE__ */ new Date()).toISOString(),
|
|
8334
|
+
validate: validateISODate
|
|
8335
|
+
})
|
|
8336
|
+
);
|
|
8337
|
+
if (options.startTime) {
|
|
8338
|
+
const startError = validateISODate(startTime);
|
|
8339
|
+
if (startError) {
|
|
8340
|
+
fail(startError);
|
|
8341
|
+
}
|
|
8342
|
+
}
|
|
8343
|
+
if (repeatFrequency === "months") {
|
|
8344
|
+
const dayOfMonth = new Date(startTime).getDate();
|
|
8345
|
+
timeTable = { monthDays: [dayOfMonth] };
|
|
8346
|
+
}
|
|
8347
|
+
let endTime;
|
|
8348
|
+
if (options.endTime) {
|
|
8349
|
+
endTime = options.endTime;
|
|
8350
|
+
} else {
|
|
8351
|
+
let endTimeResolved = false;
|
|
8352
|
+
while (!endTimeResolved) {
|
|
8353
|
+
const setEndTime = await p2.confirm({ message: "Set an end time?", initialValue: false });
|
|
8354
|
+
handleCancel(setEndTime);
|
|
8355
|
+
if (setEndTime) {
|
|
8356
|
+
const result = await p2.text({
|
|
8357
|
+
message: "End time (ISO 8601):",
|
|
8358
|
+
validate: validateEndTime(startTime)
|
|
8359
|
+
});
|
|
8360
|
+
handleCancel(result);
|
|
8361
|
+
endTime = result;
|
|
8362
|
+
endTimeResolved = true;
|
|
8363
|
+
} else {
|
|
8364
|
+
p2.log.warn("This job will run indefinitely until manually stopped or deleted.");
|
|
8365
|
+
const confirmIndefinite = await p2.confirm({ message: "Run indefinitely?", initialValue: true });
|
|
8366
|
+
handleCancel(confirmIndefinite);
|
|
8367
|
+
if (confirmIndefinite) {
|
|
8368
|
+
endTimeResolved = true;
|
|
8369
|
+
}
|
|
8370
|
+
}
|
|
8371
|
+
}
|
|
8372
|
+
}
|
|
8373
|
+
if (options.endTime) {
|
|
8374
|
+
const endError = validateEndTimeAfterStart(startTime, endTime);
|
|
8375
|
+
if (endError) {
|
|
8376
|
+
fail(endError);
|
|
8377
|
+
}
|
|
8378
|
+
}
|
|
8379
|
+
return { isEnabled: true, repeatFrequency, interval, startTime, endTime, timeTable };
|
|
8380
|
+
}
|
|
8381
|
+
async function createJobDefinition(jobNameArg, options) {
|
|
8382
|
+
p2.intro("Create a job definition");
|
|
8383
|
+
const { jobName, jobDescription, jobPath } = await collectJobDetails(jobNameArg, options);
|
|
8384
|
+
const nodeSize = await collectCompute(options);
|
|
8385
|
+
const schedule = await collectSchedule(options);
|
|
8386
|
+
const config = {
|
|
8387
|
+
jobName,
|
|
8388
|
+
jobPath,
|
|
8389
|
+
jobType: "Notebook",
|
|
8390
|
+
...jobDescription && { jobDescription },
|
|
8391
|
+
computeInfo: { nodeSize },
|
|
8392
|
+
...schedule.isEnabled && {
|
|
8393
|
+
scheduleConfig: {
|
|
8394
|
+
isEnabled: true,
|
|
8395
|
+
repeatFrequency: schedule.repeatFrequency,
|
|
8396
|
+
interval: schedule.interval,
|
|
8397
|
+
startTime: schedule.startTime,
|
|
8398
|
+
endTime: schedule.endTime,
|
|
8399
|
+
...schedule.timeTable && { timeTable: schedule.timeTable }
|
|
8400
|
+
}
|
|
8401
|
+
}
|
|
8402
|
+
};
|
|
8403
|
+
const outputPath = path3.resolve(options.output ?? `${sanitizeFileName(jobName)}.yaml`);
|
|
8404
|
+
const result = writeJobDefinitionYaml(outputPath, config);
|
|
8405
|
+
if (!result.success) {
|
|
8406
|
+
for (const issue of result.issues) {
|
|
8407
|
+
p2.log.error(issue);
|
|
8408
|
+
}
|
|
8409
|
+
throw new Error("Validation failed");
|
|
8410
|
+
}
|
|
8411
|
+
p2.log.success(`Written to ${outputPath}`);
|
|
8412
|
+
p2.outro("Job definition created successfully!");
|
|
8413
|
+
}
|
|
8414
|
+
|
|
8415
|
+
// src/actions/jobs/showJobDefinition.ts
|
|
8416
|
+
init_cjs_shims();
|
|
8417
|
+
|
|
8418
|
+
// src/utils/formatter/outputFormatter.ts
|
|
8419
|
+
init_cjs_shims();
|
|
8420
|
+
var COLUMN_SEPARATOR = " ";
|
|
8421
|
+
var HEADER_RULE_CHAR = "\u2500";
|
|
8422
|
+
var OutputFormatter = class {
|
|
8423
|
+
format;
|
|
8424
|
+
constructor(options = {}) {
|
|
8425
|
+
this.format = options.output ?? "table";
|
|
8426
|
+
}
|
|
8427
|
+
/**
|
|
8428
|
+
* Renders `rows` to stdout using the configured output format.
|
|
8429
|
+
*
|
|
8430
|
+
* @param rows - The data array to render.
|
|
8431
|
+
* @param columns - Column descriptors that define headers and value extractors.
|
|
8432
|
+
*/
|
|
8433
|
+
print(rows, columns) {
|
|
8434
|
+
if (this.format === "json") {
|
|
8435
|
+
this.printJson(rows, columns);
|
|
8436
|
+
} else {
|
|
8437
|
+
this.printTable(rows, columns);
|
|
8438
|
+
}
|
|
8439
|
+
}
|
|
8440
|
+
// ---------------------------------------------------------------------------
|
|
8441
|
+
// Table rendering
|
|
8442
|
+
// ---------------------------------------------------------------------------
|
|
8443
|
+
printTable(rows, columns) {
|
|
8444
|
+
if (rows.length === 0) {
|
|
8445
|
+
console.log("(no results)");
|
|
8446
|
+
return;
|
|
8447
|
+
}
|
|
8448
|
+
const widths = columns.map((col) => {
|
|
8449
|
+
const cellWidths = rows.map((row) => String(col.key(row) ?? "").length);
|
|
8450
|
+
return Math.max(col.header.length, ...cellWidths);
|
|
8451
|
+
});
|
|
8452
|
+
const header = columns.map((col, i) => col.header.padEnd(widths[i])).join(COLUMN_SEPARATOR);
|
|
8453
|
+
console.log(header);
|
|
8454
|
+
const rule = widths.map((w) => HEADER_RULE_CHAR.repeat(w)).join(COLUMN_SEPARATOR);
|
|
8455
|
+
console.log(rule);
|
|
8456
|
+
for (const row of rows) {
|
|
8457
|
+
const line = columns.map((col, i) => String(col.key(row) ?? "").padEnd(widths[i])).join(COLUMN_SEPARATOR);
|
|
8458
|
+
console.log(line);
|
|
8459
|
+
}
|
|
8460
|
+
}
|
|
8461
|
+
// ---------------------------------------------------------------------------
|
|
8462
|
+
// JSON rendering
|
|
8463
|
+
// ---------------------------------------------------------------------------
|
|
8464
|
+
printJson(rows, columns) {
|
|
8465
|
+
const records = rows.map((row) => {
|
|
8466
|
+
const record = {};
|
|
8467
|
+
for (const col of columns) {
|
|
8468
|
+
const key = col.jsonKey ?? col.header.toLowerCase();
|
|
8469
|
+
const value = col.key(row);
|
|
8470
|
+
record[key] = value ?? null;
|
|
8471
|
+
}
|
|
8472
|
+
return record;
|
|
8473
|
+
});
|
|
8474
|
+
console.log(JSON.stringify(records, null, 2));
|
|
8475
|
+
}
|
|
8476
|
+
};
|
|
8477
|
+
|
|
8478
|
+
// src/actions/jobs/showJobDefinition.ts
|
|
8479
|
+
var FIELD_COLUMNS = [
|
|
8480
|
+
{ header: "FIELD", key: (f) => f.label },
|
|
8481
|
+
{ header: "VALUE", key: (f) => f.value }
|
|
8482
|
+
];
|
|
8483
|
+
function buildJobFields(data) {
|
|
8484
|
+
const fields = [
|
|
8485
|
+
{ label: "Name", value: data.jobName },
|
|
8486
|
+
{ label: "Description", value: data.jobDescription ?? "" },
|
|
8487
|
+
{ label: "Type", value: data.jobType ?? "" },
|
|
8488
|
+
{ label: "Job Path", value: data.jobPath },
|
|
8489
|
+
{ label: "Cluster", value: data.computeInfo?.nodeSize ? capitalize(data.computeInfo.nodeSize) : "" },
|
|
8490
|
+
{ label: "Disabled", value: data.isDisabled ? "Yes" : "No" }
|
|
8491
|
+
];
|
|
8492
|
+
const schedule = data.scheduleConfig;
|
|
8493
|
+
if (schedule?.isEnabled) {
|
|
8494
|
+
const freq = schedule.repeatFrequency ? capitalize(schedule.repeatFrequency) : "";
|
|
8495
|
+
const interval = schedule.interval ?? 1;
|
|
8496
|
+
fields.push({ label: "Schedule", value: `Every ${interval} ${freq}` });
|
|
8497
|
+
if (schedule.timeTable?.weekDays?.length) {
|
|
8498
|
+
fields.push({ label: "Weekly Days", value: schedule.timeTable.weekDays.join(", ") });
|
|
8499
|
+
}
|
|
8500
|
+
if (schedule.timeTable?.monthDays?.length) {
|
|
8501
|
+
fields.push({ label: "Monthly Days", value: schedule.timeTable.monthDays.join(", ") });
|
|
8502
|
+
}
|
|
8503
|
+
fields.push({ label: "Start Time", value: schedule.startTime ?? "" });
|
|
8504
|
+
fields.push({ label: "End Time", value: schedule.endTime ?? "(indefinite)" });
|
|
8505
|
+
} else {
|
|
8506
|
+
fields.push({ label: "Schedule", value: "On-demand" });
|
|
8507
|
+
}
|
|
8508
|
+
fields.push({ label: "Input Tables", value: data.inputTables?.length ? data.inputTables.join(", ") : "(none)" });
|
|
8509
|
+
fields.push({ label: "Output Tables", value: data.outputTables?.length ? data.outputTables.join(", ") : "(none)" });
|
|
8510
|
+
if (data.runtimeArgs?.length) {
|
|
8511
|
+
fields.push({ label: "Runtime Args", value: data.runtimeArgs.join(", ") });
|
|
8512
|
+
}
|
|
8513
|
+
return fields;
|
|
8514
|
+
}
|
|
8515
|
+
function showJobDefinition(filePath, options) {
|
|
8516
|
+
const data = readJobDefinitionYaml(filePath);
|
|
8517
|
+
const fmt = new OutputFormatter({ output: options.output ?? "table" });
|
|
8518
|
+
const fields = buildJobFields(data);
|
|
8519
|
+
fmt.print(fields, FIELD_COLUMNS);
|
|
7511
8520
|
}
|
|
7512
8521
|
|
|
8522
|
+
// src/actions/jobs/updateJobDefinition.ts
|
|
8523
|
+
init_cjs_shims();
|
|
8524
|
+
var p3 = __toESM(require("@clack/prompts"));
|
|
8525
|
+
var UPDATABLE_FIELDS = [
|
|
8526
|
+
{ value: "description", label: "Description" },
|
|
8527
|
+
{ value: "jobPath", label: "Job path" },
|
|
8528
|
+
{ value: "cluster", label: "Cluster size" },
|
|
8529
|
+
{ value: "schedule", label: "Schedule" },
|
|
8530
|
+
{ value: "inputTables", label: "Input tables" },
|
|
8531
|
+
{ value: "outputTables", label: "Output tables" },
|
|
8532
|
+
{ value: "runtimeArgs", label: "Runtime arguments" }
|
|
8533
|
+
];
|
|
8534
|
+
async function updateDescription(config) {
|
|
8535
|
+
const result = await p3.text({
|
|
8536
|
+
message: "New description:",
|
|
8537
|
+
defaultValue: config.jobDescription ?? ""
|
|
8538
|
+
});
|
|
8539
|
+
handleCancel(result);
|
|
8540
|
+
config.jobDescription = result;
|
|
8541
|
+
}
|
|
8542
|
+
async function updateJobPath(config) {
|
|
8543
|
+
const result = await p3.text({
|
|
8544
|
+
message: "New job path (.ipynb):",
|
|
8545
|
+
defaultValue: config.jobPath,
|
|
8546
|
+
validate: validateJobPath
|
|
8547
|
+
});
|
|
8548
|
+
handleCancel(result);
|
|
8549
|
+
config.jobPath = result;
|
|
8550
|
+
}
|
|
8551
|
+
async function updateCluster(config) {
|
|
8552
|
+
const result = await p3.select({
|
|
8553
|
+
message: "New cluster size:",
|
|
8554
|
+
options: NODE_SIZE_OPTIONS,
|
|
8555
|
+
initialValue: config.computeInfo?.nodeSize ?? DEFAULT_NODE_SIZE
|
|
8556
|
+
});
|
|
8557
|
+
handleCancel(result);
|
|
8558
|
+
config.computeInfo = { nodeSize: result };
|
|
8559
|
+
}
|
|
8560
|
+
async function updateSchedule(config) {
|
|
8561
|
+
const existing = config.scheduleConfig;
|
|
8562
|
+
const wantsSchedule = await p3.confirm({
|
|
8563
|
+
message: "Enable schedule?",
|
|
8564
|
+
initialValue: existing?.isEnabled ?? true
|
|
8565
|
+
});
|
|
8566
|
+
handleCancel(wantsSchedule);
|
|
8567
|
+
if (!wantsSchedule) {
|
|
8568
|
+
config.scheduleConfig = { isEnabled: false };
|
|
8569
|
+
return;
|
|
8570
|
+
}
|
|
8571
|
+
const frequency = await p3.select({
|
|
8572
|
+
message: "Repeat frequency:",
|
|
8573
|
+
options: FREQUENCY_OPTIONS,
|
|
8574
|
+
initialValue: existing?.repeatFrequency ?? "days"
|
|
8575
|
+
});
|
|
8576
|
+
handleCancel(frequency);
|
|
8577
|
+
const repeatFrequency = frequency;
|
|
8578
|
+
let interval = 1;
|
|
8579
|
+
if (CONFIGURABLE_INTERVAL_FREQUENCIES.has(repeatFrequency)) {
|
|
8580
|
+
const defaultInterval = existing?.interval ?? (repeatFrequency === "minutes" ? 15 : 1);
|
|
8581
|
+
const intervalStr = await p3.text({
|
|
8582
|
+
message: `Interval (${repeatFrequency}):`,
|
|
8583
|
+
defaultValue: String(defaultInterval),
|
|
8584
|
+
validate: validateInterval(repeatFrequency)
|
|
8585
|
+
});
|
|
8586
|
+
handleCancel(intervalStr);
|
|
8587
|
+
interval = Number(intervalStr);
|
|
8588
|
+
}
|
|
8589
|
+
let timeTable;
|
|
8590
|
+
if (repeatFrequency === "weeks") {
|
|
8591
|
+
const existingDays = existing?.timeTable?.weekDays ?? [];
|
|
8592
|
+
const result = await p3.multiselect({
|
|
8593
|
+
message: "Which days of the week?",
|
|
8594
|
+
options: WEEKDAY_OPTIONS.map((opt) => ({
|
|
8595
|
+
...opt,
|
|
8596
|
+
selected: existingDays.includes(opt.value)
|
|
8597
|
+
})),
|
|
8598
|
+
required: true
|
|
8599
|
+
});
|
|
8600
|
+
handleCancel(result);
|
|
8601
|
+
timeTable = { weekDays: result };
|
|
8602
|
+
}
|
|
8603
|
+
const startTime = await p3.text({
|
|
8604
|
+
message: "Start time (ISO 8601):",
|
|
8605
|
+
defaultValue: existing?.startTime ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
8606
|
+
validate: validateISODate
|
|
8607
|
+
});
|
|
8608
|
+
handleCancel(startTime);
|
|
8609
|
+
if (repeatFrequency === "months") {
|
|
8610
|
+
const dayOfMonth = new Date(startTime).getDate();
|
|
8611
|
+
timeTable = { monthDays: [dayOfMonth] };
|
|
8612
|
+
}
|
|
8613
|
+
let endTime;
|
|
8614
|
+
const setEndTime = await p3.confirm({
|
|
8615
|
+
message: "Set an end time?",
|
|
8616
|
+
initialValue: !!existing?.endTime
|
|
8617
|
+
});
|
|
8618
|
+
handleCancel(setEndTime);
|
|
8619
|
+
if (setEndTime) {
|
|
8620
|
+
const result = await p3.text({
|
|
8621
|
+
message: "End time (ISO 8601):",
|
|
8622
|
+
defaultValue: existing?.endTime ?? "",
|
|
8623
|
+
validate: validateEndTime(startTime)
|
|
8624
|
+
});
|
|
8625
|
+
handleCancel(result);
|
|
8626
|
+
endTime = result;
|
|
8627
|
+
}
|
|
8628
|
+
config.scheduleConfig = {
|
|
8629
|
+
isEnabled: true,
|
|
8630
|
+
repeatFrequency,
|
|
8631
|
+
interval,
|
|
8632
|
+
startTime,
|
|
8633
|
+
endTime,
|
|
8634
|
+
...timeTable && { timeTable }
|
|
8635
|
+
};
|
|
8636
|
+
}
|
|
8637
|
+
async function updateStringArray(config, field, label) {
|
|
8638
|
+
const current = config[field] ?? [];
|
|
8639
|
+
const result = await p3.text({
|
|
8640
|
+
message: `${label} (comma-separated):`,
|
|
8641
|
+
defaultValue: current.join(", ")
|
|
8642
|
+
});
|
|
8643
|
+
handleCancel(result);
|
|
8644
|
+
const raw = result;
|
|
8645
|
+
config[field] = raw.trim() ? raw.split(",").map((s) => s.trim()) : [];
|
|
8646
|
+
}
|
|
8647
|
+
async function applyFieldUpdate(field, config) {
|
|
8648
|
+
switch (field) {
|
|
8649
|
+
case "description":
|
|
8650
|
+
return updateDescription(config);
|
|
8651
|
+
case "jobPath":
|
|
8652
|
+
return updateJobPath(config);
|
|
8653
|
+
case "cluster":
|
|
8654
|
+
return updateCluster(config);
|
|
8655
|
+
case "schedule":
|
|
8656
|
+
return updateSchedule(config);
|
|
8657
|
+
case "inputTables":
|
|
8658
|
+
return updateStringArray(config, "inputTables", "Input tables");
|
|
8659
|
+
case "outputTables":
|
|
8660
|
+
return updateStringArray(config, "outputTables", "Output tables");
|
|
8661
|
+
case "runtimeArgs":
|
|
8662
|
+
return updateStringArray(config, "runtimeArgs", "Runtime arguments");
|
|
8663
|
+
}
|
|
8664
|
+
}
|
|
8665
|
+
async function updateJobDefinition(filePath) {
|
|
8666
|
+
p3.intro("Update job definition");
|
|
8667
|
+
const data = readJobDefinitionYaml(filePath);
|
|
8668
|
+
let editing = true;
|
|
8669
|
+
while (editing) {
|
|
8670
|
+
const field = await p3.select({
|
|
8671
|
+
message: "Which field to update?",
|
|
8672
|
+
options: [...UPDATABLE_FIELDS]
|
|
8673
|
+
});
|
|
8674
|
+
handleCancel(field);
|
|
8675
|
+
await applyFieldUpdate(field, data);
|
|
8676
|
+
const again = await p3.confirm({ message: "Update another field?", initialValue: false });
|
|
8677
|
+
handleCancel(again);
|
|
8678
|
+
editing = again;
|
|
8679
|
+
}
|
|
8680
|
+
const result = writeJobDefinitionYaml(filePath, data);
|
|
8681
|
+
if (!result.success) {
|
|
8682
|
+
for (const issue of result.issues) {
|
|
8683
|
+
p3.log.error(issue);
|
|
8684
|
+
}
|
|
8685
|
+
throw new Error("Validation failed");
|
|
8686
|
+
}
|
|
8687
|
+
p3.log.success(`Updated ${filePath}`);
|
|
8688
|
+
p3.outro("Done");
|
|
8689
|
+
}
|
|
8690
|
+
|
|
8691
|
+
// src/utils/error/handleApiError.ts
|
|
8692
|
+
init_cjs_shims();
|
|
8693
|
+
function hasStatusCode(e) {
|
|
8694
|
+
return e instanceof Error && "statusCode" in e && typeof e.statusCode === "number";
|
|
8695
|
+
}
|
|
8696
|
+
function hasResponseStatus(e) {
|
|
8697
|
+
return e instanceof Error && "response" in e && e.response !== null && typeof e.response?.status === "number";
|
|
8698
|
+
}
|
|
8699
|
+
function getStatusInfo(error) {
|
|
8700
|
+
if (hasStatusCode(error)) {
|
|
8701
|
+
return ` (HTTP ${error.statusCode})`;
|
|
8702
|
+
}
|
|
8703
|
+
if (hasResponseStatus(error)) {
|
|
8704
|
+
return ` (HTTP ${error.response.status})`;
|
|
8705
|
+
}
|
|
8706
|
+
return "";
|
|
8707
|
+
}
|
|
8708
|
+
function handleApiError(context, error) {
|
|
8709
|
+
if (error instanceof Error) {
|
|
8710
|
+
console.error(`Error ${context}${getStatusInfo(error)}:`, error.message);
|
|
8711
|
+
if (process.env.DEBUG && error.stack) {
|
|
8712
|
+
console.error(error.stack);
|
|
8713
|
+
}
|
|
8714
|
+
process.exitCode = 1;
|
|
8715
|
+
throw error;
|
|
8716
|
+
}
|
|
8717
|
+
const wrapped = new Error(`Unknown error ${context}: ${String(error)}`, { cause: error });
|
|
8718
|
+
console.error(wrapped.message);
|
|
8719
|
+
process.exitCode = 1;
|
|
8720
|
+
throw wrapped;
|
|
8721
|
+
}
|
|
8722
|
+
|
|
8723
|
+
// src/commands/jobs/jobDefinitionCreate.ts
|
|
8724
|
+
function addJobDefinitionCreateCommand(definitionCommand) {
|
|
8725
|
+
definitionCommand.command("create [jobName]").description("Interactively create a job definition YAML file").option("--notebook <path>", "Path to the job file (.ipynb)").option("--description <text>", "Job description").option("--cluster <size>", "Cluster size (small | medium | large)").option("--schedule <frequency>", "Schedule frequency (minutes | hours | days | weeks | months)").option("--interval <number>", "Schedule interval").option("--start-time <datetime>", "Schedule start time (ISO 8601)").option("--end-time <datetime>", "Schedule end time (ISO 8601)").option("--output <path>", "Output YAML file path (default: ./<jobName>.yaml)").action(async (jobName, options) => {
|
|
8726
|
+
try {
|
|
8727
|
+
await createJobDefinition(jobName, options);
|
|
8728
|
+
} catch (error) {
|
|
8729
|
+
handleApiError("creating job definition", error);
|
|
8730
|
+
}
|
|
8731
|
+
});
|
|
8732
|
+
}
|
|
8733
|
+
|
|
8734
|
+
// src/commands/jobs/jobDefinitionShow.ts
|
|
8735
|
+
init_cjs_shims();
|
|
8736
|
+
function addJobDefinitionShowCommand(definitionCommand) {
|
|
8737
|
+
definitionCommand.command("show <path>").description("Display a job definition YAML file").option("--output <format>", "Output format (table | json)", "table").action((filePath, options) => {
|
|
8738
|
+
try {
|
|
8739
|
+
showJobDefinition(filePath, options);
|
|
8740
|
+
} catch (error) {
|
|
8741
|
+
handleApiError("showing job definition", error);
|
|
8742
|
+
}
|
|
8743
|
+
});
|
|
8744
|
+
}
|
|
8745
|
+
|
|
8746
|
+
// src/commands/jobs/jobDefinitionUpdate.ts
|
|
8747
|
+
init_cjs_shims();
|
|
8748
|
+
function addJobDefinitionUpdateCommand(definitionCommand) {
|
|
8749
|
+
definitionCommand.command("update <path>").description("Interactively update a job definition YAML file").action(async (filePath) => {
|
|
8750
|
+
try {
|
|
8751
|
+
await updateJobDefinition(filePath);
|
|
8752
|
+
} catch (error) {
|
|
8753
|
+
handleApiError("updating job definition", error);
|
|
8754
|
+
}
|
|
8755
|
+
});
|
|
8756
|
+
}
|
|
8757
|
+
|
|
8758
|
+
// src/commands/jobs/jobDelete.ts
|
|
8759
|
+
init_cjs_shims();
|
|
8760
|
+
var import_common21 = __toESM(require_src());
|
|
8761
|
+
|
|
8762
|
+
// src/services/jobs/index.ts
|
|
8763
|
+
init_cjs_shims();
|
|
8764
|
+
|
|
8765
|
+
// src/services/jobs/jobService.ts
|
|
8766
|
+
init_cjs_shims();
|
|
8767
|
+
var JobService = class {
|
|
8768
|
+
constructor(jobApiClient) {
|
|
8769
|
+
this.jobApiClient = jobApiClient;
|
|
8770
|
+
}
|
|
8771
|
+
async listJobs(accessToken, requestId) {
|
|
8772
|
+
return this.jobApiClient.listJobs(accessToken, requestId);
|
|
8773
|
+
}
|
|
8774
|
+
async getJob(jobName, accessToken, requestId) {
|
|
8775
|
+
return this.jobApiClient.getJob(jobName, accessToken, requestId);
|
|
8776
|
+
}
|
|
8777
|
+
async deleteJob(jobName, accessToken, requestId) {
|
|
8778
|
+
return this.jobApiClient.deleteJob(jobName, accessToken, requestId);
|
|
8779
|
+
}
|
|
8780
|
+
async disableJob(jobName, accessToken, requestId) {
|
|
8781
|
+
return this.jobApiClient.disableJob(jobName, accessToken, requestId);
|
|
8782
|
+
}
|
|
8783
|
+
async enableJob(jobName, accessToken, requestId) {
|
|
8784
|
+
return this.jobApiClient.enableJob(jobName, accessToken, requestId);
|
|
8785
|
+
}
|
|
8786
|
+
async listJobRuns(jobName, accessToken, requestId) {
|
|
8787
|
+
return this.jobApiClient.listJobRuns(jobName, accessToken, requestId);
|
|
8788
|
+
}
|
|
8789
|
+
async getJobRun(jobName, runId, accessToken, requestId) {
|
|
8790
|
+
return this.jobApiClient.getJobRun(jobName, runId, accessToken, requestId);
|
|
8791
|
+
}
|
|
8792
|
+
async startJobRun(jobName, accessToken, requestId) {
|
|
8793
|
+
return this.jobApiClient.startJobRun(jobName, accessToken, requestId);
|
|
8794
|
+
}
|
|
8795
|
+
async cancelJobRun(jobName, runId, accessToken, requestId) {
|
|
8796
|
+
return this.jobApiClient.cancelJobRun(jobName, runId, accessToken, requestId);
|
|
8797
|
+
}
|
|
8798
|
+
};
|
|
8799
|
+
|
|
7513
8800
|
// src/services/getToken.ts
|
|
7514
8801
|
init_cjs_shims();
|
|
8802
|
+
var import_common17 = __toESM(require_src());
|
|
7515
8803
|
|
|
7516
8804
|
// src/auth/constants.ts
|
|
7517
8805
|
init_cjs_shims();
|
|
@@ -7538,7 +8826,7 @@ var import_msal_node_extensions2 = require("@azure/msal-node-extensions");
|
|
|
7538
8826
|
init_cjs_shims();
|
|
7539
8827
|
var import_msal_node_extensions = require("@azure/msal-node-extensions");
|
|
7540
8828
|
var import_os = __toESM(require("os"));
|
|
7541
|
-
var
|
|
8829
|
+
var import_path3 = __toESM(require("path"));
|
|
7542
8830
|
var PlatformType = /* @__PURE__ */ ((PlatformType2) => {
|
|
7543
8831
|
PlatformType2["Windows"] = "win32";
|
|
7544
8832
|
PlatformType2["MacOS"] = "darwin";
|
|
@@ -7546,9 +8834,9 @@ var PlatformType = /* @__PURE__ */ ((PlatformType2) => {
|
|
|
7546
8834
|
return PlatformType2;
|
|
7547
8835
|
})(PlatformType || {});
|
|
7548
8836
|
async function createPersistence() {
|
|
7549
|
-
const cacheFilePath =
|
|
7550
|
-
const
|
|
7551
|
-
switch (
|
|
8837
|
+
const cacheFilePath = import_path3.default.join(import_os.default.homedir(), ".nsdcli-cache.json");
|
|
8838
|
+
const platform5 = import_os.default.platform();
|
|
8839
|
+
switch (platform5) {
|
|
7552
8840
|
case "win32" /* Windows */:
|
|
7553
8841
|
return await import_msal_node_extensions.FilePersistenceWithDataProtection.create(cacheFilePath, import_msal_node_extensions.DataProtectionScope.CurrentUser);
|
|
7554
8842
|
case "darwin" /* MacOS */:
|
|
@@ -7557,7 +8845,7 @@ async function createPersistence() {
|
|
|
7557
8845
|
return await import_msal_node_extensions.LibSecretPersistence.create("nsdcli.service", "nsdcli.account", "nsdcli");
|
|
7558
8846
|
default:
|
|
7559
8847
|
throw new Error(
|
|
7560
|
-
`Unsupported platform: ${
|
|
8848
|
+
`Unsupported platform: ${platform5}. Supported platforms are: ${Object.values(PlatformType).join(", ")}`
|
|
7561
8849
|
);
|
|
7562
8850
|
}
|
|
7563
8851
|
}
|
|
@@ -7610,7 +8898,7 @@ var getMsalInstance = async (env, authorityOverride) => {
|
|
|
7610
8898
|
};
|
|
7611
8899
|
|
|
7612
8900
|
// src/services/msalAuth.ts
|
|
7613
|
-
var
|
|
8901
|
+
var import_common15 = __toESM(require_src());
|
|
7614
8902
|
|
|
7615
8903
|
// src/actions/defaultLogin.ts
|
|
7616
8904
|
init_cjs_shims();
|
|
@@ -7637,24 +8925,24 @@ var DefaultCredentialProvider = class _DefaultCredentialProvider {
|
|
|
7637
8925
|
|
|
7638
8926
|
// src/actions/brokerLogin.ts
|
|
7639
8927
|
init_cjs_shims();
|
|
7640
|
-
var
|
|
7641
|
-
var
|
|
8928
|
+
var import_common14 = __toESM(require_src());
|
|
8929
|
+
var import_fs3 = __toESM(require("fs"));
|
|
7642
8930
|
var import_os2 = __toESM(require("os"));
|
|
7643
|
-
var
|
|
7644
|
-
var apiEnv = (0,
|
|
7645
|
-
var SENTINEL_DIR =
|
|
7646
|
-
var BROKER_ACCOUNT_FILE =
|
|
8931
|
+
var import_path4 = __toESM(require("path"));
|
|
8932
|
+
var apiEnv = (0, import_common14.getApiEnv)(import_common14.SecurityPlatformEnvironment.Production);
|
|
8933
|
+
var SENTINEL_DIR = import_path4.default.join(import_os2.default.homedir(), ".sentinel");
|
|
8934
|
+
var BROKER_ACCOUNT_FILE = import_path4.default.join(SENTINEL_DIR, "broker-account.json");
|
|
7647
8935
|
function saveBrokerAccount(account, authority) {
|
|
7648
|
-
|
|
8936
|
+
import_fs3.default.mkdirSync(SENTINEL_DIR, { recursive: true, mode: 448 });
|
|
7649
8937
|
const session = { account, authority };
|
|
7650
8938
|
const tempFile = `${BROKER_ACCOUNT_FILE}.tmp`;
|
|
7651
|
-
|
|
7652
|
-
|
|
8939
|
+
import_fs3.default.writeFileSync(tempFile, JSON.stringify(session, null, 2), { encoding: "utf8", mode: 384 });
|
|
8940
|
+
import_fs3.default.renameSync(tempFile, BROKER_ACCOUNT_FILE);
|
|
7653
8941
|
}
|
|
7654
8942
|
function loadBrokerAccount() {
|
|
7655
8943
|
try {
|
|
7656
|
-
if (
|
|
7657
|
-
const raw =
|
|
8944
|
+
if (import_fs3.default.existsSync(BROKER_ACCOUNT_FILE)) {
|
|
8945
|
+
const raw = import_fs3.default.readFileSync(BROKER_ACCOUNT_FILE, "utf8");
|
|
7658
8946
|
const session = JSON.parse(raw);
|
|
7659
8947
|
if (session.account && typeof session.account === "object" && session.authority && typeof session.authority === "string") {
|
|
7660
8948
|
return session;
|
|
@@ -7666,8 +8954,8 @@ function loadBrokerAccount() {
|
|
|
7666
8954
|
}
|
|
7667
8955
|
function deleteBrokerAccount() {
|
|
7668
8956
|
try {
|
|
7669
|
-
if (
|
|
7670
|
-
|
|
8957
|
+
if (import_fs3.default.existsSync(BROKER_ACCOUNT_FILE)) {
|
|
8958
|
+
import_fs3.default.unlinkSync(BROKER_ACCOUNT_FILE);
|
|
7671
8959
|
}
|
|
7672
8960
|
} catch {
|
|
7673
8961
|
}
|
|
@@ -7727,7 +9015,7 @@ async function brokerLogin(scopes, tenant) {
|
|
|
7727
9015
|
}
|
|
7728
9016
|
|
|
7729
9017
|
// src/services/msalAuth.ts
|
|
7730
|
-
var apiEnv2 = (0,
|
|
9018
|
+
var apiEnv2 = (0, import_common15.getApiEnv)(import_common15.SecurityPlatformEnvironment.Production);
|
|
7731
9019
|
async function loginAndGetDeviceCodeToken(scopes = [apiEnv2.gatewayAuthResourceUri]) {
|
|
7732
9020
|
const deviceCodeRequest = {
|
|
7733
9021
|
scopes,
|
|
@@ -7769,6 +9057,14 @@ async function getAccessTokenFromCache(scopes = [apiEnv2.gatewayAuthResourceUri]
|
|
|
7769
9057
|
console.log("\u{1F510} Checking MSAL cache for tokens...");
|
|
7770
9058
|
const savedSession = loadBrokerAccount();
|
|
7771
9059
|
if (savedSession) {
|
|
9060
|
+
const authoritySegment = (() => {
|
|
9061
|
+
try {
|
|
9062
|
+
return new URL(savedSession.authority).pathname.split("/").filter(Boolean).pop() ?? "";
|
|
9063
|
+
} catch {
|
|
9064
|
+
return "";
|
|
9065
|
+
}
|
|
9066
|
+
})();
|
|
9067
|
+
const expectedTid = authoritySegment && authoritySegment !== "common" && authoritySegment !== "organizations" && authoritySegment !== "consumers" ? authoritySegment : null;
|
|
7772
9068
|
try {
|
|
7773
9069
|
const sessionMsal = await getMsalInstance(apiEnv2, savedSession.authority);
|
|
7774
9070
|
const response = await sessionMsal.acquireTokenSilent({
|
|
@@ -7777,14 +9073,19 @@ async function getAccessTokenFromCache(scopes = [apiEnv2.gatewayAuthResourceUri]
|
|
|
7777
9073
|
authority: savedSession.authority
|
|
7778
9074
|
});
|
|
7779
9075
|
if (response?.accessToken) {
|
|
9076
|
+
if (expectedTid && response.account?.tenantId && response.account.tenantId !== expectedTid) {
|
|
9077
|
+
throw new Error(
|
|
9078
|
+
`Active tenant is ${expectedTid} but silent acquisition returned a token for ${response.account.tenantId}. Run 'sentinel login --tenant ${expectedTid}' (or 'sentinel tenant select') to mint a tenant-bound token.`
|
|
9079
|
+
);
|
|
9080
|
+
}
|
|
7780
9081
|
console.log("\u2705 Authenticated using MSAL cache");
|
|
7781
9082
|
return response.accessToken;
|
|
7782
9083
|
}
|
|
7783
|
-
|
|
7784
|
-
|
|
7785
|
-
|
|
7786
|
-
|
|
7787
|
-
|
|
9084
|
+
throw new Error(
|
|
9085
|
+
`Silent token acquisition returned no access token for the active tenant${expectedTid ? ` (${expectedTid})` : ""}. Run 'sentinel login${expectedTid ? ` --tenant ${expectedTid}` : ""}' to refresh credentials.`
|
|
9086
|
+
);
|
|
9087
|
+
} catch (err) {
|
|
9088
|
+
throw err instanceof Error ? err : new Error(`Silent token acquisition failed: ${String(err)}`);
|
|
7788
9089
|
}
|
|
7789
9090
|
}
|
|
7790
9091
|
const msalInstance = await getMsalInstance(apiEnv2);
|
|
@@ -7874,40 +9175,379 @@ var MsalCacheTokenProvider = class {
|
|
|
7874
9175
|
if (!env) {
|
|
7875
9176
|
throw new Error("Environment cannot be null or undefined");
|
|
7876
9177
|
}
|
|
7877
|
-
this.env = env;
|
|
7878
|
-
this.options = {
|
|
7879
|
-
...options,
|
|
7880
|
-
scopes: options?.scopes?.length ? options.scopes : [this.env.gatewayAuthResourceUri]
|
|
7881
|
-
};
|
|
9178
|
+
this.env = env;
|
|
9179
|
+
this.options = {
|
|
9180
|
+
...options,
|
|
9181
|
+
scopes: options?.scopes?.length ? options.scopes : [this.env.gatewayAuthResourceUri]
|
|
9182
|
+
};
|
|
9183
|
+
}
|
|
9184
|
+
async getAccessToken() {
|
|
9185
|
+
const token = await getAccessTokenFromCache(this.options.scopes);
|
|
9186
|
+
if (!token) {
|
|
9187
|
+
throw new Error("No cached authentication token found. Please run `sentinel login` first.");
|
|
9188
|
+
}
|
|
9189
|
+
return token;
|
|
9190
|
+
}
|
|
9191
|
+
};
|
|
9192
|
+
|
|
9193
|
+
// src/auth/provider/TokenProviderFactory.ts
|
|
9194
|
+
var TokenProviderFactory = class {
|
|
9195
|
+
static createProvider(env, method, options) {
|
|
9196
|
+
switch (method) {
|
|
9197
|
+
case "device_code":
|
|
9198
|
+
return new DeviceCodeTokenProvider(env, options);
|
|
9199
|
+
case "managed_identity":
|
|
9200
|
+
if (!options) {
|
|
9201
|
+
throw new Error("UAMI clientId required for user-assigned managed identity");
|
|
9202
|
+
}
|
|
9203
|
+
return new ManagedIdentityTokenProvider(env, options);
|
|
9204
|
+
case "msal_cache":
|
|
9205
|
+
return new MsalCacheTokenProvider(env, options);
|
|
9206
|
+
default:
|
|
9207
|
+
throw new Error(`Unsupported token method: ${method}`);
|
|
9208
|
+
}
|
|
9209
|
+
}
|
|
9210
|
+
};
|
|
9211
|
+
|
|
9212
|
+
// src/telemetry/index.ts
|
|
9213
|
+
init_cjs_shims();
|
|
9214
|
+
|
|
9215
|
+
// src/telemetry/telemetryService.ts
|
|
9216
|
+
init_cjs_shims();
|
|
9217
|
+
var import_common16 = __toESM(require_src());
|
|
9218
|
+
var import_api = require("@opentelemetry/api");
|
|
9219
|
+
var import_monitor_opentelemetry = require("@azure/monitor-opentelemetry");
|
|
9220
|
+
|
|
9221
|
+
// src/telemetry/connectionString.ts
|
|
9222
|
+
init_cjs_shims();
|
|
9223
|
+
var APPLICATION_INSIGHTS_CONNECTION_STRING = "InstrumentationKey=0dadb494-ecd4-44a5-bcc1-baa55b3778be;IngestionEndpoint=https://eastus-8.in.applicationinsights.azure.com/;LiveEndpoint=https://eastus.livediagnostics.monitor.azure.com/;ApplicationId=8bc9c85a-22a3-45f8-b4f5-0bb6cd6ddad2";
|
|
9224
|
+
|
|
9225
|
+
// src/telemetry/types.ts
|
|
9226
|
+
init_cjs_shims();
|
|
9227
|
+
var TELEMETRY_OPT_OUT_ENV_VARS = ["SENTINEL_TELEMETRY_OPTOUT", "DO_NOT_TRACK"];
|
|
9228
|
+
|
|
9229
|
+
// src/telemetry/commonProperties.ts
|
|
9230
|
+
init_cjs_shims();
|
|
9231
|
+
var os4 = __toESM(require("os"));
|
|
9232
|
+
var import_uuid = require("uuid");
|
|
9233
|
+
function readAppVersion() {
|
|
9234
|
+
return true ? "0.3.0" : "unknown";
|
|
9235
|
+
}
|
|
9236
|
+
function detectCiEnvironment(env = process.env) {
|
|
9237
|
+
if (env.TF_BUILD) {
|
|
9238
|
+
return "AzureDevOps";
|
|
9239
|
+
}
|
|
9240
|
+
if (env.GITHUB_ACTIONS) {
|
|
9241
|
+
return "GitHubActions";
|
|
9242
|
+
}
|
|
9243
|
+
if (env.BUILD_BUILDID) {
|
|
9244
|
+
return "AzureDevOps";
|
|
9245
|
+
}
|
|
9246
|
+
if (env.JENKINS_URL) {
|
|
9247
|
+
return "Jenkins";
|
|
9248
|
+
}
|
|
9249
|
+
if (env.CIRCLECI) {
|
|
9250
|
+
return "CircleCI";
|
|
9251
|
+
}
|
|
9252
|
+
if (env.GITLAB_CI) {
|
|
9253
|
+
return "GitLab";
|
|
9254
|
+
}
|
|
9255
|
+
if (env.CI) {
|
|
9256
|
+
return "Generic";
|
|
9257
|
+
}
|
|
9258
|
+
return "unknown";
|
|
9259
|
+
}
|
|
9260
|
+
function buildCommonProperties(sessionId = (0, import_uuid.v4)()) {
|
|
9261
|
+
return {
|
|
9262
|
+
appName: "sentinel-cli",
|
|
9263
|
+
appVersion: readAppVersion(),
|
|
9264
|
+
nodeVersion: process.versions.node,
|
|
9265
|
+
platform: process.platform,
|
|
9266
|
+
arch: process.arch,
|
|
9267
|
+
osRelease: os4.release(),
|
|
9268
|
+
sessionId,
|
|
9269
|
+
ciEnvironment: detectCiEnvironment()
|
|
9270
|
+
};
|
|
9271
|
+
}
|
|
9272
|
+
|
|
9273
|
+
// src/telemetry/redact.ts
|
|
9274
|
+
init_cjs_shims();
|
|
9275
|
+
var EMAIL_RE = /[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,}/gi;
|
|
9276
|
+
var GUID_RE = /\b[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\b/gi;
|
|
9277
|
+
var JWT_RE = /(?<![A-Za-z0-9_-])eyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}(?![A-Za-z0-9_-])/g;
|
|
9278
|
+
var UNIX_PATH_RE = /(?<![A-Za-z0-9_./\\-])(?:\/[^\s]+\/([^\s/]+)|\/([^\s/]+))/g;
|
|
9279
|
+
var WIN_PATH_RE = /(?<![A-Za-z0-9_./\\-])(?:[a-zA-Z]:\\[^\s]+\\([^\s\\]+)|[a-zA-Z]:\\([^\s\\]+))/g;
|
|
9280
|
+
function redactString(input) {
|
|
9281
|
+
if (!input) {
|
|
9282
|
+
return input;
|
|
9283
|
+
}
|
|
9284
|
+
return input.replace(JWT_RE, "<jwt>").replace(EMAIL_RE, "<email>").replace(GUID_RE, "<guid>").replace(UNIX_PATH_RE, (_m, deepBase, rootBase) => `<redacted>/${deepBase ?? rootBase}`).replace(WIN_PATH_RE, (_m, deepBase, rootBase) => `<redacted>\\${deepBase ?? rootBase}`);
|
|
9285
|
+
}
|
|
9286
|
+
function redactError(error) {
|
|
9287
|
+
const name = error.name || "Error";
|
|
9288
|
+
const message = redactString(error.message ?? "");
|
|
9289
|
+
const stack = error.stack ? error.stack.split("\n").slice(0, 4).map((line) => redactString(line)).join("\n") : "";
|
|
9290
|
+
return {
|
|
9291
|
+
errorName: name,
|
|
9292
|
+
errorMessage: message,
|
|
9293
|
+
errorStack: stack
|
|
9294
|
+
};
|
|
9295
|
+
}
|
|
9296
|
+
|
|
9297
|
+
// src/telemetry/telemetryService.ts
|
|
9298
|
+
var TRACER_NAME = "sentinel-cli";
|
|
9299
|
+
var TRACER_VERSION = "1.0.0";
|
|
9300
|
+
var azureMonitorInitialized = false;
|
|
9301
|
+
var TelemetryService = class _TelemetryService {
|
|
9302
|
+
sharedProperties = {};
|
|
9303
|
+
commonProperties;
|
|
9304
|
+
enabled;
|
|
9305
|
+
initialized = false;
|
|
9306
|
+
disposed = false;
|
|
9307
|
+
tracer;
|
|
9308
|
+
constructor(options = {}) {
|
|
9309
|
+
this.enabled = _TelemetryService.resolveEnabled(options);
|
|
9310
|
+
this.commonProperties = buildCommonProperties(options.sessionId);
|
|
9311
|
+
if (this.enabled) {
|
|
9312
|
+
this.initialize(options.connectionString ?? APPLICATION_INSIGHTS_CONNECTION_STRING);
|
|
9313
|
+
}
|
|
9314
|
+
}
|
|
9315
|
+
/** Determine whether telemetry should be active for this process. */
|
|
9316
|
+
static resolveEnabled(options) {
|
|
9317
|
+
if (options.forceDisabled) {
|
|
9318
|
+
return false;
|
|
9319
|
+
}
|
|
9320
|
+
for (const name of TELEMETRY_OPT_OUT_ENV_VARS) {
|
|
9321
|
+
if (process.env[name] === "1" || process.env[name]?.toLowerCase() === "true") {
|
|
9322
|
+
return false;
|
|
9323
|
+
}
|
|
9324
|
+
}
|
|
9325
|
+
return true;
|
|
9326
|
+
}
|
|
9327
|
+
/**
|
|
9328
|
+
* Initialise the Azure Monitor OpenTelemetry distro exactly once per
|
|
9329
|
+
* process, then acquire this instance's tracer. `useAzureMonitor()`
|
|
9330
|
+
* installs global SDK state (TracerProvider, exporters, processors), so
|
|
9331
|
+
* it is guarded by a module-level flag; `trace.getTracer()` is cheap and
|
|
9332
|
+
* idempotent so it is safe to call for every instance.
|
|
9333
|
+
*
|
|
9334
|
+
* Resource configuration is applied via OpenTelemetry env vars, set
|
|
9335
|
+
* programmatically *before* `useAzureMonitor()` so they're observed by
|
|
9336
|
+
* the SDK's resource-detection bootstrap:
|
|
9337
|
+
*
|
|
9338
|
+
* - `OTEL_NODE_RESOURCE_DETECTORS` — restricted to `env,os,serviceinstance`
|
|
9339
|
+
* so the `HostDetector` is **never** registered. This suppresses
|
|
9340
|
+
* `host.name` (device hostname, PII like `User-MacBook-Pro.local`),
|
|
9341
|
+
* `host.id` (stable hardware fingerprint), and `host.arch`.
|
|
9342
|
+
* - `OTEL_SERVICE_NAME` — populates `service.name`, which Azure Monitor
|
|
9343
|
+
* maps to `cloud_RoleName`. Without this, the backend records the OTel
|
|
9344
|
+
* default `"unknown_service:node"`.
|
|
9345
|
+
* - `OTEL_RESOURCE_ATTRIBUTES` — adds `service.version` (no dedicated env
|
|
9346
|
+
* var exists for it).
|
|
9347
|
+
*
|
|
9348
|
+
* Each variable is set with `??=` so any caller-provided override (e.g.
|
|
9349
|
+
* tests, advanced users) wins.
|
|
9350
|
+
*/
|
|
9351
|
+
initialize(connectionString) {
|
|
9352
|
+
if (!azureMonitorInitialized) {
|
|
9353
|
+
process.env.OTEL_NODE_RESOURCE_DETECTORS ??= "env,os,serviceinstance";
|
|
9354
|
+
process.env.OTEL_SERVICE_NAME ??= TRACER_NAME;
|
|
9355
|
+
process.env.OTEL_RESOURCE_ATTRIBUTES ??= `service.version=${TRACER_VERSION}`;
|
|
9356
|
+
(0, import_monitor_opentelemetry.useAzureMonitor)({
|
|
9357
|
+
azureMonitorExporterOptions: { connectionString },
|
|
9358
|
+
tracesPerSecond: 0,
|
|
9359
|
+
samplingRatio: 1
|
|
9360
|
+
});
|
|
9361
|
+
azureMonitorInitialized = true;
|
|
9362
|
+
}
|
|
9363
|
+
this.tracer = import_api.trace.getTracer(TRACER_NAME, TRACER_VERSION);
|
|
9364
|
+
this.initialized = true;
|
|
9365
|
+
}
|
|
9366
|
+
/**
|
|
9367
|
+
* Merge common + shared + caller-supplied properties into a flat
|
|
9368
|
+
* {@link Attributes} bag suitable for an OTel span. Primitive values
|
|
9369
|
+
* (`number`, `boolean`) are passed through unchanged so that downstream
|
|
9370
|
+
* Azure Monitor / Log Analytics queries see their native types instead
|
|
9371
|
+
* of stringified versions (which would break numeric aggregations and
|
|
9372
|
+
* boolean comparisons).
|
|
9373
|
+
*/
|
|
9374
|
+
mergeAttributes(extra) {
|
|
9375
|
+
const result = {
|
|
9376
|
+
...this.commonProperties,
|
|
9377
|
+
...this.sharedProperties
|
|
9378
|
+
};
|
|
9379
|
+
if (extra) {
|
|
9380
|
+
for (const [key, value] of Object.entries(extra)) {
|
|
9381
|
+
if (value === void 0) {
|
|
9382
|
+
continue;
|
|
9383
|
+
}
|
|
9384
|
+
result[key] = value;
|
|
9385
|
+
}
|
|
9386
|
+
}
|
|
9387
|
+
return result;
|
|
9388
|
+
}
|
|
9389
|
+
event(eventName, data) {
|
|
9390
|
+
if (!this.enabled || this.disposed || !this.tracer) {
|
|
9391
|
+
return;
|
|
9392
|
+
}
|
|
9393
|
+
const span = this.tracer.startSpan(eventName, {
|
|
9394
|
+
attributes: this.mergeAttributes(data?.properties)
|
|
9395
|
+
});
|
|
9396
|
+
if (data?.measurements) {
|
|
9397
|
+
for (const [k, v] of Object.entries(data.measurements)) {
|
|
9398
|
+
span.setAttribute(k, v);
|
|
9399
|
+
}
|
|
9400
|
+
}
|
|
9401
|
+
span.end();
|
|
9402
|
+
}
|
|
9403
|
+
span(eventName, initialAttributes) {
|
|
9404
|
+
if (!this.enabled || this.disposed || !this.tracer) {
|
|
9405
|
+
return new NoopSpanContext(eventName, initialAttributes);
|
|
9406
|
+
}
|
|
9407
|
+
return new TelemetrySpanContext(
|
|
9408
|
+
this.tracer,
|
|
9409
|
+
eventName,
|
|
9410
|
+
initialAttributes,
|
|
9411
|
+
(extras) => this.mergeAttributes(extras)
|
|
9412
|
+
);
|
|
9413
|
+
}
|
|
9414
|
+
setSharedProperty(name, value) {
|
|
9415
|
+
if (value === void 0) {
|
|
9416
|
+
delete this.sharedProperties[name];
|
|
9417
|
+
} else {
|
|
9418
|
+
this.sharedProperties[name] = value;
|
|
9419
|
+
}
|
|
9420
|
+
}
|
|
9421
|
+
getSharedProperties() {
|
|
9422
|
+
return { ...this.sharedProperties };
|
|
9423
|
+
}
|
|
9424
|
+
async dispose() {
|
|
9425
|
+
if (this.disposed) {
|
|
9426
|
+
return;
|
|
9427
|
+
}
|
|
9428
|
+
this.disposed = true;
|
|
9429
|
+
if (!this.enabled || !this.initialized) {
|
|
9430
|
+
return;
|
|
9431
|
+
}
|
|
9432
|
+
try {
|
|
9433
|
+
await (0, import_monitor_opentelemetry.shutdownAzureMonitor)();
|
|
9434
|
+
} catch {
|
|
9435
|
+
} finally {
|
|
9436
|
+
this.tracer = void 0;
|
|
9437
|
+
azureMonitorInitialized = false;
|
|
9438
|
+
}
|
|
9439
|
+
}
|
|
9440
|
+
};
|
|
9441
|
+
var TelemetrySpanContext = class {
|
|
9442
|
+
startTime = Date.now();
|
|
9443
|
+
eventName;
|
|
9444
|
+
attributes;
|
|
9445
|
+
otSpan;
|
|
9446
|
+
requestId;
|
|
9447
|
+
mergeAttributes;
|
|
9448
|
+
ended = false;
|
|
9449
|
+
constructor(tracer, eventName, initialAttributes, mergeAttributes) {
|
|
9450
|
+
this.eventName = eventName;
|
|
9451
|
+
this.attributes = { ...initialAttributes ?? {} };
|
|
9452
|
+
this.requestId = this.attributes.requestId ?? import_common16.CorrelationService.createCorrelationContext();
|
|
9453
|
+
this.attributes.requestId = this.requestId;
|
|
9454
|
+
this.mergeAttributes = mergeAttributes;
|
|
9455
|
+
this.otSpan = tracer.startSpan(eventName, {
|
|
9456
|
+
attributes: this.mergeAttributes(this.attributes)
|
|
9457
|
+
});
|
|
9458
|
+
}
|
|
9459
|
+
getRequestId() {
|
|
9460
|
+
return this.requestId;
|
|
9461
|
+
}
|
|
9462
|
+
addAttributes(extra) {
|
|
9463
|
+
this.applyAttributes(extra);
|
|
9464
|
+
}
|
|
9465
|
+
end(extra) {
|
|
9466
|
+
if (this.ended) {
|
|
9467
|
+
return;
|
|
9468
|
+
}
|
|
9469
|
+
this.applyAttributes(extra);
|
|
9470
|
+
this.finalize();
|
|
9471
|
+
}
|
|
9472
|
+
error(err, extra) {
|
|
9473
|
+
if (this.ended) {
|
|
9474
|
+
return;
|
|
9475
|
+
}
|
|
9476
|
+
const redacted = redactError(err);
|
|
9477
|
+
this.applyAttributes({ ...extra, ...redacted, success: false });
|
|
9478
|
+
const sanitized = new Error(redacted.errorMessage);
|
|
9479
|
+
sanitized.name = redacted.errorName;
|
|
9480
|
+
sanitized.stack = redacted.errorStack;
|
|
9481
|
+
this.otSpan.recordException(sanitized);
|
|
9482
|
+
this.otSpan.setStatus({ code: import_api.SpanStatusCode.ERROR, message: redacted.errorMessage });
|
|
9483
|
+
this.finalize();
|
|
9484
|
+
}
|
|
9485
|
+
/**
|
|
9486
|
+
* Merge non-undefined entries into both the local bag and the OTel span.
|
|
9487
|
+
* Values keep their native primitive type (`string | number | boolean`)
|
|
9488
|
+
* so the backing SDK records typed attributes rather than stringified ones.
|
|
9489
|
+
*/
|
|
9490
|
+
applyAttributes(extra) {
|
|
9491
|
+
if (!extra) {
|
|
9492
|
+
return;
|
|
9493
|
+
}
|
|
9494
|
+
for (const [k, v] of Object.entries(extra)) {
|
|
9495
|
+
if (v === void 0) {
|
|
9496
|
+
continue;
|
|
9497
|
+
}
|
|
9498
|
+
this.attributes[k] = v;
|
|
9499
|
+
this.otSpan.setAttribute(k, v);
|
|
9500
|
+
}
|
|
7882
9501
|
}
|
|
7883
|
-
|
|
7884
|
-
|
|
7885
|
-
|
|
7886
|
-
|
|
9502
|
+
/** Stamp duration, close the OTel span, and flip the ended flag. */
|
|
9503
|
+
finalize() {
|
|
9504
|
+
this.ended = true;
|
|
9505
|
+
const finalAttrs = this.mergeAttributes(this.attributes);
|
|
9506
|
+
for (const [k, v] of Object.entries(finalAttrs)) {
|
|
9507
|
+
if (v !== void 0) {
|
|
9508
|
+
this.otSpan.setAttribute(k, v);
|
|
9509
|
+
}
|
|
7887
9510
|
}
|
|
7888
|
-
|
|
9511
|
+
this.otSpan.setAttribute("durationMs", Date.now() - this.startTime);
|
|
9512
|
+
this.otSpan.end();
|
|
7889
9513
|
}
|
|
7890
9514
|
};
|
|
7891
|
-
|
|
7892
|
-
|
|
7893
|
-
|
|
7894
|
-
|
|
7895
|
-
|
|
7896
|
-
|
|
7897
|
-
|
|
7898
|
-
|
|
7899
|
-
|
|
7900
|
-
|
|
7901
|
-
|
|
7902
|
-
|
|
7903
|
-
|
|
7904
|
-
|
|
7905
|
-
|
|
7906
|
-
|
|
9515
|
+
var NoopSpanContext = class {
|
|
9516
|
+
startTime = Date.now();
|
|
9517
|
+
eventName;
|
|
9518
|
+
attributes;
|
|
9519
|
+
requestId;
|
|
9520
|
+
constructor(eventName, initialAttributes) {
|
|
9521
|
+
this.eventName = eventName;
|
|
9522
|
+
this.attributes = { ...initialAttributes ?? {} };
|
|
9523
|
+
this.requestId = this.attributes.requestId ?? import_common16.CorrelationService.createCorrelationContext();
|
|
9524
|
+
this.attributes.requestId = this.requestId;
|
|
9525
|
+
}
|
|
9526
|
+
getRequestId() {
|
|
9527
|
+
return this.requestId;
|
|
9528
|
+
}
|
|
9529
|
+
addAttributes(extra) {
|
|
9530
|
+
for (const [k, v] of Object.entries(extra)) {
|
|
9531
|
+
if (v !== void 0) {
|
|
9532
|
+
this.attributes[k] = v;
|
|
9533
|
+
}
|
|
7907
9534
|
}
|
|
7908
9535
|
}
|
|
9536
|
+
end() {
|
|
9537
|
+
}
|
|
9538
|
+
error() {
|
|
9539
|
+
}
|
|
7909
9540
|
};
|
|
7910
9541
|
|
|
9542
|
+
// src/telemetry/index.ts
|
|
9543
|
+
var singleton;
|
|
9544
|
+
function getTelemetry(options) {
|
|
9545
|
+
if (!singleton) {
|
|
9546
|
+
singleton = new TelemetryService(options);
|
|
9547
|
+
}
|
|
9548
|
+
return singleton;
|
|
9549
|
+
}
|
|
9550
|
+
|
|
7911
9551
|
// src/services/getToken.ts
|
|
7912
9552
|
async function getToken(env, scopes, clientId) {
|
|
7913
9553
|
let provider = null;
|
|
@@ -7921,26 +9561,34 @@ async function getToken(env, scopes, clientId) {
|
|
|
7921
9561
|
provider = TokenProviderFactory.createProvider(env, "msal_cache" /* MsalCache */, options);
|
|
7922
9562
|
}
|
|
7923
9563
|
const token = await provider.getAccessToken();
|
|
9564
|
+
stampTenantTelemetry(token);
|
|
7924
9565
|
return token;
|
|
7925
9566
|
}
|
|
9567
|
+
function stampTenantTelemetry(token) {
|
|
9568
|
+
try {
|
|
9569
|
+
const tenantId = (0, import_common17.extractTenantId)(token);
|
|
9570
|
+
getTelemetry().setSharedProperty("tenantId", tenantId || "");
|
|
9571
|
+
} catch {
|
|
9572
|
+
}
|
|
9573
|
+
}
|
|
7926
9574
|
|
|
7927
|
-
// src/client/
|
|
9575
|
+
// src/client/jobs/index.ts
|
|
7928
9576
|
init_cjs_shims();
|
|
7929
|
-
var
|
|
9577
|
+
var import_common19 = __toESM(require_src());
|
|
7930
9578
|
|
|
7931
9579
|
// src/utils/headerBuilder.ts
|
|
7932
9580
|
init_cjs_shims();
|
|
7933
|
-
var
|
|
9581
|
+
var import_common18 = __toESM(require_src());
|
|
7934
9582
|
function buildApiHeaders(token, requestId, extra) {
|
|
7935
9583
|
const base = {};
|
|
7936
9584
|
if (requestId) {
|
|
7937
|
-
base[
|
|
9585
|
+
base[import_common18.HTTP_HEADER.REQUEST_ID] = requestId;
|
|
7938
9586
|
}
|
|
7939
|
-
if (!extra || !(
|
|
7940
|
-
base[
|
|
9587
|
+
if (!extra || !(import_common18.HTTP_HEADER.CONTENT_TYPE in extra)) {
|
|
9588
|
+
base[import_common18.HTTP_HEADER.CONTENT_TYPE] = import_common18.HTTP_HEADER.APPLICATION_JSON;
|
|
7941
9589
|
}
|
|
7942
9590
|
if (token) {
|
|
7943
|
-
base[
|
|
9591
|
+
base[import_common18.HTTP_HEADER.AUTHORIZATION] = `${import_common18.HTTP_HEADER.BEARER_PREFIX}${token}`;
|
|
7944
9592
|
}
|
|
7945
9593
|
const merged = { ...base, ...extra || {} };
|
|
7946
9594
|
return Object.fromEntries(
|
|
@@ -7957,136 +9605,599 @@ var noopSpan = {
|
|
|
7957
9605
|
},
|
|
7958
9606
|
error: () => {
|
|
7959
9607
|
}
|
|
7960
|
-
};
|
|
7961
|
-
var noopTelemetry = {
|
|
7962
|
-
span: () => noopSpan
|
|
7963
|
-
};
|
|
9608
|
+
};
|
|
9609
|
+
var noopTelemetry = {
|
|
9610
|
+
span: () => noopSpan
|
|
9611
|
+
};
|
|
9612
|
+
|
|
9613
|
+
// src/client/jobs/index.ts
|
|
9614
|
+
function createJobApiClient(env, region) {
|
|
9615
|
+
const requestService = new import_common19.RequestService(noopTelemetry, buildApiHeaders);
|
|
9616
|
+
return new import_common19.JobApiClient({
|
|
9617
|
+
requestService,
|
|
9618
|
+
baseUrl: env.regions[region].gatewayEndpoint
|
|
9619
|
+
});
|
|
9620
|
+
}
|
|
9621
|
+
|
|
9622
|
+
// src/utils/parseRegion.ts
|
|
9623
|
+
init_cjs_shims();
|
|
9624
|
+
var import_common20 = __toESM(require_src());
|
|
9625
|
+
function parseRegion(value) {
|
|
9626
|
+
if (Object.values(import_common20.Region).includes(value)) {
|
|
9627
|
+
return value;
|
|
9628
|
+
}
|
|
9629
|
+
throw new Error(`Invalid region "${value}". Valid regions: ${Object.values(import_common20.Region).join(", ")}`);
|
|
9630
|
+
}
|
|
9631
|
+
|
|
9632
|
+
// src/commands/jobs/jobDelete.ts
|
|
9633
|
+
function addJobDeleteCommand(jobCommand) {
|
|
9634
|
+
jobCommand.command("delete <jobName>").description("Delete a scheduled job").option("-r, --region <region>", "Target region (default: global)", import_common21.Region.Global).action(async (jobName, options) => {
|
|
9635
|
+
try {
|
|
9636
|
+
const apiEnv4 = (0, import_common21.getApiEnv)(import_common21.SecurityPlatformEnvironment.Production);
|
|
9637
|
+
const accessToken = await getToken(apiEnv4);
|
|
9638
|
+
const region = parseRegion(options.region);
|
|
9639
|
+
const jobApiClient = createJobApiClient(apiEnv4, region);
|
|
9640
|
+
const jobService = new JobService(jobApiClient);
|
|
9641
|
+
await deleteJob(jobService, accessToken, jobName);
|
|
9642
|
+
console.log(`Job "${jobName}" deleted successfully.`);
|
|
9643
|
+
} catch (error) {
|
|
9644
|
+
handleApiError("deleting job", error);
|
|
9645
|
+
}
|
|
9646
|
+
});
|
|
9647
|
+
}
|
|
9648
|
+
|
|
9649
|
+
// src/commands/jobs/jobDisable.ts
|
|
9650
|
+
init_cjs_shims();
|
|
9651
|
+
var import_common22 = __toESM(require_src());
|
|
9652
|
+
function addJobDisableCommand(jobCommand) {
|
|
9653
|
+
jobCommand.command("disable <jobName>").description("Disable a scheduled job").option("-r, --region <region>", "Target region (default: global)", import_common22.Region.Global).action(async (jobName, options) => {
|
|
9654
|
+
try {
|
|
9655
|
+
const apiEnv4 = (0, import_common22.getApiEnv)(import_common22.SecurityPlatformEnvironment.Production);
|
|
9656
|
+
const accessToken = await getToken(apiEnv4);
|
|
9657
|
+
const region = parseRegion(options.region);
|
|
9658
|
+
const jobApiClient = createJobApiClient(apiEnv4, region);
|
|
9659
|
+
const jobService = new JobService(jobApiClient);
|
|
9660
|
+
await disableJob(jobService, accessToken, jobName);
|
|
9661
|
+
console.log(`Job "${jobName}" disabled successfully.`);
|
|
9662
|
+
} catch (error) {
|
|
9663
|
+
handleApiError("disabling job", error);
|
|
9664
|
+
}
|
|
9665
|
+
});
|
|
9666
|
+
}
|
|
9667
|
+
|
|
9668
|
+
// src/commands/jobs/jobDownload.ts
|
|
9669
|
+
init_cjs_shims();
|
|
9670
|
+
var import_common23 = __toESM(require_src());
|
|
9671
|
+
function addJobDownloadCommand(jobCommand) {
|
|
9672
|
+
jobCommand.command("download <jobName>").description("Download the notebook of a scheduled job").option("-o, --output <path>", "Output file path (defaults to <jobName>.ipynb)").option("-r, --region <region>", "Target region (default: global)", import_common23.Region.Global).action(async (jobName, options) => {
|
|
9673
|
+
try {
|
|
9674
|
+
const apiEnv4 = (0, import_common23.getApiEnv)(import_common23.SecurityPlatformEnvironment.Production);
|
|
9675
|
+
const accessToken = await getToken(apiEnv4);
|
|
9676
|
+
const region = parseRegion(options.region);
|
|
9677
|
+
const jobApiClient = createJobApiClient(apiEnv4, region);
|
|
9678
|
+
const jobService = new JobService(jobApiClient);
|
|
9679
|
+
const writtenPath = await downloadJob(jobService, accessToken, jobName, options.output);
|
|
9680
|
+
console.log(`Notebook downloaded to: ${writtenPath}`);
|
|
9681
|
+
} catch (error) {
|
|
9682
|
+
handleApiError("downloading job notebook", error);
|
|
9683
|
+
}
|
|
9684
|
+
});
|
|
9685
|
+
}
|
|
9686
|
+
|
|
9687
|
+
// src/commands/jobs/jobEnable.ts
|
|
9688
|
+
init_cjs_shims();
|
|
9689
|
+
var import_common24 = __toESM(require_src());
|
|
9690
|
+
function addJobEnableCommand(jobCommand) {
|
|
9691
|
+
jobCommand.command("enable <jobName>").description("Enable a scheduled job").option("-r, --region <region>", "Target region (default: global)", import_common24.Region.Global).action(async (jobName, options) => {
|
|
9692
|
+
try {
|
|
9693
|
+
const apiEnv4 = (0, import_common24.getApiEnv)(import_common24.SecurityPlatformEnvironment.Production);
|
|
9694
|
+
const accessToken = await getToken(apiEnv4);
|
|
9695
|
+
const region = parseRegion(options.region);
|
|
9696
|
+
const jobApiClient = createJobApiClient(apiEnv4, region);
|
|
9697
|
+
const jobService = new JobService(jobApiClient);
|
|
9698
|
+
await enableJob(jobService, accessToken, jobName);
|
|
9699
|
+
console.log(`Job "${jobName}" enabled successfully.`);
|
|
9700
|
+
} catch (error) {
|
|
9701
|
+
handleApiError("enabling job", error);
|
|
9702
|
+
}
|
|
9703
|
+
});
|
|
9704
|
+
}
|
|
9705
|
+
|
|
9706
|
+
// src/commands/jobs/jobList.ts
|
|
9707
|
+
init_cjs_shims();
|
|
9708
|
+
var import_common25 = __toESM(require_src());
|
|
9709
|
+
var JOB_COLUMNS = [
|
|
9710
|
+
{ header: "NAME", key: (j) => j.jobName },
|
|
9711
|
+
{ header: "TYPE", key: (j) => j.jobType },
|
|
9712
|
+
{ header: "DISABLED", key: (j) => String(j.isDisabled) }
|
|
9713
|
+
];
|
|
9714
|
+
function addJobListCommand(jobCommand) {
|
|
9715
|
+
jobCommand.command("list").description("List all scheduled jobs").option("-r, --region <region>", "Target region (default: global)", import_common25.Region.Global).action(async (options) => {
|
|
9716
|
+
try {
|
|
9717
|
+
const apiEnv4 = (0, import_common25.getApiEnv)(import_common25.SecurityPlatformEnvironment.Production);
|
|
9718
|
+
const accessToken = await getToken(apiEnv4);
|
|
9719
|
+
const region = parseRegion(options.region);
|
|
9720
|
+
const jobApiClient = createJobApiClient(apiEnv4, region);
|
|
9721
|
+
const jobService = new JobService(jobApiClient);
|
|
9722
|
+
const jobs = await listJobs(jobService, accessToken);
|
|
9723
|
+
const fmt = new OutputFormatter();
|
|
9724
|
+
fmt.print(jobs, JOB_COLUMNS);
|
|
9725
|
+
} catch (error) {
|
|
9726
|
+
handleApiError("listing jobs", error);
|
|
9727
|
+
}
|
|
9728
|
+
});
|
|
9729
|
+
}
|
|
9730
|
+
|
|
9731
|
+
// src/commands/jobs/jobRunCancel.ts
|
|
9732
|
+
init_cjs_shims();
|
|
9733
|
+
var import_common26 = __toESM(require_src());
|
|
9734
|
+
function addJobRunCancelCommand(runCommand) {
|
|
9735
|
+
runCommand.command("cancel <jobName> <runId>").description("Cancel a specific job run").option("-r, --region <region>", "Target region (default: global)", import_common26.Region.Global).action(async (jobName, runId, options) => {
|
|
9736
|
+
try {
|
|
9737
|
+
const apiEnv4 = (0, import_common26.getApiEnv)(import_common26.SecurityPlatformEnvironment.Production);
|
|
9738
|
+
const accessToken = await getToken(apiEnv4);
|
|
9739
|
+
const region = parseRegion(options.region);
|
|
9740
|
+
const jobApiClient = createJobApiClient(apiEnv4, region);
|
|
9741
|
+
const jobService = new JobService(jobApiClient);
|
|
9742
|
+
await cancelJobRun(jobService, accessToken, jobName, runId);
|
|
9743
|
+
console.log(`Run "${runId}" for job "${jobName}" cancelled successfully.`);
|
|
9744
|
+
} catch (error) {
|
|
9745
|
+
handleApiError("cancelling job run", error);
|
|
9746
|
+
}
|
|
9747
|
+
});
|
|
9748
|
+
}
|
|
9749
|
+
|
|
9750
|
+
// src/commands/jobs/jobRunList.ts
|
|
9751
|
+
init_cjs_shims();
|
|
9752
|
+
var import_common27 = __toESM(require_src());
|
|
9753
|
+
var RUN_COLUMNS = [
|
|
9754
|
+
{ header: "RUN ID", key: (r) => r.jobRunId ?? "" },
|
|
9755
|
+
{ header: "STATUS", key: (r) => r.status ?? "" },
|
|
9756
|
+
{ header: "STARTED", key: (r) => r.startTime ?? "" },
|
|
9757
|
+
{ header: "ENDED", key: (r) => r.endTime ?? "" }
|
|
9758
|
+
];
|
|
9759
|
+
function addJobRunListCommand(runCommand) {
|
|
9760
|
+
runCommand.command("list <jobName>").description("List all runs for a scheduled job").option("-r, --region <region>", "Target region (default: global)", import_common27.Region.Global).action(async (jobName, options) => {
|
|
9761
|
+
try {
|
|
9762
|
+
const apiEnv4 = (0, import_common27.getApiEnv)(import_common27.SecurityPlatformEnvironment.Production);
|
|
9763
|
+
const accessToken = await getToken(apiEnv4);
|
|
9764
|
+
const region = parseRegion(options.region);
|
|
9765
|
+
const jobApiClient = createJobApiClient(apiEnv4, region);
|
|
9766
|
+
const jobService = new JobService(jobApiClient);
|
|
9767
|
+
const runs = await listJobRuns(jobService, accessToken, jobName);
|
|
9768
|
+
const fmt = new OutputFormatter();
|
|
9769
|
+
fmt.print(runs, RUN_COLUMNS);
|
|
9770
|
+
} catch (error) {
|
|
9771
|
+
handleApiError("listing job runs", error);
|
|
9772
|
+
}
|
|
9773
|
+
});
|
|
9774
|
+
}
|
|
9775
|
+
|
|
9776
|
+
// src/commands/jobs/jobRunNotebookDownload.ts
|
|
9777
|
+
init_cjs_shims();
|
|
9778
|
+
var import_common28 = __toESM(require_src());
|
|
9779
|
+
function addJobRunNotebookDownloadCommand(notebookCommand) {
|
|
9780
|
+
notebookCommand.command("download <jobName> <runId>").description("Download the notebook snapshot of a job run").option("-o, --output <path>", "Output file path (defaults to <jobName>_<runId>.ipynb)").option("-r, --region <region>", "Target region (default: global)", import_common28.Region.Global).action(async (jobName, runId, options) => {
|
|
9781
|
+
try {
|
|
9782
|
+
const apiEnv4 = (0, import_common28.getApiEnv)(import_common28.SecurityPlatformEnvironment.Production);
|
|
9783
|
+
const accessToken = await getToken(apiEnv4);
|
|
9784
|
+
const region = parseRegion(options.region);
|
|
9785
|
+
const jobApiClient = createJobApiClient(apiEnv4, region);
|
|
9786
|
+
const jobService = new JobService(jobApiClient);
|
|
9787
|
+
const writtenPath = await downloadJobRunNotebook(jobService, accessToken, jobName, runId, options.output);
|
|
9788
|
+
console.log(`Notebook downloaded to: ${writtenPath}`);
|
|
9789
|
+
} catch (error) {
|
|
9790
|
+
handleApiError("downloading job run notebook", error);
|
|
9791
|
+
}
|
|
9792
|
+
});
|
|
9793
|
+
}
|
|
9794
|
+
|
|
9795
|
+
// src/commands/jobs/jobRunShow.ts
|
|
9796
|
+
init_cjs_shims();
|
|
9797
|
+
var import_common29 = __toESM(require_src());
|
|
9798
|
+
var RUN_DETAIL_COLUMNS = [
|
|
9799
|
+
{ header: "FIELD", key: (f) => f.label },
|
|
9800
|
+
{ header: "VALUE", key: (f) => f.value }
|
|
9801
|
+
];
|
|
9802
|
+
function addJobRunShowCommand(runCommand) {
|
|
9803
|
+
runCommand.command("show <jobName> <runId>").description("Show the details of a job run").option("-r, --region <region>", "Target region (default: global)", import_common29.Region.Global).action(async (jobName, runId, options) => {
|
|
9804
|
+
try {
|
|
9805
|
+
const apiEnv4 = (0, import_common29.getApiEnv)(import_common29.SecurityPlatformEnvironment.Production);
|
|
9806
|
+
const accessToken = await getToken(apiEnv4);
|
|
9807
|
+
const region = parseRegion(options.region);
|
|
9808
|
+
const jobApiClient = createJobApiClient(apiEnv4, region);
|
|
9809
|
+
const jobService = new JobService(jobApiClient);
|
|
9810
|
+
const run = await getJobRun(jobService, accessToken, jobName, runId);
|
|
9811
|
+
printRunDetails(run);
|
|
9812
|
+
} catch (error) {
|
|
9813
|
+
handleApiError("showing job run", error);
|
|
9814
|
+
}
|
|
9815
|
+
});
|
|
9816
|
+
}
|
|
9817
|
+
function printRunDetails(run) {
|
|
9818
|
+
const fields = [
|
|
9819
|
+
{ label: "Run ID", value: run.jobRunId ?? "" },
|
|
9820
|
+
{ label: "Status", value: run.status ?? "" },
|
|
9821
|
+
{ label: "Schedule", value: run.scheduleName ?? "" },
|
|
9822
|
+
{ label: "Started", value: run.startTime ?? "" },
|
|
9823
|
+
{ label: "Ended", value: run.endTime ?? "" },
|
|
9824
|
+
{ label: "Error", value: run.error?.errorMessage ?? "" }
|
|
9825
|
+
];
|
|
9826
|
+
const fmt = new OutputFormatter();
|
|
9827
|
+
fmt.print(fields, RUN_DETAIL_COLUMNS);
|
|
9828
|
+
}
|
|
9829
|
+
|
|
9830
|
+
// src/commands/jobs/jobRunStart.ts
|
|
9831
|
+
init_cjs_shims();
|
|
9832
|
+
var import_common30 = __toESM(require_src());
|
|
9833
|
+
function addJobRunStartCommand(runCommand) {
|
|
9834
|
+
runCommand.command("start <jobName>").description("Start an ad-hoc run of a scheduled job").option("-r, --region <region>", "Target region (default: global)", import_common30.Region.Global).action(async (jobName, options) => {
|
|
9835
|
+
try {
|
|
9836
|
+
const apiEnv4 = (0, import_common30.getApiEnv)(import_common30.SecurityPlatformEnvironment.Production);
|
|
9837
|
+
const accessToken = await getToken(apiEnv4);
|
|
9838
|
+
const region = parseRegion(options.region);
|
|
9839
|
+
const jobApiClient = createJobApiClient(apiEnv4, region);
|
|
9840
|
+
const jobService = new JobService(jobApiClient);
|
|
9841
|
+
const run = await startJobRun(jobService, accessToken, jobName);
|
|
9842
|
+
console.log(`Job run started. Run ID: ${run.jobRunId ?? "(unknown)"}`);
|
|
9843
|
+
} catch (error) {
|
|
9844
|
+
handleApiError("starting job run", error);
|
|
9845
|
+
}
|
|
9846
|
+
});
|
|
9847
|
+
}
|
|
9848
|
+
|
|
9849
|
+
// src/commands/jobs/jobShow.ts
|
|
9850
|
+
init_cjs_shims();
|
|
9851
|
+
var import_common31 = __toESM(require_src());
|
|
9852
|
+
var JOB_DETAIL_COLUMNS = [
|
|
9853
|
+
{ header: "FIELD", key: (f) => f.label },
|
|
9854
|
+
{ header: "VALUE", key: (f) => f.value }
|
|
9855
|
+
];
|
|
9856
|
+
function addJobShowCommand(jobCommand) {
|
|
9857
|
+
jobCommand.command("show <jobName>").description("Show the details of a scheduled job").option("-r, --region <region>", "Target region (default: global)", import_common31.Region.Global).action(async (jobName, options) => {
|
|
9858
|
+
try {
|
|
9859
|
+
const apiEnv4 = (0, import_common31.getApiEnv)(import_common31.SecurityPlatformEnvironment.Production);
|
|
9860
|
+
const accessToken = await getToken(apiEnv4);
|
|
9861
|
+
const region = parseRegion(options.region);
|
|
9862
|
+
const jobApiClient = createJobApiClient(apiEnv4, region);
|
|
9863
|
+
const jobService = new JobService(jobApiClient);
|
|
9864
|
+
const job = await getJob(jobService, accessToken, jobName);
|
|
9865
|
+
printJobDetails(job);
|
|
9866
|
+
} catch (error) {
|
|
9867
|
+
handleApiError("showing job", error);
|
|
9868
|
+
}
|
|
9869
|
+
});
|
|
9870
|
+
}
|
|
9871
|
+
function printJobDetails(job) {
|
|
9872
|
+
const def = job.jobDefinition;
|
|
9873
|
+
const fields = [
|
|
9874
|
+
{ label: "Name", value: def.jobName ?? "" },
|
|
9875
|
+
{ label: "Type", value: def.jobType ?? "" },
|
|
9876
|
+
{ label: "Disabled", value: String(def.isDisabled ?? false) },
|
|
9877
|
+
{ label: "Description", value: def.description ?? "" },
|
|
9878
|
+
{ label: "Spark Pool", value: def.computeInfo?.friendlyName ?? "" },
|
|
9879
|
+
{ label: "Created At", value: def.createdAt ?? "" },
|
|
9880
|
+
{ label: "Last Updated At", value: def.lastUpdatedAt ?? "" }
|
|
9881
|
+
];
|
|
9882
|
+
const fmt = new OutputFormatter();
|
|
9883
|
+
fmt.print(fields, JOB_DETAIL_COLUMNS);
|
|
9884
|
+
}
|
|
9885
|
+
|
|
9886
|
+
// src/commands/lake/database.ts
|
|
9887
|
+
init_cjs_shims();
|
|
9888
|
+
var import_common36 = __toESM(require_src());
|
|
9889
|
+
|
|
9890
|
+
// src/actions/lake/index.ts
|
|
9891
|
+
init_cjs_shims();
|
|
9892
|
+
|
|
9893
|
+
// src/actions/lake/listDatabases.ts
|
|
9894
|
+
init_cjs_shims();
|
|
9895
|
+
var import_common32 = __toESM(require_src());
|
|
9896
|
+
async function listDatabases(databaseService, accessToken) {
|
|
9897
|
+
const requestId = import_common32.CorrelationService.createCorrelationContext();
|
|
9898
|
+
console.info("Fetching databases...");
|
|
9899
|
+
return databaseService.listDatabases(accessToken, requestId);
|
|
9900
|
+
}
|
|
9901
|
+
|
|
9902
|
+
// src/actions/lake/listTables.ts
|
|
9903
|
+
init_cjs_shims();
|
|
9904
|
+
var import_common33 = __toESM(require_src());
|
|
9905
|
+
async function listTables(tableService, accessToken, database) {
|
|
9906
|
+
const requestId = import_common33.CorrelationService.createCorrelationContext();
|
|
9907
|
+
const scope = database ? ` for database "${database.databaseName}"` : "";
|
|
9908
|
+
console.info(`Fetching lake tables${scope}...`);
|
|
9909
|
+
return tableService.listTables(accessToken, requestId, database);
|
|
9910
|
+
}
|
|
9911
|
+
|
|
9912
|
+
// src/services/lake/index.ts
|
|
9913
|
+
init_cjs_shims();
|
|
9914
|
+
|
|
9915
|
+
// src/services/lake/databaseService.ts
|
|
9916
|
+
init_cjs_shims();
|
|
9917
|
+
var DatabaseService = class {
|
|
9918
|
+
constructor(lakeApiClient) {
|
|
9919
|
+
this.lakeApiClient = lakeApiClient;
|
|
9920
|
+
}
|
|
9921
|
+
async listDatabases(accessToken, requestId) {
|
|
9922
|
+
return this.lakeApiClient.fetchDatabases(accessToken, requestId);
|
|
9923
|
+
}
|
|
9924
|
+
};
|
|
9925
|
+
|
|
9926
|
+
// src/services/lake/tableService.ts
|
|
9927
|
+
init_cjs_shims();
|
|
9928
|
+
var TableService = class {
|
|
9929
|
+
constructor(lakeApiClient) {
|
|
9930
|
+
this.lakeApiClient = lakeApiClient;
|
|
9931
|
+
}
|
|
9932
|
+
async listTables(accessToken, requestId, database) {
|
|
9933
|
+
return this.lakeApiClient.fetchLakeTables(accessToken, requestId, database);
|
|
9934
|
+
}
|
|
9935
|
+
};
|
|
9936
|
+
|
|
9937
|
+
// src/services/lake/databaseLookup.ts
|
|
9938
|
+
init_cjs_shims();
|
|
9939
|
+
var SYSTEM_TABLES_DISPLAY_NAME = "System tables";
|
|
9940
|
+
var DEFAULT_DATABASE = { databaseName: "default" };
|
|
9941
|
+
async function lookupDatabase(options, lakeApiClient, accessToken) {
|
|
9942
|
+
if (options.databaseId) {
|
|
9943
|
+
if (options.databaseId === SYSTEM_TABLES_DISPLAY_NAME) {
|
|
9944
|
+
return DEFAULT_DATABASE;
|
|
9945
|
+
}
|
|
9946
|
+
return lookupDatabaseById(options.databaseId, lakeApiClient, accessToken);
|
|
9947
|
+
}
|
|
9948
|
+
if (options.databaseName) {
|
|
9949
|
+
if (options.databaseName === SYSTEM_TABLES_DISPLAY_NAME) {
|
|
9950
|
+
return DEFAULT_DATABASE;
|
|
9951
|
+
}
|
|
9952
|
+
return lookupDatabaseByName(options.databaseName, lakeApiClient, accessToken);
|
|
9953
|
+
}
|
|
9954
|
+
return void 0;
|
|
9955
|
+
}
|
|
9956
|
+
async function lookupDatabaseById(databaseId, lakeApiClient, accessToken) {
|
|
9957
|
+
const databaseService = new DatabaseService(lakeApiClient);
|
|
9958
|
+
const databases = await listDatabases(databaseService, accessToken);
|
|
9959
|
+
const match = databases.find((db) => db.databaseName === databaseId);
|
|
9960
|
+
if (!match) {
|
|
9961
|
+
console.error(
|
|
9962
|
+
`Error: database "${databaseId}" not found. Run "sentinel database list" to see available databases.`
|
|
9963
|
+
);
|
|
9964
|
+
process.exit(1);
|
|
9965
|
+
}
|
|
9966
|
+
return match;
|
|
9967
|
+
}
|
|
9968
|
+
async function lookupDatabaseByName(databaseName, lakeApiClient, accessToken) {
|
|
9969
|
+
const databaseService = new DatabaseService(lakeApiClient);
|
|
9970
|
+
const databases = await listDatabases(databaseService, accessToken);
|
|
9971
|
+
const match = databases.find((db) => db.sentinelWorkspace?.name === databaseName);
|
|
9972
|
+
if (!match) {
|
|
9973
|
+
console.error(
|
|
9974
|
+
`Error: database "${databaseName}" not found. Run "sentinel database list" to see available databases.`
|
|
9975
|
+
);
|
|
9976
|
+
process.exit(1);
|
|
9977
|
+
}
|
|
9978
|
+
return match;
|
|
9979
|
+
}
|
|
7964
9980
|
|
|
7965
9981
|
// src/client/lake/index.ts
|
|
9982
|
+
init_cjs_shims();
|
|
9983
|
+
var import_common34 = __toESM(require_src());
|
|
7966
9984
|
function createLakeApiClient(env) {
|
|
7967
|
-
const requestService = new
|
|
7968
|
-
return new
|
|
9985
|
+
const requestService = new import_common34.RequestService(noopTelemetry, buildApiHeaders);
|
|
9986
|
+
return new import_common34.LakeApiClient({
|
|
7969
9987
|
requestService,
|
|
7970
9988
|
telemetry: noopTelemetry,
|
|
7971
9989
|
baseUrl: env.gatewayEndpoint
|
|
7972
9990
|
});
|
|
7973
9991
|
}
|
|
7974
9992
|
|
|
7975
|
-
// src/
|
|
9993
|
+
// src/telemetry/events.ts
|
|
7976
9994
|
init_cjs_shims();
|
|
7977
|
-
var
|
|
7978
|
-
|
|
7979
|
-
|
|
7980
|
-
|
|
7981
|
-
|
|
7982
|
-
|
|
9995
|
+
var CliEvents = {
|
|
9996
|
+
/** Fired exactly once per CLI process, before Commander parses argv. */
|
|
9997
|
+
Invoked: "cli.invoked",
|
|
9998
|
+
// Top-level commands
|
|
9999
|
+
Login: "cli.login",
|
|
10000
|
+
Logout: "cli.logout",
|
|
10001
|
+
Token: "cli.token",
|
|
10002
|
+
Update: "cli.update",
|
|
10003
|
+
// `package` group
|
|
10004
|
+
PackageCreateZip: "cli.package.createzip",
|
|
10005
|
+
PackageValidate: "cli.package.validate",
|
|
10006
|
+
// `job` group
|
|
10007
|
+
JobPublish: "cli.job.publish",
|
|
10008
|
+
// `database` group
|
|
10009
|
+
DatabaseList: "cli.database.list",
|
|
10010
|
+
// `table` group
|
|
10011
|
+
TableList: "cli.table.list",
|
|
10012
|
+
TableShow: "cli.table.show"
|
|
10013
|
+
};
|
|
10014
|
+
|
|
10015
|
+
// src/telemetry/withCommandSpan.ts
|
|
10016
|
+
init_cjs_shims();
|
|
10017
|
+
|
|
10018
|
+
// src/telemetry/commandInterceptor.ts
|
|
10019
|
+
init_cjs_shims();
|
|
10020
|
+
var ATTACHED_FLAG = /* @__PURE__ */ Symbol.for("sentinel.cli.commandTelemetryAttached");
|
|
10021
|
+
function buildCommandPath(cmd) {
|
|
10022
|
+
const segments = [];
|
|
10023
|
+
let cursor = cmd;
|
|
10024
|
+
while (cursor) {
|
|
10025
|
+
segments.unshift(cursor.name());
|
|
10026
|
+
cursor = cursor.parent ?? null;
|
|
10027
|
+
}
|
|
10028
|
+
segments.shift();
|
|
10029
|
+
return segments.join(".");
|
|
10030
|
+
}
|
|
10031
|
+
function buildCommandInvokedAttributes(cmd) {
|
|
10032
|
+
const path8 = buildCommandPath(cmd);
|
|
10033
|
+
const segments = path8.split(".");
|
|
10034
|
+
const command = segments[0];
|
|
10035
|
+
const subcommand = segments.length > 1 ? segments[segments.length - 1] : "";
|
|
10036
|
+
return {
|
|
10037
|
+
command,
|
|
10038
|
+
subcommand,
|
|
10039
|
+
commandPath: path8
|
|
10040
|
+
};
|
|
10041
|
+
}
|
|
10042
|
+
function attachCommandTelemetry(program2, telemetry2) {
|
|
10043
|
+
const flagged = program2;
|
|
10044
|
+
if (flagged[ATTACHED_FLAG]) {
|
|
10045
|
+
return;
|
|
7983
10046
|
}
|
|
7984
|
-
|
|
7985
|
-
|
|
7986
|
-
|
|
7987
|
-
|
|
7988
|
-
|
|
7989
|
-
|
|
7990
|
-
print(rows, columns) {
|
|
7991
|
-
if (this.format === "json") {
|
|
7992
|
-
this.printJson(rows, columns);
|
|
7993
|
-
} else {
|
|
7994
|
-
this.printTable(rows, columns);
|
|
10047
|
+
flagged[ATTACHED_FLAG] = true;
|
|
10048
|
+
program2.hook("preAction", (_thisCommand, actionCommand) => {
|
|
10049
|
+
try {
|
|
10050
|
+
const attrs = buildCommandInvokedAttributes(actionCommand);
|
|
10051
|
+
telemetry2.event("Command.Invoked", { properties: attrs });
|
|
10052
|
+
} catch {
|
|
7995
10053
|
}
|
|
10054
|
+
});
|
|
10055
|
+
}
|
|
10056
|
+
|
|
10057
|
+
// src/telemetry/errorContext.ts
|
|
10058
|
+
init_cjs_shims();
|
|
10059
|
+
var import_common35 = __toESM(require_src());
|
|
10060
|
+
function isObject(v) {
|
|
10061
|
+
return typeof v === "object" && v !== null;
|
|
10062
|
+
}
|
|
10063
|
+
function extractErrorProperties(error) {
|
|
10064
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
10065
|
+
const redacted = redactError(err);
|
|
10066
|
+
const props = {
|
|
10067
|
+
errorName: redacted.errorName,
|
|
10068
|
+
errorMessage: redacted.errorMessage,
|
|
10069
|
+
errorStack: redacted.errorStack,
|
|
10070
|
+
isException: "true"
|
|
10071
|
+
};
|
|
10072
|
+
if (!isObject(error)) {
|
|
10073
|
+
return props;
|
|
10074
|
+
}
|
|
10075
|
+
const axiosErr = error;
|
|
10076
|
+
if (!axiosErr.response) {
|
|
10077
|
+
return props;
|
|
10078
|
+
}
|
|
10079
|
+
props.status = axiosErr.response.status !== void 0 ? String(axiosErr.response.status) : "unknown";
|
|
10080
|
+
const method = axiosErr.config?.method;
|
|
10081
|
+
props.method = typeof method === "string" ? method.toUpperCase() : "unknown";
|
|
10082
|
+
const url = axiosErr.config?.url;
|
|
10083
|
+
props.url = typeof url === "string" ? url : "unknown";
|
|
10084
|
+
const correlationId = import_common35.CorrelationService.extractCorrelationId(axiosErr.response);
|
|
10085
|
+
if (correlationId) {
|
|
10086
|
+
props.correlationId = correlationId;
|
|
10087
|
+
}
|
|
10088
|
+
return props;
|
|
10089
|
+
}
|
|
10090
|
+
function toTelemetryProperties(props) {
|
|
10091
|
+
const out = {
|
|
10092
|
+
errorName: props.errorName,
|
|
10093
|
+
errorMessage: props.errorMessage,
|
|
10094
|
+
errorStack: props.errorStack,
|
|
10095
|
+
isException: props.isException
|
|
10096
|
+
};
|
|
10097
|
+
if (props.status !== void 0) {
|
|
10098
|
+
out.status = props.status;
|
|
7996
10099
|
}
|
|
7997
|
-
|
|
7998
|
-
|
|
7999
|
-
// ---------------------------------------------------------------------------
|
|
8000
|
-
printTable(rows, columns) {
|
|
8001
|
-
if (rows.length === 0) {
|
|
8002
|
-
console.log("(no results)");
|
|
8003
|
-
return;
|
|
8004
|
-
}
|
|
8005
|
-
const widths = columns.map((col) => {
|
|
8006
|
-
const cellWidths = rows.map((row) => String(col.key(row) ?? "").length);
|
|
8007
|
-
return Math.max(col.header.length, ...cellWidths);
|
|
8008
|
-
});
|
|
8009
|
-
const header = columns.map((col, i) => col.header.padEnd(widths[i])).join(COLUMN_SEPARATOR);
|
|
8010
|
-
console.log(header);
|
|
8011
|
-
const rule = widths.map((w) => HEADER_RULE_CHAR.repeat(w)).join(COLUMN_SEPARATOR);
|
|
8012
|
-
console.log(rule);
|
|
8013
|
-
for (const row of rows) {
|
|
8014
|
-
const line = columns.map((col, i) => String(col.key(row) ?? "").padEnd(widths[i])).join(COLUMN_SEPARATOR);
|
|
8015
|
-
console.log(line);
|
|
8016
|
-
}
|
|
10100
|
+
if (props.method !== void 0) {
|
|
10101
|
+
out.method = props.method;
|
|
8017
10102
|
}
|
|
8018
|
-
|
|
8019
|
-
|
|
8020
|
-
// ---------------------------------------------------------------------------
|
|
8021
|
-
printJson(rows, columns) {
|
|
8022
|
-
const records = rows.map((row) => {
|
|
8023
|
-
const record = {};
|
|
8024
|
-
for (const col of columns) {
|
|
8025
|
-
const key = col.jsonKey ?? col.header.toLowerCase();
|
|
8026
|
-
const value = col.key(row);
|
|
8027
|
-
record[key] = value ?? null;
|
|
8028
|
-
}
|
|
8029
|
-
return record;
|
|
8030
|
-
});
|
|
8031
|
-
console.log(JSON.stringify(records, null, 2));
|
|
10103
|
+
if (props.url !== void 0) {
|
|
10104
|
+
out.url = props.url;
|
|
8032
10105
|
}
|
|
8033
|
-
|
|
10106
|
+
if (props.correlationId !== void 0) {
|
|
10107
|
+
out.correlationId = props.correlationId;
|
|
10108
|
+
}
|
|
10109
|
+
return out;
|
|
10110
|
+
}
|
|
8034
10111
|
|
|
8035
|
-
// src/
|
|
8036
|
-
|
|
8037
|
-
|
|
8038
|
-
|
|
10112
|
+
// src/telemetry/withCommandSpan.ts
|
|
10113
|
+
function withCommandSpan(eventName, handler, telemetry2) {
|
|
10114
|
+
return async (...args) => {
|
|
10115
|
+
let span;
|
|
10116
|
+
try {
|
|
10117
|
+
const command = extractCommand(args);
|
|
10118
|
+
const initialAttributes = command ? buildCommandInvokedAttributes(command) : void 0;
|
|
10119
|
+
const svc = telemetry2 ?? getTelemetry();
|
|
10120
|
+
span = svc.span(eventName, initialAttributes);
|
|
10121
|
+
} catch {
|
|
10122
|
+
span = void 0;
|
|
10123
|
+
}
|
|
10124
|
+
let success = true;
|
|
10125
|
+
try {
|
|
10126
|
+
await handler(...args);
|
|
10127
|
+
} catch (err) {
|
|
10128
|
+
success = false;
|
|
10129
|
+
const props = extractErrorProperties(err);
|
|
10130
|
+
safeError(span, err, toTelemetryProperties(props));
|
|
10131
|
+
throw err;
|
|
10132
|
+
} finally {
|
|
10133
|
+
safeAddAttributes(span, { success });
|
|
10134
|
+
safeEnd(span);
|
|
10135
|
+
}
|
|
10136
|
+
};
|
|
8039
10137
|
}
|
|
8040
|
-
function
|
|
8041
|
-
|
|
10138
|
+
function extractCommand(args) {
|
|
10139
|
+
const last = args[args.length - 1];
|
|
10140
|
+
if (last && typeof last === "object" && typeof last.name === "function") {
|
|
10141
|
+
return last;
|
|
10142
|
+
}
|
|
10143
|
+
return void 0;
|
|
8042
10144
|
}
|
|
8043
|
-
function
|
|
8044
|
-
if (
|
|
8045
|
-
return
|
|
10145
|
+
function safeAddAttributes(span, extra) {
|
|
10146
|
+
if (!span) {
|
|
10147
|
+
return;
|
|
8046
10148
|
}
|
|
8047
|
-
|
|
8048
|
-
|
|
10149
|
+
try {
|
|
10150
|
+
span.addAttributes(extra);
|
|
10151
|
+
} catch {
|
|
8049
10152
|
}
|
|
8050
|
-
return "";
|
|
8051
10153
|
}
|
|
8052
|
-
function
|
|
8053
|
-
if (
|
|
8054
|
-
|
|
8055
|
-
|
|
8056
|
-
|
|
8057
|
-
|
|
8058
|
-
}
|
|
8059
|
-
|
|
10154
|
+
function safeEnd(span, extra) {
|
|
10155
|
+
if (!span) {
|
|
10156
|
+
return;
|
|
10157
|
+
}
|
|
10158
|
+
try {
|
|
10159
|
+
span.end(extra);
|
|
10160
|
+
} catch {
|
|
10161
|
+
}
|
|
10162
|
+
}
|
|
10163
|
+
function safeError(span, err, extra) {
|
|
10164
|
+
if (!span) {
|
|
10165
|
+
return;
|
|
10166
|
+
}
|
|
10167
|
+
try {
|
|
10168
|
+
span.error(err instanceof Error ? err : new Error(String(err)), extra);
|
|
10169
|
+
} catch {
|
|
8060
10170
|
}
|
|
8061
|
-
process.exit(1);
|
|
8062
10171
|
}
|
|
8063
10172
|
|
|
8064
10173
|
// src/commands/lake/database.ts
|
|
8065
10174
|
function addDatabaseCommand(databaseCommand) {
|
|
8066
|
-
databaseCommand.command("list").description("List all available databases").action(
|
|
8067
|
-
|
|
8068
|
-
|
|
8069
|
-
|
|
8070
|
-
|
|
8071
|
-
|
|
8072
|
-
|
|
8073
|
-
|
|
8074
|
-
|
|
8075
|
-
|
|
8076
|
-
|
|
8077
|
-
|
|
8078
|
-
|
|
8079
|
-
|
|
8080
|
-
|
|
8081
|
-
|
|
8082
|
-
|
|
8083
|
-
|
|
8084
|
-
|
|
10175
|
+
databaseCommand.command("list").description("List all available databases").action(
|
|
10176
|
+
withCommandSpan(CliEvents.DatabaseList, async () => {
|
|
10177
|
+
try {
|
|
10178
|
+
const apiEnv4 = (0, import_common36.getApiEnv)(import_common36.SecurityPlatformEnvironment.Production);
|
|
10179
|
+
const accessToken = await getToken(apiEnv4);
|
|
10180
|
+
const lakeApiClient = createLakeApiClient(apiEnv4);
|
|
10181
|
+
const databaseService = new DatabaseService(lakeApiClient);
|
|
10182
|
+
const databases = await listDatabases(databaseService, accessToken);
|
|
10183
|
+
const fmt = new OutputFormatter();
|
|
10184
|
+
fmt.print(databases, [
|
|
10185
|
+
{ header: "ID", key: (db) => db.databaseName === "default" ? "System tables" : db.databaseName },
|
|
10186
|
+
{
|
|
10187
|
+
header: "NAME",
|
|
10188
|
+
key: (db) => db.databaseName === "default" ? "System tables" : db.sentinelWorkspace?.name ?? ""
|
|
10189
|
+
}
|
|
10190
|
+
]);
|
|
10191
|
+
} catch (error) {
|
|
10192
|
+
handleApiError("listing databases", error);
|
|
10193
|
+
}
|
|
10194
|
+
})
|
|
10195
|
+
);
|
|
8085
10196
|
}
|
|
8086
10197
|
|
|
8087
10198
|
// src/commands/lake/lakeTables.ts
|
|
8088
10199
|
init_cjs_shims();
|
|
8089
|
-
var
|
|
10200
|
+
var import_common37 = __toESM(require_src());
|
|
8090
10201
|
var TABLE_COLUMNS = [
|
|
8091
10202
|
{ header: "TABLE", key: (t) => t.name ?? "" },
|
|
8092
10203
|
{
|
|
@@ -8096,25 +10207,26 @@ var TABLE_COLUMNS = [
|
|
|
8096
10207
|
{ header: "CATEGORY", key: (t) => t.category ?? "" }
|
|
8097
10208
|
];
|
|
8098
10209
|
function addLakeTableListCommand(tableCommand) {
|
|
8099
|
-
tableCommand.command("list").description("List lake tables").option("--database-id <databaseId>", "Database ID to fetch tables").option("--database-name <databaseName>", "Database name to fetch tables").action(
|
|
8100
|
-
|
|
8101
|
-
|
|
8102
|
-
|
|
8103
|
-
|
|
8104
|
-
|
|
8105
|
-
|
|
8106
|
-
|
|
8107
|
-
|
|
8108
|
-
|
|
8109
|
-
|
|
8110
|
-
|
|
8111
|
-
|
|
8112
|
-
|
|
10210
|
+
tableCommand.command("list").description("List lake tables").option("--database-id <databaseId>", "Database ID to fetch tables").option("--database-name <databaseName>", "Database name to fetch tables").action(
|
|
10211
|
+
withCommandSpan(CliEvents.TableList, async (options) => {
|
|
10212
|
+
try {
|
|
10213
|
+
validateOptions(options);
|
|
10214
|
+
const apiEnv4 = (0, import_common37.getApiEnv)(import_common37.SecurityPlatformEnvironment.Production);
|
|
10215
|
+
const accessToken = await getToken(apiEnv4);
|
|
10216
|
+
const lakeApiClient = createLakeApiClient(apiEnv4);
|
|
10217
|
+
const database = await lookupDatabase(options, lakeApiClient, accessToken);
|
|
10218
|
+
const tableService = new TableService(lakeApiClient);
|
|
10219
|
+
const tables = await listTables(tableService, accessToken, database);
|
|
10220
|
+
printTables(tables);
|
|
10221
|
+
} catch (error) {
|
|
10222
|
+
handleApiError("listing lake tables", error);
|
|
10223
|
+
}
|
|
10224
|
+
})
|
|
10225
|
+
);
|
|
8113
10226
|
}
|
|
8114
10227
|
function validateOptions(options) {
|
|
8115
10228
|
if (options.databaseId && options.databaseName) {
|
|
8116
|
-
|
|
8117
|
-
process.exit(1);
|
|
10229
|
+
throw new Error("--database-id and --database-name are mutually exclusive. Provide only one.");
|
|
8118
10230
|
}
|
|
8119
10231
|
}
|
|
8120
10232
|
function printTables(tables) {
|
|
@@ -8124,38 +10236,39 @@ function printTables(tables) {
|
|
|
8124
10236
|
|
|
8125
10237
|
// src/commands/lake/lakeTableSchema.ts
|
|
8126
10238
|
init_cjs_shims();
|
|
8127
|
-
var
|
|
10239
|
+
var import_common38 = __toESM(require_src());
|
|
8128
10240
|
var SCHEMA_COLUMNS = [
|
|
8129
10241
|
{ header: "COLUMN", key: (col) => col.name },
|
|
8130
10242
|
{ header: "TYPE", key: (col) => col.type }
|
|
8131
10243
|
];
|
|
8132
10244
|
function addLakeTableShowCommand(tableCommand) {
|
|
8133
|
-
tableCommand.command("show <tableName>").description("Show the schema of a lake table").option("--database-id <databaseId>", "Database ID to look up the table in").option("--database-name <databaseName>", "Database name to look up the table in").action(
|
|
8134
|
-
|
|
8135
|
-
|
|
8136
|
-
|
|
8137
|
-
|
|
8138
|
-
|
|
8139
|
-
|
|
8140
|
-
|
|
8141
|
-
|
|
8142
|
-
|
|
8143
|
-
|
|
8144
|
-
|
|
8145
|
-
|
|
8146
|
-
|
|
8147
|
-
|
|
10245
|
+
tableCommand.command("show <tableName>").description("Show the schema of a lake table").option("--database-id <databaseId>", "Database ID to look up the table in").option("--database-name <databaseName>", "Database name to look up the table in").action(
|
|
10246
|
+
withCommandSpan(CliEvents.TableShow, async (tableName, options) => {
|
|
10247
|
+
try {
|
|
10248
|
+
validateOptions2(options);
|
|
10249
|
+
const apiEnv4 = (0, import_common38.getApiEnv)(import_common38.SecurityPlatformEnvironment.Production);
|
|
10250
|
+
const accessToken = await getToken(apiEnv4);
|
|
10251
|
+
const lakeApiClient = createLakeApiClient(apiEnv4);
|
|
10252
|
+
const database = await lookupDatabase(options, lakeApiClient, accessToken) ?? DEFAULT_DATABASE;
|
|
10253
|
+
const tableService = new TableService(lakeApiClient);
|
|
10254
|
+
const tables = await listTables(tableService, accessToken, database);
|
|
10255
|
+
const table = findTable(tables, tableName);
|
|
10256
|
+
if (!table) {
|
|
10257
|
+
console.error(
|
|
10258
|
+
`Error: table "${tableName}" not found. Run "sentinel table list" to see available tables.`
|
|
10259
|
+
);
|
|
10260
|
+
throw new Error(`Table not found: ${tableName}`);
|
|
10261
|
+
}
|
|
10262
|
+
printSchema(table);
|
|
10263
|
+
} catch (error) {
|
|
10264
|
+
handleApiError("showing lake table schema", error);
|
|
8148
10265
|
}
|
|
8149
|
-
|
|
8150
|
-
|
|
8151
|
-
handleApiError("showing lake table schema", error);
|
|
8152
|
-
}
|
|
8153
|
-
});
|
|
10266
|
+
})
|
|
10267
|
+
);
|
|
8154
10268
|
}
|
|
8155
10269
|
function validateOptions2(options) {
|
|
8156
10270
|
if (options.databaseId && options.databaseName) {
|
|
8157
|
-
|
|
8158
|
-
process.exit(1);
|
|
10271
|
+
throw new Error("--database-id and --database-name are mutually exclusive. Provide only one.");
|
|
8159
10272
|
}
|
|
8160
10273
|
}
|
|
8161
10274
|
function findTable(tables, tableName) {
|
|
@@ -8169,21 +10282,21 @@ function printSchema(table) {
|
|
|
8169
10282
|
|
|
8170
10283
|
// src/commands/login.ts
|
|
8171
10284
|
init_cjs_shims();
|
|
8172
|
-
var
|
|
10285
|
+
var os5 = __toESM(require("os"));
|
|
8173
10286
|
|
|
8174
10287
|
// src/actions/authCodeLogin.ts
|
|
8175
10288
|
init_cjs_shims();
|
|
8176
10289
|
var import_child_process = require("child_process");
|
|
8177
|
-
var
|
|
8178
|
-
var apiEnv3 = (0,
|
|
10290
|
+
var import_common39 = __toESM(require_src());
|
|
10291
|
+
var apiEnv3 = (0, import_common39.getApiEnv)(import_common39.SecurityPlatformEnvironment.Production);
|
|
8179
10292
|
function openSystemBrowser(url) {
|
|
8180
|
-
return new Promise((
|
|
10293
|
+
return new Promise((resolve2, reject) => {
|
|
8181
10294
|
const command = process.platform === "darwin" ? "open" : "xdg-open";
|
|
8182
10295
|
(0, import_child_process.execFile)(command, [url], (error) => {
|
|
8183
10296
|
if (error) {
|
|
8184
10297
|
reject(new Error(`Failed to open browser: ${error.message}`));
|
|
8185
10298
|
} else {
|
|
8186
|
-
|
|
10299
|
+
resolve2();
|
|
8187
10300
|
}
|
|
8188
10301
|
});
|
|
8189
10302
|
});
|
|
@@ -8300,7 +10413,7 @@ function loginCommand(program2) {
|
|
|
8300
10413
|
} else {
|
|
8301
10414
|
console.log("\u{1F3E2} No tenant specified, using default authority.");
|
|
8302
10415
|
}
|
|
8303
|
-
if (
|
|
10416
|
+
if (os5.platform() === "win32" /* Windows */) {
|
|
8304
10417
|
console.log("\u{1FA9F} Authenticating via Windows Native Broker (WAM)...");
|
|
8305
10418
|
await (tenant ? brokerLogin(scope, tenant) : brokerLogin(scope));
|
|
8306
10419
|
console.log("\u2705 Logged in via Windows Native Broker.");
|
|
@@ -8336,64 +10449,53 @@ function logoutCommand(program2) {
|
|
|
8336
10449
|
|
|
8337
10450
|
// src/commands/publishJob.ts
|
|
8338
10451
|
init_cjs_shims();
|
|
8339
|
-
var
|
|
8340
|
-
var
|
|
10452
|
+
var import_common41 = __toESM(require_src());
|
|
10453
|
+
var import_path6 = __toESM(require("path"));
|
|
8341
10454
|
|
|
8342
10455
|
// src/actions/publishJob.ts
|
|
8343
10456
|
init_cjs_shims();
|
|
8344
|
-
var
|
|
8345
|
-
var
|
|
8346
|
-
var
|
|
8347
|
-
var
|
|
10457
|
+
var import_common40 = __toESM(require_src());
|
|
10458
|
+
var fs6 = __toESM(require("fs"));
|
|
10459
|
+
var import_path5 = __toESM(require("path"));
|
|
10460
|
+
var YAML2 = __toESM(require("yaml"));
|
|
8348
10461
|
function parseJobConfig(jobConfigPath) {
|
|
8349
|
-
const jobConfigContent =
|
|
8350
|
-
const ext =
|
|
10462
|
+
const jobConfigContent = fs6.readFileSync(jobConfigPath, "utf-8");
|
|
10463
|
+
const ext = import_path5.default.extname(jobConfigPath);
|
|
8351
10464
|
switch (ext) {
|
|
8352
10465
|
case ".json":
|
|
8353
10466
|
return JSON.parse(jobConfigContent);
|
|
8354
10467
|
case ".yaml":
|
|
8355
10468
|
case ".yml":
|
|
8356
|
-
return
|
|
10469
|
+
return YAML2.parse(jobConfigContent);
|
|
8357
10470
|
default:
|
|
8358
10471
|
throw new Error(`Unsupported file extension: ${ext}`);
|
|
8359
10472
|
}
|
|
8360
10473
|
}
|
|
8361
10474
|
async function publish(notebookPath, jobConfigPath, jobClient, accessToken) {
|
|
8362
|
-
if (!
|
|
10475
|
+
if (!fs6.existsSync(notebookPath)) {
|
|
8363
10476
|
console.error(`File not found: ${notebookPath}`);
|
|
8364
10477
|
throw new Error(`File not found: ${notebookPath}`);
|
|
8365
10478
|
}
|
|
8366
|
-
if (!
|
|
10479
|
+
if (!fs6.existsSync(jobConfigPath)) {
|
|
8367
10480
|
console.error(`File not found: ${jobConfigPath}`);
|
|
8368
10481
|
throw new Error(`File not found: ${jobConfigPath}`);
|
|
8369
10482
|
}
|
|
8370
|
-
const requestId =
|
|
8371
|
-
const notebookBase64 =
|
|
10483
|
+
const requestId = import_common40.CorrelationService.createCorrelationContext();
|
|
10484
|
+
const notebookBase64 = fs6.readFileSync(notebookPath).toString("base64");
|
|
8372
10485
|
const jobConfig = parseJobConfig(jobConfigPath);
|
|
8373
|
-
const payload = (0,
|
|
10486
|
+
const payload = (0, import_common40.buildCompleteJobPayload)(jobConfig, notebookBase64);
|
|
8374
10487
|
const jobName = jobConfig.jobName;
|
|
8375
10488
|
await jobClient.createJob(jobName, payload, accessToken, requestId);
|
|
8376
10489
|
return jobName;
|
|
8377
10490
|
}
|
|
8378
10491
|
|
|
8379
|
-
// src/client/jobs/index.ts
|
|
8380
|
-
init_cjs_shims();
|
|
8381
|
-
var import_common14 = __toESM(require_src());
|
|
8382
|
-
function createJobApiClient(env, region) {
|
|
8383
|
-
const requestService = new import_common14.RequestService(noopTelemetry, buildApiHeaders);
|
|
8384
|
-
return new import_common14.JobApiClient({
|
|
8385
|
-
requestService,
|
|
8386
|
-
baseUrl: env.regions[region].gatewayEndpoint
|
|
8387
|
-
});
|
|
8388
|
-
}
|
|
8389
|
-
|
|
8390
10492
|
// src/commands/publishJob.ts
|
|
8391
10493
|
function addPublishCommand(jobCommand) {
|
|
8392
|
-
jobCommand.command("publish <notebookPath>").description("Publish a scheduled job.").option("-c, --config <path>", "Path to job YAML config").option("-r, --region <region>", "Target region (e.g. eastus2)",
|
|
10494
|
+
jobCommand.command("publish <notebookPath>").description("Publish a scheduled job.").option("-c, --config <path>", "Path to job YAML config").option("-r, --region <region>", "Target region (e.g. eastus2)", import_common41.Region.Global).action(async (notebookPath, options) => {
|
|
8393
10495
|
try {
|
|
8394
|
-
const resolvedNotebookPath =
|
|
8395
|
-
const resolvedConfigPath =
|
|
8396
|
-
const apiEnv4 = (0,
|
|
10496
|
+
const resolvedNotebookPath = import_path6.default.resolve(notebookPath);
|
|
10497
|
+
const resolvedConfigPath = import_path6.default.resolve(options.config);
|
|
10498
|
+
const apiEnv4 = (0, import_common41.getApiEnv)(import_common41.SecurityPlatformEnvironment.Production);
|
|
8397
10499
|
const region = options.region;
|
|
8398
10500
|
const accessToken = await getToken(apiEnv4);
|
|
8399
10501
|
const jobApiClient = createJobApiClient(apiEnv4, region);
|
|
@@ -8405,6 +10507,188 @@ function addPublishCommand(jobCommand) {
|
|
|
8405
10507
|
});
|
|
8406
10508
|
}
|
|
8407
10509
|
|
|
10510
|
+
// src/commands/tenant/tenantList.ts
|
|
10511
|
+
init_cjs_shims();
|
|
10512
|
+
var import_common43 = __toESM(require_src());
|
|
10513
|
+
|
|
10514
|
+
// src/services/tenant/index.ts
|
|
10515
|
+
init_cjs_shims();
|
|
10516
|
+
|
|
10517
|
+
// src/services/tenant/tenantService.ts
|
|
10518
|
+
init_cjs_shims();
|
|
10519
|
+
var import_common42 = __toESM(require_src());
|
|
10520
|
+
var TenantService = class {
|
|
10521
|
+
constructor(requestService, armEndpoint) {
|
|
10522
|
+
this.requestService = requestService;
|
|
10523
|
+
this.armEndpoint = armEndpoint;
|
|
10524
|
+
}
|
|
10525
|
+
/**
|
|
10526
|
+
* Fetches all tenants accessible to the authenticated user from ARM.
|
|
10527
|
+
*
|
|
10528
|
+
* @param accessToken - A valid ARM bearer access token.
|
|
10529
|
+
* @returns An array of {@link ArmTenant} objects.
|
|
10530
|
+
*/
|
|
10531
|
+
async fetchAllTenants(accessToken) {
|
|
10532
|
+
const client = new import_common42.TenantApiClient({ requestService: this.requestService, armEndpoint: this.armEndpoint });
|
|
10533
|
+
return client.fetchAllTenants(accessToken);
|
|
10534
|
+
}
|
|
10535
|
+
};
|
|
10536
|
+
|
|
10537
|
+
// src/commands/tenant/tenantList.ts
|
|
10538
|
+
var TENANT_COLUMNS = [
|
|
10539
|
+
{ header: "DISPLAY NAME", key: (t) => t.displayName },
|
|
10540
|
+
{ header: "TENANT ID", key: (t) => t.tenantId },
|
|
10541
|
+
{ header: "DEFAULT DOMAIN", key: (t) => t.defaultDomain }
|
|
10542
|
+
];
|
|
10543
|
+
function addTenantListCommand(tenantCommand) {
|
|
10544
|
+
tenantCommand.command("list").description("List accessible tenants for the signed-in user").action(async () => {
|
|
10545
|
+
try {
|
|
10546
|
+
const apiEnv4 = (0, import_common43.getApiEnv)(import_common43.SecurityPlatformEnvironment.Production);
|
|
10547
|
+
const accessToken = await getToken(apiEnv4, [apiEnv4.armScope]);
|
|
10548
|
+
const requestService = new import_common43.RequestService(noopTelemetry, buildApiHeaders);
|
|
10549
|
+
const tenantService = new TenantService(requestService, apiEnv4.armEndpoint);
|
|
10550
|
+
const tenants = await tenantService.fetchAllTenants(accessToken);
|
|
10551
|
+
printTenants(tenants);
|
|
10552
|
+
} catch (error) {
|
|
10553
|
+
handleApiError("listing tenants", error);
|
|
10554
|
+
}
|
|
10555
|
+
});
|
|
10556
|
+
}
|
|
10557
|
+
function printTenants(tenants) {
|
|
10558
|
+
const fmt = new OutputFormatter();
|
|
10559
|
+
fmt.print(tenants, TENANT_COLUMNS);
|
|
10560
|
+
}
|
|
10561
|
+
|
|
10562
|
+
// src/commands/tenant/tenantSelect.ts
|
|
10563
|
+
init_cjs_shims();
|
|
10564
|
+
var import_common44 = __toESM(require_src());
|
|
10565
|
+
var os6 = __toESM(require("os"));
|
|
10566
|
+
var readline = __toESM(require("readline"));
|
|
10567
|
+
var MAX_PROMPT_ATTEMPTS = 3;
|
|
10568
|
+
function addTenantSelectCommand(tenantCommand) {
|
|
10569
|
+
tenantCommand.command("select").description(
|
|
10570
|
+
"Select an active tenant for this account from an interactive numbered prompt. Subsequent commands will acquire tokens for the selected tenant."
|
|
10571
|
+
).action(async () => {
|
|
10572
|
+
try {
|
|
10573
|
+
const apiEnv4 = (0, import_common44.getApiEnv)(import_common44.SecurityPlatformEnvironment.Production);
|
|
10574
|
+
const armToken = await getToken(apiEnv4, [apiEnv4.armScope]);
|
|
10575
|
+
const requestService = new import_common44.RequestService(noopTelemetry, buildApiHeaders);
|
|
10576
|
+
const tenantService = new TenantService(requestService, apiEnv4.armEndpoint);
|
|
10577
|
+
const tenants = await tenantService.fetchAllTenants(armToken);
|
|
10578
|
+
if (tenants.length === 0) {
|
|
10579
|
+
console.error("\u274C No tenants accessible for the signed-in account.");
|
|
10580
|
+
process.exit(1);
|
|
10581
|
+
}
|
|
10582
|
+
const activeTenantId = getActiveTenantId();
|
|
10583
|
+
const activeIndex = activeTenantId ? tenants.findIndex((t) => t.tenantId === activeTenantId) : -1;
|
|
10584
|
+
const chosen = await promptForTenant(tenants, activeIndex);
|
|
10585
|
+
if (!chosen) {
|
|
10586
|
+
console.log("\u2139 Active tenant unchanged.");
|
|
10587
|
+
return;
|
|
10588
|
+
}
|
|
10589
|
+
await switchActiveTenant(apiEnv4, chosen);
|
|
10590
|
+
console.log(`\u2705 Active tenant set to ${chosen.tenantId} (${chosen.displayName}).`);
|
|
10591
|
+
} catch (error) {
|
|
10592
|
+
handleApiError("selecting tenant", error);
|
|
10593
|
+
}
|
|
10594
|
+
});
|
|
10595
|
+
}
|
|
10596
|
+
function getActiveTenantId() {
|
|
10597
|
+
const session = loadBrokerAccount();
|
|
10598
|
+
if (!session) {
|
|
10599
|
+
return null;
|
|
10600
|
+
}
|
|
10601
|
+
try {
|
|
10602
|
+
const url = new URL(session.authority);
|
|
10603
|
+
const segment = url.pathname.split("/").filter(Boolean).pop();
|
|
10604
|
+
if (!segment || segment === "common" || segment === "organizations" || segment === "consumers") {
|
|
10605
|
+
return null;
|
|
10606
|
+
}
|
|
10607
|
+
return segment;
|
|
10608
|
+
} catch {
|
|
10609
|
+
return null;
|
|
10610
|
+
}
|
|
10611
|
+
}
|
|
10612
|
+
async function promptForTenant(tenants, activeIndex) {
|
|
10613
|
+
const defaultIdx = activeIndex >= 0 ? activeIndex + 1 : 1;
|
|
10614
|
+
console.log("");
|
|
10615
|
+
console.log(formatTenantTable(tenants, activeIndex));
|
|
10616
|
+
console.log("");
|
|
10617
|
+
if (activeIndex >= 0) {
|
|
10618
|
+
console.log(`The default is marked with an *; the default tenant is '${tenants[activeIndex].tenantId}'.`);
|
|
10619
|
+
console.log("");
|
|
10620
|
+
}
|
|
10621
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
10622
|
+
try {
|
|
10623
|
+
for (let attempt = 0; attempt < MAX_PROMPT_ATTEMPTS; attempt++) {
|
|
10624
|
+
const answer = await new Promise((resolve2) => {
|
|
10625
|
+
rl.question(`Select a tenant by number [${defaultIdx}]: `, (a) => resolve2(a));
|
|
10626
|
+
});
|
|
10627
|
+
const trimmed = answer.trim();
|
|
10628
|
+
if (trimmed === "") {
|
|
10629
|
+
if (activeIndex >= 0) {
|
|
10630
|
+
return null;
|
|
10631
|
+
}
|
|
10632
|
+
return tenants[defaultIdx - 1];
|
|
10633
|
+
}
|
|
10634
|
+
if (/^\d+$/.test(trimmed)) {
|
|
10635
|
+
const idx = Number.parseInt(trimmed, 10);
|
|
10636
|
+
if (idx >= 1 && idx <= tenants.length) {
|
|
10637
|
+
const chosen = tenants[idx - 1];
|
|
10638
|
+
if (activeIndex >= 0 && idx - 1 === activeIndex) {
|
|
10639
|
+
return null;
|
|
10640
|
+
}
|
|
10641
|
+
return chosen;
|
|
10642
|
+
}
|
|
10643
|
+
}
|
|
10644
|
+
console.error(`Invalid selection. Enter a number between 1 and ${tenants.length}.`);
|
|
10645
|
+
}
|
|
10646
|
+
throw new Error("Too many invalid attempts. Aborting.");
|
|
10647
|
+
} finally {
|
|
10648
|
+
rl.close();
|
|
10649
|
+
}
|
|
10650
|
+
}
|
|
10651
|
+
function formatTenantTable(tenants, activeIndex) {
|
|
10652
|
+
const headers = ["No.", "", "Tenant ID", "Tenant Name", "Default Domain"];
|
|
10653
|
+
const rows = tenants.map((t, i) => {
|
|
10654
|
+
const marker = i === activeIndex ? "*" : "";
|
|
10655
|
+
return [`[${i + 1}]`, marker, t.tenantId, t.displayName, t.defaultDomain ?? ""];
|
|
10656
|
+
});
|
|
10657
|
+
const widths = headers.map((h, col) => Math.max(h.length, ...rows.map((r) => r[col].length)));
|
|
10658
|
+
const pad = (s, w) => s + " ".repeat(Math.max(0, w - s.length));
|
|
10659
|
+
const formatRow = (cells) => cells.map((c, i) => pad(c, widths[i])).join(" ");
|
|
10660
|
+
return [formatRow(headers), ...rows.map(formatRow)].join("\n");
|
|
10661
|
+
}
|
|
10662
|
+
async function switchActiveTenant(apiEnv4, chosen) {
|
|
10663
|
+
const newAuthority = `${new URL(apiEnv4.aadEndpoint).origin}/${chosen.tenantId}`;
|
|
10664
|
+
const session = loadBrokerAccount();
|
|
10665
|
+
if (!session) {
|
|
10666
|
+
throw new Error(
|
|
10667
|
+
"No active session found. Run 'sentinel login' first. Note: tenant switching is not supported for managed-identity / workload-identity sign-ins."
|
|
10668
|
+
);
|
|
10669
|
+
}
|
|
10670
|
+
const msalInstance = await getMsalInstance(apiEnv4, newAuthority);
|
|
10671
|
+
try {
|
|
10672
|
+
const result = await msalInstance.acquireTokenSilent({
|
|
10673
|
+
account: session.account,
|
|
10674
|
+
scopes: [apiEnv4.gatewayAuthResourceUri],
|
|
10675
|
+
authority: newAuthority
|
|
10676
|
+
});
|
|
10677
|
+
const acquiredTid = result?.account?.tenantId;
|
|
10678
|
+
if (result?.accessToken && acquiredTid === chosen.tenantId) {
|
|
10679
|
+
saveBrokerAccount(result.account, newAuthority);
|
|
10680
|
+
return;
|
|
10681
|
+
}
|
|
10682
|
+
} catch {
|
|
10683
|
+
}
|
|
10684
|
+
console.log(`\u2139 Silent sign-in to tenant ${chosen.tenantId} not possible \u2014 prompting interactively\u2026`);
|
|
10685
|
+
if (os6.platform() === "win32") {
|
|
10686
|
+
await brokerLogin([apiEnv4.gatewayAuthResourceUri], chosen.tenantId);
|
|
10687
|
+
} else {
|
|
10688
|
+
await browserAuthLogin([apiEnv4.gatewayAuthResourceUri], chosen.tenantId);
|
|
10689
|
+
}
|
|
10690
|
+
}
|
|
10691
|
+
|
|
8408
10692
|
// src/commands/token.ts
|
|
8409
10693
|
init_cjs_shims();
|
|
8410
10694
|
function addTokenCommand(program2) {
|
|
@@ -8420,7 +10704,7 @@ init_cjs_shims();
|
|
|
8420
10704
|
init_cjs_shims();
|
|
8421
10705
|
var import_axios = __toESM(require("axios"));
|
|
8422
10706
|
var import_child_process2 = require("child_process");
|
|
8423
|
-
var
|
|
10707
|
+
var os7 = __toESM(require("os"));
|
|
8424
10708
|
var import_semver = __toESM(require("semver"));
|
|
8425
10709
|
var PACKAGE_NAME = "@microsoft/sentinel-cli";
|
|
8426
10710
|
var NPM_REGISTRY_URL = `https://registry.npmjs.org/${PACKAGE_NAME}/latest`;
|
|
@@ -8437,8 +10721,11 @@ function isNewerVersion(current, latest) {
|
|
|
8437
10721
|
return import_semver.default.gt(l, c);
|
|
8438
10722
|
}
|
|
8439
10723
|
function runUpdateCommand(version) {
|
|
10724
|
+
if (!import_semver.default.valid(version)) {
|
|
10725
|
+
throw new Error(`Invalid version: ${version}`);
|
|
10726
|
+
}
|
|
8440
10727
|
const args = ["install", "-g", `${PACKAGE_NAME}@${version}`];
|
|
8441
|
-
(0, import_child_process2.execFileSync)("npm", args, { stdio: "inherit" });
|
|
10728
|
+
(0, import_child_process2.execFileSync)("npm", args, { stdio: "inherit", shell: true });
|
|
8442
10729
|
}
|
|
8443
10730
|
async function checkAndUpdate(currentVersion) {
|
|
8444
10731
|
console.log(`\u{1F50D} Current version: ${currentVersion}`);
|
|
@@ -8450,7 +10737,7 @@ async function checkAndUpdate(currentVersion) {
|
|
|
8450
10737
|
}
|
|
8451
10738
|
console.log(`\u{1F4E6} New version available: ${latestVersion}`);
|
|
8452
10739
|
console.log(`\u2B06\uFE0F Updating from ${currentVersion} to ${latestVersion}...`);
|
|
8453
|
-
if (
|
|
10740
|
+
if (os7.platform() !== "win32") {
|
|
8454
10741
|
console.log(
|
|
8455
10742
|
"\u2139\uFE0F On macOS/Linux, you may need administrator privileges. If the update fails, try running with sudo."
|
|
8456
10743
|
);
|
|
@@ -8463,7 +10750,7 @@ async function checkAndUpdate(currentVersion) {
|
|
|
8463
10750
|
function addUpdateCliCommand(program2) {
|
|
8464
10751
|
program2.command("update").description("Update the Sentinel CLI to the latest version").action(async () => {
|
|
8465
10752
|
try {
|
|
8466
|
-
await checkAndUpdate("0.
|
|
10753
|
+
await checkAndUpdate("0.3.0");
|
|
8467
10754
|
} catch (error) {
|
|
8468
10755
|
console.error(`\u274C Update failed: ${error instanceof Error ? error.message : error}`);
|
|
8469
10756
|
process.exitCode = 1;
|
|
@@ -8477,12 +10764,12 @@ init_cjs_shims();
|
|
|
8477
10764
|
|
|
8478
10765
|
// src/actions/validate.ts
|
|
8479
10766
|
init_cjs_shims();
|
|
8480
|
-
var
|
|
10767
|
+
var import_common45 = __toESM(require_src());
|
|
8481
10768
|
async function validateFromFile(filePath) {
|
|
8482
10769
|
if (!filePath || typeof filePath !== "string" || filePath.trim().length === 0) {
|
|
8483
10770
|
throw new Error("Invalid file path provided.");
|
|
8484
10771
|
}
|
|
8485
|
-
const manifestProcessorService = new
|
|
10772
|
+
const manifestProcessorService = new import_common45.ManifestProcessorService();
|
|
8486
10773
|
console.info("Starting validate process...");
|
|
8487
10774
|
await manifestProcessorService.validateManifest(filePath);
|
|
8488
10775
|
}
|
|
@@ -8509,6 +10796,23 @@ function addValidateCommand(packageCommand) {
|
|
|
8509
10796
|
function registerCommands(program2) {
|
|
8510
10797
|
const jobCommand = program2.command("job").description("Manage scheduled jobs");
|
|
8511
10798
|
addPublishCommand(jobCommand);
|
|
10799
|
+
addJobListCommand(jobCommand);
|
|
10800
|
+
addJobShowCommand(jobCommand);
|
|
10801
|
+
addJobDeleteCommand(jobCommand);
|
|
10802
|
+
addJobDisableCommand(jobCommand);
|
|
10803
|
+
addJobEnableCommand(jobCommand);
|
|
10804
|
+
addJobDownloadCommand(jobCommand);
|
|
10805
|
+
const runCommand = jobCommand.command("run").description("Manage job runs");
|
|
10806
|
+
addJobRunListCommand(runCommand);
|
|
10807
|
+
addJobRunShowCommand(runCommand);
|
|
10808
|
+
addJobRunStartCommand(runCommand);
|
|
10809
|
+
addJobRunCancelCommand(runCommand);
|
|
10810
|
+
const notebookCommand = runCommand.command("notebook").description("Manage job run notebooks");
|
|
10811
|
+
addJobRunNotebookDownloadCommand(notebookCommand);
|
|
10812
|
+
const definitionCommand = jobCommand.command("definition").description("Manage job definition YAML files");
|
|
10813
|
+
addJobDefinitionCreateCommand(definitionCommand);
|
|
10814
|
+
addJobDefinitionShowCommand(definitionCommand);
|
|
10815
|
+
addJobDefinitionUpdateCommand(definitionCommand);
|
|
8512
10816
|
const packageCommand = program2.command("package").description("Manage packages");
|
|
8513
10817
|
addCreateZipCommand(packageCommand);
|
|
8514
10818
|
addValidateCommand(packageCommand);
|
|
@@ -8517,6 +10821,9 @@ function registerCommands(program2) {
|
|
|
8517
10821
|
const tableCommand = program2.command("table").description("Manage sentinel lake tables");
|
|
8518
10822
|
addLakeTableListCommand(tableCommand);
|
|
8519
10823
|
addLakeTableShowCommand(tableCommand);
|
|
10824
|
+
const tenantCommand = program2.command("tenant").description("Manage tenants");
|
|
10825
|
+
addTenantListCommand(tenantCommand);
|
|
10826
|
+
addTenantSelectCommand(tenantCommand);
|
|
8520
10827
|
loginCommand(program2);
|
|
8521
10828
|
logoutCommand(program2);
|
|
8522
10829
|
addTokenCommand(program2);
|
|
@@ -8524,13 +10831,21 @@ function registerCommands(program2) {
|
|
|
8524
10831
|
}
|
|
8525
10832
|
|
|
8526
10833
|
// src/index.ts
|
|
8527
|
-
import_commander.program.name("sentinel").description("Sentinel CLI \u2014 manage lake tables, databases, scheduled jobs, packages, and authentication").version("0.
|
|
10834
|
+
import_commander.program.name("sentinel").description("Sentinel CLI \u2014 manage lake tables, databases, scheduled jobs, packages, and authentication").version("0.3.0");
|
|
8528
10835
|
registerCommands(import_commander.program);
|
|
10836
|
+
var telemetry = getTelemetry();
|
|
10837
|
+
telemetry.event("cli.invoked", {
|
|
10838
|
+
properties: { command: process.argv[2] ?? "<none>" }
|
|
10839
|
+
});
|
|
10840
|
+
attachCommandTelemetry(import_commander.program, telemetry);
|
|
8529
10841
|
(async () => {
|
|
10842
|
+
let exitCode = 0;
|
|
8530
10843
|
try {
|
|
8531
10844
|
await import_commander.program.parseAsync(process.argv);
|
|
8532
|
-
process.exit(0);
|
|
8533
10845
|
} catch {
|
|
8534
|
-
|
|
10846
|
+
exitCode = 1;
|
|
10847
|
+
} finally {
|
|
10848
|
+
await telemetry.dispose();
|
|
8535
10849
|
}
|
|
10850
|
+
process.exit(exitCode);
|
|
8536
10851
|
})();
|