diff --git a/README.md b/README.md index 34f050e5..7be20081 100644 --- a/README.md +++ b/README.md @@ -79,6 +79,12 @@ additional stores from interactive `cr init` under **Configure secrets storage**. The built-in `local-os` store is read-only configuration and cannot be removed. +Interactive `cr init` treats credential stores, repository access, LLM runtimes, +reviewer entities, and review profiles as separate reusable building blocks. +Configure repository access to define how `cr` accesses Git repositories as the +current user; review profiles then select one configured repository-access entry +instead of editing Git credentials inline. + Interactive `cr init` discovers available secrets backends by default so it can offer local 1Password account/vault choices and passive backend availability checks. Use `cr init --secret-backend-discovery=safe` to skip active inventory @@ -221,8 +227,11 @@ Host matching is case-insensitive after normalization, while namespace and repo matching are case-sensitive after trimming whitespace. An explicit `--profile` bypasses repository routing. Route targets still use the profile's configured auth mode. Passing `--profile ""` is invalid. -For GitHub App auth, `cr review` can use the PR owner/repo to look up the app -installation when `github_app_installation_id` is not staged. +For GitHub App reviewer entities, the review profile chooses whether `cr review` +discovers the installation from each PR owner/repo or uses one pinned +installation ID stored in profile config. Discovery is the normal choice for +profiles routed to multiple organizations or users; pinning is only appropriate +when every route for that profile uses the same installation. Add or replace one credential later: @@ -307,7 +316,8 @@ profiles: agent_sources: - ~/.config/codereview/agents review_policy: - major_event: comment + major_event: request_changes + resolve_threads: auto ``` For adapter-managed LLM credentials, use `auth: subscription` and omit @@ -396,15 +406,17 @@ When deploying a profile without the interactive wizard, run then use `set-credential` only for secrets that you are intentionally staging outside init. Example: -`github_app_installation_id` is optional for `cr review`, which can discover -the installation from the PR repository. Stage it when you want `cr me` and -other commands without repository context to work. +GitHub App reviewer credentials store the App ID and private key only. The +review profile stores installation routing: `discover_from_repository` for PR +context lookup, or `pinned` with one numeric installation ID when every route for +that profile shares the same installation. ```bash cr --profile work init --non-interactive \ --git-host github.com \ --git-credential-ref codereview/work \ --reviewer-auth-mode github_app \ + --reviewer-github-app-id "$GITHUB_APP_ID" \ --reviewer-credential-ref codereview/work-reviewer-app \ --llm-provider anthropic \ --llm-auth api_key \ @@ -418,13 +430,6 @@ printf '%s' "$USER_GITHUB_TOKEN" | cr set-credential \ --stdin \ --overwrite -printf '%s' "$GITHUB_APP_ID" | cr set-credential \ - --store local-os \ - --name codereview/work-reviewer-app \ - --key github_app_id \ - --stdin \ - --overwrite - printf '%s' "$GITHUB_APP_PRIVATE_KEY" | cr set-credential \ --store local-os \ --name codereview/work-reviewer-app \ @@ -432,14 +437,6 @@ printf '%s' "$GITHUB_APP_PRIVATE_KEY" | cr set-credential \ --stdin \ --overwrite -# Optional: needed for cr me and other commands without repository context. -printf '%s' "$GITHUB_APP_INSTALLATION_ID" | cr set-credential \ - --store local-os \ - --name codereview/work-reviewer-app \ - --key github_app_installation_id \ - --stdin \ - --overwrite - printf '%s' "$ANTHROPIC_API_KEY" | cr set-credential \ --store local-os \ --name codereview/work-llm \ @@ -496,10 +493,9 @@ profiles: agent_sources: - ~/.config/codereview/agents review_policy: - major_event: comment + major_event: request_changes allow_self_approve: false resolve_threads: auto - resolve_after: 24h data: retention: max_age_days: 90 @@ -593,7 +589,8 @@ Credential key matrix: |---------------|---------|---------------|---------------|---------------|-------------| | `git.credential` | User Git host auth | `pat` | `git_token` | None | Supported | | `reviewer_credentials.credential` | Reviewer Git host auth | `pat` | `git_token` | None | Supported; must use a distinct credential location from `git.credential` in the same profile | -| `git.credential` / `reviewer_credentials.credential` | Git host auth | `github_app` | `github_app_id`, `github_app_private_key` | `github_app_installation_id` | Supported for GitHub. `cr review` can discover the installation from the PR repository when the optional installation ID is omitted; commands without repository context require it | +| `git.github_app.app_id` / reviewer entity `github_app.app_id` | Git host auth | `github_app` | Config field, not a credential key | None | Non-secret GitHub App ID stored in config. Scripted init uses `--git-github-app-id` or `--reviewer-github-app-id` | +| `git.credential` / reviewer entity credential | Git host auth | `github_app` | `github_app_private_key` | None | Supported for GitHub. Reviewer GitHub App installation routing lives on `profiles..reviewer.github_app_installation`, not in the credential bundle | | `git.credential` / `reviewer_credentials.credential` | Git host auth | `oauth_device` | None | None | Reserved; config recognizes the mode but v1 rejects it and does not accept future keys such as `git_oauth_access_token` or `git_oauth_refresh_token` | | `llm.credential` | Anthropic direct API auth | `api_key` + `anthropic` | `anthropic_api_key` | None | Supported | | `llm.credential` | OpenAI direct API auth | `api_key` + `openai` | `openai_api_key` | None | Supported | @@ -718,15 +715,28 @@ Prints the build version as `cr `. It takes no arguments. cr init [flags] ``` -Creates or updates non-secret config. In v1, `--non-interactive` is required. -If the selected profile already exists, pass `--replace-profile` to replace the -profile config. +Creates or updates non-secret config. If the selected profile already exists, +pass `--replace-profile` to replace the profile config. + +Without `--non-interactive`, `cr init` opens an interactive workspace builder. +The main menu stages changes in reusable areas before a final commit: + +1. Configure secrets storage +2. Configure repository access +3. Configure LLM runtimes +4. Configure reviewer entities +5. Configure review profiles +6. Configure global settings + +Review profiles compose repository access, reviewer entity, and LLM runtime +selections. Repository access must be configured before creating a review +profile. Flags: | Flag | Semantics | |------|-----------| -| `--non-interactive` | Required in v1. Run without prompts. | +| `--non-interactive` | Run without prompts. | | `--git-host ` | Git host, default `github.com`. The PR host must match this value. | | `--git-credential-ref ` | Credential name for Git auth. Defaults to `codereview/`. | | `--git-token-stdin` | Read the Git token from stdin and write key `git_token`. | @@ -743,19 +753,19 @@ Flags: | `--llm-api-key-from-env ` | Read the LLM API key from an environment variable and write `anthropic_api_key` or `openai_api_key` according to `--llm-provider`. | | `--secret-backend-discovery ` | Interactive secrets-backend discovery mode: `full` runs active inventory probes such as 1Password account/vault lookup, `safe` uses only passive availability checks, and `off` skips backend discovery. Defaults to `full`; `CR_SECRET_BACKEND_DISCOVERY` can set the same value when the flag is omitted. | | `--agent-source ` | Add a trusted agent source directory. Repeatable. | -| `--major-event ` | `comment` or `request_changes`. Controls review event for major findings. | +| `--major-event ` | `comment` or `request_changes`. Controls review event for major findings. Defaults to `request_changes`. | | `--allow-self-approve` | Store profile policy allowing self approval. Live review can still require `--allow-self-approve` depending on invocation. | -| `--resolve-threads ` | `auto` or `never`. Empty leaves thread resolution unset. | -| `--resolve-after ` | Store a validated duration such as `24h` for future thread-resolution policy. Current review planning uses `resolve_threads`/`--no-resolve-threads`, not this delay. | +| `--resolve-threads ` | `auto` or `never`. Defaults to `auto`. | | `--overwrite` | Replace existing keyring entries written by this command. | | `--replace-profile` | Replace an existing profile config. | Only one stdin secret ingress flag may be used at a time. PAT reviewer credentials use key `git_token` under their own credential name, so `--reviewer-credential-ref` must differ from `--git-credential-ref`. GitHub App -reviewer credentials use `github_app_id` and `github_app_private_key`, plus -optional `github_app_installation_id`; `init` does not accept reviewer token -ingress for `--reviewer-auth-mode github_app`. LLM API-key ingress requires +reviewers store their non-secret App ID in config via `--reviewer-github-app-id` +and use `github_app_private_key` as the only credential-store key; installation +routing is profile config, not a credential key. `init` does not accept +reviewer token ingress for `--reviewer-auth-mode github_app`. LLM API-key ingress requires `--llm-auth api_key`. `--overwrite` with API-key auth requires an LLM key ingress flag. `--allow-self-review` is intentionally runtime-only on `cr review`; `init` only stores the profile-level self-approval policy. @@ -767,12 +777,12 @@ cr set-credential --store --name --key (--stdin | - ``` Writes one secret value to the selected credential store. Globally allowed keys are -`git_token`, `github_app_id`, `github_app_private_key`, -`github_app_installation_id`, `anthropic_api_key`, and `openai_api_key`. When +`git_token`, `github_app_private_key`, `anthropic_api_key`, and +`openai_api_key`. When `config.yml` declares the target credential location, `set-credential` narrows that global allowlist to the exact key set expected for that credential. PAT -user Git credentials and PAT reviewer credentials use `git_token`; GitHub App credentials use `github_app_id`, -`github_app_private_key`, and optional `github_app_installation_id`; Anthropic +user Git credentials and PAT reviewer credentials use `git_token`; GitHub App +credentials use `github_app_private_key`; Anthropic LLM API-key credentials use `anthropic_api_key`; OpenAI LLM API-key credentials use `openai_api_key`. diff --git a/docs/init-config-surface.md b/docs/init-config-surface.md index 12416ae3..106b7c86 100644 --- a/docs/init-config-surface.md +++ b/docs/init-config-surface.md @@ -42,47 +42,38 @@ intentionally unsupported. | Path | Interactive handling | Scripted owner | Defaults and second-run prepopulation | Mutation semantics | Helper/command owner and expected tests | |------|----------------------|----------------|---------------------------------------|--------------------|-----------------------------------------| | config.secrets.stores | Configure secrets storage creates and edits user-configured credential stores. The built-in OS credential store is projected as `local-os` and is not persisted here. | Interactive main-menu secrets-storage flow only. Scripted credential writes choose an existing store explicitly. | Omitted means only the built-in OS credential store is available. Existing stores are pre-populated in the inventory. | Store ids must not be `local-os`. Store metadata is non-secret. Creating, editing, and deleting configured stores never deletes credential values. | #356 establishes explicit stores and removes ambient/default credential-store selection. | +| config.repository_access | Configure repository access creates and edits reusable Git host/user credential definitions independently from review profiles. Profiles select one configured repository access item when composing a reviewer. | Interactive main-menu repository-access flow only for now. Future config commands may own scripted repository-access CRUD. | Omitted means no reusable repository access is configured yet. Existing profile Git blocks may be projected into repository access during the staged rewrite. | Repository access names are stable ids. Definitions store host, auth mode, non-secret GitHub App ID when applicable, and an explicit credential location. They never store secret values. | Repository-access data model tests and init repository-access UX tests. | | config.llm_runtimes | Configure LLM runtimes creates and edits reusable runtime definitions independently from review profiles. Profiles select one configured runtime when composing a reviewer. | Interactive main-menu LLM runtime flow only for now. Future config commands may own scripted runtime CRUD. | Omitted means no reusable runtimes are configured yet. The profile editor can send the user to the runtime flow when no runtime exists. Existing runtimes are pre-populated in the inventory. | Runtime names are stable ids. Subscription runtimes store only non-secret provider/auth/adapter settings. API-key runtimes store an explicit credential location and never the secret value. Deleting a runtime requires affected profiles to select a replacement or be edited. | #356 makes runtime setup standalone and keeps profile composition explicit. | | config.repository_profiles[] | Route editor opens directly with existing namespace and repo routes prefilled so the user can edit them in place or blank the field to remove all routes for the profile. | Existing `cr config route set` and `cr config route unset`; #186 documents route commands. #187 must not add a nested multi-route init grammar. | Empty or omitted means no automatic repository profile selection; runtime commands require `--profile` until a matching route is configured. Existing routes are prefilled on later runs. | Leaving the prefilled text unchanged preserves routes. Mutations must converge through shared route helpers and preserve unrelated routes. Blanking the field removes the profile's routes. | #177 extracts route helpers. #185 tests list/edit/remove, route canonicalization, and preservation. | | config.repository_profiles[].profile | Route wizard selects the profile that a route resolves to. | Existing `cr config route set --profile ...`. | No default inside an entry; required when a route exists. Existing profile is pre-populated. | Overwrite only to an existing profile. Profile rename updates matching route entries. | #177 profile rename/route reference helper. #185 tests rename updates and invalid profile rejection. | | config.repository_profiles[].match.host | Route wizard derives from selected profile host or pasted PR URL. | Existing `cr config route set --host`. | Required for a route. Existing host is pre-populated and normalized. | Must match the target profile's `git.host`. Host edits on a profile with routes are blocked or reconciled by #185. | #177 route helper, #185 PR URL derivation and host/profile validation tests. | | config.repository_profiles[].match.namespace | Route wizard asks for owner/org or derives from PR URL. | Existing `cr config route set --namespace`. | Required for a route. Existing namespace is pre-populated. | Overwrite validates non-empty and preserves repo-vs-namespace route identity. | #177 route helper. #185 namespace route tests. | | config.repository_profiles[].match.repos[] | Route wizard supports namespace-wide route when omitted or repo-specific routes when provided. | Existing repeatable `cr config route set --repo` and `cr config route unset --repo`. | Omitted means namespace-wide route. Existing repos are pre-populated in deterministic order. | Preserve on skip. Add/edit/remove dedupes and sorts via shared route helper. Clear repos converts only when the user explicitly chooses namespace-wide routing. | #177 route helper. #185 repo route and namespace conversion tests. | -| config.profiles. | Core profile wizard selects existing profile, creates a new profile, or renames an existing profile. | Existing global `--profile` with `cr init --non-interactive` owns scripted create/replace. Scripted rename is intentionally unsupported by init and belongs to future profile-management command design. | When `cr init` starts without a global `--profile`, it suggests `default` as the new profile name. Existing profile names are pre-populated. | Create requires a valid profile body. Rename preserves credential locations by default, updates repository routes, and does not delete old credential-store entries. | #177 profile rename helper. #180 tests create/select/rename and validation. | -| config.profiles..git.host | Core profile wizard edits Git host. | Existing `cr init --git-host`; existing route commands own route-safe scripted changes. | Current init defaults to `github.com`. Existing value is pre-populated. | Set validates non-empty normalized host. If routes reference the profile and reconciliation is not selected, block or defer the edit. | #180 blocks/defer route-unsafe host edits. #185 implements reconciliation tests. | -| config.profiles..git.auth_mode | Core profile wizard chooses `pat` or `github_app`; `oauth_device` remains reserved. | `cr init --git-auth-mode`, parallel to existing reviewer auth mode. Current init otherwise defaults user Git auth to PAT. | Existing value is pre-populated. New profile defaults to `pat`. | Overwrite only to supported v1 modes. Switching auth modes re-plans credential keys but does not delete old secrets. | #179 credential-ref/key-spec planner. #180 auth-mode prompt tests. | -| config.profiles..git.credential.store | User Git auth chooses an existing credential store before any secret ingress. | Interactive credential-writing flows and scripted `cr set-credential --store`. | New profiles start with `local-os` selected. Existing store id is pre-populated. | Must be `local-os` or a configured store id. Store setup is not available inline from this flow. | #356 explicit destination tests. | -| config.profiles..git.credential.name | User Git auth names the credential bundle before any secret ingress. | Interactive credential-writing flows and scripted `cr set-credential --name`. | New profile defaults to `codereview/`. Existing name is pre-populated and preserved by default. | Must use the `codereview/` credential grammar. It must differ from other credentials in the same profile when the store also matches. | #356 explicit credential-location tests. | -| config.profiles..git.identity_cache | Not shown as an editable init field. Preserve only. | Intentionally unsupported for init and config mutation. Runtime identity refresh owns it. | Existing cache is preserved. New profiles omit it. | Preserve unless a future explicit cache invalidation ticket owns behavior. Profile rename does not rewrite cache contents. | Preserve-only regression in #177/#180. | -| config.profiles..reviewer_credentials | Optional reviewer credential section. Wizard supports skip, preserve, enable, edit, or clear reviewer config. | Existing `cr init --reviewer-credential-ref` and `--reviewer-auth-mode` own enable/edit. `cr init --disable-reviewer` owns scripted removal. | Omitted means posting uses Git credentials. Existing section is pre-populated. | Clear removes the whole section. Enable requires auth mode and credential location. The store/name pair must differ from Git and LLM credential locations. | #179 planner and #180 optional section tests. #181 secret ingress tests. | -| config.profiles..reviewer_credentials.auth_mode | Reviewer wizard chooses PAT or GitHub App; `oauth_device` remains reserved. | Existing `cr init --reviewer-auth-mode`. | Current init defaults reviewer mode to `pat` when reviewer credentials are requested. Existing value is pre-populated. | Overwrite only to supported v1 modes. Switching modes re-plans key specs and preserves old secrets unless explicit overwrite/migration occurs. | #179 credential bundle tests for PAT and GitHub App. | -| config.profiles..reviewer_credentials.credential.store | Reviewer Git auth chooses an existing credential store before any secret ingress. | Interactive credential-writing flows and scripted `cr set-credential --store`. | New reviewer credentials start with `local-os` selected unless the user chooses another configured store. Existing store id is pre-populated. | Must be `local-os` or a configured store id. Store setup is not available inline from this flow. | #356 explicit destination tests. | -| config.profiles..reviewer_credentials.credential.name | Reviewer Git auth names the credential bundle before any secret ingress. | Interactive credential-writing flows and scripted `cr set-credential --name`. | New reviewer section defaults to `codereview/-reviewer`, or `codereview/