Як перевірити репозиторій з LinkedIn, перш ніж збирати його у себе
У LinkedIn трапився пост: «2.11× faster than OpenCV. 575.4× faster feature matching. 96.9% fewer vision tokens». 194 лайки, 16 коментарів і посилання на solidcv: «чиста Rust-заміна OpenCV з ядрами для Apple Silicon і NVIDIA Grace-Blackwell». У мене є Jetson Nano, тому я склонував репо і попросив Claude Code глянути, що воно вміє. Збирати я його не став. Першим знайшовся build.rs, який під час cargo build розшифровує 88 КБ коду і вкомпільовує його в бібліотеку. Цей код запустився б з моїми правами раніше, ніж я викликав би хоч одну функцію.
Нижче розбір solidcv на коміті 35c33e3 від 2026-10-22 і список перевірок, які я тепер роблю з кожним репо з ленти.
Чому збірка чужого репо — це вже запуск його коду?
cargo build спершу компілює і виконує build.rs автора, з твоїми правами і без пісочниці. У npm так само працюють preinstall і postinstall, у Python setup.py і хуки збірки. Такий скрипт може прочитати ~/.ssh, токени з ~/.config і відправити їх куди завгодно.
У src solidcv 26 407 рядків Rust, і все це з’явилося за п’ять днів. README радить перевірити множники командою cargo run --release --example full_suite_benchmark. Цей виклик першим виконує build.rs.
Що робить build.rs у solidcv?
Він читає assets/solidcv_moat_vault.bin, XOR-ить його з потоком байтів, отриманим із ключа SOLIDSF!, і розкладає результат на .rs-файли в OUT_DIR, тимчасову теку збірки. Три модулі бібліотеки підключають ці файли через include!, тобто вставляють у свій код дослівно:
$ grep -rn 'include!(concat!(env!("OUT_DIR")' src src/voxelean.rs:8:include!(concat!(env!("OUT_DIR"), "/vault_voxelean.rs")); src/worldtube.rs:8:include!(concat!(env!("OUT_DIR"), "/vault_worldtube.rs")); src/realitycomb.rs:8:include!(concat!(env!("OUT_DIR"), "/vault_realitycomb.rs")); $ xxd -l 32 assets/solidcv_moat_vault.bin 00000000: 7361 a006 64fa aed8 0436 1e93 8f7a 7289 sa..d....6...zr. 00000010: 4b52 8dfe fd1c 54b3 7c5f 1704 926f c450 KR....T.|_...o.P
Шифрований файл у збірці ще не доводить злого наміру. Але grep по репозиторію його вміст не бачить, і читач на GitHub теж. Файл з’явився в першому ж коміті (тоді 71 КБ) і ріс разом із проєктом.
Що всередині зашифрованого файлу solidcv?
Звичайний Rust без мережі, без запуску процесів і без читання файлів. Щоб це побачити, я повторив розшифровку окремим Python-скриптом у тимчасовій теці, без cargo. Алгоритм лежить відкрито в тому ж build.rs: ключ із восьми байтів SOLIDSF!, хеш у стилі splitmix64 від номера байта, XOR кожного байта, далі заголовок SSFVLT01 і список «ім’я файлу, вміст». Python запускав з -I, щоб він не підвантажив нічого з поточної теки:
$ python3 -I tools/unvault.py ~/code/solidcv/assets/solidcv_moat_vault.bin vault magic: b'SSFVLT01' realitycomb.rs 41338 байт voxelean.rs 27715 байт worldtube.rs 19016 байт $ grep -cE "std::net|std::process|TcpStream|Command" vault/*.rs vault/voxelean.rs:0 vault/realitycomb.rs:0 vault/worldtube.rs:0
Усередині 2363 рядки: октодерева, оптичний потік, три unsafe-блоки. Перші рядки першого файлу містять оголошення (адресу автора я прибрав):
* [solidSF CLASSIFIED KERNEL VAULT - REVERSE-ENGINEER BOUNTY] * Proprietary Engines: GB300 PTX | RealityComber | Voxelean | Worldtube * ---------------------------------------------------------------------------- * If you reversed the Zobrist-Feistel stream cipher to unpack this vault: * please email ... because Andy Norris wants to fly you to SF
Шифрування тут працює як маркетинговий квест: ключ лежить у відкритому build.rs. Трояна в solidcv я не знайшов ні у зашифрованому файлі, ні в src. Приклади і застосунок solidcv-app запускають ffmpeg, а приклади ще й читають свої кадри з $HOME. Це відповідає їхньому призначенню. Але той самий механізм доставки в чужому репо може нести що завгодно, і перевіряється він так само.
Звідки в solidcv цифри «у N разів швидше за OpenCV»?
Час solidcv бенчмарк заміряє, а колонку OpenCV автор вписав константами. Збирати бібліотеку безпечно, але пост продає саме ці множники. Приклад full_suite_benchmark OpenCV не викликає і друкує сім готових чисел:
$ grep -nE "opencv5?_s[0-9]+_us *=" examples/full_suite_benchmark.rs
137: let opencv5_s1_us = 35.67;
176: let opencv5_s2_us = 50.13;
215: let opencv5_s3_us = 549.10;
245: let opencv5_s4_us = 10_445.90;
281: let opencv5_s5_us = 4_605.06;
504: let opencv5_s8_us = 3_710.83;
720: let opencv_s13_us = 323.41;README це визнає в розділі FAQ: автор не хотів тягнути C++ OpenCV у залежності й записав свої заміри числами. У цитаті з LinkedIn цього застереження вже немає. А «575.4× faster feature matching» у README стосується іншого рядка таблиці. 575.35× має пошук по словнику SAE (16 запитів, 4096 атомів) у порівнянні з множенням матриць FP32. Feature matching, ORB BFMatcher проти OpenCV, у тій самій таблиці має 5.53×.
Чи рахує solidcv на NVIDIA Tensor Core?
Ні, на NVIDIA бібліотека рахує тільки процесором. README обіцяє ядра PTX (асемблер для GPU NVIDIA) для Grace-Blackwell GB300. У коді ці ядра лежать текстовою константою, яку ніхто не завантажує на відеокарту. Єдине місце, де її читають, рахує кількість входів у тексті для звіту:
$ grep -rn 'CUDA_PTX_KERNEL_SOURCE' src | grep -v '//!' src/hardware.rs:1109:pub const CUDA_PTX_KERNEL_SOURCE: &str = r#" src/hardware.rs:3377: let ptx_kernels_ready = CUDA_PTX_KERNEL_SOURCE.matches(".visible .entry").count(); $ grep -rnE 'cuLaunch|cuModuleLoad|#\[link' src src/hardware.rs:1139:#[link(name = "Metal", kind = "framework")] src/hardware.rs:1140:#[link(name = "Foundation", kind = "framework")] src/hardware.rs:1141:#[link(name = "objc")]
Лінкується тільки Metal на macOS. Виклику CUDA-драйвера (cuLaunch, cuModuleLoad) у коді немає.
пост і README
Ядра Tensor Core для GB300. 575× на feature matching. Заміряно проти OpenCV 5.0.
код
PTX лежить рядком, з GPU тільки Metal. 575× отримав SAE, matching дає 5.53×. OpenCV представлено сімома константами.
Чи запуститься solidcv на Jetson Nano?
На процесорі, найімовірніше, так. NEON-код (SIMD-інструкції ARM) в imgproc, calib3d і uplift прив’язаний лише до архітектури aarch64, і процесор Нано її має. Прискорення з hardware.rs увімкнені тільки на macOS та iOS. GPU Нано бібліотека не використає. Rust краще ставити через rustup. Це висновок з коду: на залозі я не перевіряв, і на Маку, де розбирав репо, cargo build теж не запускав.
Що перевірити в чужому репо, перш ніж його збирати?
Ось порядок, яким Claude Code пройшов solidcv:
clonegitу ~/code, нічого не збираємо
lsrepobuild.rs, assets/*.bin, Cargo.toml
loggit8 комітів, 26 407 рядків у src, 5 днів
readbuild.rsрозшифровує vault.bin у OUT_DIR
grepsrcinclude! з OUT_DIR у 3 модулях
decryptpython -Iокрема тека, без cargo
grepvault0 net · 0 process · 0 Command
grepsrcTcpStream лише в cloud_ws і solidcv_fx
grepsrcPTX лежить рядком, cuLaunch відсутній
okbuildможна збирати
Те саме списком для наступного репо з ленти:
- Повна історія. Клонувати без
--depth 1або зробитиgit fetch --unshallow: неглибокий клон завжди показує один коміт, і я на цьому сам спіткнувся. Даліgit log --format='%h %ad %an' --date=short. - Що виконується при встановленні. Rust:
build.rsіbuild-dependencies. npm:preinstall,install,postinstallу package.json, своєму і залежностей. Python:setup.pyі хуки збірки в pyproject. Прочитати повністю. - Бінарні файли.
git ls-files | xargs file | grep -v text. Усе, що не картинка і не шрифт, але читається збіркою, має мати пояснення. - Вставка згенерованого коду.
include!,eval,exec,importlib,new Function, довгі base64-рядки. - Мережа, процеси, секрети.
grep -rnE 'TcpStream|reqwest|fetch\(|requests\.|subprocess|Command::new|child_process|\.ssh|\.aws'. Кожне попадання має відповідати функції, яку ти справді викличеш. - Головна заява з поста. Знайти її в коді. «GPU»: де запуск ядра? «У N разів»: що заміряли, проти чого, і чи це той самий рядок таблиці.
- Перша збірка в контейнері або VM без твоїх ключів і токенів.
Claude Code на запит «склонуй і перевір, що там» сам зупинився на build.rs і розшифрував файл окремо, перш ніж іти далі. Наступного разу, коли в ленті буде «575× швидше», починай з cat build.rs.