@postman-cse/onboarding-repo-sync 0.14.0 → 0.14.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/dist/action.cjs CHANGED
@@ -24607,20 +24607,22 @@ async function probeSessionIdentity(baseUrl, accessToken, fetchImpl) {
24607
24607
  if (!payload) {
24608
24608
  return void 0;
24609
24609
  }
24610
- const identity = asRecord(payload.identity);
24611
- const data = asRecord(payload.data);
24610
+ const root = asRecord(payload.session) ?? payload;
24611
+ const identity = asRecord(root.identity);
24612
+ const data = asRecord(root.data);
24612
24613
  const user = asRecord(data?.user);
24613
24614
  const roleEntries = Array.isArray(user?.roles) ? user.roles.map((entry) => coerceText(entry) ?? coerceId(entry)).filter((entry) => Boolean(entry)) : [];
24614
24615
  const singleRole = coerceText(user?.role);
24615
24616
  const roles = roleEntries.length > 0 ? roleEntries : singleRole ? [singleRole] : void 0;
24616
24617
  const resolved = {
24617
24618
  source: "iapub/sessions",
24618
- userId: coerceId(user?.id),
24619
+ userId: coerceId(identity?.user) ?? coerceId(user?.id),
24619
24620
  fullName: coerceText(user?.fullName) ?? coerceText(user?.name) ?? coerceText(user?.username),
24620
24621
  teamId: coerceId(identity?.team),
24622
+ teamName: coerceText(user?.teamName),
24621
24623
  teamDomain: coerceText(identity?.domain),
24622
24624
  ...roles ? { roles } : {},
24623
- consumerType: coerceText(payload.consumerType) ?? coerceText(data?.consumerType) ?? coerceText(user?.consumerType)
24625
+ consumerType: coerceText(root.consumerType) ?? coerceText(data?.consumerType) ?? coerceText(user?.consumerType)
24624
24626
  };
24625
24627
  memoizedSessionIdentity = resolved;
24626
24628
  return resolved;
package/dist/cli.cjs CHANGED
@@ -22617,10 +22617,255 @@ var HttpError = class _HttpError extends Error {
22617
22617
  };
22618
22618
 
22619
22619
  // src/lib/postman/credential-identity.ts
22620
+ var sessionPath = "/api/sessions/current";
22621
+ var pmakMemo = /* @__PURE__ */ new Map();
22622
+ var sessionMemo = /* @__PURE__ */ new Map();
22620
22623
  var memoizedSessionIdentity;
22621
22624
  function getMemoizedSessionIdentity() {
22622
22625
  return memoizedSessionIdentity;
22623
22626
  }
22627
+ function asRecord(value) {
22628
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
22629
+ return void 0;
22630
+ }
22631
+ return value;
22632
+ }
22633
+ function coerceId(raw) {
22634
+ return raw ? String(raw) : void 0;
22635
+ }
22636
+ function coerceText(raw) {
22637
+ if (typeof raw !== "string") {
22638
+ return void 0;
22639
+ }
22640
+ const trimmed = raw.trim();
22641
+ return trimmed ? trimmed : void 0;
22642
+ }
22643
+ function normalizeBaseUrl(raw) {
22644
+ return String(raw || "").replace(/\/+$/, "");
22645
+ }
22646
+ async function resolvePmakIdentity(opts) {
22647
+ const apiKey = String(opts.apiKey || "").trim();
22648
+ if (!apiKey) {
22649
+ return void 0;
22650
+ }
22651
+ const baseUrl = normalizeBaseUrl(opts.apiBaseUrl);
22652
+ const memoKey = `${baseUrl}::${apiKey}`;
22653
+ let pending = pmakMemo.get(memoKey);
22654
+ if (!pending) {
22655
+ pending = probePmakIdentity(baseUrl, apiKey, opts.fetchImpl ?? fetch);
22656
+ pmakMemo.set(memoKey, pending);
22657
+ }
22658
+ return pending;
22659
+ }
22660
+ async function probePmakIdentity(baseUrl, apiKey, fetchImpl) {
22661
+ try {
22662
+ const response = await fetchImpl(`${baseUrl}/me`, {
22663
+ method: "GET",
22664
+ headers: { "X-Api-Key": apiKey }
22665
+ });
22666
+ if (!response.ok) {
22667
+ return void 0;
22668
+ }
22669
+ const payload = asRecord(await response.json());
22670
+ const user = asRecord(payload?.user);
22671
+ if (!user) {
22672
+ return void 0;
22673
+ }
22674
+ return {
22675
+ source: "pmak/me",
22676
+ userId: coerceId(user.id),
22677
+ fullName: coerceText(user.fullName) ?? coerceText(user.username),
22678
+ teamId: coerceId(user.teamId),
22679
+ teamName: coerceText(user.teamName),
22680
+ teamDomain: coerceText(user.teamDomain)
22681
+ };
22682
+ } catch {
22683
+ return void 0;
22684
+ }
22685
+ }
22686
+ async function resolveSessionIdentity(opts) {
22687
+ const accessToken = String(opts.accessToken || "").trim();
22688
+ if (!accessToken) {
22689
+ return void 0;
22690
+ }
22691
+ const baseUrl = normalizeBaseUrl(opts.iapubBaseUrl);
22692
+ const memoKey = `${baseUrl}::${accessToken}`;
22693
+ let pending = sessionMemo.get(memoKey);
22694
+ if (!pending) {
22695
+ pending = probeSessionIdentity(baseUrl, accessToken, opts.fetchImpl ?? fetch);
22696
+ sessionMemo.set(memoKey, pending);
22697
+ }
22698
+ return pending;
22699
+ }
22700
+ async function probeSessionIdentity(baseUrl, accessToken, fetchImpl) {
22701
+ try {
22702
+ const response = await fetchImpl(`${baseUrl}${sessionPath}`, {
22703
+ method: "GET",
22704
+ headers: { "x-access-token": accessToken }
22705
+ });
22706
+ if (!response.ok) {
22707
+ return void 0;
22708
+ }
22709
+ const payload = asRecord(await response.json());
22710
+ if (!payload) {
22711
+ return void 0;
22712
+ }
22713
+ const root = asRecord(payload.session) ?? payload;
22714
+ const identity = asRecord(root.identity);
22715
+ const data = asRecord(root.data);
22716
+ const user = asRecord(data?.user);
22717
+ const roleEntries = Array.isArray(user?.roles) ? user.roles.map((entry) => coerceText(entry) ?? coerceId(entry)).filter((entry) => Boolean(entry)) : [];
22718
+ const singleRole = coerceText(user?.role);
22719
+ const roles = roleEntries.length > 0 ? roleEntries : singleRole ? [singleRole] : void 0;
22720
+ const resolved = {
22721
+ source: "iapub/sessions",
22722
+ userId: coerceId(identity?.user) ?? coerceId(user?.id),
22723
+ fullName: coerceText(user?.fullName) ?? coerceText(user?.name) ?? coerceText(user?.username),
22724
+ teamId: coerceId(identity?.team),
22725
+ teamName: coerceText(user?.teamName),
22726
+ teamDomain: coerceText(identity?.domain),
22727
+ ...roles ? { roles } : {},
22728
+ consumerType: coerceText(root.consumerType) ?? coerceText(data?.consumerType) ?? coerceText(user?.consumerType)
22729
+ };
22730
+ memoizedSessionIdentity = resolved;
22731
+ return resolved;
22732
+ } catch {
22733
+ return void 0;
22734
+ }
22735
+ }
22736
+ function describeTeam(id) {
22737
+ const label = id?.teamName ?? id?.teamDomain;
22738
+ return `team ${id?.teamId ?? "unresolved"}${label ? ` (${label})` : ""}`;
22739
+ }
22740
+ function formatIdentityLine(id, mask) {
22741
+ const teamPart = id.teamId ? describeTeam(id) : "team unresolved";
22742
+ const domainPart = id.teamDomain ? `, domain ${id.teamDomain}` : "";
22743
+ if (id.source === "pmak/me") {
22744
+ const userPart = id.userId ? `user ${id.userId}${id.fullName ? ` (${id.fullName})` : ""}, ` : "";
22745
+ return mask(`postman: PMAK identity - ${userPart}${teamPart}${domainPart}`);
22746
+ }
22747
+ return mask(
22748
+ `postman: access-token session identity - ${teamPart}${domainPart} [source: iapub/sessions]`
22749
+ );
22750
+ }
22751
+ function crossCheckIdentities(args) {
22752
+ if (args.mode === "off") {
22753
+ return { ok: true, level: "ok", message: "" };
22754
+ }
22755
+ const pmakTeamId = args.pmak?.teamId;
22756
+ const sessionTeamId = args.session?.teamId;
22757
+ if (pmakTeamId && sessionTeamId && pmakTeamId !== sessionTeamId) {
22758
+ const level = args.mode === "enforce" ? "fail" : "note";
22759
+ const lead = level === "fail" ? "credential preflight FAILED" : "credential preflight note";
22760
+ const fix = level === "fail" ? "Use one credential pair from a single parent org: re-mint the access token from the same parent org as postman-api-key (postman-resolve-service-token-action, or POST https://api.getpostman.com/service-account-tokens with that team's PMAK), or set postman-api-key to the matching parent org." : "Use one credential pair from a single parent org. Set credential-preflight: enforce to fail the run on this condition.";
22761
+ return {
22762
+ ok: false,
22763
+ level,
22764
+ message: args.mask(
22765
+ `postman: ${lead} - PMAK belongs to ${describeTeam(args.pmak)} but the access token's session belongs to a different parent org, ${describeTeam(args.session)}. Assets would be created against one team while Bifrost linking and governance act under the other, producing duplicate-link 400s and workspaces not visible to the other credential. ` + fix
22766
+ )
22767
+ };
22768
+ }
22769
+ if (pmakTeamId && sessionTeamId) {
22770
+ const scope = args.workspaceTeamId || args.explicitTeamId ? "parent org team" : "team";
22771
+ const label = args.pmak?.teamName ?? args.pmak?.teamDomain ?? args.session?.teamName ?? args.session?.teamDomain;
22772
+ return {
22773
+ ok: true,
22774
+ level: "ok",
22775
+ message: args.mask(
22776
+ `postman: credential preflight OK - PMAK and access token both resolve to ${scope} ${pmakTeamId}${label ? ` (${label})` : ""}`
22777
+ )
22778
+ };
22779
+ }
22780
+ const missing = [
22781
+ !pmakTeamId ? "PMAK identity" : void 0,
22782
+ !sessionTeamId ? "access-token session identity" : void 0
22783
+ ].filter(Boolean).join(" and ");
22784
+ return {
22785
+ ok: false,
22786
+ level: "note",
22787
+ message: args.mask(
22788
+ `postman: credential preflight note - cross-check skipped because the ${missing} did not resolve a team id; continuing with reactive error guidance only`
22789
+ )
22790
+ };
22791
+ }
22792
+ async function runCredentialPreflight(args) {
22793
+ if (args.mode === "off") {
22794
+ return;
22795
+ }
22796
+ const mask = args.mask;
22797
+ const apiKey = String(args.postmanApiKey || "").trim();
22798
+ const accessToken = String(args.postmanAccessToken || "").trim();
22799
+ let pmak;
22800
+ if (apiKey) {
22801
+ try {
22802
+ pmak = await resolvePmakIdentity({
22803
+ apiBaseUrl: args.apiBaseUrl,
22804
+ apiKey,
22805
+ fetchImpl: args.fetchImpl
22806
+ });
22807
+ } catch (error) {
22808
+ args.log.warning(
22809
+ mask(
22810
+ `postman: credential preflight could not resolve PMAK identity: ${error instanceof Error ? error.message : String(error)}`
22811
+ )
22812
+ );
22813
+ }
22814
+ if (pmak) {
22815
+ args.log.info(formatIdentityLine(pmak, mask));
22816
+ } else {
22817
+ args.log.warning(
22818
+ mask("postman: credential preflight could not resolve PMAK identity from GET /me; continuing")
22819
+ );
22820
+ }
22821
+ }
22822
+ if (!accessToken) {
22823
+ args.log.info(mask("postman: Bifrost diagnostics limited: no access token"));
22824
+ return;
22825
+ }
22826
+ let session;
22827
+ try {
22828
+ session = await resolveSessionIdentity({
22829
+ iapubBaseUrl: args.iapubBaseUrl,
22830
+ accessToken,
22831
+ fetchImpl: args.fetchImpl
22832
+ });
22833
+ } catch (error) {
22834
+ args.log.warning(
22835
+ mask(
22836
+ `postman: credential preflight could not resolve access-token session identity: ${error instanceof Error ? error.message : String(error)}`
22837
+ )
22838
+ );
22839
+ }
22840
+ if (session) {
22841
+ args.log.info(formatIdentityLine(session, mask));
22842
+ } else {
22843
+ args.log.warning(
22844
+ mask(
22845
+ "postman: credential preflight could not resolve the access-token session identity from iapub; continuing with reactive error guidance only"
22846
+ )
22847
+ );
22848
+ }
22849
+ const result = crossCheckIdentities({
22850
+ pmak,
22851
+ session,
22852
+ workspaceTeamId: args.workspaceTeamId,
22853
+ explicitTeamId: args.explicitTeamId,
22854
+ mode: args.mode,
22855
+ mask
22856
+ });
22857
+ if (!result.message) {
22858
+ return;
22859
+ }
22860
+ if (result.level === "fail") {
22861
+ throw new Error(result.message);
22862
+ }
22863
+ if (result.level === "note") {
22864
+ args.log.warning(result.message);
22865
+ return;
22866
+ }
22867
+ args.log.info(result.message);
22868
+ }
22624
22869
 
