Spaces:
Running
Running
File size: 11,031 Bytes
cbb8671 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 | # Setting up GitHub Action secrets — least-privilege edition
The CHAINSTATE deploy workflow needs three secrets in your GitHub repository. This document gives you the *minimum-scope* version of each — a leaked secret here cannot touch anything outside this one project.
All three are added the same way:
> **GitHub repo** → **Settings** → **Secrets and variables** → **Actions** → **New repository secret**
Use the exact secret name from the table; the workflow looks them up by these names verbatim.
---
## Before you create anything · two one-time dashboard steps
These are not secrets — they're account-level setup that has to exist once, ever.
### A · Pick your `workers.dev` subdomain (one time, ever)
1. Go to https://dash.cloudflare.com → **Workers & Pages**
2. If this is your first Worker, Cloudflare prompts you to pick a subdomain (e.g. `redciprianpater`).
3. After this, your CHAINSTATE worker URL will be: `https://chainstate-worker.<your-subdomain>.workers.dev`
You will never repeat this step. It's a one-time account choice.
### B · Create the three KV namespaces locally (one time, ever)
The CF API token below cannot create namespaces for you — you must create them locally first, then commit their IDs into `wrangler.toml`. On your laptop:
```bash
# install wrangler if you haven't:
npm install --global wrangler
# log in (opens a browser, one-time):
wrangler login
# create the three namespaces:
wrangler kv:namespace create CHAINSTATE_NODES
wrangler kv:namespace create CHAINSTATE_CACHE
wrangler kv:namespace create CHAINSTATE_CONSENSUS
```
Each command prints something like:
```
🌀 Creating namespace with title "chainstate-worker-CHAINSTATE_NODES"
✨ Success!
Add the following to your configuration file in your kv_namespaces array:
{ binding = "CHAINSTATE_NODES", id = "a1b2c3d4e5f6789012345678901234ab" }
```
Take the `id` from each and paste into the matching block in `wrangler.toml`, replacing the `REPLACE_ME_AFTER_kv_namespace_create_*` placeholders. Commit and push.
---
## Summary table
| Secret name | Source | Scope |
|------------------|-----------------------------------------------------------------------------------------------|------------------------------------------------|
| `CF_API_TOKEN` | https://dash.cloudflare.com/profile/api-tokens · **Custom Token**, *not* the template | Only Workers Scripts + KV (no zones, no D1, no R2) |
| `CF_ACCOUNT_ID` | https://dash.cloudflare.com — right sidebar on any zone overview | (Not secret in the cryptographic sense; just an identifier) |
| `HF_TOKEN` | https://huggingface.co/settings/tokens · **Fine-grained**, scoped to one Space | Write to `CPater/chainstate` only |
---
## 1 · `CF_API_TOKEN` — least-privilege Custom Token
The "Edit Cloudflare Workers" template grants more than you need (it includes zone routes, tail logs, R2 read, etc). For CHAINSTATE you only need two account-level permissions. Build a **Custom Token** instead.
1. Sign in at https://dash.cloudflare.com → **My Profile** → **API Tokens**
2. Click **Create Token**, then scroll to the bottom and click **"Get started" under "Create Custom Token"** (do NOT use the template).
3. Token name: `chainstate-deploy`
4. **Permissions** section — add exactly these two rows and nothing else:
| Scope | Resource | Action |
|----------|-----------------------|----------|
| Account | Workers Scripts | **Edit** |
| Account | Workers KV Storage | **Edit** |
5. **Account Resources**:
- Choose **"Include"** → **"Specific account"** → select **the single account** that owns your `workers.dev` subdomain. Do **not** select "All accounts."
6. **Zone Resources**:
- Leave **empty** (or set to "All zones from an account" if Cloudflare insists). You do not bind a custom domain in `wrangler.toml`, so zone permissions are unnecessary.
7. **Client IP Address Filtering** (optional but recommended):
- Restrict to GitHub Actions IP ranges if you want belt-and-braces. The list is published at https://api.github.com/meta (the `actions` array). Many people skip this because the list changes; a 1-year TTL plus quick revocation is usually enough.
8. **TTL**: set to **1 year** so the token is force-rotated annually.
9. Click **Continue to summary** → **Create Token** → **copy immediately** (CF only shows it once).
10. Add to GitHub: name = `CF_API_TOKEN`, value = the token.
**What this token can do**:
- Upload, modify, or delete Worker scripts in your account
- Read, write, or delete KV namespace entries
**What this token cannot do**:
- Touch DNS, Pages, R2, D1, queues, durable objects, zones, certificates, accounts, billing, or any other Cloudflare product
- Affect any of your other (non-Workers) services
### Even-tighter variant: dedicated CF account
If you want zero blast radius, create a *separate* Cloudflare account just for CHAINSTATE. Cloudflare lets you create multiple accounts on the same email (use sub-addressing like `you+chainstate@example.com`). Add the Custom Token within that account, and the token cannot reach any of your other Cloudflare work even by account compromise.
---
## 2 · `CF_ACCOUNT_ID` — just an identifier
This is the 32-hex Cloudflare account ID. It is not a secret in the cryptographic sense — it doesn't grant any access on its own. But it has to match the account the `CF_API_TOKEN` was created under, so it goes alongside it.
1. https://dash.cloudflare.com → click into any zone (any domain you own; or **Workers & Pages** if you have no domains)
2. Right sidebar: **Account ID** — 32 lowercase hex chars
3. Copy and add to GitHub: name = `CF_ACCOUNT_ID`, value = the hex string
---
## 3 · `HF_TOKEN` — fine-grained, scoped to one Space
A "Write" role token grants write access to every repo and Space on your HuggingFace account. Use a **fine-grained token** scoped to just `CPater/chainstate`:
1. Sign in at https://huggingface.co
2. **Settings** → **Access Tokens** (or https://huggingface.co/settings/tokens)
3. Click **+ Create new token**
4. **Token type**: select **"Fine-grained"** (do NOT select Read or Write).
5. **Token name**: `chainstate-deploy`
6. **Token expiration**: set to **1 year** to force rotation.
7. Scroll to **"Repositories permissions"**:
- Click **"Add a repository"**
- Repository: `CPater/chainstate`
- Type: **Space** (not Model, not Dataset)
- Permission: **Write contents** (this is the only one you need; do not check "Manage repository settings")
8. **Leave every other section unchecked**:
- User permissions: none
- Organization permissions: none
- Inference endpoints: none
- Billing: none
9. Click **Create token** → copy the `hf_...` value immediately.
10. Add to GitHub: name = `HF_TOKEN`, value = the `hf_...` token.
**What this token can do**:
- Write files into `CPater/chainstate` Space repo
**What this token cannot do**:
- Touch any of your other Spaces, models, or datasets
- Read or write your account profile
- Bill anything on your account
- Read private repos you own
- Use inference endpoints
---
## Verifying the secrets are wired correctly
After all three are added, push a no-op commit to `main`:
```bash
git commit --allow-empty -m "trigger first deploy"
git push origin main
```
In the GitHub Actions tab you should see two jobs:
- **`cf-worker`** — succeeds when wrangler deploys the Worker. The job log prints the Worker URL near the end (`Worker is uploaded… https://chainstate-worker.<your-subdomain>.workers.dev`). If you see "permission denied on KV namespace", the IDs in `wrangler.toml` are wrong — re-create with `wrangler kv:namespace list` and update.
- **`hf-space`** — succeeds when `huggingface_hub.upload_folder` finishes. Last line is `HF Space updated ✓`. If you see "Token is unauthorized", the token is missing the repo binding — fix in step 3.7 above.
Then test the Worker directly:
```bash
curl https://chainstate-worker.<your-subdomain>.workers.dev/status
curl -X POST https://chainstate-worker.<your-subdomain>.workers.dev/query \
-H 'Content-Type: application/json' \
-d '{"query": "∫∂x → ?", "swarmSize": 20, "consensusDepth": 3}'
```
Verify the HF Space at `https://cpater-chainstate.static.hf.space/`. The Query/Terminal/SCAN pages will use the Worker once you wire its URL into the Space — easiest way is to add this script tag to `index.html` (somewhere before the closing `</body>`):
```html
<script>window.__CHAINSTATE_WORKER = "https://chainstate-worker.<your-subdomain>.workers.dev";</script>
```
Or set it temporarily via the browser console:
```js
window.__CHAINSTATE_WORKER = "https://chainstate-worker.<your-subdomain>.workers.dev"
```
---
## Triggering deploys
The workflow ships on **three** triggers:
1. **Push to `main`** — every commit on the main branch deploys. Useful for fast iteration.
2. **GitHub Release** — publish a release (e.g. `v0.1.0`) and the workflow runs. Useful for tagging stable deploys.
3. **Manual dispatch** — go to GitHub repo → **Actions** → **deploy** → **Run workflow**. Useful when you want to retry without a commit.
To publish a release:
```bash
git tag v0.1.0
git push origin v0.1.0
```
Then in GitHub: **Releases** → **Draft new release** → choose `v0.1.0` → **Publish release**. The workflow fires automatically.
---
## Rotating secrets
CF tokens have no built-in expiry by default but we set a 1-year TTL above. HF fine-grained tokens also have an explicit expiry. To rotate:
1. Create a new token following the steps above
2. **GitHub repo** → **Settings → Secrets → Actions** → click the existing secret → **Update**
3. Paste the new value, save
4. Delete the old token at the source (CF dashboard / HF tokens page)
There is no need to re-run any workflow; the next push or release will use the new value.
---
## Security notes
- These secrets are **repository-scoped** in GitHub — they're available to workflow jobs in this one repo only. They are not exposed to forks or PRs from forks.
- The values are encrypted at rest in GitHub and decrypted only inside the runner VM. Any line containing the literal value is masked as `***` in logs.
- **Anyone with push access to `main`** can effectively use these secrets via a malicious workflow change. Protect `main` with required reviews / branch protection if you have collaborators.
- Both Cloudflare and HuggingFace let you revoke a token immediately if it leaks; you should not rely on git history scrubbing if a token was committed accidentally — **revoke first**, then clean.
- If you ever suspect a token is compromised: revoke at source (CF or HF dashboard), then generate a new one and update the GitHub secret. The workflow uses the new value on the very next run.
|