Greentic · cloud-update-demo

Change a running environment from a web page

Your environment runs on your machine. This page holds a signing key it generated itself, signs an update plan with it, and uploads the bytes to a plan server. Your runtime notices, checks the signature against a key it already trusts, and switches version — on its own, with no restart.

Press a button here. Watch the packs change there.

Why this is safe

A plan is only accepted if it carries a signature from a key in your environment's trust root — a list of public keys on your disk. So step one is: this page shows you its public key, and you add it. Its private key never leaves your browser, and the plan server never sees it. The server stores bytes and hands them out; it cannot mint, alter, or forge a plan.

  ┌───────────────────────┐  sign in the browser   ┌──────────────────┐
  │  this page            │ ─────────────────────▶ │  plan server     │
  │  holds a private key  │      upload bytes      │  stores bytes.   │
  │  you never send       │                        │  holds no keys.  │
  └───────────────────────┘                        └──────────────────┘
              │                                             ▲
              │ you add its PUBLIC key                      │  poll every 60s
              │ to the env's trust root                     │  (anonymous)
              ▼                                             │
  ┌──────────────────────────────────────────────────────────────────┐
  │  greentic-start on YOUR machine                                  │
  │    verify signature vs trust root → snapshot → apply → rollback  │
  └──────────────────────────────────────────────────────────────────┘
                 no packs  →  v1 (1 pack)  →  v2 (2 packs)

1. Prepare your machine

One binary to install; bash, curl and python3 you already have. Works on Linux and macOS.

terminal — install & fetch the two bundles
$ cargo binstall greentic-deployer@1.1.10 greentic-start@1.1.9

$ export DEMO=~/greentic-demo
$ mkdir -p $DEMO/bundles $DEMO/home && cd $DEMO

$ REL=https://github.com/greenticai/greentic-cloud-update-demo/releases/download/content-v1
$ curl -fsSL -o bundles/v1.gtbundle $REL/v1.gtbundle
$ curl -fsSL -o bundles/v2.gtbundle $REL/v2.gtbundle

# the page needs this absolute path — copy what it prints
$ echo $DEMO/bundles

Use a throwaway terminal.

The next step sets HOME to $DEMO/home so nothing touches your real ~/.greentic. That also means every other command in that terminal sees the fake home. Close it when you're done.

2. The console

This runs entirely in your browser. The key is generated here and kept in this browser's local storage — nothing is uploaded but signed plans.

Page signing key generating…
Server namespace none yet
Claim a namespace to begin.

3. Start a clean environment, pointed at the server

Once you've claimed a namespace above, this block is filled in with your endpoint and your page key. It creates an environment with no packs at all, subscribes it to the server, and tells it to trust this page.

terminal — generated for you
# Claim a namespace in the console above and this fills itself in.

4. Check the environment — it is empty

terminal 2 — check config
$ greentic-deployer op env show local | python3 -c '
import json, sys
e = json.load(sys.stdin)["result"]["environment"]
live = {x["revision_id"] for s in e["traffic_splits"] for x in s["entries"] if x["weight_bps"] > 0}
rows = [r for r in e["revisions"] if r["revision_id"] in live]
print("packs:", ", ".join(p["pack_id"] for r in rows for p in r["pack_list"]) or "(none)")'

packs: (none)                                ← nothing deployed yet

Remember to re-export DEMO and HOME in this second terminal, or it will look at your real home.

5. Press “Publish v1”, then check again

Go back to the console and press Publish v1. Within 60 seconds the runtime picks it up. Run the same check:

terminal 2
packs: app-webchat-bot                          ← 1 pack. It came from the page.

6. Press “Publish v2”, and check once more

terminal 2
packs: app-webchat-bot, messaging-telegram      ← 2 packs

Now press Publish v1 again. It goes back to one pack. Flip between them as often as you like.

Going back to v1 is not a downgrade.

Anti-rollback protects the plan sequence, which only ever grows — 1, 2, 3, 4. The content a plan points at is free to move in either direction. Replaying an old signed plan stays impossible.

What this proves

ClaimWhat enforces it
The page can't be impersonated Plans are Ed25519-signed in the browser. The runtime accepts only signatures from a key in its own trust-root.json — the one you added by hand.
The server can't forge an update It stores bytes and holds no key. A plan it invented would fail verification on your machine.
The network can't either Plan reads are anonymous and unauthenticated on purpose. The signature is the trust anchor — not TLS, not the origin.
You can't be replayed an old version Each plan carries a monotonic sequence, read from the signed plan rather than from anything the server says.
Nothing is pushed at your runtime It polls. An environment with no updates block fetches nothing, ever.
A plan can't hijack the channel The updates block is stripped from a plan target before signing — here in the page, and in the CLI.

If something goes wrong

The runtime logs “no trusted signature”

The page's key is not in your trust root. That happens if you cleared browser storage (the page then generates a new key) or ran op env init after adding it. Re-run the trust-root step in section 3 with the key_id currently shown in the console.

Nothing happens after pressing a button

Give it a full minute — 60s is the poll floor. Then check the console log above: a successful publish prints the sequence number the server accepted. If the button reports an error, it is the server rejecting the upload, not your runtime.

“bundle not found” in the runtime log

The bundles directory you typed into the console is baked into the signed plan as an absolute path. It must be the real path on the machine running greentic-start. Fix the field and publish again.

Your browser has no Ed25519

The console needs WebCrypto Ed25519 (Chrome 137+, Firefox 130+, Safari 17+). On an older browser the buttons stay disabled and the key line says so.