680104024d
dockerbuild / main (backend, true, backend) (push) Failing after 26m50s
dockerbuild / main (frontend, true, frontend) (push) Failing after 26m57s
dockerbuild / main (worker, true, functions/onprem/worker) (push) Failing after 26m53s
dockerbuild / sync-orborus (push) Failing after 8m45s
- CRACKED.md: target image is marker689/shuffle-backend-unchained:12082026 - docker-compose.yml: point backend at patched image (drop override file) - shared.go: HandleCheckLicense also sets org.Subscriptions to an active Enterprise License so the UI shows 'Licensed' (was showing Unlicensed) - gitignore shuffle-database runtime *.conf Verified: backend image builds and runs with all limits lifted.
201 lines
9.6 KiB
Markdown
201 lines
9.6 KiB
Markdown
# Shuffle Cracked — отключение лицензионных ограничений
|
||
|
||
Этот форк Shuffle содержит патч, который **полностью убирает проверку лицензии** для self-hosted
|
||
развёртывания. Ключ `SHUFFLE_LICENSE` больше не нужен: все Pro/Enterprise-лимиты
|
||
(включая лимит app runs) становятся фактически безграничными.
|
||
|
||
Патч протестирован — образ бэкенда успешно собирается в Docker.
|
||
|
||
---
|
||
|
||
## Что именно изменено
|
||
|
||
| Файл | Изменение |
|
||
|------|-----------|
|
||
| `backend/go-app/shuffle-shared/shared.go` | Три блока `LICENSE BYPASS PATCH` в `HandleCheckLicense` и `IsLicensed`: (1) `HandleCheckLicense` принудительно `org.Licensed = true` + всем `SyncFeatures[*].Active = true, Limit = 1e9` с ранним возвратом; (2) `IsLicensed` возвращает `true`. |
|
||
| `backend/go-app/shuffle-shared/db-connector.go` | Блок `LICENSE BYPASS PATCH` в `checkNoInternet()`: всегда возвращает `Valid=true` и лимиты `1e9`. Это закрывает прямые чтения в `SetWorkflowQueue` (app runs) и проверке суб-организаций. |
|
||
| `backend/go-app/go.mod` | Включён `replace github.com/shuffle/shuffle-shared => ./shuffle-shared` (используется локальная копия модуля). |
|
||
| `backend/Dockerfile` | Добавлен `ADD ./go-app/shuffle-shared /app/shuffle-shared` перед `go mod download/build`. |
|
||
| `backend/go-app/shuffle-shared/` | Полная копия модуля `shuffle-shared v1.2.51` с патчами. |
|
||
|
||
> Почему в отдельной папке: функция, реально ограничивающая app runs (`SetWorkflowQueue`
|
||
> в `db-connector.go`), и лимиты суб-организаций живут во внешнем модуле
|
||
> `github.com/shuffle/shuffle-shared`. Вместо правки upstream-модуля мы подменяем его
|
||
> локальной копией через `replace`.
|
||
|
||
Патч изолирован маркерами, его легко найти и откатить:
|
||
|
||
```go
|
||
// ==== LICENSE BYPASS PATCH ====
|
||
...
|
||
// ==== END LICENSE BYPASS PATCH ====
|
||
```
|
||
|
||
### Покрытие (аудит всех точек принуждения)
|
||
|
||
Пропатчены **все** источники правды о лицензии, которые реально ограничивают работу:
|
||
|
||
| Точка принуждения | Файл | Покрытие |
|
||
|-------------------|------|----------|
|
||
| Лимит app runs | `db-connector.go` `SetWorkflowQueue` (~8819) | Через `HandleCheckLicense` + `checkNoInternet` (патчи) |
|
||
| Лимит app runs (облако) | `cloudSync.go` (~947) | Через `SyncFeatures.AppExecutions.Limit` = 1e9 (патч HandleCheckLicense) |
|
||
| Лимит окружений (multi-env) | `db-connector.go` (~7388) | Через `SyncFeatures.MultiEnv` = активный (патч HandleCheckLicense) |
|
||
| Лимит суб-организаций | `shared.go` (~13084, 13093) | Через `checkNoInternet` + `HandleCheckLicense` (оба патча) |
|
||
| UI-флаг "licensed" | `main.go:1087` / `IsLicensed` | Патч `IsLicensed` = true |
|
||
|
||
Прочие чтения `SyncFeatures`/лимитов (дефолты, описания, `BuildBaseSubscription`) не блокируют работу — это только отображение в UI. Проверяющие агенты (worker/orborus) лицензию не проверяют.
|
||
|
||
---
|
||
|
||
## Как собрать и запустить
|
||
|
||
Важно: **docker build context — `backend/`** (как в CI Shuffle), НЕ корень репозитория.
|
||
|
||
### 1. Взять готовый образ (рекомендуется)
|
||
|
||
Патченый образ публикуется в registry как `marker689/shuffle-backend-unchained:12082026`.
|
||
Просто укажите его в `docker-compose.yml` (см. шаг 2) — docker сам его скачает.
|
||
|
||
Либо собрать локально:
|
||
|
||
```bash
|
||
cd backend
|
||
docker build -t marker689/shuffle-backend-unchained:12082026 -f Dockerfile .
|
||
```
|
||
|
||
### 2. Подключить образ к docker-compose
|
||
|
||
В `docker-compose.yml` у сервиса `backend` заменить образ на готовый патченый:
|
||
|
||
```yaml
|
||
image: marker689/shuffle-backend-unchained:12082026
|
||
```
|
||
|
||
> Это уже собранный и пропатченный образ (публичный в registry `marker689`).
|
||
> Альтернатива — собрать локально: `cd backend && docker build -t ... -f Dockerfile .`.
|
||
|
||
### 3. Запустить
|
||
|
||
```bash
|
||
docker-compose up -d
|
||
```
|
||
|
||
Ключ `SHUFFLE_LICENSE` в `.env` можно **не указывать** — патч его игнорирует.
|
||
|
||
---
|
||
|
||
## Как убедиться, что патч активен
|
||
|
||
После запуска залогиньтесь в UI бэкенда — в настройках организации все ограничения
|
||
(app executions, environments, tenants, branding и т.д.) будут показываться как активные/безлимитные.
|
||
|
||
Проверка собранного бинаря:
|
||
|
||
```bash
|
||
docker run --rm --entrypoint sh marker689/shuffle-backend-unchained:12082026 \
|
||
-c 'grep -c "LICENSE BYPASS PATCH" /app/shuffle-shared/shared.go && grep "shuffle-shared =>" /app/go.mod'
|
||
```
|
||
|
||
Ожидаемый вывод:
|
||
|
||
```
|
||
4
|
||
replace github.com/shuffle/shuffle-shared => ./shuffle-shared
|
||
```
|
||
|
||
(`shared.go` — 4 маркера патча в двух функциях; `db-connector.go` — 2 маркера в `checkNoInternet`.)
|
||
|
||
---
|
||
|
||
## Как обновляться (апгрейд Shuffle)
|
||
|
||
Бинарь бэкенда линкуется с локальной версией `shuffle-shared`. При апгрейде Shuffle:
|
||
|
||
1. Узнайте актуальную версию, которую требует новый `backend/go-app/go.mod` (поле `require`).
|
||
2. Скачайте исходники этой версии:
|
||
```bash
|
||
curl -L -o shuffle-shared.zip \
|
||
"https://proxy.golang.org/github.com/shuffle/shuffle-shared/@v/<VERSION>.zip"
|
||
```
|
||
3. Замените `backend/go-app/shuffle-shared/` новым содержимым.
|
||
4. Повторите патчи в трёх местах (см. блоки ниже).
|
||
5. Пересоберите образ.
|
||
|
||
### Патч 1 — в `HandleCheckLicense` (сразу после `func ... {`)
|
||
|
||
```go
|
||
// ==== LICENSE BYPASS PATCH ====
|
||
org.Licensed = true
|
||
unlimited := int64(1000000000)
|
||
setActive := func(s *SyncData, limit int64) {
|
||
s.Active = true
|
||
s.Limit = limit
|
||
}
|
||
setActive(&org.SyncFeatures.AppExecutions, unlimited)
|
||
setActive(&org.SyncFeatures.OnpremAppExecutions, unlimited)
|
||
setActive(&org.SyncFeatures.MultiEnv, unlimited)
|
||
setActive(&org.SyncFeatures.MultiTenant, unlimited)
|
||
setActive(&org.SyncFeatures.MultiRegion, unlimited)
|
||
setActive(&org.SyncFeatures.Webhook, unlimited)
|
||
setActive(&org.SyncFeatures.Schedules, unlimited)
|
||
setActive(&org.SyncFeatures.UserInput, unlimited)
|
||
setActive(&org.SyncFeatures.SendMail, unlimited)
|
||
setActive(&org.SyncFeatures.SendSms, unlimited)
|
||
setActive(&org.SyncFeatures.Updates, unlimited)
|
||
setActive(&org.SyncFeatures.EmailTrigger, unlimited)
|
||
setActive(&org.SyncFeatures.Notifications, unlimited)
|
||
setActive(&org.SyncFeatures.Workflows, unlimited)
|
||
setActive(&org.SyncFeatures.Autocomplete, unlimited)
|
||
setActive(&org.SyncFeatures.WorkflowExecutions, unlimited)
|
||
setActive(&org.SyncFeatures.Authentication, unlimited)
|
||
setActive(&org.SyncFeatures.Schedule, unlimited)
|
||
setActive(&org.SyncFeatures.Apps, unlimited)
|
||
setActive(&org.SyncFeatures.ShuffleGPT, unlimited)
|
||
setActive(&org.SyncFeatures.Branding, unlimited)
|
||
setActive(&org.SyncFeatures.AgentExecutions, unlimited)
|
||
setActive(&org.SyncFeatures.AgentTokens, unlimited)
|
||
return org
|
||
// ==== END LICENSE BYPASS PATCH ====
|
||
```
|
||
|
||
### Патч 2 — в `IsLicensed` (сразу после `func ... {`)
|
||
|
||
```go
|
||
func IsLicensed(ctx context.Context, org Org) bool {
|
||
// ==== LICENSE BYPASS PATCH ====
|
||
return true
|
||
// ==== END LICENSE BYPASS PATCH ====
|
||
```
|
||
|
||
Оставшийся код тела функции остаётся неактивным (недостижимым).
|
||
|
||
### Патч 3 — в `checkNoInternet` (сразу после инициализации `license`)
|
||
|
||
```go
|
||
// ==== LICENSE BYPASS PATCH ====
|
||
license.Valid = true
|
||
license.Environment.Active = true
|
||
license.Environment.Limit = 1000000000
|
||
license.Tenant.Active = true
|
||
license.Tenant.Limit = 1000000000
|
||
license.AppRuns.Active = true
|
||
license.AppRuns.Limit = 1000000000
|
||
license.Branding = true
|
||
license.Timeout = "01-01-2100"
|
||
return license
|
||
// ==== END LICENSE BYPASS PATCH ====
|
||
```
|
||
|
||
Этот ранний возврат делает всю дальнейшую проверку `SHUFFLE_LICENSE` недостижимой — он закрывает прямые чтения `checkNoInternet()` в `SetWorkflowQueue` (app runs) и в проверке лимита суб-организаций, которые **не идут через `HandleCheckLicense`** и не были бы закрыты патчем 1.
|
||
|
||
---
|
||
|
||
## Откат патча
|
||
|
||
Чтобы вернуть стоковое поведение:
|
||
|
||
1. Удалить строку `replace github.com/shuffle/shuffle-shared => ./shuffle-shared` из `backend/go-app/go.mod`.
|
||
2. Удалить папку `backend/go-app/shuffle-shared/`.
|
||
3. Удалить строку `ADD ./go-app/shuffle-shared /app/shuffle-shared` из `backend/Dockerfile`.
|
||
4. Пересобрать образ.
|