diff --git a/plugins/code-modernization/README.md b/plugins/code-modernization/README.md index 048db6d..8678d69 100644 --- a/plugins/code-modernization/README.md +++ b/plugins/code-modernization/README.md @@ -10,7 +10,7 @@ Legacy modernization fails most often not because the target technology is wrong assess → map → extract-rules → brief → reimagine | transform → harden ``` -The discovery commands (`assess`, `map`, `extract-rules`) build artifacts under `analysis//`. The `brief` command synthesizes them into an approval gate. The build commands (`reimagine`, `transform`) write new code under `modernized/`. The `harden` command audits and patches the legacy system. Each step has a dedicated slash command, and specialist agents (legacy analyst, business rules extractor, architecture critic, security auditor, test engineer) are invoked from within those commands — or directly — to keep the work honest. +The discovery commands (`assess`, `map`, `extract-rules`) build artifacts under `analysis//`. The `brief` command synthesizes them into an approval gate. The build commands (`reimagine`, `transform`) write new code under `modernized/`. The `harden` command audits the legacy system and produces a reviewable remediation patch. Each step has a dedicated slash command, and specialist agents (legacy analyst, business rules extractor, architecture critic, security auditor, test engineer) are invoked from within those commands — or directly — to keep the work honest. ## Expected layout @@ -47,9 +47,7 @@ Greenfield rebuild from extracted intent rather than a structural port. Mines a Surgical, single-module strangler-fig rewrite. Plans first (HITL gate), then writes characterization tests via `test-engineer`, then an idiomatic target implementation under `modernized///`, proves equivalence by running the tests, and produces `TRANSFORMATION_NOTES.md` mapping legacy → modern with deliberate deviations called out. Reviewed by `architecture-critic`. ### `/modernize-harden ` -Security hardening pass on the **legacy** system: OWASP/CWE scan, dependency CVEs, secrets, injection. Spawns `security-auditor`. Produces `analysis//SECURITY_FINDINGS.md` ranked Critical / High / Medium / Low, then **patches Critical and High findings directly in `legacy//`** and re-scans to verify. Useful as a pre-modernization step when the legacy system will keep running in production during the migration. - -> **Note:** `/modernize-harden` is the one command that edits `legacy/`. If you adopt the `deny: Edit(legacy/**)` workspace setting below, relax it for this command — or run hardening as a separate workstream against its own checkout. +Security hardening pass on the **legacy** system: OWASP/CWE scan, dependency CVEs, secrets, injection. Spawns `security-auditor`. Produces `analysis//SECURITY_FINDINGS.md` ranked Critical / High / Medium / Low and a reviewed `analysis//security_remediation.patch` with minimal fixes for the Critical/High findings. The patch is reviewed by a second `security-auditor` pass before you see it. **Never edits `legacy/`** — you review and apply the patch yourself when ready, then re-run to verify. Useful as a pre-modernization step when the legacy system will keep running in production during the migration. ## Agents @@ -89,7 +87,7 @@ This plugin ships commands and agents, but modernization projects benefit from a } ``` -Adjust `legacy/` and `modernized/` to match your actual layout. The key invariants: `Edit` under `legacy/` is denied, and writes are scoped to `analysis/` (for documents) and `modernized/` (for the new code). The exception is `/modernize-harden`, which intentionally patches `legacy/` — see its note above. +Adjust `legacy/` and `modernized/` to match your actual layout. The key invariants: `Edit` under `legacy/` is denied, and writes are scoped to `analysis/` (for documents) and `modernized/` (for the new code). Every command in this plugin respects this — `/modernize-harden` writes a patch to `analysis/` rather than editing `legacy/` in place. ## Typical Workflow diff --git a/plugins/code-modernization/agents/security-auditor.md b/plugins/code-modernization/agents/security-auditor.md index e33ee94..f1b291d 100644 --- a/plugins/code-modernization/agents/security-auditor.md +++ b/plugins/code-modernization/agents/security-auditor.md @@ -11,28 +11,29 @@ engineer can fix. ## Coverage checklist -Adapt to the target stack — web items don't apply to a batch COBOL system, -mainframe items don't apply to a SPA. Work through what's relevant: +Adapt to the target stack — web items don't apply to a batch system, +terminal/screen items don't apply to a SPA. Work through what's relevant: -- **Injection** (SQL, NoSQL, OS command, LDAP, XPath, template, dynamic - DB2 SQL, JCL/PARM injection) — trace every user-controlled input to every sink +- **Injection** (SQL, NoSQL, OS command, LDAP, XPath, template) — trace every + user-controlled input to every sink, including dynamic SQL and shell-outs - **Authentication / session** — hardcoded creds, weak session handling, - missing auth checks on sensitive routes/transactions -- **Sensitive data exposure** — secrets in source, weak crypto, PII/PAN/SSN in - logs, cleartext data in copybooks/flat files + missing auth checks on sensitive routes/transactions/jobs +- **Sensitive data exposure** — secrets in source, weak crypto, PII in logs, + cleartext sensitive data in record layouts, flat files, or temp datasets - **Access control** — IDOR, missing ownership checks, privilege escalation; - for CICS: missing/permissive RACF transaction & resource definitions, - unguarded admin transactions -- **XSS / CSRF** — unescaped output, missing tokens (web targets only) -- **Insecure deserialization** — pickle/yaml.load/ObjectInputStream on - untrusted data + missing/permissive resource ACLs (RACF profiles, IAM policies, file perms); + unguarded admin functions +- **XSS / CSRF** — unescaped output, missing tokens (web targets) +- **Insecure deserialization** — untrusted data into pickle/yaml.load/ + `ObjectInputStream` or custom record parsers - **Vulnerable dependencies** — run `npm audit` / `pip-audit` / read manifests and flag versions with known CVEs -- **SSRF / path traversal / open redirect** (web targets only) -- **Input validation** — for CICS/3270: unvalidated BMS field input, - missing length/range/format checks before file/DB writes +- **SSRF / path traversal / open redirect** (web/network targets) +- **Input validation** — missing length/range/format checks at trust + boundaries (form/screen fields, API params, batch input records) before + persistence or downstream calls - **Security misconfiguration** — debug mode, verbose errors, default creds, - hardcoded passwords/userids in JCL, PROCs, or sign-on programs + hardcoded credentials in deployment scripts, job definitions, or config ## Tooling diff --git a/plugins/code-modernization/commands/modernize-harden.md b/plugins/code-modernization/commands/modernize-harden.md index 4ef80cf..b8f7a72 100644 --- a/plugins/code-modernization/commands/modernize-harden.md +++ b/plugins/code-modernization/commands/modernize-harden.md @@ -1,23 +1,26 @@ --- -description: Security vulnerability scan + remediation — OWASP, CVE, secrets, injection +description: Security vulnerability scan with a reviewable remediation patch — OWASP, CWE, CVE, secrets, injection argument-hint: --- Run a **security hardening pass** on `legacy/$1`: find vulnerabilities, rank -them, and fix the critical ones. +them, and produce a reviewable patch for the critical ones. + +This command never edits `legacy/` — it writes findings and a proposed patch +to `analysis/$1/`. The user reviews and applies (or not). ## Scan Spawn the **security-auditor** subagent: -"Adversarially audit legacy/$1 for security vulnerabilities. Cover: -OWASP Top 10 (injection, broken auth, XSS, SSRF, etc.), hardcoded secrets, -vulnerable dependency versions (check package manifests against known CVEs), -missing input validation, insecure deserialization, path traversal. -For each finding return: CWE ID, severity (Critical/High/Med/Low), file:line, -one-sentence exploit scenario, and recommended fix. Also run any available -SAST tooling (npm audit, pip-audit, OWASP dependency-check) and include -its raw output." +"Adversarially audit legacy/$1 for security vulnerabilities. Cover what's +relevant to the stack: injection (SQL/NoSQL/OS command/template), broken +auth, sensitive data exposure, access control gaps, insecure deserialization, +hardcoded secrets, vulnerable dependency versions, missing input validation, +path traversal. For each finding return: CWE ID, severity +(Critical/High/Med/Low), file:line, one-sentence exploit scenario, and +recommended fix. Run any available SAST tooling (npm audit, pip-audit, +OWASP dependency-check) and include its raw output." ## Triage @@ -28,19 +31,34 @@ Write `analysis/$1/SECURITY_FINDINGS.md`: ## Remediate -For each **Critical** and **High** finding, fix it directly in the source. -Make minimal, targeted changes. After each fix, add a one-line entry under -"Remediation Log" in SECURITY_FINDINGS.md: finding ID → commit-style summary -of what changed. +For each **Critical** and **High** finding, draft a minimal, targeted fix. +Do **not** edit `legacy/` — write all fixes as a single unified diff to +`analysis/$1/security_remediation.patch`, with a comment line above each +hunk citing the finding ID it addresses (`# SEC-001: parameterize the query`). -Show the cumulative diff: -```bash -git -C legacy/$1 diff -``` +Add a **Remediation Log** section to SECURITY_FINDINGS.md mapping each +finding ID → one-line summary of the proposed fix and the patch hunk that +implements it. ## Verify -Re-run the security-auditor against the patched code to confirm the -Critical/High findings are resolved. Update the scorecard with before/after. +Spawn the **security-auditor** again to **review the patch** against the +original code: + +"Review analysis/$1/security_remediation.patch against legacy/$1. For each +hunk: does it fully remediate the cited finding? Does it introduce new +vulnerabilities or change behavior beyond the fix? Return one verdict per +hunk: RESOLVES / PARTIAL / INTRODUCES-RISK, with a one-line reason." + +Add a **Patch Review** section to SECURITY_FINDINGS.md with the verdicts. +If any hunk is PARTIAL or INTRODUCES-RISK, revise the patch and re-review. + +## Present + +Tell the user the artifacts are ready: +- `analysis/$1/SECURITY_FINDINGS.md` — findings, remediation log, patch review +- `analysis/$1/security_remediation.patch` — review, then apply if appropriate + with `git -C legacy/$1 apply ../../analysis/$1/security_remediation.patch` +- Re-run `/modernize-harden $1` after applying to confirm resolution Suggest: `glow -p analysis/$1/SECURITY_FINDINGS.md` diff --git a/plugins/code-modernization/commands/modernize-map.md b/plugins/code-modernization/commands/modernize-map.md index 3a88f49..406b74c 100644 --- a/plugins/code-modernization/commands/modernize-map.md +++ b/plugins/code-modernization/commands/modernize-map.md @@ -11,39 +11,44 @@ connect? This is the map an engineer needs before touching anything. ## What to produce Write a one-off analysis script (Python or shell — your choice) that parses -the source under `legacy/$1` and extracts the four datasets below. Cover -the parse targets that are real for the stack you're looking at — these are -the ones LLMs reliably miss: +the source under `legacy/$1` and extracts the four datasets below. Three +principles apply across stacks; getting them wrong produces a misleading map: -- **Program/module call graph** — who calls whom. - - COBOL/CICS: `CALL '...'` and `EXEC CICS LINK/XCTL PROGRAM(...)`. Most - `PROGRAM(...)` targets are **data-names, not literals** — resolve them - against working-storage `VALUE` clauses and any menu/route copybooks - before declaring an edge unresolvable. - - Java: class-level imports/invocations. Node: `require`/`import`. -- **Data dependency graph** — which programs read/write which data stores. - - COBOL batch: `SELECT ... ASSIGN TO ` joined with JCL `DD` - statements (this is the *only* way to attribute file I/O to a program). - - COBOL/CICS online: `EXEC CICS READ/WRITE/REWRITE/DELETE/STARTBR/READNEXT/ - READPREV ... FILE(...)` joined with `DEFINE FILE` in the CSD. - - DB2: `EXEC SQL ... END-EXEC` table references — *not* JCL DD; DB2 access - is via plan/package binds. - - BMS: `SEND MAP`/`RECEIVE MAP` ↔ map source under `bms/` and copybooks - under `cpy-bms/` (or wherever the maps live). - - Java: JPA/MyBatis entities & tables. Node: model files. -- **Entry points** — whatever the stack's outermost invokers are. Mainframe: - JCL `EXEC PGM=` steps **and** CICS `DEFINE TRANSACTION ... PROGRAM(...)` - from the CSD — without the CSD, every online program looks unreachable. - Web: HTTP routes. CLI: argv parsing. -- **Dead-end candidates** — modules with no inbound edges. **Only trust this - once the entry-point and call-edge types above are all in the graph**, and - suppress the dead claim for any module that could be the target of an - unresolved dynamic call. A naive grep-only graph will mark most CICS - programs dead. +1. **Edges live in two places** — direct calls in source, *and* dispatcher/ + router calls whose targets are variables (config tables, route maps, + dependency injection, dynamic dispatch). Resolve variables against config + before declaring an edge unresolvable. +2. **The code↔storage join is usually external configuration**, not source — + job/deployment descriptors map logical names to physical stores. +3. **Entry points usually live in deployment config**, not source — without + parsing it, every top-level module looks unreachable. -For COBOL fixed-format, slice columns 8-72 and skip `*` indicator lines -(column 7) before regex matching, or you'll match sequence numbers and -commented-out code. +Extract: + +- **Program/module call graph** — direct calls (`CALL`, method invocations, + `import`/`require`) *and* dispatcher calls (`EXEC CICS LINK/XCTL`, DI + container wiring, framework routing, reflection/factory). Resolve variable + call targets against route tables, copybooks, config, or constant pools. +- **Data dependency graph** — which modules read/write which data stores, + joined through the relevant config: `SELECT…ASSIGN TO` ↔ JCL `DD` (batch + COBOL), `EXEC CICS READ/WRITE…FILE()` ↔ CSD `DEFINE FILE` (CICS online), + `EXEC SQL` table refs (embedded SQL), ORM annotations/mappings (Java/.NET), + model files (Node/Python/Ruby). Include UI/screen bindings (BMS maps, JSPs, + templates) — they're dependencies too. +- **Entry points** — whatever the stack's outermost invoker is, read from + where it's defined: JCL `EXEC PGM=` and CICS CSD `DEFINE TRANSACTION` + (mainframe), `web.xml`/route annotations/route files (web), `main()`/argv + parsing (CLI), queue/scheduler subscriptions (event-driven). +- **Dead-end candidates** — modules with no inbound edges. **Only meaningful + once all the entry-point and call-edge types above are in the graph.** + Suppress the dead claim for anything that could be the target of an + unresolved dynamic call. A grep-only graph will mark most dispatcher-driven + modules (CICS programs, Spring controllers, ORM-bound DAOs) dead when they + aren't. + +If the source is fixed-column (COBOL columns 8–72, RPG, etc.), slice the +code area and strip comment lines before regex matching, or you'll match +sequence numbers and commented-out code. Save the script as `analysis/$1/extract_topology.py` (or `.sh`) so it can be re-run and audited. Have it write a machine-readable