@postman-cse/onboarding-insights 0.7.2 → 0.8.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 +12 -2
- package/action.yml +2 -5
- package/dist/cli.cjs +53 -16
- package/dist/index.cjs +55 -14
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -166,8 +166,7 @@ steps:
|
|
|
166
166
|
| `environment-id` | Yes | | Postman environment UID for the onboarding association. |
|
|
167
167
|
| `system-environment-id` | No | | Postman system environment UUID for service-level Insights acknowledgment. Falls back to the value from the discovered service record. |
|
|
168
168
|
| `cluster-name` | No | | Insights cluster name. When set, the action matches `{cluster-name}/{project-name}` exactly. When omitted, falls back to suffix matching. |
|
|
169
|
-
| `
|
|
170
|
-
| `git-repository-name` | No | `project-name` | GitHub repository name. Defaults to the project name. |
|
|
169
|
+
| `repo-url` | No | Auto-detected from CI when available | Repository URL used for Git onboarding. |
|
|
171
170
|
| `postman-access-token` | Yes | | Postman session token for Bifrost API calls. See [Obtaining postman-access-token](#obtaining-postman-access-token-open-alpha). |
|
|
172
171
|
| `postman-team-id` | No | | Explicit Postman team ID for org-mode Bifrost requests. When omitted, the action leaves `x-entity-team-id` unset so Bifrost resolves team context from the access token. |
|
|
173
172
|
| `github-token` | No | ambient `GITHUB_TOKEN` env when exported by the workflow | Optional GitHub token passed as `git_api_key` only when repository auth is required by the onboarding endpoint. |
|
|
@@ -238,6 +237,17 @@ The action calls the following API endpoints in order:
|
|
|
238
237
|
7. **Workspace acknowledge** -- `POST /v2/workspaces/{id}/onboarding/acknowledge` (Bifrost akita) to activate the Insights project.
|
|
239
238
|
8. **Team verification token** -- `GET /v2/workspaces/{id}/team-verification-token` (Bifrost akita) to retrieve the DaemonSet telemetry token.
|
|
240
239
|
|
|
240
|
+
## Contract smoke monitoring
|
|
241
|
+
|
|
242
|
+
This repo includes `.github/workflows/contract-smoke.yml`, a scheduled live contract check for the upstream APIs used by Insights onboarding.
|
|
243
|
+
|
|
244
|
+
Configure these repository secrets before enabling the workflow:
|
|
245
|
+
|
|
246
|
+
- `SMOKE_ORG_API_KEY`
|
|
247
|
+
- `SMOKE_ORG_ACCESS_TOKEN`
|
|
248
|
+
|
|
249
|
+
The smoke workflow verifies `/me`, `/teams`, `iapub.postman.co/api/sessions/current`, and Bifrost API key creation so auth or payload drift shows up in CI before it hits production onboarding runs.
|
|
250
|
+
|
|
241
251
|
## Local development
|
|
242
252
|
|
|
243
253
|
```bash
|
package/action.yml
CHANGED
|
@@ -16,11 +16,8 @@ inputs:
|
|
|
16
16
|
cluster-name:
|
|
17
17
|
description: 'Insights cluster name. Matches {cluster}/{project-name} in discovered services'
|
|
18
18
|
required: false
|
|
19
|
-
|
|
20
|
-
description: '
|
|
21
|
-
required: false
|
|
22
|
-
git-repository-name:
|
|
23
|
-
description: 'GitHub repository name. Defaults to project-name'
|
|
19
|
+
repo-url:
|
|
20
|
+
description: 'Repository URL for Git onboarding. Auto-detected from CI context when omitted.'
|
|
24
21
|
required: false
|
|
25
22
|
postman-access-token:
|
|
26
23
|
description: 'Postman access token for Bifrost API calls'
|
package/dist/cli.cjs
CHANGED
|
@@ -27746,6 +27746,23 @@ async function validateApiKey(apiKey) {
|
|
|
27746
27746
|
const teamId = data?.user?.teamId ? String(data.user.teamId) : void 0;
|
|
27747
27747
|
return { valid: true, teamId };
|
|
27748
27748
|
}
|
|
27749
|
+
async function getTeams(apiKey) {
|
|
27750
|
+
try {
|
|
27751
|
+
const res = await fetch("https://api.getpostman.com/teams", {
|
|
27752
|
+
method: "GET",
|
|
27753
|
+
headers: { "x-api-key": apiKey }
|
|
27754
|
+
});
|
|
27755
|
+
if (!res.ok) return [];
|
|
27756
|
+
const data = await res.json();
|
|
27757
|
+
return (data?.data ?? []).filter((t) => t?.id && t?.name).map((t) => ({
|
|
27758
|
+
id: Number(t.id),
|
|
27759
|
+
name: String(t.name),
|
|
27760
|
+
...t.organizationId != null ? { organizationId: Number(t.organizationId) } : {}
|
|
27761
|
+
}));
|
|
27762
|
+
} catch {
|
|
27763
|
+
return [];
|
|
27764
|
+
}
|
|
27765
|
+
}
|
|
27749
27766
|
function clamp(value, min, max, fallback) {
|
|
27750
27767
|
const parsed = Number.isFinite(value) ? value : fallback;
|
|
27751
27768
|
return Math.min(max, Math.max(min, parsed));
|
|
@@ -27758,16 +27775,21 @@ function resolveInputs(env = process.env) {
|
|
|
27758
27775
|
if (!postmanAccessToken) throw new Error("postman-access-token is required");
|
|
27759
27776
|
const postmanApiKey = get("postman-api-key");
|
|
27760
27777
|
const postmanTeamId = get("postman-team-id") || env.POSTMAN_TEAM_ID?.trim() || "";
|
|
27761
|
-
const workspaceId = get("workspace-id");
|
|
27762
|
-
if (!workspaceId)
|
|
27763
|
-
|
|
27764
|
-
|
|
27778
|
+
const workspaceId = get("workspace-id") || env.POSTMAN_WORKSPACE_ID?.trim() || "";
|
|
27779
|
+
if (!workspaceId) {
|
|
27780
|
+
throw new Error(
|
|
27781
|
+
"workspace-id is required. Provide it as an input, or set the POSTMAN_WORKSPACE_ID environment variable."
|
|
27782
|
+
);
|
|
27783
|
+
}
|
|
27784
|
+
const environmentId = get("environment-id") || env.POSTMAN_ENVIRONMENT_ID?.trim() || "";
|
|
27785
|
+
if (!environmentId) {
|
|
27786
|
+
throw new Error(
|
|
27787
|
+
"environment-id is required. Provide it as an input, or set the POSTMAN_ENVIRONMENT_ID environment variable."
|
|
27788
|
+
);
|
|
27789
|
+
}
|
|
27765
27790
|
const repoSlug = env.GITHUB_REPOSITORY || env.CI_PROJECT_PATH || (env.BITBUCKET_WORKSPACE && env.BITBUCKET_REPO_SLUG ? `${env.BITBUCKET_WORKSPACE}/${env.BITBUCKET_REPO_SLUG}` : "") || env.BUILD_REPOSITORY_NAME || "";
|
|
27766
|
-
const repoOwner = repoSlug.split("/")[0] || "";
|
|
27767
|
-
const gitOwner = get("git-owner", repoOwner);
|
|
27768
|
-
const gitRepositoryName = get("git-repository-name", projectName);
|
|
27769
27791
|
const detectedRepoUrl = (env.GITHUB_SERVER_URL && env.GITHUB_REPOSITORY ? `${env.GITHUB_SERVER_URL}/${env.GITHUB_REPOSITORY}` : "") || env.CI_PROJECT_URL || env.BITBUCKET_GIT_HTTP_ORIGIN || env.BUILD_REPOSITORY_URI || "";
|
|
27770
|
-
const repoUrl = get("repo-url", detectedRepoUrl
|
|
27792
|
+
const repoUrl = get("repo-url", detectedRepoUrl);
|
|
27771
27793
|
const rawTimeout = parseInt(get("poll-timeout-seconds", String(POLL_TIMEOUT_DEFAULT)), 10);
|
|
27772
27794
|
const rawInterval = parseInt(get("poll-interval-seconds", String(POLL_INTERVAL_DEFAULT)), 10);
|
|
27773
27795
|
return {
|
|
@@ -27776,8 +27798,6 @@ function resolveInputs(env = process.env) {
|
|
|
27776
27798
|
environmentId,
|
|
27777
27799
|
systemEnvironmentId: get("system-environment-id", ""),
|
|
27778
27800
|
clusterName: get("cluster-name", ""),
|
|
27779
|
-
gitOwner,
|
|
27780
|
-
gitRepositoryName,
|
|
27781
27801
|
repoUrl,
|
|
27782
27802
|
postmanAccessToken,
|
|
27783
27803
|
postmanApiKey,
|
|
@@ -27907,12 +27927,31 @@ async function resolveApiKeyAndTeamId(inputs, client, reporter = core_exports) {
|
|
|
27907
27927
|
client.setApiKey(apiKey);
|
|
27908
27928
|
reporter.info("New API key created successfully.");
|
|
27909
27929
|
}
|
|
27910
|
-
|
|
27911
|
-
|
|
27930
|
+
let resolvedTeamId = teamId;
|
|
27931
|
+
if (!resolvedTeamId && apiKey) {
|
|
27932
|
+
try {
|
|
27933
|
+
const teams = await getTeams(apiKey);
|
|
27934
|
+
if (teams.length > 1 && teams.every((t) => t.organizationId == null)) {
|
|
27935
|
+
reporter.warning(
|
|
27936
|
+
"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."
|
|
27937
|
+
);
|
|
27938
|
+
}
|
|
27939
|
+
const orgIds = new Set(teams.filter((t) => t.organizationId != null).map((t) => t.organizationId));
|
|
27940
|
+
const meResult = await validateApiKey(apiKey);
|
|
27941
|
+
const meTeamId = meResult.teamId ? parseInt(meResult.teamId, 10) : NaN;
|
|
27942
|
+
if (teams.length > 1 && orgIds.size === 1 && !Number.isNaN(meTeamId) && orgIds.has(meTeamId)) {
|
|
27943
|
+
resolvedTeamId = String(meTeamId);
|
|
27944
|
+
reporter.info(`Org-mode auto-detected (${teams.length} sub-teams). Using team ID ${resolvedTeamId} for Bifrost headers.`);
|
|
27945
|
+
}
|
|
27946
|
+
} catch {
|
|
27947
|
+
}
|
|
27948
|
+
}
|
|
27949
|
+
if (resolvedTeamId) {
|
|
27950
|
+
reporter.info(`Using postman-team-id for Bifrost headers: ${resolvedTeamId}`);
|
|
27912
27951
|
} else {
|
|
27913
|
-
reporter.info("No
|
|
27952
|
+
reporter.info("No postman-team-id resolved; omitting x-entity-team-id so Bifrost resolves team from the access token.");
|
|
27914
27953
|
}
|
|
27915
|
-
return { apiKey, teamId };
|
|
27954
|
+
return { apiKey, teamId: resolvedTeamId };
|
|
27916
27955
|
}
|
|
27917
27956
|
async function runAction() {
|
|
27918
27957
|
const inputs = resolveInputs();
|
|
@@ -28014,8 +28053,6 @@ function parseCliArgs(argv, env = process.env) {
|
|
|
28014
28053
|
"environment-id",
|
|
28015
28054
|
"system-environment-id",
|
|
28016
28055
|
"cluster-name",
|
|
28017
|
-
"git-owner",
|
|
28018
|
-
"git-repository-name",
|
|
28019
28056
|
"repo-url",
|
|
28020
28057
|
"postman-access-token",
|
|
28021
28058
|
"postman-api-key",
|
package/dist/index.cjs
CHANGED
|
@@ -25015,6 +25015,7 @@ __export(index_exports, {
|
|
|
25015
25015
|
createPlannedOutputs: () => createPlannedOutputs,
|
|
25016
25016
|
deriveTeamId: () => deriveTeamId,
|
|
25017
25017
|
deriveTeamIdFromSession: () => deriveTeamIdFromSession,
|
|
25018
|
+
getTeams: () => getTeams,
|
|
25018
25019
|
resolveApiKeyAndTeamId: () => resolveApiKeyAndTeamId,
|
|
25019
25020
|
resolveInputs: () => resolveInputs,
|
|
25020
25021
|
runOnboarding: () => runOnboarding,
|
|
@@ -27772,6 +27773,23 @@ async function deriveTeamIdFromSession(accessToken) {
|
|
|
27772
27773
|
}
|
|
27773
27774
|
return void 0;
|
|
27774
27775
|
}
|
|
27776
|
+
async function getTeams(apiKey) {
|
|
27777
|
+
try {
|
|
27778
|
+
const res = await fetch("https://api.getpostman.com/teams", {
|
|
27779
|
+
method: "GET",
|
|
27780
|
+
headers: { "x-api-key": apiKey }
|
|
27781
|
+
});
|
|
27782
|
+
if (!res.ok) return [];
|
|
27783
|
+
const data = await res.json();
|
|
27784
|
+
return (data?.data ?? []).filter((t) => t?.id && t?.name).map((t) => ({
|
|
27785
|
+
id: Number(t.id),
|
|
27786
|
+
name: String(t.name),
|
|
27787
|
+
...t.organizationId != null ? { organizationId: Number(t.organizationId) } : {}
|
|
27788
|
+
}));
|
|
27789
|
+
} catch {
|
|
27790
|
+
return [];
|
|
27791
|
+
}
|
|
27792
|
+
}
|
|
27775
27793
|
function clamp(value, min, max, fallback) {
|
|
27776
27794
|
const parsed = Number.isFinite(value) ? value : fallback;
|
|
27777
27795
|
return Math.min(max, Math.max(min, parsed));
|
|
@@ -27784,16 +27802,21 @@ function resolveInputs(env = process.env) {
|
|
|
27784
27802
|
if (!postmanAccessToken) throw new Error("postman-access-token is required");
|
|
27785
27803
|
const postmanApiKey = get("postman-api-key");
|
|
27786
27804
|
const postmanTeamId = get("postman-team-id") || env.POSTMAN_TEAM_ID?.trim() || "";
|
|
27787
|
-
const workspaceId = get("workspace-id");
|
|
27788
|
-
if (!workspaceId)
|
|
27789
|
-
|
|
27790
|
-
|
|
27805
|
+
const workspaceId = get("workspace-id") || env.POSTMAN_WORKSPACE_ID?.trim() || "";
|
|
27806
|
+
if (!workspaceId) {
|
|
27807
|
+
throw new Error(
|
|
27808
|
+
"workspace-id is required. Provide it as an input, or set the POSTMAN_WORKSPACE_ID environment variable."
|
|
27809
|
+
);
|
|
27810
|
+
}
|
|
27811
|
+
const environmentId = get("environment-id") || env.POSTMAN_ENVIRONMENT_ID?.trim() || "";
|
|
27812
|
+
if (!environmentId) {
|
|
27813
|
+
throw new Error(
|
|
27814
|
+
"environment-id is required. Provide it as an input, or set the POSTMAN_ENVIRONMENT_ID environment variable."
|
|
27815
|
+
);
|
|
27816
|
+
}
|
|
27791
27817
|
const repoSlug = env.GITHUB_REPOSITORY || env.CI_PROJECT_PATH || (env.BITBUCKET_WORKSPACE && env.BITBUCKET_REPO_SLUG ? `${env.BITBUCKET_WORKSPACE}/${env.BITBUCKET_REPO_SLUG}` : "") || env.BUILD_REPOSITORY_NAME || "";
|
|
27792
|
-
const repoOwner = repoSlug.split("/")[0] || "";
|
|
27793
|
-
const gitOwner = get("git-owner", repoOwner);
|
|
27794
|
-
const gitRepositoryName = get("git-repository-name", projectName);
|
|
27795
27818
|
const detectedRepoUrl = (env.GITHUB_SERVER_URL && env.GITHUB_REPOSITORY ? `${env.GITHUB_SERVER_URL}/${env.GITHUB_REPOSITORY}` : "") || env.CI_PROJECT_URL || env.BITBUCKET_GIT_HTTP_ORIGIN || env.BUILD_REPOSITORY_URI || "";
|
|
27796
|
-
const repoUrl = get("repo-url", detectedRepoUrl
|
|
27819
|
+
const repoUrl = get("repo-url", detectedRepoUrl);
|
|
27797
27820
|
const rawTimeout = parseInt(get("poll-timeout-seconds", String(POLL_TIMEOUT_DEFAULT)), 10);
|
|
27798
27821
|
const rawInterval = parseInt(get("poll-interval-seconds", String(POLL_INTERVAL_DEFAULT)), 10);
|
|
27799
27822
|
return {
|
|
@@ -27802,8 +27825,6 @@ function resolveInputs(env = process.env) {
|
|
|
27802
27825
|
environmentId,
|
|
27803
27826
|
systemEnvironmentId: get("system-environment-id", ""),
|
|
27804
27827
|
clusterName: get("cluster-name", ""),
|
|
27805
|
-
gitOwner,
|
|
27806
|
-
gitRepositoryName,
|
|
27807
27828
|
repoUrl,
|
|
27808
27829
|
postmanAccessToken,
|
|
27809
27830
|
postmanApiKey,
|
|
@@ -27933,12 +27954,31 @@ async function resolveApiKeyAndTeamId(inputs, client, reporter = core_exports) {
|
|
|
27933
27954
|
client.setApiKey(apiKey);
|
|
27934
27955
|
reporter.info("New API key created successfully.");
|
|
27935
27956
|
}
|
|
27936
|
-
|
|
27937
|
-
|
|
27957
|
+
let resolvedTeamId = teamId;
|
|
27958
|
+
if (!resolvedTeamId && apiKey) {
|
|
27959
|
+
try {
|
|
27960
|
+
const teams = await getTeams(apiKey);
|
|
27961
|
+
if (teams.length > 1 && teams.every((t) => t.organizationId == null)) {
|
|
27962
|
+
reporter.warning(
|
|
27963
|
+
"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."
|
|
27964
|
+
);
|
|
27965
|
+
}
|
|
27966
|
+
const orgIds = new Set(teams.filter((t) => t.organizationId != null).map((t) => t.organizationId));
|
|
27967
|
+
const meResult = await validateApiKey(apiKey);
|
|
27968
|
+
const meTeamId = meResult.teamId ? parseInt(meResult.teamId, 10) : NaN;
|
|
27969
|
+
if (teams.length > 1 && orgIds.size === 1 && !Number.isNaN(meTeamId) && orgIds.has(meTeamId)) {
|
|
27970
|
+
resolvedTeamId = String(meTeamId);
|
|
27971
|
+
reporter.info(`Org-mode auto-detected (${teams.length} sub-teams). Using team ID ${resolvedTeamId} for Bifrost headers.`);
|
|
27972
|
+
}
|
|
27973
|
+
} catch {
|
|
27974
|
+
}
|
|
27975
|
+
}
|
|
27976
|
+
if (resolvedTeamId) {
|
|
27977
|
+
reporter.info(`Using postman-team-id for Bifrost headers: ${resolvedTeamId}`);
|
|
27938
27978
|
} else {
|
|
27939
|
-
reporter.info("No
|
|
27979
|
+
reporter.info("No postman-team-id resolved; omitting x-entity-team-id so Bifrost resolves team from the access token.");
|
|
27940
27980
|
}
|
|
27941
|
-
return { apiKey, teamId };
|
|
27981
|
+
return { apiKey, teamId: resolvedTeamId };
|
|
27942
27982
|
}
|
|
27943
27983
|
async function runAction() {
|
|
27944
27984
|
const inputs = resolveInputs();
|
|
@@ -27999,6 +28039,7 @@ runAction().catch((error2) => {
|
|
|
27999
28039
|
createPlannedOutputs,
|
|
28000
28040
|
deriveTeamId,
|
|
28001
28041
|
deriveTeamIdFromSession,
|
|
28042
|
+
getTeams,
|
|
28002
28043
|
resolveApiKeyAndTeamId,
|
|
28003
28044
|
resolveInputs,
|
|
28004
28045
|
runOnboarding,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@postman-cse/onboarding-insights",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.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",
|
|
@@ -31,7 +31,8 @@
|
|
|
31
31
|
"@actions/core": "^3.0.0"
|
|
32
32
|
},
|
|
33
33
|
"overrides": {
|
|
34
|
-
"undici": ">=6.24.0"
|
|
34
|
+
"undici": ">=6.24.0",
|
|
35
|
+
"picomatch": ">=4.0.4"
|
|
35
36
|
},
|
|
36
37
|
"devDependencies": {
|
|
37
38
|
"@types/node": "^25.3.5",
|