Skip to content

feat(autoconf): add kdn autoconf command#379

Merged
feloy merged 10 commits intoopenkaiden:mainfrom
feloy:autoconf-secrets
May 5, 2026
Merged

feat(autoconf): add kdn autoconf command#379
feloy merged 10 commits intoopenkaiden:mainfrom
feloy:autoconf-secrets

Conversation

@feloy
Copy link
Copy Markdown
Contributor

@feloy feloy commented Apr 29, 2026

Autoconfiguration based on user environment, 1st part: secrets

Scans registered secret services' environment variables, classifies detected secrets against the store and all config sources (global, project-specific, local workspace.json), and for each unset secret confirms creation and prompts for a config target. --yes skips all prompts and defaults to the global config.

New supporting types: ProjectConfigUpdater, WorkspaceConfigUpdater (pkg/config), ListServices() (secretservicesetup), and a "Configuration Commands" group in the root command.

Move detectProject to a dedicated package pkg/project, so it can be reused by autoconf.

Part of #377

To test it:

# If you have github / anthropic / gemini api keys defined in exported env vars
kdn autoconf

# If not, define the keys inline:
GH_TOKEN=... kdn autoconf
ANTHROPIC_API_KEY=... kdn autoconf

@feloy feloy force-pushed the autoconf-secrets branch from 92c66f3 to e22380d Compare April 29, 2026 09:59
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 29, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds a new autoconf feature: CLI command and runner that detect secrets from environment via registered secret services, filter already-configured secrets, optionally create secrets in the store, and record secret references into global/project/local configuration targets.

Changes

Autoconf feature (single cohesive DAG)

Layer / File(s) Summary
Data Types & Interfaces
pkg/autoconf/detect.go, pkg/autoconf/filter.go
Adds DetectedSecret, ConfiguredSecret, FilterResult; SecretDetector and SecretFilter interfaces; constructors NewSecretDetector, NewFilteredSecretDetector, and NewAlreadyConfiguredFilter.
Core Implementation
pkg/autoconf/autoconf.go
New Autoconf runner with Options (Detector, Store, Updaters, ProjectID, Yes, Confirm, SelectTarget), ConfigTarget enums, ErrSkipped, and orchestration (detect → print configured → per-secret confirm → create → add-to-config).
Detection Logic
pkg/autoconf/detect.go
Implements envSecretDetector that iterates secret services and env vars (injectable lookupEnv) producing FilterResult or delegating to a filter.
Filtering Logic
pkg/autoconf/filter.go
Implements alreadyConfiguredFilter that checks store presence and configuration scopes (global/project/workspace) to classify secrets as Configured or NeedsAction.
CLI Wiring
pkg/cmd/autoconf.go, pkg/cmd/root.go
Adds kdn autoconf Cobra command, preRun wiring (storage, ListServices, project detection, workspace config), interactive confirm and selectTarget handlers, and registration under a new "config" command group.
Config Updaters (persistence)
pkg/config/projectsupdater.go, pkg/config/workspaceupdater.go
New ProjectConfigUpdater and WorkspaceConfigUpdater interfaces and implementations for idempotent JSON persistence of secret references.
Secret Service Registry
pkg/secretservicesetup/register.go
Adds ListServices() returning constructed SecretService instances.
Project ID Abstraction
pkg/project/project.go, pkg/instances/manager.go
Adds project.Detector abstraction (wraps git detector) and refactors manager to use it; tests adjusted accordingly.
Tests
pkg/autoconf/*_test.go, pkg/autoconf/detect_test.go, pkg/autoconf/filter_test.go, pkg/cmd/autoconf_test.go, pkg/config/*_test.go, pkg/secretservicesetup/register_test.go, pkg/project/project_test.go, pkg/instances/*_test.go
Extensive unit tests and fakes covering detection, filtering, runner flows (confirm/select target/yes/skip), CLI wiring, updaters persistence and error paths, secret service registry construction, and project detection behavior.
Example Parsing & Docs
pkg/cmd/testutil/example_validator.go, .agents/skills/working-with-autoconf/SKILL.md, AGENTS.md, README.md
Example parser accepts leading ENV= assignments; documentation added for autoconf usage, ListServices() semantics, project detector, and extension points.
Dependencies
go.mod
Adds github.com/charmbracelet/huh and related indirect terminal/UI dependencies.

Sequence Diagram(s)

sequenceDiagram
    autonumber
    actor User as User
    participant CLI as "kdn autoconf"
    participant Detector as SecretDetector
    participant Filter as SecretFilter
    participant Store as SecretStore
    participant Updaters as ConfigUpdaters

    User->>CLI: run autoconf [--yes]
    CLI->>Detector: Detect()
    Detector->>Filter: (optional) Filter detected secrets
    Detector-->>CLI: FilterResult (NeedsAction, Configured)
    CLI->>CLI: print Configured list

    loop each secret in NeedsAction
        alt interactive (no --yes)
            CLI->>User: Confirm create?
            User-->>CLI: yes/no
        else --yes
            CLI-->>CLI: auto-confirm
        end

        alt confirmed
            CLI->>Store: Get / Create secret
            Store-->>CLI: success / already exists / error
            CLI->>User: SelectTarget (global/project/local)
            User-->>CLI: target / abort
            alt target selected
                CLI->>Updaters: AddSecret(target)
                Updaters-->>CLI: updated
            else aborted (ErrSkipped)
                CLI-->>CLI: print "Skipped adding"
            end
        else declined
            CLI-->>CLI: print "Skipped"
        end
    end

    CLI-->>User: done
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~75 minutes

Possibly related issues

  • #377: Implements the "kdn autoconf" feature (env-var scanning, secret creation, and config recording).

Possibly related PRs

  • #303: Related to secret service registry APIs and listing semantics used by the detector/ListServices.
  • #272: Related to embedded secretservices.json-driven registration and registry tests.
  • #338: Related to secret service registry entries (overlapping additions to service lists).
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 47.76% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'feat(autoconf): add kdn autoconf command' accurately describes the main feature addition—a new autoconf CLI command for autoconfiguring secrets from environment variables.
Description check ✅ Passed The description clearly explains the purpose (autoconfiguration of secrets from environment), the new supporting types added, the refactoring (moving detectProject to pkg/project), and provides testing instructions with examples.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (3)
pkg/config/workspaceupdater_test.go (1)

65-91: Consider checking errors from setup calls.

Several tests ignore errors from NewWorkspaceConfigUpdater and AddSecret using _. While the tests would fail on subsequent assertions if these errored, explicit error checking improves debuggability.

♻️ Suggested improvement
 func TestWorkspaceUpdater_Idempotent(t *testing.T) {
 	t.Parallel()
 	dir := t.TempDir()

-	u, _ := NewWorkspaceConfigUpdater(dir)
-	_ = u.AddSecret("github")
-	_ = u.AddSecret("github")
+	u, err := NewWorkspaceConfigUpdater(dir)
+	if err != nil {
+		t.Fatalf("NewWorkspaceConfigUpdater: %v", err)
+	}
+	if err := u.AddSecret("github"); err != nil {
+		t.Fatalf("AddSecret: %v", err)
+	}
+	if err := u.AddSecret("github"); err != nil {
+		t.Fatalf("AddSecret: %v", err)
+	}

 	secrets := readWorkspaceSecrets(t, dir)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pkg/config/workspaceupdater_test.go` around lines 65 - 91, Update the two
tests (TestWorkspaceUpdater_Idempotent and
TestWorkspaceUpdater_MultipleCalls_Accumulate) to stop discarding errors:
capture and check the error returned by NewWorkspaceConfigUpdater and each
AddSecret call (use variables like u, err := NewWorkspaceConfigUpdater(...) and
if err != nil { t.Fatalf(...) } and similarly check err after u.AddSecret(...));
this ensures failures produce immediate, clear test failures and easier
debugging.
pkg/autoconf/autoconf.go (2)

136-142: Consider handling fmt.Fprintf/fmt.Fprintln return values.

Static analysis flags unchecked error returns from fmt.Fprintf and fmt.Fprintln. While ignoring these is common practice for CLI output to stdout, the out parameter is an injected io.Writer that could be any destination. For robustness, consider using a helper or explicitly discarding with _ =.

♻️ Optional: Explicitly discard or wrap output calls

One approach is to use a helper function that wraps the writes:

func fprint(w io.Writer, format string, args ...any) {
	_, _ = fmt.Fprintf(w, format, args...)
}

Or simply prefix with _, _ = to explicitly acknowledge the ignored return values.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pkg/autoconf/autoconf.go` around lines 136 - 142, The fmt.Fprintf and
fmt.Fprintln calls in the loop over result.Configured and the subsequent
No-secrets branch ignore their returned (int, error) values; because out is an
injected io.Writer this can fail, so update these calls to explicitly discard or
handle the returns (e.g., prefix with "_, _ =" or centralize writes via a small
helper like fprint(w io.Writer, format string, args ...any) that calls
fmt.Fprintf and discards the return). Locate the writes that reference
fmt.Fprintf(out, ...) and fmt.Fprintln(out, ...) and change them to use the
chosen pattern so the returned error is acknowledged.

273-294: Verify applyTarget safety for ConfigTargetLocal.

The ConfigTargetLocal case at line 287-291 calls a.workspaceUpdater.AddSecret() without a nil check. This is safe because buildTargetOptions() only includes the local option when workspaceUpdater != nil, but this relies on an implicit invariant.

Consider adding a defensive check or a comment documenting the invariant for future maintainers.

♻️ Optional: Add defensive nil check
 	case ConfigTargetLocal:
+		if a.workspaceUpdater == nil {
+			return fmt.Errorf("workspace updater not configured for local target")
+		}
 		if err := a.workspaceUpdater.AddSecret(secretName); err != nil {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pkg/autoconf/autoconf.go` around lines 273 - 294, The ConfigTargetLocal
branch in applyTarget calls a.workspaceUpdater.AddSecret without verifying
workspaceUpdater is non-nil, relying on buildTargetOptions to only add local
when workspaceUpdater != nil; update applyTarget to either (1) defensively check
if a.workspaceUpdater == nil and return a clear error (or skip) before calling
workspaceUpdater.AddSecret, or (2) add a concise comment above the
ConfigTargetLocal case referencing buildTargetOptions as the invariant ensuring
workspaceUpdater != nil (mentioning applyTarget, ConfigTargetLocal,
workspaceUpdater.AddSecret, and buildTargetOptions) so future maintainers
understand the implicit guarantee.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@README.md`:
- Around line 680-682: The README currently shows raw secrets inline in a shell
command ("ANTHROPIC_API_KEY=sk-ant-... GH_TOKEN=ghp_... kdn autoconf --yes");
replace that example with a safe pattern: remove literal secret values and
demonstrate using environment variables or an env-file (e.g., export
ANTHROPIC_API_KEY="<REDACTED>" && export GH_TOKEN="<REDACTED>" or reference a
.env file with a placeholder line ANTHROPIC_API_KEY=<YOUR_KEY> and
GH_TOKEN=<YOUR_TOKEN>), and optionally add a note to use secret stores (e.g., gh
secret set or CI secret mechanisms) instead of embedding credentials in command
history to avoid credential leakage.

---

Nitpick comments:
In `@pkg/autoconf/autoconf.go`:
- Around line 136-142: The fmt.Fprintf and fmt.Fprintln calls in the loop over
result.Configured and the subsequent No-secrets branch ignore their returned
(int, error) values; because out is an injected io.Writer this can fail, so
update these calls to explicitly discard or handle the returns (e.g., prefix
with "_, _ =" or centralize writes via a small helper like fprint(w io.Writer,
format string, args ...any) that calls fmt.Fprintf and discards the return).
Locate the writes that reference fmt.Fprintf(out, ...) and fmt.Fprintln(out,
...) and change them to use the chosen pattern so the returned error is
acknowledged.
- Around line 273-294: The ConfigTargetLocal branch in applyTarget calls
a.workspaceUpdater.AddSecret without verifying workspaceUpdater is non-nil,
relying on buildTargetOptions to only add local when workspaceUpdater != nil;
update applyTarget to either (1) defensively check if a.workspaceUpdater == nil
and return a clear error (or skip) before calling workspaceUpdater.AddSecret, or
(2) add a concise comment above the ConfigTargetLocal case referencing
buildTargetOptions as the invariant ensuring workspaceUpdater != nil (mentioning
applyTarget, ConfigTargetLocal, workspaceUpdater.AddSecret, and
buildTargetOptions) so future maintainers understand the implicit guarantee.

In `@pkg/config/workspaceupdater_test.go`:
- Around line 65-91: Update the two tests (TestWorkspaceUpdater_Idempotent and
TestWorkspaceUpdater_MultipleCalls_Accumulate) to stop discarding errors:
capture and check the error returned by NewWorkspaceConfigUpdater and each
AddSecret call (use variables like u, err := NewWorkspaceConfigUpdater(...) and
if err != nil { t.Fatalf(...) } and similarly check err after u.AddSecret(...));
this ensures failures produce immediate, clear test failures and easier
debugging.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: c1fe8dcd-e05b-4209-9d2b-8683559400a9

📥 Commits

Reviewing files that changed from the base of the PR and between 241e554 and 92c66f3.

⛔ Files ignored due to path filters (1)
  • go.sum is excluded by !**/*.sum
📒 Files selected for processing (20)
  • .agents/skills/working-with-autoconf/SKILL.md
  • AGENTS.md
  • README.md
  • go.mod
  • pkg/autoconf/autoconf.go
  • pkg/autoconf/autoconf_test.go
  • pkg/autoconf/detect.go
  • pkg/autoconf/detect_test.go
  • pkg/autoconf/filter.go
  • pkg/autoconf/filter_test.go
  • pkg/cmd/autoconf.go
  • pkg/cmd/autoconf_test.go
  • pkg/cmd/root.go
  • pkg/cmd/testutil/example_validator.go
  • pkg/cmd/testutil/example_validator_test.go
  • pkg/config/projectsupdater.go
  • pkg/config/projectsupdater_test.go
  • pkg/config/workspaceupdater.go
  • pkg/config/workspaceupdater_test.go
  • pkg/secretservicesetup/register.go

Comment thread README.md
@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 29, 2026

@fbricon
Copy link
Copy Markdown
Contributor

fbricon commented Apr 29, 2026

./kdn autoconf 3s
✓ workspace configuration .kaiden/workspace.json created
Detected secret "gemini" from GEMINI_API_KEY
✓ Created secret "gemini".
✓ Added secret "gemini" to global project config.

When asked to create .kaiden/workspace.json I said yes, and then set to share GEMINI_API_KEY globally. So I end up with an empty .kaiden/workspace.json file. It should only be created if necessary, i.e. when user selects workspace scope

