Skip to content

Commit 1deacd2

Browse files
committed
improved json output, add analysis information and commands
1 parent 2141a99 commit 1deacd2

28 files changed

+1209
-383
lines changed

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,12 +51,12 @@ codacy <command> --help # Detailed usage for any command
5151
|---|---|
5252
| `info` | Show authenticated user info and their organizations |
5353
| `repositories <provider> <org>` | List repositories for an organization |
54-
| `repository <provider> <org> <repo>` | Show metrics for a repository, or add/remove/follow/unfollow it |
54+
| `repository <provider> <org> <repo>` | Show metrics for a repository, or add/remove/follow/unfollow/reanalyze it |
5555
| `issues <provider> <org> <repo>` | Search issues in a repository with filters |
5656
| `issue <provider> <org> <repo> <id>` | Show details for a single issue, or ignore/unignore it |
5757
| `findings <provider> <org> [repo]` | Show security findings for a repository or organization |
5858
| `finding <provider> <org> <id>` | Show details for a single security finding, or ignore/unignore it |
59-
| `pull-request <provider> <org> <repo> <pr>` | Show PR analysis, issues, diff coverage, and changed files |
59+
| `pull-request <provider> <org> <repo> <pr>` | Show PR analysis, issues, diff coverage, and changed files; or reanalyze it |
6060
| `tools <provider> <org> <repo>` | List analysis tools configured for a repository |
6161
| `tool <provider> <org> <repo> <tool>` | Enable, disable, or configure an analysis tool |
6262
| `patterns <provider> <org> <repo> <tool>` | List patterns for a tool with filters |

SPECS/README.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ This is the single source of truth for all project tasks and specs.
66

77
## Pending Tasks
88

9-
_No pending tasks._
9+
_No pending tasks._ All commands implemented.
1010

1111
## Command Inventory
1212

@@ -24,6 +24,9 @@ _No pending tasks._
2424
| `tool` | `tl` | ✅ Done | [tools-and-patterns.md](commands/tools-and-patterns.md) |
2525
| `patterns` | `pats` | ✅ Done | [tools-and-patterns.md](commands/tools-and-patterns.md) |
2626
| `pattern` | `pat` | ✅ Done | [tools-and-patterns.md](commands/tools-and-patterns.md) |
27+
| `analysis` | N/A | ✅ Done | [analysis.md](commands/analysis.md) |
28+
| `json-output` | N/A | ✅ Done | [json-output.md](commands/json-output.md) |
29+
2730

2831
## Other Specs
2932

@@ -56,3 +59,5 @@ _No pending tasks._
5659
| 2026-02-25 | `repository` actions: `--add`, `--remove`, `--follow`, `--unfollow` (4 new tests, 112 total) |
5760
| 2026-02-25 | `tools`, `tool`, `patterns`, `pattern` commands + tests (35 new tests, 147 total); `findToolByName` helper added to `utils/formatting.ts` |
5861
| 2026-03-02 | `issue --ignore`, `pull-request --ignore-issue` / `--ignore-all-false-positives`, `finding --ignore` + tests (17 new tests, 164 total); all use `-R/--ignore-reason` and `-m/--ignore-comment` options |
62+
| 2026-03-05 | Analysis status in `repository` and `pull-request` About sections using `formatAnalysisStatus()`; `--reanalyze` option for both commands (13 new tests, 185 total) |
63+
| 2026-03-05 | JSON output filtering with `pickDeep` across all commands: `info`, `repositories`, `repository`, `pull-request`, `issues`, `issue`, `findings`, `finding`, `tools`, `patterns`; documented pattern in `src/commands/CLAUDE.md` |

