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.