Solanasis Credential Setup Guide

Last updated: 2026-03-23


ERPNext API Access

From this server (localhost)

ERPNext runs on http://localhost:8080. API user: claude-bot@solanasis.com.

# Token auth (preferred)
curl -H "Authorization: token $ERPNEXT_API_KEY:$ERPNEXT_API_SECRET" \
  http://localhost:8080/api/method/frappe.auth.get_logged_user
 
# Password auth (fallback)
curl -c /tmp/cookies -H "Content-Type: application/json" \
  -d '{"usr":"claude-bot@solanasis.com","pwd":"<password>"}' \
  http://localhost:8080/api/method/login

From a second machine (Claude Code)

  1. Clone solanasis-scripts:

    gh repo clone dzinreach/solanasis-scripts
  2. Run the setup script:

    python solanasis-scripts/scripts/setup_erpnext_env.py
    
  3. Enter the API key and secret when prompted (get these from a team member securely — Signal, in-person, etc.)

  4. The script creates ~/.config/solanasis/.env (restricted permissions)

  5. After restarting your shell, Claude Code can access:

    • $ERPNEXT_URL — the ERPNext endpoint
    • $ERPNEXT_API_KEY — API key
    • $ERPNEXT_API_SECRET — API secret
  6. Test:

    curl -s -H "Authorization: token $ERPNEXT_API_KEY:$ERPNEXT_API_SECRET" \
      $ERPNEXT_URL/api/method/frappe.auth.get_logged_user

In GitHub Actions / CI

Secrets are pre-configured on these repos: solanasis_crm, solanasis_core, solanasis-scripts

# In a workflow:
env:
  ERPNEXT_URL: ${{ secrets.ERPNEXT_URL }}
  ERPNEXT_API_KEY: ${{ secrets.ERPNEXT_API_KEY }}
  ERPNEXT_API_SECRET: ${{ secrets.ERPNEXT_API_SECRET }}

Regenerating ERPNext API Keys

If keys are compromised or need rotation:

# Generate new keys (inside Docker container)
docker exec frappe_docker-backend-1 bench --site db.solanasis.com execute \
  frappe.core.doctype.user.user.generate_keys --args '["claude-bot@solanasis.com"]'
 
# IMPORTANT: Capture the api_secret from the output — shown only once
 
# Get the new api_key:
docker exec frappe_docker-backend-1 bench --site db.solanasis.com execute \
  frappe.client.get_value --kwargs '{"doctype":"User","filters":"claude-bot@solanasis.com","fieldname":"api_key"}'
 
# Update GitHub Secrets:
for repo in solanasis_crm solanasis_core solanasis-scripts; do
  gh secret set ERPNEXT_API_KEY --repo dzinreach/$repo --body "<new_key>"
  gh secret set ERPNEXT_API_SECRET --repo dzinreach/$repo --body "<new_secret>"
done
 
# Update local env on any machines that have it:
# Edit ~/.config/solanasis/.env with new values

Syncing Local .env to GitHub Secrets

Use the sync script (LOCAL → GITHUB only, not reverse):

cd solanasis-scripts

# Sync a single repo's .env to GitHub Secrets
python sync_env_secrets.py ../solanasis-site dzinreach/solanasis-site

# Sync all repos at once
python sync_env_secrets.py ../solanasis-docs dzinreach/solanasis-docs && ^
python sync_env_secrets.py ../solanasis-site dzinreach/solanasis-site && ^
python sync_env_secrets.py . dzinreach/solanasis-scripts

Important: GitHub Secrets are write-only. You cannot read them back via the API. They are a backup, not a sync target. To restore, re-enter values manually or retrieve from the original service dashboards.


Baserow API Access

