Skip to content

feat(cli): show credential auth status in tool info - #1572

Merged
ilblackdragon merged 6 commits into
stagingfrom
feat/tool-info-auth-status
Mar 25, 2026
Merged

ilblackdragon merged 6 commits into
stagingfrom
feat/tool-info-auth-status

Conversation

@ilblackdragon

@ilblackdragon ilblackdragon commented Mar 22, 2026 •

Copy link
Copy Markdown
Member

Summary

  • ironclaw tool info <name> now checks the secrets store and shows whether each required credential is configured or missing
  • Consolidates credentials from http.credentials, auth, and setup.required_secrets into a single deduplicated Auth section with ✓ configured / ✗ missing status
  • Secrets already shown in Auth are filtered from the Secrets section to avoid redundancy

Before

  Credentials:
    github_token: github_token -> Bearer
  Secrets (existence check only):
    github_token
    github_*
  Auth: GitHub [github_token]
  Required secrets:
    github_token: GitHub Personal Access Token (...)

After

  Secrets (existence check only):
    github_*
  Auth:
    github_token (GitHub) -> AuthorizationBearer  ✗ missing

Test plan

  • Run ironclaw tool info <tool_with_auth> — verify single Auth section with status
  • Run ironclaw tool info <tool_without_auth> — verify no Auth section appears
  • Store a credential via ironclaw tool auth, re-run tool info — verify ✓ configured
  • Verify secrets section only shows entries not already in Auth (e.g. wildcards)

🤖 Generated with Claude Code

`ironclaw tool info` now checks the secrets store and shows whether
each required credential is configured or missing, consolidated into
a single Auth section that deduplicates across http.credentials,
auth, and setup.required_secrets. Secrets already shown in Auth are
filtered from the Secrets section to avoid redundancy.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings March 22, 2026 20:09

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot wasn't able to review this pull request because it exceeds the maximum number of lines (20,000). Try reducing the number of changed lines and requesting a review from Copilot again.

@github-actions github-actions Bot added scope: agent Agent core (agent loop, router, scheduler) scope: channel Channel infrastructure scope: channel/cli TUI / CLI channel scope: channel/web Web gateway channel scope: channel/wasm WASM channel runtime scope: tool Tool infrastructure scope: tool/builtin Built-in tools scope: tool/wasm WASM tool sandbox scope: db Database trait / abstraction scope: db/postgres PostgreSQL backend scope: db/libsql libSQL / Turso backend scope: llm LLM integration scope: workspace Persistent memory / workspace scope: worker Container worker scope: config Configuration scope: extensions Extension management scope: setup Onboarding / setup scope: docs Documentation scope: dependencies Dependency updates size: XL 500+ changed lines risk: high Safety, secrets, auth, or critical infrastructure contributor: core 20+ merged PRs labels Mar 22, 2026
@ilblackdragon
ilblackdragon changed the base branch from main to staging March 22, 2026 20:11
@ilblackdragon
ilblackdragon requested a review from Copilot March 22, 2026 20:11
@gemini-code-assist

Copy link
Copy Markdown
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly improves the user experience for managing tool authentication by centralizing and clarifying credential status checks within the ironclaw tool info command. It streamlines the display of authentication-related information, making it easier for users to understand the setup requirements and current status of their tools.

Highlights

  • Enhanced Tool Information: The ironclaw tool info <name> command now provides a consolidated view of authentication statuses, checking the secrets store and indicating whether each required credential is configured or missing.
  • Consolidated Auth Status: Credentials from http.credentials, auth, and setup.required_secrets are now grouped into a single, deduplicated 'Auth' section with clear '✓ configured' or '✗ missing' statuses.
  • Reduced Redundancy: Secrets already displayed in the 'Auth' section are filtered from the general 'Secrets' section to avoid repetitive information.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution. ↩

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request enhances the ironclaw tool info command to display the configuration status of required credentials, consolidating information from various parts of the capabilities file into a unified 'Auth' section. The implementation is solid and achieves the goal described. I've suggested a refactoring to the logic that collects and deduplicates secrets to use a HashMap instead of a HashSet and linear scans. This would improve code clarity and performance, especially as the number of secrets grows.

