v0.1 wave 1 (steps 2+3+4): SQLite ledger + FastAPI skeleton + async job runner
- db.py: migrations + DAOs for tokens / projects / jobs / findings (SQLite WAL)
- auth.py: SHA-256 bearer hashing + LAN-CIDR allowlist + admin/app token tiers
- models.py: Pydantic shapes (Project, Subproject, Schedule, Notify, Job, CreateJobRequest)
- server.py: FastAPI on port 8810; /healthz, /admin/tokens/*, /projects/*, /jobs, /jobs/{id}, /jobs/{id}/log, /jobs/{id}/findings
- runner.py: bounded asyncio pool, per-job timeout with process-group SIGTERM→SIGKILL escalation, orphaned-job recovery on boot
- workspace.py: bare-clone + worktree materialization, gc
- config.py: env-driven
- 62 tests across db / auth / projects / jobs / runner / e2e — all green
Cross-token project access returns 404 (not 403) — existence-leak guard.
Bearer tokens hashed at rest; admin token bootstrapped on first boot.
Recipe subprocess uses start_new_session=True so killpg targets the
whole process tree on timeout — child processes can't escape SIGKILL.
Pump task guarded with wait_for(2s) + cancel fallback against any
orphan that survives the group kill.
Wave 2 (parsers + findings extraction + MCP + email digest) pending.
Spec: memory/spec-crafting-table.md
This commit is contained in:
parent
4e668a79e1
commit
0ec3a04676
20 changed files with 3328 additions and 0 deletions
33
.env.example
Normal file
33
.env.example
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
# crafting-table runtime config — every key is optional; defaults shown.
|
||||
#
|
||||
# Copy to `.env` and edit, or pass each key explicitly to `docker compose`.
|
||||
|
||||
# SQLite ledger location (created on first boot)
|
||||
CRAFTING_DB=/data/crafting.db
|
||||
|
||||
# Where workspaces (bare clones + per-job worktrees) live
|
||||
CRAFTING_WORKSPACE=/workspace
|
||||
|
||||
# Per-job log files: /data/jobs/<job_id>.log
|
||||
CRAFTING_LOG_DIR=/data/jobs
|
||||
|
||||
# Admin bearer plaintext is written here on first boot, chmod 600
|
||||
CRAFTING_ADMIN_BEARER=/data/admin-bearer.txt
|
||||
|
||||
# Bounded asyncio pool size — how many recipes can run concurrently
|
||||
CRAFTING_MAX_CONCURRENT=4
|
||||
|
||||
# HTTP listen socket
|
||||
CRAFTING_PORT=8810
|
||||
CRAFTING_BIND=0.0.0.0
|
||||
|
||||
# Default per-job timeout in seconds (recipes can override via timeout_secs)
|
||||
CRAFTING_DEFAULT_JOB_TIMEOUT=1800
|
||||
|
||||
# Override the default LAN allowlist if you want stricter scoping.
|
||||
# Default: 10/8, 172.16/12, 192.168/16, 127/8, ::1/128
|
||||
# CRAFTING_LAN_CIDRS=192.168.0.0/16,127.0.0.0/8
|
||||
|
||||
# Workspace gc — how often to sweep for stale worktrees, and the age cutoff.
|
||||
CRAFTING_GC_INTERVAL=3600
|
||||
CRAFTING_GC_AGE=86400
|
||||
Loading…
Add table
Add a link
Reference in a new issue