Verify a Self-Hosted Installer Before Running It as Root
Separate Decisions Before Execution
Downloading an installer and immediately executing it as root collapses three operational decisions into one command:
- Which artifact?
- Did these bytes arrive intact?
- Should this host execute them?
Separate those decisions and the install becomes reviewable, reproducible, and recoverable.
A Concrete Source-Review Boundary
At commit c58bcd4, the MonkeyCode runner installation template selects x86_64 or aarch64, checks AVX on x86, requires root, and downloads an architecture-specific installer before executing it. The reviewed template uses curl -4sSLk, so certificate verification is disabled by -k. It also downloads an unversioned path. I could not find a pinned version, digest, or signature check in that template.
That is a statement about controls visible in one pinned file-not a claim that the release service is compromised or that no external release control exists.
Put a Manifest Before Execution
For each release artifact, publish immutable metadata through a separately protected release process:
{
"version": "1.2.3",
"architecture": "x86_64",
"file": "runner-installer-1.2.3-x86_64",
"sha256": "<64 lowercase hex characters>",
"size": 18439210,
"rollback": {
"previous_version": "1.2.2",
"artifact": "runner-installer-1.2.2-x86_64"
}
}
SHA-256 detects bytes that differ from the manifest. It does not prove who authored the manifest. Serve the manifest over validated TLS, pin it through deployment configuration, or sign it and verify the signature with a trusted offline public key.
Verify as an Unprivileged Staging Step
The companion verify-installer.mjs checks filename, exact size, digest, version, architecture, and rollback metadata:
node verify-installer.mjs release-manifest.json fixture-installer.sh
node test-verifier.mjs
Expected output uses the fixture's actual digest:
PASS 1.2.3-fixture sha256=<digest>
PASS verified fixture; rejected tampered artifact before execution
The negative test appends a line to the artifact and requires both size and digest checks to fail. The verifier never executes the file.
A production flow should look like this:
set -euo pipefail
umask 077
curl --fail --show-error --location \
--proto '=https' --tlsv1.2 \
-o runner-installer "$ARTIFACT_URL"
node verify-installer.mjs release-manifest.json runner-installer
# Only after verification and an explicit maintenance decision:
sudo ./runner-installer --version "$EXPECTED_VERSION"
Do not add -k to make certificate errors disappear. Fix the trust store, hostname, time, or certificate deployment that caused the error.
Make Rollback an Executable Plan
"We can reinstall the old version" is not a rollback procedure. Record:
- the exact prior artifact and its verified manifest
- configuration and data-format compatibility
- service stop/start commands
- health checks and maximum recovery time
- which migrations are reversible
- cleanup for partial installation
Before promotion, install into a canary with the same architecture and kernel class, record service version and health output, inject a failed download and digest mismatch, then rehearse rollback. Keep the previous verified artifact available for the declared recovery window.
Acceptance Gate
I would allow privileged execution only when:
- TLS verification succeeds without bypass
- the URL names an immutable version and architecture
- a trusted manifest matches file, size, and digest
- signature verification succeeds when signatures are part of the release model
- the canary health check passes
- rollback bytes and procedure are already verified
That gate does not make every installer safe. It turns an opaque network-to-root transition into evidence an operator can inspect and automate.
Disclosure: I contribute to the MonkeyCode project. The installation observations are limited to the linked template at commit c58bcd4; the standalone verifier and tamper test were run locally. No vulnerability claim is made.
Comments
No comments yet. Start the discussion.