{"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-418753047709052f", "name": "Possibly dead Python function: validate_sections", "shortDescription": {"text": "Possibly dead Python function: validate_sections"}, "fullDescription": {"text": "No callers detected by AST scan in this repo. Could be exported for external callers or a framework handler."}, "properties": {"scanner": "scanner-primary", "layer": "software", "severity": "low", "confidence": 1.0}}, {"id": "scanner-95e720d8c68b607f", "name": "Possibly dead Python function: validate_filenames", "shortDescription": {"text": "Possibly dead Python function: validate_filenames"}, "fullDescription": {"text": "No callers detected by AST scan in this repo. Could be exported for external callers or a framework handler."}, "properties": {"scanner": "scanner-primary", "layer": "software", "severity": "low", "confidence": 1.0}}, {"id": "scanner-8d96cdf0274a5996", "name": "Possibly dead Python function: validate_teams", "shortDescription": {"text": "Possibly dead Python function: validate_teams"}, "fullDescription": {"text": "No callers detected by AST scan in this repo. Could be exported for external callers or a framework handler."}, "properties": {"scanner": "scanner-primary", "layer": "software", "severity": "low", "confidence": 1.0}}, {"id": "scanner-f159b874ddd9be00", "name": "`dangerouslySetInnerHTML` used in a React component \u2014 frontend/app/layout.tsx:51", "shortDescription": {"text": "`dangerouslySetInnerHTML` used in a React component \u2014 frontend/app/layout.tsx:51"}, "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-9d2fdbf88b3f5abc", "name": "`truncate` class without `title=` for hover reveal \u2014 frontend/app/uscite/page.tsx:449", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 frontend/app/uscite/page.tsx:449"}, "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-9222f728085ebd57", "name": "`truncate` class without `title=` for hover reveal \u2014 frontend/app/uscite/gestione/page.tsx:911", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 frontend/app/uscite/gestione/page.tsx:911"}, "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-0ed9a62ca2c83054", "name": "`truncate` class without `title=` for hover reveal \u2014 frontend/app/[sport]/squadre/[id]/page.tsx:164", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 frontend/app/[sport]/squadre/[id]/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-5e9f3245af59bd6c", "name": "`truncate` class without `title=` for hover reveal \u2014 frontend/app/[sport]/campionati/page.tsx:97", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 frontend/app/[sport]/campionati/page.tsx:97"}, "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-346bc4cf9ee62f8e", "name": "`truncate` class without `title=` for hover reveal \u2014 frontend/app/[sport]/campionati/[slug]/calendario/page.tsx:418", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 frontend/app/[sport]/campionati/[slug]/calendario/page.tsx:418"}, "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-0cb9d8e16c3e6d6a", "name": "`dangerouslySetInnerHTML` used in a React component \u2014 frontend/components/json-ld.tsx:13", "shortDescription": {"text": "`dangerouslySetInnerHTML` used in a React component \u2014 frontend/components/json-ld.tsx:13"}, "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-c6da53ed9621bc2c", "name": "`truncate` class without `title=` for hover reveal \u2014 frontend/components/match-team-panel.tsx:164", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 frontend/components/match-team-panel.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-a3d0a0669705ee88", "name": "`truncate` class without `title=` for hover reveal \u2014 frontend/components/global-search.tsx:114", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 frontend/components/global-search.tsx:114"}, "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-309d17db4806e5f0", "name": "`truncate` class without `title=` for hover reveal \u2014 frontend/components/live-matches-banner.tsx:43", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 frontend/components/live-matches-banner.tsx:43"}, "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-1f66ad88286ca30a", "name": "Dockerfile runs as root: backend/Dockerfile", "shortDescription": {"text": "Dockerfile runs as root: backend/Dockerfile"}, "fullDescription": {"text": "No non-root USER set. Containers running as root expand the blast radius of any vulnerability inside the image."}, "properties": {"scanner": "scanner-primary", "layer": "hardware", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-714c31ca9f474ae6", "name": "Docker base image is tag-pinned but not digest-pinned: python:3.12-slim", "shortDescription": {"text": "Docker base image is tag-pinned but not digest-pinned: python:3.12-slim"}, "fullDescription": {"text": "Container tags can be retagged upstream. Pin production base images to a reviewed digest (`image@sha256:...`) when reproducibility and supply-chain integrity matter."}, "properties": {"scanner": "scanner-primary", "layer": "hardware", "severity": "low", "confidence": 1.0}}, {"id": "scanner-a7f39cdd5fa21931", "name": "Docker base image is tag-pinned but not digest-pinned: node:22-alpine", "shortDescription": {"text": "Docker base image is tag-pinned but not digest-pinned: node:22-alpine"}, "fullDescription": {"text": "Container tags can be retagged upstream. Pin production base images to a reviewed digest (`image@sha256:...`) when reproducibility and supply-chain integrity matter."}, "properties": {"scanner": "scanner-primary", "layer": "hardware", "severity": "low", "confidence": 1.0}}, {"id": "scanner-aa5acaa49eb8315b", "name": "Containers defined but no K8s/orchestration manifest found", "shortDescription": {"text": "Containers defined but no K8s/orchestration manifest found"}, "fullDescription": {"text": "Repo has Dockerfiles/compose but no Kubernetes/Nomad manifests. If the target deployment is K8s, the manifests may live in a separate ops repo."}, "properties": {"scanner": "scanner-primary", "layer": "hardware", "severity": "low", "confidence": 1.0}}, {"id": "scanner-9e9c231a310fb881", "name": "Runtime dotenv file present in repo: backend/.env", "shortDescription": {"text": "Runtime dotenv file present in repo: backend/.env"}, "fullDescription": {"text": "`backend/.env` looks like a runtime dotenv file. It contains secret-looking assignments for SECRET_KEY. Move real values to a secret manager and keep only `.env.example` style templates in source control."}, "properties": {"scanner": "scanner-primary", "layer": "security", "severity": "critical", "confidence": 1.0}}, {"id": "scanner-2a28e4d32b2271c4", "name": "Possible secret in backend/core/management/commands/import_bak.py", "shortDescription": {"text": "Possible secret in backend/core/management/commands/import_bak.py"}, "fullDescription": {"text": "Detected pattern matching password_literal. Rotate the credential and move to a secret manager."}, "properties": {"scanner": "scanner-primary", "layer": "security", "severity": "critical", "confidence": 1.0}}, {"id": "scanner-114433d5894b6324", "name": "Insecure pattern 'dangerous_innerhtml' in frontend/app/layout.tsx:51", "shortDescription": {"text": "Insecure pattern 'dangerous_innerhtml' in frontend/app/layout.tsx:51"}, "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-c845420b6fc04283", "name": "Insecure pattern 'dangerous_innerhtml' in frontend/components/json-ld.tsx:13", "shortDescription": {"text": "Insecure pattern 'dangerous_innerhtml' in frontend/components/json-ld.tsx:13"}, "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-c43251b9322dfa3f", "name": "Very large file: backend/core/management/commands/seed_data.py (1285 lines)", "shortDescription": {"text": "Very large file: backend/core/management/commands/seed_data.py (1285 lines)"}, "fullDescription": {"text": "Files with >800 lines often hide complexity hotspots and discourage tests."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "low", "confidence": 1.0}}, {"id": "scanner-ea3b5e389d8c9c0f", "name": "Low test-to-source ratio", "shortDescription": {"text": "Low test-to-source ratio"}, "fullDescription": {"text": "41 tests / 327 src (ratio 0.13)."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "low", "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-3ab5d313dda8e5f9", "name": "Debug logging residue appears in source files", "shortDescription": {"text": "Debug logging residue appears in source files"}, "fullDescription": {"text": "Found 11 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 89 placeholder/mock markers across 37 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-b9088664ace7f748", "name": "Composite production-readiness gap", "shortDescription": {"text": "Composite production-readiness gap"}, "fullDescription": {"text": "Multiple low-cost hardening controls are missing together: license, ci. 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": "low", "confidence": 1.0}}, {"id": "scanner-14070d06d94deecd", "name": "Likely N+1 query: `for m in \u2026` triggers a query per row \u2014 backend/api/viewsets/stats.py:261", "shortDescription": {"text": "Likely N+1 query: `for m in \u2026` triggers a query per row \u2014 backend/api/viewsets/stats.py:261"}, "fullDescription": {"text": "The loop iterates a Django queryset and accesses `m.away_team.name` per row, which fires an additional database query each iteration. Add `.select_related('<fk_field>')` for FK / O2O relations or `.prefetch_related('<m2m_or_reverse>')` for many-related lookups, to load everything in 1-2 queries instead of N."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-8f3dfd90e54db003", "name": "Likely N+1 query: `for row in \u2026` triggers a query per row \u2014 backend/api/viewsets/stats.py:287", "shortDescription": {"text": "Likely N+1 query: `for row in \u2026` triggers a query per row \u2014 backend/api/viewsets/stats.py:287"}, "fullDescription": {"text": "The loop iterates a Django queryset and accesses `row.table.group` per row, which fires an additional database query each iteration. Add `.select_related('<fk_field>')` for FK / O2O relations or `.prefetch_related('<m2m_or_reverse>')` for many-related lookups, to load everything in 1-2 queries instead of N."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-b68da62d6f867b5f", "name": "Likely N+1 query: `for assignment in \u2026` triggers a query per row \u2014 backend/output/views.py:284", "shortDescription": {"text": "Likely N+1 query: `for assignment in \u2026` triggers a query per row \u2014 backend/output/views.py:284"}, "fullDescription": {"text": "The loop iterates a Django queryset and accesses `assignment.template.file_encoding` per row, which fires an additional database query each iteration. Add `.select_related('<fk_field>')` for FK / O2O relations or `.prefetch_related('<m2m_or_reverse>')` for many-related lookups, to load everything in 1-2 queries instead of N."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-ed72c44e4aefb348", "name": "Likely N+1 query: `for assignment in \u2026` triggers a query per row \u2014 backend/output/views.py:349", "shortDescription": {"text": "Likely N+1 query: `for assignment in \u2026` triggers a query per row \u2014 backend/output/views.py:349"}, "fullDescription": {"text": "The loop iterates a Django queryset and accesses `assignment.template.file_encoding` per row, which fires an additional database query each iteration. Add `.select_related('<fk_field>')` for FK / O2O relations or `.prefetch_related('<m2m_or_reverse>')` for many-related lookups, to load everything in 1-2 queries instead of N."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-08c17bb305f65f36", "name": "Likely N+1 query: `for match in \u2026` triggers a query per row \u2014 backend/output/services.py:476", "shortDescription": {"text": "Likely N+1 query: `for match in \u2026` triggers a query per row \u2014 backend/output/services.py:476"}, "fullDescription": {"text": "The loop iterates a Django queryset and accesses `match.home_team.name` per row, which fires an additional database query each iteration. Add `.select_related('<fk_field>')` for FK / O2O relations or `.prefetch_related('<m2m_or_reverse>')` for many-related lookups, to load everything in 1-2 queries instead of N."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-a34d061b213baa26", "name": "Likely N+1 query: `for match in \u2026` triggers a query per row \u2014 backend/output/services.py:584", "shortDescription": {"text": "Likely N+1 query: `for match in \u2026` triggers a query per row \u2014 backend/output/services.py:584"}, "fullDescription": {"text": "The loop iterates a Django queryset and accesses `match.home_team.name` per row, which fires an additional database query each iteration. Add `.select_related('<fk_field>')` for FK / O2O relations or `.prefetch_related('<m2m_or_reverse>')` for many-related lookups, to load everything in 1-2 queries instead of N."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-717dac192efe0c20", "name": "Likely N+1 query: `for lp in \u2026` triggers a query per row \u2014 backend/output/services.py:622", "shortDescription": {"text": "Likely N+1 query: `for lp in \u2026` triggers a query per row \u2014 backend/output/services.py:622"}, "fullDescription": {"text": "The loop iterates a Django queryset and accesses `lp.player.last_name` per row, which fires an additional database query each iteration. Add `.select_related('<fk_field>')` for FK / O2O relations or `.prefetch_related('<m2m_or_reverse>')` for many-related lookups, to load everything in 1-2 queries instead of N."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-56888126e4820a87", "name": "Likely N+1 query: `for match in \u2026` triggers a query per row \u2014 backend/output/services.py:765", "shortDescription": {"text": "Likely N+1 query: `for match in \u2026` triggers a query per row \u2014 backend/output/services.py:765"}, "fullDescription": {"text": "The loop iterates a Django queryset and accesses `match.result.home_score` per row, which fires an additional database query each iteration. Add `.select_related('<fk_field>')` for FK / O2O relations or `.prefetch_related('<m2m_or_reverse>')` for many-related lookups, to load everything in 1-2 queries instead of N."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-ee33acfafff633f0", "name": "Commented-code block (5 lines) in backend/champs/migrations/0009_alter_championship_level.py:6", "shortDescription": {"text": "Commented-code block (5 lines) in backend/champs/migrations/0009_alter_championship_level.py:6"}, "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-d85e18a26e44f4f7", "name": "Likely N+1 query: `for club in \u2026` triggers a query per row \u2014 backend/core/management/commands/seed_data.py:497", "shortDescription": {"text": "Likely N+1 query: `for club in \u2026` triggers a query per row \u2014 backend/core/management/commands/seed_data.py:497"}, "fullDescription": {"text": "The loop iterates a Django queryset and accesses `club.sports.all` per row, which fires an additional database query each iteration. Add `.select_related('<fk_field>')` for FK / O2O relations or `.prefetch_related('<m2m_or_reverse>')` for many-related lookups, to load everything in 1-2 queries instead of N."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-cc4127377bb29e77", "name": "Likely N+1 query: `for team in \u2026` triggers a query per row \u2014 backend/core/management/commands/seed_data.py:513", "shortDescription": {"text": "Likely N+1 query: `for team in \u2026` triggers a query per row \u2014 backend/core/management/commands/seed_data.py:513"}, "fullDescription": {"text": "The loop iterates a Django queryset and accesses `team.sport.slug` per row, which fires an additional database query each iteration. Add `.select_related('<fk_field>')` for FK / O2O relations or `.prefetch_related('<m2m_or_reverse>')` for many-related lookups, to load everything in 1-2 queries instead of N."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-a6fd1e40f0309f4c", "name": "Likely N+1 query: `for r in \u2026` triggers a query per row \u2014 backend/core/management/commands/seed_data.py:931", "shortDescription": {"text": "Likely N+1 query: `for r in \u2026` triggers a query per row \u2014 backend/core/management/commands/seed_data.py:931"}, "fullDescription": {"text": "The loop iterates a Django queryset and accesses `r.sport.slug` per row, which fires an additional database query each iteration. Add `.select_related('<fk_field>')` for FK / O2O relations or `.prefetch_related('<m2m_or_reverse>')` for many-related lookups, to load everything in 1-2 queries instead of N."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-753deb9bca9afb8a", "name": "Likely N+1 query: `for group in \u2026` triggers a query per row \u2014 backend/core/management/commands/seed_data.py:934", "shortDescription": {"text": "Likely N+1 query: `for group in \u2026` triggers a query per row \u2014 backend/core/management/commands/seed_data.py:934"}, "fullDescription": {"text": "The loop iterates a Django queryset and accesses `group.teams.values_list` per row, which fires an additional database query each iteration. Add `.select_related('<fk_field>')` for FK / O2O relations or `.prefetch_related('<m2m_or_reverse>')` for many-related lookups, to load everything in 1-2 queries instead of N."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-9bf904dbea33a95a", "name": "Likely N+1 query: `for group in \u2026` triggers a query per row \u2014 backend/core/management/commands/seed_data.py:1123", "shortDescription": {"text": "Likely N+1 query: `for group in \u2026` triggers a query per row \u2014 backend/core/management/commands/seed_data.py:1123"}, "fullDescription": {"text": "The loop iterates a Django queryset and accesses `group.annual_championship.championship` per row, which fires an additional database query each iteration. Add `.select_related('<fk_field>')` for FK / O2O relations or `.prefetch_related('<m2m_or_reverse>')` for many-related lookups, to load everything in 1-2 queries instead of N."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-ab70a37e3296e936", "name": "Likely N+1 query: `for m in \u2026` triggers a query per row \u2014 backend/core/management/commands/seed_data.py:1150", "shortDescription": {"text": "Likely N+1 query: `for m in \u2026` triggers a query per row \u2014 backend/core/management/commands/seed_data.py:1150"}, "fullDescription": {"text": "The loop iterates a Django queryset and accesses `m.result.home_score` per row, which fires an additional database query each iteration. Add `.select_related('<fk_field>')` for FK / O2O relations or `.prefetch_related('<m2m_or_reverse>')` for many-related lookups, to load everything in 1-2 queries instead of N."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-8113b9583858996b", "name": "Likely N+1 query: `for m in \u2026` triggers a query per row \u2014 backend/core/management/commands/seed_data.py:1169", "shortDescription": {"text": "Likely N+1 query: `for m in \u2026` triggers a query per row \u2014 backend/core/management/commands/seed_data.py:1169"}, "fullDescription": {"text": "The loop iterates a Django queryset and accesses `m.result.away_score` per row, which fires an additional database query each iteration. Add `.select_related('<fk_field>')` for FK / O2O relations or `.prefetch_related('<m2m_or_reverse>')` for many-related lookups, to load everything in 1-2 queries instead of N."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-0fe686056e7d1002", "name": "Likely N+1 query: `for m in \u2026` triggers a query per row \u2014 backend/core/management/commands/seed_data.py:1237", "shortDescription": {"text": "Likely N+1 query: `for m in \u2026` triggers a query per row \u2014 backend/core/management/commands/seed_data.py:1237"}, "fullDescription": {"text": "The loop iterates a Django queryset and accesses `m.result.home_score` per row, which fires an additional database query each iteration. Add `.select_related('<fk_field>')` for FK / O2O relations or `.prefetch_related('<m2m_or_reverse>')` for many-related lookups, to load everything in 1-2 queries instead of N."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-a64e5bcea6f58567", "name": "Likely N+1 query: `for m in \u2026` triggers a query per row \u2014 backend/core/management/commands/seed_data.py:1244", "shortDescription": {"text": "Likely N+1 query: `for m in \u2026` triggers a query per row \u2014 backend/core/management/commands/seed_data.py:1244"}, "fullDescription": {"text": "The loop iterates a Django queryset and accesses `m.result.home_score` per row, which fires an additional database query each iteration. Add `.select_related('<fk_field>')` for FK / O2O relations or `.prefetch_related('<m2m_or_reverse>')` for many-related lookups, to load everything in 1-2 queries instead of N."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-9fa557bac3cbc2ab", "name": "Likely N+1 query: `for m in \u2026` triggers a query per row \u2014 backend/core/management/commands/seed_data.py:1270", "shortDescription": {"text": "Likely N+1 query: `for m in \u2026` triggers a query per row \u2014 backend/core/management/commands/seed_data.py:1270"}, "fullDescription": {"text": "The loop iterates a Django queryset and accesses `m.result.home_score` per row, which fires an additional database query each iteration. Add `.select_related('<fk_field>')` for FK / O2O relations or `.prefetch_related('<m2m_or_reverse>')` for many-related lookups, to load everything in 1-2 queries instead of N."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-7a9681368ec2cb27", "name": "Likely N+1 query: `for m in \u2026` triggers a query per row \u2014 backend/core/management/commands/reset_demo.py:75", "shortDescription": {"text": "Likely N+1 query: `for m in \u2026` triggers a query per row \u2014 backend/core/management/commands/reset_demo.py:75"}, "fullDescription": {"text": "The loop iterates a Django queryset and accesses `m.objects.count` per row, which fires an additional database query each iteration. Add `.select_related('<fk_field>')` for FK / O2O relations or `.prefetch_related('<m2m_or_reverse>')` for many-related lookups, to load everything in 1-2 queries instead of N."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-d2a1f37a39c0ec30", "name": "Likely N+1 query: `for m in \u2026` triggers a query per row \u2014 backend/core/management/commands/reset_demo.py:87", "shortDescription": {"text": "Likely N+1 query: `for m in \u2026` triggers a query per row \u2014 backend/core/management/commands/reset_demo.py:87"}, "fullDescription": {"text": "The loop iterates a Django queryset and accesses `m.objects.all` per row, which fires an additional database query each iteration. Add `.select_related('<fk_field>')` for FK / O2O relations or `.prefetch_related('<m2m_or_reverse>')` for many-related lookups, to load everything in 1-2 queries instead of N."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-6b4f382779287234", "name": "`fetch()` without try/.catch or AbortSignal \u2014 frontend/app/uscite/page.tsx:164", "shortDescription": {"text": "`fetch()` without try/.catch or AbortSignal \u2014 frontend/app/uscite/page.tsx:164"}, "fullDescription": {"text": "Bare `fetch(...)` will throw an unhandled rejection on network failure. Wrap in try/catch, attach a `.catch(...)`, or pass an AbortSignal with a timeout."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-167faaa142570067", "name": "`fetch()` without try/.catch or AbortSignal \u2014 frontend/app/uscite/gestione/page.tsx:724", "shortDescription": {"text": "`fetch()` without try/.catch or AbortSignal \u2014 frontend/app/uscite/gestione/page.tsx:724"}, "fullDescription": {"text": "Bare `fetch(...)` will throw an unhandled rejection on network failure. Wrap in try/catch, attach a `.catch(...)`, or pass an AbortSignal with a timeout."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-43ed37da641af907", "name": "Legacy-named symbol `deactivateOld` in frontend/components/transfer-person.tsx:43", "shortDescription": {"text": "Legacy-named symbol `deactivateOld` in frontend/components/transfer-person.tsx:43"}, "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-3ea81c2c05d3ee51", "name": "`fetch()` without try/.catch or AbortSignal \u2014 frontend/lib/api.ts:38", "shortDescription": {"text": "`fetch()` without try/.catch or AbortSignal \u2014 frontend/lib/api.ts:38"}, "fullDescription": {"text": "Bare `fetch(...)` will throw an unhandled rejection on network failure. Wrap in try/catch, attach a `.catch(...)`, or pass an AbortSignal with a timeout."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-fa86294bd7b8ca79", "name": "`fetch()` without try/.catch or AbortSignal \u2014 frontend/lib/auth.ts:100", "shortDescription": {"text": "`fetch()` without try/.catch or AbortSignal \u2014 frontend/lib/auth.ts:100"}, "fullDescription": {"text": "Bare `fetch(...)` will throw an unhandled rejection on network failure. Wrap in try/catch, attach a `.catch(...)`, or pass an AbortSignal with a timeout."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-af022f937dd5b7fd", "name": "9 env vars used in code but missing from .env.example", "shortDescription": {"text": "9 env vars used in code but missing from .env.example"}, "fullDescription": {"text": "Drift between code and config docs. The first few: `CI`, `INTERNAL_API_HOST`, `NEXT_PUBLIC_SENTRY_DSN`, `NEXT_PUBLIC_SENTRY_ENVIRONMENT`, `NEXT_RUNTIME`, `SENTRY_DSN`, `SENTRY_ENVIRONMENT`, `SENTRY_ORG` + 1 more. Add them (with a placeholder/comment) to .env.example so onboarding doesn't break."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "low", "confidence": 1.0}}, {"id": "scanner-0027e313ade46c8f", "name": "Near-duplicate function bodies in 7 places", "shortDescription": {"text": "Near-duplicate function bodies in 7 places"}, "fullDescription": {"text": "Functions with the same first-5-line body hash:\nbackend/api/tests_standings_flow.py:setUp, backend/api/tests_standings_flow.py:setUp, backend/api/tests_standings_flow.py:setUp, backend/api/tests_standings_flow.py:setUp\n\nThis is *the* AI-coder failure mode (4\u00d7 more duplication in vibe-coded repos \u2014 see https://jw.hn/ai-code-hygiene). Consolidate or document why they're separate."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "low", "confidence": 1.0}}, {"id": "scanner-33a6b62e30ce7ab4", "name": "Near-duplicate function bodies in 6 places", "shortDescription": {"text": "Near-duplicate function bodies in 6 places"}, "fullDescription": {"text": "Functions with the same first-5-line body hash:\nbackend/api/tests.py:setUp, backend/api/tests.py:setUp, backend/api/tests.py:setUp, backend/api/tests.py:setUp\n\nThis is *the* AI-coder failure mode (4\u00d7 more duplication in vibe-coded repos \u2014 see https://jw.hn/ai-code-hygiene). Consolidate or document why they're separate."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "low", "confidence": 1.0}}, {"id": "scanner-2c04133e54348533", "name": "Near-duplicate function bodies in 2 places", "shortDescription": {"text": "Near-duplicate function bodies in 2 places"}, "fullDescription": {"text": "Functions with the same first-5-line body hash:\nbackend/api/tests.py:test_filter_by_status, backend/api/tests.py:test_filter_by_status\n\nThis is *the* AI-coder failure mode (4\u00d7 more duplication in vibe-coded repos \u2014 see https://jw.hn/ai-code-hygiene). Consolidate or document why they're separate."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "low", "confidence": 1.0}}, {"id": "scanner-be46ea126aa5d8dc", "name": "Near-duplicate function bodies in 3 places", "shortDescription": {"text": "Near-duplicate function bodies in 3 places"}, "fullDescription": {"text": "Functions with the same first-5-line body hash:\nbackend/api/viewsets/gare.py:perform_create, backend/api/viewsets/gare.py:perform_create, backend/api/viewsets/gare.py:perform_create\n\nThis is *the* AI-coder failure mode (4\u00d7 more duplication in vibe-coded repos \u2014 see https://jw.hn/ai-code-hygiene). Consolidate or document why they're separate."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "low", "confidence": 1.0}}, {"id": "scanner-02525d39071dd2c7", "name": "Near-duplicate function bodies in 5 places", "shortDescription": {"text": "Near-duplicate function bodies in 5 places"}, "fullDescription": {"text": "Functions with the same first-5-line body hash:\nbackend/api/viewsets/core.py:list, backend/api/viewsets/core.py:list, backend/api/viewsets/core.py:list, backend/api/viewsets/core.py:list\n\nThis is *the* AI-coder failure mode (4\u00d7 more duplication in vibe-coded repos \u2014 see https://jw.hn/ai-code-hygiene). Consolidate or document why they're separate."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "low", "confidence": 1.0}}, {"id": "scanner-9dad557909b86499", "name": "Near-duplicate function bodies in 10 places", "shortDescription": {"text": "Near-duplicate function bodies in 10 places"}, "fullDescription": {"text": "Functions with the same first-5-line body hash:\nbackend/output/tests.py:setUp, backend/output/tests.py:setUp, backend/output/tests.py:setUp, backend/output/tests.py:setUp\n\nThis is *the* AI-coder failure mode (4\u00d7 more duplication in vibe-coded repos \u2014 see https://jw.hn/ai-code-hygiene). Consolidate or document why they're separate."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "low", "confidence": 1.0}}, {"id": "scanner-122053f21232d80c", "name": "Near-duplicate function bodies in 14 places", "shortDescription": {"text": "Near-duplicate function bodies in 14 places"}, "fullDescription": {"text": "Functions with the same first-5-line body hash:\nbackend/gare/tests_gabriele.py:setUp, backend/gare/tests_gabriele.py:setUp, backend/gare/tests_gabriele.py:setUp, backend/gare/tests_gabriele.py:setUp\n\nThis is *the* AI-coder failure mode (4\u00d7 more duplication in vibe-coded repos \u2014 see https://jw.hn/ai-code-hygiene). Consolidate or document why they're separate."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "low", "confidence": 1.0}}, {"id": "scanner-7d0b5cb60878e85f", "name": "Django CBV `CustomTokenObtainPairView` lacks `LoginRequiredMixin` \u2014 backend/users/views.py:23", "shortDescription": {"text": "Django CBV `CustomTokenObtainPairView` lacks `LoginRequiredMixin` \u2014 backend/users/views.py:23"}, "fullDescription": {"text": "Class-based view defines mutating methods (post/put/delete) without inheriting `LoginRequiredMixin`. If auth is enforced via `dispatch()` override or middleware, dismiss this finding."}, "properties": {"scanner": "scanner-primary", "layer": "security", "severity": "medium", "confidence": 1.0}}]}}, "automationDetails": {"id": "repobility/24914"}, "properties": {"repository": "ChefaneFabio/sportdb", "repoUrl": "https://github.com/ChefaneFabio/sportdb", "branch": "main"}, "results": [{"ruleId": "scanner-418753047709052f", "level": "note", "message": {"text": "Possibly dead Python function: validate_sections"}, "properties": {"repobilityId": "c10186e897fa2373", "scanner": "scanner-primary", "fingerprint": "418753047709052f", "layer": "software", "severity": "low", "confidence": 1.0, "tags": ["dead-code"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "backend/api/serializers/output.py:47"}, "region": {"startLine": 1}}}]}, {"ruleId": "scanner-95e720d8c68b607f", "level": "note", "message": {"text": "Possibly dead Python function: validate_filenames"}, "properties": {"repobilityId": "e44311136839f496", "scanner": "scanner-primary", "fingerprint": "95e720d8c68b607f", "layer": "software", "severity": "low", "confidence": 1.0, "tags": ["dead-code"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "backend/api/serializers/output.py:109"}, "region": {"startLine": 1}}}]}, {"ruleId": "scanner-8d96cdf0274a5996", "level": "note", "message": {"text": "Possibly dead Python function: validate_teams"}, "properties": {"repobilityId": "0e7d1a17d3a60e17", "scanner": "scanner-primary", "fingerprint": "8d96cdf0274a5996", "layer": "software", "severity": "low", "confidence": 1.0, "tags": ["dead-code"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "backend/api/serializers/champs.py:50"}, "region": {"startLine": 1}}}]}, {"ruleId": "scanner-f159b874ddd9be00", "level": "warning", "message": {"text": "`dangerouslySetInnerHTML` used in a React component \u2014 frontend/app/layout.tsx:51"}, "properties": {"repobilityId": "c3711f4722a30929", "scanner": "scanner-primary", "fingerprint": "f159b874ddd9be00", "layer": "frontend", "severity": "medium", "confidence": 1.0, "tags": ["frontend-quality", "fq.dangerous-html"]}}, {"ruleId": "scanner-9d2fdbf88b3f5abc", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 frontend/app/uscite/page.tsx:449"}, "properties": {"repobilityId": "30c035e379759075", "scanner": "scanner-primary", "fingerprint": "9d2fdbf88b3f5abc", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-9222f728085ebd57", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 frontend/app/uscite/gestione/page.tsx:911"}, "properties": {"repobilityId": "3b9f672e3d57432b", "scanner": "scanner-primary", "fingerprint": "9222f728085ebd57", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-0ed9a62ca2c83054", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 frontend/app/[sport]/squadre/[id]/page.tsx:164"}, "properties": {"repobilityId": "372f160c8fb59ac4", "scanner": "scanner-primary", "fingerprint": "0ed9a62ca2c83054", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-5e9f3245af59bd6c", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 frontend/app/[sport]/campionati/page.tsx:97"}, "properties": {"repobilityId": "d36cf79333ecca5f", "scanner": "scanner-primary", "fingerprint": "5e9f3245af59bd6c", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-346bc4cf9ee62f8e", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 frontend/app/[sport]/campionati/[slug]/calendario/page.tsx:418"}, "properties": {"repobilityId": "10b02e403e713204", "scanner": "scanner-primary", "fingerprint": "346bc4cf9ee62f8e", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-0cb9d8e16c3e6d6a", "level": "warning", "message": {"text": "`dangerouslySetInnerHTML` used in a React component \u2014 frontend/components/json-ld.tsx:13"}, "properties": {"repobilityId": "aa77cdb35a5bfcdb", "scanner": "scanner-primary", "fingerprint": "0cb9d8e16c3e6d6a", "layer": "frontend", "severity": "medium", "confidence": 1.0, "tags": ["frontend-quality", "fq.dangerous-html"]}}, {"ruleId": "scanner-c6da53ed9621bc2c", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 frontend/components/match-team-panel.tsx:164"}, "properties": {"repobilityId": "23cb73cd8592e5fe", "scanner": "scanner-primary", "fingerprint": "c6da53ed9621bc2c", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-a3d0a0669705ee88", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 frontend/components/global-search.tsx:114"}, "properties": {"repobilityId": "2c607ea957bee69f", "scanner": "scanner-primary", "fingerprint": "a3d0a0669705ee88", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-309d17db4806e5f0", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 frontend/components/live-matches-banner.tsx:43"}, "properties": {"repobilityId": "0c5b9407d69568f5", "scanner": "scanner-primary", "fingerprint": "309d17db4806e5f0", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-1f66ad88286ca30a", "level": "warning", "message": {"text": "Dockerfile runs as root: backend/Dockerfile"}, "properties": {"repobilityId": "7afd2b0e8a8c9eeb", "scanner": "scanner-primary", "fingerprint": "1f66ad88286ca30a", "layer": "hardware", "severity": "medium", "confidence": 1.0, "tags": ["security", "container"]}}, {"ruleId": "scanner-714c31ca9f474ae6", "level": "note", "message": {"text": "Docker base image is tag-pinned but not digest-pinned: python:3.12-slim"}, "properties": {"repobilityId": "f614a1e41f331b37", "scanner": "scanner-primary", "fingerprint": "714c31ca9f474ae6", "layer": "hardware", "severity": "low", "confidence": 1.0, "tags": ["supply-chain", "docker", "pinned-dependencies"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "backend/Dockerfile"}, "region": {"startLine": 1}}}]}, {"ruleId": "scanner-a7f39cdd5fa21931", "level": "note", "message": {"text": "Docker base image is tag-pinned but not digest-pinned: node:22-alpine"}, "properties": {"repobilityId": "6086a1867bf8e871", "scanner": "scanner-primary", "fingerprint": "a7f39cdd5fa21931", "layer": "hardware", "severity": "low", "confidence": 1.0, "tags": ["supply-chain", "docker", "pinned-dependencies"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "frontend/Dockerfile"}, "region": {"startLine": 1}}}]}, {"ruleId": "scanner-aa5acaa49eb8315b", "level": "note", "message": {"text": "Containers defined but no K8s/orchestration manifest found"}, "properties": {"repobilityId": "b230ea9b68736081", "scanner": "scanner-primary", "fingerprint": "aa5acaa49eb8315b", "layer": "hardware", "severity": "low", "confidence": 1.0, "tags": ["coverage", "deployment"]}}, {"ruleId": "scanner-9e9c231a310fb881", "level": "error", "message": {"text": "Runtime dotenv file present in repo: backend/.env"}, "properties": {"repobilityId": "13e19f78c8806475", "scanner": "scanner-primary", "fingerprint": "9e9c231a310fb881", "layer": "security", "severity": "critical", "confidence": 1.0, "tags": ["secrets", "config", "env-file", "runtime-env", "env_file_with_secret"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "backend/.env"}, "region": {"startLine": 1}}}]}, {"ruleId": "scanner-2a28e4d32b2271c4", "level": "error", "message": {"text": "Possible secret in backend/core/management/commands/import_bak.py"}, "properties": {"repobilityId": "efea9a14e004a0bd", "scanner": "scanner-primary", "fingerprint": "2a28e4d32b2271c4", "layer": "security", "severity": "critical", "confidence": 1.0, "tags": ["secrets"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "backend/core/management/commands/import_bak.py"}, "region": {"startLine": 63}}}]}, {"ruleId": "scanner-114433d5894b6324", "level": "warning", "message": {"text": "Insecure pattern 'dangerous_innerhtml' in frontend/app/layout.tsx:51"}, "properties": {"repobilityId": "352266f153f8b038", "scanner": "scanner-primary", "fingerprint": "114433d5894b6324", "layer": "security", "severity": "medium", "confidence": 1.0, "tags": ["owasp", "dangerous_innerhtml"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "frontend/app/layout.tsx"}, "region": {"startLine": 51}}}]}, {"ruleId": "scanner-c845420b6fc04283", "level": "warning", "message": {"text": "Insecure pattern 'dangerous_innerhtml' in frontend/components/json-ld.tsx:13"}, "properties": {"repobilityId": "2079f0496e704dd7", "scanner": "scanner-primary", "fingerprint": "c845420b6fc04283", "layer": "security", "severity": "medium", "confidence": 1.0, "tags": ["owasp", "dangerous_innerhtml"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "frontend/components/json-ld.tsx"}, "region": {"startLine": 13}}}]}, {"ruleId": "scanner-c43251b9322dfa3f", "level": "note", "message": {"text": "Very large file: backend/core/management/commands/seed_data.py (1285 lines)"}, "properties": {"repobilityId": "2f66efc404649162", "scanner": "scanner-primary", "fingerprint": "c43251b9322dfa3f", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["complexity"]}}, {"ruleId": "scanner-ea3b5e389d8c9c0f", "level": "note", "message": {"text": "Low test-to-source ratio"}, "properties": {"repobilityId": "ef7b2552cc00a375", "scanner": "scanner-primary", "fingerprint": "ea3b5e389d8c9c0f", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["tests"]}}, {"ruleId": "scanner-141b30a41e03817b", "level": "note", "message": {"text": "No license file detected"}, "properties": {"repobilityId": "0e0d1cbc845b085f", "scanner": "scanner-primary", "fingerprint": "141b30a41e03817b", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["license", "repo-hardening", "generated-repo-pattern"]}}, {"ruleId": "scanner-3ab5d313dda8e5f9", "level": "note", "message": {"text": "Debug logging residue appears in source files"}, "properties": {"repobilityId": "d0188d4c13ef6b1d", "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": "5a234ed037360795", "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": "db64494390742f9c", "scanner": "scanner-primary", "fingerprint": "2d0c7b7ab8f8aacf", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["placeholder", "mock-data", "critical-flow", "generated-repo-pattern"]}}, {"ruleId": "scanner-b9088664ace7f748", "level": "note", "message": {"text": "Composite production-readiness gap"}, "properties": {"repobilityId": "fd784e9f90eb48bd", "scanner": "scanner-primary", "fingerprint": "b9088664ace7f748", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["production-readiness", "repo-hardening", "generated-repo-pattern"]}}, {"ruleId": "scanner-14070d06d94deecd", "level": "warning", "message": {"text": "Likely N+1 query: `for m in \u2026` triggers a query per row \u2014 backend/api/viewsets/stats.py:261"}, "properties": {"repobilityId": "0ca058b75cd40ced", "scanner": "scanner-primary", "fingerprint": "14070d06d94deecd", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["integrity", "n-plus-one", "performance"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "backend/api/viewsets/stats.py"}, "region": {"startLine": 261}}}]}, {"ruleId": "scanner-8f3dfd90e54db003", "level": "warning", "message": {"text": "Likely N+1 query: `for row in \u2026` triggers a query per row \u2014 backend/api/viewsets/stats.py:287"}, "properties": {"repobilityId": "56d671b4618034e1", "scanner": "scanner-primary", "fingerprint": "8f3dfd90e54db003", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["integrity", "n-plus-one", "performance"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "backend/api/viewsets/stats.py"}, "region": {"startLine": 287}}}]}, {"ruleId": "scanner-b68da62d6f867b5f", "level": "warning", "message": {"text": "Likely N+1 query: `for assignment in \u2026` triggers a query per row \u2014 backend/output/views.py:284"}, "properties": {"repobilityId": "1971d3ae84c9dc32", "scanner": "scanner-primary", "fingerprint": "b68da62d6f867b5f", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["integrity", "n-plus-one", "performance"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "backend/output/views.py"}, "region": {"startLine": 284}}}]}, {"ruleId": "scanner-ed72c44e4aefb348", "level": "warning", "message": {"text": "Likely N+1 query: `for assignment in \u2026` triggers a query per row \u2014 backend/output/views.py:349"}, "properties": {"repobilityId": "28fc5d8d0fc0b19b", "scanner": "scanner-primary", "fingerprint": "ed72c44e4aefb348", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["integrity", "n-plus-one", "performance"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "backend/output/views.py"}, "region": {"startLine": 349}}}]}, {"ruleId": "scanner-08c17bb305f65f36", "level": "warning", "message": {"text": "Likely N+1 query: `for match in \u2026` triggers a query per row \u2014 backend/output/services.py:476"}, "properties": {"repobilityId": "75287b799708cad2", "scanner": "scanner-primary", "fingerprint": "08c17bb305f65f36", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["integrity", "n-plus-one", "performance"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "backend/output/services.py"}, "region": {"startLine": 476}}}]}, {"ruleId": "scanner-a34d061b213baa26", "level": "warning", "message": {"text": "Likely N+1 query: `for match in \u2026` triggers a query per row \u2014 backend/output/services.py:584"}, "properties": {"repobilityId": "583d499a86d2c9e0", "scanner": "scanner-primary", "fingerprint": "a34d061b213baa26", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["integrity", "n-plus-one", "performance"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "backend/output/services.py"}, "region": {"startLine": 584}}}]}, {"ruleId": "scanner-717dac192efe0c20", "level": "warning", "message": {"text": "Likely N+1 query: `for lp in \u2026` triggers a query per row \u2014 backend/output/services.py:622"}, "properties": {"repobilityId": "532937b9c644f67d", "scanner": "scanner-primary", "fingerprint": "717dac192efe0c20", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["integrity", "n-plus-one", "performance"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "backend/output/services.py"}, "region": {"startLine": 622}}}]}, {"ruleId": "scanner-56888126e4820a87", "level": "warning", "message": {"text": "Likely N+1 query: `for match in \u2026` triggers a query per row \u2014 backend/output/services.py:765"}, "properties": {"repobilityId": "0c12d6ffc2ccdae1", "scanner": "scanner-primary", "fingerprint": "56888126e4820a87", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["integrity", "n-plus-one", "performance"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "backend/output/services.py"}, "region": {"startLine": 765}}}]}, {"ruleId": "scanner-ee33acfafff633f0", "level": "none", "message": {"text": "Commented-code block (5 lines) in backend/champs/migrations/0009_alter_championship_level.py:6"}, "properties": {"repobilityId": "20eceee682e46cfd", "scanner": "scanner-primary", "fingerprint": "ee33acfafff633f0", "layer": "quality", "severity": "info", "confidence": 1.0, "tags": ["integrity", "commented-code", "dead-code"]}}, {"ruleId": "scanner-d85e18a26e44f4f7", "level": "warning", "message": {"text": "Likely N+1 query: `for club in \u2026` triggers a query per row \u2014 backend/core/management/commands/seed_data.py:497"}, "properties": {"repobilityId": "1e46ad819201c31c", "scanner": "scanner-primary", "fingerprint": "d85e18a26e44f4f7", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["integrity", "n-plus-one", "performance"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "backend/core/management/commands/seed_data.py"}, "region": {"startLine": 497}}}]}, {"ruleId": "scanner-cc4127377bb29e77", "level": "warning", "message": {"text": "Likely N+1 query: `for team in \u2026` triggers a query per row \u2014 backend/core/management/commands/seed_data.py:513"}, "properties": {"repobilityId": "7e16eedc2e066adb", "scanner": "scanner-primary", "fingerprint": "cc4127377bb29e77", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["integrity", "n-plus-one", "performance"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "backend/core/management/commands/seed_data.py"}, "region": {"startLine": 513}}}]}, {"ruleId": "scanner-a6fd1e40f0309f4c", "level": "warning", "message": {"text": "Likely N+1 query: `for r in \u2026` triggers a query per row \u2014 backend/core/management/commands/seed_data.py:931"}, "properties": {"repobilityId": "8d0f89817ce8b17e", "scanner": "scanner-primary", "fingerprint": "a6fd1e40f0309f4c", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["integrity", "n-plus-one", "performance"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "backend/core/management/commands/seed_data.py"}, "region": {"startLine": 931}}}]}, {"ruleId": "scanner-753deb9bca9afb8a", "level": "warning", "message": {"text": "Likely N+1 query: `for group in \u2026` triggers a query per row \u2014 backend/core/management/commands/seed_data.py:934"}, "properties": {"repobilityId": "ce8eaa95e4dc9cad", "scanner": "scanner-primary", "fingerprint": "753deb9bca9afb8a", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["integrity", "n-plus-one", "performance"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "backend/core/management/commands/seed_data.py"}, "region": {"startLine": 934}}}]}, {"ruleId": "scanner-9bf904dbea33a95a", "level": "warning", "message": {"text": "Likely N+1 query: `for group in \u2026` triggers a query per row \u2014 backend/core/management/commands/seed_data.py:1123"}, "properties": {"repobilityId": "a5867d9e1018f3b2", "scanner": "scanner-primary", "fingerprint": "9bf904dbea33a95a", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["integrity", "n-plus-one", "performance"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "backend/core/management/commands/seed_data.py"}, "region": {"startLine": 1123}}}]}, {"ruleId": "scanner-ab70a37e3296e936", "level": "warning", "message": {"text": "Likely N+1 query: `for m in \u2026` triggers a query per row \u2014 backend/core/management/commands/seed_data.py:1150"}, "properties": {"repobilityId": "767aa7cc15ca0b5b", "scanner": "scanner-primary", "fingerprint": "ab70a37e3296e936", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["integrity", "n-plus-one", "performance"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "backend/core/management/commands/seed_data.py"}, "region": {"startLine": 1150}}}]}, {"ruleId": "scanner-8113b9583858996b", "level": "warning", "message": {"text": "Likely N+1 query: `for m in \u2026` triggers a query per row \u2014 backend/core/management/commands/seed_data.py:1169"}, "properties": {"repobilityId": "559892283d21560c", "scanner": "scanner-primary", "fingerprint": "8113b9583858996b", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["integrity", "n-plus-one", "performance"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "backend/core/management/commands/seed_data.py"}, "region": {"startLine": 1169}}}]}, {"ruleId": "scanner-0fe686056e7d1002", "level": "warning", "message": {"text": "Likely N+1 query: `for m in \u2026` triggers a query per row \u2014 backend/core/management/commands/seed_data.py:1237"}, "properties": {"repobilityId": "630bd5fcba68205e", "scanner": "scanner-primary", "fingerprint": "0fe686056e7d1002", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["integrity", "n-plus-one", "performance"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "backend/core/management/commands/seed_data.py"}, "region": {"startLine": 1237}}}]}, {"ruleId": "scanner-a64e5bcea6f58567", "level": "warning", "message": {"text": "Likely N+1 query: `for m in \u2026` triggers a query per row \u2014 backend/core/management/commands/seed_data.py:1244"}, "properties": {"repobilityId": "649c2a85af9d02ac", "scanner": "scanner-primary", "fingerprint": "a64e5bcea6f58567", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["integrity", "n-plus-one", "performance"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "backend/core/management/commands/seed_data.py"}, "region": {"startLine": 1244}}}]}, {"ruleId": "scanner-9fa557bac3cbc2ab", "level": "warning", "message": {"text": "Likely N+1 query: `for m in \u2026` triggers a query per row \u2014 backend/core/management/commands/seed_data.py:1270"}, "properties": {"repobilityId": "07af26b6e4cfc384", "scanner": "scanner-primary", "fingerprint": "9fa557bac3cbc2ab", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["integrity", "n-plus-one", "performance"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "backend/core/management/commands/seed_data.py"}, "region": {"startLine": 1270}}}]}, {"ruleId": "scanner-7a9681368ec2cb27", "level": "warning", "message": {"text": "Likely N+1 query: `for m in \u2026` triggers a query per row \u2014 backend/core/management/commands/reset_demo.py:75"}, "properties": {"repobilityId": "4f60576d6deda6ff", "scanner": "scanner-primary", "fingerprint": "7a9681368ec2cb27", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["integrity", "n-plus-one", "performance"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "backend/core/management/commands/reset_demo.py"}, "region": {"startLine": 75}}}]}, {"ruleId": "scanner-d2a1f37a39c0ec30", "level": "warning", "message": {"text": "Likely N+1 query: `for m in \u2026` triggers a query per row \u2014 backend/core/management/commands/reset_demo.py:87"}, "properties": {"repobilityId": "1465dd054a9ff5f5", "scanner": "scanner-primary", "fingerprint": "d2a1f37a39c0ec30", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["integrity", "n-plus-one", "performance"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "backend/core/management/commands/reset_demo.py"}, "region": {"startLine": 87}}}]}, {"ruleId": "scanner-6b4f382779287234", "level": "warning", "message": {"text": "`fetch()` without try/.catch or AbortSignal \u2014 frontend/app/uscite/page.tsx:164"}, "properties": {"repobilityId": "6481426491183bca", "scanner": "scanner-primary", "fingerprint": "6b4f382779287234", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["integrity", "fragile-runtime", "robustness"]}}, {"ruleId": "scanner-167faaa142570067", "level": "warning", "message": {"text": "`fetch()` without try/.catch or AbortSignal \u2014 frontend/app/uscite/gestione/page.tsx:724"}, "properties": {"repobilityId": "761af0caa9087f78", "scanner": "scanner-primary", "fingerprint": "167faaa142570067", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["integrity", "fragile-runtime", "robustness"]}}, {"ruleId": "scanner-43ed37da641af907", "level": "note", "message": {"text": "Legacy-named symbol `deactivateOld` in frontend/components/transfer-person.tsx:43"}, "properties": {"repobilityId": "f1ca5235b19c76ad", "scanner": "scanner-primary", "fingerprint": "43ed37da641af907", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["integrity", "legacy-marker", "dead-code"]}}, {"ruleId": "scanner-3ea81c2c05d3ee51", "level": "warning", "message": {"text": "`fetch()` without try/.catch or AbortSignal \u2014 frontend/lib/api.ts:38"}, "properties": {"repobilityId": "873d7bec1cda8224", "scanner": "scanner-primary", "fingerprint": "3ea81c2c05d3ee51", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["integrity", "fragile-runtime", "robustness"]}}, {"ruleId": "scanner-fa86294bd7b8ca79", "level": "warning", "message": {"text": "`fetch()` without try/.catch or AbortSignal \u2014 frontend/lib/auth.ts:100"}, "properties": {"repobilityId": "8e4c9e7f93ab34b7", "scanner": "scanner-primary", "fingerprint": "fa86294bd7b8ca79", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["integrity", "fragile-runtime", "robustness"]}}, {"ruleId": "scanner-af022f937dd5b7fd", "level": "note", "message": {"text": "9 env vars used in code but missing from .env.example"}, "properties": {"repobilityId": "5597384795dea7a4", "scanner": "scanner-primary", "fingerprint": "af022f937dd5b7fd", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["integrity", "config-drift"]}}, {"ruleId": "scanner-0027e313ade46c8f", "level": "note", "message": {"text": "Near-duplicate function bodies in 7 places"}, "properties": {"repobilityId": "d069f51f6197cbae", "scanner": "scanner-primary", "fingerprint": "0027e313ade46c8f", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["integrity", "duplicate", "dry"]}}, {"ruleId": "scanner-33a6b62e30ce7ab4", "level": "note", "message": {"text": "Near-duplicate function bodies in 6 places"}, "properties": {"repobilityId": "fc745e9b2779df59", "scanner": "scanner-primary", "fingerprint": "33a6b62e30ce7ab4", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["integrity", "duplicate", "dry"]}}, {"ruleId": "scanner-2c04133e54348533", "level": "note", "message": {"text": "Near-duplicate function bodies in 2 places"}, "properties": {"repobilityId": "baca6e60d8608f73", "scanner": "scanner-primary", "fingerprint": "2c04133e54348533", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["integrity", "duplicate", "dry"]}}, {"ruleId": "scanner-be46ea126aa5d8dc", "level": "note", "message": {"text": "Near-duplicate function bodies in 3 places"}, "properties": {"repobilityId": "00070486e809facb", "scanner": "scanner-primary", "fingerprint": "be46ea126aa5d8dc", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["integrity", "duplicate", "dry"]}}, {"ruleId": "scanner-be46ea126aa5d8dc", "level": "note", "message": {"text": "Near-duplicate function bodies in 3 places"}, "properties": {"repobilityId": "cc380a6007d55f1e", "scanner": "scanner-primary", "fingerprint": "be46ea126aa5d8dc", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["integrity", "duplicate", "dry"]}}, {"ruleId": "scanner-be46ea126aa5d8dc", "level": "note", "message": {"text": "Near-duplicate function bodies in 3 places"}, "properties": {"repobilityId": "f9b259aab4be4143", "scanner": "scanner-primary", "fingerprint": "be46ea126aa5d8dc", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["integrity", "duplicate", "dry"]}}, {"ruleId": "scanner-be46ea126aa5d8dc", "level": "note", "message": {"text": "Near-duplicate function bodies in 3 places"}, "properties": {"repobilityId": "1f94e7941c7fe981", "scanner": "scanner-primary", "fingerprint": "be46ea126aa5d8dc", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["integrity", "duplicate", "dry"]}}, {"ruleId": "scanner-02525d39071dd2c7", "level": "note", "message": {"text": "Near-duplicate function bodies in 5 places"}, "properties": {"repobilityId": "a5ad9c8423f7e86b", "scanner": "scanner-primary", "fingerprint": "02525d39071dd2c7", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["integrity", "duplicate", "dry"]}}, {"ruleId": "scanner-02525d39071dd2c7", "level": "note", "message": {"text": "Near-duplicate function bodies in 5 places"}, "properties": {"repobilityId": "5243e1acb9e9b138", "scanner": "scanner-primary", "fingerprint": "02525d39071dd2c7", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["integrity", "duplicate", "dry"]}}, {"ruleId": "scanner-2c04133e54348533", "level": "note", "message": {"text": "Near-duplicate function bodies in 2 places"}, "properties": {"repobilityId": "7c849aeafb4183ca", "scanner": "scanner-primary", "fingerprint": "2c04133e54348533", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["integrity", "duplicate", "dry"]}}, {"ruleId": "scanner-9dad557909b86499", "level": "note", "message": {"text": "Near-duplicate function bodies in 10 places"}, "properties": {"repobilityId": "22d0fed954db7354", "scanner": "scanner-primary", "fingerprint": "9dad557909b86499", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["integrity", "duplicate", "dry"]}}, {"ruleId": "scanner-2c04133e54348533", "level": "note", "message": {"text": "Near-duplicate function bodies in 2 places"}, "properties": {"repobilityId": "ece86f3f5cdf240f", "scanner": "scanner-primary", "fingerprint": "2c04133e54348533", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["integrity", "duplicate", "dry"]}}, {"ruleId": "scanner-2c04133e54348533", "level": "note", "message": {"text": "Near-duplicate function bodies in 2 places"}, "properties": {"repobilityId": "ab5b778258dd5459", "scanner": "scanner-primary", "fingerprint": "2c04133e54348533", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["integrity", "duplicate", "dry"]}}, {"ruleId": "scanner-2c04133e54348533", "level": "note", "message": {"text": "Near-duplicate function bodies in 2 places"}, "properties": {"repobilityId": "f400b1ae01a2b2b3", "scanner": "scanner-primary", "fingerprint": "2c04133e54348533", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["integrity", "duplicate", "dry"]}}, {"ruleId": "scanner-2c04133e54348533", "level": "note", "message": {"text": "Near-duplicate function bodies in 2 places"}, "properties": {"repobilityId": "01d7d554bf353b34", "scanner": "scanner-primary", "fingerprint": "2c04133e54348533", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["integrity", "duplicate", "dry"]}}, {"ruleId": "scanner-122053f21232d80c", "level": "note", "message": {"text": "Near-duplicate function bodies in 14 places"}, "properties": {"repobilityId": "30923a84d5fecd6c", "scanner": "scanner-primary", "fingerprint": "122053f21232d80c", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["integrity", "duplicate", "dry"]}}, {"ruleId": "scanner-2c04133e54348533", "level": "note", "message": {"text": "Near-duplicate function bodies in 2 places"}, "properties": {"repobilityId": "814f1aa7698d9850", "scanner": "scanner-primary", "fingerprint": "2c04133e54348533", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["integrity", "duplicate", "dry"]}}, {"ruleId": "scanner-2c04133e54348533", "level": "note", "message": {"text": "Near-duplicate function bodies in 2 places"}, "properties": {"repobilityId": "96c98b9d2ba3de2f", "scanner": "scanner-primary", "fingerprint": "2c04133e54348533", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["integrity", "duplicate", "dry"]}}, {"ruleId": "scanner-0027e313ade46c8f", "level": "note", "message": {"text": "Near-duplicate function bodies in 7 places"}, "properties": {"repobilityId": "36003d810354a6b0", "scanner": "scanner-primary", "fingerprint": "0027e313ade46c8f", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["integrity", "duplicate", "dry"]}}, {"ruleId": "scanner-2c04133e54348533", "level": "note", "message": {"text": "Near-duplicate function bodies in 2 places"}, "properties": {"repobilityId": "a8fce5f85364aecd", "scanner": "scanner-primary", "fingerprint": "2c04133e54348533", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["integrity", "duplicate", "dry"]}}, {"ruleId": "scanner-7d0b5cb60878e85f", "level": "warning", "message": {"text": "Django CBV `CustomTokenObtainPairView` lacks `LoginRequiredMixin` \u2014 backend/users/views.py:23"}, "properties": {"repobilityId": "f5279bbcb1f91aac", "scanner": "scanner-primary", "fingerprint": "7d0b5cb60878e85f", "layer": "security", "severity": "medium", "confidence": 1.0, "tags": ["auth", "auth.django.unauth_view"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "backend/users/views.py"}, "region": {"startLine": 23}}}]}]}]}