Skip to content

feat(security-questionnaire): add browser extension#3064

Open
tofikwest wants to merge 3 commits into
mainfrom
feat/security-questionnaire-extension
Open

feat(security-questionnaire): add browser extension#3064
tofikwest wants to merge 3 commits into
mainfrom
feat/security-questionnaire-extension

Conversation

@tofikwest

@tofikwest tofikwest commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

Adds the Comp AI Security Questionnaire Chrome extension under apps/browser-extension/security-questionnaire-ext, including popup/sidepanel/content scripts, org switching, Google Forms and Sheets support, and Chrome Web Store release workflow.

API changes:

  • Allows webpage-only /v1/questionnaire/answer-single generation without persisting questionnaire records.
  • Adds COMP_EXTENSION_TRUSTED_ORIGINS and method/path-scoped extension CORS/origin handling.

Validation:

  • bun run --filter '@trycompai/security-questionnaire-extension' test
  • bun run --filter '@trycompai/security-questionnaire-extension' typecheck
  • bun run --filter '@trycompai/security-questionnaire-extension' build
  • cd apps/api && bunx jest src/auth/origin-check.middleware.spec.ts src/auth/cors-origin.middleware.spec.ts --passWithNoTests

Note:

  • Full API typecheck currently fails in unrelated existing cloud-security/integration-platform spec files, not in this PR's auth/extension files.

Summary by cubic

Adds a Chrome MV3 extension to generate and insert security questionnaire answers on vendor pages and Google Forms/Sheets, and replaces CORS handling with stricter, route-scoped origin checks for the extension. Also supports webpage-only single-answer generation and adds a release workflow.

  • New Features

    • Extension: @trycompai/security-questionnaire-extension with popup and side panel, inline buttons/preview, org switching, domain confirmation, auto content-script injection, and a review/approve/insert queue. Google Sheets support via direct Sheets API (auto column width/wrap) or guided paste.
    • API: extracted origin-policy (static vs Chrome extension checks) and added cors-origin.middleware for preflight/credentials. Route-allowlist for the extension (/api/auth/get-session, /v1/auth/me, /api/auth/organization/set-active, /v1/questionnaire/answer-single). /v1/questionnaire/answer-single accepts webpage-only drafts and enforces org-scoped saves; improved Swagger docs.
    • Release: GitHub Action to build/sign/publish the extension from the release branch; ignore .wxt/dist in .gitignore.
  • Migration

    • API env: set COMP_EXTENSION_TRUSTED_ORIGINS=chrome-extension://<extension-id>; keep AUTH_TRUSTED_ORIGINS for web apps.
    • Extension env: set WXT_PUBLIC_API_BASE_URL and WXT_PUBLIC_APP_BASE_URL; optional WXT_EXTENSION_KEY (stable local ID) and WXT_GOOGLE_OAUTH_CLIENT_ID (direct Sheets API).
    • Push to the release branch to trigger the security-questionnaire-extension-release workflow.

Written for commit 4a11867. Summary will update on new commits.

Review in cubic

@vercel

vercel Bot commented Jun 8, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
app Ready Ready Preview, Comment Jun 9, 2026 2:27pm
comp-framework-editor Ready Ready Preview, Comment Jun 9, 2026 2:27pm
portal Ready Ready Preview, Comment Jun 9, 2026 2:27pm

Request Review

@mintlify

mintlify Bot commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

Preview deployment for your docs. Learn more about Mintlify Previews.

Project Status Preview Updated (UTC)
CompAI 🟢 Ready View Preview Jun 8, 2026, 11:18 PM

💡 Tip: Enable Workflows to automatically generate PRs for you.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

32 issues found across 117 files

