@nuvlore/extension-access-pagerduty 0.1.1

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.
Files changed (83) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +3 -0
  3. package/package.json +52 -0
  4. package/tools/pagerduty_sso_incident.mjs +32 -0
  5. package/tools/pagerduty_sso_incidents.mjs +36 -0
  6. package/tools/pagerduty_sso_oncalls.mjs +36 -0
  7. package/tools/pagerduty_sso_read.mjs +34 -0
  8. package/tools/pagerduty_sso_services.mjs +33 -0
  9. package/tools/pagerduty_sso_verify.mjs +26 -0
  10. package/vendor/extension-sso/LICENSE +202 -0
  11. package/vendor/extension-sso/README.md +35 -0
  12. package/vendor/extension-sso/commands/okta-login.md +10 -0
  13. package/vendor/extension-sso/package.json +51 -0
  14. package/vendor/extension-sso/skills/workday-okta-auth/SKILL.md +20 -0
  15. package/vendor/extension-sso/src/autoAuth.mjs +25 -0
  16. package/vendor/extension-sso/src/browserLogin.mjs +1 -0
  17. package/vendor/extension-sso/src/chromeCookies.mjs +1 -0
  18. package/vendor/extension-sso/src/cookieJar.mjs +1 -0
  19. package/vendor/extension-sso/src/extensionAccess.mjs +173 -0
  20. package/vendor/extension-sso/src/htmlSessionExtract.mjs +1 -0
  21. package/vendor/extension-sso/src/oktaAppAccess.mjs +133 -0
  22. package/vendor/extension-sso/src/oktaAppCatalog.mjs +118 -0
  23. package/vendor/extension-sso/src/oktaAppRead.mjs +119 -0
  24. package/vendor/extension-sso/src/oktaConfig.mjs +12 -0
  25. package/vendor/extension-sso/src/oktaSession.mjs +32 -0
  26. package/vendor/extension-sso/src/serviceOperations.mjs +407 -0
  27. package/vendor/extension-sso/src/serviceReadSearch.mjs +395 -0
  28. package/vendor/extension-sso/src/serviceReads.mjs +109 -0
  29. package/vendor/extension-sso/src/serviceRegistry.mjs +497 -0
  30. package/vendor/extension-sso/src/sessionAuth.mjs +339 -0
  31. package/vendor/extension-sso/src/sessionManager.mjs +212 -0
  32. package/vendor/extension-sso/src/sessionValidate.mjs +74 -0
  33. package/vendor/extension-sso/src/ssoConfig.mjs +31 -0
  34. package/vendor/extension-sso/src/ssoHttpRead.mjs +292 -0
  35. package/vendor/extension-sso/tools/extension-access-tools.shared.mjs +16 -0
  36. package/vendor/extension-sso/tools/okta-app-tools.shared.mjs +5 -0
  37. package/vendor/extension-sso/tools/okta-tools.shared.mjs +18 -0
  38. package/vendor/extension-sso/tools/workday_extension_read.mjs +51 -0
  39. package/vendor/extension-sso/tools/workday_extension_read_access.mjs +65 -0
  40. package/vendor/extension-sso/tools/workday_list_extension_access.mjs +39 -0
  41. package/vendor/extension-sso/tools/workday_list_okta_apps.mjs +18 -0
  42. package/vendor/extension-sso/tools/workday_list_service_operations.mjs +41 -0
  43. package/vendor/extension-sso/tools/workday_list_service_read_search_capabilities.mjs +34 -0
  44. package/vendor/extension-sso/tools/workday_list_services.mjs +31 -0
  45. package/vendor/extension-sso/tools/workday_okta_app_probe_all.mjs +24 -0
  46. package/vendor/extension-sso/tools/workday_okta_app_read.mjs +30 -0
  47. package/vendor/extension-sso/tools/workday_okta_app_read_access.mjs +25 -0
  48. package/vendor/extension-sso/tools/workday_okta_auth_header.mjs +58 -0
  49. package/vendor/extension-sso/tools/workday_okta_login.mjs +65 -0
  50. package/vendor/extension-sso/tools/workday_okta_open_app.mjs +63 -0
  51. package/vendor/extension-sso/tools/workday_okta_open_service.mjs +63 -0
  52. package/vendor/extension-sso/tools/workday_okta_status.mjs +35 -0
  53. package/vendor/extension-sso/tools/workday_service_auth.mjs +65 -0
  54. package/vendor/extension-sso/tools/workday_service_operation_read.mjs +51 -0
  55. package/vendor/extension-sso/tools/workday_service_read.mjs +56 -0
  56. package/vendor/extension-sso/tools/workday_service_search.mjs +62 -0
  57. package/vendor/extension-sso/tools/workday_sso_cookie_header.mjs +59 -0
  58. package/vendor/extension-sso/vendor/extension-browser-sso/LICENSE +202 -0
  59. package/vendor/extension-sso/vendor/extension-browser-sso/README.md +16 -0
  60. package/vendor/extension-sso/vendor/extension-browser-sso/package.json +47 -0
  61. package/vendor/extension-sso/vendor/extension-browser-sso/src/autoAuth.mjs +47 -0
  62. package/vendor/extension-sso/vendor/extension-browser-sso/src/browserHttpRead.mjs +76 -0
  63. package/vendor/extension-sso/vendor/extension-browser-sso/src/browserLogin.mjs +24 -0
  64. package/vendor/extension-sso/vendor/extension-browser-sso/src/chromeCookies.mjs +192 -0
  65. package/vendor/extension-sso/vendor/extension-browser-sso/src/cookieJar.mjs +132 -0
  66. package/vendor/extension-sso/vendor/extension-browser-sso/src/extensions/toolkit/devops-data-paths.mjs +222 -0
  67. package/vendor/extension-sso/vendor/extension-browser-sso/src/extensions/toolkit/devops-diagnostics.mjs +440 -0
  68. package/vendor/extension-sso/vendor/extension-browser-sso/src/extensions/toolkit/enterprise-api-read.mjs +180 -0
  69. package/vendor/extension-sso/vendor/extension-browser-sso/src/extensions/toolkit/read-only-command-pack.mjs +1 -0
  70. package/vendor/extension-sso/vendor/extension-browser-sso/src/extensions/toolkit/read-only-plan.mjs +45 -0
  71. package/vendor/extension-sso/vendor/extension-browser-sso/src/extensions/toolkit/read-only-shell-policy.d.mts +26 -0
  72. package/vendor/extension-sso/vendor/extension-browser-sso/src/extensions/toolkit/read-only-shell-policy.mjs +170 -0
  73. package/vendor/extension-sso/vendor/extension-browser-sso/src/htmlSessionExtract.mjs +64 -0
  74. package/vendor/extension-sso/vendor/extension-read-only-toolkit/LICENSE +202 -0
  75. package/vendor/extension-sso/vendor/extension-read-only-toolkit/README.md +29 -0
  76. package/vendor/extension-sso/vendor/extension-read-only-toolkit/package.json +43 -0
  77. package/vendor/extension-sso/vendor/extension-read-only-toolkit/src/devops-data-paths.mjs +222 -0
  78. package/vendor/extension-sso/vendor/extension-read-only-toolkit/src/devops-diagnostics.mjs +440 -0
  79. package/vendor/extension-sso/vendor/extension-read-only-toolkit/src/enterprise-api-read.mjs +180 -0
  80. package/vendor/extension-sso/vendor/extension-read-only-toolkit/src/read-only-command-pack.mjs +1 -0
  81. package/vendor/extension-sso/vendor/extension-read-only-toolkit/src/read-only-plan.mjs +45 -0
  82. package/vendor/extension-sso/vendor/extension-read-only-toolkit/src/read-only-shell-policy.d.mts +26 -0
  83. package/vendor/extension-sso/vendor/extension-read-only-toolkit/src/read-only-shell-policy.mjs +170 -0
