@debugg-ai/debugg-ai-mcp 6.0.0 → 6.0.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.
@@ -320,6 +320,10 @@ async function testPageChangesHandlerInner(input, context, rawProgressCallback)
320
320
  await progressCallback({ progress: 2, total: TOTAL_STEPS, message: 'Locating evaluation workflow template...' });
321
321
  }
322
322
  const repoName = input.repoName || detectRepoName();
323
+ // An environment belongs to one project, so naming one names the project:
324
+ // the backend files the run under it (platform-98fv.21). The working folder's
325
+ // repo name is only a guess, used when no environment is named.
326
+ const namedEnvironmentId = input.environmentId || input.auth?.environmentId;
323
327
  const [templateUuid, projectUuid] = await Promise.all([
324
328
  // Cache key = the dispatch slug so the cache key and the lookup can never
325
329
  // drift apart (bug clka: the key used to be a decoupled 'app evaluation'
@@ -327,7 +331,7 @@ async function testPageChangesHandlerInner(input, context, rawProgressCallback)
327
331
  getCachedTemplateUuid(getEvalTemplateSlug(), async () => {
328
332
  return client.workflows.findEvaluationTemplate();
329
333
  }),
330
- repoName
334
+ !namedEnvironmentId && repoName
331
335
  ? getCachedProjectUuid(repoName, async (repo) => {
332
336
  try {
333
337
  return await client.findProjectByRepoName(repo);
@@ -346,7 +350,7 @@ async function testPageChangesHandlerInner(input, context, rawProgressCallback)
346
350
  // semantics: project_id is required). Surfacing "link this repo to a
347
351
  // project" now — before executeWorkflow — beats letting a backend workflow
348
352
  // node fail mid-run several minutes into the evaluation.
349
- if (!projectUuid) {
353
+ if (!projectUuid && !namedEnvironmentId) {
350
354
  const payload = {
351
355
  error: 'ProjectRequired',
352
356
  message: repoName
@@ -82,8 +82,9 @@ export class DebuggAIServerClient {
82
82
  || p.repo?.name?.endsWith(`/${short}`));
83
83
  if (repoMatch)
84
84
  return repoMatch;
85
- // Fallback to first search result
86
- return projects[0];
85
+ // No match is no project. The first search hit is a different project whose
86
+ // name merely contains this one (platform-98fv.21).
87
+ return null;
87
88
  }
88
89
  /**
89
90
  * Simplified project shape used by get/update tools — drops heavy internal
@@ -3,6 +3,7 @@
3
3
  * 4-step integration: find template → execute → poll → result
4
4
  */
5
5
  import { Telemetry, TelemetryEvents } from '../utils/telemetry.js';
6
+ import { redactRunSecrets } from '../utils/redactRunSecrets.js';
6
7
  const TERMINAL_STATUSES = new Set(['completed', 'failed', 'cancelled']);
7
8
  // Exponential backoff polling: short executions (10-15s crawls) detect terminal
8
9
  // status quickly via the early polls; long executions (60-150s browser runs)
@@ -75,7 +76,9 @@ export const createWorkflowsService = (tx) => {
75
76
  if (!response) {
76
77
  throw new Error(`Execution not found: ${executionUuid}`);
77
78
  }
78
- return response;
79
+ // platform-98fv.25: every caller (executions tool, check_app polling) reads
80
+ // the execution through here, so this is where the relay drops run secrets.
81
+ return redactRunSecrets(response);
79
82
  },
80
83
  async listExecutions(filters) {
81
84
  const { makePageInfo } = await import('../utils/pagination.js');
@@ -0,0 +1,40 @@
1
+ /**
2
+ * platform-98fv.25: the relay never passes a run secret on.
3
+ *
4
+ * The backend used to persist the password a check_app_in_browser run was given
5
+ * and serve it back in `contextData.env.password`, `state.env.password` and every
6
+ * node payload. The backend now seals it at rest and redacts it on read; this is
7
+ * the relay's own copy of that rule, so an older or misbehaving backend still
8
+ * cannot leak through the MCP.
9
+ *
10
+ * Deliberately narrow and exact (mirrors sentinal `run_secrets.redact_run_secrets`):
11
+ * - any non-empty string under a key named exactly `password` / `passwd`;
12
+ * - every string value of a `projectSecrets` / `project_secrets` mapping;
13
+ * - any string carrying the backend's sealed-value prefix.
14
+ * Identifiers such as `browserSessionId` / `resolvedCredentialId` are untouched.
15
+ */
16
+ export const REDACTED = '[REDACTED]';
17
+ const SEALED_PREFIX = 'sealed:v1:';
18
+ const SECRET_KEYS = new Set(['password', 'passwd']);
19
+ const SECRET_MAPPING_KEYS = new Set(['projectSecrets', 'project_secrets']);
20
+ function isSealed(v) {
21
+ return typeof v === 'string' && v.startsWith(SEALED_PREFIX);
22
+ }
23
+ export function redactRunSecrets(value, inMapping = false) {
24
+ if (Array.isArray(value)) {
25
+ return value.map((v) => (isSealed(v) ? REDACTED : redactRunSecrets(v)));
26
+ }
27
+ if (value && typeof value === 'object') {
28
+ const out = {};
29
+ for (const [k, v] of Object.entries(value)) {
30
+ if (typeof v === 'string' && v && (inMapping || SECRET_KEYS.has(k) || isSealed(v))) {
31
+ out[k] = REDACTED;
32
+ }
33
+ else {
34
+ out[k] = redactRunSecrets(v, SECRET_MAPPING_KEYS.has(k));
35
+ }
36
+ }
37
+ return out;
38
+ }
39
+ return value;
40
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@debugg-ai/debugg-ai-mcp",
3
- "version": "6.0.0",
3
+ "version": "6.0.2",
4
4
  "description": "Zero-Config, Fully AI-Managed End-to-End Testing for all code gen platforms.",
5
5
  "type": "module",
6
6
  "caddy": "2.11.3",