feat: auth/stars API, collections and publish routes, star/author migrations

This commit is contained in:
loki5512344 2026-10-04 12:47:20 +02:00
parent 43cf0e277d
commit 65820d4ef9
Signed by: boba
GPG key ID: 253067914055423B
43 changed files with 2008 additions and 408 deletions

View file

@ -1,6 +1,6 @@
# Философия каталога Indexium — Open Source Only, Zero Storage
# Философия каталога Indexium - Open Source Only, Zero Storage
> **Тезис:** Indexium — не хостинг файлов. Ты даёшь свой GitHub, мы даём индексацию, поиск и доверие. Все моды в каталоге обязаны быть open source.
> **Тезис:** Indexium - не хостинг файлов. Ты даёшь свой GitHub, мы даём индексацию, поиск и доверие. Все моды в каталоге обязаны быть open source.
---
@ -19,22 +19,22 @@
**Почему это круто:**
- Дешёво: VPS $5 + managed Postgres, без S3.
- Честно: автор контролирует файлы, может удалить релиз — он пропадёт и у нас (через webhook `release.deleted`).
- Устойчиво к DMCA: мы — индексатор, а не дистрибьютор (как `crates.io` vs `GitHub`).
- Честно: автор контролирует файлы, может удалить релиз - он пропадёт и у нас (через webhook `release.deleted`).
- Устойчиво к DMCA: мы - индексатор, а не дистрибьютор (как `crates.io` vs `GitHub`).
---
## 2. Open Source Only — честь и правило
## 2. Open Source Only - честь и правило
### Что значит "обязан быть open source"
Мод принимается в каталог только если:
1. **Репозиторий публичный** (`private: false` через GitHub API).
2. **Есть файл лицензии** в корне: `LICENSE` / `COPYING` / `LICENSE.md`. Проверяем через `GET /repos/{owner}/{repo}/license` — поле `license.spdx_id != null` и `license.spdx_id != "NOASSERTION"`.
2. **Есть файл лицензии** в корне: `LICENSE` / `COPYING` / `LICENSE.md`. Проверяем через `GET /repos/{owner}/{repo}/license` - поле `license.spdx_id != null` и `license.spdx_id != "NOASSERTION"`.
3. **Лицензия из allow-list OSI:** `MIT`, `Apache-2.0`, `GPL-2.0`, `GPL-3.0`, `LGPL-2.1`, `LGPL-3.0`, `MPL-2.0`, `BSD-2/3-Clause`, `CC0-1.0`, `Unlicense`, `EUPL-1.2`, `AGPL-3.0`. Список расширяется через ADR.
4. **Исходники соответствуют артефакту** (best-effort): проверяем что в репо есть `fabric.mod.json` / `gradle.properties` с тем же `mod_id`/`version` что и в `.jar`. Полная reproducible-build проверка — в backlog.
5. **Нет обфускации/шифрования** в релизе без исходников: если воркер находит `Runtime.exec` без открытого кода — флаг `suspicious`.
4. **Исходники соответствуют артефакту** (best-effort): проверяем что в репо есть `fabric.mod.json` / `gradle.properties` с тем же `mod_id`/`version` что и в `.jar`. Полная reproducible-build проверка - в backlog.
5. **Нет обфускации/шифрования** в релизе без исходников: если воркер находит `Runtime.exec` без открытого кода - флаг `suspicious`.
> **На MVP** достаточно п.1 + п.2 (любая распознанная лицензия GitHub). Строгий OSI allow-list включаем после первых 100 модов.
@ -43,23 +43,23 @@
```
POST /mods/import { repo: "owner/repo" }
→ GitHub API: GET /repos/{repo} → private? reject 422
→ GET /repos/{repo}/license → null? reject 422 "LICENSE required — open source only"
→ GET /repos/{repo}/license → null? reject 422 "LICENSE required - open source only"
→ GET /repos/{repo}/contents/fabric.mod.json?ref=main → not found? reject
→ Создаём mods + ставим webhook
```
При каждом `release.published` повторно проверяем лицензию — если автор сменил на `NOASSERTION`/сделал приватным → мод помечается `deprecated`, скрывается из поиска, но старые версии доступны (кэш).
При каждом `release.published` повторно проверяем лицензию - если автор сменил на `NOASSERTION`/сделал приватным → мод помечается `deprecated`, скрывается из поиска, но старые версии доступны (кэш).
### Что показываем пользователю
- Бейдж `OSI: MIT` на карточке мода, ссылка на `LICENSE` на GitHub.
- Фильтр `license:MIT` в поиске.
- Страница `/manifesto` — манифест: "Почему только open source" (прозрачность, безопасность, форки, обучение).
- Страница `/manifesto` - манифест: "Почему только open source" (прозрачность, безопасность, форки, обучение).
### Edge cases
- **Форки:** разрешены, но `slug` уникален, показываем `fork_of: owner/repo`. Оригинал помечается `upstream`.
- **Мульти-мод репо (монорепо):** на MVP 1 репо = 1 мод. Позже — поддержка `mods.toml` с несколькими `modId`.
- **Мульти-мод репо (монорепо):** на MVP 1 репо = 1 мод. Позже - поддержка `mods.toml` с несколькими `modId`.
- **Организация vs личный акк:** оба ок, если репо публичное и лицензия есть.
- **Что если автор закрыл репо?** Webhook `repository.privatized` → скрываем мод, чистим кэш, храним метаданные 30 дней для восстановления.
@ -67,7 +67,7 @@ POST /mods/import { repo: "owner/repo" }
## 3. Что это даёт экосистеме
- **Доверие:** любой может `git clone`, проверить код, собрать самому — нет "левый jar с майнером".
- **Доверие:** любой может `git clone`, проверить код, собрать самому - нет "левый jar с майнером".
- **Долговечность:** даже если Indexium умрёт, моды живут на GitHub.
- **Культура:** стимулируем PR'ы, а не "скачал и забыл". Профили показывают контрибьюторов, а не только owner.
@ -77,6 +77,6 @@ POST /mods/import { repo: "owner/repo" }
- Не принимаем бинарники без исходников (даже если автор "обещает" открыть позже).
- Не зеркалируем закрытые репозитории, даже с токеном.
- Не храним `.jar` у себя даже кэшем (кроме 64KB хвоста для парсинга — эфемерно).
- Не храним `.jar` у себя даже кэшем (кроме 64KB хвоста для парсинга - эфемерно).
См. также: `docs/auth-profiles.md` — как профили усиливают open source (контрибьюторы, верификация), `docs/adr/004-open-source-only.md`.
См. также: `docs/auth-profiles.md` - как профили усиливают open source (контрибьюторы, верификация), `docs/adr/004-open-source-only.md`.