From a6f19f98b0d9b8cfece43849e37572fb22908ffe Mon Sep 17 00:00:00 2001 From: Dominikus Nold Date: Fri, 3 Apr 2026 02:36:30 +0200 Subject: [PATCH 1/4] Fix semgrep runner --- .../specfact-code-review/module-package.yaml | 6 ++--- .../tools/semgrep_runner.py | 25 ++++++++++++++----- 2 files changed, 22 insertions(+), 9 deletions(-) diff --git a/packages/specfact-code-review/module-package.yaml b/packages/specfact-code-review/module-package.yaml index 85ae462..92d6893 100644 --- a/packages/specfact-code-review/module-package.yaml +++ b/packages/specfact-code-review/module-package.yaml @@ -1,5 +1,5 @@ name: nold-ai/specfact-code-review -version: 0.46.1 +version: 0.46.3 commands: - code tier: official @@ -23,5 +23,5 @@ description: Official SpecFact code review bundle package. category: codebase bundle_group_command: code integrity: - checksum: sha256:13a5a27fc13e2db6d36573b42482a1fe9d294e100738f6150ad0468868581dd1 - signature: ulRchbUE1q1JhCuTRUPUolICZMiWDBCQgNmNt4YNbtyRysXMhiIcge/KJ1X1VqKtzWu4lzvEDf0OInPJ2lRxBA== + checksum: sha256:fb6181a897e49a24a5cf6dc5fbfce67d7de75588372e5f1b661be0761dca4303 + signature: qAX9yIBO+UBsqa4ODAym4YrtWlGhSoyiIb4b/UUWKKN+vv8yNentvwR8mHd32I7BnF+TBiHHmonH+ktPV9XSCQ== diff --git a/packages/specfact-code-review/src/specfact_code_review/tools/semgrep_runner.py b/packages/specfact-code-review/src/specfact_code_review/tools/semgrep_runner.py index 0fc7f2a..cd32957 100644 --- a/packages/specfact-code-review/src/specfact_code_review/tools/semgrep_runner.py +++ b/packages/specfact-code-review/src/specfact_code_review/tools/semgrep_runner.py @@ -74,11 +74,17 @@ def _normalize_rule_id(rule: str) -> str: def _resolve_config_path() -> Path: - package_root = Path(__file__).resolve().parents[3] - config_path = package_root / ".semgrep" / "clean_code.yaml" - if config_path.exists(): - return config_path - raise FileNotFoundError(f"Semgrep config not found at {config_path}") + """Locate ``.semgrep/clean_code.yaml`` for src-layout checkouts, wheels, and bundled installs. + + ``parents[3]`` only matches one tree shape; walking ancestors finds the policy pack when it lives + next to ``src/`` (development), under ``specfact_code_review/`` (some installs), or at bundle root. + """ + here = Path(__file__).resolve() + for parent in [here.parent, *here.parents]: + candidate = parent / ".semgrep" / "clean_code.yaml" + if candidate.is_file(): + return candidate + raise FileNotFoundError(f"Semgrep config not found (no .semgrep/clean_code.yaml above {here})") def _run_semgrep_command(files: list[Path]) -> subprocess.CompletedProcess[str]: @@ -96,6 +102,7 @@ def _run_semgrep_command(files: list[Path]) -> subprocess.CompletedProcess[str]: [ "semgrep", "--disable-version-check", + "--quiet", "--config", str(_resolve_config_path()), "--json", @@ -114,7 +121,13 @@ def _load_semgrep_results(files: list[Path]) -> list[object]: for _attempt in range(SEMGREP_RETRY_ATTEMPTS): try: result = _run_semgrep_command(files) - return _parse_semgrep_results(json.loads(result.stdout)) + raw_out = result.stdout.strip() + if not raw_out: + err_tail = (result.stderr or "").strip() + if len(err_tail) > 4000: + err_tail = err_tail[:4000] + "…" + raise ValueError(f"semgrep returned empty stdout (returncode={result.returncode}); stderr={err_tail!r}") + return _parse_semgrep_results(json.loads(raw_out)) except (FileNotFoundError, OSError, ValueError, json.JSONDecodeError, subprocess.TimeoutExpired) as exc: last_error = exc if last_error is None: From 4eefb67730742e5ceff5d28f9e855d102e25cde6 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 3 Apr 2026 00:38:42 +0000 Subject: [PATCH 2/4] chore(registry): publish changed modules [skip ci] --- registry/index.json | 6 +++--- .../modules/specfact-code-review-0.46.3.tar.gz | Bin 0 -> 30302 bytes .../specfact-code-review-0.46.3.tar.gz.sha256 | 1 + .../specfact-code-review-0.46.3.tar.sig | 1 + 4 files changed, 5 insertions(+), 3 deletions(-) create mode 100644 registry/modules/specfact-code-review-0.46.3.tar.gz create mode 100644 registry/modules/specfact-code-review-0.46.3.tar.gz.sha256 create mode 100644 registry/signatures/specfact-code-review-0.46.3.tar.sig diff --git a/registry/index.json b/registry/index.json index 54459f6..5816c50 100644 --- a/registry/index.json +++ b/registry/index.json @@ -78,9 +78,9 @@ }, { "id": "nold-ai/specfact-code-review", - "latest_version": "0.46.1", - "download_url": "modules/specfact-code-review-0.46.1.tar.gz", - "checksum_sha256": "cbd954a055dfa83bab76880350f3bdc5652046ed4527d0c0ff0d1550e51be1af", + "latest_version": "0.46.3", + "download_url": "modules/specfact-code-review-0.46.3.tar.gz", + "checksum_sha256": "58f3f9b01a13247b8109f856cb96abfd955e21a70ffafa37ceebf587d402888e", "core_compatibility": ">=0.44.0,<1.0.0", "tier": "official", "publisher": { diff --git a/registry/modules/specfact-code-review-0.46.3.tar.gz b/registry/modules/specfact-code-review-0.46.3.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..db33048c7b81b58643d7b3492d99811ea04863e8 GIT binary patch literal 30302 zcmV)3K+C@$iwFo349{r-|8sCFgm~W6d25$WzZpMO0w*XGR%x3%ZYYmNk@{C$x^g25D7{clLP~Rx{RW~=K;P) z{GQ}gRo@#8kd$TRMy_Rx1iGtl)z#H?ZNF&0_~&7C^GzJ}aLrYTrhq;YaNMS1)OguL6?k zfARBjqqFv>)s59x>#sVmI;&6)c7Ny9pS;df?*D8$9@i1TS?_55 zQIhA$_~HwX+VaxO%O^uvA6y&;>LaGU6(;~ED=ok#AV@LI#@=5KzWSebFC7n(i}qiS zceW4q-;~S#^}DUT_d76OuF`V0dRdz1tzmQ;L>>lQSa+(LN-V3zv6_|)|Kl36avUbYY3At1jH?_)9iz}7F$LrA8i`9xqbM1;~rX6%O`M z7sAA18#}l6b{QGSVxU`jk++Xwq|hIGs+^T@mT%hIGnP z*70#AFuA~!47LEkY2{hZwXpO)XyA^@(`g3VW{|)+@`X3eVSg3bvJr|kH71gCVrbrHi^o%C9h>G=@;jA6%HH1&|)cw2|N z9=-MQ%XB*Id*{%9V2P4J()+@TXs{d@FE>m+#L#q#WV7jA0=XE*O&lN`VE{S%7*d+W z7xB%e_bm8FGHU#9@Q+Pc|DS2)8b9Wr1^@VS_*vt}>*w%-ci?B%{?EMapZie}VTm8l zpQ$;?uYvld*Dx*dO)s9{Hfr$}%{kc-ulcYtI68nm@&Km<5IS#QX>;!yHVkz96P+D8 z>K55;JrQKXQr)*pV=o`22`Av+HviXN-v5{P|Kh%|D3;@M7<9{yg%mZKhOPt zb#1+4-Tymluhy6M|EKsMQ?m&t{1C35$qN@YtX$#k2u@Y6(|-A?y}rV)>s)GpC0F2L zlx=$H0Jx?k8mQ1?wVS8!w|IYZYlaq(_t6Aux~pYXKa+_7&h?(a$XE zr(^bwv;FMHbTFVVTuKHLlEonm0ay!mO$09J*_U0Iu9xjj^Y5$ePP_ALr61?LEMW|a zcfhC0JBC5Mg+b9gdTho$HWi-Oe=9w>5M98PXVa5I=d*Q@rPE2sSA@M@VYgT81@y9a z8TUTq(-E+Nm(kkBtIfgrtJTj}qtE~LI)3@LXzgXR(Hp$#_cjLSgI@gVb^moge!a2r z`RD7e*W!)A>iMfztLJg&^{dr>FM7G&SqGSTaxspO!Qb?L+WObuZg;;r`0V{x`A^Zy zgEw2ZqnAHq#rMOnFOSpPWcU2#`HT1OzyJ2z{m-thKEK_EE6~;T(dVOY`s-`EufH0< z{p{qcG+$^J`{)F{q0}J+y8I3yF7cA{NIxQ`{nq*jkUE`%RTr<<^SM*Pg0%y z#Uvdjy<6f0b9n$WwGgX;LYQ7M8OC`vn>d62TkE`DxA;H6#U=muBp+PaFpCG9Uj6DS zE^yW4WWJgvLlhNys+wS9NVnvTqRAxgdqqmZ_lpz&jp4V3Z-U=Rr^RGif|vNU^8ZB#8m%OBMP0psDlK)v56E>LxoPRGSZ^~Q$vpkCcZ z7vrQo9Z%u9fS7&-Ra|~_T=^v<-hCew*A-o#;ey$ z{{JaHzVEwGK*%1wcwA(+lQaP)3yQ9+kik|M4yGvo3qxVQ0jzjh5HFGQGVH}LITuCP zpOEPmSefE>g4O}Nz{wAXJK^>>JKNu)`gmm}41pnsCc0kW!yUqJdVYLEFtBpSE)DpU zLoQP7S$;e2g{Y&}o?S)28Uc$V9yL~0l7ZPQ)9_N~TpOUx|3G&{uLG$QhKJ1+r7*U8 zs@~cCRd4KGt2b8P*$Wr|-j!fIF5&{s!@@9N;`Y4A8eZ#5ZUn|g1!KjRq|S%?8lPUJ z(;np)FxLa0Tjtz_Ar=qAKWF#eWt2lb%>?ZZ-@zMSR?ng&kG(BXVh36B0AP}JhR5%O zAxsiS0cguWiNK#R<9>q!B0~~B;-Cb#Nuz8mPp{t)|F>S||5lg$-;?lvubuqg>(0yN z23qoeCH{|7+i8&u^SPP88T{Y+>Z&dOefhexFd^BoZhA@1 zY?ga*pdL4o{qlaMVKy2o|71NA)w4LC4hy3ydj!?u0?H#tH%_w=aD4xbLk>1eqH&Q2 zdfQqf$m&7mQ+Ra77&=&~BgQC23RoWtdFgh<-(Rh^Fi}fhc;vQnJoO-PG_3 zhSH_3wfXOW^@y8-9vl<PtRAmpTme8gxbYzM?-$uB#&+eK24^KC@a$6doFNgLQRpc9sZ9<}L({Z@mc>-} zIaNBX?)e!YqjNlU2uD}5e%1v|*fZj&KT;4^O%+&J!x4i!??|;kB@Am#TjQbaH zwx}9l#{I9eRgkE4go z;c6Yo9MS*z){$pZ`2! zz~jh&*H>S!Z`ktRjaO^S^Z%DQ|Fu{c2qKi78VWvCr`(=n7Ee?hcOvWN@idi?K|U)y+;K&5-aiY{mFJyK3quByfwaU3c*g( zJGq_2{WnRkkiC-*UymV)W*xijV`z(>DD)Lf={wk3(EQsZ9`>8wcTB|(qbK3zq5|x< zTf2LfTul7L$S4^MZiO*Y-^E!U1`Di}6m1=D9UmiSg@42EcTc_vx88iWdwg*813pF2 zz;M0UdAs#~?Etl#!LD@v6Ddp^Udujl02Wr;dnYaN8e58rT4S9pN?Y*k6Yn)@u3Cy zV8YCXQDXQ3bw>!xW3U8#xI~N#vxfqrfk+nUEv!Z+90E}9G8$jR{g6V8@cBhWhYdF5 zfnmB>!h*WZV6ZSHUN4%k_#`|c5N;>lSdPw|Y&wj2y@Y`Mtd3%0;$lgA)R;x&~Anmo4_q6B-$C=PEW zQ`skw<(Gq26V*l{J2+8O&#+oiR17|H5xn z)rN6km_z+1Rkq5j;XrBa2b2v3La4`q-5iY)YSLe}LP`}*zbq|sM(3WT0>(!sZwn;a zXU|#4s&fn)rx)M@pI^a@n}tDzK!p#}2GZf)XugF?_MC?Tq#~hLYx~v>cCd1p1&1PW0 z7jxXuJ6SOxoJaQRI)fXKED*>Bn`T$6XnA}MICPr!kTW=eS#QO{f7YHpdaL|Ho3M7# z!f1XG7rdDT&|Fm_G@pgg5^?#$S(iBCb|rBKf`UaEaX09?oYC1xZQw#RqRvFnc~<2y zRs)Yvu^NmAKpJ8%36`=}K`YED&U1t|N(#Z>taWI4ti!x&g+>||GO=!@{0!Gtg8JxQ z2RBy!&*^fDR7e$qIE~KIHaR&8gXl|SVoBGA8=Fnx*8KbOg zOX$aslG|7lC}c5R)*50R{AwDdh}-FE9FY0i5ODBf#ixM(qEtqWIwo+s zRL+1-WvanK2i#7zJ*s(!6}x^)@V4O||}6*Xy)5 z>Y;aS=*GkV`1MNgt**D)*2Zn$W?}SP=5O+MZM$Hj5=5IZNSwyty_UZSEOcvBv7U0n zGZD^0o7s}KbTeqWZ;iz+1n8ossOhcQyIkRI*IrC#Nm`C>X=Ti^N(Rz(qno3+APyyz zuxN<2A|!eUN-Nkbo#)-t=jKe|L+v7P=GyoCT&cP|Xa`7{s?NBcNnvy86w9Fq9Cdes z;33Ev)D8ENUi@A^+jK%Z*PW4zmNt!@${I|Wv{%5aV4v7HTq+-XtZuMc=k-0tIxoh| z#Ycu(>WoIgce#6Z1ql$-MZzg-cI7VCJ7Tkej(bULOc@2Yo{wANebXsJi5MuXEX9-- zN~$jDKHK;`4@ynb2nyJ_K|JoIIKZwyEe5U6{YGQOig+DxKZhoRh$65zF>2%J>Ergk zT%Dis!ZSJG<16*j(rZ4XS89RF7iflWW&W>HV5Uv>BtlZt9)0L1=%a!^@-FhaO~zM; z=?D7Rs0P70L<^Q{vx1xtu|z?F0ep%s&~&e~qT0Y1Q;+v0<}}V{laVk!Ncz6Xow_xw z2DX%o6-%hCU0Jwbqp#Gd)*={JuX+T47VYIH@DEyiYS-Gs<^|GmrFGqAOOxOj1ZDGx z^;8aUe-5m`?!eaicjYU}Jx0bWURNn#36cL}V6pqC}7h7@Yl(*$e7DQ4Y$-dAmOF$N5=5Cf+Q-%G3&zOUS& z)dy`AQF6HKYdaIy%jWyny`cq{JLiV>SN-Kq#+{6JXDq;RWy>LelO>gG z9*V0qQI9L?l_;2K%zjaI^eTcOYN|(dbp(MhYB}X=YK$6<6xFn6^|csPw5rj=ih7Fo z@Euli?IceJ7;2&j9`p8KA#xqwa}rp|Q#ffJ`LI{(yG#w2KxcU&b>j6VQ8zS{LfAy^ zl!=xp@8STB2pSB}C&`ES7FVaF5;JGZ->>}7Jfzx8BPmAS6@w0BIOq(MhRFMo$vSTuqqCHx9A=xP)>hVt?+r_HxF)RVQUe42 z=`-SFpPg;C*9P|g-Vq**7n)iy;+f2R?VnMg-TVCr4^QK<*GWv3srp? zT>GD}ej+|ez^}hP3pN*WBO}g&v1s23W=Ju;JlNVZheSuu z?2ZXoc|8^z09#+BEis0|ZST7V1*BV#^kC8bD$MwrUXY*a$4ge-KuK@9tM%Jrg2)bSYWKSdT4j?v#7rWY)30d`Q z5yzRJN|w{VMi~$(DLO5RCffgj84N-u6;&0u>fW>qFhMpn!(elyC+Wn~;|<)2HfdBA z`je}Hz<&A>i0K<7*+>d1jZ=z6^~6(&7lWa&18J5|Lfdy9Ii+fbv!>2eYD8ajv4YSK zrsO+J8w8^oE8u*upm%6GEj&4jk0$#i5~!;%nw8%11lN<}BP{(7zcFvOgz0gS3F99#PTm9J z;{6)re`~87W%=LwQvUZ8pVifubcg6JCJ1_XhTs)<#Mzgf)%B&o@z*Z@d)Trsod0?K zWoK;}|LsXW%lyyF{Ljn$&&&MJ%lyxO%+FH)ztsObxbfAO8*9rAzU2Qa`TzVwG8`(- z->824?e5-Qd(@v(|G&Pr_R8Y_*H&LI_5V-uX|-A_JY}$BDNRP_JVS16C= zO6W~*t+V#3)md+?cf6myca-!OxcPM0Z$*g{BcYAIcyA6?RseYZ!MnbU;VP1O=%bN) z`DHpC_Az1{@HoS1KgRDcyqMH{t?NWyXuk0H#RM-ia7lo|B!VU|(=qfuryo3^OYTJ( z6M6%NUBm^n{yvW>&*GSvL-YiUFasZj>&(CKqN_CNdy`?*i!Wg~7>%1nJEr&EF!>Op z*>&_{lBKW-^B2$#T$}*#w{bl21lNh3!OE*^9dGYoy9q<2srNV&-z2%|-@D$1CmHG7 z3%=bwK5hUkF0E&bvBw!>nH7?3L|~4&-KrOz=M?;!+Wl#o0CRZj1wU+ky}ygVc5YZ` zY?w=OM3tTNh&9f=6a$UpB;|209pk-la*HWI;t2cn=I956atw@hVT2~fZUE$QPD;@p zLdh^tl+uI)2aQwvZ(PMZAzO;)|7I~G|9x2$laNQThlj!O!QSp0Y-p?BmmvsW@F-AT zAR~M?yw6mmD8vGcsXNAW>1>_04tH~ag8tZ-m`IVlF-7GT;zmpS$_181<6APmNf1H4 zCrv5g3?dS#%D>uqdvLTv4+k)Z*dux#oV_0ofP4gxlKf|!*q_H5`Hf*;fzg6LVIriVCQ)zq) zXmA~k3zSwTz2e1Ss=^Pmi@pSmoBtg53cGl3q7?#Hr6|*ViWV!YM6gbOflmAsc`x7# zj(XEeF2*>aLh+MeEUVc24^a4Iz-`(k0Kg8WS^bP_r+Fyo95bY|dGg5A7kX`>5YC>B zK}C8&G)2M}#!%1_%XU75%|7HYyI@8xE^srA$HikoQy4^u>Lc6L>hKSh20vmrKrbdH-A9|CaZ^<>%LX|Km<&!nc-t>Gk`=cK*|_ zy#MR;Kd&}kTKB)zm#>%lpC|cjAMI?N?0Co9-|W2G@^;^P`v)i9&cAk#PmaAP3G>@= z?~9ccUTWuGCp-JczyeqWCl|f!c2cCO6uR9zr&;5cUwn4 zc;D{)Al#X}i+CIYpWjbMA(j!YrOJ!fqbnk|v;Tf?uUX1%LKiN;&8Et#U{;Y$J=5~p zJZqM7k5IMKGe^a{`)8Y*>}^w}5fLq`3NXvt-+BRi`(@Ybcw75#cwxAY!G(qa!znRvNd73559p%ngMV*T5(@_D_R;8WL~>R4uv@ z&_ElGf?6**3NHEoCI7$V|CgU%lK-bakDULzv;L}-|NC`k$^SpahtfWfxK22L@&w>y zj=$U=OZngO{Qm=<|Lbd=m&@J1JpbM2Kf0LBoBVr@^Z)fm$Ikz~y1KOgc&hWC#eX1& zqDhKwup;z>ZlWFE6!92^4_fR8g(AbG&D5MS4g&ibCTW;oCZpP1*6fdnDIztelgWw* z4G|V;$Zf>C7UZ^FVkN#|Ugj7uxvEmR%nIJbL)3#-RG?&LPAA@VLYdTcF2IfsHGcr8%BWBDqPU$+gbFeIf6r#nGy8n7czZdP3odTq0eIl1g0aK1z=pNj^T^>vzn+<+xk*T zj*S`X=0!H`;X=tYo@jYC7^c^Gb&M&l8mnsWYu%Y|0k9(QK$gV7pxlPq=t5e#0OKZT z;mf_Btu-{G5{%+Jk1i;KYe98YtWMyn;vQP5C1XzyXoUuK30VQRTBPet@f&GkTj_Xs z+a$}h^AuCYH_dvj7MjWli$7*j%77R}w=dHaN|WUv`B-^OiHw0E&kMFhbROVq5; z^OJ4olxWBYG?f%KxH&TqrC?Hsv!dpRE>K|sA)ih#Tc@ z{Dx+^5+Vtl*+)q%MO~owH8ZSgj#G1X2g%K>Do{kNg++JjRzenaM^>vY#C zCZiJl#XDkj(;ET5Lzc>fDLFbp5TT%D#{<_(Cye`luJKDRBp0QteQ%1W zi{@<82GHg(RL?56Z6UXt>ScJfKNAeZdZ}f#z(2L z06T6J<**mU7mXsd{4DjqOZo3o{=5AA&gH*&%q(jDHCzANd2Q=|U$4Dd%733o{!8BX zE#|E$yu4j1V5UuU>VM}Ef6lDK44yMlB@oGTNO7{$5gniQ+?Na9w53m z&GIxO?*x9sMYSm_U!-Buk9Di?Q1fMg3*$Vb^dRx+VOwj{9oFCKiTu8w zR0uqR3fR>1eoV@qhw&B^r;0M=vBULvI+;*T$X&q`d<6HgAeT|4Vtq#wUgE_{D^sUz zwK8H{rq?nb#wEJ6&5;d*tv(;1l!>$9O_*jORKLvZE$X===bV2C6?)DBdke*0}C|Nw1vi^U-FXd2G>^Um>MXiSaL;zJ?m0h)oINnYAacNHt zI4bmwY4nw42hV&Zo2*zUj^8W-^_>7Re`>E!vj;JO2}WP4Mq0VeGFcKZUKPkC!X`x7c9#|1?e2!;u)XLqgB z&|T1>TA3lxj*}(A771>*YUduU0oUZ28ZtmrME2FQNZo+*J{eCPP@_CUJYnc(9Pc zY~g|Nyh!0ja5-8y5414U@1?-6^4O#@bMq8!!AkGj(YZ_my$yT@#-MF_$MH{7wDw}f zu~$gML^=G;-o)eSNIX3*vK{!zT?OdbFgb6_n0BHZnQzrdt>}#m0?c2D-*dVvJWSXH z>@BieU%lUdv$yjmR7@DKUX<&R4Fqj@*p-~VId(Wc7Z-D40pD%?i-X(S-QPI|crQCE z27DZQ;Lmf@M}XV!kB$$H!lUowvLH!YrCI zql5b^?+)HTJK^5eS37%Hr7je>zXG?NP~CRIZ+5oc>>N=`j}hm#1pnRE(YFl#0s(OS z6&`~s#L!PiyN3u1VSHo=b`9 zewl@Sf~iT0TkitqI2XFmkB#Q;8%o@V1$9?_`82WJ75qmF@vcBVUZi&g^AQ5RD_~C( z_g%xMj}QN@fITn@yaMpRVDMTG9yKPskD3ZaKlV?`6y(zciq{Z!!Fcg@&4-4Kx8Z!E z=<#+l4+tV}gLr5xc^l4ShLrc2%BwfT@Q%7@HQ+2-LrN)ic_(dQC5RNle@wt!NH<4v z(&8F1WKI#z_TJWefCI-T3-HS5{`LXJZp4Q$JvaOru`TqFxD@vEyWOv-_EmBYbyrrP zQyTAeyh)jXPYvy%C!Cw^N}9zs>&~X+hp104=HslI4sbXQ1q}!Da9}u82@A(NH>i7* zsY@<+F5flWB3hbd_Ogj|puq(3wR#Wc0LrED5@GhB3gIKK=7~OfoS~=SW}f7go7f5J z43|=qWLZkK4JVMvhYMIyx*i0+i+9&DIWrAKhUCO^Fzlx9CIgKBzo1IC7bCo>Q!E%J7=!#x6idLtl~OovqM zx9C`DO5)9yx-8w+bzqyg)I8iRcHvMuygYBt($X+}4B?A%JCyjM&e%L2G7nota|k(v z3WTd$T1wqguN1+90s3w^JD#4E6j;*VispcW31FN`n6FlfPRB0J0^thWNA))gs`!+Z zB&j0G=7>UN*TCJu^gCUze7B2-c`TO7?2o276b)6W4z)RJBRe?m2MD5}>md01dK?uf zgRX&M0BvM0CP9M`mg`jsY02vv4#d%yqvNZhrya?S{6O+R%Cwm^Klq)MVQ z5pZDMHbG%`MBu)n-X)%yQ*LyN5YE#+W};VFxlrMzH69}Q$mOyzOBG;ea%sNGm69z@ z{Wb87G+%exuY292JsMs|xB1p&g1(^zV3FUf0_khtvCr*{O`HFt^h!O`7Z#tl|C1); zfO?CJHa-%{smc+mNiL>vjXXs%fsgnG$EI<&XsBtR~*Vdm8VVgn6*B@!D+3 z!?>HW?=Xl%A_C}fOYA97^E<2RJ==f8^CB+0Z8e^&c;C1MNz7`TU=BjU?sl4?Ou2U@ zgDnhoju$r77}<}&_jZx?qgxn$JIPZxo?sP%Iq8RAoj|aL$~d;3MQyBXf%8$Dfq$oq z5br5@U}agEQ}B+a=3YxEc&CdM?<*kqlqOAk@Z1)#)z#a7cH*uo?$++gP6=k^YbJnP zh~`!wuF6Va(`C;g1kcPCL~(^e$|22c=7gK%lzGDmn8hkYAq=tP+;+!dPGOm-=-eY( zS8PgU!l{(9pBc<${m$gPrM@>c+ZxSyjSFPaB!ov2Vx}X^&PML$F~wpw_pLGoo6pqH zvM~ucmm&s2K$JNa_M(gb=|rfjzSh};NgEV*ANaUebGCC(hbaWbT}a@tyjYJ6eT0BdS+i%=jHEV3u7z$H&|JScC< z=UU)6Ne>yA!i}@0jpz#42%ZAT3y`Y7EPggOd6@KZQH5&8XBHil3Wb8@u zXh`9U1)70q#92rn8}#i|FLUPox$DMkMIA;tia`Bi z#V)}CGfKD~*v4*aW3k3G4+CbftK!B40G?axj)7~zELJ%ep6I{XC{8sb;6(aC_a^Q; z6ABE(6Nt}K`MuF7N}0>om^;0z_YL0x#K1NNX8s!v7bEM$9w%rLWxz_C&jYhr10euY zJbAdOL!3pHav$pU`OPY0M5Z{yutjnY8?A17cDrXQxEx_AgvRyXuYV2vBc zu!K%88_vLx1aD>LR*Qs*QePZbd|Op)DK>Uv6ERF?lt)PC-`t9*Lqqp??|8HeDxCW~>X# zCbZFqUsm~Co%Ao1}$6HzHU~754g{gQ%C*x^sOe7J`aeTVAdB%?G z!1n+*M$rxZ>aI3`nKO7&q;2L7AoDVQCBh%Z{-(F;X6m98gXAVG?`fT4Y`X6ku1Wk5 zPYOv9=}d5u9;uW;acZ0;(J=Wh+Y7nTqoxLr)xEw<$WlPjD`doN13$zPRa4EEde)w# z0((BTOJb%u2r=39U~1-CBI-QzO^1z?VGaQA=#B&@>K$$Vd+#zSD8MTwxb)UK%;&~; z-k!8>7_zj}=jIGNSFN78Vu+Nk#lqggx)O`W*7AwRs-%3P-N}DHQA(DdrT@>;|7Yp{ zv;6$h{y*b|qrc6J|FZsaqZI$`WoKjQ|MNutKXAh#=NUcro95rJV4#;7t~-|Zjd;yd zTro4(U(WYNzlDkFEIrCw_O!`=9>w@>1|*7xoSATr@mZ6{OlDPbPqbiox_}>eMe#oci+_PCexy>u1L2!{Znm5fE5n>k;3CRm4 zdQy{rp$h9DA3Y=|Wz*|LdGR>+Pi6<2^e!Pd=vM`iP^gl=_(Z-D<{zsyIhlbPGuG3sqoaGj2q*MovF#N zE-e?Wxwuy5e^YN&nzu4!M^-mg(S4ULWoBbfx$Z8>sSY#GmY1hZexow-KngnwmVHdz zuVhF{WsM3jnJ;!w{VM`u1<7sXDTjqvkwuR$`2QbWARF-u<#h?THyT}oU;)i~e^%oqEN}6hq zL^SD%_Plaq+Q8VRzAY|+)QMr88uF^pbbGahH>b~yS%FPx&68m*qUc3F9RRgMGf5v< zTc1U=k#D6Zip&`}lUy}4mm4^XrV}V=4UAR^nVdGx*N6Bv5A+g^hBJj^$;jRX-PnO@ zf=bin>>0P&si5*|AEMMnuPC=-@HqR;MAsfU#4d=K0xeY(jyeowP5cq|+3#|jaeSY> zt)w-a~mA<|BUE{13Y5D;rWQB4$vCaK+U|B;|hI ztYj*y+@o+NjXE|7p(*3?RK^o#BeKluizru^E(8hc-Bk*33Vz`2YbR7`{1UVu5eli1dq}POCr_o-HXR5!WKlebzo(BV-pxc_W zSvb)!{ZBn^S8a0Dw0dDO;Ld4irJ5JFc(`EJ_95)*dGv!77qe#Vm8=veUF4uAY80?} z(DOH&!_}>_OE~CnU#2NMqEmket_e{Go5cm>p5ii_!KFS{KbtZUCW(WYNCMyySC7{e#c5i4sTdgLQQBcFV=+r(=m&@OE7GoXm0E)a1qHJuD_gqjL%Kp z!q2>C>~_ZAH16S{-mQC`!zK@*jMRz&`?G1ca-eNRKhhhQ&p$D1_#1VF!7@ z3J$nYhAavT;No{v4ncOE_m!(z+Y`*ys52|y#Tm{PtQMaZJdTiSzG5%X1AKcIJ+8Gf zy##$inGzTa_!>a6lv71Xm561IfFH{GEVjFPozc^fp5FVKu+i+W05%2W%5H5;a!hnB zKAEunZQNx?dPvqq8n0Rl9-2a8nG0pDelh)hm#OZVV{~_*cMs-GfJey+=HujX7dYYK zK^Ta0>iXyD5a`ftBx3au{C3pu!@>=xqj5lo3j$*0Ym4qBV=T%7UEg;7EV;NWDodXL zmst7oh#ZhBULMDQc?pHrbQgHXm}2M)qUvCnUU%U@8TNhWW-sq@1u;vnt@LqxVkH#r}$`z^l$*le1Kp)@3kn3~?7F;2Fs-<`1y!*9df zv1rbW?`m<>M~I4kBYTD}>@4j=$aD?SFt7yOMlfU5?hGX?SFQQ_ai_1>g#J<+F z9=q3tf1K*m)Wjp8)N($IsEWe8z>I-r+vad28~CUFWOQc4dp&)Dk1RG+9};F<_+YU&^-qs76sx{8?YukwVTN&Bk)G*(R&6pv$vsv|$1AeH>eeiSV<~1V z$J|RImc=q0aW4+*I?uN4x`@*C{btjm#9F1mr})A+H%D-{Ac+dycW8Qydga?tqYmy7 zhOHWp5i%DqM+4MR)U+_?%va3*94oNUD%7mRLaSkm2KY^rOajaMNDcSXY@i4DV^!`t zxn8y}*)Qwr2e5QDHs>}mWnDE#0Xqq*Vaj7+p3V2sV_R^mE;!10pqIv5 zi&~$U{LYPP3f-K$I?8pi8HE_#^wM+86-^t;mitQXhl+}<9qz0VK&Pedv*KCnCb`{zuPQ@{l1Qb5NPl+1Gxw~ zp{#T}y4FgOT`sUq?*gFRp)Ufb$?Y&i>(Ma0Hxmgw&?UCczQN%uODXG14zrv<(Y%Fh zqEXO?5e7U9jHF1&4_%Xq|bQdMj3`cY3znb6`{zhZCo76 z=_s>nWz=+3oflEfKGx!^qZK#y)*3#922$gK2-MVbWR^)uM4=Luf?TeN3%z|R0*hgC zTaA(my&j5Qk^?INDmK;0Yh=@DQ4b}>+==BwT_WW+2E3zS6^@B0Qhb$U`efv47BC#E z!K8`HnLbJ7VT)=dMyu(V9XU)-sJM_ zW5_pN` z0`3l~p|VPz8Y!th8GA`uS*OOTDQa$(&{NA_m5f;eM2_Uja*$VU>n?!$x(n3+l7f=D zKvYImv8&Pp(#GkvjU;cRUKpkQco_DlqX~5eL-JQAeKYQ=h9(jZ;||S7ptaYq=R|XE zTnwnL(d4V_)MY#F)Gm-beInrn=L2Ge8H^IuBY|Yq@qbbm()J}zmL;YGFsDpzLP0kXq+hcU-1l3&KnB5hI?UjeHJa*k-q7-V0 z;7@!H`hSpU#mo3l%lJ>r_)p9DPxHrr682Y*75`~r;$UsqFMS1)V zhtTxiCh@S3hE?z-SJZNn1naLI9?j ztQ`4o>}QxqgIGNh{mo^Wm_&;b1R8CMAD9~_L2t)tCZC}(V#v(8`IB)p(g1u&atZr3 zx)>)i14Je}0Zd!cr+W$;-SN(MJ4d@Gd~`mC?)kt8k9h#iWIRaWigvhljAeZM>(j6B z``wdo!mT&o?H(T-{UF|%PyLm*Tf2Ms4*z1dBt3u=x0?;*@-*Z%#6U|**CZm7!KEwm zGuVM+E%jj6j(sEWUse4(=OKUH0X^E|6HkO(kEl>-9 z7$3CTZ6jZH*Z*2v^Yl3tQz(Q2!l+eEX*I6YHO5z5!V~au5=bvpQ}-ZCE|PInP);~h z)}aPK0APtP=Lf*jTlN8~5+DVc0E4%gSzwN2ED;$#fF;r*ahR{tW^ZCz8WYe3uv!+l z)z&$nf8Wc~Y1WHbT%_@Ibgnw3hmWf1*ZVxqT5xFN@Px%Qud0T3gL*cl>?BZJEhHRd z44~g%GJy@=`32BkG$z5wv`9xVe6&Kruqrokzb(Y2|Fr09KxocxS!AM43S<1sd&oQZ zPa+Q^Xfy3AMWVcWkJB;t4j_4B4?X3%je@X!l|c+NSr!!$UNSROQ$EwFko1Q{W3fjq z)@n(W^oo9&BA`4T4w_OBB%GOm+~NyqE>2!WY)?stWh%hej0?1JK9W2f9~jW3W4#VA*T z2XLTY#Y0prSt$wl6y}QH=e^5#6p0jc<~|X~?XR{wzJ=U7qA3Qz;{X&*8HY)K*0wul zZXTMDtV~vr;h_YKn~Ev2Iv66m4K#&ku2luwMalByAnKl$bkfRAu1~7FAC^M}R<~$B?j@k=<#L7|v&-|PI!=DQ z6I%bi?0T;|b2X1g&CKRIi#NY9fAi)^_XwStXQu0CS%*5Ck*v`rlF^ky^vg)$Vkod~ z5neGCf*)?onUnE`0I8h{Wk&I#TVg4VUFv_9`k$r#XZiUx>wlOcWPa_>%={mnwT)8# zkJXK}rT*uM^gjnOQymJ|^(>INx(w=~Va$)caQ+XG6zT&*XIWjxyaz2gW|#m zLVgMi$HJirCK_uWg~yy@ciTB4&Y^@JMDpxuvKj4ru!8nXtr?IpD}w@{+S9?nRT&=7teeN93t;&j)%hDVpgKNyf3&?59vvK<;GK#h zi|~|y`HQNv1n%GA;nw!ITVKnX2A~(7Gb^CK5^f)Sw{wKmPQE$XIsWEg?+w)bywmPL zPu?FM!n5PugZ=Q`*3q{+M@)hF7uYX9MJT@c3%M-7Wr-rsu_qiM?1#8C=>Qtj`v<$n(8c$Aq#M1XYfj)>xPlt)j@1^Jx)p^^iX9=J_;Mby)AQ^!La%ML|pZw@ZG_i zop5LWJJbLlAMR|wh3SEHg@;Ew-|g;vFUt5-8Ygh)Unf{W)3#UDJJ~(i+YyTGszP5K zy!l~PnZu)l!-M0kJ<^MZ+j~1(`>crQ&o{gKCu}N+LU~Mmtdz7uIV+X2Tp25su&6f1 z{8~3G5K?%ub@cVl$<7;wX(zkyb`IX3kjGLHqxZ{V zw!!>Kkp{A2Q-{}R=tlO+GFd5Jlp4kk32RTDl|-qWo}=tQK_UO!9G(btIU|nK>6z+> zV|XI3f;PxHEF?z(!LbEO9NusQ4d5-b^>+2ST(P~!0xbw6lmuNYwlLRQ4%eh8G|r)ex22+D1uKi(Ca*ux)AzB$-G+&cLNxd$H`!4z!a z`E3_QKo}QK8g<~+5|-OhC$i{zfUj=#zSCBur*xLyvQ}|j*+aB1(QA@RVjeUax&;A@ z=Tsld8CwC~f1YTh)IVdH0fagbDhFC#HP#JMPU_iuXhDCbPzOe45%oY9iS;mLfrp#n=}7p$L)7CS8V#boAkohi^dGtO^{H+l2NO z^|;JFf)!w?1OquCq&nn3j4UqXOLodCo!RkxouDmZz#`n|fy@XoS579(HmPbfyuWw7 z)zUeq3do?|C?7z+li$BNlDF9_VmF9}$eL__$)9AnBB7qC9CI3MRNJ8|a6<;Z7B6^K z%{7XF%^4A-8=MyrSu{&kFs0^tnN!rt8Qi=!Y;&r4>JOIGm7?mJrWHb;3PePe(Zkwt zIONnOn4h|ZW6qLV-0^L?#{si=$R6+jb=ukz$0|gY?R_}R`zJA8_2DqX_`Ctjf!6g| z7*@1oL4aKzcqYm{#g!osrsV+Tk2$kR>u;1L?v9&8=%|UDX(h5Y?Asomz163X^c2*~ zIu9j14!seEzGgKw`{hOGs5J%dB>eZ*xEZv_}hAr`n?k0~J6=VEV64S2tnf`L5fX-)gbu zT4ce(zQYiGqX;az_J9^km#{VL!Yz#J-kPGDWVfT$9Prmn(9}hI+`Kc;>|QI)g8OS& zq>&c(KoS>@WsRnho$nXTaqAYDXxSIXS6zd>bGVucYYStFq^yPUt8|r;CKt2Ag-hBc z^GnzPu0_H$ZhzPl6o^rpajIEktQf{hy>vQe6F!>HBEz)5)h!*@vOWsQ5~HWb{M zJ-C-WYP9`X8KfCoFjpSwLod84JgDODzxr)Tp;D@Q?) z5nbGfDBd7WuPnWtedp6*vIG@bn&+2Ml8GdnM*ML-0d|GxcaDpuy^1Q@I^zXqj?@;k z&uCICLMeZPnTV6h=!lk0i_2Tu)iVB=8@nvoE4$Idtw@+?w(%m4j1dL0Tt(IgfRilv zmZf`z6a8N0sRnw4=%VOBJ(B6^#Z;elIeNn>ZWEIQBoPJeKaP2192Ku+#<&P?@hPo} zEs2M2%>rP?xv)HC3JX)Gs>JfuGg8XlX*!*msK))Bx^4$C-36-4yqwIJh~QmcF1Ym;5uQUP z?O1z~wPe{APXN?nD)?w#IevUZcZMch!6*k_eY0RRbJ}DsT%DIgsKTxEl4) zeqMGG<}U(<05`0~M>0LK+olQ1SU^ z?(8#XXPa&;!h9DjelW#Jrgfx{#7(Jf)%vcLMjfuF^g!jBSio8Jn5ke1kF*M0GwZCf zb$p_)rQMdPZFfS@wUJs_O$~@%!U=+D8cX%qV`mL%Jz>`|74ed>lyYpc2?>inCL;u9 zu_{3p!v!tgt5^DN;lZY@xXR~Epz6{qXsNL@8N}IKUL2goaNkx<7DVf=rPk6|5u+l1B_(U11QFyCrmWaeM5tOOX^Qt}V5qbv{HnY)B^4^2vh4n) z!9;8ndAJ&z?Oy{oiM2&*87nVA-V~ z0Q4{I=YO3I?cMvmlij`D{hdmH_9Mx{im<5ZI8XX<#=NVD`Ncri(h=er`piCKVdmtW z7z$8vV+Yu610@cy`#wTYA<8uo9=|1&j+}Cca!mwLrJFV4y*ZAQrdEZtU}t79xH-=w z*^~2Iu0q}{1MYfv_luoQWrg4@ZFRFWDP~d%3!wARa#4V;MFD7U&7fM=nWi6Ah+{i9 zSeIj%PQc6nc~1UQKWCWzXZa+X;~Wwv44v~`eHxub)oHTLCmG%TB6)$pb-mM|xDFBX z=;mo%%HnN_N2m7Thj?TyW8DgW2{==>A>916Fc30s#z(Laa(H_O-+ww5!i``WDwI|q zch{Y@9-Hme!TtZ!^v>g9dM)gs``(>vji_k5eC=#J25Tagxaq(-sRBk-AA0uUmEr)(+_eVQ(5Zb zfgkZ0vZz9{-ky#DH9iEKvr)m%ji9q-rrjjHWmeP~{ECzB z5j+k?2^gnRRf-;U6(d%X7dPr?$GJ|sOfiV8Hd6>vCkQDCL$nJ3>YbSM2YV)3#xAR; zF4v*P4DkE`l7TLni;r%@bLV%%q@51?#SPGfAdvLUf>w zGV`FOgwmpy8&ydl`OO$56o2cqJ1p%Ze@2wcuG(gnr-4`pyK7EcgT{*CV`1#0(jduu zrOs%kv7!Q}p%_*3{tZgdx^nX6tN+GX8V=K5c$K6><{sXqWQ1D07-_wNT2#|;g#vcs ztDTL`s$XfjWVNT%t@AaDD%g2|W5l0mlH_oPUd5qw`Yu71y)HY6&e4jET3!2rk#}Jn zUmIt6xB7s08Mhgs8WrnL@z8+%W-HygBUkvKp>x`V3SIi2xrjIC!3SsZGBS;qfa#{XGxZg zA)?r#v5Y(;AAO?a4=T#eTv;GiJ|=L^%E~86iGa%yyCP+yXmzEh;n4*N|a*+>2Cf@UOJjIPuTt;|v8^GlcC5X5#Jp&QcdOPk{rnF?G z{#N8DTye{Bl(a7C28#81YO^A4CKq_$T@Q)!%0L4Tz-?;@Sc;;i@a)> ziVF#{?U=G=T~X(}Rn@4NysF~WS39$uV;WV_GcyoKKkiQ{Qks6Z5?8BDTa>QPq~=jl z7xQ1ae6YL{w#I06V_s;pAk_mBrWB=WYdT)6s(FEJK1#;1ATxnQF`M_>Mw=eay9ZKG~QXq_eCGa+P4L1h%4}3uZ|SRsv?1 za6xfN$Vz}5g=|>TNM^D0e_K!)SjL-2_0= zfTjk-RezfiWj|a;Gi%KPUg^JmqVc!Fv90_4UinhQcpx8d+kN7cKS+V-b)av_+dn?zcs9zyRWiuNV=xl+8tIiCMl+6uDHVX!%8Q zu{=)7738vxb`B4YcTWzEexQhbl%9d|J&3#yEWx;czY>0Pa&o8@>J5{aWpB7Fib<$` z;-Ex4&Ya0EDHIh`JBG)X(Inm%VW+bIR-?TS-9E{paSrP|iZi8b-pPQk^M+|J8uHja zuqs7_Q*nJMeHyYW7F7Z>?h1AL606hewokY(PlwHEX{>#%Q+)5 z3Oi-UoyH>hDuJagGrQ}?d~>M!LAAOzco+ecfGIvXc{FUoXch3Rc(lnB084WzTXIe% zW$(RAhZs1c>#3=;f;X!dEN7|rGhtRh7}a30nEma8{o@mVzB!lOWmB$og5 z=}kO%v{}_)mL^tjZw8tQ1igsibWTvqClFPkC|X=)g*h})zdS%kBRuMb=f8cwzg=1e zRc`T}pWlvqpJH}xz-2mMxBMjYTx#{BCR>ZZKHxC(pvYn|M3@)poM^2w>@rt>tO$2F zJQfHNza(tOT}Q(Y)Jns#lS}AS(NIGMYGdJ;!eM+B51qq!M+F{xBnZEaK?WaX5a`bf zG#yvYwE}ruXu<1wpYDkACH;p?Fk@cOdcdZnaB{FBd+1^;1CI{lK`~06j+nXpQovJVdg=sw5)l*GA#S z^FVBY(0LqGVWI=e5Zb1ENc5`+RH~a2#u*LQrnb>|4e0l*sK7iZyaNT>*rXAWiRI6# zoNXLZJL>m?Qt~ExC5^eJ7`hbw_;S4Bgh~HnW>rMvHqL_5<*C70MC~vr&~z;nK?4Mj zk_U>Y1xSFpr^v&!`*A#>v@qs6oN-2*IbSjm{%EXh+f4R*P@>okzo+op+)MLl4RnIPZSn!}=uu|{<|RrMIxe&{zmyAekz zC^ko|?Gg~|u08`#5@U+z8vKX|Q&CNz6@uQLq8W0(HOZ1IXt%|j1nT0hr~s!G5m(H~ z!$;$^F6_r4YnuBfc>lgD&;I?t1r^ESL7btbbe~zVV}xTuqPG8-fukhpL9fL}+E5a| zaW~arK9#=6(&;2NqW&$yF5%YG#B2dsU{>!$*#m{wyaT5*$#3IKMr$`7uPp2#FB;0R zOT2yQ7j4i3%uJw)H@v@lYqNHw-T=Z^)iGPgrWK32X8X>uh0SeDnL?dq=Gn-zHnZB$ z&`w*9swEbqMXOd5A8_WbmOEPluiVw<&K3v>dsgM3c98r|F3O2LEgXMa%!IEg2&dqW$C6;bH$!W(k>3*Wq zj-aDnTrrfkFT>*vs zr!G^<2$@I%@%YWr52ogEQ7XDf%qpa)P#uZ+B+7CPMe0IVHDy9si#C*kTB-PZ$G0%; zHx*&`=HfN9Fnk)B(?aZN=g<|sj$GDrQl6##*V6uLY5%pf|61CA&1L`Pu*$A=1(;#~)mhtkZQFmXZ7l7-p345q zNb}?}`_laZ9&G!CafZcr6^6Uoyz8;!gFMvYOG?;@j|i`#EQu(;%A=Wrk#GUH`Sd#O zQzKO|SWSfwuTi7&spEKg?e=tnv1)^gQI=R(p?_etrA{}RgyI$+WYM+!p%N`hCwU(G zTY2omS4yX+T;X*HT9kltK2-L+vRY+K0QttqD@wf(L*k1T;?jow1lZ9uFOpuMzDoaa z?|IWRmQO8-<~c4dRJzu+tZGx>S@r;3s$+W#n;TcvRM*Hc@1iedt?YJ!vR_&Jlc=lQF^N&<84Xx`_qGIK|`2vFddf9ItG$ zV!Zs~W%YoC$Areu_-MeB4C22K2^R(OtLNFjOZly+` zr=rWq^~xEcWO=%Syy(L>Mf~X;<2k9=x;RrAuxgD8q~lcXX@5G<>7pR&E9j0vG7j^{ouJEcMfHO#^P7Ou2nD<$6yxjX9rrL_LOF2=eZE>f?wTinBlC5&A&D(Qb7zhIy@{cPuvXs=4;0lJI||7zkT7HG069-BMkkAV zY1TJVE3$x5?rcJi#3x)j-PP0fz<^8%=&42jJipaqdmbqZ`wf+8%VR_q`0x3tDV?pD z=QArANiUkvHHSf`kZx8A==jFu z?7Uve|DQy_ql4q)Z?<-iLQGU19__F+=NMxX z(@1Cj{|5g!{5!H&U$#H{M`IIzq0HvXAN!v*Hh;{Y2mjclj{M9e**~N3n!h>xJLkTj zZsV_T5e#>~-ak0nd80LZc(n6&_g_2cP#*Zl2{8SG0o;(@#05o{-1M7J?f8fN?eOUR z{>kpU9hJ5w+=0J893JfMGkI6P=j;-yHL0E@n#(rX~tY@d5GOoKU@apHp_2S$(ld!FTum&0OY!KnZ-8+_p+hCv&`$@F}f^vKjR*LuE1)x5w3tRi${-bR9S3i|s6?s04xkQ?4DI540rwp!>G2vv_)o4`j!IA;c(zEZ6t$VvFXLEM;^%=u1t+QHLado4!;dpuf`*T|3x1KQRKg?xK)z@#WfxknUU*W1_uUMgji!Nj&Tj z@EkrQoG6O>)jTeB2>H~<{yl;-9dDmD!c)7@X$vhz#UHhj{w!ZLs5STK6x12MYOE8F z;FHE1uJ=Y$vMOWnAMd4S4%;>6Mf}X>*yW9x?q|-jOju>)>5>vEZJFnGHTy_6Gj1LJ zgf3b_5csHlEH;s1&7A6#>~Pv32cLlM|B{x4vSx*<5-Df zcpR58ix*!yi!J5}1jaRQXmh%6n`22;R zt|)KL=?0D$_7*I3YnYBNR*-YX<$e<9FkMrS<{zmu*c#t{a(%&E&R*Z{9v_E$2ixKI zTSxo5`(Fbe_<2WrymNGPa0Cxm*TmEPo#PX{cp(AK>Ye1^F6VzC)q83mf#&!mQ_FB zq3My7<5Wp2`7dBcMUp9L0B&jz=&IADw^}8}@(E~CDT1FgZ!=?cXc@ndu_x0EG^-2I zuP6^OnEFj1irzc#cj@qoEdIH@IQ)`ww; zQ)KJE4pmP0ak?DsYEnwe!0#27sL&-PDBXH$tOK=ZU$SlMDx%B+U2oZqiH=h14KoC+ z1Uu8joW!oH=CfMsz6#4e%g2gbm(GW2??WE2KO8}T&}!lrrMAT9LLfPeiXtAzLc(bk zGDVUE98re1Qj?jCN|dxYZjmibH3wc54b14PkVaA!^*&^#UTiAD-Y~_}0uWVHYkFD* zA-ohX#bnNa;hrWASyv6qxz|$pacD59RGfv<6HomnOtm5Z7H@0aU2A`=~QWirhvhh_}4DKZUilHSXxgP(Kgh)SPmdUlGD*G#Cj zqd2rtbQ9p$rsxu%5|OU)GjFv~%9e~34BeJ%a++R8F7t;Z&%;q%VCvPXj5~9Cm@sFq zBxfd^jrnA^pCkjsV%ZeUb6=*!<-xnZrjX9x~IF)=_3_W#>fu zc}@8Rtspc3Qla69*{&-EhZ~C6wI2@&76aCwGBnKzt3t&!V|4Qp6Ro{@HqM;*0sX=o zgPDy8&ot)KR!+6Zo7Ib+Uw9wlc;Y36HyvZ<_`A}o-?#k**wxt^sFZ!1O6Y3aLE~I(Tx0> z30Ty_YZ34T)+*ksWz82LUL}4Nhuuy)8!4Q`kdVa4* zRzv^!O$0KiG|F_C1ud2WpicZWBmTd`Qu8Uyk}9mPm1ly)s>v|E0WzSDMrrRiFCm88^4rya0F+cKT?qx&H-!jlZ;) z4hgnw!uA)a6=SQ;Ryq#w_OzmZN44(4DCY8IsOww3JA=E8MYrOtZCJ&aS(C9*=Aj-j zNQX>GToHdLnIZUsJvK(dmwl_>i5hhd7CJ^`59q~-afa~4( zG$EdtCB)Le{?{Enq+*#qG7t#uf(P2!Gm9a2L=S0wuj92ep?M@Le9aEMf<<2_yc69o z8N^b=rP8TwX=|AMxFfI?O_B^G2wSvd95IL4xHEZq4I@#*P+AORIcK>#6YBGn*G>dp zQlM%>q~cyU7E8Tm@K+scWoiGtwEte(e=k43dHe6_V6cGs_ssY&@WZzM-dOJ}?Z2NW z{>u?8=Q8@sGXM9(&2NoB1b9uRJiLw&BRR0Xlz|y#*V<)W1{<-1cOV=iAj+{TAc_QA zS#A4ou6kM*s%pv*F7V$j{`b8zm&PQjm>itUBttN$AdDsGGIR_*>%Rq`>=A7#qPz6rh6yL z4#=XVYp_1Un#fkn!l|F7*B=?Xg-z=(6S;-jex$f9;)^3T%m3fr)$g`#1M&a!6q^2$ zI?D-~0mWQoK#{mIz>m;Fl-2vdw5`zWxcV0OL;dT)*_(zV(LV08(ve<|$R$=^-5n1rF zd#Ik6$^h%t#80jpeh}b-PQR4{C2XLU*9z3anQ^}`EobH8@IMdIQWGVfCPd4byq~ZE zTCD!x>i@0&-=_bj{y!s&X-bxjO#mD8|L@-IDCd8_-QBhN{}%#BA z7Iulk$3u(*Es&tm$M^>b_|og19G-Pg!?Ul)-6B4A8LNFt@?epSXOmTsMGF!vNPd}& zG0eIGUvsbH>2;LCrYJyv9{53|e3t1m(_?3Xd9*^vKM0zpu8(||e#LB07+l3tne zE>qZc1+zGSDZ!NI0(cIuHYG56W+QQUDypIAi^3nJM$64^xCk6DxfcdXu*47mX{_|> zt{^3zBl_iQKkRk)VMBqTYJS}*>D=v~{SkiX_q!*j^holzTYO0GmzvGO1W`3R)MK9W zmp!*3Yi!6G8?r_lvWBnz|Bj$FC6Dk0F*thFG6}z(g8AGN3^=cy!Yj@V%zCpY%0Ovq zIV=uwp17sMRUKi?c*dT}T*MkAWh#CR7@lJ?n^KB-^o?Lnk&!eOYBlsh0IX9Pt%;6VRZ5P+^cuvMl!#AI2ZKfL;4q<;!U{nuw z&!H~#HDm`k;-T3wVNo)&%V!NUIJ^v3Z|UV6*e2A&(?hQ zjbz;6`FoDKgy9e+PiV&*{+rP#j8UBgec~`PfnU7d0SA7 z{$7%lh)Fr5Q9;7cuT6zWHr96>5CbgIX4fs}jdYcrOAZY{$r(-#batg>w;fmT#>I;o zf82`SfGDnuRU(a(BHvbN2vO8>Fam{O$Hov-jpB31ixbB*Vw~s#gg@sNyLjijzU=BI z1poEUZjz2~pTbQ+a5-f+q`4Tsl0xEZ_X)~UQMx(+0c-?=XXPzZ0^dh5-vpPyL1La9mr_O50mohCFr1NTK;P@W=lUHayqfo0up-Z3^hisi8sbWcbyfB*TH>Vd5o;V0s&G_HKDs%3F8-dxv#w?^e9RPwAcO z>sG;#S{{@EB>NRJda9lbFK5K64ppS=_fZk%sJySjX%uvWLRVPBujw4d2UsRh4zy@l zd5PH2kxS!E%)c|khu7RI+uVl@KH1QOEBeG5)1V6`NbMqhe(lXZVIWaYdB<7pakgBZe%E|$AIgKo!e$Ak~>8^fC@OT z_Fk=`YQGUUl2L)fBb6cf2&Ck5ozo`R+yKcKJ`a?U4xSQAIA9=!aLq|=qD1rFt%DEp zwsl)=-p(_@3|aIRgz6Sur&q>))2H{CrdZt@ft(!bNOM2QA$6jCGuDwS>+&=zx=yc* z4b!Lh=sK%g30Y9 Date: Fri, 3 Apr 2026 02:55:04 +0200 Subject: [PATCH 3/4] Fix review findings --- .../specfact-code-review/module-package.yaml | 6 +- .../src/specfact_code_review/run/runner.py | 19 +++++ .../specfact_code_review/tools/__init__.py | 3 +- .../tools/semgrep_runner.py | 81 +++++++++++++++---- .../specfact_code_review/run/test_runner.py | 9 +-- .../tools/test_semgrep_runner.py | 31 ++++++- 6 files changed, 122 insertions(+), 27 deletions(-) diff --git a/packages/specfact-code-review/module-package.yaml b/packages/specfact-code-review/module-package.yaml index 92d6893..68caac3 100644 --- a/packages/specfact-code-review/module-package.yaml +++ b/packages/specfact-code-review/module-package.yaml @@ -1,5 +1,5 @@ name: nold-ai/specfact-code-review -version: 0.46.3 +version: 0.46.4 commands: - code tier: official @@ -23,5 +23,5 @@ description: Official SpecFact code review bundle package. category: codebase bundle_group_command: code integrity: - checksum: sha256:fb6181a897e49a24a5cf6dc5fbfce67d7de75588372e5f1b661be0761dca4303 - signature: qAX9yIBO+UBsqa4ODAym4YrtWlGhSoyiIb4b/UUWKKN+vv8yNentvwR8mHd32I7BnF+TBiHHmonH+ktPV9XSCQ== + checksum: sha256:ee7d224ac2a7894cc67d3e052764137b034e089624d5007989cab818839e5449 + signature: V+GNklTfgmdYKDWgp53SDw4s1R5GE1UF/745CVnXFJ0v3WSCWLY8APqyuabetBU6/Z1UQ1lKfEiRiZOFJw7WBg== diff --git a/packages/specfact-code-review/src/specfact_code_review/run/runner.py b/packages/specfact-code-review/src/specfact_code_review/run/runner.py index 4ccd86f..53426cc 100644 --- a/packages/specfact-code-review/src/specfact_code_review/run/runner.py +++ b/packages/specfact-code-review/src/specfact_code_review/run/runner.py @@ -301,6 +301,23 @@ def _is_empty_init_file(source_file: Path) -> bool: return stripped_content in ("", "pass") +def _is_coverage_omitted_init_by_project_policy(source_file: Path) -> bool: + """True when repo coverage omits this file (``pyproject.toml`` ``[tool.coverage.run]`` ``omit``). + + ``src/**/__init__.py`` and ``packages/**/__init__.py`` are omitted from coverage; the pytest-cov + JSON report therefore has no ``percent_covered`` for them — not a TDD gap. + """ + try: + path = source_file if source_file.is_absolute() else (Path.cwd() / source_file).resolve() + rel = path.relative_to(Path.cwd().resolve()) + except (ValueError, OSError): + rel = source_file + if rel.name != "__init__.py": + return False + parts = rel.parts + return len(parts) >= 2 and parts[0] in ("src", "packages") + + def _coverage_findings( source_files: list[Path], coverage_payload: dict[str, object], @@ -312,6 +329,8 @@ def _coverage_findings( if percent_covered is None: if source_file.name == "__init__.py" and _is_empty_init_file(source_file): continue # Exempt empty __init__.py files + if _is_coverage_omitted_init_by_project_policy(source_file): + continue return [ tool_error( tool="pytest", diff --git a/packages/specfact-code-review/src/specfact_code_review/tools/__init__.py b/packages/specfact-code-review/src/specfact_code_review/tools/__init__.py index 85e7b19..6911d4c 100644 --- a/packages/specfact-code-review/src/specfact_code_review/tools/__init__.py +++ b/packages/specfact-code-review/src/specfact_code_review/tools/__init__.py @@ -6,10 +6,11 @@ from specfact_code_review.tools.pylint_runner import run_pylint from specfact_code_review.tools.radon_runner import run_radon from specfact_code_review.tools.ruff_runner import run_ruff -from specfact_code_review.tools.semgrep_runner import run_semgrep +from specfact_code_review.tools.semgrep_runner import find_semgrep_config, run_semgrep __all__ = [ + "find_semgrep_config", "run_ast_clean_code", "run_basedpyright", "run_contract_check", diff --git a/packages/specfact-code-review/src/specfact_code_review/tools/semgrep_runner.py b/packages/specfact-code-review/src/specfact_code_review/tools/semgrep_runner.py index cd32957..7118cd7 100644 --- a/packages/specfact-code-review/src/specfact_code_review/tools/semgrep_runner.py +++ b/packages/specfact-code-review/src/specfact_code_review/tools/semgrep_runner.py @@ -26,6 +26,8 @@ } SEMGREP_TIMEOUT_SECONDS = 90 SEMGREP_RETRY_ATTEMPTS = 2 +_SEMGREP_STDERR_SNIP_MAX = 4000 +_MAX_CONFIG_PARENT_WALK = 32 SemgrepCategory = Literal["clean_code", "architecture", "naming"] @@ -73,21 +75,53 @@ def _normalize_rule_id(rule: str) -> str: return rule -def _resolve_config_path() -> Path: - """Locate ``.semgrep/clean_code.yaml`` for src-layout checkouts, wheels, and bundled installs. +def _is_bundle_boundary(directory: Path) -> bool: + """True when ``directory`` is a sensible workspace root (do not search parents above it).""" + return (directory / ".git").exists() or (directory / "module-package.yaml").is_file() - ``parents[3]`` only matches one tree shape; walking ancestors finds the policy pack when it lives - next to ``src/`` (development), under ``specfact_code_review/`` (some installs), or at bundle root. + +@beartype +@require(lambda bundle_root, module_file: bundle_root is None or isinstance(bundle_root, Path)) +@require(lambda bundle_root, module_file: module_file is None or isinstance(module_file, Path)) +@ensure(lambda result: isinstance(result, Path), "result must be a Path") +def find_semgrep_config( + *, + bundle_root: Path | None = None, + module_file: Path | None = None, +) -> Path: + """Locate ``.semgrep/clean_code.yaml`` for this package or an explicit bundle root. + + When ``bundle_root`` is set, only ``bundle_root/.semgrep/clean_code.yaml`` is considered. + + Otherwise walk parents of ``module_file`` (default: this module), checking each directory for + ``.semgrep/clean_code.yaml``. Stop ascending when a bundle boundary is hit (``.git`` or + ``module-package.yaml``) so unrelated trees (e.g. a stray ``~/.semgrep``) are never used. """ - here = Path(__file__).resolve() - for parent in [here.parent, *here.parents]: + if bundle_root is not None: + br = bundle_root.resolve() + candidate = br / ".semgrep" / "clean_code.yaml" + if candidate.is_file(): + return candidate + raise FileNotFoundError(f"Semgrep config not found at {candidate} (bundle_root={br})") + + here = (module_file if module_file is not None else Path(__file__)).resolve() + for depth, parent in enumerate([here.parent, *here.parents]): + if depth > _MAX_CONFIG_PARENT_WALK: + break + if parent == parent.parent: + break candidate = parent / ".semgrep" / "clean_code.yaml" if candidate.is_file(): return candidate - raise FileNotFoundError(f"Semgrep config not found (no .semgrep/clean_code.yaml above {here})") + if _is_bundle_boundary(parent): + break + # Installed wheels live under site-packages; do not walk into lib/, $HOME, or other trees. + if parent.name == "site-packages": + break + raise FileNotFoundError(f"Semgrep config not found (no .semgrep/clean_code.yaml under bundle for {here})") -def _run_semgrep_command(files: list[Path]) -> subprocess.CompletedProcess[str]: +def _run_semgrep_command(files: list[Path], *, bundle_root: Path | None) -> subprocess.CompletedProcess[str]: with tempfile.TemporaryDirectory(prefix="semgrep-home-") as temp_home: semgrep_home = Path(temp_home) semgrep_log_dir = semgrep_home / ".semgrep" @@ -104,7 +138,7 @@ def _run_semgrep_command(files: list[Path]) -> subprocess.CompletedProcess[str]: "--disable-version-check", "--quiet", "--config", - str(_resolve_config_path()), + str(find_semgrep_config(bundle_root=bundle_root)), "--json", *(str(file_path) for file_path in files), ], @@ -116,16 +150,22 @@ def _run_semgrep_command(files: list[Path]) -> subprocess.CompletedProcess[str]: ) -def _load_semgrep_results(files: list[Path]) -> list[object]: +def _snip_stderr_tail(stderr: str) -> str: + """Keep the last ``_SEMGREP_STDERR_SNIP_MAX`` chars so the most recent diagnostics stay visible.""" + err_raw = stderr.strip() + if len(err_raw) <= _SEMGREP_STDERR_SNIP_MAX: + return err_raw + return "…" + err_raw[-_SEMGREP_STDERR_SNIP_MAX:] + + +def _load_semgrep_results(files: list[Path], *, bundle_root: Path | None) -> list[object]: last_error: Exception | None = None for _attempt in range(SEMGREP_RETRY_ATTEMPTS): try: - result = _run_semgrep_command(files) + result = _run_semgrep_command(files, bundle_root=bundle_root) raw_out = result.stdout.strip() if not raw_out: - err_tail = (result.stderr or "").strip() - if len(err_tail) > 4000: - err_tail = err_tail[:4000] + "…" + err_tail = _snip_stderr_tail(result.stderr or "") raise ValueError(f"semgrep returned empty stdout (returncode={result.returncode}); stderr={err_tail!r}") return _parse_semgrep_results(json.loads(raw_out)) except (FileNotFoundError, OSError, ValueError, json.JSONDecodeError, subprocess.TimeoutExpired) as exc: @@ -202,13 +242,20 @@ def _finding_from_result(item: dict[str, object], *, allowed_paths: set[str]) -> lambda result: all(isinstance(finding, ReviewFinding) for finding in result), "result must contain ReviewFinding instances", ) -def run_semgrep(files: list[Path]) -> list[ReviewFinding]: - """Run Semgrep for the provided files and map findings into ReviewFinding records.""" +def run_semgrep(files: list[Path], *, bundle_root: Path | None = None) -> list[ReviewFinding]: + """Run Semgrep for the provided files and map findings into ReviewFinding records. + + Args: + files: Paths to scan. + bundle_root: Optional directory that contains ``.semgrep/clean_code.yaml`` (e.g. extracted + bundle root). When omitted, config is resolved from this package upward until a bundle + boundary (``.git`` or ``module-package.yaml``). + """ if not files: return [] try: - raw_results = _load_semgrep_results(files) + raw_results = _load_semgrep_results(files, bundle_root=bundle_root) except (FileNotFoundError, OSError, ValueError, json.JSONDecodeError, subprocess.TimeoutExpired) as exc: return _tool_error(files[0], f"Unable to parse Semgrep output: {exc}") diff --git a/tests/unit/specfact_code_review/run/test_runner.py b/tests/unit/specfact_code_review/run/test_runner.py index 01df32e..2bb18fb 100644 --- a/tests/unit/specfact_code_review/run/test_runner.py +++ b/tests/unit/specfact_code_review/run/test_runner.py @@ -471,15 +471,14 @@ def test_coverage_findings_skips_package_initializers_without_coverage_data() -> assert coverage_by_source == {} -def test_coverage_findings_does_not_skip_non_empty_package_initializers() -> None: +def test_coverage_findings_skips_package_initializers_omitted_from_coverage_reports() -> None: + """``packages/**/__init__.py`` is omitted in coverage config; JSON has no per-file summary.""" source_file = Path("packages/specfact-code-review/src/specfact_code_review/tools/__init__.py") findings, coverage_by_source = _coverage_findings([source_file], {"files": {}}) - assert len(findings) == 1 - assert findings[0].category == "tool_error" - assert "Coverage data missing" in findings[0].message - assert coverage_by_source is None + assert not findings + assert coverage_by_source == {} def test_run_pytest_with_coverage_disables_global_fail_under(monkeypatch: MonkeyPatch) -> None: diff --git a/tests/unit/specfact_code_review/tools/test_semgrep_runner.py b/tests/unit/specfact_code_review/tools/test_semgrep_runner.py index 9a0ef29..93156c2 100644 --- a/tests/unit/specfact_code_review/tools/test_semgrep_runner.py +++ b/tests/unit/specfact_code_review/tools/test_semgrep_runner.py @@ -9,7 +9,7 @@ import pytest from pytest import MonkeyPatch -from specfact_code_review.tools.semgrep_runner import run_semgrep +from specfact_code_review.tools.semgrep_runner import _snip_stderr_tail, find_semgrep_config, run_semgrep from tests.unit.specfact_code_review.tools.helpers import completed_process @@ -177,6 +177,35 @@ def test_run_semgrep_ignores_unsupported_rules(tmp_path: Path, monkeypatch: Monk assert not findings +def test_find_semgrep_config_with_explicit_bundle_root(tmp_path: Path) -> None: + root = tmp_path / "bundle" + (root / ".semgrep").mkdir(parents=True) + (root / ".semgrep" / "clean_code.yaml").write_text("rules: []\n", encoding="utf-8") + assert find_semgrep_config(bundle_root=root) == root / ".semgrep" / "clean_code.yaml" + + +def test_snip_stderr_tail_keeps_last_chars() -> None: + """Long stderr should retain the suffix (most recent diagnostics), not the prefix.""" + long = "UNIQUE_HEAD_MARKER" + ("A" * 5000) + "END_OF_ERROR" + out = _snip_stderr_tail(long) + assert "END_OF_ERROR" in out + assert out.startswith("…") + assert "UNIQUE_HEAD_MARKER" not in out + + +def test_find_semgrep_config_stops_at_git_directory(tmp_path: Path) -> None: + """Do not resolve a config outside the repo (e.g. stray ~/.semgrep).""" + repo = tmp_path / "repo" + (repo / ".git").mkdir(parents=True) + nested = repo / "nested" / "pkg" / "tools" + nested.mkdir(parents=True) + (repo / "nested" / ".semgrep").mkdir(parents=True) + (repo / "nested" / ".semgrep" / "clean_code.yaml").write_text("rules: []\n", encoding="utf-8") + fake_here = nested / "runner.py" + fake_here.write_text("#", encoding="utf-8") + assert find_semgrep_config(module_file=fake_here) == repo / "nested" / ".semgrep" / "clean_code.yaml" + + def test_run_semgrep_retries_after_transient_parse_failure(tmp_path: Path, monkeypatch: MonkeyPatch) -> None: file_path = tmp_path / "target.py" payload = { From 18284eeabe67c6ecf53fba2c07465b2adbd801ed Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 3 Apr 2026 00:55:16 +0000 Subject: [PATCH 4/4] chore(registry): publish changed modules [skip ci] --- registry/index.json | 6 +++--- .../modules/specfact-code-review-0.46.4.tar.gz | Bin 0 -> 31172 bytes .../specfact-code-review-0.46.4.tar.gz.sha256 | 1 + .../specfact-code-review-0.46.4.tar.sig | 1 + 4 files changed, 5 insertions(+), 3 deletions(-) create mode 100644 registry/modules/specfact-code-review-0.46.4.tar.gz create mode 100644 registry/modules/specfact-code-review-0.46.4.tar.gz.sha256 create mode 100644 registry/signatures/specfact-code-review-0.46.4.tar.sig diff --git a/registry/index.json b/registry/index.json index 5816c50..935d33a 100644 --- a/registry/index.json +++ b/registry/index.json @@ -78,9 +78,9 @@ }, { "id": "nold-ai/specfact-code-review", - "latest_version": "0.46.3", - "download_url": "modules/specfact-code-review-0.46.3.tar.gz", - "checksum_sha256": "58f3f9b01a13247b8109f856cb96abfd955e21a70ffafa37ceebf587d402888e", + "latest_version": "0.46.4", + "download_url": "modules/specfact-code-review-0.46.4.tar.gz", + "checksum_sha256": "caecd26d6e6308ed88047385e0a9579c5336665d46e8118c3ae9caf4cbd786c8", "core_compatibility": ">=0.44.0,<1.0.0", "tier": "official", "publisher": { diff --git a/registry/modules/specfact-code-review-0.46.4.tar.gz b/registry/modules/specfact-code-review-0.46.4.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..49d7f376272066661e3b61c41369e43559971bc4 GIT binary patch literal 31172 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
NjfQSP0OL8+$8yeAfcKv# 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 literal 0 HcmV?d00001 diff --git a/registry/modules/specfact-code-review-0.46.4.tar.gz.sha256 b/registry/modules/specfact-code-review-0.46.4.tar.gz.sha256 new file mode 100644 index 0000000..fc9c6fe --- /dev/null +++ b/registry/modules/specfact-code-review-0.46.4.tar.gz.sha256 @@ -0,0 +1 @@ +caecd26d6e6308ed88047385e0a9579c5336665d46e8118c3ae9caf4cbd786c8 diff --git a/registry/signatures/specfact-code-review-0.46.4.tar.sig b/registry/signatures/specfact-code-review-0.46.4.tar.sig new file mode 100644 index 0000000..5d58a76 --- /dev/null +++ b/registry/signatures/specfact-code-review-0.46.4.tar.sig @@ -0,0 +1 @@ +V+GNklTfgmdYKDWgp53SDw4s1R5GE1UF/745CVnXFJ0v3WSCWLY8APqyuabetBU6/Z1UQ1lKfEiRiZOFJw7WBg==