{"schema_version":"2","scorer_version":"0.1.0","scoring_version":"prov-5+qual-2+sec-2","generated_at":"2026-11-14T14:52:03.479253Z","repo":{"ref":{"host":"github.com","owner":"chr1shaefn3r","name":"grow-up"},"default_branch":"main","clone_url":"https://github.com/chr1shaefn3r/grow-up.git","html_url":"https://github.com/chr1shaefn3r/grow-up","description":"build an eye-aligned face timelapse from photos of one person in an Immich library","stars":24,"forks":3,"is_fork":false,"is_archived":false,"is_private":false,"size_kb":1134,"primary_language":"Python","license_spdx":"MIT","created_at":"2026-08-08T19:07:35Z","pushed_at":"2026-11-05T22:03:55Z","security_policy_url":null,"distribution":{"owner_created_at":"2015-04-17T15:47:39Z","owner_type":"User","release_assets":[]}},"commit_sha":"2e2d40c88dc8dfee0b2ed294184c9f10c95d5d99","profile":{"lines_by_language":{"Python":18359,"Shell":35},"files_by_category":{"test":27,"source":18,"config":5,"docs":4},"source_lines":8331,"test_lines":10063},"pillars":{"ai_provenance":{"score":100.0,"confidence":0.89,"coverage":1.0,"label":"explicit","breakdown":{"attributed_share":1.0,"suspected_share":0.0,"estimated_share":1.0,"ai_artifacts":3.0,"flagged_work_units":3.0,"flagged_releases":0.0,"style_index":0.24},"summary":"Explicit AI attribution on 100% of first-party code added; an estimated 100% including velocity signals."},"quality":{"score":77.3,"confidence":0.9,"coverage":1.0,"label":"adequate","breakdown":{"complexity":79.4,"duplication":98.3,"lint":52.9,"testing":90.0,"docs":65.0,"type_safety":40.0,"process":null},"summary":"Code quality is adequate: test-to-source ratio 1.21, CI runs tests; 8% of function code in complex or long functions; 0% duplicated lines. Weakest area: type safety."},"security":{"score":73.5,"confidence":0.85,"coverage":1.0,"label":"adequate","breakdown":{"secrets":100.0,"sast":72.2,"dependencies":null,"ci_actions":66.7,"posture":20.0,"scorecard":null},"summary":"Security posture is adequate: 9 high-severity SAST findings; 2 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":7.0,"checked":7.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":76.0,"attributed_commits":74.0,"attributed_commit_share":0.9736842105263158,"effective_loc":19735.0,"attributed_loc":19735.0,"attributed_loc_share":1.0,"tools_detected":1.0},"findings":[],"evidence":[{"kind":"attribution-summary","description":"Claude Code: 74 attributed commits, 19,735 lines added","ref":null,"url":null,"weight":1.0},{"kind":"attributed-commit","description":"Claude Code: author email noreply@anthropic.com","ref":"2e2d40c88dc8dfee0b2ed294184c9f10c95d5d99","url":"https://github.com/chr1shaefn3r/grow-up/commit/2e2d40c88dc8dfee0b2ed294184c9f10c95d5d99","weight":0.9},{"kind":"attributed-commit","description":"Claude Code: author email noreply@anthropic.com","ref":"af86092a9b77c4fb741104bb1b00dfc94e4696f3","url":"https://github.com/chr1shaefn3r/grow-up/commit/af86092a9b77c4fb741104bb1b00dfc94e4696f3","weight":0.9},{"kind":"attributed-commit","description":"Claude Code: author email noreply@anthropic.com","ref":"15d4bb3c7e32d588e64e7397e16fe1f443c7cdf2","url":"https://github.com/chr1shaefn3r/grow-up/commit/15d4bb3c7e32d588e64e7397e16fe1f443c7cdf2","weight":0.9},{"kind":"attributed-commit","description":"Claude Code: author email noreply@anthropic.com","ref":"c9acd43fb1c6655d38b977c63d4eb5ae7b621c1d","url":"https://github.com/chr1shaefn3r/grow-up/commit/c9acd43fb1c6655d38b977c63d4eb5ae7b621c1d","weight":0.9},{"kind":"attributed-commit","description":"Claude Code: author email noreply@anthropic.com","ref":"6b5b2cd4bef3c940b75875293d70c3938cb0c179","url":"https://github.com/chr1shaefn3r/grow-up/commit/6b5b2cd4bef3c940b75875293d70c3938cb0c179","weight":0.9},{"kind":"attributed-commit","description":"Claude Code: author email noreply@anthropic.com","ref":"c5e31e2e4482e9da479e7f6932de4db1cae85e2b","url":"https://github.com/chr1shaefn3r/grow-up/commit/c5e31e2e4482e9da479e7f6932de4db1cae85e2b","weight":0.9},{"kind":"attributed-commit","description":"Claude Code: author email noreply@anthropic.com","ref":"c5c7c565e2c56e935b349a5e34f18ef451acb717","url":"https://github.com/chr1shaefn3r/grow-up/commit/c5c7c565e2c56e935b349a5e34f18ef451acb717","weight":0.9},{"kind":"attributed-commit","description":"Claude Code: author email noreply@anthropic.com","ref":"a9aabe8d6798f666ab9cec9eba07518d0cd2e91d","url":"https://github.com/chr1shaefn3r/grow-up/commit/a9aabe8d6798f666ab9cec9eba07518d0cd2e91d","weight":0.9},{"kind":"attributed-commit","description":"Claude Code: author email noreply@anthropic.com","ref":"796e5554aa4f47fd552ccfd2f41e4453a6187893","url":"https://github.com/chr1shaefn3r/grow-up/commit/796e5554aa4f47fd552ccfd2f41e4453a6187893","weight":0.9},{"kind":"attributed-commit","description":"Claude Code: author email noreply@anthropic.com","ref":"8dd0bcb157c0cc50d870da92c418e4bf2c64b3b5","url":"https://github.com/chr1shaefn3r/grow-up/commit/8dd0bcb157c0cc50d870da92c418e4bf2c64b3b5","weight":0.9},{"kind":"attributed-commit","description":"Claude Code: author email noreply@anthropic.com","ref":"b9956df8f8ea9128ac4412ff156b3850931e4e81","url":"https://github.com/chr1shaefn3r/grow-up/commit/b9956df8f8ea9128ac4412ff156b3850931e4e81","weight":0.9},{"kind":"attributed-commit","description":"Claude Code: author email noreply@anthropic.com","ref":"dd2d55d81818eb8e626038a038f3876be034aa17","url":"https://github.com/chr1shaefn3r/grow-up/commit/dd2d55d81818eb8e626038a038f3876be034aa17","weight":0.9},{"kind":"attributed-commit","description":"Claude Code: author email noreply@anthropic.com","ref":"b5edaebefdc5f65bc946283467344a941c079fda","url":"https://github.com/chr1shaefn3r/grow-up/commit/b5edaebefdc5f65bc946283467344a941c079fda","weight":0.9},{"kind":"attributed-commit","description":"Claude Code: author email noreply@anthropic.com","ref":"7ec3c39e9a0f167d37fdb1be762e2826654657ee","url":"https://github.com/chr1shaefn3r/grow-up/commit/7ec3c39e9a0f167d37fdb1be762e2826654657ee","weight":0.9},{"kind":"attributed-commit","description":"Claude Code: author email noreply@anthropic.com","ref":"5b54689e4c97c39693764cadb5b51a7c85f6601e","url":"https://github.com/chr1shaefn3r/grow-up/commit/5b54689e4c97c39693764cadb5b51a7c85f6601e","weight":0.9},{"kind":"attributed-commit","description":"Claude Code: author email noreply@anthropic.com","ref":"5ddfc0901254a222da268f32dc991ced8cd9c91a","url":"https://github.com/chr1shaefn3r/grow-up/commit/5ddfc0901254a222da268f32dc991ced8cd9c91a","weight":0.9},{"kind":"attributed-commit","description":"Claude Code: author email noreply@anthropic.com","ref":"1648be82f06ef445c238d9ce23c50c079dc95fb2","url":"https://github.com/chr1shaefn3r/grow-up/commit/1648be82f06ef445c238d9ce23c50c079dc95fb2","weight":0.9},{"kind":"attributed-commit","description":"Claude Code: author email noreply@anthropic.com","ref":"760ddcceac251fd5eb49b7cf90e31f55ad449e06","url":"https://github.com/chr1shaefn3r/grow-up/commit/760ddcceac251fd5eb49b7cf90e31f55ad449e06","weight":0.9},{"kind":"attributed-commit","description":"Claude Code: author email noreply@anthropic.com","ref":"cca804a46dece508b0c7575adb2eb9b2fe76a348","url":"https://github.com/chr1shaefn3r/grow-up/commit/cca804a46dece508b0c7575adb2eb9b2fe76a348","weight":0.9},{"kind":"attributed-commit","description":"Claude Code: author email noreply@anthropic.com","ref":"13d607393f25409133375a23c835d32a9a139321","url":"https://github.com/chr1shaefn3r/grow-up/commit/13d607393f25409133375a23c835d32a9a139321","weight":0.9},{"kind":"attributed-commit","description":"Claude Code: author email noreply@anthropic.com","ref":"3c2dae7dc2a2cbb7a2f4f48eabbabd5b489ade19","url":"https://github.com/chr1shaefn3r/grow-up/commit/3c2dae7dc2a2cbb7a2f4f48eabbabd5b489ade19","weight":0.9},{"kind":"attributed-commit","description":"Claude Code: author email noreply@anthropic.com","ref":"c9bd8929adf16d99692661e53acd56296359c304","url":"https://github.com/chr1shaefn3r/grow-up/commit/c9bd8929adf16d99692661e53acd56296359c304","weight":0.9},{"kind":"attributed-commit","description":"Claude Code: author email noreply@anthropic.com","ref":"2e69a92fd68e224f80f0329041a761a738c3801b","url":"https://github.com/chr1shaefn3r/grow-up/commit/2e69a92fd68e224f80f0329041a761a738c3801b","weight":0.9},{"kind":"attributed-commit","description":"Claude Code: author email noreply@anthropic.com","ref":"a0b5866a98df141eda283a9d8f21e3a6ea043933","url":"https://github.com/chr1shaefn3r/grow-up/commit/a0b5866a98df141eda283a9d8f21e3a6ea043933","weight":0.9},{"kind":"attributed-commit","description":"Claude Code: author email noreply@anthropic.com","ref":"1319992efa4f1264e78d6b086256c9a611e9c403","url":"https://github.com/chr1shaefn3r/grow-up/commit/1319992efa4f1264e78d6b086256c9a611e9c403","weight":0.9}],"data":{"attributed_loc_by_commit":{"78f37da2e4f573af742191f5d281ca3c26f35468":3200,"1e9ececcc37da372267d41261b837d9df24a7529":0,"e2de81f096b1be38f24b9dd8f4e86372c121b313":0,"d7d8da5046283b194a1d355e17794b0fea7afd4c":609,"de65c2232528e5fa7cad54abd6b39fdfe1481fdc":284,"83f271db32a91df49c0046885a02f75af142cb8c":446,"79f851f2f7d52b1d63598753e245d5075d809ece":365,"e66bc8617afa02626af35118f6cc7f89a27a7774":85,"e9f1143f9ebfe075c3fc3bcbeff1453725387b73":120,"b60d31b60e99dfda7657ad5f310bf2ffdf1e9afd":210,"137106a5cf039aa6b90d0eeb17f56720e55c3e6b":179,"f5396144dc2712c4f9d19b44c897f40253ccd358":897,"6b4e57b8ca4b05f3d5996a9df69461af2bf5273e":82,"9fa7081f308ebeb23fc25ca1ea280258686672ca":123,"1915dcacc7f90f67b5950862d4dbb9a572eeb47e":117,"0150e2e2a9a7c1ad2583d25d564c9335e912a75b":89,"1cd9fc0ed966be0db33d1e5581260a0a5fa6464f":1007,"d6af3a3c62be4ab28f61439f414444bc9d008262":562,"f3c22cc9a094073bb3b77383fdd7658ac1c0679c":271,"592b1d07e3e8b36173d5f714c9d605ef0433cdd6":17,"476e49523010a15162ed2a53cc1a51772b61a96c":56,"160c52efa9e6f962a78949ec6a1874caf60e533b":72,"387796d9520de4c5e1603b4ff21ebd371038f79f":0,"906472d013c1cddffefdf9eb8d0c3b91356bdb26":19,"fd83b2ffd1804e3a5dc3ee65ff40c96d34d7712a":145,"9dee8f1747bdf7998ffa6916aa1cf0fe7a74fe85":1,"ebfa0b9eb87a87e5065980c35322252bd02dd1db":816,"69e93ed51bb3ddf60dd67af3d62e4400f97e0ef6":87,"2fe89352aa8dd11b80f0394d094a252c65a93518":1,"eb92668937bcad3353ffd913f1da93fdd96c1d21":859,"97dd4f3bba0e3499f5ba2a0c5c2e584a7008ba74":1,"25163e62ca69e74779a901550ba4116d378489d2":312,"f88ca4aecfadd914c580ce13d2b309d149c0e8cd":373,"8310e18a820b6adf3fe10c2766b1b371e5ab483f":57,"ff7e1b2c7007848b2250f8dc990a961fa4b1b783":0,"600728fb1d9b6e587dff8a99c5029b4837f76db5":613,"e2a34b3f3dc339242a39f90e310ff4fdfc672b91":264,"a2b7c20b3a846923827733464d105d56b27bc215":132,"0d111e1727a22e0a4aa050d8b97fe7c6e7ce49fd":161,"d87ac0b9992b494d536ebec3b01cf8c4e6600d98":211,"b77f90dcc018c4a0cab24aba4d6441dac5510772":4,"30e4de7a434402c81199071a672f18d1154cd75d":1,"ae53b52bf37fb1fbfa0ea9bded4bc736444f5511":238,"5538db3e351299ce53d77da876dfa2e8223b2470":1,"5c18df78c2df81aa2ee0b10d5a2454fa5d22ab9b":0,"3f66a36727247632b85095dfbfc3a8fa64589061":0,"8377fc91b8e7d4a20196c8ba12eef14a43be9769":0,"ad80e2da48476fb7001aedb7f26c1435baca666b":146,"936338c1095c7e6b3e43a579a5df6a134da52468":459,"1319992efa4f1264e78d6b086256c9a611e9c403":1,"a0b5866a98df141eda283a9d8f21e3a6ea043933":124,"2e69a92fd68e224f80f0329041a761a738c3801b":34,"c9bd8929adf16d99692661e53acd56296359c304":267,"3c2dae7dc2a2cbb7a2f4f48eabbabd5b489ade19":33,"13d607393f25409133375a23c835d32a9a139321":271,"cca804a46dece508b0c7575adb2eb9b2fe76a348":29,"760ddcceac251fd5eb49b7cf90e31f55ad449e06":33,"1648be82f06ef445c238d9ce23c50c079dc95fb2":53,"5ddfc0901254a222da268f32dc991ced8cd9c91a":456,"5b54689e4c97c39693764cadb5b51a7c85f6601e":444,"7ec3c39e9a0f167d37fdb1be762e2826654657ee":0,"b5edaebefdc5f65bc946283467344a941c079fda":823,"dd2d55d81818eb8e626038a038f3876be034aa17":213,"b9956df8f8ea9128ac4412ff156b3850931e4e81":1,"8dd0bcb157c0cc50d870da92c418e4bf2c64b3b5":1212,"796e5554aa4f47fd552ccfd2f41e4453a6187893":0,"a9aabe8d6798f666ab9cec9eba07518d0cd2e91d":293,"c5c7c565e2c56e935b349a5e34f18ef451acb717":356,"c5e31e2e4482e9da479e7f6932de4db1cae85e2b":1,"6b5b2cd4bef3c940b75875293d70c3938cb0c179":576,"c9acd43fb1c6655d38b977c63d4eb5ae7b621c1d":1,"15d4bb3c7e32d588e64e7397e16fe1f443c7cdf2":42,"af86092a9b77c4fb741104bb1b00dfc94e4696f3":779,"2e2d40c88dc8dfee0b2ed294184c9f10c95d5d99":1},"tools":{"claude-code":{"name":"Claude Code","commits":74,"loc":19735,"first_seen":1786219088,"last_seen":1793916016}},"monthly":{"2026-08":{"loc":13693,"attributed_loc":13693},"2026-10":{"loc":458,"attributed_loc":458},"2026-11":{"loc":5584,"attributed_loc":5584}}},"error":null},{"analyzer":"ai-artifacts","pillar":"ai_provenance","status":"ok","tool_version":"signatures-v1","metrics":{"artifacts":3.0,"workflow_agents":0.0,"tools_configured":1.0,"earliest_adoption":1786388728.0},"findings":[],"evidence":[{"kind":"ai-artifact","description":".claude/hooks/session-start.sh (claude-code configuration)","ref":".claude/hooks/session-start.sh","url":"https://github.com/chr1shaefn3r/grow-up/blob/2e2d40c88dc8dfee0b2ed294184c9f10c95d5d99/.claude/hooks/session-start.sh","weight":0.5},{"kind":"ai-artifact","description":".claude/settings.json (claude-code configuration)","ref":".claude/settings.json","url":"https://github.com/chr1shaefn3r/grow-up/blob/2e2d40c88dc8dfee0b2ed294184c9f10c95d5d99/.claude/settings.json","weight":0.5},{"kind":"ai-artifact","description":"CLAUDE.md (claude-code configuration)","ref":"CLAUDE.md","url":"https://github.com/chr1shaefn3r/grow-up/blob/2e2d40c88dc8dfee0b2ed294184c9f10c95d5d99/CLAUDE.md","weight":0.5}],"data":{"artifacts":[{"tool":"claude-code","path":".claude/hooks/session-start.sh","added_at":1786388728},{"tool":"claude-code","path":".claude/settings.json","added_at":1786388728},{"tool":"claude-code","path":"CLAUDE.md","added_at":1786388728}],"workflows":[],"tools":["claude-code"]},"error":null},{"analyzer":"ai-velocity","pillar":"ai_provenance","status":"ok","tool_version":"prov-4","metrics":{"work_units":26.0,"flagged_units":3.0,"pre_ai_era_bursts":0.0,"pre_ai_era_measured_loc":0.0,"pre_ai_era_burst_loc":0.0,"measured_loc":16535.0,"flagged_loc":5915.0,"flagged_loc_share":0.35772603568188693,"max_loc_per_hour":723.7725596739764,"median_loc_per_hour":153.25,"pr_timed_units":0.0,"excluded_import_loc":3200.0},"findings":[],"evidence":[{"kind":"velocity-burst","description":"1,036 lines of first-party code in ~1.4h (724 lines/hour, 2 commit session)","ref":"dd2d55d81818eb8e626038a038f3876be034aa17","url":"https://github.com/chr1shaefn3r/grow-up/commit/dd2d55d81818eb8e626038a038f3876be034aa17","weight":0.2171317679021929},{"kind":"velocity-burst","description":"1,602 lines of first-party code in ~2.4h (658 lines/hour, 5 commit session)","ref":"8310e18a820b6adf3fe10c2766b1b371e5ab483f","url":"https://github.com/chr1shaefn3r/grow-up/commit/8310e18a820b6adf3fe10c2766b1b371e5ab483f","weight":0.19737166324435315},{"kind":"velocity-burst","description":"3,277 lines of first-party code in ~5.2h (630 lines/hour, 10 commit session)","ref":"6b4e57b8ca4b05f3d5996a9df69461af2bf5273e","url":"https://github.com/chr1shaefn3r/grow-up/commit/6b4e57b8ca4b05f3d5996a9df69461af2bf5273e","weight":0.1889567538707955}],"data":{"flagged_loc_by_commit":{"d7d8da5046283b194a1d355e17794b0fea7afd4c":609,"de65c2232528e5fa7cad54abd6b39fdfe1481fdc":284,"83f271db32a91df49c0046885a02f75af142cb8c":446,"79f851f2f7d52b1d63598753e245d5075d809ece":365,"e66bc8617afa02626af35118f6cc7f89a27a7774":85,"e9f1143f9ebfe075c3fc3bcbeff1453725387b73":120,"b60d31b60e99dfda7657ad5f310bf2ffdf1e9afd":210,"137106a5cf039aa6b90d0eeb17f56720e55c3e6b":179,"f5396144dc2712c4f9d19b44c897f40253ccd358":897,"6b4e57b8ca4b05f3d5996a9df69461af2bf5273e":82,"eb92668937bcad3353ffd913f1da93fdd96c1d21":859,"97dd4f3bba0e3499f5ba2a0c5c2e584a7008ba74":1,"25163e62ca69e74779a901550ba4116d378489d2":312,"f88ca4aecfadd914c580ce13d2b309d149c0e8cd":373,"8310e18a820b6adf3fe10c2766b1b371e5ab483f":57,"b5edaebefdc5f65bc946283467344a941c079fda":823,"dd2d55d81818eb8e626038a038f3876be034aa17":213},"excluded_import_commits":["78f37da2e4f573af742191f5d281ca3c26f35468"]},"error":null},{"analyzer":"ai-release-velocity","pillar":"ai_provenance","status":"ok","tool_version":"prov-4","metrics":{"releases":10.0,"flagged_releases":0.0,"max_loc_per_day":28323.4},"findings":[],"evidence":[],"data":{"releases":[{"from":"v1.0.0","to":"v1.1.0","loc":904,"days":0.99,"loc_per_day":913.4,"flagged":false},{"from":"v1.1.0","to":"v1.2.0","loc":860,"days":0.05,"loc_per_day":17263.9,"flagged":false},{"from":"v1.2.0","to":"v1.3.0","loc":742,"days":0.05,"loc_per_day":14367.7,"flagged":false},{"from":"v1.3.0","to":"v1.4.0","loc":1386,"days":1.89,"loc_per_day":732.9,"flagged":false},{"from":"v1.4.0","to":"v1.5.0","loc":239,"days":2.67,"loc_per_day":89.4,"flagged":false},{"from":"v1.5.0","to":"v1.6.0","loc":606,"days":6.78,"loc_per_day":89.3,"flagged":false},{"from":"v1.6.0","to":"v1.7.0","loc":2781,"days":73.59,"loc_per_day":37.8,"flagged":false},{"from":"v1.7.0","to":"v1.8.0","loc":1862,"days":0.07,"loc_per_day":28323.4,"flagged":false},{"from":"v1.8.0","to":"v1.8.1","loc":577,"days":0.04,"loc_per_day":13848.0,"flagged":false},{"from":"v1.8.1","to":"v1.9.0","loc":822,"days":1.0,"loc_per_day":818.2,"flagged":false}]},"error":null},{"analyzer":"ai-stylometry","pillar":"ai_provenance","status":"ok","tool_version":null,"metrics":{"lines_scanned":8331.0,"index":0.24,"count:narrated_steps":2.0,"per_kloc:narrated_steps":0.24,"files:narrated_steps":1.0,"count:placeholder":0.0,"per_kloc:placeholder":0.0,"files:placeholder":0.0,"count:emoji_in_code":0.0,"per_kloc:emoji_in_code":0.0,"files:emoji_in_code":0.0,"count:assistant_voice":0.0,"per_kloc:assistant_voice":0.0,"files:assistant_voice":0.0},"findings":[],"evidence":[{"kind":"stylometry:narrated_steps","description":"step-by-step narration comment: // first, and relabelling \"the first button\" turned it into a second reject.","ref":"src/grow_up/review.py:450","url":"https://github.com/chr1shaefn3r/grow-up/blob/2e2d40c88dc8dfee0b2ed294184c9f10c95d5d99/src/grow_up/review.py#L450","weight":0.0},{"kind":"stylometry:narrated_steps","description":"step-by-step narration comment: # first, and sizing it from only gaze_x, hid that it also decides gaze","ref":"src/grow_up/review.py:1456","url":"https://github.com/chr1shaefn3r/grow-up/blob/2e2d40c88dc8dfee0b2ed294184c9f10c95d5d99/src/grow_up/review.py#L1456","weight":0.0}],"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":13.0,"findings_high":9.0,"findings_medium":4.0,"findings_low":0.0,"weighted_findings":7.75,"scanned_lines":8331.0,"parse_errors":0.0},"findings":[{"rule_id":"opengrep/python.sqlalchemy.security.sqlalchemy-execute-raw-query","severity":"high","message":"Avoiding SQL string concatenation: untrusted input concatenated with raw SQL query can result in SQL Injection. In order to execute raw query safely, prepared statement should be used. SQLAlchemy provides TextualSQL to easily used prepared statement with named parameters. For complex SQL composition [confidence low]","path":"src/grow_up/cli.py","line":755,"fingerprint":"python.sqlalchemy.security.sqlalchemy-execute-raw-query:src/grow_up/cli.py:755"},{"rule_id":"opengrep/python.sqlalchemy.security.sqlalchemy-execute-raw-query","severity":"high","message":"Avoiding SQL string concatenation: untrusted input concatenated with raw SQL query can result in SQL Injection. In order to execute raw query safely, prepared statement should be used. SQLAlchemy provides TextualSQL to easily used prepared statement with named parameters. For complex SQL composition [confidence low]","path":"src/grow_up/db.py","line":203,"fingerprint":"python.sqlalchemy.security.sqlalchemy-execute-raw-query:src/grow_up/db.py:203"},{"rule_id":"opengrep/python.sqlalchemy.security.sqlalchemy-execute-raw-query","severity":"high","message":"Avoiding SQL string concatenation: untrusted input concatenated with raw SQL query can result in SQL Injection. In order to execute raw query safely, prepared statement should be used. SQLAlchemy provides TextualSQL to easily used prepared statement with named parameters. For complex SQL composition [confidence low]","path":"src/grow_up/db.py","line":206,"fingerprint":"python.sqlalchemy.security.sqlalchemy-execute-raw-query:src/grow_up/db.py:206"},{"rule_id":"opengrep/python.lang.security.audit.dangerous-subprocess-use-audit","severity":"high","message":"Detected subprocess function 'run' without a static string. If this data can be controlled by a malicious actor, it may be an instance of command injection. Audit the use of this call to ensure it is not controllable by an external resource. You may consider using 'shlex.escape()'. [confidence low]","path":"src/grow_up/encode.py","line":371,"fingerprint":"python.lang.security.audit.dangerous-subprocess-use-audit:src/grow_up/encode.py:371"},{"rule_id":"opengrep/python.sqlalchemy.security.sqlalchemy-execute-raw-query","severity":"high","message":"Avoiding SQL string concatenation: untrusted input concatenated with raw SQL query can result in SQL Injection. In order to execute raw query safely, prepared statement should be used. SQLAlchemy provides TextualSQL to easily used prepared statement with named parameters. For complex SQL composition [confidence low]","path":"src/grow_up/pipeline.py","line":249,"fingerprint":"python.sqlalchemy.security.sqlalchemy-execute-raw-query:src/grow_up/pipeline.py:249"},{"rule_id":"opengrep/python.sqlalchemy.security.sqlalchemy-execute-raw-query","severity":"high","message":"Avoiding SQL string concatenation: untrusted input concatenated with raw SQL query can result in SQL Injection. In order to execute raw query safely, prepared statement should be used. SQLAlchemy provides TextualSQL to easily used prepared statement with named parameters. For complex SQL composition [confidence low]","path":"src/grow_up/pipeline.py","line":315,"fingerprint":"python.sqlalchemy.security.sqlalchemy-execute-raw-query:src/grow_up/pipeline.py:315"},{"rule_id":"opengrep/python.sqlalchemy.security.sqlalchemy-execute-raw-query","severity":"high","message":"Avoiding SQL string concatenation: untrusted input concatenated with raw SQL query can result in SQL Injection. In order to execute raw query safely, prepared statement should be used. SQLAlchemy provides TextualSQL to easily used prepared statement with named parameters. For complex SQL composition [confidence low]","path":"src/grow_up/pipeline.py","line":425,"fingerprint":"python.sqlalchemy.security.sqlalchemy-execute-raw-query:src/grow_up/pipeline.py:425"},{"rule_id":"opengrep/python.sqlalchemy.security.sqlalchemy-execute-raw-query","severity":"high","message":"Avoiding SQL string concatenation: untrusted input concatenated with raw SQL query can result in SQL Injection. In order to execute raw query safely, prepared statement should be used. SQLAlchemy provides TextualSQL to easily used prepared statement with named parameters. For complex SQL composition [confidence low]","path":"src/grow_up/pipeline.py","line":488,"fingerprint":"python.sqlalchemy.security.sqlalchemy-execute-raw-query:src/grow_up/pipeline.py:488"},{"rule_id":"opengrep/python.sqlalchemy.security.sqlalchemy-execute-raw-query","severity":"high","message":"Avoiding SQL string concatenation: untrusted input concatenated with raw SQL query can result in SQL Injection. In order to execute raw query safely, prepared statement should be used. SQLAlchemy provides TextualSQL to easily used prepared statement with named parameters. For complex SQL composition [confidence low]","path":"src/grow_up/pipeline.py","line":551,"fingerprint":"python.sqlalchemy.security.sqlalchemy-execute-raw-query:src/grow_up/pipeline.py:551"},{"rule_id":"opengrep/python.lang.security.audit.dynamic-urllib-use-detected","severity":"medium","message":"Detected a dynamic value being used with urllib. urllib supports 'file://' schemes, so a dynamic value controlled by a malicious actor may allow them to read arbitrary files. Audit uses of urllib calls to ensure user data cannot control the URLs, or consider using the 'requests' library instead. [confidence low]","path":"src/grow_up/cli.py","line":188,"fingerprint":"python.lang.security.audit.dynamic-urllib-use-detected:src/grow_up/cli.py:188"},{"rule_id":"opengrep/python.lang.security.audit.formatted-sql-query","severity":"medium","message":"Detected possible formatted SQL query. Use parameterized queries instead. [confidence low]","path":"src/grow_up/cli.py","line":755,"fingerprint":"python.lang.security.audit.formatted-sql-query:src/grow_up/cli.py:755"},{"rule_id":"opengrep/python.lang.security.audit.formatted-sql-query","severity":"medium","message":"Detected possible formatted SQL query. Use parameterized queries instead. [confidence low]","path":"src/grow_up/db.py","line":203,"fingerprint":"python.lang.security.audit.formatted-sql-query:src/grow_up/db.py:203"},{"rule_id":"opengrep/python.lang.security.audit.formatted-sql-query","severity":"medium","message":"Detected possible formatted SQL query. Use parameterized queries instead. [confidence low]","path":"src/grow_up/db.py","line":206,"fingerprint":"python.lang.security.audit.formatted-sql-query:src/grow_up/db.py:206"}],"evidence":[],"data":{"rulesets":["python","bash"]},"error":null},{"analyzer":"sec-deps","pillar":"security","status":"skipped","tool_version":null,"metrics":{},"findings":[],"evidence":[],"data":{},"error":null},{"analyzer":"sec-actions","pillar":"security","status":"ok","tool_version":"zizmor 1.32.0","metrics":{"workflows":1.0,"findings":3.0,"findings_high":2.0,"findings_medium":0.0,"findings_low":1.0,"penalty":24.3},"findings":[{"rule_id":"zizmor/unpinned-uses","severity":"high","message":"unpinned action reference [confidence high]","path":".github/workflows/tests.yml","line":25,"fingerprint":"unpinned-uses:.github/workflows/tests.yml:25"},{"rule_id":"zizmor/unpinned-uses","severity":"high","message":"unpinned action reference [confidence high]","path":".github/workflows/tests.yml","line":27,"fingerprint":"unpinned-uses:.github/workflows/tests.yml:27"},{"rule_id":"zizmor/artipacked","severity":"low","message":"credential persistence through GitHub Actions artifacts [confidence low]","path":".github/workflows/tests.yml","line":25,"fingerprint":"artipacked:.github/workflows/tests.yml:25"}],"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":1.0,"check:lockfiles":1.0,"signed_commit_share":0.9868,"unpinned_manifests":0.0},"findings":[],"evidence":[],"data":{},"error":null},{"analyzer":"sec-distribution","pillar":"security","status":"ok","tool_version":null,"metrics":{"signals":1.0,"binary_assets":0.0,"suspicious":0.0},"findings":[],"evidence":[{"kind":"readme-download-lure","description":"gives an archive password","ref":"README.md","url":null,"weight":0.0}],"data":{"signals":["readme-download-lure"],"suspicious":false,"unusual_traction":false,"metadata":true},"error":null},{"analyzer":"qual-complexity","pillar":"quality","status":"ok","tool_version":"lizard 1.25.1","metrics":{"functions":312.0,"function_nloc":3789.0,"mean_ccn":3.68,"p90_ccn":8.0,"complex_functions":4.0,"long_functions":1.0,"many_param_functions":6.0,"risky_nloc_share":0.0768},"findings":[],"evidence":[{"kind":"complex-function","description":"stage_encode in src/grow_up/pipeline.py: complexity 33, 86 lines","ref":"src/grow_up/pipeline.py","url":"https://github.com/chr1shaefn3r/grow-up/blob/2e2d40c88dc8dfee0b2ed294184c9f10c95d5d99/src/grow_up/pipeline.py#L756","weight":0.55},{"kind":"complex-function","description":"write_rejects_gallery in src/grow_up/review.py: complexity 28, 103 lines","ref":"src/grow_up/review.py","url":"https://github.com/chr1shaefn3r/grow-up/blob/2e2d40c88dc8dfee0b2ed294184c9f10c95d5d99/src/grow_up/review.py#L1396","weight":0.4666666666666667},{"kind":"complex-function","description":"render in src/grow_up/morph.py: complexity 18, 43 lines","ref":"src/grow_up/morph.py","url":"https://github.com/chr1shaefn3r/grow-up/blob/2e2d40c88dc8dfee0b2ed294184c9f10c95d5d99/src/grow_up/morph.py#L618","weight":0.3},{"kind":"complex-function","description":"stage_align in src/grow_up/pipeline.py: complexity 16, 59 lines","ref":"src/grow_up/pipeline.py","url":"https://github.com/chr1shaefn3r/grow-up/blob/2e2d40c88dc8dfee0b2ed294184c9f10c95d5d99/src/grow_up/pipeline.py#L592","weight":0.26666666666666666}],"data":{},"error":null},{"analyzer":"qual-duplication","pillar":"quality","status":"ok","tool_version":"repotrust-dup-w6","metrics":{"compared_lines":6466.0,"duplicated_lines":18.0,"duplicated_share":0.0028,"files":18.0},"findings":[],"evidence":[{"kind":"duplicate-code","description":"6+ duplicated lines: src/grow_up/cli.py:273 and src/grow_up/cli.py:295","ref":"src/grow_up/cli.py","url":"https://github.com/chr1shaefn3r/grow-up/blob/2e2d40c88dc8dfee0b2ed294184c9f10c95d5d99/src/grow_up/cli.py#L273","weight":0.3}],"data":{},"error":null},{"analyzer":"qual-lint","pillar":"quality","status":"ok","tool_version":"opengrep 1.33.1; rules f1d2b562b414","metrics":{"findings":20.0,"weighted_findings":21.25,"scanned_lines":8331.0,"category:correctness":14.0,"category:maintainability":6.0},"findings":[{"rule_id":"opengrep/python.lang.correctness.return-in-init","severity":"high","message":"`return` should never appear inside a class __init__ function. This will cause a runtime error.","path":"src/grow_up/progress.py","line":53,"fingerprint":"python.lang.correctness.return-in-init:src/grow_up/progress.py:53"},{"rule_id":"opengrep/python.lang.maintainability.is-function-without-parentheses","severity":"medium","message":"Is \"is_full\" a function or an attribute? If it is a function, you may have meant watermark.is_full() because watermark.is_full is always true.","path":"src/grow_up/cli.py","line":247,"fingerprint":"python.lang.maintainability.is-function-without-parentheses:src/grow_up/cli.py:247"},{"rule_id":"opengrep/python.lang.correctness.common-mistakes.string-concat-in-list","severity":"medium","message":"Detected strings that are implicitly concatenated inside a list. Python will implicitly concatenate strings when not explicitly delimited. Was this supposed to be individual elements of the list?","path":"src/grow_up/db.py","line":381,"fingerprint":"python.lang.correctness.common-mistakes.string-concat-in-list:src/grow_up/db.py:381"},{"rule_id":"opengrep/python.lang.correctness.common-mistakes.string-concat-in-list","severity":"medium","message":"Detected strings that are implicitly concatenated inside a list. Python will implicitly concatenate strings when not explicitly delimited. Was this supposed to be individual elements of the list?","path":"src/grow_up/encode.py","line":271,"fingerprint":"python.lang.correctness.common-mistakes.string-concat-in-list:src/grow_up/encode.py:271"},{"rule_id":"opengrep/python.lang.correctness.common-mistakes.string-concat-in-list","severity":"medium","message":"Detected strings that are implicitly concatenated inside a list. Python will implicitly concatenate strings when not explicitly delimited. Was this supposed to be individual elements of the list?","path":"src/grow_up/encode.py","line":281,"fingerprint":"python.lang.correctness.common-mistakes.string-concat-in-list:src/grow_up/encode.py:281"},{"rule_id":"opengrep/python.lang.correctness.common-mistakes.string-concat-in-list","severity":"medium","message":"Detected strings that are implicitly concatenated inside a list. Python will implicitly concatenate strings when not explicitly delimited. Was this supposed to be individual elements of the list?","path":"src/grow_up/encode.py","line":308,"fingerprint":"python.lang.correctness.common-mistakes.string-concat-in-list:src/grow_up/encode.py:308"},{"rule_id":"opengrep/python.lang.maintainability.is-function-without-parentheses","severity":"medium","message":"Is \"is_success\" a function or an attribute? If it is a function, you may have meant response.is_success() because response.is_success is always true.","path":"src/grow_up/immich.py","line":219,"fingerprint":"python.lang.maintainability.is-function-without-parentheses:src/grow_up/immich.py:219"},{"rule_id":"opengrep/python.lang.maintainability.is-function-without-parentheses","severity":"medium","message":"Is \"is_success\" a function or an attribute? If it is a function, you may have meant response.is_success() because response.is_success is always true.","path":"src/grow_up/immich.py","line":291,"fingerprint":"python.lang.maintainability.is-function-without-parentheses:src/grow_up/immich.py:291"},{"rule_id":"opengrep/python.lang.maintainability.is-function-without-parentheses","severity":"medium","message":"Is \"is_success\" a function or an attribute? If it is a function, you may have meant response.is_success() because response.is_success is always true.","path":"src/grow_up/immich.py","line":295,"fingerprint":"python.lang.maintainability.is-function-without-parentheses:src/grow_up/immich.py:295"},{"rule_id":"opengrep/python.lang.maintainability.is-function-without-parentheses","severity":"medium","message":"Is \"is_success\" a function or an attribute? If it is a function, you may have meant response.is_success() because response.is_success is always true.","path":"src/grow_up/immich.py","line":434,"fingerprint":"python.lang.maintainability.is-function-without-parentheses:src/grow_up/immich.py:434"},{"rule_id":"opengrep/python.lang.maintainability.is-function-without-parentheses","severity":"medium","message":"Is \"is_full\" a function or an attribute? If it is a function, you may have meant watermark.is_full() because watermark.is_full is always true.","path":"src/grow_up/pipeline.py","line":144,"fingerprint":"python.lang.maintainability.is-function-without-parentheses:src/grow_up/pipeline.py:144"},{"rule_id":"opengrep/python.lang.correctness.common-mistakes.string-concat-in-list","severity":"medium","message":"Detected strings that are implicitly concatenated inside a list. Python will implicitly concatenate strings when not explicitly delimited. Was this supposed to be individual elements of the list?","path":"src/grow_up/progress.py","line":126,"fingerprint":"python.lang.correctness.common-mistakes.string-concat-in-list:src/grow_up/progress.py:126"},{"rule_id":"opengrep/python.lang.correctness.common-mistakes.string-concat-in-list","severity":"medium","message":"Detected strings that are implicitly concatenated inside a list. Python will implicitly concatenate strings when not explicitly delimited. Was this supposed to be individual elements of the list?","path":"src/grow_up/review.py","line":1203,"fingerprint":"python.lang.correctness.common-mistakes.string-concat-in-list:src/grow_up/review.py:1203"},{"rule_id":"opengrep/python.lang.correctness.common-mistakes.string-concat-in-list","severity":"medium","message":"Detected strings that are implicitly concatenated inside a list. Python will implicitly concatenate strings when not explicitly delimited. Was this supposed to be individual elements of the list?","path":"src/grow_up/review.py","line":1439,"fingerprint":"python.lang.correctness.common-mistakes.string-concat-in-list:src/grow_up/review.py:1439"},{"rule_id":"opengrep/python.lang.correctness.common-mistakes.string-concat-in-list","severity":"medium","message":"Detected strings that are implicitly concatenated inside a list. Python will implicitly concatenate strings when not explicitly delimited. Was this supposed to be individual elements of the list?","path":"src/grow_up/timing.py","line":113,"fingerprint":"python.lang.correctness.common-mistakes.string-concat-in-list:src/grow_up/timing.py:113"},{"rule_id":"opengrep/python.lang.correctness.common-mistakes.string-concat-in-list","severity":"medium","message":"Detected strings that are implicitly concatenated inside a list. Python will implicitly concatenate strings when not explicitly delimited. Was this supposed to be individual elements of the list?","path":"src/grow_up/timing.py","line":115,"fingerprint":"python.lang.correctness.common-mistakes.string-concat-in-list:src/grow_up/timing.py:115"},{"rule_id":"opengrep/python.lang.correctness.common-mistakes.string-concat-in-list","severity":"medium","message":"Detected strings that are implicitly concatenated inside a list. Python will implicitly concatenate strings when not explicitly delimited. Was this supposed to be individual elements of the list?","path":"src/grow_up/timing.py","line":117,"fingerprint":"python.lang.correctness.common-mistakes.string-concat-in-list:src/grow_up/timing.py:117"},{"rule_id":"opengrep/python.lang.correctness.common-mistakes.string-concat-in-list","severity":"medium","message":"Detected strings that are implicitly concatenated inside a list. Python will implicitly concatenate strings when not explicitly delimited. Was this supposed to be individual elements of the list?","path":"src/grow_up/timing.py","line":120,"fingerprint":"python.lang.correctness.common-mistakes.string-concat-in-list:src/grow_up/timing.py:120"},{"rule_id":"opengrep/python.lang.correctness.common-mistakes.string-concat-in-list","severity":"medium","message":"Detected strings that are implicitly concatenated inside a list. Python will implicitly concatenate strings when not explicitly delimited. Was this supposed to be individual elements of the list?","path":"src/grow_up/timing.py","line":122,"fingerprint":"python.lang.correctness.common-mistakes.string-concat-in-list:src/grow_up/timing.py:122"},{"rule_id":"opengrep/bash.lang.correctness.unquoted-variable-expansion-in-command","severity":"low","message":"Variable expansions must be double-quoted so as to prevent being split into multiple pieces according to whitespace or whichever separator is specified by the IFS variable. If you really wish to split the variable's contents, you may use a variable that starts with an underscore e.g. $_X instead of ","path":".claude/hooks/session-start.sh","line":28,"fingerprint":"bash.lang.correctness.unquoted-variable-expansion-in-command:.claude/hooks/session-start.sh:28"}],"evidence":[],"data":{},"error":null},{"analyzer":"qual-testing","pillar":"quality","status":"ok","tool_version":null,"metrics":{"check:has_tests":1.0,"check:test_ratio":1.0,"check:ci_present":1.0,"check:ci_runs_tests":1.0,"check:ci_runs_lint":0.0,"check:tests_cochange":1.0,"test_lines":10063.0,"source_lines":8331.0,"test_ratio":1.2079,"ci_files":1.0,"cochange_share":0.8387,"cochange_commits":62.0},"findings":[],"evidence":[{"kind":"ci","description":"CI config: .github/workflows/tests.yml","ref":".github/workflows/tests.yml","url":null,"weight":0.0},{"kind":"ci","description":"CI runs tests (pytest)","ref":null,"url":null,"weight":0.0}],"data":{"test_commands":["pytest"],"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":686.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":0.0,"check:low_escape_density":1.0,"escapes":11.0,"escapes_per_kloc":1.326},"findings":[],"evidence":[],"data":{},"error":null},{"analyzer":"x-blame","pillar":"ai_provenance","status":"ok","tool_version":"git-blame","metrics":{"ai_lines":8331.0,"other_lines":0.0,"files_blamed":18.0,"blame_failures":0.0,"quality:ai_findings":20.0,"quality:ai_per_kloc":2.401,"quality:other_findings":0.0,"security:ai_findings":13.0,"security:ai_per_kloc":1.56,"security:other_findings":0.0},"findings":[],"evidence":[],"data":{"sampled":false,"comparable":false},"error":null}],"flags":[]}