Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/sanitize-advisory-functions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@codacy/codacy-cloud-cli": patch
---

Sanitize vulnerable/affected function names and the advisory ID (`CommitIssue.advisoryInformation` / `SrmItem.advisoryInformation`) before printing them in `issue`, `issues`, `pull-request --issue`, `finding`, and `findings`. These values come from the linked OSV advisory, so — like other repository-derived output — they are now passed through `sanitizeText()` to strip ANSI/OSC control bytes (CWE-150) instead of being printed raw.
5 changes: 5 additions & 0 deletions .changeset/vulnerable-functions-issues.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@codacy/codacy-cloud-cli": minor
---

`issue`, `issues`, `pull-request --issue`, `finding`, and `findings` now show vulnerable/affected functions for SCA issues and findings with a linked OSV advisory (`CommitIssue.advisoryInformation` / `SrmItem.advisoryInformation`). Card views show a compact one-line summary; detail views show the full list with advisory ID and published date. Included in `--output json` for all five commands.
2 changes: 2 additions & 0 deletions SPECS/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,3 +78,5 @@ _No pending tasks._ All commands implemented.
| 2026-07-08 | `issues --overview` noise suggestions tuned to stop firing on low-volume repos: added a `NOISE_MIN_TOTAL` (200) floor on the repo's total issues that suppresses the whole "reduce noise" section below it, and a `NOISE_MIN_PATTERN` (100) absolute floor on each pattern's own count (AND-gated with the relative rules) so a long tail of tiny patterns can't drag the median down and make a ~9-issue pattern look noisy — the total floor is kept above the per-pattern floor so it isn't dead code; the ≥10% share rule now only applies with ≥11 distinct patterns (`NOISE_MIN_PATTERNS_FOR_SHARE` — an even split only drops below 10% once N > 10, so 8–10 balanced patterns would otherwise all be flagged); and the ≥3× multiple rule (`NOISE_MEDIAN_MULTIPLE`) now measures against the **median** (via new `medianOf()`) instead of the mean, so a single huge pattern can no longer inflate the baseline and mask smaller disproportionate patterns (5 new tests, 465 total) |
| 2026-07-17 | `issues --ignore` now confirms before bulk-ignoring: `executeBulkIgnore` prints the match count then prompts via shared `confirmAction` (`utils/prompt.ts`), proceeding only on `y`. New `--skip-confirmation` (`-y`) bypasses the prompt for CI/scripts (same short flag as `tools --import --skip-approval`); non-TTY without the flag aborts rather than ignoring by accident. Confirmation runs after the fetch (count is shown) but before any `bulkIgnoreIssues` call (3 new tests, 478 total) |
| 2026-07-24 | Security (CWE-150, HackerOne): neutralize terminal control characters in human-readable output. New `src/utils/sanitize.ts` (`sanitizeText`) strips C0 (0x00–0x1F except TAB/LF), DEL (0x7F) and C1 (0x80–0x9F) — CR included — replacing each with visible caret/`\xNN` notation so a crafted PR can't inject ANSI/OSC sequences to repaint or hide findings, spoof gate status, or drive terminal side effects (OSC 52 clipboard, OSC 8 hyperlinks). Applied *before* the CLI's own `ansis` styling (can't sanitize at the console boundary — that would strip the CLI's legitimate colours, and allow-listing SGR would still pass attacker SGR through). Covers every render path: shared helpers in `utils/formatting.ts` (issue cards/detail, code context, CVE block, dependency chains, version segments) plus `pull-request` (About table, Files, diff-coverage, annotated diff line/hunk/path), `findings`/`finding`, `issues` (overview tables, noise suggestions), `issue`, `repository` (About, PRs, overview), `ls`/`directories`. JSON output left intact (JSON encoding already escapes control bytes). New `src/utils/sanitize.test.ts` + pull-request table/diff regression tests (12 new tests, 490 total) |
| 2026-07-24 | (OD-296) Vulnerable/affected functions for SCA issues: `CommitIssue.advisoryInformation` (added server-side in API `57.3.0`, bumped from pinned `56.2.9`) is now read and rendered. `issues`/`issue`/`pull-request` default cards show a compact "Vulnerable functions: fn1, fn2 (+N more)" line (`printIssueCard`); `issue`/`pull-request --issue` detail views show the full block with advisory ID + published date (`printAdvisoryBlock`, wired into `printIssueCodeContext`). Not shown for ignored issues (`IgnoredIssue` has no `advisoryInformation`). Gated purely on `advisoryInformation` presence. Added to all three commands' JSON `pickDeep` whitelists (10 new tests, 488 total). Originally scoped to the `findings` command, but `SrmItem` has no equivalent field anywhere server-side — redirected to `issues`, where the data already existed in the public API. |
| 2026-07-28 | (OD-296, findings side) `SrmItem` gained its own `advisoryInformation` field server-side (bumped pinned API `57.3.0` → `57.3.9`), closing the gap noted on 2026-07-24. `findings` (list) now shows the same compact "Vulnerable functions: fn1, fn2 (+N more)" line as `issues`, via the newly-exported `summarizeFunctions`. `finding` (detail) shows the full `printAdvisoryBlock` — but only when there's no linked Codacy issue, since `printIssueCodeContext` already renders the equivalent block from `issue.advisoryInformation` in that case; this is what makes vulnerable functions visible for SCA/dependency findings (and any other non-Codacy-source finding) that have no linked issue to borrow it from at all. Added to both commands' JSON `pickDeep` whitelists (6 new tests, 494 total) |
11 changes: 9 additions & 2 deletions SPECS/commands/finding.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# `finding` Command Spec