Comment thread src/cli/tool.rs Outdated
Comment on lines +503 to +546
let mut auth_secrets: Vec<AuthSecretInfo> = Vec::new();
let mut seen: std::collections::HashSet<String> = std::collections::HashSet::new();

// auth.display_name is the best label — seed first.
if let Some(ref auth) = caps.auth {
seen.insert(auth.secret_name.clone());
auth_secrets.push(AuthSecretInfo {
secret_name: auth.secret_name.clone(),
description: auth.display_name.clone(),
location: None,
});
}

// setup.required_secrets.prompt is second-best label.
if let Some(ref setup) = caps.setup {
for secret in &setup.required_secrets {
if seen.insert(secret.name.clone()) {
auth_secrets.push(AuthSecretInfo {
secret_name: secret.name.clone(),
description: Some(secret.prompt.clone()),
location: None,
});
}
}
}

// Merge injection location from http.credentials.
if let Some(ref http) = caps.http {
for cred in http.credentials.values() {
let loc = format!("{:?}", cred.location);
if let Some(existing) = auth_secrets
.iter_mut()
.find(|s| s.secret_name == cred.secret_name)
{
existing.location = Some(loc);
} else if seen.insert(cred.secret_name.clone()) {
auth_secrets.push(AuthSecretInfo {
secret_name: cred.secret_name.clone(),
description: None,
location: Some(loc),
});
}
}
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

The current logic for collecting and deduplicating authentication secrets from different parts of the capabilities file is a bit complex. It uses a HashSet to track seen secrets and a linear scan (find) within a loop to update existing entries. This can be simplified and made more efficient by using a HashMap to map secret names to their index in the auth_secrets vector. This avoids the O(n) scan for each credential and makes the logic for updating vs. inserting more direct.

    let mut auth_secrets: Vec<AuthSecretInfo> = Vec::new();
    let mut seen: std::collections::HashMap<String, usize> = std::collections::HashMap::new();

    // auth.display_name is the best label — seed first.
    if let Some(ref auth) = caps.auth {
        let index = auth_secrets.len();
        seen.insert(auth.secret_name.clone(), index);
        auth_secrets.push(AuthSecretInfo {
            secret_name: auth.secret_name.clone(),
            description: auth.display_name.clone(),
            location: None,
        });
    }

    // setup.required_secrets.prompt is second-best label.
    if let Some(ref setup) = caps.setup {
        for secret in &setup.required_secrets {
            if !seen.contains_key(&secret.name) {
                let index = auth_secrets.len();
                seen.insert(secret.name.clone(), index);
                auth_secrets.push(AuthSecretInfo {
                    secret_name: secret.name.clone(),
                    description: Some(secret.prompt.clone()),
                    location: None,
                });
            }
        }
    }

    // Merge injection location from http.credentials.
    if let Some(ref http) = caps.http {
        for cred in http.credentials.values() {
            let loc = format!("{:?}", cred.location);
            if let Some(&index) = seen.get(&cred.secret_name) {
                auth_secrets[index].location = Some(loc);
            } else {
                let index = auth_secrets.len();
                seen.insert(cred.secret_name.clone(), index);
                auth_secrets.push(AuthSecretInfo {
                    secret_name: cred.secret_name.clone(),
                    description: None,
                    location: Some(loc),
                });
            }
        }
    }

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Resolved in 4a3c1ec — switched to HashMap<String, usize> for O(1) index lookup, and extracted into collect_auth_secrets() helper in 9632302.

Comment thread src/cli/tool.rs Outdated
let extra: Vec<_> = secrets
.allowed_names
.iter()
.filter(|name| !seen.contains(name.as_str()))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

If you adopt my other suggestion to use a HashMap for the seen collection, you will also need to update this line to use contains_key to check for the presence of a secret.

            .filter(|name| !seen.contains_key(name.as_str()))

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Resolved — the filtering now uses collected.seen_names: HashSet which uses .contains() correctly.

Copilot AI review requested due to automatic review settings March 23, 2026 22:01
@github-actions github-actions Bot added size: L 200-499 changed lines and removed size: M 50-199 changed lines labels Mar 23, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated 3 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/cli/tool.rs Outdated
Comment on lines +439 to +445
let secrets_store = match init_secrets_store().await {
Ok(store) => Some(store),
Err(e) => {
eprintln!(" Warning: could not init secrets store: {}", e);
None
}
};

Copilot AI Mar 23, 2026

Copy link

Choose a reason for hiding this comment

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

tool info initializes the secrets store unconditionally; when secrets are not configured (e.g., missing SECRETS_MASTER_KEY), this will emit a warning even for tools that have no auth-related secrets. Consider lazily initializing the secrets store only if the parsed capabilities actually contain auth/setup/http.credentials secrets that you plan to check.

Copilot uses AI. Check for mistakes.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Resolved in 9632302 — secrets store is now lazily initialized only when caps.auth, caps.setup.required_secrets, or caps.http.credentials are present.

Comment thread src/cli/tool.rs Outdated
}

