mirror of
https://github.com/tiennm99/goclaw.git
synced 2026-10-13 22:15:47 +00:00
Merge pull request #120 from digitopvn/codex/issue-117-agent-scoped-git-credentials-plan
feat(cli-credentials): add agent-scoped git credentials
This commit is contained in:
51 files changed
+3060
-85
No files matched your search
@@ -480,7 +480,14 @@ Pre-computed usage snapshots (hourly aggregations) for analytics dashboards. Tra
|
||||
|
||||
### SecureCLIStore
|
||||
|
||||
CLI binary credential configuration with encrypted environment variable injection. Credentials are auto-injected into child processes without exposing them to command output.
|
||||
CLI binary credential configuration with encrypted environment variable
|
||||
injection. Credentials are auto-injected into child processes without exposing
|
||||
them to command output.
|
||||
|
||||
Credential rows can live at binary, agent, channel/context, or user scope.
|
||||
Runtime resolution prefers user overrides, then context credentials, then agent
|
||||
credentials, then binary defaults. The `secure_cli_agent_credentials` table
|
||||
stores one encrypted PAT/SSH/env payload per `(binary_id, agent_id, tenant_id)`.
|
||||
|
||||
| Method | Purpose |
|
||||
|--------|---------|
|
||||
@@ -492,6 +499,9 @@ CLI binary credential configuration with encrypted environment variable injectio
|
||||
| `ListByAgent(agentID)` | Return configs for a specific agent |
|
||||
| `LookupByBinary(binaryName, agentID)` | Find best-matching config (agent-specific > global) |
|
||||
| `ListEnabled()` | Return enabled configs for TOOLS.md generation |
|
||||
| `ListAgentCredentials(binaryID)` | Return masked agent credential metadata |
|
||||
| `SetAgentCredentialsTyped(binaryID, agentID, env, type, hostScope)` | Store agent-scoped PAT/SSH/env payload |
|
||||
| `DeleteAgentCredentials(binaryID, agentID)` | Remove an agent-scoped credential |
|
||||
|
||||
### APIKeyStore
|
||||
|
||||
|
||||
+7
-1
@@ -231,7 +231,7 @@ AES-256-GCM encryption for secrets stored in PostgreSQL. Key provided via `GOCLA
|
||||
| LLM provider API keys | `llm_providers` | `api_key` |
|
||||
| MCP server API keys | `mcp_servers` | `api_key` |
|
||||
| Custom tool env vars | `custom_tools` | `env` |
|
||||
| Credentialed CLI env vars | `secure_cli_binaries`, `secure_cli_agent_grants`, `secure_cli_user_credentials` | `encrypted_env` |
|
||||
| Credentialed CLI env vars | `secure_cli_binaries`, `secure_cli_agent_grants`, `secure_cli_user_credentials`, `secure_cli_agent_credentials` | `encrypted_env` |
|
||||
|
||||
**Format**: `"aes-gcm:" + base64(12-byte nonce + ciphertext + GCM tag)`
|
||||
|
||||
@@ -534,6 +534,11 @@ Implementer guide: [credential-adapter-playbook.md](./credential-adapter-playboo
|
||||
Both paths coexist. A typo in `adapter_name` falls back to passthrough, which
|
||||
restores the legacy denylist-only behavior — no silent bypass.
|
||||
|
||||
Runtime credential precedence is explicit: user override, then channel/context
|
||||
credential, then agent credential, then binary-level env defaults. Agent
|
||||
credentials are the default git trust boundary; granting access to an agent
|
||||
also grants the ability to make that agent use its stored git credential.
|
||||
|
||||
### Audit log: `security.system_env_injection`
|
||||
|
||||
Every adapter injection emits **exactly one** structured slog line. Field
|
||||
@@ -547,6 +552,7 @@ the test and operator-facing log-search recipes.
|
||||
| `adapter` | string | e.g. `git`, `psql`, `passthrough` |
|
||||
| `binary` | string | binary name (`git`, `kubectl`, …) |
|
||||
| `user_id` | string | tenant user UUID (empty for global-only contexts) |
|
||||
| `credential_source` | string | `user`, `context`, `agent`, or empty when no scoped credential row was selected |
|
||||
| `env_keys` | []string | sorted env-var NAMES (never values) |
|
||||
| `argv_prefix_len` | int | number of argv elements prepended (NOT their content) |
|
||||
| `host_scope_hash` | string | SHA-256 first 8 hex chars of normalized host_scope, or `"none"` |
|
||||
|
||||
@@ -1173,8 +1173,45 @@ CLI authentication credentials for secure command execution. Requires **admin ro
|
||||
| `DELETE` | `/v1/cli-credentials/{id}` | Delete credential |
|
||||
| `POST` | `/v1/cli-credentials/{id}/test` | Test credential connection (dry-run) |
|
||||
|
||||
### Agent Credentials
|
||||
|
||||
Agent credentials store PAT/SSH/env material for one CLI credential and one
|
||||
agent. They are the default git setup path; agent access controls who can cause
|
||||
the credential to be used. Responses return metadata only and never include raw
|
||||
typed token/key blobs.
|
||||
|
||||
| Method | Path | Description |
|
||||
|--------|------|-------------|
|
||||
| `GET` | `/v1/cli-credentials/{id}/agent-credentials` | List agent credentials for CLI cred |
|
||||
| `GET` | `/v1/cli-credentials/{id}/agent-credentials/{agentId}` | Get agent credential metadata |
|
||||
| `PUT` | `/v1/cli-credentials/{id}/agent-credentials/{agentId}` | Set agent credential |
|
||||
| `DELETE` | `/v1/cli-credentials/{id}/agent-credentials/{agentId}` | Delete agent credential |
|
||||
|
||||
Typed git request body:
|
||||
|
||||
```json
|
||||
{
|
||||
"credential_type": "pat",
|
||||
"host_scope": "github.com",
|
||||
"blob": { "token": "ghp_..." }
|
||||
}
|
||||
```
|
||||
|
||||
Env request body:
|
||||
|
||||
```json
|
||||
{
|
||||
"env": {
|
||||
"GH_TOKEN": { "kind": "sensitive", "value": "..." }
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Per-User Credentials
|
||||
|
||||
Advanced personal overrides. These remain for backward compatibility and have
|
||||
higher runtime precedence than channel/context and agent credentials.
|
||||
|
||||
| Method | Path | Description |
|
||||
|--------|------|-------------|
|
||||
| `GET` | `/v1/cli-credentials/{id}/user-credentials` | List user credentials for CLI cred |
|
||||
|
||||
@@ -335,6 +335,10 @@ CREATE TABLE secure_cli_binaries (
|
||||
| `DELETE` | `/v1/cli-credentials/{id}` | Delete a SecureCLI config |
|
||||
| `POST` | `/v1/cli-credentials/{id}/test` | Dry-run test (requires admin) |
|
||||
| `GET` | `/v1/cli-credentials/presets` | List preset templates for common CLIs |
|
||||
| `GET` | `/v1/cli-credentials/{id}/agent-credentials` | List agent-scoped credentials |
|
||||
| `GET` | `/v1/cli-credentials/{id}/agent-credentials/{agentId}` | Get agent-scoped credential metadata |
|
||||
| `PUT` | `/v1/cli-credentials/{id}/agent-credentials/{agentId}` | Create or replace agent-scoped credential |
|
||||
| `DELETE` | `/v1/cli-credentials/{id}/agent-credentials/{agentId}` | Delete agent-scoped credential |
|
||||
|
||||
### Google Workspace CLI preset
|
||||
|
||||
|
||||
@@ -24,9 +24,31 @@ The typed `git` adapter accepts either a **Personal Access Token (PAT)** or an
|
||||
| **SSH** | Self-hosted git over SSH. You manage `~/.ssh/known_hosts` or accept TOFU risk. | Passphrase-protected keys are NOT supported (see below). |
|
||||
| **Env** | Legacy path — you have a custom env-var-driven workflow. | Loses host-scoped routing; same trust profile as other CLIs. |
|
||||
|
||||
## Adding a credential (UI)
|
||||
## Adding an agent credential (UI)
|
||||
|
||||
1. Open **Settings → CLI Credentials → User Credentials → Add**.
|
||||
Agent credentials are the default path for git auth. They avoid channel-user
|
||||
ID ambiguity: the selected agent owns the credential, and anyone allowed to use
|
||||
that agent can cause it to run git with the stored credential.
|
||||
|
||||
1. Open **Packages → CLI Credentials**.
|
||||
2. Pick the `git` row and open **Agent Credentials**.
|
||||
3. Select the agent.
|
||||
4. Choose **Credential Type**: `Personal Access Token` or `SSH Private Key`.
|
||||
5. Enter **Host Scope** (required for PAT/SSH): the hostname the credential
|
||||
authenticates to.
|
||||
- Examples: `github.com`, `gitlab.example.com`, `gitea.internal:8443`.
|
||||
- Case-insensitive. Punycode normalized via `idna.ToASCII`.
|
||||
- Port included only when non-default for the scheme.
|
||||
6. Paste the token (PAT) or the unencrypted PEM body (SSH).
|
||||
7. Save.
|
||||
|
||||
## Advanced user overrides
|
||||
|
||||
Per-user credentials remain available for personal overrides and backward
|
||||
compatibility. Use them only when a stable tenant user ID is the intended
|
||||
credential boundary.
|
||||
|
||||
1. Open **Packages → CLI Credentials → Advanced User Overrides → Add**.
|
||||
2. Select user.
|
||||
3. Choose **Credential Type**: `Personal Access Token` or `SSH Private Key`.
|
||||
4. Enter **Host Scope** (required for PAT/SSH): the hostname the credential
|
||||
@@ -41,6 +63,13 @@ The stored secret is encrypted (AES-256-GCM) and can never be read back through
|
||||
the API or UI. Editing the row shows a `••••••••` placeholder; leaving the
|
||||
secret field blank preserves the stored value, typing a new value replaces it.
|
||||
|
||||
Effective credential precedence is:
|
||||
|
||||
1. User override.
|
||||
2. Channel/context credential.
|
||||
3. Agent credential.
|
||||
4. Binary-level env defaults.
|
||||
|
||||
## What gets auto-injected
|
||||
|
||||
The adapter runs ONLY for these subcommands:
|
||||
@@ -140,7 +169,7 @@ Every successful credential injection emits exactly one structured log line:
|
||||
|
||||
```
|
||||
level=WARN msg=security.system_env_injection
|
||||
adapter=git binary=git user_id=<uuid>
|
||||
adapter=git binary=git user_id=<uuid> credential_source=agent
|
||||
env_keys=[GIT_CONFIG_COUNT,GIT_CONFIG_KEY_0,GIT_CONFIG_VALUE_0]
|
||||
argv_prefix_len=0
|
||||
host_scope_hash=3aeb0024
|
||||
@@ -159,12 +188,12 @@ See `docs/09-security.md` → "CLI credential adapters" for the full schema.
|
||||
## Migration from legacy env-paste
|
||||
|
||||
Existing rows in `secure_cli_user_credentials` with `credential_type IS NULL`
|
||||
or `= 'env'` continue to work via the passthrough adapter — they keep
|
||||
emitting their env vars exactly as before. There is no forced migration.
|
||||
or `= 'env'` continue to work via the passthrough adapter. Existing user
|
||||
overrides remain higher precedence than agent credentials. There is no forced
|
||||
migration.
|
||||
|
||||
To upgrade an existing git credential, open the user-credentials dialog, pick
|
||||
PAT or SSH, paste the secret, and save. The legacy env-paste row is replaced
|
||||
atomically.
|
||||
To move to the agent-scoped model, create a matching Agent Credential for the
|
||||
agent and remove the user override when the override is no longer needed.
|
||||
|
||||
## Operator notes
|
||||
|
||||
@@ -186,7 +215,8 @@ atomically.
|
||||
|
||||
## Known limitations (v1)
|
||||
|
||||
- One credential per (user, binary, host_scope) row.
|
||||
- One credential per (agent, binary) row, plus legacy one credential per
|
||||
(user, binary) override.
|
||||
- No multi-host wildcard (`*.github.com`).
|
||||
- No passphrase-protected SSH keys.
|
||||
- No persistent `known_hosts` per credential (TOFU only).
|
||||
|
||||
@@ -4,6 +4,29 @@ Significant changes, features, and fixes in reverse chronological order.
|
||||
|
||||
---
|
||||
|
||||
## 2026-05-31
|
||||
|
||||
### Agent-scoped git credentials (issue #117)
|
||||
|
||||
**New**
|
||||
|
||||
- Added agent-scoped Secure CLI credentials with PostgreSQL migration `000077`
|
||||
and SQLite schema version `46`.
|
||||
- Added HTTP APIs under
|
||||
`/v1/cli-credentials/{id}/agent-credentials/{agentId}` for listing,
|
||||
reading metadata, saving, and deleting agent credentials.
|
||||
- Web CLI Credentials now exposes Agent Credentials as the primary git PAT/SSH
|
||||
setup path, with User Credentials renamed to advanced personal overrides.
|
||||
|
||||
**Security**
|
||||
|
||||
- Runtime credential precedence is now user override, context credential, agent
|
||||
credential, then binary env defaults.
|
||||
- Git adapter audit logs include `credential_source` without logging raw
|
||||
secrets or plaintext host scopes.
|
||||
|
||||
---
|
||||
|
||||
## 2026-05-29
|
||||
|
||||
### Passive channel memory extraction (issue #64)
|
||||
|
||||
Reference in new issue
Block a user