402 lines
16 KiB
Markdown
402 lines
16 KiB
Markdown
# Read-only Workspace Runtime Secrets Implementation Plan
|
|
|
|
> **Historical nomenclature:** this plan predates the native host CLI convergence. References to
|
|
> `thothctl` and `tools/thothctl` describe the implementation snapshot from which this plan was
|
|
> written; current operator commands and paths use native `tht` and `tools/tht`.
|
|
|
|
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
|
|
|
|
**Goal:** Make workspace consumption strictly read-only while adding installation-scoped Git identity and persistent GUI-managed runtime secrets.
|
|
|
|
**Architecture:** Git remains the source of truth and is fetched into an application-owned checkout; complete candidate commits are validated before atomic activation and the backend has no Git write path. Runtime connector credentials are discovered from trusted connector contracts, stored as authenticated ciphertext by a backend vault, and materialized only for the lifetime of diagnostics or runtime leases. The browser exposes repository/readiness status and write-only secret forms without workspace persistence.
|
|
|
|
**Tech Stack:** Fastify, TypeScript, Node.js crypto/filesystem, React 18, TanStack Query, Vitest, Go `thothctl`, Docker Compose.
|
|
|
|
---
|
|
|
|
### Task 1: Freeze the Git repository boundary to read-only
|
|
|
|
**Files:**
|
|
- Modify: `backend/src/workspaces/types.ts`
|
|
- Modify: `backend/src/workspaces/git-repository.ts`
|
|
- Modify: `backend/src/workspaces/registry.ts`
|
|
- Modify: `backend/test/workspaces-git-repository.test.ts`
|
|
- Modify: `backend/test/workspace-registry.test.ts`
|
|
- Modify: `backend/test/workspace-registry-deployment.test.ts`
|
|
|
|
**Step 1: Write failing tests**
|
|
|
|
Add tests proving that pull never configures a Git author, writes generated files, commits, or pushes; that a malformed candidate leaves the prior active snapshot intact; and that a missing catalog descriptor rejects the whole candidate instead of producing a bootstrap slot.
|
|
|
|
**Step 2: Run the focused tests**
|
|
|
|
Run: `cd backend && npx vitest run test/workspaces-git-repository.test.ts test/workspace-registry.test.ts test/workspace-registry-deployment.test.ts`
|
|
|
|
Expected: FAIL on write/publish behavior and missing-descriptor semantics.
|
|
|
|
**Step 3: Implement the read-only boundary**
|
|
|
|
Remove `gitAuthorName`, `gitAuthorEmail`, mutation helpers, generated-document reconciliation, publish/conflict types, and bootstrap-slot activation. `pull()` must fetch, validate the complete commit in a candidate snapshot, and replace active state only after validation succeeds.
|
|
|
|
**Step 4: Run focused tests**
|
|
|
|
Run the command from Step 2.
|
|
|
|
Expected: PASS.
|
|
|
|
**Step 5: Commit**
|
|
|
|
```bash
|
|
git add backend/src/workspaces backend/test/workspaces-git-repository.test.ts backend/test/workspace-registry.test.ts backend/test/workspace-registry-deployment.test.ts
|
|
git commit -m "refactor: make workspace repository strictly read only"
|
|
```
|
|
|
|
### Task 2: Remove publishing and bundle HTTP contracts
|
|
|
|
**Files:**
|
|
- Modify: `backend/src/routes/workspaces.ts`
|
|
- Modify: `backend/test/routes-workspaces.test.ts`
|
|
- Modify: `backend/test/workspaces-runtime-v3-boundaries.test.ts`
|
|
- Modify: `backend/src/config.ts`
|
|
- Modify: `backend/test/workspaces-config.test.ts`
|
|
|
|
**Step 1: Write failing route tests**
|
|
|
|
Assert `POST /workspaces/publish`, `GET /workspaces/:id/export`, and `POST /workspaces/import` return 404 and that the backend no longer registers multipart or ZIP handling. Assert configuration no longer accepts Git author or bundle-limit settings as workspace-registry fields.
|
|
|
|
**Step 2: Run tests and observe failure**
|
|
|
|
Run: `cd backend && npx vitest run test/routes-workspaces.test.ts test/workspaces-config.test.ts test/workspaces-runtime-v3-boundaries.test.ts`
|
|
|
|
Expected: FAIL because mutation and bundle routes still exist.
|
|
|
|
**Step 3: Remove the mutation surface**
|
|
|
|
Delete publish/import/export schemas and helpers, remove `multipart`, `yauzl`, and `yazl` usage from the route, and simplify safe workspace errors to read/validate/sync errors.
|
|
|
|
**Step 4: Run tests**
|
|
|
|
Run the command from Step 2 plus `cd backend && npx tsc --noEmit -p .`.
|
|
|
|
Expected: PASS.
|
|
|
|
**Step 5: Commit**
|
|
|
|
```bash
|
|
git add backend/src backend/test package.json package-lock.json
|
|
git commit -m "refactor: remove workspace publishing and bundles"
|
|
```
|
|
|
|
### Task 3: Expose a sanitized installation repository identity
|
|
|
|
**Files:**
|
|
- Modify: `backend/src/workspaces/git-repository.ts`
|
|
- Modify: `backend/src/routes/workspaces.ts`
|
|
- Modify: `backend/test/workspaces-git-repository.test.ts`
|
|
- Modify: `backend/test/routes-workspaces.test.ts`
|
|
- Modify: `tools/thothctl/internal/config/installation.go`
|
|
- Modify: `tools/thothctl/internal/config/installation_test.go`
|
|
- Modify: `deploy/psd/thothii-installation.yaml.example`
|
|
- Modify: `docs/install/examples/thothii-installation.local.yaml`
|
|
- Modify: `docs/install/examples/thothii-installation.server.yaml`
|
|
|
|
**Step 1: Write failing parser and status tests**
|
|
|
|
Cover HTTPS, SSH URL, and SCP-style remotes; reject embedded user-info for HTTPS; return only `host`, `repository`, `branch`, and `transport`; never return a token, key path, or raw credential-bearing URL. Add installation-descriptor tests for a required `workspaceRepository` block and exactly one read-only transport.
|
|
|
|
**Step 2: Run focused tests**
|
|
|
|
Run: `cd backend && npx vitest run test/workspaces-git-repository.test.ts test/routes-workspaces.test.ts && cd ../tools/thothctl && go test ./internal/config`
|
|
|
|
Expected: FAIL because repository identity and typed installation configuration do not exist.
|
|
|
|
**Step 3: Implement safe normalization and installation validation**
|
|
|
|
Add the normalized identity to registry status. Extend `thothii-installation.yaml` with remote, branch, and SSH/HTTPS access metadata, validate it against the selected Compose override and environment without reading or returning secret values, and retain the existing environment rendering boundary.
|
|
|
|
**Step 4: Run focused tests**
|
|
|
|
Run the command from Step 2.
|
|
|
|
Expected: PASS.
|
|
|
|
**Step 5: Commit**
|
|
|
|
```bash
|
|
git add backend tools/thothctl deploy docs/install/examples
|
|
git commit -m "feat: declare workspace repository in installation config"
|
|
```
|
|
|
|
### Task 4: Add the persistent encrypted workspace secret store
|
|
|
|
**Files:**
|
|
- Create: `backend/src/workspaces/secret-store.ts`
|
|
- Create: `backend/test/workspace-secret-store.test.ts`
|
|
- Modify: `backend/src/config.ts`
|
|
- Modify: `backend/src/app.ts`
|
|
- Modify: `compose.yaml`
|
|
- Modify: `deploy/compose.local.yaml`
|
|
- Modify: `deploy/compose.server.yaml`
|
|
|
|
**Step 1: Write failing vault tests**
|
|
|
|
Test first-start initialization, atomic blind replacement, deletion, enumeration by configured ID only, AES-256-GCM ciphertext with installation/workspace/field associated data, corruption failure, restrictive files/directories, size limits, and absence of plaintext in persistent bytes.
|
|
|
|
**Step 2: Run the vault test**
|
|
|
|
Run: `cd backend && npx vitest run test/workspace-secret-store.test.ts`
|
|
|
|
Expected: FAIL because `WorkspaceSecretStore` does not exist.
|
|
|
|
**Step 3: Implement the vault**
|
|
|
|
Create an injectable `WorkspaceSecretStore` backed by an application-managed data root. Persist a versioned encrypted document atomically, generate or load the installation vault key in the private control area, expose only `has`, `put`, `delete`, and scoped materialization operations, and never add a plaintext read API.
|
|
|
|
**Step 4: Run tests and typecheck**
|
|
|
|
Run: `cd backend && npx vitest run test/workspace-secret-store.test.ts && npx tsc --noEmit -p .`
|
|
|
|
Expected: PASS.
|
|
|
|
**Step 5: Commit**
|
|
|
|
```bash
|
|
git add backend compose.yaml deploy
|
|
git commit -m "feat: persist encrypted workspace runtime secrets"
|
|
```
|
|
|
|
### Task 5: Derive connector requirements and integrate temporary materialization
|
|
|
|
**Files:**
|
|
- Create: `backend/src/workspaces/secret-requirements.ts`
|
|
- Create: `backend/test/workspace-secret-requirements.test.ts`
|
|
- Modify: `backend/src/workspaces/bindings.ts`
|
|
- Modify: `backend/src/workspaces/runtime-config-lease.ts`
|
|
- Modify: `backend/src/tht/tht-runner.ts`
|
|
- Modify: `backend/src/app.ts`
|
|
- Modify: `backend/test/workspace-runtime-config-lease.test.ts`
|
|
- Modify: `backend/test/workspace-runtime-handoff.test.ts`
|
|
- Modify: `backend/test/workspaces-bindings.test.ts`
|
|
|
|
**Step 1: Write failing requirement and lifecycle tests**
|
|
|
|
Cover PostgreSQL password, REST bearer API key, unauthenticated REST, SSH private key/password, signed HTTP Evidence, and static S3 credentials. Assert temporary files are restrictive, live for exactly one diagnostic/runtime lease, disappear on release and error, and are never persisted in the encrypted vault document.
|
|
|
|
**Step 2: Run focused tests**
|
|
|
|
Run: `cd backend && npx vitest run test/workspace-secret-requirements.test.ts test/workspaces-bindings.test.ts test/workspace-runtime-config-lease.test.ts test/workspace-runtime-handoff.test.ts`
|
|
|
|
Expected: FAIL because requirements still come from installation secret-file paths.
|
|
|
|
**Step 3: Implement dynamic requirement resolution**
|
|
|
|
Use the selected DWH transport and Evidence authentication contract to map trusted installation-contract suffixes to stable GUI requirement IDs. Overlay materialized temporary file paths only while resolving existing file-oriented connectors, and attach cleanup to every runtime lease.
|
|
|
|
**Step 4: Run tests and typecheck**
|
|
|
|
Run the command from Step 2 plus `cd backend && npx tsc --noEmit -p .`.
|
|
|
|
Expected: PASS.
|
|
|
|
**Step 5: Commit**
|
|
|
|
```bash
|
|
git add backend/src backend/test
|
|
git commit -m "feat: resolve workspace secrets from connector requirements"
|
|
```
|
|
|
|
### Task 6: Add write-only workspace secret and readiness APIs
|
|
|
|
**Files:**
|
|
- Modify: `backend/src/routes/workspaces.ts`
|
|
- Modify: `backend/src/app.ts`
|
|
- Modify: `backend/src/workspaces/types.ts`
|
|
- Modify: `backend/test/routes-workspaces.test.ts`
|
|
|
|
**Step 1: Write failing API tests**
|
|
|
|
Test `GET /workspaces/:id/runtime-configuration`, blind `PUT /workspaces/:id/secrets`, and `DELETE /workspaces/:id/secrets/:requirementId`. Assert strict bodies, limits, unknown-ID rejection, status-only responses, diagnostic invalidation, and `configuration_required`/`ready` state transitions.
|
|
|
|
**Step 2: Run tests**
|
|
|
|
Run: `cd backend && npx vitest run test/routes-workspaces.test.ts`
|
|
|
|
Expected: FAIL because the routes do not exist.
|
|
|
|
**Step 3: Implement the routes and readiness projection**
|
|
|
|
Inject the secret store into workspace routes and runtime support. Compute per-workspace readiness from active descriptor, current requirement set, configured IDs, and diagnostic generation. Materialize values only inside the diagnostic request and always clean up.
|
|
|
|
**Step 4: Run backend gates**
|
|
|
|
Run: `cd backend && npx vitest run && npx tsc --noEmit -p . && npm run build`.
|
|
|
|
Expected: PASS.
|
|
|
|
**Step 5: Commit**
|
|
|
|
```bash
|
|
git add backend
|
|
git commit -m "feat: manage runtime workspace secrets through the API"
|
|
```
|
|
|
|
### Task 7: Replace workspace management with the two-level read-only UI
|
|
|
|
**Files:**
|
|
- Modify: `frontend/src/api/workspaces.ts`
|
|
- Modify: `frontend/src/api/workspaces.test.ts`
|
|
- Modify: `frontend/src/shell/WorkspaceManager.tsx`
|
|
- Modify: `frontend/src/shell/WorkspaceManager.test.tsx`
|
|
- Delete: `frontend/src/shell/WorkspacePublishDialog.tsx`
|
|
- Delete: corresponding publish-dialog tests
|
|
- Modify/Delete: `frontend/src/shell/WorkspaceEditor.tsx` and bootstrap-only tests as references permit
|
|
- Modify: `frontend/src/workspaces/drafts.ts`
|
|
- Modify: `frontend/src/workspaces/drafts.test.ts`
|
|
|
|
**Step 1: Write failing UI/API tests**
|
|
|
|
Assert the dialog uses at least 60% viewport width and height, shows general repository concepts and exact button consequences at level 1, gates workspace-specific controls on selection, renders requirement explanations and write-only fields at level 2, and has no create/edit/publish/import/export/bundle controls.
|
|
|
|
**Step 2: Run focused tests**
|
|
|
|
Run: `cd frontend && npx vitest run src/api/workspaces.test.ts src/shell/WorkspaceManager.test.tsx src/workspaces/drafts.test.ts`
|
|
|
|
Expected: FAIL on the old draft/publish interface.
|
|
|
|
**Step 3: Implement the read-only interface**
|
|
|
|
Replace bootstrap editor state with repository status, selection, validation/readiness details, dynamic secret fields, blind save/forget actions, and connection test. Remove workspace draft persistence and clear secret field component state after submit/close.
|
|
|
|
**Step 4: Run focused tests and typecheck**
|
|
|
|
Run the command from Step 2 plus `cd frontend && npx tsc -b`.
|
|
|
|
Expected: PASS.
|
|
|
|
**Step 5: Commit**
|
|
|
|
```bash
|
|
git add frontend
|
|
git commit -m "feat: add read-only workspace and secret management UI"
|
|
```
|
|
|
|
### Task 8: Remove browser-persisted workspace preferences
|
|
|
|
**Files:**
|
|
- Modify: `frontend/src/workspaces/preferences.ts`
|
|
- Modify: `frontend/src/workspaces/preferences.test.ts`
|
|
- Modify: `frontend/src/api/sessions.ts`
|
|
- Modify: `frontend/src/api/sessions.test.ts`
|
|
- Modify: `frontend/src/shell/SteerInput.tsx`
|
|
- Modify: `frontend/src/shell/SteerInput.test.tsx`
|
|
|
|
**Step 1: Write failing persistence-boundary tests**
|
|
|
|
Assert workspace/model/thinking choices are kept only in current application memory or saved through the existing backend settings API, and that no workspace code calls `localStorage`.
|
|
|
|
**Step 2: Run focused tests**
|
|
|
|
Run: `cd frontend && npx vitest run src/workspaces/preferences.test.ts src/api/sessions.test.ts src/shell/SteerInput.test.tsx`
|
|
|
|
Expected: FAIL because preferences still use browser storage.
|
|
|
|
**Step 3: Implement ephemeral preferences**
|
|
|
|
Replace the storage adapter with an in-memory external store seeded from backend settings. Preserve concurrent workspace-policy gates and session request determinism without persisting selections in the browser.
|
|
|
|
**Step 4: Run frontend gates**
|
|
|
|
Run: `cd frontend && npx vitest run && npx tsc -b && npm run build`.
|
|
|
|
Expected: PASS.
|
|
|
|
**Step 5: Commit**
|
|
|
|
```bash
|
|
git add frontend
|
|
git commit -m "refactor: stop persisting workspace state in the browser"
|
|
```
|
|
|
|
### Task 9: Update deployment contracts and documentation
|
|
|
|
**Files:**
|
|
- Modify: `compose.yaml`
|
|
- Modify: `deploy/compose.git-ssh.yaml`
|
|
- Modify: `deploy/compose.git-https.yaml`
|
|
- Modify: `deploy/workspace-registry.env.example`
|
|
- Modify: `deploy/psd/operator.env.example`
|
|
- Modify: `docs/install/local-workspace-registry.md`
|
|
- Modify: `docs/install/server-workspace-registry.md`
|
|
- Modify: `docs/guida-utente.md`
|
|
- Modify: `scripts/verify-workspace-install-docs.sh`
|
|
- Modify: `scripts/workspace-registry-smoke.sh`
|
|
|
|
**Step 1: Update executable contract tests first**
|
|
|
|
Require read-only Git wording and configuration, repository identity visibility, vault persistence,
|
|
and absence of author/push/bundle/browser-secret instructions.
|
|
|
|
**Step 2: Run contract tests and observe failure**
|
|
|
|
Run: `bash scripts/verify-workspace-install-docs.sh`
|
|
|
|
Expected: FAIL against the old manuals and examples.
|
|
|
|
**Step 3: Update deployment and manuals**
|
|
|
|
Remove Git author settings and write-oriented documentation. Document installation Git bootstrap,
|
|
GUI runtime-secret completion, platform-neutral application storage, rotation/forget flows, and
|
|
candidate validation semantics.
|
|
|
|
**Step 4: Run contract and Go gates**
|
|
|
|
Run: `bash scripts/verify-workspace-install-docs.sh && cd tools/thothctl && go test ./...`
|
|
|
|
Expected: PASS.
|
|
|
|
**Step 5: Commit**
|
|
|
|
```bash
|
|
git add compose.yaml deploy docs scripts tools/thothctl
|
|
git commit -m "docs: describe read-only workspace runtime configuration"
|
|
```
|
|
|
|
### Task 10: Full verification and deployed-container refresh
|
|
|
|
**Files:**
|
|
- Modify only files needed to fix failures found by verification.
|
|
|
|
**Step 1: Run static and unit gates**
|
|
|
|
```bash
|
|
cd backend && npx vitest run && npx tsc --noEmit -p . && npm run build
|
|
cd ../frontend && npx vitest run && npx tsc -b && npm run build
|
|
cd ../harness && .venv/bin/pytest -q
|
|
cd ../tools/thothctl && go test ./...
|
|
```
|
|
|
|
Expected: all gates PASS.
|
|
|
|
**Step 2: Run deployment contract gates**
|
|
|
|
Run: `bash scripts/verify-workspace-install-docs.sh` and the focused workspace registry smoke appropriate to the configured installation.
|
|
|
|
Expected: PASS without Git writes or secret disclosure.
|
|
|
|
**Step 3: Inspect the final diff and secret scan**
|
|
|
|
Run: `git diff --check`, inspect `git status --short`, and search active code/config for removed publish, bundle, Git author, and workspace-localStorage contracts.
|
|
|
|
Expected: no whitespace errors, no accidental secrets, and only intended changes.
|
|
|
|
**Step 4: Rebuild and restart affected services**
|
|
|
|
Use the installation-aware `thothctl` lifecycle for the configured installation to rebuild/restart `core` and `frontend`, then verify health and repository status. Do not restart if no valid local installation descriptor is available; report that external gate explicitly.
|
|
|
|
**Step 5: Commit verification fixes**
|
|
|
|
```bash
|
|
git add <only-files-changed-for-verification>
|
|
git commit -m "test: verify read-only workspace secret flow"
|
|
```
|