22625
22870
  // src/lib/postman/error-advice.ts
22626
22871
  var WORKSPACE_PERSONAL_ONLY_ADVICE = "Workspace creation failed: This may be an Org-mode account that requires a workspace-team-id input. The Postman API does not allow creating team workspaces at the organization level. Use the workspace-team-id input to specify which sub-team should own this workspace.";
@@ -24457,6 +24702,16 @@ async function runCli(argv = process.argv.slice(2), runtime = {}) {
24457
24702
  inputs.sslClientPassphrase,
24458
24703
  inputs.sslExtraCaCerts
24459
24704
  ]);
24705
+ await runCredentialPreflight({
24706
+ apiBaseUrl: inputs.postmanApiBase,
24707
+ iapubBaseUrl: inputs.postmanIapubBase,
24708
+ postmanApiKey: inputs.postmanApiKey,
24709
+ postmanAccessToken: inputs.postmanAccessToken,
24710
+ explicitTeamId: inputs.teamId || void 0,
24711
+ mode: inputs.credentialPreflight,
24712
+ mask: initialMasker,
24713
+ log: reporter
24714
+ });
24460
24715
  const resolvingExec = createCliExec(initialMasker);
24461
24716
  const resolved = await resolvePostmanApiKeyAndTeamId(
24462
24717
  inputs,
package/dist/index.cjs CHANGED
@@ -24622,20 +24622,22 @@ async function probeSessionIdentity(baseUrl, accessToken, fetchImpl) {
24622
24622
  if (!payload) {
24623
24623
  return void 0;
24624
24624
  }
24625
- const identity = asRecord(payload.identity);
24626
- const data = asRecord(payload.data);
24625
+ const root = asRecord(payload.session) ?? payload;
24626
+ const identity = asRecord(root.identity);
24627
+ const data = asRecord(root.data);
24627
24628
  const user = asRecord(data?.user);
24628
24629
  const roleEntries = Array.isArray(user?.roles) ? user.roles.map((entry) => coerceText(entry) ?? coerceId(entry)).filter((entry) => Boolean(entry)) : [];
24629
24630
  const singleRole = coerceText(user?.role);
24630
24631
  const roles = roleEntries.length > 0 ? roleEntries : singleRole ? [singleRole] : void 0;
24631
24632
  const resolved = {
24632
24633
  source: "iapub/sessions",
24633
- userId: coerceId(user?.id),
24634
+ userId: coerceId(identity?.user) ?? coerceId(user?.id),
24634
24635
  fullName: coerceText(user?.fullName) ?? coerceText(user?.name) ?? coerceText(user?.username),
24635
24636
  teamId: coerceId(identity?.team),
24637
+ teamName: coerceText(user?.teamName),
24636
24638
  teamDomain: coerceText(identity?.domain),
24637
24639
  ...roles ? { roles } : {},
24638
- consumerType: coerceText(payload.consumerType) ?? coerceText(data?.consumerType) ?? coerceText(user?.consumerType)
24640
+ consumerType: coerceText(root.consumerType) ?? coerceText(data?.consumerType) ?? coerceText(user?.consumerType)
24639
24641
  };
24640
24642
  memoizedSessionIdentity = resolved;
24641
24643
  return resolved;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@postman-cse/onboarding-repo-sync",
3
- "version": "0.14.0",
3
+ "version": "0.14.2",
4
4
  "description": "Public customer preview Postman repo sync GitHub Action.",
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs",