name: Install & Update E2E (reusable) # Runs ONE update route against ONE starting commit, in the dev sandbox, with a # real install (uv, a managed Python, Node, the venv) behind it. # # Reusable so callers can fan out over the combinations that matter -- update # from the tip vs. from an older release, `hermes update` vs. re-running the # installer -- without duplicating the runner setup. Each leg is independent: # its own sandbox, its own install, nothing rewound or shared. # # Call it: # # jobs: # tip: # uses: ./.github/workflows/install-e2e-run.yml # with: # route: update # install-ref: refs/heads/main on: workflow_call: inputs: route: description: 'Update path to exercise: update (hermes update) or installer (re-run install.sh).' required: true type: string install-ref: description: 'What to install before updating: a branch, a tag (v2026.7.7), or a SHA reachable from main.' required: false type: string default: refs/heads/main runner: description: 'Runner label.' required: false type: string default: ubuntu-latest timeout-minutes: description: 'Job timeout. A cold run installs real toolchains twice.' required: false type: number default: 45 permissions: contents: read jobs: e2e: name: ${{ inputs.route }} from ${{ inputs.install-ref }} runs-on: ${{ inputs.runner }} timeout-minutes: ${{ inputs.timeout-minutes }} steps: # Full history: the sandbox fetches the starting commit and the test # compares against this commit, so a shallow clone is not enough. - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: fetch-depth: 0 # bubblewrap + slirp4netns are what the sandbox is built on; util-linux # supplies the `unshare` that builds the multi-uid userns for the # user-level (non-root) install. - name: Install sandbox dependencies run: | set -euo pipefail sudo apt-get update -qq sudo apt-get install -y -qq bubblewrap slirp4netns uidmap util-linux # Ubuntu 24.04 restricts unprivileged user namespaces through AppArmor, # which is exactly what bwrap needs. Report the state before touching it # so a future runner-image change is visible in the log rather than # silently altering what this job proves. - name: Permit unprivileged user namespaces run: | set -euo pipefail echo "--- kernel userns settings (before)" sysctl kernel.unprivileged_userns_clone 2>/dev/null || echo " (sysctl absent)" sysctl kernel.apparmor_restrict_unprivileged_userns 2>/dev/null || echo " (sysctl absent)" if sysctl -n kernel.apparmor_restrict_unprivileged_userns >/dev/null 2>&1; then sudo sysctl -w kernel.apparmor_restrict_unprivileged_userns=0 fi echo "--- subuid/subgid for $(id -un)" grep "^$(id -un):" /etc/subuid /etc/subgid || echo " (none — sandbox will say so)" - name: Run install + update E2E run: | set -euo pipefail tests/install/install-update-e2e.sh \ --route '${{ inputs.route }}' \ --install-ref '${{ inputs.install-ref }}' env: # Outside the workspace on purpose: the script creates this directory # up front, and an untracked dir inside the repo makes the worktree # dirty -- which dev-sandbox reacts to by snapshotting the working # copy into a fresh fake-main commit on every invocation, moving the # update target mid-run. HERMES_E2E_LOG_DIR: ${{ runner.temp }}/e2e-logs # Artifact names cannot contain '/', and install-ref may be a full ref # like refs/heads/main. GitHub Actions expressions have no string-replace # function, so build the safe name here. Runs even on failure -- that is # exactly when the logs are wanted. - name: Build artifact name if: always() id: artifact run: | set -euo pipefail safe_ref='${{ inputs.install-ref }}' safe_ref="${safe_ref//\//-}" echo "name=install-e2e-${{ inputs.route }}-${safe_ref}" >> "$GITHUB_OUTPUT" # The installer's own transcripts say far more than the assertion that # tripped when a real install breaks. - name: Upload installer logs if: always() uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: # Unique per leg: a matrix over releases runs this workflow several # times per route, and same-named artifacts collide. name: ${{ steps.artifact.outputs.name }}-${{ github.sha }} path: ${{ runner.temp }}/e2e-logs retention-days: 14 if-no-files-found: ignore