Skip to content

feat: project-scoped Jira credentials, check_integrations tool, and docs update - #76

Merged
ablanrob merged 5 commits into
mainfrom
feat/jira-credentials-safety
Apr 24, 2026
Merged

ablanrob merged 5 commits into
mainfrom
feat/jira-credentials-safety

Conversation

@ablanrob

Copy link
Copy Markdown
Owner

Summary

Implements feedback items #4 (Project-Scoped Jira Credentials) and #5 (Integration Health Check / Credential Safety), plus documentation updates covering all changes from this session.

Project-scoped Jira credentials (#4)

Jira host and email can now be set per-project in .marvin/config.yaml, overriding user config and environment variables. Resolution chain: project config → user config → env vars.

The API token is intentionally excluded from project config to prevent committing secrets — it stays in user config (~/.config/marvin/config.yaml) or JIRA_API_TOKEN env var.

Backward-compatible: the legacy createJiraClient(userConfig) signature still works unchanged.

Integration health check (#5)

New check_integrations MCP tool that reports which credentials are configured without exposing secret values. Returns:

  • Host value and source (project/user/env)
  • Email configured (bool) and source
  • API token configured (bool) and source
  • Project key

This prevents agents from reading ~/.claude/mcp.json or other config files to check Jira setup.

Documentation updates

Updated 5 doc pages covering all changes from this session (PRs #72-#75):

  • personas.md — PO use-case type, DM Sprint 0 guidance
  • mcp-server.md — diagnostic tools table
  • configuration.md — project Jira overrides, AEM phase, credential resolution, env vars
  • jira.md — project-scoped credentials, check_integrations example
  • getting-started.md — onboarding tools

Test plan

  • 848 tests pass (838 existing + 10 new)
  • test/skills/jira/client-project.test.ts — 10 tests: project override priority, fallback chain, legacy compat, resolveJiraStatus safety
  • Existing 16 client tests still pass (backward compatibility)
  • Manual: set jira.host in project config, verify it takes priority over user config
  • Manual: run check_integrations and verify no secrets appear in output

Implements feedback items #4 (Project-Scoped Jira Credentials) and
#5 (Integration Health Check / Credential Safety).

Project-scoped credentials (#4):
- Add host and email to JiraProjectConfig for per-project overrides
- Resolution chain: project config → user config → env vars
- API token intentionally excluded from project config (stays in
  env vars or user config for security)
- Backward-compatible: legacy (user-only) signature still works

Integration health check (#5):
- New check_integrations tool reports credential status without
  exposing secrets — shows configured (bool), source (project/user/env),
  and host value but never email addresses or API tokens
- Prevents agents from reading ~/.claude/mcp.json to check config
- Confluence status derived from Jira credentials (same Atlassian auth)
… credentials

- personas.md: PO now includes use-case doc type; DM has Sprint 0 section
- mcp-server.md: document diagnostic tools (run_doctor, check_project_health,
  get_started, check_integrations)
- configuration.md: add jira.host/email project overrides, aem.currentPhase,
  credential resolution chain, Jira env vars
- jira.md: project-scoped credentials, check_integrations usage example
- getting-started.md: mention get_started and check_project_health tools
@coderabbitai

coderabbitai Bot commented Apr 23, 2026

Copy link
Copy Markdown

Warning

Rate limit exceeded

@ablanrob has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 34 minutes and 38 seconds before requesting another review.

Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 34 minutes and 38 seconds.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: d42275d7-35c7-42cd-8dc5-91d71047bd2a

📥 Commits

Reviewing files that changed from the base of the PR and between dc548e9 and fa993ae.

📒 Files selected for processing (2)
  • docs/guides/jira.md
  • src/skills/builtin/jira/client.ts
📝 Walkthrough

Walkthrough

Adds per-project Jira credential overrides with deterministic resolution (project → user → env), refactors Jira client and tools to consume merged credential sources, introduces a read-only MCP tool check_integrations to report integration configuration provenance, updates session allowlist, tests, and supporting documentation.

Changes

Cohort / File(s) Summary
Documentation guides
docs/guides/getting-started.md, docs/guides/jira.md, docs/guides/mcp-server.md, docs/guides/personas.md, docs/reference/configuration.md
Added onboarding/checklist and governance diagnostics docs, documented Jira env vars and per-project overrides, described credential precedence and aem.currentPhase usage.
Configuration schema
src/core/config.ts
Added optional host and email to JiraProjectConfig to allow per-project Jira settings.
Jira client core
src/skills/builtin/jira/client.ts
Refactored createJiraClient to accept JiraConfigSources (project + user + env fallback), added resolveJiraStatus to report configured flags and provenance, and retained backward-compatible input handling via a type guard.
Jira tools integration
src/skills/builtin/jira/tools.ts
Tools now build a unified jiraSources (project + user) and instantiate the client via createJiraClient(jiraSources); fetch_jira_statuses now uses jira.client.searchIssuesV3 and wraps calls in try/catch.
Diagnostic tool
src/agent/tools/doctor.ts
Added check_integrations MCP tool that loads user/project config, calls resolveJiraStatus, and returns structured Jira/Confluence configuration presence and source metadata (no secrets).
Session configuration
src/agent/session.ts
Added mcp__marvin-governance__check_integrations to the MCP tool allowlist.
Test suite
test/skills/jira/client-project.test.ts
New Vitest coverage for resolution precedence, fallback behaviors, host normalization, source reporting, and legacy-argument compatibility for createJiraClient and resolveJiraStatus.
Package metadata
package.json
Bumped package version from 0.6.1 to 0.6.2.

Sequence Diagram(s)

sequenceDiagram
  participant Agent
  participant MCP as MCP/doctor tool
  participant Config as Project/User Config
  participant JiraClient as Jira client / Env

  Agent->>MCP: invoke check_integrations
  MCP->>Config: load project + user config
  MCP->>JiraClient: resolveJiraStatus(sources)
  JiraClient-->>MCP: status (host/email/apiToken configured + source)
  MCP-->>Agent: structured result (no secrets, provenance metadata)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~40 minutes

Possibly related PRs

Poem

🐰 Hop, hop, the configs align,
Project, user, env in tidy line.
A rabbit checks integrations with a grin,
Secrets safe — only provenance peeks in.
Hooray for tools that help us begin!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 28.57% 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 accurately summarizes the main changes: project-scoped Jira credentials, a new check_integrations tool, and documentation updates—all of which are core to this PR.
Description check ✅ Passed The description provides a thorough summary, detailed changes per feature, test plan results, and checklist completion—addressing the required template structure comprehensively.
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.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/jira-credentials-safety

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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/skills/builtin/jira/tools.ts (1)

764-781: ⚠️ Potential issue | 🟠 Major

fetch_jira_statuses bypasses the new credential resolution chain.

Unlike the surrounding tools (which now use createJiraClient(jiraSources)), this block hand-rolls Basic auth using jiraUserConfig?.email/apiToken and env vars directly. That has two consequences:

  1. Project-scoped email override is ignored here. If a user relies on .marvin/config.yaml for a per-project email (the new feature this PR introduces), fetch_jira_statuses will authenticate with the wrong (or missing) identity, while other tools resolve correctly.
  2. Non-null assertions (!) on undefined values produce an "undefined:undefined" Basic header at runtime rather than a clean "not configured" error. createJiraClient already returns null in that case (handled via jiraNotConfiguredError()), so the early null-check is misleading — by the time we reach line 769, only the user config's email/token are considered.

Consider exposing the resolved credentials from createJiraClient (or a sibling helper) so this tool can reuse them, or switch to jira.client for the search instead of a raw fetch.

♻️ Sketch
-        const jira = createJiraClient(jiraSources);
+        const jira = createJiraClient(jiraSources);
         if (!jira) return jiraNotConfiguredError();

-        // Use v3 search/jql to get statuses
-        const host = jira.host;
-        const auth = `Basic ${Buffer.from(
-          `${(jiraUserConfig?.email ?? process.env.JIRA_EMAIL)!}:${(jiraUserConfig?.apiToken ?? process.env.JIRA_API_TOKEN)!}`,
-        ).toString("base64")}`;
-
-        const params = new URLSearchParams({ ... });
-        const resp = await fetch(`https://${host}/rest/api/3/search/jql?${params}`, { ... });
+        const result = await jira.client.searchIssuesV3(
+          `project = ${resolvedProjectKey}`,
+          ["status"],
+          args.maxResults ?? 100,
+        );
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/skills/builtin/jira/tools.ts` around lines 764 - 781, fetch_jira_statuses
currently builds a hand-rolled Basic auth from jiraUserConfig/env vars which
bypasses createJiraClient's credential resolution and can emit
"undefined:undefined"; change it to reuse the resolved client/credentials from
createJiraClient instead of constructing the Authorization header manually: call
createJiraClient(jiraSources), return jiraNotConfiguredError() if null, then
either use jira.client (the Jira API client returned by createJiraClient) to run
the JQL search or have createJiraClient expose the resolved email/apiToken pair
and use those values (no non-null assertions) to build auth; remove the inline
Basic header logic in fetch_jira_statuses so project-scoped overrides are
honored and missing credentials produce the existing not-configured error path.
🧹 Nitpick comments (4)
src/agent/tools/doctor.ts (1)

166-207: check_integrations correctly avoids exposing secrets.

resolveJiraStatus returns only presence/source metadata (plus normalized host), so passing loadUserConfig().jira through it is safe. Confluence derivation from the same Atlassian credentials is reasonable.

One small suggestion: wrap the body in a try/catch consistent with the sibling tools (run_doctor, check_project_health, get_started) — loadUserConfig() can throw ConfigError if the YAML is malformed, which would currently surface as an unhandled tool error.

🛡️ Proposed fix
       async () => {
+        try {
           const jiraSources = {
             project: options?.config?.jira
               ? { host: options.config.jira.host, email: options.config.jira.email }
               : undefined,
             user: loadUserConfig().jira,
           };
           ...
           return {
             content: [{ type: "text" as const, text: JSON.stringify(result, null, 2) }],
           };
+        } catch (err) {
+          return {
+            content: [
+              {
+                type: "text" as const,
+                text: `check_integrations error: ${err instanceof Error ? err.message : String(err)}`,
+              },
+            ],
+            isError: true,
+          };
+        }
       },
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/agent/tools/doctor.ts` around lines 166 - 207, Wrap the async body of the
"check_integrations" tool in a try/catch like the sibling tools (run_doctor,
check_project_health, get_started) to catch loadUserConfig() errors (e.g.,
ConfigError) and return a controlled tool response instead of letting the error
bubble; specifically, surround the calls to loadUserConfig() and
resolveJiraStatus() with try, catch the ConfigError (and fallback to a generic
catch), and in the catch return the same response shape used by other tools
(content with a text message describing the config parse error) so secrets
remain protected and malformed YAML is reported gracefully.
test/skills/jira/client-project.test.ts (1)

5-9: Consider restoring env in place rather than reassigning process.env.

process.env = { ...originalEnv } replaces the special process.env proxy with a plain object, which loses Node's automatic string coercion and case-insensitive behavior on Windows. It's harmless for these tests today, but if future tests rely on those semantics (or spawn child processes) they could behave unexpectedly. Prefer mutating in place:

♻️ Suggested cleanup
   afterEach(() => {
-    process.env = { ...originalEnv };
+    for (const k of Object.keys(process.env)) {
+      if (!(k in originalEnv)) delete process.env[k];
+    }
+    Object.assign(process.env, originalEnv);
   });

Also applies to the duplicated block at Lines 81-85.

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

In `@test/skills/jira/client-project.test.ts` around lines 5 - 9, The test resets
process.env by reassigning it to a plain object (process.env = { ...originalEnv
}), which breaks Node's special env proxy; instead, in the afterEach handler
(the afterEach block referencing originalEnv and process.env) restore keys in
place by removing any keys not in originalEnv and setting all keys from
originalEnv on process.env so the original proxy semantics are preserved; apply
the same in the duplicated cleanup block around lines referenced (the second
afterEach that also uses originalEnv/process.env).
src/skills/builtin/jira/client.ts (2)

280-305: Minor: redundant host normalization and discriminator edge case.

Two small observations on the refactor:

  1. Line 304 passes the raw host to new JiraClient(...), whose constructor (Line 123) re-applies the same replace(/^https?:\/\//, "").replace(/\/+$/, ""). You already compute normalizedHost on Line 303 — pass that in to avoid the duplicated regex pass and keep the normalization source-of-truth single.

  2. isConfigSources (Line 342-347) discriminates purely by the presence of "project" or "user" keys. That's fine today because legacy JiraConfig has neither, but the guard will misclassify any future legacy object that happens to gain a user field. Consider narrowing it to reject shapes that also contain apiToken/host/email at the top level, or expose two separate overloads (e.g. createJiraClient(user) and createJiraClientFromSources(sources)) for clearer intent.

♻️ Optional fix for (1)
   const normalizedHost = host.replace(/^https?:\/\//, "").replace(/\/+$/, "");
-  return { client: new JiraClient({ host, email, apiToken }), host: normalizedHost };
+  return { client: new JiraClient({ host: normalizedHost, email, apiToken }), host: normalizedHost };
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/skills/builtin/jira/client.ts` around lines 280 - 305, createJiraClient
currently computes normalizedHost but passes the raw host into new JiraClient
causing duplicated normalization; update createJiraClient to pass normalizedHost
into the JiraClient constructor (return { client: new JiraClient({ host:
normalizedHost, email, apiToken }), host: normalizedHost }). Also tighten the
isConfigSources type guard (or add explicit overloads like
createJiraClient(user) and createJiraClientFromSources(sources)) so it does not
treat an object with top-level credentials (apiToken/host/email) as a sources
object — e.g., ensure the guard rejects objects that contain apiToken/host/email
at the top level or use separate functions to disambiguate legacy vs new shapes.

307-340: resolveJiraStatus looks correct and secret-safe.

Source labelling precedence (projectuserenv), host-only value exposure, and the deliberate omission of email/apiToken values from the return shape all match what the check_integrations tool needs. Normalization of the reported host value is consistent with createJiraClient.

One nit: the three source fields are typed as string — tightening to a literal union ("project" | "user" | "env") would give downstream consumers (e.g. the doctor tool) better type safety.

♻️ Optional type tightening
-export function resolveJiraStatus(sources?: JiraConfigSources): {
-  host: { configured: boolean; value?: string; source?: string };
-  email: { configured: boolean; source?: string };
-  apiToken: { configured: boolean; source?: string };
-} {
+type JiraCredentialSource = "project" | "user" | "env";
+export function resolveJiraStatus(sources?: JiraConfigSources): {
+  host: { configured: boolean; value?: string; source?: JiraCredentialSource };
+  email: { configured: boolean; source?: JiraCredentialSource };
+  apiToken: { configured: boolean; source?: Exclude<JiraCredentialSource, "project"> };
+} {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/skills/builtin/jira/client.ts` around lines 307 - 340, The return type of
resolveJiraStatus should tighten the three source fields from plain string to
the literal union "project" | "user" | "env" (or undefined where appropriate) so
callers get stronger typing; update the function's return type signature (the
host.source, email.source, apiToken.source fields) to use that union, adjust any
local conditional expressions if needed to keep undefined as a possible value,
and ensure the implementation still returns the same "project"/"user"/"env"
strings from resolveJiraStatus.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@docs/guides/jira.md`:
- Around line 48-60: Update the example payload for the check_integrations
output in docs/guides/jira.md to match the actual response shape produced by
src/agent/tools/doctor.ts by adding the missing emailSource and apiTokenSource
fields under the "jira" object; locate the sample block that shows the
check_integrations JSON and insert emailSource and apiTokenSource with
representative values (e.g., "user" or "env") so the docs reflect the real tool
output produced by check_integrations in doctor.ts.

---

Outside diff comments:
In `@src/skills/builtin/jira/tools.ts`:
- Around line 764-781: fetch_jira_statuses currently builds a hand-rolled Basic
auth from jiraUserConfig/env vars which bypasses createJiraClient's credential
resolution and can emit "undefined:undefined"; change it to reuse the resolved
client/credentials from createJiraClient instead of constructing the
Authorization header manually: call createJiraClient(jiraSources), return
jiraNotConfiguredError() if null, then either use jira.client (the Jira API
client returned by createJiraClient) to run the JQL search or have
createJiraClient expose the resolved email/apiToken pair and use those values
(no non-null assertions) to build auth; remove the inline Basic header logic in
fetch_jira_statuses so project-scoped overrides are honored and missing
credentials produce the existing not-configured error path.

---

Nitpick comments:
In `@src/agent/tools/doctor.ts`:
- Around line 166-207: Wrap the async body of the "check_integrations" tool in a
try/catch like the sibling tools (run_doctor, check_project_health, get_started)
to catch loadUserConfig() errors (e.g., ConfigError) and return a controlled
tool response instead of letting the error bubble; specifically, surround the
calls to loadUserConfig() and resolveJiraStatus() with try, catch the
ConfigError (and fallback to a generic catch), and in the catch return the same
response shape used by other tools (content with a text message describing the
config parse error) so secrets remain protected and malformed YAML is reported
gracefully.

In `@src/skills/builtin/jira/client.ts`:
- Around line 280-305: createJiraClient currently computes normalizedHost but
passes the raw host into new JiraClient causing duplicated normalization; update
createJiraClient to pass normalizedHost into the JiraClient constructor (return
{ client: new JiraClient({ host: normalizedHost, email, apiToken }), host:
normalizedHost }). Also tighten the isConfigSources type guard (or add explicit
overloads like createJiraClient(user) and createJiraClientFromSources(sources))
so it does not treat an object with top-level credentials (apiToken/host/email)
as a sources object — e.g., ensure the guard rejects objects that contain
apiToken/host/email at the top level or use separate functions to disambiguate
legacy vs new shapes.
- Around line 307-340: The return type of resolveJiraStatus should tighten the
three source fields from plain string to the literal union "project" | "user" |
"env" (or undefined where appropriate) so callers get stronger typing; update
the function's return type signature (the host.source, email.source,
apiToken.source fields) to use that union, adjust any local conditional
expressions if needed to keep undefined as a possible value, and ensure the
implementation still returns the same "project"/"user"/"env" strings from
resolveJiraStatus.

In `@test/skills/jira/client-project.test.ts`:
- Around line 5-9: The test resets process.env by reassigning it to a plain
object (process.env = { ...originalEnv }), which breaks Node's special env
proxy; instead, in the afterEach handler (the afterEach block referencing
originalEnv and process.env) restore keys in place by removing any keys not in
originalEnv and setting all keys from originalEnv on process.env so the original
proxy semantics are preserved; apply the same in the duplicated cleanup block
around lines referenced (the second afterEach that also uses
originalEnv/process.env).
🪄 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: 8f3f8852-d35e-4eae-8a71-b99122a43f8b

📥 Commits

Reviewing files that changed from the base of the PR and between fab2c5a and 3e9dd42.

📒 Files selected for processing (11)
  • docs/guides/getting-started.md
  • docs/guides/jira.md
  • docs/guides/mcp-server.md
  • docs/guides/personas.md
  • docs/reference/configuration.md
  • src/agent/session.ts
  • src/agent/tools/doctor.ts
  • src/core/config.ts
  • src/skills/builtin/jira/client.ts
  • src/skills/builtin/jira/tools.ts
  • test/skills/jira/client-project.test.ts

Comment thread docs/guides/jira.md Outdated
- fetch_jira_statuses: replace hand-rolled Basic auth with
  jira.client.searchIssuesV3 so project-scoped overrides are honored
- check_integrations: wrap in try/catch for ConfigError safety
- createJiraClient: pass normalizedHost to JiraClient constructor
  to avoid double normalization
- isConfigSources: reject objects with top-level host/email/apiToken
  to prevent legacy objects being misidentified as sources
- resolveJiraStatus: tighten source field to "project"|"user"|"env"
  literal union
- Test: restore process.env via Reflect.deleteProperty instead of
  reassigning the proxy object
- Docs: add missing emailSource/apiTokenSource to jira.md example
@ablanrob

Copy link
Copy Markdown
Owner Author

@CodeRabbit review

@coderabbitai

coderabbitai Bot commented Apr 23, 2026

Copy link
Copy Markdown
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (2)
src/skills/builtin/jira/client.ts (1)

311-343: Consider extracting the inline return type.

The return shape of resolveJiraStatus is likely consumed by src/agent/tools/doctor.ts to build the check_integrations payload. Naming it (e.g., JiraIntegrationStatus) and exporting would let downstream modules reference the exact shape instead of duplicating it, and keeps the signature readable.

♻️ Proposed refactor
+export interface JiraIntegrationStatus {
+  host: { configured: boolean; value?: string; source?: CredentialSource };
+  email: { configured: boolean; source?: CredentialSource };
+  apiToken: { configured: boolean; source?: CredentialSource };
+}
+
 /** Check which Jira credentials are present without exposing values. */
-export function resolveJiraStatus(sources?: JiraConfigSources): {
-  host: { configured: boolean; value?: string; source?: CredentialSource };
-  email: { configured: boolean; source?: CredentialSource };
-  apiToken: { configured: boolean; source?: CredentialSource };
-} {
+export function resolveJiraStatus(sources?: JiraConfigSources): JiraIntegrationStatus {

Note: CredentialSource is declared at Line 345 below this function; moving it above (or exporting it) would also be cleaner if the new interface is introduced.

As per coding guidelines: "Use interface for object shapes, type for unions/intersections/aliases".

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

In `@src/skills/builtin/jira/client.ts` around lines 311 - 343, The function
resolveJiraStatus currently returns an inline object type; extract and export a
named interface (e.g., JiraIntegrationStatus) that models the returned shape
(host, email, apiToken with configured/value/source fields) and update
resolveJiraStatus's signature to return JiraIntegrationStatus; ensure
CredentialSource is available (move its declaration above or export it) so the
interface can reference it, and export the new interface so downstream modules
like src/agent/tools/doctor.ts can import and reuse the exact type.
docs/guides/jira.md (1)

48-62: Add a language specifier to the fenced block.

markdownlint flags MD040 on line 48. The block content is JSON, so label it as such for consistent rendering and linting.

📝 Proposed doc update
-```
+```json
 > check_integrations
 {
   "jira": {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/guides/jira.md` around lines 48 - 62, The fenced code block starting
with the line "> check_integrations" is missing a language specifier; update
that markdown block to use "json" (i.e., change the opening fence from ``` to
```json) so the JSON payload (the object with "jira", "configured", "host",
"emailConfigured", etc.) is properly recognized and satisfies markdownlint
MD040; locate the block containing > check_integrations and the JSON object and
add the json label to the opening ``` fence.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@docs/guides/jira.md`:
- Around line 48-62: The fenced code block starting with the line ">
check_integrations" is missing a language specifier; update that markdown block
to use "json" (i.e., change the opening fence from ``` to ```json) so the JSON
payload (the object with "jira", "configured", "host", "emailConfigured", etc.)
is properly recognized and satisfies markdownlint MD040; locate the block
containing > check_integrations and the JSON object and add the json label to
the opening ``` fence.

In `@src/skills/builtin/jira/client.ts`:
- Around line 311-343: The function resolveJiraStatus currently returns an
inline object type; extract and export a named interface (e.g.,
JiraIntegrationStatus) that models the returned shape (host, email, apiToken
with configured/value/source fields) and update resolveJiraStatus's signature to
return JiraIntegrationStatus; ensure CredentialSource is available (move its
declaration above or export it) so the interface can reference it, and export
the new interface so downstream modules like src/agent/tools/doctor.ts can
import and reuse the exact type.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: b2e6e7a7-4795-4ccc-a978-f18999eda31a

📥 Commits

Reviewing files that changed from the base of the PR and between 3e9dd42 and dc548e9.

📒 Files selected for processing (6)
  • docs/guides/jira.md
  • package.json
  • src/agent/tools/doctor.ts
  • src/skills/builtin/jira/client.ts
  • src/skills/builtin/jira/tools.ts
  • test/skills/jira/client-project.test.ts
✅ Files skipped from review due to trivial changes (1)
  • package.json
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/agent/tools/doctor.ts
  • src/skills/builtin/jira/tools.ts

…type

- Add json language specifier to check_integrations code block (MD040)
- Extract and export CredentialSource and JiraIntegrationStatus from
  resolveJiraStatus inline return type for downstream reuse
@ablanrob
ablanrob merged commit 7be0efa into main Apr 24, 2026
2 checks passed
@ablanrob
ablanrob deleted the feat/jira-credentials-safety branch April 24, 2026 08:03
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.

1 participant