Як перевірити репозиторій з LinkedIn, перш ніж збирати його у себе

7 хв читання

У 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 і список перевірок, які я тепер роблю з кожним репо з ленти.

8комітів за 5 днів, 2026-10-18…22
88 КБзашифрованого коду, який компілюється при cargo build
0місць, де запускаються CUDA-ядра з README
7чисел «OpenCV 5.0», записаних у бенчмарк константами

Чому збірка чужого репо — це вже запуск його коду?

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!, тобто вставляють у свій код дослівно:

~/code/solidcv
$ 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
solidcv · що відбувається при cargo build
cargo buildтвої права build.rsXOR-потік, ключ SOLIDSF! moat_vault.bin88 КБ, не читається очима OUT_DIR/vault_*.rs3 модулі, 2363 рядки include!у три модулі бібліотеки твій бінарник cloud_ws · solidcv_fxTcpStream → api.solidsf.com лише якщо викликати
Червоне виконується при кожній збірці, ще до твого коду. Фіолетове відкриває мережу тільки на явний виклик.

Шифрований файл у збірці ще не доводить злого наміру. Але grep по репозиторію його вміст не бачить, і читач на GitHub теж. Файл з’явився в першому ж коміті (тоді 71 КБ) і ріс разом із проєктом.

Що всередині зашифрованого файлу solidcv?

Звичайний Rust без мережі, без запуску процесів і без читання файлів. Щоб це побачити, я повторив розшифровку окремим Python-скриптом у тимчасовій теці, без cargo. Алгоритм лежить відкрито в тому ж build.rs: ключ із восьми байтів SOLIDSF!, хеш у стилі splitmix64 від номера байта, XOR кожного байта, далі заголовок SSFVLT01 і список «ім’я файлу, вміст». Python запускав з -I, щоб він не підвантажив нічого з поточної теки:

тимчасова тека · python3 -I tools/unvault.py
$ 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-блоки. Перші рядки першого файлу містять оголошення (адресу автора я прибрав):

vault/realitycomb.rs · рядки 2–6
 *  [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 не викликає і друкує сім готових чисел:

~/code/solidcv
$ 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. У коді ці ядра лежать текстовою константою, яку ніхто не завантажує на відеокарту. Єдине місце, де її читають, рахує кількість входів у тексті для звіту:

~/code/solidcv
$ 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:

розбір 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можна збирати

Те саме списком для наступного репо з ленти:

  1. Повна історія. Клонувати без --depth 1 або зробити git fetch --unshallow: неглибокий клон завжди показує один коміт, і я на цьому сам спіткнувся. Далі git log --format='%h %ad %an' --date=short.
  2. Що виконується при встановленні. Rust: build.rs і build-dependencies. npm: preinstall, install, postinstall у package.json, своєму і залежностей. Python: setup.py і хуки збірки в pyproject. Прочитати повністю.
  3. Бінарні файли. git ls-files | xargs file | grep -v text. Усе, що не картинка і не шрифт, але читається збіркою, має мати пояснення.
  4. Вставка згенерованого коду. include!, eval, exec, importlib, new Function, довгі base64-рядки.
  5. Мережа, процеси, секрети. grep -rnE 'TcpStream|reqwest|fetch\(|requests\.|subprocess|Command::new|child_process|\.ssh|\.aws'. Кожне попадання має відповідати функції, яку ти справді викличеш.
  6. Головна заява з поста. Знайти її в коді. «GPU»: де запуск ядра? «У N разів»: що заміряли, проти чого, і чи це той самий рядок таблиці.
  7. Перша збірка в контейнері або VM без твоїх ключів і токенів.

Claude Code на запит «склонуй і перевір, що там» сам зупинився на build.rs і розшифрував файл окремо, перш ніж іти далі. Наступного разу, коли в ленті буде «575× швидше», починай з cat build.rs.

AI-харнеси й агентиLLM-моделі