Compare commits

...

No commits in common. "main" and "chore/cleanup-organize-html" have entirely different histories.

16 changed files with 16 additions and 586 deletions

15
.github/CODEOWNERS vendored
View file

@ -1,15 +0,0 @@
# Default owners
* @crmuncher
# Standards + fleet (slower review)
/AGENTS.md @crmuncher
/ARCHITECTURE.md @crmuncher
/README.md @crmuncher
/STATUS.md @crmuncher
/PLAN.md @crmuncher
/ROADMAP.md @crmuncher
/DECISIONS.md @crmuncher
# Sensitive paths
/.secrets/ @crmuncher
/backend/chain_vault/ @crmuncher

View file

@ -1,68 +0,0 @@
# AGENTS.md — WalletPress
> AI agent contract. Read this before touching anything in this repo.
## Status
canonical · owner=crmuncher · last_updated=2026-07-02
## What This Repo Is
Wallet-as-a-service. Wallet engine, x402 service, chain vault, hosting. CLI for wallet management. Production-grade.
## Type
`backend` · language=Python 3.12 + FastAPI
## Where It Lives
- Source: `https://git.rugmunch.io/RugMunchMedia/walletpress`
- Deployed: Docker on Talos (/srv/walletpress/)
- Port: 8010
## Built With
- Standards: [git.rugmunch.io/RugMunchMedia/standards](https://git.rugmunch.io/RugMunchMedia/standards)
- Toolchain: [TOOLCHAIN.md](https://git.rugmunch.io/RugMunchMedia/standards/raw/branch/main/TOOLCHAIN.md)
- Conventions: [CONVENTIONS.md](https://git.rugmunch.io/RugMunchMedia/standards/raw/branch/main/CONVENTIONS.md)
## Components
- `app/`: FastAPI source (adapters, agent, cli, core, plugins, routers)
## Dependencies
- postgresql (data store)
- redis (cache + queue)
## 🚨 CRITICAL RULES
1. **No nested repos.** Don't commit other complete project trees inside this one.
2. **No secrets.** Never commit `.secrets/`, `.env`, `*.pem`, `*.key`, `*.crt`. Use gopass.
3. **No data blobs.** Don't commit `*.zip`, `*.parquet`, model weights, sqlite files.
4. **No broken files.** Shell heredoc accidents must be caught before commit.
5. **No duplicate scaffolds.** If a `backend/` or `frontend/` subdir exists at root, it's either THE app or bloat.
6. **Update STATUS.md before committing.** Builders must know where we are.
7. **Read DECISIONS.md before architectural changes.** Don't repeat rejected designs.
## Commands
```bash
make install # install deps
make dev # dev server
make test # tests
make lint # ruff + format check
make typecheck # mypy strict
make security # bandit + gitleaks
make ci # full pipeline
make commit # conventional commit
make clean # remove build artifacts
```
## Architecture
See [ARCHITECTURE.md](ARCHITECTURE.md). Update it when components change.
## Plan
[PLAN.md](PLAN.md) shows current sprint. Update weekly.
## Status
[STATUS.md](STATUS.md) shows where we are RIGHT NOW. Update before each commit.
## Owners
- Primary: crmuncher
- Backup: TBD
## Related Repos
See [standards/PRODUCTS.md](https://git.rugmunch.io/RugMunchMedia/standards/raw/branch/main/PRODUCTS.md).

View file

@ -1,27 +0,0 @@
# DECISIONS.md — WalletPress
> Architecture Decision Records (ADRs). Read before architectural changes.
## What is an ADR?
A short document capturing an important architectural decision:
- Context (what's the problem?)
- Decision (what did we choose?)
- Consequences (what does this imply?)
- Alternatives (what else did we consider?)
## How to Write a New ADR
1. Copy `docs/adr/0000-template.md` to `docs/adr/NNNN-short-title.md`
2. Fill in: Status, Context, Decision, Consequences, Alternatives
3. Add link below in "Index"
4. Commit as part of the change that triggered the ADR
## Index
<!-- Add new ADRs here, oldest first -->
| Number | Title | Status | Date |
|--------|-------|--------|------|
| [0001](docs/adr/0001-initial-architecture.md) | Initial architecture | Accepted | 2026-07-02 |
## Fleet-wide ADRs (in standards repo)
- [ADR-0001: Tailscale mesh as the only perimeter](https://git.rugmunch.io/RugMunchMedia/standards/raw/branch/main/MCP-ARCHITECTURE.md)
- [ADR-0012: 21-day sprint, not 10-week](https://git.rugmunch.io/RugMunchMedia/standards/raw/branch/main/FLEET-PLAN.md)

View file

@ -1,75 +0,0 @@
# DEPLOYMENT.md — WalletPress
> How to deploy. Build, push, restart, rollback.
## Architecture
- Container: Docker
- Image registry: local (Talos)
- Orchestration: docker-compose on Talos
- Reverse proxy: nginx on Talos
- Auto-deploy: forgejo webhook → Talos deploy script
## Deploy
### Automatic (CI/CD)
On merge to `main`:
1. forgejo webhook fires
2. Talos deploy script pulls latest commit
3. Rebuilds Docker image
4. Stops old container, starts new
5. Runs health check
6. Rolls back on failure
### Manual
```bash
ssh netcup
cd /srv/walletpress
git pull origin main
docker build -t walletpress:latest .
docker stop walletpress
docker rm walletpress
docker run -d --name walletpress --restart unless-stopped --network host -p 8010:8010 walletpress:latest
```
## Health Check
```bash
curl -fsS http://localhost:8010/health
```
## Rollback
```bash
ssh netcup
cd /srv/walletpress
git log --oneline -5 # find last good commit
git checkout <commit-hash>
docker build -t walletpress:latest .
docker restart walletpress
```
## Logs
```bash
docker logs walletpress --tail 100 -f
```
## Monitoring
- Prometheus: `/metrics` endpoint
- Grafana: dashboards in fleet-infra
- Loki: log aggregation
## Secrets
All secrets in gopass:
- `rmi/walletpress/admin_key`
- `rmi/walletpress/db_password`
- _see AGENTS.md for full list_
Loaded via docker `--env-file` or systemd `EnvironmentFile`.
## Firewall
- Public: 80, 443 (nginx)
- Internal: 8010 (localhost only, behind nginx)
- Tailscale: 8010 for admin access
## Backup
- Code: forgejo (source of truth) + Hydra bare mirror (daily 04:00)
- Data: DB snapshot to R2 (daily)
- Config: gopass

View file

@ -1,83 +0,0 @@
# DEVELOPMENT.md — WalletPress
> Dev workflow. Install, code, test, commit, PR.
## Setup
### Prerequisites
- Python 3.12+ / Node 20+
- `gopass` for secrets
- `mise` for tool version mgmt (or manual)
- `pre-commit` for hooks
### Install
```bash
git clone https://git.rugmunch.io/RugMunchMedia/walletpress.git
cd walletpress
make install
pre-commit install
```
### Environment
```bash
# Required env vars (loaded from gopass on deploy, .env locally)
# See .env.example
cp .env.example .env
$EDITOR .env # fill in test values
```
## Workflow
### 1. Create a branch
```bash
git checkout -b feat/my-feature
# or fix/my-bug, docs/my-doc, chore/my-chore
```
### 2. Make changes
- Write code
- Add tests
- Update docs (AGENTS.md, ARCHITECTURE.md, STATUS.md)
### 3. Run pre-commit locally
```bash
make lint
make test
make typecheck
make security
```
### 4. Commit (conventional)
```bash
make commit # interactive
# or:
git commit -m "feat(scope): add new feature"
```
Types: feat, fix, docs, style, refactor, perf, test, build, ci, chore, ops, security
### 5. Push + PR
```bash
git push -u origin feat/my-feature
# Open PR on forgejo: https://git.rugmunch.io/RugMunchMedia/walletpress/pulls/new
```
### 6. Wait for CI
- All checks must pass
- Review by CODEOWNERS
- Squash-merge to main
- Auto-deploys to Talos (via forgejo webhook)
## Daily End-of-Day
```bash
make status # show what's changed
fleet-commit # commit helper with checklist
```
## Code Style
- Python: ruff (lint + format), mypy strict
- TypeScript: eslint + prettier
- Shell: shellcheck
- Markdown: vale
See [standards/CONVENTIONS.md](https://git.rugmunch.io/RugMunchMedia/standards/raw/branch/main/CONVENTIONS.md).

39
PLAN.md
View file

@ -1,39 +0,0 @@
# PLAN.md — WalletPress
> Current sprint. 21-day cycles per ADR-0012.
## Status
current_sprint=2026-Q3-S1 · started=2026-07-01 · ends=2026-07-21
## Sprint Goals
1. _TODO: top 1-3 goals for this sprint_
## In Progress
- [ ] TODO: in-progress items
## Backlog (this sprint)
- [ ] TODO: planned items
## Risks
- TODO: anything blocking progress
## Done (this sprint)
- _None yet — sprint just started._
## Carry-over from previous sprint
- _None._
---
## Definition of Done
- [ ] Code complete
- [ ] Tests written (>80% coverage on changed lines)
- [ ] Pre-commit hooks pass (ruff, mypy, gitleaks, bandit)
- [ ] CI passes on forgejo
- [ ] Conventional commit message
- [ ] PR reviewed + merged
- [ ] Deployed to staging
- [ ] Smoke-tested in production
- [ ] Observability in place (metrics, logs, alerts)
- [ ] Docs updated (AGENTS.md, ARCHITECTURE.md, README.md)
- [ ] STATUS.md updated

View file

@ -1,45 +0,0 @@
## Fixes walletpress backend deployment blockers
The walletpress backend was unable to start due to 4 issues. This PR fixes all of them.
### #1 — requirements.lock incomplete
**Problem:** `requirements.lock` was missing deps. The Dockerfile used `requirements.lock` for `pip install`, so the runtime couldn't import `python-multipart` (FastAPI Form data), `mcp` (MCP SDK), and various chain-specific deps.
**Fix:** Switched Dockerfile to use `requirements.txt` (which has all loose pins) instead of the incomplete lock. Also added `python-multipart>=0.0.9` and `mcp>=1.25.0` to `requirements.txt`.
### #2 — main.py wrong import name (AuditTrail)
**Problem:** `from core.audit import AuditTrail` — class doesn't exist; only `AuditLog` does.
**Fix:** Changed import and usage to `AuditLog`.
### #3 — main.py wrong import path (PersistentStore)
**Problem:** `from routers.chain_vault import _PersistentStore` — neither `_PersistentStore` nor `_persistent_store` exists in `chain_vault.py`. The actual class is `PersistentStore` (no underscore prefix) in `routers/_persistent_store.py`.
**Fix:** Changed import to `from routers._persistent_store import PersistentStore`.
### #4 — DB volume permissions
**Problem:** `/data/walletpress/walletpress.db` couldn't be opened (`unable to open database file`). The mounted volume had wrong ownership and the previous Dockerfile chown'd `/data` to walletpress user, but only at build time — the runtime mount overwrote this.
**Fix:** Added `entrypoint.sh` that runs as root on container start, ensures `/data` exists, chowns to `walletpress:walletpress`, then `exec`s the CMD. Also fixed Dockerfile ordering (COPY entrypoint + chmod must happen before USER directive).
### Verification
After all fixes:
```
{"status":"ok","version":"1.1.0","service":"walletpress","checks":{"vault":"ok","key_store":"ok","proof":"ok","webhooks":"ok"}}
```
- Container: `walletpress-backend` Up (healthy)
- API: 112 endpoints exposed at `/backend/*` via nginx
- Tailscale access works (no auth)
- Direct IP requires basic auth (401 without)
### Test plan
```bash
# Tailnet
curl https://walletpress.rugmunch.io/backend/health
curl https://walletpress.rugmunch.io/backend/docs
# Direct IP (needs creds)
curl -u crmuncher:<password> https://152.53.80.39/backend/health
```
Closes the 4 blockers documented in fleet-infra/ADMIN-ACCESS.md.

View file

@ -1,40 +0,0 @@
# WalletPress
> Part of **Rug Munch Media LLC** — Wyoming-based crypto intelligence platform.
## What
Wallet-as-a-service. Wallet engine, x402 service, chain vault, hosting. CLI for wallet management. Production-grade.
## Type
`backend` · **Python 3.12 + FastAPI**
## Quickstart
```bash
make install # install deps
make dev # start dev server
make test # run tests
make lint # lint + format
make ci # full CI pipeline
```
## Documentation
- [AGENTS.md](AGENTS.md) — AI agent contract
- [ARCHITECTURE.md](ARCHITECTURE.md) — technical architecture
- [PLAN.md](PLAN.md) — current sprint
- [ROADMAP.md](ROADMAP.md) — long-term direction
- [STATUS.md](STATUS.md) — where we are RIGHT NOW
- [DEVELOPMENT.md](DEVELOPMENT.md) — dev workflow
- [DEPLOYMENT.md](DEPLOYMENT.md) — how to deploy
- [TESTING.md](TESTING.md) — test strategy
- [SECURITY.md](SECURITY.md) — security model
- [DECISIONS.md](DECISIONS.md) — architecture decision records
## Standards
This repo follows Rug Munch Media LLC fleet standards:
[git.rugmunch.io/RugMunchMedia/standards](https://git.rugmunch.io/RugMunchMedia/standards)
## Repository
- Source of truth: `https://git.rugmunch.io/RugMunchMedia/walletpress`
- Mirrors: GitHub (LLC + personal), GitLab, HuggingFace
- Backup: Hydra daily at 04:00 via `git-backup.sh`

View file

@ -1,36 +0,0 @@
# STATUS.md — WalletPress
> Where we are RIGHT NOW. Update before every commit.
## Last Updated
2026-07-02 (template, replace on first commit)
## Deployment Status
- **Last deploy**: TBD
- **Current version**: TBD
- **Health**: TBD
- **Uptime (30d)**: TBD
- **Active branch**: `main`
## Open Issues
- _None — track in forgejo issues_
## Recent Activity
- 2026-07-02: Repository created from `fleet-template`
## Known Issues / Tech Debt
- _None yet_
## Quick Links
- [Live URL](https://walletpress.rugmunch.io)
- [API docs](https://walletpress.rugmunch.io/docs)
- [Health](https://walletpress.rugmunch.io/health)
- [Repo](https://git.rugmunch.io/RugMunchMedia/walletpress)
## Status Indicators
Use these in commit messages + status updates:
- 🟢 healthy — deployed, monitored, no issues
- 🟡 degraded — running but with known issues
- 🔴 down — service unavailable
- 🚧 in-development — pre-production, expect breakage
- ⏸️ paused — work intentionally stopped

View file

@ -1,73 +0,0 @@
# TESTING.md — WalletPress
> Test strategy. Unit, integration, e2e, fixtures.
## Test Pyramid
```
/\
/ \ E2E (slow, few)
/----\
/ \ Integration (medium, more)
/--------\
/ \ Unit (fast, many)
/____________\
```
- **Unit tests**: test individual functions/classes in isolation
- **Integration tests**: test components together (DB, API, auth)
- **E2E tests**: test full user flows (slow, run before deploy)
## Structure
```
tests/
├── unit/ # fast, no external deps
├── integration/ # uses test DB, mocks external APIs
├── e2e/ # full stack, runs against staging
├── fixtures/ # test data (mainnet guard: no real addresses/keys)
└── conftest.py # pytest config
```
## Running
```bash
make test # all tests
make test-unit # only unit
make test-integration # only integration
make test-cov # with coverage report
pytest tests/unit/test_X.py -v # single file
```
## Fixtures
Use pytest fixtures. Examples:
- `clean_db` — fresh DB per test
- `mock_helius` — mock Helius API responses
- `auth_headers` — Bearer token for test user
- `sample_token` — fake token (test address, NOT mainnet)
**NEVER use mainnet data in tests.** Pre-commit hook blocks this.
## Coverage
- Target: >80% on changed lines
- Enforced in CI via `--cov-fail-under=80`
## Mocking
- `httpx` for HTTP mocking (use `respx` or `pytest-httpx`)
- `unittest.mock` for general mocking
- VCR.py for recording/replaying API calls
## Performance Tests
- `locust` for load testing (run against staging)
- Profile with `py-spy` or `cProfile`
## CI
Every PR runs:
1. Lint (ruff)
2. Type check (mypy strict)
3. Unit tests + coverage
4. Integration tests (test DB)
5. Security scan (bandit, gitleaks)
6. Build Docker image (verify it compiles)
Merge blocked if any fails.

View file

@ -2,43 +2,30 @@ FROM python:3.12-slim AS builder
WORKDIR /app WORKDIR /app
RUN apt-get update && apt-get install -y --no-install-recommends gcc libffi-dev libssl-dev && rm -rf /var/lib/apt/lists/* RUN apt-get update && apt-get install -y --no-install-recommends \
gcc libffi-dev libssl-dev && \
rm -rf /var/lib/apt/lists/*
COPY requirements.txt ./ COPY requirements.lock requirements.txt ./
RUN pip install --no-cache-dir -r requirements.txt RUN pip install --no-cache-dir -r requirements.lock
FROM python:3.12-slim AS runner FROM python:3.12-slim AS runner
WORKDIR /app WORKDIR /app
# Install runtime deps (no gcc needed)
RUN apt-get update && apt-get install -y --no-install-recommends libssl-dev && rm -rf /var/lib/apt/lists/*
# Copy Python deps from builder
COPY --from=builder /usr/local/lib/python3.12/site-packages /usr/local/lib/python3.12/site-packages
COPY --from=builder /usr/local/bin /usr/local/bin
# Copy app code
COPY . .
# Create data dir + set perms (as root)
RUN mkdir -p /data && chmod 755 /data
# Add entrypoint (as root) that fixes data perms then drops to walletpress user
COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh
# Create non-root user
RUN groupadd -r walletpress && useradd -r -g walletpress -d /app -s /sbin/nologin walletpress RUN groupadd -r walletpress && useradd -r -g walletpress -d /app -s /sbin/nologin walletpress
# Chown app + data dirs to walletpress COPY --from=builder /usr/local/lib/python3.12/site-packages /usr/local/lib/python3.12/site-packages
RUN chown -R walletpress:walletpress /app /data COPY --from=builder /usr/local/bin /usr/local/bin
COPY . .
RUN mkdir -p /data && chown walletpress:walletpress /data
USER walletpress USER walletpress
EXPOSE 8010 EXPOSE 8010
HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 CMD python3 -c "import urllib.request; urllib.request.urlopen('http://localhost:8010/health')" || exit 1 HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
CMD python3 -c "import urllib.request; urllib.request.urlopen('http://localhost:8010/health')" || exit 1
ENTRYPOINT ["/entrypoint.sh"]
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8010"] CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8010"]

View file

@ -1,15 +0,0 @@
#!/bin/sh
# Entry runs as root. Chown data dir then exec CMD as walletpress (per Dockerfile USER directive).
set -e
mkdir -p /data
# chown needs to be done as root (current user)
chown -R walletpress:walletpress /data
chmod 755 /data
# Print info
echo "[walletpress] data dir ready: /data"
echo "[walletpress] starting: $@"
# Exec the CMD — runs as walletpress (Dockerfile USER directive)
exec "$@"

View file

@ -108,13 +108,13 @@ async def lifespan(app: FastAPI):
# Initialize services into app.state (enables DI and testability) # Initialize services into app.state (enables DI and testability)
from core.vault import Vault from core.vault import Vault
from core.auth import KeyStore from core.auth import KeyStore
from core.audit import AuditLog from core.audit import AuditTrail
from core.license import LicenseManager from core.license import LicenseManager
from core.proof import ProofOfGeneration from core.proof import ProofOfGeneration
from wallet_engine.generator import WalletGenerator from wallet_engine.generator import WalletGenerator
app.state.vault = Vault(cfg.db_path) app.state.vault = Vault(cfg.db_path)
app.state.key_store = KeyStore(cfg.keys_path) app.state.key_store = KeyStore(cfg.keys_path)
app.state.audit = AuditLog(cfg.audit_path) app.state.audit = AuditTrail(cfg.audit_path)
app.state.license = LicenseManager() app.state.license = LicenseManager()
app.state.proof = ProofOfGeneration(cfg.data_dir / "proof.db") app.state.proof = ProofOfGeneration(cfg.data_dir / "proof.db")
app.state.generator = WalletGenerator(vault_password=cfg.vault_password) app.state.generator = WalletGenerator(vault_password=cfg.vault_password)
@ -122,8 +122,8 @@ async def lifespan(app: FastAPI):
await app.state.webhook_deliverer.start() await app.state.webhook_deliverer.start()
# Reload persisted webhooks into the live deliverer # Reload persisted webhooks into the live deliverer
from routers._persistent_store import PersistentStore from routers.chain_vault import _PersistentStore
PersistentStore.reload_webhooks() _PersistentStore.reload_webhooks()
# Anchor source commit to Arweave for on-chain code verification # Anchor source commit to Arweave for on-chain code verification
if os.getenv("WP_POF_ARWEAVE_KEY_PATH"): if os.getenv("WP_POF_ARWEAVE_KEY_PATH"):

View file

@ -27,6 +27,3 @@ monero>=0.0.4
substrate-interface>=1.8.0 substrate-interface>=1.8.0
coincurve>=18.0.0 coincurve>=18.0.0
pycardano>=0.19.0 # Cardano Kholaw (BIP32-Ed25519 IOHK) — 1.1 MB disk pycardano>=0.19.0 # Cardano Kholaw (BIP32-Ed25519 IOHK) — 1.1 MB disk
python-multipart>=0.0.9
mcp>=1.25.0

View file

@ -1,16 +0,0 @@
# ADR-NNNN: <Short Title>
## Status
Proposed | Accepted | Deprecated | Superseded by ADR-XXXX
## Context
What's the issue? What's the pressure for a decision?
## Decision
What did we choose?
## Consequences
What becomes easier? What becomes harder?
## Alternatives
What else did we consider? Why didn't we pick them?

View file

@ -1,22 +0,0 @@
# ADR-0001: Initial Architecture
## Status
Accepted · 2026-07-02
## Context
First commit of WalletPress. Need to document the foundational choices.
## Decision
- **Language**: Python 3.12 + FastAPI
- **Port**: 8010
- **Deployment**: Docker on Talos behind nginx
- **Source of truth**: forgejo
- **CI**: forgejo Actions
- **Secrets**: gopass
## Consequences
- All future decisions build on this foundation
- Breaking changes to these need a new ADR
## Alternatives
- _TBD_