Family gate built + licence read: evidence (9202, bench, floor), licence table + SparkyFitness request draft (not sent), 01 §5 family gate, 09 decision 64 built, capability map, register 422 -> 436 (R-767/R-780/R-787 closed; R-775/R-784 updated; R-788..R-801 opened), CONTEXT
gates / gates (push) Successful in 28s
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
@@ -16,6 +16,14 @@
|
||||
> and holds nothing of its own; this file does hold its own content, namely the standing rulings below.
|
||||
|
||||
|
||||
> **2026-10-02 — the family gate BUILT (R-780 CLOSED), controller v0.287.0 floored, golden 0.287.0 vouched; Grimmory and
|
||||
> MeTube published behind it (R-767 CLOSED, R-775 narrowed).** `internal/family` + `stacks/family_gate.go` +
|
||||
> `web/family_gate.go`; template fields `family_gate` / `family_gate_except` (literal, anchored `^/p(/|$)`) /
|
||||
> `min_controller`; catalog gate `check-family-gate.py` (refuses a family app while the newest baked golden < 0.287.0 —
|
||||
> why this golden was baked off-cadence). `01` §5 carries the design paragraph. Licence read of all 58 templates
|
||||
> (R-787 CLOSED): `documentation/audits/licences-2026-10-02/TABLE.md`; operator rows R-789..R-795; SparkyFitness request
|
||||
> drafted, not sent (R-784, decision 65). Register 422 → 435. Report: `REPORT-family-gate-2026-10-02.md`.
|
||||
|
||||
> **Rulings 2026-10-02 (morning, operator) — `09` §3 decisions 64, 65, recorded before the work.** **64 (R-780):** the
|
||||
> family gate — GO, both sessions. **65 (R-784 B):** SparkyFitness stays offered; the operator asks the author; no written
|
||||
> permission before the first paying customer → `lifecycle: hidden`. The licence read (R-787) runs this session.
|
||||
|
||||
@@ -192,7 +192,7 @@ likewise silent. Evidence: `audits/DRILL-r361-2026-08-22/evidence/06-part3-decis
|
||||
| Forgot dashboard password → instant reset code | controller v0.123, hub | **PROVEN-LIVE** | `DRILL-day0-take2-2026-07-12` F-15 (live re-run of the exact failure path: hash applied 1s after request, code accepted first try) | |
|
||||
| **The dashboard in English** — the household picks its language; Hungarian unchanged | controller v0.247.0 (spike) → v0.250.0 (slice 1, R-556 CLOSED) | **PARTIAL — PROVEN-LIVE for every dashboard template** (all 36 templates carry their copy in the bundles; the switch is on every dashboard page) | `audits/i18n-slice1-2026-09-17/C/live/` (and `A/`, `B/`, `audits/i18n-2026-09-17/live/`) — on demo-hp 0.250.0 each Hungarian page equals its 0.249.0 fetch once the new switch form is removed (live numbers aside; login, claim, catch-all byte-identical); `POST /settings/language` made every page English and back; the hub stored `hu`, `en`, `hu` (16:45:10Z, 16:46:06Z, 16:46:43Z). Unit: `TestI18nParity` (106 states vs fixtures from unconverted templates), `TestI18nParityCoversEveryMarker`, `TestI18nEnglishPages`, `TestDirectRenderHandlersFollowLanguage`, all red-proofed. Design `architecture/10-localisation.md` | Go-side messages and three app-name page titles (R-557 after R-553, R-566), hub e-mails (R-558), console/download page (R-559), catalog copy (R-560), guide + English stranger drill (R-561); ASCII-only Hungarian invisible to the English page test (R-565). **Hungarian households see the switch only once the fleet floor reaches 0.250.0** |
|
||||
| **The box tells visitors apart — a stranger's wrong passwords lock only the stranger** (dashboard, setup gate, apps that read the visitor from the right) | controller v0.286.1 (`felhom-tunnel`, traefik trust of cloudflared only, `clientaddr.go`), catalog router resets | **PARTIAL** | `audits/visitors-2026-10-01/A/L2-demo-hp-real-tunnel.txt` (real tunnel: the dashboard counter keyed on the visitor `37.191.56.193`, locked after 5 while forging a new X-Forwarded-For each try); `A/L1-9202-live.txt` (simulated tunnel: the household from another address in at once); `A/bookstack-3.6.txt` | The second OUTSIDE address on the real tunnel was refused by Cloudflare before the box → R-779; right-walking app settings → R-776; Emby/Jellyfin LAN rights → R-777 |
|
||||
| A permanent household gate with family accounts in front of an app (Grimmory, MeTube) | spike only | **MISSING** (spiked, passed) | `audits/permanent-gate-2026-10-01/VERDICT.md` | → R-780 (operator go/no-go) |
|
||||
| **The family gate — a permanent door with each family member's own login in front of an app** (Grimmory with its e-reader exceptions, MeTube with none) | controller v0.287.0 (`internal/family`, `stacks/family_gate.go`, the Család card), catalog `family_gate:` + `check-family-gate.py`, golden 0.287.0 | **PROVEN** on 9202 through the product: a stranger reached nothing (36 requests, LAN + simulated tunnel), members with their own logins, reset/remove/logout end access at the next request, a stranger's guesses lock only the stranger, each exception keeps the app's own login and a look-alike stays gated, the controller down → error never the app; survives an update and a remove + restore. Demo boxes on 0.287.0. Not yet: a household's phone through the real internet. | `audits/family-gate-2026-10-02/A/items.txt`, `B/box/` | R-780 closed; R-775 (narrowed), R-796, R-797 |
|
||||
| Multiple household users / per-person accounts | — | **MISSING** | — | Single dashboard password; acceptable for alpha → R-15 |
|
||||
| WireGuard base infra always-on; OOB operator access (felhom-sshd, /32 peer) | agent v0.72, hub v0.35 | **IMPLEMENTED** | `SPIKE-oob-wg-operator-peer-2026-07-05`, `SPIKE-felhom-sshd-2026-07-05` | Mutual-repair desired-state arc not built → R-13. **CHECKED 2026-08-08 (R-260) and this row was NOT claiming something untrue** — it claims the capability is implemented, never that it is monitored, so no correction was owed. What WAS untrue is narrower and sat one layer down: **the hub's own OOB health check could not see whether the operator's key was installed.** `HostOOBRow` mirrored five of the agent's eight OOB fields, so `operator_key_configured` — emitted every heartbeat since agent v0.72.0, i.e. from this row's own vintage — was discarded by `encoding/json` on arrival, and `oobDegraded` returned `ok` for a box with felhom-sshd active, reachable, a valid config, a configured peer and **no operator key at all**. `operator_peer_configured`, which it did read, only says the peer IP is in desired-state — that OOB is MEANT to work, not that entry is possible. Fixed hub v0.99.0; the missing key now degrades and the alert NAMES it; a stanza too old to carry the field is reported distinctly and is never a silent ok. Pinned end-to-end from raw report JSON by `TestHostOOB_MissingOperatorKey_EndToEnd` and `TestHostOOB_NoKeyField_IsNotSilentlyOK_EndToEnd` |
|
||||
| The operator can see WHERE a managed host is — its LAN address and its WireGuard address, on the host page | agent **v0.119.0**, hub **v0.85.0** | **PROVEN-LIVE** (2026-07-31) | `audits/host-addresses-visible-2026-07-31.md` | Before this the LAN IP was **not reportable at all** — `HostMetrics` carried no address of any kind — and the WG IP existed only in `/offsite`'s peer table keyed by pubkey (peer→host, never host→peer). New wire field `addresses[]`, one row per (interface, address); `IsGlobalUnicast()` is the whole filter, chosen by MEASURING both demo boxes, and it needs no veth/fwbr denylist because that plumbing carries no IP. Rendered live on both 0.119.0 hosts matching their `ip addr` ground truth exactly. **Two honesty properties carry the risk and are both red-proofed:** WireGuard shows the hub ALLOCATION and whether the box CONFIRMS holding it (allocation alone cannot tell a live tunnel from a peer never applied), and an agent below 0.119.0 renders **UNKNOWN, never "no addresses"** — proven live on `drill-r50-0a4f9a` (0.113.0). **Not covered:** a two-LAN-bridge box and a real WG drift, neither of which exists to observe |
|
||||
|
||||
@@ -136,8 +136,8 @@ the visitor from the RIGHT.** The controller (`clientaddr.go`) believes the chai
|
||||
traefik saw, and for the tunnel's hop reads `CF-Connecting-IP` (the edge refuses a client-sent one). Catalog apps that
|
||||
read the LEFTMOST entry have the chain removed on their router. Design and measurements:
|
||||
`audits/visitors-2026-10-01/A/DESIGN.md`. A permanent household gate with family accounts in front of an app (Grimmory,
|
||||
MeTube) was SPIKED on this base and passed (`audits/permanent-gate-2026-10-01/VERDICT.md`); it is not built — the
|
||||
operator decides.
|
||||
MeTube) was SPIKED on this base and passed (`audits/permanent-gate-2026-10-01/VERDICT.md`) and is BUILT since
|
||||
controller 0.287.0 (`09` §3 decision 64) — the family gate, at the end of this section.
|
||||
|
||||
**Who may reach an app, and through what (recorded 2026-09-29 — no document said it before; spike finding F1).**
|
||||
Every app is reached only through the box's traefik (no catalog app publishes a host port except crafty-controller's
|
||||
@@ -159,6 +159,22 @@ Since controller 0.282.0 there are two locks where the app has its own switch: t
|
||||
decision 47 gets both only when the household presses "Close sign-up now" (decision 49); wanderer, which is not gated,
|
||||
the same way.
|
||||
|
||||
**The family gate (`09` §3 decisions 63/64, controller ≥ 0.287.0).** An app whose template says `family_gate: true` is
|
||||
PERMANENTLY behind a forwardAuth door, the setup gate's mechanism with three differences: it never opens; its priority is
|
||||
below the install hold, the setup gate and the sign-up block; and the cookie it accepts is a FAMILY cookie. Each family
|
||||
member has their own name and password (the dashboard's Biztonság → Család card adds, resets and removes them; the
|
||||
password is shown once, stored as a bcrypt hash in the controller's data). A member signs in on the dashboard host's
|
||||
`/__family/login`; that sets a family session cookie on `Path=/__family` only — **never accepted by the dashboard's own
|
||||
RequireAuth** — and each app host gets a host-only cookie through a 60-second one-use token, as the setup gate does. The
|
||||
session store is asked on EVERY request, so a reset, a removal or a logout ends access at the next request. The family
|
||||
sign-in locks per real visitor (5 a minute) and per name (10 in 10 minutes) — never "everyone" (it reads the visitor
|
||||
from the right, as above). `family_gate_except:` lists LITERAL path prefixes a phone or e-reader app calls (Grimmory's
|
||||
OPDS, Kobo, KOReader, Komga API); each becomes a router without the door, anchored at a segment boundary
|
||||
(`^/prefix(/|$)`), so the app's OWN login decides there and a look-alike (`/api/v1/opdsx`) stays behind the gate. The
|
||||
gate is recorded at install (and at a removed app's restore), so a catalog change never gates or un-gates an installed
|
||||
app. Controller down → the gated app answers an error, never the app. Measured on 9202:
|
||||
`audits/family-gate-2026-10-02/A/items.txt`.
|
||||
|
||||
---
|
||||
|
||||
## 6. Enrollment & identity
|
||||
|
||||
@@ -693,7 +693,9 @@ its length, and both fixes cost something the household would notice — operato
|
||||
sessions (controller, then catalog: Grimmory and MeTube published behind it) — *operator ruling 2026-10-02 (R-780).*
|
||||
The family login never opens the dashboard; every exception is anchored (finding F1) and still needs the app's own
|
||||
login. **Why:** the spike passed every exit item; one gate the box already runs answers Grimmory's lock (R-775) and
|
||||
MeTube's "no login at all" (R-767) at once.
|
||||
MeTube's "no login at all" (R-767) at once. **Built 2026-10-02:** controller v0.287.0 (floored, golden 0.287.0),
|
||||
catalog fields `family_gate` / `family_gate_except` / `min_controller` and gate `check-family-gate.py`; Grimmory and
|
||||
MeTube published — `audits/family-gate-2026-10-02/`.
|
||||
65. **SparkyFitness stays offered (R-784, option B); the operator asks its author for written permission now; if there is
|
||||
no written permission before the first paying customer, it is hidden** (`lifecycle: hidden`) — *operator ruling
|
||||
2026-10-02.* **Why, recorded:** the operator's model is that Felhom sells installation and care, not software; that
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
## RP-F1 RequireAuth accepts a valid FAMILY session (2026-10-02T05:32:27Z) — TestFamilyGate_MemberPassesButNeverTheDashboard
|
||||
=== RUN TestFamilyGate_MemberPassesButNeverTheDashboard
|
||||
family_gate_test.go:188: a family cookie opened the dashboard at /launcher
|
||||
--- FAIL: TestFamilyGate_MemberPassesButNeverTheDashboard (0.11s)
|
||||
FAIL
|
||||
FAIL gitea.dooplex.hu/admin/felhom-controller/internal/web 0.125s
|
||||
FAIL
|
||||
|
||||
## RP-F2 exceptions not anchored (plain prefix) (2026-10-02T05:32:30Z) — TestFamilyExceptRegexp_Anchored
|
||||
=== RUN TestFamilyExceptRegexp_Anchored
|
||||
family_gate_test.go:33: "/api/v1/opdsx": match=true want false (regexp ^/api/v1/opds)
|
||||
family_gate_test.go:33: "/api/v1/opds-evil": match=true want false (regexp ^/api/v1/opds)
|
||||
family_gate_test.go:33: "/api/v1/opds.json": match=true want false (regexp ^/api/v1/opds)
|
||||
family_gate_test.go:37: a trailing slash is the same prefix: ^/api/kobo
|
||||
--- FAIL: TestFamilyExceptRegexp_Anchored (0.00s)
|
||||
FAIL
|
||||
FAIL gitea.dooplex.hu/admin/felhom-controller/internal/stacks 0.008s
|
||||
|
||||
## RP-F3 the app cookie is trusted on its MAC alone (the store is not asked) (2026-10-02T05:32:35Z) — TestFamilyGate_ResetRemoveLogoutEndAccessAtOnce
|
||||
=== RUN TestFamilyGate_ResetRemoveLogoutEndAccessAtOnce
|
||||
family_gate_test.go:212: a reset password must end the member's app access at once
|
||||
--- FAIL: TestFamilyGate_ResetRemoveLogoutEndAccessAtOnce (0.12s)
|
||||
FAIL
|
||||
FAIL gitea.dooplex.hu/admin/felhom-controller/internal/web 0.129s
|
||||
FAIL
|
||||
|
||||
## RP-F4 the sign-in counted by NAME only (no visitor counter) (2026-10-02T05:32:40Z) — TestFamilyGate_LockPerVisitorAndPerName
|
||||
=== RUN TestFamilyGate_LockPerVisitorAndPerName
|
||||
family_gate_test.go:242: the stranger's own address must be locked even with the right password: 200
|
||||
--- FAIL: TestFamilyGate_LockPerVisitorAndPerName (0.12s)
|
||||
FAIL
|
||||
FAIL gitea.dooplex.hu/admin/felhom-controller/internal/web 0.130s
|
||||
FAIL
|
||||
|
||||
## RP-F5 one global counter for every visitor (the pre-R-753 'everyone' shape) (2026-10-02T05:32:45Z) — TestFamilyGate_LockPerVisitorAndPerName
|
||||
=== RUN TestFamilyGate_LockPerVisitorAndPerName
|
||||
family_gate_test.go:245: anna from her own address must get in at once: 429
|
||||
--- FAIL: TestFamilyGate_LockPerVisitorAndPerName (0.07s)
|
||||
FAIL
|
||||
FAIL gitea.dooplex.hu/admin/felhom-controller/internal/web 0.079s
|
||||
FAIL
|
||||
|
||||
## RP-F6 the install does not write the family door (2026-10-02T05:32:48Z) — TestFamilyGate_WrittenBeforeTheFirstStart
|
||||
=== RUN TestFamilyGate_WrittenBeforeTheFirstStart
|
||||
family_gate_test.go:72: the family-gate file did not exist when the app was first started — it was published open
|
||||
--- FAIL: TestFamilyGate_WrittenBeforeTheFirstStart (0.01s)
|
||||
FAIL
|
||||
FAIL gitea.dooplex.hu/admin/felhom-controller/internal/stacks 0.018s
|
||||
FAIL
|
||||
|
||||
## RP-F7 a removed family app's restore gets no door (2026-10-02T05:32:52Z) — TestFamilyGate_RestoreOfARemovedAppAndTheLoop
|
||||
=== RUN TestFamilyGate_RestoreOfARemovedAppAndTheLoop
|
||||
family_gate_test.go:135: the restore of a removed family app must record its door
|
||||
--- FAIL: TestFamilyGate_RestoreOfARemovedAppAndTheLoop (0.00s)
|
||||
FAIL
|
||||
FAIL gitea.dooplex.hu/admin/felhom-controller/internal/stacks 0.010s
|
||||
FAIL
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
##### exit items through the product — 2026-10-02T05:53:44Z
|
||||
## item 1 — a STRANGER (no cookie), LAN and simulated tunnel
|
||||
library GET / LAN 302 GATE | tunnel 302 GATE
|
||||
library GET / LAN 401 GATE | tunnel 401 GATE
|
||||
library GET /api/v1/books LAN 401 GATE | tunnel 401 GATE
|
||||
library GET /api/v1/healthcheck LAN 401 GATE | tunnel 401 GATE
|
||||
library POST /api/v1/setup LAN 401 GATE | tunnel 401 GATE
|
||||
library POST /api/v1/auth/login LAN 401 GATE | tunnel 401 GATE
|
||||
library GET /ws/websocket LAN 401 GATE | tunnel 401 GATE
|
||||
library GET /api/v1/opdsx LAN 401 GATE | tunnel 401 GATE
|
||||
library GET /api/v1/opds-evil LAN 401 GATE | tunnel 401 GATE
|
||||
library GET /api/v1/opds/../../api/v1/books LAN 401 GATE | tunnel 401 GATE
|
||||
library GET /no-such-page LAN 302 GATE | tunnel 302 GATE
|
||||
video GET / LAN 302 GATE | tunnel 302 GATE
|
||||
video GET / LAN 401 GATE | tunnel 401 GATE
|
||||
video GET /history LAN 401 GATE | tunnel 401 GATE
|
||||
video POST /add LAN 401 GATE | tunnel 401 GATE
|
||||
video GET /socket.io/?EIO=4&transport=polling LAN 401 GATE | tunnel 401 GATE
|
||||
video GET /socket.io/?EIO=4&transport=websocket LAN 401 GATE | tunnel 401 GATE
|
||||
video GET /download/x.mp4 LAN 401 GATE | tunnel 401 GATE
|
||||
item 1: 0 app answers of 36 -> PASS
|
||||
## item 2 — family members, their OWN logins, through the product's sign-in page
|
||||
anna signs in on felhom.enkisfelhom.hu/__family/login: 200; felhom_family set; Max-Age 30 d; Path=/__family; dashboard cookie set: False
|
||||
member GET library/ -> 200 APP
|
||||
member GET library/api/v1/healthcheck -> 200 APP
|
||||
member GET video/ -> 200 APP
|
||||
member GET video/socket.io/?EIO=4&transport=polling -> 200 APP
|
||||
member GET video/history -> 200 APP
|
||||
bela MeTube websocket upgrade -> 101 APP ['Upgrade: websocket']
|
||||
bela's MeTube cookie at Grimmory -> 302 GATE
|
||||
after the CONTROLLER restarted, anna's Grimmory cookie -> 200 APP (survived)
|
||||
anna logs out (200) -> her Grimmory cookie 302 GATE (refused)
|
||||
## item 3 — a stranger's guesses at the family sign-in lock only the stranger (simulated tunnel)
|
||||
stranger 198.51.100.66, 7 wrong for anna: ['401', '401', '401', '401', '401', '429', '429']
|
||||
stranger with anna's RIGHT password while locked: 429
|
||||
anna herself from 203.0.113.10 (tunnel), at once: 200, session set
|
||||
bela from the LAN, at once: 200, session set
|
||||
controller log: 2026/10/02 05:54:55 family_gate.go:367: [WARN] [web] family sign-in failed — visitor 198.51.100.66
|
||||
2026/10/02 05:54:56 family_gate.go:360: [WARN] [web] family sign-in: too many wrong tries — visitor 198.51.100.66, name "anna"
|
||||
2026/10/02 05:54:58 family_gate.go:360: [WARN] [web] family sign-in: too many wrong tries — visitor 198.51.100.66, name "anna"
|
||||
2026/10/02 05:54:59 family_gate.go:360: [WARN] [web] family sign-in: too many wrong tries — visitor 198.51.100.66, name "anna"
|
||||
2026/10/02 05:55:01 family_gate.go:380: [INFO] [web] family sign-in: anna — visitor 203.0.113.10
|
||||
2026/10/02 05:55:01 family_gate.go:380: [INFO] [web] family sign-in: bela — visitor 192.168.0.180
|
||||
|
||||
## item 4 — Grimmory's e-reader exceptions keep Grimmory's OWN login (no family cookie)
|
||||
(setup as the household through the gate: OPDS on + an OPDS user, a Kobo token, a KOReader user — values not printed)
|
||||
OPDS, the OPDS user's own login LAN -> 200 app '<?xml version="1.0" encoding="UTF-8"?>\n<feed xmlns="http://w'
|
||||
OPDS, the OPDS user's own login tunnel -> 200 app '<?xml version="1.0" encoding="UTF-8"?>\n<feed xmlns="http://w'
|
||||
OPDS, a stranger with a wrong password tunnel -> 401 app 'HTTP Status 401 - Bad credentials'
|
||||
OPDS, a stranger with nothing tunnel -> 401 app 'HTTP Status 401 - Full authentication is required to access'
|
||||
Kobo initialization, the device token LAN -> 200 app '{"Resources":{"user_tasteprofile_genre":"https://storeapi.ko'
|
||||
Kobo, a made-up token tunnel -> 401 app '{"timestamp":"2026-10-02T05:55:12.892Z","status":401,"error"'
|
||||
KOReader sign-in, its own user + md5 key LAN -> 200 app '{"username":"korolvaso"}'
|
||||
KOReader, a stranger's wrong key tunnel -> 401 app '{"timestamp":"2026-10-02T05:55:14.437Z","status":401,"error"'
|
||||
Komga API, a stranger with nothing tunnel -> 401 app 'HTTP Status 401 - Full authentication is required to access'
|
||||
look-alike /api/v1/opdsx (F1) tunnel -> 401 GATE '{"error":"sign in with your family login"}'
|
||||
look-alike /api/koreaderx tunnel -> 401 GATE '{"error":"sign in with your family login"}'
|
||||
../ out of an exception tunnel -> 401 GATE '{"error":"sign in with your family login"}'
|
||||
## R-775 re-measured — a stranger cannot reach Grimmory's web sign-in at all, so its 15-minute lock cannot be aimed from outside
|
||||
stranger x6 at /api/v1/auth/login (tunnel): ['401', '401', '401', '401', '401', '401'] -> the household then signs in: 200
|
||||
## item 5 — the family login and the box dashboard
|
||||
family cookies at /launcher -> 302 /login?next=%2Flauncher | at /api/stacks -> 401 | anna's family password at the dashboard login -> 200, session none
|
||||
## reset and removal end access at the next request (every gated app)
|
||||
card: new password for bela -> ok=True; bela's Grimmory cookie -> 302, MeTube cookie -> 302 (302 = sent to sign in)
|
||||
card: remove bela -> ok=True members=['anna']; bela's MeTube cookie -> 401; bela signs in again -> 401
|
||||
## cost — the same request through the gated name, and straight at the container (60 pairs)
|
||||
gated (LAN→traefik→forwardAuth→app) median 9.4 ms, p90 10.5 ms; the app straight (guest→container) median 1.0 ms — the honest number is the gate's own: see the controller's forwardAuth timing below
|
||||
## the controller DOWN — a gated app answers an error, never the app; an exception still reaches the app's own login
|
||||
controller stopped: MeTube with a member cookie -> 500 ''; Grimmory API -> 500; Grimmory OPDS exception (wrong password) -> 401 (the app's own refusal)
|
||||
controller back: MeTube with bela's earlier cookie (bela was removed) -> 401 GATE
|
||||
## cost, the gate's own answer: 100 forwardAuth calls from inside the guest straight to the controller with a member cookie — codes {'200'}, median 0.49 ms, p90 0.55 ms, max 0.64 ms (2026-10-02T05:56:36Z)
|
||||
@@ -0,0 +1,12 @@
|
||||
git:
|
||||
branch: main
|
||||
repo_url: https://gitea.dooplex.hu/admin/app-catalog-drill.git
|
||||
sync_interval: 15m
|
||||
token: <redacted>
|
||||
username: "admin"
|
||||
hub:
|
||||
|
||||
CONTROL 1 — the box's clone: c3f433f DRILL: grimmory + metube behind the family gate (0.287.0 proof on 9202)
|
||||
https://gitea.dooplex.hu/admin/app-catalog-drill.git
|
||||
CONTROL 2 — live main: ['de0a9bd29fb0e2e42e3631f13ad84268eeccbab5']
|
||||
CONTROL 3 — expected: drill
|
||||
@@ -0,0 +1,10 @@
|
||||
##### family gate live setup on 9202 — controller gitea.dooplex.hu/admin/felhom-controller:0.287.0 | 2026-10-02T05:50:41Z
|
||||
Család card: add anna -> ok=True members=['anna'] password returned ONCE (len 19, not printed)
|
||||
Család card: add bela -> ok=True members=['anna', 'bela'] password returned ONCE (len 19, not printed)
|
||||
the security page carries the card: True | and no member password: True
|
||||
deploy metube -> True
|
||||
metube family-gate file: family-gate-metube.yml
|
||||
deploy grimmory -> True
|
||||
grimmory family-gate file: family-gate-grimmory.yml setup-gate-grimmory.yml
|
||||
grimmory: the household makes the first admin THROUGH THE SETUP GATE -> 200
|
||||
grimmory: setup gate opened by its probe after ~10 s; files now: family-gate-grimmory.yml
|
||||
@@ -0,0 +1,16 @@
|
||||
## RP-R801 mutant: the old rule (dict labels read by VALUE only) — 2026-10-02T07:22:42Z
|
||||
|
||||
Second list contains 1 additional elements.
|
||||
First extra element 0:
|
||||
8081
|
||||
|
||||
- []
|
||||
+ [8081]
|
||||
|
||||
----------------------------------------------------------------------
|
||||
Ran 3 tests in 0.001s
|
||||
|
||||
FAILED (failures=1)
|
||||
## restored:
|
||||
|
||||
OK
|
||||
@@ -0,0 +1,12 @@
|
||||
# B — assets for grimmory and metube, 2026-10-02T06:51:34Z
|
||||
https://felhom.eu/assets/grimmory-logo.svg -> 200 1827B
|
||||
https://felhom.eu/assets/grimmory-screenshot-1.webp -> 200 23696B
|
||||
https://felhom.eu/assets/grimmory-screenshot-2.webp -> 200 20458B
|
||||
https://felhom.eu/assets/grimmory-screenshot-3.webp -> 200 25850B
|
||||
https://felhom.eu/assets/metube-logo.svg -> 200 1147B
|
||||
https://felhom.eu/assets/metube-screenshot-1.webp -> 200 27634B
|
||||
https://felhom.eu/assets/metube-screenshot-2.webp -> 200 32112B
|
||||
https://felhom.eu/assets/metube-screenshot-3.webp -> 200 25488B
|
||||
https://felhom.eu/assets/nosuchapp-logo.svg -> 404 153B (negative control)
|
||||
logos: grimmory = static/assets/favicon.svg inside its image's app.jar (AGPL-3.0); metube = /app/ui/dist/metube/browser/assets/icons/safari-pinned-tab.svg inside ghcr.io/alexta69/metube (AGPL-3.0). screenshots 1-2: each app's own UI on 9202 (headless Chrome, tools/shots/); 3: the family sign-in page a visitor meets at the app's address (tools/shots/familylogin.js). felhom.eu commit 344081f; boxes get them with the next hub release (R-766).
|
||||
8.5: the website's claim — Több mint 45 alkalmazásból Több mint 45 alkalmazást — templates after this publish: 58 directories, of which offered (lifecycle available): 56; the claim holds
|
||||
@@ -0,0 +1,59 @@
|
||||
+ date -u
|
||||
Fri Oct 2 07:01:33 UTC 2026
|
||||
+ pct list
|
||||
VMID Status Lock Name
|
||||
9201 running demo-hp
|
||||
9202 running demo-hp-scratch
|
||||
+ free -g
|
||||
+ head -2
|
||||
total used free shared buff/cache available
|
||||
Mem: 29 5 9 0 15 23
|
||||
+ pvesm status
|
||||
Name Type Status Total (KiB) Used (KiB) Available (KiB) %
|
||||
felhom-pbs pbs active 0 0 0 0.00%
|
||||
local dir active 40453376 19527780 18838480 48.27%
|
||||
local-lvm lvmthin active 56487936 34943437 21544498 61.86%
|
||||
nvme-scratch dir active 983379700 77369600 855983488 7.87%
|
||||
+ pct config 9401
|
||||
+ head -1
|
||||
Configuration file 'nodes/demo-hp/lxc/9401.conf' does not exist
|
||||
+ pveam list local
|
||||
+ grep debian-13
|
||||
local:vztmpl/debian-13-standard_13.6-1_amd64.tar.zst 123.93MB
|
||||
+ pct create 9401 local:vztmpl/debian-13-standard_13.6-1_amd64.tar.zst --hostname upgrade-harness --cores 6 --memory 10240 --swap 0 --rootfs nvme-scratch:60 --net0 name=eth0,bridge=vmbr0,ip=dhcp --unprivileged 1 --features nesting=1,keyctl=1 --onboot 0
|
||||
+ tail -1
|
||||
done: SHA256:PyXdDIPUlAxyiDpveARaXo3kIwoxgwUdOjbhnfVXMdY root@upgrade-harness
|
||||
+ pct config 9401
|
||||
arch: amd64
|
||||
cores: 6
|
||||
features: nesting=1,keyctl=1
|
||||
hostname: upgrade-harness
|
||||
memory: 10240
|
||||
net0: name=eth0,bridge=vmbr0,hwaddr=BC:24:11:50:88:EF,ip=dhcp,type=veth
|
||||
onboot: 0
|
||||
ostype: debian
|
||||
rootfs: nvme-scratch:9401/vm-9401-disk-0.raw,size=60G
|
||||
swap: 0
|
||||
unprivileged: 1
|
||||
+ pct start 9401
|
||||
+ sleep 15
|
||||
+ pct exec 9401 -- bash -c 'dpkg --print-architecture; hostname; ip -4 -o addr show eth0 | awk "{print \$4}"; apt-get update -qq >/dev/null 2>&1; DEBIAN_FRONTEND=noninteractive apt-get install -y -qq docker.io docker-compose python3 python3-yaml curl postgresql-client sqlite3 git >/dev/null 2>&1; docker --version; docker compose version; python3 --version; git --version; docker network create traefik-public >/dev/null && echo traefik-public-net; swapon --show; free -m | head -3; df -h /'
|
||||
amd64
|
||||
upgrade-harness
|
||||
192.168.0.147/24
|
||||
Docker version 26.1.5+dfsg1, build a72d7cd
|
||||
Docker Compose version 2.26.1-4
|
||||
Python 3.13.5
|
||||
git version 2.47.3
|
||||
traefik-public-net
|
||||
total used free shared buff/cache available
|
||||
Mem: 10240 60 8502 0 1677 10179
|
||||
Swap: 0 0 0
|
||||
Filesystem Size Used Avail Use% Mounted on
|
||||
/dev/loop2 59G 1.3G 55G 3% /
|
||||
+ pvesm status
|
||||
Name Type Status Total (KiB) Used (KiB) Available (KiB) %
|
||||
felhom-pbs pbs active 0 0 0 0.00%
|
||||
local dir active 40453376 19527876 18838384 48.27%
|
||||
local-lvm lvmthin active 56487936 34943437 21544498 61.86%
|
||||
nvme-scratch dir active 983379700 78992412 854360676 8.03%
|
||||
@@ -0,0 +1,41 @@
|
||||
+ date -u
|
||||
Fri Oct 2 07:11:46 UTC 2026
|
||||
+ pct list
|
||||
VMID Status Lock Name
|
||||
9201 running demo-hp
|
||||
9202 running demo-hp-scratch
|
||||
9401 running upgrade-harness
|
||||
+ pvesm status
|
||||
Name Type Status Total (KiB) Used (KiB) Available (KiB) %
|
||||
felhom-pbs pbs active 0 0 0 0.00%
|
||||
local dir active 40453376 19527920 18838340 48.27%
|
||||
local-lvm lvmthin active 56487936 34943437 21544498 61.86%
|
||||
nvme-scratch dir active 983379700 81073172 852279916 8.24%
|
||||
+ pct exec 9401 -- bash -c 'docker ps -a --format {{.Names}} | wc -l; docker volume ls -q | wc -l'
|
||||
0
|
||||
0
|
||||
+ pct stop 9401
|
||||
+ pct destroy 9401 --purge
|
||||
purging CT 9401 from related configurations..
|
||||
+ pct list
|
||||
VMID Status Lock Name
|
||||
9201 running demo-hp
|
||||
9202 running demo-hp-scratch
|
||||
+ pct config 9401
|
||||
+ head -1
|
||||
Configuration file 'nodes/demo-hp/lxc/9401.conf' does not exist
|
||||
+ ls /mnt/hdd_1/images/
|
||||
9202
|
||||
+ pvesm status
|
||||
Name Type Status Total (KiB) Used (KiB) Available (KiB) %
|
||||
felhom-pbs pbs active 0 0 0 0.00%
|
||||
local dir active 40453376 19527852 18838408 48.27%
|
||||
local-lvm lvmthin active 56487936 34943437 21544498 61.86%
|
||||
nvme-scratch dir active 983379700 77369600 855983488 7.87%
|
||||
+ rm -rf /tmp/b9401
|
||||
+ ls /tmp
|
||||
+ grep -c b9401
|
||||
1
|
||||
teardown-script-removed
|
||||
0
|
||||
# note: the in-script "1" is the teardown script itself (/tmp/teardown-b9401.sh matches b9401); after it was removed the count is 0. nvme-scratch Used back to 77369600 KiB = the pre-create baseline; local-lvm unchanged (34943437) throughout. Nothing committed or pushed.
|
||||
@@ -0,0 +1,65 @@
|
||||
+ date -u
|
||||
Fri Oct 2 07:13:17 UTC 2026
|
||||
+ pct list
|
||||
VMID Status Lock Name
|
||||
9201 running demo-hp
|
||||
9202 running demo-hp-scratch
|
||||
+ head -2
|
||||
+ free -g
|
||||
total used free shared buff/cache available
|
||||
Mem: 29 5 10 0 14 23
|
||||
+ pvesm status
|
||||
Name Type Status Total (KiB) Used (KiB) Available (KiB) %
|
||||
felhom-pbs pbs active 0 0 0 0.00%
|
||||
local dir active 40453376 19527860 18838400 48.27%
|
||||
local-lvm lvmthin active 56487936 34943437 21544498 61.86%
|
||||
nvme-scratch dir active 983379700 77369600 855983488 7.87%
|
||||
+ pct config 9401
|
||||
+ head -1
|
||||
Configuration file 'nodes/demo-hp/lxc/9401.conf' does not exist
|
||||
+ pveam list local
|
||||
+ grep debian-13
|
||||
local:vztmpl/debian-13-standard_13.6-1_amd64.tar.zst 123.93MB
|
||||
+ pct create 9401 local:vztmpl/debian-13-standard_13.6-1_amd64.tar.zst --hostname upgrade-harness --cores 6 --memory 10240 --swap 0 --rootfs nvme-scratch:60 --net0 name=eth0,bridge=vmbr0,ip=dhcp --unprivileged 1 --features nesting=1,keyctl=1 --onboot 0
|
||||
+ tail -1
|
||||
done: SHA256:Eby8n+SmD/BjZN7bKvhPpaTpq5y5Ws7L+WO6Da40zOk root@upgrade-harness
|
||||
+ pct config 9401
|
||||
arch: amd64
|
||||
cores: 6
|
||||
features: nesting=1,keyctl=1
|
||||
hostname: upgrade-harness
|
||||
memory: 10240
|
||||
net0: name=eth0,bridge=vmbr0,hwaddr=BC:24:11:E7:95:BA,ip=dhcp,type=veth
|
||||
onboot: 0
|
||||
ostype: debian
|
||||
rootfs: nvme-scratch:9401/vm-9401-disk-0.raw,size=60G
|
||||
swap: 0
|
||||
unprivileged: 1
|
||||
+ pct start 9401
|
||||
+ sleep 15
|
||||
+ pct exec 9401 -- bash -c 'dpkg --print-architecture; hostname; ip -4 -o addr show eth0 | awk "{print \$4}"; apt-get update -qq >/dev/null 2>&1; DEBIAN_FRONTEND=noninteractive apt-get install -y -qq docker.io docker-compose python3 python3-yaml curl postgresql-client sqlite3 git >/dev/null 2>&1; docker --version; docker compose version; python3 --version; git --version; docker network create traefik-public >/dev/null && echo traefik-public-net; swapon --show; free -m | head -3; df -h /'
|
||||
amd64
|
||||
upgrade-harness
|
||||
192.168.0.116/24
|
||||
Docker version 26.1.5+dfsg1, build a72d7cd
|
||||
Docker Compose version 2.26.1-4
|
||||
Python 3.13.5
|
||||
git version 2.47.3
|
||||
traefik-public-net
|
||||
total used free shared buff/cache available
|
||||
Mem: 10240 58 8531 0 1649 10181
|
||||
Swap: 0 0 0
|
||||
Filesystem Size Used Avail Use% Mounted on
|
||||
/dev/loop2 59G 1.3G 55G 3% /
|
||||
+ pvesm status
|
||||
Name Type Status Total (KiB) Used (KiB) Available (KiB) %
|
||||
felhom-pbs pbs active 0 0 0 0.00%
|
||||
local dir active 40453376 19527956 18838304 48.27%
|
||||
local-lvm lvmthin active 56487936 34943437 21544498 61.86%
|
||||
nvme-scratch dir active 983379700 78965928 854387160 8.03%
|
||||
felhom.eu/documentation/audits/family-gate-2026-10-02/B/catalog-gates-grimmory.txt
|
||||
felhom.eu/documentation/audits/family-gate-2026-10-02/B/catalog-gates-metube-run1.txt
|
||||
felhom.eu/documentation/audits/family-gate-2026-10-02/B/catalog-gates-metube.txt
|
||||
de0a9bd SparkyFitness onboarding record (Part C: bench + 9202 measured, six rows open — R-786; licence non-commercial — R-784); CHANGELOG/CONTEXT/REPORT for the R-753 catalog work
|
||||
16
|
||||
golden-0.287.0-2026-10-02
|
||||
@@ -0,0 +1,37 @@
|
||||
+ date -u
|
||||
Fri Oct 2 07:21:59 UTC 2026
|
||||
+ pct list
|
||||
VMID Status Lock Name
|
||||
9201 running demo-hp
|
||||
9202 running demo-hp-scratch
|
||||
9401 running upgrade-harness
|
||||
+ pvesm status
|
||||
Name Type Status Total (KiB) Used (KiB) Available (KiB) %
|
||||
felhom-pbs pbs active 0 0 0 0.00%
|
||||
local dir active 40453376 19527996 18838264 48.27%
|
||||
local-lvm lvmthin active 56487936 34943437 21544498 61.86%
|
||||
nvme-scratch dir active 983379700 80106504 853246584 8.15%
|
||||
+ pct exec 9401 -- bash -c 'docker ps -a --format {{.Names}} | wc -l; docker volume ls -q | wc -l'
|
||||
0
|
||||
0
|
||||
+ pct stop 9401
|
||||
+ pct destroy 9401 --purge
|
||||
purging CT 9401 from related configurations..
|
||||
+ pct list
|
||||
VMID Status Lock Name
|
||||
9201 running demo-hp
|
||||
9202 running demo-hp-scratch
|
||||
+ pct config 9401
|
||||
+ head -1
|
||||
Configuration file 'nodes/demo-hp/lxc/9401.conf' does not exist
|
||||
+ ls /mnt/hdd_1/images/
|
||||
9202
|
||||
+ pvesm status
|
||||
Name Type Status Total (KiB) Used (KiB) Available (KiB) %
|
||||
felhom-pbs pbs active 0 0 0 0.00%
|
||||
local dir active 40453376 19527924 18838336 48.27%
|
||||
local-lvm lvmthin active 56487936 34943437 21544498 61.86%
|
||||
nvme-scratch dir active 983379700 77369600 855983488 7.87%
|
||||
+ rm -rf /tmp/b9401
|
||||
tmp-leftovers=0
|
||||
# nothing committed or pushed; evidence copied to DooPlex before the destroy
|
||||
@@ -0,0 +1,67 @@
|
||||
+ date -u
|
||||
Fri Oct 2 07:23:12 UTC 2026
|
||||
+ pct list
|
||||
VMID Status Lock Name
|
||||
9201 running demo-hp
|
||||
9202 running demo-hp-scratch
|
||||
+ free -g
|
||||
+ head -2
|
||||
total used free shared buff/cache available
|
||||
Mem: 29 5 10 0 14 23
|
||||
+ pvesm status
|
||||
Name Type Status Total (KiB) Used (KiB) Available (KiB) %
|
||||
felhom-pbs pbs active 0 0 0 0.00%
|
||||
local dir active 40453376 19527928 18838332 48.27%
|
||||
local-lvm lvmthin active 56487936 34943437 21544498 61.86%
|
||||
nvme-scratch dir active 983379700 77369600 855983488 7.87%
|
||||
+ pct config 9401
|
||||
+ head -1
|
||||
Configuration file 'nodes/demo-hp/lxc/9401.conf' does not exist
|
||||
+ pveam list local
|
||||
+ grep debian-13
|
||||
local:vztmpl/debian-13-standard_13.6-1_amd64.tar.zst 123.93MB
|
||||
+ pct create 9401 local:vztmpl/debian-13-standard_13.6-1_amd64.tar.zst --hostname upgrade-harness --cores 6 --memory 10240 --swap 0 --rootfs nvme-scratch:60 --net0 name=eth0,bridge=vmbr0,ip=dhcp --unprivileged 1 --features nesting=1,keyctl=1 --onboot 0
|
||||
+ tail -1
|
||||
done: SHA256:sD6AEj3m9KyUfvaqKMuaAkJCHSV8RV+g6DFQJDvvPnY root@upgrade-harness
|
||||
+ pct config 9401
|
||||
arch: amd64
|
||||
cores: 6
|
||||
features: nesting=1,keyctl=1
|
||||
hostname: upgrade-harness
|
||||
memory: 10240
|
||||
net0: name=eth0,bridge=vmbr0,hwaddr=BC:24:11:AF:A0:95,ip=dhcp,type=veth
|
||||
onboot: 0
|
||||
ostype: debian
|
||||
rootfs: nvme-scratch:9401/vm-9401-disk-0.raw,size=60G
|
||||
swap: 0
|
||||
unprivileged: 1
|
||||
+ pct start 9401
|
||||
+ sleep 15
|
||||
+ pct exec 9401 -- bash -c 'dpkg --print-architecture; hostname; ip -4 -o addr show eth0 | awk "{print \$4}"; apt-get update -qq >/dev/null 2>&1; DEBIAN_FRONTEND=noninteractive apt-get install -y -qq docker.io docker-compose python3 python3-yaml curl postgresql-client sqlite3 git >/dev/null 2>&1; docker --version; docker compose version; python3 --version; git --version; docker network create traefik-public >/dev/null && echo traefik-public-net; swapon --show; free -m | head -3; df -h /'
|
||||
amd64
|
||||
upgrade-harness
|
||||
192.168.0.145/24
|
||||
Docker version 26.1.5+dfsg1, build a72d7cd
|
||||
Docker Compose version 2.26.1-4
|
||||
Python 3.13.5
|
||||
git version 2.47.3
|
||||
traefik-public-net
|
||||
total used free shared buff/cache available
|
||||
Mem: 10240 60 8536 0 1643 10179
|
||||
Swap: 0 0 0
|
||||
Filesystem Size Used Avail Use% Mounted on
|
||||
/dev/loop2 59G 1.3G 55G 3% /
|
||||
+ pvesm status
|
||||
Name Type Status Total (KiB) Used (KiB) Available (KiB) %
|
||||
felhom-pbs pbs active 0 0 0 0.00%
|
||||
local dir active 40453376 19528020 18838240 48.27%
|
||||
local-lvm lvmthin active 56487936 34943437 21544498 61.86%
|
||||
nvme-scratch dir active 983379700 78960252 854392836 8.03%
|
||||
felhom.eu/documentation/audits/family-gate-2026-10-02/B/catalog-gates-grimmory-run1.txt
|
||||
felhom.eu/documentation/audits/family-gate-2026-10-02/B/catalog-gates-grimmory.txt
|
||||
felhom.eu/documentation/audits/family-gate-2026-10-02/B/catalog-gates-metube-run1.txt
|
||||
felhom.eu/documentation/audits/family-gate-2026-10-02/B/catalog-gates-metube-run2.txt
|
||||
felhom.eu/documentation/audits/family-gate-2026-10-02/B/catalog-gates-metube.txt
|
||||
de0a9bd SparkyFitness onboarding record (Part C: bench + 9202 measured, six rows open — R-786; licence non-commercial — R-784); CHANGELOG/CONTEXT/REPORT for the R-753 catalog work
|
||||
17
|
||||
golden-0.287.0-2026-10-02
|
||||
@@ -0,0 +1,37 @@
|
||||
+ date -u
|
||||
Fri Oct 2 07:35:01 UTC 2026
|
||||
+ pct list
|
||||
VMID Status Lock Name
|
||||
9201 running demo-hp
|
||||
9202 running demo-hp-scratch
|
||||
9401 running upgrade-harness
|
||||
+ pvesm status
|
||||
Name Type Status Total (KiB) Used (KiB) Available (KiB) %
|
||||
felhom-pbs pbs active 0 0 0 0.00%
|
||||
local dir active 40453376 19536264 18829996 48.29%
|
||||
local-lvm lvmthin active 56487936 34943437 21544498 61.86%
|
||||
nvme-scratch dir active 983379700 81070096 852282992 8.24%
|
||||
+ pct exec 9401 -- bash -c 'docker ps -a --format {{.Names}} | wc -l; docker volume ls -q | wc -l'
|
||||
0
|
||||
0
|
||||
+ pct stop 9401
|
||||
+ pct destroy 9401 --purge
|
||||
purging CT 9401 from related configurations..
|
||||
+ pct list
|
||||
VMID Status Lock Name
|
||||
9201 running demo-hp
|
||||
9202 running demo-hp-scratch
|
||||
+ pct config 9401
|
||||
+ head -1
|
||||
Configuration file 'nodes/demo-hp/lxc/9401.conf' does not exist
|
||||
+ ls /mnt/hdd_1/images/
|
||||
9202
|
||||
+ pvesm status
|
||||
Name Type Status Total (KiB) Used (KiB) Available (KiB) %
|
||||
felhom-pbs pbs active 0 0 0 0.00%
|
||||
local dir active 40453376 19536192 18830068 48.29%
|
||||
local-lvm lvmthin active 56487936 34943437 21544498 61.86%
|
||||
nvme-scratch dir active 983379700 77369600 855983488 7.87%
|
||||
+ rm -rf /tmp/b9401
|
||||
tmp-leftovers=0
|
||||
# nothing committed or pushed; evidence copied to DooPlex before the destroy
|
||||
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"app": "metube",
|
||||
"venue": "box 9202 (drill catalog, controller 0.287.0), the product's guarded Update",
|
||||
"from": {
|
||||
"metube": "ghcr.io/alexta69/metube:2026.09.28"
|
||||
},
|
||||
"to": {
|
||||
"metube": "ghcr.io/alexta69/metube:2026.09.29"
|
||||
},
|
||||
"verdict": "proven",
|
||||
"seed_read_before": true,
|
||||
"seed_read_after": true,
|
||||
"healthy_after": true,
|
||||
"duration_s": 34.9,
|
||||
"final_phase": "done",
|
||||
"measured_at": "2026-10-02T06:29:47Z",
|
||||
"evidence": "felhom.eu/documentation/audits/family-gate-2026-10-02/B/box/metube-step.txt"
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
##### final on 9202 — controller gitea.dooplex.hu/admin/felhom-controller:0.287.0 | catalog e42bf78 DRILL grimmory: v3.5.0 (box step behind the family g | 2026-10-02T06:53:42Z
|
||||
remove grimmory (WITH data and backups) -> 409 {'ok': False, 'error': 'A(z) /mnt/felhom-drives/scratch_hdd/userdata/grimmory tárhely jelenleg nem elérhető — az alkalmazás nem távolítható el, amíg a meghajtó vissza nem csatlakozik.'}
|
||||
refused (R-442, no agent on 9202) — remove grimmory KEEPING drive data -> 200 {'ok': True, 'data': {'removed': 'grimmory', 'volumes_removed': ['grimmory_grimmory_db'], 'hdd_paths_removed': [], 'hdd_paths_preserved': ['/mnt/felhom-drives/scratch_hdd/userdata/grimmory/appdata/gri
|
||||
the harness removed its own test folder /mnt/felhom-drives/scratch_hdd/userdata/grimmory by hand
|
||||
left after: /opt/docker/stacks/grimmory
|
||||
remove metube (WITH data and backups) -> 409 {'ok': False, 'error': 'A(z) /mnt/felhom-drives/scratch_hdd/userdata/metube tárhely jelenleg nem elérhető — az alkalmazás nem távolítható el, amíg a meghajtó vissza nem csatlakozik.'}
|
||||
refused (R-442, no agent on 9202) — remove metube KEEPING drive data -> 200 {'ok': True, 'data': {'removed': 'metube', 'volumes_removed': ['metube_metube_state'], 'hdd_paths_removed': [], 'hdd_paths_preserved': [], 'backup_paths_removed': ['/mnt/felhom-drives/scratch_hdd/user
|
||||
the harness removed its own test folder /mnt/felhom-drives/scratch_hdd/userdata/metube by hand
|
||||
left after: /opt/docker/stacks/metube
|
||||
gate files: none
|
||||
5.1 (box) metube [24954133462d] 48 samples: peak anon 83.0 MiB = 10.8 % of the limit; oom_kill 0
|
||||
5.1 (box) metube [94ba5b8a2311] 13 samples: peak anon 58.8 MiB = 7.7 % of the limit; oom_kill 0
|
||||
5.1 (box) metube [fbbc26704571] 530 samples: peak anon 61.6 MiB = 8.0 % of the limit; oom_kill 0
|
||||
5.1 (box) metube [874b43d7ca42] 36 samples: peak anon 58.8 MiB = 7.7 % of the limit; oom_kill 0
|
||||
@@ -0,0 +1,132 @@
|
||||
epoch,anon,oom_kill,limit,restarts
|
||||
1790922772,384458752,0,1073741824,0
|
||||
1790922773,384458752,0,1073741824,0
|
||||
1790922774,384946176,0,1073741824,0
|
||||
1790922775,384946176,0,1073741824,0
|
||||
1790922776,384954368,0,1073741824,0
|
||||
1790922777,384954368,0,1073741824,0
|
||||
1790922778,390242304,0,1073741824,0
|
||||
1790922779,404082688,0,1073741824,0
|
||||
1790922780,422772736,0,1073741824,0
|
||||
1790922781,396791808,0,1073741824,0
|
||||
1790922782,396800000,0,1073741824,0
|
||||
1790922783,405811200,0,1073741824,0
|
||||
1790922784,446570496,0,1073741824,0
|
||||
1790922785,481116160,0,1073741824,0
|
||||
1790922786,487124992,0,1073741824,0
|
||||
1790922787,467677184,0,1073741824,0
|
||||
1790922788,467677184,0,1073741824,0
|
||||
1790922789,467677184,0,1073741824,0
|
||||
1790922790,440795136,0,1073741824,0
|
||||
1790922791,440795136,0,1073741824,0
|
||||
1790922792,440799232,0,1073741824,0
|
||||
1790922793,440799232,0,1073741824,0
|
||||
1790922794,440799232,0,1073741824,0
|
||||
1790922795,440799232,0,1073741824,0
|
||||
1790922796,440799232,0,1073741824,0
|
||||
1790922798,440799232,0,1073741824,0
|
||||
1790922799,440799232,0,1073741824,0
|
||||
1790922800,440799232,0,1073741824,0
|
||||
1790922801,440803328,0,1073741824,0
|
||||
1790922802,440803328,0,1073741824,0
|
||||
1790922803,440811520,0,1073741824,0
|
||||
1790922804,440811520,0,1073741824,0
|
||||
1790922805,440811520,0,1073741824,0
|
||||
1790922806,440811520,0,1073741824,0
|
||||
1790922807,440811520,0,1073741824,0
|
||||
1790922808,440811520,0,1073741824,0
|
||||
1790922809,440811520,0,1073741824,0
|
||||
1790922810,440811520,0,1073741824,0
|
||||
1790922811,440868864,0,1073741824,0
|
||||
1790922812,440868864,0,1073741824,0
|
||||
1790922813,440872960,0,1073741824,0
|
||||
1790922814,440872960,0,1073741824,0
|
||||
1790922815,441974784,0,1073741824,0
|
||||
1790922816,441974784,0,1073741824,0
|
||||
1790922817,441991168,0,1073741824,0
|
||||
1790922818,441991168,0,1073741824,0
|
||||
1790922819,442015744,0,1073741824,0
|
||||
1790922820,408018944,0,1073741824,0
|
||||
1790922821,393568256,0,1073741824,0
|
||||
1790922822,393568256,0,1073741824,0
|
||||
1790922823,393568256,0,1073741824,0
|
||||
1790922825,393568256,0,1073741824,0
|
||||
1790922826,393568256,0,1073741824,0
|
||||
1790922827,393568256,0,1073741824,0
|
||||
1790922828,393568256,0,1073741824,0
|
||||
1790922829,393568256,0,1073741824,0
|
||||
1790922830,393584640,0,1073741824,0
|
||||
1790922831,393584640,0,1073741824,0
|
||||
1790922832,393584640,0,1073741824,0
|
||||
1790922833,393584640,0,1073741824,0
|
||||
1790922834,393674752,0,1073741824,0
|
||||
1790922835,393674752,0,1073741824,0
|
||||
1790922836,393674752,0,1073741824,0
|
||||
1790922837,393674752,0,1073741824,0
|
||||
1790922838,393674752,0,1073741824,0
|
||||
1790922839,393674752,0,1073741824,0
|
||||
1790922840,393674752,0,1073741824,0
|
||||
1790922841,393940992,0,1073741824,0
|
||||
1790922842,393940992,0,1073741824,0
|
||||
1790922843,393940992,0,1073741824,0
|
||||
1790922844,393940992,0,1073741824,0
|
||||
1790922845,394649600,0,1073741824,0
|
||||
1790922846,394649600,0,1073741824,0
|
||||
1790922847,394723328,0,1073741824,0
|
||||
1790922848,394723328,0,1073741824,0
|
||||
1790922849,394723328,0,1073741824,0
|
||||
1790922851,393641984,0,1073741824,0
|
||||
1790922852,393641984,0,1073741824,0
|
||||
1790922853,393641984,0,1073741824,0
|
||||
1790922854,393641984,0,1073741824,0
|
||||
1790922855,393641984,0,1073741824,0
|
||||
1790922856,393641984,0,1073741824,0
|
||||
1790922857,393641984,0,1073741824,0
|
||||
1790922858,393646080,0,1073741824,0
|
||||
1790922859,393646080,0,1073741824,0
|
||||
1790922860,393650176,0,1073741824,0
|
||||
1790922861,393650176,0,1073741824,0
|
||||
1790922862,393728000,0,1073741824,0
|
||||
1790922863,393728000,0,1073741824,0
|
||||
1790922864,393728000,0,1073741824,0
|
||||
1790922865,393728000,0,1073741824,0
|
||||
1790922866,393728000,0,1073741824,0
|
||||
1790922867,393728000,0,1073741824,0
|
||||
1790922868,393728000,0,1073741824,0
|
||||
1790922869,393728000,0,1073741824,0
|
||||
1790922870,393826304,0,1073741824,0
|
||||
1790922871,394088448,0,1073741824,0
|
||||
1790922872,394088448,0,1073741824,0
|
||||
1790922873,394088448,0,1073741824,0
|
||||
1790922874,394088448,0,1073741824,0
|
||||
1790922875,394063872,0,1073741824,0
|
||||
1790922876,395186176,0,1073741824,0
|
||||
1790922878,395186176,0,1073741824,0
|
||||
1790922879,395198464,0,1073741824,0
|
||||
1790922880,395202560,0,1073741824,0
|
||||
1790922881,395202560,0,1073741824,0
|
||||
1790922882,393576448,0,1073741824,0
|
||||
1790922883,393576448,0,1073741824,0
|
||||
1790922884,393576448,0,1073741824,0
|
||||
1790922885,393576448,0,1073741824,0
|
||||
1790922886,393576448,0,1073741824,0
|
||||
1790922887,393576448,0,1073741824,0
|
||||
1790922888,393576448,0,1073741824,0
|
||||
1790922889,393584640,0,1073741824,0
|
||||
1790922890,393584640,0,1073741824,0
|
||||
1790922891,393674752,0,1073741824,0
|
||||
1790922892,393674752,0,1073741824,0
|
||||
1790922893,393674752,0,1073741824,0
|
||||
1790922894,393674752,0,1073741824,0
|
||||
1790922895,393674752,0,1073741824,0
|
||||
1790922896,393674752,0,1073741824,0
|
||||
1790922897,393674752,0,1073741824,0
|
||||
1790922898,393674752,0,1073741824,0
|
||||
1790922899,393678848,0,1073741824,0
|
||||
1790922900,393678848,0,1073741824,0
|
||||
1790922901,393940992,0,1073741824,0
|
||||
1790922902,393940992,0,1073741824,0
|
||||
1790922903,393940992,0,1073741824,0
|
||||
1790922904,393940992,0,1073741824,0
|
||||
1790922906,393940992,0,1073741824,0
|
||||
1790922907,394600448,0,1073741824,0
|
||||
|
@@ -0,0 +1,11 @@
|
||||
##### grimmory memory on 9202 — 2026-10-02T06:32:47Z | limit 1073741824
|
||||
5.2 burst: 40 EPUB uploads through the app's own API in 2.5 s: codes {'204': 40}
|
||||
the library lists 41 books after the burst (8 s from its start); sampling 120 s more
|
||||
5.2 grimmory, 131 samples (1/s) across the burst: peak anon 464.6 MiB = 45.4 % of 1024M; oom_kill 0; restarts 0
|
||||
5.4 ghcr.io/grimmory-tools/grimmory:v3.4.1 at a 768m container limit (the image's own JAVA_TOOL_OPTIONS): size_t MaxHeapSize = 483393536 {product} {ergonomic} | double MaxRAMPercentage = 60.000000 {product} {environment}
|
||||
5.4 ghcr.io/grimmory-tools/grimmory:v3.4.1 at a 1024m container limit (the image's own JAVA_TOOL_OPTIONS): size_t MaxHeapSize = 644349952 {product} {ergonomic} | double MaxRAMPercentage = 60.000000 {product} {environment}
|
||||
5.4 ghcr.io/grimmory-tools/grimmory:v3.4.1 at a 1536m container limit (the image's own JAVA_TOOL_OPTIONS): size_t MaxHeapSize = 966524928 {product} {ergonomic} | double MaxRAMPercentage = 60.000000 {product} {environment}
|
||||
5.4 (re-read on the published tag, 2026-10-02T06:48:11Z) ghcr.io/grimmory-tools/grimmory:v3.5.0 at a 768m container limit: size_t MaxHeapSize = 483393536 {product} {ergonomic}| double MaxRAMPercentage = 60.000000 {product} {environment}|
|
||||
5.4 (re-read on the published tag, 2026-10-02T06:48:12Z) ghcr.io/grimmory-tools/grimmory:v3.5.0 at a 1024m container limit: size_t MaxHeapSize = 644349952 {product} {ergonomic}| double MaxRAMPercentage = 60.000000 {product} {environment}|
|
||||
5.4 (re-read on the published tag, 2026-10-02T06:48:14Z) ghcr.io/grimmory-tools/grimmory:v3.5.0 at a 1536m container limit: size_t MaxHeapSize = 966524928 {product} {ergonomic}| double MaxRAMPercentage = 60.000000 {product} {environment}|
|
||||
NOTE: the burst above ran on v3.4.1 (9202's Grimmory was stepped to v3.5.0 afterwards, grim-step.txt); v3.5.0's JVM options are the same (the three lines just above).
|
||||
@@ -0,0 +1,6 @@
|
||||
##### grim-seed on 9202 — controller gitea.dooplex.hu/admin/felhom-controller:0.287.0 | catalog c3f433f DRILL: grimmory + metube behind the family gate (0.2 | 2026-10-02T06:12:03Z
|
||||
grimmory: library 1, the household uploads an EPUB through its own API (behind the family gate) -> 204
|
||||
grimmory: readback http=200 found=True (controls: no token 401, wrong 401, second setup 403)
|
||||
grimmory: the seed reads back: True
|
||||
2.2/2.8 the book on the household's drive: /mnt/felhom-drives/scratch_hdd/userdata/grimmory/userdata/media/grimmory/Felhom/Felhom Csalad 4bd80aee/Felhom Csalad 4bd80aee - Felhom.epub
|
||||
2.7 sizes: grimmory_grimmory_db=169M 76K /mnt/felhom-drives/scratch_hdd/userdata/grimmory
|
||||
@@ -0,0 +1,10 @@
|
||||
##### grim-step on 9202 — controller gitea.dooplex.hu/admin/felhom-controller:0.287.0 | catalog 3d8b76d DRILL metube: ghcr.io/alexta69/metube:2026.09.29 (bo | 2026-10-02T06:35:58Z
|
||||
before: pinned={'grimmory': 'ghcr.io/grimmory-tools/grimmory:v3.4.1', 'grimmory-db': 'mariadb:11.4'}
|
||||
drill: 051749b DRILL grimmory: v3.5.0 (box step behind the family gate, 2026-10-02)
|
||||
phase +0.0s backing-up | err=None
|
||||
phase +10.3s safety-dump | err=None
|
||||
phase +11.3s failed | err=A frissítés nem indult el: az új verzió leírása nem olvasható be. Az alkalmazás változatlanul fut tovább.
|
||||
grimmory: /api/v1/healthcheck never answered
|
||||
gate files after the step: family-gate-grimmory.yml family-gate-metube.yml | a stranger at / -> LAN 401 | tunnel 401 | OPDS exception, a stranger -> LAN 401 | tunnel 401
|
||||
RESULT final_phase=failed after={'grimmory': 'ghcr.io/grimmory-tools/grimmory:v3.4.1', 'grimmory-db': 'mariadb:11.4'} seed_after=False (11.3 s)
|
||||
NOTE (2026-10-02T06:47Z): attempt 1 is a HARNESS failure, not the product's. The drill edit opened the compose for writing before reading it, so the drill template went out EMPTY; the box refused it ("backup block rejected … matches no compose bind"), took its backup, and answered "the update did not start — the app runs on unchanged" (11.3 s). Grimmory kept running at v3.4.1, healthy. The member 401s after it: box_walk cached "not gated" from a GET / asked while Grimmory restarted after the pre-update backup (no router for a moment) — fixed in box_walk.gate_cookie (a 404/5xx without a gate redirect is no longer cached). Drill restored by commit; attempt 2: grim-step.txt.
|
||||
@@ -0,0 +1,12 @@
|
||||
##### grim-step on 9202 — controller gitea.dooplex.hu/admin/felhom-controller:0.287.0 | catalog 051749b DRILL grimmory: v3.5.0 (box step behind the family g | 2026-10-02T06:46:39Z
|
||||
before: pinned={'grimmory': 'ghcr.io/grimmory-tools/grimmory:v3.4.1', 'grimmory-db': 'mariadb:11.4'}
|
||||
drill: e42bf78 DRILL grimmory: v3.5.0 (box step behind the family gate, 2026-10-02)
|
||||
phase +0.0s safety-dump | err=None
|
||||
phase +1.1s pulling | err=None
|
||||
phase +14.4s copying | err=None
|
||||
phase +17.5s starting | err=None
|
||||
phase +23.6s verifying | err=None
|
||||
phase +58.5s done | err=None
|
||||
grimmory: readback http=200 found=True (controls: no token 401, wrong 401, second setup 403)
|
||||
gate files after the step: family-gate-grimmory.yml family-gate-metube.yml | a stranger at / -> LAN 401 | tunnel 401 | OPDS exception, a stranger -> LAN 401 | tunnel 401
|
||||
RESULT final_phase=done after={'grimmory': 'ghcr.io/grimmory-tools/grimmory:v3.5.0', 'grimmory-db': 'mariadb:11.4'} seed_after=True (58.5 s)
|
||||
@@ -0,0 +1,20 @@
|
||||
##### life on 9202 — controller gitea.dooplex.hu/admin/felhom-controller:0.287.0 | catalog e42bf78 DRILL grimmory: v3.5.0 (box step behind the family g | 2026-10-02T06:48:28Z
|
||||
before: gate files: family-gate-grimmory.yml family-gate-metube.yml
|
||||
2.5 the night chain (debug action) -> 202
|
||||
2026/10/02 06:49:04 night_chain.go:93: [INFO] [night-chain] finished in 33s
|
||||
grimmory restore points: [(None, '2026-10-02T06:48:32Z')]
|
||||
metube restore points: [(None, '2026-10-02T06:48:41Z')]
|
||||
remove grimmory (KEEPING data and backups) -> 200 {'ok': True, 'data': {'removed': 'grimmory', 'volumes_removed': ['grimmory_grimmory_db'], 'hdd_paths_removed': [], 'hdd_paths_preserved': ['/mnt/felhom-drives/scratch_hdd/userdata/grimmory/appdata/grimmory/data (4.0K)'], 'verified': True}, 'message': 'Stack gr
|
||||
left after: /opt/docker/stacks/grimmory | /mnt/felhom-drives/scratch_hdd/userdata/grimmory
|
||||
remove metube (KEEPING data and backups) -> 200 {'ok': True, 'data': {'removed': 'metube', 'volumes_removed': ['metube_metube_state'], 'hdd_paths_removed': [], 'hdd_paths_preserved': [], 'verified': True}, 'message': 'Stack metube removed'}
|
||||
left after: /opt/docker/stacks/metube | /mnt/felhom-drives/scratch_hdd/userdata/metube
|
||||
after both removes: gate files: none | a stranger at library/ -> LAN 404 | tunnel 404 | video/ -> LAN 404 | tunnel 404
|
||||
2.5 restore grimmory: {'ok': True, 'snapshot_id': 'helyi', 'seconds': 64.8, 'state_after': 'running', 'hold_after': None}
|
||||
2.5 restore metube: {'ok': True, 'snapshot_id': 'helyi', 'seconds': 38.5, 'state_after': 'running', 'hold_after': None}
|
||||
after both restores: gate files: family-gate-grimmory.yml family-gate-metube.yml
|
||||
family_gate record: family_gate: since: "2026-10-02T06:50:54Z" hosts: - library.enkisfelhom.hu | family_gate: since: "2026-10-02T06:52:01Z" hosts: - video.enkisfelhom.hu
|
||||
a STRANGER (no cookie): library/ -> LAN 401 | tunnel 401 | library/api/v1/books -> LAN 401 | tunnel 401 | video/ -> LAN 401 | tunnel 401 | video/history -> LAN 401 | tunnel 401
|
||||
grimmory: readback http=200 found=True (controls: no token 401, wrong 401, second setup 403)
|
||||
2.5 grimmory: the seed reads back after remove + restore (a member, then the app's own login): True
|
||||
metube: history has it=True; GET /download/<file> http=200
|
||||
2.5 metube: the seed reads back after remove + restore (a member, then the app's own login): True
|
||||
@@ -0,0 +1,628 @@
|
||||
epoch,name,id,anon,current,swap,oom_kill,limit,restarts
|
||||
1790922425,metube,24954133462d,38817792,45064192,0,0,805306368,0
|
||||
1790922427,metube,24954133462d,61632512,68804608,0,0,805306368,0
|
||||
1790922429,metube,24954133462d,61665280,69287936,0,0,805306368,0
|
||||
1790922431,metube,24954133462d,61665280,68931584,0,0,805306368,0
|
||||
1790922433,metube,24954133462d,61665280,68931584,0,0,805306368,0
|
||||
1790922435,metube,24954133462d,61665280,69197824,0,0,805306368,0
|
||||
1790922437,metube,24954133462d,61665280,68923392,0,0,805306368,0
|
||||
1790922439,metube,24954133462d,61665280,68923392,0,0,805306368,0
|
||||
1790922441,metube,24954133462d,61665280,68923392,0,0,805306368,0
|
||||
1790922444,metube,24954133462d,61665280,68923392,0,0,805306368,0
|
||||
1790922446,metube,24954133462d,61665280,68923392,0,0,805306368,0
|
||||
1790922448,metube,24954133462d,61665280,68337664,0,0,805306368,0
|
||||
1790922450,metube,24954133462d,85819392,95543296,0,0,805306368,0
|
||||
1790922452,metube,24954133462d,85819392,94728192,0,0,805306368,0
|
||||
1790922454,metube,24954133462d,86790144,95838208,0,0,805306368,0
|
||||
1790922456,metube,24954133462d,86790144,95834112,0,0,805306368,0
|
||||
1790922458,metube,24954133462d,86790144,95834112,0,0,805306368,0
|
||||
1790922460,metube,24954133462d,87060480,96108544,0,0,805306368,0
|
||||
1790922462,metube,24954133462d,87060480,96104448,0,0,805306368,0
|
||||
1790922464,metube,24954133462d,87060480,96104448,0,0,805306368,0
|
||||
1790922467,metube,24954133462d,87060480,96104448,0,0,805306368,0
|
||||
1790922469,metube,24954133462d,87060480,96104448,0,0,805306368,0
|
||||
1790922471,metube,24954133462d,87060480,96104448,0,0,805306368,0
|
||||
1790922473,metube,24954133462d,87060480,96378880,0,0,805306368,0
|
||||
1790922475,metube,24954133462d,87060480,96116736,0,0,805306368,0
|
||||
1790922477,metube,24954133462d,87064576,96649216,0,0,805306368,0
|
||||
1790922479,metube,24954133462d,87064576,96317440,0,0,805306368,0
|
||||
1790922481,metube,24954133462d,87060480,96083968,0,0,805306368,0
|
||||
1790922483,metube,24954133462d,87064576,96083968,0,0,805306368,0
|
||||
1790922550,metube,24954133462d,59383808,63049728,0,0,805306368,0
|
||||
1790922552,metube,24954133462d,59383808,62849024,0,0,805306368,0
|
||||
1790922555,metube,24954133462d,59428864,63455232,0,0,805306368,0
|
||||
1790922557,metube,24954133462d,59428864,63004672,0,0,805306368,0
|
||||
1790922559,metube,24954133462d,59428864,63000576,0,0,805306368,0
|
||||
1790922561,metube,24954133462d,59428864,63000576,0,0,805306368,0
|
||||
1790922563,metube,24954133462d,59428864,63000576,0,0,805306368,0
|
||||
1790922565,metube,24954133462d,59428864,63000576,0,0,805306368,0
|
||||
1790922567,metube,24954133462d,59428864,63000576,0,0,805306368,0
|
||||
1790922569,metube,24954133462d,59428864,63000576,0,0,805306368,0
|
||||
1790922571,metube,24954133462d,59428864,63000576,0,0,805306368,0
|
||||
1790922573,metube,24954133462d,59428864,63000576,0,0,805306368,0
|
||||
1790922575,metube,24954133462d,59428864,63000576,0,0,805306368,0
|
||||
1790922577,metube,24954133462d,59428864,63000576,0,0,805306368,0
|
||||
1790922579,metube,24954133462d,59428864,63000576,0,0,805306368,0
|
||||
1790922582,metube,24954133462d,59428864,63000576,0,0,805306368,0
|
||||
1790922584,metube,24954133462d,59428864,63000576,0,0,805306368,0
|
||||
1790922586,metube,24954133462d,59428864,63000576,0,0,805306368,0
|
||||
1790922588,metube,24954133462d,59428864,63000576,0,0,805306368,0
|
||||
1790922590,metube,94ba5b8a2311,16261120,21282816,0,0,805306368,0
|
||||
1790922592,metube,94ba5b8a2311,61636608,68218880,0,0,805306368,0
|
||||
1790922594,metube,94ba5b8a2311,61636608,68214784,0,0,805306368,0
|
||||
1790922596,metube,94ba5b8a2311,61669376,68333568,0,0,805306368,0
|
||||
1790922598,metube,94ba5b8a2311,61669376,68333568,0,0,805306368,0
|
||||
1790922600,metube,94ba5b8a2311,61669376,68333568,0,0,805306368,0
|
||||
1790922602,metube,94ba5b8a2311,61669376,68333568,0,0,805306368,0
|
||||
1790922605,metube,94ba5b8a2311,61669376,68333568,0,0,805306368,0
|
||||
1790922607,metube,94ba5b8a2311,61669376,68329472,0,0,805306368,0
|
||||
1790922609,metube,94ba5b8a2311,61669376,68329472,0,0,805306368,0
|
||||
1790922611,metube,94ba5b8a2311,61669376,68329472,0,0,805306368,0
|
||||
1790922613,metube,94ba5b8a2311,61669376,68329472,0,0,805306368,0
|
||||
1790922615,metube,94ba5b8a2311,57085952,63406080,0,0,805306368,0
|
||||
1790922618,metube,fbbc26704571,44728320,51138560,0,0,805306368,0
|
||||
1790922621,metube,fbbc26704571,61620224,68706304,0,0,805306368,0
|
||||
1790922623,metube,fbbc26704571,61657088,69545984,0,0,805306368,0
|
||||
1790922625,metube,fbbc26704571,61657088,68829184,0,0,805306368,0
|
||||
1790922627,metube,fbbc26704571,61657088,68829184,0,0,805306368,0
|
||||
1790922629,metube,fbbc26704571,61657088,68829184,0,0,805306368,0
|
||||
1790922631,metube,fbbc26704571,61657088,68829184,0,0,805306368,0
|
||||
1790922633,metube,fbbc26704571,61657088,68829184,0,0,805306368,0
|
||||
1790922635,metube,fbbc26704571,61661184,69570560,0,0,805306368,0
|
||||
1790922637,metube,fbbc26704571,61661184,69570560,0,0,805306368,0
|
||||
1790922639,metube,fbbc26704571,61661184,69570560,0,0,805306368,0
|
||||
1790922641,metube,fbbc26704571,61661184,69844992,0,0,805306368,0
|
||||
1790922643,metube,fbbc26704571,61661184,69844992,0,0,805306368,0
|
||||
1790922646,metube,fbbc26704571,61661184,69844992,0,0,805306368,0
|
||||
1790922648,metube,fbbc26704571,61661184,69844992,0,0,805306368,0
|
||||
1790922650,metube,fbbc26704571,61661184,69844992,0,0,805306368,0
|
||||
1790922652,metube,fbbc26704571,61661184,69844992,0,0,805306368,0
|
||||
1790922654,metube,fbbc26704571,61661184,70103040,0,0,805306368,0
|
||||
1790922656,metube,fbbc26704571,61730816,70615040,0,0,805306368,0
|
||||
1790922658,metube,fbbc26704571,61730816,70004736,0,0,805306368,0
|
||||
1790922660,metube,fbbc26704571,61730816,70004736,0,0,805306368,0
|
||||
1790922662,metube,fbbc26704571,61730816,70004736,0,0,805306368,0
|
||||
1790922664,metube,fbbc26704571,61730816,71557120,0,0,805306368,0
|
||||
1790922666,metube,fbbc26704571,61730816,71557120,0,0,805306368,0
|
||||
1790922668,metube,fbbc26704571,61730816,71557120,0,0,805306368,0
|
||||
1790922671,metube,fbbc26704571,61730816,71557120,0,0,805306368,0
|
||||
1790922673,metube,fbbc26704571,61730816,71557120,0,0,805306368,0
|
||||
1790922675,metube,fbbc26704571,61730816,71553024,0,0,805306368,0
|
||||
1790922677,metube,fbbc26704571,61730816,71553024,0,0,805306368,0
|
||||
1790922679,metube,fbbc26704571,61730816,71557120,0,0,805306368,0
|
||||
1790922681,metube,fbbc26704571,61730816,71557120,0,0,805306368,0
|
||||
1790922683,metube,fbbc26704571,61730816,71630848,0,0,805306368,0
|
||||
1790922685,metube,fbbc26704571,61730816,71561216,0,0,805306368,0
|
||||
1790922687,metube,fbbc26704571,61730816,71561216,0,0,805306368,0
|
||||
1790922689,metube,fbbc26704571,61730816,71561216,0,0,805306368,0
|
||||
1790922691,metube,fbbc26704571,61730816,71561216,0,0,805306368,0
|
||||
1790922693,metube,fbbc26704571,61730816,71557120,0,0,805306368,0
|
||||
1790922695,metube,fbbc26704571,61730816,71557120,0,0,805306368,0
|
||||
1790922698,metube,fbbc26704571,61730816,71557120,0,0,805306368,0
|
||||
1790922700,metube,fbbc26704571,61730816,71557120,0,0,805306368,0
|
||||
1790922702,metube,fbbc26704571,61730816,71557120,0,0,805306368,0
|
||||
1790922704,metube,fbbc26704571,61730816,71557120,0,0,805306368,0
|
||||
1790922706,metube,fbbc26704571,61730816,71557120,0,0,805306368,0
|
||||
1790922708,metube,fbbc26704571,61730816,71557120,0,0,805306368,0
|
||||
1790922710,metube,fbbc26704571,61730816,71553024,0,0,805306368,0
|
||||
1790922712,metube,fbbc26704571,61730816,71553024,0,0,805306368,0
|
||||
1790922714,metube,fbbc26704571,61730816,71553024,0,0,805306368,0
|
||||
1790922716,metube,fbbc26704571,61730816,71553024,0,0,805306368,0
|
||||
1790922718,metube,fbbc26704571,61730816,71553024,0,0,805306368,0
|
||||
1790922720,metube,fbbc26704571,61730816,71553024,0,0,805306368,0
|
||||
1790922723,metube,fbbc26704571,61730816,71553024,0,0,805306368,0
|
||||
1790922725,metube,fbbc26704571,61730816,71553024,0,0,805306368,0
|
||||
1790922727,metube,fbbc26704571,61730816,71553024,0,0,805306368,0
|
||||
1790922729,metube,fbbc26704571,61730816,71553024,0,0,805306368,0
|
||||
1790922731,metube,fbbc26704571,61730816,71553024,0,0,805306368,0
|
||||
1790922733,metube,fbbc26704571,61730816,71553024,0,0,805306368,0
|
||||
1790922735,metube,fbbc26704571,61730816,71553024,0,0,805306368,0
|
||||
1790922737,metube,fbbc26704571,61730816,71553024,0,0,805306368,0
|
||||
1790922739,metube,fbbc26704571,61730816,71553024,0,0,805306368,0
|
||||
1790922741,metube,fbbc26704571,61730816,71553024,0,0,805306368,0
|
||||
1790922743,metube,fbbc26704571,61730816,72122368,0,0,805306368,0
|
||||
1790922745,metube,fbbc26704571,61730816,71565312,0,0,805306368,0
|
||||
1790922748,metube,fbbc26704571,61730816,71553024,0,0,805306368,0
|
||||
1790922750,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790922752,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790922754,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790922756,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790922758,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790922760,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790922762,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790922764,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790922766,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790922768,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790922770,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790922773,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790922775,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790922777,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790922779,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790922781,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790922783,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790922785,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790922787,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790922789,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790922791,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790922793,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790922795,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790922797,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790922800,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790922802,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790922804,metube,fbbc26704571,61730816,72265728,0,0,805306368,0
|
||||
1790922806,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790922808,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790922810,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790922812,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790922814,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790922816,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790922818,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790922820,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790922822,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790922825,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790922827,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790922829,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790922831,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790922833,metube,fbbc26704571,61730816,71987200,0,0,805306368,0
|
||||
1790922835,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790922837,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790922839,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790922841,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790922843,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790922845,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790922847,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790922850,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790922852,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790922854,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790922856,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790922858,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790922860,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790922862,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790922864,metube,fbbc26704571,61730816,72355840,0,0,805306368,0
|
||||
1790922866,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790922868,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790922870,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790922872,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790922874,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790922877,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790922879,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790922881,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790922883,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790922885,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790922887,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790922889,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790922891,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790922893,metube,fbbc26704571,61730816,72036352,0,0,805306368,0
|
||||
1790922895,metube,fbbc26704571,61730816,71573504,0,0,805306368,0
|
||||
1790922897,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790922899,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790922901,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790922904,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790922906,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790922908,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790922910,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790922912,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790922914,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790922916,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790922918,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790922920,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790922922,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790922924,metube,fbbc26704571,61730816,71684096,0,0,805306368,0
|
||||
1790922927,metube,fbbc26704571,61730816,71553024,0,0,805306368,0
|
||||
1790922929,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790922931,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790922933,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790922935,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790922937,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790922939,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790922941,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790922943,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790922945,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790922947,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790922949,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790922952,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790922954,metube,fbbc26704571,61730816,71688192,0,0,805306368,0
|
||||
1790922956,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790922958,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790922960,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790922962,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790922964,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790922966,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790922968,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790922970,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790922972,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790922974,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790922977,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790922979,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790922981,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790922983,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790922985,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790922987,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790922989,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790922991,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790922993,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790922995,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790922997,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790922999,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923001,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923004,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923006,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923008,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923010,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923012,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923014,metube,fbbc26704571,61730816,71630848,0,0,805306368,0
|
||||
1790923016,metube,fbbc26704571,61730816,71553024,0,0,805306368,0
|
||||
1790923018,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923020,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923022,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923024,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923026,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923029,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923031,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923033,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923035,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923037,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923039,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923041,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923043,metube,fbbc26704571,61730816,71811072,0,0,805306368,0
|
||||
1790923045,metube,fbbc26704571,61730816,71614464,0,0,805306368,0
|
||||
1790923047,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923049,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923051,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923054,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923056,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923058,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923060,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923062,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923064,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923066,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923068,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923070,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923072,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923074,metube,fbbc26704571,61730816,71802880,0,0,805306368,0
|
||||
1790923077,metube,fbbc26704571,61730816,71802880,0,0,805306368,0
|
||||
1790923079,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923081,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923083,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923085,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923087,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923089,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923091,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923093,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923095,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923097,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923099,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923101,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923104,metube,fbbc26704571,61730816,71905280,0,0,805306368,0
|
||||
1790923106,metube,fbbc26704571,61730816,71671808,0,0,805306368,0
|
||||
1790923108,metube,fbbc26704571,61730816,71557120,0,0,805306368,0
|
||||
1790923110,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923112,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923114,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923116,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923118,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923120,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923122,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923124,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923126,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923128,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923131,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923133,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923135,metube,fbbc26704571,61730816,71909376,0,0,805306368,0
|
||||
1790923137,metube,fbbc26704571,61730816,71811072,0,0,805306368,0
|
||||
1790923139,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923141,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923143,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923145,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923147,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923149,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923151,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923153,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923155,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923158,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923160,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923162,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923164,metube,fbbc26704571,61730816,72138752,0,0,805306368,0
|
||||
1790923166,metube,fbbc26704571,61730816,71725056,0,0,805306368,0
|
||||
1790923168,metube,fbbc26704571,61730816,71725056,0,0,805306368,0
|
||||
1790923170,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923172,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923174,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923176,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923178,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923180,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923182,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923185,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923187,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923189,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923191,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923193,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923195,metube,fbbc26704571,61730816,71663616,0,0,805306368,0
|
||||
1790923197,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923199,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923201,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923203,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923205,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923207,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923210,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923212,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923214,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923216,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923218,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923220,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923222,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923224,metube,fbbc26704571,61730816,72069120,0,0,805306368,0
|
||||
1790923226,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923228,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923230,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923232,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923234,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923237,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923239,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923241,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923243,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923245,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923247,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923249,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923251,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923253,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923255,metube,fbbc26704571,61730816,71798784,0,0,805306368,0
|
||||
1790923257,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923259,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923262,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923264,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923266,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923268,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923270,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923272,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923274,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923276,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923278,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923280,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923282,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923284,metube,fbbc26704571,61730816,71815168,0,0,805306368,0
|
||||
1790923286,metube,fbbc26704571,61730816,71553024,0,0,805306368,0
|
||||
1790923289,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923291,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923293,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923295,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923297,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923299,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923301,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923303,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923305,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923307,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923309,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923311,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923314,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923316,metube,fbbc26704571,61730816,71716864,0,0,805306368,0
|
||||
1790923318,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923320,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923322,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923324,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923326,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923328,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923330,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923332,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923334,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923336,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923338,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923341,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923343,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923345,metube,fbbc26704571,61730816,71766016,0,0,805306368,0
|
||||
1790923347,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923349,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923351,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923353,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923355,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923357,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923359,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923361,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923363,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923365,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923368,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923370,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923372,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923374,metube,fbbc26704571,64618496,76144640,0,0,805306368,0
|
||||
1790923376,metube,fbbc26704571,61730816,71553024,0,0,805306368,0
|
||||
1790923378,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923380,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923382,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923384,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923386,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923388,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923390,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923392,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923395,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923397,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923399,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923401,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923403,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923405,metube,fbbc26704571,61730816,72024064,0,0,805306368,0
|
||||
1790923407,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923409,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923411,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923413,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923415,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923417,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923420,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923422,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923424,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923426,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923428,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923430,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923432,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923434,metube,fbbc26704571,61730816,72056832,0,0,805306368,0
|
||||
1790923436,metube,fbbc26704571,61730816,71766016,0,0,805306368,0
|
||||
1790923438,metube,fbbc26704571,61730816,71553024,0,0,805306368,0
|
||||
1790923440,metube,fbbc26704571,61730816,71553024,0,0,805306368,0
|
||||
1790923442,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923444,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923447,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923449,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923451,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923453,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923455,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923457,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923459,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923461,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923463,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923465,metube,fbbc26704571,61730816,71847936,0,0,805306368,0
|
||||
1790923467,metube,fbbc26704571,61730816,71553024,0,0,805306368,0
|
||||
1790923469,metube,fbbc26704571,61730816,71553024,0,0,805306368,0
|
||||
1790923471,metube,fbbc26704571,61730816,71553024,0,0,805306368,0
|
||||
1790923474,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923476,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923478,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923480,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923482,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923484,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923486,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923488,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923490,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923492,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923494,metube,fbbc26704571,61730816,71979008,0,0,805306368,0
|
||||
1790923496,metube,fbbc26704571,61730816,71553024,0,0,805306368,0
|
||||
1790923499,metube,fbbc26704571,61730816,71553024,0,0,805306368,0
|
||||
1790923501,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923503,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923505,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923507,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923509,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923511,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923513,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923515,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923517,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923519,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923521,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923523,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923526,metube,fbbc26704571,61730816,71802880,0,0,805306368,0
|
||||
1790923528,metube,fbbc26704571,61730816,71778304,0,0,805306368,0
|
||||
1790923530,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923532,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923534,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923536,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923538,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923540,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923542,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923544,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923546,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923548,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923550,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923553,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923555,metube,fbbc26704571,61730816,72073216,0,0,805306368,0
|
||||
1790923557,metube,fbbc26704571,61730816,71561216,0,0,805306368,0
|
||||
1790923559,metube,fbbc26704571,61730816,71557120,0,0,805306368,0
|
||||
1790923561,metube,fbbc26704571,61730816,71557120,0,0,805306368,0
|
||||
1790923563,metube,fbbc26704571,61730816,71553024,0,0,805306368,0
|
||||
1790923565,metube,fbbc26704571,61730816,71553024,0,0,805306368,0
|
||||
1790923567,metube,fbbc26704571,61730816,71553024,0,0,805306368,0
|
||||
1790923569,metube,fbbc26704571,61730816,71553024,0,0,805306368,0
|
||||
1790923571,metube,fbbc26704571,61730816,71553024,0,0,805306368,0
|
||||
1790923573,metube,fbbc26704571,61730816,71553024,0,0,805306368,0
|
||||
1790923575,metube,fbbc26704571,61730816,71553024,0,0,805306368,0
|
||||
1790923578,metube,fbbc26704571,61730816,71553024,0,0,805306368,0
|
||||
1790923580,metube,fbbc26704571,61730816,71553024,0,0,805306368,0
|
||||
1790923582,metube,fbbc26704571,61730816,71553024,0,0,805306368,0
|
||||
1790923584,metube,fbbc26704571,61730816,71553024,0,0,805306368,0
|
||||
1790923586,metube,fbbc26704571,61730816,71675904,0,0,805306368,0
|
||||
1790923588,metube,fbbc26704571,61730816,71585792,0,0,805306368,0
|
||||
1790923590,metube,fbbc26704571,61730816,71553024,0,0,805306368,0
|
||||
1790923592,metube,fbbc26704571,61730816,71553024,0,0,805306368,0
|
||||
1790923594,metube,fbbc26704571,61730816,71553024,0,0,805306368,0
|
||||
1790923596,metube,fbbc26704571,61730816,71553024,0,0,805306368,0
|
||||
1790923598,metube,fbbc26704571,61730816,71553024,0,0,805306368,0
|
||||
1790923600,metube,fbbc26704571,61730816,71553024,0,0,805306368,0
|
||||
1790923602,metube,fbbc26704571,61730816,71553024,0,0,805306368,0
|
||||
1790923605,metube,fbbc26704571,61730816,71553024,0,0,805306368,0
|
||||
1790923607,metube,fbbc26704571,61730816,71553024,0,0,805306368,0
|
||||
1790923609,metube,fbbc26704571,61730816,71553024,0,0,805306368,0
|
||||
1790923611,metube,fbbc26704571,61730816,71553024,0,0,805306368,0
|
||||
1790923613,metube,fbbc26704571,61730816,71553024,0,0,805306368,0
|
||||
1790923615,metube,fbbc26704571,61730816,71880704,0,0,805306368,0
|
||||
1790923617,metube,fbbc26704571,61730816,71553024,0,0,805306368,0
|
||||
1790923619,metube,fbbc26704571,61730816,71553024,0,0,805306368,0
|
||||
1790923621,metube,fbbc26704571,61730816,71553024,0,0,805306368,0
|
||||
1790923623,metube,fbbc26704571,61730816,71553024,0,0,805306368,0
|
||||
1790923625,metube,fbbc26704571,61730816,71553024,0,0,805306368,0
|
||||
1790923627,metube,fbbc26704571,61730816,71553024,0,0,805306368,0
|
||||
1790923630,metube,fbbc26704571,61730816,71553024,0,0,805306368,0
|
||||
1790923632,metube,fbbc26704571,61730816,71815168,0,0,805306368,0
|
||||
1790923634,metube,fbbc26704571,61730816,71553024,0,0,805306368,0
|
||||
1790923636,metube,fbbc26704571,61730816,71553024,0,0,805306368,0
|
||||
1790923638,metube,fbbc26704571,61730816,71553024,0,0,805306368,0
|
||||
1790923640,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923642,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923644,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923646,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923648,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923650,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923653,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923655,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923657,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923659,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923661,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923663,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923665,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923667,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923669,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923671,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923673,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923675,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923678,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923680,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923682,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923684,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923686,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923688,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923690,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923692,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923694,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923696,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923698,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923700,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923702,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923705,metube,fbbc26704571,61730816,72134656,0,0,805306368,0
|
||||
1790923707,metube,fbbc26704571,61730816,71569408,0,0,805306368,0
|
||||
1790923709,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923711,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923713,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923715,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923717,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923719,metube,fbbc26704571,61730816,71548928,0,0,805306368,0
|
||||
1790923723,metube,874b43d7ca42,41361408,47796224,0,0,805306368,0
|
||||
1790923725,metube,874b43d7ca42,61632512,68202496,0,0,805306368,0
|
||||
1790923727,metube,874b43d7ca42,61669376,68382720,0,0,805306368,0
|
||||
1790923730,metube,874b43d7ca42,61669376,68218880,0,0,805306368,0
|
||||
1790923732,metube,874b43d7ca42,61669376,68214784,0,0,805306368,0
|
||||
1790923734,metube,874b43d7ca42,61669376,68214784,0,0,805306368,0
|
||||
1790923736,metube,874b43d7ca42,61669376,68218880,0,0,805306368,0
|
||||
1790923738,metube,874b43d7ca42,61669376,68218880,0,0,805306368,0
|
||||
1790923740,metube,874b43d7ca42,61669376,68214784,0,0,805306368,0
|
||||
1790923742,metube,874b43d7ca42,61669376,68214784,0,0,805306368,0
|
||||
1790923744,metube,874b43d7ca42,61669376,68214784,0,0,805306368,0
|
||||
1790923746,metube,874b43d7ca42,61669376,68214784,0,0,805306368,0
|
||||
1790923748,metube,874b43d7ca42,61669376,68214784,0,0,805306368,0
|
||||
1790923750,metube,874b43d7ca42,61669376,68214784,0,0,805306368,0
|
||||
1790923753,metube,874b43d7ca42,61669376,68214784,0,0,805306368,0
|
||||
1790923755,metube,874b43d7ca42,61669376,68214784,0,0,805306368,0
|
||||
1790923757,metube,874b43d7ca42,61669376,68214784,0,0,805306368,0
|
||||
1790923759,metube,874b43d7ca42,61669376,68591616,0,0,805306368,0
|
||||
1790923761,metube,874b43d7ca42,61669376,68366336,0,0,805306368,0
|
||||
1790923763,metube,874b43d7ca42,61669376,68218880,0,0,805306368,0
|
||||
1790923765,metube,874b43d7ca42,61669376,68218880,0,0,805306368,0
|
||||
1790923767,metube,874b43d7ca42,61669376,68218880,0,0,805306368,0
|
||||
1790923769,metube,874b43d7ca42,61669376,68218880,0,0,805306368,0
|
||||
1790923771,metube,874b43d7ca42,61669376,68218880,0,0,805306368,0
|
||||
1790923774,metube,874b43d7ca42,61669376,68218880,0,0,805306368,0
|
||||
1790923776,metube,874b43d7ca42,61669376,68218880,0,0,805306368,0
|
||||
1790923778,metube,874b43d7ca42,61669376,68218880,0,0,805306368,0
|
||||
1790923780,metube,874b43d7ca42,61669376,68218880,0,0,805306368,0
|
||||
1790923782,metube,874b43d7ca42,61669376,68218880,0,0,805306368,0
|
||||
1790923784,metube,874b43d7ca42,61669376,68218880,0,0,805306368,0
|
||||
1790923786,metube,874b43d7ca42,61669376,68218880,0,0,805306368,0
|
||||
1790923788,metube,874b43d7ca42,61673472,68222976,0,0,805306368,0
|
||||
1790923790,metube,874b43d7ca42,61673472,68222976,0,0,805306368,0
|
||||
1790923792,metube,874b43d7ca42,61673472,68222976,0,0,805306368,0
|
||||
1790923794,metube,874b43d7ca42,61673472,68222976,0,0,805306368,0
|
||||
1790923796,metube,874b43d7ca42,61673472,68222976,0,0,805306368,0
|
||||
|
@@ -0,0 +1,8 @@
|
||||
##### metube-fresh on 9202 — controller gitea.dooplex.hu/admin/felhom-controller:0.287.0 | catalog c3f433f DRILL: grimmory + metube behind the family gate (0.2 | 2026-10-02T06:12:26Z
|
||||
remove metube (WITH data and backups) -> 409 {'ok': False, 'error': 'A(z) /mnt/felhom-drives/scratch_hdd/userdata/metube tárhely jelenleg nem elérhető — az alkalmazás nem távolítható el, amíg a meghajtó vissza nem csatlakozik.'}
|
||||
left after: /opt/docker/stacks/metube | metube_metube_state | /mnt/felhom-drives/scratch_hdd/userdata/metube
|
||||
drill: 08348b6 DRILL metube: ghcr.io/alexta69/metube:2026.09.28 (box proof, family gate 2026-10-02)
|
||||
the box's catalog now pins: image: ghcr.io/alexta69/metube:2026.09.28
|
||||
guest swap: Swap: 512 19 492 (the swap-0 venue for 5.1 is the bench)
|
||||
deploy metube -> True (0 s to `deployed`)
|
||||
gate files right after the deploy: family-gate-grimmory.yml family-gate-metube.yml
|
||||
@@ -0,0 +1,5 @@
|
||||
##### metube-fresh on 9202 — controller gitea.dooplex.hu/admin/felhom-controller:0.287.0 | catalog 08348b6 DRILL metube: ghcr.io/alexta69/metube:2026.09.28 (bo | 2026-10-02T06:24:15Z
|
||||
remove metube (WITH data and backups) -> 409 {'ok': False, 'error': 'A(z) /mnt/felhom-drives/scratch_hdd/userdata/metube tárhely jelenleg nem elérhető — az alkalmazás nem távolítható el, amíg a meghajtó vissza nem csatlakozik.'}
|
||||
refused (R-442, no agent on 9202) — remove metube KEEPING drive data -> 200 {'ok': True, 'data': {'removed': 'metube', 'volumes_removed': ['metube_metube_state'], 'hdd_paths_removed': [], 'hdd_paths_preserved': [], 'backup_paths_removed': ['/mnt/felhom-drives/scratch_hdd/user
|
||||
the harness removed its own test folder /mnt/felhom-drives/scratch_hdd/userdata/metube by hand
|
||||
left after: /opt/docker/stacks/metube
|
||||
@@ -0,0 +1,22 @@
|
||||
##### metube-fresh on 9202 — controller gitea.dooplex.hu/admin/felhom-controller:0.287.0 | catalog 08348b6 DRILL metube: ghcr.io/alexta69/metube:2026.09.28 (bo | 2026-10-02T06:26:13Z
|
||||
drill: already pins ghcr.io/alexta69/metube:2026.09.28 — nothing to commit
|
||||
the box's catalog now pins: image: ghcr.io/alexta69/metube:2026.09.28
|
||||
guest swap: Swap: 512 19 492 (the swap-0 venue for 5.1 is the bench)
|
||||
deploy metube -> True (43 s to `deployed`)
|
||||
gate files right after the deploy: family-gate-grimmory.yml family-gate-metube.yml
|
||||
4.3 healthy 50 s after the press; restarts: 0 | state: running | image: ghcr.io/alexta69/metube:2026.09.28
|
||||
metube: POST /add http=200 {"status": "ok"}
|
||||
metube: the download finished (991017 bytes)
|
||||
metube: history has it=True; GET /download/<file> http=200
|
||||
C1 the seed reads back: True
|
||||
3.3/3.5 a stranger's 63 polls (GET / and POST /add, 1/s) from the press, no cookie: codes {'404 404': 37, '401 401': 26}; any app answer (200): False
|
||||
2.2/2.8 where the download landed (the household's drive, browsable): /mnt/felhom-drives/scratch_hdd/userdata/metube/userdata/media/metube/Big_Buck_Bunny_360_10s_1MB.mp4 | owner: 1000:1000 644
|
||||
2.7 sizes: metube_metube_state=12K 984K /mnt/felhom-drives/scratch_hdd/userdata/metube
|
||||
1.5 process: /usr/bin/tini -g -- ./docker-entrypoint.sh | children: OCI runtime exec failed: exec failed: unable to start container process: exec: "ps": executable file not found in $PATH
|
||||
1.8 unknown page (a member): http=404 traceback=False
|
||||
0.4 outbound connections held at rest: 050012AC:B05E
|
||||
0.4/0.5 hosts named in the first-start log: ['test-videos.co.uk']
|
||||
4.4 negative control: docker STOP metube — state before: running
|
||||
states while stopped (s, state): [(5, 'running'), (10, 'stopped')]; a member at / -> 404
|
||||
running again 10 s after docker start
|
||||
1.5 (read again from /proc, 2026-10-02T06:29Z): the server process is `python3 app/main.py` (aiohttp, MeTube's production server) under tini; yt-dlp runs in-process — no development server
|
||||
@@ -0,0 +1,33 @@
|
||||
##### metube-step on 9202 — controller gitea.dooplex.hu/admin/felhom-controller:0.287.0 | catalog 08348b6 DRILL metube: ghcr.io/alexta69/metube:2026.09.28 (bo | 2026-10-02T06:29:39Z
|
||||
before: pinned={'metube': 'ghcr.io/alexta69/metube:2026.09.28'}
|
||||
drill: 3d8b76d DRILL metube: ghcr.io/alexta69/metube:2026.09.29 (box proof, family gate 2026-10-02)
|
||||
phase +0.0s backing-up | err=None
|
||||
phase +2.1s safety-dump | err=None
|
||||
phase +3.1s pulling | err=None
|
||||
phase +26.7s copying | err=None
|
||||
phase +28.7s starting | err=None
|
||||
phase +29.7s verifying | err=None
|
||||
phase +34.9s done | err=None
|
||||
metube: history has it=True; GET /download/<file> http=200
|
||||
2026/10/02 06:29:48 update.go:536: [INFO] [stacks] update metube: accepted — guarded update started
|
||||
2026/10/02 06:29:48 update.go:1375: [INFO] [stacks] update metube: phase checking
|
||||
2026/10/02 06:29:48 update.go:793: [INFO] [stacks] update metube: ladder — the last step (1 of 1) — the catalog's current definition
|
||||
2026/10/02 06:29:48 update.go:823: [INFO] [stacks] update metube: no usable copy on any tier — younger than 24h0m0s and not older than this install's deploy (2026-10-02T06:26:35Z) (found: none) — backing up first
|
||||
2026/10/02 06:29:48 update.go:1375: [INFO] [stacks] update metube: phase backing-up
|
||||
2026/10/02 06:29:50 update.go:838: [INFO] [stacks] update metube: precondition met after the backup — Tier 2 (second drive) copy from 2026-10-02T06:29:49Z
|
||||
2026/10/02 06:29:50 update.go:1375: [INFO] [stacks] update metube: phase safety-dump
|
||||
2026/10/02 06:29:50 update.go:853: [INFO] [stacks] update metube: safety dump done (0 file(s)) []
|
||||
2026/10/02 06:29:50 undo.go:287: [INFO] [stacks] update metube: the undo copy will hold 1 named volume(s), 0.0 MiB
|
||||
2026/10/02 06:29:50 update.go:1375: [INFO] [stacks] update metube: phase pinning
|
||||
2026/10/02 06:29:50 pin.go:373: [INFO] [stacks] update metube: pin advanced to /opt/docker/felhom-controller/data/catalog-cache/templates/metube/docker-compose.yml (metube=ghcr.io/alexta69/metube:2026.09.29)
|
||||
2026/10/02 06:29:50 update.go:1375: [INFO] [stacks] update metube: phase pulling
|
||||
2026/10/02 06:30:15 update.go:1375: [INFO] [stacks] update metube: phase copying
|
||||
2026/10/02 06:30:16 update.go:1375: [INFO] [stacks] update metube: phase copying
|
||||
2026/10/02 06:30:17 undo.go:437: [INFO] [stacks] update metube: copied metube_metube_state → metube_metube_state.pre-update-20261002T063016Z in 453ms
|
||||
2026/10/02 06:30:17 update.go:1375: [INFO] [stacks] update metube: phase starting
|
||||
2026/10/02 06:30:17 update.go:1375: [INFO] [stacks] update metube: phase verifying
|
||||
2026/10/02 06:30:22 update.go:1004: [INFO] [stacks] update metube: healthy after 5s (the app's health check passed)
|
||||
2026/10/02 06:30:23 update.go:1040: [INFO] [stacks] update metube: DONE in 34s
|
||||
|
||||
gate files after the step: family-gate-grimmory.yml family-gate-metube.yml | a stranger at / -> LAN 401 | tunnel 401
|
||||
RESULT final_phase=done after={'metube': 'ghcr.io/alexta69/metube:2026.09.29'} seed_after=True verdict=proven (34.9 s)
|
||||
@@ -0,0 +1,63 @@
|
||||
06:26:31 404 404
|
||||
06:26:32 404 404
|
||||
06:26:33 404 404
|
||||
06:26:34 404 404
|
||||
06:26:35 404 404
|
||||
06:26:36 404 404
|
||||
06:26:38 404 404
|
||||
06:26:39 404 404
|
||||
06:26:40 404 404
|
||||
06:26:41 404 404
|
||||
06:26:42 404 404
|
||||
06:26:43 404 404
|
||||
06:26:44 404 404
|
||||
06:26:45 404 404
|
||||
06:26:46 404 404
|
||||
06:26:47 404 404
|
||||
06:26:48 404 404
|
||||
06:26:49 404 404
|
||||
06:26:50 404 404
|
||||
06:26:51 404 404
|
||||
06:26:52 404 404
|
||||
06:26:53 404 404
|
||||
06:26:54 404 404
|
||||
06:26:55 404 404
|
||||
06:26:56 404 404
|
||||
06:26:57 404 404
|
||||
06:26:59 404 404
|
||||
06:27:00 404 404
|
||||
06:27:01 404 404
|
||||
06:27:02 404 404
|
||||
06:27:03 404 404
|
||||
06:27:04 404 404
|
||||
06:27:05 404 404
|
||||
06:27:06 404 404
|
||||
06:27:07 404 404
|
||||
06:27:08 404 404
|
||||
06:27:09 404 404
|
||||
06:27:10 401 401
|
||||
06:27:11 401 401
|
||||
06:27:12 401 401
|
||||
06:27:13 401 401
|
||||
06:27:14 401 401
|
||||
06:27:15 401 401
|
||||
06:27:16 401 401
|
||||
06:27:17 401 401
|
||||
06:27:19 401 401
|
||||
06:27:20 401 401
|
||||
06:27:21 401 401
|
||||
06:27:22 401 401
|
||||
06:27:23 401 401
|
||||
06:27:24 401 401
|
||||
06:27:25 401 401
|
||||
06:27:26 401 401
|
||||
06:27:27 401 401
|
||||
06:27:28 401 401
|
||||
06:27:29 401 401
|
||||
06:27:30 401 401
|
||||
06:27:31 401 401
|
||||
06:27:32 401 401
|
||||
06:27:33 401 401
|
||||
06:27:34 401 401
|
||||
06:27:35 401 401
|
||||
06:27:36 401 401
|
||||
@@ -0,0 +1,111 @@
|
||||
# catalog_gates.py grimmory - 2026-10-02T07:03:03Z, bench LXC 9401 on demo-hp (debian-13, swap 0, nvme-scratch), catalog-wt de0a9bd + uncommitted working tree (13 path(s), copied with its .git), sibling felhom.eu 68c2290 (git archive HEAD of DooPlex tree = origin/main) at ../felhom.eu
|
||||
# sibling copy ALSO carries rsync/tar copies of DooPlex UNCOMMITTED documentation/audits/family-gate-2026-10-02/ and documentation/audits/licences-2026-10-02/; B/catalog-gates-grimmory.txt and B/catalog-gates-metube.txt were one-line PLACEHOLDER files in the bench sibling before the run (the onboarding records cite them) - this file is the real output that replaces the placeholder
|
||||
M FIRST-ADMIN.md
|
||||
M README.md
|
||||
M REUSE.md
|
||||
M scripts/box_walk.py
|
||||
M scripts/catalog_gates.py
|
||||
M scripts/copy_freeze/hu.json
|
||||
M scripts/test_gate_decoys.py
|
||||
M scripts/upgrade_fixtures_box.py
|
||||
?? onboarding/grimmory.md
|
||||
?? onboarding/metube.md
|
||||
?? scripts/check-family-gate.py
|
||||
?? templates/grimmory/
|
||||
?? templates/metube/
|
||||
catalog_gates — apps: grimmory
|
||||
|
||||
==============================================================================
|
||||
== gate: image-pins (check-image-pins.py)
|
||||
==============================================================================
|
||||
image-pin gate OK — 58 templates, 0 unpinned images
|
||||
|
||||
==============================================================================
|
||||
== gate: image-resolvable (check-image-resolvable.py grimmory)
|
||||
==============================================================================
|
||||
resolving 2 unique image pin(s)…
|
||||
image-resolvability gate OK — 2 unique pins, all resolve
|
||||
|
||||
==============================================================================
|
||||
== gate: volume-persistence (check-volume-persistence.py grimmory)
|
||||
==============================================================================
|
||||
self-testing the prober (both directions)…
|
||||
prober flags the R-156 signature and clears a correct template — trustworthy
|
||||
grimmory CLEAN grimmory: this container's mounts are all empty while it created entries in ['/', '/app', '/etc'] — benign when a sibling container holds the state, w
|
||||
|
||||
1 clean · 0 broken · 0 undetermined (of 1 in scope)
|
||||
volume-persistence gate OK
|
||||
|
||||
==============================================================================
|
||||
== gate: engine-major (check-engine-major.py)
|
||||
==============================================================================
|
||||
engine-major gate — range origin/main..HEAD: 0 compose file(s) changed, 0 engine pin(s) compared
|
||||
engine-major gate OK — no forbidden engine major, and no engine major bundled with another image move (rule: CLAUDE.md, amended by R-469 2026-09-21)
|
||||
|
||||
==============================================================================
|
||||
== gate: catalog-since (check-catalog-since.py)
|
||||
==============================================================================
|
||||
catalog-since gate — range origin/main..HEAD: 0 compose file(s) changed, 0 image move(s) dated
|
||||
catalog-since gate OK — every image move in the range carries a catalog_since on or after its commit day
|
||||
|
||||
==============================================================================
|
||||
== gate: copy-i18n (check-copy-i18n.py grimmory)
|
||||
==============================================================================
|
||||
copy-i18n: matcher controls OK (positive „Jelentkezz be…" convicts, negative „Encrypted notes…" does not)
|
||||
copy-i18n: retrieval-promise vocabulary matches the sibling clone
|
||||
copy-i18n: 58 apps · 1155 Hungarian copy strings frozen · 1154 with English
|
||||
copy-i18n: translated so far — actualbudget 15/15, adventurelog 18/18, audiobookshelf 21/21, bentopdf 14/14, bookstack 21/21, calcom 22/22, calibre-web 27/27, claper 20/20, code-server 20/20, crafty-controller 24/24, dawarich 21/21, docmost 19/19, emby 22/22, ghost 16/16, gitea 17/17, glance 15/15, gokapi 19/19, grafana 19/19, gramps-web 17/17, grimmory 24/24, home-assistant 18/18, homebox 17/17, homepage 15/15, immich 24/24, jellyfin 22/22, karakeep 19/19, kimai 20/20, komga 21/21, mealie 19/19, metube 19/19, n8n 17/17, navidrome 21/21, nextcloud 28/28, onlyoffice 24/24, opengist 16/16, outline 21/21, paperless-ngx 33/33, papra 14/15, plant-it 16/16, plex 25/25, privatebin 14/14, radarr 22/22, radicale 19/19, rallly 17/17, recipe-importer 19/19, romm 41/41, seerr 18/18, sonarr 22/22, sparkyfitness 21/21, tandoor 18/18, termix 12/12, uptime-kuma 16/16, vaultwarden 23/23, vikunja 18/18, wanderer 20/20, wger 20/20, wishlist 16/16, zipline 18/18
|
||||
copy-i18n: OK
|
||||
|
||||
==============================================================================
|
||||
== gate: probe-matches-compose (check-probe-matches-compose.py grimmory)
|
||||
==============================================================================
|
||||
probe-matches-compose: 1 app(s), mode: full
|
||||
|
||||
probe-matches-compose: OK — every probe dials the port (and, where it can fail, the path) that the app's own compose healthcheck dials
|
||||
|
||||
==============================================================================
|
||||
== gate: probe-measured (check-probe-measured.py grimmory)
|
||||
==============================================================================
|
||||
probe-measured: OK — 1 probes, each with a measured before/after
|
||||
|
||||
==============================================================================
|
||||
== gate: test-record (check-test-record.py grimmory)
|
||||
==============================================================================
|
||||
test-record gate — 1 template(s) read, 1 carry a ladder, 0 convicted
|
||||
|
||||
==============================================================================
|
||||
== gate: test-record-move (check-test-record-move.py)
|
||||
==============================================================================
|
||||
test-record-move gate — range origin/main..HEAD: 0 compose file(s) changed
|
||||
|
||||
==============================================================================
|
||||
== gate: onboarding (check-onboarding.py)
|
||||
==============================================================================
|
||||
onboarding gate — 61 checklist ids; 58 template dirs: 53 exempt (published before 2026-10-01), 5 new; 2 exempt app(s) with a record (shape-checked): sparkyfitness, wger
|
||||
onboarding gate OK
|
||||
|
||||
==============================================================================
|
||||
== gate: family-gate (check-family-gate.py)
|
||||
==============================================================================
|
||||
family-gate: newest baked golden 0.287.0 >= 0.287.0
|
||||
family-gate gate OK: 2 family-gated template(s) ['grimmory', 'metube']
|
||||
|
||||
==============================================================================
|
||||
== summary
|
||||
==============================================================================
|
||||
image-pins OK (exit 0)
|
||||
image-resolvable OK (exit 0)
|
||||
volume-persistence OK (exit 0)
|
||||
engine-major OK (exit 0)
|
||||
catalog-since OK (exit 0)
|
||||
copy-i18n OK (exit 0)
|
||||
probe-matches-compose OK (exit 0)
|
||||
probe-measured OK (exit 0)
|
||||
test-record OK (exit 0)
|
||||
test-record-move OK (exit 0)
|
||||
onboarding OK (exit 0)
|
||||
family-gate OK (exit 0)
|
||||
|
||||
all catalog gates OK
|
||||
catalog_gates exit code = 0
|
||||
@@ -0,0 +1,117 @@
|
||||
# catalog_gates.py grimmory - 2026-10-02T07:29:41Z, after the R-801 port fix, bench LXC 9401 on demo-hp (debian-13, swap 0, nvme-scratch), catalog-wt de0a9bd + uncommitted working tree (17 path(s), REFRESHED copy with R-788 APP_EXERCISE + R-801 routed_ports, copied with its .git), sibling felhom.eu 68c2290 (git archive) at ../felhom.eu
|
||||
# sibling copy ALSO carries tar copies of DooPlex UNCOMMITTED documentation/audits/family-gate-2026-10-02/ and documentation/audits/licences-2026-10-02/; in the bench sibling B/catalog-gates-grimmory.txt = copy of catalog-gates-grimmory-run1.txt and B/catalog-gates-metube.txt = copy of catalog-gates-metube-run2.txt so the onboarding citations resolve
|
||||
# the previous output of this file is kept as catalog-gates-grimmory-run1.txt
|
||||
M CHANGELOG.md
|
||||
M CONTEXT.md
|
||||
M FIRST-ADMIN.md
|
||||
M README.md
|
||||
M REUSE.md
|
||||
M scripts/box_walk.py
|
||||
M scripts/catalog_gates.py
|
||||
M scripts/check-volume-persistence.py
|
||||
M scripts/copy_freeze/hu.json
|
||||
M scripts/test_check_volume_persistence.py
|
||||
M scripts/test_gate_decoys.py
|
||||
M scripts/upgrade_fixtures_box.py
|
||||
?? onboarding/grimmory.md
|
||||
?? onboarding/metube.md
|
||||
?? scripts/check-family-gate.py
|
||||
?? templates/grimmory/
|
||||
?? templates/metube/
|
||||
catalog_gates — apps: grimmory
|
||||
|
||||
==============================================================================
|
||||
== gate: image-pins (check-image-pins.py)
|
||||
==============================================================================
|
||||
image-pin gate OK — 58 templates, 0 unpinned images
|
||||
|
||||
==============================================================================
|
||||
== gate: image-resolvable (check-image-resolvable.py grimmory)
|
||||
==============================================================================
|
||||
resolving 2 unique image pin(s)…
|
||||
image-resolvability gate OK — 2 unique pins, all resolve
|
||||
|
||||
==============================================================================
|
||||
== gate: volume-persistence (check-volume-persistence.py grimmory)
|
||||
==============================================================================
|
||||
self-testing the prober (both directions)…
|
||||
prober flags the R-156 signature and clears a correct template — trustworthy
|
||||
grimmory CLEAN grimmory: this container's mounts are all empty while it created entries in ['/', '/app', '/etc'] — benign when a sibling container holds the state, w
|
||||
|
||||
1 clean · 0 broken · 0 undetermined (of 1 in scope)
|
||||
volume-persistence gate OK
|
||||
|
||||
==============================================================================
|
||||
== gate: engine-major (check-engine-major.py)
|
||||
==============================================================================
|
||||
engine-major gate — range origin/main..HEAD: 0 compose file(s) changed, 0 engine pin(s) compared
|
||||
engine-major gate OK — no forbidden engine major, and no engine major bundled with another image move (rule: CLAUDE.md, amended by R-469 2026-09-21)
|
||||
|
||||
==============================================================================
|
||||
== gate: catalog-since (check-catalog-since.py)
|
||||
==============================================================================
|
||||
catalog-since gate — range origin/main..HEAD: 0 compose file(s) changed, 0 image move(s) dated
|
||||
catalog-since gate OK — every image move in the range carries a catalog_since on or after its commit day
|
||||
|
||||
==============================================================================
|
||||
== gate: copy-i18n (check-copy-i18n.py grimmory)
|
||||
==============================================================================
|
||||
copy-i18n: matcher controls OK (positive „Jelentkezz be…" convicts, negative „Encrypted notes…" does not)
|
||||
copy-i18n: retrieval-promise vocabulary matches the sibling clone
|
||||
copy-i18n: 58 apps · 1155 Hungarian copy strings frozen · 1154 with English
|
||||
copy-i18n: translated so far — actualbudget 15/15, adventurelog 18/18, audiobookshelf 21/21, bentopdf 14/14, bookstack 21/21, calcom 22/22, calibre-web 27/27, claper 20/20, code-server 20/20, crafty-controller 24/24, dawarich 21/21, docmost 19/19, emby 22/22, ghost 16/16, gitea 17/17, glance 15/15, gokapi 19/19, grafana 19/19, gramps-web 17/17, grimmory 24/24, home-assistant 18/18, homebox 17/17, homepage 15/15, immich 24/24, jellyfin 22/22, karakeep 19/19, kimai 20/20, komga 21/21, mealie 19/19, metube 19/19, n8n 17/17, navidrome 21/21, nextcloud 28/28, onlyoffice 24/24, opengist 16/16, outline 21/21, paperless-ngx 33/33, papra 14/15, plant-it 16/16, plex 25/25, privatebin 14/14, radarr 22/22, radicale 19/19, rallly 17/17, recipe-importer 19/19, romm 41/41, seerr 18/18, sonarr 22/22, sparkyfitness 21/21, tandoor 18/18, termix 12/12, uptime-kuma 16/16, vaultwarden 23/23, vikunja 18/18, wanderer 20/20, wger 20/20, wishlist 16/16, zipline 18/18
|
||||
copy-i18n: OK
|
||||
|
||||
==============================================================================
|
||||
== gate: probe-matches-compose (check-probe-matches-compose.py grimmory)
|
||||
==============================================================================
|
||||
probe-matches-compose: 1 app(s), mode: full
|
||||
|
||||
probe-matches-compose: OK — every probe dials the port (and, where it can fail, the path) that the app's own compose healthcheck dials
|
||||
|
||||
==============================================================================
|
||||
== gate: probe-measured (check-probe-measured.py grimmory)
|
||||
==============================================================================
|
||||
probe-measured: OK — 1 probes, each with a measured before/after
|
||||
|
||||
==============================================================================
|
||||
== gate: test-record (check-test-record.py grimmory)
|
||||
==============================================================================
|
||||
test-record gate — 1 template(s) read, 1 carry a ladder, 0 convicted
|
||||
|
||||
==============================================================================
|
||||
== gate: test-record-move (check-test-record-move.py)
|
||||
==============================================================================
|
||||
test-record-move gate — range origin/main..HEAD: 0 compose file(s) changed
|
||||
|
||||
==============================================================================
|
||||
== gate: onboarding (check-onboarding.py)
|
||||
==============================================================================
|
||||
onboarding gate — 61 checklist ids; 58 template dirs: 53 exempt (published before 2026-10-01), 5 new; 2 exempt app(s) with a record (shape-checked): sparkyfitness, wger
|
||||
onboarding gate OK
|
||||
|
||||
==============================================================================
|
||||
== gate: family-gate (check-family-gate.py)
|
||||
==============================================================================
|
||||
family-gate: newest baked golden 0.287.0 >= 0.287.0
|
||||
family-gate gate OK: 2 family-gated template(s) ['grimmory', 'metube']
|
||||
|
||||
==============================================================================
|
||||
== summary
|
||||
==============================================================================
|
||||
image-pins OK (exit 0)
|
||||
image-resolvable OK (exit 0)
|
||||
volume-persistence OK (exit 0)
|
||||
engine-major OK (exit 0)
|
||||
catalog-since OK (exit 0)
|
||||
copy-i18n OK (exit 0)
|
||||
probe-matches-compose OK (exit 0)
|
||||
probe-measured OK (exit 0)
|
||||
test-record OK (exit 0)
|
||||
test-record-move OK (exit 0)
|
||||
onboarding OK (exit 0)
|
||||
family-gate OK (exit 0)
|
||||
|
||||
all catalog gates OK
|
||||
catalog_gates exit code = 0
|
||||
# leftover containers: 0
|
||||
@@ -0,0 +1,113 @@
|
||||
# catalog_gates.py metube - 2026-10-02T07:06:40Z, bench LXC 9401 on demo-hp (debian-13, swap 0, nvme-scratch), catalog-wt de0a9bd + uncommitted working tree (13 path(s), copied with its .git), sibling felhom.eu 68c2290 (git archive HEAD of DooPlex tree = origin/main) at ../felhom.eu
|
||||
# sibling copy ALSO carries rsync/tar copies of DooPlex UNCOMMITTED documentation/audits/family-gate-2026-10-02/ and documentation/audits/licences-2026-10-02/; B/catalog-gates-grimmory.txt and B/catalog-gates-metube.txt were one-line PLACEHOLDER files in the bench sibling before the run (the onboarding records cite them) - this file is the real output that replaces the placeholder
|
||||
M FIRST-ADMIN.md
|
||||
M README.md
|
||||
M REUSE.md
|
||||
M scripts/box_walk.py
|
||||
M scripts/catalog_gates.py
|
||||
M scripts/copy_freeze/hu.json
|
||||
M scripts/test_gate_decoys.py
|
||||
M scripts/upgrade_fixtures_box.py
|
||||
?? onboarding/grimmory.md
|
||||
?? onboarding/metube.md
|
||||
?? scripts/check-family-gate.py
|
||||
?? templates/grimmory/
|
||||
?? templates/metube/
|
||||
catalog_gates — apps: metube
|
||||
|
||||
==============================================================================
|
||||
== gate: image-pins (check-image-pins.py)
|
||||
==============================================================================
|
||||
image-pin gate OK — 58 templates, 0 unpinned images
|
||||
|
||||
==============================================================================
|
||||
== gate: image-resolvable (check-image-resolvable.py metube)
|
||||
==============================================================================
|
||||
resolving 1 unique image pin(s)…
|
||||
image-resolvability gate OK — 1 unique pins, all resolve
|
||||
|
||||
==============================================================================
|
||||
== gate: volume-persistence (check-volume-persistence.py metube)
|
||||
==============================================================================
|
||||
self-testing the prober (both directions)…
|
||||
prober flags the R-156 signature and clears a correct template — trustworthy
|
||||
metube UNDETERMINED NOTHING this app wrote landed in ANY folder the template preserves: all 2 mount(s) across 1 container(s) are empty, yet entries were created in ['/'].
|
||||
|
||||
UNDETERMINED — NOT a pass. The question was not answered for these:
|
||||
metube: NOTHING this app wrote landed in ANY folder the template preserves: all 2 mount(s) across 1 container(s) are empty, yet entries were created in ['/']. Needs adjudication.; metube: this container's mou
|
||||
|
||||
0 clean · 0 broken · 1 undetermined (of 1 in scope)
|
||||
INCOMPLETE — no broken template among those decided, but 1 were never decided. This is not a clean bill of health.
|
||||
|
||||
==============================================================================
|
||||
== gate: engine-major (check-engine-major.py)
|
||||
==============================================================================
|
||||
engine-major gate — range origin/main..HEAD: 0 compose file(s) changed, 0 engine pin(s) compared
|
||||
engine-major gate OK — no forbidden engine major, and no engine major bundled with another image move (rule: CLAUDE.md, amended by R-469 2026-09-21)
|
||||
|
||||
==============================================================================
|
||||
== gate: catalog-since (check-catalog-since.py)
|
||||
==============================================================================
|
||||
catalog-since gate — range origin/main..HEAD: 0 compose file(s) changed, 0 image move(s) dated
|
||||
catalog-since gate OK — every image move in the range carries a catalog_since on or after its commit day
|
||||
|
||||
==============================================================================
|
||||
== gate: copy-i18n (check-copy-i18n.py metube)
|
||||
==============================================================================
|
||||
copy-i18n: matcher controls OK (positive „Jelentkezz be…" convicts, negative „Encrypted notes…" does not)
|
||||
copy-i18n: retrieval-promise vocabulary matches the sibling clone
|
||||
copy-i18n: 58 apps · 1155 Hungarian copy strings frozen · 1154 with English
|
||||
copy-i18n: translated so far — actualbudget 15/15, adventurelog 18/18, audiobookshelf 21/21, bentopdf 14/14, bookstack 21/21, calcom 22/22, calibre-web 27/27, claper 20/20, code-server 20/20, crafty-controller 24/24, dawarich 21/21, docmost 19/19, emby 22/22, ghost 16/16, gitea 17/17, glance 15/15, gokapi 19/19, grafana 19/19, gramps-web 17/17, grimmory 24/24, home-assistant 18/18, homebox 17/17, homepage 15/15, immich 24/24, jellyfin 22/22, karakeep 19/19, kimai 20/20, komga 21/21, mealie 19/19, metube 19/19, n8n 17/17, navidrome 21/21, nextcloud 28/28, onlyoffice 24/24, opengist 16/16, outline 21/21, paperless-ngx 33/33, papra 14/15, plant-it 16/16, plex 25/25, privatebin 14/14, radarr 22/22, radicale 19/19, rallly 17/17, recipe-importer 19/19, romm 41/41, seerr 18/18, sonarr 22/22, sparkyfitness 21/21, tandoor 18/18, termix 12/12, uptime-kuma 16/16, vaultwarden 23/23, vikunja 18/18, wanderer 20/20, wger 20/20, wishlist 16/16, zipline 18/18
|
||||
copy-i18n: OK
|
||||
|
||||
==============================================================================
|
||||
== gate: probe-matches-compose (check-probe-matches-compose.py metube)
|
||||
==============================================================================
|
||||
probe-matches-compose: 1 app(s), mode: full
|
||||
|
||||
probe-matches-compose: OK — every probe dials the port (and, where it can fail, the path) that the app's own compose healthcheck dials
|
||||
|
||||
==============================================================================
|
||||
== gate: probe-measured (check-probe-measured.py metube)
|
||||
==============================================================================
|
||||
probe-measured: OK — 0 probes, each with a measured before/after
|
||||
|
||||
==============================================================================
|
||||
== gate: test-record (check-test-record.py metube)
|
||||
==============================================================================
|
||||
test-record gate — 1 template(s) read, 1 carry a ladder, 0 convicted
|
||||
|
||||
==============================================================================
|
||||
== gate: test-record-move (check-test-record-move.py)
|
||||
==============================================================================
|
||||
test-record-move gate — range origin/main..HEAD: 0 compose file(s) changed
|
||||
|
||||
==============================================================================
|
||||
== gate: onboarding (check-onboarding.py)
|
||||
==============================================================================
|
||||
onboarding gate — 61 checklist ids; 58 template dirs: 53 exempt (published before 2026-10-01), 5 new; 2 exempt app(s) with a record (shape-checked): sparkyfitness, wger
|
||||
onboarding gate OK
|
||||
|
||||
==============================================================================
|
||||
== gate: family-gate (check-family-gate.py)
|
||||
==============================================================================
|
||||
family-gate: newest baked golden 0.287.0 >= 0.287.0
|
||||
family-gate gate OK: 2 family-gated template(s) ['grimmory', 'metube']
|
||||
|
||||
==============================================================================
|
||||
== summary
|
||||
==============================================================================
|
||||
image-pins OK (exit 0)
|
||||
image-resolvable OK (exit 0)
|
||||
volume-persistence INCONCLUSIVE (exit 2)
|
||||
engine-major OK (exit 0)
|
||||
catalog-since OK (exit 0)
|
||||
copy-i18n OK (exit 0)
|
||||
probe-matches-compose OK (exit 0)
|
||||
probe-measured OK (exit 0)
|
||||
test-record OK (exit 0)
|
||||
test-record-move OK (exit 0)
|
||||
onboarding OK (exit 0)
|
||||
family-gate OK (exit 0)
|
||||
UNDETERMINED (never a pass): volume-persistence
|
||||
catalog_gates exit code = 2
|
||||
@@ -0,0 +1,118 @@
|
||||
# catalog_gates.py metube - re-run after the R-788 exerciser - 2026-10-02T07:17:56Z, bench LXC 9401 on demo-hp (debian-13, swap 0, nvme-scratch), catalog-wt de0a9bd + uncommitted working tree (16 path(s), REFRESHED copy with check-volume-persistence.py APP_EXERCISE R-788, copied with its .git), sibling felhom.eu 68c2290 (git archive) at ../felhom.eu
|
||||
# sibling copy ALSO carries tar copies of DooPlex UNCOMMITTED documentation/audits/family-gate-2026-10-02/ and documentation/audits/licences-2026-10-02/ (real B/catalog-gates-grimmory.txt; B/catalog-gates-metube.txt = the run-1 output, copied from catalog-gates-metube-run1.txt so the onboarding citation resolves)
|
||||
# the previous output of this file is kept as catalog-gates-metube-run1.txt
|
||||
M CHANGELOG.md
|
||||
M CONTEXT.md
|
||||
M FIRST-ADMIN.md
|
||||
M README.md
|
||||
M REUSE.md
|
||||
M scripts/box_walk.py
|
||||
M scripts/catalog_gates.py
|
||||
M scripts/check-volume-persistence.py
|
||||
M scripts/copy_freeze/hu.json
|
||||
M scripts/test_gate_decoys.py
|
||||
M scripts/upgrade_fixtures_box.py
|
||||
?? onboarding/grimmory.md
|
||||
?? onboarding/metube.md
|
||||
?? scripts/check-family-gate.py
|
||||
?? templates/grimmory/
|
||||
?? templates/metube/
|
||||
catalog_gates — apps: metube
|
||||
|
||||
==============================================================================
|
||||
== gate: image-pins (check-image-pins.py)
|
||||
==============================================================================
|
||||
image-pin gate OK — 58 templates, 0 unpinned images
|
||||
|
||||
==============================================================================
|
||||
== gate: image-resolvable (check-image-resolvable.py metube)
|
||||
==============================================================================
|
||||
resolving 1 unique image pin(s)…
|
||||
image-resolvability gate OK — 1 unique pins, all resolve
|
||||
|
||||
==============================================================================
|
||||
== gate: volume-persistence (check-volume-persistence.py metube)
|
||||
==============================================================================
|
||||
self-testing the prober (both directions)…
|
||||
prober flags the R-156 signature and clears a correct template — trustworthy
|
||||
metube UNDETERMINED NOTHING this app wrote landed in ANY folder the template preserves: all 2 mount(s) across 1 container(s) are empty, yet entries were created in ['/'].
|
||||
|
||||
UNDETERMINED — NOT a pass. The question was not answered for these:
|
||||
metube: NOTHING this app wrote landed in ANY folder the template preserves: all 2 mount(s) across 1 container(s) are empty, yet entries were created in ['/']. Needs adjudication.; metube: this container's mou
|
||||
|
||||
0 clean · 0 broken · 1 undetermined (of 1 in scope)
|
||||
INCOMPLETE — no broken template among those decided, but 1 were never decided. This is not a clean bill of health.
|
||||
|
||||
==============================================================================
|
||||
== gate: engine-major (check-engine-major.py)
|
||||
==============================================================================
|
||||
engine-major gate — range origin/main..HEAD: 0 compose file(s) changed, 0 engine pin(s) compared
|
||||
engine-major gate OK — no forbidden engine major, and no engine major bundled with another image move (rule: CLAUDE.md, amended by R-469 2026-09-21)
|
||||
|
||||
==============================================================================
|
||||
== gate: catalog-since (check-catalog-since.py)
|
||||
==============================================================================
|
||||
catalog-since gate — range origin/main..HEAD: 0 compose file(s) changed, 0 image move(s) dated
|
||||
catalog-since gate OK — every image move in the range carries a catalog_since on or after its commit day
|
||||
|
||||
==============================================================================
|
||||
== gate: copy-i18n (check-copy-i18n.py metube)
|
||||
==============================================================================
|
||||
copy-i18n: matcher controls OK (positive „Jelentkezz be…" convicts, negative „Encrypted notes…" does not)
|
||||
copy-i18n: retrieval-promise vocabulary matches the sibling clone
|
||||
copy-i18n: 58 apps · 1155 Hungarian copy strings frozen · 1154 with English
|
||||
copy-i18n: translated so far — actualbudget 15/15, adventurelog 18/18, audiobookshelf 21/21, bentopdf 14/14, bookstack 21/21, calcom 22/22, calibre-web 27/27, claper 20/20, code-server 20/20, crafty-controller 24/24, dawarich 21/21, docmost 19/19, emby 22/22, ghost 16/16, gitea 17/17, glance 15/15, gokapi 19/19, grafana 19/19, gramps-web 17/17, grimmory 24/24, home-assistant 18/18, homebox 17/17, homepage 15/15, immich 24/24, jellyfin 22/22, karakeep 19/19, kimai 20/20, komga 21/21, mealie 19/19, metube 19/19, n8n 17/17, navidrome 21/21, nextcloud 28/28, onlyoffice 24/24, opengist 16/16, outline 21/21, paperless-ngx 33/33, papra 14/15, plant-it 16/16, plex 25/25, privatebin 14/14, radarr 22/22, radicale 19/19, rallly 17/17, recipe-importer 19/19, romm 41/41, seerr 18/18, sonarr 22/22, sparkyfitness 21/21, tandoor 18/18, termix 12/12, uptime-kuma 16/16, vaultwarden 23/23, vikunja 18/18, wanderer 20/20, wger 20/20, wishlist 16/16, zipline 18/18
|
||||
copy-i18n: OK
|
||||
|
||||
==============================================================================
|
||||
== gate: probe-matches-compose (check-probe-matches-compose.py metube)
|
||||
==============================================================================
|
||||
probe-matches-compose: 1 app(s), mode: full
|
||||
|
||||
probe-matches-compose: OK — every probe dials the port (and, where it can fail, the path) that the app's own compose healthcheck dials
|
||||
|
||||
==============================================================================
|
||||
== gate: probe-measured (check-probe-measured.py metube)
|
||||
==============================================================================
|
||||
probe-measured: OK — 0 probes, each with a measured before/after
|
||||
|
||||
==============================================================================
|
||||
== gate: test-record (check-test-record.py metube)
|
||||
==============================================================================
|
||||
test-record gate — 1 template(s) read, 1 carry a ladder, 0 convicted
|
||||
|
||||
==============================================================================
|
||||
== gate: test-record-move (check-test-record-move.py)
|
||||
==============================================================================
|
||||
test-record-move gate — range origin/main..HEAD: 0 compose file(s) changed
|
||||
|
||||
==============================================================================
|
||||
== gate: onboarding (check-onboarding.py)
|
||||
==============================================================================
|
||||
onboarding gate — 61 checklist ids; 58 template dirs: 53 exempt (published before 2026-10-01), 5 new; 2 exempt app(s) with a record (shape-checked): sparkyfitness, wger
|
||||
onboarding gate OK
|
||||
|
||||
==============================================================================
|
||||
== gate: family-gate (check-family-gate.py)
|
||||
==============================================================================
|
||||
family-gate: newest baked golden 0.287.0 >= 0.287.0
|
||||
family-gate gate OK: 2 family-gated template(s) ['grimmory', 'metube']
|
||||
|
||||
==============================================================================
|
||||
== summary
|
||||
==============================================================================
|
||||
image-pins OK (exit 0)
|
||||
image-resolvable OK (exit 0)
|
||||
volume-persistence INCONCLUSIVE (exit 2)
|
||||
engine-major OK (exit 0)
|
||||
catalog-since OK (exit 0)
|
||||
copy-i18n OK (exit 0)
|
||||
probe-matches-compose OK (exit 0)
|
||||
probe-measured OK (exit 0)
|
||||
test-record OK (exit 0)
|
||||
test-record-move OK (exit 0)
|
||||
onboarding OK (exit 0)
|
||||
family-gate OK (exit 0)
|
||||
UNDETERMINED (never a pass): volume-persistence
|
||||
catalog_gates exit code = 2
|
||||
0
|
||||
@@ -0,0 +1,117 @@
|
||||
# catalog_gates.py metube - 2026-10-02T07:32:48Z, after the R-801 port fix, bench LXC 9401 on demo-hp (debian-13, swap 0, nvme-scratch), catalog-wt de0a9bd + uncommitted working tree (17 path(s), REFRESHED copy with R-788 APP_EXERCISE + R-801 routed_ports, copied with its .git), sibling felhom.eu 68c2290 (git archive) at ../felhom.eu
|
||||
# sibling copy ALSO carries tar copies of DooPlex UNCOMMITTED documentation/audits/family-gate-2026-10-02/ and documentation/audits/licences-2026-10-02/; in the bench sibling B/catalog-gates-grimmory.txt = copy of catalog-gates-grimmory-run1.txt and B/catalog-gates-metube.txt = copy of catalog-gates-metube-run2.txt so the onboarding citations resolve
|
||||
# the previous output of this file is kept as catalog-gates-metube-run2.txt
|
||||
M CHANGELOG.md
|
||||
M CONTEXT.md
|
||||
M FIRST-ADMIN.md
|
||||
M README.md
|
||||
M REUSE.md
|
||||
M scripts/box_walk.py
|
||||
M scripts/catalog_gates.py
|
||||
M scripts/check-volume-persistence.py
|
||||
M scripts/copy_freeze/hu.json
|
||||
M scripts/test_check_volume_persistence.py
|
||||
M scripts/test_gate_decoys.py
|
||||
M scripts/upgrade_fixtures_box.py
|
||||
?? onboarding/grimmory.md
|
||||
?? onboarding/metube.md
|
||||
?? scripts/check-family-gate.py
|
||||
?? templates/grimmory/
|
||||
?? templates/metube/
|
||||
catalog_gates — apps: metube
|
||||
|
||||
==============================================================================
|
||||
== gate: image-pins (check-image-pins.py)
|
||||
==============================================================================
|
||||
image-pin gate OK — 58 templates, 0 unpinned images
|
||||
|
||||
==============================================================================
|
||||
== gate: image-resolvable (check-image-resolvable.py metube)
|
||||
==============================================================================
|
||||
resolving 1 unique image pin(s)…
|
||||
image-resolvability gate OK — 1 unique pins, all resolve
|
||||
|
||||
==============================================================================
|
||||
== gate: volume-persistence (check-volume-persistence.py metube)
|
||||
==============================================================================
|
||||
self-testing the prober (both directions)…
|
||||
prober flags the R-156 signature and clears a correct template — trustworthy
|
||||
metube CLEAN
|
||||
|
||||
1 clean · 0 broken · 0 undetermined (of 1 in scope)
|
||||
volume-persistence gate OK
|
||||
|
||||
==============================================================================
|
||||
== gate: engine-major (check-engine-major.py)
|
||||
==============================================================================
|
||||
engine-major gate — range origin/main..HEAD: 0 compose file(s) changed, 0 engine pin(s) compared
|
||||
engine-major gate OK — no forbidden engine major, and no engine major bundled with another image move (rule: CLAUDE.md, amended by R-469 2026-09-21)
|
||||
|
||||
==============================================================================
|
||||
== gate: catalog-since (check-catalog-since.py)
|
||||
==============================================================================
|
||||
catalog-since gate — range origin/main..HEAD: 0 compose file(s) changed, 0 image move(s) dated
|
||||
catalog-since gate OK — every image move in the range carries a catalog_since on or after its commit day
|
||||
|
||||
==============================================================================
|
||||
== gate: copy-i18n (check-copy-i18n.py metube)
|
||||
==============================================================================
|
||||
copy-i18n: matcher controls OK (positive „Jelentkezz be…" convicts, negative „Encrypted notes…" does not)
|
||||
copy-i18n: retrieval-promise vocabulary matches the sibling clone
|
||||
copy-i18n: 58 apps · 1155 Hungarian copy strings frozen · 1154 with English
|
||||
copy-i18n: translated so far — actualbudget 15/15, adventurelog 18/18, audiobookshelf 21/21, bentopdf 14/14, bookstack 21/21, calcom 22/22, calibre-web 27/27, claper 20/20, code-server 20/20, crafty-controller 24/24, dawarich 21/21, docmost 19/19, emby 22/22, ghost 16/16, gitea 17/17, glance 15/15, gokapi 19/19, grafana 19/19, gramps-web 17/17, grimmory 24/24, home-assistant 18/18, homebox 17/17, homepage 15/15, immich 24/24, jellyfin 22/22, karakeep 19/19, kimai 20/20, komga 21/21, mealie 19/19, metube 19/19, n8n 17/17, navidrome 21/21, nextcloud 28/28, onlyoffice 24/24, opengist 16/16, outline 21/21, paperless-ngx 33/33, papra 14/15, plant-it 16/16, plex 25/25, privatebin 14/14, radarr 22/22, radicale 19/19, rallly 17/17, recipe-importer 19/19, romm 41/41, seerr 18/18, sonarr 22/22, sparkyfitness 21/21, tandoor 18/18, termix 12/12, uptime-kuma 16/16, vaultwarden 23/23, vikunja 18/18, wanderer 20/20, wger 20/20, wishlist 16/16, zipline 18/18
|
||||
copy-i18n: OK
|
||||
|
||||
==============================================================================
|
||||
== gate: probe-matches-compose (check-probe-matches-compose.py metube)
|
||||
==============================================================================
|
||||
probe-matches-compose: 1 app(s), mode: full
|
||||
|
||||
probe-matches-compose: OK — every probe dials the port (and, where it can fail, the path) that the app's own compose healthcheck dials
|
||||
|
||||
==============================================================================
|
||||
== gate: probe-measured (check-probe-measured.py metube)
|
||||
==============================================================================
|
||||
probe-measured: OK — 0 probes, each with a measured before/after
|
||||
|
||||
==============================================================================
|
||||
== gate: test-record (check-test-record.py metube)
|
||||
==============================================================================
|
||||
test-record gate — 1 template(s) read, 1 carry a ladder, 0 convicted
|
||||
|
||||
==============================================================================
|
||||
== gate: test-record-move (check-test-record-move.py)
|
||||
==============================================================================
|
||||
test-record-move gate — range origin/main..HEAD: 0 compose file(s) changed
|
||||
|
||||
==============================================================================
|
||||
== gate: onboarding (check-onboarding.py)
|
||||
==============================================================================
|
||||
onboarding gate — 61 checklist ids; 58 template dirs: 53 exempt (published before 2026-10-01), 5 new; 2 exempt app(s) with a record (shape-checked): sparkyfitness, wger
|
||||
onboarding gate OK
|
||||
|
||||
==============================================================================
|
||||
== gate: family-gate (check-family-gate.py)
|
||||
==============================================================================
|
||||
family-gate: newest baked golden 0.287.0 >= 0.287.0
|
||||
family-gate gate OK: 2 family-gated template(s) ['grimmory', 'metube']
|
||||
|
||||
==============================================================================
|
||||
== summary
|
||||
==============================================================================
|
||||
image-pins OK (exit 0)
|
||||
image-resolvable OK (exit 0)
|
||||
volume-persistence OK (exit 0)
|
||||
engine-major OK (exit 0)
|
||||
catalog-since OK (exit 0)
|
||||
copy-i18n OK (exit 0)
|
||||
probe-matches-compose OK (exit 0)
|
||||
probe-measured OK (exit 0)
|
||||
test-record OK (exit 0)
|
||||
test-record-move OK (exit 0)
|
||||
onboarding OK (exit 0)
|
||||
family-gate OK (exit 0)
|
||||
|
||||
all catalog gates OK
|
||||
catalog_gates exit code = 0
|
||||
# leftover containers: 0
|
||||
@@ -0,0 +1,6 @@
|
||||
## gate mutant: 'if not LITERAL.match(p) or' -> 'if False and not LITERAL.match(p) or'
|
||||
XX FACT: an exception that is a regex rc=0 (expected 1)
|
||||
## gate mutant: 'if baked:' -> 'if True:'
|
||||
XX FACT: a golden DIRECTORY 0.287.0 with no bake log (a name is not a bake) rc=0 (expected 1)
|
||||
## gate mutant: 'if TOP_TRUE.match(ln):' -> 'if "family_gate: true" in ln:'
|
||||
XX DECOY: family_gate only in a COMMENT -> not gated, nothing owed rc=1 (expected 0)
|
||||
@@ -0,0 +1,8 @@
|
||||
# registry read from DooPlex, 2026-10-02T06:28:27Z — ghcr.io/grimmory-tools/grimmory (anonymous pull token, no image pulled)
|
||||
## tags (all)
|
||||
249 tags; non-sha: ['nightly-20260905-0279c15dc', 'nightly-20260906-703c7f29a', 'nightly-20260907-5186f850a', 'nightly-20260908-75495bf5f', 'nightly-20260909-53abc8bf8', 'nightly-20260910-11224eb9c', 'nightly-20260911-83dede522', 'nightly-20260912-7d768a287', 'nightly-20260913-71637619f', 'nightly-20260914-7a9cd3107', 'nightly-20260914-9b38a091e', 'v3.4.0', 'v3.4', 'nightly-20260915-e6ac37f03', 'nightly-20260915-8f19bbb07', 'v3.4.1', 'nightly-20260916-96702f0ef', 'nightly-20260917-2d7a3e9c5', 'nightly-20260918-5986e3660', 'nightly-20260919-6a778f82e', 'nightly-20260919-1042cad7a', 'nightly-20260920-569fd6687', 'nightly-20260920-402e89b44', 'v3.5.0', 'v3.5', 'nightly-20260921-bcac7ff16', 'nightly-20260922-6b70d5466', 'nightly-20260923-6b70d5466', 'nightly-20260924-6b70d5466', 'nightly-20260925-cb6fd48c7', 'nightly-20260926-839e02fc9', 'nightly-20260926-18b0c8cfb', 'nightly-20260927-bd94696eb', 'nightly-20260927-e933da740', 'nightly-20260928-e937943c4', 'nightly-20260928-5b3a8aa71', 'nightly-20260929-5b3a8aa71', 'nightly-20260930-5b3a8aa71', 'nightly-20261001-ab6d4af42', 'nightly-20261002-84a6097f8']
|
||||
## v3.5.0 manifest platforms
|
||||
[('amd64', None), ('arm64', None)]
|
||||
## mariadb:11.4 (Docker Hub) platforms
|
||||
['amd64', 'arm64', 'ppc64le', 's390x']
|
||||
## release tags (v-prefixed, plus the floating v<major>.<minor> and latest): ['v2.2.4', 'latest', 'v2.2.5', 'v2.2.6', 'v2.2.7', 'v2.3.0', 'v2.3.1', 'v3.0.0', 'v3.0.1', 'v3.0.2', 'v3.0.3', 'v3.0', 'v3.1.0', 'v3.1', 'v3.2.0', 'v3.2', 'v3.2.1', 'v3.2.2', 'v3.2.4', 'v3.3.0', 'v3.3', 'v3.3.1', 'v3.3.2', 'v3.3.3', 'v3.4.0', 'v3.4', 'v3.4.1', 'v3.5.0', 'v3.5']
|
||||
@@ -0,0 +1,189 @@
|
||||
# Grimmory v3.5.0 — upstream source READ over HTTPS (raw.githubusercontent.com at the tag), 2026-10-02T06:28:57Z. No box touched.
|
||||
|
||||
## 1.7 the image's start — Dockerfile (runtime stage) and packaging/docker/entrypoint.sh
|
||||
FROM eclipse-temurin:25-jre-alpine
|
||||
|
||||
ENV JAVA_TOOL_OPTIONS="-XX:+UseShenandoahGC \
|
||||
-XX:ShenandoahGCHeuristics=compact \
|
||||
-XX:+UseCompactObjectHeaders \
|
||||
-XX:MaxRAMPercentage=60.0 \
|
||||
-XX:InitialRAMPercentage=8.0 \
|
||||
-XX:+ExitOnOutOfMemoryError \
|
||||
-XX:MaxMetaspaceSize=256m \
|
||||
-XX:ReservedCodeCacheSize=48m \
|
||||
-Xss512k \
|
||||
-XX:CICompilerCount=2 \
|
||||
-XX:+UnlockExperimentalVMOptions \
|
||||
-XX:+UseStringDeduplication \
|
||||
-XX:ShenandoahUncommitDelay=5000 \
|
||||
-XX:ShenandoahGuaranteedGCInterval=30000 \
|
||||
-XX:MaxDirectMemorySize=256m \
|
||||
--enable-native-access=ALL-UNNAMED \
|
||||
--enable-preview"
|
||||
|
||||
RUN apk add --no-cache su-exec libstdc++ libgcc libarchive && \
|
||||
mkdir -p /bookdrop
|
||||
|
||||
# Manually link `libarchive.so.13` so java and other libraries can see it
|
||||
RUN ln -s /usr/lib/libarchive.so.13 /usr/lib/libarchive.so
|
||||
|
||||
COPY packaging/docker/entrypoint.sh /usr/local/bin/entrypoint.sh
|
||||
RUN chmod +x /usr/local/bin/entrypoint.sh
|
||||
|
||||
COPY --from=ffprobe-layer /ffprobe /usr/local/bin/ffprobe
|
||||
COPY --from=kepubify-layer /kepubify /usr/local/bin/kepubify
|
||||
|
||||
COPY --from=backend-build /workspace/backend/app.jar /app/app.jar
|
||||
|
||||
ARG APP_VERSION=development
|
||||
ARG APP_REVISION=unknown
|
||||
|
||||
LABEL org.opencontainers.image.title="Grimmory" \
|
||||
org.opencontainers.image.description="Grimmory: a self-hosted, multi-user digital library with smart shelves, auto metadata, Kobo and KOReader sync, BookDrop imports, OPDS support, and a built-in reader for EPUB, PDF, and comics." \
|
||||
org.opencontainers.image.source="https://github.com/grimmory-tools/grimmory" \
|
||||
org.opencontainers.image.url="https://github.com/grimmory-tools/grimmory" \
|
||||
org.opencontainers.image.documentation="https://grimmory.org/docs/getting-started" \
|
||||
org.opencontainers.image.version=$APP_VERSION \
|
||||
org.opencontainers.image.revision=$APP_REVISION \
|
||||
org.opencontainers.image.licenses="AGPL-3.0" \
|
||||
org.opencontainers.image.base.name="docker.io/library/eclipse-temurin:25-jre-alpine"
|
||||
|
||||
ENV APP_VERSION=${APP_VERSION} \
|
||||
APP_REVISION=${APP_REVISION}
|
||||
|
||||
EXPOSE 6060
|
||||
|
||||
HEALTHCHECK --interval=60s --timeout=10s --start-period=60s --retries=5 \
|
||||
CMD wget -q --spider http://localhost:${SERVER_PORT:-${BOOKLORE_PORT:-6060}}/api/v1/healthcheck
|
||||
|
||||
ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]
|
||||
CMD ["java", "--enable-native-access=ALL-UNNAMED", "--enable-preview", "-jar", "/app/app.jar"]
|
||||
=== backend/src/main/resources/application.yaml
|
||||
=== packaging/docker/entrypoint.sh
|
||||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
USER_ID="${USER_ID:-1000}"
|
||||
GROUP_ID="${GROUP_ID:-1000}"
|
||||
APP_USER="${APP_USER:-booklore}"
|
||||
|
||||
if getent group "$APP_USER" >/dev/null 2>&1; then
|
||||
existing_group_id="$(getent group "$APP_USER" | cut -d: -f3)"
|
||||
if [ "$existing_group_id" != "$GROUP_ID" ]; then
|
||||
echo "ERROR: APP_USER group '$APP_USER' already exists with GID $existing_group_id, expected $GROUP_ID." >&2
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# Create group and user if they don't exist
|
||||
if ! getent group "$GROUP_ID" >/dev/null 2>&1; then
|
||||
addgroup -g "$GROUP_ID" -S "$APP_USER"
|
||||
fi
|
||||
|
||||
if getent passwd "$APP_USER" >/dev/null 2>&1; then
|
||||
existing_user_id="$(getent passwd "$APP_USER" | cut -d: -f3)"
|
||||
if [ "$existing_user_id" != "$USER_ID" ]; then
|
||||
echo "ERROR: APP_USER '$APP_USER' already exists with UID $existing_user_id, expected $USER_ID." >&2
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
if ! getent passwd "$USER_ID" >/dev/null 2>&1; then
|
||||
adduser -u "$USER_ID" -G "$(getent group "$GROUP_ID" | cut -d: -f1)" -S -D "$APP_USER"
|
||||
fi
|
||||
|
||||
# Ensure data, bookdrop, and books directories exist and are writable by the target user
|
||||
mkdir -p /app/data /bookdrop /books
|
||||
chown "$USER_ID:$GROUP_ID" /app/data /bookdrop /books 2>/dev/null || true
|
||||
|
||||
exec su-exec "$USER_ID:$GROUP_ID" "$@"
|
||||
|
||||
## 1.6 / 1.8 / 0.4 — every env placeholder the app's settings read (backend/src/main/resources/application.yaml)
|
||||
3: path-config: ${APP_PATH_CONFIG:/app/data}
|
||||
4: bookdrop-folder: ${APP_BOOKDROP_FOLDER:/bookdrop}
|
||||
6: enabled: ${API_DOCS_ENABLED:false}
|
||||
12: allowed-origins: ${ALLOWED_ORIGINS:*}
|
||||
15: enabled: ${REMOTE_AUTH_ENABLED:false}
|
||||
16: create-new-users: ${REMOTE_AUTH_CREATE_NEW_USERS:true}
|
||||
17: header-name: ${REMOTE_AUTH_HEADER_NAME:Remote-Name}
|
||||
18: header-user: ${REMOTE_AUTH_HEADER_USER:Remote-User}
|
||||
19: header-email: ${REMOTE_AUTH_HEADER_EMAIL:Remote-Email}
|
||||
20: header-groups: ${REMOTE_AUTH_HEADER_GROUPS:Remote-Groups}
|
||||
21: admin-group: ${REMOTE_AUTH_ADMIN_GROUP}
|
||||
22: groups-delimiter: ${REMOTE_AUTH_GROUPS_DELIMITER:\\s+}
|
||||
23: disk-type: ${DISK_TYPE:LOCAL}
|
||||
26: force-disable: ${FORCE_DISABLE_OIDC:false}
|
||||
27: allow-unsafe-hosts: ${OIDC_ALLOW_UNSAFE_HOSTS:false} # If enabled, turn off outbound SSRF filtering
|
||||
65: port: ${SERVER_PORT:${BOOKLORE_PORT:6060}}
|
||||
97: url: ${DATABASE_URL:jdbc:mariadb://${DATABASE_HOST:${DB_HOST:mariadb}}:${DATABASE_PORT:3306}/${DATABASE_NAME:booklore}?createDatabaseIfNotExist=true&connectionTimeZone=UTC&forceConnectionTimeZoneToSession=true}
|
||||
98: username: ${DATABASE_USERNAME:root}
|
||||
99: password: ${DATABASE_PASSWORD:${MYSQL_ROOT_PASSWORD}}
|
||||
132: log_slow_query: ${HIBERNATE_SLOW_QUERY_MS:500} # Log queries taking longer than 500ms (see org.hibernate.SQL_SLOW)
|
||||
133: generate_statistics: ${HIBERNATE_STATISTICS:false}
|
||||
143: enabled: ${app.api-docs.enabled:false}
|
||||
148: root: ${ROOT_LOG_LEVEL:INFO}
|
||||
149: org.booklore: ${LOG_LEVEL:INFO}
|
||||
154: org.hibernate.session.metrics: ${HIBERNATE_METRICS_LOG_LEVEL:WARN}
|
||||
|
||||
## 1.2 upstream compose (deploy/compose/docker-compose.yml) — the database it runs
|
||||
8: image: ghcr.io/grimmory-tools/grimmory:latest
|
||||
23: # Override JVM memory defaults (the image ships sensible defaults for ~512 MB heap).
|
||||
25: # - JDK_JAVA_OPTIONS=-Xmx256m
|
||||
28: # - JDK_JAVA_OPTIONS=-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/app/data
|
||||
52: image: lscr.io/linuxserver/mariadb:11.4.8
|
||||
|
||||
## 1.9 the token-signing key — service/security/JwtSecretService.java (generated at first start, stored in the DB)
|
||||
5:import org.booklore.repository.JwtSecretRepository;
|
||||
9:import java.security.SecureRandom;
|
||||
14:public class JwtSecretService {
|
||||
31: .orElseGet(this::generateAndStoreNewSecret);
|
||||
40: private String generateAndStoreNewSecret() {
|
||||
41: String newSecret = generateRandomSecret();
|
||||
43: jwtSecretRepository.save(secretEntity);
|
||||
47: private String generateRandomSecret() {
|
||||
49: new SecureRandom().nextBytes(randomBytes);
|
||||
|
||||
## 0.4 the version check — service/VersionService.java
|
||||
77: private static final String GITHUB_REPO = "grimmory-tools/grimmory";
|
||||
78: private static final String BASE_URI = "https://api.github.com/repos/" + GITHUB_REPO;
|
||||
104: latest = fetchLatestGitHubReleaseVersion();
|
||||
117: public String fetchLatestGitHubReleaseVersion() {
|
||||
120: .uri(BASE_URI + "/releases/latest")
|
||||
143: .uri(BASE_URI + "/releases?per_page=" + MAX_RELEASES)
|
||||
|
||||
## 3.6 / 3.10 the sign-in lock — config/security/service/AuthRateLimitService.java + AuthenticationService.java
|
||||
206: private static final int MAX_ATTEMPTS = 5;
|
||||
215: .expireAfterWrite(Duration.ofMinutes(15))
|
||||
222: checkRateLimit("login:ip:" + ip, AuditAction.LOGIN_RATE_LIMITED, "Login rate limited for IP: " + ip);
|
||||
227: checkRateLimit("login:user:" + normalizedUsername, AuditAction.LOGIN_RATE_LIMITED, "Login rate limited for username: " + normalizedUsername);
|
||||
231: recordFailedAttempt("login:ip:" + ip);
|
||||
236: recordFailedAttempt("login:user:" + normalizedUsername);
|
||||
240: resetAttempts("login:ip:" + ip);
|
||||
245: resetAttempts("login:user:" + normalizedUsername);
|
||||
141: String ip = RequestUtils.getCurrentRequest().getRemoteAddr();
|
||||
143: authRateLimitService.checkLoginRateLimit(ip);
|
||||
144: authRateLimitService.checkLoginRateLimitByUsername(username);
|
||||
221: String ip = RequestUtils.getCurrentRequest().getRemoteAddr();
|
||||
64: forward-headers-strategy: native
|
||||
(Spring Boot 'native' = Tomcat RemoteIpValve: X-Forwarded-For read from the RIGHT, skipping internal proxies incl. 172.16.0.0/12 — the 2026-10-01 sweep, felhom.eu/documentation/audits/visitors-2026-10-01/A/sweep/sweep-4.md)
|
||||
|
||||
## 7.1 mail — the app's own e-mail providers (send a book by e-mail) are set in its UI, stored in its DB; no env and no mail at start
|
||||
backend/src/main/java/org/booklore/controller/EmailProviderV2Controller.java
|
||||
backend/src/main/java/org/booklore/controller/EmailRecipientV2Controller.java
|
||||
backend/src/main/java/org/booklore/controller/SendEmailV2Controller.java
|
||||
backend/src/main/java/org/booklore/mapper/EmailProviderV2Mapper.java
|
||||
backend/src/main/java/org/booklore/mapper/EmailRecipientV2Mapper.java
|
||||
backend/src/main/java/org/booklore/model/dto/EmailProviderV2.java
|
||||
backend/src/main/java/org/booklore/model/dto/EmailRecipientV2.java
|
||||
backend/src/main/java/org/booklore/model/dto/request/CreateEmailProviderRequest.java
|
||||
backend/src/main/java/org/booklore/model/dto/request/CreateEmailRecipientRequest.java
|
||||
backend/src/main/java/org/booklore/model/dto/request/SendBookByEmailRequest.java
|
||||
backend/src/main/java/org/booklore/model/entity/EmailProviderV2Entity.java
|
||||
backend/src/main/java/org/booklore/model/entity/EmailRecipientV2Entity.java
|
||||
backend/src/main/java/org/booklore/model/entity/UserEmailProviderPreferenceEntity.java
|
||||
backend/src/main/java/org/booklore/repository/EmailProviderV2Repository.java
|
||||
backend/src/main/java/org/booklore/repository/EmailRecipientV2Repository.java
|
||||
backend/src/main/java/org/booklore/repository/UserEmailProviderPreferenceRepository.java
|
||||
backend/src/main/java/org/booklore/service/email/EmailProviderV2Service.java
|
||||
backend/src/main/java/org/booklore/service/email/EmailRecipientV2Service.java
|
||||
backend/src/main/java/org/booklore/service/email/SendEmailV2Service.java
|
||||
@@ -0,0 +1,155 @@
|
||||
# MeTube reads at tag 2026.09.29 (github.com/alexta69/metube, commit a3896604540223ecbb8258b41b1d745d62647d16), 2026-10-02T06:53:24Z
|
||||
|
||||
## 1.7 the entrypoint — docker-entrypoint.sh (whole file)
|
||||
#!/bin/sh
|
||||
|
||||
PUID="${UID:-$PUID}"
|
||||
PGID="${GID:-$PGID}"
|
||||
AUDIO_DOWNLOAD_DIR="${AUDIO_DOWNLOAD_DIR:-$DOWNLOAD_DIR}"
|
||||
|
||||
echo "Setting umask to ${UMASK}"
|
||||
umask ${UMASK}
|
||||
echo "Creating download directory (${DOWNLOAD_DIR}), audio download directory (${AUDIO_DOWNLOAD_DIR}), state directory (${STATE_DIR}), and temp dir (${TEMP_DIR})"
|
||||
mkdir -p "${DOWNLOAD_DIR}" "${AUDIO_DOWNLOAD_DIR}" "${STATE_DIR}" "${TEMP_DIR}"
|
||||
|
||||
do_upgrade() {
|
||||
echo "Upgrading yt-dlp to nightly channel..."
|
||||
if ! python3 -m pip --version >/dev/null 2>&1; then
|
||||
echo "pip not found; attempting ensurepip"
|
||||
python3 -m ensurepip --upgrade >/dev/null 2>&1 || true
|
||||
fi
|
||||
if ! python3 -m pip install -U --pre "yt-dlp[default,curl-cffi,deno]"; then
|
||||
echo "Warning: yt-dlp nightly upgrade failed; continuing with existing installation"
|
||||
return 1
|
||||
fi
|
||||
echo "yt-dlp nightly upgrade complete"
|
||||
return 0
|
||||
}
|
||||
|
||||
run_supervised() {
|
||||
while true; do
|
||||
"$@" &
|
||||
child_pid=$!
|
||||
trap 'kill -TERM "$child_pid" 2>/dev/null; wait "$child_pid" 2>/dev/null' TERM INT
|
||||
wait "$child_pid"
|
||||
exit_code=$?
|
||||
trap - TERM INT
|
||||
if [ "$exit_code" -eq 42 ]; then
|
||||
echo "MeTube requested yt-dlp update restart (exit 42)"
|
||||
do_upgrade || true
|
||||
continue
|
||||
fi
|
||||
return "$exit_code"
|
||||
done
|
||||
}
|
||||
|
||||
nightly_enabled() {
|
||||
[ -n "${YTDL_NIGHTLY_UPDATE_TIME}" ]
|
||||
}
|
||||
|
||||
disable_nightly_for_non_root() {
|
||||
if nightly_enabled; then
|
||||
echo "YTDL_NIGHTLY_UPDATE_TIME is set but this container runs as a non-root user; nightly yt-dlp updates are not supported. Ignoring YTDL_NIGHTLY_UPDATE_TIME."
|
||||
unset YTDL_NIGHTLY_UPDATE_TIME
|
||||
fi
|
||||
}
|
||||
|
||||
if [ `id -u` -eq 0 ] && [ `id -g` -eq 0 ]; then
|
||||
if [ "${PUID}" -eq 0 ]; then
|
||||
echo "Warning: it is not recommended to run as root user, please check your setting of the PUID/PGID (or legacy UID/GID) environment variables"
|
||||
fi
|
||||
if [ "${CHOWN_DIRS:-true}" != "false" ]; then
|
||||
echo "Changing ownership of download and state directories to ${PUID}:${PGID}"
|
||||
chown -R "${PUID}":"${PGID}" /app "${DOWNLOAD_DIR}" "${AUDIO_DOWNLOAD_DIR}" "${STATE_DIR}" "${TEMP_DIR}"
|
||||
fi
|
||||
if nightly_enabled; then
|
||||
echo "YTDL_NIGHTLY_UPDATE_TIME is set to ${YTDL_NIGHTLY_UPDATE_TIME}; upgrading yt-dlp on startup"
|
||||
do_upgrade || true
|
||||
fi
|
||||
echo "Starting BgUtils POT Provider"
|
||||
gosu "${PUID}":"${PGID}" bgutil-pot server >/tmp/bgutil-pot.log 2>&1 &
|
||||
echo "Running MeTube as user ${PUID}:${PGID}"
|
||||
run_supervised gosu "${PUID}":"${PGID}" python3 app/main.py
|
||||
exit $?
|
||||
else
|
||||
echo "User set by docker; running MeTube as `id -u`:`id -g`"
|
||||
disable_nightly_for_non_root
|
||||
echo "Starting BgUtils POT Provider"
|
||||
bgutil-pot server >/tmp/bgutil-pot.log 2>&1 &
|
||||
run_supervised python3 app/main.py
|
||||
exit $?
|
||||
fi
|
||||
|
||||
## 1.7 Dockerfile ENTRYPOINT/CMD/ENV
|
||||
75:ENV PUID=1000
|
||||
76:ENV PGID=1000
|
||||
77:ENV UMASK=022
|
||||
79:ENV DOWNLOAD_DIR=/downloads
|
||||
80:ENV STATE_DIR=/downloads/.metube
|
||||
81:ENV TEMP_DIR=/downloads
|
||||
82:ENV PORT=8081
|
||||
84:EXPOSE 8081
|
||||
90:ENV METUBE_VERSION=$VERSION
|
||||
92:ENTRYPOINT ["/usr/bin/tini", "-g", "--", "./docker-entrypoint.sh"]
|
||||
|
||||
## 1.6 every setting the app reads (app/main.py Config._DEFAULTS) — no key, secret or password among them
|
||||
_DEFAULTS = {
|
||||
'DOWNLOAD_DIR': '.',
|
||||
'AUDIO_DOWNLOAD_DIR': '%%DOWNLOAD_DIR',
|
||||
'TEMP_DIR': '%%DOWNLOAD_DIR',
|
||||
'DOWNLOAD_DIRS_INDEXABLE': 'false',
|
||||
'CUSTOM_DIRS': 'true',
|
||||
'CREATE_CUSTOM_DIRS': 'true',
|
||||
'CUSTOM_DIRS_EXCLUDE_REGEX': r'(^|/)[.@].*$',
|
||||
'DEFAULT_FOLDER': '',
|
||||
'DELETE_FILE_ON_TRASHCAN': 'false',
|
||||
'STATE_DIR': '.',
|
||||
'URL_PREFIX': '',
|
||||
'PUBLIC_HOST_URL': 'download/',
|
||||
'PUBLIC_HOST_AUDIO_URL': 'audio_download/',
|
||||
'OUTPUT_TEMPLATE': '%(title)s.%(ext)s',
|
||||
'OUTPUT_TEMPLATE_CHAPTER': '%(title)s - %(section_number)02d - %(section_title)s.%(ext)s',
|
||||
'OUTPUT_TEMPLATE_PLAYLIST': '%(playlist_title)s/%(title)s.%(ext)s',
|
||||
'OUTPUT_TEMPLATE_CHANNEL': '%(channel)s/%(title)s.%(ext)s',
|
||||
'DEFAULT_OPTION_PLAYLIST_ITEM_LIMIT' : '0',
|
||||
'SUBSCRIPTION_DEFAULT_CHECK_INTERVAL': '60',
|
||||
'SUBSCRIPTION_SCAN_PLAYLIST_END': '50',
|
||||
'SUBSCRIPTION_MAX_SEEN_IDS': '50000',
|
||||
'CLEAR_COMPLETED_AFTER': '0',
|
||||
'YTDL_OPTIONS': '{}',
|
||||
'YTDL_OPTIONS_FILE': '',
|
||||
'YTDL_OPTIONS_PRESETS': '{}',
|
||||
'YTDL_OPTIONS_PRESETS_FILE': '',
|
||||
'ALLOW_YTDL_OPTIONS_OVERRIDES': 'false',
|
||||
'ALLOW_PRIVATE_ADDRESSES': 'false',
|
||||
'CORS_ALLOWED_ORIGINS': '',
|
||||
'ROBOTS_TXT': '',
|
||||
'HOST': '0.0.0.0',
|
||||
'PORT': '8081',
|
||||
'HTTPS': 'false',
|
||||
'CERTFILE': '',
|
||||
'KEYFILE': '',
|
||||
'BASE_DIR': '',
|
||||
'DEFAULT_THEME': 'auto',
|
||||
'MAX_CONCURRENT_DOWNLOADS': '3',
|
||||
'LOGLEVEL': 'INFO',
|
||||
'ENABLE_ACCESSLOG': 'false',
|
||||
'YTDL_NIGHTLY_UPDATE_TIME': '',
|
||||
}
|
||||
|
||||
## 0.4 / 0.5 network at start and at rest
|
||||
- yt-dlp self-update: ONLY when YTDL_NIGHTLY_UPDATE_TIME is set (default empty; the template does not set it) — then pip installs yt-dlp nightly at start and at that time each day (exit 42 restart). Off here: the image's yt-dlp stays the pinned one.
|
||||
98: 'YTDL_NIGHTLY_UPDATE_TIME': '',
|
||||
187: if self.YTDL_NIGHTLY_UPDATE_TIME and not _NIGHTLY_TIME_RE.match(self.YTDL_NIGHTLY_UPDATE_TIME):
|
||||
189: 'Environment variable "YTDL_NIGHTLY_UPDATE_TIME" must be HH:MM (24-hour), got "%s"',
|
||||
190: self.YTDL_NIGHTLY_UPDATE_TIME,
|
||||
755: time_hhmm = config.YTDL_NIGHTLY_UPDATE_TIME
|
||||
1532: sys.exit(42)
|
||||
- bgutil-pot server: started by the entrypoint (a local PO-token provider for YouTube; it talks to YouTube only when a YouTube download asks for a token).
|
||||
- no telemetry, no version check: grep for analytics/telemetry/sentry/version-check in app/:
|
||||
(empty above = none found; positive control: 'YTDL_NIGHTLY' is found by the same grep shape above)
|
||||
|
||||
## 0.7 clients
|
||||
112:| `CORS_ALLOWED_ORIGINS` | | Comma-separated origins allowed to call MeTube from other sites, as [browser extensions and bookmarklets](https://github.com/alexta69/metube/wiki/Sending-links-to-MeTube) do. `*` allows any site, so prefer naming them. |
|
||||
118:yt-dlp options are JSON objects keyed by yt-dlp's [API option names](https://github.com/yt-dlp/yt-dlp/blob/master/yt_dlp/YoutubeDL.py#L224), which differ from its command-line flags ([converter](https://github.com/yt-dlp/yt-dlp/blob/master/devscripts/cli_to_api.py)). They apply at three levels, and for an option set at more than one, the more specific level wins:
|
||||
139:* [Sending links to MeTube](https://github.com/alexta69/metube/wiki/Sending-links-to-MeTube) — browser extensions, bookmarklets, iOS and Android apps, Raycast.
|
||||
@@ -0,0 +1,38 @@
|
||||
# check-volume-persistence.py grimmory metube --evidence /root/ev3 (one run; --evidence used to show ports/exercise) - 2026-10-02T07:24:26Z, after the R-801 port fix, bench LXC 9401 on demo-hp (debian-13, swap 0, nvme-scratch), catalog-wt de0a9bd + uncommitted working tree (17 path(s), REFRESHED copy with R-788 APP_EXERCISE + R-801 routed_ports, copied with its .git), sibling felhom.eu 68c2290 (git archive) at ../felhom.eu
|
||||
# sibling copy ALSO carries tar copies of DooPlex UNCOMMITTED documentation/audits/family-gate-2026-10-02/ and documentation/audits/licences-2026-10-02/; in the bench sibling B/catalog-gates-grimmory.txt = copy of catalog-gates-grimmory-run1.txt and B/catalog-gates-metube.txt = copy of catalog-gates-metube-run2.txt so the onboarding citations resolve
|
||||
M CHANGELOG.md
|
||||
M CONTEXT.md
|
||||
M FIRST-ADMIN.md
|
||||
M README.md
|
||||
M REUSE.md
|
||||
M scripts/box_walk.py
|
||||
M scripts/catalog_gates.py
|
||||
M scripts/check-volume-persistence.py
|
||||
M scripts/copy_freeze/hu.json
|
||||
M scripts/test_check_volume_persistence.py
|
||||
M scripts/test_gate_decoys.py
|
||||
M scripts/upgrade_fixtures_box.py
|
||||
?? onboarding/grimmory.md
|
||||
?? onboarding/metube.md
|
||||
?? scripts/check-family-gate.py
|
||||
?? templates/grimmory/
|
||||
?? templates/metube/
|
||||
self-testing the prober (both directions)…
|
||||
prober flags the R-156 signature and clears a correct template — trustworthy
|
||||
grimmory CLEAN grimmory: this container's mounts are all empty while it created entries in ['/', '/app', '/etc'] — benign when a sibling container holds the state, w
|
||||
metube CLEAN
|
||||
|
||||
2 clean · 0 broken · 0 undetermined (of 2 in scope)
|
||||
volume-persistence gate OK
|
||||
check-volume-persistence exit code = 0
|
||||
|
||||
# probe evidence: ports + exercise per app
|
||||
grimmory verdict= CLEAN ports= [6060] exercise= ["172.18.0.2:6060/ -> 200", "172.21.0.3:6060/ -> 200"]
|
||||
mount /app/data files= 0 sample= []
|
||||
mount /books files= 0 sample= []
|
||||
mount /bookdrop files= 0 sample= []
|
||||
mount /var/lib/mysql files= 355 sample= ['undo001', 'tc.log', 'ddl_recovery.log', 'aria_log_control', 'ib_logfile0']
|
||||
metube verdict= CLEAN ports= [8081] exercise= ["172.18.0.2:8081/ -> 200", "POST 172.18.0.2:8081/add -> 200 (the app's own write path)"]
|
||||
mount /downloads files= 1 sample= ['Big_Buck_Bunny_360_10s_1MB.mp4']
|
||||
mount /state files= 2 sample= ['completed.json', 'queue.json']
|
||||
# leftover containers: 0
|
||||
@@ -0,0 +1,15 @@
|
||||
# DIAGNOSTIC (not a gate run): check-volume-persistence.py metube --no-self-test --evidence /root/ev on bench 9401, same tree, 2026-10-02 ~07:21Z; then the evidence probe.json fields, the bench's reachability of the R-788 test video, and the label shape 'docker compose config --format json' (Compose 2.26.1) gives for templates/metube
|
||||
exit=2
|
||||
/root/ev/metube/probe.json
|
||||
{
|
||||
"app": null,
|
||||
"ports": null,
|
||||
"exercise": null,
|
||||
"error": null
|
||||
}
|
||||
test-videos.co.uk from bench: 200
|
||||
['probe', 'reasons', 'verdict']
|
||||
probe.containers.0.mounts [{"class": "bind", "files": 0, "name": null, "sample": [], "source": "/srv/felhom-gate/hdd/userdata/media/metube", "target": "/downloads", "writable_by_app": "yes"}, {"class": "named-declared", "files": 0, "name": "volgate-metube_metube_state", "sample": [], "source": "/var/lib/docker/volumes/volgate-metube_metube_state/_data", "target": "/state", "writable_by_app": "yes"}]
|
||||
probe.exercise []
|
||||
probe.ports []
|
||||
metube dict {"traefik.enable": "true", "traefik.http.routers.metube.entrypoints": "websecure", "traefik.http.routers.metube.rule": "Host(`a.b`)", "traefik.http.routers.metube.tls": "true", "traefik.http.routers.metube.tls.certresolver": "letsencrypt", "traefik.http.services.metube.loadbalancer.server.port": "8081"}
|
||||
@@ -0,0 +1,29 @@
|
||||
# check-volume-persistence.py metube (R-788 exerciser) - 2026-10-02T07:14:46Z, bench LXC 9401 on demo-hp (debian-13, swap 0, nvme-scratch), catalog-wt de0a9bd + uncommitted working tree (16 path(s), REFRESHED copy with check-volume-persistence.py APP_EXERCISE R-788, copied with its .git), sibling felhom.eu 68c2290 (git archive) at ../felhom.eu
|
||||
# sibling copy ALSO carries tar copies of DooPlex UNCOMMITTED documentation/audits/family-gate-2026-10-02/ and documentation/audits/licences-2026-10-02/ (real B/catalog-gates-grimmory.txt; B/catalog-gates-metube.txt = the run-1 output, copied from catalog-gates-metube-run1.txt so the onboarding citation resolves)
|
||||
M CHANGELOG.md
|
||||
M CONTEXT.md
|
||||
M FIRST-ADMIN.md
|
||||
M README.md
|
||||
M REUSE.md
|
||||
M scripts/box_walk.py
|
||||
M scripts/catalog_gates.py
|
||||
M scripts/check-volume-persistence.py
|
||||
M scripts/copy_freeze/hu.json
|
||||
M scripts/test_gate_decoys.py
|
||||
M scripts/upgrade_fixtures_box.py
|
||||
?? onboarding/grimmory.md
|
||||
?? onboarding/metube.md
|
||||
?? scripts/check-family-gate.py
|
||||
?? templates/grimmory/
|
||||
?? templates/metube/
|
||||
self-testing the prober (both directions)…
|
||||
prober flags the R-156 signature and clears a correct template — trustworthy
|
||||
metube UNDETERMINED NOTHING this app wrote landed in ANY folder the template preserves: all 2 mount(s) across 1 container(s) are empty, yet entries were created in ['/'].
|
||||
|
||||
UNDETERMINED — NOT a pass. The question was not answered for these:
|
||||
metube: NOTHING this app wrote landed in ANY folder the template preserves: all 2 mount(s) across 1 container(s) are empty, yet entries were created in ['/']. Needs adjudication.; metube: this container's mou
|
||||
|
||||
0 clean · 0 broken · 1 undetermined (of 1 in scope)
|
||||
INCOMPLETE — no broken template among those decided, but 1 were never decided. This is not a clean bill of health.
|
||||
check-volume-persistence exit code = 2
|
||||
0
|
||||
@@ -0,0 +1,28 @@
|
||||
# check-volume-persistence.py metube - single RE-RUN after catalog_gates metube answered UNDETERMINED, 2026-10-02T07:09:30Z, same bench 9401 / same tree
|
||||
self-testing the prober (both directions)…
|
||||
prober flags the R-156 signature and clears a correct template — trustworthy
|
||||
metube UNDETERMINED NOTHING this app wrote landed in ANY folder the template preserves: all 2 mount(s) across 1 container(s) are empty, yet entries were created in ['/'].
|
||||
|
||||
UNDETERMINED — NOT a pass. The question was not answered for these:
|
||||
metube: NOTHING this app wrote landed in ANY folder the template preserves: all 2 mount(s) across 1 container(s) are empty, yet entries were created in ['/']. Needs adjudication.; metube: this container's mou
|
||||
|
||||
0 clean · 0 broken · 1 undetermined (of 1 in scope)
|
||||
INCOMPLETE — no broken template among those decided, but 1 were never decided. This is not a clean bill of health.
|
||||
exit=2
|
||||
|
||||
31: volumes:
|
||||
32- - ${USERDATA_PATH}/media/metube:/downloads
|
||||
33- - metube_state:/state
|
||||
34- networks:
|
||||
35- - traefik-public
|
||||
36- deploy:
|
||||
37- resources:
|
||||
--
|
||||
54:volumes:
|
||||
55- metube_state:
|
||||
56-
|
||||
57-networks:
|
||||
58- traefik-public:
|
||||
59- external: true
|
||||
0
|
||||
0
|
||||
@@ -0,0 +1,58 @@
|
||||
+ date -u
|
||||
Fri Oct 2 06:08:57 UTC 2026
|
||||
+ pct list
|
||||
VMID Status Lock Name
|
||||
9201 running demo-hp
|
||||
9202 running demo-hp-scratch
|
||||
+ free -g
|
||||
+ head -2
|
||||
total used free shared buff/cache available
|
||||
Mem: 29 5 7 0 16 23
|
||||
+ pvesm status
|
||||
Name Type Status Total (KiB) Used (KiB) Available (KiB) %
|
||||
felhom-pbs pbs active 0 0 0 0.00%
|
||||
local dir active 40453376 19518448 18847812 48.25%
|
||||
local-lvm lvmthin active 56487936 34943437 21544498 61.86%
|
||||
nvme-scratch dir active 983379700 77369564 855983524 7.87%
|
||||
+ pct config 9401
|
||||
+ head -1
|
||||
Configuration file 'nodes/demo-hp/lxc/9401.conf' does not exist
|
||||
+ pveam list local
|
||||
+ grep debian-13
|
||||
local:vztmpl/debian-13-standard_13.6-1_amd64.tar.zst 123.93MB
|
||||
+ pct create 9401 local:vztmpl/debian-13-standard_13.6-1_amd64.tar.zst --hostname upgrade-harness --cores 6 --memory 10240 --swap 0 --rootfs nvme-scratch:60 --net0 name=eth0,bridge=vmbr0,ip=dhcp --unprivileged 1 --features nesting=1,keyctl=1 --onboot 0
|
||||
+ tail -1
|
||||
done: SHA256:ykjxfuoVs3kzSX7J3C3fNvc9sHEaSuKaGmECAWYcDlY root@upgrade-harness
|
||||
+ pct config 9401
|
||||
arch: amd64
|
||||
cores: 6
|
||||
features: nesting=1,keyctl=1
|
||||
hostname: upgrade-harness
|
||||
memory: 10240
|
||||
net0: name=eth0,bridge=vmbr0,hwaddr=BC:24:11:9C:EF:0B,ip=dhcp,type=veth
|
||||
onboot: 0
|
||||
ostype: debian
|
||||
rootfs: nvme-scratch:9401/vm-9401-disk-0.raw,size=60G
|
||||
swap: 0
|
||||
unprivileged: 1
|
||||
+ pct start 9401
|
||||
+ sleep 15
|
||||
+ pct exec 9401 -- bash -c 'dpkg --print-architecture; hostname; ip -4 -o addr show eth0 | awk "{print \$4}"; apt-get update -qq >/dev/null 2>&1; DEBIAN_FRONTEND=noninteractive apt-get install -y -qq docker.io docker-compose python3 python3-yaml curl postgresql-client sqlite3 git >/dev/null 2>&1; docker --version; docker compose version; python3 --version; docker network create traefik-public >/dev/null && echo traefik-public-net; swapon --show; free -m | head -3; df -h /'
|
||||
amd64
|
||||
upgrade-harness
|
||||
192.168.0.156/24
|
||||
Docker version 26.1.5+dfsg1, build a72d7cd
|
||||
Docker Compose version 2.26.1-4
|
||||
Python 3.13.5
|
||||
traefik-public-net
|
||||
total used free shared buff/cache available
|
||||
Mem: 10240 60 8522 0 1656 10179
|
||||
Swap: 0 0 0
|
||||
Filesystem Size Used Avail Use% Mounted on
|
||||
/dev/loop2 59G 1.3G 55G 3% /
|
||||
+ pvesm status
|
||||
Name Type Status Total (KiB) Used (KiB) Available (KiB) %
|
||||
felhom-pbs pbs active 0 0 0 0.00%
|
||||
local dir active 40453376 19518540 18847720 48.25%
|
||||
local-lvm lvmthin active 56487936 34943437 21544498 61.86%
|
||||
nvme-scratch dir active 983379700 78972708 854380380 8.03%
|
||||
@@ -0,0 +1,9 @@
|
||||
Fri Oct 2 06:08:37 UTC 2026
|
||||
== docker manifest inspect ghcr.io/alexta69/metube:2026.09.28
|
||||
amd64 sha256:3faacaa516ce3317209b0654e955ffaf42351ffdadf02bfb89b2b469cb032394
|
||||
arm64 sha256:82779a818083a82ef94c6de9fa2ac6799bb4bb04004b555939571e88f75029ac
|
||||
rc=0
|
||||
== docker manifest inspect ghcr.io/alexta69/metube:2026.09.29
|
||||
amd64 sha256:8f7c95941bcc560ea4ddd9ac27142698000e1abf08ac43d709828e712f71a4ea
|
||||
arm64 sha256:8dff69bddc54b31be12d743b78a3cdf41683d0546ce7c73a929d645873e11ead
|
||||
rc=0
|
||||
@@ -0,0 +1,5 @@
|
||||
# ghcr.io/alexta69/metube tag list (registry v2 tags/list, anonymous pull token), 2026-10-02T06:36:53Z — 6.5 shape only; same-tag re-pushes NOT measured here
|
||||
tags total 221
|
||||
shapes: [('9999-99-99', 112), ('9999.99.99', 108), ('latest', 1)]
|
||||
dated tags in the last year: 93 first 2025.07.31 last ['2026.09.25', '2026.09.26', '2026.09.27', '2026.09.28', '2026.09.29']
|
||||
dash-shaped: first 2023-03-25 last 2025-07-30
|
||||
@@ -0,0 +1,8 @@
|
||||
# check-volume-persistence.py metube — bench 9401 (demo-hp, swap 0), catalog copy de0a9bd + 7 uncommitted path(s) (the unpublished metube template), 2026-10-02T06:31:46Z
|
||||
self-testing the prober (both directions)…
|
||||
prober flags the R-156 signature and clears a correct template — trustworthy
|
||||
metube CLEAN metube: declared volume /state is EMPTY
|
||||
|
||||
1 clean · 0 broken · 0 undetermined (of 1 in scope)
|
||||
volume-persistence gate OK
|
||||
gate exit code = 0
|
||||
@@ -0,0 +1,122 @@
|
||||
# catalog_gates.py metube — full clone (not shallow) of the catalog COPY on bench 9401 (demo-hp, swap 0), catalog de0a9bd + 7 uncommitted path(s), 2026-10-02T06:33:49Z
|
||||
M scripts/box_walk.py
|
||||
M scripts/catalog_gates.py
|
||||
M scripts/test_gate_decoys.py
|
||||
M scripts/upgrade_fixtures_box.py
|
||||
?? scripts/check-family-gate.py
|
||||
?? templates/grimmory/
|
||||
?? templates/metube/
|
||||
catalog_gates — apps: metube
|
||||
|
||||
==============================================================================
|
||||
== gate: image-pins (check-image-pins.py)
|
||||
==============================================================================
|
||||
image-pin gate OK — 58 templates, 0 unpinned images
|
||||
|
||||
==============================================================================
|
||||
== gate: image-resolvable (check-image-resolvable.py metube)
|
||||
==============================================================================
|
||||
resolving 1 unique image pin(s)…
|
||||
image-resolvability gate OK — 1 unique pins, all resolve
|
||||
|
||||
==============================================================================
|
||||
== gate: volume-persistence (check-volume-persistence.py metube)
|
||||
==============================================================================
|
||||
self-testing the prober (both directions)…
|
||||
prober flags the R-156 signature and clears a correct template — trustworthy
|
||||
metube CLEAN metube: declared volume /state is EMPTY
|
||||
|
||||
1 clean · 0 broken · 0 undetermined (of 1 in scope)
|
||||
volume-persistence gate OK
|
||||
|
||||
==============================================================================
|
||||
== gate: engine-major (check-engine-major.py)
|
||||
==============================================================================
|
||||
engine-major gate — range origin/main..HEAD: 0 compose file(s) changed, 0 engine pin(s) compared
|
||||
engine-major gate OK — no forbidden engine major, and no engine major bundled with another image move (rule: CLAUDE.md, amended by R-469 2026-09-21)
|
||||
|
||||
==============================================================================
|
||||
== gate: catalog-since (check-catalog-since.py)
|
||||
==============================================================================
|
||||
catalog-since gate — range origin/main..HEAD: 0 compose file(s) changed, 0 image move(s) dated
|
||||
catalog-since gate OK — every image move in the range carries a catalog_since on or after its commit day
|
||||
|
||||
==============================================================================
|
||||
== gate: copy-i18n (check-copy-i18n.py metube)
|
||||
==============================================================================
|
||||
copy-i18n: matcher controls OK (positive „Jelentkezz be…" convicts, negative „Encrypted notes…" does not)
|
||||
copy-i18n: 58 apps · 1155 Hungarian copy strings frozen · 1149 with English
|
||||
copy-i18n: translated so far — actualbudget 15/15, adventurelog 18/18, audiobookshelf 21/21, bentopdf 14/14, bookstack 21/21, calcom 22/22, calibre-web 27/27, claper 20/20, code-server 20/20, crafty-controller 24/24, dawarich 21/21, docmost 19/19, emby 22/22, ghost 16/16, gitea 17/17, glance 15/15, gokapi 19/19, grafana 19/19, gramps-web 17/17, grimmory 21/24, home-assistant 18/18, homebox 17/17, homepage 15/15, immich 24/24, jellyfin 22/22, karakeep 19/19, kimai 20/20, komga 21/21, mealie 19/19, metube 17/19, n8n 17/17, navidrome 21/21, nextcloud 28/28, onlyoffice 24/24, opengist 16/16, outline 21/21, paperless-ngx 33/33, papra 14/15, plant-it 16/16, plex 25/25, privatebin 14/14, radarr 22/22, radicale 19/19, rallly 17/17, recipe-importer 19/19, romm 41/41, seerr 18/18, sonarr 22/22, sparkyfitness 21/21, tandoor 18/18, termix 12/12, uptime-kuma 16/16, vaultwarden 23/23, vikunja 18/18, wanderer 20/20, wger 20/20, wishlist 16/16, zipline 18/18
|
||||
|
||||
copy-i18n: FAIL — 3 finding(s)
|
||||
|
||||
- grimmory: not in the freeze. A NEW app's Hungarian has never been reviewed — run `python3 scripts/check-copy-i18n.py --add-app grimmory --reason "…"` in the same commit.
|
||||
- metube: not in the freeze. A NEW app's Hungarian has never been reviewed — run `python3 scripts/check-copy-i18n.py --add-app metube --reason "…"` in the same commit.
|
||||
- English coverage: 6 strings have no English, ceiling is 1 (ABOVE).
|
||||
A push claimed translations it did not make.
|
||||
|
||||
==============================================================================
|
||||
== gate: probe-matches-compose (check-probe-matches-compose.py metube)
|
||||
==============================================================================
|
||||
probe-matches-compose: 1 app(s), mode: full
|
||||
|
||||
probe-matches-compose: OK — every probe dials the port (and, where it can fail, the path) that the app's own compose healthcheck dials
|
||||
|
||||
==============================================================================
|
||||
== gate: probe-measured (check-probe-measured.py metube)
|
||||
==============================================================================
|
||||
probe-measured: OK — 0 probes, each with a measured before/after
|
||||
|
||||
==============================================================================
|
||||
== gate: test-record (check-test-record.py metube)
|
||||
==============================================================================
|
||||
test-record gate — 1 template(s) read, 0 carry a ladder, 0 convicted
|
||||
|
||||
==============================================================================
|
||||
== gate: test-record-move (check-test-record-move.py)
|
||||
==============================================================================
|
||||
test-record-move gate — range origin/main..HEAD: 0 compose file(s) changed
|
||||
|
||||
==============================================================================
|
||||
== gate: onboarding (check-onboarding.py)
|
||||
==============================================================================
|
||||
onboarding gate — 61 checklist ids; 58 template dirs: 53 exempt (published before 2026-10-01), 5 new; 2 exempt app(s) with a record (shape-checked): sparkyfitness, wger
|
||||
NOT CHECKED here (sibling repository absent — the pre-push hook on DooPlex checks them): 224 path(s)
|
||||
felhom.eu/documentation/audits/new-apps-2026-10-01/A/A1-github-facts.txt
|
||||
felhom.eu/documentation/audits/new-apps-2026-10-01/A/A1-github-facts.txt
|
||||
felhom.eu/documentation/audits/new-apps-2026-10-01/FIT.md
|
||||
felhom.eu/documentation/audits/new-apps-2026-10-01/box/dawarich/checks.txt
|
||||
felhom.eu/documentation/audits/new-apps-2026-10-01/shots/dawarich/1.png
|
||||
felhom.eu/documentation/audits/new-apps-2026-10-01/box/dawarich/install.txt
|
||||
felhom.eu/documentation/audits/new-apps-2026-10-01/box/dawarich/install.txt
|
||||
felhom.eu/documentation/audits/new-apps-2026-10-01/bench/dawarich/evidence/MV-dawarich/verdict.json
|
||||
felhom.eu/documentation/audits/new-apps-2026-10-01/G/gates-dawarich.txt
|
||||
felhom.eu/documentation/audits/new-apps-2026-10-01/A/compose/dawarich.yml
|
||||
ONBOARDING GATE FAILED:
|
||||
grimmory: NEW app with no onboarding record — copy onboarding/_TEMPLATE.md to onboarding/grimmory.md and answer every id (NEW-APP-CHECKLIST.md)
|
||||
metube: NEW app with no onboarding record — copy onboarding/_TEMPLATE.md to onboarding/metube.md and answer every id (NEW-APP-CHECKLIST.md)
|
||||
|
||||
==============================================================================
|
||||
== gate: family-gate (check-family-gate.py)
|
||||
==============================================================================
|
||||
family-gate: rule 3 NOT CHECKED — no felhom.eu sibling with a baked golden at /opt/felhom.eu
|
||||
family-gate gate OK: 2 family-gated template(s) ['grimmory', 'metube']
|
||||
|
||||
==============================================================================
|
||||
== summary
|
||||
==============================================================================
|
||||
image-pins OK (exit 0)
|
||||
image-resolvable OK (exit 0)
|
||||
volume-persistence OK (exit 0)
|
||||
engine-major OK (exit 0)
|
||||
catalog-since OK (exit 0)
|
||||
copy-i18n FAILED (exit 1)
|
||||
probe-matches-compose OK (exit 0)
|
||||
probe-measured OK (exit 0)
|
||||
test-record OK (exit 0)
|
||||
test-record-move OK (exit 0)
|
||||
onboarding FAILED (exit 1)
|
||||
family-gate OK (exit 0)
|
||||
|
||||
CONVICTED: copy-i18n, onboarding
|
||||
catalog_gates exit code = 1
|
||||
@@ -0,0 +1,7 @@
|
||||
# check-family-gate.py — re-run with the felhom.eu sibling PRESENT (only its documentation/tests/golden-*/ dirs, felhom.eu 344081f, copied to /opt/sib/felhom.eu) so rule 3 is CHECKED; bench 9401, catalog copy, 2026-10-02T06:36:29Z
|
||||
golden-0.284.2-2026-09-30
|
||||
golden-0.285.0-2026-10-01
|
||||
golden-0.286.1-2026-10-01
|
||||
REFUSED family_gate on grimmory, metube while the newest baked golden is 0.286.1 — a box installed from it would publish the app OPEN; bake a golden >= 0.287.0 first
|
||||
family-gate gate: 1 refusal(s)
|
||||
check-family-gate exit code = 1
|
||||
@@ -0,0 +1,38 @@
|
||||
+ date -u
|
||||
Fri Oct 2 06:37:05 UTC 2026
|
||||
+ pct list
|
||||
VMID Status Lock Name
|
||||
9201 running demo-hp
|
||||
9202 running demo-hp-scratch
|
||||
9401 running upgrade-harness
|
||||
+ pvesm status
|
||||
Name Type Status Total (KiB) Used (KiB) Available (KiB) %
|
||||
felhom-pbs pbs active 0 0 0 0.00%
|
||||
local dir active 40453376 19527624 18838636 48.27%
|
||||
local-lvm lvmthin active 56487936 34943437 21544498 61.86%
|
||||
nvme-scratch dir active 983379700 81247112 852105976 8.26%
|
||||
+ pct exec 9401 -- bash -c 'docker ps -a --format {{.Names}} | wc -l; docker volume ls -q | wc -l'
|
||||
0
|
||||
0
|
||||
+ pct stop 9401
|
||||
+ pct destroy 9401 --purge
|
||||
purging CT 9401 from related configurations..
|
||||
+ pct list
|
||||
VMID Status Lock Name
|
||||
9201 running demo-hp
|
||||
9202 running demo-hp-scratch
|
||||
+ pct config 9401
|
||||
+ head -1
|
||||
Configuration file 'nodes/demo-hp/lxc/9401.conf' does not exist
|
||||
+ ls /mnt/hdd_1/images/
|
||||
9202
|
||||
+ pvesm status
|
||||
Name Type Status Total (KiB) Used (KiB) Available (KiB) %
|
||||
felhom-pbs pbs active 0 0 0 0.00%
|
||||
local dir active 40453376 19527552 18838708 48.27%
|
||||
local-lvm lvmthin active 56487936 34943437 21544498 61.86%
|
||||
nvme-scratch dir active 983379700 77370540 855982548 7.87%
|
||||
+ ls /tmp
|
||||
+ grep -E 'b9401|upg-sync|catclone|gold|burst|birth|sampler'
|
||||
tmp-leftovers=1
|
||||
+ echo tmp-leftovers=1
|
||||
@@ -0,0 +1,7 @@
|
||||
# After the idle hold ended (06:17:07Z) and the birth sampler was stopped: API probes against the birth container (not part of 5.1's numbers).
|
||||
== the fixture's own payload (no download_type), POST /add: 200, then again -> {"status": "ok", "msg": "Already in queue: Big_Buck_Bunny_360_10s_1MB"}
|
||||
== audio mp3 of Sintel_360_10s_1MB with custom_name_prefix probe1: {"status": "ok"} 200
|
||||
== video of the same URL with custom_name_prefix probe2: {"status": "ok", "msg": "Already in queue: Sintel_360_10s_1MB"} 200 <- a prefix does NOT make a second item of the same URL while it is queued
|
||||
history after 20 s:
|
||||
done Big_Buck_Bunny_360_10s_1MB finished Big_Buck_Bunny_360_10s_1MB.mp4 991017
|
||||
done probe1.Sintel_360_10s_1MB error None None ERROR: Postprocessing: WARNING: unable to obtain file audio codec with ffprobe <- the test clips carry NO audio stream (ffprobe: stream,video only), so audio-only is not usable with them
|
||||
@@ -0,0 +1,5 @@
|
||||
== re-add a URL already in done, new prefix:
|
||||
{"status": "ok"} 200
|
||||
done again1.Big_Buck_Bunny_360_10s_1MB finished again1.Big_Buck_Bunny_360_10s_1MB.mp4 991017
|
||||
done probe1.Sintel_360_10s_1MB error None None ERROR: Postprocessing: WARNING: unable to obtain file audio codec with ffprobe
|
||||
stream,video
|
||||
@@ -0,0 +1,48 @@
|
||||
"""birth.py — checklist 5.1 / 4.3 (bench half) for metube at the PIN, from birth, swap 0.
|
||||
Renders the catalog template exactly as upgrade-test.py does (its own render/build_env/settle), starts the
|
||||
from-birth sampler BEFORE `up -d`, times up -d -> every container healthy, then keeps sampling idle for HOLD s.
|
||||
Images are pre-pulled, so the time is start time, not download time. Prints no secret.
|
||||
(Copied from the visitors-2026-10-01 C bench birth.py; only the app/container names changed.)"""
|
||||
import importlib.util, json, os, subprocess, sys, time
|
||||
sys.path.insert(0, "/opt/upg"); os.chdir("/opt/upg")
|
||||
spec = importlib.util.spec_from_file_location("ut", "/opt/upg/upgrade-test.py"); ut = importlib.util.module_from_spec(spec)
|
||||
sys.argv = ["upgrade-test.py"]; spec.loader.exec_module(ut)
|
||||
from pathlib import Path
|
||||
HOLD = int(os.environ.get("HOLD", "300"))
|
||||
app, project = "metube", "birth"
|
||||
NAMES = ("metube",)
|
||||
wd = Path("/opt/upg/work/BIRTH"); ev = Path("/opt/upg/evidence/BIRTH"); ev.mkdir(parents=True, exist_ok=True)
|
||||
tdir = ut.TEMPLATES / app
|
||||
env = ut.cvp.build_env(app, (tdir / ".felhom.yml").read_text(), (tdir / "docker-compose.yml").read_text())
|
||||
ut.render(app, {}, wd, env)
|
||||
log = open(ev / "birth.log", "w", buffering=1)
|
||||
def say(m):
|
||||
l = time.strftime("[%H:%M:%S] ", time.gmtime()) + m; print(l, flush=True); log.write(l + "\n")
|
||||
say("images: " + json.dumps(ut.template_images(app, ut.TEMPLATES)))
|
||||
say("swap on the bench: " + (subprocess.run(["swapon", "--show"], capture_output=True, text=True).stdout.strip() or "none"))
|
||||
subprocess.run("rm -f /root/mem-birth.csv.stop; (NAMES='metube' OUT=/root/mem-birth.csv DUR=1200 nohup bash /opt/upg/sampler.sh >/dev/null 2>&1 &)", shell=True)
|
||||
time.sleep(1)
|
||||
t0 = time.time()
|
||||
up = ut.compose(wd, project, "up", "-d")
|
||||
say(f"up -d rc={up.returncode} in {time.time()-t0:.1f}s")
|
||||
ok, secs, states = ut.settle(project, wd, wait=600)
|
||||
say(f"settled={ok} in {time.time()-t0:.1f}s after up -d (settle loop {secs}s) :: {json.dumps(states)}")
|
||||
for c in NAMES:
|
||||
r = subprocess.run(["docker", "inspect", "-f", "{{.State.StartedAt}} {{.State.Health.Status}} rc={{.RestartCount}} mem={{.HostConfig.Memory}}", c], capture_output=True, text=True)
|
||||
say(f" {c}: {r.stdout.strip()}")
|
||||
r = subprocess.run(["docker", "inspect", "-f", "{{json .State.Health.Log}}", c], capture_output=True, text=True)
|
||||
try:
|
||||
hl = json.loads(r.stdout)
|
||||
say(f" {c}: first health probe {hl[0]['Start']} exit={hl[0]['ExitCode']}; probes so far {len(hl)}")
|
||||
except Exception as e:
|
||||
say(f" {c}: health log unreadable {e}")
|
||||
say(f"holding {HOLD}s idle for the from-birth sampler")
|
||||
time.sleep(HOLD)
|
||||
for c in NAMES:
|
||||
r = subprocess.run(["docker", "inspect", "-f", "{{.State.Status}} {{.State.Health.Status}} rc={{.RestartCount}} OOMKilled(not-used)={{.State.OOMKilled}}", c], capture_output=True, text=True)
|
||||
say(f" end {c}: {r.stdout.strip()}")
|
||||
r = subprocess.run("docker logs metube 2>&1 | head -60", shell=True, capture_output=True, text=True)
|
||||
(ev / "metube-startlines.txt").write_text(r.stdout)
|
||||
say("metube first 60 log lines saved, %d lines" % len(r.stdout.splitlines()))
|
||||
r = subprocess.run("docker exec metube sh -c 'ls -la /state /downloads; id'", shell=True, capture_output=True, text=True)
|
||||
(ev / "metube-dirs.txt").write_text(r.stdout + r.stderr)
|
||||
@@ -0,0 +1,9 @@
|
||||
[06:11:35] images: {"metube": "ghcr.io/alexta69/metube:2026.09.29"}
|
||||
[06:11:35] swap on the bench: none
|
||||
[06:11:36] up -d rc=0 in 0.4s
|
||||
[06:12:07] settled=True in 31.2s after up -d (settle loop 30.8s) :: {"metube": {"status": "running", "health": "healthy", "restarts": 0, "exit": 0}}
|
||||
[06:12:07] metube: 2026-10-02T06:11:36.683758201Z healthy rc=0 mem=805306368
|
||||
[06:12:07] metube: first health probe 2026-10-02T06:12:06.691609369Z exit=0; probes so far 1
|
||||
[06:12:07] holding 300s idle for the from-birth sampler
|
||||
[06:17:07] end metube: running healthy rc=0 OOMKilled(not-used)=false
|
||||
[06:17:07] metube first 60 log lines saved, 7 lines
|
||||
@@ -0,0 +1,10 @@
|
||||
/downloads:
|
||||
total 8
|
||||
drwxr-xr-x 2 1000 1000 4096 Oct 2 08:11 .
|
||||
drwxr-xr-x 1 root root 4096 Oct 2 08:11 ..
|
||||
|
||||
/state:
|
||||
total 8
|
||||
drwxr-xr-x 2 1000 1000 4096 Oct 2 08:11 .
|
||||
drwxr-xr-x 1 root root 4096 Oct 2 08:11 ..
|
||||
uid=0(root) gid=0(root) groups=0(root)
|
||||
@@ -0,0 +1,7 @@
|
||||
Setting umask to 022
|
||||
Creating download directory (/downloads), audio download directory (/downloads), state directory (/state), and temp dir (/downloads)
|
||||
Changing ownership of download and state directories to 1000:1000
|
||||
Starting BgUtils POT Provider
|
||||
Running MeTube as user 1000:1000
|
||||
INFO:main:Listening on 0.0.0.0:8081
|
||||
INFO:ytdl:Initializing DownloadQueue
|
||||
@@ -0,0 +1,170 @@
|
||||
1790921497,metube,fd5f36bf31db,28708864,36356096,0,0,805306368,0
|
||||
1790921499,metube,fd5f36bf31db,61612032,69578752,0,0,805306368,0
|
||||
1790921501,metube,fd5f36bf31db,61612032,69578752,0,0,805306368,0
|
||||
1790921503,metube,fd5f36bf31db,61612032,69578752,0,0,805306368,0
|
||||
1790921505,metube,fd5f36bf31db,61612032,69578752,0,0,805306368,0
|
||||
1790921507,metube,fd5f36bf31db,61612032,69578752,0,0,805306368,0
|
||||
1790921509,metube,fd5f36bf31db,61612032,69550080,0,0,805306368,0
|
||||
1790921511,metube,fd5f36bf31db,61612032,69545984,0,0,805306368,0
|
||||
1790921513,metube,fd5f36bf31db,61612032,69545984,0,0,805306368,0
|
||||
1790921515,metube,fd5f36bf31db,61612032,69545984,0,0,805306368,0
|
||||
1790921517,metube,fd5f36bf31db,61612032,69545984,0,0,805306368,0
|
||||
1790921519,metube,fd5f36bf31db,61612032,69545984,0,0,805306368,0
|
||||
1790921521,metube,fd5f36bf31db,61612032,69545984,0,0,805306368,0
|
||||
1790921524,metube,fd5f36bf31db,61612032,69545984,0,0,805306368,0
|
||||
1790921526,metube,fd5f36bf31db,61612032,69545984,0,0,805306368,0
|
||||
1790921528,metube,fd5f36bf31db,61648896,69681152,0,0,805306368,0
|
||||
1790921530,metube,fd5f36bf31db,61648896,69681152,0,0,805306368,0
|
||||
1790921532,metube,fd5f36bf31db,61648896,69677056,0,0,805306368,0
|
||||
1790921534,metube,fd5f36bf31db,61648896,69951488,0,0,805306368,0
|
||||
1790921536,metube,fd5f36bf31db,61648896,69951488,0,0,805306368,0
|
||||
1790921538,metube,fd5f36bf31db,61648896,69951488,0,0,805306368,0
|
||||
1790921540,metube,fd5f36bf31db,61648896,69951488,0,0,805306368,0
|
||||
1790921542,metube,fd5f36bf31db,61648896,69951488,0,0,805306368,0
|
||||
1790921544,metube,fd5f36bf31db,61648896,69951488,0,0,805306368,0
|
||||
1790921546,metube,fd5f36bf31db,61648896,69951488,0,0,805306368,0
|
||||
1790921548,metube,fd5f36bf31db,61648896,69951488,0,0,805306368,0
|
||||
1790921550,metube,fd5f36bf31db,61648896,69951488,0,0,805306368,0
|
||||
1790921552,metube,fd5f36bf31db,61648896,69951488,0,0,805306368,0
|
||||
1790921554,metube,fd5f36bf31db,61648896,69951488,0,0,805306368,0
|
||||
1790921557,metube,fd5f36bf31db,61648896,70660096,0,0,805306368,0
|
||||
1790921559,metube,fd5f36bf31db,61648896,69951488,0,0,805306368,0
|
||||
1790921561,metube,fd5f36bf31db,61648896,69951488,0,0,805306368,0
|
||||
1790921563,metube,fd5f36bf31db,61648896,69951488,0,0,805306368,0
|
||||
1790921565,metube,fd5f36bf31db,61648896,69951488,0,0,805306368,0
|
||||
1790921567,metube,fd5f36bf31db,61648896,69951488,0,0,805306368,0
|
||||
1790921569,metube,fd5f36bf31db,61648896,69951488,0,0,805306368,0
|
||||
1790921571,metube,fd5f36bf31db,61648896,69951488,0,0,805306368,0
|
||||
1790921573,metube,fd5f36bf31db,61648896,69951488,0,0,805306368,0
|
||||
1790921575,metube,fd5f36bf31db,61648896,69951488,0,0,805306368,0
|
||||
1790921577,metube,fd5f36bf31db,61648896,69951488,0,0,805306368,0
|
||||
1790921579,metube,fd5f36bf31db,61648896,69951488,0,0,805306368,0
|
||||
1790921581,metube,fd5f36bf31db,61648896,69951488,0,0,805306368,0
|
||||
1790921583,metube,fd5f36bf31db,61648896,69951488,0,0,805306368,0
|
||||
1790921585,metube,fd5f36bf31db,61648896,69951488,0,0,805306368,0
|
||||
1790921587,metube,fd5f36bf31db,61652992,70221824,0,0,805306368,0
|
||||
1790921589,metube,fd5f36bf31db,61652992,69955584,0,0,805306368,0
|
||||
1790921592,metube,fd5f36bf31db,61652992,69955584,0,0,805306368,0
|
||||
1790921594,metube,fd5f36bf31db,61652992,69955584,0,0,805306368,0
|
||||
1790921596,metube,fd5f36bf31db,61652992,69955584,0,0,805306368,0
|
||||
1790921598,metube,fd5f36bf31db,61652992,69955584,0,0,805306368,0
|
||||
1790921600,metube,fd5f36bf31db,61652992,69955584,0,0,805306368,0
|
||||
1790921602,metube,fd5f36bf31db,61652992,69955584,0,0,805306368,0
|
||||
1790921604,metube,fd5f36bf31db,61652992,69955584,0,0,805306368,0
|
||||
1790921606,metube,fd5f36bf31db,61652992,69955584,0,0,805306368,0
|
||||
1790921608,metube,fd5f36bf31db,61652992,69955584,0,0,805306368,0
|
||||
1790921610,metube,fd5f36bf31db,61652992,69955584,0,0,805306368,0
|
||||
1790921612,metube,fd5f36bf31db,61652992,69955584,0,0,805306368,0
|
||||
1790921614,metube,fd5f36bf31db,61652992,69955584,0,0,805306368,0
|
||||
1790921616,metube,fd5f36bf31db,61652992,69955584,0,0,805306368,0
|
||||
1790921618,metube,fd5f36bf31db,61652992,69955584,0,0,805306368,0
|
||||
1790921620,metube,fd5f36bf31db,61652992,69955584,0,0,805306368,0
|
||||
1790921622,metube,fd5f36bf31db,61652992,69955584,0,0,805306368,0
|
||||
1790921625,metube,fd5f36bf31db,61652992,69955584,0,0,805306368,0
|
||||
1790921627,metube,fd5f36bf31db,61652992,69955584,0,0,805306368,0
|
||||
1790921629,metube,fd5f36bf31db,61652992,69955584,0,0,805306368,0
|
||||
1790921631,metube,fd5f36bf31db,61652992,69955584,0,0,805306368,0
|
||||
1790921633,metube,fd5f36bf31db,61652992,69955584,0,0,805306368,0
|
||||
1790921635,metube,fd5f36bf31db,61652992,69955584,0,0,805306368,0
|
||||
1790921637,metube,fd5f36bf31db,61652992,69955584,0,0,805306368,0
|
||||
1790921639,metube,fd5f36bf31db,61652992,69955584,0,0,805306368,0
|
||||
1790921641,metube,fd5f36bf31db,61652992,69955584,0,0,805306368,0
|
||||
1790921643,metube,fd5f36bf31db,61652992,69955584,0,0,805306368,0
|
||||
1790921645,metube,fd5f36bf31db,61652992,69955584,0,0,805306368,0
|
||||
1790921647,metube,fd5f36bf31db,61652992,69959680,0,0,805306368,0
|
||||
1790921649,metube,fd5f36bf31db,61652992,69955584,0,0,805306368,0
|
||||
1790921651,metube,fd5f36bf31db,61652992,69955584,0,0,805306368,0
|
||||
1790921653,metube,fd5f36bf31db,61652992,69955584,0,0,805306368,0
|
||||
1790921655,metube,fd5f36bf31db,61652992,69955584,0,0,805306368,0
|
||||
1790921657,metube,fd5f36bf31db,61652992,69955584,0,0,805306368,0
|
||||
1790921660,metube,fd5f36bf31db,61652992,69955584,0,0,805306368,0
|
||||
1790921662,metube,fd5f36bf31db,61652992,69955584,0,0,805306368,0
|
||||
1790921664,metube,fd5f36bf31db,61652992,69955584,0,0,805306368,0
|
||||
1790921666,metube,fd5f36bf31db,61652992,69955584,0,0,805306368,0
|
||||
1790921668,metube,fd5f36bf31db,61652992,69955584,0,0,805306368,0
|
||||
1790921670,metube,fd5f36bf31db,61652992,69955584,0,0,805306368,0
|
||||
1790921672,metube,fd5f36bf31db,61652992,69955584,0,0,805306368,0
|
||||
1790921674,metube,fd5f36bf31db,61652992,69955584,0,0,805306368,0
|
||||
1790921676,metube,fd5f36bf31db,61652992,69955584,0,0,805306368,0
|
||||
1790921678,metube,fd5f36bf31db,61652992,69959680,0,0,805306368,0
|
||||
1790921680,metube,fd5f36bf31db,61652992,69955584,0,0,805306368,0
|
||||
1790921682,metube,fd5f36bf31db,61652992,69955584,0,0,805306368,0
|
||||
1790921684,metube,fd5f36bf31db,61652992,69955584,0,0,805306368,0
|
||||
1790921686,metube,fd5f36bf31db,61652992,69955584,0,0,805306368,0
|
||||
1790921688,metube,fd5f36bf31db,61652992,69955584,0,0,805306368,0
|
||||
1790921690,metube,fd5f36bf31db,61652992,69955584,0,0,805306368,0
|
||||
1790921692,metube,fd5f36bf31db,61652992,69955584,0,0,805306368,0
|
||||
1790921695,metube,fd5f36bf31db,61652992,69955584,0,0,805306368,0
|
||||
1790921697,metube,fd5f36bf31db,61652992,69955584,0,0,805306368,0
|
||||
1790921699,metube,fd5f36bf31db,61652992,69955584,0,0,805306368,0
|
||||
1790921701,metube,fd5f36bf31db,61652992,69955584,0,0,805306368,0
|
||||
1790921703,metube,fd5f36bf31db,61652992,69955584,0,0,805306368,0
|
||||
1790921705,metube,fd5f36bf31db,61652992,69955584,0,0,805306368,0
|
||||
1790921707,metube,fd5f36bf31db,61652992,70434816,0,0,805306368,0
|
||||
1790921709,metube,fd5f36bf31db,61652992,69955584,0,0,805306368,0
|
||||
1790921711,metube,fd5f36bf31db,61652992,69955584,0,0,805306368,0
|
||||
1790921713,metube,fd5f36bf31db,61652992,69955584,0,0,805306368,0
|
||||
1790921715,metube,fd5f36bf31db,61652992,69955584,0,0,805306368,0
|
||||
1790921717,metube,fd5f36bf31db,61652992,69955584,0,0,805306368,0
|
||||
1790921719,metube,fd5f36bf31db,61652992,69955584,0,0,805306368,0
|
||||
1790921721,metube,fd5f36bf31db,61652992,69955584,0,0,805306368,0
|
||||
1790921723,metube,fd5f36bf31db,61652992,69955584,0,0,805306368,0
|
||||
1790921725,metube,fd5f36bf31db,61652992,69955584,0,0,805306368,0
|
||||
1790921728,metube,fd5f36bf31db,61652992,69955584,0,0,805306368,0
|
||||
1790921730,metube,fd5f36bf31db,61652992,69955584,0,0,805306368,0
|
||||
1790921732,metube,fd5f36bf31db,61652992,69955584,0,0,805306368,0
|
||||
1790921734,metube,fd5f36bf31db,61652992,69955584,0,0,805306368,0
|
||||
1790921736,metube,fd5f36bf31db,61652992,69955584,0,0,805306368,0
|
||||
1790921738,metube,fd5f36bf31db,61652992,69959680,0,0,805306368,0
|
||||
1790921740,metube,fd5f36bf31db,61652992,69955584,0,0,805306368,0
|
||||
1790921742,metube,fd5f36bf31db,61652992,69955584,0,0,805306368,0
|
||||
1790921744,metube,fd5f36bf31db,61652992,69955584,0,0,805306368,0
|
||||
1790921746,metube,fd5f36bf31db,61652992,69955584,0,0,805306368,0
|
||||
1790921748,metube,fd5f36bf31db,61652992,69955584,0,0,805306368,0
|
||||
1790921750,metube,fd5f36bf31db,61652992,69955584,0,0,805306368,0
|
||||
1790921752,metube,fd5f36bf31db,61652992,69955584,0,0,805306368,0
|
||||
1790921754,metube,fd5f36bf31db,61652992,69955584,0,0,805306368,0
|
||||
1790921756,metube,fd5f36bf31db,61652992,69955584,0,0,805306368,0
|
||||
1790921758,metube,fd5f36bf31db,61652992,69955584,0,0,805306368,0
|
||||
1790921760,metube,fd5f36bf31db,61652992,69955584,0,0,805306368,0
|
||||
1790921763,metube,fd5f36bf31db,61652992,69955584,0,0,805306368,0
|
||||
1790921765,metube,fd5f36bf31db,61652992,69955584,0,0,805306368,0
|
||||
1790921767,metube,fd5f36bf31db,61652992,69955584,0,0,805306368,0
|
||||
1790921769,metube,fd5f36bf31db,61652992,69955584,0,0,805306368,0
|
||||
1790921771,metube,fd5f36bf31db,61652992,69955584,0,0,805306368,0
|
||||
1790921773,metube,fd5f36bf31db,61652992,69955584,0,0,805306368,0
|
||||
1790921775,metube,fd5f36bf31db,61652992,69955584,0,0,805306368,0
|
||||
1790921777,metube,fd5f36bf31db,61652992,69955584,0,0,805306368,0
|
||||
1790921779,metube,fd5f36bf31db,61652992,69955584,0,0,805306368,0
|
||||
1790921781,metube,fd5f36bf31db,61652992,69955584,0,0,805306368,0
|
||||
1790921783,metube,fd5f36bf31db,61652992,69955584,0,0,805306368,0
|
||||
1790921785,metube,fd5f36bf31db,61652992,69955584,0,0,805306368,0
|
||||
1790921787,metube,fd5f36bf31db,61652992,69955584,0,0,805306368,0
|
||||
1790921789,metube,fd5f36bf31db,61652992,69955584,0,0,805306368,0
|
||||
1790921791,metube,fd5f36bf31db,61652992,69955584,0,0,805306368,0
|
||||
1790921793,metube,fd5f36bf31db,61652992,69955584,0,0,805306368,0
|
||||
1790921796,metube,fd5f36bf31db,61652992,69955584,0,0,805306368,0
|
||||
1790921798,metube,fd5f36bf31db,61652992,70107136,0,0,805306368,0
|
||||
1790921800,metube,fd5f36bf31db,61652992,69955584,0,0,805306368,0
|
||||
1790921802,metube,fd5f36bf31db,61652992,69955584,0,0,805306368,0
|
||||
1790921804,metube,fd5f36bf31db,61652992,69955584,0,0,805306368,0
|
||||
1790921806,metube,fd5f36bf31db,61652992,69955584,0,0,805306368,0
|
||||
1790921808,metube,fd5f36bf31db,61652992,69955584,0,0,805306368,0
|
||||
1790921810,metube,fd5f36bf31db,61652992,69955584,0,0,805306368,0
|
||||
1790921812,metube,fd5f36bf31db,61652992,69955584,0,0,805306368,0
|
||||
1790921814,metube,fd5f36bf31db,61652992,69955584,0,0,805306368,0
|
||||
1790921816,metube,fd5f36bf31db,61652992,69955584,0,0,805306368,0
|
||||
1790921818,metube,fd5f36bf31db,61652992,69955584,0,0,805306368,0
|
||||
1790921820,metube,fd5f36bf31db,61652992,69955584,0,0,805306368,0
|
||||
1790921822,metube,fd5f36bf31db,61652992,69955584,0,0,805306368,0
|
||||
1790921824,metube,fd5f36bf31db,61652992,69955584,0,0,805306368,0
|
||||
1790921826,metube,fd5f36bf31db,61652992,69955584,0,0,805306368,0
|
||||
1790921828,metube,fd5f36bf31db,61652992,69959680,0,0,805306368,0
|
||||
1790921831,metube,fd5f36bf31db,61652992,69959680,0,0,805306368,0
|
||||
1790921833,metube,fd5f36bf31db,61652992,69959680,0,0,805306368,0
|
||||
1790921835,metube,fd5f36bf31db,61652992,69959680,0,0,805306368,0
|
||||
1790921837,metube,fd5f36bf31db,61652992,69959680,0,0,805306368,0
|
||||
1790921839,metube,fd5f36bf31db,61652992,69959680,0,0,805306368,0
|
||||
1790921841,metube,fd5f36bf31db,61652992,69959680,0,0,805306368,0
|
||||
1790921843,metube,fd5f36bf31db,61652992,69959680,0,0,805306368,0
|
||||
1790921845,metube,fd5f36bf31db,61652992,69959680,0,0,805306368,0
|
||||
|
@@ -0,0 +1,2 @@
|
||||
5.1 from birth at the pin (ghcr.io/alexta69/metube:2026.09.29), bench 9401 swap 0, 2 s cgroup sampler started before up -d; idle 300 s after healthy; rows up to the end of the idle hold (06:17:07Z) — after it the sampler was stopped and one /add probe was sent, see birth.out
|
||||
metube fd5f36bf31db 06:11:37-06:17:06 n= 161 peak anon 58.8 MiB = 7.7 % of 768 MiB; peak current 67.4 MiB; oom_kill 0; restarts 0; swap.current ['0']
|
||||
@@ -0,0 +1,12 @@
|
||||
# sampler.sh (run INSIDE the bench or the box): sample the cgroup of each named container from its birth, every 2 s.
|
||||
# usage: NAMES="a b c" OUT=/root/mem.csv DUR=900 bash sampler.sh & — stops at DUR or when $OUT.stop exists
|
||||
: > $OUT; t0=$(date +%s)
|
||||
while [ $(( $(date +%s) - t0 )) -lt ${DUR:-900} ] && [ ! -f $OUT.stop ]; do
|
||||
for n in $NAMES; do
|
||||
id=$(docker ps -q --no-trunc --filter name=^$n$ | head -1); [ -z "$id" ] && continue
|
||||
cg=$(ls -d /sys/fs/cgroup/system.slice/docker-$id.scope 2>/dev/null || find /sys/fs/cgroup -maxdepth 4 -type d -name "*$id*" 2>/dev/null | head -1)
|
||||
[ -f "$cg/memory.stat" ] || continue
|
||||
echo "$(date +%s),$n,${id:0:12},$(awk '$1=="anon"{print $2}' $cg/memory.stat),$(cat $cg/memory.current),$(cat $cg/memory.swap.current 2>/dev/null || echo NA),$(awk '$1=="oom_kill"{print $2}' $cg/memory.events),$(cat $cg/memory.max),$(docker inspect -f '{{.RestartCount}}' $id)" >> $OUT
|
||||
done
|
||||
sleep 2
|
||||
done
|
||||
@@ -0,0 +1,114 @@
|
||||
[06:19:20] scratch drive folders cleared before FROM (R-656): ['/srv/felhom-gate/hdd/userdata/media/metube']
|
||||
[06:19:20] MV-metube: deploying metube at FROM {'metube': 'ghcr.io/alexta69/metube:2026.09.28'}
|
||||
[06:19:51] FROM settled=True in 30.8s :: {"metube": {"status": "running", "health": "healthy", "restarts": 0, "exit": 0}}
|
||||
[06:19:51] fixture: the BOX walk's own (MeTube), through upgrade_boxport
|
||||
[06:19:52] metube: POST /add http=200 {"status": "ok"}
|
||||
[06:19:55] metube: the download finished (991017 bytes)
|
||||
[06:19:55] metube: history has it=True; GET /download/<file> http=200
|
||||
[06:19:55] C1 (seed reads back BEFORE): True
|
||||
[06:19:56] MV-metube: swapping to TO {'metube': 'ghcr.io/alexta69/metube:2026.09.29'}
|
||||
[06:19:56] TO up -d rc=0
|
||||
[06:20:27] TO settled=True in 30.8s :: {"metube": {"status": "running", "health": "healthy", "restarts": 0, "exit": 0}}
|
||||
[06:20:27] migration lines observed: 0
|
||||
[06:20:28] metube: history has it=True; GET /download/<file> http=200
|
||||
[06:20:28] RESULT (seed reads back AFTER): True
|
||||
[06:20:28] memory watch: 600s, 4 callers on 1 path(s) at 172.18.0.2:8081
|
||||
[06:20:43] + 15s metube=208M/768M peak=255M kills=0 rs=0 reqs=262
|
||||
[06:20:58] + 30s metube=206M/768M peak=255M kills=0 rs=0 reqs=562
|
||||
[06:21:13] + 45s metube=206M/768M peak=255M kills=0 rs=0 reqs=858
|
||||
[06:21:28] + 60s metube=327M/768M peak=371M kills=0 rs=0 reqs=1147
|
||||
[06:21:44] + 76s metube=326M/768M peak=371M kills=0 rs=0 reqs=1446
|
||||
[06:21:59] + 91s metube=326M/768M peak=371M kills=0 rs=0 reqs=1743
|
||||
[06:22:14] + 106s metube=429M/768M peak=465M kills=0 rs=0 reqs=2030
|
||||
[06:22:29] + 121s metube=429M/768M peak=465M kills=0 rs=0 reqs=2330
|
||||
[06:22:44] + 136s metube=430M/768M peak=465M kills=0 rs=0 reqs=2630
|
||||
[06:22:59] + 151s metube=550M/768M peak=588M kills=0 rs=0 reqs=2914
|
||||
[06:23:14] + 166s metube=550M/768M peak=588M kills=0 rs=0 reqs=3214
|
||||
[06:23:30] + 182s metube=550M/768M peak=588M kills=0 rs=0 reqs=3514
|
||||
[06:23:45] + 197s metube=653M/768M peak=692M kills=0 rs=0 reqs=3802
|
||||
[06:24:00] + 212s metube=652M/768M peak=692M kills=0 rs=0 reqs=4098
|
||||
[06:24:15] + 227s metube=652M/768M peak=692M kills=0 rs=0 reqs=4398
|
||||
[06:24:30] + 242s metube=721M/768M peak=769M kills=0 rs=0 reqs=4683
|
||||
[06:24:45] + 257s metube=719M/768M peak=769M kills=0 rs=0 reqs=4982
|
||||
[06:25:00] + 272s metube=719M/768M peak=769M kills=0 rs=0 reqs=5282
|
||||
[06:25:15] + 287s metube=724M/768M peak=770M kills=0 rs=0 reqs=5570
|
||||
[06:25:31] + 302s metube=724M/768M peak=770M kills=0 rs=0 reqs=5870
|
||||
[06:25:46] + 318s metube=724M/768M peak=770M kills=0 rs=0 reqs=6167
|
||||
[06:26:01] + 333s metube=730M/768M peak=770M kills=0 rs=0 reqs=6454
|
||||
[06:26:16] + 348s metube=731M/768M peak=770M kills=0 rs=0 reqs=6754
|
||||
[06:26:31] + 363s metube=730M/768M peak=770M kills=0 rs=0 reqs=7054
|
||||
[06:26:46] + 378s metube=705M/768M peak=771M kills=0 rs=0 reqs=7342
|
||||
[06:27:01] + 393s metube=704M/768M peak=771M kills=0 rs=0 reqs=7638
|
||||
[06:27:16] + 408s metube=705M/768M peak=771M kills=0 rs=0 reqs=7938
|
||||
[06:27:31] + 424s metube=730M/768M peak=771M kills=0 rs=0 reqs=8226
|
||||
[06:27:47] + 439s metube=729M/768M peak=771M kills=0 rs=0 reqs=8522
|
||||
[06:28:02] + 454s metube=729M/768M peak=771M kills=0 rs=0 reqs=8822
|
||||
[06:28:17] + 469s metube=714M/768M peak=771M kills=0 rs=0 reqs=9111
|
||||
[06:28:32] + 484s metube=714M/768M peak=771M kills=0 rs=0 reqs=9411
|
||||
[06:28:47] + 499s metube=715M/768M peak=771M kills=0 rs=0 reqs=9707
|
||||
[06:29:02] + 514s metube=718M/768M peak=771M kills=0 rs=0 reqs=9996
|
||||
[06:29:17] + 529s metube=718M/768M peak=771M kills=0 rs=0 reqs=10294
|
||||
[06:29:32] + 544s metube=718M/768M peak=771M kills=0 rs=0 reqs=10593
|
||||
[06:29:48] + 560s metube=718M/768M peak=771M kills=0 rs=0 reqs=10892
|
||||
[06:30:03] + 575s metube=717M/768M peak=771M kills=0 rs=0 reqs=11190
|
||||
[06:30:18] + 590s metube=693M/768M peak=771M kills=0 rs=0 reqs=11490
|
||||
[06:30:33] + 605s metube=693M/768M peak=771M kills=0 rs=0 reqs=11790
|
||||
[06:30:33] memory watch: killed=False tight=[] requests=11790 codes={'200': 11790}
|
||||
[06:30:33] MV-metube: ABORT — putting the FROM images back
|
||||
[06:31:05] metube: history has it=True; GET /download/<file> http=200
|
||||
[06:31:05] ABORT: app came back in 30.8s; data present=True
|
||||
{
|
||||
"harness_version": 4,
|
||||
"edge": "MV-metube",
|
||||
"app": "metube",
|
||||
"note": "night 2026-09-23 within-a-major move: metube=ghcr.io/alexta69/metube:2026.09.29",
|
||||
"from": {
|
||||
"metube": "ghcr.io/alexta69/metube:2026.09.28"
|
||||
},
|
||||
"to": {
|
||||
"metube": "ghcr.io/alexta69/metube:2026.09.29"
|
||||
},
|
||||
"verdict": "proven",
|
||||
"seed_read_before": true,
|
||||
"seed_read_after": true,
|
||||
"healthy_after": true,
|
||||
"migration_observed": null,
|
||||
"abort": "starts-and-serves",
|
||||
"abort_detail": null,
|
||||
"engine_state_after": null,
|
||||
"memory": {
|
||||
"soak_s": 605.3,
|
||||
"requested_s": 600,
|
||||
"requests": 11790,
|
||||
"codes": {
|
||||
"200": 11790
|
||||
},
|
||||
"first_kill": null,
|
||||
"containers": {
|
||||
"metube": {
|
||||
"limit": 805306368,
|
||||
"peak": 809365504,
|
||||
"peak_pct": 1.005,
|
||||
"anon_peak_sampled": 226152448,
|
||||
"anon_peak_pct": 0.281,
|
||||
"oom_kills": 0,
|
||||
"restarts": 0,
|
||||
"oomkilled_flag": false,
|
||||
"measured": true
|
||||
}
|
||||
},
|
||||
"unmeasured": [],
|
||||
"load": "reached"
|
||||
},
|
||||
"marks": [],
|
||||
"bench_overrides": null,
|
||||
"duration_s": 30.8,
|
||||
"measured_at": "2026-10-02T06:31:05Z",
|
||||
"evidence": "evidence/MV-metube",
|
||||
"scratch_cleared": [
|
||||
"/srv/felhom-gate/hdd/userdata/media/metube"
|
||||
],
|
||||
"files_changed": [],
|
||||
"files_changed_detail": [],
|
||||
"total_s": 705.3
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"metube": {
|
||||
"status": "running",
|
||||
"health": "healthy",
|
||||
"restarts": 0,
|
||||
"exit": 0
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
burst start 06:20:30Z base http://172.18.0.2:8081
|
||||
+ 3s round 1 posted 8 at once; adds {"200": 8}; history (200, {'queue': 8, 'pending': 0, 'done_finished': 1})
|
||||
+ 18s history (200, {'queue': 0, 'pending': 0, 'done_finished': 9})
|
||||
+ 33s history (200, {'queue': 0, 'pending': 0, 'done_finished': 9})
|
||||
+ 48s history (200, {'queue': 0, 'pending': 0, 'done_finished': 9})
|
||||
+ 49s round 2 posted 8 at once; adds {"200": 16}; history (200, {'queue': 8, 'pending': 0, 'done_finished': 9})
|
||||
+ 64s history (200, {'queue': 0, 'pending': 0, 'done_finished': 9})
|
||||
+ 79s history (200, {'queue': 0, 'pending': 0, 'done_finished': 9})
|
||||
+ 94s history (200, {'queue': 0, 'pending': 0, 'done_finished': 9})
|
||||
+ 95s round 3 posted 8 at once; adds {"200": 24}; history (200, {'queue': 8, 'pending': 0, 'done_finished': 9})
|
||||
+ 110s history (200, {'queue': 0, 'pending': 0, 'done_finished': 9})
|
||||
+ 125s history (200, {'queue': 0, 'pending': 0, 'done_finished': 9})
|
||||
+ 140s history (200, {'queue': 0, 'pending': 0, 'done_finished': 9})
|
||||
+ 141s round 4 posted 8 at once; adds {"200": 32}; history (200, {'queue': 8, 'pending': 0, 'done_finished': 9})
|
||||
+ 156s history (200, {'queue': 0, 'pending': 0, 'done_finished': 9})
|
||||
+ 171s history (200, {'queue': 0, 'pending': 0, 'done_finished': 9})
|
||||
+ 186s history (200, {'queue': 0, 'pending': 0, 'done_finished': 9})
|
||||
+ 187s round 5 posted 8 at once; adds {"200": 40}; history (200, {'queue': 8, 'pending': 0, 'done_finished': 9})
|
||||
+ 202s history (200, {'queue': 0, 'pending': 0, 'done_finished': 9})
|
||||
+ 217s history (200, {'queue': 0, 'pending': 0, 'done_finished': 9})
|
||||
+ 232s history (200, {'queue': 0, 'pending': 0, 'done_finished': 9})
|
||||
+ 232s round 6 posted 8 at once; adds {"200": 48}; history (200, {'queue': 8, 'pending': 0, 'done_finished': 9})
|
||||
+ 247s history (200, {'queue': 0, 'pending': 0, 'done_finished': 9})
|
||||
+ 262s history (200, {'queue': 0, 'pending': 0, 'done_finished': 9})
|
||||
+ 277s history (200, {'queue': 0, 'pending': 0, 'done_finished': 9})
|
||||
+ 278s round 7 posted 8 at once; adds {"200": 56}; history (200, {'queue': 8, 'pending': 0, 'done_finished': 9})
|
||||
+ 293s history (200, {'queue': 0, 'pending': 0, 'done_finished': 9})
|
||||
+ 308s history (200, {'queue': 0, 'pending': 0, 'done_finished': 9})
|
||||
+ 323s history (200, {'queue': 0, 'pending': 0, 'done_finished': 9})
|
||||
+ 324s round 8 posted 8 at once; adds {"200": 64}; history (200, {'queue': 8, 'pending': 0, 'done_finished': 9})
|
||||
+ 339s history (200, {'queue': 0, 'pending': 0, 'done_finished': 9})
|
||||
+ 354s history (200, {'queue': 0, 'pending': 0, 'done_finished': 9})
|
||||
+ 369s history (200, {'queue': 0, 'pending': 0, 'done_finished': 9})
|
||||
+ 370s round 9 posted 8 at once; adds {"200": 72}; history (200, {'queue': 8, 'pending': 0, 'done_finished': 9})
|
||||
+ 385s history (200, {'queue': 0, 'pending': 0, 'done_finished': 9})
|
||||
+ 400s history (200, {'queue': 0, 'pending': 0, 'done_finished': 9})
|
||||
+ 415s history (200, {'queue': 0, 'pending': 0, 'done_finished': 9})
|
||||
+ 416s round 10 posted 8 at once; adds {"200": 80}; history (200, {'queue': 8, 'pending': 0, 'done_finished': 9})
|
||||
+ 431s history (200, {'queue': 0, 'pending': 0, 'done_finished': 9})
|
||||
+ 446s history (200, {'queue': 0, 'pending': 0, 'done_finished': 9})
|
||||
+ 461s history (200, {'queue': 0, 'pending': 0, 'done_finished': 9})
|
||||
+ 462s round 11 posted 8 at once; adds {"200": 88}; history (200, {'queue': 8, 'pending': 0, 'done_finished': 9})
|
||||
+ 477s history (200, {'queue': 0, 'pending': 0, 'done_finished': 9})
|
||||
+ 492s history (200, {'queue': 0, 'pending': 0, 'done_finished': 9})
|
||||
+ 507s history (200, {'queue': 0, 'pending': 0, 'done_finished': 9})
|
||||
+ 508s round 12 posted 8 at once; adds {"200": 96}; history (200, {'queue': 8, 'pending': 0, 'done_finished': 9})
|
||||
+ 523s history (200, {'queue': 0, 'pending': 0, 'done_finished': 9})
|
||||
+ 538s history (200, {'queue': 0, 'pending': 0, 'done_finished': 9})
|
||||
+ 553s history (200, {'queue': 0, 'pending': 0, 'done_finished': 9})
|
||||
FINAL rounds 12 adds {"200": 96} history (200, {'queue': 0, 'pending': 0, 'done_finished': 9})
|
||||
downloads dir: files / size: ['97', '563M', '/downloads']
|
||||
@@ -0,0 +1,56 @@
|
||||
"""burst.py — checklist 5.2's "heaviest ordinary act" for MeTube on the bench: a household pasting several links at once.
|
||||
Each ROUND posts 8 DISTINCT public test videos (test-videos.co.uk, 1-10 MB, h264, 360/720/1080p) to POST /add at the
|
||||
same moment (8 threads), with a per-round custom_name_prefix so a re-added URL becomes a new item; MAX_CONCURRENT_DOWNLOADS=2
|
||||
queues the rest. Rounds every GAP s for DUR s. The fixture's own URL (BBB 360 1 MB) is deliberately NOT in the burst, so the
|
||||
seed's history entry is never replaced. Talks to the container's own port 8081, the path traefik uses. Audio-only is not
|
||||
used: the test clips have no audio stream (measured). Prints counts and codes only."""
|
||||
import json, os, subprocess, threading, time, urllib.request, urllib.error
|
||||
DUR = int(os.environ.get("DUR", "540")); GAP = int(os.environ.get("GAP", "45"))
|
||||
B = "https://test-videos.co.uk/vids/"
|
||||
URLS = [B + p for p in ("bigbuckbunny/mp4/h264/720/Big_Buck_Bunny_720_10s_5MB.mp4", "bigbuckbunny/mp4/h264/1080/Big_Buck_Bunny_1080_10s_10MB.mp4",
|
||||
"jellyfish/mp4/h264/360/Jellyfish_360_10s_1MB.mp4", "jellyfish/mp4/h264/720/Jellyfish_720_10s_5MB.mp4",
|
||||
"jellyfish/mp4/h264/1080/Jellyfish_1080_10s_10MB.mp4", "sintel/mp4/h264/360/Sintel_360_10s_1MB.mp4",
|
||||
"sintel/mp4/h264/720/Sintel_720_10s_5MB.mp4", "sintel/mp4/h264/1080/Sintel_1080_10s_10MB.mp4")]
|
||||
ip = subprocess.run(["docker", "inspect", "-f", "{{range .NetworkSettings.Networks}}{{.IPAddress}} {{end}}", "metube"],
|
||||
capture_output=True, text=True).stdout.split()[0]
|
||||
BASE = f"http://{ip}:8081"
|
||||
def req(method, path, body=None):
|
||||
r = urllib.request.Request(BASE + path, data=json.dumps(body).encode() if body is not None else None,
|
||||
headers={"Content-Type": "application/json"}, method=method)
|
||||
try:
|
||||
with urllib.request.urlopen(r, timeout=60) as resp:
|
||||
d = resp.read(); return resp.status, json.loads(d) if d[:1] in (b"{", b"[") else d
|
||||
except urllib.error.HTTPError as e:
|
||||
return e.code, e.read()[:200]
|
||||
except Exception as e:
|
||||
return "err", str(e)[:200]
|
||||
stats = {"add": {}}; lock = threading.Lock()
|
||||
def add(url, prefix):
|
||||
c, b = req("POST", "/add", {"url": url, "download_type": "video", "format": "any", "quality": "best", "auto_start": True, "custom_name_prefix": prefix})
|
||||
with lock:
|
||||
stats["add"][str(c)] = stats["add"].get(str(c), 0) + 1
|
||||
if c != 200 or (isinstance(b, dict) and b.get("status") != "ok"): print("add", prefix, url.rsplit("/", 1)[1], c, b, flush=True)
|
||||
def hist():
|
||||
c, h = req("GET", "/history")
|
||||
if not isinstance(h, dict): return c, {}
|
||||
out = {"queue": len(h.get("queue", [])), "pending": len(h.get("pending", []))}
|
||||
for d in h.get("done", []):
|
||||
out["done_" + str(d.get("status"))] = out.get("done_" + str(d.get("status")), 0) + 1
|
||||
return c, out
|
||||
t0 = time.time(); n = 0
|
||||
print("burst start", time.strftime("%H:%M:%SZ", time.gmtime()), "base", BASE, flush=True)
|
||||
while time.time() - t0 < DUR:
|
||||
n += 1
|
||||
ts = [threading.Thread(target=add, args=(u, f"r{n:02d}")) for u in URLS]
|
||||
[t.start() for t in ts]; [t.join() for t in ts]
|
||||
print(f"+{time.time()-t0:4.0f}s round {n} posted 8 at once; adds {json.dumps(stats['add'])}; history {hist()}", flush=True)
|
||||
end = time.time() + GAP
|
||||
while time.time() < end:
|
||||
time.sleep(15); print(f"+{time.time()-t0:4.0f}s history {hist()}", flush=True)
|
||||
for _ in range(40):
|
||||
c, h = hist()
|
||||
if h.get("queue", 0) == 0 and h.get("pending", 0) == 0: break
|
||||
time.sleep(5)
|
||||
print("FINAL rounds", n, "adds", json.dumps(stats["add"]), "history", hist(), flush=True)
|
||||
r = subprocess.run("docker exec metube sh -c 'ls /downloads | wc -l; du -sh /downloads'", shell=True, capture_output=True, text=True)
|
||||
print("downloads dir: files / size:", r.stdout.split(), flush=True)
|
||||
@@ -0,0 +1,8 @@
|
||||
[2Kmetube | Setting umask to 022
|
||||
[2Kmetube | Creating download directory (/downloads), audio download directory (/downloads), state directory (/state), and temp dir (/downloads)
|
||||
[2Kmetube | Changing ownership of download and state directories to 1000:1000
|
||||
[2Kmetube | Starting BgUtils POT Provider
|
||||
[2Kmetube | Running MeTube as user 1000:1000
|
||||
[2Kmetube | INFO:main:Listening on 0.0.0.0:8081
|
||||
[2Kmetube | INFO:ytdl:Initializing DownloadQueue
|
||||
[2Kmetube | INFO:main:Sending download history
|
||||
@@ -0,0 +1 @@
|
||||
null
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"/srv/felhom-gate/hdd/userdata/media/metube": {
|
||||
"Big_Buck_Bunny_360_10s_1MB.mp4": "991017:77145c94c11f3754"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"/srv/felhom-gate/hdd/userdata/media/metube": "d6e2574a091ef241a5adb382ad873254577e2799e55f7c4d7d45e626895af3f3"
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"/srv/felhom-gate/hdd/userdata/media/metube": {
|
||||
"Big_Buck_Bunny_360_10s_1MB.mp4": "991017:77145c94c11f3754"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"/srv/felhom-gate/hdd/userdata/media/metube": "d6e2574a091ef241a5adb382ad873254577e2799e55f7c4d7d45e626895af3f3"
|
||||
}
|
||||
@@ -0,0 +1,682 @@
|
||||
[
|
||||
{
|
||||
"t": 15.1,
|
||||
"containers": {
|
||||
"metube": {
|
||||
"limit": 805306368,
|
||||
"current": 218394624,
|
||||
"peak": 267948032,
|
||||
"anon": 108826624,
|
||||
"oom_kill": 0,
|
||||
"restarts": 0,
|
||||
"oomkilled_flag": false,
|
||||
"status": "running",
|
||||
"cgroup": true
|
||||
}
|
||||
},
|
||||
"requests": 262
|
||||
},
|
||||
{
|
||||
"t": 30.2,
|
||||
"containers": {
|
||||
"metube": {
|
||||
"limit": 805306368,
|
||||
"current": 216952832,
|
||||
"peak": 267948032,
|
||||
"anon": 108990464,
|
||||
"oom_kill": 0,
|
||||
"restarts": 0,
|
||||
"oomkilled_flag": false,
|
||||
"status": "running",
|
||||
"cgroup": true
|
||||
}
|
||||
},
|
||||
"requests": 562
|
||||
},
|
||||
{
|
||||
"t": 45.4,
|
||||
"containers": {
|
||||
"metube": {
|
||||
"limit": 805306368,
|
||||
"current": 216985600,
|
||||
"peak": 267948032,
|
||||
"anon": 109019136,
|
||||
"oom_kill": 0,
|
||||
"restarts": 0,
|
||||
"oomkilled_flag": false,
|
||||
"status": "running",
|
||||
"cgroup": true
|
||||
}
|
||||
},
|
||||
"requests": 858
|
||||
},
|
||||
{
|
||||
"t": 60.5,
|
||||
"containers": {
|
||||
"metube": {
|
||||
"limit": 805306368,
|
||||
"current": 342884352,
|
||||
"peak": 389664768,
|
||||
"anon": 134897664,
|
||||
"oom_kill": 0,
|
||||
"restarts": 0,
|
||||
"oomkilled_flag": false,
|
||||
"status": "running",
|
||||
"cgroup": true
|
||||
}
|
||||
},
|
||||
"requests": 1147
|
||||
},
|
||||
{
|
||||
"t": 75.6,
|
||||
"containers": {
|
||||
"metube": {
|
||||
"limit": 805306368,
|
||||
"current": 342441984,
|
||||
"peak": 389664768,
|
||||
"anon": 134897664,
|
||||
"oom_kill": 0,
|
||||
"restarts": 0,
|
||||
"oomkilled_flag": false,
|
||||
"status": "running",
|
||||
"cgroup": true
|
||||
}
|
||||
},
|
||||
"requests": 1446
|
||||
},
|
||||
{
|
||||
"t": 90.7,
|
||||
"containers": {
|
||||
"metube": {
|
||||
"limit": 805306368,
|
||||
"current": 342208512,
|
||||
"peak": 389664768,
|
||||
"anon": 134905856,
|
||||
"oom_kill": 0,
|
||||
"restarts": 0,
|
||||
"oomkilled_flag": false,
|
||||
"status": "running",
|
||||
"cgroup": true
|
||||
}
|
||||
},
|
||||
"requests": 1743
|
||||
},
|
||||
{
|
||||
"t": 105.9,
|
||||
"containers": {
|
||||
"metube": {
|
||||
"limit": 805306368,
|
||||
"current": 450744320,
|
||||
"peak": 488628224,
|
||||
"anon": 142479360,
|
||||
"oom_kill": 0,
|
||||
"restarts": 0,
|
||||
"oomkilled_flag": false,
|
||||
"status": "running",
|
||||
"cgroup": true
|
||||
}
|
||||
},
|
||||
"requests": 2030
|
||||
},
|
||||
{
|
||||
"t": 121.0,
|
||||
"containers": {
|
||||
"metube": {
|
||||
"limit": 805306368,
|
||||
"current": 450269184,
|
||||
"peak": 488628224,
|
||||
"anon": 142479360,
|
||||
"oom_kill": 0,
|
||||
"restarts": 0,
|
||||
"oomkilled_flag": false,
|
||||
"status": "running",
|
||||
"cgroup": true
|
||||
}
|
||||
},
|
||||
"requests": 2330
|
||||
},
|
||||
{
|
||||
"t": 136.1,
|
||||
"containers": {
|
||||
"metube": {
|
||||
"limit": 805306368,
|
||||
"current": 450957312,
|
||||
"peak": 488628224,
|
||||
"anon": 142479360,
|
||||
"oom_kill": 0,
|
||||
"restarts": 0,
|
||||
"oomkilled_flag": false,
|
||||
"status": "running",
|
||||
"cgroup": true
|
||||
}
|
||||
},
|
||||
"requests": 2630
|
||||
},
|
||||
{
|
||||
"t": 151.3,
|
||||
"containers": {
|
||||
"metube": {
|
||||
"limit": 805306368,
|
||||
"current": 577544192,
|
||||
"peak": 617148416,
|
||||
"anon": 168550400,
|
||||
"oom_kill": 0,
|
||||
"restarts": 0,
|
||||
"oomkilled_flag": false,
|
||||
"status": "running",
|
||||
"cgroup": true
|
||||
}
|
||||
},
|
||||
"requests": 2914
|
||||
},
|
||||
{
|
||||
"t": 166.4,
|
||||
"containers": {
|
||||
"metube": {
|
||||
"limit": 805306368,
|
||||
"current": 577257472,
|
||||
"peak": 617148416,
|
||||
"anon": 168550400,
|
||||
"oom_kill": 0,
|
||||
"restarts": 0,
|
||||
"oomkilled_flag": false,
|
||||
"status": "running",
|
||||
"cgroup": true
|
||||
}
|
||||
},
|
||||
"requests": 3214
|
||||
},
|
||||
{
|
||||
"t": 181.5,
|
||||
"containers": {
|
||||
"metube": {
|
||||
"limit": 805306368,
|
||||
"current": 576757760,
|
||||
"peak": 617148416,
|
||||
"anon": 168550400,
|
||||
"oom_kill": 0,
|
||||
"restarts": 0,
|
||||
"oomkilled_flag": false,
|
||||
"status": "running",
|
||||
"cgroup": true
|
||||
}
|
||||
},
|
||||
"requests": 3514
|
||||
},
|
||||
{
|
||||
"t": 196.7,
|
||||
"containers": {
|
||||
"metube": {
|
||||
"limit": 805306368,
|
||||
"current": 685064192,
|
||||
"peak": 726466560,
|
||||
"anon": 175656960,
|
||||
"oom_kill": 0,
|
||||
"restarts": 0,
|
||||
"oomkilled_flag": false,
|
||||
"status": "running",
|
||||
"cgroup": true
|
||||
}
|
||||
},
|
||||
"requests": 3802
|
||||
},
|
||||
{
|
||||
"t": 211.8,
|
||||
"containers": {
|
||||
"metube": {
|
||||
"limit": 805306368,
|
||||
"current": 684240896,
|
||||
"peak": 726466560,
|
||||
"anon": 175656960,
|
||||
"oom_kill": 0,
|
||||
"restarts": 0,
|
||||
"oomkilled_flag": false,
|
||||
"status": "running",
|
||||
"cgroup": true
|
||||
}
|
||||
},
|
||||
"requests": 4098
|
||||
},
|
||||
{
|
||||
"t": 226.9,
|
||||
"containers": {
|
||||
"metube": {
|
||||
"limit": 805306368,
|
||||
"current": 683790336,
|
||||
"peak": 726466560,
|
||||
"anon": 175656960,
|
||||
"oom_kill": 0,
|
||||
"restarts": 0,
|
||||
"oomkilled_flag": false,
|
||||
"status": "running",
|
||||
"cgroup": true
|
||||
}
|
||||
},
|
||||
"requests": 4398
|
||||
},
|
||||
{
|
||||
"t": 242.0,
|
||||
"containers": {
|
||||
"metube": {
|
||||
"limit": 805306368,
|
||||
"current": 756105216,
|
||||
"peak": 806682624,
|
||||
"anon": 182927360,
|
||||
"oom_kill": 0,
|
||||
"restarts": 0,
|
||||
"oomkilled_flag": false,
|
||||
"status": "running",
|
||||
"cgroup": true
|
||||
}
|
||||
},
|
||||
"requests": 4683
|
||||
},
|
||||
{
|
||||
"t": 257.1,
|
||||
"containers": {
|
||||
"metube": {
|
||||
"limit": 805306368,
|
||||
"current": 754176000,
|
||||
"peak": 806682624,
|
||||
"anon": 182927360,
|
||||
"oom_kill": 0,
|
||||
"restarts": 0,
|
||||
"oomkilled_flag": false,
|
||||
"status": "running",
|
||||
"cgroup": true
|
||||
}
|
||||
},
|
||||
"requests": 4982
|
||||
},
|
||||
{
|
||||
"t": 272.3,
|
||||
"containers": {
|
||||
"metube": {
|
||||
"limit": 805306368,
|
||||
"current": 754192384,
|
||||
"peak": 806682624,
|
||||
"anon": 182927360,
|
||||
"oom_kill": 0,
|
||||
"restarts": 0,
|
||||
"oomkilled_flag": false,
|
||||
"status": "running",
|
||||
"cgroup": true
|
||||
}
|
||||
},
|
||||
"requests": 5282
|
||||
},
|
||||
{
|
||||
"t": 287.4,
|
||||
"containers": {
|
||||
"metube": {
|
||||
"limit": 805306368,
|
||||
"current": 759549952,
|
||||
"peak": 807489536,
|
||||
"anon": 190197760,
|
||||
"oom_kill": 0,
|
||||
"restarts": 0,
|
||||
"oomkilled_flag": false,
|
||||
"status": "running",
|
||||
"cgroup": true
|
||||
}
|
||||
},
|
||||
"requests": 5570
|
||||
},
|
||||
{
|
||||
"t": 302.5,
|
||||
"containers": {
|
||||
"metube": {
|
||||
"limit": 805306368,
|
||||
"current": 759554048,
|
||||
"peak": 807489536,
|
||||
"anon": 190197760,
|
||||
"oom_kill": 0,
|
||||
"restarts": 0,
|
||||
"oomkilled_flag": false,
|
||||
"status": "running",
|
||||
"cgroup": true
|
||||
}
|
||||
},
|
||||
"requests": 5870
|
||||
},
|
||||
{
|
||||
"t": 317.6,
|
||||
"containers": {
|
||||
"metube": {
|
||||
"limit": 805306368,
|
||||
"current": 759844864,
|
||||
"peak": 807489536,
|
||||
"anon": 190197760,
|
||||
"oom_kill": 0,
|
||||
"restarts": 0,
|
||||
"oomkilled_flag": false,
|
||||
"status": "running",
|
||||
"cgroup": true
|
||||
}
|
||||
},
|
||||
"requests": 6167
|
||||
},
|
||||
{
|
||||
"t": 332.7,
|
||||
"containers": {
|
||||
"metube": {
|
||||
"limit": 805306368,
|
||||
"current": 766046208,
|
||||
"peak": 807489536,
|
||||
"anon": 197423104,
|
||||
"oom_kill": 0,
|
||||
"restarts": 0,
|
||||
"oomkilled_flag": false,
|
||||
"status": "running",
|
||||
"cgroup": true
|
||||
}
|
||||
},
|
||||
"requests": 6454
|
||||
},
|
||||
{
|
||||
"t": 347.9,
|
||||
"containers": {
|
||||
"metube": {
|
||||
"limit": 805306368,
|
||||
"current": 766574592,
|
||||
"peak": 807489536,
|
||||
"anon": 197423104,
|
||||
"oom_kill": 0,
|
||||
"restarts": 0,
|
||||
"oomkilled_flag": false,
|
||||
"status": "running",
|
||||
"cgroup": true
|
||||
}
|
||||
},
|
||||
"requests": 6754
|
||||
},
|
||||
{
|
||||
"t": 363.0,
|
||||
"containers": {
|
||||
"metube": {
|
||||
"limit": 805306368,
|
||||
"current": 766267392,
|
||||
"peak": 807489536,
|
||||
"anon": 197423104,
|
||||
"oom_kill": 0,
|
||||
"restarts": 0,
|
||||
"oomkilled_flag": false,
|
||||
"status": "running",
|
||||
"cgroup": true
|
||||
}
|
||||
},
|
||||
"requests": 7054
|
||||
},
|
||||
{
|
||||
"t": 378.1,
|
||||
"containers": {
|
||||
"metube": {
|
||||
"limit": 805306368,
|
||||
"current": 739332096,
|
||||
"peak": 809365504,
|
||||
"anon": 204529664,
|
||||
"oom_kill": 0,
|
||||
"restarts": 0,
|
||||
"oomkilled_flag": false,
|
||||
"status": "running",
|
||||
"cgroup": true
|
||||
}
|
||||
},
|
||||
"requests": 7342
|
||||
},
|
||||
{
|
||||
"t": 393.2,
|
||||
"containers": {
|
||||
"metube": {
|
||||
"limit": 805306368,
|
||||
"current": 738820096,
|
||||
"peak": 809365504,
|
||||
"anon": 204529664,
|
||||
"oom_kill": 0,
|
||||
"restarts": 0,
|
||||
"oomkilled_flag": false,
|
||||
"status": "running",
|
||||
"cgroup": true
|
||||
}
|
||||
},
|
||||
"requests": 7638
|
||||
},
|
||||
{
|
||||
"t": 408.4,
|
||||
"containers": {
|
||||
"metube": {
|
||||
"limit": 805306368,
|
||||
"current": 739340288,
|
||||
"peak": 809365504,
|
||||
"anon": 204533760,
|
||||
"oom_kill": 0,
|
||||
"restarts": 0,
|
||||
"oomkilled_flag": false,
|
||||
"status": "running",
|
||||
"cgroup": true
|
||||
}
|
||||
},
|
||||
"requests": 7938
|
||||
},
|
||||
{
|
||||
"t": 423.5,
|
||||
"containers": {
|
||||
"metube": {
|
||||
"limit": 805306368,
|
||||
"current": 765554688,
|
||||
"peak": 809365504,
|
||||
"anon": 211742720,
|
||||
"oom_kill": 0,
|
||||
"restarts": 0,
|
||||
"oomkilled_flag": false,
|
||||
"status": "running",
|
||||
"cgroup": true
|
||||
}
|
||||
},
|
||||
"requests": 8226
|
||||
},
|
||||
{
|
||||
"t": 438.6,
|
||||
"containers": {
|
||||
"metube": {
|
||||
"limit": 805306368,
|
||||
"current": 765317120,
|
||||
"peak": 809365504,
|
||||
"anon": 211742720,
|
||||
"oom_kill": 0,
|
||||
"restarts": 0,
|
||||
"oomkilled_flag": false,
|
||||
"status": "running",
|
||||
"cgroup": true
|
||||
}
|
||||
},
|
||||
"requests": 8522
|
||||
},
|
||||
{
|
||||
"t": 453.7,
|
||||
"containers": {
|
||||
"metube": {
|
||||
"limit": 805306368,
|
||||
"current": 764755968,
|
||||
"peak": 809365504,
|
||||
"anon": 211742720,
|
||||
"oom_kill": 0,
|
||||
"restarts": 0,
|
||||
"oomkilled_flag": false,
|
||||
"status": "running",
|
||||
"cgroup": true
|
||||
}
|
||||
},
|
||||
"requests": 8822
|
||||
},
|
||||
{
|
||||
"t": 468.9,
|
||||
"containers": {
|
||||
"metube": {
|
||||
"limit": 805306368,
|
||||
"current": 749535232,
|
||||
"peak": 809365504,
|
||||
"anon": 218935296,
|
||||
"oom_kill": 0,
|
||||
"restarts": 0,
|
||||
"oomkilled_flag": false,
|
||||
"status": "running",
|
||||
"cgroup": true
|
||||
}
|
||||
},
|
||||
"requests": 9111
|
||||
},
|
||||
{
|
||||
"t": 484.0,
|
||||
"containers": {
|
||||
"metube": {
|
||||
"limit": 805306368,
|
||||
"current": 749416448,
|
||||
"peak": 809365504,
|
||||
"anon": 218935296,
|
||||
"oom_kill": 0,
|
||||
"restarts": 0,
|
||||
"oomkilled_flag": false,
|
||||
"status": "running",
|
||||
"cgroup": true
|
||||
}
|
||||
},
|
||||
"requests": 9411
|
||||
},
|
||||
{
|
||||
"t": 499.1,
|
||||
"containers": {
|
||||
"metube": {
|
||||
"limit": 805306368,
|
||||
"current": 750125056,
|
||||
"peak": 809365504,
|
||||
"anon": 218935296,
|
||||
"oom_kill": 0,
|
||||
"restarts": 0,
|
||||
"oomkilled_flag": false,
|
||||
"status": "running",
|
||||
"cgroup": true
|
||||
}
|
||||
},
|
||||
"requests": 9707
|
||||
},
|
||||
{
|
||||
"t": 514.2,
|
||||
"containers": {
|
||||
"metube": {
|
||||
"limit": 805306368,
|
||||
"current": 752951296,
|
||||
"peak": 809365504,
|
||||
"anon": 226152448,
|
||||
"oom_kill": 0,
|
||||
"restarts": 0,
|
||||
"oomkilled_flag": false,
|
||||
"status": "running",
|
||||
"cgroup": true
|
||||
}
|
||||
},
|
||||
"requests": 9996
|
||||
},
|
||||
{
|
||||
"t": 529.3,
|
||||
"containers": {
|
||||
"metube": {
|
||||
"limit": 805306368,
|
||||
"current": 753430528,
|
||||
"peak": 809365504,
|
||||
"anon": 226152448,
|
||||
"oom_kill": 0,
|
||||
"restarts": 0,
|
||||
"oomkilled_flag": false,
|
||||
"status": "running",
|
||||
"cgroup": true
|
||||
}
|
||||
},
|
||||
"requests": 10294
|
||||
},
|
||||
{
|
||||
"t": 544.5,
|
||||
"containers": {
|
||||
"metube": {
|
||||
"limit": 805306368,
|
||||
"current": 752881664,
|
||||
"peak": 809365504,
|
||||
"anon": 226152448,
|
||||
"oom_kill": 0,
|
||||
"restarts": 0,
|
||||
"oomkilled_flag": false,
|
||||
"status": "running",
|
||||
"cgroup": true
|
||||
}
|
||||
},
|
||||
"requests": 10593
|
||||
},
|
||||
{
|
||||
"t": 559.6,
|
||||
"containers": {
|
||||
"metube": {
|
||||
"limit": 805306368,
|
||||
"current": 753139712,
|
||||
"peak": 809365504,
|
||||
"anon": 226152448,
|
||||
"oom_kill": 0,
|
||||
"restarts": 0,
|
||||
"oomkilled_flag": false,
|
||||
"status": "running",
|
||||
"cgroup": true
|
||||
}
|
||||
},
|
||||
"requests": 10892
|
||||
},
|
||||
{
|
||||
"t": 574.7,
|
||||
"containers": {
|
||||
"metube": {
|
||||
"limit": 805306368,
|
||||
"current": 752640000,
|
||||
"peak": 809365504,
|
||||
"anon": 226152448,
|
||||
"oom_kill": 0,
|
||||
"restarts": 0,
|
||||
"oomkilled_flag": false,
|
||||
"status": "running",
|
||||
"cgroup": true
|
||||
}
|
||||
},
|
||||
"requests": 11190
|
||||
},
|
||||
{
|
||||
"t": 589.9,
|
||||
"containers": {
|
||||
"metube": {
|
||||
"limit": 805306368,
|
||||
"current": 727638016,
|
||||
"peak": 809365504,
|
||||
"anon": 226152448,
|
||||
"oom_kill": 0,
|
||||
"restarts": 0,
|
||||
"oomkilled_flag": false,
|
||||
"status": "running",
|
||||
"cgroup": true
|
||||
}
|
||||
},
|
||||
"requests": 11490
|
||||
},
|
||||
{
|
||||
"t": 605.0,
|
||||
"containers": {
|
||||
"metube": {
|
||||
"limit": 805306368,
|
||||
"current": 727384064,
|
||||
"peak": 809365504,
|
||||
"anon": 226152448,
|
||||
"oom_kill": 0,
|
||||
"restarts": 0,
|
||||
"oomkilled_flag": false,
|
||||
"status": "running",
|
||||
"cgroup": true
|
||||
}
|
||||
},
|
||||
"requests": 11790
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,59 @@
|
||||
[06:19:20] scratch drive folders cleared before FROM (R-656): ['/srv/felhom-gate/hdd/userdata/media/metube']
|
||||
[06:19:20] MV-metube: deploying metube at FROM {'metube': 'ghcr.io/alexta69/metube:2026.09.28'}
|
||||
[06:19:51] FROM settled=True in 30.8s :: {"metube": {"status": "running", "health": "healthy", "restarts": 0, "exit": 0}}
|
||||
[06:19:51] fixture: the BOX walk's own (MeTube), through upgrade_boxport
|
||||
[06:19:52] metube: POST /add http=200 {"status": "ok"}
|
||||
[06:19:55] metube: the download finished (991017 bytes)
|
||||
[06:19:55] metube: history has it=True; GET /download/<file> http=200
|
||||
[06:19:55] C1 (seed reads back BEFORE): True
|
||||
[06:19:56] MV-metube: swapping to TO {'metube': 'ghcr.io/alexta69/metube:2026.09.29'}
|
||||
[06:19:56] TO up -d rc=0
|
||||
[06:20:27] TO settled=True in 30.8s :: {"metube": {"status": "running", "health": "healthy", "restarts": 0, "exit": 0}}
|
||||
[06:20:27] migration lines observed: 0
|
||||
[06:20:28] metube: history has it=True; GET /download/<file> http=200
|
||||
[06:20:28] RESULT (seed reads back AFTER): True
|
||||
[06:20:28] memory watch: 600s, 4 callers on 1 path(s) at 172.18.0.2:8081
|
||||
[06:20:43] + 15s metube=208M/768M peak=255M kills=0 rs=0 reqs=262
|
||||
[06:20:58] + 30s metube=206M/768M peak=255M kills=0 rs=0 reqs=562
|
||||
[06:21:13] + 45s metube=206M/768M peak=255M kills=0 rs=0 reqs=858
|
||||
[06:21:28] + 60s metube=327M/768M peak=371M kills=0 rs=0 reqs=1147
|
||||
[06:21:44] + 76s metube=326M/768M peak=371M kills=0 rs=0 reqs=1446
|
||||
[06:21:59] + 91s metube=326M/768M peak=371M kills=0 rs=0 reqs=1743
|
||||
[06:22:14] + 106s metube=429M/768M peak=465M kills=0 rs=0 reqs=2030
|
||||
[06:22:29] + 121s metube=429M/768M peak=465M kills=0 rs=0 reqs=2330
|
||||
[06:22:44] + 136s metube=430M/768M peak=465M kills=0 rs=0 reqs=2630
|
||||
[06:22:59] + 151s metube=550M/768M peak=588M kills=0 rs=0 reqs=2914
|
||||
[06:23:14] + 166s metube=550M/768M peak=588M kills=0 rs=0 reqs=3214
|
||||
[06:23:30] + 182s metube=550M/768M peak=588M kills=0 rs=0 reqs=3514
|
||||
[06:23:45] + 197s metube=653M/768M peak=692M kills=0 rs=0 reqs=3802
|
||||
[06:24:00] + 212s metube=652M/768M peak=692M kills=0 rs=0 reqs=4098
|
||||
[06:24:15] + 227s metube=652M/768M peak=692M kills=0 rs=0 reqs=4398
|
||||
[06:24:30] + 242s metube=721M/768M peak=769M kills=0 rs=0 reqs=4683
|
||||
[06:24:45] + 257s metube=719M/768M peak=769M kills=0 rs=0 reqs=4982
|
||||
[06:25:00] + 272s metube=719M/768M peak=769M kills=0 rs=0 reqs=5282
|
||||
[06:25:15] + 287s metube=724M/768M peak=770M kills=0 rs=0 reqs=5570
|
||||
[06:25:31] + 302s metube=724M/768M peak=770M kills=0 rs=0 reqs=5870
|
||||
[06:25:46] + 318s metube=724M/768M peak=770M kills=0 rs=0 reqs=6167
|
||||
[06:26:01] + 333s metube=730M/768M peak=770M kills=0 rs=0 reqs=6454
|
||||
[06:26:16] + 348s metube=731M/768M peak=770M kills=0 rs=0 reqs=6754
|
||||
[06:26:31] + 363s metube=730M/768M peak=770M kills=0 rs=0 reqs=7054
|
||||
[06:26:46] + 378s metube=705M/768M peak=771M kills=0 rs=0 reqs=7342
|
||||
[06:27:01] + 393s metube=704M/768M peak=771M kills=0 rs=0 reqs=7638
|
||||
[06:27:16] + 408s metube=705M/768M peak=771M kills=0 rs=0 reqs=7938
|
||||
[06:27:31] + 424s metube=730M/768M peak=771M kills=0 rs=0 reqs=8226
|
||||
[06:27:47] + 439s metube=729M/768M peak=771M kills=0 rs=0 reqs=8522
|
||||
[06:28:02] + 454s metube=729M/768M peak=771M kills=0 rs=0 reqs=8822
|
||||
[06:28:17] + 469s metube=714M/768M peak=771M kills=0 rs=0 reqs=9111
|
||||
[06:28:32] + 484s metube=714M/768M peak=771M kills=0 rs=0 reqs=9411
|
||||
[06:28:47] + 499s metube=715M/768M peak=771M kills=0 rs=0 reqs=9707
|
||||
[06:29:02] + 514s metube=718M/768M peak=771M kills=0 rs=0 reqs=9996
|
||||
[06:29:17] + 529s metube=718M/768M peak=771M kills=0 rs=0 reqs=10294
|
||||
[06:29:32] + 544s metube=718M/768M peak=771M kills=0 rs=0 reqs=10593
|
||||
[06:29:48] + 560s metube=718M/768M peak=771M kills=0 rs=0 reqs=10892
|
||||
[06:30:03] + 575s metube=717M/768M peak=771M kills=0 rs=0 reqs=11190
|
||||
[06:30:18] + 590s metube=693M/768M peak=771M kills=0 rs=0 reqs=11490
|
||||
[06:30:33] + 605s metube=693M/768M peak=771M kills=0 rs=0 reqs=11790
|
||||
[06:30:33] memory watch: killed=False tight=[] requests=11790 codes={'200': 11790}
|
||||
[06:30:33] MV-metube: ABORT — putting the FROM images back
|
||||
[06:31:05] metube: history has it=True; GET /download/<file> http=200
|
||||
[06:31:05] ABORT: app came back in 30.8s; data present=True
|
||||
@@ -0,0 +1,12 @@
|
||||
# sampler.sh (run INSIDE the bench or the box): sample the cgroup of each named container from its birth, every 2 s.
|
||||
# usage: NAMES="a b c" OUT=/root/mem.csv DUR=900 bash sampler.sh & — stops at DUR or when $OUT.stop exists
|
||||
: > $OUT; t0=$(date +%s)
|
||||
while [ $(( $(date +%s) - t0 )) -lt ${DUR:-900} ] && [ ! -f $OUT.stop ]; do
|
||||
for n in $NAMES; do
|
||||
id=$(docker ps -q --no-trunc --filter name=^$n$ | head -1); [ -z "$id" ] && continue
|
||||
cg=$(ls -d /sys/fs/cgroup/system.slice/docker-$id.scope 2>/dev/null || find /sys/fs/cgroup -maxdepth 4 -type d -name "*$id*" 2>/dev/null | head -1)
|
||||
[ -f "$cg/memory.stat" ] || continue
|
||||
echo "$(date +%s),$n,${id:0:12},$(awk '$1=="anon"{print $2}' $cg/memory.stat),$(cat $cg/memory.current),$(cat $cg/memory.swap.current 2>/dev/null || echo NA),$(awk '$1=="oom_kill"{print $2}' $cg/memory.events),$(cat $cg/memory.max),$(docker inspect -f '{{.RestartCount}}' $id)" >> $OUT
|
||||
done
|
||||
sleep 2
|
||||
done
|
||||
@@ -0,0 +1,7 @@
|
||||
[2Kmetube | Setting umask to 022
|
||||
[2Kmetube | Creating download directory (/downloads), audio download directory (/downloads), state directory (/state), and temp dir (/downloads)
|
||||
[2Kmetube | Changing ownership of download and state directories to 1000:1000
|
||||
[2Kmetube | Starting BgUtils POT Provider
|
||||
[2Kmetube | Running MeTube as user 1000:1000
|
||||
[2Kmetube | INFO:main:Listening on 0.0.0.0:8081
|
||||
[2Kmetube | INFO:ytdl:Initializing DownloadQueue
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"metube": {
|
||||
"status": "running",
|
||||
"health": "healthy",
|
||||
"restarts": 0,
|
||||
"exit": 0
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
{
|
||||
"harness_version": 4,
|
||||
"edge": "MV-metube",
|
||||
"app": "metube",
|
||||
"note": "night 2026-09-23 within-a-major move: metube=ghcr.io/alexta69/metube:2026.09.29",
|
||||
"from": {
|
||||
"metube": "ghcr.io/alexta69/metube:2026.09.28"
|
||||
},
|
||||
"to": {
|
||||
"metube": "ghcr.io/alexta69/metube:2026.09.29"
|
||||
},
|
||||
"verdict": "proven",
|
||||
"seed_read_before": true,
|
||||
"seed_read_after": true,
|
||||
"healthy_after": true,
|
||||
"migration_observed": null,
|
||||
"abort": "starts-and-serves",
|
||||
"abort_detail": null,
|
||||
"engine_state_after": null,
|
||||
"memory": {
|
||||
"soak_s": 605.3,
|
||||
"requested_s": 600,
|
||||
"requests": 11790,
|
||||
"codes": {
|
||||
"200": 11790
|
||||
},
|
||||
"first_kill": null,
|
||||
"containers": {
|
||||
"metube": {
|
||||
"limit": 805306368,
|
||||
"peak": 809365504,
|
||||
"peak_pct": 1.005,
|
||||
"anon_peak_sampled": 226152448,
|
||||
"anon_peak_pct": 0.281,
|
||||
"oom_kills": 0,
|
||||
"restarts": 0,
|
||||
"oomkilled_flag": false,
|
||||
"measured": true
|
||||
}
|
||||
},
|
||||
"unmeasured": [],
|
||||
"load": "reached"
|
||||
},
|
||||
"marks": [],
|
||||
"bench_overrides": null,
|
||||
"duration_s": 30.8,
|
||||
"measured_at": "2026-10-02T06:31:05Z",
|
||||
"evidence": "evidence/MV-metube",
|
||||
"scratch_cleared": [
|
||||
"/srv/felhom-gate/hdd/userdata/media/metube"
|
||||
],
|
||||
"files_changed": [],
|
||||
"files_changed_detail": [],
|
||||
"total_s": 705.3
|
||||
}
|
||||
@@ -0,0 +1,342 @@
|
||||
1790921962,metube,95a197aba812,61616128,68952064,0,0,805306368,0
|
||||
1790921964,metube,95a197aba812,61616128,68763648,0,0,805306368,0
|
||||
1790921966,metube,95a197aba812,61616128,68763648,0,0,805306368,0
|
||||
1790921968,metube,95a197aba812,61616128,68763648,0,0,805306368,0
|
||||
1790921970,metube,95a197aba812,61616128,68763648,0,0,805306368,0
|
||||
1790921972,metube,95a197aba812,61616128,68763648,0,0,805306368,0
|
||||
1790921974,metube,95a197aba812,61616128,68763648,0,0,805306368,0
|
||||
1790921976,metube,95a197aba812,61616128,68763648,0,0,805306368,0
|
||||
1790921978,metube,95a197aba812,61616128,68763648,0,0,805306368,0
|
||||
1790921980,metube,95a197aba812,61616128,68763648,0,0,805306368,0
|
||||
1790921982,metube,95a197aba812,61616128,68763648,0,0,805306368,0
|
||||
1790921984,metube,95a197aba812,61616128,68763648,0,0,805306368,0
|
||||
1790921987,metube,95a197aba812,61616128,68763648,0,0,805306368,0
|
||||
1790921989,metube,95a197aba812,61616128,68763648,0,0,805306368,0
|
||||
1790921991,metube,95a197aba812,61648896,68890624,0,0,805306368,0
|
||||
1790921993,metube,95a197aba812,86163456,97509376,0,0,805306368,0
|
||||
1790921995,metube,95a197aba812,86163456,96661504,0,0,805306368,0
|
||||
1790921997,metube,f5a3771ddb27,20725760,26169344,0,0,805306368,0
|
||||
1790921999,metube,f5a3771ddb27,61612032,68534272,0,0,805306368,0
|
||||
1790922001,metube,f5a3771ddb27,61612032,68530176,0,0,805306368,0
|
||||
1790922003,metube,f5a3771ddb27,61612032,68530176,0,0,805306368,0
|
||||
1790922005,metube,f5a3771ddb27,61612032,68530176,0,0,805306368,0
|
||||
1790922007,metube,f5a3771ddb27,61612032,68530176,0,0,805306368,0
|
||||
1790922009,metube,f5a3771ddb27,61612032,68530176,0,0,805306368,0
|
||||
1790922011,metube,f5a3771ddb27,61612032,68530176,0,0,805306368,0
|
||||
1790922013,metube,f5a3771ddb27,61612032,68530176,0,0,805306368,0
|
||||
1790922015,metube,f5a3771ddb27,61612032,68530176,0,0,805306368,0
|
||||
1790922017,metube,f5a3771ddb27,61612032,68530176,0,0,805306368,0
|
||||
1790922019,metube,f5a3771ddb27,61612032,68526080,0,0,805306368,0
|
||||
1790922022,metube,f5a3771ddb27,61612032,68526080,0,0,805306368,0
|
||||
1790922024,metube,f5a3771ddb27,61612032,68526080,0,0,805306368,0
|
||||
1790922026,metube,f5a3771ddb27,61612032,68501504,0,0,805306368,0
|
||||
1790922028,metube,f5a3771ddb27,61652992,69349376,0,0,805306368,0
|
||||
1790922030,metube,f5a3771ddb27,61751296,69353472,0,0,805306368,0
|
||||
1790922032,metube,f5a3771ddb27,91914240,99594240,0,0,805306368,0
|
||||
1790922034,metube,f5a3771ddb27,155385856,200806400,0,0,805306368,0
|
||||
1790922036,metube,f5a3771ddb27,108822528,218771456,0,0,805306368,0
|
||||
1790922038,metube,f5a3771ddb27,108822528,218599424,0,0,805306368,0
|
||||
1790922040,metube,f5a3771ddb27,108822528,218128384,0,0,805306368,0
|
||||
1790922042,metube,f5a3771ddb27,108822528,218615808,0,0,805306368,0
|
||||
1790922044,metube,f5a3771ddb27,108826624,218632192,0,0,805306368,0
|
||||
1790922046,metube,f5a3771ddb27,108847104,218398720,0,0,805306368,0
|
||||
1790922048,metube,f5a3771ddb27,108871680,218681344,0,0,805306368,0
|
||||
1790922050,metube,f5a3771ddb27,108888064,218714112,0,0,805306368,0
|
||||
1790922052,metube,f5a3771ddb27,108888064,218161152,0,0,805306368,0
|
||||
1790922054,metube,f5a3771ddb27,108888064,218673152,0,0,805306368,0
|
||||
1790922057,metube,f5a3771ddb27,109916160,218210304,0,0,805306368,0
|
||||
1790922059,metube,f5a3771ddb27,108990464,217206784,0,0,805306368,0
|
||||
1790922061,metube,f5a3771ddb27,109002752,217198592,0,0,805306368,0
|
||||
1790922063,metube,f5a3771ddb27,109002752,216719360,0,0,805306368,0
|
||||
1790922065,metube,f5a3771ddb27,109010944,217460736,0,0,805306368,0
|
||||
1790922067,metube,f5a3771ddb27,109010944,216973312,0,0,805306368,0
|
||||
1790922069,metube,f5a3771ddb27,109010944,217513984,0,0,805306368,0
|
||||
1790922071,metube,f5a3771ddb27,109010944,217493504,0,0,805306368,0
|
||||
1790922073,metube,f5a3771ddb27,109019136,217231360,0,0,805306368,0
|
||||
1790922075,metube,f5a3771ddb27,109019136,216997888,0,0,805306368,0
|
||||
1790922077,metube,f5a3771ddb27,109019136,216977408,0,0,805306368,0
|
||||
1790922079,metube,f5a3771ddb27,185978880,318234624,0,0,805306368,0
|
||||
1790922081,metube,f5a3771ddb27,134897664,342880256,0,0,805306368,0
|
||||
1790922083,metube,f5a3771ddb27,134897664,343117824,0,0,805306368,0
|
||||
1790922085,metube,f5a3771ddb27,134897664,343400448,0,0,805306368,0
|
||||
1790922087,metube,f5a3771ddb27,134897664,343687168,0,0,805306368,0
|
||||
1790922090,metube,f5a3771ddb27,134897664,342208512,0,0,805306368,0
|
||||
1790922092,metube,f5a3771ddb27,134897664,343232512,0,0,805306368,0
|
||||
1790922094,metube,f5a3771ddb27,134897664,342183936,0,0,805306368,0
|
||||
1790922096,metube,f5a3771ddb27,134897664,342765568,0,0,805306368,0
|
||||
1790922098,metube,f5a3771ddb27,134897664,342196224,0,0,805306368,0
|
||||
1790922100,metube,f5a3771ddb27,134897664,342216704,0,0,805306368,0
|
||||
1790922102,metube,f5a3771ddb27,134897664,342441984,0,0,805306368,0
|
||||
1790922104,metube,f5a3771ddb27,134897664,342462464,0,0,805306368,0
|
||||
1790922106,metube,f5a3771ddb27,134897664,342470656,0,0,805306368,0
|
||||
1790922108,metube,f5a3771ddb27,134897664,342175744,0,0,805306368,0
|
||||
1790922110,metube,f5a3771ddb27,134905856,342458368,0,0,805306368,0
|
||||
1790922112,metube,f5a3771ddb27,134905856,341962752,0,0,805306368,0
|
||||
1790922114,metube,f5a3771ddb27,134905856,342220800,0,0,805306368,0
|
||||
1790922116,metube,f5a3771ddb27,134905856,342732800,0,0,805306368,0
|
||||
1790922118,metube,f5a3771ddb27,134905856,342478848,0,0,805306368,0
|
||||
1790922120,metube,f5a3771ddb27,134905856,342482944,0,0,805306368,0
|
||||
1790922123,metube,f5a3771ddb27,134905856,342732800,0,0,805306368,0
|
||||
1790922125,metube,f5a3771ddb27,190570496,401002496,0,0,805306368,0
|
||||
1790922127,metube,f5a3771ddb27,170270720,458723328,0,0,805306368,0
|
||||
1790922129,metube,f5a3771ddb27,142479360,450789376,0,0,805306368,0
|
||||
1790922131,metube,f5a3771ddb27,142479360,451551232,0,0,805306368,0
|
||||
1790922133,metube,f5a3771ddb27,142479360,451239936,0,0,805306368,0
|
||||
1790922135,metube,f5a3771ddb27,142479360,450732032,0,0,805306368,0
|
||||
1790922137,metube,f5a3771ddb27,142479360,451461120,0,0,805306368,0
|
||||
1790922139,metube,f5a3771ddb27,142479360,450768896,0,0,805306368,0
|
||||
1790922141,metube,f5a3771ddb27,142479360,451031040,0,0,805306368,0
|
||||
1790922143,metube,f5a3771ddb27,142479360,451039232,0,0,805306368,0
|
||||
1790922145,metube,f5a3771ddb27,142479360,451330048,0,0,805306368,0
|
||||
1790922147,metube,f5a3771ddb27,142479360,451297280,0,0,805306368,0
|
||||
1790922149,metube,f5a3771ddb27,142479360,450772992,0,0,805306368,0
|
||||
1790922151,metube,f5a3771ddb27,142479360,451530752,0,0,805306368,0
|
||||
1790922153,metube,f5a3771ddb27,142479360,451297280,0,0,805306368,0
|
||||
1790922155,metube,f5a3771ddb27,142479360,450785280,0,0,805306368,0
|
||||
1790922158,metube,f5a3771ddb27,142479360,450990080,0,0,805306368,0
|
||||
1790922160,metube,f5a3771ddb27,142479360,451276800,0,0,805306368,0
|
||||
1790922162,metube,f5a3771ddb27,142479360,451002368,0,0,805306368,0
|
||||
1790922164,metube,f5a3771ddb27,142479360,451190784,0,0,805306368,0
|
||||
1790922166,metube,f5a3771ddb27,142479360,450232320,0,0,805306368,0
|
||||
1790922168,metube,f5a3771ddb27,142479360,450965504,0,0,805306368,0
|
||||
1790922170,metube,f5a3771ddb27,143896576,451883008,0,0,805306368,0
|
||||
1790922172,metube,f5a3771ddb27,228179968,577183744,0,0,805306368,0
|
||||
1790922174,metube,f5a3771ddb27,168550400,577802240,0,0,805306368,0
|
||||
1790922176,metube,f5a3771ddb27,168550400,578060288,0,0,805306368,0
|
||||
1790922178,metube,f5a3771ddb27,168550400,577794048,0,0,805306368,0
|
||||
1790922180,metube,f5a3771ddb27,168550400,577540096,0,0,805306368,0
|
||||
1790922182,metube,f5a3771ddb27,168550400,578039808,0,0,805306368,0
|
||||
1790922184,metube,f5a3771ddb27,168550400,578060288,0,0,805306368,0
|
||||
1790922186,metube,f5a3771ddb27,168550400,577531904,0,0,805306368,0
|
||||
1790922188,metube,f5a3771ddb27,168550400,577015808,0,0,805306368,0
|
||||
1790922190,metube,f5a3771ddb27,168550400,577261568,0,0,805306368,0
|
||||
1790922193,metube,f5a3771ddb27,168550400,577568768,0,0,805306368,0
|
||||
1790922195,metube,f5a3771ddb27,168550400,577515520,0,0,805306368,0
|
||||
1790922197,metube,f5a3771ddb27,168550400,577269760,0,0,805306368,0
|
||||
1790922199,metube,f5a3771ddb27,168550400,577523712,0,0,805306368,0
|
||||
1790922201,metube,f5a3771ddb27,168550400,577220608,0,0,805306368,0
|
||||
1790922203,metube,f5a3771ddb27,168550400,577458176,0,0,805306368,0
|
||||
1790922205,metube,f5a3771ddb27,168550400,577003520,0,0,805306368,0
|
||||
1790922207,metube,f5a3771ddb27,168550400,577695744,0,0,805306368,0
|
||||
1790922209,metube,f5a3771ddb27,168550400,577257472,0,0,805306368,0
|
||||
1790922211,metube,f5a3771ddb27,168550400,577232896,0,0,805306368,0
|
||||
1790922213,metube,f5a3771ddb27,168550400,577769472,0,0,805306368,0
|
||||
1790922215,metube,f5a3771ddb27,168550400,577531904,0,0,805306368,0
|
||||
1790922217,metube,f5a3771ddb27,205242368,639512576,0,0,805306368,0
|
||||
1790922219,metube,f5a3771ddb27,175656960,684793856,0,0,805306368,0
|
||||
1790922221,metube,f5a3771ddb27,175656960,685002752,0,0,805306368,0
|
||||
1790922223,metube,f5a3771ddb27,175656960,685559808,0,0,805306368,0
|
||||
1790922225,metube,f5a3771ddb27,175656960,685334528,0,0,805306368,0
|
||||
1790922228,metube,f5a3771ddb27,175656960,685051904,0,0,805306368,0
|
||||
1790922230,metube,f5a3771ddb27,175656960,684498944,0,0,805306368,0
|
||||
1790922232,metube,f5a3771ddb27,175656960,685236224,0,0,805306368,0
|
||||
1790922234,metube,f5a3771ddb27,175656960,684515328,0,0,805306368,0
|
||||
1790922236,metube,f5a3771ddb27,175656960,685252608,0,0,805306368,0
|
||||
1790922238,metube,f5a3771ddb27,175656960,685109248,0,0,805306368,0
|
||||
1790922240,metube,f5a3771ddb27,175656960,684761088,0,0,805306368,0
|
||||
1790922242,metube,f5a3771ddb27,175656960,685469696,0,0,805306368,0
|
||||
1790922244,metube,f5a3771ddb27,175656960,685023232,0,0,805306368,0
|
||||
1790922246,metube,f5a3771ddb27,175656960,684527616,0,0,805306368,0
|
||||
1790922248,metube,f5a3771ddb27,175656960,685043712,0,0,805306368,0
|
||||
1790922250,metube,f5a3771ddb27,175611904,684167168,0,0,805306368,0
|
||||
1790922252,metube,f5a3771ddb27,175656960,683786240,0,0,805306368,0
|
||||
1790922254,metube,f5a3771ddb27,175656960,684486656,0,0,805306368,0
|
||||
1790922256,metube,f5a3771ddb27,175656960,683757568,0,0,805306368,0
|
||||
1790922258,metube,f5a3771ddb27,175656960,683835392,0,0,805306368,0
|
||||
1790922260,metube,f5a3771ddb27,175656960,684019712,0,0,805306368,0
|
||||
1790922263,metube,f5a3771ddb27,243482624,754290688,0,0,805306368,0
|
||||
1790922265,metube,f5a3771ddb27,182927360,756011008,0,0,805306368,0
|
||||
1790922267,metube,f5a3771ddb27,182927360,756854784,0,0,805306368,0
|
||||
1790922269,metube,f5a3771ddb27,182927360,756580352,0,0,805306368,0
|
||||
1790922271,metube,f5a3771ddb27,182927360,756105216,0,0,805306368,0
|
||||
1790922273,metube,f5a3771ddb27,182927360,756346880,0,0,805306368,0
|
||||
1790922275,metube,f5a3771ddb27,182927360,755613696,0,0,805306368,0
|
||||
1790922277,metube,f5a3771ddb27,182927360,756346880,0,0,805306368,0
|
||||
1790922279,metube,f5a3771ddb27,182927360,755949568,0,0,805306368,0
|
||||
1790922281,metube,f5a3771ddb27,182927360,756326400,0,0,805306368,0
|
||||
1790922283,metube,f5a3771ddb27,182927360,754925568,0,0,805306368,0
|
||||
1790922285,metube,f5a3771ddb27,182927360,754438144,0,0,805306368,0
|
||||
1790922287,metube,f5a3771ddb27,182927360,754966528,0,0,805306368,0
|
||||
1790922289,metube,f5a3771ddb27,182927360,754683904,0,0,805306368,0
|
||||
1790922291,metube,f5a3771ddb27,182927360,754712576,0,0,805306368,0
|
||||
1790922293,metube,f5a3771ddb27,182927360,754450432,0,0,805306368,0
|
||||
1790922295,metube,f5a3771ddb27,182927360,754286592,0,0,805306368,0
|
||||
1790922298,metube,f5a3771ddb27,182927360,754802688,0,0,805306368,0
|
||||
1790922300,metube,f5a3771ddb27,182927360,754724864,0,0,805306368,0
|
||||
1790922302,metube,f5a3771ddb27,182927360,754417664,0,0,805306368,0
|
||||
1790922304,metube,f5a3771ddb27,182927360,754188288,0,0,805306368,0
|
||||
1790922306,metube,f5a3771ddb27,182927360,754704384,0,0,805306368,0
|
||||
1790922308,metube,f5a3771ddb27,184786944,756314112,0,0,805306368,0
|
||||
1790922310,metube,f5a3771ddb27,244506624,799944704,0,0,805306368,0
|
||||
1790922312,metube,f5a3771ddb27,190197760,762036224,0,0,805306368,0
|
||||
1790922314,metube,f5a3771ddb27,190197760,762023936,0,0,805306368,0
|
||||
1790922316,metube,f5a3771ddb27,190197760,759812096,0,0,805306368,0
|
||||
1790922318,metube,f5a3771ddb27,190197760,759586816,0,0,805306368,0
|
||||
1790922320,metube,f5a3771ddb27,190197760,759803904,0,0,805306368,0
|
||||
1790922322,metube,f5a3771ddb27,190197760,760057856,0,0,805306368,0
|
||||
1790922324,metube,f5a3771ddb27,190197760,760020992,0,0,805306368,0
|
||||
1790922326,metube,f5a3771ddb27,190197760,760291328,0,0,805306368,0
|
||||
1790922328,metube,f5a3771ddb27,190197760,759508992,0,0,805306368,0
|
||||
1790922330,metube,f5a3771ddb27,190197760,759812096,0,0,805306368,0
|
||||
1790922333,metube,f5a3771ddb27,190197760,759844864,0,0,805306368,0
|
||||
1790922335,metube,f5a3771ddb27,190197760,759545856,0,0,805306368,0
|
||||
1790922337,metube,f5a3771ddb27,190197760,760053760,0,0,805306368,0
|
||||
1790922339,metube,f5a3771ddb27,190197760,759296000,0,0,805306368,0
|
||||
1790922341,metube,f5a3771ddb27,190197760,760082432,0,0,805306368,0
|
||||
1790922343,metube,f5a3771ddb27,190197760,760135680,0,0,805306368,0
|
||||
1790922345,metube,f5a3771ddb27,190197760,759586816,0,0,805306368,0
|
||||
1790922347,metube,f5a3771ddb27,190197760,760033280,0,0,805306368,0
|
||||
1790922349,metube,f5a3771ddb27,190197760,759541760,0,0,805306368,0
|
||||
1790922351,metube,f5a3771ddb27,190197760,759296000,0,0,805306368,0
|
||||
1790922353,metube,f5a3771ddb27,190197760,759808000,0,0,805306368,0
|
||||
1790922355,metube,f5a3771ddb27,249851904,805138432,0,0,805306368,0
|
||||
1790922357,metube,f5a3771ddb27,197423104,766578688,0,0,805306368,0
|
||||
1790922359,metube,f5a3771ddb27,197423104,766566400,0,0,805306368,0
|
||||
1790922361,metube,f5a3771ddb27,197423104,766279680,0,0,805306368,0
|
||||
1790922363,metube,f5a3771ddb27,197423104,766533632,0,0,805306368,0
|
||||
1790922366,metube,f5a3771ddb27,197423104,766857216,0,0,805306368,0
|
||||
1790922368,metube,f5a3771ddb27,197423104,766750720,0,0,805306368,0
|
||||
1790922370,metube,f5a3771ddb27,197423104,765816832,0,0,805306368,0
|
||||
1790922372,metube,f5a3771ddb27,197423104,766541824,0,0,805306368,0
|
||||
1790922374,metube,f5a3771ddb27,197423104,766799872,0,0,805306368,0
|
||||
1790922376,metube,f5a3771ddb27,197423104,766574592,0,0,805306368,0
|
||||
1790922378,metube,f5a3771ddb27,197423104,766287872,0,0,805306368,0
|
||||
1790922380,metube,f5a3771ddb27,197423104,766787584,0,0,805306368,0
|
||||
1790922382,metube,f5a3771ddb27,197423104,766267392,0,0,805306368,0
|
||||
1790922384,metube,f5a3771ddb27,197423104,766509056,0,0,805306368,0
|
||||
1790922386,metube,f5a3771ddb27,197423104,766496768,0,0,805306368,0
|
||||
1790922388,metube,f5a3771ddb27,197423104,766500864,0,0,805306368,0
|
||||
1790922390,metube,f5a3771ddb27,197423104,766521344,0,0,805306368,0
|
||||
1790922392,metube,f5a3771ddb27,197423104,766033920,0,0,805306368,0
|
||||
1790922394,metube,f5a3771ddb27,197423104,766287872,0,0,805306368,0
|
||||
1790922396,metube,f5a3771ddb27,197423104,766840832,0,0,805306368,0
|
||||
1790922398,metube,f5a3771ddb27,197423104,766787584,0,0,805306368,0
|
||||
1790922401,metube,f5a3771ddb27,231120896,762380288,0,0,805306368,0
|
||||
1790922403,metube,f5a3771ddb27,204529664,740036608,0,0,805306368,0
|
||||
1790922405,metube,f5a3771ddb27,204529664,739319808,0,0,805306368,0
|
||||
1790922407,metube,f5a3771ddb27,204529664,739577856,0,0,805306368,0
|
||||
1790922409,metube,f5a3771ddb27,204529664,739336192,0,0,805306368,0
|
||||
1790922411,metube,f5a3771ddb27,204529664,739344384,0,0,805306368,0
|
||||
1790922413,metube,f5a3771ddb27,204529664,739291136,0,0,805306368,0
|
||||
1790922415,metube,f5a3771ddb27,204529664,739827712,0,0,805306368,0
|
||||
1790922417,metube,f5a3771ddb27,204529664,739581952,0,0,805306368,0
|
||||
1790922419,metube,f5a3771ddb27,204529664,739336192,0,0,805306368,0
|
||||
1790922421,metube,f5a3771ddb27,204529664,739840000,0,0,805306368,0
|
||||
1790922423,metube,f5a3771ddb27,204533760,739336192,0,0,805306368,0
|
||||
1790922425,metube,f5a3771ddb27,204533760,739291136,0,0,805306368,0
|
||||
1790922427,metube,f5a3771ddb27,204533760,739233792,0,0,805306368,0
|
||||
1790922429,metube,f5a3771ddb27,204533760,739598336,0,0,805306368,0
|
||||
1790922431,metube,f5a3771ddb27,204533760,739876864,0,0,805306368,0
|
||||
1790922433,metube,f5a3771ddb27,204533760,739573760,0,0,805306368,0
|
||||
1790922436,metube,f5a3771ddb27,204533760,739065856,0,0,805306368,0
|
||||
1790922438,metube,f5a3771ddb27,204533760,739057664,0,0,805306368,0
|
||||
1790922440,metube,f5a3771ddb27,204533760,738803712,0,0,805306368,0
|
||||
1790922442,metube,f5a3771ddb27,204533760,739323904,0,0,805306368,0
|
||||
1790922444,metube,f5a3771ddb27,204533760,739569664,0,0,805306368,0
|
||||
1790922446,metube,f5a3771ddb27,211279872,746684416,0,0,805306368,0
|
||||
1790922448,metube,f5a3771ddb27,269770752,805326848,0,0,805306368,0
|
||||
1790922450,metube,f5a3771ddb27,211742720,765071360,0,0,805306368,0
|
||||
1790922452,metube,f5a3771ddb27,211742720,765288448,0,0,805306368,0
|
||||
1790922454,metube,f5a3771ddb27,211742720,765296640,0,0,805306368,0
|
||||
1790922456,metube,f5a3771ddb27,211742720,765317120,0,0,805306368,0
|
||||
1790922458,metube,f5a3771ddb27,211742720,765784064,0,0,805306368,0
|
||||
1790922460,metube,f5a3771ddb27,211742720,765288448,0,0,805306368,0
|
||||
1790922462,metube,f5a3771ddb27,211742720,765267968,0,0,805306368,0
|
||||
1790922464,metube,f5a3771ddb27,211742720,765739008,0,0,805306368,0
|
||||
1790922466,metube,f5a3771ddb27,211742720,765579264,0,0,805306368,0
|
||||
1790922469,metube,f5a3771ddb27,211742720,766054400,0,0,805306368,0
|
||||
1790922471,metube,f5a3771ddb27,211742720,765566976,0,0,805306368,0
|
||||
1790922473,metube,f5a3771ddb27,211742720,765571072,0,0,805306368,0
|
||||
1790922475,metube,f5a3771ddb27,211742720,765575168,0,0,805306368,0
|
||||
1790922477,metube,f5a3771ddb27,211742720,765833216,0,0,805306368,0
|
||||
1790922479,metube,f5a3771ddb27,211742720,766078976,0,0,805306368,0
|
||||
1790922481,metube,f5a3771ddb27,211742720,765554688,0,0,805306368,0
|
||||
1790922483,metube,f5a3771ddb27,211742720,765542400,0,0,805306368,0
|
||||
1790922485,metube,f5a3771ddb27,211742720,765259776,0,0,805306368,0
|
||||
1790922487,metube,f5a3771ddb27,211742720,765759488,0,0,805306368,0
|
||||
1790922489,metube,f5a3771ddb27,211742720,766226432,0,0,805306368,0
|
||||
1790922491,metube,f5a3771ddb27,213061632,766840832,0,0,805306368,0
|
||||
1790922493,metube,f5a3771ddb27,263483392,785580032,0,0,805306368,0
|
||||
1790922495,metube,f5a3771ddb27,218931200,749305856,0,0,805306368,0
|
||||
1790922497,metube,f5a3771ddb27,218935296,750055424,0,0,805306368,0
|
||||
1790922499,metube,f5a3771ddb27,218935296,749936640,0,0,805306368,0
|
||||
1790922501,metube,f5a3771ddb27,218935296,750116864,0,0,805306368,0
|
||||
1790922504,metube,f5a3771ddb27,218935296,749645824,0,0,805306368,0
|
||||
1790922506,metube,f5a3771ddb27,218935296,750329856,0,0,805306368,0
|
||||
1790922508,metube,f5a3771ddb27,220262400,751992832,0,0,805306368,0
|
||||
1790922510,metube,f5a3771ddb27,218935296,749592576,0,0,805306368,0
|
||||
1790922512,metube,f5a3771ddb27,218935296,749916160,0,0,805306368,0
|
||||
1790922514,metube,f5a3771ddb27,218935296,749637632,0,0,805306368,0
|
||||
1790922516,metube,f5a3771ddb27,218935296,749121536,0,0,805306368,0
|
||||
1790922518,metube,f5a3771ddb27,218935296,750116864,0,0,805306368,0
|
||||
1790922520,metube,f5a3771ddb27,218935296,750415872,0,0,805306368,0
|
||||
1790922522,metube,f5a3771ddb27,218935296,750108672,0,0,805306368,0
|
||||
1790922524,metube,f5a3771ddb27,218935296,750104576,0,0,805306368,0
|
||||
1790922526,metube,f5a3771ddb27,218935296,749834240,0,0,805306368,0
|
||||
1790922528,metube,f5a3771ddb27,218935296,750387200,0,0,805306368,0
|
||||
1790922530,metube,f5a3771ddb27,218935296,749891584,0,0,805306368,0
|
||||
1790922532,metube,f5a3771ddb27,218935296,749891584,0,0,805306368,0
|
||||
1790922534,metube,f5a3771ddb27,218935296,750415872,0,0,805306368,0
|
||||
1790922536,metube,f5a3771ddb27,218935296,750141440,0,0,805306368,0
|
||||
1790922539,metube,f5a3771ddb27,283312128,799088640,0,0,805306368,0
|
||||
1790922541,metube,f5a3771ddb27,226152448,753377280,0,0,805306368,0
|
||||
1790922543,metube,f5a3771ddb27,226152448,753451008,0,0,805306368,0
|
||||
1790922545,metube,f5a3771ddb27,226152448,753442816,0,0,805306368,0
|
||||
1790922547,metube,f5a3771ddb27,226152448,753983488,0,0,805306368,0
|
||||
1790922549,metube,f5a3771ddb27,226152448,753479680,0,0,805306368,0
|
||||
1790922551,metube,f5a3771ddb27,226152448,753426432,0,0,805306368,0
|
||||
1790922553,metube,f5a3771ddb27,226152448,753696768,0,0,805306368,0
|
||||
1790922555,metube,f5a3771ddb27,226152448,753209344,0,0,805306368,0
|
||||
1790922557,metube,f5a3771ddb27,226152448,753975296,0,0,805306368,0
|
||||
1790922559,metube,f5a3771ddb27,226152448,753192960,0,0,805306368,0
|
||||
1790922561,metube,f5a3771ddb27,226152448,752930816,0,0,805306368,0
|
||||
1790922563,metube,f5a3771ddb27,226152448,753680384,0,0,805306368,0
|
||||
1790922565,metube,f5a3771ddb27,226152448,753201152,0,0,805306368,0
|
||||
1790922567,metube,f5a3771ddb27,226152448,753750016,0,0,805306368,0
|
||||
1790922569,metube,f5a3771ddb27,226152448,753213440,0,0,805306368,0
|
||||
1790922571,metube,f5a3771ddb27,226152448,753741824,0,0,805306368,0
|
||||
1790922573,metube,f5a3771ddb27,226152448,753147904,0,0,805306368,0
|
||||
1790922576,metube,f5a3771ddb27,226152448,752627712,0,0,805306368,0
|
||||
1790922578,metube,f5a3771ddb27,226152448,752615424,0,0,805306368,0
|
||||
1790922580,metube,f5a3771ddb27,226152448,753401856,0,0,805306368,0
|
||||
1790922582,metube,f5a3771ddb27,226152448,753401856,0,0,805306368,0
|
||||
1790922584,metube,f5a3771ddb27,226152448,752902144,0,0,805306368,0
|
||||
1790922586,metube,f5a3771ddb27,226152448,753131520,0,0,805306368,0
|
||||
1790922588,metube,f5a3771ddb27,226152448,753397760,0,0,805306368,0
|
||||
1790922590,metube,f5a3771ddb27,226152448,753127424,0,0,805306368,0
|
||||
1790922592,metube,f5a3771ddb27,226152448,753389568,0,0,805306368,0
|
||||
1790922594,metube,f5a3771ddb27,226152448,753156096,0,0,805306368,0
|
||||
1790922596,metube,f5a3771ddb27,226152448,753135616,0,0,805306368,0
|
||||
1790922598,metube,f5a3771ddb27,226152448,753610752,0,0,805306368,0
|
||||
1790922600,metube,f5a3771ddb27,226152448,752898048,0,0,805306368,0
|
||||
1790922602,metube,f5a3771ddb27,226152448,752377856,0,0,805306368,0
|
||||
1790922604,metube,f5a3771ddb27,226152448,753147904,0,0,805306368,0
|
||||
1790922606,metube,f5a3771ddb27,226152448,753405952,0,0,805306368,0
|
||||
1790922609,metube,f5a3771ddb27,226152448,753397760,0,0,805306368,0
|
||||
1790922611,metube,f5a3771ddb27,226152448,752889856,0,0,805306368,0
|
||||
1790922613,metube,f5a3771ddb27,226152448,752635904,0,0,805306368,0
|
||||
1790922615,metube,f5a3771ddb27,226152448,753397760,0,0,805306368,0
|
||||
1790922617,metube,f5a3771ddb27,226152448,727658496,0,0,805306368,0
|
||||
1790922619,metube,f5a3771ddb27,226152448,727891968,0,0,805306368,0
|
||||
1790922621,metube,f5a3771ddb27,226152448,728174592,0,0,805306368,0
|
||||
1790922623,metube,f5a3771ddb27,226152448,727375872,0,0,805306368,0
|
||||
1790922625,metube,f5a3771ddb27,226152448,727654400,0,0,805306368,0
|
||||
1790922627,metube,f5a3771ddb27,226152448,728150016,0,0,805306368,0
|
||||
1790922629,metube,f5a3771ddb27,226152448,727650304,0,0,805306368,0
|
||||
1790922631,metube,f5a3771ddb27,226152448,727908352,0,0,805306368,0
|
||||
1790922633,metube,f5a3771ddb27,226152448,727384064,0,0,805306368,0
|
||||
1790922635,metube,428f55c58f33,44060672,51523584,0,0,805306368,0
|
||||
1790922637,metube,428f55c58f33,61603840,69406720,0,0,805306368,0
|
||||
1790922639,metube,428f55c58f33,61603840,69402624,0,0,805306368,0
|
||||
1790922642,metube,428f55c58f33,61603840,69398528,0,0,805306368,0
|
||||
1790922644,metube,428f55c58f33,61603840,69398528,0,0,805306368,0
|
||||
1790922646,metube,428f55c58f33,61603840,69398528,0,0,805306368,0
|
||||
1790922648,metube,428f55c58f33,61603840,69398528,0,0,805306368,0
|
||||
1790922650,metube,428f55c58f33,61603840,69394432,0,0,805306368,0
|
||||
1790922652,metube,428f55c58f33,61603840,69394432,0,0,805306368,0
|
||||
1790922654,metube,428f55c58f33,61603840,69394432,0,0,805306368,0
|
||||
1790922656,metube,428f55c58f33,61603840,69394432,0,0,805306368,0
|
||||
1790922658,metube,428f55c58f33,61603840,69394432,0,0,805306368,0
|
||||
1790922660,metube,428f55c58f33,61603840,69394432,0,0,805306368,0
|
||||
1790922662,metube,428f55c58f33,61603840,69394432,0,0,805306368,0
|
||||
1790922664,metube,428f55c58f33,61603840,69394432,0,0,805306368,0
|
||||
|
@@ -0,0 +1,4 @@
|
||||
from-birth 2 s sampler, MV-metube (one row per container INSTANCE: FROM 2026.09.28, TO 2026.09.29 under the harness watch + burst, ABORT 2026.09.28); swap 0 bench
|
||||
metube 95a197aba812 06:19:22-06:19:55 n= 17 peak anon 82.2 MiB = 10.7 % of 768 MiB; peak current 93.0 MiB; oom_kill 0; restarts 0; swap.current ['0']
|
||||
metube f5a3771ddb27 06:19:57-06:30:33 n= 310 peak anon 270.2 MiB = 35.2 % of 768 MiB; peak current 768.0 MiB; oom_kill 0; restarts 0; swap.current ['0']
|
||||
metube 428f55c58f33 06:30:35-06:31:04 n= 15 peak anon 58.8 MiB = 7.6 % of 768 MiB; peak current 66.2 MiB; oom_kill 0; restarts 0; swap.current ['0']
|
||||
|
After Width: | Height: | Size: 72 KiB |
|
After Width: | Height: | Size: 72 KiB |
|
After Width: | Height: | Size: 66 KiB |
|
After Width: | Height: | Size: 69 KiB |
|
After Width: | Height: | Size: 553 KiB |
|
After Width: | Height: | Size: 62 KiB |
|
After Width: | Height: | Size: 84 KiB |
@@ -0,0 +1,67 @@
|
||||
"""fg.py — the family gate's live client on 9202 (product endpoints only). LAN = curl to 9202's traefik with a Host header;
|
||||
tunnel = a curl container at cloudflared's fixed address 172.16.253.2 sending what Cloudflare sends. Never prints secrets."""
|
||||
import json, os, re, subprocess, sys, urllib.parse
|
||||
sys.path.insert(0, "/mnt/5_hdd/felhom.eu/git/app-catalog-felhom.eu/scripts")
|
||||
import box_walk as w
|
||||
DOM = w.DOMAIN; CTL = f"felhom.{DOM}"
|
||||
GSH = "/tmp/claude-1000/-mnt-5-hdd-felhom-eu-git/05c3d295-b388-481a-8c36-44a2a80b7d7d/scratchpad/g.sh"
|
||||
|
||||
def lan(host, path, *a, method=None, data=None, cookie=None, hdrs=(), timeout=15):
|
||||
args = ["curl", "-sk", "--max-time", str(timeout), "-D", "-", "-H", f"Host: {host}"]
|
||||
for h in hdrs: args += ["-H", h]
|
||||
if cookie: args += ["-H", f"Cookie: {cookie}"]
|
||||
if method: args += ["-X", method]
|
||||
if data is not None: args += ["--data", data]
|
||||
r = subprocess.run(args + list(a) + [f"{w.BASE}{path}"], capture_output=True, text=True, errors="replace")
|
||||
head, _, body = r.stdout.replace("\r\n", "\n").partition("\n\n")
|
||||
while re.match(r"HTTP/\S+ 100", head) and body:
|
||||
head, _, body = body.partition("\n\n")
|
||||
m = re.match(r"HTTP/\S+ (\d+)", head)
|
||||
return (m.group(1) if m else "000"), head, body
|
||||
|
||||
def tun(host, path, visitor, forged=None, *a, timeout=15):
|
||||
xff = f"{forged}, {visitor}" if forged else visitor
|
||||
extra = " ".join("'" + x.replace("'", "'\\''") + "'" for x in a)
|
||||
cmd = (f"docker run --rm --network felhom-tunnel --ip 172.16.253.2 curlimages/curl:8.11.1 -sk --max-time {timeout} -D - "
|
||||
f"'https://traefik{path}' -H 'Host: {host}' -H 'X-Forwarded-For: {xff}' -H 'CF-Connecting-IP: {visitor}' {extra}")
|
||||
r = subprocess.run([GSH, "9202", cmd], capture_output=True, text=True, errors="replace")
|
||||
head, _, body = r.stdout.replace("\r\n", "\n").partition("\n\n")
|
||||
m = re.match(r"HTTP/\S+ (\d+)", head)
|
||||
return (m.group(1) if m else "000"), head, body
|
||||
|
||||
def loc(head):
|
||||
m = re.search(r"(?im)^location: *(\S+)", head); return m.group(1) if m else ""
|
||||
|
||||
def setc(head, name):
|
||||
m = re.search(rf"(?im)^set-cookie: *({name}=[^;\n]*)", head); return m.group(1) if m else None
|
||||
|
||||
def is_gate(code, head, body):
|
||||
if code == "302" and f"https://{CTL}/__family/start" in loc(head): return True
|
||||
return code == "401" and "sign in with your family login" in body
|
||||
|
||||
def dash_session():
|
||||
return open(f"{w.SC}/sess{os.getpid()}.txt").read().strip() # "felhom_session=…"
|
||||
|
||||
def family_login(name, pw, visitor_tunnel=None):
|
||||
data = None
|
||||
c, h, b = lan(CTL, "/__family/login")
|
||||
ft = re.search(r'name="_ft" value="([^"]+)"', b)
|
||||
form = urllib.parse.urlencode({"_ft": ft.group(1) if ft else "", "name": name, "password": pw, "rd": ""})
|
||||
if visitor_tunnel:
|
||||
c, h, b = tun(CTL, "/__family/login", visitor_tunnel, None, "-X", "POST", "-H", "Content-Type: application/x-www-form-urlencoded", "--data", form)
|
||||
else:
|
||||
c, h, b = lan(CTL, "/__family/login", method="POST", data=form, hdrs=("Content-Type: application/x-www-form-urlencoded",))
|
||||
return c, setc(h, "felhom_family"), h, b
|
||||
|
||||
def app_cookie(sub, session_cookie):
|
||||
"""Walk a browser holding session_cookie (family or dashboard) through start → callback → felhom_famgate."""
|
||||
host = f"{sub}.{DOM}"
|
||||
c, h, b = lan(host, "/", hdrs=("Accept: text/html",))
|
||||
l = loc(h)
|
||||
if "/__family/start" not in l: return None, f"app did not send to /__family/start ({c} {l[:60]})"
|
||||
u = urllib.parse.urlsplit(l)
|
||||
c, h, b = lan(u.hostname, f"{u.path}?{u.query}", cookie=session_cookie, hdrs=("Accept: text/html",))
|
||||
l = loc(h); u = urllib.parse.urlsplit(l)
|
||||
if "/__felhom_gate/fcb" not in u.path: return None, f"start did not hand a callback ({c} {l[:60]})"
|
||||
c, h, b = lan(u.hostname, f"{u.path}?{u.query}", hdrs=("Accept: text/html",))
|
||||
return setc(h, "felhom_famgate"), h
|
||||
@@ -0,0 +1,160 @@
|
||||
#!/usr/bin/env python3
|
||||
"""fg_b4.py — Part B4: Grimmory and MeTube installed on ONE demo box (demo-hp, guest 9201, controller 0.287.0, the LIVE
|
||||
catalog) through the product, measured, and removed WITH their data (the with-data half of record row 2.6 that 9202 cannot
|
||||
show — R-442). The stranger and the family member go through the REAL internet path (Cloudflare → the box's tunnel), from
|
||||
DooPlex, as well as the LAN. Secrets never printed; the test member's password lives in a 0600 scratch file and the member
|
||||
is removed at the end. Env: SC (0600 scratch with .ctlpw = the demo password), EV.
|
||||
Evidence: $EV/B4/<app>-demo.txt + $EV/B4/demo-common.txt."""
|
||||
import json, os, re, secrets, subprocess, sys, time
|
||||
os.environ.setdefault("GUEST", "9201")
|
||||
os.environ.setdefault("BASE", "https://192.168.0.155")
|
||||
sys.path.insert(0, "/mnt/5_hdd/felhom.eu/git/app-catalog-felhom.eu/scripts")
|
||||
import box_walk as w
|
||||
import upgrade_fixtures_box as fixtures
|
||||
w.HP = "hp" # `ssh hp` is the working alias for demo-hp (memory: demo-hp-guest-controller-access)
|
||||
DOM = w.DOMAIN; CTL = f"felhom.{DOM}"
|
||||
DRIVE = "/mnt/felhom-drives/hdd_1" # what this box's other apps use as HDD_PATH (read 2026-10-02)
|
||||
EVD = f"{w.EV}/B4"; os.makedirs(EVD, exist_ok=True)
|
||||
APPS = {"grimmory": ("library", fixtures.FIXTURES["grimmory"]), "metube": ("video", fixtures.FIXTURES["metube"])}
|
||||
logs = {a: open(f"{EVD}/{a}-demo.txt", "a", buffering=1) for a in APPS}
|
||||
common = open(f"{EVD}/demo-common.txt", "a", buffering=1)
|
||||
|
||||
|
||||
def say(app, *a):
|
||||
w.say(*a); (logs[app] if app else common).write(" ".join(map(str, a)) + "\n")
|
||||
|
||||
|
||||
def internet(host, path="/", cookie=None, data=None, hdrs=()):
|
||||
"""A request through the REAL public path: DooPlex → Cloudflare → the box's tunnel (no Host trick, real DNS)."""
|
||||
a = ["curl", "-s", "--max-time", "20", "-o", "/dev/null", "-w", "%{http_code}"]
|
||||
for h in hdrs: a += ["-H", h]
|
||||
if cookie: a += ["-H", f"Cookie: {cookie}"]
|
||||
if data is not None: a += ["--data", data]
|
||||
return w.sh(a + [f"https://{host}{path}"]).stdout.strip()
|
||||
|
||||
|
||||
def lan(host, path="/"):
|
||||
return w.sh(["curl", "-sk", "--max-time", "15", "-o", "/dev/null", "-w", "%{http_code}", "-H", f"Host: {host}", f"{w.BASE}{path}"]).stdout.strip()
|
||||
|
||||
|
||||
def gate_files():
|
||||
return w.guest("ls /opt/docker/stacks/traefik/dynamic/ | grep -E 'family-gate|setup-gate' | tr '\\n' ' '").strip() or "none"
|
||||
|
||||
|
||||
def deploy(app, sub):
|
||||
code, d = w.ctl("GET", f"/api/stacks/{app}/deploy-fields")
|
||||
fields = (((d.get("data") or {}).get("metadata") or {}).get("deploy_fields")) or []
|
||||
values = {"DOMAIN": DOM, "SUBDOMAIN": sub}
|
||||
for f in fields:
|
||||
ev, ty = f.get("env_var"), f.get("type")
|
||||
if ev in values or (not f.get("required") and ty != "password"):
|
||||
continue
|
||||
if ty == "path":
|
||||
values[ev] = DRIVE
|
||||
elif ty in ("secret", "password"):
|
||||
values[ev] = "Demo-" + secrets.token_hex(12)
|
||||
else:
|
||||
values[ev] = f.get("default") or f"demo-{app}"
|
||||
code, d = w.ctl("POST", f"/api/stacks/{app}/deploy", {"values": values})
|
||||
say(app, f"deploy {app} (fields beyond DOMAIN/SUBDOMAIN: {[k for k in values if k not in ('DOMAIN', 'SUBDOMAIN')]}, values not printed) -> {code} {str(d)[:100]}")
|
||||
say(app, " gate files right after the press:", gate_files())
|
||||
t0 = time.time()
|
||||
for _ in range(120):
|
||||
time.sleep(5)
|
||||
st = w.stack(app)
|
||||
if st.get("deployed") and (st.get("app_config") or {}).get("pinned_images") and st.get("state") in ("running", "degraded", "unhealthy"):
|
||||
break
|
||||
say(app, f" deployed in {round(time.time()-t0)} s: state={st.get('state')} pinned={(st.get('app_config') or {}).get('pinned_images')}")
|
||||
say(app, " family_gate record:", " ".join(w.guest(f"grep -A4 '^family_gate:' /opt/docker/stacks/{app}/app.yaml").split()))
|
||||
|
||||
|
||||
w.login()
|
||||
say(None, f"##### B4 on demo-hp 9201 — controller {w.guest('docker inspect felhom-controller --format {{.Config.Image}}').strip()} | catalog "
|
||||
+ w.guest("cd /opt/docker/felhom-controller/data/catalog-cache 2>/dev/null || cd /var/lib/docker/volumes/felhom-controller-data/_data/data/catalog-cache; git log --oneline -1").strip()[:90]
|
||||
+ f" | {time.strftime('%FT%TZ', time.gmtime())}")
|
||||
say(None, "before: gate files:", gate_files(), "| drive:", " ".join(w.guest(f"df -h {DRIVE} | tail -1").split()))
|
||||
say(None, "the public names resolve to:", w.sh(["getent", "hosts", f"video.{DOM}"]).stdout.strip(), "(Cloudflare — the REAL internet path)")
|
||||
# a test family member through the Család card (the card's own call)
|
||||
sess = open(f"{w.SC}/sess{os.getpid()}.txt").read().strip(); csrf = open(f"{w.SC}/csrf{os.getpid()}.txt").read().strip()
|
||||
r = subprocess.run(["curl", "-sk", "-H", f"Host: {CTL}", "-H", f"Cookie: {sess}", "-H", f"X-CSRF-Token: {csrf}", "-X", "POST", "--data", "name=b4teszt",
|
||||
f"{w.BASE}/family/members/add"], capture_output=True, text=True)
|
||||
dd = json.loads(r.stdout); fpw = dd["data"]["password"]
|
||||
open(f"{w.SC}/b4fam.json", "w").write(json.dumps({"b4teszt": fpw})); os.chmod(f"{w.SC}/b4fam.json", 0o600)
|
||||
say(None, f"Család card: add b4teszt -> ok={dd['ok']} (password returned once, len {len(fpw)}, not printed)")
|
||||
|
||||
toks = {}
|
||||
for app, (sub, fx) in APPS.items():
|
||||
deploy(app, sub)
|
||||
if app == "grimmory":
|
||||
w.wait_app(sub, "/api/v1/healthcheck", want=("200",), tries=90)
|
||||
pw = "Gm-" + secrets.token_hex(10)
|
||||
rc, code, _ = w.app_curl(sub, "/api/v1/setup", "-H", "Content-Type: application/json",
|
||||
data=json.dumps({"username": "admin", "password": pw, "email": "admin@felhom.invalid", "name": "Felhom"}), method="POST")
|
||||
say(app, "the household makes the first admin through the setup gate ->", code)
|
||||
for i in range(30):
|
||||
if "setup-gate-grimmory" not in gate_files(): break
|
||||
time.sleep(5)
|
||||
say(app, f" setup gate opened by its probe after ~{5*i} s; gate files: {gate_files()}")
|
||||
code, tok = fx._token(w, sub, "admin", pw)
|
||||
auth = ["-H", f"Authorization: Bearer {tok}"]
|
||||
rc, c, out = w.app_curl(sub, "/api/v1/libraries", *auth, "-H", "Content-Type: application/json",
|
||||
data=json.dumps({"name": "Konyvek", "icon": "book", "iconType": "LUCIDE", "paths": [{"path": "/books"}], "watch": True,
|
||||
"metadataSource": "EMBEDDED", "organizationMode": "BOOK_PER_FILE"}), method="POST")
|
||||
lib = json.loads(out); title = "Felhom Demo " + secrets.token_hex(4)
|
||||
import tempfile
|
||||
fn = tempfile.mktemp(suffix=".epub"); open(fn, "wb").write(fx._epub(title))
|
||||
rc, c, _ = w.app_curl(sub, "/api/v1/files/upload", *auth, "-F", f"file=@{fn};type=application/epub+zip",
|
||||
"-F", f"libraryId={lib['id']}", "-F", f"pathId={lib['paths'][0]['id']}", method="POST"); os.unlink(fn)
|
||||
toks[app] = {"user": "admin", "pw": pw, "title": title}
|
||||
say(app, "a book uploaded ->", c, "| read back:", fx.verify(w, sub, toks[app], lambda *a: say(app, *a)))
|
||||
else:
|
||||
toks[app] = fx.seed(w, sub, lambda *a: say(app, *a))
|
||||
say(app, "the seed reads back:", fx.verify(w, sub, toks[app], lambda *a: say(app, *a)) if toks[app] else "NO SEED")
|
||||
say(app, "on the drive:", " | ".join(w.guest(f"find {DRIVE} -path '*{app}*' -type f \\( -name '*.epub' -o -name '*.mp4' \\) 2>/dev/null | head -3").split("\n")).strip())
|
||||
# a STRANGER through the real internet and the LAN
|
||||
paths = ["/", "/api/v1/books", "/api/v1/opdsx", "/api/v1/opds"] if app == "grimmory" else ["/", "/history", "/socket.io/?EIO=4&transport=polling"]
|
||||
for p in paths:
|
||||
say(app, f"a STRANGER {p:40s} internet {internet(f'{sub}.{DOM}', p)} | LAN {lan(f'{sub}.{DOM}', p)}")
|
||||
|
||||
# the family member signs in through the REAL internet (the box's own page), then reaches both apps
|
||||
import http.cookiejar, urllib.request, urllib.parse, ssl
|
||||
cj = http.cookiejar.CookieJar()
|
||||
op = urllib.request.build_opener(urllib.request.HTTPCookieProcessor(cj))
|
||||
def get(url, data=None):
|
||||
try:
|
||||
r = op.open(urllib.request.Request(url, data=data, headers={"Accept": "text/html"}), timeout=30)
|
||||
return r.status, r.geturl(), r.read().decode("utf-8", "replace")
|
||||
except urllib.error.HTTPError as e:
|
||||
return e.code, url, e.read().decode("utf-8", "replace")
|
||||
for app, (sub, fx) in APPS.items():
|
||||
st, url, body = get(f"https://{sub}.{DOM}/")
|
||||
m = re.search(r'name="_ft" value="([^"]+)"', body)
|
||||
if m and "/__family/login" in url:
|
||||
form = {"_ft": m.group(1), "name": "b4teszt", "password": fpw}
|
||||
for k in re.findall(r'<input type="hidden" name="([^"]+)" value="[^"]*"', body):
|
||||
if k not in form:
|
||||
import html as _h
|
||||
form[k] = _h.unescape(re.search(rf'name="{re.escape(k)}" value="([^"]*)"', body).group(1))
|
||||
st, url, body = get(url.split("?")[0].replace("/__family/start", "/__family/login"), urllib.parse.urlencode(form).encode())
|
||||
say(app, f"the family member b4teszt through the REAL internet: the app's address → the family sign-in → back: {st} at {urllib.parse.urlsplit(url).netloc}{urllib.parse.urlsplit(url).path} "
|
||||
f"(the app's own page: {'Grimmory' in body or 'MeTube' in body})")
|
||||
|
||||
for app, (sub, fx) in APPS.items():
|
||||
w.ctl("POST", f"/api/stacks/{app}/stop")
|
||||
for _ in range(24):
|
||||
time.sleep(5)
|
||||
if w.stack(app).get("state") != "running": break
|
||||
code, d = w.ctl("POST", f"/api/stacks/{app}/remove", {"remove_hdd_data": True, "remove_backups": True})
|
||||
say(app, f"2.6 remove WITH data and backups -> {code} {str(d)[:300]}")
|
||||
time.sleep(8)
|
||||
left = w.guest(f"docker ps -a --format '{{{{.Names}}}}' | grep -E '^{app}'; docker volume ls -q | grep -i {app}; "
|
||||
f"find {DRIVE} -path '*{app}*' \\( -name '*.epub' -o -name '*.mp4' -o -name '*.sql' \\) 2>/dev/null | head; "
|
||||
f"ls -d {DRIVE}/*/{app} {DRIVE}/*/*/{app} 2>/dev/null").strip()
|
||||
say(app, f" left after: {' | '.join(left.splitlines()) or 'nothing (no container, no volume, no file of the app on the drive)'}")
|
||||
say(app, " gate files:", gate_files(), f"| a stranger at {sub}/ -> internet {internet(f'{sub}.{DOM}')} | LAN {lan(f'{sub}.{DOM}')}")
|
||||
r = subprocess.run(["curl", "-sk", "-H", f"Host: {CTL}", "-H", f"Cookie: {open(f'{w.SC}/sess{os.getpid()}.txt').read().strip()}",
|
||||
"-H", f"X-CSRF-Token: {open(f'{w.SC}/csrf{os.getpid()}.txt').read().strip()}", "-X", "POST", "--data", "name=b4teszt",
|
||||
f"{w.BASE}/family/members/remove"], capture_output=True, text=True)
|
||||
say(None, "Család card: remove b4teszt ->", json.loads(r.stdout).get("ok"), "| members now:", json.loads(r.stdout).get("data", {}).get("members"))
|
||||
os.unlink(f"{w.SC}/b4fam.json")
|
||||
say(None, "after: gate files:", gate_files(), "| stacks:", w.guest("docker ps --format '{{.Names}}' | grep -c -E '^(grimmory|metube)' || true").strip())
|
||||
@@ -0,0 +1,53 @@
|
||||
#!/usr/bin/env python3
|
||||
"""fg_grim_mem.py — Grimmory's memory rows on 9202 (checklist 5.2 burst, 5.4 self-sizing), behind the family gate.
|
||||
5.2: the household's heaviest ordinary act — a burst of book uploads (40 EPUBs through the app's own upload API, the
|
||||
library re-reading each) — while grimmory's own cgroup is sampled every second (anon, oom_kill, restarts).
|
||||
5.4: does the heap size itself from the limit? The image's JAVA_TOOL_OPTIONS carry MaxRAMPercentage=60; the JVM's own
|
||||
answer (MaxHeapSize) is read at three container limits with the SAME image and options (`docker run --rm -m`, no app).
|
||||
Evidence: $EV/B/box/grim-mem.txt."""
|
||||
import json, os, secrets, subprocess, sys, tempfile, threading, time
|
||||
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
||||
from fg import * # noqa
|
||||
import upgrade_fixtures_box as fixtures
|
||||
GM = fixtures.FIXTURES["grimmory"]
|
||||
EVD = f"{w.EV}/B/box"; log = open(f"{EVD}/grim-mem.txt", "a", buffering=1)
|
||||
def say(*a):
|
||||
w.say(*a); log.write(" ".join(map(str, a)) + "\n")
|
||||
w.login()
|
||||
t = json.load(open(w.SC + "/seed-tokens-fg.json"))["grimmory"]
|
||||
say(f"##### grimmory memory on 9202 — {time.strftime('%FT%TZ', time.gmtime())} | limit", w.guest("docker inspect grimmory --format '{{.HostConfig.Memory}}'").strip())
|
||||
w.guest("cat > /root/gm-s.sh <<'SEOF'\nid=$(docker ps -q --no-trunc --filter name=^grimmory$); cg=/sys/fs/cgroup/system.slice/docker-$id.scope; : > /root/gm-mem.csv\n"
|
||||
"while [ ! -f /root/gm-mem.stop ]; do echo \"$(date +%s),$(awk '$1==\"anon\"{print $2}' $cg/memory.stat),$(awk '$1==\"oom_kill\"{print $2}' $cg/memory.events),$(cat $cg/memory.max),$(docker inspect -f '{{.RestartCount}}' $id)\" >> /root/gm-mem.csv; sleep 1; done\nSEOF\n"
|
||||
"rm -f /root/gm-mem.stop; (nohup sh /root/gm-s.sh >/dev/null 2>&1 &)")
|
||||
time.sleep(5)
|
||||
code, tok = GM._token(w, "library", t["user"], t["pw"])
|
||||
auth = ["-H", f"Authorization: Bearer {tok}"]
|
||||
rc, code, out = w.app_curl("library", "/api/v1/libraries", *auth)
|
||||
lib = json.loads(out)[0]; lid, pid = lib["id"], lib["paths"][0]["id"]
|
||||
t0 = time.time(); codes = {}
|
||||
for i in range(40):
|
||||
fn = tempfile.mktemp(suffix=".epub"); open(fn, "wb").write(GM._epub(f"Felhom Burst {i:02d} " + secrets.token_hex(3)))
|
||||
rc, c, _ = w.app_curl("library", "/api/v1/files/upload", *auth, "-F", f"file=@{fn};type=application/epub+zip",
|
||||
"-F", f"libraryId={lid}", "-F", f"pathId={pid}", method="POST")
|
||||
os.unlink(fn); codes[c] = codes.get(c, 0) + 1
|
||||
say(f"5.2 burst: 40 EPUB uploads through the app's own API in {time.time()-t0:.1f} s: codes {codes}")
|
||||
n = 0
|
||||
for _ in range(36):
|
||||
rc, c, out = w.app_curl("library", "/api/v1/books", *auth)
|
||||
try: n = len(json.loads(out))
|
||||
except Exception: n = -1
|
||||
if n >= 41: break
|
||||
time.sleep(5)
|
||||
say(f" the library lists {n} books after the burst ({time.time()-t0:.0f} s from its start); sampling 120 s more")
|
||||
time.sleep(120)
|
||||
w.guest("touch /root/gm-mem.stop"); time.sleep(2)
|
||||
rows = [r.split(",") for r in w.guest("cat /root/gm-mem.csv").split() if r.count(",") == 4]
|
||||
lim = int(rows[0][3]); peak = max(int(r[1]) for r in rows)
|
||||
say(f"5.2 grimmory, {len(rows)} samples (1/s) across the burst: peak anon {peak/1048576:.1f} MiB = {100*peak/lim:.1f} % of {lim//1048576}M; "
|
||||
f"oom_kill {max(int(r[2]) for r in rows)}; restarts {max(int(r[4]) for r in rows)}")
|
||||
open(f"{EVD}/grim-mem-burst.csv", "w").write("epoch,anon,oom_kill,limit,restarts\n" + "\n".join(",".join(r) for r in rows) + "\n")
|
||||
w.guest("rm -f /root/gm-s.sh /root/gm-mem.csv /root/gm-mem.stop")
|
||||
img = w.guest("docker inspect grimmory --format '{{.Config.Image}}'").strip()
|
||||
for m in ("768m", "1024m", "1536m"):
|
||||
out = w.guest(f"docker run --rm -m {m} --memory-swap {m} --entrypoint java {img} -XX:+PrintFlagsFinal -version 2>/dev/null | grep -E ' MaxHeapSize | MaxRAMPercentage '")
|
||||
say(f"5.4 {img} at a {m} container limit (the image's own JAVA_TOOL_OPTIONS): " + " | ".join(" ".join(l.split()) for l in out.strip().splitlines()))
|
||||
@@ -0,0 +1,136 @@
|
||||
#!/usr/bin/env python3
|
||||
"""fg_items.py — the VERDICT's exit items 1–5 again, now THROUGH THE PRODUCT on 9202 (controller 0.287.0, no hand-made
|
||||
traefik files), plus the build's own rules (reset/remove end access, controller down = closed) and the cost."""
|
||||
import hashlib, json, os, re, statistics, subprocess, sys, time
|
||||
from fg import *
|
||||
SC = w.SC
|
||||
log = open(f"{w.EV}/items.txt", "a", buffering=1)
|
||||
def say(*a):
|
||||
w.say(*a); log.write(" ".join(map(str, a)) + "\n")
|
||||
w.login()
|
||||
fam = json.load(open(f"{SC}/fam.json")); gm = json.load(open(f"{SC}/gm.json"))
|
||||
GMH, MTH = f"library.{DOM}", f"video.{DOM}"
|
||||
say(f"##### exit items through the product — {time.strftime('%FT%TZ', time.gmtime())}")
|
||||
WS = ("Connection: Upgrade", "Upgrade: websocket", "Sec-WebSocket-Version: 13", "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==")
|
||||
cases = [(GMH, "GET", "/", ("Accept: text/html",), None), (GMH, "GET", "/", (), None), (GMH, "GET", "/api/v1/books", (), None),
|
||||
(GMH, "GET", "/api/v1/healthcheck", (), None), (GMH, "POST", "/api/v1/setup", ("Content-Type: application/json",), '{"username":"x","password":"Stranger-1234"}'),
|
||||
(GMH, "POST", "/api/v1/auth/login", ("Content-Type: application/json",), '{"username":"admin","password":"guess"}'),
|
||||
(GMH, "GET", "/ws/websocket", WS, None), (GMH, "GET", "/api/v1/opdsx", (), None), (GMH, "GET", "/api/v1/opds-evil", (), None),
|
||||
(GMH, "GET", "/api/v1/opds/../../api/v1/books", ("X-Path: as-is",), None), (GMH, "GET", "/no-such-page", ("Accept: text/html",), None),
|
||||
(MTH, "GET", "/", ("Accept: text/html",), None), (MTH, "GET", "/", (), None), (MTH, "GET", "/history", (), None),
|
||||
(MTH, "POST", "/add", ("Content-Type: application/json",), '{"url":"https://example.com/v","quality":"best"}'),
|
||||
(MTH, "GET", "/socket.io/?EIO=4&transport=polling", (), None), (MTH, "GET", "/socket.io/?EIO=4&transport=websocket", WS, None),
|
||||
(MTH, "GET", "/download/x.mp4", (), None)]
|
||||
say("## item 1 — a STRANGER (no cookie), LAN and simulated tunnel")
|
||||
apps = 0
|
||||
for host, m, p, h, d in cases:
|
||||
extra = ["--path-as-is"] if "as-is" in " ".join(h) else []
|
||||
c, hh, b = lan(host, p, *extra, method=m, data=d, hdrs=h)
|
||||
tc, th, tb = tun(host, p, "198.51.100.66", None, *extra, "-X", m, *sum([["-H", x] for x in h], []), *(["--data", d] if d else []))
|
||||
g1, g2 = is_gate(c, hh, b), is_gate(tc, th, tb)
|
||||
apps += (not g1) + (not g2)
|
||||
say(f" {host.split('.')[0]:8s} {m:4s} {p:40s} LAN {c} {'GATE' if g1 else 'APP!'} | tunnel {tc} {'GATE' if g2 else 'APP!'}")
|
||||
say(f"item 1: {apps} app answers of {2*len(cases)} -> {'PASS' if apps == 0 else 'FAIL'}")
|
||||
|
||||
say("## item 2 — family members, their OWN logins, through the product's sign-in page")
|
||||
c, sess, h, b = family_login("anna", fam["anna"])
|
||||
ma = re.search(r"(?i)max-age=(\d+)", h); path = re.search(r"(?i)path=([^;\n]+)", h)
|
||||
say(f" anna signs in on {CTL}/__family/login: {c}; felhom_family {'set' if sess else 'NONE'}; Max-Age {int(ma.group(1))//86400 if ma else '?'} d; Path={path.group(1).strip() if path else '?'}; dashboard cookie set: {'felhom_session=' in h}")
|
||||
ga = app_cookie("library", sess)[0]; mb_s = family_login("bela", fam["bela"])[1]; mt = app_cookie("video", mb_s)[0]
|
||||
for host, ck, p, hh in ((GMH, ga, "/", ("Accept: text/html",)), (GMH, ga, "/api/v1/healthcheck", ()), (MTH, mt, "/", ()),
|
||||
(MTH, mt, "/socket.io/?EIO=4&transport=polling", ()), (MTH, mt, "/history", ())):
|
||||
c, h2, b2 = lan(host, p, cookie=ck, hdrs=hh)
|
||||
say(f" member GET {host.split('.')[0]}{p} -> {c} {'GATE' if is_gate(c, h2, b2) else 'APP'}")
|
||||
c, h2, b2 = lan(MTH, "/socket.io/?EIO=4&transport=websocket", "--http1.1", cookie=mt, hdrs=WS, timeout=4)
|
||||
say(f" bela MeTube websocket upgrade -> {c} {'GATE' if is_gate(c, h2, b2) else 'APP'} {[l for l in h2.splitlines() if l.lower().startswith('upgrade')]}")
|
||||
c, h2, b2 = lan(GMH, "/", cookie=mt, hdrs=("Accept: text/html",))
|
||||
say(f" bela's MeTube cookie at Grimmory -> {c} {'GATE' if is_gate(c, h2, b2) else 'APP!'}")
|
||||
w.guest("docker restart felhom-controller >/dev/null; sleep 25")
|
||||
c, h2, b2 = lan(GMH, "/", cookie=ga, hdrs=("Accept: text/html",))
|
||||
say(f" after the CONTROLLER restarted, anna's Grimmory cookie -> {c} {'GATE' if is_gate(c, h2, b2) else 'APP (survived)'}")
|
||||
w.login()
|
||||
c, h2, b2 = lan(CTL, "/__family/logout", method="POST", cookie=sess)
|
||||
c2, h3, b3 = lan(GMH, "/", cookie=ga, hdrs=("Accept: text/html",))
|
||||
say(f" anna logs out ({c}) -> her Grimmory cookie {c2} {'GATE (refused)' if is_gate(c2, h3, b3) else 'APP! (still in)'}")
|
||||
|
||||
say("## item 3 — a stranger's guesses at the family sign-in lock only the stranger (simulated tunnel)")
|
||||
seq = [family_login("anna", f"guess-{i}", visitor_tunnel="198.51.100.66")[0] for i in range(1, 8)]
|
||||
say(f" stranger 198.51.100.66, 7 wrong for anna: {seq}")
|
||||
say(f" stranger with anna's RIGHT password while locked: {family_login('anna', fam['anna'], visitor_tunnel='198.51.100.66')[0]}")
|
||||
c, s2, h, b = family_login("anna", fam["anna"], visitor_tunnel="203.0.113.10")
|
||||
say(f" anna herself from 203.0.113.10 (tunnel), at once: {c}, session {'set' if s2 else 'NONE'}")
|
||||
c, s3, h, b = family_login("bela", fam["bela"])
|
||||
say(f" bela from the LAN, at once: {c}, session {'set' if s3 else 'NONE'}")
|
||||
say(" controller log:", w.guest("docker logs --since 2m felhom-controller 2>&1 | grep -E 'family sign-in' | tail -6"))
|
||||
|
||||
say("## item 4 — Grimmory's e-reader exceptions keep Grimmory's OWN login (no family cookie)")
|
||||
ha = app_cookie("library", w.dash_cookie() if hasattr(w, "dash_cookie") else dash_session())[0]
|
||||
c, h, b = lan(GMH, "/api/v1/auth/login", method="POST", cookie=ha, hdrs=("Content-Type: application/json",), data=json.dumps({"username": "admin", "password": gm["admin_pw"]}))
|
||||
tok = json.loads(b).get("accessToken"); A = ("Content-Type: application/json", f"Authorization: Bearer {tok}")
|
||||
opw, kpw = __import__("secrets").token_hex(8), __import__("secrets").token_hex(8)
|
||||
lan(GMH, "/api/v1/settings", method="PUT", cookie=ha, hdrs=A, data=json.dumps([{"name": "OPDS_SERVER_ENABLED", "value": True}]))
|
||||
lan(GMH, "/api/v2/opds-users", method="POST", cookie=ha, hdrs=A, data=json.dumps({"username": "olvaso", "password": opw}))
|
||||
c, h, b = lan(GMH, "/api/v1/kobo-settings/token", method="PUT", cookie=ha, hdrs=A); ktok = json.loads(b).get("token", "")
|
||||
lan(GMH, "/api/v1/koreader-users/me", method="PUT", cookie=ha, hdrs=A, data=json.dumps({"username": "korolvaso", "password": kpw}))
|
||||
lan(GMH, "/api/v1/koreader-users/me/sync?enabled=true", method="PATCH", cookie=ha, hdrs=A)
|
||||
say(" (setup as the household through the gate: OPDS on + an OPDS user, a Kobo token, a KOReader user — values not printed)")
|
||||
md5 = hashlib.md5(kpw.encode()).hexdigest()
|
||||
def row(label, path, *a, via="LAN", hd=(), timeout=40):
|
||||
c, h, b = lan(GMH, path, *a, hdrs=hd, timeout=timeout) if via == "LAN" else tun(GMH, path, "198.51.100.66", None, *a, *sum([["-H", x] for x in hd], []), timeout=timeout)
|
||||
say(f" {label:52s} {via:6s} -> {c} {'GATE' if is_gate(c, h, b) else 'app'} {b[:60].strip()!r}")
|
||||
row("OPDS, the OPDS user's own login", "/api/v1/opds", "-u", f"olvaso:{opw}")
|
||||
row("OPDS, the OPDS user's own login", "/api/v1/opds", "-u", f"olvaso:{opw}", via="tunnel")
|
||||
row("OPDS, a stranger with a wrong password", "/api/v1/opds", "-u", "olvaso:wrong", via="tunnel")
|
||||
row("OPDS, a stranger with nothing", "/api/v1/opds", via="tunnel")
|
||||
row("Kobo initialization, the device token", f"/api/kobo/{ktok}/v1/initialization")
|
||||
row("Kobo, a made-up token", "/api/kobo/0123456789abcdef/v1/library/sync", via="tunnel")
|
||||
row("KOReader sign-in, its own user + md5 key", "/api/koreader/users/auth", hd=("x-auth-user: korolvaso", f"x-auth-key: {md5}", "Accept: application/vnd.koreader.v1+json"))
|
||||
row("KOReader, a stranger's wrong key", "/api/koreader/users/auth", hd=("x-auth-user: korolvaso", "x-auth-key: 00000000000000000000000000000000", "Accept: application/vnd.koreader.v1+json"), via="tunnel")
|
||||
row("Komga API, a stranger with nothing", "/komga/api/v1/libraries", via="tunnel")
|
||||
row("look-alike /api/v1/opdsx (F1)", "/api/v1/opdsx", via="tunnel")
|
||||
row("look-alike /api/koreaderx", "/api/koreaderx/users/auth", via="tunnel")
|
||||
row("../ out of an exception", "/api/v1/opds/../../api/v1/books", "--path-as-is", via="tunnel")
|
||||
say("## R-775 re-measured — a stranger cannot reach Grimmory's web sign-in at all, so its 15-minute lock cannot be aimed from outside")
|
||||
seq = [tun(GMH, "/api/v1/auth/login", "198.51.100.66", None, "-X", "POST", "-H", "Content-Type: application/json", "--data", '{"username":"admin","password":"guess"}')[0] for _ in range(6)]
|
||||
c, h, b = lan(GMH, "/api/v1/auth/login", method="POST", cookie=ha, hdrs=("Content-Type: application/json",), data=json.dumps({"username": "admin", "password": gm["admin_pw"]}))
|
||||
say(f" stranger x6 at /api/v1/auth/login (tunnel): {seq} -> the household then signs in: {c}")
|
||||
|
||||
say("## item 5 — the family login and the box dashboard")
|
||||
c, s4, h, b = family_login("anna", fam["anna"])
|
||||
c1, h1, b1 = lan(CTL, "/launcher", cookie=f"{s4}; {ga}")
|
||||
c2, h2, b2 = lan(CTL, "/api/stacks", cookie=s4)
|
||||
c3, h3, b3 = lan(CTL, "/login", method="POST", data=f"password={fam['anna']}", hdrs=("Content-Type: application/x-www-form-urlencoded",))
|
||||
say(f" family cookies at /launcher -> {c1} {loc(h1)} | at /api/stacks -> {c2} | anna's family password at the dashboard login -> {c3}, session {'SET!' if 'felhom_session=' in h3 else 'none'}")
|
||||
|
||||
say("## reset and removal end access at the next request (every gated app)")
|
||||
c, s5, h, b = family_login("bela", fam["bela"]); g5 = app_cookie("library", s5)[0]; m5 = app_cookie("video", s5)[0]
|
||||
sess = dash_session(); csrf = open(f"{SC}/csrf{os.getpid()}.txt").read().strip()
|
||||
def card(action, name):
|
||||
r = subprocess.run(["curl", "-sk", "-H", f"Host: {CTL}", "-H", f"Cookie: {sess}", "-H", f"X-CSRF-Token: {csrf}", "-X", "POST",
|
||||
"--data", f"name={name}", f"{w.BASE}/family/members/{action}"], capture_output=True, text=True)
|
||||
return json.loads(r.stdout)
|
||||
d = card("reset", "bela"); fam["bela"] = d["data"]["password"]
|
||||
say(f" card: new password for bela -> ok={d['ok']}; bela's Grimmory cookie -> {lan(GMH, '/', cookie=g5, hdrs=('Accept: text/html',))[0]}, MeTube cookie -> {lan(MTH, '/', cookie=m5, hdrs=('Accept: text/html',))[0]} (302 = sent to sign in)")
|
||||
c, s6, h, b = family_login("bela", fam["bela"]); g6 = app_cookie("video", s6)[0]
|
||||
d = card("remove", "bela")
|
||||
say(f" card: remove bela -> ok={d['ok']} members={d['data']['members']}; bela's MeTube cookie -> {lan(MTH, '/', cookie=g6)[0]}; bela signs in again -> {family_login('bela', fam['bela'])[0]}")
|
||||
json.dump(fam, open(f"{SC}/fam.json", "w"))
|
||||
|
||||
say("## cost — the same request through the gated name, and straight at the container (60 pairs)")
|
||||
def t(cmd):
|
||||
r = subprocess.run(cmd, capture_output=True, text=True).stdout.split(); return r[0], float(r[1]) * 1000
|
||||
g, d = [], []
|
||||
for _ in range(60):
|
||||
c1, t1 = t(["curl", "-sk", "-o", "/dev/null", "-w", "%{http_code} %{time_total}", "-H", f"Host: {MTH}", "-H", f"Cookie: {mt}", f"{w.BASE}/version"])
|
||||
g.append(t1)
|
||||
ip = w.guest("docker inspect metube --format '{{range .NetworkSettings.Networks}}{{.IPAddress}} {{end}}'").split()[0]
|
||||
dd = w.guest(f"for i in $(seq 1 60); do curl -s -o /dev/null -w '%{{time_total}}\\n' http://{ip}:8081/version; done").split()
|
||||
say(f" gated (LAN→traefik→forwardAuth→app) median {statistics.median(g):.1f} ms, p90 {sorted(g)[54]:.1f} ms; the app straight (guest→container) median {statistics.median([float(x)*1000 for x in dd]):.1f} ms — the honest number is the gate's own: see the controller's forwardAuth timing below")
|
||||
say("## the controller DOWN — a gated app answers an error, never the app; an exception still reaches the app's own login")
|
||||
w.guest("docker stop felhom-controller >/dev/null")
|
||||
c1, h1, b1 = lan(MTH, "/", cookie=mt); c2, h2, b2 = lan(GMH, "/api/v1/books", cookie=ga); c3, h3, b3 = lan(GMH, "/api/v1/opds", "-u", "olvaso:wrong")
|
||||
say(f" controller stopped: MeTube with a member cookie -> {c1} {b1[:40]!r}; Grimmory API -> {c2}; Grimmory OPDS exception (wrong password) -> {c3} (the app's own refusal)")
|
||||
w.guest("docker start felhom-controller >/dev/null; sleep 25")
|
||||
w.login()
|
||||
c1, h1, b1 = lan(MTH, "/", cookie=mt)
|
||||
say(f" controller back: MeTube with bela's earlier cookie (bela was removed) -> {c1} {'GATE' if is_gate(c1,h1,b1) else 'APP'}")
|
||||
@@ -0,0 +1,299 @@
|
||||
#!/usr/bin/env python3
|
||||
"""fg_life.py <phase> — Grimmory's and MeTube's record rows on scratch 9202 (drill catalog, controller 0.287.0), behind the
|
||||
family gate, through the product's own endpoints. The family gate is passed as the household (box_walk.family_cookie);
|
||||
strangers go through traefik with no cookie. Secrets never printed; seed tokens in a 0600 scratch file. Env: SC, EV.
|
||||
|
||||
grim-seed — Grimmory: a library + a real EPUB through its own API (the admin the household made at setup), read back.
|
||||
metube-fresh — MeTube removed (with its data), the DRILL template moved back to 2026.09.28, a FRESH install with the
|
||||
memory sampler and a stranger's poll from the press; the seed (a download) and its read-back; checks.
|
||||
metube-step — the product's guarded Update 2026.09.28 -> 2026.09.29 (drill ladder entry), the download read back.
|
||||
life — the night chain; both apps removed KEEPING backups (family-gate files go); the restore button for each;
|
||||
the seeds read back; the family-gate files and the stranger's refusal come back (the R-773 lesson).
|
||||
final — both removed WITH their data and backups; nothing left.
|
||||
Evidence: $EV/B/box/<phase>.txt (+ mem-metube.csv, poll-metube.txt, box-verdict-metube.json)."""
|
||||
import json, os, re, secrets, subprocess, sys, time
|
||||
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
||||
from fg import * # noqa: F401,F403 (lan, tun, w, DOM, CTL)
|
||||
import upgrade_fixtures_box as fixtures
|
||||
|
||||
phase = sys.argv[1]
|
||||
EVD = f"{w.EV}/B/box"; os.makedirs(EVD, exist_ok=True)
|
||||
TOK = w.SC + "/seed-tokens-fg.json"
|
||||
D = "/mnt/5_hdd/felhom.eu/drill/app-catalog-drill"
|
||||
SAMPLER = open("/mnt/5_hdd/felhom.eu/git/felhom.eu/documentation/audits/new-apps-2026-10-01/tools/sampler.sh").read()
|
||||
log = open(f"{EVD}/{phase}.txt", "a", buffering=1)
|
||||
GM, MT = fixtures.FIXTURES["grimmory"], fixtures.FIXTURES["metube"]
|
||||
APPS = {"grimmory": ("library", GM), "metube": ("video", MT)}
|
||||
|
||||
|
||||
def say(*a):
|
||||
w.say(*a); log.write(" ".join(map(str, a)) + "\n")
|
||||
|
||||
|
||||
def toks():
|
||||
return json.load(open(TOK)) if os.path.exists(TOK) else {}
|
||||
|
||||
|
||||
def save(t):
|
||||
json.dump(t, open(TOK, "w")); os.chmod(TOK, 0o600)
|
||||
|
||||
|
||||
def stranger(sub, path="/"):
|
||||
c1 = lan(f"{sub}.{DOM}", path)[0]
|
||||
c2 = tun(f"{sub}.{DOM}", path, "198.51.100.77")[0]
|
||||
return f"LAN {c1} | tunnel {c2}"
|
||||
|
||||
|
||||
def gate_files():
|
||||
return w.guest("ls /opt/docker/stacks/traefik/dynamic/ | grep -E 'family-gate|setup-gate' | tr '\\n' ' '").strip() or "none"
|
||||
|
||||
|
||||
def ctlver():
|
||||
return w.guest("docker inspect felhom-controller --format {{.Config.Image}}").strip()
|
||||
|
||||
|
||||
def drill_set_metube(ref, entry=None):
|
||||
subprocess.run(["git", "-C", D, "pull", "-q", "--rebase", "origin", "main"], check=True)
|
||||
comp, fy = f"{D}/templates/metube/docker-compose.yml", f"{D}/templates/metube/.felhom.yml"
|
||||
s = re.sub(r"(image:\s*)ghcr\.io/alexta69/metube:\S+", r"\g<1>" + ref, open(comp).read())
|
||||
open(comp, "w").write(s)
|
||||
if entry:
|
||||
f = open(fy).read()
|
||||
f = (f.rstrip("\n") + "\n - " + json.dumps(entry) + "\n") if "update_ladder:" in f else (f.rstrip("\n") + "\nupdate_ladder:\n - " + json.dumps(entry) + "\n")
|
||||
open(fy, "w").write(f)
|
||||
if subprocess.run(["git", "-C", D, "diff", "--quiet"]).returncode == 0:
|
||||
say(f"drill: already pins {ref} — nothing to commit")
|
||||
return
|
||||
subprocess.run(["git", "-C", D, "commit", "-q", "-am", f"DRILL metube: {ref} (box proof, family gate 2026-10-02)"], check=True)
|
||||
subprocess.run(["git", "-C", D, "push", "-q", "origin", "main"], check=True, capture_output=True)
|
||||
say("drill:", subprocess.run(["git", "-C", D, "log", "--oneline", "-1"], capture_output=True, text=True).stdout.strip())
|
||||
|
||||
|
||||
def remove(app, data):
|
||||
w.ctl("POST", f"/api/stacks/{app}/stop")
|
||||
for _ in range(24):
|
||||
time.sleep(5)
|
||||
if w.stack(app).get("state") != "running":
|
||||
break
|
||||
code, d = w.ctl("POST", f"/api/stacks/{app}/remove", {"remove_hdd_data": data, "remove_backups": data})
|
||||
say(f"remove {app} ({'WITH data and backups' if data else 'KEEPING data and backups'}) -> {code} {str(d)[:260]}")
|
||||
if data and code == "409":
|
||||
# R-442's fail-closed guard: 9202 has no agent (`/api/disks` -> agent not configured), so the drive path never
|
||||
# resolves and "remove with data" is REFUSED, the app kept. Measured here, then the household's other choice is
|
||||
# taken and this harness tidies ITS OWN test folder by name (scratch guest; the with-data half is a demo-box row).
|
||||
code, d = w.ctl("POST", f"/api/stacks/{app}/remove", {"remove_hdd_data": False, "remove_backups": True})
|
||||
say(f" refused (R-442, no agent on 9202) — remove {app} KEEPING drive data -> {code} {str(d)[:200]}")
|
||||
w.guest(f"rm -rf /mnt/felhom-drives/scratch_hdd/userdata/{app}")
|
||||
say(f" the harness removed its own test folder /mnt/felhom-drives/scratch_hdd/userdata/{app} by hand")
|
||||
time.sleep(6)
|
||||
left = w.guest(f"ls -d /opt/docker/stacks/{app} 2>/dev/null; docker ps -a --format '{{{{.Names}}}}' | grep -E '^{app}'; "
|
||||
f"docker volume ls -q | grep -i {app}; ls -d /mnt/felhom-drives/*/userdata/{app} 2>/dev/null").strip()
|
||||
say(f" left after: {' | '.join(left.splitlines()) or 'nothing'}")
|
||||
return code
|
||||
|
||||
|
||||
w.login()
|
||||
say(f"##### {phase} on 9202 — controller {ctlver()} | catalog "
|
||||
+ w.guest("cd /var/lib/docker/volumes/felhom-controller-data/_data/data/catalog-cache && git log --oneline -1").strip()[:60]
|
||||
+ f" | {time.strftime('%FT%TZ', time.gmtime())}")
|
||||
|
||||
if phase == "grim-seed":
|
||||
t = toks()
|
||||
pw = json.load(open(f"{w.SC}/gm.json"))["admin_pw"]
|
||||
code, tok = GM._token(w, "library", "admin", pw)
|
||||
auth = ["-H", f"Authorization: Bearer {tok}"]
|
||||
rc, code, out = w.app_curl("library", "/api/v1/libraries", *auth, "-H", "Content-Type: application/json",
|
||||
data=json.dumps({"name": "Konyvek", "icon": "book", "iconType": "LUCIDE", "paths": [{"path": "/books"}],
|
||||
"watch": True, "metadataSource": "EMBEDDED", "organizationMode": "BOOK_PER_FILE"}), method="POST")
|
||||
lib = json.loads(out) if code in ("200", "201") else {}
|
||||
if not lib: # a library from an earlier run
|
||||
rc, code, out = w.app_curl("library", "/api/v1/libraries", *auth)
|
||||
lib = (json.loads(out) or [{}])[0]
|
||||
lid, pid = lib["id"], lib["paths"][0]["id"]
|
||||
title = "Felhom Csalad " + secrets.token_hex(4)
|
||||
import tempfile
|
||||
fn = tempfile.mktemp(suffix=".epub"); open(fn, "wb").write(GM._epub(title))
|
||||
rc, code, out = w.app_curl("library", "/api/v1/files/upload", *auth, "-F", f"file=@{fn};type=application/epub+zip",
|
||||
"-F", f"libraryId={lid}", "-F", f"pathId={pid}", method="POST")
|
||||
os.unlink(fn)
|
||||
say(f"grimmory: library {lid}, the household uploads an EPUB through its own API (behind the family gate) -> {code}")
|
||||
t["grimmory"] = {"user": "admin", "pw": pw, "title": title}
|
||||
save(t)
|
||||
say("grimmory: the seed reads back:", GM.verify(w, "library", t["grimmory"], say))
|
||||
say("2.2/2.8 the book on the household's drive:", " | ".join(w.guest(
|
||||
"find /mnt/felhom-drives -path '*userdata*grimmory*' -name '*.epub' 2>/dev/null | head -3").strip().splitlines()) or "NOT FOUND")
|
||||
say("2.7 sizes:", " ".join(w.guest("for v in $(docker volume ls -q | grep -i grimmory); do echo $v=$(du -sh $(docker volume inspect -f '{{.Mountpoint}}' $v) | cut -f1); done; "
|
||||
"du -sh /mnt/felhom-drives/*/userdata/grimmory 2>/dev/null").split()))
|
||||
|
||||
elif phase == "metube-fresh":
|
||||
if w.stack("metube").get("deployed"):
|
||||
remove("metube", True)
|
||||
drill_set_metube("ghcr.io/alexta69/metube:2026.09.28")
|
||||
w.sync_rescan()
|
||||
for _ in range(24):
|
||||
if "2026.09.28" in w.guest("grep image: /var/lib/docker/volumes/felhom-controller-data/_data/data/catalog-cache/templates/metube/docker-compose.yml"):
|
||||
break
|
||||
time.sleep(5); w.sync_rescan()
|
||||
say("the box's catalog now pins:", w.guest("grep image: /var/lib/docker/volumes/felhom-controller-data/_data/data/catalog-cache/templates/metube/docker-compose.yml").strip())
|
||||
say("guest swap:", " ".join(w.guest("free -m | grep -i swap").split()), "(the swap-0 venue for 5.1 is the bench)")
|
||||
w.guest(f"cat > /root/fg-sampler.sh <<'SEOF'\n{SAMPLER}\nSEOF\nrm -f /root/fg-mem-metube.csv.stop; "
|
||||
"(NAMES='metube' OUT=/root/fg-mem-metube.csv DUR=1500 nohup bash /root/fg-sampler.sh >/dev/null 2>&1 &)")
|
||||
w.guest(f"""cat > /root/fg-poll.sh <<'PEOF'
|
||||
out=/root/fg-poll-metube.txt; : > $out; t0=$(date +%s)
|
||||
while [ $(( $(date +%s) - t0 )) -lt 240 ]; do
|
||||
a=$(curl -sk --max-time 4 -o /dev/null -w '%{{http_code}}' -H 'Host: video.{DOM}' https://127.0.0.1/)
|
||||
b=$(curl -sk --max-time 4 -o /dev/null -w '%{{http_code}}' -H 'Host: video.{DOM}' -H 'Content-Type: application/json' -X POST --data '{{"url":"https://example.com/x.mp4"}}' https://127.0.0.1/add)
|
||||
echo "$(date +%H:%M:%S) $a $b" >> $out; sleep 1
|
||||
done
|
||||
PEOF
|
||||
(nohup sh /root/fg-poll.sh >/dev/null 2>&1 &)""")
|
||||
t0 = time.time(); ok = w.deploy("metube", "video"); say(f"deploy metube -> {ok} ({round(time.time()-t0)} s to `deployed`)")
|
||||
say(" gate files right after the deploy:", gate_files())
|
||||
healthy = None
|
||||
for _ in range(150):
|
||||
h = w.guest("docker inspect -f '{{if .State.Health}}{{.State.Health.Status}}{{else}}nohc{{end}}' metube 2>/dev/null").strip()
|
||||
if h == "healthy":
|
||||
healthy = time.time() - t0; break
|
||||
time.sleep(2)
|
||||
say(f"4.3 healthy {round(healthy) if healthy else 'NEVER'} s after the press; restarts:",
|
||||
w.guest("docker inspect -f '{{.RestartCount}}' metube").strip(), "| state:", w.stack("metube").get("state"),
|
||||
"| image:", w.guest("docker inspect -f '{{.Config.Image}}' metube").strip())
|
||||
t = toks(); t["metube"] = MT.seed(w, "video", say); save(t)
|
||||
say("C1 the seed reads back:", MT.verify(w, "video", t["metube"], say) if t["metube"] else "NO SEED " + str(getattr(MT, "tried", "")))
|
||||
time.sleep(3); w.guest("pkill -f fg-poll.sh || true")
|
||||
poll = w.guest("cat /root/fg-poll-metube.txt").strip().splitlines()
|
||||
codes = {}
|
||||
for l in poll:
|
||||
k = " ".join(l.split(" ")[1:3]); codes[k] = codes.get(k, 0) + 1
|
||||
say(f"3.3/3.5 a stranger's {len(poll)} polls (GET / and POST /add, 1/s) from the press, no cookie: codes {codes}; "
|
||||
f"any app answer (200): {any(' 200' in l for l in poll)}")
|
||||
open(f"{EVD}/poll-metube.txt", "w").write("\n".join(poll) + "\n")
|
||||
say("2.2/2.8 where the download landed (the household's drive, browsable):", " | ".join(w.guest(
|
||||
"find /mnt/felhom-drives -path '*userdata*' -path '*metube*' -name '*.mp4' 2>/dev/null | head -3").strip().splitlines()) or "NOT FOUND",
|
||||
"| owner:", w.guest("find /mnt/felhom-drives -path '*userdata*' -path '*metube*' -name '*.mp4' -exec stat -c '%u:%g %a' {} \\; 2>/dev/null | head -1").strip())
|
||||
say("2.7 sizes:", " ".join(w.guest("for v in $(docker volume ls -q | grep -i metube); do echo $v=$(du -sh $(docker volume inspect -f '{{.Mountpoint}}' $v) | cut -f1); done; "
|
||||
"du -sh /mnt/felhom-drives/*/userdata/metube 2>/dev/null").split()))
|
||||
say("1.5 process:", w.guest("docker exec metube sh -c 'cat /proc/1/cmdline | tr \"\\000\" \" \"'").strip()[:200],
|
||||
"| children:", " ".join(w.guest("docker exec metube ps -eo user,comm 2>/dev/null | sort -u | head -8").split())[:200])
|
||||
rc, code, body = w.app_curl("video", "/felhom-no-such-page-xyz/")
|
||||
say(f"1.8 unknown page (a member): http={code} traceback={'Traceback' in body}")
|
||||
say("0.4 outbound connections held at rest:", " ".join(w.guest(
|
||||
"docker exec metube sh -c \"cat /proc/net/tcp /proc/net/tcp6 2>/dev/null\" | awk 'NR>1 && $4==\"01\"{print $3}' | sort -u | head -8").split()) or "none")
|
||||
say("0.4/0.5 hosts named in the first-start log:", sorted(set(re.findall(r"https?://([a-z0-9.-]+\.[a-z]{2,})", w.guest("docker logs metube 2>&1 | head -300"))))[:12])
|
||||
say("4.4 negative control: docker STOP metube — state before:", w.stack("metube").get("state"))
|
||||
w.guest("docker stop metube >/dev/null"); seen = []
|
||||
for i in range(12):
|
||||
time.sleep(5); s = w.stack("metube").get("state")
|
||||
if not seen or seen[-1][1] != s: seen.append((5 * (i + 1), s))
|
||||
say(f" states while stopped (s, state): {seen}; a member at / -> {w.app_curl('video', '/')[1]}")
|
||||
w.guest("docker start metube >/dev/null")
|
||||
for i in range(36):
|
||||
time.sleep(5)
|
||||
if w.stack("metube").get("state") == "running":
|
||||
say(f" running again {5*(i+1)} s after docker start"); break
|
||||
|
||||
elif phase == "metube-step":
|
||||
t = toks()
|
||||
before = (w.stack("metube").get("app_config") or {}).get("pinned_images")
|
||||
say(f"before: pinned={before}")
|
||||
entry = {"from": {"metube": "ghcr.io/alexta69/metube:2026.09.28"}, "to": {"metube": "ghcr.io/alexta69/metube:2026.09.29"},
|
||||
"verdict": "proven", "tested_at": "DRILL", "harness_version": 4, "evidence": "DRILL (box proof in progress)",
|
||||
"marks": {"files_may_change": False, "needs_person": None, "memory_tight": False}}
|
||||
drill_set_metube("ghcr.io/alexta69/metube:2026.09.29", entry)
|
||||
w.sync_rescan("metube", "ghcr.io/alexta69/metube:2026.09.29")
|
||||
since = w.guest("date -u +%Y-%m-%dT%H:%M:%SZ").strip()
|
||||
res = w.press_update("metube", poll=1, cap_s=1800)
|
||||
for p in res.get("phases", []):
|
||||
log.write(f" phase +{p['t']}s {p['phase']} | err={p['error']}\n")
|
||||
time.sleep(10)
|
||||
read = MT.verify(w, "video", t["metube"], say)
|
||||
log.write(w.guest(f"docker logs --since {since} felhom-controller 2>&1 | grep -E 'update metube' | grep -v DEBUG | cut -c1-300") + "\n")
|
||||
st = w.stack("metube"); after = (st.get("app_config") or {}).get("pinned_images")
|
||||
say(" gate files after the step:", gate_files(), "| a stranger at / ->", stranger("video"))
|
||||
verdict = {"app": "metube", "venue": f"box 9202 (drill catalog, controller {ctlver().rsplit(':', 1)[-1]}), the product's guarded Update",
|
||||
"from": before, "to": after,
|
||||
"verdict": "proven" if (res.get("final_phase") == "done" and read and (after or {}).get("metube") == "ghcr.io/alexta69/metube:2026.09.29") else "failed",
|
||||
"seed_read_before": True, "seed_read_after": read, "healthy_after": st.get("state") == "running",
|
||||
"duration_s": res.get("duration_s"), "final_phase": res.get("final_phase"), "measured_at": since,
|
||||
"evidence": "felhom.eu/documentation/audits/family-gate-2026-10-02/B/box/metube-step.txt"}
|
||||
json.dump(verdict, open(f"{EVD}/box-verdict-metube.json", "w"), indent=2)
|
||||
say(f"RESULT final_phase={res.get('final_phase')} after={after} seed_after={read} verdict={verdict['verdict']} ({res.get('duration_s')} s)")
|
||||
|
||||
elif phase == "grim-step":
|
||||
# 9202's Grimmory was installed at v3.4.1 (the drill template kept yesterday's FROM); step it to the published v3.5.0
|
||||
# through the product's guarded Update, behind the family gate, and read the seed back.
|
||||
t = toks()
|
||||
before = (w.stack("grimmory").get("app_config") or {}).get("pinned_images")
|
||||
say(f"before: pinned={before}")
|
||||
subprocess.run(["git", "-C", D, "pull", "-q", "--rebase", "origin", "main"], check=True)
|
||||
comp, fy = f"{D}/templates/grimmory/docker-compose.yml", f"{D}/templates/grimmory/.felhom.yml"
|
||||
src = open(comp).read() # read BEFORE opening for write — the one-line form truncated the file first (attempt 1)
|
||||
assert "grimmory:v3.4.1" in src, "drill compose is not at v3.4.1"
|
||||
open(comp, "w").write(src.replace("grimmory:v3.4.1", "grimmory:v3.5.0"))
|
||||
entry = {"from": {"grimmory": "ghcr.io/grimmory-tools/grimmory:v3.4.1", "grimmory-db": "mariadb:11.4"},
|
||||
"to": {"grimmory": "ghcr.io/grimmory-tools/grimmory:v3.5.0", "grimmory-db": "mariadb:11.4"},
|
||||
"verdict": "proven", "tested_at": "DRILL", "harness_version": 4, "evidence": "DRILL (box proof in progress)",
|
||||
"marks": {"files_may_change": False, "needs_person": None, "memory_tight": False}}
|
||||
f = open(fy).read()
|
||||
f = (f.rstrip("\n") + "\n - " + json.dumps(entry) + "\n") if "update_ladder:" in f else (f.rstrip("\n") + "\nupdate_ladder:\n - " + json.dumps(entry) + "\n")
|
||||
open(fy, "w").write(f)
|
||||
subprocess.run(["git", "-C", D, "commit", "-q", "-am", "DRILL grimmory: v3.5.0 (box step behind the family gate, 2026-10-02)"], check=True)
|
||||
subprocess.run(["git", "-C", D, "push", "-q", "origin", "main"], check=True, capture_output=True)
|
||||
say("drill:", subprocess.run(["git", "-C", D, "log", "--oneline", "-1"], capture_output=True, text=True).stdout.strip())
|
||||
w.sync_rescan("grimmory", "ghcr.io/grimmory-tools/grimmory:v3.5.0")
|
||||
res = w.press_update("grimmory", poll=1, cap_s=1800)
|
||||
for p in res.get("phases", []):
|
||||
log.write(f" phase +{p['t']}s {p['phase']} | err={p['error']}\n")
|
||||
time.sleep(10)
|
||||
read = GM.verify(w, "library", t["grimmory"], say)
|
||||
after = (w.stack("grimmory").get("app_config") or {}).get("pinned_images")
|
||||
say(" gate files after the step:", gate_files(), "| a stranger at / ->", stranger("library"),
|
||||
"| OPDS exception, a stranger ->", stranger("library", "/api/v1/opds"))
|
||||
say(f"RESULT final_phase={res.get('final_phase')} after={after} seed_after={read} ({res.get('duration_s')} s)")
|
||||
|
||||
elif phase == "life":
|
||||
t = toks()
|
||||
say("before: gate files:", gate_files())
|
||||
code, d = w.ctl("POST", "/api/debug/backup/night-chain"); say("2.5 the night chain (debug action) ->", code)
|
||||
for _ in range(120):
|
||||
if "finished in" in w.guest("docker logs --since 10m felhom-controller 2>&1 | grep 'night-chain\\] finished' | tail -1"):
|
||||
break
|
||||
time.sleep(5)
|
||||
say(" ", w.guest("docker logs --since 10m felhom-controller 2>&1 | grep 'night-chain\\] finished' | tail -1").strip()[:200])
|
||||
for app in APPS:
|
||||
say(f" {app} restore points:", [(s.get("id") or s.get("snapshot_id"), s.get("time") or s.get("created")) for s in w.snapshots(app)][:2])
|
||||
for app in APPS:
|
||||
remove(app, False)
|
||||
time.sleep(8)
|
||||
say("after both removes: gate files:", gate_files(), "| a stranger at library/ ->", stranger("library"), "| video/ ->", stranger("video"))
|
||||
for app, (sub, fx) in APPS.items():
|
||||
r = w.restore(app)
|
||||
say(f"2.5 restore {app}:", {k: r.get(k) for k in ("ok", "snapshot_id", "seconds", "state_after", "hold_after")})
|
||||
time.sleep(10)
|
||||
say("after both restores: gate files:", gate_files())
|
||||
say(" family_gate record:", " | ".join(" ".join(w.guest(f"grep -A4 '^family_gate:' /opt/docker/stacks/{a}/app.yaml").split()) for a in APPS))
|
||||
say(" a STRANGER (no cookie): library/ ->", stranger("library"), "| library/api/v1/books ->", stranger("library", "/api/v1/books"),
|
||||
"| video/ ->", stranger("video"), "| video/history ->", stranger("video", "/history"))
|
||||
for app, (sub, fx) in APPS.items():
|
||||
say(f"2.5 {app}: the seed reads back after remove + restore (a member, then the app's own login):", fx.verify(w, sub, t[app], say))
|
||||
|
||||
elif phase == "final":
|
||||
for app in APPS:
|
||||
remove(app, True)
|
||||
time.sleep(8)
|
||||
say("gate files:", gate_files())
|
||||
w.guest("touch /root/fg-mem-metube.csv.stop"); time.sleep(3)
|
||||
csv = w.guest("cat /root/fg-mem-metube.csv 2>/dev/null").strip().splitlines()
|
||||
if csv:
|
||||
open(f"{EVD}/mem-metube.csv", "w").write("epoch,name,id,anon,current,swap,oom_kill,limit,restarts\n" + "\n".join(csv) + "\n")
|
||||
per = {}
|
||||
for l in csv:
|
||||
p = l.split(",")
|
||||
if len(p) >= 9 and p[3].isdigit():
|
||||
d = per.setdefault((p[1], p[2]), {"anon": 0, "oom": 0, "lim": p[7], "n": 0})
|
||||
d["anon"] = max(d["anon"], int(p[3])); d["n"] += 1
|
||||
d["oom"] = max(d["oom"], int(p[6]) if p[6].isdigit() else 0)
|
||||
for (n, i), d in per.items():
|
||||
say(f"5.1 (box) {n} [{i}] {d['n']} samples: peak anon {d['anon']/1048576:.1f} MiB = "
|
||||
f"{100.0*d['anon']/int(d['lim']) if d['lim'].isdigit() else -1:.1f} % of the limit; oom_kill {d['oom']}")
|
||||
w.guest("rm -f /root/fg-sampler.sh /root/fg-poll.sh /root/fg-poll-metube.txt /root/fg-mem-metube.csv /root/fg-mem-metube.csv.stop")
|
||||
@@ -0,0 +1,37 @@
|
||||
#!/usr/bin/env python3
|
||||
"""fg_setup.py — on 9202 (controller 0.287.0, drill catalog): two family members through the dashboard's Család card
|
||||
(POST /family/members/add — the card's own call), then MeTube and Grimmory installed through the product, and Grimmory's
|
||||
first admin made by the household through the SETUP gate (it is setup-gated AND family-gated). Secrets → 0600 scratch."""
|
||||
import json, os, re, subprocess, sys, time
|
||||
from fg import *
|
||||
SC = w.SC
|
||||
log = open(f"{w.EV}/setup.txt", "a", buffering=1)
|
||||
def say(*a):
|
||||
w.say(*a); log.write(" ".join(map(str, a)) + "\n")
|
||||
w.login()
|
||||
say(f"##### family gate live setup on 9202 — controller {w.guest('docker inspect felhom-controller --format {{.Config.Image}}').strip()} | {time.strftime('%FT%TZ', time.gmtime())}")
|
||||
sess = dash_session(); csrf = open(f"{SC}/csrf{os.getpid()}.txt").read().strip()
|
||||
fam = {}
|
||||
for name in ("anna", "bela"):
|
||||
r = subprocess.run(["curl", "-sk", "-H", f"Host: {CTL}", "-H", f"Cookie: {sess}", "-H", f"X-CSRF-Token: {csrf}",
|
||||
"-X", "POST", "--data", f"name={name}", f"{w.BASE}/family/members/add"], capture_output=True, text=True)
|
||||
d = json.loads(r.stdout)
|
||||
fam[name] = d["data"]["password"]
|
||||
say(f"Család card: add {name} -> ok={d['ok']} members={d['data']['members']} password returned ONCE (len {len(fam[name])}, not printed)")
|
||||
r = subprocess.run(["curl", "-sk", "-H", f"Host: {CTL}", "-H", f"Cookie: {sess}", f"{w.BASE}/settings/security"], capture_output=True, text=True)
|
||||
say("the security page carries the card:", 'id="family-card"' in r.stdout, "| and no member password:", not any(p in r.stdout for p in fam.values()))
|
||||
json.dump(fam, open(f"{SC}/fam.json", "w")); os.chmod(f"{SC}/fam.json", 0o600)
|
||||
for app, sub in (("metube", "video"), ("grimmory", "library")):
|
||||
say(f"deploy {app} ->", w.deploy(app, sub))
|
||||
say(f" {app} family-gate file:", w.guest(f"ls /opt/docker/stacks/traefik/dynamic/ | grep -E 'family-gate-{app}|setup-gate-{app}' | tr '\\n' ' '"))
|
||||
w.wait_app("library", "/api/v1/healthcheck", want=("200",), tries=90)
|
||||
pw = "Gm-" + __import__("secrets").token_hex(10)
|
||||
c, h, b = lan(f"library.{DOM}", "/api/v1/setup", method="POST", cookie=w.gate_cookie("library"),
|
||||
hdrs=("Content-Type: application/json",), data=json.dumps({"username": "admin", "password": pw, "email": "admin@felhom.invalid", "name": "Felhom"}))
|
||||
say("grimmory: the household makes the first admin THROUGH THE SETUP GATE ->", c)
|
||||
json.dump({"admin_pw": pw}, open(f"{SC}/gm.json", "w")); os.chmod(f"{SC}/gm.json", 0o600)
|
||||
for i in range(40):
|
||||
files = w.guest("ls /opt/docker/stacks/traefik/dynamic/ | grep -E 'grimmory' | tr '\\n' ' '")
|
||||
if "setup-gate-grimmory" not in files: break
|
||||
time.sleep(5)
|
||||
say(f"grimmory: setup gate opened by its probe after ~{5*i} s; files now: {files}")
|
||||
@@ -0,0 +1,55 @@
|
||||
#!/usr/bin/env python3
|
||||
"""repoint.py drill|restore — point scratch guest 9202 at the DRILL catalog, or back at the live one (`09` §6.5; R-615:
|
||||
the cache directory goes too). Saved config: controller.yaml.pre-familygate1002. Three controls printed each way."""
|
||||
import io, re, subprocess, sys
|
||||
import walk as w
|
||||
VOL = "/var/lib/docker/volumes/felhom-controller-data/_data"
|
||||
SAVE = f"{VOL}/controller.yaml.pre-familygate1002"
|
||||
DRILL_REPO = "https://gitea.dooplex.hu/admin/app-catalog-drill.git"
|
||||
|
||||
|
||||
def creds():
|
||||
for l in io.open("/home/kisfenyo/.git-credentials").read().strip().split("\n"):
|
||||
m = re.match(r'https://(admin):([^@]+)@gitea\.dooplex\.hu', l)
|
||||
if m:
|
||||
return m.group(1), m.group(2)
|
||||
raise SystemExit("no admin credential")
|
||||
|
||||
|
||||
def controls(want):
|
||||
print("CONTROL 1 — the box's clone:", w.guest(f"cd {VOL}/data/catalog-cache && git log --oneline -1 && git remote get-url origin | sed 's#//[^@]*@#//#'").strip())
|
||||
print("CONTROL 2 — live main:", subprocess.run(["git", "ls-remote", "https://gitea.dooplex.hu/admin/app-catalog-felhom.eu.git", "refs/heads/main"], capture_output=True, text=True).stdout.split()[:1])
|
||||
print("CONTROL 3 — expected:", want)
|
||||
|
||||
|
||||
if sys.argv[1] == "drill":
|
||||
u, t = creds()
|
||||
print(w.guest(f"""
|
||||
set -e
|
||||
test -f {SAVE} || cp -p {VOL}/controller.yaml {SAVE}
|
||||
python3 - <<'PY'
|
||||
import re
|
||||
p = "{VOL}/controller.yaml"
|
||||
s = open(p).read()
|
||||
s = re.sub(r'(^\\s+repo_url: ).*$', r'\\g<1>{DRILL_REPO}', s, count=1, flags=re.M)
|
||||
s = re.sub(r'(^git:(?:\\n\\s+.*)*?\\n\\s+token: ).*$', r'\\g<1>"{t}"', s, count=1, flags=re.M)
|
||||
s = re.sub(r'(^git:(?:\\n\\s+.*)*?\\n\\s+username: ).*$', r'\\g<1>"{u}"', s, count=1, flags=re.M)
|
||||
open(p, "w").write(s)
|
||||
PY
|
||||
rm -rf {VOL}/catalog-cache {VOL}/data/catalog-cache
|
||||
docker restart felhom-controller >/dev/null
|
||||
sleep 20
|
||||
grep -A6 '^git:' {VOL}/controller.yaml | sed 's/token:.*/token: <redacted>/'
|
||||
"""))
|
||||
else:
|
||||
print(w.guest(f"""
|
||||
set -e
|
||||
cp -p {SAVE} {VOL}/controller.yaml
|
||||
rm -rf {VOL}/catalog-cache {VOL}/data/catalog-cache
|
||||
docker restart felhom-controller >/dev/null
|
||||
sleep 20
|
||||
grep -A6 '^git:' {VOL}/controller.yaml | sed 's/token:.*/token: <redacted>/'
|
||||
"""))
|
||||
w.login()
|
||||
w.sync_rescan()
|
||||
controls(sys.argv[1])
|
||||
@@ -0,0 +1,15 @@
|
||||
// The family sign-in page a stranger (or a member without a session) meets at a family-gated app (checklist 8.3, the
|
||||
// third screenshot of Grimmory and MeTube): headless Chrome through the box's own traefik, every name mapped to it.
|
||||
const puppeteer = require('puppeteer');
|
||||
const sleep = ms => new Promise(r => setTimeout(r, ms));
|
||||
(async () => {
|
||||
const b = await puppeteer.launch({args: ['--no-sandbox', '--ignore-certificate-errors', '--lang=' + (process.env.LANGX || 'hu-HU'),
|
||||
'--host-resolver-rules=MAP * ' + process.env.TRAEFIK]});
|
||||
const p = await b.newPage();
|
||||
await p.setViewport({width: 390, height: 844, deviceScaleFactor: 2});
|
||||
await p.goto(process.env.URL, {waitUntil: 'networkidle2'});
|
||||
await sleep(1500);
|
||||
console.log(p.url().replace(/\?.*/, '?…'));
|
||||
await p.screenshot({path: '/out/3.png'});
|
||||
await b.close();
|
||||
})().catch(e => { console.error(e); process.exit(1); });
|
||||
@@ -0,0 +1,23 @@
|
||||
// Screenshots of Grimmory's own web UI (checklist 8.3): on scratch guest 9202, through traefik over https as a browser
|
||||
// does (headless Chrome), signed in as the test household account.
|
||||
const puppeteer = require('puppeteer');
|
||||
const sleep = ms => new Promise(r => setTimeout(r, ms));
|
||||
(async () => {
|
||||
const b = await puppeteer.launch({args: ['--no-sandbox', '--ignore-certificate-errors', '--lang=hu-HU']});
|
||||
const p = await b.newPage();
|
||||
await p.setViewport({width: 1280, height: 800});
|
||||
await p.goto(process.env.URL + '/login', {waitUntil: 'networkidle2'});
|
||||
await sleep(1500);
|
||||
await p.screenshot({path: '/out/3.png'});
|
||||
const user = await p.$('input[type=text], input[name=username], input[formcontrolname=username]');
|
||||
if (user) await user.type(process.env.U);
|
||||
await p.type('input[type=password]', process.env.P);
|
||||
await p.keyboard.press('Enter');
|
||||
await p.waitForNavigation({waitUntil: 'networkidle2', timeout: 30000}).catch(() => {});
|
||||
await sleep(5000);
|
||||
await p.screenshot({path: '/out/1.png'});
|
||||
await p.setViewport({width: 390, height: 844, deviceScaleFactor: 2});
|
||||
await sleep(2500);
|
||||
await p.screenshot({path: '/out/2.png'});
|
||||
await b.close();
|
||||
})().catch(e => { console.error(e); process.exit(1); });
|
||||
@@ -0,0 +1,16 @@
|
||||
// Screenshots of MeTube's own web UI (checklist 8.3): on scratch guest 9202, headless Chrome on the app's own network
|
||||
// (the family gate is in front of the public name; the picture is of the app). One download already in the history.
|
||||
const puppeteer = require('puppeteer');
|
||||
const sleep = ms => new Promise(r => setTimeout(r, ms));
|
||||
(async () => {
|
||||
const b = await puppeteer.launch({args: ['--no-sandbox', '--lang=hu-HU']});
|
||||
const p = await b.newPage();
|
||||
await p.setViewport({width: 1280, height: 800});
|
||||
await p.goto(process.env.URL + '/', {waitUntil: 'networkidle2'});
|
||||
await sleep(3000);
|
||||
await p.screenshot({path: '/out/1.png'});
|
||||
await p.setViewport({width: 390, height: 844, deviceScaleFactor: 2});
|
||||
await sleep(2500);
|
||||
await p.screenshot({path: '/out/2.png'});
|
||||
await b.close();
|
||||
})().catch(e => { console.error(e); process.exit(1); });
|
||||
@@ -0,0 +1,7 @@
|
||||
"""walk.py — this session's shim over the catalog's box client (app-catalog-felhom.eu/scripts/box_walk.py), so the
|
||||
earlier nights' boxmove/boxstep shape works unchanged. SC (0600 scratch, `.ctlpw`) and EV come from the environment."""
|
||||
import sys
|
||||
sys.path.insert(0, "/mnt/5_hdd/felhom.eu/git/app-catalog-felhom.eu/scripts")
|
||||
from box_walk import * # noqa: F401,F403
|
||||
import box_walk as _b
|
||||
SC, EV, GENERATED = _b.SC, _b.EV, _b.GENERATED
|
||||
@@ -0,0 +1,54 @@
|
||||
# Draft — a request to SparkyFitness's author for written permission (decision 65) — NOT SENT
|
||||
|
||||
**Status: a draft for the operator. Nothing was sent.** The operator reads it, changes it, and sends it from their own
|
||||
account if they agree.
|
||||
|
||||
## Where to send it — the contact route, read 2026-10-02
|
||||
|
||||
- The licence's last section says: *"For commercial use, licensing, or partnership inquiries, please contact the author:
|
||||
https://github.com/codewithcj"* (`LICENSE` on `main`, read 2026-10-02).
|
||||
- That GitHub profile shows **no e-mail address, no website, no social link** (GitHub API `users/CodeWithCJ`: `email`,
|
||||
`blog`, `twitter_username` all empty).
|
||||
- The repository has **GitHub Discussions switched on**, a project site (`codewithcj.github.io/SparkyFitness`) and a
|
||||
**Discord** server linked from the README.
|
||||
- So there is no private e-mail route. Two routes exist: (1) a GitHub Discussion in the repository (public), or (2) a
|
||||
direct message to the author on the project's Discord (private). **Recommendation: (2) first** — a licence question about
|
||||
money is better asked privately; open a Discussion only if there is no answer in two weeks.
|
||||
|
||||
## The text
|
||||
|
||||
> **Subject:** Permission to offer SparkyFitness in a paid home-server service (Felhom, Hungary)
|
||||
>
|
||||
> Hello CJ,
|
||||
>
|
||||
> I run Felhom, a small service in Hungary. We set up and look after home servers for families. Each family owns its box,
|
||||
> and it stands in their home. The family chooses apps from our catalogue, and we install and update them for a monthly
|
||||
> fee.
|
||||
>
|
||||
> SparkyFitness is in our catalogue. We like it a lot. It is the best family health tracker we tested.
|
||||
>
|
||||
> We read your licence. It says that use in a service for money needs your written permission. Our fee is for the box and
|
||||
> our care, not for SparkyFitness itself. But we think this is still the kind of use your licence asks about, so we ask
|
||||
> you first.
|
||||
>
|
||||
> What we do:
|
||||
> - We pull your official Docker images, unchanged. We do not fork, rebrand or resell the software.
|
||||
> - Each family's copy runs only on their own box, for their own household.
|
||||
> - We keep your name, licence and links in the app's description.
|
||||
> - We have no paying customers yet. We will not offer SparkyFitness to a paying customer without your answer.
|
||||
>
|
||||
> May we keep SparkyFitness in our catalogue for paying families? If you want something in return — a mention, a link,
|
||||
> a donation per family, or something else — please tell us. If your answer is no, we will take it out of our catalogue
|
||||
> for new families, and we will thank you for the time.
|
||||
>
|
||||
> Thank you for SparkyFitness.
|
||||
>
|
||||
> Best regards,
|
||||
> [operator's name]
|
||||
> Felhom — https://felhom.eu
|
||||
|
||||
## Notes for the operator
|
||||
|
||||
- If no written permission arrives before the first paying customer, the template goes to `lifecycle: hidden`
|
||||
(decision 65; STATUS standing item). Boxes already running it keep it.
|
||||
- The answer, when it comes, is filed under this folder and the register row is closed with it.
|
||||
@@ -0,0 +1,82 @@
|
||||
# Licence read — all templates, one table (R-787), 2026-10-02
|
||||
|
||||
Every image of every template in the catalog (56 directories incl. the two new ones, Grimmory and MeTube), the licence
|
||||
READ at the pinned tag. Merged from `read-1.md` and `read-2.md` (two readers, same method; the method and the exceptions
|
||||
are stated at the top of each). *Inferred* is marked in the row. **Nothing was hidden or changed because of this read**
|
||||
(the brief's rule) — the short list goes to the operator in `STATUS.md`.
|
||||
|
||||
| app | image:tag | licence (SPDX) | OSI | limiting clause (quoted) | plain meaning | evidence |
|
||||
|---|---|---|---|---|---|---|
|
||||
| actualbudget | actualbudget/actual-server:26.9.0 | MIT | yes | — | — | github.com/actualbudget/actual/blob/v26.9.0/LICENSE.txt |
|
||||
| adventurelog | adventurelog-backend/-frontend:v0.13.0 | GPL-3.0 (version from the text; -only/-or-later *inferred*) | yes | — | — | github.com/seanmorley15/AdventureLog/blob/v0.13.0/LICENSE |
|
||||
| adventurelog, dawarich | postgis/postgis:16-3.5 / 17-3.5-alpine | GPL-2.0-or-later + PostgreSQL | yes | — | — | postgis LICENSE.TXT |
|
||||
| audiobookshelf | ghcr.io/advplyr/audiobookshelf:2.37.1 | GPL-3.0 | yes | — | — | github.com/advplyr/audiobookshelf/blob/v2.37.1/LICENSE |
|
||||
| bentopdf | ghcr.io/alam00000/bentopdf:v2.8.6 | AGPL-3.0 (dual: a commercial licence optional) | yes | — | AGPL; the README labels this image the "Commercial build" and points self-hosters to `bentopdf-simple` — a label, not a licence term | github.com/alam00000/bentopdf/blob/v2.8.6/LICENSE + README "Licensing" |
|
||||
| bookstack | lscr.io/linuxserver/bookstack:26.09.1 | MIT (+ GPL-3.0 packaging) | yes | — | — | github.com/BookStackApp/BookStack/blob/v26.09.1/LICENSE |
|
||||
| bookstack, kimai | mariadb:12.3 / 11.8 | GPL-2.0-only | yes | — | — | mariadb.com/kb/en/mariadb-license/ |
|
||||
| calcom | calcom/cal.com:v6.2.0 | AGPL-3.0 AND Cal.com Commercial License (`packages/features/ee`, `apps/api/v2/src/ee`) | partly | EE: "may only be used in production, if you … have a valid Cal.com Enterprise Edition subscription … it is forbidden to copy, merge, publish, distribute, sublicense, and/or sell the Software." | EE code is in the image, off without a key (*inferred*); free features stay AGPL; any EE feature in production needs a subscription | github.com/calcom/cal.com/blob/v6.2.0/packages/features/ee/LICENSE |
|
||||
| calcom, docmost | postgres:18-alpine | PostgreSQL | yes | — | — | — |
|
||||
| calibre-web | crocodilestick/calibre-web-automated:v4.0.8 | GPL-3.0 | yes | — | — | github.com/crocodilestick/Calibre-Web-Automated/blob/v4.0.8/LICENSE |
|
||||
| claper | ghcr.io/claperco/claper:2.5 | AGPL-3.0 (read at v2.5.0; tag mapping *inferred*) | yes | — | — | github.com/ClaperCo/Claper/blob/v2.5.0/LICENSE.txt |
|
||||
| code-server | lscr.io/linuxserver/code-server:4.129.0 | MIT (+ GPL-3.0 packaging) | yes | — | no Microsoft Marketplace (*inferred*) | github.com/coder/code-server/blob/v4.129.0/LICENSE |
|
||||
| crafty-controller | crafty-4:4.11.0 | GPL-3.0 | yes | — | Minecraft jars it downloads fall under Mojang's EULA, separately | gitlab.com/crafty-controller/crafty-4/-/blob/v4.11.0/LICENSE |
|
||||
| dawarich | freikin/dawarich:1.15.3 | AGPL-3.0 | yes | — | — | github.com/Freika/dawarich/blob/1.15.3/LICENSE |
|
||||
| dawarich, docmost, immich | redis:7.4-alpine / 7-alpine (→ 7.4.11) | RSALv2 OR SSPL-1.0 | no | RSALv2: "You may not make the functionality of the Software or a Modified version available to third parties as a service or distribute the Software … in a manner that makes the functionality of the Software available to third parties." | a private cache only its app uses — *inferred* permitted; redis:7.2 / valkey (BSD-3) or Redis 8 (AGPL option) removes the question | github.com/redis/redis/blob/7.4.0/LICENSE.txt |
|
||||
| docmost | docmost/docmost:0.96.0 | AGPL-3.0 AND Docmost Enterprise License (`packages/ee`, `apps/client/src/ee`) | partly | EE: "may only be used in production, if you … have a valid Docmost Enterprise Edition subscription …" | as Cal.com: EE off without a key (*inferred*) | github.com/docmost/docmost/blob/v0.96.0/packages/ee/LICENSE |
|
||||
| **emby** | emby/embyserver:4.11.0.4 | **proprietary** | no | "Emby grants you a personal, non-commercial … non-transferable, non-sublicensable … license … you may not … copy, modify, distribute, sell, or lease any part of the Software" | the household's private use fits; a company selling its installation and care works in a context the licence does not cover; the box pulls the image from Emby, so no copies are distributed — a grey area (*inferred*) | emby.media/terms.html |
|
||||
| ghost | ghost:6.67.0-alpine | MIT | yes | — | name is a trademark | github.com/TryGhost/Ghost/blob/v6.67.0/LICENSE |
|
||||
| gitea | gitea/gitea:1.27.3 | MIT | yes | — | — | github.com/go-gitea/gitea/blob/v1.27.3/LICENSE |
|
||||
| glance | glanceapp/glance:v0.8.5 | AGPL-3.0 | yes | — | — | github.com/glanceapp/glance/blob/v0.8.5/LICENSE |
|
||||
| gokapi | f0rc3/gokapi:v1.9.6 | AGPL-3.0 | yes | — | — | github.com/Forceu/Gokapi/blob/v1.9.6/LICENSE.md |
|
||||
| grafana | grafana/grafana:13.2.3 | AGPL-3.0 (OSS image) | yes | — | trademarks | github.com/grafana/grafana/blob/v13.2.3/LICENSE |
|
||||
| gramps-web | ghcr.io/gramps-project/grampsweb:v25.6.0 | AGPL-3.0 (Gramps core GPL-2.0-or-later) | yes | — | — | github.com/gramps-project/gramps-web/blob/v25.6.0/LICENSE |
|
||||
| grimmory | ghcr.io/grimmory-tools/grimmory:v3.4.1 | AGPL-3.0 | yes | – | – | github.com/grimmory-tools/grimmory/blob/v3.4.1/LICENSE |
|
||||
| grimmory | mariadb:11.4 | GPL-2.0 | yes | – | – | MariaDB COPYING |
|
||||
| home-assistant | home-assistant:2026.9.4 | Apache-2.0 | yes | — | trademark | github.com/home-assistant/core/blob/2026.9.4/LICENSE.md |
|
||||
| homebox | ghcr.io/sysadminsmedia/homebox:0.26.2 | AGPL-3.0 | yes | — | — | github.com/sysadminsmedia/homebox/blob/v0.26.2/LICENSE |
|
||||
| homepage | ghcr.io/gethomepage/homepage:v1.13.2 | GPL-3.0 | yes | — | — | github.com/gethomepage/homepage/blob/v1.13.2/LICENSE |
|
||||
| immich | immich-server / -machine-learning:v3.2.4 | AGPL-3.0 | yes | — | ML model weights carry their own licences (not checked) | github.com/immich-app/immich/blob/v3.2.4/LICENSE |
|
||||
| immich | ghcr.io/immich-app/postgres:16-vectorchord0.4.3-pgvectors0.2.0 | PostgreSQL + (AGPL-3.0 OR Elastic-2.0) VectorChord + Apache-2.0 pgvecto.rs | yes (AGPL chosen for VectorChord) | ELv2 alternative only | — | github.com/tensorchord/VectorChord/blob/0.4.3/LICENSE |
|
||||
| jellyfin | jellyfin/jellyfin:10.11.11 | GPL-2.0 (ffmpeg GPL-3.0) | yes | — | — | github.com/jellyfin/jellyfin/blob/v10.11.11/LICENSE |
|
||||
| karakeep | ghcr.io/karakeep-app/karakeep:0.33.2 | AGPL-3.0 | yes | — | — | github.com/karakeep-app/karakeep/blob/v0.33.2/LICENSE |
|
||||
| karakeep | karakeep-chrome:151.0.7922.47-r1 | BSD-3-Clause (Chromium headless-shell — *inferred* from Chromium) | yes | — | — | chromium LICENSE |
|
||||
| karakeep | getmeili/meilisearch:v1.41.0 | MIT (Community image; BUSL EE code only in `meilisearch-enterprise`) | yes | — | never switch to the `-enterprise` image | github.com/meilisearch/meilisearch/blob/v1.41.0/LICENSE |
|
||||
| kimai | kimai/kimai2:2.67.0 | AGPL-3.0 | yes | — | paid plugins are separate | github.com/kimai/kimai/blob/2.67.0/LICENSE |
|
||||
| komga | gotson/komga:1.28.0 | MIT | yes | — | — | github.com/gotson/komga/blob/1.28.0/LICENSE |
|
||||
| mealie | ghcr.io/mealie-recipes/mealie:v3.28.0 | AGPL-3.0 | yes | — | — | github.com/mealie-recipes/mealie/blob/v3.28.0/LICENSE |
|
||||
| metube | ghcr.io/alexta69/metube:2026.09.29 | AGPL-3.0 | yes | – | – | github.com/alexta69/metube/blob/2026.09.29/LICENSE |
|
||||
| n8n | n8nio/n8n:2.42.1 | custom: Sustainable Use License 1.0 (+ `.ee.` files: n8n Enterprise License) | no | "You may use or modify the software only for your own internal business purposes or for non-commercial or personal use. You may distribute the software or provide it to others only if you do so free of charge for non-commercial purposes." | the household's private use is allowed; Felhom charging while "providing it to others" is a grey zone (pulling the official image unchanged is arguably not distributing — *inferred*) | github.com/n8n-io/n8n/blob/n8n@2.42.1/LICENSE.md |
|
||||
| navidrome | deluan/navidrome:0.64.2 | GPL-3.0 | yes | – | – | github.com/navidrome/navidrome/blob/v0.64.2/LICENSE |
|
||||
| nextcloud | nextcloud:34.0.4-apache | AGPL-3.0 | yes | – | – | github.com/nextcloud/server/blob/v34.0.4/COPYING |
|
||||
| nextcloud | mariadb:12.3 | GPL-2.0 | yes | – | – | MariaDB COPYING |
|
||||
| nextcloud, outline, paperless-ngx, romm | redis:7-alpine (→ 7.4.11) | RSALv2 OR SSPL-1.0 | no | RSALv2: "You may not make the functionality of the Software or a Modified version available to third parties as a service" | an internal cache on the customer's own box, not Redis offered as a service — *inferred* not to bite; Valkey (BSD) or redis:8 (AGPL option) removes the question | github.com/redis/redis/blob/7.4.11/LICENSE.txt |
|
||||
| onlyoffice | onlyoffice/documentserver:9.4.0 | AGPL-3.0 + §7 terms (logo, no trademark licence) | yes (base) | §7 keep the logo / no trademark licence | the image runs unchanged, so the terms are met | github.com/ONLYOFFICE/DocumentServer/blob/v9.4.0/LICENSE |
|
||||
| opengist | ghcr.io/thomiceli/opengist:1.15 | AGPL-3.0 | yes | – | – | github.com/thomiceli/opengist/blob/v1.15.0/LICENSE |
|
||||
| outline | outlinewiki/outline:1.10.1 | BUSL-1.1 (Change Date 2030-09-09 → Apache-2.0) | no | "you may not use the Licensed Work for a Document Service. A 'Document Service' is a commercial offering that allows third parties (other than your employees and contractors) to access the functionality of the Licensed Work by creating teams and documents controlled by such third parties." | the household's own instance on its own hardware is not a Document Service; Felhom hosting it for paying third parties itself would be — *inferred* | github.com/outline/outline/blob/v1.10.1/LICENSE |
|
||||
| outline, paperless-ngx, rallly, sparkyfitness | postgres:18-alpine | PostgreSQL | yes | – | – | postgres COPYRIGHT |
|
||||
| paperless-ngx | ghcr.io/paperless-ngx/paperless-ngx:2.20.15 | GPL-3.0 | yes | – | – | github.com/paperless-ngx/paperless-ngx/blob/v2.20.15/LICENSE |
|
||||
| papra | ghcr.io/papra-hq/papra:26.6.2-rootless | AGPL-3.0 | yes | – | – | github.com/papra-hq/papra (tag @papra/app@26.6.2) LICENSE |
|
||||
| plant-it | msdeluise/plant-it:0.10.0 | GPL-3.0 | yes | – | – | github.com/MDeLuise/plant-it/blob/0.10.0/LICENSE.txt |
|
||||
| plex | plexinc/pms-docker:1.41.4.9463-630c9f557 | proprietary (Plex Terms of Service) | no | "personal (non-commercial), revocable, limited, non-exclusive, nontransferable, and non-sublicensable license to access and use the Plex Solution" (search snippet; the page 403'd) | the household uses it under its own Plex account; Felhom gets no right and installs it only as the household's agent; selling Plex or a Plex Pass is not covered | plex.tv/about/privacy-legal/plex-terms-of-service/ |
|
||||
| privatebin | privatebin/pdo:2.0.6 | Zlib (bundled GPL-2.0, BSD-3, MIT, Apache, CC-BY) | yes | – | – | github.com/PrivateBin/PrivateBin/blob/2.0.6/LICENSE.md |
|
||||
| radarr | lscr.io/linuxserver/radarr:6.4.4 | GPL-3.0 | yes | – | – | github.com/Radarr/Radarr LICENSE |
|
||||
| radicale | ghcr.io/kozea/radicale:3.8.1 | GPL-3.0 | yes | – | – | github.com/Kozea/Radicale/blob/v3.8.1/COPYING.md |
|
||||
| rallly | lukevella/rallly:4.15.3 | AGPL-3.0 | yes | – | – | github.com/lukevella/rallly/blob/v4.15.3/LICENSE |
|
||||
| recipe-importer | gitea.dooplex.hu/admin/recipe-importer:v0.9.11 | none (all rights reserved — Felhom's own) | n/a | no licence file | Felhom owns it; dependencies (Flask, gunicorn, requests, bs4, lxml) permissive — *inferred* from requirements.txt | /home/kisfenyo/git/recipe-importer |
|
||||
| romm | rommapp/romm:5.3.1 | AGPL-3.0 | yes | – | – | github.com/rommapp/romm/blob/5.3.1/LICENSE |
|
||||
| romm | mariadb:11.8 | GPL-2.0 | yes | – | – | MariaDB COPYING |
|
||||
| seerr | fallenbagel/jellyseerr:2.7.3 | MIT | yes | – | – | github.com/fallenbagel/jellyseerr/blob/v2.7.3/LICENSE |
|
||||
| sonarr | lscr.io/linuxserver/sonarr:4.0.20 | GPL-3.0 | yes | – | – | github.com/Sonarr/Sonarr LICENSE.md |
|
||||
| sparkyfitness | codewithcj/sparkyfitness(_server):v0.17.3 | custom non-commercial | no | "The Software may not be used, directly or indirectly, in any product, service, or project primarily intended for or resulting in commercial advantage or monetary compensation, without prior written permission from the author." §7 terminates on a breach | offering it in a paid install-and-care service is commercial use: written permission needed (decision 65) | github.com/CodeWithCJ/SparkyFitness/blob/v0.17.3/LICENSE |
|
||||
| **tandoor** | ghcr.io/tandoorrecipes/recipes:2.6.15 | **AGPL-3.0 WITH Commons Clause v1.0 (custom)** | **no** | "the License does not grant to you, the right to Sell the Software… 'Sell' means… to provide to third parties, for a fee or other consideration (including without limitation fees for hosting or consulting/ support services related to the Software), a product or service whose value derives, entirely or substantially, from the functionality of the Software." | charging for installing or supporting Tandoor is what the clause names, if the paid service's value comes "substantially" from Tandoor; permission from the author, or keep it out of what Felhom charges for | github.com/TandoorRecipes/recipes/blob/2.6.15/LICENSE.md |
|
||||
| tandoor | postgres:17-alpine | PostgreSQL | yes | – | – | – |
|
||||
| termix | ghcr.io/lukegus/termix:2.8.0 | Apache-2.0 | yes | – | – | github.com/Termix-SSH/Termix LICENSE |
|
||||
| uptime-kuma | louislam/uptime-kuma:2.5.5 | MIT | yes | – | – | github.com/louislam/uptime-kuma/blob/2.5.5/LICENSE |
|
||||
| vaultwarden | vaultwarden/server:1.36.0-alpine | AGPL-3.0 (web-vault GPL-3.0) | yes | – | – | github.com/dani-garcia/vaultwarden/blob/1.36.0/LICENSE.txt |
|
||||
| vikunja | vikunja/vikunja:2.6.0 | AGPL-3.0 | yes | – | – | github.com/go-vikunja/vikunja/blob/v2.6.0/LICENSE |
|
||||
| wanderer | flomp/wanderer-web/-db:v0.20.0 | AGPL-3.0 (db = PocketBase MIT — *inferred*) | yes | – | – | github.com/Flomp/wanderer/blob/v0.20.0/LICENSE |
|
||||
| wanderer | getmeili/meilisearch:v1.36.0 | MIT AND BUSL-1.1 (EE modules) | core yes; EE no | LICENSE-EE: "non-production purposes only… Production use of the Licensed Work requires a commercial license" | Enterprise modules only (e.g. sharding); plain search is the MIT core — fine unless an EE feature is on (*inferred*) | github.com/meilisearch/meilisearch/blob/v1.36.0/LICENSE |
|
||||
| wger | wger/server:2.7 | AGPL-3.0 | yes | – | – | github.com/wger-project/wger/blob/2.7/LICENSE.txt |
|
||||
| wishlist | ghcr.io/cmintey/wishlist:v0.67.1 | MIT | yes | – | – | github.com/cmintey/wishlist/blob/v0.67.1/LICENSE |
|
||||
| zipline | ghcr.io/diced/zipline:4.8.0 | MIT | yes | – | – | github.com/diced/zipline/blob/v4.8.0/LICENSE |
|
||||
| zipline | postgres:16-alpine | PostgreSQL | yes | – | – | – |
|
||||
@@ -0,0 +1,48 @@
|
||||
# Licence read, part 1 of 2 (R-787) — READ at each pinned tag, 2026-10-02 (subagent, verbatim in substance)
|
||||
|
||||
Apps: actualbudget adventurelog audiobookshelf bentopdf bookstack calcom calibre-web claper code-server crafty-controller
|
||||
dawarich docmost emby ghost gitea glance gokapi grafana gramps-web home-assistant homebox homepage immich jellyfin karakeep
|
||||
kimai komga mealie. Licences read from the upstream file at the pinned tag, except linuxserver packaging, PostGIS and
|
||||
immich base-images (read from `master`/`main`) and the MariaDB, Postgres, Chromium and Emby pages. *Inferred* is marked.
|
||||
|
||||
| app | image:tag | licence (SPDX) | OSI | limiting clause (quoted) | plain meaning | evidence |
|
||||
|---|---|---|---|---|---|---|
|
||||
| actualbudget | actualbudget/actual-server:26.9.0 | MIT | yes | — | — | github.com/actualbudget/actual/blob/v26.9.0/LICENSE.txt |
|
||||
| adventurelog | adventurelog-backend/-frontend:v0.13.0 | GPL-3.0 (version from the text; -only/-or-later *inferred*) | yes | — | — | github.com/seanmorley15/AdventureLog/blob/v0.13.0/LICENSE |
|
||||
| adventurelog, dawarich | postgis/postgis:16-3.5 / 17-3.5-alpine | GPL-2.0-or-later + PostgreSQL | yes | — | — | postgis LICENSE.TXT |
|
||||
| audiobookshelf | ghcr.io/advplyr/audiobookshelf:2.37.1 | GPL-3.0 | yes | — | — | github.com/advplyr/audiobookshelf/blob/v2.37.1/LICENSE |
|
||||
| bentopdf | ghcr.io/alam00000/bentopdf:v2.8.6 | AGPL-3.0 (dual: a commercial licence optional) | yes | — | AGPL; the README labels this image the "Commercial build" and points self-hosters to `bentopdf-simple` — a label, not a licence term | github.com/alam00000/bentopdf/blob/v2.8.6/LICENSE + README "Licensing" |
|
||||
| bookstack | lscr.io/linuxserver/bookstack:26.09.1 | MIT (+ GPL-3.0 packaging) | yes | — | — | github.com/BookStackApp/BookStack/blob/v26.09.1/LICENSE |
|
||||
| bookstack, kimai | mariadb:12.3 / 11.8 | GPL-2.0-only | yes | — | — | mariadb.com/kb/en/mariadb-license/ |
|
||||
| calcom | calcom/cal.com:v6.2.0 | AGPL-3.0 AND Cal.com Commercial License (`packages/features/ee`, `apps/api/v2/src/ee`) | partly | EE: "may only be used in production, if you … have a valid Cal.com Enterprise Edition subscription … it is forbidden to copy, merge, publish, distribute, sublicense, and/or sell the Software." | EE code is in the image, off without a key (*inferred*); free features stay AGPL; any EE feature in production needs a subscription | github.com/calcom/cal.com/blob/v6.2.0/packages/features/ee/LICENSE |
|
||||
| calcom, docmost | postgres:18-alpine | PostgreSQL | yes | — | — | — |
|
||||
| calibre-web | crocodilestick/calibre-web-automated:v4.0.8 | GPL-3.0 | yes | — | — | github.com/crocodilestick/Calibre-Web-Automated/blob/v4.0.8/LICENSE |
|
||||
| claper | ghcr.io/claperco/claper:2.5 | AGPL-3.0 (read at v2.5.0; tag mapping *inferred*) | yes | — | — | github.com/ClaperCo/Claper/blob/v2.5.0/LICENSE.txt |
|
||||
| code-server | lscr.io/linuxserver/code-server:4.129.0 | MIT (+ GPL-3.0 packaging) | yes | — | no Microsoft Marketplace (*inferred*) | github.com/coder/code-server/blob/v4.129.0/LICENSE |
|
||||
| crafty-controller | crafty-4:4.11.0 | GPL-3.0 | yes | — | Minecraft jars it downloads fall under Mojang's EULA, separately | gitlab.com/crafty-controller/crafty-4/-/blob/v4.11.0/LICENSE |
|
||||
| dawarich | freikin/dawarich:1.15.3 | AGPL-3.0 | yes | — | — | github.com/Freika/dawarich/blob/1.15.3/LICENSE |
|
||||
| dawarich, docmost, immich | redis:7.4-alpine / 7-alpine (→ 7.4.11) | RSALv2 OR SSPL-1.0 | no | RSALv2: "You may not make the functionality of the Software or a Modified version available to third parties as a service or distribute the Software … in a manner that makes the functionality of the Software available to third parties." | a private cache only its app uses — *inferred* permitted; redis:7.2 / valkey (BSD-3) or Redis 8 (AGPL option) removes the question | github.com/redis/redis/blob/7.4.0/LICENSE.txt |
|
||||
| docmost | docmost/docmost:0.96.0 | AGPL-3.0 AND Docmost Enterprise License (`packages/ee`, `apps/client/src/ee`) | partly | EE: "may only be used in production, if you … have a valid Docmost Enterprise Edition subscription …" | as Cal.com: EE off without a key (*inferred*) | github.com/docmost/docmost/blob/v0.96.0/packages/ee/LICENSE |
|
||||
| **emby** | emby/embyserver:4.11.0.4 | **proprietary** | no | "Emby grants you a personal, non-commercial … non-transferable, non-sublicensable … license … you may not … copy, modify, distribute, sell, or lease any part of the Software" | the household's private use fits; a company selling its installation and care works in a context the licence does not cover; the box pulls the image from Emby, so no copies are distributed — a grey area (*inferred*) | emby.media/terms.html |
|
||||
| ghost | ghost:6.67.0-alpine | MIT | yes | — | name is a trademark | github.com/TryGhost/Ghost/blob/v6.67.0/LICENSE |
|
||||
| gitea | gitea/gitea:1.27.3 | MIT | yes | — | — | github.com/go-gitea/gitea/blob/v1.27.3/LICENSE |
|
||||
| glance | glanceapp/glance:v0.8.5 | AGPL-3.0 | yes | — | — | github.com/glanceapp/glance/blob/v0.8.5/LICENSE |
|
||||
| gokapi | f0rc3/gokapi:v1.9.6 | AGPL-3.0 | yes | — | — | github.com/Forceu/Gokapi/blob/v1.9.6/LICENSE.md |
|
||||
| grafana | grafana/grafana:13.2.3 | AGPL-3.0 (OSS image) | yes | — | trademarks | github.com/grafana/grafana/blob/v13.2.3/LICENSE |
|
||||
| gramps-web | ghcr.io/gramps-project/grampsweb:v25.6.0 | AGPL-3.0 (Gramps core GPL-2.0-or-later) | yes | — | — | github.com/gramps-project/gramps-web/blob/v25.6.0/LICENSE |
|
||||
| home-assistant | home-assistant:2026.9.4 | Apache-2.0 | yes | — | trademark | github.com/home-assistant/core/blob/2026.9.4/LICENSE.md |
|
||||
| homebox | ghcr.io/sysadminsmedia/homebox:0.26.2 | AGPL-3.0 | yes | — | — | github.com/sysadminsmedia/homebox/blob/v0.26.2/LICENSE |
|
||||
| homepage | ghcr.io/gethomepage/homepage:v1.13.2 | GPL-3.0 | yes | — | — | github.com/gethomepage/homepage/blob/v1.13.2/LICENSE |
|
||||
| immich | immich-server / -machine-learning:v3.2.4 | AGPL-3.0 | yes | — | ML model weights carry their own licences (not checked) | github.com/immich-app/immich/blob/v3.2.4/LICENSE |
|
||||
| immich | ghcr.io/immich-app/postgres:16-vectorchord0.4.3-pgvectors0.2.0 | PostgreSQL + (AGPL-3.0 OR Elastic-2.0) VectorChord + Apache-2.0 pgvecto.rs | yes (AGPL chosen for VectorChord) | ELv2 alternative only | — | github.com/tensorchord/VectorChord/blob/0.4.3/LICENSE |
|
||||
| jellyfin | jellyfin/jellyfin:10.11.11 | GPL-2.0 (ffmpeg GPL-3.0) | yes | — | — | github.com/jellyfin/jellyfin/blob/v10.11.11/LICENSE |
|
||||
| karakeep | ghcr.io/karakeep-app/karakeep:0.33.2 | AGPL-3.0 | yes | — | — | github.com/karakeep-app/karakeep/blob/v0.33.2/LICENSE |
|
||||
| karakeep | karakeep-chrome:151.0.7922.47-r1 | BSD-3-Clause (Chromium headless-shell — *inferred* from Chromium) | yes | — | — | chromium LICENSE |
|
||||
| karakeep | getmeili/meilisearch:v1.41.0 | MIT (Community image; BUSL EE code only in `meilisearch-enterprise`) | yes | — | never switch to the `-enterprise` image | github.com/meilisearch/meilisearch/blob/v1.41.0/LICENSE |
|
||||
| kimai | kimai/kimai2:2.67.0 | AGPL-3.0 | yes | — | paid plugins are separate | github.com/kimai/kimai/blob/2.67.0/LICENSE |
|
||||
| komga | gotson/komga:1.28.0 | MIT | yes | — | — | github.com/gotson/komga/blob/1.28.0/LICENSE |
|
||||
| mealie | ghcr.io/mealie-recipes/mealie:v3.28.0 | AGPL-3.0 | yes | — | — | github.com/mealie-recipes/mealie/blob/v3.28.0/LICENSE |
|
||||
|
||||
**Not OSI-approved (part 1):** emby (proprietary, personal non-commercial — the real business risk in this set); calcom and
|
||||
docmost (proprietary EE folders inside the AGPL image, off without a key); redis 7.4.11 in dawarich, docmost, immich
|
||||
(RSALv2/SSPL — internal cache).
|
||||
@@ -0,0 +1,52 @@
|
||||
# Licence read, part 2 of 2 (R-787) — READ at each pinned tag, 2026-10-02 (subagent, verbatim in substance)
|
||||
|
||||
Apps: n8n navidrome nextcloud onlyoffice opengist outline paperless-ngx papra plant-it plex privatebin radarr radicale
|
||||
rallly recipe-importer romm seerr sonarr sparkyfitness tandoor termix uptime-kuma vaultwarden vikunja wanderer wger
|
||||
wishlist zipline grimmory (held WIP) metube (new). Upstream LICENSE files read from raw.githubusercontent.com at the pinned
|
||||
tag, except Plex (ToS page 403 — quoted from a search snippet) and the rows marked *inferred*.
|
||||
|
||||
| app | image:tag | licence (SPDX) | OSI | limiting clause (quoted) | plain meaning | evidence |
|
||||
|---|---|---|---|---|---|---|
|
||||
| n8n | n8nio/n8n:2.42.1 | custom: Sustainable Use License 1.0 (+ `.ee.` files: n8n Enterprise License) | no | "You may use or modify the software only for your own internal business purposes or for non-commercial or personal use. You may distribute the software or provide it to others only if you do so free of charge for non-commercial purposes." | the household's private use is allowed; Felhom charging while "providing it to others" is a grey zone (pulling the official image unchanged is arguably not distributing — *inferred*) | github.com/n8n-io/n8n/blob/n8n@2.42.1/LICENSE.md |
|
||||
| navidrome | deluan/navidrome:0.64.2 | GPL-3.0 | yes | – | – | github.com/navidrome/navidrome/blob/v0.64.2/LICENSE |
|
||||
| nextcloud | nextcloud:34.0.4-apache | AGPL-3.0 | yes | – | – | github.com/nextcloud/server/blob/v34.0.4/COPYING |
|
||||
| nextcloud | mariadb:12.3 | GPL-2.0 | yes | – | – | MariaDB COPYING |
|
||||
| nextcloud, outline, paperless-ngx, romm | redis:7-alpine (→ 7.4.11) | RSALv2 OR SSPL-1.0 | no | RSALv2: "You may not make the functionality of the Software or a Modified version available to third parties as a service" | an internal cache on the customer's own box, not Redis offered as a service — *inferred* not to bite; Valkey (BSD) or redis:8 (AGPL option) removes the question | github.com/redis/redis/blob/7.4.11/LICENSE.txt |
|
||||
| onlyoffice | onlyoffice/documentserver:9.4.0 | AGPL-3.0 + §7 terms (logo, no trademark licence) | yes (base) | §7 keep the logo / no trademark licence | the image runs unchanged, so the terms are met | github.com/ONLYOFFICE/DocumentServer/blob/v9.4.0/LICENSE |
|
||||
| opengist | ghcr.io/thomiceli/opengist:1.15 | AGPL-3.0 | yes | – | – | github.com/thomiceli/opengist/blob/v1.15.0/LICENSE |
|
||||
| outline | outlinewiki/outline:1.10.1 | BUSL-1.1 (Change Date 2030-09-09 → Apache-2.0) | no | "you may not use the Licensed Work for a Document Service. A 'Document Service' is a commercial offering that allows third parties (other than your employees and contractors) to access the functionality of the Licensed Work by creating teams and documents controlled by such third parties." | the household's own instance on its own hardware is not a Document Service; Felhom hosting it for paying third parties itself would be — *inferred* | github.com/outline/outline/blob/v1.10.1/LICENSE |
|
||||
| outline, paperless-ngx, rallly, sparkyfitness | postgres:18-alpine | PostgreSQL | yes | – | – | postgres COPYRIGHT |
|
||||
| paperless-ngx | ghcr.io/paperless-ngx/paperless-ngx:2.20.15 | GPL-3.0 | yes | – | – | github.com/paperless-ngx/paperless-ngx/blob/v2.20.15/LICENSE |
|
||||
| papra | ghcr.io/papra-hq/papra:26.6.2-rootless | AGPL-3.0 | yes | – | – | github.com/papra-hq/papra (tag @papra/app@26.6.2) LICENSE |
|
||||
| plant-it | msdeluise/plant-it:0.10.0 | GPL-3.0 | yes | – | – | github.com/MDeLuise/plant-it/blob/0.10.0/LICENSE.txt |
|
||||
| plex | plexinc/pms-docker:1.41.4.9463-630c9f557 | proprietary (Plex Terms of Service) | no | "personal (non-commercial), revocable, limited, non-exclusive, nontransferable, and non-sublicensable license to access and use the Plex Solution" (search snippet; the page 403'd) | the household uses it under its own Plex account; Felhom gets no right and installs it only as the household's agent; selling Plex or a Plex Pass is not covered | plex.tv/about/privacy-legal/plex-terms-of-service/ |
|
||||
| privatebin | privatebin/pdo:2.0.6 | Zlib (bundled GPL-2.0, BSD-3, MIT, Apache, CC-BY) | yes | – | – | github.com/PrivateBin/PrivateBin/blob/2.0.6/LICENSE.md |
|
||||
| radarr | lscr.io/linuxserver/radarr:6.4.4 | GPL-3.0 | yes | – | – | github.com/Radarr/Radarr LICENSE |
|
||||
| radicale | ghcr.io/kozea/radicale:3.8.1 | GPL-3.0 | yes | – | – | github.com/Kozea/Radicale/blob/v3.8.1/COPYING.md |
|
||||
| rallly | lukevella/rallly:4.15.3 | AGPL-3.0 | yes | – | – | github.com/lukevella/rallly/blob/v4.15.3/LICENSE |
|
||||
| recipe-importer | gitea.dooplex.hu/admin/recipe-importer:v0.9.11 | none (all rights reserved — Felhom's own) | n/a | no licence file | Felhom owns it; dependencies (Flask, gunicorn, requests, bs4, lxml) permissive — *inferred* from requirements.txt | /home/kisfenyo/git/recipe-importer |
|
||||
| romm | rommapp/romm:5.3.1 | AGPL-3.0 | yes | – | – | github.com/rommapp/romm/blob/5.3.1/LICENSE |
|
||||
| romm | mariadb:11.8 | GPL-2.0 | yes | – | – | MariaDB COPYING |
|
||||
| seerr | fallenbagel/jellyseerr:2.7.3 | MIT | yes | – | – | github.com/fallenbagel/jellyseerr/blob/v2.7.3/LICENSE |
|
||||
| sonarr | lscr.io/linuxserver/sonarr:4.0.20 | GPL-3.0 | yes | – | – | github.com/Sonarr/Sonarr LICENSE.md |
|
||||
| sparkyfitness | codewithcj/sparkyfitness(_server):v0.17.3 | custom non-commercial | no | "The Software may not be used, directly or indirectly, in any product, service, or project primarily intended for or resulting in commercial advantage or monetary compensation, without prior written permission from the author." §7 terminates on a breach | offering it in a paid install-and-care service is commercial use: written permission needed (decision 65) | github.com/CodeWithCJ/SparkyFitness/blob/v0.17.3/LICENSE |
|
||||
| **tandoor** | ghcr.io/tandoorrecipes/recipes:2.6.15 | **AGPL-3.0 WITH Commons Clause v1.0 (custom)** | **no** | "the License does not grant to you, the right to Sell the Software… 'Sell' means… to provide to third parties, for a fee or other consideration (including without limitation fees for hosting or consulting/ support services related to the Software), a product or service whose value derives, entirely or substantially, from the functionality of the Software." | charging for installing or supporting Tandoor is what the clause names, if the paid service's value comes "substantially" from Tandoor; permission from the author, or keep it out of what Felhom charges for | github.com/TandoorRecipes/recipes/blob/2.6.15/LICENSE.md |
|
||||
| tandoor | postgres:17-alpine | PostgreSQL | yes | – | – | – |
|
||||
| termix | ghcr.io/lukegus/termix:2.8.0 | Apache-2.0 | yes | – | – | github.com/Termix-SSH/Termix LICENSE |
|
||||
| uptime-kuma | louislam/uptime-kuma:2.5.5 | MIT | yes | – | – | github.com/louislam/uptime-kuma/blob/2.5.5/LICENSE |
|
||||
| vaultwarden | vaultwarden/server:1.36.0-alpine | AGPL-3.0 (web-vault GPL-3.0) | yes | – | – | github.com/dani-garcia/vaultwarden/blob/1.36.0/LICENSE.txt |
|
||||
| vikunja | vikunja/vikunja:2.6.0 | AGPL-3.0 | yes | – | – | github.com/go-vikunja/vikunja/blob/v2.6.0/LICENSE |
|
||||
| wanderer | flomp/wanderer-web/-db:v0.20.0 | AGPL-3.0 (db = PocketBase MIT — *inferred*) | yes | – | – | github.com/Flomp/wanderer/blob/v0.20.0/LICENSE |
|
||||
| wanderer | getmeili/meilisearch:v1.36.0 | MIT AND BUSL-1.1 (EE modules) | core yes; EE no | LICENSE-EE: "non-production purposes only… Production use of the Licensed Work requires a commercial license" | Enterprise modules only (e.g. sharding); plain search is the MIT core — fine unless an EE feature is on (*inferred*) | github.com/meilisearch/meilisearch/blob/v1.36.0/LICENSE |
|
||||
| wger | wger/server:2.7 | AGPL-3.0 | yes | – | – | github.com/wger-project/wger/blob/2.7/LICENSE.txt |
|
||||
| wishlist | ghcr.io/cmintey/wishlist:v0.67.1 | MIT | yes | – | – | github.com/cmintey/wishlist/blob/v0.67.1/LICENSE |
|
||||
| zipline | ghcr.io/diced/zipline:4.8.0 | MIT | yes | – | – | github.com/diced/zipline/blob/v4.8.0/LICENSE |
|
||||
| zipline | postgres:16-alpine | PostgreSQL | yes | – | – | – |
|
||||
| grimmory | ghcr.io/grimmory-tools/grimmory:v3.4.1 | AGPL-3.0 | yes | – | – | github.com/grimmory-tools/grimmory/blob/v3.4.1/LICENSE |
|
||||
| grimmory | mariadb:11.4 | GPL-2.0 | yes | – | – | MariaDB COPYING |
|
||||
| metube | ghcr.io/alexta69/metube:2026.09.29 | AGPL-3.0 | yes | – | – | github.com/alexta69/metube/blob/2026.09.29/LICENSE |
|
||||
|
||||
**Not OSI-approved (part 2):** tandoor (Commons Clause — the most serious: it names paid hosting and support), sparkyfitness
|
||||
(non-commercial; decision 65), n8n (Sustainable Use — grey zone), plex (proprietary, personal use; the household is the
|
||||
licensee), outline (BUSL-1.1 — only a commercial "Document Service"), redis:7-alpine 7.4.11 in four apps (RSALv2/SSPL —
|
||||
internal cache), meilisearch v1.36.0 EE modules (wanderer — not used), recipe-importer (Felhom's own, no licence file).
|
||||