Commit graph

6 commits

Author SHA1 Message Date
d467b2f5be v0.1 wave 2A (steps 5+6): per-language parsers + findings extraction
- parsers/ package: rust / python / go / typescript / generic
- parser registry with language+recipe -> fallback resolution
- fingerprint hash (kind+file+line+code) for cross-run dedup
- runner.py post-exec hook: parse log, persist findings, count on job row
  (extraction runs before mark_job_finished so callers polling on terminal
  status see findings_count populated atomically)
- db.insert_finding / list_findings / increment_findings_count DAOs already
  shipped in wave 1; wired here
- GET /jobs/{id}/findings now returns real data (server route already
  shipped; was returning empty list because nothing populated the table)
- tests/test_parsers/: 6 modules + 11 fixtures (rust/python/go/typescript)
- tests/test_runner_findings.py: 3 integration tests
- README: tick steps 2-6, add Findings section

Suite: 108 passing (62 wave-1 + 46 new).
Spec: memory/spec-crafting-table.md
2026-04-29 08:36:16 -07:00
98306ca2e0 v0.1 wave 2C (step 8): email digest scheduler
- digest.py: DigestScheduler with daily 06:00 PT loop
- SmtpConfig env-driven (CRAFTING_SMTP_*)
- notify.on event filter respected per project
- GET /digests/{date} + POST /admin/digest/run-now (dry_run flag)
- migration 006: digest_runs (idempotency via UNIQUE(date, project_name))
- text + HTML email bodies; matches spec's worked example
- Server lifespan integration; gracefully disables if SMTP not configured
- tests/test_digest.py: 8 tests (aggregation / filter / smtp mock / idempotency / endpoint)

Patch-drafted line is a placeholder until wave 3 / step 9 ships.

Spec: memory/spec-crafting-table.md
2026-04-29 08:33:37 -07:00
2e16ec886d wave 1 wiring: Dockerfile API stage + compose API command + README quickstart
- Dockerfile: pip-install requirements.txt and copy crafting_table/ into
  /app, switch CMD from /bin/bash to uvicorn server (port 8810). pip lands
  in /usr/local/bin so the crafter user runs uvicorn without elevation.
- compose.yml: replace smoke.sh entrypoint with the API server command;
  bind 192.168.0.5:8810:8810 (LAN-only); switch named volumes to real
  Lucy appdata paths so /data + /workspace + /caches survive recreate.
  env_file marked optional so a fresh checkout boots without copying
  .env.example.
- README.md: tick steps 1-4 done, document API surface table, add
  curl-based quickstart (mint token → register project → kick off job →
  poll → stream log), and an architecture-notes section covering the
  recipe-immutability snapshot, process-group SIGTERM/SIGKILL escalation,
  WAL+single-writer trade-off, and the recipe-security stance.

Smoke remains runnable on demand:
  docker compose run --rm crafting-table /usr/local/bin/smoke.sh
2026-04-29 08:28:51 -07:00
0ec3a04676 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
2026-04-29 08:17:41 -07:00
4e668a79e1 v0.1 step 1: Dockerfile + per-language toolchain smoke
Monolith image with every toolchain in the spec:
- Python 3.12 + uv/ruff/mypy/pytest/pip-audit/semgrep
- Node 22 LTS + bun
- Go 1.22 + govulncheck/staticcheck
- Rust stable + cargo-audit/cargo-deny
- Ruby 3.x + bundler-audit
- PHP 8.x + composer/phpstan
- JDK 17 + 21 + Maven + Gradle
- .NET 8 SDK
- Swift 5.9.2
- Kotlin 1.9.25
- clang + cmake + valgrind + ASan/UBSan/TSan
- bash + shellcheck

smoke.sh proves each toolchain compiles + runs a hello-world.
compose.yml uses the existing 'sulkta' bridge network.

No API yet (steps 2-3); no MCP yet (step 7); no runner yet (step 4).
This is the foundation.

NOTE: docker build + smoke verification not yet run — sandbox doesn't
have docker. Needs `docker compose build && docker compose up` on Lucy
or any real Docker host before we trust the Dockerfile.

Spec: memory/spec-crafting-table.md
2026-04-29 07:29:53 -07:00
5bd1b1de7e Initial commit 2026-04-29 07:22:04 -07:00