import java.util.*; /** * CWE-407 unit tests for ansible-0002 and ansible-0003. * * ansible-0002: Host.add_group() uses `group not in self.groups` list scan O(G) * inside ancestor loop — O(A*G) per call, O(H*G*A) total. * * ansible-0003: Handler.is_host_notified() uses `host in self.notified_hosts` * list scan — O(H) per notify, O(H^2) total. * * Fix: set alongside list for O(1) membership. */ public class AnsibleTest { static long ops; // ===== ansible-0002: Host.add_group linear scan ===== /** Simulates adding G groups to a host, each with some ancestors */ static long hostAddGroupDefective(int G) { ops = 0; List hostGroups = new ArrayList<>(); // self.groups as list for (int g = 0; g < G; g++) { // Simulate: group not in self.groups (linear scan) boolean found = false; for (String existing : hostGroups) { ops++; if (existing.equals("group-" + g)) { found = true; break; } } if (!found) { hostGroups.add("group-" + g); } } return ops; } static long hostAddGroupFixed(int G) { ops = 0; List hostGroups = new ArrayList<>(); Set hostGroupsSet = new HashSet<>(); for (int g = 0; g < G; g++) { ops++; // HashSet.contains = O(1), count as 1 op if (!hostGroupsSet.contains("group-" + g)) { hostGroups.add("group-" + g); hostGroupsSet.add("group-" + g); } } return ops; } // ===== ansible-0003: Handler.notify_host linear scan ===== /** Simulates notifying H hosts on a handler */ static long handlerNotifyDefective(int H) { ops = 0; List notifiedHosts = new ArrayList<>(); // self.notified_hosts as list for (int h = 0; h < H; h++) { String host = "host-" + h; // is_host_notified: host in self.notified_hosts (linear scan) boolean found = false; for (String existing : notifiedHosts) { ops++; if (existing.equals(host)) { found = true; break; } } if (!found) { notifiedHosts.add(host); } } return ops; } static long handlerNotifyFixed(int H) { ops = 0; List notifiedHosts = new ArrayList<>(); Set notifiedSet = new HashSet<>(); for (int h = 0; h < H; h++) { String host = "host-" + h; ops++; // HashSet.contains = O(1) if (!notifiedSet.contains(host)) { notifiedHosts.add(host); notifiedSet.add(host); } } return ops; } public static void main(String[] args) { int[] sizes = {200, 500, 1000}; boolean allPass = true; // --- ansible-0002 --- System.out.println("ansible-0002: Host.add_group() list membership scan"); System.out.println("==================================================="); System.out.printf("%-8s %14s %14s %10s %s%n", "G", "Defect(ops)", "Fixed(ops)", "Ratio", "Status"); for (int G : sizes) { long dOps = hostAddGroupDefective(G); long fOps = hostAddGroupFixed(G); double ratio = (double) dOps / Math.max(fOps, 1); String status = (ratio >= 5.0) ? "PASS" : "FAIL"; if (!status.equals("PASS")) allPass = false; System.out.printf("%-8d %14d %14d %10.1fx %s%n", G, dOps, fOps, ratio, status); } System.out.println(); // --- ansible-0003 --- System.out.println("ansible-0003: Handler.notify_host() list membership scan"); System.out.println("======================================================="); System.out.printf("%-8s %14s %14s %10s %s%n", "H", "Defect(ops)", "Fixed(ops)", "Ratio", "Status"); for (int H : sizes) { long dOps = handlerNotifyDefective(H); long fOps = handlerNotifyFixed(H); double ratio = (double) dOps / Math.max(fOps, 1); String status = (ratio >= 5.0) ? "PASS" : "FAIL"; if (!status.equals("PASS")) allPass = false; System.out.printf("%-8d %14d %14d %10.1fx %s%n", H, dOps, fOps, ratio, status); } System.out.println(); System.out.println(allPass ? "ALL PASS" : "SOME FAIL"); System.exit(allPass ? 0 : 1); } }