@commonlyai/cli 0.1.74 → 0.1.75
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
CHANGED
|
@@ -76,6 +76,37 @@ export const isShippedCommonlyMcpEntry = (server) => {
|
|
|
76
76
|
// True when a string still contains `${` after the known placeholders are
|
|
77
77
|
// removed — a `${VAR}`, `${VAR:-default}` or any other expansion the CLI
|
|
78
78
|
// would resolve from an environment this declaration does not own.
|
|
79
|
+
// A field the guard cannot READ is not a field it can judge. `env` and
|
|
80
|
+
// `headers` are spread by every reader (`{ ...server.env }`), so a STRING there
|
|
81
|
+
// becomes single-character keys and the declaration is silently dropped rather
|
|
82
|
+
// than honoured — the next consumer that parses the string instead would honour
|
|
83
|
+
// it, and this guard would have admitted the entry on the strength of its other
|
|
84
|
+
// fields (TASK-069: judge the whole entry, not selected fields). `args` is read
|
|
85
|
+
// only through `Array.isArray`, and `cwd` through `typeof === 'string'` in
|
|
86
|
+
// `executionShape`, so a value of the wrong type there is dropped the same way —
|
|
87
|
+
// and for `cwd` that drop is load-bearing: the normalised shape then equals an
|
|
88
|
+
// installed entry that declares NO cwd, so the entry is admitted as one the
|
|
89
|
+
// operator already installed (Vera, hold on #1915).
|
|
90
|
+
// Fail closed: an unreadable shape is a refusal, never an absence.
|
|
91
|
+
const unreadableField = (server) => {
|
|
92
|
+
for (const key of ['env', 'headers']) {
|
|
93
|
+
const value = server[key];
|
|
94
|
+
if (value === undefined || value === null) continue;
|
|
95
|
+
if (typeof value !== 'object' || Array.isArray(value)) {
|
|
96
|
+
return `${key} is of type ${typeof value}, not an object`;
|
|
97
|
+
}
|
|
98
|
+
const badValue = Object.entries(value).find(([, v]) => typeof v !== 'string');
|
|
99
|
+
if (badValue) return `${key}.${badValue[0]} is not a string`;
|
|
100
|
+
}
|
|
101
|
+
if (server.cwd !== undefined && server.cwd !== null && typeof server.cwd !== 'string') {
|
|
102
|
+
return `cwd is of type ${typeof server.cwd}, not a string`;
|
|
103
|
+
}
|
|
104
|
+
if (server.args === undefined || server.args === null) return null;
|
|
105
|
+
if (!Array.isArray(server.args)) return `args is of type ${typeof server.args}, not an array`;
|
|
106
|
+
if (server.args.some((a) => typeof a !== 'string')) return 'args carries a non-string';
|
|
107
|
+
return null;
|
|
108
|
+
};
|
|
109
|
+
|
|
79
110
|
const hasForeignExpansion = (value) => {
|
|
80
111
|
if (typeof value !== 'string') return false;
|
|
81
112
|
let rest = value;
|
|
@@ -127,6 +158,11 @@ export const auditDeclaredMcp = (environment, { instanceUrl, allowedStdioEntries
|
|
|
127
158
|
}
|
|
128
159
|
const name = typeof server.name === 'string' && server.name ? server.name : `mcp[${index}]`;
|
|
129
160
|
const transport = server.transport || 'stdio';
|
|
161
|
+
const unreadable = unreadableField(server);
|
|
162
|
+
if (unreadable) {
|
|
163
|
+
refusals.push(`'${name}': declares ${unreadable}, so this guard cannot judge what the entry would run; refusing it rather than reading the field as absent`);
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
130
166
|
// One shape per entry. The adapters classified by which field was present,
|
|
131
167
|
// so `{transport:'http', url:<instance>, command:['sh','-c',…]}` passed an
|
|
132
168
|
// origin check here and ran as stdio there with the token substituted
|