Skip to main content

assessment-report-converter

Convert an arbitrary CSV report (e.g. a Black Duck export or a custom migration-issue inventory) into a schema-valid assessment `report.json` the modernization pipeline can consume — so it appears in the assessment UI and migration solutions resolve automatically. This skill is LLM-driven: you read and interpret the CSV yourself and author `report.json` by hand against the schema. A small helper script only does deterministic lookups (migration solutions, the ruleId for a solution) and validates the finished report. There is NO "convert everything" script and NO assumed column layout. Triggers: "convert csv to assessment report", "import csv report", "turn this spreadsheet into a report.json", "Black Duck csv to report", "build report.json from csv", "migrate a third-party assessment export". NOT for: AppCAT-style analysis from source (use `assessment`), generating a modernization plan (use `create-modernization-plan`), or editing a report.json the pipeline already produced.

Quellinformationen

Repository
microsoft/github-copilot-modernization
Letzte Quellaktivität
22. September 2026 um 08:42
Erkannte Sprache von SKILL.md
Englisch
Sterne
49
Forks
14

Installationsoptionen

Standardmäßig ist der Prompt ausgewählt, der zuerst die Quelle prüft. Sie können zu einem direkten Befehl wechseln oder eine lokale Kopie herunterladen.

Quelldateien prüfen

Lesen Sie SKILL.md und alle von SkillsMP angezeigten Begleitdateien, bevor Sie sich für eine Installation entscheiden.

Datei-Explorer
7 Dateien

SKILL.md wird angezeigt

