Seal the four credential columns with AES-256-GCM (random nonce per value,
AAD "<table>.<column>"): llm_profiles.api_key and task_credentials.password
store "enc:v1:<base64(nonce||ciphertext)>"; mcp_servers.env and
notification_channels.config store {"__artex_enc":"enc:v1:..."} over the
canonical JSON. The db layer encrypts on write and decrypts on read, so agent
tools (LLM provider, MCP, notifier, test credentials) get plaintext
server-side. Decryption failure is an error, never a plaintext fallback.
Key: ARTEX_SECRET_KEY (32 bytes, base64 or hex) or keys/secret.key next to
jwt.key, generated with crypto/rand at first start (0600). Startup refuses
when encrypted values exist and no key is available, and when the key does
not decrypt them. An idempotent backfill under the schema advisory lock
encrypts legacy plaintext rows and logs only a count.
API: MCP env is masked on read and masked placeholders on write keep the
stored value; task credential passwords are masked server-side and a masked
password on write is refused. ARTEX_SECRET_KEY is scrubbed from the process
environment with the other startup secrets.
- resetLLMFailStreaksForTest helper: the package-global streak is in-memory
state, so the no-switch-on-ordinary-error subtests now reset it before each
case (accumulation across subtests sharing task/profile keys made the third
case escalate, breaking the contract the test guards)
- core lifecycle and credentials fixtures: goals now name the lab target, per
the ambiguity gate (these tests exercise lifecycle/credentials, not the gate)
- canonical reset helper moved into task_llm.go next to the counter it resets
Task credentials (#3): declare test accounts at task creation, and never
lose the accounts the agent registers on its own.
- task_credentials table (unique per task+domain+username; upsert
overwrites the password in place), idempotent schema migration
- POST /api/tasks accepts credentials; GET/POST/DELETE
/api/tasks/{id}/credentials serve the UI (manual add, e.g. relaying an
OTP-verified account; delete)
- empty password = the "agent generates" mode: the entry surfaces in the
worker's graph overview with an explicit instruction to register that
account with a strong password and record it
- new tools save_task_credential / list_task_credentials for worker and
pentest; the graph overview injects the task's credentials each round
with a standing note: reuse matching entries, always record accounts
you register
- New Task dialog: optional credentials section (domain, username,
password, note) with a dedicated-test-accounts hint
- task detail: Credentials tab, passwords masked with explicit
reveal/copy, agent-recorded badge, light polling so mid-run recordings
appear
One-shot binding migration (settings-flag-guarded, same pattern as the
other seeds) grants the two tools to worker+pentest on databases seeded
before this change; fresh DBs get them via WorkerTools()/the pentest
catalog.
Closes#3