{"version": "2.1.0", "$schema": "https://json.schemastore.org/sarif-2.1.0.json", "runs": [{"tool": {"driver": {"name": "Repobility", "informationUri": "https://repobility.com", "rules": [{"id": "scanner-bead75b0f9233e05", "name": "No API endpoints detected", "shortDescription": {"text": "No API endpoints detected"}, "fullDescription": {"text": "The scanner did not find FastAPI/Flask/Express/NestJS/GraphQL/gRPC routes. If this repo exposes APIs, the framework may be unsupported."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "info", "confidence": 1.0}}, {"id": "scanner-5a9e824bc9fa7eba", "name": "`dangerouslySetInnerHTML` used in a React component \u2014 sites/chef-s-kitchen/src/app/layout.tsx:74", "shortDescription": {"text": "`dangerouslySetInnerHTML` used in a React component \u2014 sites/chef-s-kitchen/src/app/layout.tsx:74"}, "fullDescription": {"text": "Open XSS surface unless the input is provably trusted. Replace with explicit JSX or sanitize via a vetted library.\n\nWhy: OWASP basics. Already partially flagged by the security analyzer.\nRule id: fq.dangerous-html"}, "properties": {"scanner": "scanner-primary", "layer": "frontend", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-1d20c89705e6b875", "name": "`truncate` class without `title=` for hover reveal \u2014 sites/chef-s-kitchen/src/app/search/page.tsx:249", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 sites/chef-s-kitchen/src/app/search/page.tsx:249"}, "fullDescription": {"text": "A truncated value should reveal the full text on hover. Pass the full string via `title={...}` so the user can read it.\n\nWhy: P2 in CHECKLIST.md \u2014 truncate without hover-reveal.\nRule id: fq.truncate.no-title"}, "properties": {"scanner": "scanner-primary", "layer": "frontend", "severity": "info", "confidence": 1.0}}, {"id": "scanner-bd60fce9c9f36215", "name": "`truncate` class without `title=` for hover reveal \u2014 sites/chef-s-kitchen/src/app/products/[slug]/page.tsx:164", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 sites/chef-s-kitchen/src/app/products/[slug]/page.tsx:164"}, "fullDescription": {"text": "A truncated value should reveal the full text on hover. Pass the full string via `title={...}` so the user can read it.\n\nWhy: P2 in CHECKLIST.md \u2014 truncate without hover-reveal.\nRule id: fq.truncate.no-title"}, "properties": {"scanner": "scanner-primary", "layer": "frontend", "severity": "info", "confidence": 1.0}}, {"id": "scanner-57bb6300bdf201b7", "name": "`dangerouslySetInnerHTML` used in a React component \u2014 sites/chef-s-kitchen/src/app/products/[slug]/page.tsx:151", "shortDescription": {"text": "`dangerouslySetInnerHTML` used in a React component \u2014 sites/chef-s-kitchen/src/app/products/[slug]/page.tsx:151"}, "fullDescription": {"text": "Open XSS surface unless the input is provably trusted. Replace with explicit JSX or sanitize via a vetted library.\n\nWhy: OWASP basics. Already partially flagged by the security analyzer.\nRule id: fq.dangerous-html"}, "properties": {"scanner": "scanner-primary", "layer": "frontend", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-b85ba489004b119b", "name": "`truncate` class without `title=` for hover reveal \u2014 sites/chef-s-kitchen/src/components/cart/CartItemsList.tsx:59", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 sites/chef-s-kitchen/src/components/cart/CartItemsList.tsx:59"}, "fullDescription": {"text": "A truncated value should reveal the full text on hover. Pass the full string via `title={...}` so the user can read it.\n\nWhy: P2 in CHECKLIST.md \u2014 truncate without hover-reveal.\nRule id: fq.truncate.no-title"}, "properties": {"scanner": "scanner-primary", "layer": "frontend", "severity": "info", "confidence": 1.0}}, {"id": "scanner-9e0724014866b892", "name": "`truncate` class without `title=` for hover reveal \u2014 sites/chef-s-kitchen/src/components/search/SearchTypeahead.tsx:258", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 sites/chef-s-kitchen/src/components/search/SearchTypeahead.tsx:258"}, "fullDescription": {"text": "A truncated value should reveal the full text on hover. Pass the full string via `title={...}` so the user can read it.\n\nWhy: P2 in CHECKLIST.md \u2014 truncate without hover-reveal.\nRule id: fq.truncate.no-title"}, "properties": {"scanner": "scanner-primary", "layer": "frontend", "severity": "info", "confidence": 1.0}}, {"id": "scanner-288487f3299608d3", "name": "`dangerouslySetInnerHTML` used in a React component \u2014 sites/chef-s-kitchen/src/components/search/SearchTypeahead.tsx:259", "shortDescription": {"text": "`dangerouslySetInnerHTML` used in a React component \u2014 sites/chef-s-kitchen/src/components/search/SearchTypeahead.tsx:259"}, "fullDescription": {"text": "Open XSS surface unless the input is provably trusted. Replace with explicit JSX or sanitize via a vetted library.\n\nWhy: OWASP basics. Already partially flagged by the security analyzer.\nRule id: fq.dangerous-html"}, "properties": {"scanner": "scanner-primary", "layer": "frontend", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-18acb51a6b999d92", "name": "`truncate` class without `title=` for hover reveal \u2014 sites/chef-s-kitchen/src/components/quote/QuoteItemsList.tsx:65", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 sites/chef-s-kitchen/src/components/quote/QuoteItemsList.tsx:65"}, "fullDescription": {"text": "A truncated value should reveal the full text on hover. Pass the full string via `title={...}` so the user can read it.\n\nWhy: P2 in CHECKLIST.md \u2014 truncate without hover-reveal.\nRule id: fq.truncate.no-title"}, "properties": {"scanner": "scanner-primary", "layer": "frontend", "severity": "info", "confidence": 1.0}}, {"id": "scanner-6d33b66bcefa8130", "name": "`dangerouslySetInnerHTML` used in a React component \u2014 sites/chef-s-kitchen/src/components/content/RichContent.tsx:104", "shortDescription": {"text": "`dangerouslySetInnerHTML` used in a React component \u2014 sites/chef-s-kitchen/src/components/content/RichContent.tsx:104"}, "fullDescription": {"text": "Open XSS surface unless the input is provably trusted. Replace with explicit JSX or sanitize via a vetted library.\n\nWhy: OWASP basics. Already partially flagged by the security analyzer.\nRule id: fq.dangerous-html"}, "properties": {"scanner": "scanner-primary", "layer": "frontend", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-ffaed09919e03fb0", "name": "Stray `console.log` in TS/JS \u2014 sites/chef-s-kitchen/src/components/hero/useWaveScene.ts:34", "shortDescription": {"text": "Stray `console.log` in TS/JS \u2014 sites/chef-s-kitchen/src/components/hero/useWaveScene.ts:34"}, "fullDescription": {"text": "Replace with the toast helper, an error boundary, or remove. `console.warn` / `console.error` are acceptable.\n\nWhy: Hygiene \u2014 easy to leak debug output.\nRule id: fq.console-leak"}, "properties": {"scanner": "scanner-primary", "layer": "frontend", "severity": "low", "confidence": 1.0}}, {"id": "scanner-17e8b09beb88c3f5", "name": "`truncate` class without `title=` for hover reveal \u2014 sites/chef-s-kitchen/src/components/product/ProductTabs.tsx:158", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 sites/chef-s-kitchen/src/components/product/ProductTabs.tsx:158"}, "fullDescription": {"text": "A truncated value should reveal the full text on hover. Pass the full string via `title={...}` so the user can read it.\n\nWhy: P2 in CHECKLIST.md \u2014 truncate without hover-reveal.\nRule id: fq.truncate.no-title"}, "properties": {"scanner": "scanner-primary", "layer": "frontend", "severity": "info", "confidence": 1.0}}, {"id": "scanner-da658aa7feaf93f2", "name": "`truncate` class without `title=` for hover reveal \u2014 sites/industry-kitchens/src/app/search/page.tsx:214", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 sites/industry-kitchens/src/app/search/page.tsx:214"}, "fullDescription": {"text": "A truncated value should reveal the full text on hover. Pass the full string via `title={...}` so the user can read it.\n\nWhy: P2 in CHECKLIST.md \u2014 truncate without hover-reveal.\nRule id: fq.truncate.no-title"}, "properties": {"scanner": "scanner-primary", "layer": "frontend", "severity": "info", "confidence": 1.0}}, {"id": "scanner-99f64ea91264af93", "name": "`truncate` class without `title=` for hover reveal \u2014 sites/industry-kitchens/src/app/products/[slug]/page.tsx:130", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 sites/industry-kitchens/src/app/products/[slug]/page.tsx:130"}, "fullDescription": {"text": "A truncated value should reveal the full text on hover. Pass the full string via `title={...}` so the user can read it.\n\nWhy: P2 in CHECKLIST.md \u2014 truncate without hover-reveal.\nRule id: fq.truncate.no-title"}, "properties": {"scanner": "scanner-primary", "layer": "frontend", "severity": "info", "confidence": 1.0}}, {"id": "scanner-bc9061f41cfc7b54", "name": "`truncate` class without `title=` for hover reveal \u2014 sites/industry-kitchens/src/app/blog/[slug]/page.tsx:57", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 sites/industry-kitchens/src/app/blog/[slug]/page.tsx:57"}, "fullDescription": {"text": "A truncated value should reveal the full text on hover. Pass the full string via `title={...}` so the user can read it.\n\nWhy: P2 in CHECKLIST.md \u2014 truncate without hover-reveal.\nRule id: fq.truncate.no-title"}, "properties": {"scanner": "scanner-primary", "layer": "frontend", "severity": "info", "confidence": 1.0}}, {"id": "scanner-41ec479eb6746cd4", "name": "`truncate` class without `title=` for hover reveal \u2014 sites/industry-kitchens/src/components/cart/CartItemsList.tsx:59", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 sites/industry-kitchens/src/components/cart/CartItemsList.tsx:59"}, "fullDescription": {"text": "A truncated value should reveal the full text on hover. Pass the full string via `title={...}` so the user can read it.\n\nWhy: P2 in CHECKLIST.md \u2014 truncate without hover-reveal.\nRule id: fq.truncate.no-title"}, "properties": {"scanner": "scanner-primary", "layer": "frontend", "severity": "info", "confidence": 1.0}}, {"id": "scanner-248038fc108a514d", "name": "`truncate` class without `title=` for hover reveal \u2014 sites/industry-kitchens/src/components/layout/HeaderSearch.tsx:208", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 sites/industry-kitchens/src/components/layout/HeaderSearch.tsx:208"}, "fullDescription": {"text": "A truncated value should reveal the full text on hover. Pass the full string via `title={...}` so the user can read it.\n\nWhy: P2 in CHECKLIST.md \u2014 truncate without hover-reveal.\nRule id: fq.truncate.no-title"}, "properties": {"scanner": "scanner-primary", "layer": "frontend", "severity": "info", "confidence": 1.0}}, {"id": "scanner-1b8bc5f5cf9aaf25", "name": "`dangerouslySetInnerHTML` used in a React component \u2014 sites/industry-kitchens/src/components/layout/HeaderSearch.tsx:209", "shortDescription": {"text": "`dangerouslySetInnerHTML` used in a React component \u2014 sites/industry-kitchens/src/components/layout/HeaderSearch.tsx:209"}, "fullDescription": {"text": "Open XSS surface unless the input is provably trusted. Replace with explicit JSX or sanitize via a vetted library.\n\nWhy: OWASP basics. Already partially flagged by the security analyzer.\nRule id: fq.dangerous-html"}, "properties": {"scanner": "scanner-primary", "layer": "frontend", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-246bae3e62ab1db1", "name": "`truncate` class without `title=` for hover reveal \u2014 sites/industry-kitchens/src/components/search/SearchTypeahead.tsx:2", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 sites/industry-kitchens/src/components/search/SearchTypeahead.tsx:239"}, "fullDescription": {"text": "A truncated value should reveal the full text on hover. Pass the full string via `title={...}` so the user can read it.\n\nWhy: P2 in CHECKLIST.md \u2014 truncate without hover-reveal.\nRule id: fq.truncate.no-title"}, "properties": {"scanner": "scanner-primary", "layer": "frontend", "severity": "info", "confidence": 1.0}}, {"id": "scanner-c4a6be640f7e86ca", "name": "`dangerouslySetInnerHTML` used in a React component \u2014 sites/industry-kitchens/src/components/search/SearchTypeahead.tsx:", "shortDescription": {"text": "`dangerouslySetInnerHTML` used in a React component \u2014 sites/industry-kitchens/src/components/search/SearchTypeahead.tsx:240"}, "fullDescription": {"text": "Open XSS surface unless the input is provably trusted. Replace with explicit JSX or sanitize via a vetted library.\n\nWhy: OWASP basics. Already partially flagged by the security analyzer.\nRule id: fq.dangerous-html"}, "properties": {"scanner": "scanner-primary", "layer": "frontend", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-d769cf9e5bc2b81a", "name": "`truncate` class without `title=` for hover reveal \u2014 sites/industry-kitchens/src/components/quote/QuoteItemsList.tsx:65", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 sites/industry-kitchens/src/components/quote/QuoteItemsList.tsx:65"}, "fullDescription": {"text": "A truncated value should reveal the full text on hover. Pass the full string via `title={...}` so the user can read it.\n\nWhy: P2 in CHECKLIST.md \u2014 truncate without hover-reveal.\nRule id: fq.truncate.no-title"}, "properties": {"scanner": "scanner-primary", "layer": "frontend", "severity": "info", "confidence": 1.0}}, {"id": "scanner-c38a35070b7a0a58", "name": "`dangerouslySetInnerHTML` used in a React component \u2014 sites/industry-kitchens/src/components/content/RichContent.tsx:104", "shortDescription": {"text": "`dangerouslySetInnerHTML` used in a React component \u2014 sites/industry-kitchens/src/components/content/RichContent.tsx:104"}, "fullDescription": {"text": "Open XSS surface unless the input is provably trusted. Replace with explicit JSX or sanitize via a vetted library.\n\nWhy: OWASP basics. Already partially flagged by the security analyzer.\nRule id: fq.dangerous-html"}, "properties": {"scanner": "scanner-primary", "layer": "frontend", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-baf78ee7ffae5fff", "name": "`truncate` class without `title=` for hover reveal \u2014 sites/industry-kitchens/src/components/product/ProductTabs.tsx:125", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 sites/industry-kitchens/src/components/product/ProductTabs.tsx:125"}, "fullDescription": {"text": "A truncated value should reveal the full text on hover. Pass the full string via `title={...}` so the user can read it.\n\nWhy: P2 in CHECKLIST.md \u2014 truncate without hover-reveal.\nRule id: fq.truncate.no-title"}, "properties": {"scanner": "scanner-primary", "layer": "frontend", "severity": "info", "confidence": 1.0}}, {"id": "scanner-62a651dedfa78608", "name": "`truncate` class without `title=` for hover reveal \u2014 template/src/app/search/page.tsx:214", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 template/src/app/search/page.tsx:214"}, "fullDescription": {"text": "A truncated value should reveal the full text on hover. Pass the full string via `title={...}` so the user can read it.\n\nWhy: P2 in CHECKLIST.md \u2014 truncate without hover-reveal.\nRule id: fq.truncate.no-title"}, "properties": {"scanner": "scanner-primary", "layer": "frontend", "severity": "info", "confidence": 1.0}}, {"id": "scanner-60d7b3cf4dfa04d0", "name": "`truncate` class without `title=` for hover reveal \u2014 template/src/app/products/[slug]/page.tsx:130", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 template/src/app/products/[slug]/page.tsx:130"}, "fullDescription": {"text": "A truncated value should reveal the full text on hover. Pass the full string via `title={...}` so the user can read it.\n\nWhy: P2 in CHECKLIST.md \u2014 truncate without hover-reveal.\nRule id: fq.truncate.no-title"}, "properties": {"scanner": "scanner-primary", "layer": "frontend", "severity": "info", "confidence": 1.0}}, {"id": "scanner-4393005f14661615", "name": "`truncate` class without `title=` for hover reveal \u2014 template/src/app/blog/[slug]/page.tsx:57", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 template/src/app/blog/[slug]/page.tsx:57"}, "fullDescription": {"text": "A truncated value should reveal the full text on hover. Pass the full string via `title={...}` so the user can read it.\n\nWhy: P2 in CHECKLIST.md \u2014 truncate without hover-reveal.\nRule id: fq.truncate.no-title"}, "properties": {"scanner": "scanner-primary", "layer": "frontend", "severity": "info", "confidence": 1.0}}, {"id": "scanner-ccd9e57f5285772d", "name": "`truncate` class without `title=` for hover reveal \u2014 template/src/components/cart/CartItemsList.tsx:59", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 template/src/components/cart/CartItemsList.tsx:59"}, "fullDescription": {"text": "A truncated value should reveal the full text on hover. Pass the full string via `title={...}` so the user can read it.\n\nWhy: P2 in CHECKLIST.md \u2014 truncate without hover-reveal.\nRule id: fq.truncate.no-title"}, "properties": {"scanner": "scanner-primary", "layer": "frontend", "severity": "info", "confidence": 1.0}}, {"id": "scanner-291bc5119df3dd91", "name": "`truncate` class without `title=` for hover reveal \u2014 template/src/components/search/SearchTypeahead.tsx:239", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 template/src/components/search/SearchTypeahead.tsx:239"}, "fullDescription": {"text": "A truncated value should reveal the full text on hover. Pass the full string via `title={...}` so the user can read it.\n\nWhy: P2 in CHECKLIST.md \u2014 truncate without hover-reveal.\nRule id: fq.truncate.no-title"}, "properties": {"scanner": "scanner-primary", "layer": "frontend", "severity": "info", "confidence": 1.0}}, {"id": "scanner-2925dfea1c869c92", "name": "`dangerouslySetInnerHTML` used in a React component \u2014 template/src/components/search/SearchTypeahead.tsx:240", "shortDescription": {"text": "`dangerouslySetInnerHTML` used in a React component \u2014 template/src/components/search/SearchTypeahead.tsx:240"}, "fullDescription": {"text": "Open XSS surface unless the input is provably trusted. Replace with explicit JSX or sanitize via a vetted library.\n\nWhy: OWASP basics. Already partially flagged by the security analyzer.\nRule id: fq.dangerous-html"}, "properties": {"scanner": "scanner-primary", "layer": "frontend", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-375684e61b976dae", "name": "`truncate` class without `title=` for hover reveal \u2014 template/src/components/quote/QuoteItemsList.tsx:65", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 template/src/components/quote/QuoteItemsList.tsx:65"}, "fullDescription": {"text": "A truncated value should reveal the full text on hover. Pass the full string via `title={...}` so the user can read it.\n\nWhy: P2 in CHECKLIST.md \u2014 truncate without hover-reveal.\nRule id: fq.truncate.no-title"}, "properties": {"scanner": "scanner-primary", "layer": "frontend", "severity": "info", "confidence": 1.0}}, {"id": "scanner-2a21a2d82b6b7d1c", "name": "`dangerouslySetInnerHTML` used in a React component \u2014 template/src/components/content/RichContent.tsx:104", "shortDescription": {"text": "`dangerouslySetInnerHTML` used in a React component \u2014 template/src/components/content/RichContent.tsx:104"}, "fullDescription": {"text": "Open XSS surface unless the input is provably trusted. Replace with explicit JSX or sanitize via a vetted library.\n\nWhy: OWASP basics. Already partially flagged by the security analyzer.\nRule id: fq.dangerous-html"}, "properties": {"scanner": "scanner-primary", "layer": "frontend", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-41448b28e31b44d1", "name": "`truncate` class without `title=` for hover reveal \u2014 template/src/components/product/ProductTabs.tsx:125", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 template/src/components/product/ProductTabs.tsx:125"}, "fullDescription": {"text": "A truncated value should reveal the full text on hover. Pass the full string via `title={...}` so the user can read it.\n\nWhy: P2 in CHECKLIST.md \u2014 truncate without hover-reveal.\nRule id: fq.truncate.no-title"}, "properties": {"scanner": "scanner-primary", "layer": "frontend", "severity": "info", "confidence": 1.0}}, {"id": "scanner-b36b7578faede371", "name": "Insecure pattern 'dangerous_innerhtml' in sites/chef-s-kitchen/src/app/layout.tsx:74", "shortDescription": {"text": "Insecure pattern 'dangerous_innerhtml' in sites/chef-s-kitchen/src/app/layout.tsx:74"}, "fullDescription": {"text": "Found a known-risky pattern (dangerous_innerhtml). Review and replace if possible."}, "properties": {"scanner": "scanner-primary", "layer": "security", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-93d000199b6f9dfd", "name": "Insecure pattern 'dangerous_innerhtml' in sites/chef-s-kitchen/src/app/products/[slug]/page.tsx:151", "shortDescription": {"text": "Insecure pattern 'dangerous_innerhtml' in sites/chef-s-kitchen/src/app/products/[slug]/page.tsx:151"}, "fullDescription": {"text": "Found a known-risky pattern (dangerous_innerhtml). Review and replace if possible."}, "properties": {"scanner": "scanner-primary", "layer": "security", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-fcd98152584fdf96", "name": "Insecure pattern 'dangerous_innerhtml' in sites/chef-s-kitchen/src/components/search/SearchTypeahead.tsx:259", "shortDescription": {"text": "Insecure pattern 'dangerous_innerhtml' in sites/chef-s-kitchen/src/components/search/SearchTypeahead.tsx:259"}, "fullDescription": {"text": "Found a known-risky pattern (dangerous_innerhtml). Review and replace if possible."}, "properties": {"scanner": "scanner-primary", "layer": "security", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-64a267e5b7cad171", "name": "Insecure pattern 'dangerous_innerhtml' in sites/industry-kitchens/src/components/layout/HeaderSearch.tsx:209", "shortDescription": {"text": "Insecure pattern 'dangerous_innerhtml' in sites/industry-kitchens/src/components/layout/HeaderSearch.tsx:209"}, "fullDescription": {"text": "Found a known-risky pattern (dangerous_innerhtml). Review and replace if possible."}, "properties": {"scanner": "scanner-primary", "layer": "security", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-3ec42881ece30b17", "name": "Insecure pattern 'dangerous_innerhtml' in sites/industry-kitchens/src/components/search/SearchTypeahead.tsx:240", "shortDescription": {"text": "Insecure pattern 'dangerous_innerhtml' in sites/industry-kitchens/src/components/search/SearchTypeahead.tsx:240"}, "fullDescription": {"text": "Found a known-risky pattern (dangerous_innerhtml). Review and replace if possible."}, "properties": {"scanner": "scanner-primary", "layer": "security", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-606817832a490cce", "name": "Insecure pattern 'node_child_process' in orchestrator/new-site.mjs:19", "shortDescription": {"text": "Insecure pattern 'node_child_process' in orchestrator/new-site.mjs:19"}, "fullDescription": {"text": "Found a known-risky pattern (node_child_process). Review and replace if possible."}, "properties": {"scanner": "scanner-primary", "layer": "security", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-29156bc0a78f6ad9", "name": "Insecure pattern 'node_child_process' in orchestrator/sync-sites.mjs:16", "shortDescription": {"text": "Insecure pattern 'node_child_process' in orchestrator/sync-sites.mjs:16"}, "fullDescription": {"text": "Found a known-risky pattern (node_child_process). Review and replace if possible."}, "properties": {"scanner": "scanner-primary", "layer": "security", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-28c4a04bd807da0c", "name": "GitHub Action is tag-pinned rather than SHA-pinned", "shortDescription": {"text": "GitHub Action is tag-pinned rather than SHA-pinned"}, "fullDescription": {"text": "actions/checkout@v4 can move without a code change in this repo. Pin third-party actions to a reviewed 40-character commit SHA."}, "properties": {"scanner": "scanner-primary", "layer": "cicd", "severity": "low", "confidence": 1.0}}, {"id": "scanner-ad6701f0a8405e22", "name": "GitHub Actions workflow grants broad write permissions", "shortDescription": {"text": "GitHub Actions workflow grants broad write permissions"}, "fullDescription": {"text": "CI tokens with write permissions increase blast radius when an action, dependency, or PR workflow is compromised. Prefer job-level least-privilege permissions."}, "properties": {"scanner": "scanner-primary", "layer": "cicd", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-6c033dfc37761060", "name": "GitHub Action is tag-pinned rather than SHA-pinned", "shortDescription": {"text": "GitHub Action is tag-pinned rather than SHA-pinned"}, "fullDescription": {"text": "actions/checkout@v4 can move without a code change in this repo. Pin third-party actions to a reviewed 40-character commit SHA."}, "properties": {"scanner": "scanner-primary", "layer": "cicd", "severity": "low", "confidence": 1.0}}, {"id": "scanner-5ba0f6edd635051b", "name": "GitHub Actions workflow grants broad write permissions", "shortDescription": {"text": "GitHub Actions workflow grants broad write permissions"}, "fullDescription": {"text": "CI tokens with write permissions increase blast radius when an action, dependency, or PR workflow is compromised. Prefer job-level least-privilege permissions."}, "properties": {"scanner": "scanner-primary", "layer": "cicd", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-6893a6c8b0861585", "name": "Very low test-to-source ratio", "shortDescription": {"text": "Very low test-to-source ratio"}, "fullDescription": {"text": "0 test file(s) for 367 source file(s) (ratio 0.00). Consider adding integration or unit tests for critical paths."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-141b30a41e03817b", "name": "No license file detected", "shortDescription": {"text": "No license file detected"}, "fullDescription": {"text": "No LICENSE/COPYING/NOTICE file was found. Generated repositories often omit licensing, which blocks reuse and automated intake."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "low", "confidence": 1.0}}, {"id": "scanner-faccb9061e9b52a0", "name": "No README detected", "shortDescription": {"text": "No README detected"}, "fullDescription": {"text": "No README file was found. Generated repos without README context are hard to operate, validate, or safely hand off."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "low", "confidence": 1.0}}, {"id": "scanner-6eb9a21894a18533", "name": "Node manifest has dependencies but no lockfile: sites/chef-s-kitchen/package.json", "shortDescription": {"text": "Node manifest has dependencies but no lockfile: sites/chef-s-kitchen/package.json"}, "fullDescription": {"text": "`package.json` declares dependencies, but no same-directory npm/pnpm/yarn/bun lockfile was found. Generated projects without lockfiles are less reproducible and harder to secure-scan precisely."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "low", "confidence": 1.0}}, {"id": "scanner-42a0768e4da22449", "name": "Node manifest has dependencies but no lockfile: sites/industry-kitchens/package.json", "shortDescription": {"text": "Node manifest has dependencies but no lockfile: sites/industry-kitchens/package.json"}, "fullDescription": {"text": "`package.json` declares dependencies, but no same-directory npm/pnpm/yarn/bun lockfile was found. Generated projects without lockfiles are less reproducible and harder to secure-scan precisely."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "low", "confidence": 1.0}}, {"id": "scanner-65d50559d781a338", "name": "Node manifest has dependencies but no lockfile: template/package.json", "shortDescription": {"text": "Node manifest has dependencies but no lockfile: template/package.json"}, "fullDescription": {"text": "`package.json` declares dependencies, but no same-directory npm/pnpm/yarn/bun lockfile was found. Generated projects without lockfiles are less reproducible and harder to secure-scan precisely."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "low", "confidence": 1.0}}, {"id": "scanner-3ab5d313dda8e5f9", "name": "Debug logging residue appears in source files", "shortDescription": {"text": "Debug logging residue appears in source files"}, "fullDescription": {"text": "Found 27 console/debugger/print-style debug statements in non-test source. This is a common fast-generation residue before production cleanup."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "low", "confidence": 1.0}}, {"id": "scanner-72b2a6250083a784", "name": "Placeholder or mock-heavy implementation detected", "shortDescription": {"text": "Placeholder or mock-heavy implementation detected"}, "fullDescription": {"text": "Found 56 placeholder/mock markers across 29 source files. This often means the repo looks complete while core flows still use generated scaffolding or fake data."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-2d0c7b7ab8f8aacf", "name": "Critical user flow still appears backed by mock or placeholder data", "shortDescription": {"text": "Critical user flow still appears backed by mock or placeholder data"}, "fullDescription": {"text": "A payment/auth/admin/order/billing-style flow contains mock, fake, TODO, dummy, or placeholder markers in runtime source. In the Fable corpus this is a high-leverage completeness smell: the app can look finished while the money, identity, or tenant flow is still scaffolded."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-11825279136b53a3", "name": "CI is configured but no tests are detected", "shortDescription": {"text": "CI is configured but no tests are detected"}, "fullDescription": {"text": "A CI pipeline exists, but the scan found no test files to gate. Opus labeled this generated-code pattern as config theater: release machinery exists, but it has little behavioral signal."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-b9088664ace7f748", "name": "Composite production-readiness gap", "shortDescription": {"text": "Composite production-readiness gap"}, "fullDescription": {"text": "Multiple low-cost hardening controls are missing together: license, tests, operator-readme, lockfile. Opus verification showed these co-occurring gaps are a better readiness signal than reading each flag in isolation."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-749d4bc1bd66df5f", "name": "Agent instructions exist but release-hardening basics are missing", "shortDescription": {"text": "Agent instructions exist but release-hardening basics are missing"}, "fullDescription": {"text": "AI-coder instruction files were found, but the repo is missing license, tests, operator-readme, lockfile. Treat this as a contract gap: the agent is guided, but the generated output is not yet guarded by the controls that make it repeatable."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-7ed20b9f0de98fe7", "name": "Commented-code block (6 lines) in sites/chef-s-kitchen/src/lib/store.ts:75", "shortDescription": {"text": "Commented-code block (6 lines) in sites/chef-s-kitchen/src/lib/store.ts:75"}, "fullDescription": {"text": "A long run of `//` or `#` lines usually means abandoned code. Delete or move to git history. Keeps the canvas + dead-code detection honest."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "info", "confidence": 1.0}}, {"id": "scanner-289920c72e6c180b", "name": "Commented-code block (5 lines) in sites/chef-s-kitchen/src/lib/actions/quote.ts:122", "shortDescription": {"text": "Commented-code block (5 lines) in sites/chef-s-kitchen/src/lib/actions/quote.ts:122"}, "fullDescription": {"text": "A long run of `//` or `#` lines usually means abandoned code. Delete or move to git history. Keeps the canvas + dead-code detection honest."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "info", "confidence": 1.0}}, {"id": "scanner-6546b4c3a5a316fb", "name": "Legacy-named symbol `homepage_copy` in sites/industry-kitchens/src/lib/store.ts:478", "shortDescription": {"text": "Legacy-named symbol `homepage_copy` in sites/industry-kitchens/src/lib/store.ts:478"}, "fullDescription": {"text": "Names with suffixes like `_old`, `_v1`, `_deprecated` usually indicate replaced-but-not-removed code (typical AI-coder leftover). Confirm and delete, or rename if it's the active version."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "low", "confidence": 1.0}}, {"id": "scanner-ef18a7668dfe0e12", "name": "Commented-code block (6 lines) in sites/industry-kitchens/src/lib/store.ts:76", "shortDescription": {"text": "Commented-code block (6 lines) in sites/industry-kitchens/src/lib/store.ts:76"}, "fullDescription": {"text": "A long run of `//` or `#` lines usually means abandoned code. Delete or move to git history. Keeps the canvas + dead-code detection honest."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "info", "confidence": 1.0}}, {"id": "scanner-c236a8c5e3858250", "name": "Commented-code block (5 lines) in sites/industry-kitchens/src/lib/actions/quote.ts:122", "shortDescription": {"text": "Commented-code block (5 lines) in sites/industry-kitchens/src/lib/actions/quote.ts:122"}, "fullDescription": {"text": "A long run of `//` or `#` lines usually means abandoned code. Delete or move to git history. Keeps the canvas + dead-code detection honest."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "info", "confidence": 1.0}}, {"id": "scanner-97c10360d0ed80d2", "name": "Legacy-named symbol `homepage_copy` in template/src/lib/store.ts:478", "shortDescription": {"text": "Legacy-named symbol `homepage_copy` in template/src/lib/store.ts:478"}, "fullDescription": {"text": "Names with suffixes like `_old`, `_v1`, `_deprecated` usually indicate replaced-but-not-removed code (typical AI-coder leftover). Confirm and delete, or rename if it's the active version."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "low", "confidence": 1.0}}, {"id": "scanner-4dd8c1535f164a8a", "name": "Commented-code block (6 lines) in template/src/lib/store.ts:76", "shortDescription": {"text": "Commented-code block (6 lines) in template/src/lib/store.ts:76"}, "fullDescription": {"text": "A long run of `//` or `#` lines usually means abandoned code. Delete or move to git history. Keeps the canvas + dead-code detection honest."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "info", "confidence": 1.0}}, {"id": "scanner-568a1f6f661ab265", "name": "Commented-code block (5 lines) in template/src/lib/actions/quote.ts:122", "shortDescription": {"text": "Commented-code block (5 lines) in template/src/lib/actions/quote.ts:122"}, "fullDescription": {"text": "A long run of `//` or `#` lines usually means abandoned code. Delete or move to git history. Keeps the canvas + dead-code detection honest."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "info", "confidence": 1.0}}, {"id": "scanner-2eafc3188c36bb02", "name": "3 env vars used in code but missing from .env.example", "shortDescription": {"text": "3 env vars used in code but missing from .env.example"}, "fullDescription": {"text": "Drift between code and config docs. The first few: `IMAGE_CACHE_S3_BUCKET`, `IMAGE_CACHE_S3_REGION`, `NODE_ENV`. Add them (with a placeholder/comment) to .env.example so onboarding doesn't break."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "info", "confidence": 1.0}}]}}, "automationDetails": {"id": "repobility/25026"}, "properties": {"repository": "cmlibra71/keenan-group-channels", "repoUrl": "https://github.com/cmlibra71/keenan-group-channels", "branch": "main"}, "results": [{"ruleId": "scanner-bead75b0f9233e05", "level": "none", "message": {"text": "No API endpoints detected"}, "properties": {"repobilityId": "0f8bb852027c38f8", "scanner": "scanner-primary", "fingerprint": "bead75b0f9233e05", "layer": "api", "severity": "info", "confidence": 1.0, "tags": ["coverage"]}}, {"ruleId": "scanner-5a9e824bc9fa7eba", "level": "warning", "message": {"text": "`dangerouslySetInnerHTML` used in a React component \u2014 sites/chef-s-kitchen/src/app/layout.tsx:74"}, "properties": {"repobilityId": "202e795d9ca7bec3", "scanner": "scanner-primary", "fingerprint": "5a9e824bc9fa7eba", "layer": "frontend", "severity": "medium", "confidence": 1.0, "tags": ["frontend-quality", "fq.dangerous-html"]}}, {"ruleId": "scanner-1d20c89705e6b875", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 sites/chef-s-kitchen/src/app/search/page.tsx:249"}, "properties": {"repobilityId": "db755af90ff6eb76", "scanner": "scanner-primary", "fingerprint": "1d20c89705e6b875", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-bd60fce9c9f36215", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 sites/chef-s-kitchen/src/app/products/[slug]/page.tsx:164"}, "properties": {"repobilityId": "22d20d0722a7af2a", "scanner": "scanner-primary", "fingerprint": "bd60fce9c9f36215", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-57bb6300bdf201b7", "level": "warning", "message": {"text": "`dangerouslySetInnerHTML` used in a React component \u2014 sites/chef-s-kitchen/src/app/products/[slug]/page.tsx:151"}, "properties": {"repobilityId": "2410a6bd6c2e36d7", "scanner": "scanner-primary", "fingerprint": "57bb6300bdf201b7", "layer": "frontend", "severity": "medium", "confidence": 1.0, "tags": ["frontend-quality", "fq.dangerous-html"]}}, {"ruleId": "scanner-b85ba489004b119b", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 sites/chef-s-kitchen/src/components/cart/CartItemsList.tsx:59"}, "properties": {"repobilityId": "4927ce2d5bca951b", "scanner": "scanner-primary", "fingerprint": "b85ba489004b119b", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-9e0724014866b892", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 sites/chef-s-kitchen/src/components/search/SearchTypeahead.tsx:258"}, "properties": {"repobilityId": "366800d7fd8e59cf", "scanner": "scanner-primary", "fingerprint": "9e0724014866b892", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-288487f3299608d3", "level": "warning", "message": {"text": "`dangerouslySetInnerHTML` used in a React component \u2014 sites/chef-s-kitchen/src/components/search/SearchTypeahead.tsx:259"}, "properties": {"repobilityId": "0ccae65470c12a1c", "scanner": "scanner-primary", "fingerprint": "288487f3299608d3", "layer": "frontend", "severity": "medium", "confidence": 1.0, "tags": ["frontend-quality", "fq.dangerous-html"]}}, {"ruleId": "scanner-18acb51a6b999d92", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 sites/chef-s-kitchen/src/components/quote/QuoteItemsList.tsx:65"}, "properties": {"repobilityId": "197d5afab8d6f68b", "scanner": "scanner-primary", "fingerprint": "18acb51a6b999d92", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-6d33b66bcefa8130", "level": "warning", "message": {"text": "`dangerouslySetInnerHTML` used in a React component \u2014 sites/chef-s-kitchen/src/components/content/RichContent.tsx:104"}, "properties": {"repobilityId": "24a69bb78ce670b6", "scanner": "scanner-primary", "fingerprint": "6d33b66bcefa8130", "layer": "frontend", "severity": "medium", "confidence": 1.0, "tags": ["frontend-quality", "fq.dangerous-html"]}}, {"ruleId": "scanner-ffaed09919e03fb0", "level": "note", "message": {"text": "Stray `console.log` in TS/JS \u2014 sites/chef-s-kitchen/src/components/hero/useWaveScene.ts:34"}, "properties": {"repobilityId": "8d4a42ce640859c4", "scanner": "scanner-primary", "fingerprint": "ffaed09919e03fb0", "layer": "frontend", "severity": "low", "confidence": 1.0, "tags": ["frontend-quality", "fq.console-leak"]}}, {"ruleId": "scanner-17e8b09beb88c3f5", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 sites/chef-s-kitchen/src/components/product/ProductTabs.tsx:158"}, "properties": {"repobilityId": "aba6d95c1fead657", "scanner": "scanner-primary", "fingerprint": "17e8b09beb88c3f5", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-da658aa7feaf93f2", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 sites/industry-kitchens/src/app/search/page.tsx:214"}, "properties": {"repobilityId": "03ef78208022a1c2", "scanner": "scanner-primary", "fingerprint": "da658aa7feaf93f2", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-99f64ea91264af93", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 sites/industry-kitchens/src/app/products/[slug]/page.tsx:130"}, "properties": {"repobilityId": "32745595678534d7", "scanner": "scanner-primary", "fingerprint": "99f64ea91264af93", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-bc9061f41cfc7b54", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 sites/industry-kitchens/src/app/blog/[slug]/page.tsx:57"}, "properties": {"repobilityId": "68bd3c9a172db00c", "scanner": "scanner-primary", "fingerprint": "bc9061f41cfc7b54", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-41ec479eb6746cd4", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 sites/industry-kitchens/src/components/cart/CartItemsList.tsx:59"}, "properties": {"repobilityId": "734fb54f5ea81535", "scanner": "scanner-primary", "fingerprint": "41ec479eb6746cd4", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-248038fc108a514d", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 sites/industry-kitchens/src/components/layout/HeaderSearch.tsx:208"}, "properties": {"repobilityId": "21422ee63f9dfc7d", "scanner": "scanner-primary", "fingerprint": "248038fc108a514d", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-1b8bc5f5cf9aaf25", "level": "warning", "message": {"text": "`dangerouslySetInnerHTML` used in a React component \u2014 sites/industry-kitchens/src/components/layout/HeaderSearch.tsx:209"}, "properties": {"repobilityId": "e4f5e629f3087e9a", "scanner": "scanner-primary", "fingerprint": "1b8bc5f5cf9aaf25", "layer": "frontend", "severity": "medium", "confidence": 1.0, "tags": ["frontend-quality", "fq.dangerous-html"]}}, {"ruleId": "scanner-246bae3e62ab1db1", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 sites/industry-kitchens/src/components/search/SearchTypeahead.tsx:239"}, "properties": {"repobilityId": "fb51b1f326f5995a", "scanner": "scanner-primary", "fingerprint": "246bae3e62ab1db1", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-c4a6be640f7e86ca", "level": "warning", "message": {"text": "`dangerouslySetInnerHTML` used in a React component \u2014 sites/industry-kitchens/src/components/search/SearchTypeahead.tsx:240"}, "properties": {"repobilityId": "811917f8bbf0c8e1", "scanner": "scanner-primary", "fingerprint": "c4a6be640f7e86ca", "layer": "frontend", "severity": "medium", "confidence": 1.0, "tags": ["frontend-quality", "fq.dangerous-html"]}}, {"ruleId": "scanner-d769cf9e5bc2b81a", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 sites/industry-kitchens/src/components/quote/QuoteItemsList.tsx:65"}, "properties": {"repobilityId": "2d29e8d548a5a0fb", "scanner": "scanner-primary", "fingerprint": "d769cf9e5bc2b81a", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-c38a35070b7a0a58", "level": "warning", "message": {"text": "`dangerouslySetInnerHTML` used in a React component \u2014 sites/industry-kitchens/src/components/content/RichContent.tsx:104"}, "properties": {"repobilityId": "a1937a2fea5158a2", "scanner": "scanner-primary", "fingerprint": "c38a35070b7a0a58", "layer": "frontend", "severity": "medium", "confidence": 1.0, "tags": ["frontend-quality", "fq.dangerous-html"]}}, {"ruleId": "scanner-baf78ee7ffae5fff", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 sites/industry-kitchens/src/components/product/ProductTabs.tsx:125"}, "properties": {"repobilityId": "9b5ef0bf63ce56e8", "scanner": "scanner-primary", "fingerprint": "baf78ee7ffae5fff", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-62a651dedfa78608", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 template/src/app/search/page.tsx:214"}, "properties": {"repobilityId": "b14a44644461cc5b", "scanner": "scanner-primary", "fingerprint": "62a651dedfa78608", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-60d7b3cf4dfa04d0", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 template/src/app/products/[slug]/page.tsx:130"}, "properties": {"repobilityId": "8e2b558dbd65ff4d", "scanner": "scanner-primary", "fingerprint": "60d7b3cf4dfa04d0", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-4393005f14661615", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 template/src/app/blog/[slug]/page.tsx:57"}, "properties": {"repobilityId": "c7055b8ba4b04aa0", "scanner": "scanner-primary", "fingerprint": "4393005f14661615", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-ccd9e57f5285772d", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 template/src/components/cart/CartItemsList.tsx:59"}, "properties": {"repobilityId": "6f3f4cf332836db9", "scanner": "scanner-primary", "fingerprint": "ccd9e57f5285772d", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-291bc5119df3dd91", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 template/src/components/search/SearchTypeahead.tsx:239"}, "properties": {"repobilityId": "b19f487b65472807", "scanner": "scanner-primary", "fingerprint": "291bc5119df3dd91", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-2925dfea1c869c92", "level": "warning", "message": {"text": "`dangerouslySetInnerHTML` used in a React component \u2014 template/src/components/search/SearchTypeahead.tsx:240"}, "properties": {"repobilityId": "02a6eca5aac0deba", "scanner": "scanner-primary", "fingerprint": "2925dfea1c869c92", "layer": "frontend", "severity": "medium", "confidence": 1.0, "tags": ["frontend-quality", "fq.dangerous-html"]}}, {"ruleId": "scanner-375684e61b976dae", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 template/src/components/quote/QuoteItemsList.tsx:65"}, "properties": {"repobilityId": "6d20fa8e20fa079e", "scanner": "scanner-primary", "fingerprint": "375684e61b976dae", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-2a21a2d82b6b7d1c", "level": "warning", "message": {"text": "`dangerouslySetInnerHTML` used in a React component \u2014 template/src/components/content/RichContent.tsx:104"}, "properties": {"repobilityId": "2f556c6f7b0b5a6a", "scanner": "scanner-primary", "fingerprint": "2a21a2d82b6b7d1c", "layer": "frontend", "severity": "medium", "confidence": 1.0, "tags": ["frontend-quality", "fq.dangerous-html"]}}, {"ruleId": "scanner-41448b28e31b44d1", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 template/src/components/product/ProductTabs.tsx:125"}, "properties": {"repobilityId": "52caa594e0d44a87", "scanner": "scanner-primary", "fingerprint": "41448b28e31b44d1", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-b36b7578faede371", "level": "warning", "message": {"text": "Insecure pattern 'dangerous_innerhtml' in sites/chef-s-kitchen/src/app/layout.tsx:74"}, "properties": {"repobilityId": "4a374a888f692381", "scanner": "scanner-primary", "fingerprint": "b36b7578faede371", "layer": "security", "severity": "medium", "confidence": 1.0, "tags": ["owasp", "dangerous_innerhtml"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "sites/chef-s-kitchen/src/app/layout.tsx"}, "region": {"startLine": 74}}}]}, {"ruleId": "scanner-93d000199b6f9dfd", "level": "warning", "message": {"text": "Insecure pattern 'dangerous_innerhtml' in sites/chef-s-kitchen/src/app/products/[slug]/page.tsx:151"}, "properties": {"repobilityId": "f7ed13d3715e81d3", "scanner": "scanner-primary", "fingerprint": "93d000199b6f9dfd", "layer": "security", "severity": "medium", "confidence": 1.0, "tags": ["owasp", "dangerous_innerhtml"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "sites/chef-s-kitchen/src/app/products/[slug]/page.tsx"}, "region": {"startLine": 151}}}]}, {"ruleId": "scanner-fcd98152584fdf96", "level": "warning", "message": {"text": "Insecure pattern 'dangerous_innerhtml' in sites/chef-s-kitchen/src/components/search/SearchTypeahead.tsx:259"}, "properties": {"repobilityId": "649128bf96542cc2", "scanner": "scanner-primary", "fingerprint": "fcd98152584fdf96", "layer": "security", "severity": "medium", "confidence": 1.0, "tags": ["owasp", "dangerous_innerhtml"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "sites/chef-s-kitchen/src/components/search/SearchTypeahead.tsx"}, "region": {"startLine": 259}}}]}, {"ruleId": "scanner-64a267e5b7cad171", "level": "warning", "message": {"text": "Insecure pattern 'dangerous_innerhtml' in sites/industry-kitchens/src/components/layout/HeaderSearch.tsx:209"}, "properties": {"repobilityId": "49bc43764fc374cc", "scanner": "scanner-primary", "fingerprint": "64a267e5b7cad171", "layer": "security", "severity": "medium", "confidence": 1.0, "tags": ["owasp", "dangerous_innerhtml"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "sites/industry-kitchens/src/components/layout/HeaderSearch.tsx"}, "region": {"startLine": 209}}}]}, {"ruleId": "scanner-3ec42881ece30b17", "level": "warning", "message": {"text": "Insecure pattern 'dangerous_innerhtml' in sites/industry-kitchens/src/components/search/SearchTypeahead.tsx:240"}, "properties": {"repobilityId": "73191e47714e3ea5", "scanner": "scanner-primary", "fingerprint": "3ec42881ece30b17", "layer": "security", "severity": "medium", "confidence": 1.0, "tags": ["owasp", "dangerous_innerhtml"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "sites/industry-kitchens/src/components/search/SearchTypeahead.tsx"}, "region": {"startLine": 240}}}]}, {"ruleId": "scanner-606817832a490cce", "level": "warning", "message": {"text": "Insecure pattern 'node_child_process' in orchestrator/new-site.mjs:19"}, "properties": {"repobilityId": "fab715f5df887c18", "scanner": "scanner-primary", "fingerprint": "606817832a490cce", "layer": "security", "severity": "medium", "confidence": 1.0, "tags": ["owasp", "node_child_process"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "orchestrator/new-site.mjs"}, "region": {"startLine": 19}}}]}, {"ruleId": "scanner-29156bc0a78f6ad9", "level": "warning", "message": {"text": "Insecure pattern 'node_child_process' in orchestrator/sync-sites.mjs:16"}, "properties": {"repobilityId": "08de8dfddc30bb68", "scanner": "scanner-primary", "fingerprint": "29156bc0a78f6ad9", "layer": "security", "severity": "medium", "confidence": 1.0, "tags": ["owasp", "node_child_process"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "orchestrator/sync-sites.mjs"}, "region": {"startLine": 16}}}]}, {"ruleId": "scanner-28c4a04bd807da0c", "level": "note", "message": {"text": "GitHub Action is tag-pinned rather than SHA-pinned"}, "properties": {"repobilityId": "2aee2e2d969c7c6b", "scanner": "scanner-primary", "fingerprint": "28c4a04bd807da0c", "layer": "cicd", "severity": "low", "confidence": 1.0, "tags": ["supply-chain", "github-actions", "pinned-dependencies"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": ".github/workflows/deploy.yml"}, "region": {"startLine": 43}}}]}, {"ruleId": "scanner-28c4a04bd807da0c", "level": "warning", "message": {"text": "GitHub Action is tag-pinned rather than SHA-pinned"}, "properties": {"repobilityId": "5206950cf3c3cb8f", "scanner": "scanner-primary", "fingerprint": "28c4a04bd807da0c", "layer": "cicd", "severity": "medium", "confidence": 1.0, "tags": ["supply-chain", "github-actions", "pinned-dependencies"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": ".github/workflows/deploy.yml"}, "region": {"startLine": 58}}}]}, {"ruleId": "scanner-28c4a04bd807da0c", "level": "warning", "message": {"text": "GitHub Action is tag-pinned rather than SHA-pinned"}, "properties": {"repobilityId": "a996444fe9d8260b", "scanner": "scanner-primary", "fingerprint": "28c4a04bd807da0c", "layer": "cicd", "severity": "medium", "confidence": 1.0, "tags": ["supply-chain", "github-actions", "pinned-dependencies"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": ".github/workflows/deploy.yml"}, "region": {"startLine": 72}}}]}, {"ruleId": "scanner-28c4a04bd807da0c", "level": "warning", "message": {"text": "GitHub Action is tag-pinned rather than SHA-pinned"}, "properties": {"repobilityId": "4319262162feb627", "scanner": "scanner-primary", "fingerprint": "28c4a04bd807da0c", "layer": "cicd", "severity": "medium", "confidence": 1.0, "tags": ["supply-chain", "github-actions", "pinned-dependencies"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": ".github/workflows/deploy.yml"}, "region": {"startLine": 95}}}]}, {"ruleId": "scanner-ad6701f0a8405e22", "level": "warning", "message": {"text": "GitHub Actions workflow grants broad write permissions"}, "properties": {"repobilityId": "8384c23520d55657", "scanner": "scanner-primary", "fingerprint": "ad6701f0a8405e22", "layer": "cicd", "severity": "medium", "confidence": 1.0, "tags": ["supply-chain", "github-actions", "least-privilege"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": ".github/workflows/deploy.yml"}, "region": {"startLine": 1}}}]}, {"ruleId": "scanner-6c033dfc37761060", "level": "note", "message": {"text": "GitHub Action is tag-pinned rather than SHA-pinned"}, "properties": {"repobilityId": "38c2495a41d67afe", "scanner": "scanner-primary", "fingerprint": "6c033dfc37761060", "layer": "cicd", "severity": "low", "confidence": 1.0, "tags": ["supply-chain", "github-actions", "pinned-dependencies"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": ".github/workflows/admin-task.yml"}, "region": {"startLine": 51}}}]}, {"ruleId": "scanner-6c033dfc37761060", "level": "warning", "message": {"text": "GitHub Action is tag-pinned rather than SHA-pinned"}, "properties": {"repobilityId": "947c3f955a2565dc", "scanner": "scanner-primary", "fingerprint": "6c033dfc37761060", "layer": "cicd", "severity": "medium", "confidence": 1.0, "tags": ["supply-chain", "github-actions", "pinned-dependencies"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": ".github/workflows/admin-task.yml"}, "region": {"startLine": 63}}}]}, {"ruleId": "scanner-6c033dfc37761060", "level": "warning", "message": {"text": "GitHub Action is tag-pinned rather than SHA-pinned"}, "properties": {"repobilityId": "ce9466fc022efe0c", "scanner": "scanner-primary", "fingerprint": "6c033dfc37761060", "layer": "cicd", "severity": "medium", "confidence": 1.0, "tags": ["supply-chain", "github-actions", "pinned-dependencies"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": ".github/workflows/admin-task.yml"}, "region": {"startLine": 70}}}]}, {"ruleId": "scanner-6c033dfc37761060", "level": "warning", "message": {"text": "GitHub Action is tag-pinned rather than SHA-pinned"}, "properties": {"repobilityId": "26876fccdee8718c", "scanner": "scanner-primary", "fingerprint": "6c033dfc37761060", "layer": "cicd", "severity": "medium", "confidence": 1.0, "tags": ["supply-chain", "github-actions", "pinned-dependencies"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": ".github/workflows/admin-task.yml"}, "region": {"startLine": 84}}}]}, {"ruleId": "scanner-5ba0f6edd635051b", "level": "warning", "message": {"text": "GitHub Actions workflow grants broad write permissions"}, "properties": {"repobilityId": "28d65a605c614aba", "scanner": "scanner-primary", "fingerprint": "5ba0f6edd635051b", "layer": "cicd", "severity": "medium", "confidence": 1.0, "tags": ["supply-chain", "github-actions", "least-privilege"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": ".github/workflows/admin-task.yml"}, "region": {"startLine": 1}}}]}, {"ruleId": "scanner-6893a6c8b0861585", "level": "warning", "message": {"text": "Very low test-to-source ratio"}, "properties": {"repobilityId": "54a7de3f06314bf0", "scanner": "scanner-primary", "fingerprint": "6893a6c8b0861585", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["tests", "coverage"]}}, {"ruleId": "scanner-141b30a41e03817b", "level": "note", "message": {"text": "No license file detected"}, "properties": {"repobilityId": "eb1f2ed6e155b9eb", "scanner": "scanner-primary", "fingerprint": "141b30a41e03817b", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["license", "repo-hardening", "generated-repo-pattern"]}}, {"ruleId": "scanner-faccb9061e9b52a0", "level": "note", "message": {"text": "No README detected"}, "properties": {"repobilityId": "7ae3edbdc279411e", "scanner": "scanner-primary", "fingerprint": "faccb9061e9b52a0", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["docs", "readme", "repo-hardening", "generated-repo-pattern"]}}, {"ruleId": "scanner-6eb9a21894a18533", "level": "note", "message": {"text": "Node manifest has dependencies but no lockfile: sites/chef-s-kitchen/package.json"}, "properties": {"repobilityId": "907744a7deb155c6", "scanner": "scanner-primary", "fingerprint": "6eb9a21894a18533", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["dependency", "lockfile", "reproducibility", "generated-repo-pattern"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "sites/chef-s-kitchen/package.json"}, "region": {"startLine": 1}}}]}, {"ruleId": "scanner-42a0768e4da22449", "level": "note", "message": {"text": "Node manifest has dependencies but no lockfile: sites/industry-kitchens/package.json"}, "properties": {"repobilityId": "eb18f79abd860621", "scanner": "scanner-primary", "fingerprint": "42a0768e4da22449", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["dependency", "lockfile", "reproducibility", "generated-repo-pattern"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "sites/industry-kitchens/package.json"}, "region": {"startLine": 1}}}]}, {"ruleId": "scanner-65d50559d781a338", "level": "note", "message": {"text": "Node manifest has dependencies but no lockfile: template/package.json"}, "properties": {"repobilityId": "cc58069ca5380079", "scanner": "scanner-primary", "fingerprint": "65d50559d781a338", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["dependency", "lockfile", "reproducibility", "generated-repo-pattern"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "template/package.json"}, "region": {"startLine": 1}}}]}, {"ruleId": "scanner-3ab5d313dda8e5f9", "level": "note", "message": {"text": "Debug logging residue appears in source files"}, "properties": {"repobilityId": "c669465965ecb770", "scanner": "scanner-primary", "fingerprint": "3ab5d313dda8e5f9", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["debug", "cleanup", "repo-hardening", "generated-repo-pattern"]}}, {"ruleId": "scanner-72b2a6250083a784", "level": "warning", "message": {"text": "Placeholder or mock-heavy implementation detected"}, "properties": {"repobilityId": "e5ef8b243611d24e", "scanner": "scanner-primary", "fingerprint": "72b2a6250083a784", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["placeholder", "mock-data", "incomplete", "generated-repo-pattern"]}}, {"ruleId": "scanner-2d0c7b7ab8f8aacf", "level": "warning", "message": {"text": "Critical user flow still appears backed by mock or placeholder data"}, "properties": {"repobilityId": "ba835fa28ff66853", "scanner": "scanner-primary", "fingerprint": "2d0c7b7ab8f8aacf", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["placeholder", "mock-data", "critical-flow", "generated-repo-pattern"]}}, {"ruleId": "scanner-11825279136b53a3", "level": "warning", "message": {"text": "CI is configured but no tests are detected"}, "properties": {"repobilityId": "0599aba23cba6c77", "scanner": "scanner-primary", "fingerprint": "11825279136b53a3", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["tests", "ci", "config-theater", "repo-hardening", "generated-repo-pattern"]}}, {"ruleId": "scanner-b9088664ace7f748", "level": "warning", "message": {"text": "Composite production-readiness gap"}, "properties": {"repobilityId": "db5b0cd3f8e4ba19", "scanner": "scanner-primary", "fingerprint": "b9088664ace7f748", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["production-readiness", "repo-hardening", "generated-repo-pattern"]}}, {"ruleId": "scanner-749d4bc1bd66df5f", "level": "warning", "message": {"text": "Agent instructions exist but release-hardening basics are missing"}, "properties": {"repobilityId": "8cba649854a98262", "scanner": "scanner-primary", "fingerprint": "749d4bc1bd66df5f", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["agent-instructions", "repo-hardening", "generated-repo-pattern"]}}, {"ruleId": "scanner-7ed20b9f0de98fe7", "level": "none", "message": {"text": "Commented-code block (6 lines) in sites/chef-s-kitchen/src/lib/store.ts:75"}, "properties": {"repobilityId": "182ff9baf8e50308", "scanner": "scanner-primary", "fingerprint": "7ed20b9f0de98fe7", "layer": "quality", "severity": "info", "confidence": 1.0, "tags": ["integrity", "commented-code", "dead-code"]}}, {"ruleId": "scanner-289920c72e6c180b", "level": "none", "message": {"text": "Commented-code block (5 lines) in sites/chef-s-kitchen/src/lib/actions/quote.ts:122"}, "properties": {"repobilityId": "83d465d212ac2d89", "scanner": "scanner-primary", "fingerprint": "289920c72e6c180b", "layer": "quality", "severity": "info", "confidence": 1.0, "tags": ["integrity", "commented-code", "dead-code"]}}, {"ruleId": "scanner-6546b4c3a5a316fb", "level": "note", "message": {"text": "Legacy-named symbol `homepage_copy` in sites/industry-kitchens/src/lib/store.ts:478"}, "properties": {"repobilityId": "8dde8c641f8ec9a2", "scanner": "scanner-primary", "fingerprint": "6546b4c3a5a316fb", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["integrity", "legacy-marker", "dead-code"]}}, {"ruleId": "scanner-ef18a7668dfe0e12", "level": "none", "message": {"text": "Commented-code block (6 lines) in sites/industry-kitchens/src/lib/store.ts:76"}, "properties": {"repobilityId": "515413b5aa80ffe3", "scanner": "scanner-primary", "fingerprint": "ef18a7668dfe0e12", "layer": "quality", "severity": "info", "confidence": 1.0, "tags": ["integrity", "commented-code", "dead-code"]}}, {"ruleId": "scanner-c236a8c5e3858250", "level": "none", "message": {"text": "Commented-code block (5 lines) in sites/industry-kitchens/src/lib/actions/quote.ts:122"}, "properties": {"repobilityId": "3e1458f7528e5eb5", "scanner": "scanner-primary", "fingerprint": "c236a8c5e3858250", "layer": "quality", "severity": "info", "confidence": 1.0, "tags": ["integrity", "commented-code", "dead-code"]}}, {"ruleId": "scanner-97c10360d0ed80d2", "level": "note", "message": {"text": "Legacy-named symbol `homepage_copy` in template/src/lib/store.ts:478"}, "properties": {"repobilityId": "1d1401e46713d4e2", "scanner": "scanner-primary", "fingerprint": "97c10360d0ed80d2", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["integrity", "legacy-marker", "dead-code"]}}, {"ruleId": "scanner-4dd8c1535f164a8a", "level": "none", "message": {"text": "Commented-code block (6 lines) in template/src/lib/store.ts:76"}, "properties": {"repobilityId": "459cb66c5857aac2", "scanner": "scanner-primary", "fingerprint": "4dd8c1535f164a8a", "layer": "quality", "severity": "info", "confidence": 1.0, "tags": ["integrity", "commented-code", "dead-code"]}}, {"ruleId": "scanner-568a1f6f661ab265", "level": "none", "message": {"text": "Commented-code block (5 lines) in template/src/lib/actions/quote.ts:122"}, "properties": {"repobilityId": "fd02cf463a7b8f92", "scanner": "scanner-primary", "fingerprint": "568a1f6f661ab265", "layer": "quality", "severity": "info", "confidence": 1.0, "tags": ["integrity", "commented-code", "dead-code"]}}, {"ruleId": "scanner-2eafc3188c36bb02", "level": "none", "message": {"text": "3 env vars used in code but missing from .env.example"}, "properties": {"repobilityId": "bd934ba112b02ffa", "scanner": "scanner-primary", "fingerprint": "2eafc3188c36bb02", "layer": "quality", "severity": "info", "confidence": 1.0, "tags": ["integrity", "config-drift"]}}]}]}