**Status:** ✅ Done (2026-02-24); CVE enrichment ✅ Done (2026-02-24)
**Status:** ✅ Done (2026-02-24); CVE enrichment ✅ Done (2026-02-24); vulnerable functions (advisoryInformation) ✅ Done (2026-07-28)

## Purpose

Expand Down Expand Up @@ -36,6 +36,7 @@ The `findingId` is the UUID shown in dim gray at the end of each findings card.
- Then in parallel: `ToolsService.getPattern(toolUuid, patternId)` + `FileService.getFileContent(...)`
- Failures at steps 2/3 are silently caught — the finding is still shown
3. When `item.cve` is present, fetch CVE data from `https://cveawg.mitre.org/api/cve/{CVE-ID}` in parallel with step 2
4. `item.advisoryInformation` (vulnerable functions), when present, comes inline on the `getSecurityItem` response itself — no extra request

## Output Format

Expand All @@ -55,6 +56,8 @@ The `findingId` is the UUID shown in dim gray at the end of each findings card.
{Optional: Remediation:}
{Optional: remediation}

{Optional: Vulnerable Functions block, from item.advisoryInformation — only when there is no linked Codacy issue}

{For Codacy-source: shared printIssueCodeContext output — file context + pattern docs}
```

Expand All @@ -70,6 +73,10 @@ When `item.cve` is present, fetch CVE data from `https://cveawg.mitre.org/api/cv

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.

## Vulnerable functions (advisoryInformation)

When `item.advisoryInformation` is present, shows the shared `printAdvisoryBlock` (advisory ID header, optional published date, one bullet per vulnerable function) via `utils/formatting.ts` — the same renderer used by `issue`/`pull-request --issue`. Shown here only when there is **no** linked Codacy issue; when there is one, `printIssueCodeContext` already renders the equivalent block from `issue.advisoryInformation`, so this avoids a duplicate. This is what makes vulnerable functions visible for SCA/dependency findings and any other non-Codacy-source finding, which have no linked issue to borrow the block from. Included in `--output json` as `finding.advisoryInformation.{advisoryId,vulnerableFunctions,publishedAt}`.

## Dependency import chains (SCA)

When a finding carries `dependencyChains` (`string[][]`), **all** chains are listed
Expand All @@ -83,4 +90,4 @@ to `<first> → ... N more ... → <last>`). See `SPECS/commands/findings.md`.

## Tests

File: `src/commands/finding.test.ts` — 23 tests.
File: `src/commands/finding.test.ts` — 26 tests (23 + 3 for advisoryInformation).
9 changes: 7 additions & 2 deletions SPECS/commands/findings.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# `findings` Command Spec

**Status:** ✅ Done (2026-02-20)
**Status:** ✅ Done (2026-02-20); vulnerable functions (advisoryInformation) ✅ Done (2026-07-28)

## Purpose

Expand Down Expand Up @@ -46,6 +46,7 @@ Card-style format:

{Status} {DueAt} | {Optional: CVE or CWE} | {Optional: AffectedVersion → FixedVersion} | {Optional: Application}
{Optional: Dependency import chain (SCA findings with dependencyChains)}
{Optional: Vulnerable functions: fn1, fn2 (+N more) — from item.advisoryInformation}