Self-hosted instance (https://baserow.solanasis.com)

Two auth methods available:

MethodHeaderExpires?Use for
DB TokenAuthorization: Token {key}NeverRow CRUD (scripts, automation)
JWTAuthorization: JWT {token}10 min access / 7 day refreshSchema operations (create tables, fields)

DB Token auth (preferred for scripts)

curl -H "Authorization: Token $BASEROW_DB_TOKEN" \
  -H "Host: baserow.solanasis.com" \
  http://localhost:8880/api/database/rows/table/{TABLE_ID}/

Note: When calling from the server (localhost:8880), you MUST include Host: baserow.solanasis.com header. Through the tunnel URL, this isn’t needed but Cloudflare may block automated requests (error 1010).

JWT auth (for admin/schema operations)

import requests
 
# Step 1: Get JWT token
resp = requests.post("http://localhost:8880/api/user/token-auth/",
    json={"email": BASEROW_EMAIL, "password": BASEROW_PASSWORD},
    headers={"Host": "baserow.solanasis.com"})
access_token = resp.json()["access_token"]
 
# Step 2: Use token
resp = requests.get("http://localhost:8880/api/database/tables/database/54/",
    headers={"Authorization": f"JWT {access_token}", "Host": "baserow.solanasis.com"})

Environment variables

Stored in solanasis-scripts/.env:

VariablePurpose
BASEROW_BASE_URLhttps://baserow.solanasis.com
BASEROW_DB_TOKENDatabase token (claude-bot, full CRUD)
BASEROW_EMAILAdmin email (ds@solanasis.com)
BASEROW_PASSWORDAdmin password
BASEROW_DATABASE_ID54

Regenerating Baserow DB Token

# Via JWT auth — create a new token
import requests
 
resp = requests.post("http://localhost:8880/api/user/token-auth/",
    json={"email": BASEROW_EMAIL, "password": BASEROW_PASSWORD},
    headers={"Host": "baserow.solanasis.com"})
jwt = resp.json()["access_token"]
 
resp = requests.post("http://localhost:8880/api/database/tokens/",
    json={"name": "claude-bot-v2", "workspace": 45,
          "permissions": [{"type": "create", "value": True}, {"type": "read", "value": True},
                          {"type": "update", "value": True}, {"type": "delete", "value": True}]},
    headers={"Authorization": f"JWT {jwt}", "Host": "baserow.solanasis.com"})
print(resp.json()["key"])  # New token

Then update .env and GitHub Secrets (gh secret set BASEROW_DB_TOKEN --repo dzinreach/solanasis-scripts --body "NEW_TOKEN").


Cloudflare Credentials

For Cloudflare Pages (solanasis-site deployment)

Stored in GitHub Secrets on solanasis-site repo:

  • CLOUDFLARE_ACCOUNT_ID — Solanasis Cloudflare account
  • CLOUDFLARE_API_TOKEN — Pages deployment permissions

For Cloudflare Tunnel (ACTIVE)

Tunnel solanasis (ID: c57c4d9c-e408-4e43-b0d5-190baa70568e) uses locally-managed credentials:

FilePurpose
~/.cloudflared/cert.pemAccount cert for solanasis.com zone (from cloudflared login)
~/.cloudflared/c57c4d9c-...jsonTunnel-specific credentials (auto-generated on tunnel create)
~/.cloudflared/config.ymlIngress routing rules

To re-authenticate (e.g., cert expired): Move cert.pem out of the way, run cloudflared login, select solanasis.com zone.

To recreate the tunnel (e.g., credentials compromised): Delete the tunnel (cloudflared tunnel delete solanasis), create a new one, update config.yml with new UUID, update DNS routes.


Credential Storage Architecture

Tier 1 — Local Development
├── ~/.config/solanasis/.env (chmod 600) — ERPNext API creds
├── _solanasis/frappe_docker/.env (gitignored) — ERPNext Docker config
├── _solanasis/solanasis-site/.env (gitignored) — Website dev config
├── ~/.cloudflared/cert.pem — Solanasis account cert (cloudflared login)
├── ~/.cloudflared/<UUID>.json — Tunnel credentials (cloudflared tunnel create)
└── ~/.cloudflared/config.yml — Tunnel ingress routing rules

Tier 2 — CI/CD (GitHub Secrets)
├── solanasis_crm: ERPNEXT_URL, ERPNEXT_API_KEY, ERPNEXT_API_SECRET
├── solanasis_core: ERPNEXT_URL, ERPNEXT_API_KEY, ERPNEXT_API_SECRET
├── solanasis-scripts: ERPNEXT_*, BASEROW_*, GOOGLE_AI_*, SHORT_IO_*
└── solanasis-site: CLOUDFLARE_*, BREVO_*, TURNSTILE_*, SITE_*

Tier 3 — Production (Cloudflare Worker Secrets)
└── Set via: wrangler pages secret put <NAME>

Security Rules

  • NEVER commit .env, .env.*, or .dev.vars to git
  • NEVER hardcode credentials in source files
  • All .env files must be in .gitignore
  • Local credential files must be chmod 600
  • If credentials are accidentally committed, follow: solanasis-docs/solanasis-credentials-security-playbook.md