Skip to content
Open
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
39 changes: 31 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,17 @@ It bundles an embedded CPython (nothing to install first) and runs the
same `install.py` the script path uses — zero install logic of its own
(`installer/windows/`). macOS/Linux stay on the one-liner above.

> **Before you install, two things to know:**
> - **Auto-update:** on session start (once/day) VibeMon checks for a new
> release and installs it. Updates are **Ed25519-signed and verified against a
> key baked into the client before running** — a tampered release fails
> verification and is not executed ([SECURITY.md](SECURITY.md)). Pin a tag (the
> second command above) if you'd rather update by hand.
> - **Telemetry:** hooks send an anonymized activity envelope (event type,
> file paths/extensions, line counts, git `owner/repo`, local hour/timezone).
> **Code, prompts, diffs, and command bodies are stripped** and this is
> enforced in CI. Full details + opt-outs: [PRIVACY.md](PRIVACY.md).

---

## What this code does
Expand Down Expand Up @@ -150,22 +161,34 @@ git diff contract/golden/ # REVIEW carefully

## Releasing

**One-time setup (enables signed auto-update):** run `python3 scripts/keygen.py`,
store the printed seed as the GitHub Actions secret `VIBEMON_SIGNING_SEED`, and
commit the updated `src/release_pubkey.py`. Until this is done the shipped client
is fail-closed: it will not auto-update (no unsigned exec), and releases fail at
the signing step.

1. Edit `VERSION` (e.g. `10` → `11`).
2. Run `python3 scripts/build.py`. Commit `dist/install.sh` + `VERSION`.
2. Run `python3 scripts/build.py`. Commit `dist/` + `VERSION`.
3. Tag: `git tag v11 && git push --tags`.
4. CI builds, tests, attaches `install.sh` + `sha256sum.txt` to a
GitHub Release.
5. `vibemon.dev/install.sh` automatically redirects to the latest tag.
4. CI builds, tests, **signs** (`scripts/sign.py` → `install.sh.sig` /
`install.ps1.sig`), and attaches the installers + `.sig` + `sha256sum.txt`
to a GitHub Release.
5. `vibemon.dev/install.sh` (and `…/install.sh.sig`) redirect to the latest tag.

The `auto-update` mechanism inside `notify.sh` / `notify.py` polls the new release
once a day on `session_start`, **downloads the installer + its signature, verifies
it against the baked-in public key, and only then** re-runs `install.sh` when
VERSION bumps. A tampered or unsigned artifact is never executed.

The `auto-update` mechanism inside `notify.sh` polls the new release
once a day on `session_start` and re-runs `install.sh` when VERSION
bumps.
> **Serving note:** `vibemon.dev` must serve/redirect `install.sh.sig` and
> `install.ps1.sig` alongside the installers (same 302-to-Release pattern). If the
> `.sig` is missing the client fails closed and skips the update.

---

## Reporting a vulnerability

See [SECURITY.md](SECURITY.md). TL;DR — email security@streamize.net,
See [SECURITY.md](SECURITY.md). TL;DR — email admin@streamize.net,
do not file a public issue. We respond within 72 hours.

---
Expand Down
33 changes: 29 additions & 4 deletions SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,33 @@ is supported. Older `dist/install.sh` artifacts are kept on GitHub
Releases for audit purposes only — the auto-update mechanism in
`notify.sh` will roll users forward within 24 hours of a new release.

## How the auto-updater is secured (signed releases)

`notify.sh` / `notify.py` check for a new version once/day on session start. The
updater **never pipes a remote script to a shell.** It downloads the installer
**and a detached Ed25519 signature** (`install.sh.sig` / `install.ps1.sig`), then
verifies the bytes against a **public key baked into the client**
(`src/release_pubkey.py`) with a pure-stdlib verifier (`src/ed25519.py`) before
executing anything. Invalid signature, missing signature, or an unconfigured key
⇒ **nothing runs** (fail-closed).

The signing **secret seed** exists only as the GitHub Actions secret
`VIBEMON_SIGNING_SEED` and is never in the repo. A compromised `vibemon.dev` or
GitHub Release can swap the artifact bytes but **cannot forge a signature**, so a
tampered installer fails verification and is not executed. This closes the prior
unsigned-update channel (CWE-494). Correctness + fail-closed behavior are enforced
in CI by `tests/test_signature.py` (RFC 8032 known-answer vector, tamper
rejection, and a PyNaCl cross-check).

Key rotation: run `python3 scripts/keygen.py`, store the printed seed as the
`VIBEMON_SIGNING_SEED` secret, commit the updated `src/release_pubkey.py` + `dist/`,
and cut a release.

## Reporting a vulnerability

**Do not file a public issue or pull request.**

Email **security@streamize.net** with:
Email **admin@streamize.net** with:

- A description of the issue
- Steps to reproduce
Expand Down Expand Up @@ -45,11 +67,14 @@ We design and test against:
install URL is a 302 redirect to a GitHub Release artifact, which is
immutable and matches the build for that tag.

- **Distribution tampering / compromised release** — a malicious installer
served from `vibemon.dev` or a GitHub Release (including via a compromised
account or domain). Mitigation: **Ed25519-signed releases** verified by the
client before execution (see "How the auto-updater is secured" above). Without
the offline signing seed, a swapped artifact fails verification and never runs.

We do **not** currently defend against:

- A compromised GitHub account pushing a malicious release. Releases
are not yet signed (`cosign` integration is a planned follow-up).
Pin to a known-good tag if you need stronger guarantees.
- A malicious AI agent manipulating the JSON it sends to `notify.sh` in
a way that triggers unintended POSTs to the VibeMon backend. The
envelope is sent regardless of payload — no data exfiltration vector
Expand Down
Loading
Loading