Address Hans' workflow feedback - make it actionable
1. Created QUICKSTART.md (60 second read vs 1295 line handbook) - Who you are, 4 session-start actions, critical rules - All CLAUDE.md files now reference QUICKSTART first 2. Created scripts/daily-review.sh (automates Part 4 checks) - Runs Section A, F, G checks automatically - Reports PASS/FAIL with colors - Fails fast on foundation violations 3. Added workflow section to handbook - Where to find tasks (git.clavitor.ai) - Priority order (CRITICAL > HIGH > MEDIUM) - Engineer vs Reviewer responsibilities 4. Created tasks skill (.claude/skills/tasks/SKILL.md) - For querying Gitea issues programmatically - Will integrate with agent workflow 5. Updated all 11 CLAUDE.md files with concise headers - Quickstart link (60s) - Deep reference link (handbook Section V) - Agent identity + daily script command Hans' feedback addressed: - ✅ Handbook too long → QUICKSTART.md - ✅ Daily review manual → automated script - ✅ Vague instructions → specific script + task query - ✅ No task queue → skill created
This commit is contained in:
parent
fd27a9d173
commit
b920203314
|
|
@ -1,6 +1,9 @@
|
||||||
# Clavitor — Agent Instructions
|
# Clavitor — Agent Instructions
|
||||||
|
|
||||||
> **Required reading before any work**: [CLAVITOR-AGENT-HANDBOOK.md](CLAVITOR-AGENT-HANDBOOK.md) — Section I (Culture), Section II (Security), and Section III (Workflow). Read end-to-end on first session. Run the Section III → Daily review checklist each morning. Drift gets fixed before any new feature work.
|
> **Quickstart (60 seconds):** [QUICKSTART.md](QUICKSTART.md) — who you are, 4 things to do, critical rules.
|
||||||
|
> **Deep reference:** [CLAVITOR-AGENT-HANDBOOK.md](CLAVITOR-AGENT-HANDBOOK.md) — full principles, all sections.
|
||||||
|
> **First session ever:** Read handbook end-to-end. All other sessions: Quickstart + your domain in Section V.
|
||||||
|
> **Daily:** Run `./scripts/daily-review.sh` before any work. Fix failures first.
|
||||||
|
|
||||||
## Foundation First — No Mediocrity. Ever.
|
## Foundation First — No Mediocrity. Ever.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,70 @@
|
||||||
|
# Clavitor Quickstart
|
||||||
|
|
||||||
|
**For:** Hans (NOC / Operations)
|
||||||
|
**Time to read:** 60 seconds
|
||||||
|
**Full handbook:** [CLAVITOR-AGENT-HANDBOOK.md](CLAVITOR-AGENT-HANDBOOK.md)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Who You Are
|
||||||
|
|
||||||
|
**Hans** — NOC / Operations agent. Infrastructure, monitoring, POP health, alerts.
|
||||||
|
|
||||||
|
Your domain: `operations/*`, `monitoring/*`, `noc/*`, `clavis-telemetry/*`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Session Start (30 seconds)
|
||||||
|
|
||||||
|
1. **Run daily checks:** `./scripts/daily-review.sh`
|
||||||
|
2. **See your tasks:** `tea issues list --repo johan/clavitor --assignees hans`
|
||||||
|
3. **Read CLAUDE.md** in whatever subproject you're touching
|
||||||
|
4. **Execute** per handbook Section III
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Before Any Code Change
|
||||||
|
|
||||||
|
**Must pass:**
|
||||||
|
- [ ] `./scripts/daily-review.sh` — all checks green
|
||||||
|
- [ ] Test added for new logic (Section F3)
|
||||||
|
- [ ] Error handling has unique code (Section I, "Error messages that actually help")
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## The Workflow (60 seconds)
|
||||||
|
|
||||||
|
```
|
||||||
|
1. Pick up issue from git.clavitor.ai (assigned to you)
|
||||||
|
2. Create branch: git checkout -b hans/fix-###
|
||||||
|
3. Implement per issue spec
|
||||||
|
4. Run: ./scripts/daily-review.sh (must pass)
|
||||||
|
5. Commit with "Fixes ####"
|
||||||
|
6. Push, create PR, wait for Yurii/Victoria/Arthur review
|
||||||
|
7. DO NOT merge your own PR
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Critical Rules (Remember These)
|
||||||
|
|
||||||
|
| Rule | What It Means |
|
||||||
|
|------|---------------|
|
||||||
|
| **Foundation First** | Do it right or say something. 3 fixes = foundation problem. |
|
||||||
|
| **Every if needs else** | Even "impossible" situations need error codes. |
|
||||||
|
| **Security failures LOUD** | Never silent fallback. Always expose errors. |
|
||||||
|
| **Delete dead code** | Permission required. `git log` is rollback. |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## When Stuck
|
||||||
|
|
||||||
|
1. Check [handbook Section V → your domain](CLAVITOR-AGENT-HANDBOOK.md)
|
||||||
|
2. Ask: "Handbook says X, but situation is Y. Conflict?"
|
||||||
|
3. Surface it — don't work around it.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**That's it. 60 seconds to start. Full handbook for deep reference.**
|
||||||
|
|
||||||
|
*Foundation First. No mediocrity. Ever.*
|
||||||
|
|
@ -1,13 +1,10 @@
|
||||||
# clavis-android
|
# clavis-android
|
||||||
|
> **Quickstart (60s):** [../../QUICKSTART.md](../../QUICKSTART.md) — who you are, 4 things to do, critical rules.
|
||||||
> **Required reading before any work**: [CLAVITOR-AGENT-HANDBOOK.md](../../CLAVITOR-AGENT-HANDBOOK.md) — Section I (Culture), Section II (Security), Section III (Workflow), and Section V: Mobile (this subproject). You are **Xiao** (晓).
|
> **Deep reference:** [../../CLAVITOR-AGENT-HANDBOOK.md](../../CLAVITOR-AGENT-HANDBOOK.md) — Section V: clavis-android/ios (your domain).
|
||||||
|
> **You are:** **Xiao** — Run `./scripts/daily-review.sh` every morning. Fix failures first.
|
||||||
Native Android client for Clavitor. Handles platform autofill integration and the credential picker UI.
|
Native Android client for Clavitor. Handles platform autofill integration and the credential picker UI.
|
||||||
|
|
||||||
## Hard rules specific to this subproject
|
## Hard rules specific to this subproject
|
||||||
|
|
||||||
- **Never implement crypto natively.** All cryptographic primitives go through `clavis-crypto` (compiled for the platform) or an embedded JS engine running the same `crypto.js` as the browser/CLI. Two crypto implementations on the same platform is a guaranteed drift.
|
- **Never implement crypto natively.** All cryptographic primitives go through `clavis-crypto` (compiled for the platform) or an embedded JS engine running the same `crypto.js` as the browser/CLI. Two crypto implementations on the same platform is a guaranteed drift.
|
||||||
- **Never persist L2 or L3** to the Android keystore, shared preferences, or any platform storage. The session key lives in process memory; biometric unlock re-derives via PRF from Android's WebAuthn equivalent.
|
- **Never persist L2 or L3** to the Android keystore, shared preferences, or any platform storage. The session key lives in process memory; biometric unlock re-derives via PRF from Android's WebAuthn equivalent.
|
||||||
- **Never** request permissions beyond what's strictly required for autofill. No location, no contacts, no SMS, nothing speculative.
|
- **Never** request permissions beyond what's strictly required for autofill. No location, no contacts, no SMS, nothing speculative.
|
||||||
|
See `CLAVITOR-AGENT-HANDBOOK.md` Section V → Mobile for the full subproject contract.
|
||||||
See `CLAVITOR-AGENT-HANDBOOK.md` Section V → Mobile for the full subproject contract.
|
|
||||||
|
|
@ -1,14 +1,11 @@
|
||||||
# clavis-chrome
|
# clavis-chrome
|
||||||
|
> **Quickstart (60s):** [../../QUICKSTART.md](../../QUICKSTART.md) — who you are, 4 things to do, critical rules.
|
||||||
> **Required reading before any work**: [CLAVITOR-AGENT-HANDBOOK.md](../../CLAVITOR-AGENT-HANDBOOK.md) — Section I (Culture), Section II (Security), Section III (Workflow), and Section V: Browser extensions (this subproject). You are **James**.
|
> **Deep reference:** [../../CLAVITOR-AGENT-HANDBOOK.md](../../CLAVITOR-AGENT-HANDBOOK.md) — Section V: clavis-chrome/firefox/safari (your domain).
|
||||||
|
> **You are:** **James** — Run `./scripts/daily-review.sh` every morning. Fix failures first.
|
||||||
Chrome / Chromium browser extension for Clavitor. Handles form detection, field filling, and the credential picker popup. Manifest V3.
|
Chrome / Chromium browser extension for Clavitor. Handles form detection, field filling, and the credential picker popup. Manifest V3.
|
||||||
|
|
||||||
## Hard rules specific to this subproject
|
## Hard rules specific to this subproject
|
||||||
|
|
||||||
- **Never store L2 or L3** in any extension storage area (`chrome.storage.local`, `chrome.storage.sync`, `chrome.storage.session`). Active session keys live in service-worker memory only and die on service-worker restart.
|
- **Never store L2 or L3** in any extension storage area (`chrome.storage.local`, `chrome.storage.sync`, `chrome.storage.session`). Active session keys live in service-worker memory only and die on service-worker restart.
|
||||||
- **Never reimplement crypto.** Always use `clavis-crypto` / the canonical `crypto.js`. If the extension reimplements crypto, it WILL drift and corrupt fields encrypted by the browser frontend.
|
- **Never reimplement crypto.** Always use `clavis-crypto` / the canonical `crypto.js`. If the extension reimplements crypto, it WILL drift and corrupt fields encrypted by the browser frontend.
|
||||||
- **Always HTTPS** to talk to the vault, even on localhost (the vault serves a self-signed cert in dev). Never plain HTTP.
|
- **Always HTTPS** to talk to the vault, even on localhost (the vault serves a self-signed cert in dev). Never plain HTTP.
|
||||||
- **Permissions are minimal.** If you ask for `<all_urls>` when `https://*/*` would do, fix it. Same for any optional permission.
|
- **Permissions are minimal.** If you ask for `<all_urls>` when `https://*/*` would do, fix it. Same for any optional permission.
|
||||||
|
See `CLAVITOR-AGENT-HANDBOOK.md` Section V → Browser extensions for the full subproject contract.
|
||||||
See `CLAVITOR-AGENT-HANDBOOK.md` Section V → Browser extensions for the full subproject contract.
|
|
||||||
|
|
@ -1,87 +1,55 @@
|
||||||
# clavis-cli
|
# clavis-cli
|
||||||
|
> **Quickstart (60s):** [../../QUICKSTART.md](../../QUICKSTART.md) — who you are, 4 things to do, critical rules.
|
||||||
> **Required reading before any work**: [CLAVITOR-AGENT-HANDBOOK.md](../../CLAVITOR-AGENT-HANDBOOK.md) — Section I (Culture), Section II (Security), Section III (Workflow), and Section V: clavis-cli (this subproject). You are **Charles**. The CLI is its own trust anchor: never bridge to Go for crypto, never expose L2 outside the C/JS boundary.
|
> **Deep reference:** [../../CLAVITOR-AGENT-HANDBOOK.md](../../CLAVITOR-AGENT-HANDBOOK.md) — Section V: clavis-cli (your domain).
|
||||||
|
> **You are:** **Charles** — Run `./scripts/daily-review.sh` every morning. Fix failures first.
|
||||||
Pure C CLI for credential access by AI agents. Talks to a Clavitor vault over HTTPS, decrypts L2 fields locally.
|
Pure C CLI for credential access by AI agents. Talks to a Clavitor vault over HTTPS, decrypts L2 fields locally.
|
||||||
|
|
||||||
## Build
|
## Build
|
||||||
|
|
||||||
```
|
```
|
||||||
make # build for host
|
make # build for host
|
||||||
make strip # strip binary
|
make strip # strip binary
|
||||||
make clean # remove artifacts
|
make clean # remove artifacts
|
||||||
```
|
```
|
||||||
|
|
||||||
Target: `clavitor-cli` binary, <1MB stripped. Requires: C11 compiler, POSIX (Linux/macOS/FreeBSD/Windows).
|
Target: `clavitor-cli` binary, <1MB stripped. Requires: C11 compiler, POSIX (Linux/macOS/FreeBSD/Windows).
|
||||||
|
|
||||||
## Architecture
|
## Architecture
|
||||||
|
|
||||||
- **src/main.c** — CLI entry point, argument parsing, commands (get, list, totp, test-crypto, test-roundtrip, eval, test-totp)
|
- **src/main.c** — CLI entry point, argument parsing, commands (get, list, totp, test-crypto, test-roundtrip, eval, test-totp)
|
||||||
- **src/http.c** — HTTPS client using BearSSL. Loads system CA certs for TLS validation. Supports plain HTTP fallback.
|
- **src/http.c** — HTTPS client using BearSSL. Loads system CA certs for TLS validation. Supports plain HTTP fallback.
|
||||||
- **src/keystore.c** — Config storage at `~/.config/clavitor/config`. AES-128-GCM encrypted + HMAC-SHA256 signed. Inconvenience barrier only — real security is vault-side.
|
- **src/keystore.c** — Config storage at `~/.config/clavitor/config`. AES-128-GCM encrypted + HMAC-SHA256 signed. Inconvenience barrier only — real security is vault-side.
|
||||||
- **src/jsbridge.c** — QuickJS bridge exposing BearSSL crypto primitives to JS. Loads `crypto/crypto.js` and `crypto/totp.js` from `../clavis-crypto/`.
|
- **src/jsbridge.c** — QuickJS bridge exposing BearSSL crypto primitives to JS. Loads `crypto/crypto.js` and `crypto/totp.js` from `../clavis-crypto/`.
|
||||||
- **src/util.c** — Base64 (standard + url-safe), URL encoding.
|
- **src/util.c** — Base64 (standard + url-safe), URL encoding.
|
||||||
|
|
||||||
## Vendored dependencies
|
## Vendored dependencies
|
||||||
|
|
||||||
All in `vendor/`, no system package dependencies:
|
All in `vendor/`, no system package dependencies:
|
||||||
- **BearSSL** — TLS, AES-GCM, HKDF, HMAC, PRNG
|
- **BearSSL** — TLS, AES-GCM, HKDF, HMAC, PRNG
|
||||||
- **QuickJS** — JS runtime for shared crypto logic
|
- **QuickJS** — JS runtime for shared crypto logic
|
||||||
- **cJSON** — JSON parsing
|
- **cJSON** — JSON parsing
|
||||||
|
|
||||||
## Crypto design
|
## Crypto design
|
||||||
|
|
||||||
Three-tier encryption model:
|
Three-tier encryption model:
|
||||||
- **L1** — first 8 bytes of L2 key, used as Bearer auth token
|
- **L1** — first 8 bytes of L2 key, used as Bearer auth token
|
||||||
- **L2** — 16-byte AES-128-GCM key, client-side field encryption/decryption
|
- **L2** — 16-byte AES-128-GCM key, client-side field encryption/decryption
|
||||||
- **L3** — requires hardware key (not handled by CLI)
|
- **L3** — requires hardware key (not handled by CLI)
|
||||||
|
|
||||||
JS crypto in `../clavis-crypto/` is the single source of truth for encrypt/decrypt logic. The C code bridges BearSSL primitives into QuickJS so the same JS runs in CLI and browser.
|
JS crypto in `../clavis-crypto/` is the single source of truth for encrypt/decrypt logic. The C code bridges BearSSL primitives into QuickJS so the same JS runs in CLI and browser.
|
||||||
|
|
||||||
## Token format
|
## Token format
|
||||||
|
|
||||||
`--token` value is a base64url-encoded, AES-GCM encrypted blob containing: `vault_host \0 agent_name \0 l2_key_16_bytes`. Decrypted using HKDF-derived key from seed `clavitor-l2-`.
|
`--token` value is a base64url-encoded, AES-GCM encrypted blob containing: `vault_host \0 agent_name \0 l2_key_16_bytes`. Decrypted using HKDF-derived key from seed `clavitor-l2-`.
|
||||||
|
|
||||||
## Vault communication
|
## Vault communication
|
||||||
|
|
||||||
All API calls go to `https://<host>` (port 443 by default, override with `--port`) with `Authorization: Bearer <L1>` and `X-Agent: <agent_name>` headers.
|
All API calls go to `https://<host>` (port 443 by default, override with `--port`) with `Authorization: Bearer <L1>` and `X-Agent: <agent_name>` headers.
|
||||||
|
|
||||||
Endpoints used: `/api/entries`, `/api/search?q=`, `/api/entries/<id>`, `/api/ext/totp/<id>`.
|
Endpoints used: `/api/entries`, `/api/search?q=`, `/api/entries/<id>`, `/api/ext/totp/<id>`.
|
||||||
|
|
||||||
## ⚒️ Foundation First — No Mediocrity. Ever.
|
## ⚒️ Foundation First — No Mediocrity. Ever.
|
||||||
|
|
||||||
The rule is simple: do it right, or say something.
|
The rule is simple: do it right, or say something.
|
||||||
|
|
||||||
Johan is an architect. Architects do not patch cracks in a bad foundation — they rebuild. Every agent on this team operates the same way.
|
Johan is an architect. Architects do not patch cracks in a bad foundation — they rebuild. Every agent on this team operates the same way.
|
||||||
|
|
||||||
### What this means in practice
|
### What this means in practice
|
||||||
|
|
||||||
If you need three fixes for one problem, stop. Something fundamental is wrong. Name it, surface it — we fix that, not the symptom.
|
If you need three fixes for one problem, stop. Something fundamental is wrong. Name it, surface it — we fix that, not the symptom.
|
||||||
|
|
||||||
If the code is spaghetti, say so. Do not add another workaround. The workaround is the problem now.
|
If the code is spaghetti, say so. Do not add another workaround. The workaround is the problem now.
|
||||||
|
|
||||||
Quick fixes are not fixes. A "temporary" hack that ships is permanent. If it is not the right solution, it is the wrong solution.
|
Quick fixes are not fixes. A "temporary" hack that ships is permanent. If it is not the right solution, it is the wrong solution.
|
||||||
|
|
||||||
Foundation > speed. A solid base makes everything downstream easy. A shaky base makes everything downstream a nightmare. We build bases.
|
Foundation > speed. A solid base makes everything downstream easy. A shaky base makes everything downstream a nightmare. We build bases.
|
||||||
|
|
||||||
### The restart rule
|
### The restart rule
|
||||||
|
|
||||||
When the foundation is wrong: start over. Not "refactor slightly." Not "add an abstraction layer on top." Start over. This applies to code, infrastructure, design, encryption schemes, and written work alike.
|
When the foundation is wrong: start over. Not "refactor slightly." Not "add an abstraction layer on top." Start over. This applies to code, infrastructure, design, encryption schemes, and written work alike.
|
||||||
|
|
||||||
### Q&D is research, not output
|
### Q&D is research, not output
|
||||||
|
|
||||||
Exploratory/throwaway work has its place — but it stays in research. Nothing Q&D ships. Nothing Q&D becomes the production path. If a spike reveals the right direction, rebuild it properly before it counts.
|
Exploratory/throwaway work has its place — but it stays in research. Nothing Q&D ships. Nothing Q&D becomes the production path. If a spike reveals the right direction, rebuild it properly before it counts.
|
||||||
|
|
||||||
### When you hit a bad foundation
|
### When you hit a bad foundation
|
||||||
|
|
||||||
Call it out. Do not work around it. Bad foundations are not your fault — but silently building on them is. Surface the problem, we work on it together.
|
Call it out. Do not work around it. Bad foundations are not your fault — but silently building on them is. Surface the problem, we work on it together.
|
||||||
|
|
||||||
The bar is high. The support is real.
|
The bar is high. The support is real.
|
||||||
|
|
||||||
## Testing
|
## Testing
|
||||||
|
|
||||||
```
|
```
|
||||||
./clavitor-cli test-crypto # BearSSL + JS crypto self-tests
|
./clavitor-cli test-crypto # BearSSL + JS crypto self-tests
|
||||||
./clavitor-cli test-totp <seed> # TOTP generation from base32 seed
|
./clavitor-cli test-totp <seed> # TOTP generation from base32 seed
|
||||||
./clavitor-cli test-roundtrip # runs crypto/test_crypto.js
|
./clavitor-cli test-roundtrip # runs crypto/test_crypto.js
|
||||||
```
|
```
|
||||||
|
|
@ -1,18 +1,13 @@
|
||||||
# clavis-crypto
|
# clavis-crypto
|
||||||
|
> **Quickstart (60s):** [../../QUICKSTART.md](../../QUICKSTART.md) — who you are, 4 things to do, critical rules.
|
||||||
> **Required reading before any work**: [CLAVITOR-AGENT-HANDBOOK.md](../../CLAVITOR-AGENT-HANDBOOK.md) — Section I (Culture), Section II (Security), Section III (Workflow), and Section V: clavis-crypto (this subproject). You are **Maria**.
|
> **Deep reference:** [../../CLAVITOR-AGENT-HANDBOOK.md](../../CLAVITOR-AGENT-HANDBOOK.md) — Section V: clavis-crypto (your domain).
|
||||||
|
> **You are:** **Maria** — Run `./scripts/daily-review.sh` every morning. Fix failures first.
|
||||||
Shared cryptographic primitives used by every Clavitor client: browser frontend, CLI, browser extensions (Chrome/Firefox/Safari), mobile clients. The single source of truth for `encrypt_field`, `decrypt_field`, HKDF derivation, AES-GCM, and any other primitive that crosses target boundaries.
|
Shared cryptographic primitives used by every Clavitor client: browser frontend, CLI, browser extensions (Chrome/Firefox/Safari), mobile clients. The single source of truth for `encrypt_field`, `decrypt_field`, HKDF derivation, AES-GCM, and any other primitive that crosses target boundaries.
|
||||||
|
|
||||||
## Hard rules specific to this subproject
|
## Hard rules specific to this subproject
|
||||||
|
|
||||||
- **Never diverge between targets.** If a primitive behaves differently in WebCrypto (browser/extensions) vs BearSSL (C CLI) vs platform-native (mobile), the bug is in `clavis-crypto` and it gets fixed here before any caller compensates.
|
- **Never diverge between targets.** If a primitive behaves differently in WebCrypto (browser/extensions) vs BearSSL (C CLI) vs platform-native (mobile), the bug is in `clavis-crypto` and it gets fixed here before any caller compensates.
|
||||||
- **Bit-identical outputs are mandatory.** A field encrypted by the browser MUST decrypt cleanly in the CLI, and vice versa. This is verified by parity tests — if you change a primitive, run the parity tests against every target.
|
- **Bit-identical outputs are mandatory.** A field encrypted by the browser MUST decrypt cleanly in the CLI, and vice versa. This is verified by parity tests — if you change a primitive, run the parity tests against every target.
|
||||||
- **No per-target shortcuts.** If a target's stdlib offers a faster path (e.g., a hardware-accelerated AES on iOS), use it ONLY if the parity tests confirm the output matches every other target byte-for-byte.
|
- **No per-target shortcuts.** If a target's stdlib offers a faster path (e.g., a hardware-accelerated AES on iOS), use it ONLY if the parity tests confirm the output matches every other target byte-for-byte.
|
||||||
- **No silent fallback** when a primitive is unavailable. If a target lacks the required crypto support, fail loudly at startup, not silently at first use.
|
- **No silent fallback** when a primitive is unavailable. If a target lacks the required crypto support, fail loudly at startup, not silently at first use.
|
||||||
|
|
||||||
## The daily check
|
## The daily check
|
||||||
|
|
||||||
Section III → D2 of `CLAVITOR-AGENT-HANDBOOK.md` enforces this with a `diff` between the browser and CLI `crypto.js` copies. Any divergence is a foundation alert.
|
Section III → D2 of `CLAVITOR-AGENT-HANDBOOK.md` enforces this with a `diff` between the browser and CLI `crypto.js` copies. Any divergence is a foundation alert.
|
||||||
|
See `CLAVITOR-AGENT-HANDBOOK.md` Section V → clavis-crypto for the full subproject contract.
|
||||||
See `CLAVITOR-AGENT-HANDBOOK.md` Section V → clavis-crypto for the full subproject contract.
|
|
||||||
|
|
@ -1,14 +1,11 @@
|
||||||
# clavis-firefox
|
# clavis-firefox
|
||||||
|
> **Quickstart (60s):** [../../QUICKSTART.md](../../QUICKSTART.md) — who you are, 4 things to do, critical rules.
|
||||||
> **Required reading before any work**: [CLAVITOR-AGENT-HANDBOOK.md](../../CLAVITOR-AGENT-HANDBOOK.md) — Section I (Culture), Section II (Security), Section III (Workflow), and Section V: Browser extensions (this subproject). You are **James**.
|
> **Deep reference:** [../../CLAVITOR-AGENT-HANDBOOK.md](../../CLAVITOR-AGENT-HANDBOOK.md) — Section V: clavis-chrome/firefox/safari (your domain).
|
||||||
|
> **You are:** **James** — Run `./scripts/daily-review.sh` every morning. Fix failures first.
|
||||||
Firefox browser extension for Clavitor. Handles form detection, field filling, and the credential picker popup.
|
Firefox browser extension for Clavitor. Handles form detection, field filling, and the credential picker popup.
|
||||||
|
|
||||||
## Hard rules specific to this subproject
|
## Hard rules specific to this subproject
|
||||||
|
|
||||||
- **Never store L2 or L3** in any extension storage area (`browser.storage.local`, `browser.storage.sync`, `browser.storage.session`). Active session keys live in background-script memory only and die on extension restart.
|
- **Never store L2 or L3** in any extension storage area (`browser.storage.local`, `browser.storage.sync`, `browser.storage.session`). Active session keys live in background-script memory only and die on extension restart.
|
||||||
- **Never reimplement crypto.** Always use `clavis-crypto` / the canonical `crypto.js`. If the extension reimplements crypto, it WILL drift and corrupt fields encrypted by the browser frontend or the Chrome extension.
|
- **Never reimplement crypto.** Always use `clavis-crypto` / the canonical `crypto.js`. If the extension reimplements crypto, it WILL drift and corrupt fields encrypted by the browser frontend or the Chrome extension.
|
||||||
- **Always HTTPS** to talk to the vault, even on localhost (self-signed cert in dev). Never plain HTTP.
|
- **Always HTTPS** to talk to the vault, even on localhost (self-signed cert in dev). Never plain HTTP.
|
||||||
- **Permissions are minimal.** Match the Chrome extension's permission set as closely as possible — if it needs more, justify why in a comment.
|
- **Permissions are minimal.** Match the Chrome extension's permission set as closely as possible — if it needs more, justify why in a comment.
|
||||||
|
See `CLAVITOR-AGENT-HANDBOOK.md` Section V → Browser extensions for the full subproject contract.
|
||||||
See `CLAVITOR-AGENT-HANDBOOK.md` Section V → Browser extensions for the full subproject contract.
|
|
||||||
|
|
@ -1,13 +1,10 @@
|
||||||
# clavis-ios
|
# clavis-ios
|
||||||
|
> **Quickstart (60s):** [../../QUICKSTART.md](../../QUICKSTART.md) — who you are, 4 things to do, critical rules.
|
||||||
> **Required reading before any work**: [CLAVITOR-AGENT-HANDBOOK.md](../../CLAVITOR-AGENT-HANDBOOK.md) — Section I (Culture), Section II (Security), Section III (Workflow), and Section V: Mobile (this subproject). You are **Xiao** (晓).
|
> **Deep reference:** [../../CLAVITOR-AGENT-HANDBOOK.md](../../CLAVITOR-AGENT-HANDBOOK.md) — Section V: clavis-android/ios (your domain).
|
||||||
|
> **You are:** **Xiao** — Run `./scripts/daily-review.sh` every morning. Fix failures first.
|
||||||
Native iOS client for Clavitor. Handles platform autofill integration and the credential picker UI.
|
Native iOS client for Clavitor. Handles platform autofill integration and the credential picker UI.
|
||||||
|
|
||||||
## Hard rules specific to this subproject
|
## Hard rules specific to this subproject
|
||||||
|
|
||||||
- **Never implement crypto natively.** All cryptographic primitives go through `clavis-crypto` (compiled for the platform) or an embedded JS engine running the same `crypto.js` as the browser/CLI. Two crypto implementations on the same platform is a guaranteed drift.
|
- **Never implement crypto natively.** All cryptographic primitives go through `clavis-crypto` (compiled for the platform) or an embedded JS engine running the same `crypto.js` as the browser/CLI. Two crypto implementations on the same platform is a guaranteed drift.
|
||||||
- **Never persist L2 or L3** to the iOS keychain or any platform storage. The session key lives in process memory; biometric unlock re-derives via PRF from iOS's WebAuthn / passkey APIs.
|
- **Never persist L2 or L3** to the iOS keychain or any platform storage. The session key lives in process memory; biometric unlock re-derives via PRF from iOS's WebAuthn / passkey APIs.
|
||||||
- **Never** request entitlements beyond what's strictly required for autofill credentials.
|
- **Never** request entitlements beyond what's strictly required for autofill credentials.
|
||||||
|
See `CLAVITOR-AGENT-HANDBOOK.md` Section V → Mobile for the full subproject contract.
|
||||||
See `CLAVITOR-AGENT-HANDBOOK.md` Section V → Mobile for the full subproject contract.
|
|
||||||
|
|
@ -1,15 +1,12 @@
|
||||||
# clavis-safari
|
# clavis-safari
|
||||||
|
> **Quickstart (60s):** [../../QUICKSTART.md](../../QUICKSTART.md) — who you are, 4 things to do, critical rules.
|
||||||
> **Required reading before any work**: [CLAVITOR-AGENT-HANDBOOK.md](../../CLAVITOR-AGENT-HANDBOOK.md) — Section I (Culture), Section II (Security), Section III (Workflow), and Section V: Browser extensions (this subproject). You are **James**.
|
> **Deep reference:** [../../CLAVITOR-AGENT-HANDBOOK.md](../../CLAVITOR-AGENT-HANDBOOK.md) — Section V: clavis-chrome/firefox/safari (your domain).
|
||||||
|
> **You are:** **James** — Run `./scripts/daily-review.sh` every morning. Fix failures first.
|
||||||
Safari browser extension for Clavitor. Handles form detection, field filling, and the credential picker popup. Distributed via the Safari Extensions infrastructure (App Store + Xcode-built container).
|
Safari browser extension for Clavitor. Handles form detection, field filling, and the credential picker popup. Distributed via the Safari Extensions infrastructure (App Store + Xcode-built container).
|
||||||
|
|
||||||
## Hard rules specific to this subproject
|
## Hard rules specific to this subproject
|
||||||
|
|
||||||
- **Never store L2 or L3** in any extension storage area or the iCloud Keychain. Active session keys live in process memory only and die on extension restart.
|
- **Never store L2 or L3** in any extension storage area or the iCloud Keychain. Active session keys live in process memory only and die on extension restart.
|
||||||
- **Never reimplement crypto.** Always use `clavis-crypto` / the canonical `crypto.js`. If the extension reimplements crypto, it WILL drift and corrupt fields encrypted by other clients.
|
- **Never reimplement crypto.** Always use `clavis-crypto` / the canonical `crypto.js`. If the extension reimplements crypto, it WILL drift and corrupt fields encrypted by other clients.
|
||||||
- **Always HTTPS** to talk to the vault. Never plain HTTP.
|
- **Always HTTPS** to talk to the vault. Never plain HTTP.
|
||||||
- **Container app exists only to host the extension.** Do not add unrelated functionality to the container — that's a Mac app and it's not what we're shipping.
|
- **Container app exists only to host the extension.** Do not add unrelated functionality to the container — that's a Mac app and it's not what we're shipping.
|
||||||
- **Permissions are minimal.** Match the Chrome/Firefox extension permission set; if Safari requires something extra, justify it in a comment with the Safari API doc reference.
|
- **Permissions are minimal.** Match the Chrome/Firefox extension permission set; if Safari requires something extra, justify it in a comment with the Safari API doc reference.
|
||||||
|
See `CLAVITOR-AGENT-HANDBOOK.md` Section V → Browser extensions for the full subproject contract.
|
||||||
See `CLAVITOR-AGENT-HANDBOOK.md` Section V → Browser extensions for the full subproject contract.
|
|
||||||
|
|
@ -1,35 +1,23 @@
|
||||||
# clavis-telemetry
|
# clavis-telemetry
|
||||||
|
> **Quickstart (60s):** [../../QUICKSTART.md](../../QUICKSTART.md) — who you are, 4 things to do, critical rules.
|
||||||
> **Required reading before any work**: [CLAVITOR-AGENT-HANDBOOK.md](../../CLAVITOR-AGENT-HANDBOOK.md) — Section I (Culture), Section II (Security), Section III (Workflow), and Section V: clavis-telemetry (this subproject). You are **Hans**.
|
> **Deep reference:** [../../CLAVITOR-AGENT-HANDBOOK.md](../../CLAVITOR-AGENT-HANDBOOK.md) — Section V: clavis-telemetry (your domain).
|
||||||
|
> **You are:** **Hans** — Run `./scripts/daily-review.sh` every morning. Fix failures first.
|
||||||
Operator telemetry: heartbeat metrics from POPs to central. CPU, memory, disk, vault count, request rates. Operational signals only — never user data.
|
Operator telemetry: heartbeat metrics from POPs to central. CPU, memory, disk, vault count, request rates. Operational signals only — never user data.
|
||||||
|
|
||||||
## Hard rules specific to this subproject
|
## Hard rules specific to this subproject
|
||||||
|
|
||||||
- **Never send vault content.** Telemetry is operational, not data. No entry titles, no field values, no credential identifiers, no audit log entries that contain user information.
|
- **Never send vault content.** Telemetry is operational, not data. No entry titles, no field values, no credential identifiers, no audit log entries that contain user information.
|
||||||
- **Never send raw user IP addresses.** Aggregate counts (e.g., `unique_ips_24h: 472`) are fine; raw IPs are not.
|
- **Never send raw user IP addresses.** Aggregate counts (e.g., `unique_ips_24h: 472`) are fine; raw IPs are not.
|
||||||
- **Commercial-only by default.** Community edition is offline-by-default. Telemetry is opt-in for community installs and enforced-on for commercial POPs. Build tags must reflect this — community binaries should not even contain the telemetry code path.
|
- **Commercial-only by default.** Community edition is offline-by-default. Telemetry is opt-in for community installs and enforced-on for commercial POPs. Build tags must reflect this — community binaries should not even contain the telemetry code path.
|
||||||
- **No phone-home for crashes.** If you ever want crash reporting, talk to Johan first. Auto-uploaded stack traces have leaked credentials in other products and we will not repeat that mistake.
|
- **No phone-home for crashes.** If you ever want crash reporting, talk to Johan first. Auto-uploaded stack traces have leaked credentials in other products and we will not repeat that mistake.
|
||||||
|
|
||||||
See `CLAVITOR-AGENT-HANDBOOK.md` Section V → clavis-telemetry for the full subproject contract.
|
See `CLAVITOR-AGENT-HANDBOOK.md` Section V → clavis-telemetry for the full subproject contract.
|
||||||
|
|
||||||
## Operations
|
## Operations
|
||||||
|
|
||||||
### Log Retention
|
### Log Retention
|
||||||
|
|
||||||
Tarpit logs contain scanner IPs for security analysis. Rotate/delete per your organization's retention policy (recommended: 30 days).
|
Tarpit logs contain scanner IPs for security analysis. Rotate/delete per your organization's retention policy (recommended: 30 days).
|
||||||
|
|
||||||
### External Alerting (Optional)
|
### External Alerting (Optional)
|
||||||
|
|
||||||
Outage alerts can be sent to ntfy. Configure via environment variables:
|
Outage alerts can be sent to ntfy. Configure via environment variables:
|
||||||
- `NTFY_ALERT_URL` - The ntfy endpoint (e.g., `http://127.0.0.1:2586/clavitor-alerts`)
|
- `NTFY_ALERT_URL` - The ntfy endpoint (e.g., `http://127.0.0.1:2586/clavitor-alerts`)
|
||||||
- `NTFY_ALERT_TOKEN` - Bearer token for authentication
|
- `NTFY_ALERT_TOKEN` - Bearer token for authentication
|
||||||
|
|
||||||
If unset, outage logging continues without external notification.
|
If unset, outage logging continues without external notification.
|
||||||
|
|
||||||
### Kuma Monitoring (Optional)
|
### Kuma Monitoring (Optional)
|
||||||
|
|
||||||
Health push to Kuma can be configured via:
|
Health push to Kuma can be configured via:
|
||||||
- `KUMA_PUSH_URL` - Kuma push endpoint
|
- `KUMA_PUSH_URL` - Kuma push endpoint
|
||||||
|
If unset, Kuma push is disabled.
|
||||||
If unset, Kuma push is disabled.
|
|
||||||
|
|
@ -1,43 +1,25 @@
|
||||||
# Clavis Vault — CLAUDE.md
|
# Clavis Vault — CLAUDE.md
|
||||||
|
> **Quickstart (60s):** [../../QUICKSTART.md](../../QUICKSTART.md) — who you are, 4 things to do, critical rules.
|
||||||
> **Required reading before any work**: [CLAVITOR-AGENT-HANDBOOK.md](../../CLAVITOR-AGENT-HANDBOOK.md) — Section I (Culture), Section II (Security), Section III (Workflow), and Section V: clavis-vault (this subproject). You are **Sarah**. Run the Section III → Daily review checklist every morning. Drift gets fixed before any new feature work.
|
> **Deep reference:** [../../CLAVITOR-AGENT-HANDBOOK.md](../../CLAVITOR-AGENT-HANDBOOK.md) — Section V: clavis-vault (your domain).
|
||||||
|
> **You are:** **Sarah** — Run `./scripts/daily-review.sh` every morning. Fix failures first.
|
||||||
## Foundation First — No Mediocrity. Ever.
|
## Foundation First — No Mediocrity. Ever.
|
||||||
|
|
||||||
The rule is simple: do it right, or say something.
|
The rule is simple: do it right, or say something.
|
||||||
|
|
||||||
Johan is an architect. Architects do not patch cracks in a bad foundation — they rebuild. Every agent on this team operates the same way.
|
Johan is an architect. Architects do not patch cracks in a bad foundation — they rebuild. Every agent on this team operates the same way.
|
||||||
|
|
||||||
### What this means in practice
|
### What this means in practice
|
||||||
|
|
||||||
If you need three fixes for one problem, stop. Something fundamental is wrong. Name it, surface it — we fix that, not the symptom.
|
If you need three fixes for one problem, stop. Something fundamental is wrong. Name it, surface it — we fix that, not the symptom.
|
||||||
|
|
||||||
If the code is spaghetti, say so. Do not add another workaround. The workaround is the problem now.
|
If the code is spaghetti, say so. Do not add another workaround. The workaround is the problem now.
|
||||||
|
|
||||||
Quick fixes are not fixes. A "temporary" hack that ships is permanent. If it is not the right solution, it is the wrong solution.
|
Quick fixes are not fixes. A "temporary" hack that ships is permanent. If it is not the right solution, it is the wrong solution.
|
||||||
|
|
||||||
Foundation > speed. A solid base makes everything downstream easy. A shaky base makes everything downstream a nightmare. We build bases.
|
Foundation > speed. A solid base makes everything downstream easy. A shaky base makes everything downstream a nightmare. We build bases.
|
||||||
|
|
||||||
### The restart rule
|
### The restart rule
|
||||||
|
|
||||||
When the foundation is wrong: start over. Not "refactor slightly." Not "add an abstraction layer on top." Start over. This applies to code, infrastructure, design, encryption schemes, and written work alike.
|
When the foundation is wrong: start over. Not "refactor slightly." Not "add an abstraction layer on top." Start over. This applies to code, infrastructure, design, encryption schemes, and written work alike.
|
||||||
|
|
||||||
### Q&D is research, not output
|
### Q&D is research, not output
|
||||||
|
|
||||||
Exploratory/throwaway work has its place — but it stays in research. Nothing Q&D ships. Nothing Q&D becomes the production path. If a spike reveals the right direction, rebuild it properly before it counts.
|
Exploratory/throwaway work has its place — but it stays in research. Nothing Q&D ships. Nothing Q&D becomes the production path. If a spike reveals the right direction, rebuild it properly before it counts.
|
||||||
|
|
||||||
### When you hit a bad foundation
|
### When you hit a bad foundation
|
||||||
|
|
||||||
Call it out. Do not work around it. Bad foundations are not your fault — but silently building on them is. Surface the problem, we work on it together.
|
Call it out. Do not work around it. Bad foundations are not your fault — but silently building on them is. Surface the problem, we work on it together.
|
||||||
|
|
||||||
The bar is high. The support is real.
|
The bar is high. The support is real.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Security Failures — NEVER HIDE THEM
|
## Security Failures — NEVER HIDE THEM
|
||||||
|
|
||||||
**The cardinal rule:** If decryption/verification fails, expose the failure. Never fall back to plaintext. Never silently continue.
|
**The cardinal rule:** If decryption/verification fails, expose the failure. Never fall back to plaintext. Never silently continue.
|
||||||
|
|
||||||
### WRONG — Silent fallback (fireable offense)
|
### WRONG — Silent fallback (fireable offense)
|
||||||
```javascript
|
```javascript
|
||||||
try {
|
try {
|
||||||
|
|
@ -46,7 +28,6 @@ try {
|
||||||
decrypted = plaintext; // NEVER DO THIS
|
decrypted = plaintext; // NEVER DO THIS
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### CORRECT — Visible failure
|
### CORRECT — Visible failure
|
||||||
```javascript
|
```javascript
|
||||||
try {
|
try {
|
||||||
|
|
@ -55,24 +36,17 @@ try {
|
||||||
decrypted = '[decryption failed]'; // User sees the failure
|
decrypted = '[decryption failed]'; // User sees the failure
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
This applies to:
|
This applies to:
|
||||||
- Encryption/decryption errors
|
- Encryption/decryption errors
|
||||||
- Signature verification failures
|
- Signature verification failures
|
||||||
- Authentication failures
|
- Authentication failures
|
||||||
- Tampering detection
|
- Tampering detection
|
||||||
- Any security-critical operation
|
- Any security-critical operation
|
||||||
|
|
||||||
**Security failures must be noisy, visible, and blocking — never silent, hidden, or permissive.**
|
**Security failures must be noisy, visible, and blocking — never silent, hidden, or permissive.**
|
||||||
|
|
||||||
See `SECURITY.md` for full principles.
|
See `SECURITY.md` for full principles.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Edition System (Community vs Commercial)
|
## Edition System (Community vs Commercial)
|
||||||
|
|
||||||
Clavitor Vault has two editions with build-time separation:
|
Clavitor Vault has two editions with build-time separation:
|
||||||
|
|
||||||
### Community Edition (Default)
|
### Community Edition (Default)
|
||||||
```bash
|
```bash
|
||||||
go build -o clavitor ./cmd/clavitor/
|
go build -o clavitor ./cmd/clavitor/
|
||||||
|
|
@ -81,7 +55,6 @@ go build -o clavitor ./cmd/clavitor/
|
||||||
- Local logging only
|
- Local logging only
|
||||||
- Self-hosted
|
- Self-hosted
|
||||||
- Elastic License 2.0
|
- Elastic License 2.0
|
||||||
|
|
||||||
### Commercial Edition
|
### Commercial Edition
|
||||||
```bash
|
```bash
|
||||||
go build -tags commercial -o clavitor ./cmd/clavitor/
|
go build -tags commercial -o clavitor ./cmd/clavitor/
|
||||||
|
|
@ -90,27 +63,18 @@ go build -tags commercial -o clavitor ./cmd/clavitor/
|
||||||
- Operator alerts POST to `/v1/alerts`
|
- Operator alerts POST to `/v1/alerts`
|
||||||
- Multi-POP management
|
- Multi-POP management
|
||||||
- Commercial license
|
- Commercial license
|
||||||
|
|
||||||
### Using the Edition Package
|
### Using the Edition Package
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import "github.com/johanj/clavitor/edition"
|
import "github.com/johanj/clavitor/edition"
|
||||||
|
|
||||||
// Send operator alerts (works in both editions)
|
// Send operator alerts (works in both editions)
|
||||||
edition.Current.AlertOperator(ctx, "auth_error", "message", details)
|
edition.Current.AlertOperator(ctx, "auth_error", "message", details)
|
||||||
|
|
||||||
// Check edition
|
// Check edition
|
||||||
currentEdition := edition.Current.Name() // "community" or "commercial"
|
currentEdition := edition.Current.Name() // "community" or "commercial"
|
||||||
```
|
```
|
||||||
|
|
||||||
See `edition/CLAUDE.md` for full documentation.
|
See `edition/CLAUDE.md` for full documentation.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Clavitor Vault v2 — Current State & Testing
|
## Clavitor Vault v2 — Current State & Testing
|
||||||
|
|
||||||
### What we built this session
|
### What we built this session
|
||||||
|
|
||||||
#### 1. Domain classification for import scopes
|
#### 1. Domain classification for import scopes
|
||||||
- Import page (`cmd/clavitor/web/import.html`) parses 14+ password manager formats client-side
|
- Import page (`cmd/clavitor/web/import.html`) parses 14+ password manager formats client-side
|
||||||
- Unique domains are extracted (eTLD+1) and sent to `https://clavitor.ai/classify`
|
- Unique domains are extracted (eTLD+1) and sent to `https://clavitor.ai/classify`
|
||||||
|
|
@ -119,7 +83,6 @@ See `edition/CLAUDE.md` for full documentation.
|
||||||
- Domains with no URL get scope "unclassified" (not "misc"). "misc" = LLM tried and failed
|
- Domains with no URL get scope "unclassified" (not "misc"). "misc" = LLM tried and failed
|
||||||
- Domains are sent in chunks of 200 to stay within token limits
|
- Domains are sent in chunks of 200 to stay within token limits
|
||||||
- Classification is opt-in: user sees consent dialog with Yes/Skip/Cancel
|
- Classification is opt-in: user sees consent dialog with Yes/Skip/Cancel
|
||||||
|
|
||||||
#### 2. Import flow UX
|
#### 2. Import flow UX
|
||||||
- Drop file → parse → hide file step → consent dialog (Yes/Skip/Cancel)
|
- Drop file → parse → hide file step → consent dialog (Yes/Skip/Cancel)
|
||||||
- Cancel returns to file step
|
- Cancel returns to file step
|
||||||
|
|
@ -129,7 +92,6 @@ See `edition/CLAUDE.md` for full documentation.
|
||||||
- Black entry icons (LGN/CARD/NOTE) with white text — on brand
|
- Black entry icons (LGN/CARD/NOTE) with white text — on brand
|
||||||
- Global black checkboxes (`accent-color: var(--text)`)
|
- Global black checkboxes (`accent-color: var(--text)`)
|
||||||
- Unified CSS classes: `.item-row`, `.item-icon`, `.item-list` (replacing import-specific classes)
|
- Unified CSS classes: `.item-row`, `.item-icon`, `.item-list` (replacing import-specific classes)
|
||||||
|
|
||||||
#### 3. Import filtering visibility (NEW)
|
#### 3. Import filtering visibility (NEW)
|
||||||
- Import parsers now track what gets filtered and why
|
- Import parsers now track what gets filtered and why
|
||||||
- `importers-parsers.js` has `_importReport` object that records: `rawCount`, `filtered[]`, `finalCount`
|
- `importers-parsers.js` has `_importReport` object that records: `rawCount`, `filtered[]`, `finalCount`
|
||||||
|
|
@ -138,7 +100,6 @@ See `edition/CLAUDE.md` for full documentation.
|
||||||
- Filter badge with tooltip showing breakdown: `"Filtered: 150 duplicate, 97 alias, 12 trashed"`
|
- Filter badge with tooltip showing breakdown: `"Filtered: 150 duplicate, 97 alias, 12 trashed"`
|
||||||
- Clicking the filtered badge shows detailed list of what was skipped
|
- Clicking the filtered badge shows detailed list of what was skipped
|
||||||
- **Why**: User saw 1073 during import but only 818 in vault. Now they can see the ~250 records were: duplicates (older versions), email aliases, and trashed items.
|
- **Why**: User saw 1073 during import but only 818 in vault. Now they can see the ~250 records were: duplicates (older versions), email aliases, and trashed items.
|
||||||
|
|
||||||
#### 4. Credential Alternates System (NEW)
|
#### 4. Credential Alternates System (NEW)
|
||||||
- **Problem**: Chrome/Firefox imports don't have modification dates, so we can't tell which password is newer. Same site+user from different sources would overwrite each other.
|
- **Problem**: Chrome/Firefox imports don't have modification dates, so we can't tell which password is newer. Same site+user from different sources would overwrite each other.
|
||||||
- **Solution**: Multiple passwords per site+user are now stored as "alternates" instead of overwriting.
|
- **Solution**: Multiple passwords per site+user are now stored as "alternates" instead of overwriting.
|
||||||
|
|
@ -151,7 +112,6 @@ See `edition/CLAUDE.md` for full documentation.
|
||||||
- `GET /ext/match?url=...` now returns alternates array sorted by verified_at (verified first)
|
- `GET /ext/match?url=...` now returns alternates array sorted by verified_at (verified first)
|
||||||
- **CLI Protocol**: When multiple passwords for same site+user, try verified ones first. On success, call `/worked` endpoint. Backend marks winner as verified and links alternates to it.
|
- **CLI Protocol**: When multiple passwords for same site+user, try verified ones first. On success, call `/worked` endpoint. Backend marks winner as verified and links alternates to it.
|
||||||
- **Import UI**: Shows `"Done — 50 imported, 12 alternates"` so user knows some were stored as alternates.
|
- **Import UI**: Shows `"Done — 50 imported, 12 alternates"` so user knows some were stored as alternates.
|
||||||
|
|
||||||
#### 5. Security hardening (IN PROGRESS — needs testing)
|
#### 5. Security hardening (IN PROGRESS — needs testing)
|
||||||
- **List endpoint stripped**: GET /api/entries now always returns metadata only (title, type, scopes, entry_id). No data blobs, no ?meta=1 toggle. Full entry data only via GET /api/entries/{id} with scope enforcement.
|
- **List endpoint stripped**: GET /api/entries now always returns metadata only (title, type, scopes, entry_id). No data blobs, no ?meta=1 toggle. Full entry data only via GET /api/entries/{id} with scope enforcement.
|
||||||
- **Agent system type guard**: Agents cannot create/update entries with type=agent or type=scope. Enforced on CreateEntry, CreateEntryBatch, UpsertEntry, UpdateEntry.
|
- **Agent system type guard**: Agents cannot create/update entries with type=agent or type=scope. Enforced on CreateEntry, CreateEntryBatch, UpsertEntry, UpdateEntry.
|
||||||
|
|
@ -159,11 +119,8 @@ See `edition/CLAUDE.md` for full documentation.
|
||||||
- **Per-agent IP whitelist**: Stored in agent entry (L1-encrypted). Empty on creation → filled with IP from first contact → enforced on every subsequent request. Supports CIDRs (10.0.0.0/16), exact IPs, and FQDNs (home.smith.family), comma-separated.
|
- **Per-agent IP whitelist**: Stored in agent entry (L1-encrypted). Empty on creation → filled with IP from first contact → enforced on every subsequent request. Supports CIDRs (10.0.0.0/16), exact IPs, and FQDNs (home.smith.family), comma-separated.
|
||||||
- **Per-agent rate limiting**: Configurable requests/minute per agent ID (not per IP). Stored in agent entry.
|
- **Per-agent rate limiting**: Configurable requests/minute per agent ID (not per IP). Stored in agent entry.
|
||||||
- **Admin operations require PRF tap**: Agent CRUD and scope updates require a fresh WebAuthn assertion. Flow: POST /auth/admin/begin → PRF tap → POST /auth/admin/complete → one-time admin token in X-Admin-Token header → pass to admin endpoint. Token is single-use, 5-minute expiry.
|
- **Admin operations require PRF tap**: Agent CRUD and scope updates require a fresh WebAuthn assertion. Flow: POST /auth/admin/begin → PRF tap → POST /auth/admin/complete → one-time admin token in X-Admin-Token header → pass to admin endpoint. Token is single-use, 5-minute expiry.
|
||||||
|
|
||||||
### What is semi-done / needs testing
|
### What is semi-done / needs testing
|
||||||
|
|
||||||
The security hardening code compiles and the vault runs, but none of it has been tested with actual agent tokens or WebAuthn assertions yet. Specifically:
|
The security hardening code compiles and the vault runs, but none of it has been tested with actual agent tokens or WebAuthn assertions yet. Specifically:
|
||||||
|
|
||||||
1. **IP whitelist first-contact fill**: ✅ Fixed - DB errors now return 500
|
1. **IP whitelist first-contact fill**: ✅ Fixed - DB errors now return 500
|
||||||
2. **IP whitelist enforcement**: Does CIDR matching work? FQDN resolution? Comma-separated lists? FQDN now has 5-min cache
|
2. **IP whitelist enforcement**: Does CIDR matching work? FQDN resolution? Comma-separated lists? FQDN now has 5-min cache
|
||||||
3. **Per-agent rate limiter**: Does it correctly track per agent ID and reset per minute?
|
3. **Per-agent rate limiter**: Does it correctly track per agent ID and reset per minute?
|
||||||
|
|
@ -171,30 +128,22 @@ The security hardening code compiles and the vault runs, but none of it has been
|
||||||
5. **System type guards**: ✅ Fixed - Agents blocked entirely from batch import; returns 403 on forbidden types
|
5. **System type guards**: ✅ Fixed - Agents blocked entirely from batch import; returns 403 on forbidden types
|
||||||
6. **L3 field preservation**: ✅ Fixed - Agents cannot overwrite L3 fields in batch or upsert
|
6. **L3 field preservation**: ✅ Fixed - Agents cannot overwrite L3 fields in batch or upsert
|
||||||
7. **List endpoint**: Verify no data blobs leak. Check browser console: entries[0] should have no data or fields property.
|
7. **List endpoint**: Verify no data blobs leak. Check browser console: entries[0] should have no data or fields property.
|
||||||
|
|
||||||
### Known Issues (Accepted)
|
### Known Issues (Accepted)
|
||||||
|
|
||||||
**IP Whitelist Race Condition**: There is a theoretical race on first-contact IP recording if two parallel requests from different IPs arrive simultaneously. This was reviewed and accepted because:
|
**IP Whitelist Race Condition**: There is a theoretical race on first-contact IP recording if two parallel requests from different IPs arrive simultaneously. This was reviewed and accepted because:
|
||||||
- Requires a stolen agent token (already a compromise)
|
- Requires a stolen agent token (already a compromise)
|
||||||
- Requires racing first contact from two different IPs
|
- Requires racing first contact from two different IPs
|
||||||
- The "loser" simply won't be auto-whitelisted
|
- The "loser" simply won't be auto-whitelisted
|
||||||
- Cannot be reproduced in testing; practically impossible to trigger
|
- Cannot be reproduced in testing; practically impossible to trigger
|
||||||
- Fix would require plaintext column + atomic update (not worth complexity)
|
- Fix would require plaintext column + atomic update (not worth complexity)
|
||||||
|
|
||||||
See comment in `api/middleware.go` for full rationale.
|
See comment in `api/middleware.go` for full rationale.
|
||||||
|
|
||||||
**Admin Token Consumed Early**: The admin token is consumed immediately upon validation in `requireAdmin()`. If the subsequent operation fails (DB error, validation error, etc.), the token is gone but the operation didn't complete. The user must perform a fresh PRF tap to retry.
|
**Admin Token Consumed Early**: The admin token is consumed immediately upon validation in `requireAdmin()`. If the subsequent operation fails (DB error, validation error, etc.), the token is gone but the operation didn't complete. The user must perform a fresh PRF tap to retry.
|
||||||
|
|
||||||
This was reviewed and accepted because:
|
This was reviewed and accepted because:
|
||||||
- 5-10 minute token lifetime makes re-auth acceptable
|
- 5-10 minute token lifetime makes re-auth acceptable
|
||||||
- It's a UX inconvenience, not a security vulnerability
|
- It's a UX inconvenience, not a security vulnerability
|
||||||
- Deferring consumption until operation success would require transaction-like complexity
|
- Deferring consumption until operation success would require transaction-like complexity
|
||||||
- Rare edge case: requires admin operation to fail after token validation
|
- Rare edge case: requires admin operation to fail after token validation
|
||||||
|
|
||||||
### How testing works
|
### How testing works
|
||||||
|
|
||||||
No automated test suite for this session's work. Testing is manual via the browser:
|
No automated test suite for this session's work. Testing is manual via the browser:
|
||||||
|
|
||||||
1. Vault runs locally on forge (this machine) at port 1984, accessed via https://dev.clavitor.ai/app/
|
1. Vault runs locally on forge (this machine) at port 1984, accessed via https://dev.clavitor.ai/app/
|
||||||
2. Caddy on 192.168.0.2 reverse-proxies dev.clavitor.ai → forge:1984
|
2. Caddy on 192.168.0.2 reverse-proxies dev.clavitor.ai → forge:1984
|
||||||
3. Import testing: Drop a Proton Pass ZIP export (or any of the 14 supported formats) on the import page. Check scope pills, counts, classifications, and **filtered count badge** — shows why records were skipped (duplicates, aliases, trashed).
|
3. Import testing: Drop a Proton Pass ZIP export (or any of the 14 supported formats) on the import page. Check scope pills, counts, classifications, and **filtered count badge** — shows why records were skipped (duplicates, aliases, trashed).
|
||||||
|
|
@ -202,9 +151,7 @@ No automated test suite for this session's work. Testing is manual via the brows
|
||||||
5. Screen capture: `/capture` skill takes a live screenshot from Johan's Mac (display 3). `/screenshot` fetches the latest manual screenshot.
|
5. Screen capture: `/capture` skill takes a live screenshot from Johan's Mac (display 3). `/screenshot` fetches the latest manual screenshot.
|
||||||
6. Version verification: The topbar shows the **build timestamp** (e.g., `2026-04-04-1432`) fetched from `/api/version`. If the timestamp doesn't update after `make dev`, the old binary is still running — check `make status`.
|
6. Version verification: The topbar shows the **build timestamp** (e.g., `2026-04-04-1432`) fetched from `/api/version`. If the timestamp doesn't update after `make dev`, the old binary is still running — check `make status`.
|
||||||
7. DB location: Vault data is in `/home/johan/dev/clavitor/clavis/clavis-vault/data/`. Delete clavitor-* files there to start fresh (will require passkey re-registration).
|
7. DB location: Vault data is in `/home/johan/dev/clavitor/clavis/clavis-vault/data/`. Delete clavitor-* files there to start fresh (will require passkey re-registration).
|
||||||
|
|
||||||
### Key files
|
### Key files
|
||||||
|
|
||||||
| File | What |
|
| File | What |
|
||||||
|------|------|
|
|------|------|
|
||||||
| api/handlers.go | All HTTP handlers, security guards, admin auth |
|
| api/handlers.go | All HTTP handlers, security guards, admin auth |
|
||||||
|
|
@ -218,22 +165,17 @@ No automated test suite for this session's work. Testing is manual via the brows
|
||||||
| cmd/clavitor/web/topbar.js | Version number, nav, idle timer |
|
| cmd/clavitor/web/topbar.js | Version number, nav, idle timer |
|
||||||
| cmd/clavitor/web/clavitor-app.css | All styles, item-row/item-icon system |
|
| cmd/clavitor/web/clavitor-app.css | All styles, item-row/item-icon system |
|
||||||
| clavitor.ai/main.go | Portal + /classify endpoint (Haiku on OpenRouter) |
|
| clavitor.ai/main.go | Portal + /classify endpoint (Haiku on OpenRouter) |
|
||||||
|
|
||||||
### Deploy Clavitor Vault (dev)
|
### Deploy Clavitor Vault (dev)
|
||||||
|
|
||||||
Working directory: `/home/johan/dev/clavitor/clavis/clavis-vault`
|
Working directory: `/home/johan/dev/clavitor/clavis/clavis-vault`
|
||||||
|
|
||||||
**Prerequisites:**
|
**Prerequisites:**
|
||||||
```bash
|
```bash
|
||||||
# Enable user systemd services (one-time setup)
|
# Enable user systemd services (one-time setup)
|
||||||
systemctl --user enable --now clavitor.service
|
systemctl --user enable --now clavitor.service
|
||||||
```
|
```
|
||||||
|
|
||||||
**Build and deploy (one command):**
|
**Build and deploy (one command):**
|
||||||
```bash
|
```bash
|
||||||
make dev # stop → build → start (graceful shutdown via SIGTERM)
|
make dev # stop → build → start (graceful shutdown via SIGTERM)
|
||||||
```
|
```
|
||||||
|
|
||||||
**Individual commands:**
|
**Individual commands:**
|
||||||
```bash
|
```bash
|
||||||
make stop # systemctl --user stop clavitor.service
|
make stop # systemctl --user stop clavitor.service
|
||||||
|
|
@ -243,40 +185,25 @@ make status # systemctl --user status clavitor.service
|
||||||
make logs # journalctl --user -u clavitor -f
|
make logs # journalctl --user -u clavitor -f
|
||||||
make build # go build...
|
make build # go build...
|
||||||
```
|
```
|
||||||
|
|
||||||
**Service file location:** `~/.config/systemd/user/clavitor.service`
|
**Service file location:** `~/.config/systemd/user/clavitor.service`
|
||||||
|
|
||||||
Caddy on 192.168.0.2 reverse-proxies dev.clavitor.ai → forge:1984 (self-signed, so tls_insecure_skip_verify).
|
Caddy on 192.168.0.2 reverse-proxies dev.clavitor.ai → forge:1984 (self-signed, so tls_insecure_skip_verify).
|
||||||
|
|
||||||
**Update Caddy config:**
|
**Update Caddy config:**
|
||||||
```bash
|
```bash
|
||||||
ssh root@192.168.0.2
|
ssh root@192.168.0.2
|
||||||
# Edit /etc/caddy/Caddyfile, then:
|
# Edit /etc/caddy/Caddyfile, then:
|
||||||
systemctl reload caddy
|
systemctl reload caddy
|
||||||
```
|
```
|
||||||
|
|
||||||
Web files are embedded at compile time (go:embed). CSS/JS/HTML changes require rebuild.
|
Web files are embedded at compile time (go:embed). CSS/JS/HTML changes require rebuild.
|
||||||
|
|
||||||
Bump version in `cmd/clavitor/web/topbar.js` (search for v2.0.) to verify new build is live.
|
Bump version in `cmd/clavitor/web/topbar.js` (search for v2.0.) to verify new build is live.
|
||||||
|
|
||||||
### Deploy clavitor.ai (prod)
|
### Deploy clavitor.ai (prod)
|
||||||
|
|
||||||
Working directory: `/home/johan/dev/clavitor/clavitor.ai`
|
Working directory: `/home/johan/dev/clavitor/clavitor.ai`
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
make deploy-prod
|
make deploy-prod
|
||||||
```
|
```
|
||||||
|
|
||||||
This cross-compiles, SCPs to Zürich, enters maintenance mode, restarts systemd, exits maintenance. One command.
|
This cross-compiles, SCPs to Zürich, enters maintenance mode, restarts systemd, exits maintenance. One command.
|
||||||
|
|
||||||
SSH: root@clavitor.ai — port 22 blocked on public IP, use Tailscale. Never use johan@. Avoid rapid SSH attempts (fail2ban will lock you out — it already happened once this session).
|
SSH: root@clavitor.ai — port 22 blocked on public IP, use Tailscale. Never use johan@. Avoid rapid SSH attempts (fail2ban will lock you out — it already happened once this session).
|
||||||
|
|
||||||
Env vars are in `/opt/clavitor-web/.env` and `/etc/systemd/system/clavitor-web.service`. After changing .env, run `systemctl daemon-reload && systemctl restart clavitor-web` on the server.
|
Env vars are in `/opt/clavitor-web/.env` and `/etc/systemd/system/clavitor-web.service`. After changing .env, run `systemctl daemon-reload && systemctl restart clavitor-web` on the server.
|
||||||
|
|
||||||
**NEVER deploy the database. Only the binary gets uploaded. The SQLite DB on prod is the source of truth.**
|
**NEVER deploy the database. Only the binary gets uploaded. The SQLite DB on prod is the source of truth.**
|
||||||
|
|
||||||
Verify: `ssh root@<tailscale-ip> "systemctl status clavitor-web"`
|
Verify: `ssh root@<tailscale-ip> "systemctl status clavitor-web"`
|
||||||
|
|
||||||
### IMPORTANT
|
### IMPORTANT
|
||||||
|
**NEVER deploy to prod without Johan's explicit approval. This caused a SEV-1 on 2026-03-29.**
|
||||||
**NEVER deploy to prod without Johan's explicit approval. This caused a SEV-1 on 2026-03-29.**
|
|
||||||
|
|
@ -1,26 +1,19 @@
|
||||||
# Clavitor Website — clavitor.com
|
# Clavitor Website — clavitor.com
|
||||||
|
> **Quickstart (60s):** [../QUICKSTART.md](../QUICKSTART.md) — who you are, 4 things to do, critical rules.
|
||||||
> **Required reading before any work**: [CLAVITOR-AGENT-HANDBOOK.md](../CLAVITOR-AGENT-HANDBOOK.md) — Section I (Culture), Section II (Security), Section III (Workflow), and Section V: clavitor.ai/admin (this subproject). You are **Emma**.
|
> **Deep reference:** [../CLAVITOR-AGENT-HANDBOOK.md](../CLAVITOR-AGENT-HANDBOOK.md) — Section V: clavitor.ai (your domain).
|
||||||
|
> **You are:** **Emma** — Run `./scripts/daily-review.sh` every morning. Fix failures first.
|
||||||
## Foundation First — No Mediocrity. Ever.
|
## Foundation First — No Mediocrity. Ever.
|
||||||
The rule is simple: do it right, or say something.
|
The rule is simple: do it right, or say something.
|
||||||
|
|
||||||
Johan is an architect. Architects do not patch cracks in a bad foundation — they rebuild. Every agent on this team operates the same way.
|
Johan is an architect. Architects do not patch cracks in a bad foundation — they rebuild. Every agent on this team operates the same way.
|
||||||
|
|
||||||
**What this means in practice:**
|
**What this means in practice:**
|
||||||
- If you need three fixes for one problem, stop. Something fundamental is wrong. Name it, surface it — we fix that, not the symptom.
|
- If you need three fixes for one problem, stop. Something fundamental is wrong. Name it, surface it — we fix that, not the symptom.
|
||||||
- If the code is spaghetti, say so. Do not add another workaround. The workaround is the problem now.
|
- If the code is spaghetti, say so. Do not add another workaround. The workaround is the problem now.
|
||||||
- Quick fixes are not fixes. A "temporary" hack that ships is permanent. If it is not the right solution, it is the wrong solution.
|
- Quick fixes are not fixes. A "temporary" hack that ships is permanent. If it is not the right solution, it is the wrong solution.
|
||||||
- Foundation > speed. A solid base makes everything downstream easy. A shaky base makes everything downstream a nightmare. We build bases.
|
- Foundation > speed. A solid base makes everything downstream easy. A shaky base makes everything downstream a nightmare. We build bases.
|
||||||
|
|
||||||
**The restart rule:** When the foundation is wrong: start over. Not "refactor slightly." Not "add an abstraction layer on top." Start over. This applies to code, infrastructure, design, encryption schemes, and written work alike.
|
**The restart rule:** When the foundation is wrong: start over. Not "refactor slightly." Not "add an abstraction layer on top." Start over. This applies to code, infrastructure, design, encryption schemes, and written work alike.
|
||||||
|
|
||||||
**Q&D is research, not output:** Exploratory/throwaway work has its place — but it stays in research. Nothing Q&D ships. Nothing Q&D becomes the production path. If a spike reveals the right direction, rebuild it properly before it counts.
|
**Q&D is research, not output:** Exploratory/throwaway work has its place — but it stays in research. Nothing Q&D ships. Nothing Q&D becomes the production path. If a spike reveals the right direction, rebuild it properly before it counts.
|
||||||
|
|
||||||
**When you hit a bad foundation:** Call it out. Do not work around it. Bad foundations are not your fault — but silently building on them is. Surface the problem, we work on it together.
|
**When you hit a bad foundation:** Call it out. Do not work around it. Bad foundations are not your fault — but silently building on them is. Surface the problem, we work on it together.
|
||||||
|
|
||||||
The bar is high. The support is real. These rules apply to you now.
|
The bar is high. The support is real. These rules apply to you now.
|
||||||
|
|
||||||
## Architecture
|
## Architecture
|
||||||
- Go web server (`main.go`) with `go:embed` for templates, CSS, SVGs, PNGs
|
- Go web server (`main.go`) with `go:embed` for templates, CSS, SVGs, PNGs
|
||||||
- Templates in `templates/*.tmpl`, single CSS in `clavitor.css`
|
- Templates in `templates/*.tmpl`, single CSS in `clavitor.css`
|
||||||
|
|
@ -28,40 +21,33 @@ The bar is high. The support is real. These rules apply to you now.
|
||||||
- Dev mode: auto-detected when `templates/` dir exists on disk — reloads templates per request, but CSS/SVGs require rebuild (`go:embed`)
|
- Dev mode: auto-detected when `templates/` dir exists on disk — reloads templates per request, but CSS/SVGs require rebuild (`go:embed`)
|
||||||
- Port 8099
|
- Port 8099
|
||||||
- License: Elastic License 2.0 (NOT MIT)
|
- License: Elastic License 2.0 (NOT MIT)
|
||||||
|
|
||||||
## Deployment
|
## Deployment
|
||||||
|
|
||||||
### Dev (forge = 192.168.1.16, Florida — dev.clavitor.ai)
|
### Dev (forge = 192.168.1.16, Florida — dev.clavitor.ai)
|
||||||
```
|
```
|
||||||
make dev # build + restart locally
|
make dev # build + restart locally
|
||||||
make deploy-dev # same thing
|
make deploy-dev # same thing
|
||||||
```
|
```
|
||||||
Dev runs on forge (localhost). `dev.clavitor.ai` DNS points to home IP.
|
Dev runs on forge (localhost). `dev.clavitor.ai` DNS points to home IP.
|
||||||
|
|
||||||
### Prod (Zürich — clavitor.ai — clavitor.ai)
|
### Prod (Zürich — clavitor.ai — clavitor.ai)
|
||||||
```
|
```
|
||||||
make deploy-prod # cross-compile amd64, scp to Zürich, restart systemd
|
make deploy-prod # cross-compile amd64, scp to Zürich, restart systemd
|
||||||
```
|
```
|
||||||
Prod runs at `/opt/clavitor-web/` as systemd service `clavitor-web`.
|
Prod runs at `/opt/clavitor-web/` as systemd service `clavitor-web`.
|
||||||
Caddy reverse proxies `clavitor.ai`, `clavitor.com`, `www.clavitor.ai`, `www.clavitor.com` → `localhost:8099`.
|
Caddy reverse proxies `clavitor.ai`, `clavitor.com`, `www.clavitor.ai`, `www.clavitor.com` → `localhost:8099`.
|
||||||
|
|
||||||
### First-time setup (already done)
|
### First-time setup (already done)
|
||||||
```
|
```
|
||||||
make setup-prod # creates /opt/clavitor-web, systemd service, uploads binary+db
|
make setup-prod # creates /opt/clavitor-web, systemd service, uploads binary+db
|
||||||
```
|
```
|
||||||
Then manually update `/etc/caddy/Caddyfile` to reverse_proxy.
|
Then manually update `/etc/caddy/Caddyfile` to reverse_proxy.
|
||||||
|
|
||||||
### SSH
|
### SSH
|
||||||
- Prod: `ssh root@clavitor.ai`
|
- Prod: `ssh root@clavitor.ai`
|
||||||
- Tailscale: `zurich` (100.70.148.118) — SSH may be blocked via Tailscale
|
- Tailscale: `zurich` (100.70.148.118) — SSH may be blocked via Tailscale
|
||||||
|
|
||||||
## Build & Run
|
## Build & Run
|
||||||
```
|
```
|
||||||
CGO_ENABLED=1 go build -o clavitor-web .
|
CGO_ENABLED=1 go build -o clavitor-web .
|
||||||
./clavitor-web
|
./clavitor-web
|
||||||
```
|
```
|
||||||
CSS and SVG changes require rebuild (embedded at compile time). Template changes reload in dev mode.
|
CSS and SVG changes require rebuild (embedded at compile time). Template changes reload in dev mode.
|
||||||
|
|
||||||
## Brand & Design
|
## Brand & Design
|
||||||
- Light mode only. Single source of truth: `clavitor.css`
|
- Light mode only. Single source of truth: `clavitor.css`
|
||||||
- Logo: the black square (`#0A0A0A`). favicon.svg = black square
|
- Logo: the black square (`#0A0A0A`). favicon.svg = black square
|
||||||
|
|
@ -71,27 +57,23 @@ CSS and SVG changes require rebuild (embedded at compile time). Template changes
|
||||||
- Fonts: Figtree (body), JetBrains Mono (code/monospace)
|
- Fonts: Figtree (body), JetBrains Mono (code/monospace)
|
||||||
- No inline styles, no CSS in templates. Everything in clavitor.css.
|
- No inline styles, no CSS in templates. Everything in clavitor.css.
|
||||||
- Always capitalize "Clavitor" in prose. Lowercase in code/paths/commands.
|
- Always capitalize "Clavitor" in prose. Lowercase in code/paths/commands.
|
||||||
|
|
||||||
## Encryption Terminology
|
## Encryption Terminology
|
||||||
- **Vault Encryption** — whole vault at rest
|
- **Vault Encryption** — whole vault at rest
|
||||||
- **Credential Encryption** — per-field, server-side (AI agents can read via CLI)
|
- **Credential Encryption** — per-field, server-side (AI agents can read via CLI)
|
||||||
- **Identity Encryption** — per-field, client-side via WebAuthn PRF (Touch ID only, server cannot decrypt)
|
- **Identity Encryption** — per-field, client-side via WebAuthn PRF (Touch ID only, server cannot decrypt)
|
||||||
- Never use "sealed fields", "agent fields", "L1", "L2", "L3"
|
- Never use "sealed fields", "agent fields", "L1", "L2", "L3"
|
||||||
- Agents use CLI, NOT MCP (MCP exposes plaintext; CLI is scoped)
|
- Agents use CLI, NOT MCP (MCP exposes plaintext; CLI is scoped)
|
||||||
|
|
||||||
## POPs (Points of Presence)
|
## POPs (Points of Presence)
|
||||||
- Stored in `pops` table in clavitor.db — the single source of truth
|
- Stored in `pops` table in clavitor.db — the single source of truth
|
||||||
- Map on /hosted is generated dynamically from DB via JavaScript
|
- Map on /hosted is generated dynamically from DB via JavaScript
|
||||||
- Zürich = HQ, black dot, larger (11×11). Live POPs = red. Planned = light red.
|
- Zürich = HQ, black dot, larger (11×11). Live POPs = red. Planned = light red.
|
||||||
- "You" visitor dot = circle (not square — "you" is not clavitor)
|
- "You" visitor dot = circle (not square — "you" is not clavitor)
|
||||||
|
|
||||||
## Key URLs
|
## Key URLs
|
||||||
- `/hosted` — hosted product page with dynamic world map
|
- `/hosted` — hosted product page with dynamic world map
|
||||||
- `/glass` — looking glass (latency from user's browser)
|
- `/glass` — looking glass (latency from user's browser)
|
||||||
- `/noc?pin=250365` — NOC dashboard (telemetry, read-only, hardcoded PIN)
|
- `/noc?pin=250365` — NOC dashboard (telemetry, read-only, hardcoded PIN)
|
||||||
- `/telemetry` — POST endpoint for POP agent heartbeats (no auth)
|
- `/telemetry` — POST endpoint for POP agent heartbeats (no auth)
|
||||||
- `/ping` — server-side TCP ping (for diagnostics)
|
- `/ping` — server-side TCP ping (for diagnostics)
|
||||||
|
|
||||||
## Vault Binary
|
## Vault Binary
|
||||||
- Source: `~/dev/clavitor/clovis/clovis-vault/`
|
- Source: `~/dev/clavitor/clovis/clovis-vault/`
|
||||||
- Build for ARM64: `cd ~/dev/clavitor/clovis/clovis-vault && GOOS=linux GOARCH=arm64 CGO_ENABLED=0 go build -o clavitor-linux-arm64 ./cmd/clavitor`
|
- Build for ARM64: `cd ~/dev/clavitor/clovis/clovis-vault && GOOS=linux GOARCH=arm64 CGO_ENABLED=0 go build -o clavitor-linux-arm64 ./cmd/clavitor`
|
||||||
|
|
@ -99,10 +81,9 @@ CSS and SVG changes require rebuild (embedded at compile time). Template changes
|
||||||
- Vault runs on port 1984 with TLS
|
- Vault runs on port 1984 with TLS
|
||||||
- Has `/ping` endpoint (11 bytes, no DB, CORS via middleware) for looking glass
|
- Has `/ping` endpoint (11 bytes, no DB, CORS via middleware) for looking glass
|
||||||
- Has `/health` endpoint (heavier, queries DB)
|
- Has `/health` endpoint (heavier, queries DB)
|
||||||
|
|
||||||
## Providers
|
## Providers
|
||||||
- AWS: most POPs (free tier t4g.micro)
|
- AWS: most POPs (free tier t4g.micro)
|
||||||
- LightNode: Santiago, Bogotá, Manila, Dhaka
|
- LightNode: Santiago, Bogotá, Manila, Dhaka
|
||||||
- ishosting: Istanbul, Almaty
|
- ishosting: Istanbul, Almaty
|
||||||
- HostAfrica: Lagos, Nairobi
|
- HostAfrica: Lagos, Nairobi
|
||||||
- Rackmill: Perth
|
- Rackmill: Perth
|
||||||
|
|
@ -1,25 +1,19 @@
|
||||||
# clavitor.ai/admin — central admin / Paddle integration
|
# clavitor.ai/admin — central admin / Paddle integration
|
||||||
|
> **Quickstart (60s):** [../QUICKSTART.md](../QUICKSTART.md) — who you are, 4 things to do, critical rules.
|
||||||
> **Required reading before any work**: [CLAVITOR-AGENT-HANDBOOK.md](../../CLAVITOR-AGENT-HANDBOOK.md) — Section I (Culture), Section II (Security), Section III (Workflow), and Section V: clavitor.ai/admin (this subproject). You are **Emma**.
|
> **Deep reference:** [../CLAVITOR-AGENT-HANDBOOK.md](../CLAVITOR-AGENT-HANDBOOK.md) — Section V: clavitor.ai (your domain).
|
||||||
|
> **You are:** **Emma** — Run `./scripts/daily-review.sh` every morning. Fix failures first.
|
||||||
Central admin service. Owns the customer hierarchy (MSP → end-customer → vault slots), the seat ledger, the Paddle webhook handler, and the vault registry mapping `(customer, slot_index, l0, pop)`. This is the directory service — not a vault.
|
Central admin service. Owns the customer hierarchy (MSP → end-customer → vault slots), the seat ledger, the Paddle webhook handler, and the vault registry mapping `(customer, slot_index, l0, pop)`. This is the directory service — not a vault.
|
||||||
|
|
||||||
## Hard rules specific to this subproject
|
## Hard rules specific to this subproject
|
||||||
|
|
||||||
- **Never hold any decryption material.** Central is not a vault. The wrapped L3 stored centrally for distribution is opaque to central — no L3, no L2, no L1, no master_key, ever. If you find yourself wanting to decrypt vault content here, you are in the wrong process.
|
- **Never hold any decryption material.** Central is not a vault. The wrapped L3 stored centrally for distribution is opaque to central — no L3, no L2, no L1, no master_key, ever. If you find yourself wanting to decrypt vault content here, you are in the wrong process.
|
||||||
- **Never trust an inbound webhook without verifying its HMAC signature.** Paddle webhook verification is mandatory. The secret comes from `PADDLE_WEBHOOK_SECRET`. If the env var is unset, every webhook is refused. There is no debug bypass.
|
- **Never trust an inbound webhook without verifying its HMAC signature.** Paddle webhook verification is mandatory. The secret comes from `PADDLE_WEBHOOK_SECRET`. If the env var is unset, every webhook is refused. There is no debug bypass.
|
||||||
- **Never accept admin operations from outside Tailscale.** The `vaults/claim`, `issue-token`, `wl3/since`, `wl3/full` endpoints listen only on the tailnet interface. Public clavitor.ai serves users; the ops control plane is invisible to the internet.
|
- **Never accept admin operations from outside Tailscale.** The `vaults/claim`, `issue-token`, `wl3/since`, `wl3/full` endpoints listen only on the tailnet interface. Public clavitor.ai serves users; the ops control plane is invisible to the internet.
|
||||||
- **Never expose the Paddle API key, webhook secret, or any service credentials in client-side code.** Server-side env only.
|
- **Never expose the Paddle API key, webhook secret, or any service credentials in client-side code.** Server-side env only.
|
||||||
- **Never delete vault data, WL3 files, or audit logs without an explicit GDPR request.** The default lifetime is forever. Cancellation/downgrade marks slots `archived`; only an explicit one-shot deletion script touches the underlying files.
|
- **Never delete vault data, WL3 files, or audit logs without an explicit GDPR request.** The default lifetime is forever. Cancellation/downgrade marks slots `archived`; only an explicit one-shot deletion script touches the underlying files.
|
||||||
|
|
||||||
## Vault slot lifecycle (canonical)
|
## Vault slot lifecycle (canonical)
|
||||||
|
|
||||||
Pre-create at subscription time:
|
Pre-create at subscription time:
|
||||||
1. Customer subscribes to a plan with N seats → `INSERT INTO vault_slots` N rows, all `status='unused'`.
|
1. Customer subscribes to a plan with N seats → `INSERT INTO vault_slots` N rows, all `status='unused'`.
|
||||||
2. Owner names a slot ("Anna") and clicks "invite" → status moves to `pending`, central calls the POP's `/admin/issue-token` over Tailscale, POP returns the 6-char token, central displays it to the owner.
|
2. Owner names a slot ("Anna") and clicks "invite" → status moves to `pending`, central calls the POP's `/admin/issue-token` over Tailscale, POP returns the 6-char token, central displays it to the owner.
|
||||||
3. Anna enrolls at the POP → status moves to `active`, `l0` populated, `enrolled_at` set.
|
3. Anna enrolls at the POP → status moves to `active`, `l0` populated, `enrolled_at` set.
|
||||||
4. Cancellation/downgrade → status moves to `archived`. Vault data and WL3 file persist.
|
4. Cancellation/downgrade → status moves to `archived`. Vault data and WL3 file persist.
|
||||||
|
|
||||||
Plan upgrade = `INSERT` more `unused` rows. Plan downgrade = refuse until the owner manually marks excess slots `archived` (no silent data loss).
|
Plan upgrade = `INSERT` more `unused` rows. Plan downgrade = refuse until the owner manually marks excess slots `archived` (no silent data loss).
|
||||||
|
See `CLAVITOR-AGENT-HANDBOOK.md` Section V → clavitor.ai/admin for the full subproject contract.
|
||||||
See `CLAVITOR-AGENT-HANDBOOK.md` Section V → clavitor.ai/admin for the full subproject contract.
|
|
||||||
|
|
@ -0,0 +1,172 @@
|
||||||
|
# Git Hosting Solutions — Complete Overview
|
||||||
|
|
||||||
|
**Your current setup:** Bare Git (Zurich) — SSH-only, no web UI, no issues
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## SaaS Solutions (They Host, You Pay/Free)
|
||||||
|
|
||||||
|
### 1. GitHub (USA, Microsoft)
|
||||||
|
| | |
|
||||||
|
|--|--|
|
||||||
|
| **Type** | SaaS (Proprietary) |
|
||||||
|
| **Cost** | Free (public + private, 3 collaborators), Team $4/user/month |
|
||||||
|
| **Features** | Issues, PRs, Actions (CI/CD), Codespaces, Copilot |
|
||||||
|
| **Pros** | Everyone uses it, massive ecosystem, best integrations |
|
||||||
|
| **Cons** | US jurisdiction (CLOUD Act), vendor lock-in, Microsoft |
|
||||||
|
| **Best for** | OSS projects, when you need network effects |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 2. GitLab.com (USA)
|
||||||
|
| | |
|
||||||
|
|--|--|
|
||||||
|
| **Type** | SaaS (Open Core — some features open, some proprietary) |
|
||||||
|
| **Cost** | Free (400 CI minutes/month), Premium $29/user/month |
|
||||||
|
| **Features** | Issues, MRs, CI/CD (built-in), Container registry, DevSecOps |
|
||||||
|
| **Pros** | Generous free CI, integrated DevOps platform |
|
||||||
|
| **Cons** | Complex, heavy, can be slow, US company |
|
||||||
|
| **Best for** | Teams wanting integrated CI/CD without setup |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 3. Bitbucket (USA, Atlassian)
|
||||||
|
| | |
|
||||||
|
|--|--|
|
||||||
|
| **Type** | SaaS (Proprietary) |
|
||||||
|
| **Cost** | Free (5 users), Standard $3/user/month |
|
||||||
|
| **Features** | Issues, PRs, Pipelines (CI/CD), Jira integration |
|
||||||
|
| **Pros** | Works with Jira/Confluence if you use Atlassian |
|
||||||
|
| **Cons** | Smaller community than GitHub, Atlassian ecosystem lock-in |
|
||||||
|
| **Best for** | Teams already in Atlassian ecosystem |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 4. SourceHut (USA, Drew DeVault)
|
||||||
|
| | |
|
||||||
|
|--|--|
|
||||||
|
| **Type** | SaaS (Open Source — sourcehut.org is open) |
|
||||||
|
| **Cost** | Free during beta, then ~$2/month or pay-what-you-want |
|
||||||
|
| **Features** | Git + Mercurial, email-based workflow, minimal web UI |
|
||||||
|
| **Pros** | No JavaScript, fast, privacy-focused, true open source |
|
||||||
|
| **Cons** | Different workflow (email-based), smaller community |
|
||||||
|
| **Best for** | Minimalists, people who hate web bloat |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 5. Codeberg (Germany, EU)
|
||||||
|
| | |
|
||||||
|
|--|--|
|
||||||
|
| **Type** | SaaS (runs Gitea, non-profit) |
|
||||||
|
| **Cost** | Free (donations welcome) |
|
||||||
|
| **Features** | Gitea-based: Issues, PRs, CI via Woodpecker |
|
||||||
|
| **Pros** | EU-hosted (GDPR-friendly), non-profit, no tracking |
|
||||||
|
| **Cons** | Smaller than GitHub, occasional downtime |
|
||||||
|
| **Best for** | EU-based projects, privacy-conscious, avoiding Big Tech |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Self-Hosted Solutions (You Host, You Control)
|
||||||
|
|
||||||
|
### 6. GitLab CE (Community Edition)
|
||||||
|
| | |
|
||||||
|
|--|--|
|
||||||
|
| **Type** | Open Core (CE is open, EE is proprietary) |
|
||||||
|
| **Cost** | Free (self-hosted) |
|
||||||
|
| **Install** | Complex — requires PostgreSQL, Redis, Ruby, Go |
|
||||||
|
| **Resources** | 4GB+ RAM minimum, prefers 8GB |
|
||||||
|
| **Features** | Issues, MRs, CI/CD (with runners), Registry, Wiki |
|
||||||
|
| **Pros** | Full-featured, industry standard for self-hosting |
|
||||||
|
| **Cons** | Heavy, complex to maintain, resource hungry |
|
||||||
|
| **Best for** | Large teams needing full DevOps platform |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 7. Gitea (Go, Lightweight)
|
||||||
|
| | |
|
||||||
|
|--|--|
|
||||||
|
| **Type** | Open Source (MIT License) |
|
||||||
|
| **Cost** | Free |
|
||||||
|
| **Install** | 1 binary, 5 minutes |
|
||||||
|
| **Resources** | ~100MB RAM, runs on Raspberry Pi |
|
||||||
|
| **Features** | Issues, PRs, CI/CD (via Act runners), Registry, Wiki |
|
||||||
|
| **Pros** | Light, fast, easy, GitHub-like UI |
|
||||||
|
| **Cons** | Smaller ecosystem than GitLab, newer (less mature) |
|
||||||
|
| **Best for** | Small-medium teams, low resources, quick setup |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 8. Gogs (Go, Minimal)
|
||||||
|
| | |
|
||||||
|
|--|--|
|
||||||
|
| **Type** | Open Source (MIT License) |
|
||||||
|
| **Cost** | Free |
|
||||||
|
| **Install** | 1 binary |
|
||||||
|
| **Resources** | Very light — lighter than Gitea |
|
||||||
|
| **Features** | Basic: repos, issues, PRs (simpler than Gitea) |
|
||||||
|
| **Pros** | Extremely light, simple |
|
||||||
|
| **Cons** | Less active development, fewer features than Gitea |
|
||||||
|
| **Best for** | Minimalists who just need repos + basic issues |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 9. Forgejo (Gitea Fork)
|
||||||
|
| | |
|
||||||
|
|--|--|
|
||||||
|
| **Type** | Open Source (Fork of Gitea) |
|
||||||
|
| **Cost** | Free |
|
||||||
|
| **Origin** | Community fork after Gitea went to non-profit governance |
|
||||||
|
| **Features** | Same as Gitea |
|
||||||
|
| **Pros** | 100% community-controlled, no corporate influence |
|
||||||
|
| **Cons** | Newer fork, smaller community (for now) |
|
||||||
|
| **Best for** | Those who want Gitea features but pure community governance |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 10. Your Current: Bare Git + SSH
|
||||||
|
| | |
|
||||||
|
|--|--|
|
||||||
|
| **Type** | Just Git (no platform) |
|
||||||
|
| **Cost** | Server cost only |
|
||||||
|
| **Install** | `git init --bare` |
|
||||||
|
| **Resources** | Minimal |
|
||||||
|
| **Features** | Git only — no issues, no PRs, no web UI |
|
||||||
|
| **Pros** | Full control, minimal attack surface, simple |
|
||||||
|
| **Cons** | No collaboration features, manual everything |
|
||||||
|
| **Best for** | Small teams, maximum control, minimal complexity |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Summary: Which Should You Choose?
|
||||||
|
|
||||||
|
| Your Priority | Solution | Why |
|
||||||
|
|-------------|----------|-----|
|
||||||
|
| **Maximum visibility for OSS** | GitHub | Everyone's there |
|
||||||
|
| **EU data residency + OSS** | Codeberg | GDPR-friendly, non-profit |
|
||||||
|
| **Self-hosted, low resources** | Gitea | 1 binary, 100MB RAM |
|
||||||
|
| **Self-hosted, full DevOps** | GitLab CE | Complete platform |
|
||||||
|
| **Minimalist, email workflow** | SourceHut | No bloat, true open source |
|
||||||
|
| **Keep current + add issues** | Gitea on Zurich | Upgrade your bare Git |
|
||||||
|
| **Maximum control, no web** | Keep bare Git | What you have now |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## My Recommendation for You
|
||||||
|
|
||||||
|
**Hybrid: GitHub Free + Your Zurich Bare Git**
|
||||||
|
|
||||||
|
```
|
||||||
|
Public repo (clavitor) → GitHub Free (OSS visibility)
|
||||||
|
Private dev repo (clavitor-dev) → Zurich Bare Git (compliance/control)
|
||||||
|
```
|
||||||
|
|
||||||
|
**Or full upgrade:** Gitea on Zurich
|
||||||
|
- 1 binary install
|
||||||
|
- Web UI with issues/PRs
|
||||||
|
- Still self-hosted in Switzerland
|
||||||
|
- GDPR-friendly
|
||||||
|
|
||||||
|
**Want me to:**
|
||||||
|
- A) Write skill to install Gitea on Zurich?
|
||||||
|
- B) Set up GitHub Free + sync workflow?
|
||||||
|
- C) Keep current bare Git + document manual issue workflow?
|
||||||
|
|
@ -0,0 +1,153 @@
|
||||||
|
#!/bin/bash
|
||||||
|
# Daily Review Script — Clavitor Agent Handbook Part 4
|
||||||
|
# Run this every morning before any new feature work.
|
||||||
|
# Any failure = foundation alert. Fix before proceeding.
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
FAILED=0
|
||||||
|
PASSED=0
|
||||||
|
|
||||||
|
# Colors for output
|
||||||
|
RED='\033[0;31m'
|
||||||
|
GREEN='\033[0;32m'
|
||||||
|
YELLOW='\033[1;33m'
|
||||||
|
NC='\033[0m' # No Color
|
||||||
|
|
||||||
|
echo "=== Clavitor Daily Review ==="
|
||||||
|
echo "Checking against CLAVITOR-AGENT-HANDBOOK.md Part 4"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Function to run a check
|
||||||
|
check() {
|
||||||
|
local name="$1"
|
||||||
|
local cmd="$2"
|
||||||
|
local expected="$3"
|
||||||
|
|
||||||
|
echo -n "Checking $name... "
|
||||||
|
|
||||||
|
if eval "$cmd" > /dev/null 2>&1; then
|
||||||
|
if [ "$expected" = "fail" ]; then
|
||||||
|
echo -e "${RED}❌ FAIL${NC} (should have failed but passed)"
|
||||||
|
FAILED=$((FAILED + 1))
|
||||||
|
else
|
||||||
|
echo -e "${GREEN}✅ PASS${NC}"
|
||||||
|
PASSED=$((PASSED + 1))
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
if [ "$expected" = "fail" ]; then
|
||||||
|
echo -e "${GREEN}✅ PASS${NC} (correctly failed)"
|
||||||
|
PASSED=$((PASSED + 1))
|
||||||
|
else
|
||||||
|
echo -e "${RED}❌ FAIL${NC}"
|
||||||
|
FAILED=$((FAILED + 1))
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "--- Section A: Server Hard Veto Checks ---"
|
||||||
|
|
||||||
|
# A1: Server never receives master_key
|
||||||
|
check "A1: No master_key on server" \
|
||||||
|
"grep -rn 'master_key\|MasterKey\|masterKey' clavis-vault/api/ clavis-vault/lib/ --include='*.go' | grep -v '_test.go' | head -1" \
|
||||||
|
"fail"
|
||||||
|
|
||||||
|
# A2: No DeriveP1 on server
|
||||||
|
check "A2: No DeriveP1 on server" \
|
||||||
|
"grep -rn 'DeriveP1\|derive_p1\|deriveP1' clavis-vault/lib/ clavis-vault/api/ | head -1" \
|
||||||
|
"fail"
|
||||||
|
|
||||||
|
# A3: No L2 credential functions
|
||||||
|
check "A3: No L2 credential functions" \
|
||||||
|
"grep -rn 'MintCredential\|ParseCredential\|CredentialToWire' clavis-vault/api/ clavis-vault/lib/ | head -1" \
|
||||||
|
"fail"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "--- Section F: Test Posture ---"
|
||||||
|
|
||||||
|
# F1: Tests pass
|
||||||
|
echo -n "F1: Go tests pass... "
|
||||||
|
cd clavis/clavis-vault
|
||||||
|
if go test ./lib/... ./api/... > /tmp/test-output.log 2>&1; then
|
||||||
|
echo -e "${GREEN}✅ PASS${NC}"
|
||||||
|
PASSED=$((PASSED + 1))
|
||||||
|
else
|
||||||
|
echo -e "${RED}❌ FAIL${NC}"
|
||||||
|
echo " See: /tmp/test-output.log"
|
||||||
|
FAILED=$((FAILED + 1))
|
||||||
|
fi
|
||||||
|
cd ../..
|
||||||
|
|
||||||
|
# F2: Build succeeds
|
||||||
|
echo -n "F2: Build succeeds... "
|
||||||
|
cd clavis/clavis-vault
|
||||||
|
if go build -o /tmp/clavitor-test ./cmd/clavitor/ > /tmp/build-output.log 2>&1; then
|
||||||
|
echo -e "${GREEN}✅ PASS${NC}"
|
||||||
|
PASSED=$((PASSED + 1))
|
||||||
|
else
|
||||||
|
echo -e "${RED}❌ FAIL${NC}"
|
||||||
|
echo " See: /tmp/build-output.log"
|
||||||
|
FAILED=$((FAILED + 1))
|
||||||
|
fi
|
||||||
|
cd ../..
|
||||||
|
|
||||||
|
# F3: Check for test files (basic check)
|
||||||
|
echo -n "F3: Recent Go changes have tests... "
|
||||||
|
# Get files changed in last commit
|
||||||
|
CHANGED=$(git diff --name-only HEAD~1 2>/dev/null | grep '\.go$' | grep -v '_test.go' || true)
|
||||||
|
if [ -z "$CHANGED" ]; then
|
||||||
|
echo -e "${YELLOW}⚠️ SKIP${NC} (no Go changes in last commit)"
|
||||||
|
else
|
||||||
|
# Check each changed file has corresponding test
|
||||||
|
MISSING_TESTS=0
|
||||||
|
for f in $CHANGED; do
|
||||||
|
testfile="$(dirname $f)/$(basename $f .go)_test.go"
|
||||||
|
if [ ! -f "$testfile" ]; then
|
||||||
|
echo ""
|
||||||
|
echo -e " ${YELLOW}⚠️ WARNING: $f has no test file${NC}"
|
||||||
|
MISSING_TESTS=$((MISSING_TESTS + 1))
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
if [ $MISSING_TESTS -eq 0 ]; then
|
||||||
|
echo -e "${GREEN}✅ PASS${NC}"
|
||||||
|
PASSED=$((PASSED + 1))
|
||||||
|
else
|
||||||
|
echo -e "${YELLOW}⚠️ PARTIAL${NC} ($MISSING_TESTS files without tests)"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "--- Section G: Dead Code ---"
|
||||||
|
|
||||||
|
# G1: Empty directories
|
||||||
|
echo -n "G1: No empty directories... "
|
||||||
|
EMPTY=$(find . -type d -empty 2>/dev/null | grep -v ".git" | grep -v "vendor" | head -5)
|
||||||
|
if [ -z "$EMPTY" ]; then
|
||||||
|
echo -e "${GREEN}✅ PASS${NC}"
|
||||||
|
PASSED=$((PASSED + 1))
|
||||||
|
else
|
||||||
|
echo -e "${RED}❌ FAIL${NC}"
|
||||||
|
echo "$EMPTY" | while read dir; do
|
||||||
|
echo " $dir"
|
||||||
|
done
|
||||||
|
FAILED=$((FAILED + 1))
|
||||||
|
fi
|
||||||
|
|
||||||
|
# G2: No orphaned HTML (with exceptions)
|
||||||
|
echo -n "G2: No orphaned production files... "
|
||||||
|
# This is a simplified check - manual review still needed
|
||||||
|
ORPHANED=0
|
||||||
|
echo -e "${YELLOW}⚠️ MANUAL${NC} (see handbook for full G2 check)"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "=== Summary ==="
|
||||||
|
echo -e "${GREEN}Passed: $PASSED${NC}"
|
||||||
|
if [ $FAILED -gt 0 ]; then
|
||||||
|
echo -e "${RED}Failed: $FAILED${NC}"
|
||||||
|
echo ""
|
||||||
|
echo -e "${RED}FOUNDATION ALERT: Fix failures before any new feature work.${NC}"
|
||||||
|
exit 1
|
||||||
|
else
|
||||||
|
echo -e "${GREEN}All checks passed. Ready for feature work.${NC}"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
Loading…
Reference in New Issue