Commit graph

5 commits

Author SHA1 Message Date
3c29af55a2
Add curl|bash installer + wire upload into publish script
scripts/install.sh is the one-command installer end users run as

  curl -fsSL https://releases.thaloco.com/banger/install.sh | bash

Design choices:

* Runs as the invoking user. All network work + signature verification
  happens unprivileged; sudo is only re-execed for the actual install
  step that writes to /usr/local and creates systemd units.
* Right before the sudo prompt, the script prints a plain-language
  summary of exactly what's about to happen — the file paths it will
  create and a one-line "why sudo" — so the user authorises a known
  scope rather than the whole pipeline. Detail link in the docs.
* Uses openssl (universally available) for signature verification, not
  cosign. cosign is needed only by the *signer*, never the verifier.
* No jq dependency. The latest_stable field is extracted from the
  manifest with grep+sed, since the manifest shape is well-defined and
  we control it.
* /dev/tty fallback for the confirmation prompt so it works through
  the curl|bash pipe.
* --yes for non-interactive CI use, --user for installing into
  ~/.local/bin without touching system paths, --version vX.Y.Z to pin.

publish-banger-release.sh now uploads install.sh to the bucket root
on every publish, so the curl URL is stable but the script logic
matches the latest verified release. It also runs a key-drift check:
if scripts/install.sh's embedded cosign public key differs from the
one in internal/updater/verify_signature.go, publishing aborts. The
two copies must stay in sync or one of them ends up rejecting every
release.

README's Quick start now leads with the installer one-liner and
documents the audit-first variant alongside it; building from source
moves below.

Smoke-tested end to end against the live bucket with --user mode:
manifest fetch → tarball download → cosign signature verify → hash
verify → extract → install. The installed binary reports v0.1.0 at
commit 6fdebd9, matching the published artifact.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-29 14:06:34 -03:00
6fdebd929e
publish-script: split RCLONE_BUCKET out of BUCKET_PATH
The previous form passed rclone paths like releases:banger/v0.1.0/,
which rclone parses as bucket=banger, key=v0.1.0/... — wrong, because
the actual R2 bucket is named "releases" (BUCKET_PATH was meant as
an in-bucket key prefix only). Uploads 403'd because the token has
no view of a bucket called "banger".

Introduce RCLONE_BUCKET as a separate env var (default: "releases")
and route every rclone copy through ${RCLONE_REMOTE}:${RCLONE_BUCKET}/${BUCKET_PATH}.
The public URLs in the manifest stay unchanged: BASE_URL is the
bucket's public custom domain, so the bucket name is implicit there.

The defaults now resolve to the live setup:
  rclone target:  releases:releases/banger/<version>/<file>
  public URL:     https://releases.thaloco.com/banger/<version>/<file>

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-29 13:35:53 -03:00
12f7a92bb4
publish-script: don't clobber COSIGN_PASSWORD with empty default
The previous form did

  COSIGN_PASSWORD="${COSIGN_PASSWORD:-}" cosign sign-blob ...

which set COSIGN_PASSWORD to "" when the caller hadn't exported one.
cosign sees an explicit empty password and tries to decrypt with
it instead of prompting interactively, so any real password-protected
offline key fails with "decryption failed".

Drop the prefix entirely. If COSIGN_PASSWORD is already in env, it
gets inherited normally; if it isn't, cosign prompts on the terminal
— which is the right UX for a maintainer running the publish script
locally with the offline private key.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-29 13:27:23 -03:00
3d748b87c8
publish-script: fix pubkey extraction and cosign v3 compatibility
Two bugs found while dry-running the publish flow end-to-end:

1. The awk pipeline that pulled BangerReleasePublicKey out of
   verify_signature.go didn't strip Go's raw-string-literal wrapping
   (`var ... = ` + backtick on the BEGIN line, trailing backtick on
   the END line). The "verify against embedded pub key" step thus
   compared sigs against a malformed PEM. Replaced with a sed pair
   that yields a clean PEM block byte-identical to cosign.pub.

2. cosign v3.x defaults sign-blob to a new bundle format and
   pushes signatures to Rekor; both are incompatible with banger's
   "embedded pub key, raw ASN.1 DER signature" trust model.
   Add --use-signing-config=false / --tlog-upload=false /
   --new-bundle-format=false to opt out, and --insecure-ignore-tlog
   on verify-blob. These flags also work on cosign v2.x, so the
   script is forward- and backward-compatible across the v2→v3
   boundary.

Validated by an end-to-end dry-run on this machine: built binaries,
tarred, sha256summed, cosign-signed, verified against the embedded
pub key, then re-verified through internal/updater's
crypto/ecdsa.VerifyASN1 path — all green.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-29 13:23:09 -03:00
fae28e3d8b
update: docs + publish script for the self-update feature
README gets a top-level Updating section; docs/privileges.md gains
a step-by-step trust-model writeup of `banger update`. The new
scripts/publish-banger-release.sh drives the manual release cut:
build, tar, sha256sum, cosign sign-blob, verify against the embedded
public key, jq-merge into manifest.json, rclone upload to the R2
bucket. Refuses outright if the embedded key is still the placeholder
so we can't accidentally publish an unverifiable release. Also folds
in gofmt drift accumulated across the updater package and a few
sibling files.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-29 12:43:46 -03:00