@vellumai/credential-executor 0.4.55
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/Dockerfile +55 -0
- package/bun.lock +37 -0
- package/package.json +32 -0
- package/src/__tests__/command-executor.test.ts +1333 -0
- package/src/__tests__/command-validator.test.ts +708 -0
- package/src/__tests__/command-workspace.test.ts +997 -0
- package/src/__tests__/grant-store.test.ts +467 -0
- package/src/__tests__/http-executor.test.ts +1251 -0
- package/src/__tests__/http-policy.test.ts +970 -0
- package/src/__tests__/local-materializers.test.ts +826 -0
- package/src/__tests__/managed-materializers.test.ts +961 -0
- package/src/__tests__/toolstore.test.ts +539 -0
- package/src/__tests__/transport.test.ts +388 -0
- package/src/audit/store.ts +188 -0
- package/src/commands/auth-adapters.ts +169 -0
- package/src/commands/executor.ts +840 -0
- package/src/commands/output-scan.ts +157 -0
- package/src/commands/profiles.ts +282 -0
- package/src/commands/validator.ts +438 -0
- package/src/commands/workspace.ts +512 -0
- package/src/grants/index.ts +17 -0
- package/src/grants/persistent-store.ts +247 -0
- package/src/grants/rpc-handlers.ts +269 -0
- package/src/grants/temporary-store.ts +219 -0
- package/src/http/audit.ts +84 -0
- package/src/http/executor.ts +540 -0
- package/src/http/path-template.ts +179 -0
- package/src/http/policy.ts +256 -0
- package/src/http/response-filter.ts +233 -0
- package/src/index.ts +106 -0
- package/src/main.ts +263 -0
- package/src/managed-main.ts +420 -0
- package/src/materializers/local.ts +300 -0
- package/src/materializers/managed-platform.ts +270 -0
- package/src/paths.ts +137 -0
- package/src/server.ts +636 -0
- package/src/subjects/local.ts +177 -0
- package/src/subjects/managed.ts +290 -0
- package/src/toolstore/integrity.ts +94 -0
- package/src/toolstore/manifest.ts +154 -0
- package/src/toolstore/publish.ts +342 -0
- package/tsconfig.json +20 -0
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Output file scanner for CES workspace copyback.
|
|
3
|
+
*
|
|
4
|
+
* Before any command output file is copied back into the assistant-visible
|
|
5
|
+
* workspace, it is scanned for:
|
|
6
|
+
*
|
|
7
|
+
* 1. **Exact secret matches** — The file content is checked against a set
|
|
8
|
+
* of known secret values that were injected into the command environment.
|
|
9
|
+
* If any secret appears verbatim in the output, copyback is rejected.
|
|
10
|
+
*
|
|
11
|
+
* 2. **Auth-bearing config artifacts** — Common configuration file patterns
|
|
12
|
+
* that typically contain credentials (e.g. `.netrc`, AWS credentials files,
|
|
13
|
+
* GitHub token files) are detected by filename and content heuristics.
|
|
14
|
+
*
|
|
15
|
+
* Both checks are conservative: false positives are acceptable (the user can
|
|
16
|
+
* explicitly re-request the file), but false negatives are not.
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
// ---------------------------------------------------------------------------
|
|
20
|
+
// Types
|
|
21
|
+
// ---------------------------------------------------------------------------
|
|
22
|
+
|
|
23
|
+
export interface OutputScanResult {
|
|
24
|
+
/** Whether the file passed all scans and is safe to copy back. */
|
|
25
|
+
safe: boolean;
|
|
26
|
+
/** List of reasons the file was rejected (empty when safe). */
|
|
27
|
+
violations: string[];
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// ---------------------------------------------------------------------------
|
|
31
|
+
// Auth-bearing config artifact patterns
|
|
32
|
+
// ---------------------------------------------------------------------------
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Filenames (basenames) that are known to contain credentials in their
|
|
36
|
+
* standard format. Matched case-insensitively.
|
|
37
|
+
*/
|
|
38
|
+
const AUTH_BEARING_FILENAMES: ReadonlySet<string> = new Set([
|
|
39
|
+
".netrc",
|
|
40
|
+
".npmrc",
|
|
41
|
+
".pypirc",
|
|
42
|
+
".docker/config.json",
|
|
43
|
+
"credentials", // AWS ~/.aws/credentials
|
|
44
|
+
"config.json", // Docker, various
|
|
45
|
+
".git-credentials",
|
|
46
|
+
".env",
|
|
47
|
+
".env.local",
|
|
48
|
+
".env.production",
|
|
49
|
+
".env.development",
|
|
50
|
+
]);
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Content patterns that indicate auth-bearing config artifacts.
|
|
54
|
+
* Each entry is a regex tested against file content.
|
|
55
|
+
*/
|
|
56
|
+
const AUTH_BEARING_CONTENT_PATTERNS: ReadonlyArray<{
|
|
57
|
+
pattern: RegExp;
|
|
58
|
+
description: string;
|
|
59
|
+
}> = [
|
|
60
|
+
{
|
|
61
|
+
pattern: /machine\s+\S+\s+login\s+\S+\s+password\s+\S+/i,
|
|
62
|
+
description: "netrc-format credentials (machine/login/password)",
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
pattern: /\[default\]\s*\n\s*aws_access_key_id\s*=/i,
|
|
66
|
+
description: "AWS credentials file format",
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
pattern: /aws_secret_access_key\s*=\s*\S+/i,
|
|
70
|
+
description: "AWS secret access key in config",
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
pattern: /-----BEGIN\s+(RSA\s+)?PRIVATE\s+KEY-----/,
|
|
74
|
+
description: "PEM private key",
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
pattern: /-----BEGIN\s+OPENSSH\s+PRIVATE\s+KEY-----/,
|
|
78
|
+
description: "OpenSSH private key",
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
pattern: /"auth"\s*:\s*"[A-Za-z0-9+/=]{20,}"/,
|
|
82
|
+
description: "Docker registry auth token",
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
pattern: /\/\/[^:]+:_authToken\s*=\s*\S+/,
|
|
86
|
+
description: "npm registry auth token",
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
pattern: /password\s*=\s*\S+/i,
|
|
90
|
+
description: "Plain-text password in config file",
|
|
91
|
+
},
|
|
92
|
+
];
|
|
93
|
+
|
|
94
|
+
// ---------------------------------------------------------------------------
|
|
95
|
+
// Scanner
|
|
96
|
+
// ---------------------------------------------------------------------------
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Scan a file's content for secret leakage before allowing copyback.
|
|
100
|
+
*
|
|
101
|
+
* @param filename — The basename of the output file (used for artifact detection).
|
|
102
|
+
* @param content — The raw file content (string or Buffer).
|
|
103
|
+
* @param secrets — Set of known secret values that were injected into the
|
|
104
|
+
* command's environment. Each value is checked for verbatim
|
|
105
|
+
* presence in the file content.
|
|
106
|
+
*
|
|
107
|
+
* @returns A {@link OutputScanResult} indicating whether the file is safe.
|
|
108
|
+
*/
|
|
109
|
+
export function scanOutputFile(
|
|
110
|
+
filename: string,
|
|
111
|
+
content: string | Buffer,
|
|
112
|
+
secrets: ReadonlySet<string>,
|
|
113
|
+
): OutputScanResult {
|
|
114
|
+
const violations: string[] = [];
|
|
115
|
+
const contentStr =
|
|
116
|
+
typeof content === "string" ? content : content.toString("utf-8");
|
|
117
|
+
|
|
118
|
+
// -- Check 1: Exact secret matches
|
|
119
|
+
for (const secret of secrets) {
|
|
120
|
+
if (secret.length === 0) continue;
|
|
121
|
+
if (contentStr.includes(secret)) {
|
|
122
|
+
// Don't include the actual secret in the violation message
|
|
123
|
+
violations.push(
|
|
124
|
+
`File contains an exact match of a credential value ` +
|
|
125
|
+
`(${secret.length} chars). Secrets must not leak into command outputs.`,
|
|
126
|
+
);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// -- Check 2: Auth-bearing filename detection
|
|
131
|
+
const lowerFilename = filename.toLowerCase();
|
|
132
|
+
const basenameOnly = lowerFilename.includes("/")
|
|
133
|
+
? lowerFilename.slice(lowerFilename.lastIndexOf("/") + 1)
|
|
134
|
+
: lowerFilename;
|
|
135
|
+
|
|
136
|
+
if (AUTH_BEARING_FILENAMES.has(basenameOnly)) {
|
|
137
|
+
violations.push(
|
|
138
|
+
`Filename "${filename}" matches a known auth-bearing config artifact. ` +
|
|
139
|
+
`These files commonly contain credentials and cannot be copied back.`,
|
|
140
|
+
);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// -- Check 3: Auth-bearing content pattern detection
|
|
144
|
+
for (const { pattern, description } of AUTH_BEARING_CONTENT_PATTERNS) {
|
|
145
|
+
if (pattern.test(contentStr)) {
|
|
146
|
+
violations.push(
|
|
147
|
+
`File content matches auth-bearing pattern: ${description}. ` +
|
|
148
|
+
`Output files containing credential patterns cannot be copied back.`,
|
|
149
|
+
);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
return {
|
|
154
|
+
safe: violations.length === 0,
|
|
155
|
+
violations,
|
|
156
|
+
};
|
|
157
|
+
}
|
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Secure command profile manifest schema (v1).
|
|
3
|
+
*
|
|
4
|
+
* A secure command profile defines the complete execution boundary for a
|
|
5
|
+
* credential-bearing command. Profiles are manifest-driven — there is no
|
|
6
|
+
* default of "run any subcommand on this binary." Every allowed invocation
|
|
7
|
+
* must be declared explicitly.
|
|
8
|
+
*
|
|
9
|
+
* Manifest fields:
|
|
10
|
+
*
|
|
11
|
+
* - **bundleDigest** — SHA-256 digest of the command bundle (for
|
|
12
|
+
* integrity verification).
|
|
13
|
+
* - **bundleId** — Unique identifier for the command bundle
|
|
14
|
+
* (e.g. "gh-cli", "aws-cli").
|
|
15
|
+
* - **version** — Semantic version of the bundle.
|
|
16
|
+
* - **entrypoint** — Path to the executable within the bundle
|
|
17
|
+
* (e.g. "bin/gh").
|
|
18
|
+
* - **commandProfiles** — Map of named profiles, each declaring allowed
|
|
19
|
+
* argv grammar, denied subcommands, and network
|
|
20
|
+
* targets.
|
|
21
|
+
* - **authAdapter** — How credentials are injected (env_var,
|
|
22
|
+
* temp_file, or credential_process).
|
|
23
|
+
* - **egressMode** — Network egress enforcement mode. Must be
|
|
24
|
+
* `proxy_required` unless the command has no
|
|
25
|
+
* network needs.
|
|
26
|
+
* - **cleanConfigDirs** — List of config directories to mount as empty
|
|
27
|
+
* tmpfs (prevents the command from reading host
|
|
28
|
+
* config files that could contain secrets).
|
|
29
|
+
*/
|
|
30
|
+
|
|
31
|
+
import type { AuthAdapterConfig } from "./auth-adapters.js";
|
|
32
|
+
|
|
33
|
+
// ---------------------------------------------------------------------------
|
|
34
|
+
// Egress mode
|
|
35
|
+
// ---------------------------------------------------------------------------
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Network egress enforcement mode for a secure command profile.
|
|
39
|
+
*
|
|
40
|
+
* - `proxy_required` — All network traffic MUST route through the CES
|
|
41
|
+
* egress proxy. The command's environment is
|
|
42
|
+
* configured with HTTP_PROXY/HTTPS_PROXY. Direct
|
|
43
|
+
* connections are blocked.
|
|
44
|
+
* - `no_network` — The command has no network requirements. Any
|
|
45
|
+
* network access is blocked entirely.
|
|
46
|
+
*
|
|
47
|
+
* There is intentionally no "direct" or "unrestricted" mode. Commands
|
|
48
|
+
* that need network access must go through the egress proxy so CES can
|
|
49
|
+
* enforce credential injection and audit logging.
|
|
50
|
+
*/
|
|
51
|
+
export const EgressMode = {
|
|
52
|
+
ProxyRequired: "proxy_required",
|
|
53
|
+
NoNetwork: "no_network",
|
|
54
|
+
} as const;
|
|
55
|
+
|
|
56
|
+
export type EgressMode = (typeof EgressMode)[keyof typeof EgressMode];
|
|
57
|
+
|
|
58
|
+
/** All valid egress mode strings. */
|
|
59
|
+
export const EGRESS_MODES: readonly EgressMode[] = Object.values(
|
|
60
|
+
EgressMode,
|
|
61
|
+
) as EgressMode[];
|
|
62
|
+
|
|
63
|
+
// ---------------------------------------------------------------------------
|
|
64
|
+
// Allowed argv grammar
|
|
65
|
+
// ---------------------------------------------------------------------------
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Defines the allowed argument grammar for a command profile.
|
|
69
|
+
*
|
|
70
|
+
* Allowed patterns use a simple grammar:
|
|
71
|
+
* - Literal strings match exactly (e.g. "api", "--json")
|
|
72
|
+
* - `<param>` matches any single argument (positional placeholder)
|
|
73
|
+
* - `<param...>` matches one or more remaining arguments (rest placeholder)
|
|
74
|
+
*
|
|
75
|
+
* Example: `["api", "<endpoint>", "--method", "<method>"]` allows
|
|
76
|
+
* `gh api /repos --method GET` but not `gh auth login`.
|
|
77
|
+
*/
|
|
78
|
+
export interface AllowedArgvPattern {
|
|
79
|
+
/**
|
|
80
|
+
* Human-readable name for this pattern (e.g. "api-call", "list-repos").
|
|
81
|
+
* Used in audit logs and error messages.
|
|
82
|
+
*/
|
|
83
|
+
name: string;
|
|
84
|
+
/**
|
|
85
|
+
* Ordered sequence of argv tokens. Each token is either a literal
|
|
86
|
+
* string or a placeholder (`<name>` or `<name...>`).
|
|
87
|
+
*/
|
|
88
|
+
tokens: string[];
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// ---------------------------------------------------------------------------
|
|
92
|
+
// Network target allowlist
|
|
93
|
+
// ---------------------------------------------------------------------------
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Declares a network target that the command is allowed to contact.
|
|
97
|
+
*/
|
|
98
|
+
export interface AllowedNetworkTarget {
|
|
99
|
+
/** Host pattern (glob). E.g. "api.github.com", "*.amazonaws.com". */
|
|
100
|
+
hostPattern: string;
|
|
101
|
+
/** Allowed port(s). Null means any port. */
|
|
102
|
+
ports?: number[];
|
|
103
|
+
/** Allowed protocol(s). Defaults to ["https"]. */
|
|
104
|
+
protocols?: Array<"http" | "https">;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// ---------------------------------------------------------------------------
|
|
108
|
+
// Command profile (single named profile within a manifest)
|
|
109
|
+
// ---------------------------------------------------------------------------
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* A single named command profile within a manifest.
|
|
113
|
+
*
|
|
114
|
+
* Each profile defines a narrow slice of allowed behaviour for the command.
|
|
115
|
+
* A manifest may contain multiple profiles (e.g. "read-repos" and
|
|
116
|
+
* "create-issue" for the GitHub CLI).
|
|
117
|
+
*/
|
|
118
|
+
export interface CommandProfile {
|
|
119
|
+
/** Human-readable description of what this profile allows. */
|
|
120
|
+
description: string;
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Allowed argv patterns. The command is rejected unless its arguments
|
|
124
|
+
* match at least one pattern.
|
|
125
|
+
*/
|
|
126
|
+
allowedArgvPatterns: AllowedArgvPattern[];
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Subcommands that are explicitly denied even if they would otherwise
|
|
130
|
+
* match an argv pattern. This is a safety net against overly broad
|
|
131
|
+
* patterns.
|
|
132
|
+
*
|
|
133
|
+
* Each entry is matched against the first N argv tokens.
|
|
134
|
+
*/
|
|
135
|
+
deniedSubcommands: string[];
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Flags (argv tokens starting with `-`) that are explicitly denied.
|
|
139
|
+
* Matched literally (e.g. "--exec", "-e").
|
|
140
|
+
*/
|
|
141
|
+
deniedFlags?: string[];
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Network targets this profile is allowed to contact. Only relevant
|
|
145
|
+
* when egressMode is `proxy_required`.
|
|
146
|
+
*/
|
|
147
|
+
allowedNetworkTargets?: AllowedNetworkTarget[];
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// ---------------------------------------------------------------------------
|
|
151
|
+
// Secure command manifest (top-level)
|
|
152
|
+
// ---------------------------------------------------------------------------
|
|
153
|
+
|
|
154
|
+
/** Current manifest schema version. */
|
|
155
|
+
export const MANIFEST_SCHEMA_VERSION = "1" as const;
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* v1 secure command manifest.
|
|
159
|
+
*
|
|
160
|
+
* This is the top-level schema that defines a complete execution boundary
|
|
161
|
+
* for a credential-bearing command binary.
|
|
162
|
+
*/
|
|
163
|
+
export interface SecureCommandManifest {
|
|
164
|
+
/** Manifest schema version. Must be "1". */
|
|
165
|
+
schemaVersion: typeof MANIFEST_SCHEMA_VERSION;
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* SHA-256 hex digest of the command bundle. Used for integrity
|
|
169
|
+
* verification before execution.
|
|
170
|
+
*/
|
|
171
|
+
bundleDigest: string;
|
|
172
|
+
|
|
173
|
+
/** Unique identifier for the command bundle (e.g. "gh-cli"). */
|
|
174
|
+
bundleId: string;
|
|
175
|
+
|
|
176
|
+
/** Semantic version of the bundle. */
|
|
177
|
+
version: string;
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Path to the executable entrypoint within the bundle
|
|
181
|
+
* (e.g. "bin/gh", "bin/aws").
|
|
182
|
+
*/
|
|
183
|
+
entrypoint: string;
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Named command profiles. Each profile defines a narrow execution
|
|
187
|
+
* boundary. Keyed by profile name.
|
|
188
|
+
*/
|
|
189
|
+
commandProfiles: Record<string, CommandProfile>;
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Auth adapter configuration describing how credentials are
|
|
193
|
+
* materialised into the command's environment.
|
|
194
|
+
*/
|
|
195
|
+
authAdapter: AuthAdapterConfig;
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Network egress enforcement mode. Must be `proxy_required` for commands
|
|
199
|
+
* that contact the network, or `no_network` for offline-only commands.
|
|
200
|
+
*/
|
|
201
|
+
egressMode: EgressMode;
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* Config directories to mount as empty tmpfs during execution. Prevents
|
|
205
|
+
* the command from reading host config files that might contain secrets.
|
|
206
|
+
*
|
|
207
|
+
* Map from source path pattern to a description.
|
|
208
|
+
* E.g. `{ "~/.aws": "AWS CLI config", "~/.config/gh": "GitHub CLI config" }`.
|
|
209
|
+
*/
|
|
210
|
+
cleanConfigDirs?: Record<string, string>;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
// ---------------------------------------------------------------------------
|
|
214
|
+
// Denied binaries — structurally rejected as secure command profiles
|
|
215
|
+
// ---------------------------------------------------------------------------
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Binaries that are structurally banned from being registered as secure
|
|
219
|
+
* command profiles. These are generic HTTP clients, interpreters, and
|
|
220
|
+
* shell trampolines that would undermine the manifest-driven security
|
|
221
|
+
* model.
|
|
222
|
+
*
|
|
223
|
+
* This list is checked against the entrypoint basename (the last path
|
|
224
|
+
* segment) and against bundleId.
|
|
225
|
+
*/
|
|
226
|
+
export const DENIED_BINARIES: ReadonlySet<string> = new Set([
|
|
227
|
+
// Generic HTTP clients
|
|
228
|
+
"curl",
|
|
229
|
+
"wget",
|
|
230
|
+
"http", // httpie
|
|
231
|
+
"https", // httpie alias
|
|
232
|
+
"httpie",
|
|
233
|
+
|
|
234
|
+
// Interpreters
|
|
235
|
+
"python",
|
|
236
|
+
"python3",
|
|
237
|
+
"python3.10",
|
|
238
|
+
"python3.11",
|
|
239
|
+
"python3.12",
|
|
240
|
+
"python3.13",
|
|
241
|
+
"python3.14",
|
|
242
|
+
"node",
|
|
243
|
+
"bun",
|
|
244
|
+
"deno",
|
|
245
|
+
"ruby",
|
|
246
|
+
"perl",
|
|
247
|
+
"lua",
|
|
248
|
+
"php",
|
|
249
|
+
|
|
250
|
+
// Shell trampolines
|
|
251
|
+
"bash",
|
|
252
|
+
"sh",
|
|
253
|
+
"zsh",
|
|
254
|
+
"fish",
|
|
255
|
+
"dash",
|
|
256
|
+
"ksh",
|
|
257
|
+
"csh",
|
|
258
|
+
"tcsh",
|
|
259
|
+
"env", // /usr/bin/env can trampoline to any binary
|
|
260
|
+
"xargs", // can execute arbitrary commands
|
|
261
|
+
"exec",
|
|
262
|
+
"nohup",
|
|
263
|
+
"strace",
|
|
264
|
+
"ltrace",
|
|
265
|
+
]);
|
|
266
|
+
|
|
267
|
+
/**
|
|
268
|
+
* Returns the basename of a path (last segment after the last `/`).
|
|
269
|
+
*/
|
|
270
|
+
export function pathBasename(path: string): string {
|
|
271
|
+
const lastSlash = path.lastIndexOf("/");
|
|
272
|
+
return lastSlash === -1 ? path : path.slice(lastSlash + 1);
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
/**
|
|
276
|
+
* Check if a binary name (basename or full path) is in the denied set.
|
|
277
|
+
* Matches against the basename portion of the path.
|
|
278
|
+
*/
|
|
279
|
+
export function isDeniedBinary(binaryNameOrPath: string): boolean {
|
|
280
|
+
const basename = pathBasename(binaryNameOrPath);
|
|
281
|
+
return DENIED_BINARIES.has(basename);
|
|
282
|
+
}
|