// Only filter secrets already in auth when we will actually render the Auth section.
let will_render_auth = secrets_store.is_some() && !auth_secrets.is_empty();

Copilot AI Mar 23, 2026

Copy link

Choose a reason for hiding this comment

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

Auth output is currently gated on secrets_store.is_some(). If secrets store initialization fails, the Auth: section is suppressed entirely, which can hide required credential names/locations that are still useful to display. Consider always rendering the consolidated Auth section when auth_secrets is non-empty, using an unknown status (or similar) when the store is unavailable, and still applying the Secrets-section dedupe accordingly.

Suggested change
let will_render_auth = secrets_store.is_some() && !auth_secrets.is_empty();
let will_render_auth = !auth_secrets.is_empty();

Copilot uses AI. Check for mistakes.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Resolved in 9632302 — Auth section is always rendered when auth_secrets is non-empty, using ? unknown when the store is unavailable. Secrets-section dedupe is also applied unconditionally now since Auth always renders.

Comment thread src/cli/tool.rs Outdated
Comment on lines +1303 to +1344
// Build auth_secrets the same way print_capabilities_detail does.
let mut auth_secrets: Vec<AuthSecretInfo> = Vec::new();
let mut seen: std::collections::HashMap<String, usize> = std::collections::HashMap::new();

if let Some(ref auth) = caps.auth {
let index = auth_secrets.len();
seen.insert(auth.secret_name.clone(), index);
auth_secrets.push(AuthSecretInfo {
secret_name: auth.secret_name.clone(),
description: auth.display_name.clone(),
location: None,
});
}
if let Some(ref setup) = caps.setup {
for secret in &setup.required_secrets {
if !seen.contains_key(&secret.name) {
let index = auth_secrets.len();
seen.insert(secret.name.clone(), index);
auth_secrets.push(AuthSecretInfo {
secret_name: secret.name.clone(),
description: Some(secret.prompt.clone()),
location: None,
});
}
}
}
if let Some(ref http) = caps.http {
for cred in http.credentials.values() {
let loc = format!("{:?}", cred.location);
if let Some(&index) = seen.get(&cred.secret_name) {
auth_secrets[index].location = Some(loc);
} else {
let index = auth_secrets.len();
seen.insert(cred.secret_name.clone(), index);
auth_secrets.push(AuthSecretInfo {
secret_name: cred.secret_name.clone(),
description: None,
location: Some(loc),
});
}
}
}

Copilot AI Mar 23, 2026

Copy link

Choose a reason for hiding this comment

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

