{"schema_version":"2","scorer_version":"0.1.0","scoring_version":"prov-5+qual-2+sec-2","generated_at":"2026-11-14T14:52:01.649683Z","repo":{"ref":{"host":"github.com","owner":"RaihanKaskandar","name":"basket"},"default_branch":"main","clone_url":"https://github.com/RaihanKaskandar/basket.git","html_url":"https://github.com/RaihanKaskandar/basket","description":"A self-hosted household grocery list that understands English and Dutch","stars":0,"forks":0,"is_fork":false,"is_archived":false,"is_private":false,"size_kb":1275,"primary_language":"TypeScript","license_spdx":"MIT","created_at":"2026-10-23T09:14:29Z","pushed_at":"2026-11-10T11:51:19Z","security_policy_url":null,"distribution":{"owner_created_at":"2020-12-25T16:12:57Z","owner_type":"User","release_assets":[]}},"commit_sha":"cdb0f513c6c82f4683a880260b37e8a49593d0bc","profile":{"lines_by_language":{"TypeScript":4001,"JavaScript":137},"files_by_category":{"source":34,"binary":11,"config":10,"other":4,"docs":2,"test":2,"generated":1},"source_lines":4023,"test_lines":115},"pillars":{"ai_provenance":{"score":0.0,"confidence":0.41,"coverage":1.0,"label":"possible","breakdown":{"attributed_share":0.0,"suspected_share":0.0,"estimated_share":0.0,"ai_artifacts":0.0,"flagged_work_units":0.0,"flagged_releases":null,"style_index":1.989},"summary":"Weak signals consistent with AI-assisted development. Comments and strings use phrasing typical of LLM-written code (see the coding style evidence)."},"quality":{"score":77.0,"confidence":0.9,"coverage":1.0,"label":"adequate","breakdown":{"complexity":64.1,"duplication":95.0,"lint":94.0,"testing":66.4,"docs":65.0,"type_safety":100.0,"process":null},"summary":"Code quality is adequate: test-to-source ratio 0.03, CI runs tests; 15% of function code in complex or long functions; 1% duplicated lines. Weakest area: complexity."},"security":{"score":77.2,"confidence":0.85,"coverage":1.0,"label":"adequate","breakdown":{"secrets":100.0,"sast":100.0,"dependencies":87.5,"ci_actions":46.8,"posture":0.0,"scorecard":null},"summary":"Security posture is adequate: 1 known vulnerabilities in 1 dependencies; 3 high-severity workflow issues. Weakest area: posture."}},"analyzer_results":[{"analyzer":"sec-scorecard","pillar":"security","status":"skipped","tool_version":null,"metrics":{},"findings":[],"evidence":[],"data":{},"error":"no published OpenSSF Scorecard result for this repo"},{"analyzer":"sec-registry","pillar":"security","status":"ok","tool_version":null,"metrics":{"declared":12.0,"checked":12.0,"missing":0.0,"recent":0.0,"lookup_errors":0.0},"findings":[],"evidence":[],"data":{"phantom":false},"error":null},{"analyzer":"ai-attribution","pillar":"ai_provenance","status":"ok","tool_version":"signatures-v1","metrics":{"commits":2.0,"attributed_commits":0.0,"attributed_commit_share":0.0,"effective_loc":4154.0,"attributed_loc":0.0,"attributed_loc_share":0.0,"tools_detected":0.0},"findings":[],"evidence":[],"data":{"attributed_loc_by_commit":{},"tools":{},"monthly":{"2026-10":{"loc":4145,"attributed_loc":0},"2026-11":{"loc":9,"attributed_loc":0}}},"error":null},{"analyzer":"ai-artifacts","pillar":"ai_provenance","status":"ok","tool_version":"signatures-v1","metrics":{"artifacts":0.0,"workflow_agents":0.0,"tools_configured":0.0},"findings":[],"evidence":[],"data":{"artifacts":[],"workflows":[],"tools":[]},"error":null},{"analyzer":"ai-velocity","pillar":"ai_provenance","status":"ok","tool_version":"prov-4","metrics":{"work_units":1.0,"flagged_units":0.0,"pre_ai_era_bursts":0.0,"pre_ai_era_measured_loc":0.0,"pre_ai_era_burst_loc":0.0,"measured_loc":9.0,"flagged_loc":0.0,"flagged_loc_share":0.0,"max_loc_per_hour":2.25,"median_loc_per_hour":0.0,"pr_timed_units":0.0,"excluded_import_loc":4145.0},"findings":[],"evidence":[],"data":{"flagged_loc_by_commit":{},"excluded_import_commits":["9f781a750597f022316a4f9cf2411df0f9c9708a"]},"error":null},{"analyzer":"ai-release-velocity","pillar":"ai_provenance","status":"skipped","tool_version":null,"metrics":{},"findings":[],"evidence":[],"data":{},"error":null},{"analyzer":"ai-stylometry","pillar":"ai_provenance","status":"ok","tool_version":null,"metrics":{"lines_scanned":4023.0,"index":1.989,"count:narrated_steps":0.0,"per_kloc:narrated_steps":0.0,"files:narrated_steps":0.0,"count:placeholder":0.0,"per_kloc:placeholder":0.0,"files:placeholder":0.0,"count:emoji_in_code":16.0,"per_kloc:emoji_in_code":3.977,"files:emoji_in_code":3.0,"count:assistant_voice":0.0,"per_kloc:assistant_voice":0.0,"files:assistant_voice":0.0},"findings":[],"evidence":[],"data":{},"error":null},{"analyzer":"sec-secrets","pillar":"security","status":"ok","tool_version":"gitleaks 8.30.1","metrics":{"secrets_current":0.0,"secrets_history":0.0,"secrets_nonprod":0.0,"secrets_low_confidence":0.0},"findings":[],"evidence":[],"data":{},"error":null},{"analyzer":"sec-sast","pillar":"security","status":"ok","tool_version":"opengrep 1.33.1; rules f1d2b562b414","metrics":{"findings":0.0,"findings_high":0.0,"findings_medium":0.0,"findings_low":0.0,"weighted_findings":0.0,"scanned_lines":4023.0,"parse_errors":0.0},"findings":[],"evidence":[],"data":{"rulesets":["typescript","javascript","dockerfile"]},"error":null},{"analyzer":"sec-deps","pillar":"security","status":"ok","tool_version":"osv-scanner version: 2.7.1","metrics":{"vulnerable_packages":1.0,"vulnerabilities":1.0,"vulns_critical":0.0,"vulns_high":1.0,"vulns_medium":0.0,"vulns_low":0.0,"vulns_unknown":0.0,"penalty":8.0},"findings":[{"rule_id":"osv/GHSA-27r3-jxmh-p828","severity":"high","message":"body-parser@2.3.0 (npm) is affected by GHSA-27r3-jxmh-p828","path":"package-lock.json","line":null,"fingerprint":"body-parser@2.3.0 (npm):GHSA-27r3-jxmh-p828"}],"evidence":[],"data":{"ecosystems":["npm"]},"error":null},{"analyzer":"sec-actions","pillar":"security","status":"ok","tool_version":"zizmor 1.32.0","metrics":{"workflows":1.0,"findings":8.0,"findings_high":3.0,"findings_medium":5.0,"findings_low":0.0,"penalty":45.6},"findings":[{"rule_id":"zizmor/unpinned-uses","severity":"high","message":"unpinned action reference [confidence high]","path":".github/workflows/ci.yml","line":12,"fingerprint":"unpinned-uses:.github/workflows/ci.yml:12"},{"rule_id":"zizmor/unpinned-uses","severity":"high","message":"unpinned action reference [confidence high]","path":".github/workflows/ci.yml","line":13,"fingerprint":"unpinned-uses:.github/workflows/ci.yml:13"},{"rule_id":"zizmor/unpinned-uses","severity":"high","message":"unpinned action reference [confidence high]","path":".github/workflows/ci.yml","line":26,"fingerprint":"unpinned-uses:.github/workflows/ci.yml:26"},{"rule_id":"zizmor/artipacked","severity":"medium","message":"credential persistence through GitHub Actions artifacts [confidence low]","path":".github/workflows/ci.yml","line":12,"fingerprint":"artipacked:.github/workflows/ci.yml:12"},{"rule_id":"zizmor/artipacked","severity":"medium","message":"credential persistence through GitHub Actions artifacts [confidence low]","path":".github/workflows/ci.yml","line":26,"fingerprint":"artipacked:.github/workflows/ci.yml:26"},{"rule_id":"zizmor/excessive-permissions","severity":"medium","message":"overly broad permissions [confidence medium]","path":".github/workflows/ci.yml","line":1,"fingerprint":"excessive-permissions:.github/workflows/ci.yml:1"},{"rule_id":"zizmor/excessive-permissions","severity":"medium","message":"overly broad permissions [confidence medium]","path":".github/workflows/ci.yml","line":9,"fingerprint":"excessive-permissions:.github/workflows/ci.yml:9"},{"rule_id":"zizmor/excessive-permissions","severity":"medium","message":"overly broad permissions [confidence medium]","path":".github/workflows/ci.yml","line":23,"fingerprint":"excessive-permissions:.github/workflows/ci.yml:23"}],"evidence":[],"data":{},"error":null},{"analyzer":"sec-posture","pillar":"security","status":"ok","tool_version":null,"metrics":{"check:security_policy":0.0,"check:dependency_updates":0.0,"check:signed_commits":0.0,"check:lockfiles":1.0,"signed_commit_share":0.0,"unpinned_manifests":0.0},"findings":[],"evidence":[],"data":{},"error":null},{"analyzer":"sec-distribution","pillar":"security","status":"ok","tool_version":null,"metrics":{"signals":0.0,"binary_assets":0.0,"suspicious":0.0},"findings":[],"evidence":[],"data":{"signals":[],"suspicious":false,"unusual_traction":false,"metadata":true},"error":null},{"analyzer":"qual-complexity","pillar":"quality","status":"ok","tool_version":"lizard 1.25.1","metrics":{"functions":418.0,"function_nloc":2693.0,"mean_ccn":2.19,"p90_ccn":4.0,"complex_functions":3.0,"long_functions":2.0,"many_param_functions":0.0,"risky_nloc_share":0.1485},"findings":[],"evidence":[{"kind":"complex-function","description":"paint in scripts/make-icons.mjs: complexity 21, 26 lines","ref":"scripts/make-icons.mjs","url":"https://github.com/RaihanKaskandar/basket/blob/cdb0f513c6c82f4683a880260b37e8a49593d0bc/scripts/make-icons.mjs#L79","weight":0.35},{"kind":"complex-function","description":"suggestions in server/suggest.ts: complexity 18, 46 lines","ref":"server/suggest.ts","url":"https://github.com/RaihanKaskandar/basket/blob/cdb0f513c6c82f4683a880260b37e8a49593d0bc/server/suggest.ts#L16","weight":0.3},{"kind":"complex-function","description":"scoreTerm in shared/match.ts: complexity 17, 16 lines","ref":"shared/match.ts","url":"https://github.com/RaihanKaskandar/basket/blob/cdb0f513c6c82f4683a880260b37e8a49593d0bc/shared/match.ts#L191","weight":0.2833333333333333},{"kind":"complex-function","description":"App in src/App.tsx: complexity 13, 138 lines","ref":"src/App.tsx","url":"https://github.com/RaihanKaskandar/basket/blob/cdb0f513c6c82f4683a880260b37e8a49593d0bc/src/App.tsx#L43","weight":0.21666666666666667},{"kind":"complex-function","description":"SettingsSheet in src/components/SettingsSheet.tsx: complexity 3, 174 lines","ref":"src/components/SettingsSheet.tsx","url":"https://github.com/RaihanKaskandar/basket/blob/cdb0f513c6c82f4683a880260b37e8a49593d0bc/src/components/SettingsSheet.tsx#L83","weight":0.05}],"data":{},"error":null},{"analyzer":"qual-duplication","pillar":"quality","status":"ok","tool_version":"repotrust-dup-w6","metrics":{"compared_lines":3054.0,"duplicated_lines":26.0,"duplicated_share":0.0085,"files":34.0},"findings":[],"evidence":[{"kind":"duplicate-code","description":"6+ duplicated lines: src/App.tsx:9 and src/api.ts:8","ref":"src/App.tsx","url":"https://github.com/RaihanKaskandar/basket/blob/cdb0f513c6c82f4683a880260b37e8a49593d0bc/src/App.tsx#L9","weight":0.3},{"kind":"duplicate-code","description":"6+ duplicated lines: src/components/Sidebar.tsx:101 and src/components/Suggestions.tsx:28","ref":"src/components/Sidebar.tsx","url":"https://github.com/RaihanKaskandar/basket/blob/cdb0f513c6c82f4683a880260b37e8a49593d0bc/src/components/Sidebar.tsx#L101","weight":0.3}],"data":{},"error":null},{"analyzer":"qual-lint","pillar":"quality","status":"ok","tool_version":"opengrep 1.33.1; rules f1d2b562b414","metrics":{"findings":1.0,"weighted_findings":1.0,"scanned_lines":4023.0,"category:best-practice":1.0},"findings":[{"rule_id":"opengrep/typescript.react.best-practice.react-props-spreading","severity":"medium","message":"It's best practice to explicitly pass props to an HTML component rather than use the spread operator. The spread operator risks passing invalid HTML props to an HTML element, which can cause console warnings or worse, give malicious actors a way to inject unexpected attributes.","path":"src/components/ListView.tsx","line":63,"fingerprint":"typescript.react.best-practice.react-props-spreading:src/components/ListView.tsx:63"}],"evidence":[],"data":{},"error":null},{"analyzer":"qual-testing","pillar":"quality","status":"ok","tool_version":null,"metrics":{"check:has_tests":1.0,"check:test_ratio":0.0572,"check:ci_present":1.0,"check:ci_runs_tests":1.0,"check:ci_runs_lint":0.0,"check:tests_cochange":1.0,"test_lines":115.0,"source_lines":4023.0,"test_ratio":0.0286,"ci_files":1.0,"cochange_share":0.5,"cochange_commits":2.0},"findings":[],"evidence":[{"kind":"ci","description":"CI config: .github/workflows/ci.yml","ref":".github/workflows/ci.yml","url":null,"weight":0.0},{"kind":"ci","description":"CI runs tests (npm test)","ref":null,"url":null,"weight":0.0}],"data":{"test_commands":["npm test"],"lint_commands":[]},"error":null},{"analyzer":"qual-docs","pillar":"quality","status":"ok","tool_version":null,"metrics":{"check:readme":1.0,"check:license":1.0,"check:contributing":0.0,"check:changelog":0.0,"readme_lines":143.0},"findings":[],"evidence":[{"kind":"docs","description":"README.md","ref":"README.md","url":null,"weight":0.0},{"kind":"docs","description":"LICENSE","ref":"LICENSE","url":null,"weight":0.0}],"data":{},"error":null},{"analyzer":"qual-type-safety","pillar":"quality","status":"ok","tool_version":null,"metrics":{"check:strict_config":1.0,"check:low_escape_density":1.0,"escapes":0.0,"escapes_per_kloc":0.0},"findings":[],"evidence":[{"kind":"typing","description":"TypeScript strict type checking: tsconfig.json","ref":"tsconfig.json","url":null,"weight":0.0}],"data":{},"error":null}],"flags":[]}