SPECS/commands/analysis.md

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
# Analysis Status & Reanalyze Spec
2+
3+
**Status:** ✅ Done (2026-03-05)
4+
5+
## Purpose
6+
7+
Show analysis status of the HEAD commit in the `repository` and `pull-request` commands, and allow triggering reanalysis.
8+
9+
## Usage
10+
11+
```
12+
codacy repository <provider> <organization> <repository> --reanalyze
13+
codacy pull-request <provider> <organization> <repository> <prNumber> --reanalyze
14+
```
15+
16+
On success, show: "Reanalysis requested successfully, new results will be available in a few minutes."
17+
On failure, show: "Failed to request reanalysis: \<error message\>".
18+
19+
## Updates to existing commands
20+
21+
### `repository` command — About section
22+
23+
The "Last Analysis" row is replaced by "Analysis", showing the current analysis status of the HEAD commit:
24+
25+
- Reanalysis in progress (HEAD commit already analyzed, but currently being reanalyzed):
26+
```
27+
Analysis Finished 12h ago (c00e638) — Reanalysis in progress...
28+
```
29+
30+
- First analysis (HEAD commit not yet analyzed):
31+
```
32+
Analysis In progress... (c00e638)
33+
```
34+
35+
- Analysis finished, waiting for coverage (within 3h):
36+
```
37+
Analysis Finished 12h ago (c00e638) — Waiting for coverage reports...
38+
```
39+
40+
- Analysis finished, coverage overdue (>3h):
41+
```
42+
Analysis Finished 12h ago (c00e638) — Missing coverage reports
43+
```
44+
45+
- Normal finished state:
46+
```
47+
Analysis Finished 12h ago (c00e638)
48+
```
49+
50+
"In progress..." and "Reanalysis in progress..." are colored light blue. "Missing coverage reports" is yellow.
51+
52+
### `pull-request` command — About section
53+
54+
Same "Analysis" row replaces the former "Head Commit" row, with the same status logic applied to the PR's HEAD commit.
55+
56+
## Analysis Status Logic
57+
58+
- **Being analyzed**: `startedAnalysis` is set AND (`endedAnalysis` is absent OR `startedAnalysis > endedAnalysis`)
59+
- **Coverage expected**: determined by `listCoverageReports(limit=1).data.hasCoverageOverview`
60+
- **Coverage data present**: `diffCoverage.value !== undefined OR deltaCoverage !== undefined` (PR); `coveragePercentage !== undefined` (repo)
61+
- **Wait threshold**: 3 hours from `endedAnalysis`
62+
63+
Implemented in `formatAnalysisStatus()` in `src/utils/formatting.ts`.
64+
65+
## API Endpoints
66+
67+
- [`reanalyzeCommitById`](https://api.codacy.com/api/api-docs#reanalyzecommitbyid)`RepositoryService.reanalyzeCommitById(provider, org, repo, { commitUuid: sha })`
68+
- [`getPullRequestCommits`](https://api.codacy.com/api/api-docs#getpullrequestcommits) with `limit=1` — head commit timing for PR
69+
- [`listRepositoryCommits`](https://api.codacy.com/api/api-docs#listrepositorycommits) with `limit=1` — head commit timing for repo
70+
- [`listCoverageReports`](https://api.codacy.com/api/api-docs#listcoveragereports) with `limit=1` — check `hasCoverageOverview`
71+
72+
## Tasks
73+
74+
- [x] Update analysis status in the About section of the `repository` command
75+
- [x] Update analysis status in the About section of the `pull-request` command
76+
- [x] Add `--reanalyze` option to the `repository` command
77+
- [x] Add `--reanalyze` option to the `pull-request` command
78+
- [x] Update existing tests for the status sections
79+
- [x] Add tests for the new `--reanalyze` option
80+
81+
## Tests
82+
83+
- `src/utils/formatting.test.ts` — 6 unit tests for `formatAnalysisStatus`
84+
- `src/commands/repository.test.ts` — 4 new tests (analysis status, reanalyze)
85+
- `src/commands/pull-request.test.ts` — 3 new tests (analysis status, reanalyze)

SPECS/commands/finding.md

Lines changed: 22 additions & 120 deletions
Original file line numberDiff line numberDiff line change
@@ -12,23 +12,34 @@ Show full details of a single security finding.
1212
codacy finding <provider> <organization> <findingId>
1313
codacy fin gh my-org abc123-uuid
1414
codacy fin gh my-org abc123-uuid --output json
15+
codacy fin gh my-org abc123-uuid --ignore
16+
codacy fin gh my-org abc123-uuid --ignore --ignore-reason FalsePositive --ignore-comment "Verified safe"
17+
codacy fin gh my-org abc123-uuid --unignore
1518
```
1619

1720
The `findingId` is the UUID shown in dim gray at the end of each findings card.
1821

22+
## Options
23+
24+
| Option | Short | Description |
25+
|---|---|---|
26+
| `--ignore` | `-I` | Ignore this finding |
27+
| `--ignore-reason <reason>` | `-R` | Reason: `AcceptedUse` (default) \| `FalsePositive` \| `NotExploitable` \| `TestCode` \| `ExternalCode` |
28+
| `--ignore-comment <comment>` | `-m` | Optional comment |
29+
| `--unignore` | `-U` | Unignore this finding |
30+
1931
## API Endpoints
2032

2133
1. [`getSecurityItem`](https://api.codacy.com/api/api-docs#getsecurityitem)`SecurityService.getSecurityItem(provider, org, findingId)`
2234
2. For Codacy-source findings (`itemSource === 'Codacy'`), after step 1:
2335
- `AnalysisService.getIssue(provider, org, item.repository, parseInt(item.itemSourceId))` → linked quality issue
2436
- Then in parallel: `ToolsService.getPattern(toolUuid, patternId)` + `FileService.getFileContent(...)`
2537
- Failures at steps 2/3 are silently caught — the finding is still shown
38+
3. When `item.cve` is present, fetch CVE data from `https://cveawg.mitre.org/api/cve/{CVE-ID}` in parallel with step 2
2639

2740
## Output Format
2841

2942
```
30-
────────────────────────────────────────
31-
3243
{Priority colored} | {SecurityCategory} {ScanType} | {Optional: Likelihood} {EffortToFix} | {Optional: Repository} {id dimmed}
3344
{Finding title}
3445
@@ -44,129 +55,20 @@ The `findingId` is the UUID shown in dim gray at the end of each findings card.
4455
{Optional: remediation}
4556
4657
{For Codacy-source: shared printIssueCodeContext output — file context + pattern docs}
47-
48-
────────────────────────────────────────
4958
```
5059

51-
## CVE Enrichment (Pending)
60+
## CVE Enrichment
5261

53-
When `item.cve` is present, fetch CVE data from `https://cveawg.mitre.org/api/cve/{CVE-CODE}` and add it to the output.
62+
When `item.cve` is present, fetch CVE data from `https://cveawg.mitre.org/api/cve/{CVE-ID}` and display:
5463

55-
Use types from `src/utils/cve.ts` to parse the response. Show the enriched CVE information (description, CVSS score, references) after the finding's metadata block.
64+
- CVE ID as a bold header ("About {cveId}")
65+
- CVSS score(s) and severity, published/updated dates (from `cveMetadata`)
66+
- Title (from `containers.cna.title` or first English problem type description)
67+
- English description (from `containers.cna.descriptions`)
68+
- Deduplicated references from `cna` and all `adp` containers
5669

57-
The output should match the component we have in our UI. Here's the React component code:
58-
59-
```
60-
const CVSS_COLOR_MAP: Record<string, PillLabelStatus> = {
61-
low: 'success',
62-
medium: 'warning',
63-
high: 'high',
64-
critical: 'critical',
65-
default: 'default',
66-
}
67-
68-
const CVEMetric: React.FC<{ score?: number; severity?: string }> = ({ score, severity }) => (
69-
<PillLabel size="md" ml={2} status={CVSS_COLOR_MAP[severity?.toLowerCase() || 'default']}>
70-
{score || '-'} | {capitalize(severity || '-')}
71-
</PillLabel>
72-
)
73-
74-
export const CVEContent: React.FCC<CVEContentProps> = ({ cve, ...props }) => {
75-
const { data: cveData, isLoading, isError } = useCVE(cve)
76-
77-
return (
78-
<Box backgroundColor="background-primary" p={5} borderRadius={1} {...props}>
79-
{isLoading && <CVEContentSkeleton />}
80-
{!isLoading && isError && (
81-
<EmptyState template="noMatch" py={6} maxWidth="50%">
82-
<Subheader size="lg">Sadly, we couldn't show CVE details for {cve}</Subheader>
83-
<Paragraph mt={4} size="md">
84-
The CVE data is not available or the CVE code is invalid. You can{' '}
85-
<Link href={`https://www.cve.org/CVERecord?id=${cve}`} isExternal size="md">
86-
go to the CVE website
87-
</Link>{' '}
88-
to see the details.
89-
</Paragraph>
90-
</EmptyState>
91-
)}
92-
{!isLoading && !isError && cveData && (
93-
<Box>
94-
<Flex flexDirection="row" alignItems="center" justifyContent="space-between" mb={2}>
95-
<Subheader size="sm" mr={2} flexGrow={1}>
96-
<Link href={`https://www.cve.org/CVERecord?id=${cveData.cveMetadata.cveId}`} isExternal size="lg">
97-
{cveData.cveMetadata.cveId}
98-
</Link>
99-
</Subheader>
100-
{!!cveData.containers.cna.metrics?.length && (
101-
<Caption size="sm" color="tertiary" mr={1}>
102-
<span title="Common Vulnerability Scoring System">CVSS:</span>
103-
</Caption>
104-
)}
105-
{cveData.containers.cna.metrics?.map((metric) => (
106-
<CVEMetric
107-
key={metric.format}
108-
score={
109-
metric.cvssV4_0?.baseScore ||
110-
metric.cvssV3_1?.baseScore ||
111-
metric.cvssV3_0?.baseScore ||
112-
metric.cvssV2_0?.baseScore
113-
}
114-
severity={
115-
metric.cvssV4_0?.baseSeverity || metric.cvssV3_1?.baseSeverity || metric.cvssV3_0?.baseSeverity
116-
}
117-
/>
118-
))}
119-
</Flex>
120-
121-
<Caption size="sm" color="tertiary" mb={4}>
122-
{!!cveData.cveMetadata.datePublished && (
123-
<>
124-
Published: <TimeCaption value={cveData.cveMetadata.datePublished} mr={2} />
125-
</>
126-
)}
127-
{!!cveData.cveMetadata.dateUpdated && (
128-
<>
129-
Updated: <TimeCaption value={cveData.cveMetadata.dateUpdated} mr={2} />
130-
</>
131-
)}
132-
</Caption>
133-
134-
{(cveData.containers.cna.title || cveData.containers.cna.problemTypes?.length) && (
135-
<Subheader size="sm" mb={2}>
136-
{cveData.containers.cna.title ||
137-
cveData.containers.cna.problemTypes?.[0]?.descriptions?.filter(
138-
(description) => description.lang === 'en'
139-
)[0]?.description}
140-
</Subheader>
141-
)}
142-
<Paragraph size="md" mb={6}>
143-
{cveData.containers.cna.descriptions?.filter((description) => description.lang === 'en')[0]?.value}
144-
</Paragraph>
145-
<Subheader size="xs" mb={2}>
146-
References
147-
</Subheader>
148-
<BulletedList>
149-
{uniqBy(
150-
[
151-
...(cveData.containers.cna.references || []),
152-
...(cveData.containers.adp?.flatMap((adp) => adp.references || []) || []),
153-
],
154-
'url'
155-
).map((reference) => (
156-
<li key={reference.url}>
157-
<Link href={reference.url} isExternal size="sm" styleType="light">
158-
{reference.url}
159-
</Link>
160-
</li>
161-
))}
162-
</BulletedList>
163-
</Box>
164-
)}
165-
</Box>
166-
)
167-
}
168-
```
70+
For Codacy-source findings, the CVE block is injected between the code context and the pattern documentation. For non-Codacy-source findings, it follows the prose fields.
16971

17072
## Tests
17173

172-
File: `src/commands/finding.test.ts`9 tests.
74+
File: `src/commands/finding.test.ts`14 tests (9 original + 5 for CVE enrichment).

SPECS/commands/findings.md

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ Show security findings for a repository or an organization. The repository argum
1212
codacy findings <provider> <organization> [repository]
1313
codacy findings gh my-org my-repo
1414
codacy findings gh my-org
15-
codacy fins gh my-org --severities High,Critical --statuses OnTrack
16-
codacy fins gh my-org my-repo --output json
15+
codacy find gh my-org --severities High,Critical --statuses OnTrack
16+
codacy find gh my-org my-repo --output json
1717
```
1818