────────────────────────────────────────
```
Expand All @@ -68,6 +69,10 @@ is dropped from the status line (it would duplicate the chain line).
- Chains with **4+ packages** collapse their middle: `<first> → ... N more ... → <last>` (N = length − 2).
- Multiple chains append `... and X more` (X = chains − 1).

### Vulnerable functions (advisoryInformation)

When an item carries `advisoryInformation` (`{advisoryId, vulnerableFunctions, publishedAt}`), a compact `Vulnerable functions: fn1, fn2 (+N more)` line is shown below the status/chain lines, via the shared `summarizeFunctions` helper (`utils/formatting.ts`, capped at 3 entries) — same rendering as `issue`/`pull-request`'s card view. Included in `--output json` as `advisoryInformation.{advisoryId,vulnerableFunctions,publishedAt}` per item.

## Tests

File: `src/commands/findings.test.ts` — 24 tests.
File: `src/commands/findings.test.ts` — 27 tests (24 + 3 for advisoryInformation).
21 changes: 19 additions & 2 deletions SPECS/commands/issue.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# `issue` Command Spec

**Status:** ✅ Done (2026-02-23); ignore/unignore added 2026-03-02
**Status:** ✅ Done (2026-02-23); ignore/unignore added 2026-03-02; vulnerable functions block added 2026-07-24

## Purpose

Expand Down Expand Up @@ -66,6 +66,23 @@ Detected by: {tool name}
{pattern title} ({pattern id})
```

**Vulnerable Functions block** — shown between the false-positive warning and the pattern
docs whenever `issue.advisoryInformation` is present (SCA issues linked to an OSV advisory):

```
Vulnerable Functions ({advisoryId})
Published: {publishedAt, formatted YYYY-MM-DD}

• {vulnerableFunctions[0]}
• {vulnerableFunctions[1]}
...
```