@feloy
Copy link
Copy Markdown
Contributor Author

feloy commented Apr 29, 2026

./kdn autoconf 3s ✓ workspace configuration .kaiden/workspace.json created Detected secret "gemini" from GEMINI_API_KEY ✓ Created secret "gemini". ✓ Added secret "gemini" to global project config.

When asked to create .kaiden/workspace.json I said yes, and then set to share GEMINI_API_KEY globally. So I end up with an empty .kaiden/workspace.json file. It should only be created if necessary, i.e. when user selects workspace scope

Yes you're right, I'll change
Thanks

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
pkg/cmd/testutil/example_validator.go (1)

80-83: Optional: simplify the character-class condition for readability.

The predicate at Line 81 is correct but dense; introducing small booleans makes maintenance easier.

♻️ Suggested readability refactor
 	for _, ch := range key {
-		if !((ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z') || (ch >= '0' && ch <= '9') || ch == '_') {
+		isUpper := ch >= 'A' && ch <= 'Z'
+		isLower := ch >= 'a' && ch <= 'z'
+		isDigit := ch >= '0' && ch <= '9'
+		if !(isUpper || isLower || isDigit || ch == '_') {
 			return false
 		}
 	}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pkg/cmd/testutil/example_validator.go` around lines 80 - 83, The
character-class check inside the loop over "key" is correct but hard to read;
refactor the condition in the loop (for _, ch := range key) by introducing small
boolean locals like isUpper, isLower, isDigit and isUnderscore and then replace
the dense if with if !(isUpper || isLower || isDigit || isUnderscore) { return
false }, which preserves behavior while improving readability and
maintainability.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@pkg/autoconf/autoconf.go`:
- Around line 239-258: applyTarget currently silently ignores unknown
ConfigTarget values (returning nil), which can cause secrets to be created
without updating configs; update the applyTarget method to handle unexpected
enum values by adding a default case that returns a clear error (e.g.,
fmt.Errorf("unknown ConfigTarget: %v", target)) so callers like SelectTarget
cannot inject a bad value and cause silent failures; keep the existing branches
for ConfigTargetGlobal, ConfigTargetProject, and ConfigTargetLocal and ensure
the function returns an error for the default path.
- Around line 121-259: The writes to the provided out writer are currently
ignoring returned errors; update all fmt.Fprintf/Fprintln calls in Run,
processSecret, createSecret, addToConfig and applyTarget to check their error
return and propagate it (wrap with context, e.g. fmt.Errorf("write failed: %w")
or similar) so the command stops on broken pipes/closed writers; specifically
locate calls that print status lines (including the "Secret %q already
configured", "Detected secret %q", skip/create/added messages that use
greenCheck/greyDash, and the "No secrets detected" message) and return any write
errors instead of dropping them.

---

Nitpick comments:
In `@pkg/cmd/testutil/example_validator.go`:
- Around line 80-83: The character-class check inside the loop over "key" is
correct but hard to read; refactor the condition in the loop (for _, ch := range
key) by introducing small boolean locals like isUpper, isLower, isDigit and
isUnderscore and then replace the dense if with if !(isUpper || isLower ||
isDigit || isUnderscore) { return false }, which preserves behavior while
improving readability and maintainability.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 052c04cc-7973-4a99-ab82-e520c3aab6ae

📥 Commits

Reviewing files that changed from the base of the PR and between 92c66f3 and 8eb6ed7.

⛔ Files ignored due to path filters (1)
  • go.sum is excluded by !**/*.sum
📒 Files selected for processing (20)
  • .agents/skills/working-with-autoconf/SKILL.md
  • AGENTS.md
  • README.md
  • go.mod
  • pkg/autoconf/autoconf.go
  • pkg/autoconf/autoconf_test.go
  • pkg/autoconf/detect.go
  • pkg/autoconf/detect_test.go
  • pkg/autoconf/filter.go
  • pkg/autoconf/filter_test.go
  • pkg/cmd/autoconf.go
  • pkg/cmd/autoconf_test.go
  • pkg/cmd/root.go
  • pkg/cmd/testutil/example_validator.go
  • pkg/cmd/testutil/example_validator_test.go
  • pkg/config/projectsupdater.go
  • pkg/config/projectsupdater_test.go
  • pkg/config/workspaceupdater.go
  • pkg/config/workspaceupdater_test.go
  • pkg/secretservicesetup/register.go
✅ Files skipped from review due to trivial changes (4)
  • AGENTS.md
  • README.md
  • .agents/skills/working-with-autoconf/SKILL.md
  • go.mod
🚧 Files skipped from review as they are similar to previous changes (8)
  • pkg/cmd/root.go
  • pkg/cmd/testutil/example_validator_test.go
  • pkg/secretservicesetup/register.go
  • pkg/cmd/autoconf_test.go
  • pkg/config/projectsupdater.go
  • pkg/config/workspaceupdater_test.go
  • pkg/autoconf/filter.go
  • pkg/autoconf/detect.go

Comment thread pkg/autoconf/autoconf.go
Comment thread pkg/autoconf/autoconf.go
@feloy feloy force-pushed the autoconf-secrets branch from 662818e to 4d60a7b Compare April 29, 2026 12:50
@feloy feloy requested review from benoitf, fbricon and jeffmaury April 29, 2026 12:57
@feloy feloy force-pushed the autoconf-secrets branch 2 times, most recently from 99cdb3a to 3e8c452 Compare May 1, 2026 14:06
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 7

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@pkg/autoconf/autoconf.go`:
- Around line 253-255: The ConfigTargetLocal branch calls
a.workspaceUpdater.AddSecret without checking for nil, which can panic if
SelectTarget returns local but no workspace updater is configured; update the
case for ConfigTargetLocal in pkg/autoconf/autoconf.go to first check that
a.workspaceUpdater is not nil and return a clear error (or handle appropriately)
when it is nil, otherwise call a.workspaceUpdater.AddSecret(secretName) and
propagate any returned error (preserving the existing fmt.Errorf wrapping).

In `@pkg/autoconf/detect.go`:
- Around line 30-35: DetectedSecret is currently an exported concrete struct;
change it to an exported interface and provide an unexported concrete
implementation plus a factory: declare type DetectedSecret interface {
ServiceName() string; EnvVarName() string; Value() string }, add an unexported
struct (e.g. detectedSecretImpl) that implements those methods, and add a
constructor NewDetectedSecret(service, envVar, value string) DetectedSecret that
returns the unexported implementation; update any code referencing the struct
fields to use the interface accessor methods or the factory return type
(references: DetectedSecret, NewDetectedSecret, detectedSecretImpl).

In `@pkg/autoconf/filter.go`:
- Around line 32-46: Change the exported structs ConfiguredSecret and
FilterResult into interfaces and provide unexported concrete implementations and
constructors: define interfaces named ConfiguredSecret and FilterResult, add
unexported structs configuredSecret and filterResult that implement those
interfaces, and supply factory functions NewConfiguredSecret(...) and
NewFilterResult(...) that return the interface types. Update any creation sites
and the SecretFilter.Filter signature/return type to use the FilterResult
interface (and use NewConfiguredSecret to create configured entries), and ensure
fields (Locations, NeedsAction, Configured) are exposed via interface methods on
the new interfaces so existing callers use the methods instead of struct fields.
- Around line 104-106: The code currently treats any error from
f.store.Get(d.ServiceName) as "not in store" by setting inStore := storeErr ==
nil; instead, detect whether storeErr means "not found" vs an actual failure:
call f.store.Get(d.ServiceName), if storeErr == nil set inStore=true; else if
errors.Is(storeErr, <store.NotFoundErr> or whatever sentinel your store uses)
set inStore=false; otherwise return or propagate storeErr (do not downgrade to
NeedsAction). Update the classification logic around f.store.Get/d.ServiceName
to handle non-not-found errors by returning the error up the call stack. Ensure
you use errors.Is (or the store package's exported sentinel) rather than string
matching.

In `@pkg/cmd/autoconf.go`:
- Around line 97-101: The workspace config updater (created via
config.NewWorkspaceConfigUpdater) is being instantiated in preRun causing
.kaiden/workspace.json to be created even when the user later selects a global
target; defer creation until the user actually selects ConfigTargetLocal by
removing the NewWorkspaceConfigUpdater call from preRun and instead
instantiating a.workspaceUpdater only at the point where ConfigTargetLocal is
confirmed (e.g., in the run/command execution path or the target-selection
handler), and propagate or handle any error from that call there so you only
create the workspace updater when needed.

In `@pkg/config/workspaceupdater.go`:
- Around line 80-93: The readConfig function currently fails when workspace.json
exists but is zero-bytes or only whitespace because json.Unmarshal returns EOF;
update workspaceConfigUpdater.readConfig to treat empty or whitespace-only file
contents as an empty configuration by trimming whitespace from data (e.g.,
bytes.TrimSpace) and returning &workspace.WorkspaceConfiguration{} when the
trimmed length is zero before calling json.Unmarshal, keeping existing error
handling for other read/parse errors.

In `@pkg/project/project.go`:
- Around line 52-57: In DetectProject, when gitDetector.DetectRepository fails
and you take the non-git fallback, convert the supplied dir to an absolute path
before returning it: call filepath.Abs(dir) inside the error branch of
detector.DetectProject, handle the Abs error (e.g., if Abs returns an error,
still return the original dir as a safe fallback) and return the absolute path
string so project IDs don’t vary with the caller’s cwd; update imports to
include "path/filepath" if needed and reference the existing DetectProject
method and gitDetector.DetectRepository in your change.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: f4d5c008-cbdb-4083-9643-d591e0cf4c14

📥 Commits

Reviewing files that changed from the base of the PR and between 8eb6ed7 and 99cdb3a.

⛔ Files ignored due to path filters (1)
  • go.sum is excluded by !**/*.sum
📒 Files selected for processing (27)
  • .agents/skills/working-with-autoconf/SKILL.md
  • AGENTS.md
  • README.md
  • go.mod
  • pkg/autoconf/autoconf.go
  • pkg/autoconf/autoconf_test.go
  • pkg/autoconf/detect.go
  • pkg/autoconf/detect_test.go
  • pkg/autoconf/filter.go
  • pkg/autoconf/filter_test.go
  • pkg/cmd/autoconf.go
  • pkg/cmd/autoconf_test.go
  • pkg/cmd/root.go
  • pkg/cmd/testutil/example_validator.go
  • pkg/cmd/testutil/example_validator_test.go
  • pkg/config/projectsupdater.go
  • pkg/config/projectsupdater_test.go
  • pkg/config/workspaceupdater.go
  • pkg/config/workspaceupdater_test.go
  • pkg/instances/manager.go
  • pkg/instances/manager_project_test.go
  • pkg/instances/manager_terminal_test.go
  • pkg/instances/manager_test.go
  • pkg/project/project.go
  • pkg/project/project_test.go
  • pkg/secretservicesetup/register.go
  • pkg/secretservicesetup/register_test.go
💤 Files with no reviewable changes (1)
  • pkg/instances/manager_project_test.go
✅ Files skipped from review due to trivial changes (2)
  • pkg/config/projectsupdater.go
  • .agents/skills/working-with-autoconf/SKILL.md
🚧 Files skipped from review as they are similar to previous changes (3)
  • pkg/cmd/testutil/example_validator_test.go
  • README.md
  • pkg/autoconf/autoconf_test.go

Comment thread pkg/autoconf/autoconf.go
Comment thread pkg/autoconf/detect.go
Comment thread pkg/autoconf/filter.go
Comment thread pkg/autoconf/filter.go
Comment thread pkg/cmd/autoconf.go
Comment thread pkg/config/workspaceupdater.go
Comment thread pkg/project/project.go
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@pkg/autoconf/autoconf.go`:
- Around line 225-229: buildTargetOptions currently always adds a
ConfigTargetProject entry even when a.projectID is empty, which lets users
select "Project" but results in AddSecret("", ...) writing as global; change
buildTargetOptions to only append the {Target: ConfigTargetProject, Label: ...}
option when a.projectID != "" and add a defensive check where the project-target
is handled (the code path that calls AddSecret / the project-branch logic
referenced around lines 247-249) to reject or error if
Target==ConfigTargetProject but a.projectID == "" so we never perform a silent
project-scoped write with an empty project ID.

In `@pkg/autoconf/filter_test.go`:
- Around line 400-403: Replace the weak length-only assertion on
got.Configured[0].Locations with a concrete equality check against the exact
expected order [ConfigTargetProject, ConfigTargetLocal]; e.g., compare locs
(from got.Configured[0].Locations) to the expected slice using reflect.DeepEqual
(import reflect if needed) or the testing/compare utility and call t.Errorf or
t.Fatalf with both expected and actual when they differ so the test fails if the
wrong pair (like global+local) is returned.

In `@pkg/config/workspaceupdater_test.go`:
- Around line 205-207: The test uses os.Getuid() which is unavailable on Windows
and causes compile errors; either add a platform build constraint (add
//go:build !windows at the top of workspaceupdater_test.go before the package
declaration) to exclude the file on Windows, or replace the os.Getuid() check
with a cross-platform alternative (use user.Current() from the os/user package
and inspect u.Uid or compare u.Username to detect root-equivalent) and update
the test guard around that code (references: os.Getuid(),
workspaceupdater_test.go test function containing the runtime skip).

In `@pkg/project/project_test.go`:
- Around line 35-47: The test TestDetectProject_NotGitRepo assumes DetectProject
returns the literal "/some/dir", but DetectProject normalizes paths with
filepath.Abs; update the test to compute the expected absolute path instead of
hardcoding "/some/dir": inside TestDetectProject_NotGitRepo call
filepath.Abs("/some/dir") (handle the returned error with t.Fatal or t.Fatalf)
to produce expected, then compare got to that expected; reference functions:
TestDetectProject_NotGitRepo, detect, and DetectProject.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 95d826e9-b18b-4339-9b90-418b9d35d4e1

📥 Commits

Reviewing files that changed from the base of the PR and between 99cdb3a and e78f78b.

📒 Files selected for processing (20)
  • .agents/skills/cross-platform-development/SKILL.md
  • .agents/skills/working-with-autoconf/SKILL.md
  • AGENTS.md
  • README.md
  • pkg/autoconf/autoconf.go
  • pkg/autoconf/autoconf_test.go
  • pkg/autoconf/detect_test.go
  • pkg/autoconf/filter.go
  • pkg/autoconf/filter_test.go
  • pkg/cmd/autoconf.go
  • pkg/cmd/autoconf_test.go
  • pkg/config/projectsupdater_test.go
  • pkg/config/workspaceupdater.go
  • pkg/config/workspaceupdater_test.go
  • pkg/instances/manager.go
  • pkg/instances/manager_project_test.go
  • pkg/instances/manager_terminal_test.go
  • pkg/instances/manager_test.go
  • pkg/project/project.go
  • pkg/project/project_test.go
💤 Files with no reviewable changes (1)
  • pkg/instances/manager_project_test.go
✅ Files skipped from review due to trivial changes (4)
  • .agents/skills/working-with-autoconf/SKILL.md
  • pkg/cmd/autoconf.go
  • README.md
  • pkg/instances/manager_terminal_test.go
🚧 Files skipped from review as they are similar to previous changes (3)
  • AGENTS.md
  • pkg/autoconf/filter.go
  • pkg/instances/manager_test.go

Comment thread pkg/autoconf/autoconf.go
Comment thread pkg/autoconf/filter_test.go
Comment thread pkg/config/workspaceupdater_test.go
Comment thread pkg/project/project_test.go
@feloy
Copy link
Copy Markdown
Contributor Author

feloy commented May 4, 2026

@benoitf @jeffmaury @fbricon this PR is ready for review

feloy and others added 10 commits May 5, 2026 16:46
Scans registered secret services' environment variables, classifies
detected secrets against the store and all config sources (global,
project-specific, local workspace.json), and for each unset secret
confirms creation and prompts for a config target. --yes skips all
prompts and defaults to the global config.

New supporting types: ProjectConfigUpdater, WorkspaceConfigUpdater
(pkg/config), ListServices() (secretservicesetup), and a
"Configuration Commands" group in the root command.

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Philippe Martin <phmartin@redhat.com>
…on demand

Removed the upfront workspace init prompt and WorkspaceFileExists flag.
WorkspaceConfigUpdater.AddSecret already handles a missing file via
MkdirAll, so the local target is now always listed and the file is
created only if the user actually selects it.

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Philippe Martin <phmartin@redhat.com>
Adds tests for preRun dependency wiring (store, updater, detector,
confirm, selectTarget, projectID), the preRun nil-guard for
injected detectors, run() with no secrets and with --yes, and all
four detectProjectID scenarios (non-git, no-remote, with-remote,
with-remote + subdir).

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Philippe Martin <phmartin@redhat.com>
…ilable/ListServices

Adds tests for the four previously uncovered functions:
listServicesWithFactories, listAvailableWithFactories, ListAvailable,
and ListServices. Coverage rises from 59% to 94%.

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Philippe Martin <phmartin@redhat.com>
t.TempDir() on macOS returns paths under /var/folders/... which is a
symlink to /private/var/..., while git rev-parse --show-toplevel
resolves to the real path. Calling filepath.EvalSymlinks on the temp
dir before use ensures the paths match and the relative-path
computation produces the expected result.

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Philippe Martin <phmartin@redhat.com>
…ctor

instances.manager.detectProject and cmd.detectProjectID contained
identical logic for computing a project identifier from a source
directory. The new pkg/project package exposes a Detector interface
backed by git.Detector, giving both callers a single authoritative
implementation with its own test suite.

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Philippe Martin <phmartin@redhat.com>
Signed-off-by: Philippe Martin <phmartin@redhat.com>
- Propagate non-ErrSecretNotFound store.Get errors in filter.go
  instead of silently treating backend failures as "not in store"
- Guard ConfigTargetLocal against nil workspaceUpdater in applyTarget
- Add default case to applyTarget to reject unknown ConfigTarget values
- Treat empty/whitespace-only workspace.json as missing in readConfig
- Normalize non-git dir to absolute path in project.DetectProject
- Replace raw inline secrets in examples with command substitution

Tests added for each new behaviour.

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Philippe Martin <phmartin@redhat.com>
The hardcoded Unix path "/some/dir" was converted to a
drive-prefixed Windows path by filepath.Abs, causing the test to
fail on Windows. Using t.TempDir() provides a real absolute path
that is stable across all platforms.

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Philippe Martin <phmartin@redhat.com>
buildTargetOptions was always adding the "Project" option even when no
project was detected; selecting it called AddSecret("", ...), silently
writing to the global scope instead. The project option is now
conditional on projectID != "", and applyTarget returns an explicit
error if the project target is somehow selected with an empty ID.

Also tightens TestFilter_ProjectScopedLocation_WithLocal to assert the
actual location values, fixes discarded errors in two workspace updater
test setups, and simplifies the char-class condition in
isEnvVarAssignment.

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Philippe Martin <phmartin@redhat.com>
@feloy feloy force-pushed the autoconf-secrets branch from c40e839 to 911fdce Compare May 5, 2026 14:46
@feloy feloy merged commit 781891a into openkaiden:main May 5, 2026
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants