@postman-cse/onboarding-insights 2.1.1 → 2.1.2
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/README.md +7 -5
- package/action.yml +11 -3
- package/dist/action.cjs +508 -170
- package/dist/cli.cjs +678 -346
- package/dist/index.cjs +512 -153
- package/package.json +1 -1
package/dist/cli.cjs
CHANGED
|
@@ -18691,6 +18691,140 @@ var import_node_fs2 = require("node:fs");
|
|
|
18691
18691
|
var import_promises = require("node:fs/promises");
|
|
18692
18692
|
var import_node_path2 = __toESM(require("node:path"), 1);
|
|
18693
18693
|
|
|
18694
|
+
// src/lib/secrets.ts
|
|
18695
|
+
var REDACTED = "[REDACTED]";
|
|
18696
|
+
var SENSITIVE_HEADER_NAMES = /* @__PURE__ */ new Set([
|
|
18697
|
+
"authorization",
|
|
18698
|
+
"cookie",
|
|
18699
|
+
"proxy-authorization",
|
|
18700
|
+
"set-cookie",
|
|
18701
|
+
"x-access-token",
|
|
18702
|
+
"x-api-key"
|
|
18703
|
+
]);
|
|
18704
|
+
function isIterable(value) {
|
|
18705
|
+
return value !== null && value !== void 0 && typeof value !== "string" && typeof value[Symbol.iterator] === "function";
|
|
18706
|
+
}
|
|
18707
|
+
function appendSecretValues(value, results) {
|
|
18708
|
+
if (value === null || value === void 0) {
|
|
18709
|
+
return;
|
|
18710
|
+
}
|
|
18711
|
+
if (typeof value === "string") {
|
|
18712
|
+
const normalized = value.trim();
|
|
18713
|
+
if (normalized) {
|
|
18714
|
+
results.push(normalized);
|
|
18715
|
+
}
|
|
18716
|
+
return;
|
|
18717
|
+
}
|
|
18718
|
+
if (typeof value === "number" || typeof value === "boolean") {
|
|
18719
|
+
results.push(String(value));
|
|
18720
|
+
return;
|
|
18721
|
+
}
|
|
18722
|
+
if (Array.isArray(value) || isIterable(value)) {
|
|
18723
|
+
for (const entry of value) {
|
|
18724
|
+
appendSecretValues(entry, results);
|
|
18725
|
+
}
|
|
18726
|
+
}
|
|
18727
|
+
}
|
|
18728
|
+
function normalizeSecretValues(secretValues) {
|
|
18729
|
+
const values = [];
|
|
18730
|
+
appendSecretValues(secretValues, values);
|
|
18731
|
+
return [...new Set(values)].sort((left, right) => right.length - left.length);
|
|
18732
|
+
}
|
|
18733
|
+
function redactSecrets(input, secretValues, replacement = REDACTED) {
|
|
18734
|
+
const source = String(input ?? "");
|
|
18735
|
+
const secrets = normalizeSecretValues(secretValues);
|
|
18736
|
+
if (!source || secrets.length === 0) {
|
|
18737
|
+
return source;
|
|
18738
|
+
}
|
|
18739
|
+
return secrets.reduce((sanitized, secret) => {
|
|
18740
|
+
if (!secret) {
|
|
18741
|
+
return sanitized;
|
|
18742
|
+
}
|
|
18743
|
+
return sanitized.split(secret).join(replacement);
|
|
18744
|
+
}, source);
|
|
18745
|
+
}
|
|
18746
|
+
function createSecretMasker(secretValues, replacement = REDACTED) {
|
|
18747
|
+
return (input) => redactSecrets(input, secretValues, replacement);
|
|
18748
|
+
}
|
|
18749
|
+
function headerEntries(headers) {
|
|
18750
|
+
if (headers instanceof Headers) {
|
|
18751
|
+
return Array.from(headers.entries());
|
|
18752
|
+
}
|
|
18753
|
+
if (Array.isArray(headers)) {
|
|
18754
|
+
return headers.map(([name, value]) => [name, String(value)]);
|
|
18755
|
+
}
|
|
18756
|
+
return Object.entries(headers).map(([name, value]) => [name, String(value)]);
|
|
18757
|
+
}
|
|
18758
|
+
function sanitizeHeaders(headers, secretValues) {
|
|
18759
|
+
if (!headers) {
|
|
18760
|
+
return {};
|
|
18761
|
+
}
|
|
18762
|
+
const sanitized = {};
|
|
18763
|
+
for (const [name, value] of headerEntries(headers)) {
|
|
18764
|
+
const normalizedName = name.toLowerCase();
|
|
18765
|
+
sanitized[normalizedName] = SENSITIVE_HEADER_NAMES.has(normalizedName) ? REDACTED : redactSecrets(value, secretValues);
|
|
18766
|
+
}
|
|
18767
|
+
return sanitized;
|
|
18768
|
+
}
|
|
18769
|
+
|
|
18770
|
+
// src/lib/http-error.ts
|
|
18771
|
+
function truncate(value, limit) {
|
|
18772
|
+
if (value.length <= limit) {
|
|
18773
|
+
return value;
|
|
18774
|
+
}
|
|
18775
|
+
return `${value.slice(0, limit)}...[truncated]`;
|
|
18776
|
+
}
|
|
18777
|
+
function buildMessage(init) {
|
|
18778
|
+
const method = String(init.method || "GET").toUpperCase();
|
|
18779
|
+
const status = `${init.status}${init.statusText ? ` ${init.statusText}` : ""}`;
|
|
18780
|
+
const url = redactSecrets(init.url, init.secretValues);
|
|
18781
|
+
const body = truncate(
|
|
18782
|
+
redactSecrets(init.responseBody || "", init.secretValues),
|
|
18783
|
+
Math.max(0, init.bodyLimit ?? 800)
|
|
18784
|
+
);
|
|
18785
|
+
return body ? `${method} ${url} failed: ${status} - ${body}` : `${method} ${url} failed: ${status}`;
|
|
18786
|
+
}
|
|
18787
|
+
var HttpError = class _HttpError extends Error {
|
|
18788
|
+
method;
|
|
18789
|
+
requestHeaders;
|
|
18790
|
+
responseBody;
|
|
18791
|
+
secretValues;
|
|
18792
|
+
status;
|
|
18793
|
+
statusText;
|
|
18794
|
+
url;
|
|
18795
|
+
constructor(init) {
|
|
18796
|
+
super(buildMessage(init));
|
|
18797
|
+
this.name = "HttpError";
|
|
18798
|
+
this.method = String(init.method || "GET").toUpperCase();
|
|
18799
|
+
this.requestHeaders = init.requestHeaders;
|
|
18800
|
+
this.responseBody = init.responseBody || "";
|
|
18801
|
+
this.secretValues = init.secretValues;
|
|
18802
|
+
this.status = init.status;
|
|
18803
|
+
this.statusText = init.statusText;
|
|
18804
|
+
this.url = init.url;
|
|
18805
|
+
}
|
|
18806
|
+
static async fromResponse(response, init) {
|
|
18807
|
+
const responseBody = init.responseBody ?? await response.text().catch(() => "");
|
|
18808
|
+
return new _HttpError({
|
|
18809
|
+
...init,
|
|
18810
|
+
responseBody,
|
|
18811
|
+
status: response.status,
|
|
18812
|
+
statusText: response.statusText
|
|
18813
|
+
});
|
|
18814
|
+
}
|
|
18815
|
+
toJSON() {
|
|
18816
|
+
return {
|
|
18817
|
+
method: this.method,
|
|
18818
|
+
name: this.name,
|
|
18819
|
+
requestHeaders: sanitizeHeaders(this.requestHeaders, this.secretValues),
|
|
18820
|
+
responseBody: redactSecrets(this.responseBody, this.secretValues),
|
|
18821
|
+
status: this.status,
|
|
18822
|
+
statusText: this.statusText,
|
|
18823
|
+
url: redactSecrets(this.url, this.secretValues)
|
|
18824
|
+
};
|
|
18825
|
+
}
|
|
18826
|
+
};
|
|
18827
|
+
|
|
18694
18828
|
// src/lib/retry.ts
|
|
18695
18829
|
function sleep(delayMs) {
|
|
18696
18830
|
return new Promise((resolve2) => {
|
|
@@ -18737,6 +18871,42 @@ async function retry(operation, options = {}) {
|
|
|
18737
18871
|
}
|
|
18738
18872
|
throw new Error("Retry exhausted without returning or throwing");
|
|
18739
18873
|
}
|
|
18874
|
+
function isTransientHttpStatus(status) {
|
|
18875
|
+
return status === 408 || status === 429 || status >= 500;
|
|
18876
|
+
}
|
|
18877
|
+
function extractStatus(error2) {
|
|
18878
|
+
if (error2 instanceof HttpError) {
|
|
18879
|
+
return error2.status;
|
|
18880
|
+
}
|
|
18881
|
+
if (error2 && typeof error2 === "object" && "status" in error2) {
|
|
18882
|
+
const status = error2.status;
|
|
18883
|
+
return typeof status === "number" ? status : void 0;
|
|
18884
|
+
}
|
|
18885
|
+
if (error2 && typeof error2 === "object" && "cause" in error2) {
|
|
18886
|
+
return extractStatus(error2.cause);
|
|
18887
|
+
}
|
|
18888
|
+
return void 0;
|
|
18889
|
+
}
|
|
18890
|
+
function shouldRetryReadError(error2) {
|
|
18891
|
+
const status = extractStatus(error2);
|
|
18892
|
+
if (status === void 0) {
|
|
18893
|
+
return true;
|
|
18894
|
+
}
|
|
18895
|
+
return isTransientHttpStatus(status);
|
|
18896
|
+
}
|
|
18897
|
+
function isAmbiguousMutationFailure(error2) {
|
|
18898
|
+
const status = extractStatus(error2);
|
|
18899
|
+
if (status === void 0) {
|
|
18900
|
+
return true;
|
|
18901
|
+
}
|
|
18902
|
+
return isTransientHttpStatus(status);
|
|
18903
|
+
}
|
|
18904
|
+
var SAFE_READ_RETRY = {
|
|
18905
|
+
maxAttempts: 3,
|
|
18906
|
+
delayMs: 2e3,
|
|
18907
|
+
backoffMultiplier: 2,
|
|
18908
|
+
shouldRetry: (error2) => shouldRetryReadError(error2)
|
|
18909
|
+
};
|
|
18740
18910
|
|
|
18741
18911
|
// src/lib/postman/base-urls.ts
|
|
18742
18912
|
var POSTMAN_ENDPOINT_PROFILES = {
|
|
@@ -21627,188 +21797,76 @@ function adviseFromBifrostBody(status, body, ctx) {
|
|
|
21627
21797
|
});
|
|
21628
21798
|
}
|
|
21629
21799
|
|
|
21630
|
-
// src/lib/
|
|
21631
|
-
var
|
|
21632
|
-
var
|
|
21633
|
-
|
|
21634
|
-
|
|
21635
|
-
|
|
21636
|
-
|
|
21637
|
-
|
|
21638
|
-
"
|
|
21639
|
-
]);
|
|
21640
|
-
function isIterable(value) {
|
|
21641
|
-
return value !== null && value !== void 0 && typeof value !== "string" && typeof value[Symbol.iterator] === "function";
|
|
21800
|
+
// src/lib/bifrost-client.ts
|
|
21801
|
+
var DEFAULT_BIFROST_BASE_URL = POSTMAN_ENDPOINT_PROFILES.prod.bifrostBaseUrl;
|
|
21802
|
+
var BIFROST_PROXY_PATH = "/ws/proxy";
|
|
21803
|
+
var DEFAULT_OBSERVABILITY_BASE_URL = POSTMAN_ENDPOINT_PROFILES.prod.observabilityBaseUrl;
|
|
21804
|
+
var DEFAULT_OBSERVABILITY_ENV = POSTMAN_ENDPOINT_PROFILES.prod.observabilityEnv;
|
|
21805
|
+
var MAX_DISCOVERED_SERVICE_PAGES = 100;
|
|
21806
|
+
var MAX_PROVIDER_SERVICE_PAGES = 100;
|
|
21807
|
+
function isExpiredAuthError(status, body) {
|
|
21808
|
+
return status === 401 || body.includes("UNAUTHENTICATED") || body.includes("authenticationError");
|
|
21642
21809
|
}
|
|
21643
|
-
function
|
|
21644
|
-
|
|
21645
|
-
|
|
21810
|
+
function normalizeRepoUrl(url) {
|
|
21811
|
+
return url.trim().replace(/\/+$/, "").toLowerCase();
|
|
21812
|
+
}
|
|
21813
|
+
async function mutateOnceThenReconcile(options) {
|
|
21814
|
+
const existing = await options.findExisting();
|
|
21815
|
+
if (existing !== null) {
|
|
21816
|
+
return existing;
|
|
21646
21817
|
}
|
|
21647
|
-
|
|
21648
|
-
|
|
21649
|
-
|
|
21650
|
-
|
|
21818
|
+
try {
|
|
21819
|
+
return await options.mutate();
|
|
21820
|
+
} catch (error2) {
|
|
21821
|
+
if (!isAmbiguousMutationFailure(error2)) {
|
|
21822
|
+
throw error2;
|
|
21651
21823
|
}
|
|
21652
|
-
|
|
21653
|
-
|
|
21654
|
-
|
|
21655
|
-
results.push(String(value));
|
|
21656
|
-
return;
|
|
21657
|
-
}
|
|
21658
|
-
if (Array.isArray(value) || isIterable(value)) {
|
|
21659
|
-
for (const entry of value) {
|
|
21660
|
-
appendSecretValues(entry, results);
|
|
21824
|
+
const adopted = await options.findExisting();
|
|
21825
|
+
if (adopted !== null) {
|
|
21826
|
+
return adopted;
|
|
21661
21827
|
}
|
|
21828
|
+
throw error2;
|
|
21662
21829
|
}
|
|
21663
21830
|
}
|
|
21664
|
-
|
|
21665
|
-
|
|
21666
|
-
|
|
21667
|
-
|
|
21668
|
-
|
|
21669
|
-
|
|
21670
|
-
|
|
21671
|
-
|
|
21672
|
-
|
|
21673
|
-
|
|
21831
|
+
var BifrostCatalogClient = class {
|
|
21832
|
+
tokenProvider;
|
|
21833
|
+
teamId;
|
|
21834
|
+
apiKey;
|
|
21835
|
+
fetchFn;
|
|
21836
|
+
secretValues;
|
|
21837
|
+
bifrostProxyUrl;
|
|
21838
|
+
observabilityBaseUrl;
|
|
21839
|
+
observabilityEnv;
|
|
21840
|
+
constructor(options) {
|
|
21841
|
+
this.tokenProvider = options.tokenProvider ?? new AccessTokenProvider({
|
|
21842
|
+
accessToken: options.accessToken,
|
|
21843
|
+
apiKey: options.apiKey
|
|
21844
|
+
});
|
|
21845
|
+
this.teamId = options.teamId;
|
|
21846
|
+
this.apiKey = options.apiKey;
|
|
21847
|
+
this.fetchFn = options.fetchFn ?? globalThis.fetch;
|
|
21848
|
+
this.secretValues = [this.tokenProvider.current(), options.apiKey].filter(Boolean);
|
|
21849
|
+
const base = (options.bifrostBaseUrl || DEFAULT_BIFROST_BASE_URL).replace(/\/+$/, "");
|
|
21850
|
+
this.bifrostProxyUrl = `${base}${BIFROST_PROXY_PATH}`;
|
|
21851
|
+
this.observabilityBaseUrl = (options.observabilityBaseUrl || DEFAULT_OBSERVABILITY_BASE_URL).replace(/\/+$/, "");
|
|
21852
|
+
this.observabilityEnv = options.observabilityEnv || DEFAULT_OBSERVABILITY_ENV;
|
|
21674
21853
|
}
|
|
21675
|
-
|
|
21676
|
-
|
|
21677
|
-
|
|
21854
|
+
setApiKey(apiKey) {
|
|
21855
|
+
this.apiKey = apiKey;
|
|
21856
|
+
if (apiKey && !this.secretValues.includes(apiKey)) {
|
|
21857
|
+
this.secretValues.push(apiKey);
|
|
21678
21858
|
}
|
|
21679
|
-
return sanitized.split(secret).join(replacement);
|
|
21680
|
-
}, source);
|
|
21681
|
-
}
|
|
21682
|
-
function createSecretMasker(secretValues, replacement = REDACTED) {
|
|
21683
|
-
return (input) => redactSecrets(input, secretValues, replacement);
|
|
21684
|
-
}
|
|
21685
|
-
function headerEntries(headers) {
|
|
21686
|
-
if (headers instanceof Headers) {
|
|
21687
|
-
return Array.from(headers.entries());
|
|
21688
|
-
}
|
|
21689
|
-
if (Array.isArray(headers)) {
|
|
21690
|
-
return headers.map(([name, value]) => [name, String(value)]);
|
|
21691
21859
|
}
|
|
21692
|
-
|
|
21693
|
-
|
|
21694
|
-
|
|
21695
|
-
|
|
21696
|
-
return {};
|
|
21697
|
-
}
|
|
21698
|
-
const sanitized = {};
|
|
21699
|
-
for (const [name, value] of headerEntries(headers)) {
|
|
21700
|
-
const normalizedName = name.toLowerCase();
|
|
21701
|
-
sanitized[normalizedName] = SENSITIVE_HEADER_NAMES.has(normalizedName) ? REDACTED : redactSecrets(value, secretValues);
|
|
21702
|
-
}
|
|
21703
|
-
return sanitized;
|
|
21704
|
-
}
|
|
21705
|
-
|
|
21706
|
-
// src/lib/http-error.ts
|
|
21707
|
-
function truncate(value, limit) {
|
|
21708
|
-
if (value.length <= limit) {
|
|
21709
|
-
return value;
|
|
21710
|
-
}
|
|
21711
|
-
return `${value.slice(0, limit)}...[truncated]`;
|
|
21712
|
-
}
|
|
21713
|
-
function buildMessage(init) {
|
|
21714
|
-
const method = String(init.method || "GET").toUpperCase();
|
|
21715
|
-
const status = `${init.status}${init.statusText ? ` ${init.statusText}` : ""}`;
|
|
21716
|
-
const url = redactSecrets(init.url, init.secretValues);
|
|
21717
|
-
const body = truncate(
|
|
21718
|
-
redactSecrets(init.responseBody || "", init.secretValues),
|
|
21719
|
-
Math.max(0, init.bodyLimit ?? 800)
|
|
21720
|
-
);
|
|
21721
|
-
return body ? `${method} ${url} failed: ${status} - ${body}` : `${method} ${url} failed: ${status}`;
|
|
21722
|
-
}
|
|
21723
|
-
var HttpError = class _HttpError extends Error {
|
|
21724
|
-
method;
|
|
21725
|
-
requestHeaders;
|
|
21726
|
-
responseBody;
|
|
21727
|
-
secretValues;
|
|
21728
|
-
status;
|
|
21729
|
-
statusText;
|
|
21730
|
-
url;
|
|
21731
|
-
constructor(init) {
|
|
21732
|
-
super(buildMessage(init));
|
|
21733
|
-
this.name = "HttpError";
|
|
21734
|
-
this.method = String(init.method || "GET").toUpperCase();
|
|
21735
|
-
this.requestHeaders = init.requestHeaders;
|
|
21736
|
-
this.responseBody = init.responseBody || "";
|
|
21737
|
-
this.secretValues = init.secretValues;
|
|
21738
|
-
this.status = init.status;
|
|
21739
|
-
this.statusText = init.statusText;
|
|
21740
|
-
this.url = init.url;
|
|
21741
|
-
}
|
|
21742
|
-
static async fromResponse(response, init) {
|
|
21743
|
-
const responseBody = init.responseBody ?? await response.text().catch(() => "");
|
|
21744
|
-
return new _HttpError({
|
|
21745
|
-
...init,
|
|
21746
|
-
responseBody,
|
|
21747
|
-
status: response.status,
|
|
21748
|
-
statusText: response.statusText
|
|
21749
|
-
});
|
|
21750
|
-
}
|
|
21751
|
-
toJSON() {
|
|
21752
|
-
return {
|
|
21753
|
-
method: this.method,
|
|
21754
|
-
name: this.name,
|
|
21755
|
-
requestHeaders: sanitizeHeaders(this.requestHeaders, this.secretValues),
|
|
21756
|
-
responseBody: redactSecrets(this.responseBody, this.secretValues),
|
|
21757
|
-
status: this.status,
|
|
21758
|
-
statusText: this.statusText,
|
|
21759
|
-
url: redactSecrets(this.url, this.secretValues)
|
|
21760
|
-
};
|
|
21761
|
-
}
|
|
21762
|
-
};
|
|
21763
|
-
|
|
21764
|
-
// src/lib/bifrost-client.ts
|
|
21765
|
-
var DEFAULT_BIFROST_BASE_URL = POSTMAN_ENDPOINT_PROFILES.prod.bifrostBaseUrl;
|
|
21766
|
-
var BIFROST_PROXY_PATH = "/ws/proxy";
|
|
21767
|
-
var DEFAULT_OBSERVABILITY_BASE_URL = POSTMAN_ENDPOINT_PROFILES.prod.observabilityBaseUrl;
|
|
21768
|
-
var DEFAULT_OBSERVABILITY_ENV = POSTMAN_ENDPOINT_PROFILES.prod.observabilityEnv;
|
|
21769
|
-
var MAX_DISCOVERED_SERVICE_PAGES = 100;
|
|
21770
|
-
var MAX_PROVIDER_SERVICE_PAGES = 100;
|
|
21771
|
-
function isExpiredAuthError(status, body) {
|
|
21772
|
-
return status === 401 || body.includes("UNAUTHENTICATED") || body.includes("authenticationError");
|
|
21773
|
-
}
|
|
21774
|
-
var BifrostCatalogClient = class {
|
|
21775
|
-
tokenProvider;
|
|
21776
|
-
teamId;
|
|
21777
|
-
apiKey;
|
|
21778
|
-
fetchFn;
|
|
21779
|
-
secretValues;
|
|
21780
|
-
bifrostProxyUrl;
|
|
21781
|
-
observabilityBaseUrl;
|
|
21782
|
-
observabilityEnv;
|
|
21783
|
-
constructor(options) {
|
|
21784
|
-
this.tokenProvider = options.tokenProvider ?? new AccessTokenProvider({
|
|
21785
|
-
accessToken: options.accessToken,
|
|
21786
|
-
apiKey: options.apiKey
|
|
21787
|
-
});
|
|
21788
|
-
this.teamId = options.teamId;
|
|
21789
|
-
this.apiKey = options.apiKey;
|
|
21790
|
-
this.fetchFn = options.fetchFn ?? globalThis.fetch;
|
|
21791
|
-
this.secretValues = [this.tokenProvider.current(), options.apiKey].filter(Boolean);
|
|
21792
|
-
const base = (options.bifrostBaseUrl || DEFAULT_BIFROST_BASE_URL).replace(/\/+$/, "");
|
|
21793
|
-
this.bifrostProxyUrl = `${base}${BIFROST_PROXY_PATH}`;
|
|
21794
|
-
this.observabilityBaseUrl = (options.observabilityBaseUrl || DEFAULT_OBSERVABILITY_BASE_URL).replace(/\/+$/, "");
|
|
21795
|
-
this.observabilityEnv = options.observabilityEnv || DEFAULT_OBSERVABILITY_ENV;
|
|
21796
|
-
}
|
|
21797
|
-
setApiKey(apiKey) {
|
|
21798
|
-
this.apiKey = apiKey;
|
|
21799
|
-
if (apiKey && !this.secretValues.includes(apiKey)) {
|
|
21800
|
-
this.secretValues.push(apiKey);
|
|
21801
|
-
}
|
|
21802
|
-
}
|
|
21803
|
-
registerAccessToken(token) {
|
|
21804
|
-
if (token && !this.secretValues.includes(token)) {
|
|
21805
|
-
this.secretValues.push(token);
|
|
21806
|
-
}
|
|
21860
|
+
registerAccessToken(token) {
|
|
21861
|
+
if (token && !this.secretValues.includes(token)) {
|
|
21862
|
+
this.secretValues.push(token);
|
|
21863
|
+
}
|
|
21807
21864
|
}
|
|
21808
21865
|
/**
|
|
21809
21866
|
* Build Bifrost proxy headers.
|
|
21810
|
-
* x-entity-team-id is ONLY included when teamId is present (
|
|
21811
|
-
* Non-org-mode tokens must OMIT it so Bifrost resolves team
|
|
21867
|
+
* x-entity-team-id is ONLY included when teamId is present (explicit input /
|
|
21868
|
+
* POSTMAN_TEAM_ID). Non-org-mode tokens must OMIT it so Bifrost resolves team
|
|
21869
|
+
* from the access token. Team is never inferred from PMAK.
|
|
21812
21870
|
*/
|
|
21813
21871
|
headers() {
|
|
21814
21872
|
const h = {
|
|
@@ -21836,7 +21894,7 @@ var BifrostCatalogClient = class {
|
|
|
21836
21894
|
mask: createSecretMasker(this.secretValues)
|
|
21837
21895
|
};
|
|
21838
21896
|
}
|
|
21839
|
-
async proxyRequest(method, path7, body = {}, operation = "api-catalog request") {
|
|
21897
|
+
async proxyRequest(method, path7, body = {}, operation = "api-catalog request", allowAuthReplay = false) {
|
|
21840
21898
|
const send2 = async () => this.fetchFn(this.bifrostProxyUrl, {
|
|
21841
21899
|
method: "POST",
|
|
21842
21900
|
headers: this.headers(),
|
|
@@ -21850,7 +21908,7 @@ var BifrostCatalogClient = class {
|
|
|
21850
21908
|
let response = await send2();
|
|
21851
21909
|
if (!response.ok) {
|
|
21852
21910
|
const bodyText = await response.text().catch(() => "");
|
|
21853
|
-
if (isExpiredAuthError(response.status, bodyText) && this.tokenProvider.canRefresh()) {
|
|
21911
|
+
if (allowAuthReplay && isExpiredAuthError(response.status, bodyText) && this.tokenProvider.canRefresh()) {
|
|
21854
21912
|
try {
|
|
21855
21913
|
const refreshed = await this.tokenProvider.refresh();
|
|
21856
21914
|
this.registerAccessToken(refreshed);
|
|
@@ -21901,7 +21959,7 @@ var BifrostCatalogClient = class {
|
|
|
21901
21959
|
}
|
|
21902
21960
|
return data;
|
|
21903
21961
|
}
|
|
21904
|
-
async akitaProxyRequest(method, path7, body = {}, operation = "Insights request") {
|
|
21962
|
+
async akitaProxyRequest(method, path7, body = {}, operation = "Insights request", allowAuthReplay = false) {
|
|
21905
21963
|
const send2 = async () => this.fetchFn(this.bifrostProxyUrl, {
|
|
21906
21964
|
method: "POST",
|
|
21907
21965
|
headers: this.headers(),
|
|
@@ -21915,7 +21973,7 @@ var BifrostCatalogClient = class {
|
|
|
21915
21973
|
let response = await send2();
|
|
21916
21974
|
if (!response.ok) {
|
|
21917
21975
|
const text = await response.text().catch(() => "");
|
|
21918
|
-
if (isExpiredAuthError(response.status, text) && this.tokenProvider.canRefresh()) {
|
|
21976
|
+
if (allowAuthReplay && isExpiredAuthError(response.status, text) && this.tokenProvider.canRefresh()) {
|
|
21919
21977
|
try {
|
|
21920
21978
|
const refreshed = await this.tokenProvider.refresh();
|
|
21921
21979
|
this.registerAccessToken(refreshed);
|
|
@@ -21944,6 +22002,17 @@ ${advised.message}` : advised.message : text;
|
|
|
21944
22002
|
const data = await response.json();
|
|
21945
22003
|
return { ok: true, status: response.status, data, errorText: "" };
|
|
21946
22004
|
}
|
|
22005
|
+
throwAkitaFailure(status, errorText, operation, path7) {
|
|
22006
|
+
const httpErr = new HttpError({
|
|
22007
|
+
method: "POST",
|
|
22008
|
+
url: `bifrost:akita:${path7}`,
|
|
22009
|
+
status,
|
|
22010
|
+
statusText: status >= 500 ? "Error" : "Client Error",
|
|
22011
|
+
responseBody: errorText
|
|
22012
|
+
});
|
|
22013
|
+
const advised = adviseFromHttpError(httpErr, this.adviceContext(operation));
|
|
22014
|
+
throw advised ?? httpErr;
|
|
22015
|
+
}
|
|
21947
22016
|
async listDiscoveredServices() {
|
|
21948
22017
|
return retry(
|
|
21949
22018
|
async () => {
|
|
@@ -21971,26 +22040,80 @@ ${advised.message}` : advised.message : text;
|
|
|
21971
22040
|
}
|
|
21972
22041
|
return allItems;
|
|
21973
22042
|
},
|
|
21974
|
-
|
|
22043
|
+
SAFE_READ_RETRY
|
|
21975
22044
|
);
|
|
21976
22045
|
}
|
|
21977
|
-
|
|
22046
|
+
/** List discovered + integrated services for exact link reconciliation. */
|
|
22047
|
+
async listServicesForReconcile() {
|
|
21978
22048
|
return retry(
|
|
21979
22049
|
async () => {
|
|
22050
|
+
const allItems = [];
|
|
22051
|
+
let cursor = null;
|
|
22052
|
+
const seenCursors = /* @__PURE__ */ new Set();
|
|
22053
|
+
for (let page = 0; page < MAX_DISCOVERED_SERVICE_PAGES; page += 1) {
|
|
22054
|
+
const query = cursor ? `?cursor=${encodeURIComponent(cursor)}` : "";
|
|
22055
|
+
const data = await this.proxyRequest(
|
|
22056
|
+
"GET",
|
|
22057
|
+
`/api/v1/onboarding/discovered-services${query}`,
|
|
22058
|
+
{},
|
|
22059
|
+
"service link reconciliation"
|
|
22060
|
+
);
|
|
22061
|
+
allItems.push(...data.items || []);
|
|
22062
|
+
if (data.total && allItems.length >= data.total) {
|
|
22063
|
+
break;
|
|
22064
|
+
}
|
|
22065
|
+
const nextCursor = data.nextCursor || null;
|
|
22066
|
+
if (!nextCursor || seenCursors.has(nextCursor)) {
|
|
22067
|
+
break;
|
|
22068
|
+
}
|
|
22069
|
+
seenCursors.add(nextCursor);
|
|
22070
|
+
cursor = nextCursor;
|
|
22071
|
+
}
|
|
22072
|
+
return allItems;
|
|
22073
|
+
},
|
|
22074
|
+
SAFE_READ_RETRY
|
|
22075
|
+
);
|
|
22076
|
+
}
|
|
22077
|
+
async findPreparedCollection(serviceId, workspaceId) {
|
|
22078
|
+
const services = await this.listServicesForReconcile();
|
|
22079
|
+
const match = services.find(
|
|
22080
|
+
(service) => service.id === serviceId && Boolean(service.collectionId) && service.workspaceId === workspaceId
|
|
22081
|
+
);
|
|
22082
|
+
return match?.collectionId ? String(match.collectionId) : null;
|
|
22083
|
+
}
|
|
22084
|
+
async findGitLink(params) {
|
|
22085
|
+
const services = await this.listServicesForReconcile();
|
|
22086
|
+
const match = services.find((service) => {
|
|
22087
|
+
if (service.id !== params.serviceId) return false;
|
|
22088
|
+
if (service.workspaceId !== params.workspaceId) return false;
|
|
22089
|
+
if (service.environmentId !== params.environmentId) return false;
|
|
22090
|
+
if (!service.gitRepositoryUrl) return false;
|
|
22091
|
+
return normalizeRepoUrl(service.gitRepositoryUrl) === normalizeRepoUrl(params.gitRepositoryUrl);
|
|
22092
|
+
});
|
|
22093
|
+
return match ? true : null;
|
|
22094
|
+
}
|
|
22095
|
+
async prepareCollection(serviceId, workspaceId) {
|
|
22096
|
+
return mutateOnceThenReconcile({
|
|
22097
|
+
findExisting: () => this.findPreparedCollection(serviceId, workspaceId),
|
|
22098
|
+
mutate: async () => {
|
|
21980
22099
|
const data = await this.proxyRequest(
|
|
21981
22100
|
"POST",
|
|
21982
22101
|
"/api/v1/onboarding/prepare-collection",
|
|
21983
22102
|
{ service_id: String(serviceId), workspace_id: workspaceId },
|
|
21984
|
-
"collection preparation"
|
|
22103
|
+
"collection preparation",
|
|
22104
|
+
false
|
|
21985
22105
|
);
|
|
22106
|
+
if (!data?.id) {
|
|
22107
|
+
throw new Error("prepare-collection succeeded without a collection id");
|
|
22108
|
+
}
|
|
21986
22109
|
return data.id;
|
|
21987
|
-
}
|
|
21988
|
-
|
|
21989
|
-
);
|
|
22110
|
+
}
|
|
22111
|
+
});
|
|
21990
22112
|
}
|
|
21991
22113
|
async onboardGit(params) {
|
|
21992
|
-
await
|
|
21993
|
-
|
|
22114
|
+
await mutateOnceThenReconcile({
|
|
22115
|
+
findExisting: () => this.findGitLink(params),
|
|
22116
|
+
mutate: async () => {
|
|
21994
22117
|
const body = {
|
|
21995
22118
|
via_integrations: false,
|
|
21996
22119
|
git_service_name: "github",
|
|
@@ -22006,24 +22129,32 @@ ${advised.message}` : advised.message : text;
|
|
|
22006
22129
|
"POST",
|
|
22007
22130
|
"/api/v1/onboarding/git",
|
|
22008
22131
|
body,
|
|
22009
|
-
"git onboarding"
|
|
22132
|
+
"git onboarding",
|
|
22133
|
+
false
|
|
22010
22134
|
);
|
|
22011
|
-
|
|
22012
|
-
|
|
22013
|
-
);
|
|
22135
|
+
return true;
|
|
22136
|
+
}
|
|
22137
|
+
});
|
|
22014
22138
|
}
|
|
22015
|
-
async
|
|
22139
|
+
async listProviderServices() {
|
|
22016
22140
|
const allServices = [];
|
|
22017
22141
|
let page = 1;
|
|
22018
22142
|
const pageSize = 100;
|
|
22019
22143
|
for (let pageCount = 0; pageCount < MAX_PROVIDER_SERVICE_PAGES; pageCount += 1) {
|
|
22020
22144
|
const result = await this.akitaProxyRequest(
|
|
22021
22145
|
"GET",
|
|
22022
|
-
`/v2/api-catalog/services?
|
|
22146
|
+
`/v2/api-catalog/services?populate_endpoints=false&populate_discovery_metadata=true&page=${page}&page_size=${pageSize}`,
|
|
22023
22147
|
{},
|
|
22024
22148
|
"provider service resolution"
|
|
22025
22149
|
);
|
|
22026
|
-
if (!result.ok || !result.data)
|
|
22150
|
+
if (!result.ok || !result.data) {
|
|
22151
|
+
this.throwAkitaFailure(
|
|
22152
|
+
result.status,
|
|
22153
|
+
result.errorText,
|
|
22154
|
+
"provider service resolution",
|
|
22155
|
+
"GET /v2/api-catalog/services"
|
|
22156
|
+
);
|
|
22157
|
+
}
|
|
22027
22158
|
const services = result.data.services || [];
|
|
22028
22159
|
allServices.push(...services);
|
|
22029
22160
|
if (result.data.total && allServices.length >= result.data.total) {
|
|
@@ -22034,86 +22165,225 @@ ${advised.message}` : advised.message : text;
|
|
|
22034
22165
|
}
|
|
22035
22166
|
page++;
|
|
22036
22167
|
}
|
|
22168
|
+
return allServices;
|
|
22169
|
+
}
|
|
22170
|
+
async resolveProviderServiceId(projectName, clusterName) {
|
|
22171
|
+
const allServices = await retry(
|
|
22172
|
+
async () => this.listProviderServices(),
|
|
22173
|
+
SAFE_READ_RETRY
|
|
22174
|
+
);
|
|
22037
22175
|
if (clusterName) {
|
|
22038
22176
|
const fullName = `${clusterName}/${projectName}`;
|
|
22039
22177
|
const exactMatch = allServices.find((s) => s.name === fullName);
|
|
22040
22178
|
return exactMatch?.id || null;
|
|
22041
22179
|
}
|
|
22042
|
-
const
|
|
22180
|
+
const finalSegmentMatches = allServices.filter(
|
|
22043
22181
|
(s) => getFinalServiceSegment(s.name) === projectName
|
|
22044
22182
|
);
|
|
22045
|
-
if (
|
|
22046
|
-
|
|
22183
|
+
if (finalSegmentMatches.length > 1) {
|
|
22184
|
+
throw new Error(
|
|
22185
|
+
`Ambiguous Insights provider service "${projectName}": multiple final-segment matches (${finalSegmentMatches.map((s) => s.name).join(", ")}). Provide cluster-name to select the canonical service identity.`
|
|
22186
|
+
);
|
|
22187
|
+
}
|
|
22188
|
+
if (finalSegmentMatches.length === 1) return finalSegmentMatches[0].id;
|
|
22189
|
+
const bracketedMatches = allServices.filter(
|
|
22047
22190
|
(s) => getFinalServiceSegment(s.name).includes(`[${projectName}]`)
|
|
22048
22191
|
);
|
|
22049
|
-
|
|
22192
|
+
if (bracketedMatches.length > 1) {
|
|
22193
|
+
throw new Error(
|
|
22194
|
+
`Ambiguous Insights provider service "${projectName}": multiple bracketed matches. Provide cluster-name to select the canonical service identity.`
|
|
22195
|
+
);
|
|
22196
|
+
}
|
|
22197
|
+
return bracketedMatches[0]?.id || null;
|
|
22198
|
+
}
|
|
22199
|
+
async findAcknowledgedOnboarding(providerServiceId, workspaceId, systemEnvironmentId) {
|
|
22200
|
+
const services = await this.listProviderServices();
|
|
22201
|
+
const match = services.find(
|
|
22202
|
+
(service) => service.id === providerServiceId && service.workspace_id === workspaceId && service.system_env === systemEnvironmentId && (service.status === "onboarded" || service.status === "integrated" || Boolean(service.workspace_id))
|
|
22203
|
+
);
|
|
22204
|
+
return match ? true : null;
|
|
22050
22205
|
}
|
|
22051
22206
|
async acknowledgeOnboarding(providerServiceId, workspaceId, systemEnvironmentId) {
|
|
22052
|
-
|
|
22053
|
-
|
|
22054
|
-
|
|
22055
|
-
|
|
22056
|
-
|
|
22057
|
-
|
|
22058
|
-
|
|
22059
|
-
|
|
22060
|
-
|
|
22207
|
+
await mutateOnceThenReconcile({
|
|
22208
|
+
findExisting: () => this.findAcknowledgedOnboarding(providerServiceId, workspaceId, systemEnvironmentId),
|
|
22209
|
+
mutate: async () => {
|
|
22210
|
+
const result = await this.akitaProxyRequest(
|
|
22211
|
+
"POST",
|
|
22212
|
+
"/v2/api-catalog/services/onboard",
|
|
22213
|
+
{
|
|
22214
|
+
services: [{
|
|
22215
|
+
service_id: providerServiceId,
|
|
22216
|
+
workspace_id: workspaceId,
|
|
22217
|
+
system_env: systemEnvironmentId
|
|
22218
|
+
}]
|
|
22219
|
+
},
|
|
22220
|
+
"Insights onboarding acknowledgment",
|
|
22221
|
+
false
|
|
22222
|
+
);
|
|
22223
|
+
if (!result.ok) {
|
|
22224
|
+
this.throwAkitaFailure(
|
|
22225
|
+
result.status,
|
|
22226
|
+
result.errorText,
|
|
22227
|
+
"Insights onboarding acknowledgment",
|
|
22228
|
+
"POST /v2/api-catalog/services/onboard"
|
|
22229
|
+
);
|
|
22230
|
+
}
|
|
22231
|
+
return true;
|
|
22232
|
+
}
|
|
22233
|
+
});
|
|
22234
|
+
}
|
|
22235
|
+
async findWorkspaceAcknowledged(workspaceId) {
|
|
22236
|
+
const result = await retry(
|
|
22237
|
+
async () => {
|
|
22238
|
+
const response = await this.akitaProxyRequest(
|
|
22239
|
+
"GET",
|
|
22240
|
+
`/v2/workspaces/${workspaceId}/onboarding/acknowledge`,
|
|
22241
|
+
{},
|
|
22242
|
+
"workspace onboarding acknowledgment status"
|
|
22243
|
+
);
|
|
22244
|
+
if (!response.ok) {
|
|
22245
|
+
this.throwAkitaFailure(
|
|
22246
|
+
response.status,
|
|
22247
|
+
response.errorText,
|
|
22248
|
+
"workspace onboarding acknowledgment status",
|
|
22249
|
+
`GET /v2/workspaces/${workspaceId}/onboarding/acknowledge`
|
|
22250
|
+
);
|
|
22251
|
+
}
|
|
22252
|
+
return response;
|
|
22061
22253
|
},
|
|
22062
|
-
|
|
22254
|
+
SAFE_READ_RETRY
|
|
22063
22255
|
);
|
|
22064
|
-
|
|
22065
|
-
throw new Error(`Insights acknowledge failed: ${result.status} ${result.errorText}`);
|
|
22066
|
-
}
|
|
22256
|
+
return result.data?.onboarding_acknowledged ? true : null;
|
|
22067
22257
|
}
|
|
22068
22258
|
async acknowledgeWorkspace(workspaceId) {
|
|
22069
|
-
|
|
22070
|
-
|
|
22071
|
-
|
|
22072
|
-
|
|
22073
|
-
|
|
22074
|
-
|
|
22075
|
-
|
|
22076
|
-
|
|
22077
|
-
|
|
22259
|
+
await mutateOnceThenReconcile({
|
|
22260
|
+
findExisting: () => this.findWorkspaceAcknowledged(workspaceId),
|
|
22261
|
+
mutate: async () => {
|
|
22262
|
+
const result = await this.akitaProxyRequest(
|
|
22263
|
+
"POST",
|
|
22264
|
+
`/v2/workspaces/${workspaceId}/onboarding/acknowledge`,
|
|
22265
|
+
{},
|
|
22266
|
+
"workspace onboarding acknowledgment",
|
|
22267
|
+
false
|
|
22268
|
+
);
|
|
22269
|
+
if (!result.ok) {
|
|
22270
|
+
this.throwAkitaFailure(
|
|
22271
|
+
result.status,
|
|
22272
|
+
result.errorText,
|
|
22273
|
+
"workspace onboarding acknowledgment",
|
|
22274
|
+
`POST /v2/workspaces/${workspaceId}/onboarding/acknowledge`
|
|
22275
|
+
);
|
|
22276
|
+
}
|
|
22277
|
+
return true;
|
|
22278
|
+
}
|
|
22279
|
+
});
|
|
22078
22280
|
}
|
|
22079
|
-
|
|
22080
|
-
// application-binding endpoint (POST /v2/agent/api-catalog/workspaces/:id/
|
|
22081
|
-
// applications) showed x-access-token is rejected identically to the x-api-key
|
|
22082
|
-
// control: both return 401 {"message":"Postman User not found"} for a
|
|
22083
|
-
// service-account credential, because the observability service has no
|
|
22084
|
-
// "Postman User" for a service account. The access token offers no improvement
|
|
22085
|
-
// over the API key here, so this route is not migrated to access-token-primary
|
|
22086
|
-
// (the suite-wide migration explicitly leaves probe-failed routes on PMAK).
|
|
22087
|
-
async createApplication(workspaceId, systemEnv) {
|
|
22281
|
+
async findApplication(workspaceId, systemEnv, expectedServiceId) {
|
|
22088
22282
|
const response = await this.fetchFn(
|
|
22089
22283
|
`${this.observabilityBaseUrl}/v2/agent/api-catalog/workspaces/${workspaceId}/applications`,
|
|
22090
22284
|
{
|
|
22091
|
-
method: "
|
|
22285
|
+
method: "GET",
|
|
22092
22286
|
headers: {
|
|
22093
22287
|
"x-api-key": this.apiKey,
|
|
22094
22288
|
"x-postman-env": this.observabilityEnv,
|
|
22095
22289
|
"Content-Type": "application/json"
|
|
22096
|
-
}
|
|
22097
|
-
body: JSON.stringify({ system_env: systemEnv })
|
|
22290
|
+
}
|
|
22098
22291
|
}
|
|
22099
22292
|
);
|
|
22100
22293
|
if (!response.ok) {
|
|
22101
22294
|
const httpErr = await HttpError.fromResponse(response, {
|
|
22102
|
-
method: "
|
|
22103
|
-
url: `observability:
|
|
22295
|
+
method: "GET",
|
|
22296
|
+
url: `observability:listApplications(${workspaceId})`,
|
|
22104
22297
|
secretValues: this.secretValues
|
|
22105
22298
|
});
|
|
22106
|
-
const advised = adviseFromHttpError(httpErr, this.adviceContext("application binding"));
|
|
22299
|
+
const advised = adviseFromHttpError(httpErr, this.adviceContext("application binding lookup"));
|
|
22107
22300
|
throw advised ?? httpErr;
|
|
22108
22301
|
}
|
|
22109
|
-
|
|
22302
|
+
const data = await response.json();
|
|
22303
|
+
const matches = (data.applications || []).filter(
|
|
22304
|
+
(app) => app.application_id && app.service_id && app.system_env === systemEnv && (!expectedServiceId || app.service_id === expectedServiceId)
|
|
22305
|
+
);
|
|
22306
|
+
if (matches.length > 1) {
|
|
22307
|
+
throw new Error(
|
|
22308
|
+
`Multiple application bindings match workspace ${workspaceId}, system environment ${systemEnv}, and service ${expectedServiceId || "(unspecified)"}`
|
|
22309
|
+
);
|
|
22310
|
+
}
|
|
22311
|
+
const match = matches[0];
|
|
22312
|
+
if (!match?.application_id || !match.service_id) {
|
|
22313
|
+
return null;
|
|
22314
|
+
}
|
|
22315
|
+
return {
|
|
22316
|
+
application_id: String(match.application_id),
|
|
22317
|
+
service_id: String(match.service_id)
|
|
22318
|
+
};
|
|
22319
|
+
}
|
|
22320
|
+
// PMAK-only by proven exception. A live probe against the observability
|
|
22321
|
+
// application-binding endpoint (POST /v2/agent/api-catalog/workspaces/:id/
|
|
22322
|
+
// applications) showed x-access-token is rejected identically to the x-api-key
|
|
22323
|
+
// control: both return 401 {"message":"Postman User not found"} for a
|
|
22324
|
+
// service-account credential, because the observability service has no
|
|
22325
|
+
// "Postman User" for a service account. The access token offers no improvement
|
|
22326
|
+
// over the API key here, so this route is not migrated to access-token-primary
|
|
22327
|
+
// (the suite-wide migration explicitly leaves probe-failed routes on PMAK).
|
|
22328
|
+
async createApplication(workspaceId, systemEnv, expectedServiceId) {
|
|
22329
|
+
return mutateOnceThenReconcile({
|
|
22330
|
+
findExisting: () => retry(
|
|
22331
|
+
() => this.findApplication(workspaceId, systemEnv, expectedServiceId),
|
|
22332
|
+
SAFE_READ_RETRY
|
|
22333
|
+
),
|
|
22334
|
+
mutate: async () => {
|
|
22335
|
+
const response = await this.fetchFn(
|
|
22336
|
+
`${this.observabilityBaseUrl}/v2/agent/api-catalog/workspaces/${workspaceId}/applications`,
|
|
22337
|
+
{
|
|
22338
|
+
method: "POST",
|
|
22339
|
+
headers: {
|
|
22340
|
+
"x-api-key": this.apiKey,
|
|
22341
|
+
"x-postman-env": this.observabilityEnv,
|
|
22342
|
+
"Content-Type": "application/json"
|
|
22343
|
+
},
|
|
22344
|
+
body: JSON.stringify({ system_env: systemEnv })
|
|
22345
|
+
}
|
|
22346
|
+
);
|
|
22347
|
+
if (!response.ok) {
|
|
22348
|
+
const httpErr = await HttpError.fromResponse(response, {
|
|
22349
|
+
method: "POST",
|
|
22350
|
+
url: `observability:createApplication(${workspaceId})`,
|
|
22351
|
+
secretValues: this.secretValues
|
|
22352
|
+
});
|
|
22353
|
+
const advised = adviseFromHttpError(httpErr, this.adviceContext("application binding"));
|
|
22354
|
+
throw advised ?? httpErr;
|
|
22355
|
+
}
|
|
22356
|
+
const created = await response.json();
|
|
22357
|
+
if (expectedServiceId && created.service_id !== expectedServiceId) {
|
|
22358
|
+
throw new Error(
|
|
22359
|
+
`Application binding credential/scope mismatch: expected service ${expectedServiceId}, received ${created.service_id}`
|
|
22360
|
+
);
|
|
22361
|
+
}
|
|
22362
|
+
return created;
|
|
22363
|
+
}
|
|
22364
|
+
});
|
|
22110
22365
|
}
|
|
22111
22366
|
async getTeamVerificationToken(workspaceId) {
|
|
22112
|
-
const result = await
|
|
22113
|
-
|
|
22114
|
-
|
|
22115
|
-
|
|
22116
|
-
|
|
22367
|
+
const result = await retry(
|
|
22368
|
+
async () => {
|
|
22369
|
+
const page = await this.akitaProxyRequest(
|
|
22370
|
+
"GET",
|
|
22371
|
+
`/v2/workspaces/${workspaceId}/team-verification-token`,
|
|
22372
|
+
{},
|
|
22373
|
+
"team verification token retrieval"
|
|
22374
|
+
);
|
|
22375
|
+
if (!page.ok && (page.status === 408 || page.status === 429 || page.status >= 500)) {
|
|
22376
|
+
throw new HttpError({
|
|
22377
|
+
method: "GET",
|
|
22378
|
+
url: `bifrost:akita:GET /v2/workspaces/${workspaceId}/team-verification-token`,
|
|
22379
|
+
status: page.status,
|
|
22380
|
+
statusText: "Error",
|
|
22381
|
+
responseBody: page.errorText
|
|
22382
|
+
});
|
|
22383
|
+
}
|
|
22384
|
+
return page;
|
|
22385
|
+
},
|
|
22386
|
+
SAFE_READ_RETRY
|
|
22117
22387
|
);
|
|
22118
22388
|
if (!result.ok || !result.data) return null;
|
|
22119
22389
|
return result.data.team_verification_token || null;
|
|
@@ -22146,18 +22416,52 @@ ${advised.message}` : advised.message : text;
|
|
|
22146
22416
|
return String(apikey.key);
|
|
22147
22417
|
}
|
|
22148
22418
|
};
|
|
22419
|
+
function buildCanonicalServiceIdentity(service, projectName, clusterName, providerServiceId) {
|
|
22420
|
+
const derivedCluster = clusterName || (service.name.includes("/") ? service.name.slice(0, service.name.lastIndexOf("/")) : null);
|
|
22421
|
+
return {
|
|
22422
|
+
serviceId: service.id,
|
|
22423
|
+
serviceName: service.name,
|
|
22424
|
+
clusterName: derivedCluster,
|
|
22425
|
+
projectName,
|
|
22426
|
+
...providerServiceId ? { providerServiceId } : {}
|
|
22427
|
+
};
|
|
22428
|
+
}
|
|
22149
22429
|
function findDiscoveredService(services, projectName, clusterName) {
|
|
22150
22430
|
if (clusterName) {
|
|
22151
22431
|
const fullName = `${clusterName}/${projectName}`;
|
|
22152
|
-
|
|
22432
|
+
const match = services.find((s) => s.name === fullName);
|
|
22433
|
+
if (match) {
|
|
22434
|
+
match.canonicalIdentity = buildCanonicalServiceIdentity(match, projectName, clusterName);
|
|
22435
|
+
}
|
|
22436
|
+
return match;
|
|
22153
22437
|
}
|
|
22154
|
-
const
|
|
22438
|
+
const finalSegmentMatches = services.filter(
|
|
22155
22439
|
(service) => getFinalServiceSegment(service.name) === projectName
|
|
22156
22440
|
);
|
|
22157
|
-
if (
|
|
22158
|
-
|
|
22441
|
+
if (finalSegmentMatches.length > 1) {
|
|
22442
|
+
throw new Error(
|
|
22443
|
+
`Ambiguous discovered service "${projectName}": multiple final-segment matches (${finalSegmentMatches.map((s) => s.name).join(", ")}). cluster-name is required to select the canonical service identity.`
|
|
22444
|
+
);
|
|
22445
|
+
}
|
|
22446
|
+
if (finalSegmentMatches.length === 1) {
|
|
22447
|
+
const match = finalSegmentMatches[0];
|
|
22448
|
+
match.canonicalIdentity = buildCanonicalServiceIdentity(match, projectName);
|
|
22449
|
+
return match;
|
|
22450
|
+
}
|
|
22451
|
+
const bracketedMatches = services.filter(
|
|
22159
22452
|
(service) => getFinalServiceSegment(service.name).includes(`[${projectName}]`)
|
|
22160
22453
|
);
|
|
22454
|
+
if (bracketedMatches.length > 1) {
|
|
22455
|
+
throw new Error(
|
|
22456
|
+
`Ambiguous discovered service "${projectName}": multiple bracketed matches. cluster-name is required to select the canonical service identity.`
|
|
22457
|
+
);
|
|
22458
|
+
}
|
|
22459
|
+
if (bracketedMatches.length === 1) {
|
|
22460
|
+
const match = bracketedMatches[0];
|
|
22461
|
+
match.canonicalIdentity = buildCanonicalServiceIdentity(match, projectName);
|
|
22462
|
+
return match;
|
|
22463
|
+
}
|
|
22464
|
+
return void 0;
|
|
22161
22465
|
}
|
|
22162
22466
|
function getFinalServiceSegment(serviceName) {
|
|
22163
22467
|
const lastSlash = serviceName.lastIndexOf("/");
|
|
@@ -22349,7 +22653,7 @@ function normalize(value) {
|
|
|
22349
22653
|
const trimmed = (value ?? "").trim();
|
|
22350
22654
|
return trimmed.length > 0 ? trimmed : void 0;
|
|
22351
22655
|
}
|
|
22352
|
-
function
|
|
22656
|
+
function normalizeRepoUrl2(url) {
|
|
22353
22657
|
const raw = normalize(url);
|
|
22354
22658
|
if (!raw) {
|
|
22355
22659
|
return void 0;
|
|
@@ -22417,7 +22721,7 @@ function classifyRefKind(env = process.env) {
|
|
|
22417
22721
|
return "unknown";
|
|
22418
22722
|
}
|
|
22419
22723
|
function detectRepoContext(input, env = process.env) {
|
|
22420
|
-
const repoUrl =
|
|
22724
|
+
const repoUrl = normalizeRepoUrl2(input.repoUrl) ?? normalizeRepoUrl2(env.GITHUB_SERVER_URL && env.GITHUB_REPOSITORY ? `${env.GITHUB_SERVER_URL}/${env.GITHUB_REPOSITORY}` : void 0) ?? normalizeRepoUrl2(env.CI_PROJECT_URL) ?? normalizeRepoUrl2(env.BITBUCKET_GIT_HTTP_ORIGIN) ?? normalizeRepoUrl2(env.BUILD_REPOSITORY_URI);
|
|
22421
22725
|
const repoSlug = normalize(input.repoSlug) ?? normalize(env.GITHUB_REPOSITORY) ?? normalize(env.CI_PROJECT_PATH) ?? (env.BITBUCKET_WORKSPACE && env.BITBUCKET_REPO_SLUG ? normalize(`${env.BITBUCKET_WORKSPACE}/${env.BITBUCKET_REPO_SLUG}`) : void 0) ?? normalize(env.BUILD_REPOSITORY_NAME);
|
|
22422
22726
|
const ref = normalize(input.ref) ?? normalize(env.GITHUB_REF_NAME) ?? normalize(env.CI_COMMIT_REF_NAME) ?? normalize(env.BITBUCKET_BRANCH) ?? normalize(env.BUILD_SOURCEBRANCHNAME);
|
|
22423
22727
|
const sha = normalize(input.sha) ?? normalize(env.GITHUB_SHA) ?? normalize(env.CI_COMMIT_SHA) ?? normalize(env.BITBUCKET_COMMIT) ?? normalize(env.BUILD_SOURCEVERSION);
|
|
@@ -22594,7 +22898,7 @@ var DEFAULT_POSTMAN_BIFROST_BASE = PROD_ENDPOINTS.bifrostBaseUrl;
|
|
|
22594
22898
|
var DEFAULT_POSTMAN_IAPUB_BASE = PROD_ENDPOINTS.iapubBaseUrl;
|
|
22595
22899
|
var DEFAULT_POSTMAN_OBSERVABILITY_BASE = PROD_ENDPOINTS.observabilityBaseUrl;
|
|
22596
22900
|
function parsePreflightMode(value) {
|
|
22597
|
-
const normalized = String(value || "
|
|
22901
|
+
const normalized = String(value || "enforce").trim().toLowerCase();
|
|
22598
22902
|
if (normalized === "enforce" || normalized === "warn") {
|
|
22599
22903
|
return normalized;
|
|
22600
22904
|
}
|
|
@@ -22602,6 +22906,27 @@ function parsePreflightMode(value) {
|
|
|
22602
22906
|
`Unsupported credential-preflight "${value}". Supported values: enforce, warn`
|
|
22603
22907
|
);
|
|
22604
22908
|
}
|
|
22909
|
+
function parseServiceNotFoundPolicy(value) {
|
|
22910
|
+
const normalized = String(value || "fail").trim().toLowerCase();
|
|
22911
|
+
if (normalized === "fail" || normalized === "warn") {
|
|
22912
|
+
return normalized;
|
|
22913
|
+
}
|
|
22914
|
+
throw new Error(
|
|
22915
|
+
`Unsupported service-not-found-policy "${value}". Supported values: fail, warn`
|
|
22916
|
+
);
|
|
22917
|
+
}
|
|
22918
|
+
function parseCreateApiKey(value) {
|
|
22919
|
+
const normalized = String(value || "false").trim().toLowerCase();
|
|
22920
|
+
if (normalized === "true") {
|
|
22921
|
+
return true;
|
|
22922
|
+
}
|
|
22923
|
+
if (normalized === "false" || normalized === "") {
|
|
22924
|
+
return false;
|
|
22925
|
+
}
|
|
22926
|
+
throw new Error(
|
|
22927
|
+
`Unsupported create-api-key "${value}". Supported values: true, false`
|
|
22928
|
+
);
|
|
22929
|
+
}
|
|
22605
22930
|
function trimTrailingSlash(value) {
|
|
22606
22931
|
return value.replace(/\/+$/, "");
|
|
22607
22932
|
}
|
|
@@ -22620,23 +22945,6 @@ async function validateApiKey(apiKey, apiBase = DEFAULT_POSTMAN_API_BASE) {
|
|
|
22620
22945
|
const teamId = data?.user?.teamId ? String(data.user.teamId) : void 0;
|
|
22621
22946
|
return { valid: true, teamId };
|
|
22622
22947
|
}
|
|
22623
|
-
async function getTeams(apiKey, apiBase = DEFAULT_POSTMAN_API_BASE) {
|
|
22624
|
-
try {
|
|
22625
|
-
const res = await fetch(`${trimTrailingSlash(apiBase)}/teams`, {
|
|
22626
|
-
method: "GET",
|
|
22627
|
-
headers: { "x-api-key": apiKey }
|
|
22628
|
-
});
|
|
22629
|
-
if (!res.ok) return [];
|
|
22630
|
-
const data = await res.json();
|
|
22631
|
-
return (data?.data ?? []).filter((t) => t?.id && t?.name).map((t) => ({
|
|
22632
|
-
id: Number(t.id),
|
|
22633
|
-
name: String(t.name),
|
|
22634
|
-
...t.organizationId != null ? { organizationId: Number(t.organizationId) } : {}
|
|
22635
|
-
}));
|
|
22636
|
-
} catch {
|
|
22637
|
-
return [];
|
|
22638
|
-
}
|
|
22639
|
-
}
|
|
22640
22948
|
function clamp(value, min, max, fallback) {
|
|
22641
22949
|
const parsed = Number.isFinite(value) ? value : fallback;
|
|
22642
22950
|
return Math.min(max, Math.max(min, parsed));
|
|
@@ -22683,7 +22991,9 @@ function resolveInputs(env = process.env) {
|
|
|
22683
22991
|
postmanApiKey,
|
|
22684
22992
|
postmanTeamId,
|
|
22685
22993
|
githubToken: get("github-token", env.GITHUB_TOKEN || ""),
|
|
22686
|
-
credentialPreflight: parsePreflightMode(get("credential-preflight", "
|
|
22994
|
+
credentialPreflight: parsePreflightMode(get("credential-preflight", "enforce")),
|
|
22995
|
+
createApiKey: parseCreateApiKey(get("create-api-key", "false")),
|
|
22996
|
+
serviceNotFoundPolicy: parseServiceNotFoundPolicy(get("service-not-found-policy", "fail")),
|
|
22687
22997
|
pollTimeoutSeconds: clamp(rawTimeout, POLL_TIMEOUT_MIN, POLL_TIMEOUT_MAX, POLL_TIMEOUT_DEFAULT),
|
|
22688
22998
|
pollIntervalSeconds: clamp(rawInterval, POLL_INTERVAL_MIN, POLL_INTERVAL_MAX, POLL_INTERVAL_DEFAULT),
|
|
22689
22999
|
postmanRegion,
|
|
@@ -22699,6 +23009,7 @@ async function runOnboarding(inputs, client, sleepFn = sleep, reporter = core_ex
|
|
|
22699
23009
|
const timeoutMs = inputs.pollTimeoutSeconds * 1e3;
|
|
22700
23010
|
const intervalMs = inputs.pollIntervalSeconds * 1e3;
|
|
22701
23011
|
const startTime = Date.now();
|
|
23012
|
+
const policy = inputs.serviceNotFoundPolicy ?? "fail";
|
|
22702
23013
|
reporter.info(`Looking for discovered service matching "${inputs.clusterName ? `${inputs.clusterName}/` : ""}${inputs.projectName}"...`);
|
|
22703
23014
|
let match = void 0;
|
|
22704
23015
|
while (Date.now() - startTime < timeoutMs) {
|
|
@@ -22713,15 +23024,35 @@ async function runOnboarding(inputs, client, sleepFn = sleep, reporter = core_ex
|
|
|
22713
23024
|
await sleepFn(intervalMs);
|
|
22714
23025
|
}
|
|
22715
23026
|
if (!match) {
|
|
22716
|
-
|
|
22717
|
-
|
|
22718
|
-
|
|
22719
|
-
|
|
22720
|
-
|
|
22721
|
-
|
|
22722
|
-
|
|
22723
|
-
|
|
22724
|
-
|
|
23027
|
+
const message = `Service "${inputs.projectName}" not found in discovered services after ${inputs.pollTimeoutSeconds}s`;
|
|
23028
|
+
if (policy === "warn") {
|
|
23029
|
+
reporter.warning(message);
|
|
23030
|
+
return {
|
|
23031
|
+
discoveredServiceId: 0,
|
|
23032
|
+
discoveredServiceName: "",
|
|
23033
|
+
collectionId: "",
|
|
23034
|
+
applicationId: "",
|
|
23035
|
+
verificationToken: null,
|
|
23036
|
+
status: "not-found"
|
|
23037
|
+
};
|
|
23038
|
+
}
|
|
23039
|
+
throw new Error(`${message}. Full linking requires a discovered service (service-not-found-policy=fail).`);
|
|
23040
|
+
}
|
|
23041
|
+
const canonicalBase = match.canonicalIdentity ?? buildCanonicalServiceIdentity(match, inputs.projectName, inputs.clusterName || void 0);
|
|
23042
|
+
const providerServiceId = await client.resolveProviderServiceId(
|
|
23043
|
+
inputs.projectName,
|
|
23044
|
+
inputs.clusterName || void 0
|
|
23045
|
+
);
|
|
23046
|
+
if (!providerServiceId) {
|
|
23047
|
+
throw new Error(
|
|
23048
|
+
`Insights provider service "${canonicalBase.serviceName}" was not found. Full linking requires one exact canonical service identity.`
|
|
23049
|
+
);
|
|
23050
|
+
}
|
|
23051
|
+
const sysEnvId = inputs.systemEnvironmentId || match.systemEnvironmentId || "";
|
|
23052
|
+
if (!sysEnvId) {
|
|
23053
|
+
throw new Error(
|
|
23054
|
+
`No system environment id is available for "${canonicalBase.serviceName}"; refusing partial linking writes.`
|
|
23055
|
+
);
|
|
22725
23056
|
}
|
|
22726
23057
|
reporter.info(`Preparing collection for service ${match.id} in workspace ${inputs.workspaceId}...`);
|
|
22727
23058
|
const collectionId = await client.prepareCollection(match.id, inputs.workspaceId);
|
|
@@ -22741,27 +23072,12 @@ async function runOnboarding(inputs, client, sleepFn = sleep, reporter = core_ex
|
|
|
22741
23072
|
} else {
|
|
22742
23073
|
reporter.info(`Skipping git onboarding for non-GitHub repo: ${repoUrl}`);
|
|
22743
23074
|
}
|
|
22744
|
-
|
|
22745
|
-
|
|
22746
|
-
|
|
22747
|
-
);
|
|
22748
|
-
|
|
22749
|
-
|
|
22750
|
-
const sysEnvId = inputs.systemEnvironmentId || match.systemEnvironmentId || "";
|
|
22751
|
-
if (sysEnvId) {
|
|
22752
|
-
reporter.info(`Acknowledging Insights onboarding for ${providerServiceId}...`);
|
|
22753
|
-
await client.acknowledgeOnboarding(providerServiceId, inputs.workspaceId, sysEnvId);
|
|
22754
|
-
reporter.info(`Insights acknowledged: ${providerServiceId}`);
|
|
22755
|
-
reporter.info(`Creating application binding for workspace ${inputs.workspaceId} with system_env ${sysEnvId}...`);
|
|
22756
|
-
const appResult = await client.createApplication(inputs.workspaceId, sysEnvId);
|
|
22757
|
-
applicationId = appResult.application_id;
|
|
22758
|
-
reporter.info(`Application binding created: ${appResult.application_id} for service ${appResult.service_id}`);
|
|
22759
|
-
} else {
|
|
22760
|
-
reporter.warning("No systemEnvironmentId available; skipping Insights acknowledgment and application binding");
|
|
22761
|
-
}
|
|
22762
|
-
} else {
|
|
22763
|
-
reporter.warning("Could not resolve Akita provider service ID; skipping acknowledgment and application binding");
|
|
22764
|
-
}
|
|
23075
|
+
reporter.info(`Acknowledging Insights onboarding for ${providerServiceId}...`);
|
|
23076
|
+
await client.acknowledgeOnboarding(providerServiceId, inputs.workspaceId, sysEnvId);
|
|
23077
|
+
reporter.info(`Insights acknowledged: ${providerServiceId}`);
|
|
23078
|
+
reporter.info(`Creating application binding for workspace ${inputs.workspaceId} with system_env ${sysEnvId}...`);
|
|
23079
|
+
const appResult = await client.createApplication(inputs.workspaceId, sysEnvId, providerServiceId);
|
|
23080
|
+
reporter.info(`Application binding created: ${appResult.application_id} for service ${appResult.service_id}`);
|
|
22765
23081
|
reporter.info(`Acknowledging workspace onboarding for ${inputs.workspaceId}...`);
|
|
22766
23082
|
await client.acknowledgeWorkspace(inputs.workspaceId);
|
|
22767
23083
|
reporter.info("Workspace onboarding acknowledged");
|
|
@@ -22777,9 +23093,13 @@ async function runOnboarding(inputs, client, sleepFn = sleep, reporter = core_ex
|
|
|
22777
23093
|
discoveredServiceId: match.id,
|
|
22778
23094
|
discoveredServiceName: match.name,
|
|
22779
23095
|
collectionId,
|
|
22780
|
-
applicationId,
|
|
23096
|
+
applicationId: appResult.application_id,
|
|
22781
23097
|
verificationToken,
|
|
22782
|
-
status: "success"
|
|
23098
|
+
status: "success",
|
|
23099
|
+
canonicalIdentity: {
|
|
23100
|
+
...canonicalBase,
|
|
23101
|
+
...providerServiceId ? { providerServiceId } : {}
|
|
23102
|
+
}
|
|
22783
23103
|
};
|
|
22784
23104
|
}
|
|
22785
23105
|
async function resolveApiKeyAndTeamId(inputs, client, reporter = core_exports) {
|
|
@@ -22788,6 +23108,7 @@ async function resolveApiKeyAndTeamId(inputs, client, reporter = core_exports) {
|
|
|
22788
23108
|
let keyValid = false;
|
|
22789
23109
|
let pmakIdentity;
|
|
22790
23110
|
const apiBase = inputs.postmanApiBase || DEFAULT_POSTMAN_API_BASE;
|
|
23111
|
+
const createApiKey = inputs.createApiKey === true;
|
|
22791
23112
|
if (apiKey) {
|
|
22792
23113
|
const result = await validateApiKey(apiKey, apiBase);
|
|
22793
23114
|
keyValid = result.valid;
|
|
@@ -22798,49 +23119,36 @@ async function resolveApiKeyAndTeamId(inputs, client, reporter = core_exports) {
|
|
|
22798
23119
|
}
|
|
22799
23120
|
}
|
|
22800
23121
|
if (!keyValid) {
|
|
22801
|
-
|
|
22802
|
-
|
|
23122
|
+
if (!createApiKey) {
|
|
23123
|
+
if (apiKey) {
|
|
23124
|
+
throw new Error(
|
|
23125
|
+
"postman-api-key is invalid or expired. Provide a valid key, or set create-api-key=true to opt in to durable Bifrost API-key creation."
|
|
23126
|
+
);
|
|
23127
|
+
}
|
|
23128
|
+
throw new Error(
|
|
23129
|
+
"postman-api-key is required for application binding. Provide a valid key, or set create-api-key=true to opt in to durable Bifrost API-key creation."
|
|
23130
|
+
);
|
|
23131
|
+
}
|
|
23132
|
+
reporter.info("create-api-key=true: generating a durable Postman API key via Bifrost identity service...");
|
|
23133
|
+
const keyName = `insights-onboarding-${inputs.projectName}`;
|
|
22803
23134
|
apiKey = await client.createApiKey(keyName);
|
|
22804
23135
|
reporter.setSecret(apiKey);
|
|
22805
23136
|
client.setApiKey(apiKey);
|
|
22806
|
-
|
|
22807
|
-
|
|
22808
|
-
|
|
22809
|
-
if (!resolvedTeamId && apiKey) {
|
|
22810
|
-
try {
|
|
22811
|
-
const teams = await getTeams(apiKey, apiBase);
|
|
22812
|
-
if (teams.length > 1 && teams.every((t) => t.organizationId == null)) {
|
|
22813
|
-
reporter.warning(
|
|
22814
|
-
"GET /teams returned multiple teams but none include organizationId. Org-mode auto-detection may be degraded due to an upstream API change. Set postman-team-id explicitly if Bifrost calls fail."
|
|
22815
|
-
);
|
|
22816
|
-
}
|
|
22817
|
-
const isOrgMode = teams.some((t) => t.organizationId != null);
|
|
22818
|
-
if (isOrgMode) {
|
|
22819
|
-
if (teams.length === 1) {
|
|
22820
|
-
resolvedTeamId = String(teams[0].id);
|
|
22821
|
-
reporter.info(
|
|
22822
|
-
`Org-mode account detected. Using sub-team ${teams[0].id} (${teams[0].name ?? "unknown"}) for Bifrost calls.`
|
|
22823
|
-
);
|
|
22824
|
-
} else {
|
|
22825
|
-
const meResult = await validateApiKey(apiKey, apiBase);
|
|
22826
|
-
const meTeamId = meResult.teamId ? parseInt(meResult.teamId, 10) : NaN;
|
|
22827
|
-
if (!Number.isNaN(meTeamId) && teams.some((t) => t.id === meTeamId)) {
|
|
22828
|
-
resolvedTeamId = String(meTeamId);
|
|
22829
|
-
reporter.info(
|
|
22830
|
-
`Org-mode account detected. Using sub-team ${meTeamId} (from /me) for Bifrost calls.`
|
|
22831
|
-
);
|
|
22832
|
-
}
|
|
22833
|
-
}
|
|
22834
|
-
}
|
|
22835
|
-
} catch {
|
|
23137
|
+
const createdIdentity = await validateApiKey(apiKey, apiBase);
|
|
23138
|
+
if (!createdIdentity.valid) {
|
|
23139
|
+
throw new Error("The explicitly created postman-api-key could not be validated; refusing linking writes.");
|
|
22836
23140
|
}
|
|
23141
|
+
pmakIdentity = { source: "pmak/me", teamId: createdIdentity.teamId };
|
|
23142
|
+
reporter.info(`New API key created successfully (${keyName}).`);
|
|
22837
23143
|
}
|
|
22838
|
-
if (
|
|
22839
|
-
reporter.info(`Using postman-team-id for Bifrost headers: ${
|
|
23144
|
+
if (teamId) {
|
|
23145
|
+
reporter.info(`Using explicit postman-team-id for Bifrost headers: ${teamId}`);
|
|
22840
23146
|
} else {
|
|
22841
|
-
reporter.info(
|
|
23147
|
+
reporter.info(
|
|
23148
|
+
"No postman-team-id / POSTMAN_TEAM_ID provided; omitting x-entity-team-id so Bifrost resolves team from the access token."
|
|
23149
|
+
);
|
|
22842
23150
|
}
|
|
22843
|
-
return { apiKey, teamId
|
|
23151
|
+
return { apiKey, teamId, pmakIdentity };
|
|
22844
23152
|
}
|
|
22845
23153
|
async function runCredentialPreflightForInputs(inputs, pmak, reporter, fetchImpl, liveAccessToken) {
|
|
22846
23154
|
const accessToken = liveAccessToken ?? inputs.postmanAccessToken;
|
|
@@ -22886,7 +23194,9 @@ var INPUT_NAMES = [
|
|
|
22886
23194
|
"repo-url",
|
|
22887
23195
|
"postman-access-token",
|
|
22888
23196
|
"postman-api-key",
|
|
23197
|
+
"create-api-key",
|
|
22889
23198
|
"credential-preflight",
|
|
23199
|
+
"service-not-found-policy",
|
|
22890
23200
|
"postman-team-id",
|
|
22891
23201
|
"github-token",
|
|
22892
23202
|
"poll-timeout-seconds",
|
|
@@ -23126,31 +23436,53 @@ async function runCli(argv = process.argv.slice(2), runtime = {}) {
|
|
|
23126
23436
|
inputs.postmanTeamId,
|
|
23127
23437
|
inputs.postmanApiKey
|
|
23128
23438
|
);
|
|
23129
|
-
const { apiKey, teamId, pmakIdentity } = await resolveApiKeyAndTeamId(
|
|
23130
|
-
inputs,
|
|
23131
|
-
preliminaryClient,
|
|
23132
|
-
reporter
|
|
23133
|
-
);
|
|
23134
|
-
const activeTokenProvider = apiKey !== inputs.postmanApiKey ? new AccessTokenProvider({
|
|
23135
|
-
accessToken: tokenProvider.current(),
|
|
23136
|
-
apiKey,
|
|
23137
|
-
apiBaseUrl: inputs.postmanApiBase || DEFAULT_POSTMAN_API_BASE,
|
|
23138
|
-
onToken: (token) => reporter.setSecret(token)
|
|
23139
|
-
}) : tokenProvider;
|
|
23140
23439
|
const telemetry = createTelemetryContext({ action: "postman-insights-onboarding-action", actionVersion: resolveActionVersion2(), logger: reporter });
|
|
23141
|
-
telemetry.setTeamId(inputs.postmanTeamId
|
|
23142
|
-
if (apiKey) {
|
|
23143
|
-
reporter.setSecret(apiKey);
|
|
23144
|
-
}
|
|
23440
|
+
telemetry.setTeamId(inputs.postmanTeamId);
|
|
23145
23441
|
let result;
|
|
23146
23442
|
try {
|
|
23443
|
+
let preflightPmakIdentity;
|
|
23444
|
+
if (inputs.postmanApiKey) {
|
|
23445
|
+
const validated = await validateApiKey(
|
|
23446
|
+
inputs.postmanApiKey,
|
|
23447
|
+
inputs.postmanApiBase || DEFAULT_POSTMAN_API_BASE
|
|
23448
|
+
);
|
|
23449
|
+
if (validated.valid) {
|
|
23450
|
+
preflightPmakIdentity = { source: "pmak/me", teamId: validated.teamId };
|
|
23451
|
+
} else if (!inputs.createApiKey) {
|
|
23452
|
+
throw new Error(
|
|
23453
|
+
"postman-api-key is invalid or expired. Provide a valid key, or set create-api-key=true to opt in to durable Bifrost API-key creation."
|
|
23454
|
+
);
|
|
23455
|
+
}
|
|
23456
|
+
} else if (!inputs.createApiKey) {
|
|
23457
|
+
throw new Error(
|
|
23458
|
+
"postman-api-key is required for application binding. Provide a valid key, or set create-api-key=true to opt in to durable Bifrost API-key creation."
|
|
23459
|
+
);
|
|
23460
|
+
}
|
|
23147
23461
|
await runCredentialPreflightForInputs(
|
|
23148
23462
|
inputs,
|
|
23149
|
-
|
|
23463
|
+
preflightPmakIdentity,
|
|
23150
23464
|
reporter,
|
|
23151
23465
|
void 0,
|
|
23152
|
-
|
|
23466
|
+
tokenProvider.current()
|
|
23153
23467
|
);
|
|
23468
|
+
const { apiKey, teamId, pmakIdentity } = await resolveApiKeyAndTeamId(inputs, preliminaryClient, reporter);
|
|
23469
|
+
telemetry.setTeamId(inputs.postmanTeamId || pmakIdentity?.teamId);
|
|
23470
|
+
reporter.setSecret(apiKey);
|
|
23471
|
+
const activeTokenProvider = apiKey !== inputs.postmanApiKey ? new AccessTokenProvider({
|
|
23472
|
+
accessToken: tokenProvider.current(),
|
|
23473
|
+
apiKey,
|
|
23474
|
+
apiBaseUrl: inputs.postmanApiBase || DEFAULT_POSTMAN_API_BASE,
|
|
23475
|
+
onToken: (token) => reporter.setSecret(token)
|
|
23476
|
+
}) : tokenProvider;
|
|
23477
|
+
if (pmakIdentity?.teamId !== preflightPmakIdentity?.teamId) {
|
|
23478
|
+
await runCredentialPreflightForInputs(
|
|
23479
|
+
inputs,
|
|
23480
|
+
pmakIdentity,
|
|
23481
|
+
reporter,
|
|
23482
|
+
void 0,
|
|
23483
|
+
activeTokenProvider.current()
|
|
23484
|
+
);
|
|
23485
|
+
}
|
|
23154
23486
|
const client = createInsightsBifrostClient(inputs, activeTokenProvider, teamId, apiKey);
|
|
23155
23487
|
result = await (runtime.executeOnboarding ?? runOnboarding)(
|
|
23156
23488
|
inputs,
|