Rendered via `printAdvisoryBlock` in `utils/formatting.ts`, called from `printIssueCodeContext`
(so it's also shared with the `pull-request --issue` detail view). No conditional on issue
category — gated purely on `advisoryInformation` being present, mirroring how the CVE block
is gated on `cve` for `finding`.

## Tests

File: `src/commands/issue.test.ts` — 8 tests.
File: `src/commands/issue.test.ts` — 20 tests (17 + 3 for the vulnerable functions block).
12 changes: 10 additions & 2 deletions SPECS/commands/issues.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# `issues` Command Spec

**Status:** ✅ Done (2026-02-19)
**Status:** ✅ Done (2026-02-19); vulnerable functions line added 2026-07-24

## Purpose

Expand Down Expand Up @@ -62,12 +62,20 @@ Card-style format, sorted by severity (Error > High > Warning > Info):
{FilePath}:{LineNumber}
{LineText}
{Optional: Potential false positive warning}
{Optional: Vulnerable functions: fn1, fn2, fn3 (+N more)}

────────────────────────────────────────
```

Severity colors: Error=red, High=orange, Warning=yellow, Info=blue.

The "Vulnerable functions" line is shown when `issue.advisoryInformation` is present (SCA
issues linked to an OSV advisory), listing up to 3 function names with a "(+N more)" suffix
for longer lists. Rendered via `printIssueCard` in `utils/formatting.ts`. `--output json`
includes the full `advisoryInformation` object (`advisoryId`, `vulnerableFunctions`,
`publishedAt`) — no truncation there. Not shown for ignored issues (`IgnoredIssue` has no
`advisoryInformation` field).

Shows pagination warning if more results exist.

### Overview mode (`--overview`)
Expand Down Expand Up @@ -177,4 +185,4 @@ Cannot be combined with `--overview` or `--limit`.

## Tests

File: `src/commands/issues.test.ts` — 64 tests.
File: `src/commands/issues.test.ts` — 68 tests (64 + 4 for the vulnerable functions line).
9 changes: 7 additions & 2 deletions SPECS/commands/pull-request.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# `pull-request` Command Spec

**Status:** ✅ Done (2026-02-18); `--issue` added 2026-02-23; `--diff` + Diff Coverage Summary added 2026-02-25; ignore/unignore options added 2026-03-02; analysis status + `--reanalyze` added 2026-03-05
**Status:** ✅ Done (2026-02-18); `--issue` added 2026-02-23; `--diff` + Diff Coverage Summary added 2026-02-25; ignore/unignore options added 2026-03-02; analysis status + `--reanalyze` added 2026-03-05; vulnerable functions (default cards + `--issue` detail) added 2026-07-24

## Purpose

Expand Down Expand Up @@ -45,7 +45,12 @@ When `--issue <issueId>` is provided:
1. Fetch all PR issues (confirmed + potential) using `fetchAllPrIssues()` pagination helper
2. Find the issue by `resultDataId`
3. Fetch `getPattern` + `getFileContent` in parallel
4. Render using shared `printIssueDetail` from `utils/formatting.ts`
4. Render using shared `printIssueDetail` from `utils/formatting.ts` — includes the Vulnerable
Functions block (see `issue.md`) when `advisoryInformation` is present, since it's shared
via `printIssueCodeContext`

Default-mode issue cards (and `--issue` cards) also show the compact "Vulnerable functions:"
line — see `issues.md` for the format, shared via `printIssueCard`.

## `--diff` mode

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
"prepublishOnly": "npm run update-api && npm run build",
"start": "npx ts-node src/index.ts",
"start:dist": "node dist/index.js",
"fetch-api": "curl https://artifacts.codacy.com/api/codacy-api/56.2.9/apiv3-bundled.yaml -o ./api-v3/api-swagger.yaml --create-dirs",
"fetch-api": "curl https://artifacts.codacy.com/api/codacy-api/57.3.9/apiv3-bundled.yaml -o ./api-v3/api-swagger.yaml --create-dirs",
"generate-api": "rm -rf ./src/api/client && openapi --input ./api-v3/api-swagger.yaml --output ./src/api/client --useUnionTypes --indent 2 --client fetch",
"update-api": "npm run fetch-api && npm run generate-api",
"check-types": "tsc --noEmit"
Expand Down
5 changes: 5 additions & 0 deletions src/commands/AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,10 @@ Dependency-chain helpers shared between `findings.ts` (list) and `finding.ts` (d
- `formatDependencyChainsLine(chains, fixedVersion)` — one-line list summary: first chain with its Direct/Transitive label + `... and N more`; returns `null` for no chains
- `formatDependencyChainsBlock(chains, fixedVersion)` — multi-line detail block: all chains, label shown once, continuation lines aligned under the label; returns `null` for no chains

Advisory-information helpers shared between `issue.ts`/`pull-request.ts` (via `CommitIssue.advisoryInformation`) and `finding.ts`/`findings.ts` (via `SrmItem.advisoryInformation`) — same `AdvisoryInformation` shape from either source:
- `summarizeFunctions(fns, limit = 3)` — compact `fn1, fn2 (+N more)` string for card views (`issue`/`pull-request` cards, `findings` list)
- `printAdvisoryBlock(advisory)` — full detail block: bold `Vulnerable Functions (<advisoryId>)` header, optional `Published:` date, one bullet per function; used by `printIssueCodeContext` (issue detail views) and directly by `finding.ts` when there's no linked Codacy issue to render it via that path

Pattern helpers shared between `patterns.ts` (list) and `pattern.ts` (single info):
- `printPatternCard(cp)` — the configured-pattern card (icons, enforced-by line, metadata, why/how, parameters)
- `PATTERN_JSON_FIELDS` — `pickDeep` paths for the JSON projection of a `ConfiguredPattern`
Expand Down Expand Up @@ -312,6 +316,7 @@ Keeps the two command handlers thin: they only supply the API-specific callbacks
- `-m, --ignore-comment`: optional free-text comment
- **`--unignore` mode** (`-U`): calls `SecurityService.unignoreSecurityItem`; skips rendering finding details
- **Dependency import chains** (SCA findings): when `item.dependencyChains` (`string[][]`) is present, both `finding` (detail) and `findings` (list) render the vulnerable dependency's import path. A chain with a single package is a **direct** dependency (`Direct - Update <pkg> to <fixedVersion>`); 2+ packages is **transitive** (`Transitive - <chain> (Fixed in <fixedVersion>)`). Chains with **4+ packages** collapse the middle to `<first> → ... N more ... → <last>` (N = length − 2). The list shows only the first chain + `... and X more`; the detail lists **all** chains with the Direct/Transitive label shown once and continuation lines indented so the `-` aligns. When chains are present, the redundant `AffectedVersion → FixedVersion` segment is dropped from the status line. Mixed direct/transitive chains (rare) take their label from the first chain. Rendering lives in `formatDependencyChainsLine` / `formatDependencyChainsBlock` (see Shared Formatting Utilities).
- **Vulnerable functions** (`item.advisoryInformation`, both `finding` and `findings`): `findings` (list) shows the compact `Vulnerable functions: fn1, fn2 (+N more)` line via `summarizeFunctions` (same helper `issue`/`pull-request`'s card view uses). `finding` (detail) shows the full `printAdvisoryBlock` — but **only when there is no linked Codacy issue**; when there is one, `printIssueCodeContext` already renders the equivalent block from `issue.advisoryInformation`, so `finding` skips its own to avoid a duplicate. This is what makes vulnerable functions visible for SCA/dependency findings (and any other non-Codacy-source finding), which have no linked issue to borrow the block from at all.

## pull-request command (`pull-request.ts`)

Expand Down
Loading
Loading