@unbrained/pm-cli 2026.5.10 → 2026.5.11
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/.claude-plugin/marketplace.json +4 -4
- package/.pi/README.md +10 -1
- package/.pi/agents/pm-triage-agent.md +19 -0
- package/.pi/agents/pm-verification-agent.md +21 -0
- package/.pi/chains/pm-native-delivery.chain.md +11 -0
- package/.pi/extensions/pm-cli/index.js +276 -36
- package/.pi/skills/pm-native/SKILL.md +6 -2
- package/CHANGELOG.md +7 -0
- package/README.md +9 -1
- package/dist/cli/argv-utils.d.ts +5 -0
- package/dist/cli/argv-utils.js +34 -0
- package/dist/cli/argv-utils.js.map +1 -0
- package/dist/cli/bootstrap-args.d.ts +15 -0
- package/dist/cli/bootstrap-args.js +211 -0
- package/dist/cli/bootstrap-args.js.map +1 -1
- package/dist/cli/commander-usage.js +109 -3
- package/dist/cli/commander-usage.js.map +1 -1
- package/dist/cli/commands/completion.js +7 -3
- package/dist/cli/commands/completion.js.map +1 -1
- package/dist/cli/commands/contracts.d.ts +19 -0
- package/dist/cli/commands/contracts.js +33 -1
- package/dist/cli/commands/contracts.js.map +1 -1
- package/dist/cli/commands/create.js +112 -51
- package/dist/cli/commands/create.js.map +1 -1
- package/dist/cli/commands/docs.js +9 -2
- package/dist/cli/commands/docs.js.map +1 -1
- package/dist/cli/commands/extension.d.ts +3 -1
- package/dist/cli/commands/extension.js +174 -2
- package/dist/cli/commands/extension.js.map +1 -1
- package/dist/cli/commands/files.js +9 -2
- package/dist/cli/commands/files.js.map +1 -1
- package/dist/cli/commands/init.d.ts +2 -0
- package/dist/cli/commands/init.js +21 -1
- package/dist/cli/commands/init.js.map +1 -1
- package/dist/cli/commands/metadata-normalizers.d.ts +4 -0
- package/dist/cli/commands/metadata-normalizers.js +37 -0
- package/dist/cli/commands/metadata-normalizers.js.map +1 -0
- package/dist/cli/commands/reindex.js +173 -135
- package/dist/cli/commands/reindex.js.map +1 -1
- package/dist/cli/commands/search.js +16 -6
- package/dist/cli/commands/search.js.map +1 -1
- package/dist/cli/commands/test.js +9 -2
- package/dist/cli/commands/test.js.map +1 -1
- package/dist/cli/commands/update.js +70 -39
- package/dist/cli/commands/update.js.map +1 -1
- package/dist/cli/error-guidance.d.ts +9 -1
- package/dist/cli/error-guidance.js +147 -6
- package/dist/cli/error-guidance.js.map +1 -1
- package/dist/cli/help-json-payload.js +11 -1
- package/dist/cli/help-json-payload.js.map +1 -1
- package/dist/cli/main.js +69 -6
- package/dist/cli/main.js.map +1 -1
- package/dist/cli/register-setup.js +14 -0
- package/dist/cli/register-setup.js.map +1 -1
- package/dist/cli/telemetry-flush.d.ts +2 -0
- package/dist/cli/telemetry-flush.js +4 -0
- package/dist/cli/telemetry-flush.js.map +1 -0
- package/dist/cli.js +1 -2
- package/dist/cli.js.map +1 -1
- package/dist/core/extensions/extension-types.d.ts +72 -0
- package/dist/core/extensions/extension-types.js +24 -0
- package/dist/core/extensions/extension-types.js.map +1 -1
- package/dist/core/extensions/loader.d.ts +1 -0
- package/dist/core/extensions/loader.js +766 -7
- package/dist/core/extensions/loader.js.map +1 -1
- package/dist/core/lock/lock.js +2 -0
- package/dist/core/lock/lock.js.map +1 -1
- package/dist/core/sentry/instrument.d.ts +15 -0
- package/dist/core/sentry/instrument.js +35 -3
- package/dist/core/sentry/instrument.js.map +1 -1
- package/dist/core/shared/constants.js +20 -0
- package/dist/core/shared/constants.js.map +1 -1
- package/dist/core/shared/errors.d.ts +8 -0
- package/dist/core/shared/errors.js.map +1 -1
- package/dist/core/shared/levenshtein.d.ts +1 -0
- package/dist/core/shared/levenshtein.js +37 -0
- package/dist/core/shared/levenshtein.js.map +1 -0
- package/dist/core/store/paths.js +34 -1
- package/dist/core/store/paths.js.map +1 -1
- package/dist/core/store/settings.js +210 -1
- package/dist/core/store/settings.js.map +1 -1
- package/dist/core/telemetry/runtime.d.ts +1 -0
- package/dist/core/telemetry/runtime.js +102 -3
- package/dist/core/telemetry/runtime.js.map +1 -1
- package/dist/mcp/server.js +3 -1
- package/dist/mcp/server.js.map +1 -1
- package/dist/pi/native.js +57 -4
- package/dist/pi/native.js.map +1 -1
- package/dist/sdk/cli-contracts.d.ts +21 -1
- package/dist/sdk/cli-contracts.js +250 -0
- package/dist/sdk/cli-contracts.js.map +1 -1
- package/dist/sdk/index.d.ts +12 -1
- package/dist/sdk/index.js +8 -1
- package/dist/sdk/index.js.map +1 -1
- package/dist/types.d.ts +41 -0
- package/dist/types.js.map +1 -1
- package/docs/CLAUDE_CODE_PLUGIN.md +39 -0
- package/docs/EXTENSIONS.md +687 -0
- package/docs/MIGRATION_CLI_SIMPLIFICATION.md +64 -0
- package/docs/PI_PACKAGE.md +95 -10
- package/docs/SDK.md +441 -0
- package/docs/examples/ci/github-actions-pm-extension-gate.yml +53 -0
- package/docs/examples/ci/gitlab-ci-pm-extension-gate.yml +41 -0
- package/docs/examples/ci/jenkins-pm-extension-gate.Jenkinsfile +45 -0
- package/docs/examples/policy-restricted-extension/README.md +74 -0
- package/docs/examples/policy-restricted-extension/index.js +21 -0
- package/docs/examples/policy-restricted-extension/manifest.json +21 -0
- package/docs/examples/policy-restricted-extension/package.json +8 -0
- package/docs/examples/sdk-app-embedding/README.md +39 -0
- package/docs/examples/sdk-app-embedding/package.json +9 -0
- package/docs/examples/sdk-app-embedding/run-embedded-pm.mjs +61 -0
- package/docs/examples/sdk-contract-consumer/README.md +57 -0
- package/docs/examples/sdk-contract-consumer/inspect-contracts.mjs +47 -0
- package/docs/examples/sdk-contract-consumer/package.json +10 -0
- package/docs/examples/starter-extension/README.md +57 -42
- package/docs/examples/starter-extension/manifest.json +15 -0
- package/marketplace.json +3 -3
- package/package.json +1 -1
- package/plugins/pm-cli-claude/.claude-plugin/plugin.json +2 -2
- package/plugins/pm-cli-claude/README.md +55 -14
- package/plugins/pm-cli-claude/agents/pm-delivery-chain.md +88 -0
- package/plugins/pm-cli-claude/agents/pm-triage-agent.md +83 -0
- package/plugins/pm-cli-claude/agents/pm-verification-agent.md +88 -0
- package/plugins/pm-cli-claude/hooks/session-start.mjs +87 -22
|
@@ -3,7 +3,7 @@ import path from "node:path";
|
|
|
3
3
|
import { pathToFileURL } from "node:url";
|
|
4
4
|
import { pathExists } from "../fs/fs-utils.js";
|
|
5
5
|
import { resolveGlobalPmRoot } from "../store/paths.js";
|
|
6
|
-
import { KNOWN_EXTENSION_CAPABILITIES, EXTENSION_CAPABILITY_CONTRACT_VERSION, EXTENSION_CAPABILITY_LEGACY_ALIASES, } from "./extension-types.js";
|
|
6
|
+
import { KNOWN_EXTENSION_CAPABILITIES, KNOWN_EXTENSION_POLICY_MODES, KNOWN_EXTENSION_POLICY_SURFACES, KNOWN_EXTENSION_SANDBOX_PROFILES, KNOWN_EXTENSION_TRUST_MODES, EXTENSION_CAPABILITY_CONTRACT_VERSION, EXTENSION_CAPABILITY_LEGACY_ALIASES, } from "./extension-types.js";
|
|
7
7
|
export * from "./extension-types.js";
|
|
8
8
|
const DEFAULT_EXTENSION_PRIORITY = 100;
|
|
9
9
|
/* Types now in extension-types.ts - re-exported via `export * from "./extension-types.js"` above */
|
|
@@ -16,6 +16,517 @@ function isKnownExtensionCapability(value) {
|
|
|
16
16
|
function collectUnknownExtensionCapabilities(capabilities) {
|
|
17
17
|
return capabilities.filter((capability) => !isKnownExtensionCapability(capability));
|
|
18
18
|
}
|
|
19
|
+
const DEFAULT_EXTENSION_POLICY = Object.freeze({
|
|
20
|
+
mode: "off",
|
|
21
|
+
trust_mode: "off",
|
|
22
|
+
require_provenance: false,
|
|
23
|
+
trusted_extensions: [],
|
|
24
|
+
default_sandbox_profile: "none",
|
|
25
|
+
allowed_extensions: [],
|
|
26
|
+
blocked_extensions: [],
|
|
27
|
+
allowed_capabilities: [],
|
|
28
|
+
blocked_capabilities: [],
|
|
29
|
+
allowed_surfaces: [],
|
|
30
|
+
blocked_surfaces: [],
|
|
31
|
+
allowed_commands: [],
|
|
32
|
+
blocked_commands: [],
|
|
33
|
+
allowed_actions: [],
|
|
34
|
+
blocked_actions: [],
|
|
35
|
+
allowed_services: [],
|
|
36
|
+
blocked_services: [],
|
|
37
|
+
extension_overrides: [],
|
|
38
|
+
});
|
|
39
|
+
let extensionReloadEpoch = 0;
|
|
40
|
+
export function nextExtensionReloadToken(seed = Date.now()) {
|
|
41
|
+
extensionReloadEpoch += 1;
|
|
42
|
+
return `${extensionReloadEpoch}-${seed}`;
|
|
43
|
+
}
|
|
44
|
+
function normalizePolicyName(value) {
|
|
45
|
+
if (typeof value !== "string") {
|
|
46
|
+
return "";
|
|
47
|
+
}
|
|
48
|
+
return value.trim().toLowerCase();
|
|
49
|
+
}
|
|
50
|
+
function normalizePolicyStringSet(values) {
|
|
51
|
+
return new Set((values ?? [])
|
|
52
|
+
.map((value) => value.trim().toLowerCase())
|
|
53
|
+
.filter((value) => value.length > 0));
|
|
54
|
+
}
|
|
55
|
+
function normalizePolicySurfaceToken(value) {
|
|
56
|
+
const normalized = value.trim().toLowerCase();
|
|
57
|
+
if (normalized.length === 0) {
|
|
58
|
+
return "";
|
|
59
|
+
}
|
|
60
|
+
const segments = normalized
|
|
61
|
+
.split(/[.:/]/)
|
|
62
|
+
.map((segment) => segment.replace(/[\s_-]+/g, ""))
|
|
63
|
+
.filter((segment) => segment.length > 0);
|
|
64
|
+
if (segments.length === 0) {
|
|
65
|
+
return "";
|
|
66
|
+
}
|
|
67
|
+
if (segments.length === 1) {
|
|
68
|
+
return segments[0];
|
|
69
|
+
}
|
|
70
|
+
return `${segments[0]}.${segments.slice(1).join("")}`;
|
|
71
|
+
}
|
|
72
|
+
function normalizePolicySurfaceSet(values) {
|
|
73
|
+
return new Set((values ?? [])
|
|
74
|
+
.map((value) => normalizePolicySurfaceToken(value))
|
|
75
|
+
.filter((value) => value.length > 0));
|
|
76
|
+
}
|
|
77
|
+
function normalizePolicyMode(value) {
|
|
78
|
+
const normalized = normalizePolicyName(value);
|
|
79
|
+
if (KNOWN_EXTENSION_POLICY_MODES.includes(normalized)) {
|
|
80
|
+
return normalized;
|
|
81
|
+
}
|
|
82
|
+
return "off";
|
|
83
|
+
}
|
|
84
|
+
function normalizePolicyTrustMode(value) {
|
|
85
|
+
const normalized = normalizePolicyName(value);
|
|
86
|
+
if (KNOWN_EXTENSION_TRUST_MODES.includes(normalized)) {
|
|
87
|
+
return normalized;
|
|
88
|
+
}
|
|
89
|
+
return "off";
|
|
90
|
+
}
|
|
91
|
+
function normalizePolicySandboxProfile(value) {
|
|
92
|
+
const normalized = normalizePolicyName(value);
|
|
93
|
+
if (KNOWN_EXTENSION_SANDBOX_PROFILES.includes(normalized)) {
|
|
94
|
+
return normalized;
|
|
95
|
+
}
|
|
96
|
+
return "none";
|
|
97
|
+
}
|
|
98
|
+
function toSortedList(values) {
|
|
99
|
+
return [...new Set(values)].sort((left, right) => left.localeCompare(right));
|
|
100
|
+
}
|
|
101
|
+
function normalizeExtensionPolicy(settings) {
|
|
102
|
+
const policy = settings.extensions.policy;
|
|
103
|
+
const mode = normalizePolicyMode(policy?.mode);
|
|
104
|
+
const trustMode = normalizePolicyTrustMode(policy?.trust_mode);
|
|
105
|
+
const requireProvenance = policy?.require_provenance === true;
|
|
106
|
+
const trustedExtensions = normalizePolicyStringSet(policy?.trusted_extensions);
|
|
107
|
+
const defaultSandboxProfile = normalizePolicySandboxProfile(policy?.default_sandbox_profile);
|
|
108
|
+
const allowedExtensions = normalizePolicyStringSet(policy?.allowed_extensions);
|
|
109
|
+
const blockedExtensions = normalizePolicyStringSet(policy?.blocked_extensions);
|
|
110
|
+
const allowedCapabilities = normalizePolicyStringSet(policy?.allowed_capabilities);
|
|
111
|
+
const blockedCapabilities = normalizePolicyStringSet(policy?.blocked_capabilities);
|
|
112
|
+
const allowedSurfaces = normalizePolicySurfaceSet(policy?.allowed_surfaces);
|
|
113
|
+
const blockedSurfaces = normalizePolicySurfaceSet(policy?.blocked_surfaces);
|
|
114
|
+
const allowedCommands = normalizePolicyStringSet(policy?.allowed_commands);
|
|
115
|
+
const blockedCommands = normalizePolicyStringSet(policy?.blocked_commands);
|
|
116
|
+
const allowedActions = normalizePolicyStringSet(policy?.allowed_actions);
|
|
117
|
+
const blockedActions = normalizePolicyStringSet(policy?.blocked_actions);
|
|
118
|
+
const allowedServices = normalizePolicyStringSet(policy?.allowed_services);
|
|
119
|
+
const blockedServices = normalizePolicyStringSet(policy?.blocked_services);
|
|
120
|
+
const overridesByName = new Map();
|
|
121
|
+
for (const rawOverride of policy?.extension_overrides ?? []) {
|
|
122
|
+
const name = normalizePolicyName(rawOverride.name);
|
|
123
|
+
if (name.length === 0) {
|
|
124
|
+
continue;
|
|
125
|
+
}
|
|
126
|
+
overridesByName.set(name, {
|
|
127
|
+
name,
|
|
128
|
+
disabled: rawOverride.disabled === true,
|
|
129
|
+
requireTrusted: rawOverride.require_trusted === true,
|
|
130
|
+
requireProvenance: rawOverride.require_provenance === true,
|
|
131
|
+
sandboxProfile: rawOverride.sandbox_profile !== undefined
|
|
132
|
+
? normalizePolicySandboxProfile(rawOverride.sandbox_profile)
|
|
133
|
+
: undefined,
|
|
134
|
+
allowedCapabilities: normalizePolicyStringSet(rawOverride.allowed_capabilities),
|
|
135
|
+
blockedCapabilities: normalizePolicyStringSet(rawOverride.blocked_capabilities),
|
|
136
|
+
allowedSurfaces: normalizePolicySurfaceSet(rawOverride.allowed_surfaces),
|
|
137
|
+
blockedSurfaces: normalizePolicySurfaceSet(rawOverride.blocked_surfaces),
|
|
138
|
+
allowedCommands: normalizePolicyStringSet(rawOverride.allowed_commands),
|
|
139
|
+
blockedCommands: normalizePolicyStringSet(rawOverride.blocked_commands),
|
|
140
|
+
allowedActions: normalizePolicyStringSet(rawOverride.allowed_actions),
|
|
141
|
+
blockedActions: normalizePolicyStringSet(rawOverride.blocked_actions),
|
|
142
|
+
allowedServices: normalizePolicyStringSet(rawOverride.allowed_services),
|
|
143
|
+
blockedServices: normalizePolicyStringSet(rawOverride.blocked_services),
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
const warnings = [];
|
|
147
|
+
for (const capability of toSortedList([...allowedCapabilities, ...blockedCapabilities])) {
|
|
148
|
+
if (!isKnownExtensionCapability(capability)) {
|
|
149
|
+
warnings.push(`extension_policy_unknown_capability:${capability}`);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
for (const override of [...overridesByName.values()].sort((left, right) => left.name.localeCompare(right.name))) {
|
|
153
|
+
for (const capability of toSortedList([...override.allowedCapabilities, ...override.blockedCapabilities])) {
|
|
154
|
+
if (!isKnownExtensionCapability(capability)) {
|
|
155
|
+
warnings.push(`extension_policy_unknown_capability:${override.name}:${capability}`);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
const knownSurfaces = new Set(KNOWN_EXTENSION_POLICY_SURFACES);
|
|
160
|
+
for (const surface of toSortedList([...allowedSurfaces, ...blockedSurfaces])) {
|
|
161
|
+
if (!knownSurfaces.has(surface)) {
|
|
162
|
+
warnings.push(`extension_policy_unknown_surface:${surface}`);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
for (const override of [...overridesByName.values()].sort((left, right) => left.name.localeCompare(right.name))) {
|
|
166
|
+
for (const surface of toSortedList([...override.allowedSurfaces, ...override.blockedSurfaces])) {
|
|
167
|
+
if (!knownSurfaces.has(surface)) {
|
|
168
|
+
warnings.push(`extension_policy_unknown_surface:${override.name}:${surface}`);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
return {
|
|
173
|
+
mode,
|
|
174
|
+
trustMode,
|
|
175
|
+
requireProvenance,
|
|
176
|
+
trustedExtensions,
|
|
177
|
+
defaultSandboxProfile,
|
|
178
|
+
allowedExtensions,
|
|
179
|
+
blockedExtensions,
|
|
180
|
+
allowedCapabilities,
|
|
181
|
+
blockedCapabilities,
|
|
182
|
+
allowedSurfaces,
|
|
183
|
+
blockedSurfaces,
|
|
184
|
+
allowedCommands,
|
|
185
|
+
blockedCommands,
|
|
186
|
+
allowedActions,
|
|
187
|
+
blockedActions,
|
|
188
|
+
allowedServices,
|
|
189
|
+
blockedServices,
|
|
190
|
+
overridesByName,
|
|
191
|
+
warnings: [...new Set(warnings)].sort((left, right) => left.localeCompare(right)),
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
function serializeExtensionPolicy(policy) {
|
|
195
|
+
const overrides = [...policy.overridesByName.values()]
|
|
196
|
+
.sort((left, right) => left.name.localeCompare(right.name))
|
|
197
|
+
.map((override) => ({
|
|
198
|
+
name: override.name,
|
|
199
|
+
...(override.disabled ? { disabled: true } : {}),
|
|
200
|
+
...(override.requireTrusted ? { require_trusted: true } : {}),
|
|
201
|
+
...(override.requireProvenance ? { require_provenance: true } : {}),
|
|
202
|
+
...(override.sandboxProfile ? { sandbox_profile: override.sandboxProfile } : {}),
|
|
203
|
+
...(override.allowedCapabilities.size > 0 ? { allowed_capabilities: toSortedList(override.allowedCapabilities) } : {}),
|
|
204
|
+
...(override.blockedCapabilities.size > 0 ? { blocked_capabilities: toSortedList(override.blockedCapabilities) } : {}),
|
|
205
|
+
...(override.allowedSurfaces.size > 0 ? { allowed_surfaces: toSortedList(override.allowedSurfaces) } : {}),
|
|
206
|
+
...(override.blockedSurfaces.size > 0 ? { blocked_surfaces: toSortedList(override.blockedSurfaces) } : {}),
|
|
207
|
+
...(override.allowedCommands.size > 0 ? { allowed_commands: toSortedList(override.allowedCommands) } : {}),
|
|
208
|
+
...(override.blockedCommands.size > 0 ? { blocked_commands: toSortedList(override.blockedCommands) } : {}),
|
|
209
|
+
...(override.allowedActions.size > 0 ? { allowed_actions: toSortedList(override.allowedActions) } : {}),
|
|
210
|
+
...(override.blockedActions.size > 0 ? { blocked_actions: toSortedList(override.blockedActions) } : {}),
|
|
211
|
+
...(override.allowedServices.size > 0 ? { allowed_services: toSortedList(override.allowedServices) } : {}),
|
|
212
|
+
...(override.blockedServices.size > 0 ? { blocked_services: toSortedList(override.blockedServices) } : {}),
|
|
213
|
+
}));
|
|
214
|
+
return {
|
|
215
|
+
mode: policy.mode,
|
|
216
|
+
trust_mode: policy.trustMode,
|
|
217
|
+
require_provenance: policy.requireProvenance,
|
|
218
|
+
trusted_extensions: toSortedList(policy.trustedExtensions),
|
|
219
|
+
default_sandbox_profile: policy.defaultSandboxProfile,
|
|
220
|
+
allowed_extensions: toSortedList(policy.allowedExtensions),
|
|
221
|
+
blocked_extensions: toSortedList(policy.blockedExtensions),
|
|
222
|
+
allowed_capabilities: toSortedList(policy.allowedCapabilities),
|
|
223
|
+
blocked_capabilities: toSortedList(policy.blockedCapabilities),
|
|
224
|
+
allowed_surfaces: toSortedList(policy.allowedSurfaces),
|
|
225
|
+
blocked_surfaces: toSortedList(policy.blockedSurfaces),
|
|
226
|
+
allowed_commands: toSortedList(policy.allowedCommands),
|
|
227
|
+
blocked_commands: toSortedList(policy.blockedCommands),
|
|
228
|
+
allowed_actions: toSortedList(policy.allowedActions),
|
|
229
|
+
blocked_actions: toSortedList(policy.blockedActions),
|
|
230
|
+
allowed_services: toSortedList(policy.allowedServices),
|
|
231
|
+
blocked_services: toSortedList(policy.blockedServices),
|
|
232
|
+
extension_overrides: overrides,
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
function hydrateExtensionPolicy(policy) {
|
|
236
|
+
const overridesByName = new Map();
|
|
237
|
+
for (const rawOverride of policy.extension_overrides ?? []) {
|
|
238
|
+
const name = normalizePolicyName(rawOverride.name);
|
|
239
|
+
if (name.length === 0) {
|
|
240
|
+
continue;
|
|
241
|
+
}
|
|
242
|
+
overridesByName.set(name, {
|
|
243
|
+
name,
|
|
244
|
+
disabled: rawOverride.disabled === true,
|
|
245
|
+
requireTrusted: rawOverride.require_trusted === true,
|
|
246
|
+
requireProvenance: rawOverride.require_provenance === true,
|
|
247
|
+
sandboxProfile: rawOverride.sandbox_profile !== undefined
|
|
248
|
+
? normalizePolicySandboxProfile(rawOverride.sandbox_profile)
|
|
249
|
+
: undefined,
|
|
250
|
+
allowedCapabilities: normalizePolicyStringSet(rawOverride.allowed_capabilities),
|
|
251
|
+
blockedCapabilities: normalizePolicyStringSet(rawOverride.blocked_capabilities),
|
|
252
|
+
allowedSurfaces: normalizePolicySurfaceSet(rawOverride.allowed_surfaces),
|
|
253
|
+
blockedSurfaces: normalizePolicySurfaceSet(rawOverride.blocked_surfaces),
|
|
254
|
+
allowedCommands: normalizePolicyStringSet(rawOverride.allowed_commands),
|
|
255
|
+
blockedCommands: normalizePolicyStringSet(rawOverride.blocked_commands),
|
|
256
|
+
allowedActions: normalizePolicyStringSet(rawOverride.allowed_actions),
|
|
257
|
+
blockedActions: normalizePolicyStringSet(rawOverride.blocked_actions),
|
|
258
|
+
allowedServices: normalizePolicyStringSet(rawOverride.allowed_services),
|
|
259
|
+
blockedServices: normalizePolicyStringSet(rawOverride.blocked_services),
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
return {
|
|
263
|
+
mode: normalizePolicyMode(policy.mode),
|
|
264
|
+
trustMode: normalizePolicyTrustMode(policy.trust_mode),
|
|
265
|
+
requireProvenance: policy.require_provenance === true,
|
|
266
|
+
trustedExtensions: normalizePolicyStringSet(policy.trusted_extensions),
|
|
267
|
+
defaultSandboxProfile: normalizePolicySandboxProfile(policy.default_sandbox_profile),
|
|
268
|
+
allowedExtensions: normalizePolicyStringSet(policy.allowed_extensions),
|
|
269
|
+
blockedExtensions: normalizePolicyStringSet(policy.blocked_extensions),
|
|
270
|
+
allowedCapabilities: normalizePolicyStringSet(policy.allowed_capabilities),
|
|
271
|
+
blockedCapabilities: normalizePolicyStringSet(policy.blocked_capabilities),
|
|
272
|
+
allowedSurfaces: normalizePolicySurfaceSet(policy.allowed_surfaces),
|
|
273
|
+
blockedSurfaces: normalizePolicySurfaceSet(policy.blocked_surfaces),
|
|
274
|
+
allowedCommands: normalizePolicyStringSet(policy.allowed_commands),
|
|
275
|
+
blockedCommands: normalizePolicyStringSet(policy.blocked_commands),
|
|
276
|
+
allowedActions: normalizePolicyStringSet(policy.allowed_actions),
|
|
277
|
+
blockedActions: normalizePolicyStringSet(policy.blocked_actions),
|
|
278
|
+
allowedServices: normalizePolicyStringSet(policy.allowed_services),
|
|
279
|
+
blockedServices: normalizePolicyStringSet(policy.blocked_services),
|
|
280
|
+
overridesByName,
|
|
281
|
+
warnings: [],
|
|
282
|
+
};
|
|
283
|
+
}
|
|
284
|
+
function resolvePolicyOverride(policy, extensionName) {
|
|
285
|
+
return policy.overridesByName.get(normalizePolicyName(extensionName)) ?? null;
|
|
286
|
+
}
|
|
287
|
+
function evaluatePolicySet(allowed, blocked, value, notAllowlistedReason, blockedReason) {
|
|
288
|
+
if (blocked.has(value)) {
|
|
289
|
+
return blockedReason;
|
|
290
|
+
}
|
|
291
|
+
if (allowed.size > 0 && !allowed.has(value)) {
|
|
292
|
+
return notAllowlistedReason;
|
|
293
|
+
}
|
|
294
|
+
return null;
|
|
295
|
+
}
|
|
296
|
+
function resolvePolicyCapabilityReason(policy, extension, capability) {
|
|
297
|
+
const normalizedCapability = capability.trim().toLowerCase();
|
|
298
|
+
const override = resolvePolicyOverride(policy, extension.name);
|
|
299
|
+
const allowed = override && override.allowedCapabilities.size > 0 ? override.allowedCapabilities : policy.allowedCapabilities;
|
|
300
|
+
const blocked = new Set([
|
|
301
|
+
...policy.blockedCapabilities,
|
|
302
|
+
...(override ? override.blockedCapabilities : []),
|
|
303
|
+
]);
|
|
304
|
+
return evaluatePolicySet(allowed, blocked, normalizedCapability, "capability_not_allowlisted", "capability_blocked");
|
|
305
|
+
}
|
|
306
|
+
function resolvePolicySurfaceReason(policy, extension, surface) {
|
|
307
|
+
const override = resolvePolicyOverride(policy, extension.name);
|
|
308
|
+
const allowed = override && override.allowedSurfaces.size > 0 ? override.allowedSurfaces : policy.allowedSurfaces;
|
|
309
|
+
const blocked = new Set([
|
|
310
|
+
...policy.blockedSurfaces,
|
|
311
|
+
...(override ? override.blockedSurfaces : []),
|
|
312
|
+
]);
|
|
313
|
+
return evaluatePolicySet(allowed, blocked, surface, "surface_not_allowlisted", "surface_blocked");
|
|
314
|
+
}
|
|
315
|
+
function resolvePolicyCommandReason(policy, extension, command) {
|
|
316
|
+
const normalizedCommand = normalizeCommandName(command);
|
|
317
|
+
if (normalizedCommand.length === 0) {
|
|
318
|
+
return null;
|
|
319
|
+
}
|
|
320
|
+
const override = resolvePolicyOverride(policy, extension.name);
|
|
321
|
+
const allowed = override && override.allowedCommands.size > 0 ? override.allowedCommands : policy.allowedCommands;
|
|
322
|
+
const blocked = new Set([
|
|
323
|
+
...policy.blockedCommands,
|
|
324
|
+
...(override ? override.blockedCommands : []),
|
|
325
|
+
]);
|
|
326
|
+
return evaluatePolicySet(allowed, blocked, normalizedCommand, "command_not_allowlisted", "command_blocked");
|
|
327
|
+
}
|
|
328
|
+
function resolvePolicyActionReason(policy, extension, action) {
|
|
329
|
+
const normalizedAction = normalizePolicyName(action).replace(/\s+/g, "-");
|
|
330
|
+
if (normalizedAction.length === 0) {
|
|
331
|
+
return null;
|
|
332
|
+
}
|
|
333
|
+
const override = resolvePolicyOverride(policy, extension.name);
|
|
334
|
+
const allowed = override && override.allowedActions.size > 0 ? override.allowedActions : policy.allowedActions;
|
|
335
|
+
const blocked = new Set([
|
|
336
|
+
...policy.blockedActions,
|
|
337
|
+
...(override ? override.blockedActions : []),
|
|
338
|
+
]);
|
|
339
|
+
return evaluatePolicySet(allowed, blocked, normalizedAction, "action_not_allowlisted", "action_blocked");
|
|
340
|
+
}
|
|
341
|
+
function resolvePolicyServiceReason(policy, extension, service) {
|
|
342
|
+
const normalizedService = normalizePolicyName(service);
|
|
343
|
+
if (normalizedService.length === 0) {
|
|
344
|
+
return null;
|
|
345
|
+
}
|
|
346
|
+
const override = resolvePolicyOverride(policy, extension.name);
|
|
347
|
+
const allowed = override && override.allowedServices.size > 0 ? override.allowedServices : policy.allowedServices;
|
|
348
|
+
const blocked = new Set([
|
|
349
|
+
...policy.blockedServices,
|
|
350
|
+
...(override ? override.blockedServices : []),
|
|
351
|
+
]);
|
|
352
|
+
return evaluatePolicySet(allowed, blocked, normalizedService, "service_not_allowlisted", "service_blocked");
|
|
353
|
+
}
|
|
354
|
+
function resolvePolicyExtensionReason(policy, extension) {
|
|
355
|
+
const name = normalizePolicyName(extension.name);
|
|
356
|
+
const override = resolvePolicyOverride(policy, extension.name);
|
|
357
|
+
if (override?.disabled === true) {
|
|
358
|
+
return "extension_override_disabled";
|
|
359
|
+
}
|
|
360
|
+
return evaluatePolicySet(policy.allowedExtensions, policy.blockedExtensions, name, "extension_not_allowlisted", "extension_blocked");
|
|
361
|
+
}
|
|
362
|
+
function resolvePolicyTrustReason(policy, extension) {
|
|
363
|
+
if (policy.trustMode === "off") {
|
|
364
|
+
return null;
|
|
365
|
+
}
|
|
366
|
+
const override = resolvePolicyOverride(policy, extension.name);
|
|
367
|
+
const name = normalizePolicyName(extension.name);
|
|
368
|
+
const trusted = extension.trusted === true;
|
|
369
|
+
const provenanceVerified = extension.provenanceVerified === true;
|
|
370
|
+
if (policy.trustedExtensions.size > 0 && !policy.trustedExtensions.has(name)) {
|
|
371
|
+
return "extension_not_trusted";
|
|
372
|
+
}
|
|
373
|
+
if ((override?.requireTrusted === true || policy.trustMode === "warn" || policy.trustMode === "enforce") && !trusted) {
|
|
374
|
+
return "extension_untrusted";
|
|
375
|
+
}
|
|
376
|
+
if ((policy.requireProvenance || override?.requireProvenance === true) && !provenanceVerified) {
|
|
377
|
+
return "provenance_missing_or_unverified";
|
|
378
|
+
}
|
|
379
|
+
return null;
|
|
380
|
+
}
|
|
381
|
+
function resolvePolicySandboxReason(policy, extension) {
|
|
382
|
+
if (policy.mode === "off") {
|
|
383
|
+
return null;
|
|
384
|
+
}
|
|
385
|
+
const override = resolvePolicyOverride(policy, extension.name);
|
|
386
|
+
const profile = override?.sandboxProfile ?? extension.sandboxProfile ?? policy.defaultSandboxProfile;
|
|
387
|
+
if (profile === "none") {
|
|
388
|
+
return null;
|
|
389
|
+
}
|
|
390
|
+
const permissions = extension.permissions;
|
|
391
|
+
if (!permissions) {
|
|
392
|
+
return "sandbox_permissions_missing";
|
|
393
|
+
}
|
|
394
|
+
const hasPermission = (name) => permissions[name] === true;
|
|
395
|
+
if (profile === "restricted") {
|
|
396
|
+
if (hasPermission("process_spawn")) {
|
|
397
|
+
return "sandbox_restricted_disallows_process_spawn";
|
|
398
|
+
}
|
|
399
|
+
if (hasPermission("env_write")) {
|
|
400
|
+
return "sandbox_restricted_disallows_env_write";
|
|
401
|
+
}
|
|
402
|
+
return null;
|
|
403
|
+
}
|
|
404
|
+
if (profile === "strict") {
|
|
405
|
+
if (hasPermission("process_spawn")) {
|
|
406
|
+
return "sandbox_strict_disallows_process_spawn";
|
|
407
|
+
}
|
|
408
|
+
if (hasPermission("network")) {
|
|
409
|
+
return "sandbox_strict_disallows_network";
|
|
410
|
+
}
|
|
411
|
+
if (hasPermission("fs_write")) {
|
|
412
|
+
return "sandbox_strict_disallows_fs_write";
|
|
413
|
+
}
|
|
414
|
+
if (hasPermission("env_write")) {
|
|
415
|
+
return "sandbox_strict_disallows_env_write";
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
return null;
|
|
419
|
+
}
|
|
420
|
+
function buildPolicyWarning(mode, scope, extension, reason, details = {}) {
|
|
421
|
+
const tokens = Object.entries(details)
|
|
422
|
+
.sort((left, right) => left[0].localeCompare(right[0]))
|
|
423
|
+
.map(([key, value]) => `${key}=${value}`)
|
|
424
|
+
.join(":");
|
|
425
|
+
const suffix = tokens.length > 0 ? `:${tokens}` : "";
|
|
426
|
+
return `extension_policy_${mode}_${scope}:${extension.layer}:${extension.name}:reason=${reason}${suffix}`;
|
|
427
|
+
}
|
|
428
|
+
function evaluateExtensionPolicyForExtension(policy, extension) {
|
|
429
|
+
if (policy.mode === "off" && policy.trustMode === "off") {
|
|
430
|
+
return { allowed: true, warning: null };
|
|
431
|
+
}
|
|
432
|
+
const reason = resolvePolicyExtensionReason(policy, extension);
|
|
433
|
+
const trustReason = resolvePolicyTrustReason(policy, extension);
|
|
434
|
+
const sandboxReason = resolvePolicySandboxReason(policy, extension);
|
|
435
|
+
const extensionEnforced = reason && policy.mode === "enforce";
|
|
436
|
+
const trustEnforced = trustReason && policy.trustMode === "enforce";
|
|
437
|
+
const sandboxEnforced = sandboxReason && policy.mode === "enforce";
|
|
438
|
+
if (!reason && !trustReason && !sandboxReason) {
|
|
439
|
+
return { allowed: true, warning: null };
|
|
440
|
+
}
|
|
441
|
+
if (extensionEnforced) {
|
|
442
|
+
return {
|
|
443
|
+
allowed: false,
|
|
444
|
+
warning: buildPolicyWarning("blocked", "extension", extension, reason),
|
|
445
|
+
};
|
|
446
|
+
}
|
|
447
|
+
if (trustEnforced) {
|
|
448
|
+
return {
|
|
449
|
+
allowed: false,
|
|
450
|
+
warning: buildPolicyWarning("blocked", "trust", extension, trustReason),
|
|
451
|
+
};
|
|
452
|
+
}
|
|
453
|
+
if (sandboxEnforced) {
|
|
454
|
+
return {
|
|
455
|
+
allowed: false,
|
|
456
|
+
warning: buildPolicyWarning("blocked", "extension", extension, sandboxReason),
|
|
457
|
+
};
|
|
458
|
+
}
|
|
459
|
+
if (reason && policy.mode === "warn") {
|
|
460
|
+
return {
|
|
461
|
+
allowed: true,
|
|
462
|
+
warning: buildPolicyWarning("violation", "extension", extension, reason),
|
|
463
|
+
};
|
|
464
|
+
}
|
|
465
|
+
if (trustReason && policy.trustMode === "warn") {
|
|
466
|
+
return {
|
|
467
|
+
allowed: true,
|
|
468
|
+
warning: buildPolicyWarning("violation", "trust", extension, trustReason),
|
|
469
|
+
};
|
|
470
|
+
}
|
|
471
|
+
if (sandboxReason && policy.mode === "warn") {
|
|
472
|
+
return {
|
|
473
|
+
allowed: true,
|
|
474
|
+
warning: buildPolicyWarning("violation", "extension", extension, sandboxReason),
|
|
475
|
+
};
|
|
476
|
+
}
|
|
477
|
+
return {
|
|
478
|
+
allowed: true,
|
|
479
|
+
warning: null,
|
|
480
|
+
};
|
|
481
|
+
}
|
|
482
|
+
function evaluateExtensionPolicyForCapability(policy, extension, capability) {
|
|
483
|
+
if (policy.mode === "off") {
|
|
484
|
+
return { allowed: true, warning: null };
|
|
485
|
+
}
|
|
486
|
+
const reason = resolvePolicyCapabilityReason(policy, extension, capability);
|
|
487
|
+
if (!reason) {
|
|
488
|
+
return { allowed: true, warning: null };
|
|
489
|
+
}
|
|
490
|
+
return {
|
|
491
|
+
allowed: policy.mode === "warn",
|
|
492
|
+
warning: buildPolicyWarning(policy.mode === "warn" ? "violation" : "blocked", "capability", extension, reason, { capability: capability.trim().toLowerCase() }),
|
|
493
|
+
};
|
|
494
|
+
}
|
|
495
|
+
function evaluateExtensionPolicyForRegistration(policy, extension, surface, method, capability, details) {
|
|
496
|
+
if (policy.mode === "off") {
|
|
497
|
+
return { allowed: true, warning: null };
|
|
498
|
+
}
|
|
499
|
+
const capabilityReason = typeof capability === "string" ? resolvePolicyCapabilityReason(policy, extension, capability) : null;
|
|
500
|
+
const surfaceReason = resolvePolicySurfaceReason(policy, extension, surface);
|
|
501
|
+
const commandReason = details?.command ? resolvePolicyCommandReason(policy, extension, details.command) : null;
|
|
502
|
+
const actionReason = details?.action ? resolvePolicyActionReason(policy, extension, details.action) : null;
|
|
503
|
+
const serviceReason = details?.service ? resolvePolicyServiceReason(policy, extension, details.service) : null;
|
|
504
|
+
const reason = capabilityReason ?? surfaceReason ?? commandReason ?? actionReason ?? serviceReason;
|
|
505
|
+
if (!reason) {
|
|
506
|
+
return { allowed: true, warning: null };
|
|
507
|
+
}
|
|
508
|
+
const warningDetails = {
|
|
509
|
+
method: normalizePolicyName(method).replace(/\s+/g, "_"),
|
|
510
|
+
surface,
|
|
511
|
+
};
|
|
512
|
+
if (capability) {
|
|
513
|
+
warningDetails.capability = capability;
|
|
514
|
+
}
|
|
515
|
+
if (details?.command) {
|
|
516
|
+
warningDetails.command = normalizeCommandName(details.command);
|
|
517
|
+
}
|
|
518
|
+
if (details?.action) {
|
|
519
|
+
warningDetails.action = normalizePolicyName(details.action).replace(/\s+/g, "-");
|
|
520
|
+
}
|
|
521
|
+
if (details?.service) {
|
|
522
|
+
warningDetails.service = normalizePolicyName(details.service);
|
|
523
|
+
}
|
|
524
|
+
const warning = buildPolicyWarning(policy.mode === "warn" ? "violation" : "blocked", "registration", extension, reason, warningDetails);
|
|
525
|
+
return {
|
|
526
|
+
allowed: policy.mode === "warn",
|
|
527
|
+
warning,
|
|
528
|
+
};
|
|
529
|
+
}
|
|
19
530
|
function resolveLegacyExtensionCapabilityAlias(capability) {
|
|
20
531
|
const normalized = capability.trim().toLowerCase();
|
|
21
532
|
if (normalized.length === 0) {
|
|
@@ -182,6 +693,94 @@ function parseManifest(raw) {
|
|
|
182
693
|
}
|
|
183
694
|
priority = candidate.priority;
|
|
184
695
|
}
|
|
696
|
+
let manifestVersion;
|
|
697
|
+
if ("manifest_version" in candidate && candidate.manifest_version !== undefined && candidate.manifest_version !== null) {
|
|
698
|
+
if (typeof candidate.manifest_version !== "number" || !Number.isInteger(candidate.manifest_version)) {
|
|
699
|
+
return null;
|
|
700
|
+
}
|
|
701
|
+
manifestVersion = candidate.manifest_version;
|
|
702
|
+
}
|
|
703
|
+
let trusted;
|
|
704
|
+
if ("trusted" in candidate && candidate.trusted !== undefined && candidate.trusted !== null) {
|
|
705
|
+
if (typeof candidate.trusted !== "boolean") {
|
|
706
|
+
return null;
|
|
707
|
+
}
|
|
708
|
+
trusted = candidate.trusted;
|
|
709
|
+
}
|
|
710
|
+
let sandboxProfile;
|
|
711
|
+
if ("sandbox_profile" in candidate && candidate.sandbox_profile !== undefined && candidate.sandbox_profile !== null) {
|
|
712
|
+
if (typeof candidate.sandbox_profile !== "string") {
|
|
713
|
+
return null;
|
|
714
|
+
}
|
|
715
|
+
const normalizedProfile = normalizePolicySandboxProfile(candidate.sandbox_profile);
|
|
716
|
+
if (normalizedProfile !== candidate.sandbox_profile.trim().toLowerCase()) {
|
|
717
|
+
return null;
|
|
718
|
+
}
|
|
719
|
+
sandboxProfile = normalizedProfile;
|
|
720
|
+
}
|
|
721
|
+
let provenance;
|
|
722
|
+
if ("provenance" in candidate && candidate.provenance !== undefined && candidate.provenance !== null) {
|
|
723
|
+
const provenanceRecord = asRecord(candidate.provenance);
|
|
724
|
+
if (!provenanceRecord) {
|
|
725
|
+
return null;
|
|
726
|
+
}
|
|
727
|
+
const source = typeof provenanceRecord.source === "string" && provenanceRecord.source.trim().length > 0
|
|
728
|
+
? provenanceRecord.source.trim()
|
|
729
|
+
: undefined;
|
|
730
|
+
const signature = typeof provenanceRecord.signature === "string" && provenanceRecord.signature.trim().length > 0
|
|
731
|
+
? provenanceRecord.signature.trim()
|
|
732
|
+
: undefined;
|
|
733
|
+
const attestation = typeof provenanceRecord.attestation === "string" && provenanceRecord.attestation.trim().length > 0
|
|
734
|
+
? provenanceRecord.attestation.trim()
|
|
735
|
+
: undefined;
|
|
736
|
+
const verified = provenanceRecord.verified === undefined || provenanceRecord.verified === null
|
|
737
|
+
? undefined
|
|
738
|
+
: typeof provenanceRecord.verified === "boolean"
|
|
739
|
+
? provenanceRecord.verified
|
|
740
|
+
: null;
|
|
741
|
+
if (verified === null) {
|
|
742
|
+
return null;
|
|
743
|
+
}
|
|
744
|
+
provenance = {
|
|
745
|
+
...(source ? { source } : {}),
|
|
746
|
+
...(signature ? { signature } : {}),
|
|
747
|
+
...(attestation ? { attestation } : {}),
|
|
748
|
+
...(typeof verified === "boolean" ? { verified } : {}),
|
|
749
|
+
};
|
|
750
|
+
}
|
|
751
|
+
let permissions;
|
|
752
|
+
if ("permissions" in candidate && candidate.permissions !== undefined && candidate.permissions !== null) {
|
|
753
|
+
const permissionsRecord = asRecord(candidate.permissions);
|
|
754
|
+
if (!permissionsRecord) {
|
|
755
|
+
return null;
|
|
756
|
+
}
|
|
757
|
+
const parseOptionalBoolean = (value) => {
|
|
758
|
+
if (value === undefined || value === null) {
|
|
759
|
+
return undefined;
|
|
760
|
+
}
|
|
761
|
+
if (typeof value !== "boolean") {
|
|
762
|
+
return null;
|
|
763
|
+
}
|
|
764
|
+
return value;
|
|
765
|
+
};
|
|
766
|
+
const fsRead = parseOptionalBoolean(permissionsRecord.fs_read);
|
|
767
|
+
const fsWrite = parseOptionalBoolean(permissionsRecord.fs_write);
|
|
768
|
+
const network = parseOptionalBoolean(permissionsRecord.network);
|
|
769
|
+
const envRead = parseOptionalBoolean(permissionsRecord.env_read);
|
|
770
|
+
const envWrite = parseOptionalBoolean(permissionsRecord.env_write);
|
|
771
|
+
const processSpawn = parseOptionalBoolean(permissionsRecord.process_spawn);
|
|
772
|
+
if ([fsRead, fsWrite, network, envRead, envWrite, processSpawn].includes(null)) {
|
|
773
|
+
return null;
|
|
774
|
+
}
|
|
775
|
+
permissions = {
|
|
776
|
+
...(typeof fsRead === "boolean" ? { fs_read: fsRead } : {}),
|
|
777
|
+
...(typeof fsWrite === "boolean" ? { fs_write: fsWrite } : {}),
|
|
778
|
+
...(typeof network === "boolean" ? { network } : {}),
|
|
779
|
+
...(typeof envRead === "boolean" ? { env_read: envRead } : {}),
|
|
780
|
+
...(typeof envWrite === "boolean" ? { env_write: envWrite } : {}),
|
|
781
|
+
...(typeof processSpawn === "boolean" ? { process_spawn: processSpawn } : {}),
|
|
782
|
+
};
|
|
783
|
+
}
|
|
185
784
|
let capabilities = [];
|
|
186
785
|
let legacyCapabilityAliases = [];
|
|
187
786
|
if ("capabilities" in candidate && candidate.capabilities !== undefined && candidate.capabilities !== null) {
|
|
@@ -197,6 +796,11 @@ function parseManifest(raw) {
|
|
|
197
796
|
version: candidate.version.trim(),
|
|
198
797
|
entry: candidate.entry.trim(),
|
|
199
798
|
priority,
|
|
799
|
+
manifest_version: manifestVersion,
|
|
800
|
+
trusted,
|
|
801
|
+
provenance,
|
|
802
|
+
sandbox_profile: sandboxProfile,
|
|
803
|
+
permissions,
|
|
200
804
|
capabilities,
|
|
201
805
|
legacy_capability_aliases: legacyCapabilityAliases.length > 0 ? legacyCapabilityAliases : undefined,
|
|
202
806
|
};
|
|
@@ -303,6 +907,11 @@ function summarizeCandidate(candidate) {
|
|
|
303
907
|
entry: candidate.manifest.entry,
|
|
304
908
|
priority: candidate.manifest.priority,
|
|
305
909
|
entry_path: candidate.entry_path,
|
|
910
|
+
manifest_version: candidate.manifest.manifest_version,
|
|
911
|
+
trusted: candidate.manifest.trusted,
|
|
912
|
+
provenance: candidate.manifest.provenance,
|
|
913
|
+
sandbox_profile: candidate.manifest.sandbox_profile,
|
|
914
|
+
permissions: candidate.manifest.permissions,
|
|
306
915
|
capabilities: [...candidate.manifest.capabilities],
|
|
307
916
|
};
|
|
308
917
|
}
|
|
@@ -441,6 +1050,8 @@ export async function discoverExtensions(options) {
|
|
|
441
1050
|
const roots = resolveExtensionRoots(options.pmRoot, options.cwd ?? process.cwd());
|
|
442
1051
|
const configured_enabled = normalizeNames(options.settings.extensions.enabled);
|
|
443
1052
|
const configured_disabled = normalizeNames(options.settings.extensions.disabled);
|
|
1053
|
+
const policy = normalizeExtensionPolicy(options.settings);
|
|
1054
|
+
const serializedPolicy = serializeExtensionPolicy(policy);
|
|
444
1055
|
if (options.noExtensions) {
|
|
445
1056
|
return {
|
|
446
1057
|
disabled_by_flag: true,
|
|
@@ -449,14 +1060,50 @@ export async function discoverExtensions(options) {
|
|
|
449
1060
|
configured_disabled,
|
|
450
1061
|
discovered: [],
|
|
451
1062
|
effective: [],
|
|
452
|
-
warnings: [],
|
|
1063
|
+
warnings: [...policy.warnings],
|
|
1064
|
+
policy: serializedPolicy,
|
|
453
1065
|
};
|
|
454
1066
|
}
|
|
455
1067
|
const enabled = new Set(configured_enabled);
|
|
456
1068
|
const disabled = new Set(configured_disabled);
|
|
457
1069
|
const globalScan = await scanExtensionLayer("global", roots.global, enabled, disabled);
|
|
458
1070
|
const projectScan = await scanExtensionLayer("project", roots.project, enabled, disabled);
|
|
459
|
-
const
|
|
1071
|
+
const policyWarnings = [...policy.warnings];
|
|
1072
|
+
const effectiveCandidates = buildEffectiveExtensions(globalScan.candidates, projectScan.candidates);
|
|
1073
|
+
const effective = [];
|
|
1074
|
+
for (const candidate of effectiveCandidates) {
|
|
1075
|
+
const extensionRef = {
|
|
1076
|
+
layer: candidate.layer,
|
|
1077
|
+
name: candidate.manifest.name,
|
|
1078
|
+
trusted: candidate.manifest.trusted === true,
|
|
1079
|
+
provenanceVerified: candidate.manifest.provenance?.verified === true,
|
|
1080
|
+
sandboxProfile: candidate.manifest.sandbox_profile,
|
|
1081
|
+
permissions: candidate.manifest.permissions && typeof candidate.manifest.permissions === "object"
|
|
1082
|
+
? {
|
|
1083
|
+
fs_read: candidate.manifest.permissions.fs_read,
|
|
1084
|
+
fs_write: candidate.manifest.permissions.fs_write,
|
|
1085
|
+
network: candidate.manifest.permissions.network,
|
|
1086
|
+
env_read: candidate.manifest.permissions.env_read,
|
|
1087
|
+
env_write: candidate.manifest.permissions.env_write,
|
|
1088
|
+
process_spawn: candidate.manifest.permissions.process_spawn,
|
|
1089
|
+
}
|
|
1090
|
+
: undefined,
|
|
1091
|
+
};
|
|
1092
|
+
const extensionDecision = evaluateExtensionPolicyForExtension(policy, extensionRef);
|
|
1093
|
+
if (extensionDecision.warning) {
|
|
1094
|
+
policyWarnings.push(extensionDecision.warning);
|
|
1095
|
+
}
|
|
1096
|
+
if (!extensionDecision.allowed) {
|
|
1097
|
+
continue;
|
|
1098
|
+
}
|
|
1099
|
+
for (const capability of candidate.manifest.capabilities) {
|
|
1100
|
+
const capabilityDecision = evaluateExtensionPolicyForCapability(policy, extensionRef, capability);
|
|
1101
|
+
if (capabilityDecision.warning) {
|
|
1102
|
+
policyWarnings.push(capabilityDecision.warning);
|
|
1103
|
+
}
|
|
1104
|
+
}
|
|
1105
|
+
effective.push(summarizeCandidate(candidate));
|
|
1106
|
+
}
|
|
460
1107
|
return {
|
|
461
1108
|
disabled_by_flag: false,
|
|
462
1109
|
roots,
|
|
@@ -464,7 +1111,8 @@ export async function discoverExtensions(options) {
|
|
|
464
1111
|
configured_disabled,
|
|
465
1112
|
discovered: [...globalScan.diagnostics, ...projectScan.diagnostics],
|
|
466
1113
|
effective,
|
|
467
|
-
warnings: [...globalScan.warnings, ...projectScan.warnings],
|
|
1114
|
+
warnings: [...new Set([...globalScan.warnings, ...projectScan.warnings, ...policyWarnings])],
|
|
1115
|
+
policy: serializedPolicy,
|
|
468
1116
|
};
|
|
469
1117
|
}
|
|
470
1118
|
function formatUnknownError(error) {
|
|
@@ -473,6 +1121,31 @@ function formatUnknownError(error) {
|
|
|
473
1121
|
}
|
|
474
1122
|
return String(error);
|
|
475
1123
|
}
|
|
1124
|
+
async function fingerprintPath(pathToInspect) {
|
|
1125
|
+
try {
|
|
1126
|
+
const stats = await fs.stat(pathToInspect);
|
|
1127
|
+
return `${Math.trunc(stats.mtimeMs)}-${stats.size}`;
|
|
1128
|
+
}
|
|
1129
|
+
catch {
|
|
1130
|
+
return "missing";
|
|
1131
|
+
}
|
|
1132
|
+
}
|
|
1133
|
+
async function resolveExtensionImportHref(extension, options) {
|
|
1134
|
+
const baseUrl = new URL(pathToFileURL(extension.entry_path).href);
|
|
1135
|
+
const shouldCacheBust = options.cache_bust === true || typeof options.reload_token === "string";
|
|
1136
|
+
if (!shouldCacheBust) {
|
|
1137
|
+
return baseUrl.href;
|
|
1138
|
+
}
|
|
1139
|
+
const [entryFingerprint, manifestFingerprint] = await Promise.all([
|
|
1140
|
+
fingerprintPath(extension.entry_path),
|
|
1141
|
+
fingerprintPath(extension.manifest_path),
|
|
1142
|
+
]);
|
|
1143
|
+
const reloadToken = options.reload_token ?? nextExtensionReloadToken();
|
|
1144
|
+
baseUrl.searchParams.set("pm_ext_reload", reloadToken);
|
|
1145
|
+
baseUrl.searchParams.set("pm_ext_entry", entryFingerprint);
|
|
1146
|
+
baseUrl.searchParams.set("pm_ext_manifest", manifestFingerprint);
|
|
1147
|
+
return baseUrl.href;
|
|
1148
|
+
}
|
|
476
1149
|
export async function loadExtensions(options) {
|
|
477
1150
|
const discovery = await discoverExtensions(options);
|
|
478
1151
|
const loaded = [];
|
|
@@ -488,7 +1161,8 @@ export async function loadExtensions(options) {
|
|
|
488
1161
|
}
|
|
489
1162
|
for (const extension of discovery.effective) {
|
|
490
1163
|
try {
|
|
491
|
-
const
|
|
1164
|
+
const importHref = await resolveExtensionImportHref(extension, options);
|
|
1165
|
+
const module = await import(importHref);
|
|
492
1166
|
loaded.push({
|
|
493
1167
|
...extension,
|
|
494
1168
|
module,
|
|
@@ -912,7 +1586,34 @@ function assertExtensionCapability(extension, capability, method) {
|
|
|
912
1586
|
throw new TypeError(`${method} requires capability '${capability}' in extension manifest capabilities`);
|
|
913
1587
|
}
|
|
914
1588
|
}
|
|
915
|
-
function createExtensionApi(extension, hooks, commands, parsers, preflight, services, renderers, registrations, activationWarnings) {
|
|
1589
|
+
function createExtensionApi(extension, hooks, commands, parsers, preflight, services, renderers, registrations, activationWarnings, policy) {
|
|
1590
|
+
const extensionRef = {
|
|
1591
|
+
layer: extension.layer,
|
|
1592
|
+
name: extension.name,
|
|
1593
|
+
trusted: extension.trusted === true,
|
|
1594
|
+
provenanceVerified: extension.provenance?.verified === true,
|
|
1595
|
+
sandboxProfile: extension.sandbox_profile,
|
|
1596
|
+
permissions: extension.permissions && typeof extension.permissions === "object"
|
|
1597
|
+
? {
|
|
1598
|
+
fs_read: extension.permissions.fs_read,
|
|
1599
|
+
fs_write: extension.permissions.fs_write,
|
|
1600
|
+
network: extension.permissions.network,
|
|
1601
|
+
env_read: extension.permissions.env_read,
|
|
1602
|
+
env_write: extension.permissions.env_write,
|
|
1603
|
+
process_spawn: extension.permissions.process_spawn,
|
|
1604
|
+
}
|
|
1605
|
+
: undefined,
|
|
1606
|
+
};
|
|
1607
|
+
const pushPolicyWarning = (warning) => {
|
|
1608
|
+
if (warning) {
|
|
1609
|
+
activationWarnings.push(warning);
|
|
1610
|
+
}
|
|
1611
|
+
};
|
|
1612
|
+
const allowRegistration = (surface, method, capability, details) => {
|
|
1613
|
+
const decision = evaluateExtensionPolicyForRegistration(policy, extensionRef, surface, method, capability, details);
|
|
1614
|
+
pushPolicyWarning(decision.warning);
|
|
1615
|
+
return decision.allowed;
|
|
1616
|
+
};
|
|
916
1617
|
const registerCommandTrace = (mode, command, expectedSchema, received, hint) => ({
|
|
917
1618
|
method: "registerCommand",
|
|
918
1619
|
registration_index: mode === "override" ? commands.overrides.length : commands.handlers.length,
|
|
@@ -932,6 +1633,9 @@ function createExtensionApi(extension, hooks, commands, parsers, preflight, serv
|
|
|
932
1633
|
const trace = registerCommandTrace("override", normalizedCommand, 'registerCommand("<command>", (context) => unknown)', { command: commandOrDefinition, override }, "Provide a function as the second registerCommand argument.");
|
|
933
1634
|
throw createRegistrationValidationError(`registerCommand requires an override function when command name is provided (command="${normalizedCommand}", registration_index=${trace.registration_index})`, trace);
|
|
934
1635
|
}
|
|
1636
|
+
if (!allowRegistration("commands.override", "registerCommand", "commands", { command: normalizedCommand })) {
|
|
1637
|
+
return;
|
|
1638
|
+
}
|
|
935
1639
|
commands.overrides.push({
|
|
936
1640
|
layer: extension.layer,
|
|
937
1641
|
name: extension.name,
|
|
@@ -965,6 +1669,9 @@ function createExtensionApi(extension, hooks, commands, parsers, preflight, serv
|
|
|
965
1669
|
assertOptionalStringField("registerCommand definition.description", commandOrDefinition.description);
|
|
966
1670
|
assertOptionalStringField("registerCommand definition.intent", commandOrDefinition.intent);
|
|
967
1671
|
const action = resolveCommandDefinitionAction(normalizedCommand, commandOrDefinition.action);
|
|
1672
|
+
if (!allowRegistration("commands.handler", "registerCommand", "commands", { command: normalizedCommand, action })) {
|
|
1673
|
+
return;
|
|
1674
|
+
}
|
|
968
1675
|
const description = commandOrDefinition.description?.trim();
|
|
969
1676
|
const intent = commandOrDefinition.intent?.trim();
|
|
970
1677
|
const examples = normalizeOptionalStringArrayField("registerCommand definition.examples", commandOrDefinition.examples);
|
|
@@ -1011,6 +1718,9 @@ function createExtensionApi(extension, hooks, commands, parsers, preflight, serv
|
|
|
1011
1718
|
};
|
|
1012
1719
|
const registerParser = (command, override) => {
|
|
1013
1720
|
assertExtensionCapability(extension, "parser", "registerParser");
|
|
1721
|
+
if (!allowRegistration("parser.override", "registerParser", "parser")) {
|
|
1722
|
+
return;
|
|
1723
|
+
}
|
|
1014
1724
|
const normalizedCommand = normalizeCommandName(assertNonEmptyString("registerParser command", command));
|
|
1015
1725
|
assertFunctionHandler("registerParser override", override);
|
|
1016
1726
|
parsers.overrides.push({
|
|
@@ -1022,6 +1732,9 @@ function createExtensionApi(extension, hooks, commands, parsers, preflight, serv
|
|
|
1022
1732
|
};
|
|
1023
1733
|
const registerPreflight = (override) => {
|
|
1024
1734
|
assertExtensionCapability(extension, "preflight", "registerPreflight");
|
|
1735
|
+
if (!allowRegistration("preflight.override", "registerPreflight", "preflight")) {
|
|
1736
|
+
return;
|
|
1737
|
+
}
|
|
1025
1738
|
assertFunctionHandler("registerPreflight override", override);
|
|
1026
1739
|
preflight.overrides.push({
|
|
1027
1740
|
layer: extension.layer,
|
|
@@ -1035,6 +1748,9 @@ function createExtensionApi(extension, hooks, commands, parsers, preflight, serv
|
|
|
1035
1748
|
if (!isExtensionServiceName(normalizedService)) {
|
|
1036
1749
|
throw new TypeError(`registerService service must be one of: ${EXTENSION_SERVICE_NAMES.join(", ")}`);
|
|
1037
1750
|
}
|
|
1751
|
+
if (!allowRegistration("services.override", "registerService", "services", { service: normalizedService })) {
|
|
1752
|
+
return;
|
|
1753
|
+
}
|
|
1038
1754
|
assertFunctionHandler("registerService override", override);
|
|
1039
1755
|
services.overrides.push({
|
|
1040
1756
|
layer: extension.layer,
|
|
@@ -1045,6 +1761,9 @@ function createExtensionApi(extension, hooks, commands, parsers, preflight, serv
|
|
|
1045
1761
|
};
|
|
1046
1762
|
const registerRenderer = (format, renderer) => {
|
|
1047
1763
|
assertExtensionCapability(extension, "renderers", "registerRenderer");
|
|
1764
|
+
if (!allowRegistration("renderers.override", "registerRenderer", "renderers")) {
|
|
1765
|
+
return;
|
|
1766
|
+
}
|
|
1048
1767
|
if (typeof renderer !== "function") {
|
|
1049
1768
|
throw new TypeError("registerRenderer requires a renderer function");
|
|
1050
1769
|
}
|
|
@@ -1061,6 +1780,9 @@ function createExtensionApi(extension, hooks, commands, parsers, preflight, serv
|
|
|
1061
1780
|
};
|
|
1062
1781
|
const registerFlags = (targetCommand, flags) => {
|
|
1063
1782
|
assertExtensionCapability(extension, "schema", "registerFlags");
|
|
1783
|
+
if (!allowRegistration("schema.flags", "registerFlags", "schema")) {
|
|
1784
|
+
return;
|
|
1785
|
+
}
|
|
1064
1786
|
const normalizedTargetCommand = normalizeCommandName(assertNonEmptyString("registerFlags targetCommand", targetCommand));
|
|
1065
1787
|
validateFlagDefinitions(flags);
|
|
1066
1788
|
const normalizedFlags = normalizeRegistrationRecordList("registerFlags flags", flags);
|
|
@@ -1076,6 +1798,9 @@ function createExtensionApi(extension, hooks, commands, parsers, preflight, serv
|
|
|
1076
1798
|
};
|
|
1077
1799
|
const registerItemFields = (fields) => {
|
|
1078
1800
|
assertExtensionCapability(extension, "schema", "registerItemFields");
|
|
1801
|
+
if (!allowRegistration("schema.itemfields", "registerItemFields", "schema")) {
|
|
1802
|
+
return;
|
|
1803
|
+
}
|
|
1079
1804
|
validateItemFieldDefinitions(fields);
|
|
1080
1805
|
const normalizedFields = normalizeRegistrationRecordList("registerItemFields fields", fields);
|
|
1081
1806
|
if (normalizedFields.length === 0) {
|
|
@@ -1089,6 +1814,9 @@ function createExtensionApi(extension, hooks, commands, parsers, preflight, serv
|
|
|
1089
1814
|
};
|
|
1090
1815
|
const registerItemTypes = (types) => {
|
|
1091
1816
|
assertExtensionCapability(extension, "schema", "registerItemTypes");
|
|
1817
|
+
if (!allowRegistration("schema.itemtypes", "registerItemTypes", "schema")) {
|
|
1818
|
+
return;
|
|
1819
|
+
}
|
|
1092
1820
|
validateItemTypeDefinitions(types);
|
|
1093
1821
|
const normalizedTypes = normalizeRegistrationRecordList("registerItemTypes types", types);
|
|
1094
1822
|
if (normalizedTypes.length === 0) {
|
|
@@ -1102,6 +1830,9 @@ function createExtensionApi(extension, hooks, commands, parsers, preflight, serv
|
|
|
1102
1830
|
};
|
|
1103
1831
|
const registerMigration = (definition) => {
|
|
1104
1832
|
assertExtensionCapability(extension, "schema", "registerMigration");
|
|
1833
|
+
if (!allowRegistration("schema.migrations", "registerMigration", "schema")) {
|
|
1834
|
+
return;
|
|
1835
|
+
}
|
|
1105
1836
|
validateMigrationDefinition(definition);
|
|
1106
1837
|
const runtimeDefinition = normalizeRuntimeRegistrationRecord("registerMigration definition", definition);
|
|
1107
1838
|
registrations.migrations.push(attachRuntimeDefinition({
|
|
@@ -1112,6 +1843,9 @@ function createExtensionApi(extension, hooks, commands, parsers, preflight, serv
|
|
|
1112
1843
|
};
|
|
1113
1844
|
const registerImporter = (name, importer) => {
|
|
1114
1845
|
assertExtensionCapability(extension, "importers", "registerImporter");
|
|
1846
|
+
if (!allowRegistration("importers.importer", "registerImporter", "importers")) {
|
|
1847
|
+
return;
|
|
1848
|
+
}
|
|
1115
1849
|
const normalizedName = normalizeRegistrationName(assertNonEmptyString("registerImporter name", name));
|
|
1116
1850
|
assertFunctionHandler("registerImporter importer", importer);
|
|
1117
1851
|
const commandPath = toRegistrationCommandPath(normalizedName, "import");
|
|
@@ -1137,6 +1871,9 @@ function createExtensionApi(extension, hooks, commands, parsers, preflight, serv
|
|
|
1137
1871
|
};
|
|
1138
1872
|
const registerExporter = (name, exporter) => {
|
|
1139
1873
|
assertExtensionCapability(extension, "importers", "registerExporter");
|
|
1874
|
+
if (!allowRegistration("importers.exporter", "registerExporter", "importers")) {
|
|
1875
|
+
return;
|
|
1876
|
+
}
|
|
1140
1877
|
const normalizedName = normalizeRegistrationName(assertNonEmptyString("registerExporter name", name));
|
|
1141
1878
|
assertFunctionHandler("registerExporter exporter", exporter);
|
|
1142
1879
|
const commandPath = toRegistrationCommandPath(normalizedName, "export");
|
|
@@ -1162,6 +1899,9 @@ function createExtensionApi(extension, hooks, commands, parsers, preflight, serv
|
|
|
1162
1899
|
};
|
|
1163
1900
|
const registerSearchProvider = (provider) => {
|
|
1164
1901
|
assertExtensionCapability(extension, "search", "registerSearchProvider");
|
|
1902
|
+
if (!allowRegistration("search.provider", "registerSearchProvider", "search")) {
|
|
1903
|
+
return;
|
|
1904
|
+
}
|
|
1165
1905
|
const runtimeDefinition = normalizeRuntimeRegistrationRecord("registerSearchProvider provider", provider);
|
|
1166
1906
|
registrations.search_providers.push(attachRuntimeDefinition({
|
|
1167
1907
|
layer: extension.layer,
|
|
@@ -1171,6 +1911,9 @@ function createExtensionApi(extension, hooks, commands, parsers, preflight, serv
|
|
|
1171
1911
|
};
|
|
1172
1912
|
const registerVectorStoreAdapter = (adapter) => {
|
|
1173
1913
|
assertExtensionCapability(extension, "search", "registerVectorStoreAdapter");
|
|
1914
|
+
if (!allowRegistration("search.vectorstore", "registerVectorStoreAdapter", "search")) {
|
|
1915
|
+
return;
|
|
1916
|
+
}
|
|
1174
1917
|
const runtimeDefinition = normalizeRuntimeRegistrationRecord("registerVectorStoreAdapter adapter", adapter);
|
|
1175
1918
|
registrations.vector_store_adapters.push(attachRuntimeDefinition({
|
|
1176
1919
|
layer: extension.layer,
|
|
@@ -1180,6 +1923,9 @@ function createExtensionApi(extension, hooks, commands, parsers, preflight, serv
|
|
|
1180
1923
|
};
|
|
1181
1924
|
const registerBeforeCommand = (hook) => {
|
|
1182
1925
|
assertExtensionCapability(extension, "hooks", "api.hooks.beforeCommand");
|
|
1926
|
+
if (!allowRegistration("hooks.beforecommand", "api.hooks.beforeCommand", "hooks")) {
|
|
1927
|
+
return;
|
|
1928
|
+
}
|
|
1183
1929
|
assertHookHandler("beforeCommand", hook);
|
|
1184
1930
|
hooks.beforeCommand.push({
|
|
1185
1931
|
layer: extension.layer,
|
|
@@ -1189,6 +1935,9 @@ function createExtensionApi(extension, hooks, commands, parsers, preflight, serv
|
|
|
1189
1935
|
};
|
|
1190
1936
|
const registerAfterCommand = (hook) => {
|
|
1191
1937
|
assertExtensionCapability(extension, "hooks", "api.hooks.afterCommand");
|
|
1938
|
+
if (!allowRegistration("hooks.aftercommand", "api.hooks.afterCommand", "hooks")) {
|
|
1939
|
+
return;
|
|
1940
|
+
}
|
|
1192
1941
|
assertHookHandler("afterCommand", hook);
|
|
1193
1942
|
hooks.afterCommand.push({
|
|
1194
1943
|
layer: extension.layer,
|
|
@@ -1198,6 +1947,9 @@ function createExtensionApi(extension, hooks, commands, parsers, preflight, serv
|
|
|
1198
1947
|
};
|
|
1199
1948
|
const registerOnWrite = (hook) => {
|
|
1200
1949
|
assertExtensionCapability(extension, "hooks", "api.hooks.onWrite");
|
|
1950
|
+
if (!allowRegistration("hooks.onwrite", "api.hooks.onWrite", "hooks")) {
|
|
1951
|
+
return;
|
|
1952
|
+
}
|
|
1201
1953
|
assertHookHandler("onWrite", hook);
|
|
1202
1954
|
hooks.onWrite.push({
|
|
1203
1955
|
layer: extension.layer,
|
|
@@ -1207,6 +1959,9 @@ function createExtensionApi(extension, hooks, commands, parsers, preflight, serv
|
|
|
1207
1959
|
};
|
|
1208
1960
|
const registerOnRead = (hook) => {
|
|
1209
1961
|
assertExtensionCapability(extension, "hooks", "api.hooks.onRead");
|
|
1962
|
+
if (!allowRegistration("hooks.onread", "api.hooks.onRead", "hooks")) {
|
|
1963
|
+
return;
|
|
1964
|
+
}
|
|
1210
1965
|
assertHookHandler("onRead", hook);
|
|
1211
1966
|
hooks.onRead.push({
|
|
1212
1967
|
layer: extension.layer,
|
|
@@ -1216,6 +1971,9 @@ function createExtensionApi(extension, hooks, commands, parsers, preflight, serv
|
|
|
1216
1971
|
};
|
|
1217
1972
|
const registerOnIndex = (hook) => {
|
|
1218
1973
|
assertExtensionCapability(extension, "hooks", "api.hooks.onIndex");
|
|
1974
|
+
if (!allowRegistration("hooks.onindex", "api.hooks.onIndex", "hooks")) {
|
|
1975
|
+
return;
|
|
1976
|
+
}
|
|
1219
1977
|
assertHookHandler("onIndex", hook);
|
|
1220
1978
|
hooks.onIndex.push({
|
|
1221
1979
|
layer: extension.layer,
|
|
@@ -1374,6 +2132,7 @@ function collectServiceCollisionWarnings(services) {
|
|
|
1374
2132
|
return warnings;
|
|
1375
2133
|
}
|
|
1376
2134
|
export async function activateExtensions(loadResult) {
|
|
2135
|
+
const policy = hydrateExtensionPolicy(loadResult.policy ?? DEFAULT_EXTENSION_POLICY);
|
|
1377
2136
|
const hooks = createEmptyExtensionHookRegistry();
|
|
1378
2137
|
const commands = createEmptyExtensionCommandRegistry();
|
|
1379
2138
|
const parsers = createEmptyExtensionParserRegistry();
|
|
@@ -1389,7 +2148,7 @@ export async function activateExtensions(loadResult) {
|
|
|
1389
2148
|
continue;
|
|
1390
2149
|
}
|
|
1391
2150
|
try {
|
|
1392
|
-
await activatable.activate(createExtensionApi(extension, hooks, commands, parsers, preflight, services, renderers, registrations, warnings));
|
|
2151
|
+
await activatable.activate(createExtensionApi(extension, hooks, commands, parsers, preflight, services, renderers, registrations, warnings, policy));
|
|
1393
2152
|
}
|
|
1394
2153
|
catch (error) {
|
|
1395
2154
|
warnings.push(`extension_activate_failed:${extension.layer}:${extension.name}`);
|