@postman-cse/onboarding-insights 1.0.3 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +15 -13
- package/action.yml +3 -3
- package/dist/action.cjs +357 -46
- package/dist/cli.cjs +449 -138
- package/dist/index.cjs +361 -46
- package/package.json +4 -4
package/dist/index.cjs
CHANGED
|
@@ -12167,7 +12167,7 @@ var require_response = __commonJS({
|
|
|
12167
12167
|
var assert = require("node:assert");
|
|
12168
12168
|
var { types } = require("node:util");
|
|
12169
12169
|
var textEncoder = new TextEncoder("utf-8");
|
|
12170
|
-
var
|
|
12170
|
+
var Response2 = class _Response {
|
|
12171
12171
|
// Creates network error Response.
|
|
12172
12172
|
static error() {
|
|
12173
12173
|
const responseObject = fromInnerResponse(makeNetworkError(), "immutable");
|
|
@@ -12310,8 +12310,8 @@ var require_response = __commonJS({
|
|
|
12310
12310
|
return `Response ${nodeUtil.formatWithOptions(options, properties)}`;
|
|
12311
12311
|
}
|
|
12312
12312
|
};
|
|
12313
|
-
mixinBody(
|
|
12314
|
-
Object.defineProperties(
|
|
12313
|
+
mixinBody(Response2);
|
|
12314
|
+
Object.defineProperties(Response2.prototype, {
|
|
12315
12315
|
type: kEnumerableProperty,
|
|
12316
12316
|
url: kEnumerableProperty,
|
|
12317
12317
|
status: kEnumerableProperty,
|
|
@@ -12327,7 +12327,7 @@ var require_response = __commonJS({
|
|
|
12327
12327
|
configurable: true
|
|
12328
12328
|
}
|
|
12329
12329
|
});
|
|
12330
|
-
Object.defineProperties(
|
|
12330
|
+
Object.defineProperties(Response2, {
|
|
12331
12331
|
json: kEnumerableProperty,
|
|
12332
12332
|
redirect: kEnumerableProperty,
|
|
12333
12333
|
error: kEnumerableProperty
|
|
@@ -12460,7 +12460,7 @@ var require_response = __commonJS({
|
|
|
12460
12460
|
}
|
|
12461
12461
|
}
|
|
12462
12462
|
function fromInnerResponse(innerResponse, guard) {
|
|
12463
|
-
const response = new
|
|
12463
|
+
const response = new Response2(kConstruct);
|
|
12464
12464
|
response[kState] = innerResponse;
|
|
12465
12465
|
response[kHeaders] = new Headers3(kConstruct);
|
|
12466
12466
|
setHeadersList(response[kHeaders], innerResponse.headersList);
|
|
@@ -12528,7 +12528,7 @@ var require_response = __commonJS({
|
|
|
12528
12528
|
makeResponse,
|
|
12529
12529
|
makeAppropriateNetworkError,
|
|
12530
12530
|
filterResponse,
|
|
12531
|
-
Response,
|
|
12531
|
+
Response: Response2,
|
|
12532
12532
|
cloneResponse,
|
|
12533
12533
|
fromInnerResponse
|
|
12534
12534
|
};
|
|
@@ -15200,7 +15200,7 @@ var require_cache = __commonJS({
|
|
|
15200
15200
|
var { urlEquals, getFieldValues } = require_util5();
|
|
15201
15201
|
var { kEnumerableProperty, isDisturbed } = require_util();
|
|
15202
15202
|
var { webidl } = require_webidl();
|
|
15203
|
-
var { Response, cloneResponse, fromInnerResponse } = require_response();
|
|
15203
|
+
var { Response: Response2, cloneResponse, fromInnerResponse } = require_response();
|
|
15204
15204
|
var { Request, fromInnerRequest } = require_request2();
|
|
15205
15205
|
var { kState } = require_symbols2();
|
|
15206
15206
|
var { fetching } = require_fetch();
|
|
@@ -15727,7 +15727,7 @@ var require_cache = __commonJS({
|
|
|
15727
15727
|
converter: webidl.converters.DOMString
|
|
15728
15728
|
}
|
|
15729
15729
|
]);
|
|
15730
|
-
webidl.converters.Response = webidl.interfaceConverter(
|
|
15730
|
+
webidl.converters.Response = webidl.interfaceConverter(Response2);
|
|
15731
15731
|
webidl.converters["sequence<RequestInfo>"] = webidl.sequenceConverter(
|
|
15732
15732
|
webidl.converters.RequestInfo
|
|
15733
15733
|
);
|
|
@@ -18682,6 +18682,8 @@ __export(index_exports, {
|
|
|
18682
18682
|
DEFAULT_POSTMAN_BIFROST_BASE: () => DEFAULT_POSTMAN_BIFROST_BASE,
|
|
18683
18683
|
DEFAULT_POSTMAN_IAPUB_BASE: () => DEFAULT_POSTMAN_IAPUB_BASE,
|
|
18684
18684
|
DEFAULT_POSTMAN_OBSERVABILITY_BASE: () => DEFAULT_POSTMAN_OBSERVABILITY_BASE,
|
|
18685
|
+
createInsightsBifrostClient: () => createInsightsBifrostClient,
|
|
18686
|
+
createInsightsTokenProvider: () => createInsightsTokenProvider,
|
|
18685
18687
|
createPlannedOutputs: () => createPlannedOutputs,
|
|
18686
18688
|
getTeams: () => getTeams,
|
|
18687
18689
|
parsePreflightMode: () => parsePreflightMode,
|
|
@@ -21501,6 +21503,117 @@ function resolvePostmanEndpointProfile(stack, region = "us") {
|
|
|
21501
21503
|
return profile;
|
|
21502
21504
|
}
|
|
21503
21505
|
|
|
21506
|
+
// src/lib/postman/token-provider.ts
|
|
21507
|
+
var MintError = class extends Error {
|
|
21508
|
+
permanent;
|
|
21509
|
+
constructor(message, permanent) {
|
|
21510
|
+
super(message);
|
|
21511
|
+
this.name = "MintError";
|
|
21512
|
+
this.permanent = permanent;
|
|
21513
|
+
}
|
|
21514
|
+
};
|
|
21515
|
+
function extractAccessToken(payload) {
|
|
21516
|
+
if (!payload || typeof payload !== "object") return void 0;
|
|
21517
|
+
const record = payload;
|
|
21518
|
+
const direct = record.access_token;
|
|
21519
|
+
if (typeof direct === "string" && direct.trim()) return direct.trim();
|
|
21520
|
+
const session = record.session;
|
|
21521
|
+
if (session && typeof session === "object") {
|
|
21522
|
+
const token = session.token;
|
|
21523
|
+
if (typeof token === "string" && token.trim()) return token.trim();
|
|
21524
|
+
}
|
|
21525
|
+
return void 0;
|
|
21526
|
+
}
|
|
21527
|
+
var AccessTokenProvider = class {
|
|
21528
|
+
token;
|
|
21529
|
+
apiKey;
|
|
21530
|
+
apiBaseUrl;
|
|
21531
|
+
fetchImpl;
|
|
21532
|
+
maxAttempts;
|
|
21533
|
+
onToken;
|
|
21534
|
+
sleep;
|
|
21535
|
+
inflight;
|
|
21536
|
+
constructor(options) {
|
|
21537
|
+
this.token = String(options.accessToken || "").trim();
|
|
21538
|
+
this.apiKey = String(options.apiKey || "").trim();
|
|
21539
|
+
this.apiBaseUrl = String(
|
|
21540
|
+
options.apiBaseUrl || POSTMAN_ENDPOINT_PROFILES.prod.apiBaseUrl
|
|
21541
|
+
).replace(/\/+$/, "");
|
|
21542
|
+
this.fetchImpl = options.fetchImpl ?? fetch;
|
|
21543
|
+
this.maxAttempts = Math.max(1, options.maxAttempts ?? 2);
|
|
21544
|
+
this.onToken = options.onToken;
|
|
21545
|
+
this.sleep = options.sleep;
|
|
21546
|
+
}
|
|
21547
|
+
current() {
|
|
21548
|
+
return this.token;
|
|
21549
|
+
}
|
|
21550
|
+
/** True when a PMAK is present, so an expired token can be re-minted. */
|
|
21551
|
+
canRefresh() {
|
|
21552
|
+
return Boolean(this.apiKey);
|
|
21553
|
+
}
|
|
21554
|
+
refresh() {
|
|
21555
|
+
this.inflight ??= this.mintWithRetry().finally(() => {
|
|
21556
|
+
this.inflight = void 0;
|
|
21557
|
+
});
|
|
21558
|
+
return this.inflight;
|
|
21559
|
+
}
|
|
21560
|
+
async mintWithRetry() {
|
|
21561
|
+
if (!this.apiKey) {
|
|
21562
|
+
throw new Error(
|
|
21563
|
+
"postman: the access token expired and cannot be refreshed because no postman-api-key is present. Service-account access tokens expire after about 1 to 1.5 hours. Re-mint a fresh token (postman-resolve-service-token-action) and re-run."
|
|
21564
|
+
);
|
|
21565
|
+
}
|
|
21566
|
+
const token = await retry(() => this.mintOnce(), {
|
|
21567
|
+
maxAttempts: this.maxAttempts,
|
|
21568
|
+
delayMs: 1e3,
|
|
21569
|
+
backoffMultiplier: 2,
|
|
21570
|
+
...this.sleep ? { sleep: this.sleep } : {},
|
|
21571
|
+
shouldRetry: (error2) => !(error2 instanceof MintError && error2.permanent)
|
|
21572
|
+
});
|
|
21573
|
+
this.token = token;
|
|
21574
|
+
this.onToken?.(token);
|
|
21575
|
+
return token;
|
|
21576
|
+
}
|
|
21577
|
+
async mintOnce() {
|
|
21578
|
+
const response = await this.fetchImpl(`${this.apiBaseUrl}/service-account-tokens`, {
|
|
21579
|
+
method: "POST",
|
|
21580
|
+
headers: {
|
|
21581
|
+
"Content-Type": "application/json",
|
|
21582
|
+
"x-api-key": this.apiKey
|
|
21583
|
+
},
|
|
21584
|
+
body: JSON.stringify({ apiKey: this.apiKey })
|
|
21585
|
+
});
|
|
21586
|
+
const body = await response.text().catch(() => "");
|
|
21587
|
+
if (!response.ok) {
|
|
21588
|
+
const status = response.status;
|
|
21589
|
+
if (status === 401 || status === 403) {
|
|
21590
|
+
throw new MintError(
|
|
21591
|
+
`postman: re-mint failed because the postman-api-key was rejected (PMAK rejected, HTTP ${status}); confirm it is a valid, enabled service-account PMAK for the intended team.`,
|
|
21592
|
+
true
|
|
21593
|
+
);
|
|
21594
|
+
}
|
|
21595
|
+
if (status === 400 && body.toLowerCase().includes("service accounts not enabled")) {
|
|
21596
|
+
throw new MintError(
|
|
21597
|
+
"postman: re-mint failed because service accounts are not enabled for this team; enable them in Team Settings or use a team where they are.",
|
|
21598
|
+
true
|
|
21599
|
+
);
|
|
21600
|
+
}
|
|
21601
|
+
throw new MintError(`postman: re-mint failed (service-account-tokens HTTP ${status}).`, false);
|
|
21602
|
+
}
|
|
21603
|
+
let parsed;
|
|
21604
|
+
try {
|
|
21605
|
+
parsed = JSON.parse(body);
|
|
21606
|
+
} catch {
|
|
21607
|
+
parsed = void 0;
|
|
21608
|
+
}
|
|
21609
|
+
const token = extractAccessToken(parsed);
|
|
21610
|
+
if (!token) {
|
|
21611
|
+
throw new MintError("postman: re-mint succeeded but no access token was returned.", false);
|
|
21612
|
+
}
|
|
21613
|
+
return token;
|
|
21614
|
+
}
|
|
21615
|
+
};
|
|
21616
|
+
|
|
21504
21617
|
// src/lib/bifrost-client.ts
|
|
21505
21618
|
var DEFAULT_BIFROST_BASE_URL = POSTMAN_ENDPOINT_PROFILES.prod.bifrostBaseUrl;
|
|
21506
21619
|
var BIFROST_PROXY_PATH = "/ws/proxy";
|
|
@@ -21508,8 +21621,11 @@ var DEFAULT_OBSERVABILITY_BASE_URL = POSTMAN_ENDPOINT_PROFILES.prod.observabilit
|
|
|
21508
21621
|
var DEFAULT_OBSERVABILITY_ENV = POSTMAN_ENDPOINT_PROFILES.prod.observabilityEnv;
|
|
21509
21622
|
var MAX_DISCOVERED_SERVICE_PAGES = 100;
|
|
21510
21623
|
var MAX_PROVIDER_SERVICE_PAGES = 100;
|
|
21624
|
+
function isExpiredAuthError(status, body) {
|
|
21625
|
+
return status === 401 || body.includes("UNAUTHENTICATED") || body.includes("authenticationError");
|
|
21626
|
+
}
|
|
21511
21627
|
var BifrostCatalogClient = class {
|
|
21512
|
-
|
|
21628
|
+
tokenProvider;
|
|
21513
21629
|
teamId;
|
|
21514
21630
|
apiKey;
|
|
21515
21631
|
fetchFn;
|
|
@@ -21518,11 +21634,14 @@ var BifrostCatalogClient = class {
|
|
|
21518
21634
|
observabilityBaseUrl;
|
|
21519
21635
|
observabilityEnv;
|
|
21520
21636
|
constructor(options) {
|
|
21521
|
-
this.
|
|
21637
|
+
this.tokenProvider = options.tokenProvider ?? new AccessTokenProvider({
|
|
21638
|
+
accessToken: options.accessToken,
|
|
21639
|
+
apiKey: options.apiKey
|
|
21640
|
+
});
|
|
21522
21641
|
this.teamId = options.teamId;
|
|
21523
21642
|
this.apiKey = options.apiKey;
|
|
21524
21643
|
this.fetchFn = options.fetchFn ?? globalThis.fetch;
|
|
21525
|
-
this.secretValues = [
|
|
21644
|
+
this.secretValues = [this.tokenProvider.current(), options.apiKey].filter(Boolean);
|
|
21526
21645
|
const base = (options.bifrostBaseUrl || DEFAULT_BIFROST_BASE_URL).replace(/\/+$/, "");
|
|
21527
21646
|
this.bifrostProxyUrl = `${base}${BIFROST_PROXY_PATH}`;
|
|
21528
21647
|
this.observabilityBaseUrl = (options.observabilityBaseUrl || DEFAULT_OBSERVABILITY_BASE_URL).replace(/\/+$/, "");
|
|
@@ -21534,6 +21653,11 @@ var BifrostCatalogClient = class {
|
|
|
21534
21653
|
this.secretValues.push(apiKey);
|
|
21535
21654
|
}
|
|
21536
21655
|
}
|
|
21656
|
+
registerAccessToken(token) {
|
|
21657
|
+
if (token && !this.secretValues.includes(token)) {
|
|
21658
|
+
this.secretValues.push(token);
|
|
21659
|
+
}
|
|
21660
|
+
}
|
|
21537
21661
|
/**
|
|
21538
21662
|
* Build Bifrost proxy headers.
|
|
21539
21663
|
* x-entity-team-id is ONLY included when teamId is present (org-mode tokens).
|
|
@@ -21541,7 +21665,7 @@ var BifrostCatalogClient = class {
|
|
|
21541
21665
|
*/
|
|
21542
21666
|
headers() {
|
|
21543
21667
|
const h = {
|
|
21544
|
-
"x-access-token": this.
|
|
21668
|
+
"x-access-token": this.tokenProvider.current(),
|
|
21545
21669
|
"Content-Type": "application/json"
|
|
21546
21670
|
};
|
|
21547
21671
|
if (this.teamId) {
|
|
@@ -21557,7 +21681,7 @@ var BifrostCatalogClient = class {
|
|
|
21557
21681
|
const session = getMemoizedSessionIdentity();
|
|
21558
21682
|
return {
|
|
21559
21683
|
operation,
|
|
21560
|
-
hasAccessToken: Boolean(this.
|
|
21684
|
+
hasAccessToken: Boolean(this.tokenProvider.current()),
|
|
21561
21685
|
sessionTeamId: session?.teamId,
|
|
21562
21686
|
sessionRoles: session?.roles,
|
|
21563
21687
|
sessionConsumerType: session?.consumerType,
|
|
@@ -21566,7 +21690,7 @@ var BifrostCatalogClient = class {
|
|
|
21566
21690
|
};
|
|
21567
21691
|
}
|
|
21568
21692
|
async proxyRequest(method, path6, body = {}, operation = "api-catalog request") {
|
|
21569
|
-
const
|
|
21693
|
+
const send2 = async () => this.fetchFn(this.bifrostProxyUrl, {
|
|
21570
21694
|
method: "POST",
|
|
21571
21695
|
headers: this.headers(),
|
|
21572
21696
|
body: JSON.stringify({
|
|
@@ -21576,6 +21700,39 @@ var BifrostCatalogClient = class {
|
|
|
21576
21700
|
body
|
|
21577
21701
|
})
|
|
21578
21702
|
});
|
|
21703
|
+
let response = await send2();
|
|
21704
|
+
if (!response.ok) {
|
|
21705
|
+
const bodyText = await response.text().catch(() => "");
|
|
21706
|
+
if (isExpiredAuthError(response.status, bodyText) && this.tokenProvider.canRefresh()) {
|
|
21707
|
+
try {
|
|
21708
|
+
const refreshed = await this.tokenProvider.refresh();
|
|
21709
|
+
this.registerAccessToken(refreshed);
|
|
21710
|
+
response = await send2();
|
|
21711
|
+
} catch {
|
|
21712
|
+
const httpErr = await HttpError.fromResponse(
|
|
21713
|
+
new Response(bodyText, { status: response.status, headers: response.headers }),
|
|
21714
|
+
{
|
|
21715
|
+
method: "POST",
|
|
21716
|
+
url: `bifrost:api-catalog:${method} ${path6}`,
|
|
21717
|
+
secretValues: this.secretValues
|
|
21718
|
+
}
|
|
21719
|
+
);
|
|
21720
|
+
const advised = adviseFromHttpError(httpErr, this.adviceContext(operation));
|
|
21721
|
+
throw advised ?? httpErr;
|
|
21722
|
+
}
|
|
21723
|
+
} else {
|
|
21724
|
+
const httpErr = await HttpError.fromResponse(
|
|
21725
|
+
new Response(bodyText, { status: response.status, headers: response.headers }),
|
|
21726
|
+
{
|
|
21727
|
+
method: "POST",
|
|
21728
|
+
url: `bifrost:api-catalog:${method} ${path6}`,
|
|
21729
|
+
secretValues: this.secretValues
|
|
21730
|
+
}
|
|
21731
|
+
);
|
|
21732
|
+
const advised = adviseFromHttpError(httpErr, this.adviceContext(operation));
|
|
21733
|
+
throw advised ?? httpErr;
|
|
21734
|
+
}
|
|
21735
|
+
}
|
|
21579
21736
|
if (!response.ok) {
|
|
21580
21737
|
const httpErr = await HttpError.fromResponse(response, {
|
|
21581
21738
|
method: "POST",
|
|
@@ -21598,7 +21755,7 @@ var BifrostCatalogClient = class {
|
|
|
21598
21755
|
return data;
|
|
21599
21756
|
}
|
|
21600
21757
|
async akitaProxyRequest(method, path6, body = {}, operation = "Insights request") {
|
|
21601
|
-
const
|
|
21758
|
+
const send2 = async () => this.fetchFn(this.bifrostProxyUrl, {
|
|
21602
21759
|
method: "POST",
|
|
21603
21760
|
headers: this.headers(),
|
|
21604
21761
|
body: JSON.stringify({
|
|
@@ -21608,8 +21765,30 @@ var BifrostCatalogClient = class {
|
|
|
21608
21765
|
body
|
|
21609
21766
|
})
|
|
21610
21767
|
});
|
|
21768
|
+
let response = await send2();
|
|
21611
21769
|
if (!response.ok) {
|
|
21612
21770
|
const text = await response.text().catch(() => "");
|
|
21771
|
+
if (isExpiredAuthError(response.status, text) && this.tokenProvider.canRefresh()) {
|
|
21772
|
+
try {
|
|
21773
|
+
const refreshed = await this.tokenProvider.refresh();
|
|
21774
|
+
this.registerAccessToken(refreshed);
|
|
21775
|
+
response = await send2();
|
|
21776
|
+
if (response.ok) {
|
|
21777
|
+
const data2 = await response.json();
|
|
21778
|
+
return { ok: true, status: response.status, data: data2, errorText: "" };
|
|
21779
|
+
}
|
|
21780
|
+
const retryText = await response.text().catch(() => "");
|
|
21781
|
+
const advised2 = adviseFromBifrostBody(response.status, retryText, this.adviceContext(operation));
|
|
21782
|
+
const errorText2 = advised2 ? retryText ? `${retryText}
|
|
21783
|
+
${advised2.message}` : advised2.message : retryText;
|
|
21784
|
+
return { ok: false, status: response.status, data: null, errorText: errorText2 };
|
|
21785
|
+
} catch {
|
|
21786
|
+
const advised2 = adviseFromBifrostBody(response.status, text, this.adviceContext(operation));
|
|
21787
|
+
const errorText2 = advised2 ? text ? `${text}
|
|
21788
|
+
${advised2.message}` : advised2.message : text;
|
|
21789
|
+
return { ok: false, status: response.status, data: null, errorText: errorText2 };
|
|
21790
|
+
}
|
|
21791
|
+
}
|
|
21613
21792
|
const advised = adviseFromBifrostBody(response.status, text, this.adviceContext(operation));
|
|
21614
21793
|
const errorText = advised ? text ? `${text}
|
|
21615
21794
|
${advised.message}` : advised.message : text;
|
|
@@ -21708,12 +21887,19 @@ ${advised.message}` : advised.message : text;
|
|
|
21708
21887
|
}
|
|
21709
21888
|
page++;
|
|
21710
21889
|
}
|
|
21711
|
-
|
|
21712
|
-
|
|
21713
|
-
|
|
21714
|
-
|
|
21715
|
-
|
|
21716
|
-
|
|
21890
|
+
if (clusterName) {
|
|
21891
|
+
const fullName = `${clusterName}/${projectName}`;
|
|
21892
|
+
const exactMatch = allServices.find((s) => s.name === fullName);
|
|
21893
|
+
return exactMatch?.id || null;
|
|
21894
|
+
}
|
|
21895
|
+
const finalSegmentMatch = allServices.find(
|
|
21896
|
+
(s) => getFinalServiceSegment(s.name) === projectName
|
|
21897
|
+
);
|
|
21898
|
+
if (finalSegmentMatch) return finalSegmentMatch.id;
|
|
21899
|
+
const bracketedMatch = allServices.find(
|
|
21900
|
+
(s) => getFinalServiceSegment(s.name).includes(`[${projectName}]`)
|
|
21901
|
+
);
|
|
21902
|
+
return bracketedMatch?.id || null;
|
|
21717
21903
|
}
|
|
21718
21904
|
async acknowledgeOnboarding(providerServiceId, workspaceId, systemEnvironmentId) {
|
|
21719
21905
|
const result = await this.akitaProxyRequest(
|
|
@@ -21743,6 +21929,14 @@ ${advised.message}` : advised.message : text;
|
|
|
21743
21929
|
throw new Error(`Workspace acknowledge failed: ${result.status} ${result.errorText}`);
|
|
21744
21930
|
}
|
|
21745
21931
|
}
|
|
21932
|
+
// PMAK-only by proven exception. A live probe against the observability
|
|
21933
|
+
// application-binding endpoint (POST /v2/agent/api-catalog/workspaces/:id/
|
|
21934
|
+
// applications) showed x-access-token is rejected identically to the x-api-key
|
|
21935
|
+
// control: both return 401 {"message":"Postman User not found"} for a
|
|
21936
|
+
// service-account credential, because the observability service has no
|
|
21937
|
+
// "Postman User" for a service account. The access token offers no improvement
|
|
21938
|
+
// over the API key here, so this route is not migrated to access-token-primary
|
|
21939
|
+
// (the suite-wide migration explicitly leaves probe-failed routes on PMAK).
|
|
21746
21940
|
async createApplication(workspaceId, systemEnv) {
|
|
21747
21941
|
const response = await this.fetchFn(
|
|
21748
21942
|
`${this.observabilityBaseUrl}/v2/agent/api-catalog/workspaces/${workspaceId}/applications`,
|
|
@@ -21810,7 +22004,17 @@ function findDiscoveredService(services, projectName, clusterName) {
|
|
|
21810
22004
|
const fullName = `${clusterName}/${projectName}`;
|
|
21811
22005
|
return services.find((s) => s.name === fullName);
|
|
21812
22006
|
}
|
|
21813
|
-
|
|
22007
|
+
const finalSegmentMatch = services.find(
|
|
22008
|
+
(service) => getFinalServiceSegment(service.name) === projectName
|
|
22009
|
+
);
|
|
22010
|
+
if (finalSegmentMatch) return finalSegmentMatch;
|
|
22011
|
+
return services.find(
|
|
22012
|
+
(service) => getFinalServiceSegment(service.name).includes(`[${projectName}]`)
|
|
22013
|
+
);
|
|
22014
|
+
}
|
|
22015
|
+
function getFinalServiceSegment(serviceName) {
|
|
22016
|
+
const lastSlash = serviceName.lastIndexOf("/");
|
|
22017
|
+
return lastSlash === -1 ? serviceName : serviceName.slice(lastSlash + 1);
|
|
21814
22018
|
}
|
|
21815
22019
|
|
|
21816
22020
|
// node_modules/@postman-cse/automation-telemetry-core/dist/ci-context.js
|
|
@@ -21818,7 +22022,65 @@ function norm(value) {
|
|
|
21818
22022
|
const trimmed = (value ?? "").trim();
|
|
21819
22023
|
return trimmed.length > 0 ? trimmed : void 0;
|
|
21820
22024
|
}
|
|
22025
|
+
function detectEventTrigger(env = process.env) {
|
|
22026
|
+
const ghEvent = norm(env.GITHUB_EVENT_NAME)?.toLowerCase();
|
|
22027
|
+
if (ghEvent) {
|
|
22028
|
+
if (ghEvent === "push")
|
|
22029
|
+
return "push";
|
|
22030
|
+
if (ghEvent === "pull_request" || ghEvent === "pull_request_target")
|
|
22031
|
+
return "pull_request";
|
|
22032
|
+
if (ghEvent === "schedule")
|
|
22033
|
+
return "schedule";
|
|
22034
|
+
if (ghEvent === "workflow_dispatch" || ghEvent === "repository_dispatch")
|
|
22035
|
+
return "manual";
|
|
22036
|
+
return "other";
|
|
22037
|
+
}
|
|
22038
|
+
const glSource = norm(env.CI_PIPELINE_SOURCE)?.toLowerCase();
|
|
22039
|
+
if (glSource) {
|
|
22040
|
+
if (glSource === "push")
|
|
22041
|
+
return "push";
|
|
22042
|
+
if (glSource === "merge_request_event")
|
|
22043
|
+
return "pull_request";
|
|
22044
|
+
if (glSource === "schedule")
|
|
22045
|
+
return "schedule";
|
|
22046
|
+
if (glSource === "web" || glSource === "api" || glSource === "trigger" || glSource === "pipeline") {
|
|
22047
|
+
return "manual";
|
|
22048
|
+
}
|
|
22049
|
+
return "other";
|
|
22050
|
+
}
|
|
22051
|
+
if (norm(env.BITBUCKET_PR_ID))
|
|
22052
|
+
return "pull_request";
|
|
22053
|
+
if (norm(env.CI) || norm(env.BUILD_BUILDID) || norm(env.JENKINS_URL) || norm(env.TEAMCITY_VERSION)) {
|
|
22054
|
+
return "other";
|
|
22055
|
+
}
|
|
22056
|
+
return "unknown";
|
|
22057
|
+
}
|
|
22058
|
+
function detectRunnerOs(env = process.env) {
|
|
22059
|
+
const runnerOs = norm(env.RUNNER_OS)?.toLowerCase();
|
|
22060
|
+
if (runnerOs === "linux")
|
|
22061
|
+
return "linux";
|
|
22062
|
+
if (runnerOs === "macos")
|
|
22063
|
+
return "macos";
|
|
22064
|
+
if (runnerOs === "windows")
|
|
22065
|
+
return "windows";
|
|
22066
|
+
const platform2 = typeof process !== "undefined" ? process.platform : void 0;
|
|
22067
|
+
if (platform2 === "linux")
|
|
22068
|
+
return "linux";
|
|
22069
|
+
if (platform2 === "darwin")
|
|
22070
|
+
return "macos";
|
|
22071
|
+
if (platform2 === "win32")
|
|
22072
|
+
return "windows";
|
|
22073
|
+
return "unknown";
|
|
22074
|
+
}
|
|
21821
22075
|
function detectCiContext(env = process.env) {
|
|
22076
|
+
const provider = detectCiProviderContext(env);
|
|
22077
|
+
return {
|
|
22078
|
+
...provider,
|
|
22079
|
+
eventTrigger: detectEventTrigger(env),
|
|
22080
|
+
runnerOs: detectRunnerOs(env)
|
|
22081
|
+
};
|
|
22082
|
+
}
|
|
22083
|
+
function detectCiProviderContext(env = process.env) {
|
|
21822
22084
|
if (norm(env.GITHUB_ACTIONS)) {
|
|
21823
22085
|
const runnerEnv = norm(env.RUNNER_ENVIRONMENT);
|
|
21824
22086
|
const runnerKind = runnerEnv === "github-hosted" ? "hosted" : runnerEnv === "self-hosted" ? "self-hosted" : "unknown";
|
|
@@ -21956,25 +22218,49 @@ function parseProvider(explicitProvider, repoUrl, env) {
|
|
|
21956
22218
|
}
|
|
21957
22219
|
return "unknown";
|
|
21958
22220
|
}
|
|
22221
|
+
function classifyRefKind(env = process.env) {
|
|
22222
|
+
const githubRefType = normalize(env.GITHUB_REF_TYPE)?.toLowerCase();
|
|
22223
|
+
const githubRef = normalize(env.GITHUB_REF);
|
|
22224
|
+
const azureRef = normalize(env.BUILD_SOURCEBRANCH);
|
|
22225
|
+
if (githubRefType === "tag" || githubRef?.startsWith("refs/tags/") || normalize(env.CI_COMMIT_TAG) || normalize(env.BITBUCKET_TAG) || azureRef?.startsWith("refs/tags/")) {
|
|
22226
|
+
return "tag";
|
|
22227
|
+
}
|
|
22228
|
+
const githubRefName = normalize(env.GITHUB_REF_NAME);
|
|
22229
|
+
const githubDefault = normalize(env.GITHUB_DEFAULT_BRANCH);
|
|
22230
|
+
if (githubRefName && githubDefault) {
|
|
22231
|
+
return githubRefName === githubDefault ? "default-branch" : "branch";
|
|
22232
|
+
}
|
|
22233
|
+
const gitlabRef = normalize(env.CI_COMMIT_REF_NAME);
|
|
22234
|
+
const gitlabDefault = normalize(env.CI_DEFAULT_BRANCH);
|
|
22235
|
+
if (gitlabRef && gitlabDefault) {
|
|
22236
|
+
return gitlabRef === gitlabDefault ? "default-branch" : "branch";
|
|
22237
|
+
}
|
|
22238
|
+
if (githubRefName || githubRef?.startsWith("refs/heads/") || gitlabRef || normalize(env.BITBUCKET_BRANCH) || normalize(env.BUILD_SOURCEBRANCHNAME) || azureRef?.startsWith("refs/heads/")) {
|
|
22239
|
+
return "branch";
|
|
22240
|
+
}
|
|
22241
|
+
return "unknown";
|
|
22242
|
+
}
|
|
21959
22243
|
function detectRepoContext(input, env = process.env) {
|
|
21960
22244
|
const repoUrl = normalizeRepoUrl(input.repoUrl) ?? normalizeRepoUrl(env.GITHUB_SERVER_URL && env.GITHUB_REPOSITORY ? `${env.GITHUB_SERVER_URL}/${env.GITHUB_REPOSITORY}` : void 0) ?? normalizeRepoUrl(env.CI_PROJECT_URL) ?? normalizeRepoUrl(env.BITBUCKET_GIT_HTTP_ORIGIN) ?? normalizeRepoUrl(env.BUILD_REPOSITORY_URI);
|
|
21961
22245
|
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);
|
|
21962
22246
|
const ref = normalize(input.ref) ?? normalize(env.GITHUB_REF_NAME) ?? normalize(env.CI_COMMIT_REF_NAME) ?? normalize(env.BITBUCKET_BRANCH) ?? normalize(env.BUILD_SOURCEBRANCHNAME);
|
|
21963
22247
|
const sha = normalize(input.sha) ?? normalize(env.GITHUB_SHA) ?? normalize(env.CI_COMMIT_SHA) ?? normalize(env.BITBUCKET_COMMIT) ?? normalize(env.BUILD_SOURCEVERSION);
|
|
21964
22248
|
const provider = parseProvider(input.gitProvider, repoUrl, env);
|
|
22249
|
+
const refKind = classifyRefKind(env);
|
|
21965
22250
|
return {
|
|
21966
22251
|
provider,
|
|
21967
22252
|
repoUrl,
|
|
21968
22253
|
repoSlug,
|
|
21969
22254
|
ref,
|
|
21970
|
-
sha
|
|
22255
|
+
sha,
|
|
22256
|
+
refKind
|
|
21971
22257
|
};
|
|
21972
22258
|
}
|
|
21973
22259
|
|
|
21974
22260
|
// node_modules/@postman-cse/automation-telemetry-core/dist/telemetry.js
|
|
21975
22261
|
var import_node_crypto = require("node:crypto");
|
|
21976
22262
|
var import_undici2 = __toESM(require_undici(), 1);
|
|
21977
|
-
var SCHEMA_VERSION =
|
|
22263
|
+
var SCHEMA_VERSION = 3;
|
|
21978
22264
|
var DEFAULT_TIMEOUT_MS = 1500;
|
|
21979
22265
|
var DEFAULT_ENDPOINT = "https://events.pm-cse.dev/v1/events";
|
|
21980
22266
|
var proxyDispatcher;
|
|
@@ -21985,7 +22271,7 @@ function resolveActionVersion(explicit) {
|
|
|
21985
22271
|
if (explicit) {
|
|
21986
22272
|
return explicit;
|
|
21987
22273
|
}
|
|
21988
|
-
return "
|
|
22274
|
+
return "2.0.0" ? "2.0.0" : "unknown";
|
|
21989
22275
|
}
|
|
21990
22276
|
function telemetryDisabled(env) {
|
|
21991
22277
|
const flag = String(env.POSTMAN_ACTIONS_TELEMETRY ?? "").trim().toLowerCase();
|
|
@@ -22014,7 +22300,7 @@ function maybeNotice(logger) {
|
|
|
22014
22300
|
return;
|
|
22015
22301
|
}
|
|
22016
22302
|
noticeShown = true;
|
|
22017
|
-
logger.info("note: postman-actions sends anonymous usage data (team id, action, CI provider, account type). Disable with POSTMAN_ACTIONS_TELEMETRY=off or DO_NOT_TRACK=1.");
|
|
22303
|
+
logger.info("note: postman-actions sends anonymous usage data (team id, action, CI provider, account type, run trigger, runner OS). Disable with POSTMAN_ACTIONS_TELEMETRY=off or DO_NOT_TRACK=1.");
|
|
22018
22304
|
}
|
|
22019
22305
|
function buildTelemetryEvent(params) {
|
|
22020
22306
|
const { action, actionVersion, teamId, accountType, outcome, env, now } = params;
|
|
@@ -22036,6 +22322,9 @@ function buildTelemetryEvent(params) {
|
|
|
22036
22322
|
repo_id: repoSource ? sha256(repoSource) : void 0,
|
|
22037
22323
|
org_id: owner ? sha256(owner) : void 0,
|
|
22038
22324
|
account_type: accountType,
|
|
22325
|
+
event_trigger: ci.eventTrigger,
|
|
22326
|
+
runner_os: ci.runnerOs,
|
|
22327
|
+
ref_kind: repo.refKind,
|
|
22039
22328
|
outcome,
|
|
22040
22329
|
ts: now()
|
|
22041
22330
|
};
|
|
@@ -22371,19 +22660,39 @@ async function resolveApiKeyAndTeamId(inputs, client, reporter = core_exports) {
|
|
|
22371
22660
|
}
|
|
22372
22661
|
return { apiKey, teamId: resolvedTeamId, pmakIdentity };
|
|
22373
22662
|
}
|
|
22374
|
-
async function runCredentialPreflightForInputs(inputs, pmak, reporter, fetchImpl) {
|
|
22663
|
+
async function runCredentialPreflightForInputs(inputs, pmak, reporter, fetchImpl, liveAccessToken) {
|
|
22664
|
+
const accessToken = liveAccessToken ?? inputs.postmanAccessToken;
|
|
22375
22665
|
await runCredentialPreflight({
|
|
22376
22666
|
apiBaseUrl: inputs.postmanApiBase || DEFAULT_POSTMAN_API_BASE,
|
|
22377
22667
|
iapubBaseUrl: inputs.postmanIapubBase || DEFAULT_POSTMAN_IAPUB_BASE,
|
|
22378
22668
|
pmak,
|
|
22379
|
-
postmanAccessToken:
|
|
22669
|
+
postmanAccessToken: accessToken,
|
|
22380
22670
|
explicitTeamId: inputs.postmanTeamId || void 0,
|
|
22381
22671
|
mode: inputs.credentialPreflight,
|
|
22382
|
-
mask: createSecretMasker([inputs.postmanApiKey,
|
|
22672
|
+
mask: createSecretMasker([inputs.postmanApiKey, accessToken]),
|
|
22383
22673
|
log: reporter,
|
|
22384
22674
|
fetchImpl
|
|
22385
22675
|
});
|
|
22386
22676
|
}
|
|
22677
|
+
function createInsightsTokenProvider(inputs, reporter, apiKey = inputs.postmanApiKey) {
|
|
22678
|
+
return new AccessTokenProvider({
|
|
22679
|
+
accessToken: inputs.postmanAccessToken,
|
|
22680
|
+
apiKey,
|
|
22681
|
+
apiBaseUrl: inputs.postmanApiBase || DEFAULT_POSTMAN_API_BASE,
|
|
22682
|
+
onToken: (token) => reporter.setSecret(token)
|
|
22683
|
+
});
|
|
22684
|
+
}
|
|
22685
|
+
function createInsightsBifrostClient(inputs, tokenProvider, teamId, apiKey) {
|
|
22686
|
+
return new BifrostCatalogClient({
|
|
22687
|
+
tokenProvider,
|
|
22688
|
+
accessToken: tokenProvider.current(),
|
|
22689
|
+
teamId,
|
|
22690
|
+
apiKey,
|
|
22691
|
+
bifrostBaseUrl: inputs.postmanBifrostBase,
|
|
22692
|
+
observabilityBaseUrl: inputs.postmanObservabilityBase,
|
|
22693
|
+
observabilityEnv: inputs.postmanObservabilityEnv
|
|
22694
|
+
});
|
|
22695
|
+
}
|
|
22387
22696
|
async function runAction() {
|
|
22388
22697
|
const inputs = resolveInputs();
|
|
22389
22698
|
const planned = createPlannedOutputs(inputs);
|
|
@@ -22393,28 +22702,32 @@ async function runAction() {
|
|
|
22393
22702
|
setSecret(inputs.postmanAccessToken);
|
|
22394
22703
|
if (inputs.postmanApiKey) setSecret(inputs.postmanApiKey);
|
|
22395
22704
|
if (inputs.githubToken) setSecret(inputs.githubToken);
|
|
22396
|
-
const
|
|
22397
|
-
|
|
22398
|
-
|
|
22399
|
-
|
|
22400
|
-
|
|
22401
|
-
|
|
22402
|
-
|
|
22403
|
-
});
|
|
22705
|
+
const tokenProvider = createInsightsTokenProvider(inputs, core_exports);
|
|
22706
|
+
const preliminaryClient = createInsightsBifrostClient(
|
|
22707
|
+
inputs,
|
|
22708
|
+
tokenProvider,
|
|
22709
|
+
inputs.postmanTeamId,
|
|
22710
|
+
inputs.postmanApiKey
|
|
22711
|
+
);
|
|
22404
22712
|
const { apiKey, teamId, pmakIdentity } = await resolveApiKeyAndTeamId(inputs, preliminaryClient, core_exports);
|
|
22713
|
+
const activeTokenProvider = apiKey !== inputs.postmanApiKey ? new AccessTokenProvider({
|
|
22714
|
+
accessToken: tokenProvider.current(),
|
|
22715
|
+
apiKey,
|
|
22716
|
+
apiBaseUrl: inputs.postmanApiBase || DEFAULT_POSTMAN_API_BASE,
|
|
22717
|
+
onToken: (token) => setSecret(token)
|
|
22718
|
+
}) : tokenProvider;
|
|
22405
22719
|
const telemetry = createTelemetryContext({ action: "postman-insights-onboarding-action", logger: core_exports });
|
|
22406
22720
|
telemetry.setTeamId(inputs.postmanTeamId || pmakIdentity?.teamId);
|
|
22407
22721
|
let result;
|
|
22408
22722
|
try {
|
|
22409
|
-
await runCredentialPreflightForInputs(
|
|
22410
|
-
|
|
22411
|
-
|
|
22412
|
-
|
|
22413
|
-
|
|
22414
|
-
|
|
22415
|
-
|
|
22416
|
-
|
|
22417
|
-
});
|
|
22723
|
+
await runCredentialPreflightForInputs(
|
|
22724
|
+
inputs,
|
|
22725
|
+
pmakIdentity,
|
|
22726
|
+
core_exports,
|
|
22727
|
+
void 0,
|
|
22728
|
+
activeTokenProvider.current()
|
|
22729
|
+
);
|
|
22730
|
+
const client = createInsightsBifrostClient(inputs, activeTokenProvider, teamId, apiKey);
|
|
22418
22731
|
result = await runOnboarding(inputs, client, sleep, core_exports);
|
|
22419
22732
|
} catch (error2) {
|
|
22420
22733
|
const message = error2 instanceof Error ? error2.message : String(error2);
|
|
@@ -22445,6 +22758,8 @@ async function runAction() {
|
|
|
22445
22758
|
DEFAULT_POSTMAN_BIFROST_BASE,
|
|
22446
22759
|
DEFAULT_POSTMAN_IAPUB_BASE,
|
|
22447
22760
|
DEFAULT_POSTMAN_OBSERVABILITY_BASE,
|
|
22761
|
+
createInsightsBifrostClient,
|
|
22762
|
+
createInsightsTokenProvider,
|
|
22448
22763
|
createPlannedOutputs,
|
|
22449
22764
|
getTeams,
|
|
22450
22765
|
parsePreflightMode,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@postman-cse/onboarding-insights",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"description": "GitHub Action to onboard Postman Insights discovered services to API Catalog workspaces.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.cjs",
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
37
|
"@actions/core": "^3.0.1",
|
|
38
|
-
"@postman-cse/automation-telemetry-core": "^0.
|
|
38
|
+
"@postman-cse/automation-telemetry-core": "^0.2.0",
|
|
39
39
|
"undici": "^6.24.0"
|
|
40
40
|
},
|
|
41
41
|
"overrides": {
|
|
@@ -43,8 +43,8 @@
|
|
|
43
43
|
"picomatch": ">=4.0.4"
|
|
44
44
|
},
|
|
45
45
|
"devDependencies": {
|
|
46
|
-
"@commitlint/cli": "^
|
|
47
|
-
"@commitlint/config-conventional": "^
|
|
46
|
+
"@commitlint/cli": "^21.0.2",
|
|
47
|
+
"@commitlint/config-conventional": "^21.0.2",
|
|
48
48
|
"@eslint/js": "^10.0.1",
|
|
49
49
|
"@types/node": "^24.12.4",
|
|
50
50
|
"esbuild": "^0.28.0",
|