1919
## API Endpoints
@@ -24,13 +24,15 @@ codacy fins gh my-org my-repo --output json
2424

2525
| Option | Short | Description |
2626
|---|---|---|
27-
| `--search <term>` | `-s` | Search term to filter findings |
28-
| `--severities <list>` | `-S` | Comma-separated priority levels |
29-
| `--statuses <list>` | `-t` | Comma-separated status names |
27+
| `--search <term>` | `-q` | Search term to filter findings |
28+
| `--severities <list>` | `-s` | Comma-separated priority levels: Critical, High, Medium, Low |
29+
| `--statuses <list>` | `-S` | Comma-separated statuses: Overdue, OnTrack, DueSoon, ClosedOnTime, ClosedLate, Ignored |
3030
| `--categories <list>` | `-c` | Comma-separated security category names |
31-
| `--scan-types <list>` | `-T` | Comma-separated scan types |
31+
| `--scan-types <list>` | `-T` | Comma-separated scan types: SAST, Secrets, SCA, CICD, IaC, DAST, PenTesting, License, CSPM |
3232
| `--dast-targets <list>` | `-d` | Comma-separated DAST target URLs |
3333

34+
Default status filter: `Overdue,OnTrack,DueSoon`.
35+
3436
## Output
3537

3638
Card-style format:
@@ -40,13 +42,14 @@ Card-style format:
4042
4143
{Priority colored} | {SecurityCategory} {ScanType} | {Optional: Likelihood} {Optional: EffortToFix} | {Optional: Repository} {id dimmed}
4244
{Finding title}
45+
{Optional: affectedTargets}
4346
44-
{Status} {DueAt} | {Optional: CVE or CWE} | {Optional: AffectedVersion → FixedVersion} | {Optional: Application} | {Optional: AffectedTargets}
47+
{Status} {DueAt} | {Optional: CVE or CWE} | {Optional: AffectedVersion → FixedVersion} | {Optional: Application}
4548
4649
────────────────────────────────────────
4750
```
4851

49-
The `id` (UUID) is shown in dim gray at the end of line 1 for use with the `finding` command.
52+
The `id` (UUID) is shown in dim gray at the end of line 1 use it with the `finding` command to see full details.
5053

5154
Priority colors: Critical=red, High=orange, Medium=yellow, Low=blue.
5255

0 commit comments

Comments
 (0)