@@ -0,0 +1,35 @@
1
+ # @nuvlore/extension-sso
2
+
3
+ Okta browser SSO for Workday — log in once in Chrome, reuse cookies across Nuvlore Workday tools.
4
+
5
+ Workday Okta does not support OIDC device authorization; this extension imports session cookies from Chrome (macOS) and persists them locally.
6
+
7
+ ## Configure
8
+
9
+ Copy the repo `.env.example` to `.env` and set:
10
+
11
+ - `WORKDAY_OKTA_DOMAIN` — e.g. `workday.okta.com`
12
+ - `WORKDAY_OKTA_LOGIN_URL` — default `https://<domain>/app/UserHome`
13
+
14
+ No `WORKDAY_OKTA_CLIENT_ID` is required.
15
+
16
+ Cookies are stored at `~/.Nuvlore/workday/cookie-jar.json` (mode 600).
17
+
18
+ This repository vendors the Nuvlore browser SSO and read-only toolkit packages under `vendor/`
19
+ so private-repo CI can install dependencies without organization-wide package registry credentials.
20
+
21
+ ## Tools
22
+
23
+ | Tool | Purpose |
24
+ |------|---------|
25
+ | `workday_okta_login` | Ensure session (opens Chrome only when needed) |
26
+ | `workday_okta_status` | Session status |
27
+ | `workday_okta_auth_header` | Cookie header for Okta org (legacy tool name) |
28
+ | `workday_sso_cookie_header` | Cookie header for a service host |
29
+ | `workday_service_auth` | Check SSO readiness per service |
30
+
31
+ ## Test
32
+
33
+ ```sh
34
+ npm exec -- Nuvlore-package-test
35
+ ```
@@ -0,0 +1,10 @@
1
+ # okta-login
2
+
3
+ Log in to Workday Okta SSO once for `$ARGUMENTS`.
4
+
5
+ Steps:
6
+
7
+ 1. Load the `workday-okta-auth` skill.
8
+ 2. Call `workday_okta_status`.
9
+ 3. If needed, call `workday_okta_login` and wait for browser SSO completion.
10
+ 4. Confirm session with `workday_okta_status`.
@@ -0,0 +1,51 @@
1
+ {
2
+ "name": "@nuvlore/extension-sso",
3
+ "version": "0.1.0",
4
+ "private": true,
5
+ "description": "Okta browser SSO for Workday services — one Chrome login, shared session cookies.",
6
+ "license": "Apache-2.0",
7
+ "type": "module",
8
+ "exports": {
9
+ "./sso-http-read": "./src/ssoHttpRead.mjs",
10
+ "./okta-app-access": "./src/oktaAppAccess.mjs",
11
+ "./okta-app-read": "./src/oktaAppRead.mjs",
12
+ "./service-reads": "./src/serviceReads.mjs",
13
+ "./service-operations": "./src/serviceOperations.mjs",
14
+ "./service-read-search": "./src/serviceReadSearch.mjs",
15
+ "./html-session-extract": "./src/htmlSessionExtract.mjs",
16
+ "./auto-auth": "./src/autoAuth.mjs",
17
+ "./session-auth": "./src/sessionAuth.mjs",
18
+ "./session-manager": "./src/sessionManager.mjs",
19
+ "./sso-config": "./src/ssoConfig.mjs"
20
+ },
21
+ "files": [
22
+ "LICENSE",
23
+ "README.md",
24
+ "tools",
25
+ "skills",
26
+ "commands",
27
+ "src"
28
+ ],
29
+ "scripts": {
30
+ "test": "npm run test:unit && npm run test:integration",
31
+ "test:unit": "vitest run test/*.test.ts",
32
+ "test:integration": "vitest run test/integration/*.test.ts"
33
+ },
34
+ "agentRuntimeDistribution": {
35
+ "visibility": "private",
36
+ "group": "sso",
37
+ "serviceGrouping": "single-service",
38
+ "publicService": false,
39
+ "rationale": "Centralized Okta SSO for Workday Okta-protected services."
40
+ },
41
+ "agentRuntimeTools": {
42
+ "service": "sso"
43
+ },
44
+ "dependencies": {
45
+ "@nuvlore/extension-browser-sso": "file:vendor/extension-browser-sso",
46
+ "@nuvlore/extension-read-only-toolkit": "file:vendor/extension-read-only-toolkit"
47
+ },
48
+ "devDependencies": {
49
+ "vitest": "^3.1.3"
50
+ }
51
+ }
@@ -0,0 +1,20 @@
1
+ ---
2
+ name: workday-okta-auth
3
+ description: Use when the user needs Okta SSO login or shared auth for Workday services.
4
+ ---
5
+
6
+ # Workday Okta Auth
7
+
8
+ ## When To Use
9
+
10
+ Use this skill when accessing Workday Okta-protected systems (Bamboo, Jira, Confluence, Bitbucket, Pharos, Slack) and the user should not manage per-service access tokens manually.
11
+
12
+ ## Procedure
13
+
14
+ 1. Check `workday_okta_status` for an existing browser session.
15
+ 2. If unauthenticated, run `workday_okta_login`. Chrome opens only when cookies are missing or expired; if the user is already logged into Okta in Chrome, cookies are imported silently.
16
+ 3. For HTTP calls to a specific service, use `workday_sso_cookie_header` with the extension service id (e.g. `jira`, `bitbucket`, `pharos`, `dashboard`, `workday-infra-access`). Run `workday_list_services` to see all extension mappings.
17
+ 4. `workday_okta_auth_header` returns the Okta org Cookie header (not a Bearer token).
18
+ 5. For Slack, use `workday_okta_open_app({ app: "Slack" })` when Chrome/Okta/Slack needs user-facing authentication, then use `slack_okta_search_messages` / `slack_okta_search_all` for read-only context.
19
+ 6. **Read-only by default** — use SSO cookies for GET/browse/investigation. Never create, update, delete, merge, deploy, or mutate any Workday service through this product unless the user explicitly requests a one-off write in the current chat.
20
+ 7. For explicit Slack send requests, use `slack_okta_send_message` with a concrete Slack conversation id. Do not print Slack browser-session tokens or cookies.
@@ -0,0 +1,25 @@
1
+ export {
2
+ isAuthStatusResponse,
3
+ shouldRetryAuthAfterFailure
4
+ } from "@nuvlore/extension-browser-sso/auto-auth";
5
+
6
+ import {
7
+ isAutoAuthEnabled as isBrowserAutoAuthEnabled,
8
+ resolveAutoAuthOptions as resolveBrowserAutoAuthOptions
9
+ } from "@nuvlore/extension-browser-sso/auto-auth";
10
+
11
+ /** Map product-specific env aliases onto generic browser-sso flags. */
12
+ function mergeAutoAuthEnv(env = process.env) {
13
+ const legacyFlag = env.WORKDAY_SSO_AUTO_AUTH?.trim();
14
+ if (!legacyFlag) return env;
15
+ return { ...env, BROWSER_SSO_AUTO_AUTH: legacyFlag };
16
+ }
17
+
18
+ export function isAutoAuthEnabled(env = process.env) {
19
+ return isBrowserAutoAuthEnabled(mergeAutoAuthEnv(env));
20
+ }
21
+
22
+ export function resolveAutoAuthOptions(options = {}) {
23
+ const env = mergeAutoAuthEnv(options.env ?? process.env);
24
+ return resolveBrowserAutoAuthOptions({ ...options, env });
25
+ }
@@ -0,0 +1 @@
1
+ export * from "@nuvlore/extension-browser-sso/browser-login";
@@ -0,0 +1 @@
1
+ export * from "@nuvlore/extension-browser-sso/chrome-cookies";
@@ -0,0 +1 @@
1
+ export * from "@nuvlore/extension-browser-sso/cookie-jar";
@@ -0,0 +1,173 @@
1
+ import { buildRequestUrl, normalizeBaseUrl, parseResponseBody } from "@nuvlore/extension-read-only-toolkit/enterprise-api-read";
2
+ import { assertNonHtmlApiResponse } from "@nuvlore/extension-read-only-toolkit/devops-diagnostics";
3
+ import { resolveAutoAuthOptions } from "./autoAuth.mjs";
4
+ import { getServiceCookieHeader } from "./sessionAuth.mjs";
5
+ import { getSsoConfig } from "./ssoConfig.mjs";
6
+ import { getRequiredServices, getWorkdayService, listWorkdayServices } from "./serviceRegistry.mjs";
7
+ import { ssoReadGet } from "./ssoHttpRead.mjs";
8
+ import { oktaAppReadGet } from "./oktaAppAccess.mjs";
9
+
10
+ export function assertReadOnlyHttpRequest({ method = "GET", path = "" } = {}) {
11
+ const normalizedMethod = String(method).toUpperCase();
12
+ if (normalizedMethod !== "GET") {
13
+ throw new Error(`Read-only product: HTTP method ${normalizedMethod} is not allowed. Use GET only.`);
14
+ }
15
+ const rawPath = String(path || "");
16
+ if (/^https?:\/\//i.test(rawPath)) {
17
+ throw new Error("Read-only extension access: use restPath relative to defaultBaseUrl, not an absolute URL.");
18
+ }
19
+ if (rawPath.includes("..")) {
20
+ throw new Error("Read-only extension access: path cannot contain parent directory traversal.");
21
+ }
22
+ if (/\/(delete|edit|transition|merge|deploy|apply|update|create)(\/|$)/i.test(rawPath)) {
23
+ throw new Error(`Read-only product: path appears mutating and is blocked: ${rawPath}`);
24
+ }
25
+ }
26
+
27
+ function accessMode(service) {
28
+ return service.readAccess?.mode ?? "unsupported";
29
+ }
30
+
31
+ export async function getExtensionReadAccess(serviceId, options = {}) {
32
+ const service = getWorkdayService(serviceId);
33
+ const readAccess = service.readAccess ?? { readOnly: true, mode: "unsupported" };
34
+ const mode = accessMode(service);
35
+
36
+ if (mode === "workflow") {
37
+ return {
38
+ readOnly: true,
39
+ methods: readAccess.methods ?? ["GET"],
40
+ mode,
41
+ service: serviceId,
42
+ extension: service.extension,
43
+ label: service.label,
44
+ requires: getRequiredServices(serviceId).map((dep) => ({
45
+ service: dep.id,
46
+ extension: dep.extension,
47
+ label: dep.label,
48
+ readOnly: true,
49
+ mode: dep.readAccess?.mode ?? "unsupported"
50
+ })),
51
+ recommendation: "Workflow extension — call workday_extension_read_access on each required extension service directly."
52
+ };
53
+ }
54
+
55
+ if (mode === "cli-readonly" || mode === "ssh-readonly" || mode === "local" || mode === "library" || mode === "mcp" || mode === "unsupported") {
56
+ return {
57
+ readOnly: true,
58
+ methods: readAccess.methods ?? [],
59
+ mode,
60
+ service: serviceId,
61
+ extension: service.extension,
62
+ label: service.label,
63
+ ready: mode !== "unsupported",
64
+ platforms: readAccess.platforms,
65
+ note: readAccess.note ?? `${service.label} uses read-only tools, not browser cookie HTTP.`,
66
+ recommendation:
67
+ mode === "local" || mode === "library"
68
+ ? "No remote SSO needed."
69
+ : "Use the extension's read-only command-pack tool."
70
+ };
71
+ }
72
+
73
+ const authOptions = resolveAutoAuthOptions(options);
74
+ const config = authOptions.config ?? getSsoConfig();
75
+ const baseUrl = normalizeBaseUrl(
76
+ authOptions.baseUrl || readAccess.defaultBaseUrl || `https://${service.domains?.[0] || ""}`
77
+ );
78
+ const cookieResult =
79
+ mode === "public-http"
80
+ ? { ok: true, cookie: "", host: new URL(baseUrl).host, summary: { authenticated: true } }
81
+ : await getServiceCookieHeader(serviceId, { ...authOptions, config });
82
+
83
+ return {
84
+ readOnly: true,
85
+ methods: readAccess.methods ?? ["GET"],
86
+ mode,
87
+ service: serviceId,
88
+ extension: service.extension,
89
+ label: service.label,
90
+ baseUrl,
91
+ host: cookieResult.host,
92
+ restPathPrefix: readAccess.restPathPrefix ?? "",
93
+ ready: cookieResult.ok || mode === "public-http",
94
+ headers: {
95
+ accept: "application/json",
96
+ ...(cookieResult.cookie ? { cookie: cookieResult.cookie } : {})
97
+ },
98
+ userAgent: `Mozilla/5.0 nuvlore/0.1 ${serviceId}-read`,
99
+ summary: cookieResult.summary,
100
+ recommendation: cookieResult.ok
101
+ ? `Read-only GET ${baseUrl}<restPath> via workday_extension_read (service=${serviceId}).`
102
+ : cookieResult.authUrl
103
+ ? `Open ${cookieResult.authUrl} in Chrome via Okta to refresh session, then retry.`
104
+ : "Run workday_okta_login, then retry."
105
+ };
106
+ }
107
+
108
+ export async function extensionReadGet(serviceId, input = {}, options = {}) {
109
+ assertReadOnlyHttpRequest({ method: "GET", path: input.restPath || input.path });
110
+ const authOptions = resolveAutoAuthOptions(options);
111
+ const service = getWorkdayService(serviceId);
112
+ if (service.readAccess?.oktaAppName) {
113
+ return oktaAppReadGet(service.readAccess.oktaAppName, input, authOptions);
114
+ }
115
+ const access = await getExtensionReadAccess(serviceId, authOptions);
116
+ if (access.mode === "workflow") {
117
+ throw new Error(
118
+ `Extension ${access.extension} is a workflow bundle. Use workday_extension_read_access and call a required extension service directly.`
119
+ );
120
+ }
121
+ if (access.mode === "cookie-http") {
122
+ return ssoReadGet(serviceId, input, authOptions);
123
+ }
124
+ if (access.mode !== "public-http") {
125
+ throw new Error(`Extension ${access.extension} does not support read-only HTTP GET (${access.mode}).`);
126
+ }
127
+ if (!access.ready) {
128
+ throw new Error(access.recommendation || `Read access not ready for ${serviceId}.`);
129
+ }
130
+
131
+ const fetchImpl = options.fetchImpl ?? globalThis.fetch;
132
+ const restPath = String(input.restPath || input.path || "").trim();
133
+ if (!restPath) throw new Error("restPath is required for read-only extension GET.");
134
+ const baseUrl = normalizeBaseUrl(input.baseUrl || access.baseUrl);
135
+ const url = buildRequestUrl(baseUrl, restPath, input.query);
136
+ const response = await fetchImpl(url, {
137
+ method: "GET",
138
+ headers: {
139
+ accept: access.headers.accept,
140
+ "user-agent": access.userAgent,
141
+ ...(access.headers.cookie ? { cookie: access.headers.cookie } : {})
142
+ }
143
+ });
144
+ const text = await response.text();
145
+ assertNonHtmlApiResponse(access.label, text);
146
+ const data = parseResponseBody(text);
147
+ if (!response.ok) {
148
+ throw new Error(`${access.label} read failed with status ${response.status}.`);
149
+ }
150
+ return {
151
+ readOnly: true,
152
+ method: "GET",
153
+ service: serviceId,
154
+ extension: access.extension,
155
+ baseUrl,
156
+ restPath,
157
+ url: url.toString(),
158
+ status: response.status,
159
+ data
160
+ };
161
+ }
162
+
163
+ export function listExtensionReadAccess() {
164
+ return listWorkdayServices().map((service) => ({
165
+ service: service.id,
166
+ extension: service.extension,
167
+ label: service.label,
168
+ auth: service.auth,
169
+ readOnly: service.readAccess?.readOnly !== false,
170
+ mode: accessMode(service),
171
+ requires: service.requires ?? []
172
+ }));
173
+ }
@@ -0,0 +1 @@
1
+ export * from "@nuvlore/extension-browser-sso/html-session-extract";
@@ -0,0 +1,133 @@
1
+ import { resolveBestCookieHost } from "./cookieJar.mjs";
2
+ import { getExtensionReadAccess, extensionReadGet } from "./extensionAccess.mjs";
3
+ import { ensureSsoSession, syncAllOktaCatalogCookies } from "./sessionManager.mjs";
4
+ import { resolveAutoAuthOptions } from "./autoAuth.mjs";
5
+ import { ensureOktaAppSession } from "./sessionAuth.mjs";
6
+ import { getSsoConfig } from "./ssoConfig.mjs";
7
+ import { getOktaApp, listOktaApps } from "./oktaAppCatalog.mjs";
8
+ import { oktaAppHttpRead } from "./oktaAppRead.mjs";
9
+ import { readServiceDefault } from "./serviceReads.mjs";
10
+ import { probeReadOnlyUrl } from "./sessionValidate.mjs";
11
+
12
+ export { probeReadOnlyUrl };
13
+
14
+ export async function getOktaAppReadAccess(appName, options = {}) {
15
+ const app = getOktaApp(appName);
16
+ const readOnly = true;
17
+
18
+ if (app.serviceId && app.mode !== "cli-readonly") {
19
+ try {
20
+ const extensionAccess = await getExtensionReadAccess(app.serviceId, options);
21
+ return {
22
+ readOnly,
23
+ oktaApp: appName,
24
+ ...extensionAccess,
25
+ probePath: app.probePath,
26
+ defaultBaseUrl: app.defaultBaseUrl ?? extensionAccess.baseUrl
27
+ };
28
+ } catch {
29
+ // fall through to cookie probe
30
+ }
31
+ }
32
+
33
+ if (app.mode === "cli-readonly") {
34
+ return {
35
+ readOnly,
36
+ oktaApp: appName,
37
+ service: app.serviceId,
38
+ mode: "cli-readonly",
39
+ platform: app.platform,
40
+ ready: true,
41
+ recommendation: "Read-only CLI tools only — describe/list/get/logs."
42
+ };
43
+ }
44
+
45
+ const authOptions = resolveAutoAuthOptions(options);
46
+ const config = authOptions.config ?? getSsoConfig();
47
+ const { jar } = await ensureOktaAppSession(appName, { ...authOptions, config });
48
+ const { host, cookie, hasCookies } = resolveBestCookieHost(jar, app.domains ?? []);
49
+ const probe = hasCookies
50
+ ? await probeReadOnlyUrl(jar, { host, path: app.probePath ?? "/", cookie, fetchImpl: options.fetchImpl })
51
+ : { ready: false, reason: "no_cookies" };
52
+
53
+ return {
54
+ readOnly,
55
+ methods: ["GET"],
56
+ oktaApp: appName,
57
+ service: app.serviceId,
58
+ mode: app.mode ?? "cookie-http",
59
+ baseUrl: app.defaultBaseUrl,
60
+ host,
61
+ hasCookies,
62
+ ready: Boolean(hasCookies && probe.ready),
63
+ probe,
64
+ cookiePresent: Boolean(cookie),
65
+ recommendation: probe.ready
66
+ ? `Read-only GET ${app.defaultBaseUrl}${app.probePath ?? "/"}`
67
+ : hasCookies
68
+ ? "Cookies present but session probe failed — open app in Chrome once."
69
+ : "Open app in Chrome via Okta, then retry."
70
+ };
71
+ }
72
+
73
+ export async function oktaAppReadGet(appName, input = {}, options = {}) {
74
+ const app = getOktaApp(appName);
75
+
76
+ if (app.serviceId && !input.forceCookie) {
77
+ try {
78
+ if (input.useDefault) {
79
+ return readServiceDefault(app.serviceId, options);
80
+ }
81
+ return await extensionReadGet(
82
+ app.serviceId,
83
+ {
84
+ restPath: input.restPath || app.probePath,
85
+ baseUrl: input.baseUrl || app.defaultBaseUrl,
86
+ query: input.query,
87
+ followRedirects: input.followRedirects
88
+ },
89
+ options
90
+ );
91
+ } catch (error) {
92
+ if (!input.allowCookieFallback) throw error;
93
+ }
94
+ }
95
+
96
+ return oktaAppHttpRead(appName, input, options);
97
+ }
98
+
99
+ export async function probeAllOktaApps(options = {}) {
100
+ const authOptions = resolveAutoAuthOptions(options);
101
+ if (!authOptions.probeOnly) {
102
+ await ensureSsoSession({
103
+ config: authOptions.config ?? getSsoConfig(),
104
+ openBrowserOnMissing: authOptions.openBrowserOnMissing,
105
+ forceBrowser: authOptions.forceBrowser === true,
106
+ onStatus: authOptions.onStatus
107
+ }).catch(() => {});
108
+ }
109
+ await syncAllOktaCatalogCookies(options);
110
+ const results = [];
111
+ for (const app of listOktaApps()) {
112
+ try {
113
+ const access = await getOktaAppReadAccess(app.name, { ...options, probeOnly: true });
114
+ results.push({
115
+ app: app.name,
116
+ service: app.serviceId,
117
+ mode: access.mode,
118
+ ready: access.ready === true,
119
+ host: access.host,
120
+ status: access.probe?.status
121
+ });
122
+ } catch (error) {
123
+ results.push({
124
+ app: app.name,
125
+ ready: false,
126
+ error: error instanceof Error ? error.message : String(error)
127
+ });
128
+ }
129
+ }
130
+ return results;
131
+ }
132
+
133
+ export { listOktaApps };
@@ -0,0 +1,118 @@
1
+ /**
2
+ * All apps visible on https://workday.okta.com/app/UserHome
3
+ * Read-only access only — probe paths are GET.
4
+ */
5
+ export const OKTA_USER_HOME_APPS = {
6
+ Workday: {
7
+ serviceId: "sso",
8
+ domains: ["workday.okta.com"],
9
+ defaultBaseUrl: "https://workday.okta.com",
10
+ probePath: "/app/UserHome"
11
+ },
12
+ JIRA2: { serviceId: "jira", domains: ["jira2.workday.com"], defaultBaseUrl: "https://jira2.workday.com", probePath: "/rest/api/latest/myself" },
13
+ Bitbucket: { serviceId: "bitbucket", domains: ["bitbucket.workday.com"], defaultBaseUrl: "https://bitbucket.workday.com", probePath: "/" },
14
+ Confluence: { serviceId: "confluence", domains: ["confluence.workday.com"], defaultBaseUrl: "https://confluence.workday.com", probePath: "/rest/api/user/current" },
15
+ Pharos: { serviceId: "pharos", domains: ["grafana.produs.us.wdpharos.io"], defaultBaseUrl: "https://grafana.produs.us.wdpharos.io", probePath: "/login" },
16
+ "GitHub EMU Cloud": { serviceId: "github", domains: ["ghe.megaleo.com"], defaultBaseUrl: "https://ghe.megaleo.com", probePath: "/" },
17
+ PagerDuty: { serviceId: "pagerduty", domains: ["workday.pagerduty.com"], defaultBaseUrl: "https://workday.pagerduty.com", probePath: "/" },
18
+ "Amazon Web Services - AWS": { serviceId: "workday-infra-access", platform: "aws", domains: ["signin.aws.amazon.com"], defaultBaseUrl: "https://signin.aws.amazon.com", probePath: "/", mode: "cli-readonly" },
19
+ Slack: {
20
+ domains: ["workday.enterprise.slack.com", "workday.slack.com", "workday-dev.slack.com", "slack.com", "app.slack.com"],
21
+ defaultBaseUrl: "https://workday.enterprise.slack.com",
22
+ probePath: "/"
23
+ },
24
+ Zoom: { domains: ["workday.zoom.us", "zoom.us", "us.telemetry.zoom.us"], defaultBaseUrl: "https://workday.zoom.us", probePath: "/" },
25
+ Horizon: { domains: ["horizon.workdayinternal.com"], defaultBaseUrl: "https://horizon.workdayinternal.com", probePath: "/" },
26
+ "On Horizon": { domains: ["horizon.workdayinternal.com"], defaultBaseUrl: "https://horizon.workdayinternal.com", probePath: "/" },
27
+ "People & Purpose on Horizon": { domains: ["horizon.workdayinternal.com"], defaultBaseUrl: "https://horizon.workdayinternal.com", probePath: "/" },
28
+ "Workday Service Hub": { domains: ["workday.service-now.com"], defaultBaseUrl: "https://workday.service-now.com", probePath: "/" },
29
+ "Analytics Hub": { domains: ["console.cloud.google.com"], defaultBaseUrl: "https://console.cloud.google.com", probePath: "/", mode: "cli-readonly" },
30
+ "Internal Analytics": { domains: ["console.cloud.google.com"], defaultBaseUrl: "https://console.cloud.google.com", probePath: "/", mode: "cli-readonly" },
31
+ "Workday - Google Apps Drive": {
32
+ domains: ["drive.google.com", "accounts.google.com", "google.com"],
33
+ defaultBaseUrl: "https://drive.google.com",
34
+ probePath: "/drive/"
35
+ },
36
+ Sana: {
37
+ domains: ["workday.sana.ai", "sana.ai", "sanalabs.com"],
38
+ defaultBaseUrl: "https://workday.sana.ai",
39
+ agentsUrl: "https://sana.ai/tPNxyS5GyK1r",
40
+ agentsWorkspaceId: "tPNxyS5GyK1r",
41
+ probePath: "/",
42
+ launchViaUserHome: true
43
+ },
44
+ Peakon: { domains: ["workday.peakon.com", "peakon.com"], defaultBaseUrl: "https://workday.peakon.com", probePath: "/" },
45
+ "Workday Community": { domains: ["community.workday.com"], defaultBaseUrl: "https://community.workday.com", probePath: "/" },
46
+ Achievers: { domains: ["workday.achievers.com"], defaultBaseUrl: "https://workday.achievers.com", probePath: "/" },
47
+ Workboard: { domains: ["workboard.com"], defaultBaseUrl: "https://www.workboard.com", probePath: "/" },
48
+ "Eptura Office Space Tool & Desk Reservations": { domains: ["workday.iofficeconnect.com"], defaultBaseUrl: "https://workday.iofficeconnect.com", probePath: "/" },
49
+ Miro: { domains: ["miro.com", "www.miro.com"], defaultBaseUrl: "https://miro.com", probePath: "/app/dashboard/" },
50
+ OneTrust: { domains: ["app.onetrust.com"], defaultBaseUrl: "https://app.onetrust.com", probePath: "/" },
51
+ "Collibra Data Intelligence Platform": { domains: ["workday.collibra.com"], defaultBaseUrl: "https://workday.collibra.com", probePath: "/" },
52
+ Snyk: { domains: ["app.snyk.io"], defaultBaseUrl: "https://app.snyk.io", probePath: "/" },
53
+ Seismic: { domains: ["workday.seismic.com"], defaultBaseUrl: "https://workday.seismic.com", probePath: "/" },
54
+ Togglr: { domains: ["togglr.io"], defaultBaseUrl: "https://togglr.io", probePath: "/" },
55
+ "Togglr - Internal": { domains: ["togglr.io"], defaultBaseUrl: "https://togglr.io", probePath: "/" },
56
+ "Metrics Portal": { domains: ["metrics.workday.com"], defaultBaseUrl: "https://metrics.workday.com", probePath: "/" },
57
+ "Security Portal": { domains: ["security.workday.com"], defaultBaseUrl: "https://security.workday.com", probePath: "/" },
58
+ "Microsoft Office 365 Office Portal": { domains: ["office.com"], defaultBaseUrl: "https://www.office.com", probePath: "/" },
59
+ "Microsoft Outlook": { domains: ["outlook.office.com"], defaultBaseUrl: "https://outlook.office.com", probePath: "/" },
60
+ Mixpanel: { domains: ["mixpanel.com"], defaultBaseUrl: "https://mixpanel.com", probePath: "/" },
61
+ "Secure Code Warrior": { domains: ["securecodewarrior.com"], defaultBaseUrl: "https://portal.securecodewarrior.com", probePath: "/" },
62
+ "Proofpoint Security Education Platform": { domains: ["proofpoint.com"], defaultBaseUrl: "https://www.proofpoint.com", probePath: "/" },
63
+ "HackerRank For Work": { domains: ["hackerrank.com"], defaultBaseUrl: "https://www.hackerrank.com", probePath: "/" },
64
+ "Visitor Registration": { domains: ["envoy.com"], defaultBaseUrl: "https://envoy.com", probePath: "/" },
65
+ "Healthy Working": { domains: ["cardinus.com"], defaultBaseUrl: "https://www.cardinus.com", probePath: "/" },
66
+ Meetingselect: { domains: ["meetingselect.com"], defaultBaseUrl: "https://www.meetingselect.com", probePath: "/" },
67
+ EveryoneSocial: { domains: ["everyonesocial.com"], defaultBaseUrl: "https://everyonesocial.com", probePath: "/" },
68
+ Aperian: { domains: ["aperianglobal.com"], defaultBaseUrl: "https://www.aperianglobal.com", probePath: "/" },
69
+ "BT diagramming": { domains: ["lucid.co"], defaultBaseUrl: "https://lucid.co", probePath: "/" },
70
+ "Fragomen Nomadic": { domains: ["fragomen.com"], defaultBaseUrl: "https://www.fragomen.com", probePath: "/" },
71
+ "6120 Meeting Center Booking": { domains: ["briefingsource.com"], defaultBaseUrl: "https://www.briefingsource.com", probePath: "/" },
72
+ "WCP Dev Site": { domains: ["workday.com"], defaultBaseUrl: "https://developer.workday.com", probePath: "/" },
73
+ "Workday Procurement": { domains: ["workday.com"], defaultBaseUrl: "https://www.workday.com", probePath: "/" },
74
+ "Workday Travel Tool - US": { domains: ["workday.com"], defaultBaseUrl: "https://www.workday.com", probePath: "/" },
75
+ "Workday Policies": { domains: ["workday.com"], defaultBaseUrl: "https://www.workday.com", probePath: "/" },
76
+ "Workday Pattern Library": { domains: ["workday.com"], defaultBaseUrl: "https://canvas.workday.com", probePath: "/" },
77
+ "Canvas Design System": { domains: ["workday.com"], defaultBaseUrl: "https://canvas.workday.com", probePath: "/" },
78
+ "Global Records Retention Schedule": { domains: ["workday.com"], defaultBaseUrl: "https://www.workday.com", probePath: "/" },
79
+ "Digital Event Library": { domains: ["workday.com"], defaultBaseUrl: "https://www.workday.com", probePath: "/" },
80
+ "Employee Event Registration": { domains: ["workday.com"], defaultBaseUrl: "https://www.workday.com", probePath: "/" },
81
+ DevCon: { domains: ["workday.com"], defaultBaseUrl: "https://www.workday.com", probePath: "/" },
82
+ WOAH: { domains: ["workday.com"], defaultBaseUrl: "https://www.workday.com", probePath: "/" },
83
+ "VitalSource eBooks": { domains: ["vitalsource.com"], defaultBaseUrl: "https://www.vitalsource.com", probePath: "/" },
84
+ "P&T Planner": { domains: ["workday.com"], defaultBaseUrl: "https://www.workday.com", probePath: "/" },
85
+ "P&T Okta Password Check": { domains: ["workday.okta.com"], defaultBaseUrl: "https://workday.okta.com", probePath: "/" },
86
+ "INF-IDM": { domains: ["workday.okta.com"], defaultBaseUrl: "https://workday.okta.com", probePath: "/" },
87
+ ISD: { domains: ["workday.okta.com"], defaultBaseUrl: "https://workday.okta.com", probePath: "/", mode: "oidc-app" },
88
+ "SkyLab Portal": { domains: ["workday.okta.com"], defaultBaseUrl: "https://workday.okta.com", probePath: "/", mode: "oidc-app" },
89
+ "Prod LDAP Password Tool": { domains: ["workday.okta.com"], defaultBaseUrl: "https://workday.okta.com", probePath: "/", mode: "oidc-app" },
90
+ "PRM-Wallboard": { domains: ["workday.okta.com"], defaultBaseUrl: "https://workday.okta.com", probePath: "/", mode: "oidc-app" },
91
+ Osprey: { domains: ["workday.okta.com"], defaultBaseUrl: "https://workday.okta.com", probePath: "/", mode: "oidc-app" },
92
+ ArcPrime: { domains: ["workday.okta.com"], defaultBaseUrl: "https://workday.okta.com", probePath: "/", mode: "oidc-app" },
93
+ "Google Gemini": { domains: ["gemini.google.com"], defaultBaseUrl: "https://gemini.google.com", probePath: "/", mode: "bookmark" },
94
+ NotebookLM: { domains: ["notebooklm.google.com"], defaultBaseUrl: "https://notebooklm.google.com", probePath: "/", mode: "bookmark" },
95
+ Lovable: { domains: ["lovable.dev"], defaultBaseUrl: "https://lovable.dev", probePath: "/", mode: "bookmark" }
96
+ };
97
+
98
+ export function listOktaApps() {
99
+ return Object.entries(OKTA_USER_HOME_APPS).map(([name, app]) => ({
100
+ name,
101
+ readOnly: true,
102
+ ...app,
103
+ mode: app.mode ?? (app.serviceId ? "extension" : "cookie-http")
104
+ }));
105
+ }
106
+
107
+ export function getOktaApp(name) {
108
+ const app = OKTA_USER_HOME_APPS[name];
109
+ if (!app) {
110
+ throw new Error(`Unknown Okta app: ${name}`);
111
+ }
112
+ return { name, readOnly: true, ...app, mode: app.mode ?? (app.serviceId ? "extension" : "cookie-http") };
113
+ }
114
+
115
+ export function getOktaAppByServiceId(serviceId) {
116
+ const match = listOktaApps().find((app) => app.serviceId === serviceId);
117
+ return match ?? null;
118
+ }