main
32
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
7129cc346d |
perf(memory): keep install, update and runtime inside a small-RAM budget (#83)
* perf(memory): keep install, update and runtime inside a small-RAM budget Small NAT/VPS targets have 128-512MB of RAM and no swap, so anything that cannot be reclaimed is fatal. This tuning touches no swap and no mmap; it works by not allocating in the first place. Installer (covers install and update; update.sh only execs install.sh): - Put the scratch directory under DATA_DIR instead of mktemp -d. /tmp is tmpfs on many of these hosts, and without swap every byte there is pinned in RAM: bundle, extracted release and a copy of the data directory were held at once, exceeding total RAM of the machines being targeted. - Hash assets on the way to disk instead of re-reading them. Download is a single pass now; verification still completes before tar sees the bytes. - Release the intermediate data.tar right after extraction rather than holding the data directory twice for the rest of the run. - Check scratch capacity before downloading, so we fail before the old service is stopped rather than halfway through. - Refresh Environment=GOMEMLIMIT/GOGC/THREE_M_UI_CORE_LOW_MEMORY and MemoryMax on an existing unit. write_service() keeps an operator's unit, which meant the values baked in at install time never tracked updates. Panel: - Bound the Go heap from the process itself via debug.SetMemoryLimit, so the tuning reaches manual runs, containers and the installer's own init and healthcheck instead of only a systemd unit. It acts in-process, so the Mihomo core never inherits the panel's tighter GC target. An explicit GOMEMLIMIT or GOGC always wins. - Emit geodata-loader: memconservative for the core when low-memory mode is on. The key is omitempty and pinned after user fragments merge, so nothing changes for anyone who does not opt in, and no fragment can undo it. No new calls to Mmap/Munmap/Madvise, no swap or mmap anywhere in the tree. * fix(ci): keep the new scratch directory out of the installer's own paths Two problems CI caught on the small-memory change, both from moving the scratch directory from mktemp into DATA_DIR. restore_files() rebuilds the data directory by deleting everything in it except backups. The scratch directory now lives inside it, so a rollback deleted the very directory it was reading its own rollback out of, and the restore died looking for restore/ENABLED. Rollback therefore had to be skipped, exempting the scratch directory from that purge; the cleanup trap already removes it. The test curl also modelled only one of curl's output modes. Writing to stdout and answering -I are both normal curl behaviour, and both are now covered, so the mock no longer pins the installer to a single invocation shape. The distribution fake likewise emits its tampered asset on stdout instead of through --output, keeping that test about checksum rejection rather than about which flag was used. --------- Co-authored-by: 風雪 <kazeyukiro@users.noreply.github.com> perf(memory): keep install, update and runtime inside a small-RAM budget (#83) * perf(memory): keep install, update and runtime inside a small-RAM budget Small NAT/VPS targets have 128-512MB of RAM and no swap, so anything that cannot be reclaimed is fatal. This tuning touches no swap and no mmap; it works by not allocating in the first place. Installer (covers install and update; update.sh only execs install.sh): - Put the scratch directory under DATA_DIR instead of mktemp -d. /tmp is tmpfs on many of these hosts, and without swap every byte there is pinned in RAM: bundle, extracted release and a copy of the data directory were held at once, exceeding total RAM of the machines being targeted. - Hash assets on the way to disk instead of re-reading them. Download is a single pass now; verification still completes before tar sees the bytes. - Release the intermediate data.tar right after extraction rather than holding the data directory twice for the rest of the run. - Check scratch capacity before downloading, so we fail before the old service is stopped rather than halfway through. - Refresh Environment=GOMEMLIMIT/GOGC/THREE_M_UI_CORE_LOW_MEMORY and MemoryMax on an existing unit. write_service() keeps an operator's unit, which meant the values baked in at install time never tracked updates. Panel: - Bound the Go heap from the process itself via debug.SetMemoryLimit, so the tuning reaches manual runs, containers and the installer's own init and healthcheck instead of only a systemd unit. It acts in-process, so the Mihomo core never inherits the panel's tighter GC target. An explicit GOMEMLIMIT or GOGC always wins. - Emit geodata-loader: memconservative for the core when low-memory mode is on. The key is omitempty and pinned after user fragments merge, so nothing changes for anyone who does not opt in, and no fragment can undo it. No new calls to Mmap/Munmap/Madvise, no swap or mmap anywhere in the tree. * fix(ci): keep the new scratch directory out of the installer's own paths Two problems CI caught on the small-memory change, both from moving the scratch directory from mktemp into DATA_DIR. restore_files() rebuilds the data directory by deleting everything in it except backups. The scratch directory now lives inside it, so a rollback deleted the very directory it was reading its own rollback out of, and the restore died looking for restore/ENABLED. Rollback therefore had to be skipped, exempting the scratch directory from that purge; the cleanup trap already removes it. The test curl also modelled only one of curl's output modes. Writing to stdout and answering -I are both normal curl behaviour, and both are now covered, so the mock no longer pins the installer to a single invocation shape. The distribution fake likewise emits its tampered asset on stdout instead of through --output, keeping that test about checksum rejection rather than about which flag was used. --------- Co-authored-by: 風雪 <kazeyukiro@users.noreply.github.com> perf(memory): keep install, update and runtime inside a small-RAM budget (#83) * perf(memory): keep install, update and runtime inside a small-RAM budget Small NAT/VPS targets have 128-512MB of RAM and no swap, so anything that cannot be reclaimed is fatal. This tuning touches no swap and no mmap; it works by not allocating in the first place. Installer (covers install and update; update.sh only execs install.sh): - Put the scratch directory under DATA_DIR instead of mktemp -d. /tmp is tmpfs on many of these hosts, and without swap every byte there is pinned in RAM: bundle, extracted release and a copy of the data directory were held at once, exceeding total RAM of the machines being targeted. - Hash assets on the way to disk instead of re-reading them. Download is a single pass now; verification still completes before tar sees the bytes. - Release the intermediate data.tar right after extraction rather than holding the data directory twice for the rest of the run. - Check scratch capacity before downloading, so we fail before the old service is stopped rather than halfway through. - Refresh Environment=GOMEMLIMIT/GOGC/THREE_M_UI_CORE_LOW_MEMORY and MemoryMax on an existing unit. write_service() keeps an operator's unit, which meant the values baked in at install time never tracked updates. Panel: - Bound the Go heap from the process itself via debug.SetMemoryLimit, so the tuning reaches manual runs, containers and the installer's own init and healthcheck instead of only a systemd unit. It acts in-process, so the Mihomo core never inherits the panel's tighter GC target. An explicit GOMEMLIMIT or GOGC always wins. - Emit geodata-loader: memconservative for the core when low-memory mode is on. The key is omitempty and pinned after user fragments merge, so nothing changes for anyone who does not opt in, and no fragment can undo it. No new calls to Mmap/Munmap/Madvise, no swap or mmap anywhere in the tree. * fix(ci): keep the new scratch directory out of the installer's own paths Two problems CI caught on the small-memory change, both from moving the scratch directory from mktemp into DATA_DIR. restore_files() rebuilds the data directory by deleting everything in it except backups. The scratch directory now lives inside it, so a rollback deleted the very directory it was reading its own rollback out of, and the restore died looking for restore/ENABLED. Rollback therefore had to be skipped, exempting the scratch directory from that purge; the cleanup trap already removes it. The test curl also modelled only one of curl's output modes. Writing to stdout and answering -I are both normal curl behaviour, and both are now covered, so the mock no longer pins the installer to a single invocation shape. The distribution fake likewise emits its tampered asset on stdout instead of through --output, keeping that test about checksum rejection rather than about which flag was used. --------- Co-authored-by: 風雪 <kazeyukiro@users.noreply.github.com> perf(memory): keep install, update and runtime inside a small-RAM budget (#83) * perf(memory): keep install, update and runtime inside a small-RAM budget Small NAT/VPS targets have 128-512MB of RAM and no swap, so anything that cannot be reclaimed is fatal. This tuning touches no swap and no mmap; it works by not allocating in the first place. Installer (covers install and update; update.sh only execs install.sh): - Put the scratch directory under DATA_DIR instead of mktemp -d. /tmp is tmpfs on many of these hosts, and without swap every byte there is pinned in RAM: bundle, extracted release and a copy of the data directory were held at once, exceeding total RAM of the machines being targeted. - Hash assets on the way to disk instead of re-reading them. Download is a single pass now; verification still completes before tar sees the bytes. - Release the intermediate data.tar right after extraction rather than holding the data directory twice for the rest of the run. - Check scratch capacity before downloading, so we fail before the old service is stopped rather than halfway through. - Refresh Environment=GOMEMLIMIT/GOGC/THREE_M_UI_CORE_LOW_MEMORY and MemoryMax on an existing unit. write_service() keeps an operator's unit, which meant the values baked in at install time never tracked updates. Panel: - Bound the Go heap from the process itself via debug.SetMemoryLimit, so the tuning reaches manual runs, containers and the installer's own init and healthcheck instead of only a systemd unit. It acts in-process, so the Mihomo core never inherits the panel's tighter GC target. An explicit GOMEMLIMIT or GOGC always wins. - Emit geodata-loader: memconservative for the core when low-memory mode is on. The key is omitempty and pinned after user fragments merge, so nothing changes for anyone who does not opt in, and no fragment can undo it. No new calls to Mmap/Munmap/Madvise, no swap or mmap anywhere in the tree. * fix(ci): keep the new scratch directory out of the installer's own paths Two problems CI caught on the small-memory change, both from moving the scratch directory from mktemp into DATA_DIR. restore_files() rebuilds the data directory by deleting everything in it except backups. The scratch directory now lives inside it, so a rollback deleted the very directory it was reading its own rollback out of, and the restore died looking for restore/ENABLED. Rollback therefore had to be skipped, exempting the scratch directory from that purge; the cleanup trap already removes it. The test curl also modelled only one of curl's output modes. Writing to stdout and answering -I are both normal curl behaviour, and both are now covered, so the mock no longer pins the installer to a single invocation shape. The distribution fake likewise emits its tampered asset on stdout instead of through --output, keeping that test about checksum rejection rather than about which flag was used. --------- Co-authored-by: 風雪 <kazeyukiro@users.noreply.github.com> perf(memory): keep install, update and runtime inside a small-RAM budget (#83) * perf(memory): keep install, update and runtime inside a small-RAM budget Small NAT/VPS targets have 128-512MB of RAM and no swap, so anything that cannot be reclaimed is fatal. This tuning touches no swap and no mmap; it works by not allocating in the first place. Installer (covers install and update; update.sh only execs install.sh): - Put the scratch directory under DATA_DIR instead of mktemp -d. /tmp is tmpfs on many of these hosts, and without swap every byte there is pinned in RAM: bundle, extracted release and a copy of the data directory were held at once, exceeding total RAM of the machines being targeted. - Hash assets on the way to disk instead of re-reading them. Download is a single pass now; verification still completes before tar sees the bytes. - Release the intermediate data.tar right after extraction rather than holding the data directory twice for the rest of the run. - Check scratch capacity before downloading, so we fail before the old service is stopped rather than halfway through. - Refresh Environment=GOMEMLIMIT/GOGC/THREE_M_UI_CORE_LOW_MEMORY and MemoryMax on an existing unit. write_service() keeps an operator's unit, which meant the values baked in at install time never tracked updates. Panel: - Bound the Go heap from the process itself via debug.SetMemoryLimit, so the tuning reaches manual runs, containers and the installer's own init and healthcheck instead of only a systemd unit. It acts in-process, so the Mihomo core never inherits the panel's tighter GC target. An explicit GOMEMLIMIT or GOGC always wins. - Emit geodata-loader: memconservative for the core when low-memory mode is on. The key is omitempty and pinned after user fragments merge, so nothing changes for anyone who does not opt in, and no fragment can undo it. No new calls to Mmap/Munmap/Madvise, no swap or mmap anywhere in the tree. * fix(ci): keep the new scratch directory out of the installer's own paths Two problems CI caught on the small-memory change, both from moving the scratch directory from mktemp into DATA_DIR. restore_files() rebuilds the data directory by deleting everything in it except backups. The scratch directory now lives inside it, so a rollback deleted the very directory it was reading its own rollback out of, and the restore died looking for restore/ENABLED. Rollback therefore had to be skipped, exempting the scratch directory from that purge; the cleanup trap already removes it. The test curl also modelled only one of curl's output modes. Writing to stdout and answering -I are both normal curl behaviour, and both are now covered, so the mock no longer pins the installer to a single invocation shape. The distribution fake likewise emits its tampered asset on stdout instead of through --output, keeping that test about checksum rejection rather than about which flag was used. --------- Co-authored-by: 風雪 <kazeyukiro@users.noreply.github.com> perf(memory): keep install, update and runtime inside a small-RAM budget (#83) * perf(memory): keep install, update and runtime inside a small-RAM budget Small NAT/VPS targets have 128-512MB of RAM and no swap, so anything that cannot be reclaimed is fatal. This tuning touches no swap and no mmap; it works by not allocating in the first place. Installer (covers install and update; update.sh only execs install.sh): - Put the scratch directory under DATA_DIR instead of mktemp -d. /tmp is tmpfs on many of these hosts, and without swap every byte there is pinned in RAM: bundle, extracted release and a copy of the data directory were held at once, exceeding total RAM of the machines being targeted. - Hash assets on the way to disk instead of re-reading them. Download is a single pass now; verification still completes before tar sees the bytes. - Release the intermediate data.tar right after extraction rather than holding the data directory twice for the rest of the run. - Check scratch capacity before downloading, so we fail before the old service is stopped rather than halfway through. - Refresh Environment=GOMEMLIMIT/GOGC/THREE_M_UI_CORE_LOW_MEMORY and MemoryMax on an existing unit. write_service() keeps an operator's unit, which meant the values baked in at install time never tracked updates. Panel: - Bound the Go heap from the process itself via debug.SetMemoryLimit, so the tuning reaches manual runs, containers and the installer's own init and healthcheck instead of only a systemd unit. It acts in-process, so the Mihomo core never inherits the panel's tighter GC target. An explicit GOMEMLIMIT or GOGC always wins. - Emit geodata-loader: memconservative for the core when low-memory mode is on. The key is omitempty and pinned after user fragments merge, so nothing changes for anyone who does not opt in, and no fragment can undo it. No new calls to Mmap/Munmap/Madvise, no swap or mmap anywhere in the tree. * fix(ci): keep the new scratch directory out of the installer's own paths Two problems CI caught on the small-memory change, both from moving the scratch directory from mktemp into DATA_DIR. restore_files() rebuilds the data directory by deleting everything in it except backups. The scratch directory now lives inside it, so a rollback deleted the very directory it was reading its own rollback out of, and the restore died looking for restore/ENABLED. Rollback therefore had to be skipped, exempting the scratch directory from that purge; the cleanup trap already removes it. The test curl also modelled only one of curl's output modes. Writing to stdout and answering -I are both normal curl behaviour, and both are now covered, so the mock no longer pins the installer to a single invocation shape. The distribution fake likewise emits its tampered asset on stdout instead of through --output, keeping that test about checksum rejection rather than about which flag was used. --------- Co-authored-by: 風雪 <kazeyukiro@users.noreply.github.com> perf(memory): keep install, update and runtime inside a small-RAM budget (#83) * perf(memory): keep install, update and runtime inside a small-RAM budget Small NAT/VPS targets have 128-512MB of RAM and no swap, so anything that cannot be reclaimed is fatal. This tuning touches no swap and no mmap; it works by not allocating in the first place. Installer (covers install and update; update.sh only execs install.sh): - Put the scratch directory under DATA_DIR instead of mktemp -d. /tmp is tmpfs on many of these hosts, and without swap every byte there is pinned in RAM: bundle, extracted release and a copy of the data directory were held at once, exceeding total RAM of the machines being targeted. - Hash assets on the way to disk instead of re-reading them. Download is a single pass now; verification still completes before tar sees the bytes. - Release the intermediate data.tar right after extraction rather than holding the data directory twice for the rest of the run. - Check scratch capacity before downloading, so we fail before the old service is stopped rather than halfway through. - Refresh Environment=GOMEMLIMIT/GOGC/THREE_M_UI_CORE_LOW_MEMORY and MemoryMax on an existing unit. write_service() keeps an operator's unit, which meant the values baked in at install time never tracked updates. Panel: - Bound the Go heap from the process itself via debug.SetMemoryLimit, so the tuning reaches manual runs, containers and the installer's own init and healthcheck instead of only a systemd unit. It acts in-process, so the Mihomo core never inherits the panel's tighter GC target. An explicit GOMEMLIMIT or GOGC always wins. - Emit geodata-loader: memconservative for the core when low-memory mode is on. The key is omitempty and pinned after user fragments merge, so nothing changes for anyone who does not opt in, and no fragment can undo it. No new calls to Mmap/Munmap/Madvise, no swap or mmap anywhere in the tree. * fix(ci): keep the new scratch directory out of the installer's own paths Two problems CI caught on the small-memory change, both from moving the scratch directory from mktemp into DATA_DIR. restore_files() rebuilds the data directory by deleting everything in it except backups. The scratch directory now lives inside it, so a rollback deleted the very directory it was reading its own rollback out of, and the restore died looking for restore/ENABLED. Rollback therefore had to be skipped, exempting the scratch directory from that purge; the cleanup trap already removes it. The test curl also modelled only one of curl's output modes. Writing to stdout and answering -I are both normal curl behaviour, and both are now covered, so the mock no longer pins the installer to a single invocation shape. The distribution fake likewise emits its tampered asset on stdout instead of through --output, keeping that test about checksum rejection rather than about which flag was used. --------- Co-authored-by: 風雪 <kazeyukiro@users.noreply.github.com> perf(memory): keep install, update and runtime inside a small-RAM budget (#83) * perf(memory): keep install, update and runtime inside a small-RAM budget Small NAT/VPS targets have 128-512MB of RAM and no swap, so anything that cannot be reclaimed is fatal. This tuning touches no swap and no mmap; it works by not allocating in the first place. Installer (covers install and update; update.sh only execs install.sh): - Put the scratch directory under DATA_DIR instead of mktemp -d. /tmp is tmpfs on many of these hosts, and without swap every byte there is pinned in RAM: bundle, extracted release and a copy of the data directory were held at once, exceeding total RAM of the machines being targeted. - Hash assets on the way to disk instead of re-reading them. Download is a single pass now; verification still completes before tar sees the bytes. - Release the intermediate data.tar right after extraction rather than holding the data directory twice for the rest of the run. - Check scratch capacity before downloading, so we fail before the old service is stopped rather than halfway through. - Refresh Environment=GOMEMLIMIT/GOGC/THREE_M_UI_CORE_LOW_MEMORY and MemoryMax on an existing unit. write_service() keeps an operator's unit, which meant the values baked in at install time never tracked updates. Panel: - Bound the Go heap from the process itself via debug.SetMemoryLimit, so the tuning reaches manual runs, containers and the installer's own init and healthcheck instead of only a systemd unit. It acts in-process, so the Mihomo core never inherits the panel's tighter GC target. An explicit GOMEMLIMIT or GOGC always wins. - Emit geodata-loader: memconservative for the core when low-memory mode is on. The key is omitempty and pinned after user fragments merge, so nothing changes for anyone who does not opt in, and no fragment can undo it. No new calls to Mmap/Munmap/Madvise, no swap or mmap anywhere in the tree. * fix(ci): keep the new scratch directory out of the installer's own paths Two problems CI caught on the small-memory change, both from moving the scratch directory from mktemp into DATA_DIR. restore_files() rebuilds the data directory by deleting everything in it except backups. The scratch directory now lives inside it, so a rollback deleted the very directory it was reading its own rollback out of, and the restore died looking for restore/ENABLED. Rollback therefore had to be skipped, exempting the scratch directory from that purge; the cleanup trap already removes it. The test curl also modelled only one of curl's output modes. Writing to stdout and answering -I are both normal curl behaviour, and both are now covered, so the mock no longer pins the installer to a single invocation shape. The distribution fake likewise emits its tampered asset on stdout instead of through --output, keeping that test about checksum rejection rather than about which flag was used. --------- Co-authored-by: 風雪 <kazeyukiro@users.noreply.github.com> perf(memory): keep install, update and runtime inside a small-RAM budget (#83) * perf(memory): keep install, update and runtime inside a small-RAM budget Small NAT/VPS targets have 128-512MB of RAM and no swap, so anything that cannot be reclaimed is fatal. This tuning touches no swap and no mmap; it works by not allocating in the first place. Installer (covers install and update; update.sh only execs install.sh): - Put the scratch directory under DATA_DIR instead of mktemp -d. /tmp is tmpfs on many of these hosts, and without swap every byte there is pinned in RAM: bundle, extracted release and a copy of the data directory were held at once, exceeding total RAM of the machines being targeted. - Hash assets on the way to disk instead of re-reading them. Download is a single pass now; verification still completes before tar sees the bytes. - Release the intermediate data.tar right after extraction rather than holding the data directory twice for the rest of the run. - Check scratch capacity before downloading, so we fail before the old service is stopped rather than halfway through. - Refresh Environment=GOMEMLIMIT/GOGC/THREE_M_UI_CORE_LOW_MEMORY and MemoryMax on an existing unit. write_service() keeps an operator's unit, which meant the values baked in at install time never tracked updates. Panel: - Bound the Go heap from the process itself via debug.SetMemoryLimit, so the tuning reaches manual runs, containers and the installer's own init and healthcheck instead of only a systemd unit. It acts in-process, so the Mihomo core never inherits the panel's tighter GC target. An explicit GOMEMLIMIT or GOGC always wins. - Emit geodata-loader: memconservative for the core when low-memory mode is on. The key is omitempty and pinned after user fragments merge, so nothing changes for anyone who does not opt in, and no fragment can undo it. No new calls to Mmap/Munmap/Madvise, no swap or mmap anywhere in the tree. * fix(ci): keep the new scratch directory out of the installer's own paths Two problems CI caught on the small-memory change, both from moving the scratch directory from mktemp into DATA_DIR. restore_files() rebuilds the data directory by deleting everything in it except backups. The scratch directory now lives inside it, so a rollback deleted the very directory it was reading its own rollback out of, and the restore died looking for restore/ENABLED. Rollback therefore had to be skipped, exempting the scratch directory from that purge; the cleanup trap already removes it. The test curl also modelled only one of curl's output modes. Writing to stdout and answering -I are both normal curl behaviour, and both are now covered, so the mock no longer pins the installer to a single invocation shape. The distribution fake likewise emits its tampered asset on stdout instead of through --output, keeping that test about checksum rejection rather than about which flag was used. --------- Co-authored-by: 風雪 <kazeyukiro@users.noreply.github.com> perf(memory): keep install, update and runtime inside a small-RAM budget (#83) * perf(memory): keep install, update and runtime inside a small-RAM budget Small NAT/VPS targets have 128-512MB of RAM and no swap, so anything that cannot be reclaimed is fatal. This tuning touches no swap and no mmap; it works by not allocating in the first place. Installer (covers install and update; update.sh only execs install.sh): - Put the scratch directory under DATA_DIR instead of mktemp -d. /tmp is tmpfs on many of these hosts, and without swap every byte there is pinned in RAM: bundle, extracted release and a copy of the data directory were held at once, exceeding total RAM of the machines being targeted. - Hash assets on the way to disk instead of re-reading them. Download is a single pass now; verification still completes before tar sees the bytes. - Release the intermediate data.tar right after extraction rather than holding the data directory twice for the rest of the run. - Check scratch capacity before downloading, so we fail before the old service is stopped rather than halfway through. - Refresh Environment=GOMEMLIMIT/GOGC/THREE_M_UI_CORE_LOW_MEMORY and MemoryMax on an existing unit. write_service() keeps an operator's unit, which meant the values baked in at install time never tracked updates. Panel: - Bound the Go heap from the process itself via debug.SetMemoryLimit, so the tuning reaches manual runs, containers and the installer's own init and healthcheck instead of only a systemd unit. It acts in-process, so the Mihomo core never inherits the panel's tighter GC target. An explicit GOMEMLIMIT or GOGC always wins. - Emit geodata-loader: memconservative for the core when low-memory mode is on. The key is omitempty and pinned after user fragments merge, so nothing changes for anyone who does not opt in, and no fragment can undo it. No new calls to Mmap/Munmap/Madvise, no swap or mmap anywhere in the tree. * fix(ci): keep the new scratch directory out of the installer's own paths Two problems CI caught on the small-memory change, both from moving the scratch directory from mktemp into DATA_DIR. restore_files() rebuilds the data directory by deleting everything in it except backups. The scratch directory now lives inside it, so a rollback deleted the very directory it was reading its own rollback out of, and the restore died looking for restore/ENABLED. Rollback therefore had to be skipped, exempting the scratch directory from that purge; the cleanup trap already removes it. The test curl also modelled only one of curl's output modes. Writing to stdout and answering -I are both normal curl behaviour, and both are now covered, so the mock no longer pins the installer to a single invocation shape. The distribution fake likewise emits its tampered asset on stdout instead of through --output, keeping that test about checksum rejection rather than about which flag was used. --------- Co-authored-by: 風雪 <kazeyukiro@users.noreply.github.com> perf(memory): keep install, update and runtime inside a small-RAM budget (#83) * perf(memory): keep install, update and runtime inside a small-RAM budget Small NAT/VPS targets have 128-512MB of RAM and no swap, so anything that cannot be reclaimed is fatal. This tuning touches no swap and no mmap; it works by not allocating in the first place. Installer (covers install and update; update.sh only execs install.sh): - Put the scratch directory under DATA_DIR instead of mktemp -d. /tmp is tmpfs on many of these hosts, and without swap every byte there is pinned in RAM: bundle, extracted release and a copy of the data directory were held at once, exceeding total RAM of the machines being targeted. - Hash assets on the way to disk instead of re-reading them. Download is a single pass now; verification still completes before tar sees the bytes. - Release the intermediate data.tar right after extraction rather than holding the data directory twice for the rest of the run. - Check scratch capacity before downloading, so we fail before the old service is stopped rather than halfway through. - Refresh Environment=GOMEMLIMIT/GOGC/THREE_M_UI_CORE_LOW_MEMORY and MemoryMax on an existing unit. write_service() keeps an operator's unit, which meant the values baked in at install time never tracked updates. Panel: - Bound the Go heap from the process itself via debug.SetMemoryLimit, so the tuning reaches manual runs, containers and the installer's own init and healthcheck instead of only a systemd unit. It acts in-process, so the Mihomo core never inherits the panel's tighter GC target. An explicit GOMEMLIMIT or GOGC always wins. - Emit geodata-loader: memconservative for the core when low-memory mode is on. The key is omitempty and pinned after user fragments merge, so nothing changes for anyone who does not opt in, and no fragment can undo it. No new calls to Mmap/Munmap/Madvise, no swap or mmap anywhere in the tree. * fix(ci): keep the new scratch directory out of the installer's own paths Two problems CI caught on the small-memory change, both from moving the scratch directory from mktemp into DATA_DIR. restore_files() rebuilds the data directory by deleting everything in it except backups. The scratch directory now lives inside it, so a rollback deleted the very directory it was reading its own rollback out of, and the restore died looking for restore/ENABLED. Rollback therefore had to be skipped, exempting the scratch directory from that purge; the cleanup trap already removes it. The test curl also modelled only one of curl's output modes. Writing to stdout and answering -I are both normal curl behaviour, and both are now covered, so the mock no longer pins the installer to a single invocation shape. The distribution fake likewise emits its tampered asset on stdout instead of through --output, keeping that test about checksum rejection rather than about which flag was used. --------- Co-authored-by: 風雪 <kazeyukiro@users.noreply.github.com> perf(memory): keep install, update and runtime inside a small-RAM budget (#83) * perf(memory): keep install, update and runtime inside a small-RAM budget Small NAT/VPS targets have 128-512MB of RAM and no swap, so anything that cannot be reclaimed is fatal. This tuning touches no swap and no mmap; it works by not allocating in the first place. Installer (covers install and update; update.sh only execs install.sh): - Put the scratch directory under DATA_DIR instead of mktemp -d. /tmp is tmpfs on many of these hosts, and without swap every byte there is pinned in RAM: bundle, extracted release and a copy of the data directory were held at once, exceeding total RAM of the machines being targeted. - Hash assets on the way to disk instead of re-reading them. Download is a single pass now; verification still completes before tar sees the bytes. - Release the intermediate data.tar right after extraction rather than holding the data directory twice for the rest of the run. - Check scratch capacity before downloading, so we fail before the old service is stopped rather than halfway through. - Refresh Environment=GOMEMLIMIT/GOGC/THREE_M_UI_CORE_LOW_MEMORY and MemoryMax on an existing unit. write_service() keeps an operator's unit, which meant the values baked in at install time never tracked updates. Panel: - Bound the Go heap from the process itself via debug.SetMemoryLimit, so the tuning reaches manual runs, containers and the installer's own init and healthcheck instead of only a systemd unit. It acts in-process, so the Mihomo core never inherits the panel's tighter GC target. An explicit GOMEMLIMIT or GOGC always wins. - Emit geodata-loader: memconservative for the core when low-memory mode is on. The key is omitempty and pinned after user fragments merge, so nothing changes for anyone who does not opt in, and no fragment can undo it. No new calls to Mmap/Munmap/Madvise, no swap or mmap anywhere in the tree. * fix(ci): keep the new scratch directory out of the installer's own paths Two problems CI caught on the small-memory change, both from moving the scratch directory from mktemp into DATA_DIR. restore_files() rebuilds the data directory by deleting everything in it except backups. The scratch directory now lives inside it, so a rollback deleted the very directory it was reading its own rollback out of, and the restore died looking for restore/ENABLED. Rollback therefore had to be skipped, exempting the scratch directory from that purge; the cleanup trap already removes it. The test curl also modelled only one of curl's output modes. Writing to stdout and answering -I are both normal curl behaviour, and both are now covered, so the mock no longer pins the installer to a single invocation shape. The distribution fake likewise emits its tampered asset on stdout instead of through --output, keeping that test about checksum rejection rather than about which flag was used. --------- Co-authored-by: 風雪 <kazeyukiro@users.noreply.github.com> |
||
|
|
d50664377f |
feat(mem): Go runtime memory auto-tuning (no swap, no mmap)
Pure Go runtime tuning via GOMEMLIMIT + GOGC, applied at every stage of install AND update. No swap file creation. No mmap tricks. 4-tier auto-detection based on /proc/meminfo: RAM ≤ 128MB: GOMEMLIMIT=48MiB GOGC=20 MemoryMax=72M RAM ≤ 256MB: GOMEMLIMIT=96MiB GOGC=50 MemoryMax=144M RAM ≤ 512MB: GOMEMLIMIT=192MiB GOGC=75 MemoryMax=288M RAM > 512MB: off GOGC=100 MemoryMax=infinity Applied to: 1. Early: export GOMEMLIMIT/GOGC before install_deps so download + extract + init all inherit the limits. 2. init step: explicitly passed GOMEMLIMIT/GOGC to the Go binary. 3. healthcheck: explicitly passed to the Go binary. 4. systemd unit: Environment=GOMEMLIMIT=... + Environment=GOGC=... + MemoryMax=... (hard OOM cap, kills panel not SSH). 5. OpenRC unit (Alpine): export GOMEMLIMIT/GOGC (OpenRC doesn't support MemoryMax, but GOMEMLIMIT handles it at Go runtime level). Override: THREE_M_UI_GOMEMLIMIT=80MiB THREE_M_UI_GOGC=75 Why this works without swap: - GOMEMLIMIT tells Go GC 'you have X MiB of heap, GC aggressively to stay under it'. Go runtime respects this natively (Go 1.19+). - GOGC=20 means GC triggers at 1.2x live heap (vs default 2x), keeping RSS tight at the cost of ~3-5% more CPU. - MemoryMax is the systemd safety net: if Go somehow leaks past GOMEMLIMIT×1.5, systemd kills the panel (which Restart=always brings back), not SSH. - No swap needed: the goal is to keep RSS within physical RAM, not to extend virtual memory. feat(mem): Go runtime memory auto-tuning (no swap, no mmap) Pure Go runtime tuning via GOMEMLIMIT + GOGC, applied at every stage of install AND update. No swap file creation. No mmap tricks. 4-tier auto-detection based on /proc/meminfo: RAM ≤ 128MB: GOMEMLIMIT=48MiB GOGC=20 MemoryMax=72M RAM ≤ 256MB: GOMEMLIMIT=96MiB GOGC=50 MemoryMax=144M RAM ≤ 512MB: GOMEMLIMIT=192MiB GOGC=75 MemoryMax=288M RAM > 512MB: off GOGC=100 MemoryMax=infinity Applied to: 1. Early: export GOMEMLIMIT/GOGC before install_deps so download + extract + init all inherit the limits. 2. init step: explicitly passed GOMEMLIMIT/GOGC to the Go binary. 3. healthcheck: explicitly passed to the Go binary. 4. systemd unit: Environment=GOMEMLIMIT=... + Environment=GOGC=... + MemoryMax=... (hard OOM cap, kills panel not SSH). 5. OpenRC unit (Alpine): export GOMEMLIMIT/GOGC (OpenRC doesn't support MemoryMax, but GOMEMLIMIT handles it at Go runtime level). Override: THREE_M_UI_GOMEMLIMIT=80MiB THREE_M_UI_GOGC=75 Why this works without swap: - GOMEMLIMIT tells Go GC 'you have X MiB of heap, GC aggressively to stay under it'. Go runtime respects this natively (Go 1.19+). - GOGC=20 means GC triggers at 1.2x live heap (vs default 2x), keeping RSS tight at the cost of ~3-5% more CPU. - MemoryMax is the systemd safety net: if Go somehow leaks past GOMEMLIMIT×1.5, systemd kills the panel (which Restart=always brings back), not SSH. - No swap needed: the goal is to keep RSS within physical RAM, not to extend virtual memory. feat(mem): Go runtime memory auto-tuning (no swap, no mmap) Pure Go runtime tuning via GOMEMLIMIT + GOGC, applied at every stage of install AND update. No swap file creation. No mmap tricks. 4-tier auto-detection based on /proc/meminfo: RAM ≤ 128MB: GOMEMLIMIT=48MiB GOGC=20 MemoryMax=72M RAM ≤ 256MB: GOMEMLIMIT=96MiB GOGC=50 MemoryMax=144M RAM ≤ 512MB: GOMEMLIMIT=192MiB GOGC=75 MemoryMax=288M RAM > 512MB: off GOGC=100 MemoryMax=infinity Applied to: 1. Early: export GOMEMLIMIT/GOGC before install_deps so download + extract + init all inherit the limits. 2. init step: explicitly passed GOMEMLIMIT/GOGC to the Go binary. 3. healthcheck: explicitly passed to the Go binary. 4. systemd unit: Environment=GOMEMLIMIT=... + Environment=GOGC=... + MemoryMax=... (hard OOM cap, kills panel not SSH). 5. OpenRC unit (Alpine): export GOMEMLIMIT/GOGC (OpenRC doesn't support MemoryMax, but GOMEMLIMIT handles it at Go runtime level). Override: THREE_M_UI_GOMEMLIMIT=80MiB THREE_M_UI_GOGC=75 Why this works without swap: - GOMEMLIMIT tells Go GC 'you have X MiB of heap, GC aggressively to stay under it'. Go runtime respects this natively (Go 1.19+). - GOGC=20 means GC triggers at 1.2x live heap (vs default 2x), keeping RSS tight at the cost of ~3-5% more CPU. - MemoryMax is the systemd safety net: if Go somehow leaks past GOMEMLIMIT×1.5, systemd kills the panel (which Restart=always brings back), not SSH. - No swap needed: the goal is to keep RSS within physical RAM, not to extend virtual memory. feat(mem): Go runtime memory auto-tuning (no swap, no mmap) Pure Go runtime tuning via GOMEMLIMIT + GOGC, applied at every stage of install AND update. No swap file creation. No mmap tricks. 4-tier auto-detection based on /proc/meminfo: RAM ≤ 128MB: GOMEMLIMIT=48MiB GOGC=20 MemoryMax=72M RAM ≤ 256MB: GOMEMLIMIT=96MiB GOGC=50 MemoryMax=144M RAM ≤ 512MB: GOMEMLIMIT=192MiB GOGC=75 MemoryMax=288M RAM > 512MB: off GOGC=100 MemoryMax=infinity Applied to: 1. Early: export GOMEMLIMIT/GOGC before install_deps so download + extract + init all inherit the limits. 2. init step: explicitly passed GOMEMLIMIT/GOGC to the Go binary. 3. healthcheck: explicitly passed to the Go binary. 4. systemd unit: Environment=GOMEMLIMIT=... + Environment=GOGC=... + MemoryMax=... (hard OOM cap, kills panel not SSH). 5. OpenRC unit (Alpine): export GOMEMLIMIT/GOGC (OpenRC doesn't support MemoryMax, but GOMEMLIMIT handles it at Go runtime level). Override: THREE_M_UI_GOMEMLIMIT=80MiB THREE_M_UI_GOGC=75 Why this works without swap: - GOMEMLIMIT tells Go GC 'you have X MiB of heap, GC aggressively to stay under it'. Go runtime respects this natively (Go 1.19+). - GOGC=20 means GC triggers at 1.2x live heap (vs default 2x), keeping RSS tight at the cost of ~3-5% more CPU. - MemoryMax is the systemd safety net: if Go somehow leaks past GOMEMLIMIT×1.5, systemd kills the panel (which Restart=always brings back), not SSH. - No swap needed: the goal is to keep RSS within physical RAM, not to extend virtual memory. feat(mem): Go runtime memory auto-tuning (no swap, no mmap) Pure Go runtime tuning via GOMEMLIMIT + GOGC, applied at every stage of install AND update. No swap file creation. No mmap tricks. 4-tier auto-detection based on /proc/meminfo: RAM ≤ 128MB: GOMEMLIMIT=48MiB GOGC=20 MemoryMax=72M RAM ≤ 256MB: GOMEMLIMIT=96MiB GOGC=50 MemoryMax=144M RAM ≤ 512MB: GOMEMLIMIT=192MiB GOGC=75 MemoryMax=288M RAM > 512MB: off GOGC=100 MemoryMax=infinity Applied to: 1. Early: export GOMEMLIMIT/GOGC before install_deps so download + extract + init all inherit the limits. 2. init step: explicitly passed GOMEMLIMIT/GOGC to the Go binary. 3. healthcheck: explicitly passed to the Go binary. 4. systemd unit: Environment=GOMEMLIMIT=... + Environment=GOGC=... + MemoryMax=... (hard OOM cap, kills panel not SSH). 5. OpenRC unit (Alpine): export GOMEMLIMIT/GOGC (OpenRC doesn't support MemoryMax, but GOMEMLIMIT handles it at Go runtime level). Override: THREE_M_UI_GOMEMLIMIT=80MiB THREE_M_UI_GOGC=75 Why this works without swap: - GOMEMLIMIT tells Go GC 'you have X MiB of heap, GC aggressively to stay under it'. Go runtime respects this natively (Go 1.19+). - GOGC=20 means GC triggers at 1.2x live heap (vs default 2x), keeping RSS tight at the cost of ~3-5% more CPU. - MemoryMax is the systemd safety net: if Go somehow leaks past GOMEMLIMIT×1.5, systemd kills the panel (which Restart=always brings back), not SSH. - No swap needed: the goal is to keep RSS within physical RAM, not to extend virtual memory. feat(mem): Go runtime memory auto-tuning (no swap, no mmap) Pure Go runtime tuning via GOMEMLIMIT + GOGC, applied at every stage of install AND update. No swap file creation. No mmap tricks. 4-tier auto-detection based on /proc/meminfo: RAM ≤ 128MB: GOMEMLIMIT=48MiB GOGC=20 MemoryMax=72M RAM ≤ 256MB: GOMEMLIMIT=96MiB GOGC=50 MemoryMax=144M RAM ≤ 512MB: GOMEMLIMIT=192MiB GOGC=75 MemoryMax=288M RAM > 512MB: off GOGC=100 MemoryMax=infinity Applied to: 1. Early: export GOMEMLIMIT/GOGC before install_deps so download + extract + init all inherit the limits. 2. init step: explicitly passed GOMEMLIMIT/GOGC to the Go binary. 3. healthcheck: explicitly passed to the Go binary. 4. systemd unit: Environment=GOMEMLIMIT=... + Environment=GOGC=... + MemoryMax=... (hard OOM cap, kills panel not SSH). 5. OpenRC unit (Alpine): export GOMEMLIMIT/GOGC (OpenRC doesn't support MemoryMax, but GOMEMLIMIT handles it at Go runtime level). Override: THREE_M_UI_GOMEMLIMIT=80MiB THREE_M_UI_GOGC=75 Why this works without swap: - GOMEMLIMIT tells Go GC 'you have X MiB of heap, GC aggressively to stay under it'. Go runtime respects this natively (Go 1.19+). - GOGC=20 means GC triggers at 1.2x live heap (vs default 2x), keeping RSS tight at the cost of ~3-5% more CPU. - MemoryMax is the systemd safety net: if Go somehow leaks past GOMEMLIMIT×1.5, systemd kills the panel (which Restart=always brings back), not SSH. - No swap needed: the goal is to keep RSS within physical RAM, not to extend virtual memory. feat(mem): Go runtime memory auto-tuning (no swap, no mmap) Pure Go runtime tuning via GOMEMLIMIT + GOGC, applied at every stage of install AND update. No swap file creation. No mmap tricks. 4-tier auto-detection based on /proc/meminfo: RAM ≤ 128MB: GOMEMLIMIT=48MiB GOGC=20 MemoryMax=72M RAM ≤ 256MB: GOMEMLIMIT=96MiB GOGC=50 MemoryMax=144M RAM ≤ 512MB: GOMEMLIMIT=192MiB GOGC=75 MemoryMax=288M RAM > 512MB: off GOGC=100 MemoryMax=infinity Applied to: 1. Early: export GOMEMLIMIT/GOGC before install_deps so download + extract + init all inherit the limits. 2. init step: explicitly passed GOMEMLIMIT/GOGC to the Go binary. 3. healthcheck: explicitly passed to the Go binary. 4. systemd unit: Environment=GOMEMLIMIT=... + Environment=GOGC=... + MemoryMax=... (hard OOM cap, kills panel not SSH). 5. OpenRC unit (Alpine): export GOMEMLIMIT/GOGC (OpenRC doesn't support MemoryMax, but GOMEMLIMIT handles it at Go runtime level). Override: THREE_M_UI_GOMEMLIMIT=80MiB THREE_M_UI_GOGC=75 Why this works without swap: - GOMEMLIMIT tells Go GC 'you have X MiB of heap, GC aggressively to stay under it'. Go runtime respects this natively (Go 1.19+). - GOGC=20 means GC triggers at 1.2x live heap (vs default 2x), keeping RSS tight at the cost of ~3-5% more CPU. - MemoryMax is the systemd safety net: if Go somehow leaks past GOMEMLIMIT×1.5, systemd kills the panel (which Restart=always brings back), not SSH. - No swap needed: the goal is to keep RSS within physical RAM, not to extend virtual memory. feat(mem): Go runtime memory auto-tuning (no swap, no mmap) Pure Go runtime tuning via GOMEMLIMIT + GOGC, applied at every stage of install AND update. No swap file creation. No mmap tricks. 4-tier auto-detection based on /proc/meminfo: RAM ≤ 128MB: GOMEMLIMIT=48MiB GOGC=20 MemoryMax=72M RAM ≤ 256MB: GOMEMLIMIT=96MiB GOGC=50 MemoryMax=144M RAM ≤ 512MB: GOMEMLIMIT=192MiB GOGC=75 MemoryMax=288M RAM > 512MB: off GOGC=100 MemoryMax=infinity Applied to: 1. Early: export GOMEMLIMIT/GOGC before install_deps so download + extract + init all inherit the limits. 2. init step: explicitly passed GOMEMLIMIT/GOGC to the Go binary. 3. healthcheck: explicitly passed to the Go binary. 4. systemd unit: Environment=GOMEMLIMIT=... + Environment=GOGC=... + MemoryMax=... (hard OOM cap, kills panel not SSH). 5. OpenRC unit (Alpine): export GOMEMLIMIT/GOGC (OpenRC doesn't support MemoryMax, but GOMEMLIMIT handles it at Go runtime level). Override: THREE_M_UI_GOMEMLIMIT=80MiB THREE_M_UI_GOGC=75 Why this works without swap: - GOMEMLIMIT tells Go GC 'you have X MiB of heap, GC aggressively to stay under it'. Go runtime respects this natively (Go 1.19+). - GOGC=20 means GC triggers at 1.2x live heap (vs default 2x), keeping RSS tight at the cost of ~3-5% more CPU. - MemoryMax is the systemd safety net: if Go somehow leaks past GOMEMLIMIT×1.5, systemd kills the panel (which Restart=always brings back), not SSH. - No swap needed: the goal is to keep RSS within physical RAM, not to extend virtual memory. feat(mem): Go runtime memory auto-tuning (no swap, no mmap) Pure Go runtime tuning via GOMEMLIMIT + GOGC, applied at every stage of install AND update. No swap file creation. No mmap tricks. 4-tier auto-detection based on /proc/meminfo: RAM ≤ 128MB: GOMEMLIMIT=48MiB GOGC=20 MemoryMax=72M RAM ≤ 256MB: GOMEMLIMIT=96MiB GOGC=50 MemoryMax=144M RAM ≤ 512MB: GOMEMLIMIT=192MiB GOGC=75 MemoryMax=288M RAM > 512MB: off GOGC=100 MemoryMax=infinity Applied to: 1. Early: export GOMEMLIMIT/GOGC before install_deps so download + extract + init all inherit the limits. 2. init step: explicitly passed GOMEMLIMIT/GOGC to the Go binary. 3. healthcheck: explicitly passed to the Go binary. 4. systemd unit: Environment=GOMEMLIMIT=... + Environment=GOGC=... + MemoryMax=... (hard OOM cap, kills panel not SSH). 5. OpenRC unit (Alpine): export GOMEMLIMIT/GOGC (OpenRC doesn't support MemoryMax, but GOMEMLIMIT handles it at Go runtime level). Override: THREE_M_UI_GOMEMLIMIT=80MiB THREE_M_UI_GOGC=75 Why this works without swap: - GOMEMLIMIT tells Go GC 'you have X MiB of heap, GC aggressively to stay under it'. Go runtime respects this natively (Go 1.19+). - GOGC=20 means GC triggers at 1.2x live heap (vs default 2x), keeping RSS tight at the cost of ~3-5% more CPU. - MemoryMax is the systemd safety net: if Go somehow leaks past GOMEMLIMIT×1.5, systemd kills the panel (which Restart=always brings back), not SSH. - No swap needed: the goal is to keep RSS within physical RAM, not to extend virtual memory. feat(mem): Go runtime memory auto-tuning (no swap, no mmap) Pure Go runtime tuning via GOMEMLIMIT + GOGC, applied at every stage of install AND update. No swap file creation. No mmap tricks. 4-tier auto-detection based on /proc/meminfo: RAM ≤ 128MB: GOMEMLIMIT=48MiB GOGC=20 MemoryMax=72M RAM ≤ 256MB: GOMEMLIMIT=96MiB GOGC=50 MemoryMax=144M RAM ≤ 512MB: GOMEMLIMIT=192MiB GOGC=75 MemoryMax=288M RAM > 512MB: off GOGC=100 MemoryMax=infinity Applied to: 1. Early: export GOMEMLIMIT/GOGC before install_deps so download + extract + init all inherit the limits. 2. init step: explicitly passed GOMEMLIMIT/GOGC to the Go binary. 3. healthcheck: explicitly passed to the Go binary. 4. systemd unit: Environment=GOMEMLIMIT=... + Environment=GOGC=... + MemoryMax=... (hard OOM cap, kills panel not SSH). 5. OpenRC unit (Alpine): export GOMEMLIMIT/GOGC (OpenRC doesn't support MemoryMax, but GOMEMLIMIT handles it at Go runtime level). Override: THREE_M_UI_GOMEMLIMIT=80MiB THREE_M_UI_GOGC=75 Why this works without swap: - GOMEMLIMIT tells Go GC 'you have X MiB of heap, GC aggressively to stay under it'. Go runtime respects this natively (Go 1.19+). - GOGC=20 means GC triggers at 1.2x live heap (vs default 2x), keeping RSS tight at the cost of ~3-5% more CPU. - MemoryMax is the systemd safety net: if Go somehow leaks past GOMEMLIMIT×1.5, systemd kills the panel (which Restart=always brings back), not SSH. - No swap needed: the goal is to keep RSS within physical RAM, not to extend virtual memory. feat(mem): Go runtime memory auto-tuning (no swap, no mmap) Pure Go runtime tuning via GOMEMLIMIT + GOGC, applied at every stage of install AND update. No swap file creation. No mmap tricks. 4-tier auto-detection based on /proc/meminfo: RAM ≤ 128MB: GOMEMLIMIT=48MiB GOGC=20 MemoryMax=72M RAM ≤ 256MB: GOMEMLIMIT=96MiB GOGC=50 MemoryMax=144M RAM ≤ 512MB: GOMEMLIMIT=192MiB GOGC=75 MemoryMax=288M RAM > 512MB: off GOGC=100 MemoryMax=infinity Applied to: 1. Early: export GOMEMLIMIT/GOGC before install_deps so download + extract + init all inherit the limits. 2. init step: explicitly passed GOMEMLIMIT/GOGC to the Go binary. 3. healthcheck: explicitly passed to the Go binary. 4. systemd unit: Environment=GOMEMLIMIT=... + Environment=GOGC=... + MemoryMax=... (hard OOM cap, kills panel not SSH). 5. OpenRC unit (Alpine): export GOMEMLIMIT/GOGC (OpenRC doesn't support MemoryMax, but GOMEMLIMIT handles it at Go runtime level). Override: THREE_M_UI_GOMEMLIMIT=80MiB THREE_M_UI_GOGC=75 Why this works without swap: - GOMEMLIMIT tells Go GC 'you have X MiB of heap, GC aggressively to stay under it'. Go runtime respects this natively (Go 1.19+). - GOGC=20 means GC triggers at 1.2x live heap (vs default 2x), keeping RSS tight at the cost of ~3-5% more CPU. - MemoryMax is the systemd safety net: if Go somehow leaks past GOMEMLIMIT×1.5, systemd kills the panel (which Restart=always brings back), not SSH. - No swap needed: the goal is to keep RSS within physical RAM, not to extend virtual memory. feat(mem): Go runtime memory auto-tuning (no swap, no mmap) Pure Go runtime tuning via GOMEMLIMIT + GOGC, applied at every stage of install AND update. No swap file creation. No mmap tricks. 4-tier auto-detection based on /proc/meminfo: RAM ≤ 128MB: GOMEMLIMIT=48MiB GOGC=20 MemoryMax=72M RAM ≤ 256MB: GOMEMLIMIT=96MiB GOGC=50 MemoryMax=144M RAM ≤ 512MB: GOMEMLIMIT=192MiB GOGC=75 MemoryMax=288M RAM > 512MB: off GOGC=100 MemoryMax=infinity Applied to: 1. Early: export GOMEMLIMIT/GOGC before install_deps so download + extract + init all inherit the limits. 2. init step: explicitly passed GOMEMLIMIT/GOGC to the Go binary. 3. healthcheck: explicitly passed to the Go binary. 4. systemd unit: Environment=GOMEMLIMIT=... + Environment=GOGC=... + MemoryMax=... (hard OOM cap, kills panel not SSH). 5. OpenRC unit (Alpine): export GOMEMLIMIT/GOGC (OpenRC doesn't support MemoryMax, but GOMEMLIMIT handles it at Go runtime level). Override: THREE_M_UI_GOMEMLIMIT=80MiB THREE_M_UI_GOGC=75 Why this works without swap: - GOMEMLIMIT tells Go GC 'you have X MiB of heap, GC aggressively to stay under it'. Go runtime respects this natively (Go 1.19+). - GOGC=20 means GC triggers at 1.2x live heap (vs default 2x), keeping RSS tight at the cost of ~3-5% more CPU. - MemoryMax is the systemd safety net: if Go somehow leaks past GOMEMLIMIT×1.5, systemd kills the panel (which Restart=always brings back), not SSH. - No swap needed: the goal is to keep RSS within physical RAM, not to extend virtual memory. |
||
|
|
0918929195 |
fix(update): run self-update outside 3m-ui.service cgroup
Panel web update and any updater still inside the service were killed by systemctl stop before start. Schedule via systemd-run (fallback setsid) and re-escape in install.sh when cgroup is 3m-ui.service. fix(update): run self-update outside 3m-ui.service cgroup Panel web update and any updater still inside the service were killed by systemctl stop before start. Schedule via systemd-run (fallback setsid) and re-escape in install.sh when cgroup is 3m-ui.service. fix(update): run self-update outside 3m-ui.service cgroup Panel web update and any updater still inside the service were killed by systemctl stop before start. Schedule via systemd-run (fallback setsid) and re-escape in install.sh when cgroup is 3m-ui.service. fix(update): run self-update outside 3m-ui.service cgroup Panel web update and any updater still inside the service were killed by systemctl stop before start. Schedule via systemd-run (fallback setsid) and re-escape in install.sh when cgroup is 3m-ui.service. fix(update): run self-update outside 3m-ui.service cgroup Panel web update and any updater still inside the service were killed by systemctl stop before start. Schedule via systemd-run (fallback setsid) and re-escape in install.sh when cgroup is 3m-ui.service. fix(update): run self-update outside 3m-ui.service cgroup Panel web update and any updater still inside the service were killed by systemctl stop before start. Schedule via systemd-run (fallback setsid) and re-escape in install.sh when cgroup is 3m-ui.service. fix(update): run self-update outside 3m-ui.service cgroup Panel web update and any updater still inside the service were killed by systemctl stop before start. Schedule via systemd-run (fallback setsid) and re-escape in install.sh when cgroup is 3m-ui.service. fix(update): run self-update outside 3m-ui.service cgroup Panel web update and any updater still inside the service were killed by systemctl stop before start. Schedule via systemd-run (fallback setsid) and re-escape in install.sh when cgroup is 3m-ui.service. fix(update): run self-update outside 3m-ui.service cgroup Panel web update and any updater still inside the service were killed by systemctl stop before start. Schedule via systemd-run (fallback setsid) and re-escape in install.sh when cgroup is 3m-ui.service. fix(update): run self-update outside 3m-ui.service cgroup Panel web update and any updater still inside the service were killed by systemctl stop before start. Schedule via systemd-run (fallback setsid) and re-escape in install.sh when cgroup is 3m-ui.service. fix(update): run self-update outside 3m-ui.service cgroup Panel web update and any updater still inside the service were killed by systemctl stop before start. Schedule via systemd-run (fallback setsid) and re-escape in install.sh when cgroup is 3m-ui.service. fix(update): run self-update outside 3m-ui.service cgroup Panel web update and any updater still inside the service were killed by systemctl stop before start. Schedule via systemd-run (fallback setsid) and re-escape in install.sh when cgroup is 3m-ui.service. |
||
|
|
00249cd168 |
feat(scripts): wire reset-config into 3m-ui CLI wrapper + install hint
The new '3m-ui reset-config' Go subcommand (commit 8639b01) lets SSH operators undo panel misconfigurations (wrong port / 127.0.0.1 bind / broken SSL). This change exposes it through the systemd management wrapper and documents it in the install banner. scripts/3m-ui.sh: - Add 'reset_config' function: stops the panel service (required by the Go binary since it writes config.yaml + DB rows the running panel might cache), invokes 3m-ui-bin reset-config <flags>, then restarts the panel. - --help / -h short-circuits the stop/restart cycle (read-only). - Add 'reset-config' to the main case dispatch. - Document the new subcommand + flags in usage() with examples. scripts/install.sh: - Append a line to the post-install banner pointing operators at '3m-ui reset-config --panel --yes' for SSH rescue scenarios. USAGE sudo 3m-ui reset-config # interactive y/N, panel scope sudo 3m-ui reset-config --panel --yes # scripted rescue (common case) sudo 3m-ui reset-config --all --yes # full reset sudo 3m-ui reset-config --help # full help (no service touched) Smoke-tested with a fake binary: dispatch + flag passthrough + env vars all correct; --help does not stop the service. feat(scripts): wire reset-config into 3m-ui CLI wrapper + install hint The new '3m-ui reset-config' Go subcommand (commit 8639b01) lets SSH operators undo panel misconfigurations (wrong port / 127.0.0.1 bind / broken SSL). This change exposes it through the systemd management wrapper and documents it in the install banner. scripts/3m-ui.sh: - Add 'reset_config' function: stops the panel service (required by the Go binary since it writes config.yaml + DB rows the running panel might cache), invokes 3m-ui-bin reset-config <flags>, then restarts the panel. - --help / -h short-circuits the stop/restart cycle (read-only). - Add 'reset-config' to the main case dispatch. - Document the new subcommand + flags in usage() with examples. scripts/install.sh: - Append a line to the post-install banner pointing operators at '3m-ui reset-config --panel --yes' for SSH rescue scenarios. USAGE sudo 3m-ui reset-config # interactive y/N, panel scope sudo 3m-ui reset-config --panel --yes # scripted rescue (common case) sudo 3m-ui reset-config --all --yes # full reset sudo 3m-ui reset-config --help # full help (no service touched) Smoke-tested with a fake binary: dispatch + flag passthrough + env vars all correct; --help does not stop the service. feat(scripts): wire reset-config into 3m-ui CLI wrapper + install hint The new '3m-ui reset-config' Go subcommand (commit 8639b01) lets SSH operators undo panel misconfigurations (wrong port / 127.0.0.1 bind / broken SSL). This change exposes it through the systemd management wrapper and documents it in the install banner. scripts/3m-ui.sh: - Add 'reset_config' function: stops the panel service (required by the Go binary since it writes config.yaml + DB rows the running panel might cache), invokes 3m-ui-bin reset-config <flags>, then restarts the panel. - --help / -h short-circuits the stop/restart cycle (read-only). - Add 'reset-config' to the main case dispatch. - Document the new subcommand + flags in usage() with examples. scripts/install.sh: - Append a line to the post-install banner pointing operators at '3m-ui reset-config --panel --yes' for SSH rescue scenarios. USAGE sudo 3m-ui reset-config # interactive y/N, panel scope sudo 3m-ui reset-config --panel --yes # scripted rescue (common case) sudo 3m-ui reset-config --all --yes # full reset sudo 3m-ui reset-config --help # full help (no service touched) Smoke-tested with a fake binary: dispatch + flag passthrough + env vars all correct; --help does not stop the service. feat(scripts): wire reset-config into 3m-ui CLI wrapper + install hint The new '3m-ui reset-config' Go subcommand (commit 8639b01) lets SSH operators undo panel misconfigurations (wrong port / 127.0.0.1 bind / broken SSL). This change exposes it through the systemd management wrapper and documents it in the install banner. scripts/3m-ui.sh: - Add 'reset_config' function: stops the panel service (required by the Go binary since it writes config.yaml + DB rows the running panel might cache), invokes 3m-ui-bin reset-config <flags>, then restarts the panel. - --help / -h short-circuits the stop/restart cycle (read-only). - Add 'reset-config' to the main case dispatch. - Document the new subcommand + flags in usage() with examples. scripts/install.sh: - Append a line to the post-install banner pointing operators at '3m-ui reset-config --panel --yes' for SSH rescue scenarios. USAGE sudo 3m-ui reset-config # interactive y/N, panel scope sudo 3m-ui reset-config --panel --yes # scripted rescue (common case) sudo 3m-ui reset-config --all --yes # full reset sudo 3m-ui reset-config --help # full help (no service touched) Smoke-tested with a fake binary: dispatch + flag passthrough + env vars all correct; --help does not stop the service. feat(scripts): wire reset-config into 3m-ui CLI wrapper + install hint The new '3m-ui reset-config' Go subcommand (commit 8639b01) lets SSH operators undo panel misconfigurations (wrong port / 127.0.0.1 bind / broken SSL). This change exposes it through the systemd management wrapper and documents it in the install banner. scripts/3m-ui.sh: - Add 'reset_config' function: stops the panel service (required by the Go binary since it writes config.yaml + DB rows the running panel might cache), invokes 3m-ui-bin reset-config <flags>, then restarts the panel. - --help / -h short-circuits the stop/restart cycle (read-only). - Add 'reset-config' to the main case dispatch. - Document the new subcommand + flags in usage() with examples. scripts/install.sh: - Append a line to the post-install banner pointing operators at '3m-ui reset-config --panel --yes' for SSH rescue scenarios. USAGE sudo 3m-ui reset-config # interactive y/N, panel scope sudo 3m-ui reset-config --panel --yes # scripted rescue (common case) sudo 3m-ui reset-config --all --yes # full reset sudo 3m-ui reset-config --help # full help (no service touched) Smoke-tested with a fake binary: dispatch + flag passthrough + env vars all correct; --help does not stop the service. feat(scripts): wire reset-config into 3m-ui CLI wrapper + install hint The new '3m-ui reset-config' Go subcommand (commit 8639b01) lets SSH operators undo panel misconfigurations (wrong port / 127.0.0.1 bind / broken SSL). This change exposes it through the systemd management wrapper and documents it in the install banner. scripts/3m-ui.sh: - Add 'reset_config' function: stops the panel service (required by the Go binary since it writes config.yaml + DB rows the running panel might cache), invokes 3m-ui-bin reset-config <flags>, then restarts the panel. - --help / -h short-circuits the stop/restart cycle (read-only). - Add 'reset-config' to the main case dispatch. - Document the new subcommand + flags in usage() with examples. scripts/install.sh: - Append a line to the post-install banner pointing operators at '3m-ui reset-config --panel --yes' for SSH rescue scenarios. USAGE sudo 3m-ui reset-config # interactive y/N, panel scope sudo 3m-ui reset-config --panel --yes # scripted rescue (common case) sudo 3m-ui reset-config --all --yes # full reset sudo 3m-ui reset-config --help # full help (no service touched) Smoke-tested with a fake binary: dispatch + flag passthrough + env vars all correct; --help does not stop the service. feat(scripts): wire reset-config into 3m-ui CLI wrapper + install hint The new '3m-ui reset-config' Go subcommand (commit 8639b01) lets SSH operators undo panel misconfigurations (wrong port / 127.0.0.1 bind / broken SSL). This change exposes it through the systemd management wrapper and documents it in the install banner. scripts/3m-ui.sh: - Add 'reset_config' function: stops the panel service (required by the Go binary since it writes config.yaml + DB rows the running panel might cache), invokes 3m-ui-bin reset-config <flags>, then restarts the panel. - --help / -h short-circuits the stop/restart cycle (read-only). - Add 'reset-config' to the main case dispatch. - Document the new subcommand + flags in usage() with examples. scripts/install.sh: - Append a line to the post-install banner pointing operators at '3m-ui reset-config --panel --yes' for SSH rescue scenarios. USAGE sudo 3m-ui reset-config # interactive y/N, panel scope sudo 3m-ui reset-config --panel --yes # scripted rescue (common case) sudo 3m-ui reset-config --all --yes # full reset sudo 3m-ui reset-config --help # full help (no service touched) Smoke-tested with a fake binary: dispatch + flag passthrough + env vars all correct; --help does not stop the service. feat(scripts): wire reset-config into 3m-ui CLI wrapper + install hint The new '3m-ui reset-config' Go subcommand (commit 8639b01) lets SSH operators undo panel misconfigurations (wrong port / 127.0.0.1 bind / broken SSL). This change exposes it through the systemd management wrapper and documents it in the install banner. scripts/3m-ui.sh: - Add 'reset_config' function: stops the panel service (required by the Go binary since it writes config.yaml + DB rows the running panel might cache), invokes 3m-ui-bin reset-config <flags>, then restarts the panel. - --help / -h short-circuits the stop/restart cycle (read-only). - Add 'reset-config' to the main case dispatch. - Document the new subcommand + flags in usage() with examples. scripts/install.sh: - Append a line to the post-install banner pointing operators at '3m-ui reset-config --panel --yes' for SSH rescue scenarios. USAGE sudo 3m-ui reset-config # interactive y/N, panel scope sudo 3m-ui reset-config --panel --yes # scripted rescue (common case) sudo 3m-ui reset-config --all --yes # full reset sudo 3m-ui reset-config --help # full help (no service touched) Smoke-tested with a fake binary: dispatch + flag passthrough + env vars all correct; --help does not stop the service. feat(scripts): wire reset-config into 3m-ui CLI wrapper + install hint The new '3m-ui reset-config' Go subcommand (commit 8639b01) lets SSH operators undo panel misconfigurations (wrong port / 127.0.0.1 bind / broken SSL). This change exposes it through the systemd management wrapper and documents it in the install banner. scripts/3m-ui.sh: - Add 'reset_config' function: stops the panel service (required by the Go binary since it writes config.yaml + DB rows the running panel might cache), invokes 3m-ui-bin reset-config <flags>, then restarts the panel. - --help / -h short-circuits the stop/restart cycle (read-only). - Add 'reset-config' to the main case dispatch. - Document the new subcommand + flags in usage() with examples. scripts/install.sh: - Append a line to the post-install banner pointing operators at '3m-ui reset-config --panel --yes' for SSH rescue scenarios. USAGE sudo 3m-ui reset-config # interactive y/N, panel scope sudo 3m-ui reset-config --panel --yes # scripted rescue (common case) sudo 3m-ui reset-config --all --yes # full reset sudo 3m-ui reset-config --help # full help (no service touched) Smoke-tested with a fake binary: dispatch + flag passthrough + env vars all correct; --help does not stop the service. feat(scripts): wire reset-config into 3m-ui CLI wrapper + install hint The new '3m-ui reset-config' Go subcommand (commit 8639b01) lets SSH operators undo panel misconfigurations (wrong port / 127.0.0.1 bind / broken SSL). This change exposes it through the systemd management wrapper and documents it in the install banner. scripts/3m-ui.sh: - Add 'reset_config' function: stops the panel service (required by the Go binary since it writes config.yaml + DB rows the running panel might cache), invokes 3m-ui-bin reset-config <flags>, then restarts the panel. - --help / -h short-circuits the stop/restart cycle (read-only). - Add 'reset-config' to the main case dispatch. - Document the new subcommand + flags in usage() with examples. scripts/install.sh: - Append a line to the post-install banner pointing operators at '3m-ui reset-config --panel --yes' for SSH rescue scenarios. USAGE sudo 3m-ui reset-config # interactive y/N, panel scope sudo 3m-ui reset-config --panel --yes # scripted rescue (common case) sudo 3m-ui reset-config --all --yes # full reset sudo 3m-ui reset-config --help # full help (no service touched) Smoke-tested with a fake binary: dispatch + flag passthrough + env vars all correct; --help does not stop the service. feat(scripts): wire reset-config into 3m-ui CLI wrapper + install hint The new '3m-ui reset-config' Go subcommand (commit 8639b01) lets SSH operators undo panel misconfigurations (wrong port / 127.0.0.1 bind / broken SSL). This change exposes it through the systemd management wrapper and documents it in the install banner. scripts/3m-ui.sh: - Add 'reset_config' function: stops the panel service (required by the Go binary since it writes config.yaml + DB rows the running panel might cache), invokes 3m-ui-bin reset-config <flags>, then restarts the panel. - --help / -h short-circuits the stop/restart cycle (read-only). - Add 'reset-config' to the main case dispatch. - Document the new subcommand + flags in usage() with examples. scripts/install.sh: - Append a line to the post-install banner pointing operators at '3m-ui reset-config --panel --yes' for SSH rescue scenarios. USAGE sudo 3m-ui reset-config # interactive y/N, panel scope sudo 3m-ui reset-config --panel --yes # scripted rescue (common case) sudo 3m-ui reset-config --all --yes # full reset sudo 3m-ui reset-config --help # full help (no service touched) Smoke-tested with a fake binary: dispatch + flag passthrough + env vars all correct; --help does not stop the service. feat(scripts): wire reset-config into 3m-ui CLI wrapper + install hint The new '3m-ui reset-config' Go subcommand (commit 8639b01) lets SSH operators undo panel misconfigurations (wrong port / 127.0.0.1 bind / broken SSL). This change exposes it through the systemd management wrapper and documents it in the install banner. scripts/3m-ui.sh: - Add 'reset_config' function: stops the panel service (required by the Go binary since it writes config.yaml + DB rows the running panel might cache), invokes 3m-ui-bin reset-config <flags>, then restarts the panel. - --help / -h short-circuits the stop/restart cycle (read-only). - Add 'reset-config' to the main case dispatch. - Document the new subcommand + flags in usage() with examples. scripts/install.sh: - Append a line to the post-install banner pointing operators at '3m-ui reset-config --panel --yes' for SSH rescue scenarios. USAGE sudo 3m-ui reset-config # interactive y/N, panel scope sudo 3m-ui reset-config --panel --yes # scripted rescue (common case) sudo 3m-ui reset-config --all --yes # full reset sudo 3m-ui reset-config --help # full help (no service touched) Smoke-tested with a fake binary: dispatch + flag passthrough + env vars all correct; --help does not stop the service. |
||
|
|
0084c4f053 |
fix(install): always refresh all lifecycle scripts on update
- Force-install 3m-ui-bin, install/update/uninstall.sh, 3m-ui.sh, 3m-ui - Re-install /usr/local/bin/3m-ui from the same release (no stale entry) - Log each installed path; verify executables after write - chmod scripts in prepare_release; document in update.sh fix(install): always refresh all lifecycle scripts on update - Force-install 3m-ui-bin, install/update/uninstall.sh, 3m-ui.sh, 3m-ui - Re-install /usr/local/bin/3m-ui from the same release (no stale entry) - Log each installed path; verify executables after write - chmod scripts in prepare_release; document in update.sh fix(install): always refresh all lifecycle scripts on update - Force-install 3m-ui-bin, install/update/uninstall.sh, 3m-ui.sh, 3m-ui - Re-install /usr/local/bin/3m-ui from the same release (no stale entry) - Log each installed path; verify executables after write - chmod scripts in prepare_release; document in update.sh fix(install): always refresh all lifecycle scripts on update - Force-install 3m-ui-bin, install/update/uninstall.sh, 3m-ui.sh, 3m-ui - Re-install /usr/local/bin/3m-ui from the same release (no stale entry) - Log each installed path; verify executables after write - chmod scripts in prepare_release; document in update.sh fix(install): always refresh all lifecycle scripts on update - Force-install 3m-ui-bin, install/update/uninstall.sh, 3m-ui.sh, 3m-ui - Re-install /usr/local/bin/3m-ui from the same release (no stale entry) - Log each installed path; verify executables after write - chmod scripts in prepare_release; document in update.sh fix(install): always refresh all lifecycle scripts on update - Force-install 3m-ui-bin, install/update/uninstall.sh, 3m-ui.sh, 3m-ui - Re-install /usr/local/bin/3m-ui from the same release (no stale entry) - Log each installed path; verify executables after write - chmod scripts in prepare_release; document in update.sh fix(install): always refresh all lifecycle scripts on update - Force-install 3m-ui-bin, install/update/uninstall.sh, 3m-ui.sh, 3m-ui - Re-install /usr/local/bin/3m-ui from the same release (no stale entry) - Log each installed path; verify executables after write - chmod scripts in prepare_release; document in update.sh fix(install): always refresh all lifecycle scripts on update - Force-install 3m-ui-bin, install/update/uninstall.sh, 3m-ui.sh, 3m-ui - Re-install /usr/local/bin/3m-ui from the same release (no stale entry) - Log each installed path; verify executables after write - chmod scripts in prepare_release; document in update.sh fix(install): always refresh all lifecycle scripts on update - Force-install 3m-ui-bin, install/update/uninstall.sh, 3m-ui.sh, 3m-ui - Re-install /usr/local/bin/3m-ui from the same release (no stale entry) - Log each installed path; verify executables after write - chmod scripts in prepare_release; document in update.sh fix(install): always refresh all lifecycle scripts on update - Force-install 3m-ui-bin, install/update/uninstall.sh, 3m-ui.sh, 3m-ui - Re-install /usr/local/bin/3m-ui from the same release (no stale entry) - Log each installed path; verify executables after write - chmod scripts in prepare_release; document in update.sh fix(install): always refresh all lifecycle scripts on update - Force-install 3m-ui-bin, install/update/uninstall.sh, 3m-ui.sh, 3m-ui - Re-install /usr/local/bin/3m-ui from the same release (no stale entry) - Log each installed path; verify executables after write - chmod scripts in prepare_release; document in update.sh fix(install): always refresh all lifecycle scripts on update - Force-install 3m-ui-bin, install/update/uninstall.sh, 3m-ui.sh, 3m-ui - Re-install /usr/local/bin/3m-ui from the same release (no stale entry) - Log each installed path; verify executables after write - chmod scripts in prepare_release; document in update.sh |
||
|
|
2e6256fb6a |
feat(distribution): add complete installation and recovery workflows
Ship stable-only Linux bundles and multiarch Docker images with a pinned Mihomo core. Share secure first-run initialization across native and container installs. Validate downloads before downtime, snapshot persistent state before updates, and restore the previous installation after a failed upgrade. Add backup, restore, healthcheck, and randomized administrator reset commands. Add release verification, lifecycle regression tests, and installation documentation. feat(distribution): add complete installation and recovery workflows Ship stable-only Linux bundles and multiarch Docker images with a pinned Mihomo core. Share secure first-run initialization across native and container installs. Validate downloads before downtime, snapshot persistent state before updates, and restore the previous installation after a failed upgrade. Add backup, restore, healthcheck, and randomized administrator reset commands. Add release verification, lifecycle regression tests, and installation documentation. feat(distribution): add complete installation and recovery workflows Ship stable-only Linux bundles and multiarch Docker images with a pinned Mihomo core. Share secure first-run initialization across native and container installs. Validate downloads before downtime, snapshot persistent state before updates, and restore the previous installation after a failed upgrade. Add backup, restore, healthcheck, and randomized administrator reset commands. Add release verification, lifecycle regression tests, and installation documentation. feat(distribution): add complete installation and recovery workflows Ship stable-only Linux bundles and multiarch Docker images with a pinned Mihomo core. Share secure first-run initialization across native and container installs. Validate downloads before downtime, snapshot persistent state before updates, and restore the previous installation after a failed upgrade. Add backup, restore, healthcheck, and randomized administrator reset commands. Add release verification, lifecycle regression tests, and installation documentation. feat(distribution): add complete installation and recovery workflows Ship stable-only Linux bundles and multiarch Docker images with a pinned Mihomo core. Share secure first-run initialization across native and container installs. Validate downloads before downtime, snapshot persistent state before updates, and restore the previous installation after a failed upgrade. Add backup, restore, healthcheck, and randomized administrator reset commands. Add release verification, lifecycle regression tests, and installation documentation. feat(distribution): add complete installation and recovery workflows Ship stable-only Linux bundles and multiarch Docker images with a pinned Mihomo core. Share secure first-run initialization across native and container installs. Validate downloads before downtime, snapshot persistent state before updates, and restore the previous installation after a failed upgrade. Add backup, restore, healthcheck, and randomized administrator reset commands. Add release verification, lifecycle regression tests, and installation documentation. feat(distribution): add complete installation and recovery workflows Ship stable-only Linux bundles and multiarch Docker images with a pinned Mihomo core. Share secure first-run initialization across native and container installs. Validate downloads before downtime, snapshot persistent state before updates, and restore the previous installation after a failed upgrade. Add backup, restore, healthcheck, and randomized administrator reset commands. Add release verification, lifecycle regression tests, and installation documentation. feat(distribution): add complete installation and recovery workflows Ship stable-only Linux bundles and multiarch Docker images with a pinned Mihomo core. Share secure first-run initialization across native and container installs. Validate downloads before downtime, snapshot persistent state before updates, and restore the previous installation after a failed upgrade. Add backup, restore, healthcheck, and randomized administrator reset commands. Add release verification, lifecycle regression tests, and installation documentation. feat(distribution): add complete installation and recovery workflows Ship stable-only Linux bundles and multiarch Docker images with a pinned Mihomo core. Share secure first-run initialization across native and container installs. Validate downloads before downtime, snapshot persistent state before updates, and restore the previous installation after a failed upgrade. Add backup, restore, healthcheck, and randomized administrator reset commands. Add release verification, lifecycle regression tests, and installation documentation. feat(distribution): add complete installation and recovery workflows Ship stable-only Linux bundles and multiarch Docker images with a pinned Mihomo core. Share secure first-run initialization across native and container installs. Validate downloads before downtime, snapshot persistent state before updates, and restore the previous installation after a failed upgrade. Add backup, restore, healthcheck, and randomized administrator reset commands. Add release verification, lifecycle regression tests, and installation documentation. feat(distribution): add complete installation and recovery workflows Ship stable-only Linux bundles and multiarch Docker images with a pinned Mihomo core. Share secure first-run initialization across native and container installs. Validate downloads before downtime, snapshot persistent state before updates, and restore the previous installation after a failed upgrade. Add backup, restore, healthcheck, and randomized administrator reset commands. Add release verification, lifecycle regression tests, and installation documentation. feat(distribution): add complete installation and recovery workflows Ship stable-only Linux bundles and multiarch Docker images with a pinned Mihomo core. Share secure first-run initialization across native and container installs. Validate downloads before downtime, snapshot persistent state before updates, and restore the previous installation after a failed upgrade. Add backup, restore, healthcheck, and randomized administrator reset commands. Add release verification, lifecycle regression tests, and installation documentation. |
||
|
|
db08c0745c |
fix(scripts): quiet Mihomo download; try asset name variants; stable tag for mihomo
The curl 404 during 3m-ui update was optional Mihomo core refresh (wrong/pre tag or missing -compatible asset). Panel update already succeeded. fix(scripts): quiet Mihomo download; try asset name variants; stable tag for mihomo The curl 404 during 3m-ui update was optional Mihomo core refresh (wrong/pre tag or missing -compatible asset). Panel update already succeeded. fix(scripts): quiet Mihomo download; try asset name variants; stable tag for mihomo The curl 404 during 3m-ui update was optional Mihomo core refresh (wrong/pre tag or missing -compatible asset). Panel update already succeeded. fix(scripts): quiet Mihomo download; try asset name variants; stable tag for mihomo The curl 404 during 3m-ui update was optional Mihomo core refresh (wrong/pre tag or missing -compatible asset). Panel update already succeeded. fix(scripts): quiet Mihomo download; try asset name variants; stable tag for mihomo The curl 404 during 3m-ui update was optional Mihomo core refresh (wrong/pre tag or missing -compatible asset). Panel update already succeeded. fix(scripts): quiet Mihomo download; try asset name variants; stable tag for mihomo The curl 404 during 3m-ui update was optional Mihomo core refresh (wrong/pre tag or missing -compatible asset). Panel update already succeeded. fix(scripts): quiet Mihomo download; try asset name variants; stable tag for mihomo The curl 404 during 3m-ui update was optional Mihomo core refresh (wrong/pre tag or missing -compatible asset). Panel update already succeeded. fix(scripts): quiet Mihomo download; try asset name variants; stable tag for mihomo The curl 404 during 3m-ui update was optional Mihomo core refresh (wrong/pre tag or missing -compatible asset). Panel update already succeeded. fix(scripts): quiet Mihomo download; try asset name variants; stable tag for mihomo The curl 404 during 3m-ui update was optional Mihomo core refresh (wrong/pre tag or missing -compatible asset). Panel update already succeeded. fix(scripts): quiet Mihomo download; try asset name variants; stable tag for mihomo The curl 404 during 3m-ui update was optional Mihomo core refresh (wrong/pre tag or missing -compatible asset). Panel update already succeeded. fix(scripts): quiet Mihomo download; try asset name variants; stable tag for mihomo The curl 404 during 3m-ui update was optional Mihomo core refresh (wrong/pre tag or missing -compatible asset). Panel update already succeeded. fix(scripts): quiet Mihomo download; try asset name variants; stable tag for mihomo The curl 404 during 3m-ui update was optional Mihomo core refresh (wrong/pre tag or missing -compatible asset). Panel update already succeeded. |
||
|
|
b7f0389353 |
ci(test): single rolling Pre-release tag 'pre' (overwrite, no duplicates)
ci(test): single rolling Pre-release tag 'pre' (overwrite, no duplicates) ci(test): single rolling Pre-release tag 'pre' (overwrite, no duplicates) ci(test): single rolling Pre-release tag 'pre' (overwrite, no duplicates) ci(test): single rolling Pre-release tag 'pre' (overwrite, no duplicates) ci(test): single rolling Pre-release tag 'pre' (overwrite, no duplicates) ci(test): single rolling Pre-release tag 'pre' (overwrite, no duplicates) ci(test): single rolling Pre-release tag 'pre' (overwrite, no duplicates) ci(test): single rolling Pre-release tag 'pre' (overwrite, no duplicates) ci(test): single rolling Pre-release tag 'pre' (overwrite, no duplicates) ci(test): single rolling Pre-release tag 'pre' (overwrite, no duplicates) ci(test): single rolling Pre-release tag 'pre' (overwrite, no duplicates) |
||
|
|
db96350bd8 | fix(scripts): clean version argument case pattern | ||
|
|
8086e729c0 | fix(scripts): dedupe version arg pattern after test-* support | ||
|
|
f4bb43ecd3 |
ci(test): publish Pre-releases; install/update prefer newest prerelease
ci(test): publish Pre-releases; install/update prefer newest prerelease ci(test): publish Pre-releases; install/update prefer newest prerelease ci(test): publish Pre-releases; install/update prefer newest prerelease ci(test): publish Pre-releases; install/update prefer newest prerelease ci(test): publish Pre-releases; install/update prefer newest prerelease ci(test): publish Pre-releases; install/update prefer newest prerelease ci(test): publish Pre-releases; install/update prefer newest prerelease ci(test): publish Pre-releases; install/update prefer newest prerelease ci(test): publish Pre-releases; install/update prefer newest prerelease ci(test): publish Pre-releases; install/update prefer newest prerelease ci(test): publish Pre-releases; install/update prefer newest prerelease |
||
|
|
1f484b8c06 |
feat(p1-p3): safe config publish, batch user ops, cluster push, update harden, settings icons
- Config: generate no longer applies; Apply accepts editor YAML; Rollback UI - Users batch: extend-days and add-traffic (GiB) - Cluster: POST push-node with dry-run then create disabled on remote - Install: NONINTERACTIVE result file; update: longer health poll, strip more seccomp - Settings sidebar icons softer/outlined set feat(p1-p3): safe config publish, batch user ops, cluster push, update harden, settings icons - Config: generate no longer applies; Apply accepts editor YAML; Rollback UI - Users batch: extend-days and add-traffic (GiB) - Cluster: POST push-node with dry-run then create disabled on remote - Install: NONINTERACTIVE result file; update: longer health poll, strip more seccomp - Settings sidebar icons softer/outlined set feat(p1-p3): safe config publish, batch user ops, cluster push, update harden, settings icons - Config: generate no longer applies; Apply accepts editor YAML; Rollback UI - Users batch: extend-days and add-traffic (GiB) - Cluster: POST push-node with dry-run then create disabled on remote - Install: NONINTERACTIVE result file; update: longer health poll, strip more seccomp - Settings sidebar icons softer/outlined set feat(p1-p3): safe config publish, batch user ops, cluster push, update harden, settings icons - Config: generate no longer applies; Apply accepts editor YAML; Rollback UI - Users batch: extend-days and add-traffic (GiB) - Cluster: POST push-node with dry-run then create disabled on remote - Install: NONINTERACTIVE result file; update: longer health poll, strip more seccomp - Settings sidebar icons softer/outlined set feat(p1-p3): safe config publish, batch user ops, cluster push, update harden, settings icons - Config: generate no longer applies; Apply accepts editor YAML; Rollback UI - Users batch: extend-days and add-traffic (GiB) - Cluster: POST push-node with dry-run then create disabled on remote - Install: NONINTERACTIVE result file; update: longer health poll, strip more seccomp - Settings sidebar icons softer/outlined set feat(p1-p3): safe config publish, batch user ops, cluster push, update harden, settings icons - Config: generate no longer applies; Apply accepts editor YAML; Rollback UI - Users batch: extend-days and add-traffic (GiB) - Cluster: POST push-node with dry-run then create disabled on remote - Install: NONINTERACTIVE result file; update: longer health poll, strip more seccomp - Settings sidebar icons softer/outlined set feat(p1-p3): safe config publish, batch user ops, cluster push, update harden, settings icons - Config: generate no longer applies; Apply accepts editor YAML; Rollback UI - Users batch: extend-days and add-traffic (GiB) - Cluster: POST push-node with dry-run then create disabled on remote - Install: NONINTERACTIVE result file; update: longer health poll, strip more seccomp - Settings sidebar icons softer/outlined set feat(p1-p3): safe config publish, batch user ops, cluster push, update harden, settings icons - Config: generate no longer applies; Apply accepts editor YAML; Rollback UI - Users batch: extend-days and add-traffic (GiB) - Cluster: POST push-node with dry-run then create disabled on remote - Install: NONINTERACTIVE result file; update: longer health poll, strip more seccomp - Settings sidebar icons softer/outlined set feat(p1-p3): safe config publish, batch user ops, cluster push, update harden, settings icons - Config: generate no longer applies; Apply accepts editor YAML; Rollback UI - Users batch: extend-days and add-traffic (GiB) - Cluster: POST push-node with dry-run then create disabled on remote - Install: NONINTERACTIVE result file; update: longer health poll, strip more seccomp - Settings sidebar icons softer/outlined set feat(p1-p3): safe config publish, batch user ops, cluster push, update harden, settings icons - Config: generate no longer applies; Apply accepts editor YAML; Rollback UI - Users batch: extend-days and add-traffic (GiB) - Cluster: POST push-node with dry-run then create disabled on remote - Install: NONINTERACTIVE result file; update: longer health poll, strip more seccomp - Settings sidebar icons softer/outlined set feat(p1-p3): safe config publish, batch user ops, cluster push, update harden, settings icons - Config: generate no longer applies; Apply accepts editor YAML; Rollback UI - Users batch: extend-days and add-traffic (GiB) - Cluster: POST push-node with dry-run then create disabled on remote - Install: NONINTERACTIVE result file; update: longer health poll, strip more seccomp - Settings sidebar icons softer/outlined set feat(p1-p3): safe config publish, batch user ops, cluster push, update harden, settings icons - Config: generate no longer applies; Apply accepts editor YAML; Rollback UI - Users batch: extend-days and add-traffic (GiB) - Cluster: POST push-node with dry-run then create disabled on remote - Install: NONINTERACTIVE result file; update: longer health poll, strip more seccomp - Settings sidebar icons softer/outlined set |
||
|
|
6102d9cf55 | fix(systemd): drop SystemCallFilter causing SIGSYS (status=31) on pure-Go binary | ||
|
|
286873b128 |
feat(ops+sub): Phase A/B install menu, admin reset CLI, UA/sub UX
- Keep initial admin password as admin (no random password) - Install summary prints local/public panel URLs - Management menu: show URL, reset-admin to admin, BBR, geo update, public_url - Binary: reset-admin command - Expand subscription User-Agent auto-detect; frontend hints + user status filters feat(ops+sub): Phase A/B install menu, admin reset CLI, UA/sub UX - Keep initial admin password as admin (no random password) - Install summary prints local/public panel URLs - Management menu: show URL, reset-admin to admin, BBR, geo update, public_url - Binary: reset-admin command - Expand subscription User-Agent auto-detect; frontend hints + user status filters feat(ops+sub): Phase A/B install menu, admin reset CLI, UA/sub UX - Keep initial admin password as admin (no random password) - Install summary prints local/public panel URLs - Management menu: show URL, reset-admin to admin, BBR, geo update, public_url - Binary: reset-admin command - Expand subscription User-Agent auto-detect; frontend hints + user status filters feat(ops+sub): Phase A/B install menu, admin reset CLI, UA/sub UX - Keep initial admin password as admin (no random password) - Install summary prints local/public panel URLs - Management menu: show URL, reset-admin to admin, BBR, geo update, public_url - Binary: reset-admin command - Expand subscription User-Agent auto-detect; frontend hints + user status filters feat(ops+sub): Phase A/B install menu, admin reset CLI, UA/sub UX - Keep initial admin password as admin (no random password) - Install summary prints local/public panel URLs - Management menu: show URL, reset-admin to admin, BBR, geo update, public_url - Binary: reset-admin command - Expand subscription User-Agent auto-detect; frontend hints + user status filters feat(ops+sub): Phase A/B install menu, admin reset CLI, UA/sub UX - Keep initial admin password as admin (no random password) - Install summary prints local/public panel URLs - Management menu: show URL, reset-admin to admin, BBR, geo update, public_url - Binary: reset-admin command - Expand subscription User-Agent auto-detect; frontend hints + user status filters feat(ops+sub): Phase A/B install menu, admin reset CLI, UA/sub UX - Keep initial admin password as admin (no random password) - Install summary prints local/public panel URLs - Management menu: show URL, reset-admin to admin, BBR, geo update, public_url - Binary: reset-admin command - Expand subscription User-Agent auto-detect; frontend hints + user status filters feat(ops+sub): Phase A/B install menu, admin reset CLI, UA/sub UX - Keep initial admin password as admin (no random password) - Install summary prints local/public panel URLs - Management menu: show URL, reset-admin to admin, BBR, geo update, public_url - Binary: reset-admin command - Expand subscription User-Agent auto-detect; frontend hints + user status filters feat(ops+sub): Phase A/B install menu, admin reset CLI, UA/sub UX - Keep initial admin password as admin (no random password) - Install summary prints local/public panel URLs - Management menu: show URL, reset-admin to admin, BBR, geo update, public_url - Binary: reset-admin command - Expand subscription User-Agent auto-detect; frontend hints + user status filters feat(ops+sub): Phase A/B install menu, admin reset CLI, UA/sub UX - Keep initial admin password as admin (no random password) - Install summary prints local/public panel URLs - Management menu: show URL, reset-admin to admin, BBR, geo update, public_url - Binary: reset-admin command - Expand subscription User-Agent auto-detect; frontend hints + user status filters feat(ops+sub): Phase A/B install menu, admin reset CLI, UA/sub UX - Keep initial admin password as admin (no random password) - Install summary prints local/public panel URLs - Management menu: show URL, reset-admin to admin, BBR, geo update, public_url - Binary: reset-admin command - Expand subscription User-Agent auto-detect; frontend hints + user status filters feat(ops+sub): Phase A/B install menu, admin reset CLI, UA/sub UX - Keep initial admin password as admin (no random password) - Install summary prints local/public panel URLs - Management menu: show URL, reset-admin to admin, BBR, geo update, public_url - Binary: reset-admin command - Expand subscription User-Agent auto-detect; frontend hints + user status filters |
||
|
|
dbec0b3099 |
fix(scripts): install/update/uninstall port handling
Three script-level port UX issues found and fixed: == install.sh: re-install with PANEL_PORT now updates existing config == write_config previously returned early when config.yaml already existed, ignoring PANEL_PORT env var. Re-running 'PANEL_PORT=9000 bash install.sh' on an existing install silently kept the old port. Fix: when config.yaml exists and PANEL_PORT/THREE_M_UI_PORT is explicitly set, sed-update the port/listen/public_url in the existing file. First- time install (no config.yaml) still writes full config with random keys. == update.sh: show panel port after successful update == Update completed with no indication of which port the panel is on. Users had to check config.yaml manually. Fix: after '[5/5] Update completed', read server.port from config.yaml and display: Panel: http://SERVER_IP:<port>/ (to change port: 3m-ui config port <new-port>) Also added CONFIG_DIR constant (was missing). == uninstall.sh: show previous panel port before removing config == Uninstall removed config without telling the user what port was in use. Fix: before rm -rf $CONFIG_DIR, read and display: Previous panel port: <port> fix(scripts): install/update/uninstall port handling Three script-level port UX issues found and fixed: == install.sh: re-install with PANEL_PORT now updates existing config == write_config previously returned early when config.yaml already existed, ignoring PANEL_PORT env var. Re-running 'PANEL_PORT=9000 bash install.sh' on an existing install silently kept the old port. Fix: when config.yaml exists and PANEL_PORT/THREE_M_UI_PORT is explicitly set, sed-update the port/listen/public_url in the existing file. First- time install (no config.yaml) still writes full config with random keys. == update.sh: show panel port after successful update == Update completed with no indication of which port the panel is on. Users had to check config.yaml manually. Fix: after '[5/5] Update completed', read server.port from config.yaml and display: Panel: http://SERVER_IP:<port>/ (to change port: 3m-ui config port <new-port>) Also added CONFIG_DIR constant (was missing). == uninstall.sh: show previous panel port before removing config == Uninstall removed config without telling the user what port was in use. Fix: before rm -rf $CONFIG_DIR, read and display: Previous panel port: <port> fix(scripts): install/update/uninstall port handling Three script-level port UX issues found and fixed: == install.sh: re-install with PANEL_PORT now updates existing config == write_config previously returned early when config.yaml already existed, ignoring PANEL_PORT env var. Re-running 'PANEL_PORT=9000 bash install.sh' on an existing install silently kept the old port. Fix: when config.yaml exists and PANEL_PORT/THREE_M_UI_PORT is explicitly set, sed-update the port/listen/public_url in the existing file. First- time install (no config.yaml) still writes full config with random keys. == update.sh: show panel port after successful update == Update completed with no indication of which port the panel is on. Users had to check config.yaml manually. Fix: after '[5/5] Update completed', read server.port from config.yaml and display: Panel: http://SERVER_IP:<port>/ (to change port: 3m-ui config port <new-port>) Also added CONFIG_DIR constant (was missing). == uninstall.sh: show previous panel port before removing config == Uninstall removed config without telling the user what port was in use. Fix: before rm -rf $CONFIG_DIR, read and display: Previous panel port: <port> fix(scripts): install/update/uninstall port handling Three script-level port UX issues found and fixed: == install.sh: re-install with PANEL_PORT now updates existing config == write_config previously returned early when config.yaml already existed, ignoring PANEL_PORT env var. Re-running 'PANEL_PORT=9000 bash install.sh' on an existing install silently kept the old port. Fix: when config.yaml exists and PANEL_PORT/THREE_M_UI_PORT is explicitly set, sed-update the port/listen/public_url in the existing file. First- time install (no config.yaml) still writes full config with random keys. == update.sh: show panel port after successful update == Update completed with no indication of which port the panel is on. Users had to check config.yaml manually. Fix: after '[5/5] Update completed', read server.port from config.yaml and display: Panel: http://SERVER_IP:<port>/ (to change port: 3m-ui config port <new-port>) Also added CONFIG_DIR constant (was missing). == uninstall.sh: show previous panel port before removing config == Uninstall removed config without telling the user what port was in use. Fix: before rm -rf $CONFIG_DIR, read and display: Previous panel port: <port> fix(scripts): install/update/uninstall port handling Three script-level port UX issues found and fixed: == install.sh: re-install with PANEL_PORT now updates existing config == write_config previously returned early when config.yaml already existed, ignoring PANEL_PORT env var. Re-running 'PANEL_PORT=9000 bash install.sh' on an existing install silently kept the old port. Fix: when config.yaml exists and PANEL_PORT/THREE_M_UI_PORT is explicitly set, sed-update the port/listen/public_url in the existing file. First- time install (no config.yaml) still writes full config with random keys. == update.sh: show panel port after successful update == Update completed with no indication of which port the panel is on. Users had to check config.yaml manually. Fix: after '[5/5] Update completed', read server.port from config.yaml and display: Panel: http://SERVER_IP:<port>/ (to change port: 3m-ui config port <new-port>) Also added CONFIG_DIR constant (was missing). == uninstall.sh: show previous panel port before removing config == Uninstall removed config without telling the user what port was in use. Fix: before rm -rf $CONFIG_DIR, read and display: Previous panel port: <port> fix(scripts): install/update/uninstall port handling Three script-level port UX issues found and fixed: == install.sh: re-install with PANEL_PORT now updates existing config == write_config previously returned early when config.yaml already existed, ignoring PANEL_PORT env var. Re-running 'PANEL_PORT=9000 bash install.sh' on an existing install silently kept the old port. Fix: when config.yaml exists and PANEL_PORT/THREE_M_UI_PORT is explicitly set, sed-update the port/listen/public_url in the existing file. First- time install (no config.yaml) still writes full config with random keys. == update.sh: show panel port after successful update == Update completed with no indication of which port the panel is on. Users had to check config.yaml manually. Fix: after '[5/5] Update completed', read server.port from config.yaml and display: Panel: http://SERVER_IP:<port>/ (to change port: 3m-ui config port <new-port>) Also added CONFIG_DIR constant (was missing). == uninstall.sh: show previous panel port before removing config == Uninstall removed config without telling the user what port was in use. Fix: before rm -rf $CONFIG_DIR, read and display: Previous panel port: <port> fix(scripts): install/update/uninstall port handling Three script-level port UX issues found and fixed: == install.sh: re-install with PANEL_PORT now updates existing config == write_config previously returned early when config.yaml already existed, ignoring PANEL_PORT env var. Re-running 'PANEL_PORT=9000 bash install.sh' on an existing install silently kept the old port. Fix: when config.yaml exists and PANEL_PORT/THREE_M_UI_PORT is explicitly set, sed-update the port/listen/public_url in the existing file. First- time install (no config.yaml) still writes full config with random keys. == update.sh: show panel port after successful update == Update completed with no indication of which port the panel is on. Users had to check config.yaml manually. Fix: after '[5/5] Update completed', read server.port from config.yaml and display: Panel: http://SERVER_IP:<port>/ (to change port: 3m-ui config port <new-port>) Also added CONFIG_DIR constant (was missing). == uninstall.sh: show previous panel port before removing config == Uninstall removed config without telling the user what port was in use. Fix: before rm -rf $CONFIG_DIR, read and display: Previous panel port: <port> fix(scripts): install/update/uninstall port handling Three script-level port UX issues found and fixed: == install.sh: re-install with PANEL_PORT now updates existing config == write_config previously returned early when config.yaml already existed, ignoring PANEL_PORT env var. Re-running 'PANEL_PORT=9000 bash install.sh' on an existing install silently kept the old port. Fix: when config.yaml exists and PANEL_PORT/THREE_M_UI_PORT is explicitly set, sed-update the port/listen/public_url in the existing file. First- time install (no config.yaml) still writes full config with random keys. == update.sh: show panel port after successful update == Update completed with no indication of which port the panel is on. Users had to check config.yaml manually. Fix: after '[5/5] Update completed', read server.port from config.yaml and display: Panel: http://SERVER_IP:<port>/ (to change port: 3m-ui config port <new-port>) Also added CONFIG_DIR constant (was missing). == uninstall.sh: show previous panel port before removing config == Uninstall removed config without telling the user what port was in use. Fix: before rm -rf $CONFIG_DIR, read and display: Previous panel port: <port> fix(scripts): install/update/uninstall port handling Three script-level port UX issues found and fixed: == install.sh: re-install with PANEL_PORT now updates existing config == write_config previously returned early when config.yaml already existed, ignoring PANEL_PORT env var. Re-running 'PANEL_PORT=9000 bash install.sh' on an existing install silently kept the old port. Fix: when config.yaml exists and PANEL_PORT/THREE_M_UI_PORT is explicitly set, sed-update the port/listen/public_url in the existing file. First- time install (no config.yaml) still writes full config with random keys. == update.sh: show panel port after successful update == Update completed with no indication of which port the panel is on. Users had to check config.yaml manually. Fix: after '[5/5] Update completed', read server.port from config.yaml and display: Panel: http://SERVER_IP:<port>/ (to change port: 3m-ui config port <new-port>) Also added CONFIG_DIR constant (was missing). == uninstall.sh: show previous panel port before removing config == Uninstall removed config without telling the user what port was in use. Fix: before rm -rf $CONFIG_DIR, read and display: Previous panel port: <port> fix(scripts): install/update/uninstall port handling Three script-level port UX issues found and fixed: == install.sh: re-install with PANEL_PORT now updates existing config == write_config previously returned early when config.yaml already existed, ignoring PANEL_PORT env var. Re-running 'PANEL_PORT=9000 bash install.sh' on an existing install silently kept the old port. Fix: when config.yaml exists and PANEL_PORT/THREE_M_UI_PORT is explicitly set, sed-update the port/listen/public_url in the existing file. First- time install (no config.yaml) still writes full config with random keys. == update.sh: show panel port after successful update == Update completed with no indication of which port the panel is on. Users had to check config.yaml manually. Fix: after '[5/5] Update completed', read server.port from config.yaml and display: Panel: http://SERVER_IP:<port>/ (to change port: 3m-ui config port <new-port>) Also added CONFIG_DIR constant (was missing). == uninstall.sh: show previous panel port before removing config == Uninstall removed config without telling the user what port was in use. Fix: before rm -rf $CONFIG_DIR, read and display: Previous panel port: <port> fix(scripts): install/update/uninstall port handling Three script-level port UX issues found and fixed: == install.sh: re-install with PANEL_PORT now updates existing config == write_config previously returned early when config.yaml already existed, ignoring PANEL_PORT env var. Re-running 'PANEL_PORT=9000 bash install.sh' on an existing install silently kept the old port. Fix: when config.yaml exists and PANEL_PORT/THREE_M_UI_PORT is explicitly set, sed-update the port/listen/public_url in the existing file. First- time install (no config.yaml) still writes full config with random keys. == update.sh: show panel port after successful update == Update completed with no indication of which port the panel is on. Users had to check config.yaml manually. Fix: after '[5/5] Update completed', read server.port from config.yaml and display: Panel: http://SERVER_IP:<port>/ (to change port: 3m-ui config port <new-port>) Also added CONFIG_DIR constant (was missing). == uninstall.sh: show previous panel port before removing config == Uninstall removed config without telling the user what port was in use. Fix: before rm -rf $CONFIG_DIR, read and display: Previous panel port: <port> fix(scripts): install/update/uninstall port handling Three script-level port UX issues found and fixed: == install.sh: re-install with PANEL_PORT now updates existing config == write_config previously returned early when config.yaml already existed, ignoring PANEL_PORT env var. Re-running 'PANEL_PORT=9000 bash install.sh' on an existing install silently kept the old port. Fix: when config.yaml exists and PANEL_PORT/THREE_M_UI_PORT is explicitly set, sed-update the port/listen/public_url in the existing file. First- time install (no config.yaml) still writes full config with random keys. == update.sh: show panel port after successful update == Update completed with no indication of which port the panel is on. Users had to check config.yaml manually. Fix: after '[5/5] Update completed', read server.port from config.yaml and display: Panel: http://SERVER_IP:<port>/ (to change port: 3m-ui config port <new-port>) Also added CONFIG_DIR constant (was missing). == uninstall.sh: show previous panel port before removing config == Uninstall removed config without telling the user what port was in use. Fix: before rm -rf $CONFIG_DIR, read and display: Previous panel port: <port> |
||
|
|
7bc01e0298 |
fix(installers): Mihomo checksum via GitHub API digest, best-effort by default
The previous verify_mihomo_sha256 tried to download a SHA256SUMS file
from MetaCubeX/mihomo releases. Mihomo does NOT publish such a file
(verified across v1.17.0 — v1.19.30, all 404), so every install that
reached the Mihomo step failed with:
'Error: Mihomo checksum verification failed.
Set THREE_M_UI_INSECURE=1 to bypass (NOT recommended).'
Two-part fix:
1. Use GitHub's Release API per-asset 'digest' field instead of a
SHA256SUMS file. GitHub computes sha256 server-side when an asset
is uploaded, so the digest is authoritative even though Mihomo
itself publishes no checksums. Added github_asset_digest() helper
that queries /repos/{repo}/releases/tags/{tag} and parses the
matching asset's digest field (no jq dependency, pure awk).
2. Make Mihomo verification best-effort by default. Anonymous GitHub
API is rate-limited to 60 requests/hour/IP, so hard-failing would
break installs for anyone sharing a NAT IP or after a few retries.
The fail-closed guarantee already covers our own 3m-ui binary
(SHA256SUMS + cosign). Mihomo integrity is additionally protected
by HTTPS transport + the ELF smoke-test.
Users who want strict Mihomo verification can set
THREE_M_UI_VERIFY_MIHOMO=1 to make verification failures abort
(requires GitHub API to be reachable).
Threat model unchanged: our binary is fully verified end-to-end;
Mihomo is an independent project we can only best-effort verify.
The HTTPS download to GitHub + ELF check catches the realistic
threats (network MITM, truncated download, wrong file).
fix(installers): Mihomo checksum via GitHub API digest, best-effort by default
The previous verify_mihomo_sha256 tried to download a SHA256SUMS file
from MetaCubeX/mihomo releases. Mihomo does NOT publish such a file
(verified across v1.17.0 — v1.19.30, all 404), so every install that
reached the Mihomo step failed with:
'Error: Mihomo checksum verification failed.
Set THREE_M_UI_INSECURE=1 to bypass (NOT recommended).'
Two-part fix:
1. Use GitHub's Release API per-asset 'digest' field instead of a
SHA256SUMS file. GitHub computes sha256 server-side when an asset
is uploaded, so the digest is authoritative even though Mihomo
itself publishes no checksums. Added github_asset_digest() helper
that queries /repos/{repo}/releases/tags/{tag} and parses the
matching asset's digest field (no jq dependency, pure awk).
2. Make Mihomo verification best-effort by default. Anonymous GitHub
API is rate-limited to 60 requests/hour/IP, so hard-failing would
break installs for anyone sharing a NAT IP or after a few retries.
The fail-closed guarantee already covers our own 3m-ui binary
(SHA256SUMS + cosign). Mihomo integrity is additionally protected
by HTTPS transport + the ELF smoke-test.
Users who want strict Mihomo verification can set
THREE_M_UI_VERIFY_MIHOMO=1 to make verification failures abort
(requires GitHub API to be reachable).
Threat model unchanged: our binary is fully verified end-to-end;
Mihomo is an independent project we can only best-effort verify.
The HTTPS download to GitHub + ELF check catches the realistic
threats (network MITM, truncated download, wrong file).
fix(installers): Mihomo checksum via GitHub API digest, best-effort by default
The previous verify_mihomo_sha256 tried to download a SHA256SUMS file
from MetaCubeX/mihomo releases. Mihomo does NOT publish such a file
(verified across v1.17.0 — v1.19.30, all 404), so every install that
reached the Mihomo step failed with:
'Error: Mihomo checksum verification failed.
Set THREE_M_UI_INSECURE=1 to bypass (NOT recommended).'
Two-part fix:
1. Use GitHub's Release API per-asset 'digest' field instead of a
SHA256SUMS file. GitHub computes sha256 server-side when an asset
is uploaded, so the digest is authoritative even though Mihomo
itself publishes no checksums. Added github_asset_digest() helper
that queries /repos/{repo}/releases/tags/{tag} and parses the
matching asset's digest field (no jq dependency, pure awk).
2. Make Mihomo verification best-effort by default. Anonymous GitHub
API is rate-limited to 60 requests/hour/IP, so hard-failing would
break installs for anyone sharing a NAT IP or after a few retries.
The fail-closed guarantee already covers our own 3m-ui binary
(SHA256SUMS + cosign). Mihomo integrity is additionally protected
by HTTPS transport + the ELF smoke-test.
Users who want strict Mihomo verification can set
THREE_M_UI_VERIFY_MIHOMO=1 to make verification failures abort
(requires GitHub API to be reachable).
Threat model unchanged: our binary is fully verified end-to-end;
Mihomo is an independent project we can only best-effort verify.
The HTTPS download to GitHub + ELF check catches the realistic
threats (network MITM, truncated download, wrong file).
fix(installers): Mihomo checksum via GitHub API digest, best-effort by default
The previous verify_mihomo_sha256 tried to download a SHA256SUMS file
from MetaCubeX/mihomo releases. Mihomo does NOT publish such a file
(verified across v1.17.0 — v1.19.30, all 404), so every install that
reached the Mihomo step failed with:
'Error: Mihomo checksum verification failed.
Set THREE_M_UI_INSECURE=1 to bypass (NOT recommended).'
Two-part fix:
1. Use GitHub's Release API per-asset 'digest' field instead of a
SHA256SUMS file. GitHub computes sha256 server-side when an asset
is uploaded, so the digest is authoritative even though Mihomo
itself publishes no checksums. Added github_asset_digest() helper
that queries /repos/{repo}/releases/tags/{tag} and parses the
matching asset's digest field (no jq dependency, pure awk).
2. Make Mihomo verification best-effort by default. Anonymous GitHub
API is rate-limited to 60 requests/hour/IP, so hard-failing would
break installs for anyone sharing a NAT IP or after a few retries.
The fail-closed guarantee already covers our own 3m-ui binary
(SHA256SUMS + cosign). Mihomo integrity is additionally protected
by HTTPS transport + the ELF smoke-test.
Users who want strict Mihomo verification can set
THREE_M_UI_VERIFY_MIHOMO=1 to make verification failures abort
(requires GitHub API to be reachable).
Threat model unchanged: our binary is fully verified end-to-end;
Mihomo is an independent project we can only best-effort verify.
The HTTPS download to GitHub + ELF check catches the realistic
threats (network MITM, truncated download, wrong file).
fix(installers): Mihomo checksum via GitHub API digest, best-effort by default
The previous verify_mihomo_sha256 tried to download a SHA256SUMS file
from MetaCubeX/mihomo releases. Mihomo does NOT publish such a file
(verified across v1.17.0 — v1.19.30, all 404), so every install that
reached the Mihomo step failed with:
'Error: Mihomo checksum verification failed.
Set THREE_M_UI_INSECURE=1 to bypass (NOT recommended).'
Two-part fix:
1. Use GitHub's Release API per-asset 'digest' field instead of a
SHA256SUMS file. GitHub computes sha256 server-side when an asset
is uploaded, so the digest is authoritative even though Mihomo
itself publishes no checksums. Added github_asset_digest() helper
that queries /repos/{repo}/releases/tags/{tag} and parses the
matching asset's digest field (no jq dependency, pure awk).
2. Make Mihomo verification best-effort by default. Anonymous GitHub
API is rate-limited to 60 requests/hour/IP, so hard-failing would
break installs for anyone sharing a NAT IP or after a few retries.
The fail-closed guarantee already covers our own 3m-ui binary
(SHA256SUMS + cosign). Mihomo integrity is additionally protected
by HTTPS transport + the ELF smoke-test.
Users who want strict Mihomo verification can set
THREE_M_UI_VERIFY_MIHOMO=1 to make verification failures abort
(requires GitHub API to be reachable).
Threat model unchanged: our binary is fully verified end-to-end;
Mihomo is an independent project we can only best-effort verify.
The HTTPS download to GitHub + ELF check catches the realistic
threats (network MITM, truncated download, wrong file).
fix(installers): Mihomo checksum via GitHub API digest, best-effort by default
The previous verify_mihomo_sha256 tried to download a SHA256SUMS file
from MetaCubeX/mihomo releases. Mihomo does NOT publish such a file
(verified across v1.17.0 — v1.19.30, all 404), so every install that
reached the Mihomo step failed with:
'Error: Mihomo checksum verification failed.
Set THREE_M_UI_INSECURE=1 to bypass (NOT recommended).'
Two-part fix:
1. Use GitHub's Release API per-asset 'digest' field instead of a
SHA256SUMS file. GitHub computes sha256 server-side when an asset
is uploaded, so the digest is authoritative even though Mihomo
itself publishes no checksums. Added github_asset_digest() helper
that queries /repos/{repo}/releases/tags/{tag} and parses the
matching asset's digest field (no jq dependency, pure awk).
2. Make Mihomo verification best-effort by default. Anonymous GitHub
API is rate-limited to 60 requests/hour/IP, so hard-failing would
break installs for anyone sharing a NAT IP or after a few retries.
The fail-closed guarantee already covers our own 3m-ui binary
(SHA256SUMS + cosign). Mihomo integrity is additionally protected
by HTTPS transport + the ELF smoke-test.
Users who want strict Mihomo verification can set
THREE_M_UI_VERIFY_MIHOMO=1 to make verification failures abort
(requires GitHub API to be reachable).
Threat model unchanged: our binary is fully verified end-to-end;
Mihomo is an independent project we can only best-effort verify.
The HTTPS download to GitHub + ELF check catches the realistic
threats (network MITM, truncated download, wrong file).
fix(installers): Mihomo checksum via GitHub API digest, best-effort by default
The previous verify_mihomo_sha256 tried to download a SHA256SUMS file
from MetaCubeX/mihomo releases. Mihomo does NOT publish such a file
(verified across v1.17.0 — v1.19.30, all 404), so every install that
reached the Mihomo step failed with:
'Error: Mihomo checksum verification failed.
Set THREE_M_UI_INSECURE=1 to bypass (NOT recommended).'
Two-part fix:
1. Use GitHub's Release API per-asset 'digest' field instead of a
SHA256SUMS file. GitHub computes sha256 server-side when an asset
is uploaded, so the digest is authoritative even though Mihomo
itself publishes no checksums. Added github_asset_digest() helper
that queries /repos/{repo}/releases/tags/{tag} and parses the
matching asset's digest field (no jq dependency, pure awk).
2. Make Mihomo verification best-effort by default. Anonymous GitHub
API is rate-limited to 60 requests/hour/IP, so hard-failing would
break installs for anyone sharing a NAT IP or after a few retries.
The fail-closed guarantee already covers our own 3m-ui binary
(SHA256SUMS + cosign). Mihomo integrity is additionally protected
by HTTPS transport + the ELF smoke-test.
Users who want strict Mihomo verification can set
THREE_M_UI_VERIFY_MIHOMO=1 to make verification failures abort
(requires GitHub API to be reachable).
Threat model unchanged: our binary is fully verified end-to-end;
Mihomo is an independent project we can only best-effort verify.
The HTTPS download to GitHub + ELF check catches the realistic
threats (network MITM, truncated download, wrong file).
fix(installers): Mihomo checksum via GitHub API digest, best-effort by default
The previous verify_mihomo_sha256 tried to download a SHA256SUMS file
from MetaCubeX/mihomo releases. Mihomo does NOT publish such a file
(verified across v1.17.0 — v1.19.30, all 404), so every install that
reached the Mihomo step failed with:
'Error: Mihomo checksum verification failed.
Set THREE_M_UI_INSECURE=1 to bypass (NOT recommended).'
Two-part fix:
1. Use GitHub's Release API per-asset 'digest' field instead of a
SHA256SUMS file. GitHub computes sha256 server-side when an asset
is uploaded, so the digest is authoritative even though Mihomo
itself publishes no checksums. Added github_asset_digest() helper
that queries /repos/{repo}/releases/tags/{tag} and parses the
matching asset's digest field (no jq dependency, pure awk).
2. Make Mihomo verification best-effort by default. Anonymous GitHub
API is rate-limited to 60 requests/hour/IP, so hard-failing would
break installs for anyone sharing a NAT IP or after a few retries.
The fail-closed guarantee already covers our own 3m-ui binary
(SHA256SUMS + cosign). Mihomo integrity is additionally protected
by HTTPS transport + the ELF smoke-test.
Users who want strict Mihomo verification can set
THREE_M_UI_VERIFY_MIHOMO=1 to make verification failures abort
(requires GitHub API to be reachable).
Threat model unchanged: our binary is fully verified end-to-end;
Mihomo is an independent project we can only best-effort verify.
The HTTPS download to GitHub + ELF check catches the realistic
threats (network MITM, truncated download, wrong file).
fix(installers): Mihomo checksum via GitHub API digest, best-effort by default
The previous verify_mihomo_sha256 tried to download a SHA256SUMS file
from MetaCubeX/mihomo releases. Mihomo does NOT publish such a file
(verified across v1.17.0 — v1.19.30, all 404), so every install that
reached the Mihomo step failed with:
'Error: Mihomo checksum verification failed.
Set THREE_M_UI_INSECURE=1 to bypass (NOT recommended).'
Two-part fix:
1. Use GitHub's Release API per-asset 'digest' field instead of a
SHA256SUMS file. GitHub computes sha256 server-side when an asset
is uploaded, so the digest is authoritative even though Mihomo
itself publishes no checksums. Added github_asset_digest() helper
that queries /repos/{repo}/releases/tags/{tag} and parses the
matching asset's digest field (no jq dependency, pure awk).
2. Make Mihomo verification best-effort by default. Anonymous GitHub
API is rate-limited to 60 requests/hour/IP, so hard-failing would
break installs for anyone sharing a NAT IP or after a few retries.
The fail-closed guarantee already covers our own 3m-ui binary
(SHA256SUMS + cosign). Mihomo integrity is additionally protected
by HTTPS transport + the ELF smoke-test.
Users who want strict Mihomo verification can set
THREE_M_UI_VERIFY_MIHOMO=1 to make verification failures abort
(requires GitHub API to be reachable).
Threat model unchanged: our binary is fully verified end-to-end;
Mihomo is an independent project we can only best-effort verify.
The HTTPS download to GitHub + ELF check catches the realistic
threats (network MITM, truncated download, wrong file).
fix(installers): Mihomo checksum via GitHub API digest, best-effort by default
The previous verify_mihomo_sha256 tried to download a SHA256SUMS file
from MetaCubeX/mihomo releases. Mihomo does NOT publish such a file
(verified across v1.17.0 — v1.19.30, all 404), so every install that
reached the Mihomo step failed with:
'Error: Mihomo checksum verification failed.
Set THREE_M_UI_INSECURE=1 to bypass (NOT recommended).'
Two-part fix:
1. Use GitHub's Release API per-asset 'digest' field instead of a
SHA256SUMS file. GitHub computes sha256 server-side when an asset
is uploaded, so the digest is authoritative even though Mihomo
itself publishes no checksums. Added github_asset_digest() helper
that queries /repos/{repo}/releases/tags/{tag} and parses the
matching asset's digest field (no jq dependency, pure awk).
2. Make Mihomo verification best-effort by default. Anonymous GitHub
API is rate-limited to 60 requests/hour/IP, so hard-failing would
break installs for anyone sharing a NAT IP or after a few retries.
The fail-closed guarantee already covers our own 3m-ui binary
(SHA256SUMS + cosign). Mihomo integrity is additionally protected
by HTTPS transport + the ELF smoke-test.
Users who want strict Mihomo verification can set
THREE_M_UI_VERIFY_MIHOMO=1 to make verification failures abort
(requires GitHub API to be reachable).
Threat model unchanged: our binary is fully verified end-to-end;
Mihomo is an independent project we can only best-effort verify.
The HTTPS download to GitHub + ELF check catches the realistic
threats (network MITM, truncated download, wrong file).
fix(installers): Mihomo checksum via GitHub API digest, best-effort by default
The previous verify_mihomo_sha256 tried to download a SHA256SUMS file
from MetaCubeX/mihomo releases. Mihomo does NOT publish such a file
(verified across v1.17.0 — v1.19.30, all 404), so every install that
reached the Mihomo step failed with:
'Error: Mihomo checksum verification failed.
Set THREE_M_UI_INSECURE=1 to bypass (NOT recommended).'
Two-part fix:
1. Use GitHub's Release API per-asset 'digest' field instead of a
SHA256SUMS file. GitHub computes sha256 server-side when an asset
is uploaded, so the digest is authoritative even though Mihomo
itself publishes no checksums. Added github_asset_digest() helper
that queries /repos/{repo}/releases/tags/{tag} and parses the
matching asset's digest field (no jq dependency, pure awk).
2. Make Mihomo verification best-effort by default. Anonymous GitHub
API is rate-limited to 60 requests/hour/IP, so hard-failing would
break installs for anyone sharing a NAT IP or after a few retries.
The fail-closed guarantee already covers our own 3m-ui binary
(SHA256SUMS + cosign). Mihomo integrity is additionally protected
by HTTPS transport + the ELF smoke-test.
Users who want strict Mihomo verification can set
THREE_M_UI_VERIFY_MIHOMO=1 to make verification failures abort
(requires GitHub API to be reachable).
Threat model unchanged: our binary is fully verified end-to-end;
Mihomo is an independent project we can only best-effort verify.
The HTTPS download to GitHub + ELF check catches the realistic
threats (network MITM, truncated download, wrong file).
fix(installers): Mihomo checksum via GitHub API digest, best-effort by default
The previous verify_mihomo_sha256 tried to download a SHA256SUMS file
from MetaCubeX/mihomo releases. Mihomo does NOT publish such a file
(verified across v1.17.0 — v1.19.30, all 404), so every install that
reached the Mihomo step failed with:
'Error: Mihomo checksum verification failed.
Set THREE_M_UI_INSECURE=1 to bypass (NOT recommended).'
Two-part fix:
1. Use GitHub's Release API per-asset 'digest' field instead of a
SHA256SUMS file. GitHub computes sha256 server-side when an asset
is uploaded, so the digest is authoritative even though Mihomo
itself publishes no checksums. Added github_asset_digest() helper
that queries /repos/{repo}/releases/tags/{tag} and parses the
matching asset's digest field (no jq dependency, pure awk).
2. Make Mihomo verification best-effort by default. Anonymous GitHub
API is rate-limited to 60 requests/hour/IP, so hard-failing would
break installs for anyone sharing a NAT IP or after a few retries.
The fail-closed guarantee already covers our own 3m-ui binary
(SHA256SUMS + cosign). Mihomo integrity is additionally protected
by HTTPS transport + the ELF smoke-test.
Users who want strict Mihomo verification can set
THREE_M_UI_VERIFY_MIHOMO=1 to make verification failures abort
(requires GitHub API to be reachable).
Threat model unchanged: our binary is fully verified end-to-end;
Mihomo is an independent project we can only best-effort verify.
The HTTPS download to GitHub + ELF check catches the realistic
threats (network MITM, truncated download, wrong file).
|
||
|
|
8d730a2d08 |
fix(installers): cosign verify accepts tag-ref or main-branch identity
The back-filled v1.0.0 was signed via workflow_dispatch (ref=main), so its OIDC certificate identity is .../release.yml@refs/heads/main rather than the tag-ref identity .../release.yml@refs/tags/v1.0.0 that tag-pushed releases produce. Make verify_release_cosign try both identities so verification works for both normal tag-triggered releases and workflow_dispatch back-fills. If either matches, verification passes. fix(installers): cosign verify accepts tag-ref or main-branch identity The back-filled v1.0.0 was signed via workflow_dispatch (ref=main), so its OIDC certificate identity is .../release.yml@refs/heads/main rather than the tag-ref identity .../release.yml@refs/tags/v1.0.0 that tag-pushed releases produce. Make verify_release_cosign try both identities so verification works for both normal tag-triggered releases and workflow_dispatch back-fills. If either matches, verification passes. fix(installers): cosign verify accepts tag-ref or main-branch identity The back-filled v1.0.0 was signed via workflow_dispatch (ref=main), so its OIDC certificate identity is .../release.yml@refs/heads/main rather than the tag-ref identity .../release.yml@refs/tags/v1.0.0 that tag-pushed releases produce. Make verify_release_cosign try both identities so verification works for both normal tag-triggered releases and workflow_dispatch back-fills. If either matches, verification passes. fix(installers): cosign verify accepts tag-ref or main-branch identity The back-filled v1.0.0 was signed via workflow_dispatch (ref=main), so its OIDC certificate identity is .../release.yml@refs/heads/main rather than the tag-ref identity .../release.yml@refs/tags/v1.0.0 that tag-pushed releases produce. Make verify_release_cosign try both identities so verification works for both normal tag-triggered releases and workflow_dispatch back-fills. If either matches, verification passes. fix(installers): cosign verify accepts tag-ref or main-branch identity The back-filled v1.0.0 was signed via workflow_dispatch (ref=main), so its OIDC certificate identity is .../release.yml@refs/heads/main rather than the tag-ref identity .../release.yml@refs/tags/v1.0.0 that tag-pushed releases produce. Make verify_release_cosign try both identities so verification works for both normal tag-triggered releases and workflow_dispatch back-fills. If either matches, verification passes. fix(installers): cosign verify accepts tag-ref or main-branch identity The back-filled v1.0.0 was signed via workflow_dispatch (ref=main), so its OIDC certificate identity is .../release.yml@refs/heads/main rather than the tag-ref identity .../release.yml@refs/tags/v1.0.0 that tag-pushed releases produce. Make verify_release_cosign try both identities so verification works for both normal tag-triggered releases and workflow_dispatch back-fills. If either matches, verification passes. fix(installers): cosign verify accepts tag-ref or main-branch identity The back-filled v1.0.0 was signed via workflow_dispatch (ref=main), so its OIDC certificate identity is .../release.yml@refs/heads/main rather than the tag-ref identity .../release.yml@refs/tags/v1.0.0 that tag-pushed releases produce. Make verify_release_cosign try both identities so verification works for both normal tag-triggered releases and workflow_dispatch back-fills. If either matches, verification passes. fix(installers): cosign verify accepts tag-ref or main-branch identity The back-filled v1.0.0 was signed via workflow_dispatch (ref=main), so its OIDC certificate identity is .../release.yml@refs/heads/main rather than the tag-ref identity .../release.yml@refs/tags/v1.0.0 that tag-pushed releases produce. Make verify_release_cosign try both identities so verification works for both normal tag-triggered releases and workflow_dispatch back-fills. If either matches, verification passes. fix(installers): cosign verify accepts tag-ref or main-branch identity The back-filled v1.0.0 was signed via workflow_dispatch (ref=main), so its OIDC certificate identity is .../release.yml@refs/heads/main rather than the tag-ref identity .../release.yml@refs/tags/v1.0.0 that tag-pushed releases produce. Make verify_release_cosign try both identities so verification works for both normal tag-triggered releases and workflow_dispatch back-fills. If either matches, verification passes. fix(installers): cosign verify accepts tag-ref or main-branch identity The back-filled v1.0.0 was signed via workflow_dispatch (ref=main), so its OIDC certificate identity is .../release.yml@refs/heads/main rather than the tag-ref identity .../release.yml@refs/tags/v1.0.0 that tag-pushed releases produce. Make verify_release_cosign try both identities so verification works for both normal tag-triggered releases and workflow_dispatch back-fills. If either matches, verification passes. fix(installers): cosign verify accepts tag-ref or main-branch identity The back-filled v1.0.0 was signed via workflow_dispatch (ref=main), so its OIDC certificate identity is .../release.yml@refs/heads/main rather than the tag-ref identity .../release.yml@refs/tags/v1.0.0 that tag-pushed releases produce. Make verify_release_cosign try both identities so verification works for both normal tag-triggered releases and workflow_dispatch back-fills. If either matches, verification passes. fix(installers): cosign verify accepts tag-ref or main-branch identity The back-filled v1.0.0 was signed via workflow_dispatch (ref=main), so its OIDC certificate identity is .../release.yml@refs/heads/main rather than the tag-ref identity .../release.yml@refs/tags/v1.0.0 that tag-pushed releases produce. Make verify_release_cosign try both identities so verification works for both normal tag-triggered releases and workflow_dispatch back-fills. If either matches, verification passes. |
||
|
|
4f038eba42 |
feat(release): cosign keyless signing of SHA256SUMS
Closes M-10 (supply-chain authenticity). Replaces the TODO comment with a working cosign keyless OIDC signing flow. Workflow (release.yml): - Add id-token: write permission (required for GitHub OIDC token). - Add sigstore/cosign-installer@v3 step. - After SHA256SUMS is generated, cosign sign-blob --yes produces SHA256SUMS.pem (certificate) and SHA256SUMS.sig (signature). These are uploaded alongside the existing release assets. - No long-lived secret is stored on GitHub; the signing identity is the ephemeral GitHub Actions OIDC token bound to this workflow + tag. - Release notes body updated with the cosign verify-blob command so users know how to verify authenticity end-to-end. Installers (install.sh / update.sh): - Add verify_release_cosign() function. OPT-IN via THREE_M_UI_VERIFY_COSIGN=1 (off by default to keep the curl|bash UX simple — SHA256SUMS integrity is already fail-closed). - When enabled AND cosign is installed, downloads SHA256SUMS.pem + SHA256SUMS.sig and runs cosign verify-blob against the identity 'https://github.com/<repo>/.github/workflows/release.yml@refs/tags/<tag>'. - If cosign is missing or the release predates signing, prints a warning and continues (does not hard-fail). - If verification runs and FAILS, aborts (fail-closed, bypassable via THREE_M_UI_INSECURE=1). Threat model: - Before: SHA256SUMS provided integrity but not authenticity — an attacker who could modify the release assets could also modify SHA256SUMS, defeating the checksum. - After: cosign signature ties SHA256SUMS to the GitHub Actions OIDC identity, so a modified sums file fails signature verification even if the attacker controls the release CDN. Verification command (for end users): cosign verify-blob \ --certificate SHA256SUMS.pem \ --signature SHA256SUMS.sig \ --certificate-identity 'https://github.com/kazeyukiro/3m-ui/.github/workflows/release.yml@refs/tags/<tag>' \ --certificate-oidc-issuer https://token.actions.githubusercontent.com \ SHA256SUMS feat(release): cosign keyless signing of SHA256SUMS Closes M-10 (supply-chain authenticity). Replaces the TODO comment with a working cosign keyless OIDC signing flow. Workflow (release.yml): - Add id-token: write permission (required for GitHub OIDC token). - Add sigstore/cosign-installer@v3 step. - After SHA256SUMS is generated, cosign sign-blob --yes produces SHA256SUMS.pem (certificate) and SHA256SUMS.sig (signature). These are uploaded alongside the existing release assets. - No long-lived secret is stored on GitHub; the signing identity is the ephemeral GitHub Actions OIDC token bound to this workflow + tag. - Release notes body updated with the cosign verify-blob command so users know how to verify authenticity end-to-end. Installers (install.sh / update.sh): - Add verify_release_cosign() function. OPT-IN via THREE_M_UI_VERIFY_COSIGN=1 (off by default to keep the curl|bash UX simple — SHA256SUMS integrity is already fail-closed). - When enabled AND cosign is installed, downloads SHA256SUMS.pem + SHA256SUMS.sig and runs cosign verify-blob against the identity 'https://github.com/<repo>/.github/workflows/release.yml@refs/tags/<tag>'. - If cosign is missing or the release predates signing, prints a warning and continues (does not hard-fail). - If verification runs and FAILS, aborts (fail-closed, bypassable via THREE_M_UI_INSECURE=1). Threat model: - Before: SHA256SUMS provided integrity but not authenticity — an attacker who could modify the release assets could also modify SHA256SUMS, defeating the checksum. - After: cosign signature ties SHA256SUMS to the GitHub Actions OIDC identity, so a modified sums file fails signature verification even if the attacker controls the release CDN. Verification command (for end users): cosign verify-blob \ --certificate SHA256SUMS.pem \ --signature SHA256SUMS.sig \ --certificate-identity 'https://github.com/kazeyukiro/3m-ui/.github/workflows/release.yml@refs/tags/<tag>' \ --certificate-oidc-issuer https://token.actions.githubusercontent.com \ SHA256SUMS feat(release): cosign keyless signing of SHA256SUMS Closes M-10 (supply-chain authenticity). Replaces the TODO comment with a working cosign keyless OIDC signing flow. Workflow (release.yml): - Add id-token: write permission (required for GitHub OIDC token). - Add sigstore/cosign-installer@v3 step. - After SHA256SUMS is generated, cosign sign-blob --yes produces SHA256SUMS.pem (certificate) and SHA256SUMS.sig (signature). These are uploaded alongside the existing release assets. - No long-lived secret is stored on GitHub; the signing identity is the ephemeral GitHub Actions OIDC token bound to this workflow + tag. - Release notes body updated with the cosign verify-blob command so users know how to verify authenticity end-to-end. Installers (install.sh / update.sh): - Add verify_release_cosign() function. OPT-IN via THREE_M_UI_VERIFY_COSIGN=1 (off by default to keep the curl|bash UX simple — SHA256SUMS integrity is already fail-closed). - When enabled AND cosign is installed, downloads SHA256SUMS.pem + SHA256SUMS.sig and runs cosign verify-blob against the identity 'https://github.com/<repo>/.github/workflows/release.yml@refs/tags/<tag>'. - If cosign is missing or the release predates signing, prints a warning and continues (does not hard-fail). - If verification runs and FAILS, aborts (fail-closed, bypassable via THREE_M_UI_INSECURE=1). Threat model: - Before: SHA256SUMS provided integrity but not authenticity — an attacker who could modify the release assets could also modify SHA256SUMS, defeating the checksum. - After: cosign signature ties SHA256SUMS to the GitHub Actions OIDC identity, so a modified sums file fails signature verification even if the attacker controls the release CDN. Verification command (for end users): cosign verify-blob \ --certificate SHA256SUMS.pem \ --signature SHA256SUMS.sig \ --certificate-identity 'https://github.com/kazeyukiro/3m-ui/.github/workflows/release.yml@refs/tags/<tag>' \ --certificate-oidc-issuer https://token.actions.githubusercontent.com \ SHA256SUMS feat(release): cosign keyless signing of SHA256SUMS Closes M-10 (supply-chain authenticity). Replaces the TODO comment with a working cosign keyless OIDC signing flow. Workflow (release.yml): - Add id-token: write permission (required for GitHub OIDC token). - Add sigstore/cosign-installer@v3 step. - After SHA256SUMS is generated, cosign sign-blob --yes produces SHA256SUMS.pem (certificate) and SHA256SUMS.sig (signature). These are uploaded alongside the existing release assets. - No long-lived secret is stored on GitHub; the signing identity is the ephemeral GitHub Actions OIDC token bound to this workflow + tag. - Release notes body updated with the cosign verify-blob command so users know how to verify authenticity end-to-end. Installers (install.sh / update.sh): - Add verify_release_cosign() function. OPT-IN via THREE_M_UI_VERIFY_COSIGN=1 (off by default to keep the curl|bash UX simple — SHA256SUMS integrity is already fail-closed). - When enabled AND cosign is installed, downloads SHA256SUMS.pem + SHA256SUMS.sig and runs cosign verify-blob against the identity 'https://github.com/<repo>/.github/workflows/release.yml@refs/tags/<tag>'. - If cosign is missing or the release predates signing, prints a warning and continues (does not hard-fail). - If verification runs and FAILS, aborts (fail-closed, bypassable via THREE_M_UI_INSECURE=1). Threat model: - Before: SHA256SUMS provided integrity but not authenticity — an attacker who could modify the release assets could also modify SHA256SUMS, defeating the checksum. - After: cosign signature ties SHA256SUMS to the GitHub Actions OIDC identity, so a modified sums file fails signature verification even if the attacker controls the release CDN. Verification command (for end users): cosign verify-blob \ --certificate SHA256SUMS.pem \ --signature SHA256SUMS.sig \ --certificate-identity 'https://github.com/kazeyukiro/3m-ui/.github/workflows/release.yml@refs/tags/<tag>' \ --certificate-oidc-issuer https://token.actions.githubusercontent.com \ SHA256SUMS feat(release): cosign keyless signing of SHA256SUMS Closes M-10 (supply-chain authenticity). Replaces the TODO comment with a working cosign keyless OIDC signing flow. Workflow (release.yml): - Add id-token: write permission (required for GitHub OIDC token). - Add sigstore/cosign-installer@v3 step. - After SHA256SUMS is generated, cosign sign-blob --yes produces SHA256SUMS.pem (certificate) and SHA256SUMS.sig (signature). These are uploaded alongside the existing release assets. - No long-lived secret is stored on GitHub; the signing identity is the ephemeral GitHub Actions OIDC token bound to this workflow + tag. - Release notes body updated with the cosign verify-blob command so users know how to verify authenticity end-to-end. Installers (install.sh / update.sh): - Add verify_release_cosign() function. OPT-IN via THREE_M_UI_VERIFY_COSIGN=1 (off by default to keep the curl|bash UX simple — SHA256SUMS integrity is already fail-closed). - When enabled AND cosign is installed, downloads SHA256SUMS.pem + SHA256SUMS.sig and runs cosign verify-blob against the identity 'https://github.com/<repo>/.github/workflows/release.yml@refs/tags/<tag>'. - If cosign is missing or the release predates signing, prints a warning and continues (does not hard-fail). - If verification runs and FAILS, aborts (fail-closed, bypassable via THREE_M_UI_INSECURE=1). Threat model: - Before: SHA256SUMS provided integrity but not authenticity — an attacker who could modify the release assets could also modify SHA256SUMS, defeating the checksum. - After: cosign signature ties SHA256SUMS to the GitHub Actions OIDC identity, so a modified sums file fails signature verification even if the attacker controls the release CDN. Verification command (for end users): cosign verify-blob \ --certificate SHA256SUMS.pem \ --signature SHA256SUMS.sig \ --certificate-identity 'https://github.com/kazeyukiro/3m-ui/.github/workflows/release.yml@refs/tags/<tag>' \ --certificate-oidc-issuer https://token.actions.githubusercontent.com \ SHA256SUMS feat(release): cosign keyless signing of SHA256SUMS Closes M-10 (supply-chain authenticity). Replaces the TODO comment with a working cosign keyless OIDC signing flow. Workflow (release.yml): - Add id-token: write permission (required for GitHub OIDC token). - Add sigstore/cosign-installer@v3 step. - After SHA256SUMS is generated, cosign sign-blob --yes produces SHA256SUMS.pem (certificate) and SHA256SUMS.sig (signature). These are uploaded alongside the existing release assets. - No long-lived secret is stored on GitHub; the signing identity is the ephemeral GitHub Actions OIDC token bound to this workflow + tag. - Release notes body updated with the cosign verify-blob command so users know how to verify authenticity end-to-end. Installers (install.sh / update.sh): - Add verify_release_cosign() function. OPT-IN via THREE_M_UI_VERIFY_COSIGN=1 (off by default to keep the curl|bash UX simple — SHA256SUMS integrity is already fail-closed). - When enabled AND cosign is installed, downloads SHA256SUMS.pem + SHA256SUMS.sig and runs cosign verify-blob against the identity 'https://github.com/<repo>/.github/workflows/release.yml@refs/tags/<tag>'. - If cosign is missing or the release predates signing, prints a warning and continues (does not hard-fail). - If verification runs and FAILS, aborts (fail-closed, bypassable via THREE_M_UI_INSECURE=1). Threat model: - Before: SHA256SUMS provided integrity but not authenticity — an attacker who could modify the release assets could also modify SHA256SUMS, defeating the checksum. - After: cosign signature ties SHA256SUMS to the GitHub Actions OIDC identity, so a modified sums file fails signature verification even if the attacker controls the release CDN. Verification command (for end users): cosign verify-blob \ --certificate SHA256SUMS.pem \ --signature SHA256SUMS.sig \ --certificate-identity 'https://github.com/kazeyukiro/3m-ui/.github/workflows/release.yml@refs/tags/<tag>' \ --certificate-oidc-issuer https://token.actions.githubusercontent.com \ SHA256SUMS feat(release): cosign keyless signing of SHA256SUMS Closes M-10 (supply-chain authenticity). Replaces the TODO comment with a working cosign keyless OIDC signing flow. Workflow (release.yml): - Add id-token: write permission (required for GitHub OIDC token). - Add sigstore/cosign-installer@v3 step. - After SHA256SUMS is generated, cosign sign-blob --yes produces SHA256SUMS.pem (certificate) and SHA256SUMS.sig (signature). These are uploaded alongside the existing release assets. - No long-lived secret is stored on GitHub; the signing identity is the ephemeral GitHub Actions OIDC token bound to this workflow + tag. - Release notes body updated with the cosign verify-blob command so users know how to verify authenticity end-to-end. Installers (install.sh / update.sh): - Add verify_release_cosign() function. OPT-IN via THREE_M_UI_VERIFY_COSIGN=1 (off by default to keep the curl|bash UX simple — SHA256SUMS integrity is already fail-closed). - When enabled AND cosign is installed, downloads SHA256SUMS.pem + SHA256SUMS.sig and runs cosign verify-blob against the identity 'https://github.com/<repo>/.github/workflows/release.yml@refs/tags/<tag>'. - If cosign is missing or the release predates signing, prints a warning and continues (does not hard-fail). - If verification runs and FAILS, aborts (fail-closed, bypassable via THREE_M_UI_INSECURE=1). Threat model: - Before: SHA256SUMS provided integrity but not authenticity — an attacker who could modify the release assets could also modify SHA256SUMS, defeating the checksum. - After: cosign signature ties SHA256SUMS to the GitHub Actions OIDC identity, so a modified sums file fails signature verification even if the attacker controls the release CDN. Verification command (for end users): cosign verify-blob \ --certificate SHA256SUMS.pem \ --signature SHA256SUMS.sig \ --certificate-identity 'https://github.com/kazeyukiro/3m-ui/.github/workflows/release.yml@refs/tags/<tag>' \ --certificate-oidc-issuer https://token.actions.githubusercontent.com \ SHA256SUMS feat(release): cosign keyless signing of SHA256SUMS Closes M-10 (supply-chain authenticity). Replaces the TODO comment with a working cosign keyless OIDC signing flow. Workflow (release.yml): - Add id-token: write permission (required for GitHub OIDC token). - Add sigstore/cosign-installer@v3 step. - After SHA256SUMS is generated, cosign sign-blob --yes produces SHA256SUMS.pem (certificate) and SHA256SUMS.sig (signature). These are uploaded alongside the existing release assets. - No long-lived secret is stored on GitHub; the signing identity is the ephemeral GitHub Actions OIDC token bound to this workflow + tag. - Release notes body updated with the cosign verify-blob command so users know how to verify authenticity end-to-end. Installers (install.sh / update.sh): - Add verify_release_cosign() function. OPT-IN via THREE_M_UI_VERIFY_COSIGN=1 (off by default to keep the curl|bash UX simple — SHA256SUMS integrity is already fail-closed). - When enabled AND cosign is installed, downloads SHA256SUMS.pem + SHA256SUMS.sig and runs cosign verify-blob against the identity 'https://github.com/<repo>/.github/workflows/release.yml@refs/tags/<tag>'. - If cosign is missing or the release predates signing, prints a warning and continues (does not hard-fail). - If verification runs and FAILS, aborts (fail-closed, bypassable via THREE_M_UI_INSECURE=1). Threat model: - Before: SHA256SUMS provided integrity but not authenticity — an attacker who could modify the release assets could also modify SHA256SUMS, defeating the checksum. - After: cosign signature ties SHA256SUMS to the GitHub Actions OIDC identity, so a modified sums file fails signature verification even if the attacker controls the release CDN. Verification command (for end users): cosign verify-blob \ --certificate SHA256SUMS.pem \ --signature SHA256SUMS.sig \ --certificate-identity 'https://github.com/kazeyukiro/3m-ui/.github/workflows/release.yml@refs/tags/<tag>' \ --certificate-oidc-issuer https://token.actions.githubusercontent.com \ SHA256SUMS feat(release): cosign keyless signing of SHA256SUMS Closes M-10 (supply-chain authenticity). Replaces the TODO comment with a working cosign keyless OIDC signing flow. Workflow (release.yml): - Add id-token: write permission (required for GitHub OIDC token). - Add sigstore/cosign-installer@v3 step. - After SHA256SUMS is generated, cosign sign-blob --yes produces SHA256SUMS.pem (certificate) and SHA256SUMS.sig (signature). These are uploaded alongside the existing release assets. - No long-lived secret is stored on GitHub; the signing identity is the ephemeral GitHub Actions OIDC token bound to this workflow + tag. - Release notes body updated with the cosign verify-blob command so users know how to verify authenticity end-to-end. Installers (install.sh / update.sh): - Add verify_release_cosign() function. OPT-IN via THREE_M_UI_VERIFY_COSIGN=1 (off by default to keep the curl|bash UX simple — SHA256SUMS integrity is already fail-closed). - When enabled AND cosign is installed, downloads SHA256SUMS.pem + SHA256SUMS.sig and runs cosign verify-blob against the identity 'https://github.com/<repo>/.github/workflows/release.yml@refs/tags/<tag>'. - If cosign is missing or the release predates signing, prints a warning and continues (does not hard-fail). - If verification runs and FAILS, aborts (fail-closed, bypassable via THREE_M_UI_INSECURE=1). Threat model: - Before: SHA256SUMS provided integrity but not authenticity — an attacker who could modify the release assets could also modify SHA256SUMS, defeating the checksum. - After: cosign signature ties SHA256SUMS to the GitHub Actions OIDC identity, so a modified sums file fails signature verification even if the attacker controls the release CDN. Verification command (for end users): cosign verify-blob \ --certificate SHA256SUMS.pem \ --signature SHA256SUMS.sig \ --certificate-identity 'https://github.com/kazeyukiro/3m-ui/.github/workflows/release.yml@refs/tags/<tag>' \ --certificate-oidc-issuer https://token.actions.githubusercontent.com \ SHA256SUMS feat(release): cosign keyless signing of SHA256SUMS Closes M-10 (supply-chain authenticity). Replaces the TODO comment with a working cosign keyless OIDC signing flow. Workflow (release.yml): - Add id-token: write permission (required for GitHub OIDC token). - Add sigstore/cosign-installer@v3 step. - After SHA256SUMS is generated, cosign sign-blob --yes produces SHA256SUMS.pem (certificate) and SHA256SUMS.sig (signature). These are uploaded alongside the existing release assets. - No long-lived secret is stored on GitHub; the signing identity is the ephemeral GitHub Actions OIDC token bound to this workflow + tag. - Release notes body updated with the cosign verify-blob command so users know how to verify authenticity end-to-end. Installers (install.sh / update.sh): - Add verify_release_cosign() function. OPT-IN via THREE_M_UI_VERIFY_COSIGN=1 (off by default to keep the curl|bash UX simple — SHA256SUMS integrity is already fail-closed). - When enabled AND cosign is installed, downloads SHA256SUMS.pem + SHA256SUMS.sig and runs cosign verify-blob against the identity 'https://github.com/<repo>/.github/workflows/release.yml@refs/tags/<tag>'. - If cosign is missing or the release predates signing, prints a warning and continues (does not hard-fail). - If verification runs and FAILS, aborts (fail-closed, bypassable via THREE_M_UI_INSECURE=1). Threat model: - Before: SHA256SUMS provided integrity but not authenticity — an attacker who could modify the release assets could also modify SHA256SUMS, defeating the checksum. - After: cosign signature ties SHA256SUMS to the GitHub Actions OIDC identity, so a modified sums file fails signature verification even if the attacker controls the release CDN. Verification command (for end users): cosign verify-blob \ --certificate SHA256SUMS.pem \ --signature SHA256SUMS.sig \ --certificate-identity 'https://github.com/kazeyukiro/3m-ui/.github/workflows/release.yml@refs/tags/<tag>' \ --certificate-oidc-issuer https://token.actions.githubusercontent.com \ SHA256SUMS feat(release): cosign keyless signing of SHA256SUMS Closes M-10 (supply-chain authenticity). Replaces the TODO comment with a working cosign keyless OIDC signing flow. Workflow (release.yml): - Add id-token: write permission (required for GitHub OIDC token). - Add sigstore/cosign-installer@v3 step. - After SHA256SUMS is generated, cosign sign-blob --yes produces SHA256SUMS.pem (certificate) and SHA256SUMS.sig (signature). These are uploaded alongside the existing release assets. - No long-lived secret is stored on GitHub; the signing identity is the ephemeral GitHub Actions OIDC token bound to this workflow + tag. - Release notes body updated with the cosign verify-blob command so users know how to verify authenticity end-to-end. Installers (install.sh / update.sh): - Add verify_release_cosign() function. OPT-IN via THREE_M_UI_VERIFY_COSIGN=1 (off by default to keep the curl|bash UX simple — SHA256SUMS integrity is already fail-closed). - When enabled AND cosign is installed, downloads SHA256SUMS.pem + SHA256SUMS.sig and runs cosign verify-blob against the identity 'https://github.com/<repo>/.github/workflows/release.yml@refs/tags/<tag>'. - If cosign is missing or the release predates signing, prints a warning and continues (does not hard-fail). - If verification runs and FAILS, aborts (fail-closed, bypassable via THREE_M_UI_INSECURE=1). Threat model: - Before: SHA256SUMS provided integrity but not authenticity — an attacker who could modify the release assets could also modify SHA256SUMS, defeating the checksum. - After: cosign signature ties SHA256SUMS to the GitHub Actions OIDC identity, so a modified sums file fails signature verification even if the attacker controls the release CDN. Verification command (for end users): cosign verify-blob \ --certificate SHA256SUMS.pem \ --signature SHA256SUMS.sig \ --certificate-identity 'https://github.com/kazeyukiro/3m-ui/.github/workflows/release.yml@refs/tags/<tag>' \ --certificate-oidc-issuer https://token.actions.githubusercontent.com \ SHA256SUMS feat(release): cosign keyless signing of SHA256SUMS Closes M-10 (supply-chain authenticity). Replaces the TODO comment with a working cosign keyless OIDC signing flow. Workflow (release.yml): - Add id-token: write permission (required for GitHub OIDC token). - Add sigstore/cosign-installer@v3 step. - After SHA256SUMS is generated, cosign sign-blob --yes produces SHA256SUMS.pem (certificate) and SHA256SUMS.sig (signature). These are uploaded alongside the existing release assets. - No long-lived secret is stored on GitHub; the signing identity is the ephemeral GitHub Actions OIDC token bound to this workflow + tag. - Release notes body updated with the cosign verify-blob command so users know how to verify authenticity end-to-end. Installers (install.sh / update.sh): - Add verify_release_cosign() function. OPT-IN via THREE_M_UI_VERIFY_COSIGN=1 (off by default to keep the curl|bash UX simple — SHA256SUMS integrity is already fail-closed). - When enabled AND cosign is installed, downloads SHA256SUMS.pem + SHA256SUMS.sig and runs cosign verify-blob against the identity 'https://github.com/<repo>/.github/workflows/release.yml@refs/tags/<tag>'. - If cosign is missing or the release predates signing, prints a warning and continues (does not hard-fail). - If verification runs and FAILS, aborts (fail-closed, bypassable via THREE_M_UI_INSECURE=1). Threat model: - Before: SHA256SUMS provided integrity but not authenticity — an attacker who could modify the release assets could also modify SHA256SUMS, defeating the checksum. - After: cosign signature ties SHA256SUMS to the GitHub Actions OIDC identity, so a modified sums file fails signature verification even if the attacker controls the release CDN. Verification command (for end users): cosign verify-blob \ --certificate SHA256SUMS.pem \ --signature SHA256SUMS.sig \ --certificate-identity 'https://github.com/kazeyukiro/3m-ui/.github/workflows/release.yml@refs/tags/<tag>' \ --certificate-oidc-issuer https://token.actions.githubusercontent.com \ SHA256SUMS |
||
|
|
39608cd0fb |
fix(infra): fail-closed checksums, sandbox hardening, non-root Docker
Critical (supply chain): - C-3: Mihomo binary download had no checksum. Add verify_mihomo_sha256() downloading MetaCubeX SHA256SUMS and verifying the .gz BEFORE decompression. Mismatch is fatal. - C-4: verify_release_sha256 soft-failed (return 0) when SHA256SUMS was missing or asset unlisted. Now fail-closed: err exit unless the operator sets THREE_M_UI_INSECURE=1 (prints a loud WARNING). sha256 tooling is now a hard dependency. - C-5: Downloaded binaries were executed as root (--version / -v) for smoke-testing. Remove every invocation; rely on checksum + 'file' ELF check instead. - H-1: Drop raw.githubusercontent.com fallback for helper scripts. Missing release asset now hard-fails (supply-chain posture). Sandbox: - H-2: systemd unit gains UMask=0077, ProtectSystem=strict, ProtectHome, PrivateTmp, PrivateDevices, ProtectKernelTunables/ Modules/Logs, ProtectControlGroups, ReadWritePaths, RestrictAddressFamilies, RestrictNamespaces, RestrictRealtime, RestrictSUIDSGID, LockPersonality, SystemCallArchitectures=native, SystemCallFilter=@system-service ~@privileged @resources. CapabilityBoundingSet now includes CAP_NET_ADMIN for Mihomo TUN. - C-4(Docker): Dockerfile creates non-root user 3m-ui (UID 10001), pre-creates & chowns volumes, sets USER 10001:10001. - M-3: docker-compose ports 8080:8080 -> 127.0.0.1:8080:8080 (loopback-only by default; operator uses reverse proxy). - M-9: docker-compose gains security notes (reverse-proxy guidance, admin/admin + forced first-login change, THREE_M_UI_ADMIN_PASSWORD example, UID 10001 volume ownership). - M-10: release.yml gains a TODO comment for cosign keyless signing. - LOW: AGENTS.md Go 1.24+ -> Go 1.25+; install.sh final message now 'Initial administrator: admin / admin. You MUST change the password on first login.' fix(infra): fail-closed checksums, sandbox hardening, non-root Docker Critical (supply chain): - C-3: Mihomo binary download had no checksum. Add verify_mihomo_sha256() downloading MetaCubeX SHA256SUMS and verifying the .gz BEFORE decompression. Mismatch is fatal. - C-4: verify_release_sha256 soft-failed (return 0) when SHA256SUMS was missing or asset unlisted. Now fail-closed: err exit unless the operator sets THREE_M_UI_INSECURE=1 (prints a loud WARNING). sha256 tooling is now a hard dependency. - C-5: Downloaded binaries were executed as root (--version / -v) for smoke-testing. Remove every invocation; rely on checksum + 'file' ELF check instead. - H-1: Drop raw.githubusercontent.com fallback for helper scripts. Missing release asset now hard-fails (supply-chain posture). Sandbox: - H-2: systemd unit gains UMask=0077, ProtectSystem=strict, ProtectHome, PrivateTmp, PrivateDevices, ProtectKernelTunables/ Modules/Logs, ProtectControlGroups, ReadWritePaths, RestrictAddressFamilies, RestrictNamespaces, RestrictRealtime, RestrictSUIDSGID, LockPersonality, SystemCallArchitectures=native, SystemCallFilter=@system-service ~@privileged @resources. CapabilityBoundingSet now includes CAP_NET_ADMIN for Mihomo TUN. - C-4(Docker): Dockerfile creates non-root user 3m-ui (UID 10001), pre-creates & chowns volumes, sets USER 10001:10001. - M-3: docker-compose ports 8080:8080 -> 127.0.0.1:8080:8080 (loopback-only by default; operator uses reverse proxy). - M-9: docker-compose gains security notes (reverse-proxy guidance, admin/admin + forced first-login change, THREE_M_UI_ADMIN_PASSWORD example, UID 10001 volume ownership). - M-10: release.yml gains a TODO comment for cosign keyless signing. - LOW: AGENTS.md Go 1.24+ -> Go 1.25+; install.sh final message now 'Initial administrator: admin / admin. You MUST change the password on first login.' fix(infra): fail-closed checksums, sandbox hardening, non-root Docker Critical (supply chain): - C-3: Mihomo binary download had no checksum. Add verify_mihomo_sha256() downloading MetaCubeX SHA256SUMS and verifying the .gz BEFORE decompression. Mismatch is fatal. - C-4: verify_release_sha256 soft-failed (return 0) when SHA256SUMS was missing or asset unlisted. Now fail-closed: err exit unless the operator sets THREE_M_UI_INSECURE=1 (prints a loud WARNING). sha256 tooling is now a hard dependency. - C-5: Downloaded binaries were executed as root (--version / -v) for smoke-testing. Remove every invocation; rely on checksum + 'file' ELF check instead. - H-1: Drop raw.githubusercontent.com fallback for helper scripts. Missing release asset now hard-fails (supply-chain posture). Sandbox: - H-2: systemd unit gains UMask=0077, ProtectSystem=strict, ProtectHome, PrivateTmp, PrivateDevices, ProtectKernelTunables/ Modules/Logs, ProtectControlGroups, ReadWritePaths, RestrictAddressFamilies, RestrictNamespaces, RestrictRealtime, RestrictSUIDSGID, LockPersonality, SystemCallArchitectures=native, SystemCallFilter=@system-service ~@privileged @resources. CapabilityBoundingSet now includes CAP_NET_ADMIN for Mihomo TUN. - C-4(Docker): Dockerfile creates non-root user 3m-ui (UID 10001), pre-creates & chowns volumes, sets USER 10001:10001. - M-3: docker-compose ports 8080:8080 -> 127.0.0.1:8080:8080 (loopback-only by default; operator uses reverse proxy). - M-9: docker-compose gains security notes (reverse-proxy guidance, admin/admin + forced first-login change, THREE_M_UI_ADMIN_PASSWORD example, UID 10001 volume ownership). - M-10: release.yml gains a TODO comment for cosign keyless signing. - LOW: AGENTS.md Go 1.24+ -> Go 1.25+; install.sh final message now 'Initial administrator: admin / admin. You MUST change the password on first login.' fix(infra): fail-closed checksums, sandbox hardening, non-root Docker Critical (supply chain): - C-3: Mihomo binary download had no checksum. Add verify_mihomo_sha256() downloading MetaCubeX SHA256SUMS and verifying the .gz BEFORE decompression. Mismatch is fatal. - C-4: verify_release_sha256 soft-failed (return 0) when SHA256SUMS was missing or asset unlisted. Now fail-closed: err exit unless the operator sets THREE_M_UI_INSECURE=1 (prints a loud WARNING). sha256 tooling is now a hard dependency. - C-5: Downloaded binaries were executed as root (--version / -v) for smoke-testing. Remove every invocation; rely on checksum + 'file' ELF check instead. - H-1: Drop raw.githubusercontent.com fallback for helper scripts. Missing release asset now hard-fails (supply-chain posture). Sandbox: - H-2: systemd unit gains UMask=0077, ProtectSystem=strict, ProtectHome, PrivateTmp, PrivateDevices, ProtectKernelTunables/ Modules/Logs, ProtectControlGroups, ReadWritePaths, RestrictAddressFamilies, RestrictNamespaces, RestrictRealtime, RestrictSUIDSGID, LockPersonality, SystemCallArchitectures=native, SystemCallFilter=@system-service ~@privileged @resources. CapabilityBoundingSet now includes CAP_NET_ADMIN for Mihomo TUN. - C-4(Docker): Dockerfile creates non-root user 3m-ui (UID 10001), pre-creates & chowns volumes, sets USER 10001:10001. - M-3: docker-compose ports 8080:8080 -> 127.0.0.1:8080:8080 (loopback-only by default; operator uses reverse proxy). - M-9: docker-compose gains security notes (reverse-proxy guidance, admin/admin + forced first-login change, THREE_M_UI_ADMIN_PASSWORD example, UID 10001 volume ownership). - M-10: release.yml gains a TODO comment for cosign keyless signing. - LOW: AGENTS.md Go 1.24+ -> Go 1.25+; install.sh final message now 'Initial administrator: admin / admin. You MUST change the password on first login.' fix(infra): fail-closed checksums, sandbox hardening, non-root Docker Critical (supply chain): - C-3: Mihomo binary download had no checksum. Add verify_mihomo_sha256() downloading MetaCubeX SHA256SUMS and verifying the .gz BEFORE decompression. Mismatch is fatal. - C-4: verify_release_sha256 soft-failed (return 0) when SHA256SUMS was missing or asset unlisted. Now fail-closed: err exit unless the operator sets THREE_M_UI_INSECURE=1 (prints a loud WARNING). sha256 tooling is now a hard dependency. - C-5: Downloaded binaries were executed as root (--version / -v) for smoke-testing. Remove every invocation; rely on checksum + 'file' ELF check instead. - H-1: Drop raw.githubusercontent.com fallback for helper scripts. Missing release asset now hard-fails (supply-chain posture). Sandbox: - H-2: systemd unit gains UMask=0077, ProtectSystem=strict, ProtectHome, PrivateTmp, PrivateDevices, ProtectKernelTunables/ Modules/Logs, ProtectControlGroups, ReadWritePaths, RestrictAddressFamilies, RestrictNamespaces, RestrictRealtime, RestrictSUIDSGID, LockPersonality, SystemCallArchitectures=native, SystemCallFilter=@system-service ~@privileged @resources. CapabilityBoundingSet now includes CAP_NET_ADMIN for Mihomo TUN. - C-4(Docker): Dockerfile creates non-root user 3m-ui (UID 10001), pre-creates & chowns volumes, sets USER 10001:10001. - M-3: docker-compose ports 8080:8080 -> 127.0.0.1:8080:8080 (loopback-only by default; operator uses reverse proxy). - M-9: docker-compose gains security notes (reverse-proxy guidance, admin/admin + forced first-login change, THREE_M_UI_ADMIN_PASSWORD example, UID 10001 volume ownership). - M-10: release.yml gains a TODO comment for cosign keyless signing. - LOW: AGENTS.md Go 1.24+ -> Go 1.25+; install.sh final message now 'Initial administrator: admin / admin. You MUST change the password on first login.' fix(infra): fail-closed checksums, sandbox hardening, non-root Docker Critical (supply chain): - C-3: Mihomo binary download had no checksum. Add verify_mihomo_sha256() downloading MetaCubeX SHA256SUMS and verifying the .gz BEFORE decompression. Mismatch is fatal. - C-4: verify_release_sha256 soft-failed (return 0) when SHA256SUMS was missing or asset unlisted. Now fail-closed: err exit unless the operator sets THREE_M_UI_INSECURE=1 (prints a loud WARNING). sha256 tooling is now a hard dependency. - C-5: Downloaded binaries were executed as root (--version / -v) for smoke-testing. Remove every invocation; rely on checksum + 'file' ELF check instead. - H-1: Drop raw.githubusercontent.com fallback for helper scripts. Missing release asset now hard-fails (supply-chain posture). Sandbox: - H-2: systemd unit gains UMask=0077, ProtectSystem=strict, ProtectHome, PrivateTmp, PrivateDevices, ProtectKernelTunables/ Modules/Logs, ProtectControlGroups, ReadWritePaths, RestrictAddressFamilies, RestrictNamespaces, RestrictRealtime, RestrictSUIDSGID, LockPersonality, SystemCallArchitectures=native, SystemCallFilter=@system-service ~@privileged @resources. CapabilityBoundingSet now includes CAP_NET_ADMIN for Mihomo TUN. - C-4(Docker): Dockerfile creates non-root user 3m-ui (UID 10001), pre-creates & chowns volumes, sets USER 10001:10001. - M-3: docker-compose ports 8080:8080 -> 127.0.0.1:8080:8080 (loopback-only by default; operator uses reverse proxy). - M-9: docker-compose gains security notes (reverse-proxy guidance, admin/admin + forced first-login change, THREE_M_UI_ADMIN_PASSWORD example, UID 10001 volume ownership). - M-10: release.yml gains a TODO comment for cosign keyless signing. - LOW: AGENTS.md Go 1.24+ -> Go 1.25+; install.sh final message now 'Initial administrator: admin / admin. You MUST change the password on first login.' fix(infra): fail-closed checksums, sandbox hardening, non-root Docker Critical (supply chain): - C-3: Mihomo binary download had no checksum. Add verify_mihomo_sha256() downloading MetaCubeX SHA256SUMS and verifying the .gz BEFORE decompression. Mismatch is fatal. - C-4: verify_release_sha256 soft-failed (return 0) when SHA256SUMS was missing or asset unlisted. Now fail-closed: err exit unless the operator sets THREE_M_UI_INSECURE=1 (prints a loud WARNING). sha256 tooling is now a hard dependency. - C-5: Downloaded binaries were executed as root (--version / -v) for smoke-testing. Remove every invocation; rely on checksum + 'file' ELF check instead. - H-1: Drop raw.githubusercontent.com fallback for helper scripts. Missing release asset now hard-fails (supply-chain posture). Sandbox: - H-2: systemd unit gains UMask=0077, ProtectSystem=strict, ProtectHome, PrivateTmp, PrivateDevices, ProtectKernelTunables/ Modules/Logs, ProtectControlGroups, ReadWritePaths, RestrictAddressFamilies, RestrictNamespaces, RestrictRealtime, RestrictSUIDSGID, LockPersonality, SystemCallArchitectures=native, SystemCallFilter=@system-service ~@privileged @resources. CapabilityBoundingSet now includes CAP_NET_ADMIN for Mihomo TUN. - C-4(Docker): Dockerfile creates non-root user 3m-ui (UID 10001), pre-creates & chowns volumes, sets USER 10001:10001. - M-3: docker-compose ports 8080:8080 -> 127.0.0.1:8080:8080 (loopback-only by default; operator uses reverse proxy). - M-9: docker-compose gains security notes (reverse-proxy guidance, admin/admin + forced first-login change, THREE_M_UI_ADMIN_PASSWORD example, UID 10001 volume ownership). - M-10: release.yml gains a TODO comment for cosign keyless signing. - LOW: AGENTS.md Go 1.24+ -> Go 1.25+; install.sh final message now 'Initial administrator: admin / admin. You MUST change the password on first login.' fix(infra): fail-closed checksums, sandbox hardening, non-root Docker Critical (supply chain): - C-3: Mihomo binary download had no checksum. Add verify_mihomo_sha256() downloading MetaCubeX SHA256SUMS and verifying the .gz BEFORE decompression. Mismatch is fatal. - C-4: verify_release_sha256 soft-failed (return 0) when SHA256SUMS was missing or asset unlisted. Now fail-closed: err exit unless the operator sets THREE_M_UI_INSECURE=1 (prints a loud WARNING). sha256 tooling is now a hard dependency. - C-5: Downloaded binaries were executed as root (--version / -v) for smoke-testing. Remove every invocation; rely on checksum + 'file' ELF check instead. - H-1: Drop raw.githubusercontent.com fallback for helper scripts. Missing release asset now hard-fails (supply-chain posture). Sandbox: - H-2: systemd unit gains UMask=0077, ProtectSystem=strict, ProtectHome, PrivateTmp, PrivateDevices, ProtectKernelTunables/ Modules/Logs, ProtectControlGroups, ReadWritePaths, RestrictAddressFamilies, RestrictNamespaces, RestrictRealtime, RestrictSUIDSGID, LockPersonality, SystemCallArchitectures=native, SystemCallFilter=@system-service ~@privileged @resources. CapabilityBoundingSet now includes CAP_NET_ADMIN for Mihomo TUN. - C-4(Docker): Dockerfile creates non-root user 3m-ui (UID 10001), pre-creates & chowns volumes, sets USER 10001:10001. - M-3: docker-compose ports 8080:8080 -> 127.0.0.1:8080:8080 (loopback-only by default; operator uses reverse proxy). - M-9: docker-compose gains security notes (reverse-proxy guidance, admin/admin + forced first-login change, THREE_M_UI_ADMIN_PASSWORD example, UID 10001 volume ownership). - M-10: release.yml gains a TODO comment for cosign keyless signing. - LOW: AGENTS.md Go 1.24+ -> Go 1.25+; install.sh final message now 'Initial administrator: admin / admin. You MUST change the password on first login.' fix(infra): fail-closed checksums, sandbox hardening, non-root Docker Critical (supply chain): - C-3: Mihomo binary download had no checksum. Add verify_mihomo_sha256() downloading MetaCubeX SHA256SUMS and verifying the .gz BEFORE decompression. Mismatch is fatal. - C-4: verify_release_sha256 soft-failed (return 0) when SHA256SUMS was missing or asset unlisted. Now fail-closed: err exit unless the operator sets THREE_M_UI_INSECURE=1 (prints a loud WARNING). sha256 tooling is now a hard dependency. - C-5: Downloaded binaries were executed as root (--version / -v) for smoke-testing. Remove every invocation; rely on checksum + 'file' ELF check instead. - H-1: Drop raw.githubusercontent.com fallback for helper scripts. Missing release asset now hard-fails (supply-chain posture). Sandbox: - H-2: systemd unit gains UMask=0077, ProtectSystem=strict, ProtectHome, PrivateTmp, PrivateDevices, ProtectKernelTunables/ Modules/Logs, ProtectControlGroups, ReadWritePaths, RestrictAddressFamilies, RestrictNamespaces, RestrictRealtime, RestrictSUIDSGID, LockPersonality, SystemCallArchitectures=native, SystemCallFilter=@system-service ~@privileged @resources. CapabilityBoundingSet now includes CAP_NET_ADMIN for Mihomo TUN. - C-4(Docker): Dockerfile creates non-root user 3m-ui (UID 10001), pre-creates & chowns volumes, sets USER 10001:10001. - M-3: docker-compose ports 8080:8080 -> 127.0.0.1:8080:8080 (loopback-only by default; operator uses reverse proxy). - M-9: docker-compose gains security notes (reverse-proxy guidance, admin/admin + forced first-login change, THREE_M_UI_ADMIN_PASSWORD example, UID 10001 volume ownership). - M-10: release.yml gains a TODO comment for cosign keyless signing. - LOW: AGENTS.md Go 1.24+ -> Go 1.25+; install.sh final message now 'Initial administrator: admin / admin. You MUST change the password on first login.' fix(infra): fail-closed checksums, sandbox hardening, non-root Docker Critical (supply chain): - C-3: Mihomo binary download had no checksum. Add verify_mihomo_sha256() downloading MetaCubeX SHA256SUMS and verifying the .gz BEFORE decompression. Mismatch is fatal. - C-4: verify_release_sha256 soft-failed (return 0) when SHA256SUMS was missing or asset unlisted. Now fail-closed: err exit unless the operator sets THREE_M_UI_INSECURE=1 (prints a loud WARNING). sha256 tooling is now a hard dependency. - C-5: Downloaded binaries were executed as root (--version / -v) for smoke-testing. Remove every invocation; rely on checksum + 'file' ELF check instead. - H-1: Drop raw.githubusercontent.com fallback for helper scripts. Missing release asset now hard-fails (supply-chain posture). Sandbox: - H-2: systemd unit gains UMask=0077, ProtectSystem=strict, ProtectHome, PrivateTmp, PrivateDevices, ProtectKernelTunables/ Modules/Logs, ProtectControlGroups, ReadWritePaths, RestrictAddressFamilies, RestrictNamespaces, RestrictRealtime, RestrictSUIDSGID, LockPersonality, SystemCallArchitectures=native, SystemCallFilter=@system-service ~@privileged @resources. CapabilityBoundingSet now includes CAP_NET_ADMIN for Mihomo TUN. - C-4(Docker): Dockerfile creates non-root user 3m-ui (UID 10001), pre-creates & chowns volumes, sets USER 10001:10001. - M-3: docker-compose ports 8080:8080 -> 127.0.0.1:8080:8080 (loopback-only by default; operator uses reverse proxy). - M-9: docker-compose gains security notes (reverse-proxy guidance, admin/admin + forced first-login change, THREE_M_UI_ADMIN_PASSWORD example, UID 10001 volume ownership). - M-10: release.yml gains a TODO comment for cosign keyless signing. - LOW: AGENTS.md Go 1.24+ -> Go 1.25+; install.sh final message now 'Initial administrator: admin / admin. You MUST change the password on first login.' fix(infra): fail-closed checksums, sandbox hardening, non-root Docker Critical (supply chain): - C-3: Mihomo binary download had no checksum. Add verify_mihomo_sha256() downloading MetaCubeX SHA256SUMS and verifying the .gz BEFORE decompression. Mismatch is fatal. - C-4: verify_release_sha256 soft-failed (return 0) when SHA256SUMS was missing or asset unlisted. Now fail-closed: err exit unless the operator sets THREE_M_UI_INSECURE=1 (prints a loud WARNING). sha256 tooling is now a hard dependency. - C-5: Downloaded binaries were executed as root (--version / -v) for smoke-testing. Remove every invocation; rely on checksum + 'file' ELF check instead. - H-1: Drop raw.githubusercontent.com fallback for helper scripts. Missing release asset now hard-fails (supply-chain posture). Sandbox: - H-2: systemd unit gains UMask=0077, ProtectSystem=strict, ProtectHome, PrivateTmp, PrivateDevices, ProtectKernelTunables/ Modules/Logs, ProtectControlGroups, ReadWritePaths, RestrictAddressFamilies, RestrictNamespaces, RestrictRealtime, RestrictSUIDSGID, LockPersonality, SystemCallArchitectures=native, SystemCallFilter=@system-service ~@privileged @resources. CapabilityBoundingSet now includes CAP_NET_ADMIN for Mihomo TUN. - C-4(Docker): Dockerfile creates non-root user 3m-ui (UID 10001), pre-creates & chowns volumes, sets USER 10001:10001. - M-3: docker-compose ports 8080:8080 -> 127.0.0.1:8080:8080 (loopback-only by default; operator uses reverse proxy). - M-9: docker-compose gains security notes (reverse-proxy guidance, admin/admin + forced first-login change, THREE_M_UI_ADMIN_PASSWORD example, UID 10001 volume ownership). - M-10: release.yml gains a TODO comment for cosign keyless signing. - LOW: AGENTS.md Go 1.24+ -> Go 1.25+; install.sh final message now 'Initial administrator: admin / admin. You MUST change the password on first login.' fix(infra): fail-closed checksums, sandbox hardening, non-root Docker Critical (supply chain): - C-3: Mihomo binary download had no checksum. Add verify_mihomo_sha256() downloading MetaCubeX SHA256SUMS and verifying the .gz BEFORE decompression. Mismatch is fatal. - C-4: verify_release_sha256 soft-failed (return 0) when SHA256SUMS was missing or asset unlisted. Now fail-closed: err exit unless the operator sets THREE_M_UI_INSECURE=1 (prints a loud WARNING). sha256 tooling is now a hard dependency. - C-5: Downloaded binaries were executed as root (--version / -v) for smoke-testing. Remove every invocation; rely on checksum + 'file' ELF check instead. - H-1: Drop raw.githubusercontent.com fallback for helper scripts. Missing release asset now hard-fails (supply-chain posture). Sandbox: - H-2: systemd unit gains UMask=0077, ProtectSystem=strict, ProtectHome, PrivateTmp, PrivateDevices, ProtectKernelTunables/ Modules/Logs, ProtectControlGroups, ReadWritePaths, RestrictAddressFamilies, RestrictNamespaces, RestrictRealtime, RestrictSUIDSGID, LockPersonality, SystemCallArchitectures=native, SystemCallFilter=@system-service ~@privileged @resources. CapabilityBoundingSet now includes CAP_NET_ADMIN for Mihomo TUN. - C-4(Docker): Dockerfile creates non-root user 3m-ui (UID 10001), pre-creates & chowns volumes, sets USER 10001:10001. - M-3: docker-compose ports 8080:8080 -> 127.0.0.1:8080:8080 (loopback-only by default; operator uses reverse proxy). - M-9: docker-compose gains security notes (reverse-proxy guidance, admin/admin + forced first-login change, THREE_M_UI_ADMIN_PASSWORD example, UID 10001 volume ownership). - M-10: release.yml gains a TODO comment for cosign keyless signing. - LOW: AGENTS.md Go 1.24+ -> Go 1.25+; install.sh final message now 'Initial administrator: admin / admin. You MUST change the password on first login.' |
||
|
|
1d1a69bf74 | feat(nat): custom panel port/listen/public_url via env, API, settings UI, install.sh | ||
|
|
5cdbedaabf | fix: restore install.sh + SHA256SUMS basename matching | ||
|
|
52a66c88cc | fix: SHA256SUMS basename match; attach scripts to release assets | ||
|
|
29ccad2597 |
revert(scripts): restore pre-s-ui menu/banner versions
revert(scripts): restore pre-s-ui menu/banner versions revert(scripts): restore pre-s-ui menu/banner versions revert(scripts): restore pre-s-ui menu/banner versions revert(scripts): restore pre-s-ui menu/banner versions revert(scripts): restore pre-s-ui menu/banner versions revert(scripts): restore pre-s-ui menu/banner versions revert(scripts): restore pre-s-ui menu/banner versions revert(scripts): restore pre-s-ui menu/banner versions revert(scripts): restore pre-s-ui menu/banner versions revert(scripts): restore pre-s-ui menu/banner versions revert(scripts): restore pre-s-ui menu/banner versions |
||
|
|
6a859d2e60 | feat(install): s-ui style finish banner with panel URLs | ||
|
|
4585f304a6 | fix(scripts): checksum verify, versioned update, backup retention, safer traps | ||
|
|
82713edf82 |
fix: panel must start even if Mihomo/SSL fails on boot
- Soft-fail ApplyConfig / config generation / SSL bind so the management UI remains reachable after deploy - Preserve os.IsNotExist in ConfigManager.ReadConfig (first-boot path) - systemd unit: CAP_NET_BIND_SERVICE + LimitNOFILE for optional ACME fix: panel must start even if Mihomo/SSL fails on boot - Soft-fail ApplyConfig / config generation / SSL bind so the management UI remains reachable after deploy - Preserve os.IsNotExist in ConfigManager.ReadConfig (first-boot path) - systemd unit: CAP_NET_BIND_SERVICE + LimitNOFILE for optional ACME fix: panel must start even if Mihomo/SSL fails on boot - Soft-fail ApplyConfig / config generation / SSL bind so the management UI remains reachable after deploy - Preserve os.IsNotExist in ConfigManager.ReadConfig (first-boot path) - systemd unit: CAP_NET_BIND_SERVICE + LimitNOFILE for optional ACME fix: panel must start even if Mihomo/SSL fails on boot - Soft-fail ApplyConfig / config generation / SSL bind so the management UI remains reachable after deploy - Preserve os.IsNotExist in ConfigManager.ReadConfig (first-boot path) - systemd unit: CAP_NET_BIND_SERVICE + LimitNOFILE for optional ACME fix: panel must start even if Mihomo/SSL fails on boot - Soft-fail ApplyConfig / config generation / SSL bind so the management UI remains reachable after deploy - Preserve os.IsNotExist in ConfigManager.ReadConfig (first-boot path) - systemd unit: CAP_NET_BIND_SERVICE + LimitNOFILE for optional ACME fix: panel must start even if Mihomo/SSL fails on boot - Soft-fail ApplyConfig / config generation / SSL bind so the management UI remains reachable after deploy - Preserve os.IsNotExist in ConfigManager.ReadConfig (first-boot path) - systemd unit: CAP_NET_BIND_SERVICE + LimitNOFILE for optional ACME fix: panel must start even if Mihomo/SSL fails on boot - Soft-fail ApplyConfig / config generation / SSL bind so the management UI remains reachable after deploy - Preserve os.IsNotExist in ConfigManager.ReadConfig (first-boot path) - systemd unit: CAP_NET_BIND_SERVICE + LimitNOFILE for optional ACME fix: panel must start even if Mihomo/SSL fails on boot - Soft-fail ApplyConfig / config generation / SSL bind so the management UI remains reachable after deploy - Preserve os.IsNotExist in ConfigManager.ReadConfig (first-boot path) - systemd unit: CAP_NET_BIND_SERVICE + LimitNOFILE for optional ACME fix: panel must start even if Mihomo/SSL fails on boot - Soft-fail ApplyConfig / config generation / SSL bind so the management UI remains reachable after deploy - Preserve os.IsNotExist in ConfigManager.ReadConfig (first-boot path) - systemd unit: CAP_NET_BIND_SERVICE + LimitNOFILE for optional ACME fix: panel must start even if Mihomo/SSL fails on boot - Soft-fail ApplyConfig / config generation / SSL bind so the management UI remains reachable after deploy - Preserve os.IsNotExist in ConfigManager.ReadConfig (first-boot path) - systemd unit: CAP_NET_BIND_SERVICE + LimitNOFILE for optional ACME fix: panel must start even if Mihomo/SSL fails on boot - Soft-fail ApplyConfig / config generation / SSL bind so the management UI remains reachable after deploy - Preserve os.IsNotExist in ConfigManager.ReadConfig (first-boot path) - systemd unit: CAP_NET_BIND_SERVICE + LimitNOFILE for optional ACME fix: panel must start even if Mihomo/SSL fails on boot - Soft-fail ApplyConfig / config generation / SSL bind so the management UI remains reachable after deploy - Preserve os.IsNotExist in ConfigManager.ReadConfig (first-boot path) - systemd unit: CAP_NET_BIND_SERVICE + LimitNOFILE for optional ACME |
||
|
|
4d6241740d |
feat: complete panel ACME SSL, sub HTML templates, Telegram alerts wiring
Wire acme/subpage into app and router, native v2ray/base64 subscription, Delete depleted UI, Settings panels for SSL and subscription theme, Telegram traffic/expiry thresholds. Docker + static multi-arch scripts. feat: complete panel ACME SSL, sub HTML templates, Telegram alerts wiring Wire acme/subpage into app and router, native v2ray/base64 subscription, Delete depleted UI, Settings panels for SSL and subscription theme, Telegram traffic/expiry thresholds. Docker + static multi-arch scripts. feat: complete panel ACME SSL, sub HTML templates, Telegram alerts wiring Wire acme/subpage into app and router, native v2ray/base64 subscription, Delete depleted UI, Settings panels for SSL and subscription theme, Telegram traffic/expiry thresholds. Docker + static multi-arch scripts. feat: complete panel ACME SSL, sub HTML templates, Telegram alerts wiring Wire acme/subpage into app and router, native v2ray/base64 subscription, Delete depleted UI, Settings panels for SSL and subscription theme, Telegram traffic/expiry thresholds. Docker + static multi-arch scripts. feat: complete panel ACME SSL, sub HTML templates, Telegram alerts wiring Wire acme/subpage into app and router, native v2ray/base64 subscription, Delete depleted UI, Settings panels for SSL and subscription theme, Telegram traffic/expiry thresholds. Docker + static multi-arch scripts. feat: complete panel ACME SSL, sub HTML templates, Telegram alerts wiring Wire acme/subpage into app and router, native v2ray/base64 subscription, Delete depleted UI, Settings panels for SSL and subscription theme, Telegram traffic/expiry thresholds. Docker + static multi-arch scripts. feat: complete panel ACME SSL, sub HTML templates, Telegram alerts wiring Wire acme/subpage into app and router, native v2ray/base64 subscription, Delete depleted UI, Settings panels for SSL and subscription theme, Telegram traffic/expiry thresholds. Docker + static multi-arch scripts. feat: complete panel ACME SSL, sub HTML templates, Telegram alerts wiring Wire acme/subpage into app and router, native v2ray/base64 subscription, Delete depleted UI, Settings panels for SSL and subscription theme, Telegram traffic/expiry thresholds. Docker + static multi-arch scripts. feat: complete panel ACME SSL, sub HTML templates, Telegram alerts wiring Wire acme/subpage into app and router, native v2ray/base64 subscription, Delete depleted UI, Settings panels for SSL and subscription theme, Telegram traffic/expiry thresholds. Docker + static multi-arch scripts. feat: complete panel ACME SSL, sub HTML templates, Telegram alerts wiring Wire acme/subpage into app and router, native v2ray/base64 subscription, Delete depleted UI, Settings panels for SSL and subscription theme, Telegram traffic/expiry thresholds. Docker + static multi-arch scripts. feat: complete panel ACME SSL, sub HTML templates, Telegram alerts wiring Wire acme/subpage into app and router, native v2ray/base64 subscription, Delete depleted UI, Settings panels for SSL and subscription theme, Telegram traffic/expiry thresholds. Docker + static multi-arch scripts. feat: complete panel ACME SSL, sub HTML templates, Telegram alerts wiring Wire acme/subpage into app and router, native v2ray/base64 subscription, Delete depleted UI, Settings panels for SSL and subscription theme, Telegram traffic/expiry thresholds. Docker + static multi-arch scripts. |
||
|
|
2d647ef468 | feat(scripts): full Linux arch/distro support; README static multi-arch docs | ||
|
|
d9dacf0f6f | fix: preserve default initial admin password in installer | ||
|
|
5442b1c3a2 | fix: update installer bootstrap credential message | ||
|
|
6613dd925a | fix installer repository owner | ||
|
|
5b4cb63a73 |
fix: align listener generation with mihomo official spec
- Port now supports mihomo ports format (single/range/list) - Add explicit RoutingMark field support - Auto-propagate UDP flag for vmess/vless/trojan/anytls/trusttunnel - Update validator to accept port ranges - Sync visual config and client converter port types - Rename module from dzx941 to kazeyukiro - Fix missing ExpiresAt in JWTClaims - Fix nodeDTO Port type to string - Fix frontend tsconfig and add missing dependencies |