cobolwork · Roadmap
Features by target release
Targets give the order of the work, not dates: a feature moves when what it depends on moves, and stays on its target card with a pill naming the release that shipped it. An additional pill marks a feature added after the first roadmap, of 30 September 2026.
0.3.0released
Precision, and where data goes
- Subscript and length findings: fewer false positives where a loop exit, a constant or a check keeps the index inside its table or field. A length beside a varying start is judged with the start, and a counter a performed paragraph raises only under a test that leaves room stays bounded.Limit: some cases are still reported, among them a length checked only after it is computed and an index bounded through a third field.in 0.3.0
- The HIGH rules that block most builds: fewer builds stopped in error. The rules were audited for precision: two classes of false positive are fixed, and the other top rules read true on the sample.in 0.2.140
- Two rules corrected by planted flaws: each credits a check where it protects the operation. A COMMAREA length check counts only where EIBCALEN bounds the read, and an IF that ends the run before a dynamic CALL stays an allow-list across a loop that calls through the checked name.in 0.2.150additional
- A directory a drive fails to list: a scan with unread directories is undecided rather than passed. The directory is retried, then counted unread.in 0.3.0additional
- FTP
GETandSITE: an FTP step’s transfers are followed as data movement.in 0.2.140 - IDCAMS
PRINTandALTER NEWNAME: each says where it moves data.in 0.2.140 - A TSO batch step’s
ALLOCATE,CALLandDSN RUN: the programs and data sets a TSO step reaches are read, fromSYSTSIN.in 0.2.140 - The GitHub Action: the build gate runs on GitHub-hosted runners, pull-request base included.in 0.2.117
- ironwork diagnostics read by code: the build gate reads
ironwork check’s return code, which follows IBM’s severities. ironwork compiles ENTRY and ALTER and refuses EXEC DLI by name.Limit: two kinds of refusal are still read by their wording, since ironwork’s messages carry no ids.in 0.2.140 - SLSA build provenance: each PyPI file can be traced to the build that made it.Limit: the npm package and the GitHub release’s tgz are not attested yet.in 0.2.140
- IBM’s reserved words by column: ironwork’s compile check refuses a reserved word used as a name.in 0.2.140
0.4.0released
Source from git, and a caller for the remediation gate
- A reference caller for
cobolwork gate: a drafted fix passes only when the gate shows it fixed its finding and moved nothing else. commitwork’s remediation caller commits each draft through a private index with no checkout, gates it at--head, stops after three attempts, and runs the resweep with--target-only. A passing draft is lodged for review, not applied.- A patch that deletes the flagged statement or its source fails the gate.
explainquotes every line of a statement, and a patch that stops a program compiling gives the gate up to three of the compiler’s error lines.
- A source tree read from a git revision: a change is compared without checking either revision out.
diffreads both revisions out of git and writes nothing, and the parser reads copybooks through the source-tree port.Limit:buildandgatestill write each revision, since the compiler reads files.in 0.2.150 - A PDS export as a source tree: an estate downloaded from z/OS is scanned as it lands.
scan --pds-exportreads whatzowe zos-files download all-memberswrites, or a directory named for each data set, and names each findingDATA.SET/MEMBER. Members are classified by what they hold, whatever extension the download gave them.Limit:diffandbuilddo not take it yet, and XMIT and IEBCOPY unload files are not read.in 0.2.150 - Crafted input: crafted input cannot slow a scan, split an argument or open a link. A long line of trailing blanks, a padded directive and a
>>DEFINEbody with a stray line break are each read in linear time.in 0.4.0additional - COBIT 2019 mappings by identifier: every rule but two maps to a COBIT 2019 practice, with this project’s own rationale and no ISACA text, each following the rule’s NIST control.in 0.2.150
- Card, layout and embedded-SQL modules: the groundwork for more languages. Data layout, the card column model and one reader of Db2 host variables each have their own module, split out of the parser and the flow engine.in 0.2.150
0.5.0released
Precision measured by machine labels
6 of 6 features done · 3 changes
- Precision per rule and per exploitability verdict: how far to trust each rule is published with each release. Each number names its label source, and unknowns are shown as a range. The first table is in the 0.5.0 release notes.in 0.4.0
1 change
- Precision per rule and per verdict from machine labels
- Labels from execution: a path finding is confirmed by a run that shows input reaching the operation. Each finding’s verification plan runs in ironwork, with a marker put in at the source; the marker reaching the sink’s operand confirms the finding, and the sealed run journal is its evidence. An operation that acts never runs; a storage sink is confirmed by the SSRANGE abend at the finding’s line, against a control run. Over 500 held-out repositories, 34 of 1,896 path findings are confirmed and none refuted.Limit: most findings stay unknown: ironwork does not trace a file assigned from a data item, and refuses GnuCOBOL’s command-line and environment reads.in 0.4.0
2 changes
- Execution labels, each path finding's plan run in ironwork
- Storage findings labelled by the SSRANGE abend, with a control
- Every route of a finding: a finding can name every route from its sources to its sink, not only the shortest.
--all-routesonscanandflowlists every source and every statement on any route to the sink.in 0.5.0additional - CALL write-back: fewer path findings that no run can take. A value a CALL writes back through a parameter returns only to the call it came in by. Path findings fell from 3,659 to 1,950 on 500 random repositories, and from 1,506 to 1,214 on 500 recently active ones.in 0.4.0additional
- Planted flaws: recall is measured on real programs. Known flaws and near-miss negatives are planted into real programs, labelled by construction. Over 500 repositories, seven rules reported all 275 planted flaws and none of the 325 near-misses.in 0.5.0additional
fixAton the input field: the check goes where the value enters. Where a STRING built the SQL statement or command an operation runs, the finding names the input field folded in and the STRING statement.in 0.4.0
0.6.0released
Findings witnessed by a run, with ironwork 0.3.0
5 of 5 features done · 7 changes
- Abends as findings: a crash is found by fuzzing, with the input that causes it. Each
S0C7,S0C4or SSRANGE subscript or reference-modification failure that ironwork’s fuzzing kept is reported under theexecutionevidence kind, read fromCOBOLWORK_ABENDS, with its journals verified.In 0.6.0, an input that keeps a loop running past a limit (input-causes-hang) or chooses the program a CALL loads (input-selects-program) is a finding of its own, an abend fromironwork fuzz --jobis placed in the COBOL step that gave it, and a subprogram fuzzed at its interface reports what a caller passing those arguments would cause, gated by the policy keyinterface. Over the 500 held-out repositories, ironwork 0.4.0’s fuzzing gives 1,372 findings in 105 repositories, 744 of them in one repository of generated copies. Limit: needs ironwork 0.3.0 or later, forironwork fuzz, and 0.5.0 or later for a subprogram fuzzed at its interface.in 0.6.07 changes
- An abend ironwork's fuzzing kept is a finding, with its input
- Place a fuzz abend in a library member under that library
- Place a fuzz abend in a CALLed program under the library holding it
- Report a CICS task's data exception as an S0C7 finding
- Refuse a fuzz manifest in a format it does not read
- Read a subprogram fuzzed at its interface
- Gate abends from interface fuzzing by their own key
- Confirmation in a test region: a finding is confirmed by a harmless run. An ironwork run uses the harmless value a verification plan names, traced from the input to the operation. A witness result cites the run, and a scan confirms the finding only where the run’s verified journal shows the marker reaching the operation, or an abend, at the finding’s file and line.Limit: needs ironwork 0.2.0 or later, for
--trace-marker.in 0.4.0 - Execution coverage: a finding says whether the estate’s runs entered its paragraph, read from
COBOLWORK_EXECUTION.Limit: needs ironwork 0.2.0 or later, forrun --coverage.in 0.2.150 - Releases that publish themselves: each package is published by the release workflow, after every build passes. A release tag is protected, each registry waits for the maintainer’s approval, and the npm package carries provenance, as the PyPI files do.in 0.6.0additional
- A versioned baseline: a baseline written today is read by every later release. The file carries a version, and one written before it is read as version 0 and migrated.in 0.6.0additional
0.7.0released
The CICS web API, and credential rules upstream
- CICS web API rules: findings for programs that serve or call the web through CICS. An outbound connection asking for HTTP rather than HTTPS, a
WEB RECEIVEorWEB CONVERSEthat lets a body overrun its area, and weak cryptography asked of ICSF: a single-length DES key, an MD5 or SHA-1 hash, a fixed initialization vector. Each was measured over the 14 public repositories that use the CICS web API and the 3 that call ICSF.In 0.7.0, a web request’s form fields, query parameters and headers, whichWEB READ,WEB READNEXTandWEB EXTRACTreturn, are web input. Limit:TRANSFORM XMLTODATAand the rest of the identity rules were measured and not built: one witness for the first, and no impersonation shape in any repository for the second.in 0.5.0 - The mainframe credential rules in Betterleaks: Betterleaks can find a RACF password or password phrase in JCL, a credential in a COBOL
VALUEand a password in an SQLCONNECTwithout cobolwork. Four rules are in a pull request awaiting review, betterleaks#379: the JCL password, the new password when a JOB card changes it, the COBOLVALUEand the SQLCONNECT. Betterleaks is the successor to gitleaks, which takes no new rules. Over the 500 held-out repositories they report 23 findings in 9 repositories, all literal credentials.cobolwork 0.7.0 does not depend on it: its rules stay inrules/gitleaks-mainframe.toml, and thesecretsset runs without gitleaks or Betterleaks. Limit: the TSO logon, RACF command and CICS sign-on rules are not in it, since the corpus holds no instance of them.started
0.8.0released
BMS, then four more languages
3 of 3 features done · 4 changes
- BMS maps: a map’s input fields are declared items, and RECEIVE MAP is a terminal source on them. A COPY of a mapset the tree holds only as BMS source reads the symbolic map BMS would generate.Limit: mapsets with GRPNAME or OCCURS fields are not generated, and the four
bms-*rules are not built.in 0.4.0additional1 change
- A COPY of a mapset held only as BMS reads its symbolic map
- HLASM: assembler stubs are read beside the COBOL that calls them. A switch to key zero or supervisor state, an instruction run through
EX, cross-memory calls and direct calls to the security product are reported, and a COBOLCALLor a job step resolves to the CSECT or ENTRY that defines it. Every one of the 276 files z390 assembles in the 3,185-repository corpus reads with no card error.In 0.6.0, each statement is parsed by its kind, with 2,388 machine instructions from the Principles of Operation, and LINK, XCTL, LOAD and ATTACH that name a module by its address are reported. Graded against z390 on values no macro expansion changes, the locator places 2,511 of 2,546 statement locations on the development corpus and 1,631 of 1,675 on the held-out one, none differing. In 0.7.0, MVS 3.8 macro operands are read, aMODESETswitch to any system key is reported at high, and every program of a batch file is read; outside conditional assembly, 5,784 of 5,796 statements parse on the held-out corpus. Limit: HLASM is read, not assembled, so an operation a site macro issues is seen where the macro is defined.in 0.5.0 - PL/I, IMS DBD and PSB, and Db2 DDL: the rest of an estate is read beside its COBOL, as planned in language-coverage.md.In 0.7.0, every scan reads PL/I programs into the data-flow graph, and IMS DBDs and PSBs and Db2 13 for z/OS DDL through the
imsandddlrule sets. 98.8% of 9,547 hand-written PL/I statements parse on the development corpus and 99.8% on each held-out set, and reading PL/I adds 73 findings over the 20 repositories of the 500 set that hold it. A PSB granting an option its programs’ DL/I calls never use is high, and a GRANT toPUBLIC,WITH GRANT OPTIONor of a system authority is reported. Limit: PL/I has no compiler that may grade the reader, and a pointer, an entry variable or the preprocessor takes PL/I’s flow out of sight; those are listed, not followed. DL/IISRTandREPLare not sinks yet.in 0.7.03 changes
- Read PL/I in every scan, and finish the Db2 DDL phase
- Run the IMS and Db2 rules in every scan
- Read DL/I calls and hold each PSB to the calls that use it
0.9.0released
The release candidate: every repository read to the end, the remaining rule sets, and frozen formats
5 of 8 features done · 9 changes
- Every repository read to the end: a large estate is scanned completely, within a stated time. The flow set keeps a compact graph and analyses each distinct program once, and leaves out no route a run could take.In 0.7.0, the control analyses of programs of 32 KiB or more are built in worker threads, at most four by default: with four, cnafbadboy’s
Batchscans in 109 s against 314 s, at up to 2.5 GB more peak memory, and reports are identical to those built without workers on 11 repositories. In 0.9.0, a state with a call context examines only its own call’s return from a subprogram many places call, and the walk bounds rise to 79 million edges a walk and 2.1 billion in all, where 5 million and 500 million cut 82 of ACAS’s walks: ACAS walks every source and reports 185 findings for 120. Limit: Unieuro’s flow walk still stops at the total bound.startedadditional1 change
- Raise the walk bounds to what ACAS needs
- Three more rule sets in the build gate: a build fails on status codes nothing tests, values cut short, and credentials in source. I/O, SQL and CICS responses no statement checks; text and numbers a MOVE truncates; credentials written into source. Each starts as a warning until it is measured.The secrets set, credentials written into source, is in 0.6.0. In 0.9.0, the errors set reports a file, Db2 or CICS status the program sets and never tests, and the truncation set reports input a STRING, a MOVE, an arithmetic statement or a selector drops without an abend: three status rules and eighteen truncation rules, each a warning until its rate is recorded.in 0.9.0additional
1 change
- Let phrases, CLOSE and a cursor's FETCH answer for a status
- CICS and SQL translated before the compiler:
buildcompiles CICS and SQL programs as IBM’s translators leave them. CICS WEB, DOCUMENT, INQUIRE and SET are translated too, and the flow engine reads each command through the translator’s table.In 0.7.0,build --precompiletranslates each program holding EXEC SQL or EXEC CICS and compiles the translation with-fsyntax-onlybefore the compiler command runs. The precompile table names 61 more commands, WEB, DOCUMENT, and INQUIRE and SET for eight resources among them, and the flow engine reads each EXEC block once, by that table. In 0.8.0, what CICS says about an abend, the region or its resources reaches only what a web caller is sent. Limit: a program holding EXEC DLI is left to the compiler command, and the translation is a check, never the artifact.in 0.7.0additional3 changes
- Check precompiled EXEC programs with --precompile
- Direct WEB, DOCUMENT, INQUIRE and SET commands
- Read each EXEC block once, named by the precompile table
- A z/OS download everywhere:
diffandbuildtake a PDS export asscandoes, and XMIT and IEBCOPY unload files are read.In 0.7.0,scan,diffandbuildtake--pds-export, and a TSO TRANSMIT file or an IEBCOPY unload is read into its data set, placing each member by its directory entry. Limit: a PDSE unload, an IEBCOPY marked in error or a transmission of several files is reported and not read, andbuildrefuses a compiler command over an export.in 0.7.0additional3 changes
- Read XMIT files and IEBCOPY unloads in a PDS export
- Compare two revisions of a PDS export member by member
- Judge a PDS export's members by their data set names
- Negatives from coverage: a finding the runs did not confirm is never called false on a guess. A run that reached the sink without the input is no refutation: a step can run without carrying the value, a source can deliver nothing, a write can fall between two steps, and a subscript’s input steers rather than arrives. Each coverage label stays unknown until an argument over every path exists.On main,
bench/label.mjs --trace-inputrecords beside each unknown label whether input reached the sink, ironwork’s taint following EXEC CICS too. On the 500-repository set the 109 CICS findings whose operation ran without the marker all read false, and the two inspected are real findings the labeller’s input did not route. 0.9.0 ships it unmeasured, as decision D-11 allows, and the measurement moves to 1.1. Limit: needs ironwork 0.4.0 or later, for--trace-input, which follows which bytes of each operand came from the input.plannedadditional - Two models on the rest: findings execution leaves unknown can still get a label. Each is labelled only where two models agree, after their accuracy is measured on the execution-labelled findings. Both models run on the machine that holds the source.0.9.0 ships without it, as decision D-11 allows, and the two-model labels move to 1.1.plannedadditional
- A sound fix to a command passes the gate: the remediation gate passes a fix that parameterises a command or tests the whole field.In 0.9.0, a value the program sets in an environment variable is followed to a literal command that reads it. The route is credited where the command reads the variable only as a quoted argument and the field passed a test against a class with no shell syntax and no leading
-.in 0.9.0additional1 change
- Credit a command that reads a checked field as one argument
- Formats frozen: every file cobolwork writes or reads carries a version and a schema, and changes only at a major release. Findings, baselines, the site file, evidence and witness feeds, and SARIF with CWE taxonomies. Fingerprints are pinned by test.In 0.7.0, a schema under
schema/describes every document cobolwork writes or reads, and a test holds real output to it. The site file and the witness and reach feeds carry a version and name the keys they ignore, SARIF relates each rule to its CWE, andSTABILITY.mdstates what changes only at a major release. In 0.8.0, a label names the ironwork assumptions its runs rested on, where a run’s journal lists them.in 0.8.0additional
1.0.0started
Stable
1 of 7 features done · 9 changes
- Reference for every command: each command, option, exit code, environment variable and setting is documented, generated from the tool itself.additional
- Precision for every rule: each rule says how far to trust it, with its label source, its labelled count, the share still unknown, and the share that rests on an ironwork assumption no IBM compiler has checked.additional
- A stated scope: what cobolwork reads, what it refuses and what it leaves unmeasured is written down.additional
- Every release file attested: each file can be traced to the build that made it and rebuilt to the same bytes, with an SBOM of cobolwork itself.additional
- ironwork’s results read by id: the build gate reads
ironwork checkby message id, never by wording.In 0.7.0, the gate keeps the id ironwork puts before a message apart from its wording, and reads an IWR id, a construct ironwork does not run yet, as undecided. In 0.8.0, the id decides: an IWR message leaves a program undecided, an IWS, IWC or IGY message, what Enterprise COBOL refuses, means it does not compile, and the wording is read only for a message without an id. Limit: needs ironwork 0.9.0.startedadditional - Findings and evidence mapped to compliance frameworks: each rule and each kind of evidence names the DORA, NIST SP 800-53, FFIEC and COBIT 2019 clauses it bears on, in the report’s
ruleCompliance, on each SARIF rule, and inevidence verify’scompliance. A clause no evidence can support says why.Limit: the COBIT ids are not yet checked against a licensed copy.in 0.7.0additional2 changes
- Map the tools' evidence to framework clauses
- Carry each rule's framework clauses on its descriptor
- One document of advice: every remediation and best practice for a repository comes from one document, each item naming the rule, practice or compiler message it rests on,
cobolwork advisewrites it as JSON, SARIF or Markdown, with ironwork compiling every program where it is present: 19 practice rules, 872 ironwork message ids with 78 remedies, and IBM references on 97 rules.Limit: the practice rules stay unmeasured until their samples are read, and commitwork’s pinned cobolwork has noadviseyet.startedadditional7 changes
- Add the advice document, its schema and catalogue
- Render the advice document as SARIF and as Markdown
- Add steps, IBM references and pack remedies
- Read ironwork check into compile items
- Write advise as SARIF or Markdown with --format
- Report the practices a repository misses
- Describe the practice set in the rule-set catalogue