codegate-ai 0.14.1 → 0.14.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/dist/pipeline.js CHANGED
@@ -202,9 +202,6 @@ function layer3ErrorFinding(resourceId, status, description) {
202
202
  suppressed: false,
203
203
  });
204
204
  }
205
- function isRegistryMetadataResource(resourceId) {
206
- return (resourceId.startsWith("npm:") || resourceId.startsWith("pypi:") || resourceId.startsWith("git:"));
207
- }
208
205
  export function layer3OutcomesToFindings(outcomes, options = {}) {
209
206
  const findings = [];
210
207
  for (const outcome of outcomes) {
@@ -219,11 +216,17 @@ export function layer3OutcomesToFindings(outcomes, options = {}) {
219
216
  const parsed = parseLayer3Response(outcome.resourceId, outcome.result.metadata);
220
217
  const derived = deriveLayer3ToolFindings(outcome.resourceId, outcome.result.metadata, options);
221
218
  const combined = [...parsed, ...derived];
219
+ // If a Layer 3 resource was fetched successfully but carries no
220
+ // actionable metadata (no `findings[]`, no `tools[]`), that is not an
221
+ // issue with the scan target itself — it usually means the default
222
+ // no-outbound-call resource executor recorded only a URL stub, or that
223
+ // a host-configured MCP endpoint simply returned an unrecognised
224
+ // payload. Previously we emitted a LOW `layer3-network_error`
225
+ // "schema mismatch" finding whose `file_path` was the remote URL,
226
+ // which leaked host-level noise into every per-target scan report.
227
+ // Fetch-level anomalies that are unrelated to the scan target are now
228
+ // dropped silently for all resource kinds.
222
229
  if (combined.length === 0) {
223
- if (isRegistryMetadataResource(outcome.resourceId)) {
224
- continue;
225
- }
226
- findings.push(layer3ErrorFinding(outcome.resourceId, "network_error", "Deep scan response schema mismatch: expected metadata.findings[] or metadata.tools[]"));
227
230
  continue;
228
231
  }
229
232
  findings.push(...combined);
package/dist/scan.js CHANGED
@@ -121,6 +121,47 @@ function isRegularFile(path) {
121
121
  return false;
122
122
  }
123
123
  }
124
+ /** True when `candidatePath` resolves at or below `root`. */
125
+ function isPathInside(root, candidatePath) {
126
+ const resolvedCandidate = resolve(candidatePath);
127
+ const resolvedRoot = resolve(root);
128
+ if (resolvedCandidate === resolvedRoot) {
129
+ return true;
130
+ }
131
+ const rel = relative(resolvedRoot, resolvedCandidate);
132
+ if (rel === "" || rel === ".") {
133
+ return true;
134
+ }
135
+ if (rel.startsWith("..")) {
136
+ return false;
137
+ }
138
+ // On Windows, relative() may return an absolute path across drives.
139
+ if (rel.includes(":")) {
140
+ return false;
141
+ }
142
+ return true;
143
+ }
144
+ /**
145
+ * Decide whether a user-scope candidate at `candidatePath` should be attached
146
+ * to a scan of `scanTarget` rooted at `homeDir`.
147
+ *
148
+ * User-scope patterns (e.g. `~/.agents/skills/*/SKILL.md`) walk the whole
149
+ * home directory, so they can match files belonging to completely unrelated
150
+ * skills or agents. When the scan target is itself a specific location
151
+ * **inside** the user's home — e.g. scanning a single skill directory — any
152
+ * user-scope match outside that scan target belongs to a different scan and
153
+ * must not be attributed here.
154
+ *
155
+ * When the scan target lives outside the home directory (for example a
156
+ * project root in a workspace), user-scope matches are accepted as legitimate
157
+ * host-wide context for that scan.
158
+ */
159
+ function shouldKeepUserScopeCandidate(scanTarget, homeDir, candidatePath) {
160
+ if (isPathInside(homeDir, scanTarget)) {
161
+ return isPathInside(scanTarget, candidatePath);
162
+ }
163
+ return true;
164
+ }
124
165
  function toUserReportPath(pattern) {
125
166
  const normalized = normalizeUserScopePattern(pattern);
126
167
  return `~/${normalized}`;
@@ -261,6 +302,14 @@ function collectSelectedCandidates(absoluteTarget, walkedFiles, patterns, option
261
302
  const userPattern = normalizeUserScopePattern(candidate.pattern);
262
303
  if (userPattern.includes("*")) {
263
304
  for (const match of collectUserScopeWildcardMatches(options.homeDir, userPattern)) {
305
+ // A scan whose target itself lives under the user's home directory
306
+ // (e.g. a single skill at `~/.codex/skills/foo`) must only report
307
+ // findings about files inside that target. User-scope wildcards
308
+ // walk the whole home tree, so they can match sibling skills or
309
+ // other agents that belong to different scans; drop those here.
310
+ if (!shouldKeepUserScopeCandidate(absoluteTarget, options.homeDir, match.absolutePath)) {
311
+ continue;
312
+ }
264
313
  const reportPath = toUserReportPath(match.relativePath);
265
314
  if (!matchesCollectionKinds(reportPath, options.collectKinds)) {
266
315
  continue;
@@ -280,6 +329,9 @@ function collectSelectedCandidates(absoluteTarget, walkedFiles, patterns, option
280
329
  if (!existsSync(absolutePath) || !isRegularFile(absolutePath)) {
281
330
  continue;
282
331
  }
332
+ if (!shouldKeepUserScopeCandidate(absoluteTarget, options.homeDir, absolutePath)) {
333
+ continue;
334
+ }
283
335
  const reportPath = toUserReportPath(userPattern);
284
336
  if (!matchesCollectionKinds(reportPath, options.collectKinds)) {
285
337
  continue;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codegate-ai",
3
- "version": "0.14.1",
3
+ "version": "0.14.2",
4
4
  "description": "Pre-flight security scanner for AI coding tool configurations.",
5
5
  "license": "MIT",
6
6
  "type": "module",