@nuvlore/extension-access-okta-slack 0.1.1 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +4 -19
- package/vendor/extension-sso/LICENSE +0 -202
- package/vendor/extension-sso/README.md +0 -35
- package/vendor/extension-sso/commands/okta-login.md +0 -10
- package/vendor/extension-sso/package.json +0 -53
- package/vendor/extension-sso/skills/workday-okta-auth/SKILL.md +0 -20
- package/vendor/extension-sso/src/autoAuth.mjs +0 -25
- package/vendor/extension-sso/src/browserLogin.mjs +0 -1
- package/vendor/extension-sso/src/chromeCookies.mjs +0 -1
- package/vendor/extension-sso/src/cookieJar.mjs +0 -1
- package/vendor/extension-sso/src/extensionAccess.mjs +0 -173
- package/vendor/extension-sso/src/htmlSessionExtract.mjs +0 -1
- package/vendor/extension-sso/src/oktaAppAccess.mjs +0 -133
- package/vendor/extension-sso/src/oktaAppCatalog.mjs +0 -118
- package/vendor/extension-sso/src/oktaAppRead.mjs +0 -119
- package/vendor/extension-sso/src/oktaConfig.mjs +0 -12
- package/vendor/extension-sso/src/oktaSession.mjs +0 -32
- package/vendor/extension-sso/src/serviceOperations.mjs +0 -407
- package/vendor/extension-sso/src/serviceReadSearch.mjs +0 -395
- package/vendor/extension-sso/src/serviceReads.mjs +0 -109
- package/vendor/extension-sso/src/serviceRegistry.mjs +0 -497
- package/vendor/extension-sso/src/sessionAuth.mjs +0 -339
- package/vendor/extension-sso/src/sessionManager.mjs +0 -212
- package/vendor/extension-sso/src/sessionValidate.mjs +0 -74
- package/vendor/extension-sso/src/ssoConfig.mjs +0 -31
- package/vendor/extension-sso/src/ssoHttpRead.mjs +0 -292
- package/vendor/extension-sso/tools/extension-access-tools.shared.mjs +0 -16
- package/vendor/extension-sso/tools/okta-app-tools.shared.mjs +0 -5
- package/vendor/extension-sso/tools/okta-tools.shared.mjs +0 -18
- package/vendor/extension-sso/tools/workday_extension_read.mjs +0 -51
- package/vendor/extension-sso/tools/workday_extension_read_access.mjs +0 -65
- package/vendor/extension-sso/tools/workday_list_extension_access.mjs +0 -39
- package/vendor/extension-sso/tools/workday_list_okta_apps.mjs +0 -18
- package/vendor/extension-sso/tools/workday_list_service_operations.mjs +0 -41
- package/vendor/extension-sso/tools/workday_list_service_read_search_capabilities.mjs +0 -34
- package/vendor/extension-sso/tools/workday_list_services.mjs +0 -31
- package/vendor/extension-sso/tools/workday_okta_app_probe_all.mjs +0 -24
- package/vendor/extension-sso/tools/workday_okta_app_read.mjs +0 -30
- package/vendor/extension-sso/tools/workday_okta_app_read_access.mjs +0 -25
- package/vendor/extension-sso/tools/workday_okta_auth_header.mjs +0 -58
- package/vendor/extension-sso/tools/workday_okta_login.mjs +0 -65
- package/vendor/extension-sso/tools/workday_okta_open_app.mjs +0 -63
- package/vendor/extension-sso/tools/workday_okta_open_service.mjs +0 -63
- package/vendor/extension-sso/tools/workday_okta_status.mjs +0 -35
- package/vendor/extension-sso/tools/workday_service_auth.mjs +0 -65
- package/vendor/extension-sso/tools/workday_service_operation_read.mjs +0 -51
- package/vendor/extension-sso/tools/workday_service_read.mjs +0 -56
- package/vendor/extension-sso/tools/workday_service_search.mjs +0 -62
- package/vendor/extension-sso/tools/workday_sso_cookie_header.mjs +0 -59
- package/vendor/extension-sso/vendor/extension-browser-sso/LICENSE +0 -202
- package/vendor/extension-sso/vendor/extension-browser-sso/README.md +0 -16
- package/vendor/extension-sso/vendor/extension-browser-sso/package.json +0 -47
- package/vendor/extension-sso/vendor/extension-browser-sso/src/autoAuth.mjs +0 -47
- package/vendor/extension-sso/vendor/extension-browser-sso/src/browserHttpRead.mjs +0 -76
- package/vendor/extension-sso/vendor/extension-browser-sso/src/browserLogin.mjs +0 -24
- package/vendor/extension-sso/vendor/extension-browser-sso/src/chromeCookies.mjs +0 -192
- package/vendor/extension-sso/vendor/extension-browser-sso/src/cookieJar.mjs +0 -132
- package/vendor/extension-sso/vendor/extension-browser-sso/src/extensions/toolkit/devops-data-paths.mjs +0 -222
- package/vendor/extension-sso/vendor/extension-browser-sso/src/extensions/toolkit/devops-diagnostics.mjs +0 -440
- package/vendor/extension-sso/vendor/extension-browser-sso/src/extensions/toolkit/enterprise-api-read.mjs +0 -180
- package/vendor/extension-sso/vendor/extension-browser-sso/src/extensions/toolkit/read-only-command-pack.mjs +0 -1
- package/vendor/extension-sso/vendor/extension-browser-sso/src/extensions/toolkit/read-only-plan.mjs +0 -45
- package/vendor/extension-sso/vendor/extension-browser-sso/src/extensions/toolkit/read-only-shell-policy.d.mts +0 -26
- package/vendor/extension-sso/vendor/extension-browser-sso/src/extensions/toolkit/read-only-shell-policy.mjs +0 -170
- package/vendor/extension-sso/vendor/extension-browser-sso/src/htmlSessionExtract.mjs +0 -64
- package/vendor/extension-sso/vendor/extension-read-only-toolkit/LICENSE +0 -202
- package/vendor/extension-sso/vendor/extension-read-only-toolkit/README.md +0 -29
- package/vendor/extension-sso/vendor/extension-read-only-toolkit/package.json +0 -43
- package/vendor/extension-sso/vendor/extension-read-only-toolkit/src/devops-data-paths.mjs +0 -222
- package/vendor/extension-sso/vendor/extension-read-only-toolkit/src/devops-diagnostics.mjs +0 -440
- package/vendor/extension-sso/vendor/extension-read-only-toolkit/src/enterprise-api-read.mjs +0 -180
- package/vendor/extension-sso/vendor/extension-read-only-toolkit/src/read-only-command-pack.mjs +0 -1
- package/vendor/extension-sso/vendor/extension-read-only-toolkit/src/read-only-plan.mjs +0 -45
- package/vendor/extension-sso/vendor/extension-read-only-toolkit/src/read-only-shell-policy.d.mts +0 -26
- package/vendor/extension-sso/vendor/extension-read-only-toolkit/src/read-only-shell-policy.mjs +0 -170
|
@@ -1,180 +0,0 @@
|
|
|
1
|
-
import { execFile } from "node:child_process";
|
|
2
|
-
import { promisify } from "node:util";
|
|
3
|
-
import { assertNonHtmlApiResponse } from "./devops-diagnostics.mjs";
|
|
4
|
-
|
|
5
|
-
const execFileAsync = promisify(execFile);
|
|
6
|
-
|
|
7
|
-
export function normalizeBaseUrl(value) {
|
|
8
|
-
const raw = String(value || "").trim();
|
|
9
|
-
if (!raw) return "";
|
|
10
|
-
try {
|
|
11
|
-
const url = new URL(raw);
|
|
12
|
-
url.pathname = url.pathname.replace(/\/+$/, "");
|
|
13
|
-
url.search = "";
|
|
14
|
-
url.hash = "";
|
|
15
|
-
return url.toString().replace(/\/+$/, "");
|
|
16
|
-
} catch {
|
|
17
|
-
return "";
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
export function appendQueryValue(searchParams, key, value) {
|
|
22
|
-
if (Array.isArray(value)) {
|
|
23
|
-
for (const item of value) appendQueryValue(searchParams, key, item);
|
|
24
|
-
return;
|
|
25
|
-
}
|
|
26
|
-
if (value === undefined || value === null) return;
|
|
27
|
-
searchParams.append(key, String(value));
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
export function buildRequestUrl(baseUrl, requestPath, query) {
|
|
31
|
-
const url = new URL(`${baseUrl}${requestPath}`);
|
|
32
|
-
for (const [key, value] of Object.entries(query || {})) {
|
|
33
|
-
if (key) appendQueryValue(url.searchParams, key, value);
|
|
34
|
-
}
|
|
35
|
-
return url;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
export function extractTokenFromKeychainSecret(rawSecret = "") {
|
|
39
|
-
const text = typeof rawSecret === "string" ? rawSecret.trim() : "";
|
|
40
|
-
if (!text) return "";
|
|
41
|
-
try {
|
|
42
|
-
const parsed = JSON.parse(text);
|
|
43
|
-
return typeof parsed?.token === "string" ? parsed.token.trim() : "";
|
|
44
|
-
} catch {
|
|
45
|
-
return text;
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
export async function readTokenFromKeychain({ execFileImpl = execFileAsync, keychainService, keychainAccount }) {
|
|
50
|
-
try {
|
|
51
|
-
const result = await execFileImpl("/usr/bin/security", [
|
|
52
|
-
"find-generic-password",
|
|
53
|
-
"-s",
|
|
54
|
-
keychainService,
|
|
55
|
-
"-a",
|
|
56
|
-
keychainAccount,
|
|
57
|
-
"-w"
|
|
58
|
-
], { maxBuffer: 1024 * 1024 });
|
|
59
|
-
return extractTokenFromKeychainSecret(String(result?.stdout || ""));
|
|
60
|
-
} catch {
|
|
61
|
-
return "";
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
export function parseResponseBody(text) {
|
|
66
|
-
try {
|
|
67
|
-
return JSON.parse(text);
|
|
68
|
-
} catch {
|
|
69
|
-
return String(text || "");
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
export class KeychainBearerAuthProvider {
|
|
74
|
-
constructor(options = {}) {
|
|
75
|
-
this.mode = "keychain";
|
|
76
|
-
this.execFileImpl = options.execFileImpl || execFileAsync;
|
|
77
|
-
this.keychainService = options.keychainService;
|
|
78
|
-
this.keychainAccount = options.keychainAccount;
|
|
79
|
-
this.authorizationHeader = options.authorizationHeader || ((token) => `Bearer ${token}`);
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
async buildHeaders() {
|
|
83
|
-
const token = await readTokenFromKeychain({
|
|
84
|
-
execFileImpl: this.execFileImpl,
|
|
85
|
-
keychainService: this.keychainService,
|
|
86
|
-
keychainAccount: this.keychainAccount
|
|
87
|
-
});
|
|
88
|
-
if (!token) {
|
|
89
|
-
throw new Error(
|
|
90
|
-
`Keychain token missing for ${this.keychainService}/${this.keychainAccount}. Save the personal access token in Keychain.`
|
|
91
|
-
);
|
|
92
|
-
}
|
|
93
|
-
return { authorization: this.authorizationHeader(token) };
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
/** Cookie SSO auth — inject `resolveCookieHeader(input)` from @nuvlore/extension-browser-sso. */
|
|
98
|
-
export class CookieSsoAuthProvider {
|
|
99
|
-
constructor(options = {}) {
|
|
100
|
-
this.mode = "cookie-sso";
|
|
101
|
-
this.resolveCookieHeader = options.resolveCookieHeader;
|
|
102
|
-
if (typeof this.resolveCookieHeader !== "function") {
|
|
103
|
-
throw new Error("CookieSsoAuthProvider requires resolveCookieHeader(input) async function.");
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
async buildHeaders(input = {}) {
|
|
108
|
-
const cookie = await this.resolveCookieHeader(input);
|
|
109
|
-
if (!cookie) {
|
|
110
|
-
throw new Error("Browser SSO cookie header is missing. Open the service in Chrome via Okta and retry.");
|
|
111
|
-
}
|
|
112
|
-
return { cookie };
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
export class EnterpriseApiReadService {
|
|
117
|
-
constructor(options = {}) {
|
|
118
|
-
this.fetchImpl = options.fetchImpl || globalThis.fetch;
|
|
119
|
-
this.execFileImpl = options.execFileImpl || execFileAsync;
|
|
120
|
-
this.serviceName = options.serviceName;
|
|
121
|
-
this.defaultBaseUrl = options.defaultBaseUrl;
|
|
122
|
-
this.defaultUserAgent = options.defaultUserAgent;
|
|
123
|
-
this.keychainService = options.keychainService;
|
|
124
|
-
this.keychainAccount = options.keychainAccount;
|
|
125
|
-
this.normalizePath = options.normalizePath;
|
|
126
|
-
this.accept = options.accept || "application/json";
|
|
127
|
-
this.extraHeaders = options.extraHeaders || {};
|
|
128
|
-
this.authorizationHeader = options.authorizationHeader || ((token) => `Bearer ${token}`);
|
|
129
|
-
this.formatErrorPayload = options.formatErrorPayload;
|
|
130
|
-
this.includeMethodInPayload = options.includeMethodInPayload === true;
|
|
131
|
-
this.transformPayload = options.transformPayload || ((payload) => payload);
|
|
132
|
-
this.authProvider =
|
|
133
|
-
options.authProvider ??
|
|
134
|
-
new KeychainBearerAuthProvider({
|
|
135
|
-
execFileImpl: this.execFileImpl,
|
|
136
|
-
keychainService: this.keychainService,
|
|
137
|
-
keychainAccount: this.keychainAccount,
|
|
138
|
-
authorizationHeader: this.authorizationHeader
|
|
139
|
-
});
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
async invoke(input = {}) {
|
|
143
|
-
if (typeof this.fetchImpl !== "function") {
|
|
144
|
-
throw new Error(`Fetch API is unavailable for ${this.serviceName} requests.`);
|
|
145
|
-
}
|
|
146
|
-
const baseUrl = normalizeBaseUrl(input.baseUrl || this.defaultBaseUrl);
|
|
147
|
-
if (!baseUrl) {
|
|
148
|
-
throw new Error(`${this.serviceName} base URL is missing or invalid. Expected something like ${this.defaultBaseUrl}.`);
|
|
149
|
-
}
|
|
150
|
-
const requestPath = this.normalizePath(input.restPath || input.path);
|
|
151
|
-
const url = buildRequestUrl(baseUrl, requestPath, input.query);
|
|
152
|
-
const authHeaders = await this.authProvider.buildHeaders(input);
|
|
153
|
-
const response = await this.fetchImpl(url, {
|
|
154
|
-
method: "GET",
|
|
155
|
-
headers: {
|
|
156
|
-
accept: this.accept,
|
|
157
|
-
"user-agent": this.defaultUserAgent,
|
|
158
|
-
...this.extraHeaders,
|
|
159
|
-
...authHeaders,
|
|
160
|
-
...(input.headers ?? {})
|
|
161
|
-
}
|
|
162
|
-
});
|
|
163
|
-
const text = await response.text();
|
|
164
|
-
assertNonHtmlApiResponse(this.serviceName, text);
|
|
165
|
-
const payload = parseResponseBody(text);
|
|
166
|
-
if (!response.ok) {
|
|
167
|
-
throw new Error(`${this.serviceName} request failed with status ${response.status}: ${this.formatErrorPayload(payload)}.`);
|
|
168
|
-
}
|
|
169
|
-
const output = {
|
|
170
|
-
baseUrl,
|
|
171
|
-
restPath: requestPath,
|
|
172
|
-
path: requestPath,
|
|
173
|
-
url: url.toString(),
|
|
174
|
-
status: response.status,
|
|
175
|
-
data: this.transformPayload(payload)
|
|
176
|
-
};
|
|
177
|
-
if (this.includeMethodInPayload) output.method = "GET";
|
|
178
|
-
return JSON.stringify(output, null, 2);
|
|
179
|
-
}
|
|
180
|
-
}
|
package/vendor/extension-sso/vendor/extension-read-only-toolkit/src/read-only-command-pack.mjs
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from "./read-only-plan.mjs";
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
export function shellQuote(value) {
|
|
2
|
-
return `'${String(value).replaceAll("'", "'\\''")}'`;
|
|
3
|
-
}
|
|
4
|
-
|
|
5
|
-
export function remoteCommandInput({ host, command, timeoutMs = 60_000 }) {
|
|
6
|
-
return {
|
|
7
|
-
targetType: "ssh",
|
|
8
|
-
host,
|
|
9
|
-
command,
|
|
10
|
-
timeoutMs
|
|
11
|
-
};
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export class ReadOnlyStep {
|
|
15
|
-
constructor({ id, purpose, command, expectedEvidence }) {
|
|
16
|
-
this.id = id;
|
|
17
|
-
this.purpose = purpose;
|
|
18
|
-
this.command = command;
|
|
19
|
-
this.expectedEvidence = expectedEvidence;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
toMarkdown() {
|
|
23
|
-
return [
|
|
24
|
-
`### ${this.id}`,
|
|
25
|
-
`Purpose: ${this.purpose}`,
|
|
26
|
-
"",
|
|
27
|
-
"```bash",
|
|
28
|
-
this.command,
|
|
29
|
-
"```",
|
|
30
|
-
"",
|
|
31
|
-
`Evidence to capture: ${this.expectedEvidence}`
|
|
32
|
-
].join("\n");
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
toJson() {
|
|
36
|
-
return {
|
|
37
|
-
id: this.id,
|
|
38
|
-
purpose: this.purpose,
|
|
39
|
-
command: this.command,
|
|
40
|
-
expectedEvidence: this.expectedEvidence
|
|
41
|
-
};
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
export class ReadOnlyCommand extends ReadOnlyStep {}
|
package/vendor/extension-sso/vendor/extension-read-only-toolkit/src/read-only-shell-policy.d.mts
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
export type ReadOnlyValidation = {
|
|
2
|
-
allowed: boolean;
|
|
3
|
-
reason: string;
|
|
4
|
-
};
|
|
5
|
-
|
|
6
|
-
export type ReadOnlyPolicyConfig = {
|
|
7
|
-
extraReadOnlyCommandPatterns?: RegExp[];
|
|
8
|
-
};
|
|
9
|
-
|
|
10
|
-
export const READ_ONLY_ALLOWED_TOOLS: readonly string[];
|
|
11
|
-
export const READ_ONLY_DISALLOWED_TOOLS: readonly string[];
|
|
12
|
-
export const MUTATING_SHELL_TOKENS: RegExp[];
|
|
13
|
-
export const READ_ONLY_COMMAND_PATTERNS: RegExp[];
|
|
14
|
-
|
|
15
|
-
export class ReadOnlyShellPolicy {
|
|
16
|
-
constructor(config?: ReadOnlyPolicyConfig);
|
|
17
|
-
validate(command: string): ReadOnlyValidation;
|
|
18
|
-
readOnlyPatterns(): RegExp[];
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
export class ReadOnlyPolicyDescription {
|
|
22
|
-
text(): string;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
export function isReadOnlyShellCommand(command: string, config?: ReadOnlyPolicyConfig): ReadOnlyValidation;
|
|
26
|
-
export function describeReadOnlyPolicy(): string;
|
package/vendor/extension-sso/vendor/extension-read-only-toolkit/src/read-only-shell-policy.mjs
DELETED
|
@@ -1,170 +0,0 @@
|
|
|
1
|
-
export const READ_ONLY_ALLOWED_TOOLS = [
|
|
2
|
-
"Read",
|
|
3
|
-
"Glob",
|
|
4
|
-
"Grep"
|
|
5
|
-
];
|
|
6
|
-
|
|
7
|
-
export const READ_ONLY_DISALLOWED_TOOLS = [
|
|
8
|
-
"Agent",
|
|
9
|
-
"Task",
|
|
10
|
-
"TaskCreate",
|
|
11
|
-
"Write",
|
|
12
|
-
"Edit",
|
|
13
|
-
"NotebookEdit",
|
|
14
|
-
"TodoWrite",
|
|
15
|
-
"ExitPlanMode",
|
|
16
|
-
"EnterWorktree",
|
|
17
|
-
"WebFetch",
|
|
18
|
-
"WebSearch",
|
|
19
|
-
"AskUserQuestion"
|
|
20
|
-
];
|
|
21
|
-
|
|
22
|
-
export const MUTATING_SHELL_TOKENS = [
|
|
23
|
-
/\bapply\b/i,
|
|
24
|
-
/\bcreate\b/i,
|
|
25
|
-
/\bdelete\b/i,
|
|
26
|
-
/\bdestroy\b/i,
|
|
27
|
-
/\bedit\b/i,
|
|
28
|
-
/\binstall\b/i,
|
|
29
|
-
/\bpatch\b/i,
|
|
30
|
-
/\bpush\b/i,
|
|
31
|
-
/\breplace\b/i,
|
|
32
|
-
/\brestart\b/i,
|
|
33
|
-
/\brollout\s+(restart|undo)\b/i,
|
|
34
|
-
/\brm\b/i,
|
|
35
|
-
/\bscale\b/i,
|
|
36
|
-
/\bset\b/i,
|
|
37
|
-
/\bstart\b/i,
|
|
38
|
-
/\bstop\b/i,
|
|
39
|
-
/\btaint\b/i,
|
|
40
|
-
/\buntaint\b/i,
|
|
41
|
-
/\bupgrade\b/i,
|
|
42
|
-
/\bwrite\b/i,
|
|
43
|
-
/\bchmod\b/i,
|
|
44
|
-
/\bchown\b/i,
|
|
45
|
-
/\bmv\b/i,
|
|
46
|
-
/\bcp\b/i,
|
|
47
|
-
/\bmkdir\b/i,
|
|
48
|
-
/\btouch\b/i,
|
|
49
|
-
/\btee\b/i,
|
|
50
|
-
/\bcurl\b.*\|\s*(sh|bash)\b/i,
|
|
51
|
-
/\bwget\b.*\|\s*(sh|bash)\b/i,
|
|
52
|
-
/(^|[^<])>(?!\s*&\d)/,
|
|
53
|
-
/>>/,
|
|
54
|
-
/\|\s*(xargs\s+)?(sh|bash|kubectl\s+apply|terraform\s+apply|helm\s+upgrade|rm|tee)\b/i,
|
|
55
|
-
/(^|[^&|]);\s*/,
|
|
56
|
-
/&&|\|\|/,
|
|
57
|
-
/`|\$\(/,
|
|
58
|
-
/\b--write\b/i,
|
|
59
|
-
/\b--force\b/i,
|
|
60
|
-
/\b--yes\b|\b-y\b/i
|
|
61
|
-
];
|
|
62
|
-
|
|
63
|
-
export const READ_ONLY_COMMAND_PATTERNS = [
|
|
64
|
-
/^\s*pwd\s*$/,
|
|
65
|
-
/^\s*ls(\s|$)/,
|
|
66
|
-
/^\s*find\s+/,
|
|
67
|
-
/^\s*(rg|grep)\s+/,
|
|
68
|
-
/^\s*(cat|head|tail|sed|awk|wc)\s+/,
|
|
69
|
-
/^\s*curl\s+-k\s+-sS\s+-o\s+\/dev\/null\s+-w\s+'[A-Za-z0-9_=%{}:./ -]+\\n'\s+https:\/\/[A-Za-z0-9_.:-]+\/[A-Za-z0-9_./:@%+=,~-]+(\s|$)/,
|
|
70
|
-
/^\s*hostname(\s|$)/,
|
|
71
|
-
/^\s*command\s+-v\s+/,
|
|
72
|
-
/^\s*klist(\s|$)/,
|
|
73
|
-
/^\s*git\s+(status|diff|log|show|branch|remote|rev-parse|describe|ls-files)(\s|$)/,
|
|
74
|
-
/^\s*kubectl\s+(get|describe|logs|top|api-resources|api-versions|explain|version|cluster-info|config\s+(current-context|get-contexts|view))(\s|$)/,
|
|
75
|
-
/^\s*kubectl\s+exec\s+-n\s+airflow\s+(?:pod\/)?[A-Za-z0-9._:@%/-]+(?:\s+-c\s+[A-Za-z0-9._:@%/-]+)?\s+--\s+airflow\s+dags\s+list-runs\s+-d\s+[A-Za-z0-9_.:@/-]+(?:\s+--no-backfill)?(?:\s+--output\s+(?:json|table|yaml|plain))?(?:\s+\|\s+head\s+-\d+)?\s*$/,
|
|
76
|
-
/^\s*kubectl\s+exec\s+-n\s+airflow\s+(?:pod\/)?[A-Za-z0-9._:@%/-]+(?:\s+-c\s+[A-Za-z0-9._:@%/-]+)?\s+--\s+airflow\s+tasks\s+states-for-dag-run\s+[A-Za-z0-9_.:@/-]+\s+[A-Za-z0-9_.:@+=,~%/-]+(?:\s+--output\s+(?:json|table|yaml|plain))?(?:\s+\|\s+head\s+-\d+)?\s*$/,
|
|
77
|
-
/^\s*kubectl\s+exec\s+-n\s+airflow\s+(?:pod\/)?[A-Za-z0-9._:@%/-]+(?:\s+-c\s+[A-Za-z0-9._:@%/-]+)?\s+--\s+airflow\s+tasks\s+logs\s+[A-Za-z0-9_.:@/-]+\s+[A-Za-z0-9_.:@/-]+\s+[A-Za-z0-9_.:@+=,~%/-]+\s+--try-number\s+\d+\s+\|\s+head\s+-\d+\s*$/,
|
|
78
|
-
/^\s*kubectl\s+exec\s+-n\s+airflow\s+(?:pod\/)?[A-Za-z0-9._:@%/-]+(?:\s+-c\s+[A-Za-z0-9._:@%/-]+)?\s+--\s+airflow\s+tasks\s+render\s+[A-Za-z0-9_.:@/-]+\s+[A-Za-z0-9_.:@/-]+\s+[A-Za-z0-9_.:@+=,~%/-]+\s+\|\s+head\s+-\d+\s*$/,
|
|
79
|
-
/^\s*kubectl\s+exec\s+-n\s+airflow\s+(?:pod\/)?[A-Za-z0-9._:@%/-]+(?:\s+-c\s+[A-Za-z0-9._:@%/-]+)?\s+--\s+cat\s+\/(?:(?:data|hadoop\/disk2)\/workday-bds-airflow|data\/airflow)\/logs\/[A-Za-z0-9_.:@+=,~%/-]+(?:\s+\|\s+head\s+-\d+)?\s*$/,
|
|
80
|
-
/^\s*kubectl\s+exec\s+-n\s+airflow\s+(?:pod\/)?[A-Za-z0-9._:@%/-]+(?:\s+-c\s+[A-Za-z0-9._:@%/-]+)?\s+--\s+grep\s+-E\s+'[A-Za-z0-9_.:@+=,~%|/-]+'\s+\/(?:(?:data|hadoop\/disk2)\/workday-bds-airflow|data\/airflow)\/logs\/[A-Za-z0-9_.:@+=,~%/-]+(?:\s+\|\s+tail\s+-n\s+\d+)?\s*$/,
|
|
81
|
-
/^\s*kubectl\s+exec\s+-n\s+airflow\s+(?:pod\/)?[A-Za-z0-9._:@%/-]+(?:\s+-c\s+[A-Za-z0-9._:@%/-]+)?\s+--\s+grep\s+-E\s+'[A-Za-z0-9_.:@+=,~%|/-]+'\s+\/usr\/local\/airflow\/(?:airflow_s3_config\.json|dags\/[A-Za-z0-9_.:@+=,~%/-]+)(?:\s+\|\s+(?:head|tail)\s+-\d+)?\s*$/,
|
|
82
|
-
/^\s*kubectl\s+exec\s+-n\s+airflow\s+(?:pod\/)?[A-Za-z0-9._:@%/-]+(?:\s+-c\s+[A-Za-z0-9._:@%/-]+)?\s+--\s+printenv\s+\|\s+grep\s+-E\s+'\^\(AWS_\|GOOGLE_\|GOOGLE_APPLICATION_CREDENTIALS\|HADOOP_\|HADOOP_CONF_DIR\|AIRFLOW_S3_CONFIG_PATH\)'\s+\|\s+sed\s+-E\s+'s\/=\.\*\/=\[present\]\/'\s+\|\s+head\s+-\d+\s*$/,
|
|
83
|
-
/^\s*kubectl\s+exec\s+-n\s+airflow\s+(?:pod\/)?[A-Za-z0-9._:@%/-]+(?:\s+-c\s+[A-Za-z0-9._:@%/-]+)?\s+--\s+printenv\s+HADOOP_CREDENTIAL_PROVIDER_PATH\s*$/,
|
|
84
|
-
/^\s*kubectl\s+exec\s+-n\s+airflow\s+(?:pod\/)?[A-Za-z0-9._:@%/-]+(?:\s+-c\s+[A-Za-z0-9._:@%/-]+)?\s+--\s+hadoop\s+credential\s+list\s+\|\s+head\s+-\d+\s*$/,
|
|
85
|
-
/^\s*kubectl\s+exec\s+-n\s+airflow\s+(?:pod\/)?[A-Za-z0-9._:@%/-]+(?:\s+-c\s+[A-Za-z0-9._:@%/-]+)?\s+--\s+grep\s+-h\s+-E\s+'fs\.s3a\.aws\.credentials\.provider\|fs\.s3a\.endpoint\|fs\.s3a\.impl\|google\.cloud\.auth'\s+\/etc\/hadoop\/conf\/(?:core-site|hdfs-site|mapred-site|yarn-site)\.xml(?:\s+\/etc\/hadoop\/conf\/(?:core-site|hdfs-site|mapred-site|yarn-site)\.xml)*\s+\|\s+head\s+-\d+\s*$/,
|
|
86
|
-
/^\s*kubectl\s+exec\s+-n\s+airflow\s+(?:pod\/)?[A-Za-z0-9._:@%/-]+(?:\s+-c\s+[A-Za-z0-9._:@%/-]+)?\s+--\s+cat\s+\/usr\/local\/airflow\/(?:airflow_s3_config\.json|dags\/[A-Za-z0-9_.:@+=,~%/-]+)(?:\s+\|\s+head\s+-\d+)?\s*$/,
|
|
87
|
-
/^\s*kubectl\s+exec\s+-n\s+airflow\s+(?:pod\/)?[A-Za-z0-9._:@%/-]+(?:\s+-c\s+[A-Za-z0-9._:@%/-]+)?\s+--\s+hadoop\s+fs\s+-(?:ls|du|count|stat|test)(?:\s+-d)?\s+s3a:\/\/[A-Za-z0-9][A-Za-z0-9_.-]*[A-Za-z0-9](?:\/[A-Za-z0-9_.:@+=,~%/-]*)?(?:\s+\|\s+head\s+-\d+)?\s*$/,
|
|
88
|
-
/^\s*kcsb\s+(get|describe|logs|top|api-resources|api-versions|explain|version|cluster-info|config\s+(current-context|get-contexts|view))(\s|$)/,
|
|
89
|
-
/^\s*kinit\s+-kt\s+\/[A-Za-z0-9._/-]+\s+[A-Za-z0-9_.@/-]+(\s|$)/,
|
|
90
|
-
/^\s*yarn\s+application\s+-status\s+application_[0-9]+_[0-9]+(\s|$)/,
|
|
91
|
-
/^\s*yarn\s+logs\s+-applicationId\s+application_[0-9]+_[0-9]+(\s|$)/,
|
|
92
|
-
/^\s*yarn\s+node\s+-status\s+(?!-)[A-Za-z0-9._:@%-]+:45454(\s|$)/,
|
|
93
|
-
/^\s*hdfs\s+crypto\s+-listZones(\s|$)/,
|
|
94
|
-
/^\s*hdfs\s+dfs\s+-(ls|du|find|cat|tail|test|count|stat)\s+/,
|
|
95
|
-
/^\s*hdfs\s+dfsadmin\s+-report(\s|$)/,
|
|
96
|
-
/^\s*hadoop\s+fs\s+-(ls|cat|head|du|count|stat|test|text)(\s|$)/,
|
|
97
|
-
/^\s*helm\s+(list|status|history|get|version|repo\s+list)(\s|$)/,
|
|
98
|
-
/^\s*aws\s+(?:--profile\s+\S+\s+)?(?:--region\s+\S+\s+)?sts\s+get-caller-identity(\s|$)/,
|
|
99
|
-
/^\s*aws\s+(?:--profile\s+\S+\s+)?(?:--region\s+\S+\s+)?[a-z0-9-]+\s+(describe|list|get|head)-[a-z0-9-]+(\s|$)/,
|
|
100
|
-
/^\s*aws\s+(?:--profile\s+\S+\s+)?(?:--region\s+\S+\s+)?s3\s+ls(\s|$)/,
|
|
101
|
-
/^\s*gcloud\s+(?:--project=\S+\s+)?(?:--account=\S+\s+)?auth\s+list(\s|$)/,
|
|
102
|
-
/^\s*gcloud\s+(?:--project=\S+\s+)?(?:--account=\S+\s+)?config\s+list(\s|$)/,
|
|
103
|
-
/^\s*gcloud\s+(?:--project=\S+\s+)?(?:--account=\S+\s+)?projects\s+(describe|get-iam-policy)(\s|$)/,
|
|
104
|
-
/^\s*gcloud\s+(?:--project=\S+\s+)?(?:--account=\S+\s+)?[a-z0-9-]+(?:\s+[a-z0-9-]+)*\s+(list|describe|read)(\s|$)/,
|
|
105
|
-
/^\s*gcloud\s+storage\s+(buckets|objects)\s+list(\s|$)/,
|
|
106
|
-
/^\s*terraform\s+(version|show|state\s+list|state\s+show|providers|workspace\s+show|output)(\s|$)/,
|
|
107
|
-
/^\s*docker\s+(ps|images|logs|inspect|stats|version|info)(\s|$)/,
|
|
108
|
-
/^\s*(df|du|free|uptime|uname|whoami|id|date|env|printenv)(\s|$)/,
|
|
109
|
-
/^\s*journalctl\s+-k\s+--since\s+/,
|
|
110
|
-
/^\s*(systemctl|journalctl)\s+(status|-u|--unit)(\s|$)/
|
|
111
|
-
];
|
|
112
|
-
|
|
113
|
-
export class ReadOnlyShellPolicy {
|
|
114
|
-
constructor(config = {}) {
|
|
115
|
-
this.config = config;
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
validate(command) {
|
|
119
|
-
const normalized = String(command ?? "").trim();
|
|
120
|
-
|
|
121
|
-
if (!normalized) {
|
|
122
|
-
return { allowed: false, reason: "empty shell command" };
|
|
123
|
-
}
|
|
124
|
-
if (normalized.includes("\n") || normalized.includes("\r")) {
|
|
125
|
-
return { allowed: false, reason: "multi-line shell commands are not allowed" };
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
const mutatingToken = MUTATING_SHELL_TOKENS.find((token) => token.test(normalized));
|
|
129
|
-
if (mutatingToken) {
|
|
130
|
-
return {
|
|
131
|
-
allowed: false,
|
|
132
|
-
reason: `shell command contains mutating or high-risk syntax: ${mutatingToken.source}`
|
|
133
|
-
};
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
if (this.readOnlyPatterns().some((pattern) => pattern.test(normalized))) {
|
|
137
|
-
return { allowed: true, reason: "matches read-only command allowlist" };
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
return { allowed: false, reason: "command is not in the read-only allowlist" };
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
readOnlyPatterns() {
|
|
144
|
-
return [
|
|
145
|
-
...READ_ONLY_COMMAND_PATTERNS,
|
|
146
|
-
...(this.config.extraReadOnlyCommandPatterns ?? [])
|
|
147
|
-
];
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
export class ReadOnlyPolicyDescription {
|
|
152
|
-
text() {
|
|
153
|
-
return [
|
|
154
|
-
"Read-only DevOps policy:",
|
|
155
|
-
`- Auto-approved tools: ${READ_ONLY_ALLOWED_TOOLS.join(", ")}`,
|
|
156
|
-
`- Always denied tools: ${READ_ONLY_DISALLOWED_TOOLS.join(", ")}`,
|
|
157
|
-
"- Bash: denied by default; only explicit read-only command patterns are allowed.",
|
|
158
|
-
"- Filesystem sandbox: enabled with denyWrite on all paths.",
|
|
159
|
-
"- Permission mode: dontAsk, so unapproved tools fail closed."
|
|
160
|
-
].join("\n");
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
export function isReadOnlyShellCommand(command, config = {}) {
|
|
165
|
-
return new ReadOnlyShellPolicy(config).validate(command);
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
export function describeReadOnlyPolicy() {
|
|
169
|
-
return new ReadOnlyPolicyDescription().text();
|
|
170
|
-
}
|