SKILL.md
Quellanweisungen · Schreibgeschützte Vorschau
name
assessment-report-converter
description
Convert an arbitrary CSV report (e.g. a Black Duck export or a custom migration-issue inventory) into a schema-valid assessment `report.json` the modernization pipeline can consume — so it appears in the assessment UI and migration solutions resolve automatically. This skill is LLM-driven: you read and interpret the CSV yourself and author `report.json` by hand against the schema. A small helper script only does deterministic lookups (migration solutions, the ruleId for a solution) and validates the finished report. There is NO "convert everything" script and NO assumed column layout. Triggers: "convert csv to assessment report", "import csv report", "turn this spreadsheet into a report.json", "Black Duck csv to report", "build report.json from csv", "migrate a third-party assessment export". NOT for: AppCAT-style analysis from source (use `assessment`), generating a modernization plan (use `create-modernization-plan`), or editing a report.json the pipeline already produced.
# Assessment Report Converter (CSV → report.json) ## What this skill does You take a **row-oriented CSV** of migration issues and produce a canonical **`report.json`** conforming to the assessment report schema. Once written to the versioned reports directory, the report is picked up by the assessment UI and by the solution-resolution logic — exactly like a native AppCAT report. **This is an LLM-driven conversion, not a fixed mapping script.** CSV layouts vary between tools and change over time, so *you* read the file, decide what each column means, classify every row, and author `report.json`. You do **not** rely on hard-coded column names. A small helper script — [scripts/report_tools.sh](scripts/report_tools.sh) (bash + jq) or its PowerShell twin [scripts/report_tools.ps1](scripts/report_tools.ps1) (PowerShell 7+) — provides only the deterministic pieces you should never guess: - **`list-solutions`** — discover the available migration solutions. - **`rules-for-solution`** — get the canonical `ruleId`(s) for a chosen solution. - **`upgrade-solutions`** — the canonical JDK / Spring Boot / Spring Framework / Jakarta EE upgrade solutions + ruleIds. - **`validate`** — structural + consistency validation of the finished `report.json`. ```mermaid flowchart LR A[Read CSV] --> B[Understand columns] --> C[Find projects] --> D{Audit each row} D -->|CVE / CWE| E[Security finding] D -->|Needs upgrade| F[Upgrade incident] D -->|Other| G[Solution → ruleId → incident] E --> H[Assemble report] F --> H G --> H H --> I[Validate] --> J[Save report.json] --> K[Summarize] ``` ## Input parameters - `csv-path` (mandatory): Path to the source CSV file. - `workspace-path` (optional): Output root. Defaults to the current directory. The report is written to `{workspace-path}/.github/modernize/assessment/reports/report-{reportId}/report.json`. - `producer` (optional): A label identifying the source tool, stored in `report.producer` (e.g. `"Black Duck"`). Defaults to `"CSV import"`. ## When to use this skill Use this when you have a **CSV** — not an AppCAT `report.json` — and you want it to behave like a real assessment report: a Black Duck / third-party export, or a hand-maintained spreadsheet of migration issues. Do **not** use it to run analysis from source code (that is the `assessment` skill). ## The helper script The helper ships as two interchangeable implementations of the same CLI — use whichever fits the machine: [scripts/report_tools.sh](scripts/report_tools.sh) (**bash + jq**) and [scripts/report_tools.ps1](scripts/report_tools.ps1) (**PowerShell 7+**, no extra dependencies). Both behave identically and never read the CSV. Run them from the `scripts/` directory. ```bash # bash + jq ./report_tools.sh list-solutions [--query KW] [--type Formula|Chat] [--ids-only] ./report_tools.sh rules-for-solution <solutionId> ./report_tools.sh upgrade-solutions ./report_tools.sh validate <path/to/report.json> ``` ```powershell # PowerShell 7+ pwsh ./report_tools.ps1 list-solutions [--query KW] [--type Formula|Chat] [--ids-only] pwsh ./report_tools.ps1 rules-for-solution <solutionId> pwsh ./report_tools.ps1 upgrade-solutions pwsh ./report_tools.ps1 validate <path/to/report.json> ``` - `list-solutions` prints the matching solutions from [scripts/solution-mapping.json](scripts/solution-mapping.json) as whole JSON objects (each always has `solutionId`, `name`, `type`, and `tooltip`; some also carry `effort` / `prompt`); `--query` filters by substring on id/name/tooltip. - `rules-for-solution` prints `{ solutionId, ruleCount, rules: [{ruleId, sourceCategory}], preferredRuleId }`. An empty list means the solution has **no** rule (e.g. a security-only solution) — do not invent a ruleId. - `upgrade-solutions` prints, per component (`jdk`, `spring-boot`, `spring-framework`, `jakarta-ee`), the `solutionId` and its resolved `preferredRuleId`. - `validate` runs structural + cross-field consistency checks (incident→rule references, required `domain`/`category` rule fields, enum values, security-finding shape and dedupe, and `metadata.domains`↔content consistency). Exit code is `0` valid, `1` invalid, `2` when the report can't be read/parsed. It accepts a `--schema <path>` flag for CLI compatibility but ignores it — the checks are self-contained. ## Reference material Detailed reference material is consolidated in the [Reference](#reference) section at the end of this file. The workflow below links to the relevant part at the step where you need it — you do not have to open any separate files: - [Report structure](#report-structure) — the top-level `report.json` shape and the authoring conventions the schema can't express (the schema owns the field shape). - [Assessment domains](#assessment-domains) — the `metadata.domains` values and when to include each. - [Security severity mapping](#security-severity-mapping) — normalizing a source CVE/CWE severity to the security `mandatory|potential|optional` scale. - [Rule classification](#rule-classification) — the required `domain` / `category` rule fields that group and render a rule's incidents. ## Workflow ### Step 1 — Understand the report structure (do this first) Read the authoritative schema [scripts/assessment-report.schema.json](scripts/assessment-report.schema.json) — it is the source of truth for the field shape. The report is a single root object `{ version, producer, metadata, projects, rules, security? }`, and `additionalProperties` is `false` almost everywhere (there is **no** `summary` object). The [report structure reference](#report-structure) adds the authoring conventions the schema can't express. You must know the required fields before authoring anything. ### Step 2 — Read and understand the CSV Read the CSV file directly (headers + a representative sample of rows). Then **interpret the columns by meaning**, since names and order vary by tool. Identify whichever of these the CSV actually carries (any may be absent): - a **project / module / service** identifier, - an **application** name, - an issue **title** and **description**, - a **severity / criticality / priority**, - a **category / domain / type**, - a **CVE / CWE** identifier, - an **affected component / package / library** and its **version**, - a **file** path and **line**, - an **effort / story-point** estimate, - a **reference / URL**. When a concept is missing, leave the corresponding report field empty or at its default — never fabricate data. ### Step 3 — Determine the projects Work out **how many projects** the CSV describes and group rows accordingly: - If a project/module/service column exists, group rows by it — one project per distinct value, using that value as `project.path`. - If the CSV has **no project information**, create a **single project** with `path` `"."` and minimal properties (`appName` `""`; leave optional `jdkVersion` / `frameworks` / `languages` / `tools` off or empty). - Populate `project.properties` **only** from what the CSV actually provides; otherwise keep them empty. Only `appName` is required. Every incident you create later belongs to exactly one of these projects. ### Step 4 — Audit each row, within its project Classify every row into exactly one of three branches and attach the result to the row's project. Every rule you add to `rules{}` must set its `domain` and `category` **fields** (that is what groups and renders its incidents) — see [rule classification](#rule-classification). Incidents do **not** require any label. 1. **CVE / CWE → security finding (directly).** When a row carries a `CVE-…` / `CWE-…` identifier (or unambiguously describes one), add a security finding to `report.security[]`. Capture **as much of the column as possible**: `id` (the CVE/CWE token), `title`, `category`, `severity` (the security scale `mandatory | potential | optional` — normalize the source severity per [security issue severity mapping](#security-severity-mapping)), `description`, `evidence.files` (affected paths), `evidence.explanation`, and optional `storyPoint`. **Merge by id** — one finding per CVE/CWE; accumulate evidence files and keep the strongest severity (`mandatory` > `potential` > `optional`). Security findings are **not** incidents; they live only in `report.security[]` (there is no summary to count them in). 2. **Needs a major-component version upgrade → upgrade incident.** If the row implies upgrading a major component — **JDK**, **Spring Boot**, **Spring Framework**, or **Java EE / Jakarta EE** (e.g. a CVE against `spring-boot`, an out-of-support runtime, an explicit "upgrade JDK") — run the `upgrade-solutions` command, pick the component, and use its `preferredRuleId`. Add that rule to `rules{}` (`severity: "mandatory"`, `domain: "java-upgrade"`, a `category`, a reasonable `effort`) and add an **incident** to the project — one upgrade rule per component per project, one incident per triggering row. A CVE that implies an upgrade produces **both** a security finding (branch 1) **and** an upgrade incident — that is what makes the upgrade resolve as a migration solution. 3. **Any other issue → solution → ruleId → incident.** Find the migration solution that fits the issue with the `list-solutions --query <keyword>` command, then get its canonical ruleId with `rules-for-solution <solutionId>` (use `preferredRuleId`). Add that rule to `rules{}` (with `domain`, `category`, `severity`, `effort`) and an incident to the project. If no solution fits, you may still record the issue with a clear **synthetic** ruleId (it just won't carry an automatic Formula solution) — or leave it for the "remaining" list in your summary. Either way, report it. #### Process rows in parallel Classifying a row is independent work, so for large CSVs do it concurrently rather than one row at a time: - **Batch the rows** (e.g. 20–50 per batch, or one batch per project) and dispatch the batches **in parallel** — launch several `Explore`/worker subagents at once, each auditing its batch into a partial result (security findings, upgrade hits, and ordinary incidents with their resolved ruleIds). Ask each worker to return structured JSON; it does **not** write files. - **Share the deterministic lookups.** Run the `upgrade-solutions` command and the `list-solutions` / `rules-for-solution` queries **once up front** (results are stable) and pass them to the workers, so parallel batches don't repeat the same lookups or race on them. - **Keep workers side-effect free**, then **merge sequentially** in one place so shared state stays correct: - **Security findings** — merge by `id` (one finding per CVE/CWE; union `evidence.files`, keep the strongest severity). - **Upgrade rules** — collapse to one rule per `(project, component)`; keep every triggering incident. - **`incidentId`s** — assign `"<ruleId>/<n>"` **after** the merge, never inside a worker (so ids are deterministic regardless of batch order). - If the CSV is small, just process the rows sequentially — the parallel split only pays off at scale. ### Step 5 — Assemble the report and finalize metadata There is **no** `summary` object to compute — assemble the top-level document and fill `metadata`: - `projects[]` = your projects, each with `properties` (only `appName` required) and its `incidents[]`. - `rules{}` = every distinct rule you referenced, keyed by ruleId, each with `id`, `title`, `severity`, `effort`, `domain`, and `category`. - `report.security[]` = the deduped findings (omit or leave empty when there are none). - `metadata.domains` = the assessment domains your report actually has content for, consistent with your `rule.domain` values — see [assessment domains](#assessment-domains). - `metadata.mode` (optional) = `"full"` when any security finding exists, else `"issue-only"`. - `metadata.status` = `"completed"`; `metadata.targetIds` = the target ids in scope (may be empty). - `metadata.id` (and the report-directory id) = `analysisStartTime` formatted `yyyyMMddHHmmss` (UTC); use the current UTC time when the CSV has no timestamp. ### Step 6 — Write and validate Write `report.json` to the versioned location ([Output location](#output-location)), then validate and fix until clean: ```bash # bash + jq ./report_tools.sh validate "<workspace>/.github/modernize/assessment/reports/report-<id>/report.json" # …or PowerShell 7+ pwsh ./report_tools.ps1 validate "<workspace>/.github/modernize/assessment/reports/report-<id>/report.json" ``` Resolve every reported consistency error before finishing. ### Step 7 — Summarize for the user Report a concise conversion summary: - **Converted rows** — number of security findings (CVE/CWE), upgrade incidents (with components), and ordinary issue incidents (with the solutions they mapped to); plus the project / rule / incident counts and the report path + id. - **Remaining rows** — rows you could not confidently map, and *why* (no matching solution, ambiguous column, missing id). - **Suggestions** — concrete next steps (e.g. pick a specific solution for a remaining row, add a project column to the CSV, supply severities), so the user can close the gaps. ## Output location - `{workspace-path}/.github/modernize/assessment/reports/report-{reportId}/report.json` - `reportId` = the report's `metadata.id` from Step 5 (`analysisStartTime` as `yyyyMMddHHmmss`, UTC). - Consider copying the original CSV next to `report.json` as `source.csv` for provenance. ## Success criteria - ✅ `report.json` is written to the versioned reports directory and the `validate` command reports **VALID**. - ✅ Projects reflect the CSV (one per module/service, or a single project with `appName: ""` when none is given). - ✅ CVE/CWE rows are `security[]` findings (deduped by id) with a `mandatory|potential|optional` severity; `mode` is `full`. - ✅ Rows implying a JDK / Spring Boot / Spring Framework / Jakarta EE upgrade add a mandatory upgrade incident whose `ruleId` came from the `upgrade-solutions` command. - ✅ Other issues map to a solution's canonical `ruleId` (via `list-solutions` + `rules-for-solution`) wherever one fits. - ✅ Every rule carries `domain` and `category` fields; every incident's `ruleId` resolves to a rule in `rules{}`; CVE/CWE findings stay in `security[]`, not `incidents[]`. - ✅ `metadata.domains` matches the report's content and the emitted `rule.domain` values (enforced by `validate`). - ✅ The user gets a summary of converted rows, remaining rows, and suggestions. ## Troubleshooting - **`validate` reports a consistency error** (e.g. an incident `ruleId` with no matching rule, or a `domains`/`security` mismatch) — the message names the exact field; fix that field. - **Don't add fields the schema doesn't allow** (e.g. a `summary` object, or `issues`/`storyPoints` on a project). The helper's `validate` is lenient about extra keys, but the app's importer enforces `additionalProperties: false` and will reject the report — this schema has no summary. Keep to the documented shape. - **A row has a CVE/CWE *and* needs an upgrade** — emit both: a `security[]` finding **and** an upgrade incident. They are not duplicates; the finding documents the vulnerability, the incident drives the upgrade solution. - **No solution fits an issue** — `list-solutions --query` returns nothing useful. Record the issue with a synthetic, descriptive `ruleId` (no Formula will attach) or list it under "remaining" with a suggestion.
Auf GitHub ansehen
Diese SKILL.md ist sehr gross, daher zeigt SkillsMP hier nur den ersten Abschnitt. Auf GitHub ansehen