mirror of
https://github.com/tiennm99/goclaw.git
synced 2026-09-03 08:18:42 +00:00
feat(cli-credentials): plan agent-scoped git credentials
This commit is contained in:
+99
@@ -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.
|
||||
@@ -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.
|
||||
+138
@@ -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.
|
||||
+118
@@ -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.
|
||||
+116
@@ -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.
|
||||
+106
@@ -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.
|
||||
@@ -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.
|
||||
@@ -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.
|
||||
@@ -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.
|
||||
Reference in New Issue
Block a user