max / makenotwork
| 1 | #!/usr/bin/env bash |
| 2 | # Install a staged companion binary and restart its unit. Runs as ROOT, invoked |
| 3 | # by Sando's deploy step over the node's executor as: |
| 4 | # |
| 5 | # sudo /usr/local/lib/mnw/install-companion.sh <src> <dst> <service> |
| 6 | # |
| 7 | # where <src> is the companion binary inside the just-rsynced release bundle |
| 8 | # (e.g. /opt/mnw/releases/<ver>/companions/mnw-cli), <dst> is the unit's |
| 9 | # ExecStart path (e.g. /opt/mnw-cli/mnw-cli), and <service> is the systemd unit |
| 10 | # to restart (e.g. mnw-cli.service). This wrapper exists so the deploy user's |
| 11 | # sudo grant is ONE auditable script rather than a broad install/systemctl grant. |
| 12 | # |
| 13 | # Install (one-time per node, as root): |
| 14 | # sudo install -d /usr/local/lib/mnw |
| 15 | # sudo install -m 0755 install-companion.sh /usr/local/lib/mnw/install-companion.sh |
| 16 | # # then add the scoped sudoers line — see mnw-companion.sudoers |
| 17 | # |
| 18 | # The install is atomic (install(1) writes a temp then renames), so a running |
| 19 | # companion never execs a half-written file. The service is restarted only after |
| 20 | # a successful install; a failed install leaves the unit on its current binary. |
| 21 | |
| 22 | |
| 23 | if ; then |
| 24 | |
| 25 | |
| 26 | fi |
| 27 | |
| 28 | SRC="" |
| 29 | DST="" |
| 30 | SERVICE="" |
| 31 | |
| 32 | # Guard rails: refuse a src outside a release bundle or a dst outside /opt, and a |
| 33 | # service name that isn't a bare unit. These bound what a caller (already behind |
| 34 | # the single sudoers grant) can install/restart — defense in depth, not the |
| 35 | # primary control. Being the ONLY control on a NOPASSWD grant, though, they have |
| 36 | # to actually hold. |
| 37 | # |
| 38 | # Normalise BEFORE testing the prefix. These were once glob-only tests against |
| 39 | # the raw arguments, which `..` walks straight out of: `/opt/../etc/systemd/ |
| 40 | # system/x.service` matches `/opt/*`, and `.../releases/v/companions/../../../ |
| 41 | # ../etc/shadow` matches the src pattern — i.e. `install -m 0755` as root to |
| 42 | # anywhere on the filesystem. `realpath -m` resolves `..` and symlinks without |
| 43 | # requiring the path to exist (the dst usually does not on a first install). |
| 44 | # |
| 45 | # /opt itself is resolved too, so the comparison still holds if it is a symlink. |
| 46 | SRC="" |
| 47 | DST="" |
| 48 | OPT_ROOT="" |
| 49 | |
| 50 | case "" in |
| 51 | */releases/*/companions/*) ;; |
| 52 | *) ; ;; |
| 53 | esac |
| 54 | case "" in |
| 55 | ""/*) ;; |
| 56 | *) ; ;; |
| 57 | esac |
| 58 | case "" in |
| 59 | *[/[:space:]]*|"") ; ;; |
| 60 | *.service) ;; |
| 61 | *) ; ;; |
| 62 | esac |
| 63 | |
| 64 | if ; then |
| 65 | |
| 66 | |
| 67 | fi |
| 68 | |
| 69 | # Installs the normalised paths, not the raw arguments, so there is no gap |
| 70 | # between what was checked and what is written. |
| 71 | |
| 72 | |
| 73 | |
| 74 | |
| 75 | |
| 76 | |
| 77 |