diff --git a/plans/260531-1545-agent-scoped-git-credentials/phase-01-research-and-contract-tests.md b/plans/260531-1545-agent-scoped-git-credentials/phase-01-research-and-contract-tests.md new file mode 100644 index 00000000..a1b76117 --- /dev/null +++ b/plans/260531-1545-agent-scoped-git-credentials/phase-01-research-and-contract-tests.md @@ -0,0 +1,99 @@ +--- +phase: 1 +title: "Research and contract tests" +status: pending +effort: "" +--- + +# Phase 1: Research and contract tests + +## Context Links + +- Issue: https://github.com/digitopvn/goclaw/issues/117 +- Current user ID resolver: `internal/agent/user_identity_resolver.go:40` +- Tool execution context injection: `internal/agent/loop_pipeline_tool_callbacks.go:47` +- Secure CLI store contract: `internal/store/secure_cli_store.go:120` +- Current per-user HTTP API: `internal/http/secure_cli_user_credentials.go:13` +- Current git UI entry point: `ui/web/src/pages/cli-credentials/cli-credentials-table.tsx:80` + +## Overview + +Write characterization and contract tests before schema or UI changes. The goal is to pin the current failure mode: git typed credentials depend on a user credential row, but cross-channel usage often cannot map to the same credential user ID. + +Priority: P1. + +Status: pending. + +## Key Insights + +- Agent identity is stable for the runtime path; external user identity is not stable across channels. +- User credentials should stay supported, but they should not be the primary git credential setup path. +- Existing context credentials already show that credential resolution is not purely per-user; agent credentials should join that explicit precedence chain. + +## Requirements + +- Preserve existing per-user credential behavior. +- Add tests that fail under the current implementation when no matching `userID` exists but an agent credential exists. +- Make API and UI requirements explicit before implementation. + +## Architecture + +Effective credential source should become a small explicit enum in tests and later code: + +1. `user` for explicit per-user override. +2. `context` for group/member/channel scoped credential. +3. `agent` for the new agent-scoped credential. +4. `binary` for legacy/global binary env. +5. `none` when no typed credential is available. + +## Related Code Files + +- Modify tests under `internal/store/pg/`, `internal/store/sqlitestore/`, `internal/tools/`, and `internal/http/`. +- Add or extend UI tests under `ui/web/src/pages/cli-credentials/__tests__/`. +- No production code changes in this phase except test fixtures if needed. + +## Implementation Steps + +1. Add store contract tests proving the intended precedence: user > context > agent > binary. +2. Add a runtime test where the same agent executes `git clone` from two different credential user IDs and resolves the same agent credential. +3. Add an HTTP route contract test for planned agent credential endpoints: + - `GET /v1/cli-credentials/{id}/agent-credentials` + - `GET /v1/cli-credentials/{id}/agent-credentials/{agentId}` + - `PUT /v1/cli-credentials/{id}/agent-credentials/{agentId}` + - `DELETE /v1/cli-credentials/{id}/agent-credentials/{agentId}` +4. Add negative API tests: + - invalid `binaryID` + - invalid `agentID` + - missing `host_scope` for `pat` and `ssh_key` + - unsupported `credential_type` + - response never includes raw token/key/blob +5. Add Web UI tests that the git credential action defaults to Agent Credentials, with User Credentials shown as advanced/personal override. +6. Document which tests fail before implementation. + +## Todo List + +- [ ] Store precedence tests written. +- [ ] Runtime cross-channel agent credential test written. +- [ ] HTTP endpoint contract tests written. +- [ ] UI default-flow test written. +- [ ] Initial failing test set documented in the phase notes. + +## Success Criteria + +- [ ] Tests prove the current user-id keyed design cannot satisfy the target behavior. +- [ ] Tests define the exact endpoint contract and response masking. +- [ ] No implementation-only code is added before the contract tests exist. + +## Risk Assessment + +- Risk: tests could encode a wrong precedence order. Mitigation: keep user override highest for compatibility, but make agent credential the default UI path. +- Risk: agent credential could accidentally grant binary execution access. Mitigation: test that credential rows do not bypass non-global agent grants. + +## Security Considerations + +- Contract tests must assert no plaintext credential values appear in list/detail responses, audit labels, logs, or errors. +- Tests must assert tenant isolation for every new endpoint. + +## Next Steps + +- Phase 2 adds schema and store implementation until Phase 1 tests pass. diff --git a/plans/260531-1545-agent-scoped-git-credentials/phase-02-schema-and-store-resolver.md b/plans/260531-1545-agent-scoped-git-credentials/phase-02-schema-and-store-resolver.md new file mode 100644 index 00000000..088bc698 --- /dev/null +++ b/plans/260531-1545-agent-scoped-git-credentials/phase-02-schema-and-store-resolver.md @@ -0,0 +1,135 @@ +--- +phase: 2 +title: "Schema and store resolver" +status: pending +effort: "" +--- + +# Phase 2: Schema and store resolver + +## Context Links + +- User credential struct: `internal/store/secure_cli_store.go:79` +- Agent grant struct: `internal/store/secure_cli_store.go:97` +- PostgreSQL lookup path: `internal/store/pg/secure_cli.go:337` +- Context credential overlay: `internal/store/pg/secure_cli.go:505` +- SQLite schema version map: `internal/store/sqlitestore/schema.go` +- PostgreSQL latest migration at planning time: `migrations/000076_channel_memory_extraction.up.sql` + +## Overview + +Create durable agent-scoped typed credential storage and make `LookupByBinary` return an effective credential source without depending on channel-specific user IDs. + +Priority: P1. + +Status: pending. + +## Key Insights + +- `secure_cli_agent_grants.encrypted_env` is a policy override payload, not a typed credential identity. It lacks `credential_type` and `host_scope`. +- A dedicated table keeps grant authorization separate from credential material. +- SQLite must be updated in both fresh schema and incremental migrations. + +## Requirements + +- Add `secure_cli_agent_credentials` for both PostgreSQL and SQLite. +- Encrypt secret blob with the same AES-256-GCM pattern as existing SecureCLI credentials. +- Preserve per-user and context credentials. +- Return source metadata for audit and UI. +- Do not let an agent credential row grant access to a non-global CLI binary by itself. + +## Architecture + +New table shape: + +```sql +secure_cli_agent_credentials ( + id uuid/text primary key, + tenant_id uuid/text not null, + binary_id uuid/text not null, + agent_id uuid/text not null, + encrypted_env bytea/blob not null, + metadata jsonb/text not null default '{}', + credential_type text null, + host_scope text null, + created_by text not null default '', + created_at timestamptz/text not null, + updated_at timestamptz/text not null, + unique (tenant_id, binary_id, agent_id) +) +``` + +Effective precedence: + +1. Per-user credential when `userID` maps to a row. +2. Context scoped credential from the channel scope chain. +3. Agent credential for `(tenant_id, binary_id, agent_id)`. +4. Binary/global env. + +Authorization rule: + +- If `secure_cli_binaries.is_global = false`, `secure_cli_agent_grants` must still allow the agent before runtime uses the binary or its credential. +- If `is_global = true`, an agent credential can specialize the otherwise global binary for that agent. + +## Related Code Files + +- Add migration: `migrations/000077_secure_cli_agent_credentials.up.sql` and `.down.sql`, if `000077` is still the next number. +- Update `internal/upgrade/version.go`. +- Update `internal/store/secure_cli_store.go`. +- Add `internal/store/pg/secure_cli_agent_credentials.go`. +- Add `internal/store/sqlitestore/secure-cli-agent-credentials.go`. +- Update `internal/store/pg/secure_cli.go`. +- Update `internal/store/sqlitestore/secure-cli.go`. +- Update `internal/store/sqlitestore/schema.sql` and `internal/store/sqlitestore/schema.go`. + +## Implementation Steps + +1. Re-run `find migrations -name '*.up.sql' | sort | tail` and choose the next migration number. +2. Add PG migration with foreign keys to `secure_cli_binaries`, `agents`, and tenant scope. Add indexes on `(tenant_id, binary_id)`, `(tenant_id, agent_id)`, and unique `(tenant_id, binary_id, agent_id)`. +3. Add SQLite fresh schema and incremental migration. Bump `SchemaVersion`. +4. Add `SecureCLIAgentCredential` struct and store methods: + - `GetAgentCredentials(ctx, binaryID, agentID)` + - `SetAgentCredentialsTyped(ctx, binaryID, agentID, encryptedEnv, credentialType, hostScope)` + - `SetAgentCredentials(ctx, binaryID, agentID, encryptedEnv)` for legacy env + - `DeleteAgentCredentials(ctx, binaryID, agentID)` + - `ListAgentCredentials(ctx, binaryID)` +5. Extend lookup result with effective credential source fields. Prefer a neutral name such as `CredentialEnv`, `CredentialType`, `CredentialHostScope`, `CredentialSource`, and `CredentialSubjectID` instead of reusing `User*` fields for non-user sources. +6. Update PG and SQLite lookup: + - join user credential only when `userID` exists + - join agent credential when `agentID` exists + - apply context credentials before agent credential if context credential exists + - preserve grant authorization check before returning a non-global binary +7. Update fake stores in tests to implement the new interface. +8. Run targeted store tests for PG and SQLite. + +## Todo List + +- [ ] PG migration added and down migration removes table/indexes. +- [ ] SQLite schema and version migration added. +- [ ] Store interface and concrete PG/SQLite methods added. +- [ ] Effective source metadata added without breaking JSON responses. +- [ ] Phase 1 store tests pass. + +## Success Criteria + +- [ ] `LookupByBinary` can resolve typed git credentials for an agent even when `userID == ""`. +- [ ] Per-user credential still wins when present. +- [ ] Context credential still wins over agent credential. +- [ ] Non-global binaries still require enabled grants. +- [ ] PG and SQLite tests cover fresh and migrated schemas. + +## Risk Assessment + +- Risk: reusing `UserEnv` for agent credentials hides source semantics. Mitigation: introduce source-neutral fields and keep `User*` only for backward compatibility during refactor. +- Risk: migration number collision. Mitigation: verify immediately before implementation. +- Risk: SQLite desktop startup breaks. Mitigation: update both schema.sql and incremental migration map. + +## Security Considerations + +- Secret values remain encrypted at rest. +- Store methods must scope by tenant in every query. +- Delete binary or agent should cascade or fail predictably; use foreign keys consistent with existing store behavior. + +## Next Steps + +- Phase 3 exposes API CRUD over the new store methods. diff --git a/plans/260531-1545-agent-scoped-git-credentials/phase-03-http-api-credential-management.md b/plans/260531-1545-agent-scoped-git-credentials/phase-03-http-api-credential-management.md new file mode 100644 index 00000000..da29401b --- /dev/null +++ b/plans/260531-1545-agent-scoped-git-credentials/phase-03-http-api-credential-management.md @@ -0,0 +1,138 @@ +--- +phase: 3 +title: "HTTP API credential management" +status: pending +effort: "" +--- + +# Phase 3: HTTP API credential management + +## Context Links + +- Route registration: `internal/http/secure_cli.go:38` +- Current user credential handlers: `internal/http/secure_cli_user_credentials.go:13` +- Typed credential validator: `internal/http/secure_cli_typed_credentials.go:54` +- API docs table: `docs/18-http-api.md:1176` + +## Overview + +Add HTTP API endpoints for agent-scoped CLI credential management. This is required by the user request and must not be left as a UI-only feature. + +Priority: P1. + +Status: pending. + +## Key Insights + +- The validator for `{credential_type, host_scope, blob}` already exists for user credentials and should be reused for agent credentials. +- API must make clear that credentials are not grants. A credential row stores secret material; `agent-grants` still controls non-global binary access. +- Responses should mirror the user credential API, but use `agent_id` and optional agent display metadata. + +## Requirements + +- Add routes: + - `GET /v1/cli-credentials/{id}/agent-credentials` + - `GET /v1/cli-credentials/{id}/agent-credentials/{agentId}` + - `PUT /v1/cli-credentials/{id}/agent-credentials/{agentId}` + - `DELETE /v1/cli-credentials/{id}/agent-credentials/{agentId}` +- Reuse typed payload body: + - `credential_type: "pat" | "ssh_key" | "env"` + - `host_scope` + - `blob: {"token": "..."} | {"key": "..."}` + - legacy `env` for env-only CLIs +- Return masked metadata only. +- Emit audit events with credential type and IDs, never secret values. +- Require admin auth and tenant scope. + +## Architecture + +Response list shape: + +```json +{ + "agent_credentials": [ + { + "id": "...", + "binary_id": "...", + "agent_id": "...", + "agent_key": "builder", + "has_secret": true, + "credential_type": "pat", + "host_scope": "github.com", + "created_at": "...", + "updated_at": "..." + } + ] +} +``` + +Detail response: + +```json +{ + "agent_id": "...", + "credential_type": "pat", + "host_scope": "github.com", + "has_secret": true +} +``` + +Legacy env credentials may include sanitized `env` entries. Typed credentials must not return `blob`, `token`, or `key`. + +## Related Code Files + +- Add `internal/http/secure_cli_agent_credentials.go`. +- Extend `internal/http/secure_cli_typed_credentials.go` if shared helpers need neutral names. +- Update `internal/http/secure_cli.go` route registration. +- Add tests near `internal/http/secure_cli_typed_credentials_test.go`. +- Update API docs in `docs/18-http-api.md` and `docs/20-api-keys-auth.md`. + +## Implementation Steps + +1. Refactor `typedCredentialBody`, `prepareTypedCredentialEnv`, and `writeTypedCredentialError` only if needed to support both user and agent handlers. +2. Add handler methods for list/get/put/delete agent credentials. +3. Validate `binaryID` and `agentID` path params with `uuid.Parse`. +4. Verify binary and agent exist through store methods before writing. +5. For PUT: + - typed branch: validate blob and call `SetAgentCredentialsTyped` + - env branch: merge env object and call `SetAgentCredentials` +6. For GET/list: + - return metadata and `has_secret` + - suppress `env` for typed credentials +7. Emit audit events: + - `secure_cli.agent_credentials.updated` + - `secure_cli.agent_credentials.deleted` +8. Invalidate SecureCLI cache after update/delete. +9. Run HTTP tests. + +## Todo List + +- [ ] Agent credential routes registered. +- [ ] Handler tests cover list/get/put/delete. +- [ ] Typed validation shared with user credential API. +- [ ] Responses mask typed secrets. +- [ ] API docs updated with endpoint table and body examples. + +## Success Criteria + +- [ ] API can fully manage agent-scoped PAT and SSH credentials. +- [ ] API can edit legacy env credentials for non-git binaries. +- [ ] Invalid agent/binary returns a clear 404 or 400. +- [ ] Non-admin cannot manage credentials. +- [ ] No API response leaks raw credential material. + +## Risk Assessment + +- Risk: new credential endpoint may be mistaken for grant endpoint. Mitigation: docs and UI state credential does not grant access. +- Risk: duplicate validation forks. Mitigation: reuse the existing typed credential validator. + +## Security Considerations + +- Use `http.MaxBytesReader` or existing JSON binding limits. +- Do not log raw request body. +- Audit should include `credential_type` and resource IDs only. +- All writes must be tenant-scoped. + +## Next Steps + +- Phase 4 consumes these endpoints from the Web UI. diff --git a/plans/260531-1545-agent-scoped-git-credentials/phase-04-web-ui-credential-management.md b/plans/260531-1545-agent-scoped-git-credentials/phase-04-web-ui-credential-management.md new file mode 100644 index 00000000..3d6368c4 --- /dev/null +++ b/plans/260531-1545-agent-scoped-git-credentials/phase-04-web-ui-credential-management.md @@ -0,0 +1,118 @@ +--- +phase: 4 +title: "Web UI credential management" +status: pending +effort: "" +--- + +# Phase 4: Web UI credential management + +## Context Links + +- CLI credentials table action: `ui/web/src/pages/cli-credentials/cli-credentials-table.tsx:70` +- Current user credential dialog: `ui/web/src/pages/cli-credentials/cli-user-credentials-dialog.tsx:70` +- Current git typed fields: `ui/web/src/pages/cli-credentials/cli-credential-git-fields.tsx` +- Current hooks: `ui/web/src/pages/cli-credentials/hooks/use-cli-credentials.ts` +- Current i18n namespace: `ui/web/src/i18n/locales/en/cli-credentials.json` + +## Overview + +Make agent credentials the primary UI path for git PAT and SSH setup. Keep user credentials available but visually demote them to advanced personal overrides. + +Priority: P1. + +Status: pending. + +## Key Insights + +- Current UI exposes git typed fields inside `User Credentials`, which requires operators to know a stable `user_id`. +- Issue #117 asks for obvious `GH_PAT` or SSH fields. The primary action should therefore be per-agent credential setup from the git template row. +- Agent access becomes the practical permission boundary. UI must say this plainly without leaking secrets. + +## Requirements + +- Add Agent Credentials action/button in the CLI credentials table. +- For git adapter rows, default the credential form to PAT with `host_scope = github.com` placeholder. +- Support SSH key as second option. +- Show effective credential source where useful: user override, context, agent, binary. +- Move User Credentials into advanced/personal override wording. +- Keep mobile-safe dialog behavior. +- Add en/vi/zh i18n keys. + +## Architecture + +Preferred UI structure: + +- Main table actions: + - Grants + - Agent Credentials + - Advanced: User Credentials + - Edit + - Delete +- New dialog: + - agent picker + - credential type selector + - host scope input + - PAT token field or SSH private key textarea + - masked secret state on edit + - help text explaining agent access implies credential use +- Use existing `CliCredentialGitFields` by extracting labels/state shape into reusable props if needed. + +## Related Code Files + +- Add `ui/web/src/pages/cli-credentials/cli-agent-credentials-dialog.tsx`. +- Reuse or refactor `cli-credential-git-fields.tsx`. +- Extend `ui/web/src/pages/cli-credentials/hooks/use-cli-credentials.ts`. +- Update `cli-credentials-table.tsx` and panel state. +- Update all locale files under `ui/web/src/i18n/locales/{en,vi,zh}/cli-credentials.json`. +- Add/update tests in `ui/web/src/pages/cli-credentials/__tests__/`. + +## Implementation Steps + +1. Add API hook methods: + - `listAgentCredentials(binaryId)` + - `getAgentCredential(binaryId, agentId)` + - `setAgentCredential(binaryId, agentId, payload)` + - `deleteAgentCredential(binaryId, agentId)` +2. Add `CliAgentCredentialsDialog`. +3. Reuse typed git fields and env vars section. Avoid copy-pasting validation logic unless component boundaries require it. +4. Update table/panel to open Agent Credentials as the main credential action. +5. Rename current User Credentials copy to "Advanced user overrides" or equivalent in all locale files. +6. Add a warning/info line: users with access to this agent can cause it to use this credential. +7. Add UI tests: + - git row shows Agent Credentials action + - PAT form posts to `/agent-credentials/{agentId}` + - edit state shows masked secret and does not submit empty replacement + - User Credentials remains reachable as advanced override +8. Run `pnpm` tests/build for `ui/web`. + +## Todo List + +- [ ] Agent credential dialog implemented. +- [ ] Hooks added for all new endpoints. +- [ ] Table/panel actions updated. +- [ ] i18n updated in en/vi/zh. +- [ ] UI tests pass. + +## Success Criteria + +- [ ] Operator can configure `GH_PAT` for `github.com` without typing a channel user ID. +- [ ] Operator can configure SSH private key for a host-scoped git remote. +- [ ] User Credentials path remains available but no longer looks like the default git setup. +- [ ] UI makes the agent-access security boundary visible. + +## Risk Assessment + +- Risk: table action area becomes crowded. Mitigation: use icon buttons/tooltips or a compact menu if needed. +- Risk: duplicated form state between user and agent dialogs. Mitigation: extract only the shared typed git fields, not the whole dialog. +- Risk: mobile overflow in credential dialog. Mitigation: keep `max-h` scroll region and mobile-safe input sizes. + +## Security Considerations + +- Never render raw stored token/key after save. +- Clear plaintext form state on close/unmount. +- Do not store plaintext in Zustand or route state. + +## Next Steps + +- Phase 5 validates runtime behavior against the new source model. diff --git a/plans/260531-1545-agent-scoped-git-credentials/phase-05-runtime-git-adapter-validation.md b/plans/260531-1545-agent-scoped-git-credentials/phase-05-runtime-git-adapter-validation.md new file mode 100644 index 00000000..28b209bb --- /dev/null +++ b/plans/260531-1545-agent-scoped-git-credentials/phase-05-runtime-git-adapter-validation.md @@ -0,0 +1,116 @@ +--- +phase: 5 +title: "Runtime git adapter validation" +status: pending +effort: "" +--- + +# Phase 5: Runtime git adapter validation + +## Context Links + +- Adapter prepare call: `internal/tools/credentialed_exec.go:466` +- Synthetic user credential helper: `internal/tools/credentialed_exec.go:511` +- Git adapter: `internal/tools/credential_adapter_git.go` +- Git adapter tests: `internal/tools/credential_adapter_git_test.go` +- SSH adapter tests: `internal/tools/credential_adapter_git_ssh_test.go` +- Current docs mention User Credentials: `docs/git-credential-adapter.md:29` + +## Overview + +Wire the effective credential source into runtime execution and validate the git adapter still injects PAT/SSH credentials only for remote git operations. + +Priority: P1. + +Status: pending. + +## Key Insights + +- `credentialed_exec.go` currently synthesizes a `SecureCLIUserCredential` from `UserEnv`, `UserCredentialType`, and `UserHostScope`. +- After Phase 2, the adapter should receive a source-neutral credential object, or the helper should be renamed so non-user sources are not misrepresented. +- Git operations must be tested with same-agent, different-channel contexts. + +## Requirements + +- Keep `git status`, `git log`, and other local-only commands uncredentialed. +- Continue denying sandbox mode for non-passthrough adapters unless sandbox support is explicitly added later. +- Add audit source metadata so operators can tell whether `user`, `context`, or `agent` credential was used. +- Validate PAT header behavior against a GitHub-like HTTP endpoint or fixture. +- Validate SSH key injection still scrubs temp paths and key bytes. + +## Architecture + +Runtime should deal with a neutral credential payload: + +```go +type SecureCLIEffectiveCredential struct { + BinaryID uuid.UUID + SubjectID string + Source string // user, context, agent + EncryptedEnv []byte + CredentialType *string + HostScope *string +} +``` + +If implementation keeps `SecureCLIUserCredential` as the adapter input for minimal change, add comments/tests that prove `UserID` is metadata-only and do not expose it as the credential source. + +## Related Code Files + +- Update `internal/tools/credential_adapter.go` if a neutral type is introduced. +- Update `internal/tools/credentialed_exec.go`. +- Update `internal/tools/credential_audit_log_test.go`. +- Update `internal/tools/shell_credentialed_gate_test.go` fake store. +- Update git adapter tests. + +## Implementation Steps + +1. Decide minimal runtime shape: + - preferred: introduce neutral `SecureCLIEffectiveCredential` + - fallback: keep `SecureCLIUserCredential` but add source metadata elsewhere +2. Update `userCredFromBinary` or replace it with `effectiveCredentialFromBinary`. +3. Ensure adapters receive credential data from user/context/agent source. +4. Add audit source to `emitSystemEnvInjectionAudit`. +5. Add tests: + - no `userID`, agent credential present, git clone injects PAT + - two different `CredentialUserID` values use same agent credential + - user credential overrides agent credential + - context credential overrides agent credential + - agent credential does not bypass grant for non-global binary + - PAT and SSH paths scrub secrets and temp paths +6. Validate PAT transport: + - create a local HTTP test server that captures git extra header behavior, or unit-test the generated Git config/env args + - reconcile docs and code on Basic vs Bearer if mismatch is found +7. Run targeted Go tests for tools/store/http. + +## Todo List + +- [ ] Runtime uses effective credential from agent source. +- [ ] Audit includes credential source without raw host or secret value. +- [ ] Cross-channel runtime tests pass. +- [ ] Git PAT and SSH adapter tests pass. +- [ ] Grant boundary tests pass. + +## Success Criteria + +- [ ] Git clone/fetch/pull/push can use an agent credential without a matching user credential. +- [ ] Same agent uses the same credential from Discord, Telegram, HTTP, and cron contexts. +- [ ] Per-user overrides remain backward compatible. +- [ ] Local git operations remain uncredentialed. +- [ ] Secrets remain scrubbed from output, logs, and errors. + +## Risk Assessment + +- Risk: adapter API churn touches many tests. Mitigation: start with a small neutral adapter type and update fake stores in one pass. +- Risk: PAT auth behavior is wrong for GitHub. Mitigation: add characterization test and update docs/code together. +- Risk: audit source reveals too much host info. Mitigation: keep host hashed or omit host value, matching current audit style. + +## Security Considerations + +- Host scope validation remains exact host or host:port, no wildcards. +- Deny patterns from binary/grant/context still apply after credential resolution. +- Temporary SSH files must be removed and scrubbed from errors. + +## Next Steps + +- Phase 6 updates docs and performs final plan/implementation validation. diff --git a/plans/260531-1545-agent-scoped-git-credentials/phase-06-docs-validation-and-handoff.md b/plans/260531-1545-agent-scoped-git-credentials/phase-06-docs-validation-and-handoff.md new file mode 100644 index 00000000..3cb5e7e2 --- /dev/null +++ b/plans/260531-1545-agent-scoped-git-credentials/phase-06-docs-validation-and-handoff.md @@ -0,0 +1,106 @@ +--- +phase: 6 +title: "Docs validation and handoff" +status: pending +effort: "" +--- + +# Phase 6: Docs validation and handoff + +## Context Links + +- Git guide: `docs/git-credential-adapter.md` +- HTTP API docs: `docs/18-http-api.md` +- API auth docs: `docs/20-api-keys-auth.md` +- Security docs: `docs/09-security.md` +- Store model docs: `docs/06-store-data-model.md` +- Project changelog: `docs/project-changelog.md` + +## Overview + +Update user-facing and developer docs, run validation, and leave a clean handoff for implementation review. + +Priority: P1. + +Status: pending. + +## Key Insights + +- The current git guide says to open User Credentials. That will become the advanced path. +- API docs must include the new endpoints because user specifically asked for endpoint support. +- Docs must state the trust model: agent access implies ability to cause that agent to use its configured git credential. + +## Requirements + +- Update docs for agent credential default. +- Keep user credential override documented. +- Add HTTP API endpoint table and examples. +- Update security/data-model docs. +- Update changelog. +- Run code, test, and build validation appropriate to touched files. + +## Architecture + +Documentation model: + +- Quick start: create git CLI credential, grant/use agent, add agent credential. +- PAT path: fine-grained PAT preferred where possible, `host_scope = github.com`. +- SSH path: unencrypted private key only, public key added to git host by operator. +- Advanced path: per-user credential overrides for personal credentials. +- Security model: any principal with access to run the agent can trigger the credential. + +## Related Code Files + +- `docs/git-credential-adapter.md` +- `docs/18-http-api.md` +- `docs/20-api-keys-auth.md` +- `docs/09-security.md` +- `docs/06-store-data-model.md` +- `docs/project-changelog.md` + +## Implementation Steps + +1. Rewrite git guide "Adding a credential" around Agent Credentials first. +2. Add "Advanced user overrides" section. +3. Add endpoint documentation for all agent credential routes. +4. Add request/response examples for PAT and SSH. +5. Update security docs with trust boundary and secret masking. +6. Update data model docs with `secure_cli_agent_credentials`. +7. Update changelog with issue #117 entry. +8. Run validation: + - `go test ./internal/store/... ./internal/http/... ./internal/tools/...` + - `go build ./...` + - `go build -tags sqliteonly ./...` + - `cd ui/web && pnpm test -- --run` + - `cd ui/web && pnpm build` +9. If full integration tests are skipped due local database requirements, state that explicitly in final handoff. + +## Todo List + +- [ ] Git guide updated. +- [ ] HTTP/API auth docs updated. +- [ ] Security and data-model docs updated. +- [ ] Changelog updated. +- [ ] Validation commands recorded with pass/fail status. + +## Success Criteria + +- [ ] A new operator can find where to enter `GH_PAT` or SSH key without knowing channel user IDs. +- [ ] API consumers can manage agent credentials without reading code. +- [ ] Security docs describe agent access as the permission boundary. +- [ ] Build/test output supports merge readiness. + +## Risk Assessment + +- Risk: docs overpromise support for GitHub App or passphrase SSH. Mitigation: keep out-of-scope section explicit. +- Risk: endpoint examples drift from implementation. Mitigation: generate examples from handler tests where practical. + +## Security Considerations + +- Do not include real tokens, keys, or screenshots with secrets. +- Use placeholder values only. +- State least-privilege recommendation: fine-grained PAT or deploy key per host/repo where possible. + +## Next Steps + +- After implementation and validation, open PR referencing issue #117 and this plan. diff --git a/plans/260531-1545-agent-scoped-git-credentials/plan.md b/plans/260531-1545-agent-scoped-git-credentials/plan.md new file mode 100644 index 00000000..aacfd4b6 --- /dev/null +++ b/plans/260531-1545-agent-scoped-git-credentials/plan.md @@ -0,0 +1,64 @@ +--- +title: "Agent-scoped Git credentials" +description: "TDD plan for moving git typed credentials from channel/user-id keyed defaults to agent-scoped credentials, with HTTP API and Web UI management." +status: pending +priority: P1 +issue: 117 +branch: "codex/issue-117-agent-scoped-git-credentials-plan" +tags: [] +blockedBy: [] +blocks: [] +created: "2026-05-31T08:45:33.071Z" +createdBy: "ck:plan" +source: skill +--- + +# Agent-scoped Git credentials + +## Overview + +Issue #117 started as a UI gap: the git template does not make it obvious where to enter `GH_PAT` or SSH key material. The deeper design problem is that current `User Credentials` are keyed by credential user ID, while the same human can appear as different external IDs across Discord, Telegram, HTTP, or group contexts. + +Decision: make agent-scoped git credentials the primary model. Granting access to an agent becomes the security boundary for whether a user can cause that agent to use a git PAT or SSH key. Keep per-user credentials as an advanced override for backward compatibility and truly personal credentials. + +TDD target: + +- Add contract tests first for effective credential precedence and API behavior. +- Add a dedicated agent credential storage surface instead of mixing typed secrets into agent grant policy rows. +- Add HTTP endpoints for create, edit, list, detail, and delete of agent-scoped CLI credentials. +- Update Web UI so git PAT and SSH setup is managed from Agent Credentials by default. +- Validate runtime injection across Discord/Telegram/userless contexts uses the same agent credential. + +## Phases + +| Phase | Name | Status | +|-------|------|--------| +| 1 | [Research and contract tests](./phase-01-research-and-contract-tests.md) | Pending | +| 2 | [Schema and store resolver](./phase-02-schema-and-store-resolver.md) | Pending | +| 3 | [HTTP API credential management](./phase-03-http-api-credential-management.md) | Pending | +| 4 | [Web UI credential management](./phase-04-web-ui-credential-management.md) | Pending | +| 5 | [Runtime git adapter validation](./phase-05-runtime-git-adapter-validation.md) | Pending | +| 6 | [Docs validation and handoff](./phase-06-docs-validation-and-handoff.md) | Pending | + +## Dependencies + +- Current typed git adapter and validation: `internal/tools/credential_adapter_git.go`, `internal/http/secure_cli_typed_credentials.go`. +- Current lookup joins per-user credentials in `internal/store/pg/secure_cli.go` and SQLite equivalent. +- Current UI git form lives under `ui/web/src/pages/cli-credentials/cli-user-credentials-dialog.tsx`. +- Migration number must be re-verified at implementation time. As of plan creation, latest PostgreSQL migration is `000076_channel_memory_extraction`. + +## Verified Facts + +- `LookupByBinary` takes `(binaryName, agentID, userID)` and only joins `secure_cli_user_credentials` when `userID` is non-empty. +- Context credentials can currently override/fill credential fields via `applyContextSecureCLI`, but there is no agent credential typed secret row. +- `SecureCLIAgentGrant` already has `encrypted_env`, but lacks `credential_type` and `host_scope`; using it for typed git secrets would mix policy and secret identity. +- HTTP routes currently expose `/v1/cli-credentials/{id}/user-credentials...` but not agent credential endpoints. +- The Web UI currently opens User Credentials from the CLI credentials table action. + +## Out of Scope + +- GitHub App installation tokens. +- OAuth/device-code token minting. +- Wildcard host scopes. +- Passphrase-protected SSH keys. +- Sandbox-mode git credential injection. diff --git a/plans/260531-1545-agent-scoped-git-credentials/reports/redteam-report.md b/plans/260531-1545-agent-scoped-git-credentials/reports/redteam-report.md new file mode 100644 index 00000000..6bbf093c --- /dev/null +++ b/plans/260531-1545-agent-scoped-git-credentials/reports/redteam-report.md @@ -0,0 +1,75 @@ +# Redteam Report: Agent-scoped Git Credentials + +Date: 2026-05-31 + +Scope: plan review for issue #117 before implementation. + +## Findings + +### R1 - Credential rows could accidentally bypass grants + +Risk: If runtime joins `secure_cli_agent_credentials` without preserving the existing non-global grant gate, creating a credential row becomes an implicit grant. + +Fix in plan: Phase 2 and Phase 5 require tests that non-global binaries still need `secure_cli_agent_grants`. Credential rows store secrets only. + +Status: fixed in plan. + +### R2 - Agent grants are the wrong place for typed secrets + +Risk: `secure_cli_agent_grants.encrypted_env` already exists and is tempting to reuse, but it is policy override state and lacks `credential_type` and `host_scope`. + +Fix in plan: Phase 2 uses dedicated `secure_cli_agent_credentials`. + +Status: fixed in plan. + +### R3 - User credential precedence could preserve the confusing default + +Risk: Keeping user credentials as the visible default would not solve cross-channel identity confusion. + +Fix in plan: Phase 4 makes Agent Credentials the primary git path and moves User Credentials to advanced overrides. + +Status: fixed in plan. + +### R4 - API support could lag behind UI + +Risk: A UI-only feature would block automation and contradict the user requirement. + +Fix in plan: Phase 3 defines full CRUD endpoints, request bodies, response masking, audit events, docs, and tests. + +Status: fixed in plan. + +### R5 - Typed validation might fork and drift + +Risk: Copying PAT/SSH validation into a new handler can create inconsistent behavior between user and agent credentials. + +Fix in plan: Phase 3 requires reusing `prepareTypedCredentialEnv` or a shared equivalent. + +Status: fixed in plan. + +### R6 - SQLite migration can be missed + +Risk: Desktop edition uses SQLite and can break if only PostgreSQL migrations are added. + +Fix in plan: Phase 2 requires PG migration, SQLite fresh schema, SQLite incremental migration, and version bump. + +Status: fixed in plan. + +### R7 - Runtime audit source can become misleading + +Risk: Existing audit uses credential user ID. Agent credentials would make that label inaccurate. + +Fix in plan: Phase 5 requires source-neutral credential metadata and audit source coverage. + +Status: fixed in plan. + +### R8 - PAT transport behavior needs proof + +Risk: Docs and adapter assumptions around GitHub HTTPS auth can silently diverge. + +Fix in plan: Phase 5 requires a GitHub-like PAT transport characterization test and code/docs reconciliation. + +Status: fixed in plan. + +## Unresolved Questions + +None. diff --git a/plans/260531-1545-agent-scoped-git-credentials/reports/validation-report.md b/plans/260531-1545-agent-scoped-git-credentials/reports/validation-report.md new file mode 100644 index 00000000..039c30c5 --- /dev/null +++ b/plans/260531-1545-agent-scoped-git-credentials/reports/validation-report.md @@ -0,0 +1,75 @@ +# Validation Report: Agent-scoped Git Credentials Plan + +Date: 2026-05-31 + +Scope: validate plan completeness and consistency against current code. + +## Checks + +### V1 - Current failure mode is represented + +Evidence: current resolver can return channel-specific user IDs, and `LookupByBinary` only joins user credentials when `userID` is non-empty. + +Plan coverage: Phase 1 and Phase 5 include cross-channel/no-user tests. + +Status: pass. + +### V2 - API endpoints are included + +Evidence: current routes include user credential endpoints only. + +Plan coverage: Phase 3 defines list/get/put/delete agent credential endpoints and docs updates. + +Status: pass. + +### V3 - Store model separates policy from secret identity + +Evidence: `SecureCLIAgentGrant` has policy fields plus encrypted env override but no typed credential metadata. + +Plan coverage: Phase 2 adds dedicated `secure_cli_agent_credentials`. + +Status: pass. + +### V4 - Dual database migration is covered + +Evidence: repo has separate PostgreSQL migrations and SQLite schema/version migrations. + +Plan coverage: Phase 2 explicitly updates both systems. + +Status: pass. + +### V5 - UI default path matches product decision + +Evidence: current table opens User Credentials, and current git guide documents User Credentials. + +Plan coverage: Phase 4 and Phase 6 make Agent Credentials the default and keep User Credentials as advanced override. + +Status: pass. + +### V6 - TDD gates are explicit + +Evidence: implementation phases depend on failing tests from Phase 1. + +Plan coverage: every phase lists tests or validation commands. + +Status: pass. + +### V7 - Security boundary is explicit + +Evidence: agent access is the proposed operational permission boundary. + +Plan coverage: Phase 3, Phase 4, and Phase 6 all require warnings/docs/tests that credential does not grant binary access but agent users can trigger credential use. + +Status: pass. + +## Fixes Applied During Validation + +- Added explicit non-global grant boundary tests. +- Added exact HTTP endpoint list and response shapes. +- Added SQLite migration requirement. +- Added runtime audit source requirement. +- Added PAT transport characterization requirement. + +## Unresolved Questions + +None.