Confidence score: 2/5

  • Several high-confidence, user-facing regressions are present in the extension flow, including disabled docs footer actions in apps/browser-extension/security-questionnaire-ext/src/entrypoints/sidepanel/surface-ui.ts and regenerate overwriting manual edits in apps/browser-extension/security-questionnaire-ext/src/lib/queue.ts.
  • There are concrete correctness/race risks in async UI handling (apps/browser-extension/security-questionnaire-ext/src/entrypoints/content.ts) and fallback reliability gaps (apps/browser-extension/security-questionnaire-ext/src/lib/dom/sheets-detection.ts, apps/browser-extension/security-questionnaire-ext/src/lib/dom/sheets-runtime.ts) that can misroute previews or stop detection.
  • Security posture needs tightening before merge: formula-injection hardening is missing in apps/browser-extension/security-questionnaire-ext/src/lib/sheets-paste-plan.ts, origin/CORS handling has unsafe edge cases in apps/api/src/auth/origin-policy.ts and apps/api/src/auth/cors-origin.middleware.ts, and dialog confirmation can be bypassed via open shadow root in apps/browser-extension/security-questionnaire-ext/src/lib/dom/content-dialog.ts.
  • Pay close attention to apps/browser-extension/security-questionnaire-ext/src/lib/sheets-paste-plan.ts, apps/api/src/auth/origin-policy.ts, apps/api/src/auth/cors-origin.middleware.ts, apps/browser-extension/security-questionnaire-ext/src/entrypoints/content.ts, apps/browser-extension/security-questionnaire-ext/src/lib/queue.ts - these combine security-sensitive behavior with high-confidence user-impacting regressions.
Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="apps/browser-extension/security-questionnaire-ext/src/entrypoints/sidepanel/surface-ui.ts">

<violation number="1" location="apps/browser-extension/security-questionnaire-ext/src/entrypoints/sidepanel/surface-ui.ts:32">
P2: Docs CTA label says “Insert” while action is copy, creating misleading UI behavior.</violation>

<violation number="2" location="apps/browser-extension/security-questionnaire-ext/src/entrypoints/sidepanel/surface-ui.ts:45">
P1: Docs footer action is always disabled, so `copy-sheet-answers` cannot run.</violation>
</file>

<file name="apps/api/src/auth/cors-origin.middleware.ts">

<violation number="1" location="apps/api/src/auth/cors-origin.middleware.ts:23">
P2: Dynamic CORS response headers are missing `Vary`, which can cause cache-mixed CORS decisions across origins. Add `Vary: Origin` (and request-header vary) when reflecting origin/headers.</violation>
</file>

<file name="apps/browser-extension/security-questionnaire-ext/src/lib/dom/sheets-detection.ts">

<violation number="1" location="apps/browser-extension/security-questionnaire-ext/src/lib/dom/sheets-detection.ts:94">
P2: Uncaught fetch errors break endpoint fallback flow. Catch fetch failures in `fetchTable` and return `null` so later endpoints can still be attempted.</violation>
</file>

<file name="apps/browser-extension/security-questionnaire-ext/src/lib/dom/sheets-runtime.ts">

<violation number="1" location="apps/browser-extension/security-questionnaire-ext/src/lib/dom/sheets-runtime.ts:10">
P2: Runtime message failure prevents local sheet-question fallback detection. Catch message errors here so page/DOM detection still runs.</violation>
</file>

<file name="apps/browser-extension/security-questionnaire-ext/src/lib/background/google-sheets-formatting.ts">

<violation number="1" location="apps/browser-extension/security-questionnaire-ext/src/lib/background/google-sheets-formatting.ts:53">
P2: `gid` validation allows negative sheet IDs, which can generate invalid Google Sheets batchUpdate ranges.</violation>
</file>

<file name="apps/browser-extension/security-questionnaire-ext/src/lib/dom/sheets-table.ts">

<violation number="1" location="apps/browser-extension/security-questionnaire-ext/src/lib/dom/sheets-table.ts:27">
P2: Uncaught JSON.parse can crash table parsing on malformed GViz responses. Guard parse errors and return null for invalid payloads.</violation>
</file>

<file name="apps/browser-extension/security-questionnaire-ext/src/lib/queue-approval.ts">

<violation number="1" location="apps/browser-extension/security-questionnaire-ext/src/lib/queue-approval.ts:6">
P2: Bulk approval accepts whitespace-only answers as approved content. Use a trimmed non-empty check before approving.</violation>
</file>

<file name="apps/browser-extension/security-questionnaire-ext/src/lib/storage.ts">

<violation number="1" location="apps/browser-extension/security-questionnaire-ext/src/lib/storage.ts:16">
P2: `setSelectedOrganizationId` does not trim/normalize input, allowing whitespace-only IDs to be persisted as active organization IDs.

