feat(loyalty): production readiness round 2 — 12 security, integrity & correctness fixes
Some checks failed
Some checks failed
Security: - Fix TOCTOU race conditions: move balance/limit checks after row lock in redeem_points, add_stamp, redeem_stamps - Add PIN ownership verification to update/delete/unlock store routes - Gate adjust_points endpoint to merchant_owner role only Data integrity: - Track total_points_voided in void_points - Add order_reference idempotency guard in earn_points Correctness: - Fix LoyaltyProgramAlreadyExistsException to use merchant_id parameter - Add StorefrontProgramResponse excluding wallet IDs from public API - Add bounds (±100000) to PointsAdjustRequest.points_delta Audit & config: - Add CARD_REACTIVATED transaction type with audit record - Improve admin audit logging with actor identity and old values - Use merchant-specific PIN lockout settings with global fallback - Guard MerchantLoyaltySettings creation with get_or_create pattern Tests: 27 new tests (265 total) covering all 12 items — unit and integration. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1074,6 +1074,48 @@ sudo systemctl status gitea-runner
|
||||
|
||||
Verify the runner shows as **Online** in Gitea: **Site Administration > Actions > Runners**.
|
||||
|
||||
### 15.1 Runner Configuration
|
||||
|
||||
Generate a config file to override defaults (notably the 3h job timeout which causes silent CI failures on a 4GB server):
|
||||
|
||||
```bash
|
||||
cd ~/gitea-runner
|
||||
./act_runner generate-config > config.yaml
|
||||
sed -i 's/timeout: 3h/timeout: 1h/' config.yaml
|
||||
sudo systemctl restart gitea-runner
|
||||
```
|
||||
|
||||
Key settings in `config.yaml`:
|
||||
|
||||
| Setting | Default | Recommended | Why |
|
||||
|---|---|---|---|
|
||||
| `runner.timeout` | 3h | 1h | Prevents silent failures — tests take ~25min, so 1h is generous |
|
||||
| `runner.shutdown_timeout` | 0s | 0s | OK as-is |
|
||||
| `runner.fetch_timeout` | 5s | 5s | OK as-is |
|
||||
|
||||
!!! tip "CI also has per-job and per-test timeouts"
|
||||
The `.gitea/workflows/ci.yml` sets `timeout-minutes: 45` on the pytest job and `--timeout=120` per individual test. These work together with the runner timeout to catch different failure modes.
|
||||
|
||||
### 15.2 Swap for CI Stability
|
||||
|
||||
The CI runner spins up Docker-in-Docker containers for each job. On a 4GB server running the full app stack, this can exhaust available RAM and silently kill the pytest process. Adding 1GB swap prevents this.
|
||||
|
||||
!!! note "No extra cost"
|
||||
Swap uses existing SSD disk space, not additional Hetzner resources.
|
||||
|
||||
```bash
|
||||
sudo fallocate -l 1G /swapfile
|
||||
sudo chmod 600 /swapfile
|
||||
sudo mkswap /swapfile
|
||||
sudo swapon /swapfile
|
||||
echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab
|
||||
|
||||
# Verify
|
||||
free -h
|
||||
```
|
||||
|
||||
Expected output should show `Swap: 1.0Gi` in the total column.
|
||||
|
||||
## Step 16: Continuous Deployment
|
||||
|
||||
Automate deployment on every successful push to master. The Gitea Actions runner and the app both run on the same server, so the deploy job SSHes from the CI Docker container to `172.17.0.1` (Docker bridge gateway — see note in 16.2).
|
||||
|
||||
Reference in New Issue
Block a user