This test re-implements the auth-secret collection logic inline rather than exercising print_capabilities_detail (or a shared helper), so it can pass even if the production dedup/merge behavior diverges. Consider extracting the auth-secret collection/dedup (and secrets filtering decision) into a helper that returns structured data, and unit test that helper directly (and/or capture/assert rendered output).

Copilot uses AI. Check for mistakes.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Resolved in 9632302 — extracted collect_auth_secrets() helper that returns CollectedAuthSecrets. Test now calls this helper directly instead of re-implementing the logic. Also added test_collect_auth_secrets_empty_caps for the empty-capabilities edge case.

ilblackdragon and others added 2 commits March 23, 2026 15:25
…h section

Address review feedback:
- Extract dedup logic into `collect_auth_secrets()` so the test exercises
  the same code path as production (not a re-implementation)
- Always render the Auth section when auth secrets exist, showing
  "? unknown" status when the secrets store is unavailable instead of
  hiding credential names entirely
- Lazily init secrets store only when capabilities contain auth secrets,
  avoiding spurious warnings for tools with no auth
- Add test for empty capabilities edge case

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings March 24, 2026 00:34
@ilblackdragon

Copy link
Copy Markdown
Member Author

Addressing @zmanian's review suggestions:

  1. Inline HashMap import — Fixed in 81b8546: moved HashMap/HashSet to top-level imports.
  2. format!("{:?}") for CredentialLocation — CredentialLocation doesn't have a Display impl today; adding one would be a separate PR touching src/secrets/types.rs. Keeping Debug for now — it produces AuthorizationBearer, Header { name: "X-Token" } etc. which are reasonably readable.
  3. Unicode symbols on Windows — Good point. The tool is primarily used in terminals that support UTF-8, and the Windows CI builds pass. Can revisit with ASCII fallbacks if users report issues.
  4. Tests — Added in 9632302 with extracted collect_auth_secrets() helper + two unit tests.

@zmanian zmanian left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Code Review — show credential auth status in tool info

+268 / -14 in src/cli/tool.rs. Adds credential status checking (✓ configured / ✗ missing) to ironclaw tool info. Nice UX improvement.


Issues

1. Secrets store errors silently suppress Auth section (medium)

When init_secrets_store() fails (commands.rs:451-454), secrets_store is None and print_capabilities_detail receives no store. The Auth section then shows ? unknown for every secret. This is handled, but the eprintln! warning could be easy to miss in a wall of output.

More importantly, collect_auth_secrets still runs and populates seen_names, so secrets covered by auth entries are filtered from the Secrets section — but their status is shown as ? unknown. The user loses information about which secrets are needed. Consider showing the Auth section with ? unknown status AND keeping those entries in the Secrets section when the store is unavailable.

2. --user flag defaults to "default" silently (low-medium)

The --user flag (tool.rs:83) defaults to "default", but ironclaw tool auth --user X can store credentials under any user ID. A user who ran tool auth --user myid will see ✗ missing in tool info unless they also pass --user myid. Consider documenting this in the --help text, e.g., "Must match the --user used with tool auth".

3. Debug formatting for credential location (low)

format!("{:?}", cred.location) (tool.rs:580) uses Rust's Debug trait, producing output like AuthorizationBearer — which is the variant name without spaces. If CredentialLocation has a Display impl, prefer that. If not, this is fine but slightly jarring for users.

4. Test exercises collection logic but not rendering (low)

test_auth_secret_dedup_and_status (tool.rs:1305) tests collect_auth_secrets and the store's exists() method, but doesn't exercise print_capabilities_detail. The dedup logic could diverge from the rendering path. This is acceptable for a first pass — the collection function is the interesting part.


What's good

  • Lazy secrets store init: only initializes when auth sections exist (avoids errors for tools without auth)
  • Clean dedup with priority: auth.display_name > setup.prompt, injection location merged from http.credentials
  • Secrets section filtering: removes entries already shown in Auth, keeps wildcards (gh_*)
  • Sorted output: collected.secrets.sort_by(...) gives deterministic output
  • Good test coverage: dedup, empty caps, store integration with create/exists