(Based on your team's feedback about normalizing blank organization identifiers before persistence.) [FEEDBACK_USED].</violation>

<violation number="2" location="apps/browser-extension/security-questionnaire-ext/src/lib/storage.ts:28">
P2: Non-atomic read/merge/write on shared storage maps can lose updates under concurrent calls. This can drop confirmed-domain or detection settings set by another tab/context.</violation>
</file>

<file name="apps/browser-extension/security-questionnaire-ext/src/lib/scan-debug.ts">

<violation number="1" location="apps/browser-extension/security-questionnaire-ext/src/lib/scan-debug.ts:8">
P3: Surface validation is duplicated instead of using the shared guard. Reuse `isQuestionnaireSurface` to keep one source of truth and avoid future mismatch bugs.</violation>
</file>

<file name="apps/browser-extension/security-questionnaire-ext/src/entrypoints/sidepanel/sheet-mapping-actions.ts">

<violation number="1" location="apps/browser-extension/security-questionnaire-ext/src/entrypoints/sidepanel/sheet-mapping-actions.ts:40">
P2: Failed mapping save drops the user’s submitted draft instead of allowing retry with existing input. Keep the dialog open or restore the draft after error so users don’t lose entered mapping data.</violation>
</file>

<file name="apps/browser-extension/security-questionnaire-ext/src/lib/dom/review-panel.ts">

<violation number="1" location="apps/browser-extension/security-questionnaire-ext/src/lib/dom/review-panel.ts:5">
P3: `ReviewPanel` is unused dead code; no caller imports or instantiates it.</violation>
</file>

<file name="apps/browser-extension/security-questionnaire-ext/src/entrypoints/sidepanel/answer-edits.ts">

<violation number="1" location="apps/browser-extension/security-questionnaire-ext/src/entrypoints/sidepanel/answer-edits.ts:10">
P2: Autosave errors are silently ignored in the change handler, so failed saves can be lost without user-visible feedback.

(Based on your team's feedback about surfacing failed autosaves instead of silently dropping them.) [FEEDBACK_USED]</violation>
</file>

<file name="apps/browser-extension/security-questionnaire-ext/src/lib/background/queue-actions.ts">

<violation number="1" location="apps/browser-extension/security-questionnaire-ext/src/lib/background/queue-actions.ts:125">
P2: Single-item generation can leave queue items permanently in `generating` when API generation fails. Catch generation errors and convert them to a failed/flagged generated-answer payload so status is finalized.</violation>
</file>

<file name="apps/browser-extension/security-questionnaire-ext/src/lib/api.ts">

<violation number="1" location="apps/browser-extension/security-questionnaire-ext/src/lib/api.ts:49">
P2: Uncaught JSON.parse can mask HTTP failures and throw non-actionable SyntaxError. Parse failures should fall back to a normal request error path.</violation>
</file>

<file name="apps/browser-extension/security-questionnaire-ext/src/lib/queue.ts">

<violation number="1" location="apps/browser-extension/security-questionnaire-ext/src/lib/queue.ts:137">
P1: Regenerate path clobbers manually edited answers. Preserve edited non-empty item.answer and skip seeding generated text for those items.</violation>
</file>

<file name="apps/browser-extension/security-questionnaire-ext/src/lib/dom/sheets-dom.ts">

<violation number="1" location="apps/browser-extension/security-questionnaire-ext/src/lib/dom/sheets-dom.ts:27">
P2: Matrix allocation uses absolute sheet indices instead of normalizing to visible bounds, causing unnecessary large arrays and slow parsing.</violation>

<violation number="2" location="apps/browser-extension/security-questionnaire-ext/src/lib/dom/sheets-dom.ts:84">
P2: `parseGid` can throw on malformed URL hash because `decodeURIComponent` is not guarded.</violation>
</file>

<file name="apps/browser-extension/security-questionnaire-ext/src/entrypoints/content.ts">

<violation number="1" location="apps/browser-extension/security-questionnaire-ext/src/entrypoints/content.ts:131">
P1: Using global `activePreview` across awaited generate calls causes cross-request UI races. Concurrent clicks can render one field’s result in another field’s preview or close the wrong preview.</violation>
</file>

<file name="apps/browser-extension/security-questionnaire-ext/src/lib/content-messaging.ts">

<violation number="1" location="apps/browser-extension/security-questionnaire-ext/src/lib/content-messaging.ts:24">
P2: `comp:generate-visible-page` is parsed but never handled by the content script. Calls of this message will always return an error despite being treated as valid input.</violation>
</file>

<file name="apps/browser-extension/security-questionnaire-ext/src/lib/background/batch-generation.ts">

<violation number="1" location="apps/browser-extension/security-questionnaire-ext/src/lib/background/batch-generation.ts:45">
P2: Batch generation writes stale queue snapshots and can clobber concurrent queue updates. This can revert item approvals/edits while generation is in progress.</violation>
</file>

<file name="apps/browser-extension/security-questionnaire-ext/src/lib/sheets-paste-plan.ts">

<violation number="1" location="apps/browser-extension/security-questionnaire-ext/src/lib/sheets-paste-plan.ts:62">
P2: Row/column parsing accepts 0, but Sheets A1 coordinates are 1-based. Reject zero indices in fieldId parsing to avoid invalid range output.</violation>

<violation number="2" location="apps/browser-extension/security-questionnaire-ext/src/lib/sheets-paste-plan.ts:95">
P1: TSV cell escaping misses formula-injection hardening for leading spreadsheet formula characters. Prefix dangerous leading chars after quote-escaping to prevent pasted cells executing formulas.

(Based on your team's feedback about CSV/TSV formula-injection escaping order.) [FEEDBACK_USED].</violation>
</file>

<file name="apps/browser-extension/security-questionnaire-ext/src/entrypoints/sidepanel/content-collector.ts">

<violation number="1" location="apps/browser-extension/security-questionnaire-ext/src/entrypoints/sidepanel/content-collector.ts:21">
P2: Nullish coalescing here suppresses fallback debug text when `sheetScan.message` is empty. Use a truthy fallback so content-scan debug is shown instead of blank status.</violation>
</file>

<file name="apps/browser-extension/security-questionnaire-ext/src/entrypoints/sidepanel/active-tab.ts">

<violation number="1" location="apps/browser-extension/security-questionnaire-ext/src/entrypoints/sidepanel/active-tab.ts:9">
P3: Duplicate `getHost` implementation in popup/main.ts — import from active-tab.ts instead.</violation>
</file>

<file name="apps/api/src/auth/origin-policy.ts">

<violation number="1" location="apps/api/src/auth/origin-policy.ts:78">
P1: Wildcard trusted-origin fallback accepts non-HTTPS origins. Require HTTPS before allowing `.trycomp.ai`/`.trust.inc` hostname matches.</violation>
</file>

<file name="apps/browser-extension/security-questionnaire-ext/src/lib/response-guards.ts">

<violation number="1" location="apps/browser-extension/security-questionnaire-ext/src/lib/response-guards.ts:24">
P2: `isItemResponse` claims `queue` is present but does not validate it. This makes the type guard unsound and can let malformed runtime messages pass as valid.</violation>
</file>

<file name="apps/browser-extension/security-questionnaire-ext/src/lib/message-utils.ts">

<violation number="1" location="apps/browser-extension/security-questionnaire-ext/src/lib/message-utils.ts:10">
P2: `parseDetectedQuestion` allows empty-string `id`, which can cause incorrect matches in the queue lookup (`fieldId === id`). Add `value.id.length === 0` to the rejection condition.</violation>
</file>

<file name="apps/browser-extension/security-questionnaire-ext/src/lib/dom/field-detection.ts">

<violation number="1" location="apps/browser-extension/security-questionnaire-ext/src/lib/dom/field-detection.ts:275">
P2: Keyword fallback misclassifies first-person compliance statements as questions, causing over-detection of fields from answer-like text.

(Based on your team's feedback about conservative questionnaire chunking and excluding first-person prefixes.) [FEEDBACK_USED].</violation>
</file>

<file name="apps/browser-extension/security-questionnaire-ext/src/lib/dom/sheets-question-cells.ts">

<violation number="1" location="apps/browser-extension/security-questionnaire-ext/src/lib/dom/sheets-question-cells.ts:200">
P2: Header detection uses substring matching for answer headers, so data rows containing words like "response" can be misclassified as headers and removed from extraction.</violation>
</file>

<file name="apps/browser-extension/security-questionnaire-ext/src/lib/dom/content-dialog.ts">

<violation number="1" location="apps/browser-extension/security-questionnaire-ext/src/lib/dom/content-dialog.ts:10">
P1: Domain confirmation can be bypassed because the dialog shadow root is open to page scripts. Use a closed shadow root so untrusted page JS cannot programmatically press Confirm.</violation>
</file>

Tip: instead of fixing issues one by one fix them all with cubic
Partial review: This PR has more than 100 files, so cubic reviewed the highest-priority files first.
For a deeper review of large PRs, comment @cubic-dev-ai ultrareview. Learn more.

Re-trigger cubic

answerCount: number;
surface: Surface;
}): string {
if (params.surface === 'docs') return 'disabled';

@cubic-dev-ai cubic-dev-ai Bot Jun 8, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: Docs footer action is always disabled, so copy-sheet-answers cannot run.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/browser-extension/security-questionnaire-ext/src/entrypoints/sidepanel/surface-ui.ts, line 45:

<comment>Docs footer action is always disabled, so `copy-sheet-answers` cannot run.</comment>

<file context>
@@ -0,0 +1,47 @@
+  answerCount: number;
+  surface: Surface;
+}): string {
+  if (params.surface === 'docs') return 'disabled';
+  return params.approved === 0 ? 'disabled' : '';
+}
</file context>
Fix with cubic

return {
...item,
status: hasAnswer ? 'generated' : 'flagged',
answer: hasAnswer ? answer : null,

@cubic-dev-ai cubic-dev-ai Bot Jun 8, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: Regenerate path clobbers manually edited answers. Preserve edited non-empty item.answer and skip seeding generated text for those items.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/browser-extension/security-questionnaire-ext/src/lib/queue.ts, line 137:

<comment>Regenerate path clobbers manually edited answers. Preserve edited non-empty item.answer and skip seeding generated text for those items.</comment>

<file context>
@@ -0,0 +1,272 @@
+    return {
+      ...item,
+      status: hasAnswer ? 'generated' : 'flagged',
+      answer: hasAnswer ? answer : null,
+      confidence: hasAnswer ? getAnswerConfidence(params.answer) : 'low',
+      sources: params.answer.sources,
</file context>
Fix with cubic


setInlineButtonState(button, 'busy');
activePreview?.close();
activePreview = new InlinePreview(button);

@cubic-dev-ai cubic-dev-ai Bot Jun 8, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: Using global activePreview across awaited generate calls causes cross-request UI races. Concurrent clicks can render one field’s result in another field’s preview or close the wrong preview.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/browser-extension/security-questionnaire-ext/src/entrypoints/content.ts, line 131:

<comment>Using global `activePreview` across awaited generate calls causes cross-request UI races. Concurrent clicks can render one field’s result in another field’s preview or close the wrong preview.</comment>

<file context>
@@ -0,0 +1,296 @@
+
+  setInlineButtonState(button, 'busy');
+  activePreview?.close();
+  activePreview = new InlinePreview(button);
+  activePreview.showLoading(candidate.question);
+
</file context>
Fix with cubic

}

function escapeTsvCell(value: string): string {
return value.replace(/\r?\n/g, ' ').replace(/\t/g, ' ').trim();

@cubic-dev-ai cubic-dev-ai Bot Jun 8, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: TSV cell escaping misses formula-injection hardening for leading spreadsheet formula characters. Prefix dangerous leading chars after quote-escaping to prevent pasted cells executing formulas.

(Based on your team's feedback about CSV/TSV formula-injection escaping order.) .

View Feedback

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/browser-extension/security-questionnaire-ext/src/lib/sheets-paste-plan.ts, line 95:

<comment>TSV cell escaping misses formula-injection hardening for leading spreadsheet formula characters. Prefix dangerous leading chars after quote-escaping to prevent pasted cells executing formulas.

(Based on your team's feedback about CSV/TSV formula-injection escaping order.) .</comment>

<file context>
@@ -0,0 +1,96 @@
+}
+
+function escapeTsvCell(value: string): string {
+  return value.replace(/\r?\n/g, ' ').replace(/\t/g, ' ').trim();
+}
</file context>
Fix with cubic

origin: string;
path: string;
}): boolean {
return (

@cubic-dev-ai cubic-dev-ai Bot Jun 8, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: Wildcard trusted-origin fallback accepts non-HTTPS origins. Require HTTPS before allowing .trycomp.ai/.trust.inc hostname matches.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/api/src/auth/origin-policy.ts, line 78:

<comment>Wildcard trusted-origin fallback accepts non-HTTPS origins. Require HTTPS before allowing `.trycomp.ai`/`.trust.inc` hostname matches.</comment>

<file context>
@@ -0,0 +1,112 @@
+  origin: string;
+  path: string;
+}): boolean {
+  return (
+    isCompExtensionOrigin(params.origin) &&
+    isCompExtensionAllowedRoute({ method: params.method, path: params.path })
</file context>
Fix with cubic

) {
return true;
}
return /\b(access|audit|availability|backup|business continuity|compliance|control|data|disaster recovery|encryption|incident|information security|mfa|password|policy|privacy|risk|soc 2|security|subprocessor|vendor)\b/i

@cubic-dev-ai cubic-dev-ai Bot Jun 8, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Keyword fallback misclassifies first-person compliance statements as questions, causing over-detection of fields from answer-like text.

(Based on your team's feedback about conservative questionnaire chunking and excluding first-person prefixes.) .

View Feedback

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/browser-extension/security-questionnaire-ext/src/lib/dom/field-detection.ts, line 275:

<comment>Keyword fallback misclassifies first-person compliance statements as questions, causing over-detection of fields from answer-like text.

(Based on your team's feedback about conservative questionnaire chunking and excluding first-person prefixes.) .</comment>

<file context>
@@ -0,0 +1,277 @@
+  ) {
+    return true;
+  }
+  return /\b(access|audit|availability|backup|business continuity|compliance|control|data|disaster recovery|encryption|incident|information security|mfa|password|policy|privacy|risk|soc 2|security|subprocessor|vendor)\b/i
+    .test(value);
+}
</file context>
Fix with cubic

questionColumn: number;
}): number {
const answerIndex = params.header.findIndex((value) =>
/answer|response|reply|vendor response/i.test(value),

@cubic-dev-ai cubic-dev-ai Bot Jun 8, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Header detection uses substring matching for answer headers, so data rows containing words like "response" can be misclassified as headers and removed from extraction.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/browser-extension/security-questionnaire-ext/src/lib/dom/sheets-question-cells.ts, line 200:

<comment>Header detection uses substring matching for answer headers, so data rows containing words like "response" can be misclassified as headers and removed from extraction.</comment>

<file context>
@@ -0,0 +1,287 @@
+  questionColumn: number;
+}): number {
+  const answerIndex = params.header.findIndex((value) =>
+    /answer|response|reply|vendor response/i.test(value),
+  );
+  return answerIndex >= 0 ? answerIndex : params.questionColumn + 1;
</file context>
Fix with cubic

if (!isRecord(value) || !isRecord(value.debug)) return null;
const debug = value.debug;
if (
debug.surface !== 'sheets' &&

@cubic-dev-ai cubic-dev-ai Bot Jun 8, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P3: Surface validation is duplicated instead of using the shared guard. Reuse isQuestionnaireSurface to keep one source of truth and avoid future mismatch bugs.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/browser-extension/security-questionnaire-ext/src/lib/scan-debug.ts, line 8:

<comment>Surface validation is duplicated instead of using the shared guard. Reuse `isQuestionnaireSurface` to keep one source of truth and avoid future mismatch bugs.</comment>

<file context>
@@ -0,0 +1,66 @@
+  if (!isRecord(value) || !isRecord(value.debug)) return null;
+  const debug = value.debug;
+  if (
+    debug.surface !== 'sheets' &&
+    debug.surface !== 'docs' &&
+    debug.surface !== 'forms' &&
</file context>
Fix with cubic

import type { WritableField } from './field-detection';
import { insertAnswerIntoField } from './field-actions';

export class ReviewPanel {

@cubic-dev-ai cubic-dev-ai Bot Jun 8, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P3: ReviewPanel is unused dead code; no caller imports or instantiates it.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/browser-extension/security-questionnaire-ext/src/lib/dom/review-panel.ts, line 5:

<comment>`ReviewPanel` is unused dead code; no caller imports or instantiates it.</comment>

<file context>
@@ -0,0 +1,142 @@
+import type { WritableField } from './field-detection';
+import { insertAnswerIntoField } from './field-actions';
+
+export class ReviewPanel {
+  private root: HTMLElement;
+
</file context>
Fix with cubic

return tab;
}

export function getHost(url: string): string {

@cubic-dev-ai cubic-dev-ai Bot Jun 8, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P3: Duplicate getHost implementation in popup/main.ts — import from active-tab.ts instead.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/browser-extension/security-questionnaire-ext/src/entrypoints/sidepanel/active-tab.ts, line 9:

<comment>Duplicate `getHost` implementation in popup/main.ts — import from active-tab.ts instead.</comment>

<file context>
@@ -0,0 +1,15 @@
+  return tab;
+}
+
+export function getHost(url: string): string {
+  try {
+    return new URL(url).host;
</file context>
Fix with cubic

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant