max / makenotwork
| 1 | #!/usr/bin/env bash |
| 2 | # Install a staged service binary and restart its unit. Runs as ROOT, invoked by |
| 3 | # Bento's deploy step over the host's executor as: |
| 4 | # |
| 5 | # sudo /usr/local/lib/bento/install-service.sh <src> <dst> <service> |
| 6 | # |
| 7 | # where <src> is the binary Bento staged under /var/tmp/bento-deploy/<app>/, |
| 8 | # <dst> is the unit's ExecStart path (/usr/local/bin/pom), and <service> is the |
| 9 | # systemd unit to restart (pom.service). |
| 10 | # |
| 11 | # This wrapper exists so the deploy user's sudo grant is ONE auditable script |
| 12 | # rather than a broad install/systemctl grant on a box running production. Same |
| 13 | # shape, and the same reasoning, as sando/deploy/install-companion.sh. |
| 14 | # |
| 15 | # Install (one-time per host, as root): |
| 16 | # sudo install -d /usr/local/lib/bento |
| 17 | # sudo install -m 0755 install-service.sh /usr/local/lib/bento/install-service.sh |
| 18 | # # then add the scoped sudoers line -- see bento-deploy.sudoers |
| 19 | # |
| 20 | # What this deliberately does NOT touch: |
| 21 | # |
| 22 | # Config. pom-astra.toml and pom-hetzner.toml differ per instance, and the |
| 23 | # live config on prod once carried a [targets.mnw.tests] block the repo did |
| 24 | # not have. The old deploy.sh copied config over the top with no diff and no |
| 25 | # backup, which is how that block would have been silently deleted. A deploy |
| 26 | # ships the binary; config is a separate, deliberate act. |
| 27 | # |
| 28 | # The unit file. Same reasoning: a hardened unit that drifted from the repo is |
| 29 | # a question for a human, not something a binary deploy overwrites. |
| 30 | # |
| 31 | # The install is atomic (install(1) writes a temp then renames), so a running |
| 32 | # service never execs a half-written file. The previous binary is kept next to |
| 33 | # the new one as <dst>.prev, which is the whole rollback: put it back and |
| 34 | # restart. The unit is restarted only after a successful install, so a failed |
| 35 | # install leaves the service on the binary it already had. |
| 36 | |
| 37 | |
| 38 | if ; then |
| 39 | |
| 40 | |
| 41 | fi |
| 42 | |
| 43 | STAGING_ROOT=/var/tmp/bento-deploy |
| 44 | |
| 45 | SRC="" |
| 46 | DST="" |
| 47 | SERVICE="" |
| 48 | |
| 49 | # Guard rails. These bound what a caller -- already behind the single sudoers |
| 50 | # grant -- can install and restart. Being the ONLY control on a NOPASSWD grant, |
| 51 | # they have to actually hold, so normalise BEFORE testing any prefix: a |
| 52 | # glob-only test against the raw argument is something `..` walks straight out |
| 53 | # of. `/var/tmp/bento-deploy/../../../etc/shadow` matches a naive src pattern, |
| 54 | # and `/usr/local/bin/../../../etc/systemd/system/x` a naive dst one -- i.e. |
| 55 | # `install -m 0755` as root to anywhere on the filesystem. `realpath -m` |
| 56 | # resolves `..` and symlinks without requiring the path to exist (the dst does |
| 57 | # not on a first install). The roots are resolved too, so the comparison still |
| 58 | # holds if either is a symlink. |
| 59 | SRC="" |
| 60 | DST="" |
| 61 | STAGING_ROOT="" |
| 62 | BIN_ROOT="" |
| 63 | |
| 64 | case "" in |
| 65 | ""/*) ;; |
| 66 | *) ; ;; |
| 67 | esac |
| 68 | case "" in |
| 69 | ""/*) ;; |
| 70 | *) ; ;; |
| 71 | esac |
| 72 | case "" in |
| 73 | *[/[:space:]]*|"") ; ;; |
| 74 | *.service) ;; |
| 75 | *) ; ;; |
| 76 | esac |
| 77 | |
| 78 | if ; then |
| 79 | |
| 80 | |
| 81 | fi |
| 82 | |
| 83 | # Refuse a binary that cannot run here. Bento checks this too, before it stages |
| 84 | # anything, but that check reads the build host's objdump output; this one is |
| 85 | # the target actually trying to load it. A unit restarted onto a binary it |
| 86 | # cannot exec is down until someone notices. |
| 87 | if ! ; then |
| 88 | |
| 89 | || |
| 90 | |
| 91 | fi |
| 92 | |
| 93 | if ; then |
| 94 | |
| 95 | |
| 96 | fi |
| 97 | |
| 98 | # Installs the normalised paths, not the raw arguments, so there is no gap |
| 99 | # between what was checked and what is written. |
| 100 | |
| 101 | |
| 102 | |
| 103 | |
| 104 | |
| 105 | |
| 106 |