feat(fls): write the system software of a .fls, loaded by Java as the original
topologyWriter.ts now sets the system software each device's constructor makes, through its setters: a switch's SSID and learning time, a host's SSID, RIP, manual routes, DHCP client and server with static assignments, static NAT, the modem, and a router's or home router's firewall. The firewall is reached as XMLEncoder reaches it, through the web server's `konfig` plug-in: the constructor hangs the same object there and among the applications, where its key differs (Firewall on a router, NatGateway on a home router). A switch's SSID the file lacked stays unwritten, so Java rolls one as it did. Files and applications are later layers. javaBeansWriter.ts: a call can carry statements on its result (a map's value changed through get(key)), checked by Java's XMLDecoder in a new case; a short() helper for Java's short values. Checked by Java against Java: every corpus file, read and written again, loads with the same system software (without files and applications) as the original. The synthetic topology adds what the corpus lacks: a router firewall switched on with rules of every protocol (one with a null address), every flag away from its default, a modem with its own port and target, and a PC's SSID, routes and DHCP server. 16 mutation probes, each rewritten and loaded by Java, were all caught. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,8 +1,9 @@
|
||||
// Every corpus file, read and written again: Java FILIUS loads the written
|
||||
// file (tools/java-oracle, written.java.json) to the same topology as the
|
||||
// original (corpus.java.json) — devices, names, positions, interfaces,
|
||||
// cables and documentation. Java against Java: no mapping of this package
|
||||
// stands between the two.
|
||||
// system software (without files and applications), cables and
|
||||
// documentation. Java against Java: no mapping of this package stands
|
||||
// between the two.
|
||||
//
|
||||
// UPDATE_WRITTEN=1 writes the files to test/written/ (not checked in); the
|
||||
// Java oracle then loads them and records each file's SHA-256, which must
|
||||
@@ -28,13 +29,30 @@ function flsFiles(directory: string): string[] {
|
||||
});
|
||||
}
|
||||
|
||||
type JavaNode = { class: string; name: string | null; bounds: number[]; useIpAsName: boolean; useMacAsName: boolean; ports: unknown };
|
||||
type JavaNode = {
|
||||
class: string;
|
||||
name: string | null;
|
||||
bounds: number[];
|
||||
useIpAsName: boolean;
|
||||
useMacAsName: boolean;
|
||||
ports: unknown;
|
||||
system: Record<string, unknown>;
|
||||
};
|
||||
type JavaFile = { success: boolean; nodes: JavaNode[]; cables: unknown[]; documentation: unknown[]; sha256?: string };
|
||||
|
||||
const original = JSON.parse(readFileSync(join(corpusRoot, 'corpus.java.json'), 'utf8')) as Record<string, JavaFile>;
|
||||
const written = JSON.parse(readFileSync(join(here, 'written.java.json'), 'utf8')) as Record<string, JavaFile>;
|
||||
|
||||
/** The topology of Java's view: the label's position, not its size, which Java works out itself. */
|
||||
/** The system software without its files and applications, which are later layers. */
|
||||
function systemOf(system: Record<string, unknown>) {
|
||||
const { fileSystem: _files, applications: _applications, ...settings } = system;
|
||||
return settings;
|
||||
}
|
||||
|
||||
/**
|
||||
* The topology of Java's view: the label's position, not its size, which
|
||||
* Java works out itself.
|
||||
*/
|
||||
function topologyOf(view: JavaFile) {
|
||||
return {
|
||||
success: view.success,
|
||||
@@ -45,6 +63,7 @@ function topologyOf(view: JavaFile) {
|
||||
useIpAsName: node.useIpAsName,
|
||||
useMacAsName: node.useMacAsName,
|
||||
ports: node.ports,
|
||||
system: systemOf(node.system),
|
||||
})),
|
||||
cables: view.cables,
|
||||
documentation: view.documentation,
|
||||
@@ -70,7 +89,13 @@ describe('the topology written again, as Java loads it', () => {
|
||||
}
|
||||
});
|
||||
|
||||
/** What the corpus does not have: a name set to null, useMACAsName, fewer ports than the constructor makes, more interfaces. */
|
||||
/**
|
||||
* What the corpus does not have: a name set to null, useMACAsName, fewer
|
||||
* ports than the constructor makes, more interfaces; a PC's SSID, routes and
|
||||
* DHCP server with static assignments; a router's firewall switched on, with
|
||||
* every flag away from its default and rules of every protocol, one with a
|
||||
* null address; a modem's own port and address.
|
||||
*/
|
||||
const SYNTHETIC: TopologyToWrite = {
|
||||
nodes: [
|
||||
{
|
||||
@@ -82,8 +107,32 @@ const SYNTHETIC: TopologyToWrite = {
|
||||
useMacAsName: true,
|
||||
interfaces: [{ ip: '10.0.0.1', mask: '255.0.0.0', mac: 'AA:BB:CC:DD:EE:01', gateway: null, dns: '10.0.0.53' }],
|
||||
portCount: 1,
|
||||
system: {
|
||||
ssid: 'Lab',
|
||||
manualRoutes: [['10.1.0.0', '255.255.0.0', '10.0.0.254', '10.0.0.1']],
|
||||
dhcpClient: true,
|
||||
dhcpServer: {
|
||||
isActive: true,
|
||||
lowerBound: '10.0.0.100',
|
||||
upperBound: '10.0.0.199',
|
||||
gateway: '10.0.0.254',
|
||||
dnsServer: '10.0.0.53',
|
||||
useOwnSettings: true,
|
||||
staticAssignedAddresses: [{ mac: 'AA:BB:CC:DD:EE:77', ip: '10.0.0.77' }],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
javaClass: 'Switch',
|
||||
name: 'S',
|
||||
x: 100,
|
||||
y: 20,
|
||||
useIpAsName: false,
|
||||
useMacAsName: false,
|
||||
interfaces: [],
|
||||
portCount: 3,
|
||||
system: { ssid: 'S-net', retentionTime: 1234 },
|
||||
},
|
||||
{ javaClass: 'Switch', name: 'S', x: 100, y: 20, useIpAsName: false, useMacAsName: false, interfaces: [], portCount: 3 },
|
||||
{
|
||||
javaClass: 'Vermittlungsrechner',
|
||||
name: 'R',
|
||||
@@ -99,8 +148,34 @@ const SYNTHETIC: TopologyToWrite = {
|
||||
dns: '',
|
||||
})),
|
||||
portCount: 3,
|
||||
system: {
|
||||
ripEnabled: true,
|
||||
firewall: {
|
||||
activated: true,
|
||||
defaultPolicy: 1,
|
||||
dropICMP: true,
|
||||
filterSYNSegmentsOnly: false,
|
||||
filterUdp: false,
|
||||
rules: [
|
||||
{ srcIP: '10.0.1.0', srcMask: '255.255.255.0', destIP: '', destMask: '', port: -1, protocol: -1, action: 1 },
|
||||
{ srcIP: '', srcMask: '', destIP: '10.0.2.5', destMask: '255.255.255.255', port: 80, protocol: 6, action: 0 },
|
||||
{ srcIP: null, srcMask: '', destIP: '', destMask: '', port: 53, protocol: 17, action: 1 },
|
||||
{ srcIP: '', srcMask: '', destIP: '', destMask: '', port: -1, protocol: 1, action: 0 },
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
javaClass: 'Modem',
|
||||
name: 'M',
|
||||
x: 300,
|
||||
y: 20,
|
||||
useIpAsName: false,
|
||||
useMacAsName: false,
|
||||
interfaces: [],
|
||||
portCount: 1,
|
||||
system: { modem: { mode: 1, port: 4242, ipAddress: '192.168.1.5' } },
|
||||
},
|
||||
{ javaClass: 'Modem', name: 'M', x: 300, y: 20, useIpAsName: false, useMacAsName: false, interfaces: [], portCount: 1 },
|
||||
],
|
||||
links: [
|
||||
{ ends: [{ node: 0, port: 0 }, { node: 1, port: 2 }], wireless: false, panel: [0, 1] },
|
||||
@@ -109,6 +184,17 @@ const SYNTHETIC: TopologyToWrite = {
|
||||
documentation: [{ type: 1, text: null, x: 5, y: 6, width: 70, height: 80, color: null, font: null }],
|
||||
};
|
||||
|
||||
/** The DHCP server as every IP stack's constructor leaves it. */
|
||||
const JAVA_DHCP_DEFAULTS = {
|
||||
aktiv: false,
|
||||
untergrenze: '0.0.0.0',
|
||||
obergrenze: '0.0.0.0',
|
||||
gatewayip: '0.0.0.0',
|
||||
dnsserverip: '0.0.0.0',
|
||||
ownSettings: false,
|
||||
staticAssignedAddresses: [],
|
||||
};
|
||||
|
||||
describe('a topology beyond the corpus, as Java loads it', () => {
|
||||
it('keeps what the corpus never sets', () => {
|
||||
const name = 'synthetic/synthetic.fls';
|
||||
@@ -132,8 +218,30 @@ describe('a topology beyond the corpus, as Java loads it', () => {
|
||||
useIpAsName: false,
|
||||
useMacAsName: true,
|
||||
ports: [{ ip: '10.0.0.1', mask: '255.0.0.0', mac: 'AA:BB:CC:DD:EE:01', gateway: null, dns: '10.0.0.53' }],
|
||||
system: {
|
||||
ssid: 'Lab',
|
||||
manualRoutes: [['10.1.0.0', '255.255.0.0', '10.0.0.254', '10.0.0.1']],
|
||||
dhcpClient: true,
|
||||
dhcpServer: {
|
||||
aktiv: true,
|
||||
untergrenze: '10.0.0.100',
|
||||
obergrenze: '10.0.0.199',
|
||||
gatewayip: '10.0.0.254',
|
||||
dnsserverip: '10.0.0.53',
|
||||
ownSettings: true,
|
||||
staticAssignedAddresses: ['AA:BB:CC:DD:EE:77 10.0.0.77'],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
class: 'Switch',
|
||||
name: 'S',
|
||||
position: [100, 20],
|
||||
useIpAsName: undefined,
|
||||
useMacAsName: undefined,
|
||||
ports: [{}, {}, {}],
|
||||
system: { ssid: 'S-net', retentionTime: 1234 },
|
||||
},
|
||||
{ class: 'Switch', name: 'S', position: [100, 20], useIpAsName: undefined, useMacAsName: undefined, ports: [{}, {}, {}] },
|
||||
{
|
||||
class: 'Vermittlungsrechner',
|
||||
name: 'R',
|
||||
@@ -141,8 +249,35 @@ describe('a topology beyond the corpus, as Java loads it', () => {
|
||||
useIpAsName: undefined,
|
||||
useMacAsName: undefined,
|
||||
ports: ['1', '2', '3'].map(plainInterface),
|
||||
system: {
|
||||
ripEnabled: true,
|
||||
manualRoutes: [],
|
||||
dhcpClient: false,
|
||||
dhcpServer: JAVA_DHCP_DEFAULTS,
|
||||
firewall: {
|
||||
activated: true,
|
||||
defaultPolicy: 1,
|
||||
dropICMP: true,
|
||||
filterSYNSegmentsOnly: false,
|
||||
filterUdp: false,
|
||||
rules: [
|
||||
['10.0.1.0', '255.255.255.0', '', '', -1, -1, 1],
|
||||
['', '', '10.0.2.5', '255.255.255.255', 80, 6, 0],
|
||||
[null, '', '', '', 53, 17, 1],
|
||||
['', '', '', '', -1, 1, 0],
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
class: 'Modem',
|
||||
name: 'M',
|
||||
position: [300, 20],
|
||||
useIpAsName: undefined,
|
||||
useMacAsName: undefined,
|
||||
ports: [{}],
|
||||
system: { modem: { mode: 1, port: 4242, ipAdresse: '192.168.1.5' } },
|
||||
},
|
||||
{ class: 'Modem', name: 'M', position: [300, 20], useIpAsName: undefined, useMacAsName: undefined, ports: [{}] },
|
||||
],
|
||||
cables: [
|
||||
{ ends: [[0, 0], [1, 2]], wireless: false, panel: [0, 1] },
|
||||
|
||||
Reference in New Issue
Block a user