cobolwork and ironwork
COBOL · JCL · CICS
cobolwork
Security analysis that reads COBOL the way the compiler does.
It finds where untrusted input from a job’s PARM, in-stream data, ACCEPT … FROM COMMAND-LINE or a CICS terminal reaches dynamic SQL, a dynamic CALL, a subscript or the internal reader, across CALL … USING, with copybooks resolved and reference format read. As a build gate it stops the compile on blocking findings or a missing SSRANGE, and it flags RACF, PASSWORD= and TSO logon credentials.
critargv-or-env-to-os-commandCWE-784 hops
ACCEPT … FROM COMMAND-LINEP1.cbl:8CALL 'P2'argument 1P1.cbl:10CALL 'SYSTEM' USING WS-LOCALP2.cbl:10
- Runtime dependencies
- 0
- Node
- 22 or later
- Licence
- AGPL-3.0-or-later
Enterprise COBOL · z/Architecture
ironwork
A COBOL compiler that targets Enterprise COBOL byte for byte.
Today an interpreter runs batch programs, with SORT, Report Writer and EXEC SQL, and CICS tasks on a 3270 terminal, and abends S0C7 where z/OS would. WORKING-STORAGE stays in EBCDIC, packed and zoned decimal behave as PACK, ZAP, AP and DP treat them, COMP-1 and COMP-2 are hexadecimal floating point, and ARITH, TRUNC, NUMPROC and CODEPAGE on the CBL card work as they do in IBM’s compiler. ironwork compile writes a program as a load module. Limit: running a module waits on the VM.
CUST-REC16 bytesCODEPAGE(1140)
F0F0F1F2F3C1C3D4C5400012345D0929
payadd.cbl:9:21: ABEND S0C7: Data exception
- Written in
- Rust
- Unsafe code
- Forbidden
- Licence
- AGPL-3.0-or-later
How they fit
Two repositories, one boundary
ironwork owns everything that defines or executes COBOL semantics: the machine and compiler models, the conformance oracle, the front end, the storage layout, the interpreter, code generation and the runtime.
cobolwork stays a zero-dependency analysis tool and never links ironwork. It keeps estate reading across COBOL, JCL, CICS and BMS, option resolution across installation defaults, PARM and CBL cards for the build gate, and its findings. The two share data only: IBM’s tables and fixtures, listed under Shared data.
What ironwork learns reaches cobolwork as analysis rules. The first three shipped in cobolwork 0.2.117:
TRUNC(OPT) receiversshipped
Finds binary stores where IBM leaves the result to the generated code.
The rule flags a binary receiver given more integer digits than its PICTURE, in a program compiled TRUNC(OPT), and is the static counterpart of ironwork’s checked mode.
Characters in EBCDIC and ASCIIshipped
Finds character ranges that are empty on one platform.
The rule flags a THRU range of characters, in an 88-level or a WHEN, that is in order in EBCDIC and reversed in ASCII, or the other way round.
Intermediates past ARITHshipped
Finds arithmetic that loses high-order digits with no SIZE ERROR.
The rule flags a COMPUTE with an intermediate wider than 30 digits, or 31 under ARITH(EXTEND), where IBM drops the high-order digits.
Roadmap
Features the two build together, by target release
cobolwork runs ironwork as a separate program, as it runs cobc. Targets give the order of the work, not dates. An additional pill marks a feature added after the first roadmap, of 30 September 2026. Each product’s own roadmap has a page: cobolwork, ironwork.
Shippeddone
cobolwork 0.2.117 and ironwork 0.1.2
- ironwork in the build gate: an IBM estate is compile-checked by a compiler that follows IBM’s rules. For estates that target IBM,
cobolwork buildcompiles withironwork checkinstead ofcobc. - Shared data: the two read the same IBM tables, held equal by a drift test on each side. IBM’s compiler-option table, the CICS command, DFHRESP and DFHVALUE tables, the host-variable table and IBM’s reserved words, with BMS, SQL and CSD fixtures, are copied into each repository.
- Rules from ironwork’s model: what ironwork learns about IBM’s semantics becomes a cobolwork rule: the three rules under How they fit.
- Equivalence for a change: a change can be shown to leave every output unchanged before it merges. ironwork’s
compareruns a program before and after a change on the same inputs and states whether every output matches, and cobolwork’s build gate can require that statement for each program a change edits.
cobolwork 0.3.0 · ironwork 0.2.0released
A compile check with IBM’s severities, in cobolwork 0.2.140 and ironwork 0.1.2
- 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 - IBM’s reserved words by column: a reserved word used as a name is refused, as IBM refuses it. cobolwork generates the table, and ironwork refuses by it.in 0.2.140
cobolwork 0.5.0 and 0.6.0 · ironwork 0.3.0released
Findings witnessed by a run
- Machine-labelled precision: how far to trust each rule is published. Each finding’s verification plan runs in ironwork with a marker; the finding is labelled by whether the marker reaches the sink, and precision is published per rule with the label source named.The first table is in cobolwork 0.5.0, from labels made with ironwork 0.2.0.released
- Abends as findings: a crash is found by fuzzing, with its input. Programs are fuzzed through ironwork, so an
S0C7, anS0C4or a subscript out of range becomes a cobolwork finding with the input that caused it.cobolwork 0.4.0 reads the abends, and ironwork 0.2.0 ends an SSRANGE failure withU4038and IBM’s message id. In cobolwork 0.6.0, ironwork 0.4.0’s fuzzing gives 1,372 findings in 105 of 500 held-out repositories. Limit:ironwork fuzz, in ironwork 0.3.0, fuzzes batch programs only.released - Confirmation in a test region: a finding is confirmed by a harmless run. An ironwork run uses the harmless value a cobolwork verification plan names, traced from the input to the operation. A witness result cites the ironwork run that reproduced it.In cobolwork 0.4.0 and ironwork 0.2.0.released
- Execution coverage: a finding says whether the estate’s runs entered its paragraph.
ironwork run --coveragereports the paragraphs a run reached.In cobolwork 0.2.150 and ironwork 0.2.0.released
ironwork 0.6.0released
Running the jobs cobolwork reads
- A JCL runner: the jobs cobolwork reads run off the mainframe, with the utilities cobolwork documents.released
- Migration equivalence for a job: a migrated job’s outputs are checked against production’s.in 0.1.2
cobolwork 0.9.0 · ironwork 0.7.0started
Every label the runs can give
- Negatives from coverage: a finding is refuted only when runs covered every route and input never reached the operation. ironwork follows input byte by byte, and cobolwork refutes on that evidence alone.cobolwork 0.9.0 ships it unmeasured, as decision D-11 allows, and the measurement moves to 1.1.plannedadditional
- Files named at run time: findings that write to a file assigned from a data item get labels from runs.ironwork 0.7.0 runs and traces it under
--compliance extended, and cobolwork 0.7.0’s labeller labels these findings, each row recordinglabelledOn: extended.releasedadditional
cobolwork 1.0 · ironwork 1.0planned
Stable together
- Results read by id: cobolwork reads ironwork’s results by message id, and ironwork adds ids without changing old ones.cobolwork 0.7.0 reads the message id ironwork puts before a diagnostic, and an IWR id, a construct ironwork does not run yet, as undecided.startedadditional
- One convention for exit codes: both tools report pass, fail and undecided the same way.additional
- Release order: each 1.0 is cut against the other’s release candidate: cobolwork 0.9.0, then ironwork 0.9.0, then cobolwork 1.0, then ironwork 1.0.additional
Unscheduleddecision
After the Enterprise COBOL goldens
- IBM layouts as a witness: IBM-only size rules gain an independent witness. ironwork’s storage layouts become cobolwork fixtures.Limit: until goldens exist, ironwork is no independent witness.additional