Verdict

Approve. No blocking issues. Item 1 (store failure suppressing auth info) is the main thing to consider improving, but the current ? unknown fallback is reasonable for a v1.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated 1 comment.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/cli/tool.rs Outdated
"credentials": {
"github": {
"secret_name": "gh_token",
"location": "AuthorizationBearer",

Copilot AI Mar 24, 2026

Copy link

Choose a reason for hiding this comment

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

The JSON fixture in test_auth_secret_dedup_and_status uses an invalid http.credentials.*.location value ("AuthorizationBearer"). In the capabilities schema, location is a tagged object (e.g. { "type": "bearer" }, { "type": "header", ... }), so CapabilitiesFile::from_json(...).unwrap() will panic and the test will fail. Update the fixture to use the correct schema representation for location (and, if you expect the rendered output to say AuthorizationBearer, adjust the rendering logic accordingly; today it will format the schema variant as Bearer).

Suggested change
"location": "AuthorizationBearer",
"location": { "type": "bearer" },

Copilot uses AI. Check for mistakes.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Fixed in 19c118d — updated test fixture to use {"type": "bearer"} which matches the CredentialLocationSchema tagged enum format.

The CredentialLocationSchema uses serde tagged enum format
({"type": "bearer"}), not a bare string ("AuthorizationBearer").

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@ilblackdragon

Copy link
Copy Markdown
Member Author

@zmanian Thanks for both reviews. Here's where each item landed:

First review (non-blocking suggestions):

  1. Tests — Added in 9632302. Extracted collect_auth_secrets() helper and test it directly with test_auth_secret_dedup_and_status + test_collect_auth_secrets_empty_caps.
  2. Unicode symbols on Windows — Noted. Windows CI builds pass; will add ASCII fallbacks if users report rendering issues.
  3. Debug formatting for CredentialLocation — No Display impl exists on the type today. Adding one would touch src/secrets/types.rs which is out of scope. The Debug output (Bearer, Header { name: "X-Token" }) is readable enough for now.
  4. Inline HashMap import — Fixed in 81b8546, moved to top-level imports.

Second review (4 issues):

  1. Store failure suppressing Auth section — The Auth section now always renders with ? unknown when the store is unavailable (9632302). The Secrets-section dedupe is also always applied since Auth always renders — so credential names are never hidden. Your suggestion to also keep them in the Secrets section is a fair point, but showing them twice (once as ? unknown in Auth, once in Secrets) felt redundant. Happy to revisit if you feel strongly.
  2. --user flag help text — Good call. Will improve the help string in a follow-up.
  3. Debug formatting — Same as above, no Display impl available. Tracked for a separate PR.
  4. Test covers collection but not rendering — Agreed this is acceptable for v1. The extracted collect_auth_secrets() is the critical logic; rendering is a thin println layer on top.

@ilblackdragon
ilblackdragon requested a review from zmanian March 24, 2026 15:38
@ilblackdragon
ilblackdragon merged commit 6561517 into staging Mar 25, 2026
14 checks passed
@ilblackdragon
ilblackdragon deleted the feat/tool-info-auth-status branch March 25, 2026 06:01
bkutasi pushed a commit to bkutasi/ironclaw that referenced this pull request Mar 28, 2026
* feat(cli): show credential auth status in `tool info`

`ironclaw tool info` now checks the secrets store and shows whether
each required credential is configured or missing, consolidated into
a single Auth section that deduplicates across http.credentials,
auth, and setup.required_secrets. Secrets already shown in Auth are
filtered from the Secrets section to avoid redundancy.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(cli): address review feedback on tool info auth status

- Fix clippy collapsible-if by using `if let` + `&&`
- Use HashMap<String, usize> for O(1) dedup instead of HashSet + linear scan
- Add --user flag to `tool info` for checking non-default user credentials
- Show "? unknown" on secrets store errors instead of silently reporting missing
- Surface secrets store init failure via eprintln instead of silent .ok()
- Sort auth entries by secret name for deterministic output

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(cli): only filter secrets when auth section renders, add regression test

When the secrets store fails to initialize, the Auth section is not
rendered. Previously, secret names were still filtered from the Secrets
section, causing credential names to disappear entirely. Now secrets
are only filtered when the Auth section will actually be displayed.

Adds test verifying auth secret deduplication across auth, setup, and
http.credentials sections, plus secrets store existence checks.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* refactor(cli): extract collect_auth_secrets helper, always render Auth section

Address review feedback:
- Extract dedup logic into `collect_auth_secrets()` so the test exercises
  the same code path as production (not a re-implementation)
- Always render the Auth section when auth secrets exist, showing
  "? unknown" status when the secrets store is unavailable instead of
  hiding credential names entirely
- Lazily init secrets store only when capabilities contain auth secrets,
  avoiding spurious warnings for tools with no auth
- Add test for empty capabilities edge case

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* style(cli): move HashMap/HashSet imports to top of file

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(cli): use correct tagged JSON format for credential location in test

The CredentialLocationSchema uses serde tagged enum format
({"type": "bearer"}), not a bare string ("AuthorizationBearer").

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
drchirag1991 pushed a commit to drchirag1991/ironclaw that referenced this pull request Apr 8, 2026
* feat(cli): show credential auth status in `tool info`

`ironclaw tool info` now checks the secrets store and shows whether
each required credential is configured or missing, consolidated into
a single Auth section that deduplicates across http.credentials,
auth, and setup.required_secrets. Secrets already shown in Auth are
filtered from the Secrets section to avoid redundancy.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(cli): address review feedback on tool info auth status

- Fix clippy collapsible-if by using `if let` + `&&`
- Use HashMap<String, usize> for O(1) dedup instead of HashSet + linear scan
- Add --user flag to `tool info` for checking non-default user credentials
- Show "? unknown" on secrets store errors instead of silently reporting missing
- Surface secrets store init failure via eprintln instead of silent .ok()
- Sort auth entries by secret name for deterministic output

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(cli): only filter secrets when auth section renders, add regression test

When the secrets store fails to initialize, the Auth section is not
rendered. Previously, secret names were still filtered from the Secrets
section, causing credential names to disappear entirely. Now secrets
are only filtered when the Auth section will actually be displayed.

Adds test verifying auth secret deduplication across auth, setup, and
http.credentials sections, plus secrets store existence checks.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* refactor(cli): extract collect_auth_secrets helper, always render Auth section

Address review feedback:
- Extract dedup logic into `collect_auth_secrets()` so the test exercises
  the same code path as production (not a re-implementation)
- Always render the Auth section when auth secrets exist, showing
  "? unknown" status when the secrets store is unavailable instead of
  hiding credential names entirely
- Lazily init secrets store only when capabilities contain auth secrets,
  avoiding spurious warnings for tools with no auth
- Add test for empty capabilities edge case

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* style(cli): move HashMap/HashSet imports to top of file

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(cli): use correct tagged JSON format for credential location in test

The CredentialLocationSchema uses serde tagged enum format
({"type": "bearer"}), not a bare string ("AuthorizationBearer").

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

contributor: core 20+ merged PRs risk: low Changes to docs, tests, or low-risk modules scope: agent Agent core (agent loop, router, scheduler) scope: channel/cli TUI / CLI channel scope: channel/wasm WASM channel runtime scope: channel/web Web gateway channel scope: channel Channel infrastructure scope: config Configuration scope: db/libsql libSQL / Turso backend scope: db/postgres PostgreSQL backend scope: db Database trait / abstraction scope: dependencies Dependency updates scope: docs Documentation scope: extensions Extension management scope: llm LLM integration scope: setup Onboarding / setup scope: tool/builtin Built-in tools scope: tool/wasm WASM tool sandbox scope: tool Tool infrastructure scope: worker Container worker scope: workspace Persistent memory / workspace size: L 200-499 changed lines

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants