Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 16 additions & 4 deletions site/public/install-linux-units.sh
Original file line number Diff line number Diff line change
Expand Up @@ -33,14 +33,26 @@ fi
|| { echo "The verified 1Helm release is missing its host lifecycle scripts." >&2; exit 1; }
id "$SERVICE_USER" >/dev/null 2>&1 || { echo "The 1Helm service account does not exist." >&2; exit 1; }

# `install /dev/stdin DEST <<EOF` reopens fd 0 via /proc, which fails with
# "No such file or directory" when this script runs under systemd-run (the path
# a host UPDATE takes, as opposed to a fresh install run from an operator
# shell). Capture the heredoc to a real temp file first, then install that.
install_stdin() {
local mode="$1" dest="$2" tmp
tmp="$(mktemp)"
cat >"$tmp"
install -o root -g root -m "$mode" "$tmp" "$dest"
rm -f "$tmp"
}
Comment on lines +40 to +46

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/sh
set -eu

file="$(fd -t f -a 'install-linux-units\.sh$' . | head -n 1)"
[ -n "$file" ]
printf '%s\n' "== file: $file =="
cat -n "$file" | sed -n '1,150p'

printf '%s\n' '== relevant shell constructs =='
rg -n -C 3 'install_stdin|mktemp|trap|set -|tmpfiles|systemctl|install ' "$file"

Repository: gitcommit90/1Helm

Length of output: 9880


🏁 Script executed:

#!/usr/bin/env bash
set -u

work="$(mktemp -d)"
trap 'rm -rf "$work"' EXIT
tmpdir="$work/tmp"
mkdir "$tmpdir"

run_case() {
  local name="$1" implementation="$2"
  local case_dir="$work/$name" output status
  mkdir "$case_dir"

  if [[ "$implementation" == current ]]; then
    function install_stdin() {
      local mode="$1" dest="$2" tmp
      tmp="$(TMPDIR="$tmpdir" mktemp)"
      cat >"$tmp"
      install -o root -g root -m "$mode" "$tmp" "$dest"
      rm -f "$tmp"
    }
  else
    function install_stdin() (
      local mode="$1" dest="$2" tmp
      tmp="$(TMPDIR="$tmpdir" mktemp)" || exit 1
      trap 'rm -f -- "$tmp"' EXIT
      cat >"$tmp" || exit 1
      install -o root -g root -m "$mode" "$tmp" "$dest"
    )
  fi

  set +e
  printf '%s\n' content | install_stdin 0644 "$case_dir/missing/output"
  status=$?
  set -e
  output="$(find "$tmpdir" -maxdepth 1 -type f -printf '%f\n' | sort | paste -sd, -)"
  printf '%s: status=%s remaining_temp_files=%s\n' "$name" "$status" "${output:-none}"
}

run_case current current
run_case proposed proposed

printf '%s\n' 'signal test: proposed implementation'
signal_dir="$work/signal"
mkdir "$signal_dir"
function install_stdin() (
  local mode="$1" dest="$2" tmp
  tmp="$(TMPDIR="$tmpdir" mktemp)" || exit 1
  trap 'rm -f -- "$tmp"' EXIT
  printf '%s\n' content >"$tmp"
  kill -TERM "$BASHPID"
  sleep 10
  install -o root -g root -m "$mode" "$tmp" "$dest"
)
set +e
install_stdin 0644 "$signal_dir/missing/output"
signal_status=$?
set -e
signal_files="$(find "$tmpdir" -maxdepth 1 -type f -printf '%f\n' | sort | paste -sd, -)"
printf 'signal: status=%s remaining_temp_files=%s\n' "$signal_status" "${signal_files:-none}"

Repository: gitcommit90/1Helm

Length of output: 241


🏁 Script executed:

#!/usr/bin/env bash
set -u

work="$(mktemp -d)"
trap 'rm -rf "$work"' EXIT

run_case() {
  local name="$1" implementation="$2" case_dir="$work/$1" status count
  mkdir "$case_dir"

  if [[ "$implementation" == current ]]; then
    bash -c '
      set -e
      install() { return 42; }
      install_stdin() {
        local mode="$1" dest="$2" tmp
        tmp="$(mktemp)"
        cat >"$tmp"
        install -o root -g root -m "$mode" "$tmp" "$dest"
        rm -f "$tmp"
      }
      printf "%s\n" content | install_stdin 0644 "$1/missing/output"
    ' bash "$case_dir" >/dev/null 2>&1
  else
    bash -c '
      set -e
      install() { return 42; }
      install_stdin() (
        local mode="$1" dest="$2" tmp
        tmp="$(mktemp)" || exit 1
        trap '\''rm -f -- "$tmp"'\'' EXIT
        cat >"$tmp" || exit 1
        install -o root -g root -m "$mode" "$tmp" "$dest"
      )
      printf "%s\n" content | install_stdin 0644 "$1/missing/output"
    ' bash "$case_dir" >/dev/null 2>&1
  fi
  status=$?

  count="$(python3 - "$case_dir" <<'PY'
import glob
import sys
print(len(glob.glob(sys.argv[1] + "/*")))
PY
)"
  printf '%s: status=%s remaining_files=%s\n' "$name" "$status" "$count"
}

run_case current current
run_case proposed proposed

printf '%s\n' 'signal test: proposed implementation'
signal_dir="$work/signal"
mkdir "$signal_dir"
set +e
bash -c '
  set -e
  install() { return 42; }
  install_stdin() (
    local mode="$1" dest="$2" tmp
    tmp="$(mktemp)" || exit 1
    trap '\''rm -f -- "$tmp"'\'' EXIT
    printf "%s\n" content >"$tmp"
    kill -TERM "$BASHPID"
    sleep 10
    install -o root -g root -m "$mode" "$tmp" "$dest"
  )
  install_stdin 0644 "$1/missing/output"
' bash "$signal_dir" >/dev/null 2>&1
signal_status=$?
set -e
signal_count="$(python3 - "$tmpdir" <<'PY'
import glob
import sys
print(len(glob.glob(sys.argv[1] + "/*")))
PY
)"
printf 'signal: status=%s remaining_temp_files=%s\n' "$signal_status" "$signal_count"

Repository: gitcommit90/1Helm

Length of output: 307


🏁 Script executed:

#!/usr/bin/env bash
set -u

work="$(mktemp -d)"
trap 'rm -rf "$work"' EXIT

run_case() {
  local name="$1" implementation="$2" case_dir="$work/$1" status count
  mkdir "$case_dir"

  if [[ "$implementation" == current ]]; then
    TMPDIR="$case_dir" bash -c '
      set -e
      install() { return 42; }
      install_stdin() {
        local mode="$1" dest="$2" tmp
        tmp="$(mktemp)"
        cat >"$tmp"
        install -o root -g root -m "$mode" "$tmp" "$dest"
        rm -f "$tmp"
      }
      printf "%s\n" content | install_stdin 0644 "$1/missing/output"
    ' bash "$case_dir" >/dev/null 2>&1
  else
    TMPDIR="$case_dir" bash -c '
      set -e
      install() { return 42; }
      install_stdin() (
        local mode="$1" dest="$2" tmp
        tmp="$(mktemp)" || exit 1
        trap '\''rm -f -- "$tmp"'\'' EXIT
        cat >"$tmp" || exit 1
        install -o root -g root -m "$mode" "$tmp" "$dest"
      )
      printf "%s\n" content | install_stdin 0644 "$1/missing/output"
    ' bash "$case_dir" >/dev/null 2>&1
  fi
  status=$?

  count="$(python3 - "$case_dir" <<'PY'
import glob
import sys
print(len(glob.glob(sys.argv[1] + "/*")))
PY
)"
  printf '%s: status=%s remaining_files=%s\n' "$name" "$status" "$count"
}

run_case current current
run_case proposed proposed

signal_dir="$work/signal"
mkdir "$signal_dir"
set +e
TMPDIR="$signal_dir" bash -c '
  set -e
  install() { return 42; }
  install_stdin() (
    local mode="$1" dest="$2" tmp
    tmp="$(mktemp)" || exit 1
    trap '\''rm -f -- "$tmp"'\'' EXIT
    printf "%s\n" content >"$tmp"
    kill -TERM "$BASHPID"
    sleep 10
    install -o root -g root -m "$mode" "$tmp" "$dest"
  )
  install_stdin 0644 "$1/missing/output"
' bash "$signal_dir" >/dev/null 2>&1
signal_status=$?
set -e
signal_count="$(python3 - "$signal_dir" <<'PY'
import glob
import sys
print(len(glob.glob(sys.argv[1] + "/*")))
PY
)"
printf 'signal: status=%s remaining_files=%s\n' "$signal_status" "$signal_count"

Repository: gitcommit90/1Helm

Length of output: 267


Clean up the temporary file when install_stdin fails.

With set -e, a failed cat or install exits before rm -f "$tmp". Run the helper in a subshell, set an EXIT trap after mktemp, and check cat with || exit 1.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@site/public/install-linux-units.sh` around lines 40 - 46, Update
install_stdin to execute its temporary-file workflow in a subshell, install an
EXIT trap immediately after mktemp to remove tmp, and guard cat with || exit 1
so cleanup runs when cat or install fails. Preserve the existing install
arguments and success behavior.


install -o root -g root -m 0755 "$RELEASE_ROOT/site/public/update-host.sh" "$INSTALL_ROOT/update-host.sh"
install -o root -g root -m 0755 "$RELEASE_ROOT/site/public/uninstall-host.sh" "$INSTALL_ROOT/uninstall-host.sh"

# ProtectSystem=strict resolves ReadWritePaths before it runs the service. Keep
# Podman's host-only scratch roots present both now and after every reboot so a
# completely fresh machine never fails mount-namespace setup before 1Helm can
# invoke its root-owned runtime helper.
install -m 0644 /dev/stdin /etc/tmpfiles.d/1helm-oci.conf <<'EOF'
install_stdin 0644 /etc/tmpfiles.d/1helm-oci.conf <<'EOF'
d /run/1helm-oci 0755 root root -
d /run/1helm-oci/tmp 1777 root root -
d /run/containers 0755 root root -
Expand All @@ -50,7 +62,7 @@ d /run/netns 0755 root root -
EOF
systemd-tmpfiles --create /etc/tmpfiles.d/1helm-oci.conf

install -m 0644 /dev/stdin /etc/systemd/system/1helm.service <<EOF
install_stdin 0644 /etc/systemd/system/1helm.service <<EOF
[Unit]
Description=1Helm durable agent workspace
After=network-online.target
Expand Down Expand Up @@ -93,7 +105,7 @@ Delegate=yes
WantedBy=multi-user.target
EOF

install -m 0644 /dev/stdin /etc/systemd/system/1helm-update.service <<EOF
install_stdin 0644 /etc/systemd/system/1helm-update.service <<EOF
[Unit]
Description=Install a verified 1Helm host update
After=network-online.target
Expand All @@ -112,7 +124,7 @@ ProtectSystem=strict
ReadWritePaths=$INSTALL_ROOT $STATE_ROOT /run/1helm-oci /usr/libexec /usr/lib/1helm-oci /etc/1helm /etc/default /etc/systemd/system /etc/sudoers.d /etc/subuid /etc/subgid
EOF

install -m 0644 /dev/stdin /etc/systemd/system/1helm-update.path <<EOF
install_stdin 0644 /etc/systemd/system/1helm-update.path <<EOF
[Unit]
Description=Watch for Captain-authorized 1Helm host updates

Expand Down
6 changes: 6 additions & 0 deletions test/site.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,12 @@ test("installer assets are explicit and syntax-valid", () => {
const updater = readFileSync(`${root}/site/public/update-host.sh`, "utf8");
const linuxUnits = readFileSync(`${root}/site/public/install-linux-units.sh`, "utf8");
const releaseApply = readFileSync(`${root}/site/public/apply-linux-release.sh`, "utf8");
// `install /dev/stdin DEST <<EOF` reopens fd 0 through /proc and fails with
// ENOENT when this script runs inside a systemd-run oneshot - the exact path a
// host UPDATE takes, while fresh installs run it from an operator shell where
// it works. That is why the first live update failed and every fresh install
// passed. Writing unit files must not depend on reopening stdin.
assert.doesNotMatch(linuxUnits, /^\s*install\b[^\n]*\/dev\/stdin/m, "unit files must not be installed by reopening /dev/stdin (breaks under systemd-run)");
assert.match(updater, /browser_download_url/);
assert.match(linuxUnits, /Environment=HELM_APP_ROOT=\$INSTALL_ROOT\/current/, "Linux explicitly exposes the active packaged root to runtime resource resolvers");
assert.match(updater, /\^sha256:\[a-f0-9\]\{64\}\$/, "the Linux updater requires GitHub's exact SHA-256 asset digest");
Expand Down
Loading