From 1d282855ba8e0796b02437e0ead2c789cf8f08a4 Mon Sep 17 00:00:00 2001 From: Nikhil Verma Date: Wed, 4 Feb 2026 18:25:17 +0530 Subject: [PATCH 1/7] Add WASI build support and npm package This adds the ability to build regula as a WASI (WebAssembly System Interface) binary that can be run via Node.js 18+. New files: - build-wasi.sh: Build script that applies vendor patches and compiles to WASI - patches/: WASI-compatible vendor patches (applied only during WASI build) - package.json: npm package configuration (regula-wasi) - index.js: Programmatic API (runRegula, validate functions) - cli.js: CLI wrapper for the WASM binary - test/: Test suite including WASI/native parity tests Usage: - Build WASI: ./build-wasi.sh - Build native: go build -mod vendor (unchanged) - Run tests: npm test && npm run test:wasi The WASI build produces identical output to the native binary. Co-Authored-By: Claude Opus 4.5 --- .gitignore | 7 + .npmignore | 36 + build-wasi.sh | 29 + cli.js | 32 + index.js | 83 ++ package.json | 45 + patches/chzyer/readline/term.go | 1259 +++++++++++++++++ patches/chzyer/readline/term_unix.go | 25 + patches/chzyer/readline/term_wasip1.go | 38 + patches/chzyer/readline/utils_wasip1.go | 59 + patches/coreos/go-systemd/journal/journal.go | 226 +++ patches/fsnotify/fsnotify/backend_other.go | 69 + .../logrus/terminal_check_appengine.go | 12 + .../logrus/terminal_check_notappengine.go | 18 + patches/spf13/afero/const_wasip1.go | 25 + patches/spf13/afero/const_win_unix.go | 22 + test/fixtures/insecure.tf | 29 + test/fixtures/valid.tf | 33 + test/test-wasi.js | 201 +++ test/test.js | 94 ++ 20 files changed, 2342 insertions(+) create mode 100644 .npmignore create mode 100755 build-wasi.sh create mode 100755 cli.js create mode 100644 index.js create mode 100644 package.json create mode 100644 patches/chzyer/readline/term.go create mode 100644 patches/chzyer/readline/term_unix.go create mode 100644 patches/chzyer/readline/term_wasip1.go create mode 100644 patches/chzyer/readline/utils_wasip1.go create mode 100644 patches/coreos/go-systemd/journal/journal.go create mode 100644 patches/fsnotify/fsnotify/backend_other.go create mode 100644 patches/sirupsen/logrus/terminal_check_appengine.go create mode 100644 patches/sirupsen/logrus/terminal_check_notappengine.go create mode 100644 patches/spf13/afero/const_wasip1.go create mode 100644 patches/spf13/afero/const_win_unix.go create mode 100644 test/fixtures/insecure.tf create mode 100644 test/fixtures/valid.tf create mode 100644 test/test-wasi.js create mode 100644 test/test.js diff --git a/.gitignore b/.gitignore index f336d807..817e0ee7 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,10 @@ dist/ .vscode/ .scratch/ .regula-history + +# WASM build +regula.wasm + +# npm +node_modules/ +package-lock.json diff --git a/.npmignore b/.npmignore new file mode 100644 index 00000000..459f71bb --- /dev/null +++ b/.npmignore @@ -0,0 +1,36 @@ +# Source code +*.go +go.mod +go.sum +vendor/ +patches/ + +# Build files +Makefile +.goreleaser.yml +Dockerfile +build-wasi.sh + +# Development +.github/ +.git/ +.gitignore +.gitmodules +test/ +bin/ +dist/ +docs/ +changes/ + +# Rego source (embedded in binary) +rego/ + +# Other +*.md +!README.md +pkg/ +cmd/ +swagger.yaml +.regula.yaml +.regula-history +.scratch/ diff --git a/build-wasi.sh b/build-wasi.sh new file mode 100755 index 00000000..ad78db88 --- /dev/null +++ b/build-wasi.sh @@ -0,0 +1,29 @@ +#!/bin/bash +set -e + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +cd "$SCRIPT_DIR" + +echo "==> Applying WASI patches to vendor..." + +# Apply patches by copying files from patches/ to vendor/github.com/ +cp patches/spf13/afero/const_wasip1.go vendor/github.com/spf13/afero/ +cp patches/spf13/afero/const_win_unix.go vendor/github.com/spf13/afero/ + +cp patches/sirupsen/logrus/terminal_check_appengine.go vendor/github.com/sirupsen/logrus/ +cp patches/sirupsen/logrus/terminal_check_notappengine.go vendor/github.com/sirupsen/logrus/ + +cp patches/coreos/go-systemd/journal/journal.go vendor/github.com/coreos/go-systemd/journal/ + +cp patches/fsnotify/fsnotify/backend_other.go vendor/github.com/fsnotify/fsnotify/ + +cp patches/chzyer/readline/term.go vendor/github.com/chzyer/readline/ +cp patches/chzyer/readline/term_unix.go vendor/github.com/chzyer/readline/ +cp patches/chzyer/readline/term_wasip1.go vendor/github.com/chzyer/readline/ +cp patches/chzyer/readline/utils_wasip1.go vendor/github.com/chzyer/readline/ + +echo "==> Building WASI binary..." +GOOS=wasip1 GOARCH=wasm go build -mod vendor -o regula.wasm + +echo "==> Build complete: regula.wasm" +ls -lh regula.wasm diff --git a/cli.js b/cli.js new file mode 100755 index 00000000..bbc24f29 --- /dev/null +++ b/cli.js @@ -0,0 +1,32 @@ +#!/usr/bin/env node + +import { WASI } from "wasi"; +import { readFile } from "fs/promises"; +import { fileURLToPath } from "url"; +import { dirname, join } from "path"; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = dirname(__filename); + +const args = process.argv.slice(2); + +const wasi = new WASI({ + version: "preview1", + args: ["regula", ...args], + env: process.env, + preopens: { "/": "/" }, + returnOnExit: true, +}); + +try { + const wasmPath = join(__dirname, "regula.wasm"); + const wasm = await readFile(wasmPath); + const { instance } = await WebAssembly.instantiate(wasm, wasi.getImportObject()); + wasi.start(instance); +} catch (err) { + if (err.code === "ERR_WASI_EXITED") { + process.exit(err.exitCode); + } + console.error("Error:", err.message); + process.exit(1); +} diff --git a/index.js b/index.js new file mode 100644 index 00000000..9e399502 --- /dev/null +++ b/index.js @@ -0,0 +1,83 @@ +import { execFile } from "child_process"; +import { fileURLToPath } from "url"; +import { dirname, join } from "path"; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = dirname(__filename); + +/** + * Run regula on the specified path(s) + * @param {string|string[]} paths - Path(s) to IaC files or directories + * @param {Object} options - Optional configuration + * @param {string} options.inputType - Input type: auto, tf, tf-plan, cfn, k8s, arm + * @param {string} options.format - Output format: json, text, table, sarif, junit, tap + * @param {string[]} options.include - Additional rego files to include + * @param {string[]} options.only - Only run specific rules + * @param {string[]} options.exclude - Exclude specific rules + * @returns {Promise} - Regula output + */ +export async function runRegula(paths, options = {}) { + const pathArray = Array.isArray(paths) ? paths : [paths]; + + const args = ["run", "--format", "json"]; + + if (options.inputType) { + args.push("--input-type", options.inputType); + } + + if (options.include) { + const includes = Array.isArray(options.include) ? options.include : [options.include]; + for (const inc of includes) { + args.push("--include", inc); + } + } + + if (options.only) { + const onlyRules = Array.isArray(options.only) ? options.only : [options.only]; + for (const rule of onlyRules) { + args.push("--only", rule); + } + } + + if (options.exclude) { + const excludeRules = Array.isArray(options.exclude) ? options.exclude : [options.exclude]; + for (const rule of excludeRules) { + args.push("--exclude", rule); + } + } + + args.push(...pathArray); + + return new Promise((resolve, reject) => { + const cliPath = join(__dirname, "cli.js"); + + execFile("node", [cliPath, ...args], { maxBuffer: 50 * 1024 * 1024 }, (error, stdout, stderr) => { + if (stderr) { + console.error(stderr); + } + + try { + const result = JSON.parse(stdout); + resolve(result); + } catch (parseError) { + if (error) { + reject(new Error(`Regula failed: ${error.message}\nOutput: ${stdout}`)); + } else { + reject(new Error(`Failed to parse regula output: ${stdout}`)); + } + } + }); + }); +} + +/** + * Validate IaC files and return rule results + * @param {string|string[]} paths - Path(s) to IaC files or directories + * @param {Object} options - Optional configuration + * @returns {Promise} - Object with rule_results and summary + */ +export async function validate(paths, options = {}) { + return runRegula(paths, options); +} + +export default { runRegula, validate }; diff --git a/package.json b/package.json new file mode 100644 index 00000000..b4371e60 --- /dev/null +++ b/package.json @@ -0,0 +1,45 @@ +{ + "name": "regula-wasi", + "version": "3.2.2", + "description": "Infrastructure as Code security and compliance evaluation tool (WASI build)", + "type": "module", + "main": "index.js", + "bin": { + "regula": "cli.js" + }, + "scripts": { + "build": "./build-wasi.sh", + "test": "node test/test.js", + "test:wasi": "node test/test-wasi.js", + "prepublishOnly": "npm run build" + }, + "files": [ + "index.js", + "cli.js", + "regula.wasm", + "README.md" + ], + "keywords": [ + "regula", + "iac", + "infrastructure-as-code", + "terraform", + "cloudformation", + "kubernetes", + "security", + "compliance", + "opa", + "rego", + "wasi", + "wasm" + ], + "author": "Fugue, Inc.", + "license": "Apache-2.0", + "repository": { + "type": "git", + "url": "git+https://github.com/fugue/regula.git" + }, + "engines": { + "node": ">=18.0.0" + } +} diff --git a/patches/chzyer/readline/term.go b/patches/chzyer/readline/term.go new file mode 100644 index 00000000..5331f095 --- /dev/null +++ b/patches/chzyer/readline/term.go @@ -0,0 +1,1259 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build darwin || dragonfly || freebsd || (linux && !appengine) || netbsd || openbsd || solaris || wasip1 +// +build darwin dragonfly freebsd linux,!appengine netbsd openbsd solaris wasip1 + +// Package terminal provides support functions for dealing with terminals, as +// commonly found on UNIX systems. +// +// Putting a terminal into raw mode is the most common requirement: +// +// oldState, err := terminal.MakeRaw(0) +// if err != nil { +// panic(err) +// } +// defer terminal.Restore(0, oldState) +package readline + +import ( + "io" + "syscall" + // "syscall" +) + +const ( + AF_APPLETALK = 0x10 + AF_CCITT = 0xa + AF_CHAOS = 0x5 + AF_CNT = 0x15 + AF_COIP = 0x14 + AF_DATAKIT = 0x9 + AF_DECnet = 0xc + AF_DLI = 0xd + AF_E164 = 0x1c + AF_ECMA = 0x8 + AF_HYLINK = 0xf + AF_IEEE80211 = 0x25 + AF_IMPLINK = 0x3 + AF_INET = 0x2 + AF_INET6 = 0x1e + AF_IPX = 0x17 + AF_ISDN = 0x1c + AF_ISO = 0x7 + AF_LAT = 0xe + AF_LINK = 0x12 + AF_LOCAL = 0x1 + AF_MAX = 0x28 + AF_NATM = 0x1f + AF_NDRV = 0x1b + AF_NETBIOS = 0x21 + AF_NS = 0x6 + AF_OSI = 0x7 + AF_PPP = 0x22 + AF_PUP = 0x4 + AF_RESERVED_36 = 0x24 + AF_ROUTE = 0x11 + AF_SIP = 0x18 + AF_SNA = 0xb + AF_SYSTEM = 0x20 + AF_UNIX = 0x1 + AF_UNSPEC = 0x0 + AF_UTUN = 0x26 + B0 = 0x0 + B110 = 0x6e + B115200 = 0x1c200 + B1200 = 0x4b0 + B134 = 0x86 + B14400 = 0x3840 + B150 = 0x96 + B1800 = 0x708 + B19200 = 0x4b00 + B200 = 0xc8 + B230400 = 0x38400 + B2400 = 0x960 + B28800 = 0x7080 + B300 = 0x12c + B38400 = 0x9600 + B4800 = 0x12c0 + B50 = 0x32 + B57600 = 0xe100 + B600 = 0x258 + B7200 = 0x1c20 + B75 = 0x4b + B76800 = 0x12c00 + B9600 = 0x2580 + BIOCFLUSH = 0x20004268 + BIOCGBLEN = 0x40044266 + BIOCGDLT = 0x4004426a + BIOCGDLTLIST = 0xc00c4279 + BIOCGETIF = 0x4020426b + BIOCGHDRCMPLT = 0x40044274 + BIOCGRSIG = 0x40044272 + BIOCGRTIMEOUT = 0x4010426e + BIOCGSEESENT = 0x40044276 + BIOCGSTATS = 0x4008426f + BIOCIMMEDIATE = 0x80044270 + BIOCPROMISC = 0x20004269 + BIOCSBLEN = 0xc0044266 + BIOCSDLT = 0x80044278 + BIOCSETF = 0x80104267 + BIOCSETIF = 0x8020426c + BIOCSHDRCMPLT = 0x80044275 + BIOCSRSIG = 0x80044273 + BIOCSRTIMEOUT = 0x8010426d + BIOCSSEESENT = 0x80044277 + BIOCVERSION = 0x40044271 + BPF_A = 0x10 + BPF_ABS = 0x20 + BPF_ADD = 0x0 + BPF_ALIGNMENT = 0x4 + BPF_ALU = 0x4 + BPF_AND = 0x50 + BPF_B = 0x10 + BPF_DIV = 0x30 + BPF_H = 0x8 + BPF_IMM = 0x0 + BPF_IND = 0x40 + BPF_JA = 0x0 + BPF_JEQ = 0x10 + BPF_JGE = 0x30 + BPF_JGT = 0x20 + BPF_JMP = 0x5 + BPF_JSET = 0x40 + BPF_K = 0x0 + BPF_LD = 0x0 + BPF_LDX = 0x1 + BPF_LEN = 0x80 + BPF_LSH = 0x60 + BPF_MAJOR_VERSION = 0x1 + BPF_MAXBUFSIZE = 0x80000 + BPF_MAXINSNS = 0x200 + BPF_MEM = 0x60 + BPF_MEMWORDS = 0x10 + BPF_MINBUFSIZE = 0x20 + BPF_MINOR_VERSION = 0x1 + BPF_MISC = 0x7 + BPF_MSH = 0xa0 + BPF_MUL = 0x20 + BPF_NEG = 0x80 + BPF_OR = 0x40 + BPF_RELEASE = 0x30bb6 + BPF_RET = 0x6 + BPF_RSH = 0x70 + BPF_ST = 0x2 + BPF_STX = 0x3 + BPF_SUB = 0x10 + BPF_TAX = 0x0 + BPF_TXA = 0x80 + BPF_W = 0x0 + BPF_X = 0x8 + BRKINT = 0x2 + CFLUSH = 0xf + CLOCAL = 0x8000 + CREAD = 0x800 + CS5 = 0x0 + CS6 = 0x100 + CS7 = 0x200 + CS8 = 0x300 + CSIZE = 0x300 + CSTART = 0x11 + CSTATUS = 0x14 + CSTOP = 0x13 + CSTOPB = 0x400 + CSUSP = 0x1a + CTL_MAXNAME = 0xc + CTL_NET = 0x4 + DLT_APPLE_IP_OVER_IEEE1394 = 0x8a + DLT_ARCNET = 0x7 + DLT_ATM_CLIP = 0x13 + DLT_ATM_RFC1483 = 0xb + DLT_AX25 = 0x3 + DLT_CHAOS = 0x5 + DLT_CHDLC = 0x68 + DLT_C_HDLC = 0x68 + DLT_EN10MB = 0x1 + DLT_EN3MB = 0x2 + DLT_FDDI = 0xa + DLT_IEEE802 = 0x6 + DLT_IEEE802_11 = 0x69 + DLT_IEEE802_11_RADIO = 0x7f + DLT_IEEE802_11_RADIO_AVS = 0xa3 + DLT_LINUX_SLL = 0x71 + DLT_LOOP = 0x6c + DLT_NULL = 0x0 + DLT_PFLOG = 0x75 + DLT_PFSYNC = 0x12 + DLT_PPP = 0x9 + DLT_PPP_BSDOS = 0x10 + DLT_PPP_SERIAL = 0x32 + DLT_PRONET = 0x4 + DLT_RAW = 0xc + DLT_SLIP = 0x8 + DLT_SLIP_BSDOS = 0xf + DT_BLK = 0x6 + DT_CHR = 0x2 + DT_DIR = 0x4 + DT_FIFO = 0x1 + DT_LNK = 0xa + DT_REG = 0x8 + DT_SOCK = 0xc + DT_UNKNOWN = 0x0 + DT_WHT = 0xe + ECHO = 0x8 + ECHOCTL = 0x40 + ECHOE = 0x2 + ECHOK = 0x4 + ECHOKE = 0x1 + ECHONL = 0x10 + ECHOPRT = 0x20 + EVFILT_AIO = -0x3 + EVFILT_FS = -0x9 + EVFILT_MACHPORT = -0x8 + EVFILT_PROC = -0x5 + EVFILT_READ = -0x1 + EVFILT_SIGNAL = -0x6 + EVFILT_SYSCOUNT = 0xe + EVFILT_THREADMARKER = 0xe + EVFILT_TIMER = -0x7 + EVFILT_USER = -0xa + EVFILT_VM = -0xc + EVFILT_VNODE = -0x4 + EVFILT_WRITE = -0x2 + EV_ADD = 0x1 + EV_CLEAR = 0x20 + EV_DELETE = 0x2 + EV_DISABLE = 0x8 + EV_DISPATCH = 0x80 + EV_ENABLE = 0x4 + EV_EOF = 0x8000 + EV_ERROR = 0x4000 + EV_FLAG0 = 0x1000 + EV_FLAG1 = 0x2000 + EV_ONESHOT = 0x10 + EV_OOBAND = 0x2000 + EV_POLL = 0x1000 + EV_RECEIPT = 0x40 + EV_SYSFLAGS = 0xf000 + EXTA = 0x4b00 + EXTB = 0x9600 + EXTPROC = 0x800 + FD_CLOEXEC = 0x1 + FD_SETSIZE = 0x400 + FLUSHO = 0x800000 + F_ADDFILESIGS = 0x3d + F_ADDSIGS = 0x3b + F_ALLOCATEALL = 0x4 + F_ALLOCATECONTIG = 0x2 + F_CHKCLEAN = 0x29 + F_DUPFD = 0x0 + F_DUPFD_CLOEXEC = 0x43 + F_FINDSIGS = 0x4e + F_FLUSH_DATA = 0x28 + F_FREEZE_FS = 0x35 + F_FULLFSYNC = 0x33 + F_GETCODEDIR = 0x48 + F_GETFD = 0x1 + F_GETFL = 0x3 + F_GETLK = 0x7 + F_GETLKPID = 0x42 + F_GETNOSIGPIPE = 0x4a + F_GETOWN = 0x5 + F_GETPATH = 0x32 + F_GETPATH_MTMINFO = 0x47 + F_GETPROTECTIONCLASS = 0x3f + F_GETPROTECTIONLEVEL = 0x4d + F_GLOBAL_NOCACHE = 0x37 + F_LOG2PHYS = 0x31 + F_LOG2PHYS_EXT = 0x41 + F_NOCACHE = 0x30 + F_NODIRECT = 0x3e + F_OK = 0x0 + F_PATHPKG_CHECK = 0x34 + F_PEOFPOSMODE = 0x3 + F_PREALLOCATE = 0x2a + F_RDADVISE = 0x2c + F_RDAHEAD = 0x2d + F_RDLCK = 0x1 + F_SETBACKINGSTORE = 0x46 + F_SETFD = 0x2 + F_SETFL = 0x4 + F_SETLK = 0x8 + F_SETLKW = 0x9 + F_SETLKWTIMEOUT = 0xa + F_SETNOSIGPIPE = 0x49 + F_SETOWN = 0x6 + F_SETPROTECTIONCLASS = 0x40 + F_SETSIZE = 0x2b + F_SINGLE_WRITER = 0x4c + F_THAW_FS = 0x36 + F_TRANSCODEKEY = 0x4b + F_UNLCK = 0x2 + F_VOLPOSMODE = 0x4 + F_WRLCK = 0x3 + HUPCL = 0x4000 + ICANON = 0x100 + ICMP6_FILTER = 0x12 + ICRNL = 0x100 + IEXTEN = 0x400 + IFF_ALLMULTI = 0x200 + IFF_ALTPHYS = 0x4000 + IFF_BROADCAST = 0x2 + IFF_DEBUG = 0x4 + IFF_LINK0 = 0x1000 + IFF_LINK1 = 0x2000 + IFF_LINK2 = 0x4000 + IFF_LOOPBACK = 0x8 + IFF_MULTICAST = 0x8000 + IFF_NOARP = 0x80 + IFF_NOTRAILERS = 0x20 + IFF_OACTIVE = 0x400 + IFF_POINTOPOINT = 0x10 + IFF_PROMISC = 0x100 + IFF_RUNNING = 0x40 + IFF_SIMPLEX = 0x800 + IFF_UP = 0x1 + IFNAMSIZ = 0x10 + IFT_1822 = 0x2 + IFT_AAL5 = 0x31 + IFT_ARCNET = 0x23 + IFT_ARCNETPLUS = 0x24 + IFT_ATM = 0x25 + IFT_BRIDGE = 0xd1 + IFT_CARP = 0xf8 + IFT_CELLULAR = 0xff + IFT_CEPT = 0x13 + IFT_DS3 = 0x1e + IFT_ENC = 0xf4 + IFT_EON = 0x19 + IFT_ETHER = 0x6 + IFT_FAITH = 0x38 + IFT_FDDI = 0xf + IFT_FRELAY = 0x20 + IFT_FRELAYDCE = 0x2c + IFT_GIF = 0x37 + IFT_HDH1822 = 0x3 + IFT_HIPPI = 0x2f + IFT_HSSI = 0x2e + IFT_HY = 0xe + IFT_IEEE1394 = 0x90 + IFT_IEEE8023ADLAG = 0x88 + IFT_ISDNBASIC = 0x14 + IFT_ISDNPRIMARY = 0x15 + IFT_ISO88022LLC = 0x29 + IFT_ISO88023 = 0x7 + IFT_ISO88024 = 0x8 + IFT_ISO88025 = 0x9 + IFT_ISO88026 = 0xa + IFT_L2VLAN = 0x87 + IFT_LAPB = 0x10 + IFT_LOCALTALK = 0x2a + IFT_LOOP = 0x18 + IFT_MIOX25 = 0x26 + IFT_MODEM = 0x30 + IFT_NSIP = 0x1b + IFT_OTHER = 0x1 + IFT_P10 = 0xc + IFT_P80 = 0xd + IFT_PARA = 0x22 + IFT_PDP = 0xff + IFT_PFLOG = 0xf5 + IFT_PFSYNC = 0xf6 + IFT_PPP = 0x17 + IFT_PROPMUX = 0x36 + IFT_PROPVIRTUAL = 0x35 + IFT_PTPSERIAL = 0x16 + IFT_RS232 = 0x21 + IFT_SDLC = 0x11 + IFT_SIP = 0x1f + IFT_SLIP = 0x1c + IFT_SMDSDXI = 0x2b + IFT_SMDSICIP = 0x34 + IFT_SONET = 0x27 + IFT_SONETPATH = 0x32 + IFT_SONETVT = 0x33 + IFT_STARLAN = 0xb + IFT_STF = 0x39 + IFT_T1 = 0x12 + IFT_ULTRA = 0x1d + IFT_V35 = 0x2d + IFT_X25 = 0x5 + IFT_X25DDN = 0x4 + IFT_X25PLE = 0x28 + IFT_XETHER = 0x1a + IGNBRK = 0x1 + IGNCR = 0x80 + IGNPAR = 0x4 + IMAXBEL = 0x2000 + INLCR = 0x40 + INPCK = 0x10 + IN_CLASSA_HOST = 0xffffff + IN_CLASSA_MAX = 0x80 + IN_CLASSA_NET = 0xff000000 + IN_CLASSA_NSHIFT = 0x18 + IN_CLASSB_HOST = 0xffff + IN_CLASSB_MAX = 0x10000 + IN_CLASSB_NET = 0xffff0000 + IN_CLASSB_NSHIFT = 0x10 + IN_CLASSC_HOST = 0xff + IN_CLASSC_NET = 0xffffff00 + IN_CLASSC_NSHIFT = 0x8 + IN_CLASSD_HOST = 0xfffffff + IN_CLASSD_NET = 0xf0000000 + IN_CLASSD_NSHIFT = 0x1c + IN_LINKLOCALNETNUM = 0xa9fe0000 + IN_LOOPBACKNET = 0x7f + IPPROTO_3PC = 0x22 + IPPROTO_ADFS = 0x44 + IPPROTO_AH = 0x33 + IPPROTO_AHIP = 0x3d + IPPROTO_APES = 0x63 + IPPROTO_ARGUS = 0xd + IPPROTO_AX25 = 0x5d + IPPROTO_BHA = 0x31 + IPPROTO_BLT = 0x1e + IPPROTO_BRSATMON = 0x4c + IPPROTO_CFTP = 0x3e + IPPROTO_CHAOS = 0x10 + IPPROTO_CMTP = 0x26 + IPPROTO_CPHB = 0x49 + IPPROTO_CPNX = 0x48 + IPPROTO_DDP = 0x25 + IPPROTO_DGP = 0x56 + IPPROTO_DIVERT = 0xfe + IPPROTO_DONE = 0x101 + IPPROTO_DSTOPTS = 0x3c + IPPROTO_EGP = 0x8 + IPPROTO_EMCON = 0xe + IPPROTO_ENCAP = 0x62 + IPPROTO_EON = 0x50 + IPPROTO_ESP = 0x32 + IPPROTO_ETHERIP = 0x61 + IPPROTO_FRAGMENT = 0x2c + IPPROTO_GGP = 0x3 + IPPROTO_GMTP = 0x64 + IPPROTO_GRE = 0x2f + IPPROTO_HELLO = 0x3f + IPPROTO_HMP = 0x14 + IPPROTO_HOPOPTS = 0x0 + IPPROTO_ICMP = 0x1 + IPPROTO_ICMPV6 = 0x3a + IPPROTO_IDP = 0x16 + IPPROTO_IDPR = 0x23 + IPPROTO_IDRP = 0x2d + IPPROTO_IGMP = 0x2 + IPPROTO_IGP = 0x55 + IPPROTO_IGRP = 0x58 + IPPROTO_IL = 0x28 + IPPROTO_INLSP = 0x34 + IPPROTO_INP = 0x20 + IPPROTO_IP = 0x0 + IPPROTO_IPCOMP = 0x6c + IPPROTO_IPCV = 0x47 + IPPROTO_IPEIP = 0x5e + IPPROTO_IPIP = 0x4 + IPPROTO_IPPC = 0x43 + IPPROTO_IPV4 = 0x4 + IPPROTO_IPV6 = 0x29 + IPPROTO_IRTP = 0x1c + IPPROTO_KRYPTOLAN = 0x41 + IPPROTO_LARP = 0x5b + IPPROTO_LEAF1 = 0x19 + IPPROTO_LEAF2 = 0x1a + IPPROTO_MAX = 0x100 + IPPROTO_MAXID = 0x34 + IPPROTO_MEAS = 0x13 + IPPROTO_MHRP = 0x30 + IPPROTO_MICP = 0x5f + IPPROTO_MTP = 0x5c + IPPROTO_MUX = 0x12 + IPPROTO_ND = 0x4d + IPPROTO_NHRP = 0x36 + IPPROTO_NONE = 0x3b + IPPROTO_NSP = 0x1f + IPPROTO_NVPII = 0xb + IPPROTO_OSPFIGP = 0x59 + IPPROTO_PGM = 0x71 + IPPROTO_PIGP = 0x9 + IPPROTO_PIM = 0x67 + IPPROTO_PRM = 0x15 + IPPROTO_PUP = 0xc + IPPROTO_PVP = 0x4b + IPPROTO_RAW = 0xff + IPPROTO_RCCMON = 0xa + IPPROTO_RDP = 0x1b + IPPROTO_ROUTING = 0x2b + IPPROTO_RSVP = 0x2e + IPPROTO_RVD = 0x42 + IPPROTO_SATEXPAK = 0x40 + IPPROTO_SATMON = 0x45 + IPPROTO_SCCSP = 0x60 + IPPROTO_SCTP = 0x84 + IPPROTO_SDRP = 0x2a + IPPROTO_SEP = 0x21 + IPPROTO_SRPC = 0x5a + IPPROTO_ST = 0x7 + IPPROTO_SVMTP = 0x52 + IPPROTO_SWIPE = 0x35 + IPPROTO_TCF = 0x57 + IPPROTO_TCP = 0x6 + IPPROTO_TP = 0x1d + IPPROTO_TPXX = 0x27 + IPPROTO_TRUNK1 = 0x17 + IPPROTO_TRUNK2 = 0x18 + IPPROTO_TTP = 0x54 + IPPROTO_UDP = 0x11 + IPPROTO_VINES = 0x53 + IPPROTO_VISA = 0x46 + IPPROTO_VMTP = 0x51 + IPPROTO_WBEXPAK = 0x4f + IPPROTO_WBMON = 0x4e + IPPROTO_WSN = 0x4a + IPPROTO_XNET = 0xf + IPPROTO_XTP = 0x24 + IPV6_2292DSTOPTS = 0x17 + IPV6_2292HOPLIMIT = 0x14 + IPV6_2292HOPOPTS = 0x16 + IPV6_2292NEXTHOP = 0x15 + IPV6_2292PKTINFO = 0x13 + IPV6_2292PKTOPTIONS = 0x19 + IPV6_2292RTHDR = 0x18 + IPV6_BINDV6ONLY = 0x1b + IPV6_BOUND_IF = 0x7d + IPV6_CHECKSUM = 0x1a + IPV6_DEFAULT_MULTICAST_HOPS = 0x1 + IPV6_DEFAULT_MULTICAST_LOOP = 0x1 + IPV6_DEFHLIM = 0x40 + IPV6_FAITH = 0x1d + IPV6_FLOWINFO_MASK = 0xffffff0f + IPV6_FLOWLABEL_MASK = 0xffff0f00 + IPV6_FRAGTTL = 0x78 + IPV6_FW_ADD = 0x1e + IPV6_FW_DEL = 0x1f + IPV6_FW_FLUSH = 0x20 + IPV6_FW_GET = 0x22 + IPV6_FW_ZERO = 0x21 + IPV6_HLIMDEC = 0x1 + IPV6_IPSEC_POLICY = 0x1c + IPV6_JOIN_GROUP = 0xc + IPV6_LEAVE_GROUP = 0xd + IPV6_MAXHLIM = 0xff + IPV6_MAXOPTHDR = 0x800 + IPV6_MAXPACKET = 0xffff + IPV6_MAX_GROUP_SRC_FILTER = 0x200 + IPV6_MAX_MEMBERSHIPS = 0xfff + IPV6_MAX_SOCK_SRC_FILTER = 0x80 + IPV6_MIN_MEMBERSHIPS = 0x1f + IPV6_MMTU = 0x500 + IPV6_MULTICAST_HOPS = 0xa + IPV6_MULTICAST_IF = 0x9 + IPV6_MULTICAST_LOOP = 0xb + IPV6_PORTRANGE = 0xe + IPV6_PORTRANGE_DEFAULT = 0x0 + IPV6_PORTRANGE_HIGH = 0x1 + IPV6_PORTRANGE_LOW = 0x2 + IPV6_RECVTCLASS = 0x23 + IPV6_RTHDR_LOOSE = 0x0 + IPV6_RTHDR_STRICT = 0x1 + IPV6_RTHDR_TYPE_0 = 0x0 + IPV6_SOCKOPT_RESERVED1 = 0x3 + IPV6_TCLASS = 0x24 + IPV6_UNICAST_HOPS = 0x4 + IPV6_V6ONLY = 0x1b + IPV6_VERSION = 0x60 + IPV6_VERSION_MASK = 0xf0 + IP_ADD_MEMBERSHIP = 0xc + IP_ADD_SOURCE_MEMBERSHIP = 0x46 + IP_BLOCK_SOURCE = 0x48 + IP_BOUND_IF = 0x19 + IP_DEFAULT_MULTICAST_LOOP = 0x1 + IP_DEFAULT_MULTICAST_TTL = 0x1 + IP_DF = 0x4000 + IP_DROP_MEMBERSHIP = 0xd + IP_DROP_SOURCE_MEMBERSHIP = 0x47 + IP_DUMMYNET_CONFIGURE = 0x3c + IP_DUMMYNET_DEL = 0x3d + IP_DUMMYNET_FLUSH = 0x3e + IP_DUMMYNET_GET = 0x40 + IP_FAITH = 0x16 + IP_FW_ADD = 0x28 + IP_FW_DEL = 0x29 + IP_FW_FLUSH = 0x2a + IP_FW_GET = 0x2c + IP_FW_RESETLOG = 0x2d + IP_FW_ZERO = 0x2b + IP_HDRINCL = 0x2 + IP_IPSEC_POLICY = 0x15 + IP_MAXPACKET = 0xffff + IP_MAX_GROUP_SRC_FILTER = 0x200 + IP_MAX_MEMBERSHIPS = 0xfff + IP_MAX_SOCK_MUTE_FILTER = 0x80 + IP_MAX_SOCK_SRC_FILTER = 0x80 + IP_MF = 0x2000 + IP_MIN_MEMBERSHIPS = 0x1f + IP_MSFILTER = 0x4a + IP_MSS = 0x240 + IP_MULTICAST_IF = 0x9 + IP_MULTICAST_IFINDEX = 0x42 + IP_MULTICAST_LOOP = 0xb + IP_MULTICAST_TTL = 0xa + IP_MULTICAST_VIF = 0xe + IP_NAT__XXX = 0x37 + IP_OFFMASK = 0x1fff + IP_OLD_FW_ADD = 0x32 + IP_OLD_FW_DEL = 0x33 + IP_OLD_FW_FLUSH = 0x34 + IP_OLD_FW_GET = 0x36 + IP_OLD_FW_RESETLOG = 0x38 + IP_OLD_FW_ZERO = 0x35 + IP_OPTIONS = 0x1 + IP_PKTINFO = 0x1a + IP_PORTRANGE = 0x13 + IP_PORTRANGE_DEFAULT = 0x0 + IP_PORTRANGE_HIGH = 0x1 + IP_PORTRANGE_LOW = 0x2 + IP_RECVDSTADDR = 0x7 + IP_RECVIF = 0x14 + IP_RECVOPTS = 0x5 + IP_RECVPKTINFO = 0x1a + IP_RECVRETOPTS = 0x6 + IP_RECVTTL = 0x18 + IP_RETOPTS = 0x8 + IP_RF = 0x8000 + IP_RSVP_OFF = 0x10 + IP_RSVP_ON = 0xf + IP_RSVP_VIF_OFF = 0x12 + IP_RSVP_VIF_ON = 0x11 + IP_STRIPHDR = 0x17 + IP_TOS = 0x3 + IP_TRAFFIC_MGT_BACKGROUND = 0x41 + IP_TTL = 0x4 + IP_UNBLOCK_SOURCE = 0x49 + ISIG = 0x80 + ISTRIP = 0x20 + IUTF8 = 0x4000 + IXANY = 0x800 + IXOFF = 0x400 + IXON = 0x200 + LOCK_EX = 0x2 + LOCK_NB = 0x4 + LOCK_SH = 0x1 + LOCK_UN = 0x8 + MADV_CAN_REUSE = 0x9 + MADV_DONTNEED = 0x4 + MADV_FREE = 0x5 + MADV_FREE_REUSABLE = 0x7 + MADV_FREE_REUSE = 0x8 + MADV_NORMAL = 0x0 + MADV_RANDOM = 0x1 + MADV_SEQUENTIAL = 0x2 + MADV_WILLNEED = 0x3 + MADV_ZERO_WIRED_PAGES = 0x6 + MAP_ANON = 0x1000 + MAP_COPY = 0x2 + MAP_FILE = 0x0 + MAP_FIXED = 0x10 + MAP_HASSEMAPHORE = 0x200 + MAP_JIT = 0x800 + MAP_NOCACHE = 0x400 + MAP_NOEXTEND = 0x100 + MAP_NORESERVE = 0x40 + MAP_PRIVATE = 0x2 + MAP_RENAME = 0x20 + MAP_RESERVED0080 = 0x80 + MAP_SHARED = 0x1 + MCL_CURRENT = 0x1 + MCL_FUTURE = 0x2 + MSG_CTRUNC = 0x20 + MSG_DONTROUTE = 0x4 + MSG_DONTWAIT = 0x80 + MSG_EOF = 0x100 + MSG_EOR = 0x8 + MSG_FLUSH = 0x400 + MSG_HAVEMORE = 0x2000 + MSG_HOLD = 0x800 + MSG_NEEDSA = 0x10000 + MSG_OOB = 0x1 + MSG_PEEK = 0x2 + MSG_RCVMORE = 0x4000 + MSG_SEND = 0x1000 + MSG_TRUNC = 0x10 + MSG_WAITALL = 0x40 + MSG_WAITSTREAM = 0x200 + MS_ASYNC = 0x1 + MS_DEACTIVATE = 0x8 + MS_INVALIDATE = 0x2 + MS_KILLPAGES = 0x4 + MS_SYNC = 0x10 + NAME_MAX = 0xff + NET_RT_DUMP = 0x1 + NET_RT_DUMP2 = 0x7 + NET_RT_FLAGS = 0x2 + NET_RT_IFLIST = 0x3 + NET_RT_IFLIST2 = 0x6 + NET_RT_MAXID = 0xa + NET_RT_STAT = 0x4 + NET_RT_TRASH = 0x5 + NOFLSH = 0x80000000 + NOTE_ABSOLUTE = 0x8 + NOTE_ATTRIB = 0x8 + NOTE_BACKGROUND = 0x40 + NOTE_CHILD = 0x4 + NOTE_CRITICAL = 0x20 + NOTE_DELETE = 0x1 + NOTE_EXEC = 0x20000000 + NOTE_EXIT = 0x80000000 + NOTE_EXITSTATUS = 0x4000000 + NOTE_EXIT_CSERROR = 0x40000 + NOTE_EXIT_DECRYPTFAIL = 0x10000 + NOTE_EXIT_DETAIL = 0x2000000 + NOTE_EXIT_DETAIL_MASK = 0x70000 + NOTE_EXIT_MEMORY = 0x20000 + NOTE_EXIT_REPARENTED = 0x80000 + NOTE_EXTEND = 0x4 + NOTE_FFAND = 0x40000000 + NOTE_FFCOPY = 0xc0000000 + NOTE_FFCTRLMASK = 0xc0000000 + NOTE_FFLAGSMASK = 0xffffff + NOTE_FFNOP = 0x0 + NOTE_FFOR = 0x80000000 + NOTE_FORK = 0x40000000 + NOTE_LEEWAY = 0x10 + NOTE_LINK = 0x10 + NOTE_LOWAT = 0x1 + NOTE_NONE = 0x80 + NOTE_NSECONDS = 0x4 + NOTE_PCTRLMASK = -0x100000 + NOTE_PDATAMASK = 0xfffff + NOTE_REAP = 0x10000000 + NOTE_RENAME = 0x20 + NOTE_REVOKE = 0x40 + NOTE_SECONDS = 0x1 + NOTE_SIGNAL = 0x8000000 + NOTE_TRACK = 0x1 + NOTE_TRACKERR = 0x2 + NOTE_TRIGGER = 0x1000000 + NOTE_USECONDS = 0x2 + NOTE_VM_ERROR = 0x10000000 + NOTE_VM_PRESSURE = 0x80000000 + NOTE_VM_PRESSURE_SUDDEN_TERMINATE = 0x20000000 + NOTE_VM_PRESSURE_TERMINATE = 0x40000000 + NOTE_WRITE = 0x2 + OCRNL = 0x10 + OFDEL = 0x20000 + OFILL = 0x80 + ONLCR = 0x2 + ONLRET = 0x40 + ONOCR = 0x20 + ONOEOT = 0x8 + OPOST = 0x1 + O_ACCMODE = 0x3 + O_ALERT = 0x20000000 + O_APPEND = 0x8 + O_ASYNC = 0x40 + O_CLOEXEC = 0x1000000 + O_CREAT = 0x200 + O_DIRECTORY = 0x100000 + O_DP_GETRAWENCRYPTED = 0x1 + O_DSYNC = 0x400000 + O_EVTONLY = 0x8000 + O_EXCL = 0x800 + O_EXLOCK = 0x20 + O_FSYNC = 0x80 + O_NDELAY = 0x4 + O_NOCTTY = 0x20000 + O_NOFOLLOW = 0x100 + O_NONBLOCK = 0x4 + O_POPUP = 0x80000000 + O_RDONLY = 0x0 + O_RDWR = 0x2 + O_SHLOCK = 0x10 + O_SYMLINK = 0x200000 + O_SYNC = 0x80 + O_TRUNC = 0x400 + O_WRONLY = 0x1 + PARENB = 0x1000 + PARMRK = 0x8 + PARODD = 0x2000 + PENDIN = 0x20000000 + PRIO_PGRP = 0x1 + PRIO_PROCESS = 0x0 + PRIO_USER = 0x2 + PROT_EXEC = 0x4 + PROT_NONE = 0x0 + PROT_READ = 0x1 + PROT_WRITE = 0x2 + PT_ATTACH = 0xa + PT_ATTACHEXC = 0xe + PT_CONTINUE = 0x7 + PT_DENY_ATTACH = 0x1f + PT_DETACH = 0xb + PT_FIRSTMACH = 0x20 + PT_FORCEQUOTA = 0x1e + PT_KILL = 0x8 + PT_READ_D = 0x2 + PT_READ_I = 0x1 + PT_READ_U = 0x3 + PT_SIGEXC = 0xc + PT_STEP = 0x9 + PT_THUPDATE = 0xd + PT_TRACE_ME = 0x0 + PT_WRITE_D = 0x5 + PT_WRITE_I = 0x4 + PT_WRITE_U = 0x6 + RLIMIT_AS = 0x5 + RLIMIT_CORE = 0x4 + RLIMIT_CPU = 0x0 + RLIMIT_CPU_USAGE_MONITOR = 0x2 + RLIMIT_DATA = 0x2 + RLIMIT_FSIZE = 0x1 + RLIMIT_NOFILE = 0x8 + RLIMIT_STACK = 0x3 + RLIM_INFINITY = 0x7fffffffffffffff + RTAX_AUTHOR = 0x6 + RTAX_BRD = 0x7 + RTAX_DST = 0x0 + RTAX_GATEWAY = 0x1 + RTAX_GENMASK = 0x3 + RTAX_IFA = 0x5 + RTAX_IFP = 0x4 + RTAX_MAX = 0x8 + RTAX_NETMASK = 0x2 + RTA_AUTHOR = 0x40 + RTA_BRD = 0x80 + RTA_DST = 0x1 + RTA_GATEWAY = 0x2 + RTA_GENMASK = 0x8 + RTA_IFA = 0x20 + RTA_IFP = 0x10 + RTA_NETMASK = 0x4 + RTF_BLACKHOLE = 0x1000 + RTF_BROADCAST = 0x400000 + RTF_CLONING = 0x100 + RTF_CONDEMNED = 0x2000000 + RTF_DELCLONE = 0x80 + RTF_DONE = 0x40 + RTF_DYNAMIC = 0x10 + RTF_GATEWAY = 0x2 + RTF_HOST = 0x4 + RTF_IFREF = 0x4000000 + RTF_IFSCOPE = 0x1000000 + RTF_LLINFO = 0x400 + RTF_LOCAL = 0x200000 + RTF_MODIFIED = 0x20 + RTF_MULTICAST = 0x800000 + RTF_PINNED = 0x100000 + RTF_PRCLONING = 0x10000 + RTF_PROTO1 = 0x8000 + RTF_PROTO2 = 0x4000 + RTF_PROTO3 = 0x40000 + RTF_PROXY = 0x8000000 + RTF_REJECT = 0x8 + RTF_ROUTER = 0x10000000 + RTF_STATIC = 0x800 + RTF_UP = 0x1 + RTF_WASCLONED = 0x20000 + RTF_XRESOLVE = 0x200 + RTM_ADD = 0x1 + RTM_CHANGE = 0x3 + RTM_DELADDR = 0xd + RTM_DELETE = 0x2 + RTM_DELMADDR = 0x10 + RTM_GET = 0x4 + RTM_GET2 = 0x14 + RTM_IFINFO = 0xe + RTM_IFINFO2 = 0x12 + RTM_LOCK = 0x8 + RTM_LOSING = 0x5 + RTM_MISS = 0x7 + RTM_NEWADDR = 0xc + RTM_NEWMADDR = 0xf + RTM_NEWMADDR2 = 0x13 + RTM_OLDADD = 0x9 + RTM_OLDDEL = 0xa + RTM_REDIRECT = 0x6 + RTM_RESOLVE = 0xb + RTM_RTTUNIT = 0xf4240 + RTM_VERSION = 0x5 + RTV_EXPIRE = 0x4 + RTV_HOPCOUNT = 0x2 + RTV_MTU = 0x1 + RTV_RPIPE = 0x8 + RTV_RTT = 0x40 + RTV_RTTVAR = 0x80 + RTV_SPIPE = 0x10 + RTV_SSTHRESH = 0x20 + RUSAGE_CHILDREN = -0x1 + RUSAGE_SELF = 0x0 + SCM_CREDS = 0x3 + SCM_RIGHTS = 0x1 + SCM_TIMESTAMP = 0x2 + SCM_TIMESTAMP_MONOTONIC = 0x4 + SHUT_RD = 0x0 + SHUT_RDWR = 0x2 + SHUT_WR = 0x1 + SIOCADDMULTI = 0x80206931 + SIOCAIFADDR = 0x8040691a + SIOCARPIPLL = 0xc0206928 + SIOCATMARK = 0x40047307 + SIOCAUTOADDR = 0xc0206926 + SIOCAUTONETMASK = 0x80206927 + SIOCDELMULTI = 0x80206932 + SIOCDIFADDR = 0x80206919 + SIOCDIFPHYADDR = 0x80206941 + SIOCGDRVSPEC = 0xc028697b + SIOCGETVLAN = 0xc020697f + SIOCGHIWAT = 0x40047301 + SIOCGIFADDR = 0xc0206921 + SIOCGIFALTMTU = 0xc0206948 + SIOCGIFASYNCMAP = 0xc020697c + SIOCGIFBOND = 0xc0206947 + SIOCGIFBRDADDR = 0xc0206923 + SIOCGIFCAP = 0xc020695b + SIOCGIFCONF = 0xc00c6924 + SIOCGIFDEVMTU = 0xc0206944 + SIOCGIFDSTADDR = 0xc0206922 + SIOCGIFFLAGS = 0xc0206911 + SIOCGIFGENERIC = 0xc020693a + SIOCGIFKPI = 0xc0206987 + SIOCGIFMAC = 0xc0206982 + SIOCGIFMEDIA = 0xc02c6938 + SIOCGIFMETRIC = 0xc0206917 + SIOCGIFMTU = 0xc0206933 + SIOCGIFNETMASK = 0xc0206925 + SIOCGIFPDSTADDR = 0xc0206940 + SIOCGIFPHYS = 0xc0206935 + SIOCGIFPSRCADDR = 0xc020693f + SIOCGIFSTATUS = 0xc331693d + SIOCGIFVLAN = 0xc020697f + SIOCGIFWAKEFLAGS = 0xc0206988 + SIOCGLOWAT = 0x40047303 + SIOCGPGRP = 0x40047309 + SIOCIFCREATE = 0xc0206978 + SIOCIFCREATE2 = 0xc020697a + SIOCIFDESTROY = 0x80206979 + SIOCIFGCLONERS = 0xc0106981 + SIOCRSLVMULTI = 0xc010693b + SIOCSDRVSPEC = 0x8028697b + SIOCSETVLAN = 0x8020697e + SIOCSHIWAT = 0x80047300 + SIOCSIFADDR = 0x8020690c + SIOCSIFALTMTU = 0x80206945 + SIOCSIFASYNCMAP = 0x8020697d + SIOCSIFBOND = 0x80206946 + SIOCSIFBRDADDR = 0x80206913 + SIOCSIFCAP = 0x8020695a + SIOCSIFDSTADDR = 0x8020690e + SIOCSIFFLAGS = 0x80206910 + SIOCSIFGENERIC = 0x80206939 + SIOCSIFKPI = 0x80206986 + SIOCSIFLLADDR = 0x8020693c + SIOCSIFMAC = 0x80206983 + SIOCSIFMEDIA = 0xc0206937 + SIOCSIFMETRIC = 0x80206918 + SIOCSIFMTU = 0x80206934 + SIOCSIFNETMASK = 0x80206916 + SIOCSIFPHYADDR = 0x8040693e + SIOCSIFPHYS = 0x80206936 + SIOCSIFVLAN = 0x8020697e + SIOCSLOWAT = 0x80047302 + SIOCSPGRP = 0x80047308 + SOCK_DGRAM = 0x2 + SOCK_MAXADDRLEN = 0xff + SOCK_RAW = 0x3 + SOCK_RDM = 0x4 + SOCK_SEQPACKET = 0x5 + SOCK_STREAM = 0x1 + SOL_SOCKET = 0xffff + SOMAXCONN = 0x80 + SO_ACCEPTCONN = 0x2 + SO_BROADCAST = 0x20 + SO_DEBUG = 0x1 + SO_DONTROUTE = 0x10 + SO_DONTTRUNC = 0x2000 + SO_ERROR = 0x1007 + SO_KEEPALIVE = 0x8 + SO_LABEL = 0x1010 + SO_LINGER = 0x80 + SO_LINGER_SEC = 0x1080 + SO_NKE = 0x1021 + SO_NOADDRERR = 0x1023 + SO_NOSIGPIPE = 0x1022 + SO_NOTIFYCONFLICT = 0x1026 + SO_NP_EXTENSIONS = 0x1083 + SO_NREAD = 0x1020 + SO_NUMRCVPKT = 0x1112 + SO_NWRITE = 0x1024 + SO_OOBINLINE = 0x100 + SO_PEERLABEL = 0x1011 + SO_RANDOMPORT = 0x1082 + SO_RCVBUF = 0x1002 + SO_RCVLOWAT = 0x1004 + SO_RCVTIMEO = 0x1006 + SO_REUSEADDR = 0x4 + SO_REUSEPORT = 0x200 + SO_REUSESHAREUID = 0x1025 + SO_SNDBUF = 0x1001 + SO_SNDLOWAT = 0x1003 + SO_SNDTIMEO = 0x1005 + SO_TIMESTAMP = 0x400 + SO_TIMESTAMP_MONOTONIC = 0x800 + SO_TYPE = 0x1008 + SO_UPCALLCLOSEWAIT = 0x1027 + SO_USELOOPBACK = 0x40 + SO_WANTMORE = 0x4000 + SO_WANTOOBFLAG = 0x8000 + S_IEXEC = 0x40 + S_IFBLK = 0x6000 + S_IFCHR = 0x2000 + S_IFDIR = 0x4000 + S_IFIFO = 0x1000 + S_IFLNK = 0xa000 + S_IFMT = 0xf000 + S_IFREG = 0x8000 + S_IFSOCK = 0xc000 + S_IFWHT = 0xe000 + S_IREAD = 0x100 + S_IRGRP = 0x20 + S_IROTH = 0x4 + S_IRUSR = 0x100 + S_IRWXG = 0x38 + S_IRWXO = 0x7 + S_IRWXU = 0x1c0 + S_ISGID = 0x400 + S_ISTXT = 0x200 + S_ISUID = 0x800 + S_ISVTX = 0x200 + S_IWGRP = 0x10 + S_IWOTH = 0x2 + S_IWRITE = 0x80 + S_IWUSR = 0x80 + S_IXGRP = 0x8 + S_IXOTH = 0x1 + S_IXUSR = 0x40 + TCIFLUSH = 0x1 + TCIOFLUSH = 0x3 + TCOFLUSH = 0x2 + TCP_CONNECTIONTIMEOUT = 0x20 + TCP_ENABLE_ECN = 0x104 + TCP_KEEPALIVE = 0x10 + TCP_KEEPCNT = 0x102 + TCP_KEEPINTVL = 0x101 + TCP_MAXHLEN = 0x3c + TCP_MAXOLEN = 0x28 + TCP_MAXSEG = 0x2 + TCP_MAXWIN = 0xffff + TCP_MAX_SACK = 0x4 + TCP_MAX_WINSHIFT = 0xe + TCP_MINMSS = 0xd8 + TCP_MSS = 0x200 + TCP_NODELAY = 0x1 + TCP_NOOPT = 0x8 + TCP_NOPUSH = 0x4 + TCP_NOTSENT_LOWAT = 0x201 + TCP_RXT_CONNDROPTIME = 0x80 + TCP_RXT_FINDROP = 0x100 + TCP_SENDMOREACKS = 0x103 + TCSAFLUSH = 0x2 + TIOCCBRK = 0x2000747a + TIOCCDTR = 0x20007478 + TIOCCONS = 0x80047462 + TIOCDCDTIMESTAMP = 0x40107458 + TIOCDRAIN = 0x2000745e + TIOCDSIMICROCODE = 0x20007455 + TIOCEXCL = 0x2000740d + TIOCEXT = 0x80047460 + TIOCFLUSH = 0x80047410 + TIOCGDRAINWAIT = 0x40047456 + TIOCGETA = 0x40487413 + TIOCGETD = 0x4004741a + TIOCGPGRP = 0x40047477 + TIOCGWINSZ = 0x40087468 + TIOCIXOFF = 0x20007480 + TIOCIXON = 0x20007481 + TIOCMBIC = 0x8004746b + TIOCMBIS = 0x8004746c + TIOCMGDTRWAIT = 0x4004745a + TIOCMGET = 0x4004746a + TIOCMODG = 0x40047403 + TIOCMODS = 0x80047404 + TIOCMSDTRWAIT = 0x8004745b + TIOCMSET = 0x8004746d + TIOCM_CAR = 0x40 + TIOCM_CD = 0x40 + TIOCM_CTS = 0x20 + TIOCM_DSR = 0x100 + TIOCM_DTR = 0x2 + TIOCM_LE = 0x1 + TIOCM_RI = 0x80 + TIOCM_RNG = 0x80 + TIOCM_RTS = 0x4 + TIOCM_SR = 0x10 + TIOCM_ST = 0x8 + TIOCNOTTY = 0x20007471 + TIOCNXCL = 0x2000740e + TIOCOUTQ = 0x40047473 + TIOCPKT = 0x80047470 + TIOCPKT_DATA = 0x0 + TIOCPKT_DOSTOP = 0x20 + TIOCPKT_FLUSHREAD = 0x1 + TIOCPKT_FLUSHWRITE = 0x2 + TIOCPKT_IOCTL = 0x40 + TIOCPKT_NOSTOP = 0x10 + TIOCPKT_START = 0x8 + TIOCPKT_STOP = 0x4 + TIOCPTYGNAME = 0x40807453 + TIOCPTYGRANT = 0x20007454 + TIOCPTYUNLK = 0x20007452 + TIOCREMOTE = 0x80047469 + TIOCSBRK = 0x2000747b + TIOCSCONS = 0x20007463 + TIOCSCTTY = 0x20007461 + TIOCSDRAINWAIT = 0x80047457 + TIOCSDTR = 0x20007479 + TIOCSETA = 0x80487414 + TIOCSETAF = 0x80487416 + TIOCSETAW = 0x80487415 + TIOCSETD = 0x8004741b + TIOCSIG = 0x2000745f + TIOCSPGRP = 0x80047476 + TIOCSTART = 0x2000746e + TIOCSTAT = 0x20007465 + TIOCSTI = 0x80017472 + TIOCSTOP = 0x2000746f + TIOCSWINSZ = 0x80087467 + TIOCTIMESTAMP = 0x40107459 + TIOCUCNTL = 0x80047466 + TOSTOP = 0x400000 + VDISCARD = 0xf + VDSUSP = 0xb + VEOF = 0x0 + VEOL = 0x1 + VEOL2 = 0x2 + VERASE = 0x3 + VINTR = 0x8 + VKILL = 0x5 + VLNEXT = 0xe + VMIN = 0x10 + VQUIT = 0x9 + VREPRINT = 0x6 + VSTART = 0xc + VSTATUS = 0x12 + VSTOP = 0xd + VSUSP = 0xa + VT0 = 0x0 + VT1 = 0x10000 + VTDLY = 0x10000 + VTIME = 0x11 + VWERASE = 0x4 + WCONTINUED = 0x10 + WCOREFLAG = 0x80 + WEXITED = 0x4 + WNOHANG = 0x1 + WNOWAIT = 0x20 + WORDSIZE = 0x40 + WSTOPPED = 0x8 + WUNTRACED = 0x2 +) + +// State contains the state of a terminal. +type State struct { + termios Termios +} + +// IsTerminal returns true if the given file descriptor is a terminal. +func IsTerminal(fd int) bool { + _, err := getTermios(fd) + return err == nil +} + +// MakeRaw put the terminal connected to the given file descriptor into raw +// mode and returns the previous state of the terminal so that it can be +// restored. +func MakeRaw(fd int) (*State, error) { + var oldState State + + if termios, err := getTermios(fd); err != nil { + return nil, err + } else { + oldState.termios = *termios + } + + newState := oldState.termios + // This attempts to replicate the behaviour documented for cfmakeraw in + // the termios(3) manpage. + newState.Iflag &^= IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON + // newState.Oflag &^= OPOST + newState.Lflag &^= ECHO | ECHONL | ICANON | ISIG | IEXTEN + newState.Cflag &^= CSIZE | PARENB + newState.Cflag |= CS8 + + newState.Cc[VMIN] = 1 + newState.Cc[VTIME] = 0 + + return &oldState, setTermios(fd, &newState) +} + +// GetState returns the current state of a terminal which may be useful to +// restore the terminal after a signal. +func GetState(fd int) (*State, error) { + termios, err := getTermios(fd) + if err != nil { + return nil, err + } + + return &State{termios: *termios}, nil +} + +// Restore restores the terminal connected to the given file descriptor to a +// previous state. +func restoreTerm(fd int, state *State) error { + return setTermios(fd, &state.termios) +} + +// ReadPassword reads a line of input from a terminal without local echo. This +// is commonly used for inputting passwords and other sensitive data. The slice +// returned does not include the \n. +func ReadPassword(fd int) ([]byte, error) { + oldState, err := getTermios(fd) + if err != nil { + return nil, err + } + + newState := oldState + newState.Lflag &^= ECHO + newState.Lflag |= ICANON | ISIG + newState.Iflag |= ICRNL + if err := setTermios(fd, newState); err != nil { + return nil, err + } + + defer func() { + setTermios(fd, oldState) + }() + + var buf [16]byte + var ret []byte + for { + n, err := syscall.Read(fd, buf[:]) + if err != nil { + return nil, err + } + if n == 0 { + if len(ret) == 0 { + return nil, io.EOF + } + break + } + if buf[n-1] == '\n' { + n-- + } + ret = append(ret, buf[:n]...) + if n < len(buf) { + break + } + } + + return ret, nil +} diff --git a/patches/chzyer/readline/term_unix.go b/patches/chzyer/readline/term_unix.go new file mode 100644 index 00000000..55372f59 --- /dev/null +++ b/patches/chzyer/readline/term_unix.go @@ -0,0 +1,25 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build darwin || dragonfly || freebsd || (linux && !appengine) || netbsd || openbsd +// +build darwin dragonfly freebsd linux,!appengine netbsd openbsd + +package readline + +import ( + "syscall" + "unsafe" +) + +type Termios syscall.Termios + +// GetSize returns the dimensions of the given terminal. +func GetSize(fd int) (int, int, error) { + var dimensions [4]uint16 + _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), uintptr(syscall.TIOCGWINSZ), uintptr(unsafe.Pointer(&dimensions)), 0, 0, 0) + if err != 0 { + return 0, 0, err + } + return int(dimensions[1]), int(dimensions[0]), nil +} diff --git a/patches/chzyer/readline/term_wasip1.go b/patches/chzyer/readline/term_wasip1.go new file mode 100644 index 00000000..51379f74 --- /dev/null +++ b/patches/chzyer/readline/term_wasip1.go @@ -0,0 +1,38 @@ +//go:build wasip1 +// +build wasip1 + +package readline + +import ( + "errors" +) + +type Termios struct { + Iflag uint64 + Oflag uint64 + Cflag uint64 + Lflag uint64 + Cc [20]uint8 + Pad_cgo_0 [4]byte + Ispeed uint64 + Ospeed uint64 +} + +// getTermios is a mock function in WASI and returns an error as terminal I/O control is not supported. +func getTermios(fd int) (*Termios, error) { + return nil, errors.New("unsupported on WASI") +} + +// setTermios is a mock function in WASI and returns an error as terminal I/O control is not supported. +func setTermios(fd int, termios *Termios) error { + return errors.New("unsupported on WASI") +} + +// GetSize returns the dimensions of the terminal. +// Since WASI does not support ioctl system calls, we mock this function. +func GetSize(fd int) (int, int, error) { + // Mocking terminal size, as there's no terminal support in WASI + // You can choose to return fixed dimensions, or an error depending on your use case + return 80, 24, nil // Returning a standard terminal size of 80x24 + // or return 0, 0, errors.New("unsupported on WASI") if you prefer to handle this as an error +} diff --git a/patches/chzyer/readline/utils_wasip1.go b/patches/chzyer/readline/utils_wasip1.go new file mode 100644 index 00000000..2902f0cc --- /dev/null +++ b/patches/chzyer/readline/utils_wasip1.go @@ -0,0 +1,59 @@ +//go:build wasip1 +// +build wasip1 + +package readline + +import ( + "io" + "sync" +) + +type winsize struct { + Row uint16 + Col uint16 + Xpixel uint16 + Ypixel uint16 +} + +// SuspendMe is a no-op in WASI as signals are not supported. +func SuspendMe() { + // No-op for WASI +} + +// getWidth is a stub in WASI, returning a fixed width or an error. +func getWidth(stdoutFd int) int { + return 80 // Return a fixed width of 80 columns as a default +} + +// GetScreenWidth returns a fixed width as terminal size detection is not supported in WASI. +func GetScreenWidth() int { + return getWidth(0) // Use the stub getWidth function +} + +// ClearScreen clears the console screen. +func ClearScreen(w io.Writer) (int, error) { + return w.Write([]byte("\033[H")) +} + +// DefaultIsTerminal always returns false as terminal detection is not supported in WASI. +func DefaultIsTerminal() bool { + return false +} + +// GetStdin returns a constant value as stdin is managed differently in WASI. +func GetStdin() int { + return 0 // Returning a dummy value +} + +// ----------------------------------------------------------------------------- + +var ( + widthChange sync.Once + widthChangeCallback func() +) + +// DefaultOnWidthChanged is a no-op in WASI as signal handling is not supported. +func DefaultOnWidthChanged(f func()) { + // No-op for WASI + widthChangeCallback = func() {} // Assign an empty function to avoid nil dereferences +} diff --git a/patches/coreos/go-systemd/journal/journal.go b/patches/coreos/go-systemd/journal/journal.go new file mode 100644 index 00000000..b5f54363 --- /dev/null +++ b/patches/coreos/go-systemd/journal/journal.go @@ -0,0 +1,226 @@ +// Copyright 2015 CoreOS, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Package journal provides write bindings to the local systemd journal. +// It is implemented in pure Go and connects to the journal directly over its +// unix socket. +// +// To read from the journal, see the "sdjournal" package, which wraps the +// sd-journal a C API. +// +// http://www.freedesktop.org/software/systemd/man/systemd-journald.service.html +package journal + +import ( + "bytes" + "encoding/binary" + "errors" + "fmt" + "io" + "io/ioutil" + "net" + "os" + "strconv" + "strings" + "sync" + "sync/atomic" + "syscall" + "unsafe" +) + +// Priority of a journal message +type Priority int + +const ( + PriEmerg Priority = iota + PriAlert + PriCrit + PriErr + PriWarning + PriNotice + PriInfo + PriDebug +) + +var ( + // This can be overridden at build-time: + // https://github.com/golang/go/wiki/GcToolchainTricks#including-build-information-in-the-executable + journalSocket = "/run/systemd/journal/socket" + + // unixConnPtr atomically holds the local unconnected Unix-domain socket. + // Concrete safe pointer type: *net.UnixConn + unixConnPtr unsafe.Pointer + // onceConn ensures that unixConnPtr is initialized exactly once. + onceConn sync.Once +) + +func init() { + onceConn.Do(initConn) +} + +// Enabled checks whether the local systemd journal is available for logging. +func Enabled() bool { + onceConn.Do(initConn) + + if (*net.UnixConn)(atomic.LoadPointer(&unixConnPtr)) == nil { + return false + } + + if _, err := net.Dial("unixgram", journalSocket); err != nil { + return false + } + + return true +} + +// Send a message to the local systemd journal. vars is a map of journald +// fields to values. Fields must be composed of uppercase letters, numbers, +// and underscores, but must not start with an underscore. Within these +// restrictions, any arbitrary field name may be used. Some names have special +// significance: see the journalctl documentation +// (http://www.freedesktop.org/software/systemd/man/systemd.journal-fields.html) +// for more details. vars may be nil. +func Send(message string, priority Priority, vars map[string]string) error { + conn := (*net.UnixConn)(atomic.LoadPointer(&unixConnPtr)) + if conn == nil { + return errors.New("could not initialize socket to journald") + } + + socketAddr := &net.UnixAddr{ + Name: journalSocket, + Net: "unixgram", + } + + data := new(bytes.Buffer) + appendVariable(data, "PRIORITY", strconv.Itoa(int(priority))) + appendVariable(data, "MESSAGE", message) + for k, v := range vars { + appendVariable(data, k, v) + } + + _, _, err := conn.WriteMsgUnix(data.Bytes(), nil, socketAddr) + if err == nil { + return nil + } + if !isSocketSpaceError(err) { + return err + } + + // Large log entry, send it via tempfile and ancillary-fd. + file, err := tempFd() + if err != nil { + return err + } + defer file.Close() + _, err = io.Copy(file, data) + if err != nil { + return err + } + // @nonfx - Disabled for wasip1 compilation + // rights := syscall.UnixRights(int(file.Fd())) + // _, _, err = conn.WriteMsgUnix([]byte{}, rights, socketAddr) + // if err != nil { + // return err + // } + + return nil +} + +// Print prints a message to the local systemd journal using Send(). +func Print(priority Priority, format string, a ...interface{}) error { + return Send(fmt.Sprintf(format, a...), priority, nil) +} + +func appendVariable(w io.Writer, name, value string) { + if err := validVarName(name); err != nil { + fmt.Fprintf(os.Stderr, "variable name %s contains invalid character, ignoring\n", name) + } + if strings.ContainsRune(value, '\n') { + /* When the value contains a newline, we write: + * - the variable name, followed by a newline + * - the size (in 64bit little endian format) + * - the data, followed by a newline + */ + fmt.Fprintln(w, name) + binary.Write(w, binary.LittleEndian, uint64(len(value))) + fmt.Fprintln(w, value) + } else { + /* just write the variable and value all on one line */ + fmt.Fprintf(w, "%s=%s\n", name, value) + } +} + +// validVarName validates a variable name to make sure journald will accept it. +// The variable name must be in uppercase and consist only of characters, +// numbers and underscores, and may not begin with an underscore: +// https://www.freedesktop.org/software/systemd/man/sd_journal_print.html +func validVarName(name string) error { + if name == "" { + return errors.New("Empty variable name") + } else if name[0] == '_' { + return errors.New("Variable name begins with an underscore") + } + + for _, c := range name { + if !(('A' <= c && c <= 'Z') || ('0' <= c && c <= '9') || c == '_') { + return errors.New("Variable name contains invalid characters") + } + } + return nil +} + +// isSocketSpaceError checks whether the error is signaling +// an "overlarge message" condition. +func isSocketSpaceError(err error) bool { + opErr, ok := err.(*net.OpError) + if !ok || opErr == nil { + return false + } + + sysErr, ok := opErr.Err.(*os.SyscallError) + if !ok || sysErr == nil { + return false + } + + return sysErr.Err == syscall.EMSGSIZE || sysErr.Err == syscall.ENOBUFS +} + +// tempFd creates a temporary, unlinked file under `/dev/shm`. +func tempFd() (*os.File, error) { + file, err := ioutil.TempFile("/dev/shm/", "journal.XXXXX") + if err != nil { + return nil, err + } + err = syscall.Unlink(file.Name()) + if err != nil { + return nil, err + } + return file, nil +} + +// initConn initializes the global `unixConnPtr` socket. +// It is meant to be called exactly once, at program startup. +func initConn() { + autobind, err := net.ResolveUnixAddr("unixgram", "") + if err != nil { + return + } + + sock, err := net.ListenUnixgram("unixgram", autobind) + if err != nil { + return + } + + atomic.StorePointer(&unixConnPtr, unsafe.Pointer(sock)) +} diff --git a/patches/fsnotify/fsnotify/backend_other.go b/patches/fsnotify/fsnotify/backend_other.go new file mode 100644 index 00000000..506be1e5 --- /dev/null +++ b/patches/fsnotify/fsnotify/backend_other.go @@ -0,0 +1,69 @@ +//go:build (!darwin && !dragonfly && !freebsd && !openbsd && !linux && !netbsd && !solaris && !windows) || wasip1 +// +build !darwin,!dragonfly,!freebsd,!openbsd,!linux,!netbsd,!solaris,!windows wasip1 + +package fsnotify + +import ( + "fmt" + "runtime" +) + +// Watcher watches a set of files, delivering events to a channel. +type Watcher struct { + Events chan Event + Errors chan error +} + +// NewWatcher creates a new Watcher. +func NewWatcher() (*Watcher, error) { + return nil, fmt.Errorf("fsnotify not supported on %s", runtime.GOOS) +} + +// Close removes all watches and closes the events channel. +func (w *Watcher) Close() error { + return nil +} + +// Add starts monitoring the path for changes. +// +// A path can only be watched once; attempting to watch it more than once will +// return an error. Paths that do not yet exist on the filesystem cannot be +// added. A watch will be automatically removed if the path is deleted. +// +// A path will remain watched if it gets renamed to somewhere else on the same +// filesystem, but the monitor will get removed if the path gets deleted and +// re-created, or if it's moved to a different filesystem. +// +// Notifications on network filesystems (NFS, SMB, FUSE, etc.) or special +// filesystems (/proc, /sys, etc.) generally don't work. +// +// # Watching directories +// +// All files in a directory are monitored, including new files that are created +// after the watcher is started. Subdirectories are not watched (i.e. it's +// non-recursive). +// +// # Watching files +// +// Watching individual files (rather than directories) is generally not +// recommended as many tools update files atomically. Instead of "just" writing +// to the file a temporary file will be written to first, and if successful the +// temporary file is moved to to destination removing the original, or some +// variant thereof. The watcher on the original file is now lost, as it no +// longer exists. +// +// Instead, watch the parent directory and use Event.Name to filter out files +// you're not interested in. There is an example of this in [cmd/fsnotify/file.go]. +func (w *Watcher) Add(name string) error { + return nil +} + +// Remove stops monitoring the path for changes. +// +// Directories are always removed non-recursively. For example, if you added +// /tmp/dir and /tmp/dir/subdir then you will need to remove both. +// +// Removing a path that has not yet been added returns [ErrNonExistentWatch]. +func (w *Watcher) Remove(name string) error { + return nil +} diff --git a/patches/sirupsen/logrus/terminal_check_appengine.go b/patches/sirupsen/logrus/terminal_check_appengine.go new file mode 100644 index 00000000..a56b2efb --- /dev/null +++ b/patches/sirupsen/logrus/terminal_check_appengine.go @@ -0,0 +1,12 @@ +//go:build appengine || wasip1 +// +build appengine wasip1 + +package logrus + +import ( + "io" +) + +func checkIfTerminal(w io.Writer) bool { + return true +} diff --git a/patches/sirupsen/logrus/terminal_check_notappengine.go b/patches/sirupsen/logrus/terminal_check_notappengine.go new file mode 100644 index 00000000..571795b4 --- /dev/null +++ b/patches/sirupsen/logrus/terminal_check_notappengine.go @@ -0,0 +1,18 @@ +//go:build !wasip1 && !appengine && !js && !windows && !nacl && !plan9 +// +build !wasip1,!appengine,!js,!windows,!nacl,!plan9 + +package logrus + +import ( + "io" + "os" +) + +func checkIfTerminal(w io.Writer) bool { + switch v := w.(type) { + case *os.File: + return isTerminal(int(v.Fd())) + default: + return false + } +} diff --git a/patches/spf13/afero/const_wasip1.go b/patches/spf13/afero/const_wasip1.go new file mode 100644 index 00000000..d43c430b --- /dev/null +++ b/patches/spf13/afero/const_wasip1.go @@ -0,0 +1,25 @@ +// Copyright © 2016 Steve Francia . +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +//go:build wasip1 +// +build wasip1 + +package afero + +type Errno uintptr + +const BADFD = Errno(0x9) + +// Dummy implementation to compile it to WASI +func (e Errno) Error() string { + return "dummy" +} diff --git a/patches/spf13/afero/const_win_unix.go b/patches/spf13/afero/const_win_unix.go new file mode 100644 index 00000000..d112194e --- /dev/null +++ b/patches/spf13/afero/const_win_unix.go @@ -0,0 +1,22 @@ +// Copyright © 2016 Steve Francia . +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +//go:build !darwin && !openbsd && !freebsd && !dragonfly && !netbsd && !aix && !wasip1 +// +build !darwin,!openbsd,!freebsd,!dragonfly,!netbsd,!aix,!wasip1 + +package afero + +import ( + "syscall" +) + +const BADFD = syscall.EBADFD diff --git a/test/fixtures/insecure.tf b/test/fixtures/insecure.tf new file mode 100644 index 00000000..4468c901 --- /dev/null +++ b/test/fixtures/insecure.tf @@ -0,0 +1,29 @@ +provider "aws" { + region = "us-east-1" +} + +# Insecure S3 bucket - no encryption, no versioning, no logging +resource "aws_s3_bucket" "insecure" { + bucket = "my-insecure-bucket" + acl = "public-read" +} + +# Security group with overly permissive ingress +resource "aws_security_group" "insecure" { + name = "insecure-sg" + description = "Insecure security group" + + ingress { + from_port = 0 + to_port = 0 + protocol = "-1" + cidr_blocks = ["0.0.0.0/0"] + } + + egress { + from_port = 0 + to_port = 0 + protocol = "-1" + cidr_blocks = ["0.0.0.0/0"] + } +} diff --git a/test/fixtures/valid.tf b/test/fixtures/valid.tf new file mode 100644 index 00000000..59304958 --- /dev/null +++ b/test/fixtures/valid.tf @@ -0,0 +1,33 @@ +provider "aws" { + region = "us-east-1" +} + +resource "aws_s3_bucket" "example" { + bucket = "my-secure-bucket" + + versioning { + enabled = true + } + + server_side_encryption_configuration { + rule { + apply_server_side_encryption_by_default { + sse_algorithm = "AES256" + } + } + } + + logging { + target_bucket = "my-logging-bucket" + target_prefix = "logs/" + } +} + +resource "aws_s3_bucket_public_access_block" "example" { + bucket = aws_s3_bucket.example.id + + block_public_acls = true + block_public_policy = true + ignore_public_acls = true + restrict_public_buckets = true +} diff --git a/test/test-wasi.js b/test/test-wasi.js new file mode 100644 index 00000000..269106e1 --- /dev/null +++ b/test/test-wasi.js @@ -0,0 +1,201 @@ +/** + * WASI Build Test Suite + * + * Compares WASI binary output against the regular binary to ensure parity. + */ + +import { execFile } from "child_process"; +import { fileURLToPath } from "url"; +import { dirname, join } from "path"; +import assert from "assert"; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = dirname(__filename); +const rootDir = join(__dirname, ".."); + +const cliPath = join(rootDir, "cli.js"); +const binaryPath = join(rootDir, "bin", "regula"); +const fixturesDir = join(__dirname, "fixtures"); + +let passed = 0; +let failed = 0; + +function test(name, fn) { + return fn() + .then(() => { + console.log(`✓ ${name}`); + passed++; + }) + .catch((err) => { + console.log(`✗ ${name}`); + console.log(` Error: ${err.message}`); + failed++; + }); +} + +function runWasi(args) { + return new Promise((resolve, reject) => { + execFile("node", [cliPath, ...args], { maxBuffer: 50 * 1024 * 1024 }, (error, stdout, stderr) => { + resolve({ error, stdout, stderr, exitCode: error?.code || 0 }); + }); + }); +} + +function runBinary(args) { + return new Promise((resolve, reject) => { + execFile(binaryPath, args, { maxBuffer: 50 * 1024 * 1024 }, (error, stdout, stderr) => { + resolve({ error, stdout, stderr, exitCode: error?.code || 0 }); + }); + }); +} + +function normalizeJson(str) { + try { + const obj = JSON.parse(str); + // Remove timing-dependent fields + if (obj.rule_results) { + obj.rule_results.forEach(r => { + delete r.source_location; // May have slight path differences + }); + } + return JSON.stringify(obj, null, 2); + } catch { + return str; + } +} + +async function runTests() { + console.log("WASI Build Parity Tests\n"); + console.log("Comparing WASI binary against regular binary...\n"); + + // Test 1: Version command parity + await test("Version output matches", async () => { + const wasi = await runWasi(["version"]); + const binary = await runBinary(["version"]); + assert.strictEqual(wasi.stdout.trim(), binary.stdout.trim(), "Version output should match"); + }); + + // Test 2: Help output parity + await test("Help output matches", async () => { + const wasi = await runWasi(["--help"]); + const binary = await runBinary(["--help"]); + assert.strictEqual(wasi.stdout, binary.stdout, "Help output should match"); + }); + + // Test 3: Run command help parity + await test("Run command help matches", async () => { + const wasi = await runWasi(["run", "--help"]); + const binary = await runBinary(["run", "--help"]); + assert.strictEqual(wasi.stdout, binary.stdout, "Run help output should match"); + }); + + // Test 4: JSON output parity on valid.tf + await test("JSON output matches for valid.tf", async () => { + const wasi = await runWasi(["run", "--format", "json", join(fixturesDir, "valid.tf")]); + const binary = await runBinary(["run", "--format", "json", join(fixturesDir, "valid.tf")]); + + const wasiJson = normalizeJson(wasi.stdout); + const binaryJson = normalizeJson(binary.stdout); + + assert.strictEqual(wasiJson, binaryJson, "JSON output should match"); + }); + + // Test 5: JSON output parity on insecure.tf + await test("JSON output matches for insecure.tf", async () => { + const wasi = await runWasi(["run", "--format", "json", join(fixturesDir, "insecure.tf")]); + const binary = await runBinary(["run", "--format", "json", join(fixturesDir, "insecure.tf")]); + + const wasiJson = normalizeJson(wasi.stdout); + const binaryJson = normalizeJson(binary.stdout); + + assert.strictEqual(wasiJson, binaryJson, "JSON output should match"); + }); + + // Test 6: Rule count parity + await test("Same number of rule results", async () => { + const wasi = await runWasi(["run", "--format", "json", fixturesDir]); + const binary = await runBinary(["run", "--format", "json", fixturesDir]); + + const wasiResults = JSON.parse(wasi.stdout); + const binaryResults = JSON.parse(binary.stdout); + + assert.strictEqual( + wasiResults.rule_results.length, + binaryResults.rule_results.length, + "Should have same number of rule results" + ); + }); + + // Test 7: Summary parity + await test("Summary statistics match", async () => { + const wasi = await runWasi(["run", "--format", "json", fixturesDir]); + const binary = await runBinary(["run", "--format", "json", fixturesDir]); + + const wasiResults = JSON.parse(wasi.stdout); + const binaryResults = JSON.parse(binary.stdout); + + assert.deepStrictEqual( + wasiResults.summary.rule_results, + binaryResults.summary.rule_results, + "Summary rule_results should match" + ); + + assert.deepStrictEqual( + wasiResults.summary.severities, + binaryResults.summary.severities, + "Summary severities should match" + ); + }); + + // Test 8: Input type flag works + await test("Input type flag works identically", async () => { + const wasi = await runWasi(["run", "--format", "json", "--input-type", "tf", join(fixturesDir, "valid.tf")]); + const binary = await runBinary(["run", "--format", "json", "--input-type", "tf", join(fixturesDir, "valid.tf")]); + + const wasiJson = normalizeJson(wasi.stdout); + const binaryJson = normalizeJson(binary.stdout); + + assert.strictEqual(wasiJson, binaryJson, "JSON output with input-type flag should match"); + }); + + // Test 9: Rego test command parity + await test("Rego test results match", async () => { + const testPath = join(rootDir, "rego/tests/lib/"); + + const wasi = await runWasi(["test", testPath]); + const binary = await runBinary(["test", testPath]); + + // Extract PASS/FAIL counts + const wasiMatch = wasi.stdout.match(/PASS: (\d+)\/(\d+)\nFAIL: (\d+)\/(\d+)/); + const binaryMatch = binary.stdout.match(/PASS: (\d+)\/(\d+)\nFAIL: (\d+)\/(\d+)/); + + assert(wasiMatch, "WASI should have test results"); + assert(binaryMatch, "Binary should have test results"); + assert.strictEqual(wasiMatch[1], binaryMatch[1], "PASS count should match"); + assert.strictEqual(wasiMatch[3], binaryMatch[3], "FAIL count should match"); + }); + + // Test 10: Exit codes match + await test("Exit codes match for failures", async () => { + const wasi = await runWasi(["run", "--format", "json", join(fixturesDir, "insecure.tf")]); + const binary = await runBinary(["run", "--format", "json", join(fixturesDir, "insecure.tf")]); + + // Both should have non-zero exit for files with violations + const wasiHasFailures = JSON.parse(wasi.stdout).summary.rule_results.FAIL > 0; + const binaryHasFailures = JSON.parse(binary.stdout).summary.rule_results.FAIL > 0; + + assert.strictEqual(wasiHasFailures, binaryHasFailures, "Both should detect failures"); + }); + + // Summary + console.log(`\n${"=".repeat(50)}`); + console.log(`WASI Parity Tests: ${passed} passed, ${failed} failed`); + console.log(`${"=".repeat(50)}`); + + process.exit(failed > 0 ? 1 : 0); +} + +runTests().catch((err) => { + console.error("Test runner error:", err); + process.exit(1); +}); diff --git a/test/test.js b/test/test.js new file mode 100644 index 00000000..c1ef572d --- /dev/null +++ b/test/test.js @@ -0,0 +1,94 @@ +import { runRegula } from "../index.js"; +import { execFile } from "child_process"; +import { fileURLToPath } from "url"; +import { dirname, join } from "path"; +import assert from "assert"; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = dirname(__filename); + +const fixturesDir = join(__dirname, "fixtures"); +const cliPath = join(__dirname, "..", "cli.js"); + +let passed = 0; +let failed = 0; + +function test(name, fn) { + return fn() + .then(() => { + console.log(`✓ ${name}`); + passed++; + }) + .catch((err) => { + console.log(`✗ ${name}`); + console.log(` Error: ${err.message}`); + failed++; + }); +} + +async function runCli(args) { + return new Promise((resolve, reject) => { + execFile("node", [cliPath, ...args], { maxBuffer: 50 * 1024 * 1024 }, (error, stdout, stderr) => { + resolve({ error, stdout, stderr, exitCode: error?.code || 0 }); + }); + }); +} + +// Tests +async function runTests() { + console.log("Running regula WASI tests...\n"); + + // Test 1: CLI --help works + await test("CLI --help returns usage info", async () => { + const { stdout } = await runCli(["--help"]); + assert(stdout.includes("regula"), "Should contain 'regula'"); + assert(stdout.includes("Available Commands"), "Should show available commands"); + }); + + // Test 2: CLI version works + await test("CLI version command works", async () => { + const { stdout } = await runCli(["version"]); + assert(stdout.includes("OPA") || stdout.includes("version"), "Should contain version info"); + }); + + // Test 3: Run on valid terraform file + await test("Run on valid terraform file returns results", async () => { + const result = await runRegula(join(fixturesDir, "valid.tf")); + assert(result.rule_results, "Should have rule_results"); + assert(result.summary, "Should have summary"); + }); + + // Test 4: Run on insecure terraform file finds issues + await test("Run on insecure terraform file finds violations", async () => { + const result = await runRegula(join(fixturesDir, "insecure.tf")); + assert(result.rule_results, "Should have rule_results"); + assert(result.summary, "Should have summary"); + // Should find some failures for the insecure config + const failures = result.rule_results.filter((r) => r.rule_result === "FAIL"); + assert(failures.length > 0, "Should find security violations"); + }); + + // Test 5: Programmatic API with options + await test("Programmatic API accepts options", async () => { + const result = await runRegula(join(fixturesDir, "valid.tf"), { + inputType: "tf", + }); + assert(result.rule_results, "Should have rule_results"); + }); + + // Test 6: Run on directory + await test("Run on directory works", async () => { + const result = await runRegula(fixturesDir); + assert(result.rule_results, "Should have rule_results"); + assert(result.summary, "Should have summary"); + }); + + // Summary + console.log(`\n${passed} passed, ${failed} failed`); + process.exit(failed > 0 ? 1 : 0); +} + +runTests().catch((err) => { + console.error("Test runner error:", err); + process.exit(1); +}); From d25cd7e15245ac470ac5159ac1c368586fc27916 Mon Sep 17 00:00:00 2001 From: Nikhil Verma Date: Wed, 4 Feb 2026 18:27:57 +0530 Subject: [PATCH 2/7] Update package.json for npm publishing - Add LICENSE to published files - Update description to note it's a fork - Point repository URL to nonfx/regula Co-Authored-By: Claude Opus 4.5 --- package.json | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index b4371e60..69d4919d 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "regula-wasi", "version": "3.2.2", - "description": "Infrastructure as Code security and compliance evaluation tool (WASI build)", + "description": "Infrastructure as Code security and compliance evaluation tool (WASI build). Fork of fugue/regula with security patches.", "type": "module", "main": "index.js", "bin": { @@ -17,7 +17,8 @@ "index.js", "cli.js", "regula.wasm", - "README.md" + "README.md", + "LICENSE" ], "keywords": [ "regula", @@ -37,7 +38,7 @@ "license": "Apache-2.0", "repository": { "type": "git", - "url": "git+https://github.com/fugue/regula.git" + "url": "git+https://github.com/nonfx/regula.git" }, "engines": { "node": ">=18.0.0" From ffb8fd981b51080243ea1170289071b501acff27 Mon Sep 17 00:00:00 2001 From: Nikhil Verma Date: Wed, 4 Feb 2026 18:34:24 +0530 Subject: [PATCH 3/7] Update WASI build for new dependencies - Update build-wasi.sh to run go mod vendor first - Add -ldflags for stripped builds - Skip patches that don't apply (go-systemd removed) - Update fsnotify patch for new package structure Requires Go 1.25+ for WASM linking of large binaries. Co-Authored-By: Claude Opus 4.5 --- build-wasi.sh | 37 +++++++---- patches/fsnotify/fsnotify/backend_other.go | 71 ++++------------------ 2 files changed, 38 insertions(+), 70 deletions(-) diff --git a/build-wasi.sh b/build-wasi.sh index ad78db88..38db617e 100755 --- a/build-wasi.sh +++ b/build-wasi.sh @@ -4,26 +4,41 @@ set -e SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" cd "$SCRIPT_DIR" +echo "==> Vendoring dependencies..." +go mod vendor + echo "==> Applying WASI patches to vendor..." +# Helper function to apply patch if target exists +apply_patch() { + local src="$1" + local dest="$2" + if [ -d "$(dirname "$dest")" ]; then + cp "$src" "$dest" + echo " Applied: $dest" + else + echo " Skipped (not found): $dest" + fi +} + # Apply patches by copying files from patches/ to vendor/github.com/ -cp patches/spf13/afero/const_wasip1.go vendor/github.com/spf13/afero/ -cp patches/spf13/afero/const_win_unix.go vendor/github.com/spf13/afero/ +apply_patch patches/spf13/afero/const_wasip1.go vendor/github.com/spf13/afero/const_wasip1.go +apply_patch patches/spf13/afero/const_win_unix.go vendor/github.com/spf13/afero/const_win_unix.go -cp patches/sirupsen/logrus/terminal_check_appengine.go vendor/github.com/sirupsen/logrus/ -cp patches/sirupsen/logrus/terminal_check_notappengine.go vendor/github.com/sirupsen/logrus/ +apply_patch patches/sirupsen/logrus/terminal_check_appengine.go vendor/github.com/sirupsen/logrus/terminal_check_appengine.go +apply_patch patches/sirupsen/logrus/terminal_check_notappengine.go vendor/github.com/sirupsen/logrus/terminal_check_notappengine.go -cp patches/coreos/go-systemd/journal/journal.go vendor/github.com/coreos/go-systemd/journal/ +apply_patch patches/coreos/go-systemd/journal/journal.go vendor/github.com/coreos/go-systemd/journal/journal.go -cp patches/fsnotify/fsnotify/backend_other.go vendor/github.com/fsnotify/fsnotify/ +apply_patch patches/fsnotify/fsnotify/backend_other.go vendor/github.com/fsnotify/fsnotify/backend_other.go -cp patches/chzyer/readline/term.go vendor/github.com/chzyer/readline/ -cp patches/chzyer/readline/term_unix.go vendor/github.com/chzyer/readline/ -cp patches/chzyer/readline/term_wasip1.go vendor/github.com/chzyer/readline/ -cp patches/chzyer/readline/utils_wasip1.go vendor/github.com/chzyer/readline/ +apply_patch patches/chzyer/readline/term.go vendor/github.com/chzyer/readline/term.go +apply_patch patches/chzyer/readline/term_unix.go vendor/github.com/chzyer/readline/term_unix.go +apply_patch patches/chzyer/readline/term_wasip1.go vendor/github.com/chzyer/readline/term_wasip1.go +apply_patch patches/chzyer/readline/utils_wasip1.go vendor/github.com/chzyer/readline/utils_wasip1.go echo "==> Building WASI binary..." -GOOS=wasip1 GOARCH=wasm go build -mod vendor -o regula.wasm +GOOS=wasip1 GOARCH=wasm go build -mod vendor -ldflags="-s -w" -o regula.wasm echo "==> Build complete: regula.wasm" ls -lh regula.wasm diff --git a/patches/fsnotify/fsnotify/backend_other.go b/patches/fsnotify/fsnotify/backend_other.go index 506be1e5..df82542b 100644 --- a/patches/fsnotify/fsnotify/backend_other.go +++ b/patches/fsnotify/fsnotify/backend_other.go @@ -1,69 +1,22 @@ -//go:build (!darwin && !dragonfly && !freebsd && !openbsd && !linux && !netbsd && !solaris && !windows) || wasip1 -// +build !darwin,!dragonfly,!freebsd,!openbsd,!linux,!netbsd,!solaris,!windows wasip1 +//go:build appengine || wasip1 || (!darwin && !dragonfly && !freebsd && !openbsd && !linux && !netbsd && !solaris && !windows) package fsnotify -import ( - "fmt" - "runtime" -) +import "errors" -// Watcher watches a set of files, delivering events to a channel. -type Watcher struct { +type other struct { Events chan Event Errors chan error } -// NewWatcher creates a new Watcher. -func NewWatcher() (*Watcher, error) { - return nil, fmt.Errorf("fsnotify not supported on %s", runtime.GOOS) -} - -// Close removes all watches and closes the events channel. -func (w *Watcher) Close() error { - return nil -} - -// Add starts monitoring the path for changes. -// -// A path can only be watched once; attempting to watch it more than once will -// return an error. Paths that do not yet exist on the filesystem cannot be -// added. A watch will be automatically removed if the path is deleted. -// -// A path will remain watched if it gets renamed to somewhere else on the same -// filesystem, but the monitor will get removed if the path gets deleted and -// re-created, or if it's moved to a different filesystem. -// -// Notifications on network filesystems (NFS, SMB, FUSE, etc.) or special -// filesystems (/proc, /sys, etc.) generally don't work. -// -// # Watching directories -// -// All files in a directory are monitored, including new files that are created -// after the watcher is started. Subdirectories are not watched (i.e. it's -// non-recursive). -// -// # Watching files -// -// Watching individual files (rather than directories) is generally not -// recommended as many tools update files atomically. Instead of "just" writing -// to the file a temporary file will be written to first, and if successful the -// temporary file is moved to to destination removing the original, or some -// variant thereof. The watcher on the original file is now lost, as it no -// longer exists. -// -// Instead, watch the parent directory and use Event.Name to filter out files -// you're not interested in. There is an example of this in [cmd/fsnotify/file.go]. -func (w *Watcher) Add(name string) error { - return nil -} +var defaultBufferSize = 0 -// Remove stops monitoring the path for changes. -// -// Directories are always removed non-recursively. For example, if you added -// /tmp/dir and /tmp/dir/subdir then you will need to remove both. -// -// Removing a path that has not yet been added returns [ErrNonExistentWatch]. -func (w *Watcher) Remove(name string) error { - return nil +func newBackend(ev chan Event, errs chan error) (backend, error) { + return nil, errors.New("fsnotify not supported on the current platform") } +func (w *other) Close() error { return nil } +func (w *other) WatchList() []string { return nil } +func (w *other) Add(name string) error { return nil } +func (w *other) AddWith(name string, opts ...addOpt) error { return nil } +func (w *other) Remove(name string) error { return nil } +func (w *other) xSupports(op Op) bool { return false } From 53a44dd4c946468f19c76f17e4af13786ef6b096 Mon Sep 17 00:00:00 2001 From: Nikhil Verma Date: Wed, 4 Feb 2026 18:36:41 +0530 Subject: [PATCH 4/7] Update README for fork with WASI/npm support - Document this as a maintained fork of fugue/regula - List security patches and dependency upgrades - Add WASI build documentation - Add npm installation and usage instructions - Update available commands and options Co-Authored-By: Claude Opus 4.5 --- README.md | 265 +++++++++++++++++++++++++++++++++--------------------- 1 file changed, 164 insertions(+), 101 deletions(-) diff --git a/README.md b/README.md index 38cdf8dc..c03edb29 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,31 @@ -# Regula +# Regula (nonfx fork) -**Tip: See all of our documentation at [regula.dev](https://regula.dev)!** +> **Note:** This is a maintained fork of [fugue/regula](https://github.com/fugue/regula), which is now archived. This fork includes security patches, dependency upgrades, and WASI/npm support. -- [Regula](#regula) - - [Introduction](#introduction) - - [Installation](#installation) - - [Homebrew (macOS & Linux)](#homebrew-macos--linux) - - [Prebuilt binary (all platforms)](#prebuilt-binary-all-platforms) - - [Docker (all platforms)](#docker-all-platforms) - - [From source](#from-source) - - [Usage](#usage) - - [For more information](#for-more-information) +## What's Different in This Fork + +### Security Patches & Upgrades +- **OPA upgraded** from v0.45.1 to v1.12.2 (latest) +- **Go upgraded** to 1.24.11 with stdlib CVE fixes +- **AWS SDK** migrated to maintained fork +- **go-getter** upgraded from 1.6.2 to 1.7.0 +- **golang.org/x/net** upgraded to fix vulnerabilities +- **google.golang.org/grpc** upgraded to 1.56.3 + +### WASI/WebAssembly Support +This fork can be compiled to WASI (WebAssembly System Interface), allowing it to run in Node.js 18+ without native dependencies. This is useful for: +- Serverless environments +- Browser-based tools +- Cross-platform distribution via npm + +### Vendor Patches for WASI +The following vendor patches are applied during WASI builds: +- `spf13/afero` - WASI-compatible errno handling +- `sirupsen/logrus` - Terminal detection bypass for WASI +- `fsnotify/fsnotify` - No-op file watcher for WASI +- `chzyer/readline` - Terminal stubs for WASI + +--- ## Introduction @@ -22,141 +37,189 @@ Regula supports the following file types: - Terraform source code - Terraform JSON plans - Kubernetes YAML manifests -- Azure Resource Manager (ARM) JSON templates _(in preview)_ - -Regula includes a library of rules written in Rego, the policy language used by the [Open Policy Agent](https://www.openpolicyagent.org/) (OPA) project. Regula works with your favorite CI/CD tools such as Jenkins, Circle CI, and AWS CodePipeline; we’ve included a [GitHub Actions example](https://github.com/fugue/regula-action) so you can get started quickly. Where relevant, we’ve mapped Regula policies to the CIS AWS, Azure, Google Cloud, and Kubernetes Foundations Benchmarks so you can assess compliance posture. Regula is maintained by engineers at [Fugue](https://fugue.co). +- Azure Resource Manager (ARM) JSON templates -Regula is also available as a Docker image on DockerHub [here](https://hub.docker.com/r/fugue/regula). +Regula includes a library of rules written in Rego, the policy language used by the [Open Policy Agent](https://www.openpolicyagent.org/) (OPA) project. -More information is available at [regula.dev](https://regula.dev). +--- ## Installation -### Homebrew (macOS & Linux) +### npm (Node.js 18+) -To install Regula via [Homebrew](https://brew.sh/): +The easiest way to use Regula in JavaScript/TypeScript projects: +```bash +npm install regula-wasi ``` -brew tap fugue/regula -brew install regula -``` -To upgrade Regula: +#### CLI Usage + +```bash +# Run directly with npx +npx regula-wasi run ./terraform/ +# Or install globally +npm install -g regula-wasi +regula run ./terraform/ ``` -brew upgrade regula + +#### Programmatic Usage + +```javascript +import { runRegula, validate } from 'regula-wasi'; + +// Basic usage +const result = await runRegula('./terraform/'); +console.log(result.summary); + +// With options +const result = await runRegula('./main.tf', { + inputType: 'tf', // auto, tf, tf-plan, cfn, k8s, arm + include: ['./custom-rules/'], + only: ['FG_R00229'], // Only run specific rules + exclude: ['FG_R00100'], // Exclude specific rules +}); + +// Check for failures +if (result.summary.rule_results.FAIL > 0) { + console.error('Security violations found!'); + process.exit(1); +} ``` -### Prebuilt binary (all platforms) +### Prebuilt Binary + +Download from [Releases](https://github.com/nonfx/regula/releases) for your platform. -1. Download the Regula archive for your platform from the [Releases](https://github.com/fugue/regula/releases) page. -2. Extract the downloaded archive. -3. Move the extracted `regula` binary to somewhere in your PATH: +### From Source + +Requires Go 1.21+ + +```bash +# Build native binary +make binary # outputs to ./bin/regula +make install # installs to /usr/local/bin/regula + +# Build WASI binary (requires Go 1.25+) +./build-wasi.sh # outputs regula.wasm +``` - macOS: +### Docker - ``` - mv regula /usr/local/bin - ``` +```bash +docker run --rm -v $(pwd):/workspace ghcr.io/nonfx/regula run /workspace +``` - Linux: +--- - ``` - sudo mv regula /usr/local/bin - ``` +## Usage - Windows (cmd): +### Basic Commands - ``` - md C:\regula\bin - move regula.exe C:\regula\bin - setx PATH "%PATH%;C:\regula\bin" - ``` +```bash +# Scan Terraform directory +regula run ./terraform/ - Windows (PowerShell): +# Scan with specific input type +regula run --input-type tf ./main.tf - ``` - md C:\regula\bin - move regula.exe C:\regula\bin - $env:Path += ";C:\regula\bin" - # You can add '$env:Path += ";C:\regula\bin"' to your profile.ps1 file to - # persist that change across shell sessions. - ``` +# Output as JSON +regula run --format json ./terraform/ -4. _Windows users only:_ Close cmd and re-open it so the changes take effect. -5. You can now run `regula`. +# Include custom rules +regula run --include ./custom-rules/ ./terraform/ -### Docker (all platforms) +# Run only specific rules +regula run --only FG_R00229 ./terraform/ +``` -Regula is available as a Docker image on DockerHub [here](https://hub.docker.com/r/fugue/regula). +### Output Formats -For usage, see [Running Regula with Docker](https://regula.dev/usage.html#running-regula-with-docker). +- `text` (default) - Human-readable output +- `json` - JSON output for programmatic use +- `table` - Tabular output +- `sarif` - SARIF format for GitHub Code Scanning +- `junit` - JUnit XML for CI/CD integration +- `tap` - Test Anything Protocol -### From source +### Exit Codes -_macOS, Linux, and [WSL](https://docs.microsoft.com/en-us/windows/wsl/install) only_ +- `0` - No violations found +- `1` - Violations found or error occurred -1. [Install Go (v1.18+)](https://go.dev/doc/install) +--- -2. Build binary and move to `/usr/local/bin/regula`: +## Available Commands - ```bash - make # this builds ./bin/regula - make install # this builds ./bin/regula and installs it to /usr/local/bin/regula - ``` +``` +regula [command] -Once you've built the binary, execute the following to run tests: +Commands: + run Evaluate rules against infrastructure as code + test Run OPA test with Regula + repl Start an interactive session for testing rules + init Create a new Regula configuration file + show Show debug information + version Print version information + completion Generate shell autocompletion script +Flags: + -h, --help Help for regula + -v, --verbose Verbose output ``` -git submodule update --init --recursive -make test + +--- + +## Building + +### Native Binary + +```bash +# Standard build +go build -mod vendor -o bin/regula . + +# Or use make +make binary ``` -## Usage +### WASI Binary -**For a tutorial on using Regula with example IaC, see [Getting Started](https://regula.dev/getting-started.html#tutorial-run-regula-locally-on-terraform-iac).** +Requires Go 1.25+ for large binary WASM linking. +```bash +./build-wasi.sh ``` -Regula - -Usage: - regula [command] - -Available Commands: - completion generate the autocompletion script for the specified shell - help Help about any command - init Create a new Regula configuration file in the current working directory. - repl Start an interactive session for testing rules with Regula - run Evaluate rules against infrastructure as code with Regula. - show Show debug information. - test Run OPA test with Regula. - version Print version information. - write-test-inputs Persist dynamically-generated test inputs for use with other Rego interpreters -Flags: - -h, --help help for regula - -v, --verbose verbose output +This will: +1. Vendor dependencies (`go mod vendor`) +2. Apply WASI patches from `patches/` directory +3. Build `regula.wasm` (121MB) -Use "regula [command] --help" for more information about a command. +### Running Tests + +```bash +# Go tests +make test + +# npm tests (requires WASI build) +npm test # Basic API tests +npm run test:wasi # Parity tests vs native binary ``` -For details about each command, including examples, see [Usage](https://regula.dev/usage.html). +--- + +## License -## For more information +Apache 2.0 - See [LICENSE](LICENSE) -Visit [regula.dev](https://regula.dev) for more information about Regula, including: +Originally created by [Fugue, Inc.](https://fugue.co) -- [Regula's report output](https://regula.dev/report.html) -- [Integrations](https://regula.dev/integrations/conftest.html) -- [Writing](https://regula.dev/development/writing-rules.html) and [testing](https://regula.dev/development/testing-rules.html) custom rules -- [Configuring waivers and disabling rules](https://regula.dev/configuration.html) -- and more! +--- +## Links -[opa]: https://www.openpolicyagent.org/ -[fregot]: https://github.com/fugue/fregot -[CloudFormation]: https://docs.aws.amazon.com/cloudformation/ -[Terraform]: https://www.terraform.io/ -[Rego]: https://www.openpolicyagent.org/docs/latest/policy-language/ -[Fugue Custom Rules]: https://docs.fugue.co/rules.html -[Conftest]: https://github.com/open-policy-agent/conftest +- [Original Documentation](https://regula.dev) (may be outdated) +- [Original Repository](https://github.com/fugue/regula) (archived) +- [This Fork](https://github.com/nonfx/regula) +- [npm Package](https://www.npmjs.com/package/regula-wasi) From 1f3cc00c37fe3e7c596147683df1b2294f1063b3 Mon Sep 17 00:00:00 2001 From: Nikhil Verma Date: Wed, 4 Feb 2026 18:51:15 +0530 Subject: [PATCH 5/7] Address code review feedback - fsnotify: Return ErrNotSupported instead of nil for unsupported methods - cli.js: Add comment explaining why preopens '/' is necessary - index.js: Remove misleading format option from docs, add noBuiltIns/noIgnore/varFiles options - Remove unused patches (go-systemd, terraform.patch) - Update build script to remove go-systemd reference Co-Authored-By: Claude Opus 4.5 --- build-wasi.sh | 2 - cli.js | 3 + index.js | 27 ++- patches/coreos/go-systemd/journal/journal.go | 226 ------------------- patches/fsnotify/fsnotify/backend_other.go | 13 +- patches/terraform.patch | 109 --------- 6 files changed, 34 insertions(+), 346 deletions(-) delete mode 100644 patches/coreos/go-systemd/journal/journal.go delete mode 100644 patches/terraform.patch diff --git a/build-wasi.sh b/build-wasi.sh index 38db617e..7accadb0 100755 --- a/build-wasi.sh +++ b/build-wasi.sh @@ -28,8 +28,6 @@ apply_patch patches/spf13/afero/const_win_unix.go vendor/github.com/spf13/afero/ apply_patch patches/sirupsen/logrus/terminal_check_appengine.go vendor/github.com/sirupsen/logrus/terminal_check_appengine.go apply_patch patches/sirupsen/logrus/terminal_check_notappengine.go vendor/github.com/sirupsen/logrus/terminal_check_notappengine.go -apply_patch patches/coreos/go-systemd/journal/journal.go vendor/github.com/coreos/go-systemd/journal/journal.go - apply_patch patches/fsnotify/fsnotify/backend_other.go vendor/github.com/fsnotify/fsnotify/backend_other.go apply_patch patches/chzyer/readline/term.go vendor/github.com/chzyer/readline/term.go diff --git a/cli.js b/cli.js index bbc24f29..50b17d3c 100755 --- a/cli.js +++ b/cli.js @@ -10,6 +10,9 @@ const __dirname = dirname(__filename); const args = process.argv.slice(2); +// Note: preopens "/" is required because regula needs to read IaC files from +// any path the user specifies (including absolute paths like /home/user/terraform/). +// This is expected behavior for a CLI tool that processes user-specified file paths. const wasi = new WASI({ version: "preview1", args: ["regula", ...args], diff --git a/index.js b/index.js index 9e399502..1203fd88 100644 --- a/index.js +++ b/index.js @@ -6,19 +6,22 @@ const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); /** - * Run regula on the specified path(s) + * Run regula on the specified path(s) and return parsed JSON results. * @param {string|string[]} paths - Path(s) to IaC files or directories * @param {Object} options - Optional configuration * @param {string} options.inputType - Input type: auto, tf, tf-plan, cfn, k8s, arm - * @param {string} options.format - Output format: json, text, table, sarif, junit, tap * @param {string[]} options.include - Additional rego files to include * @param {string[]} options.only - Only run specific rules * @param {string[]} options.exclude - Exclude specific rules - * @returns {Promise} - Regula output + * @param {boolean} options.noBuiltIns - Disable built-in rules (use only custom rules from include) + * @param {boolean} options.noIgnore - Disable .gitignore filtering + * @param {string[]} options.varFiles - Terraform variable files to use + * @returns {Promise} - Parsed regula output with rule_results and summary */ export async function runRegula(paths, options = {}) { const pathArray = Array.isArray(paths) ? paths : [paths]; + // Always use JSON format for programmatic parsing const args = ["run", "--format", "json"]; if (options.inputType) { @@ -46,6 +49,21 @@ export async function runRegula(paths, options = {}) { } } + if (options.noBuiltIns) { + args.push("--no-built-ins"); + } + + if (options.noIgnore) { + args.push("--no-ignore"); + } + + if (options.varFiles) { + const varFiles = Array.isArray(options.varFiles) ? options.varFiles : [options.varFiles]; + for (const varFile of varFiles) { + args.push("--var-file", varFile); + } + } + args.push(...pathArray); return new Promise((resolve, reject) => { @@ -71,7 +89,8 @@ export async function runRegula(paths, options = {}) { } /** - * Validate IaC files and return rule results + * Validate IaC files and return rule results. + * Alias for runRegula(). * @param {string|string[]} paths - Path(s) to IaC files or directories * @param {Object} options - Optional configuration * @returns {Promise} - Object with rule_results and summary diff --git a/patches/coreos/go-systemd/journal/journal.go b/patches/coreos/go-systemd/journal/journal.go deleted file mode 100644 index b5f54363..00000000 --- a/patches/coreos/go-systemd/journal/journal.go +++ /dev/null @@ -1,226 +0,0 @@ -// Copyright 2015 CoreOS, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Package journal provides write bindings to the local systemd journal. -// It is implemented in pure Go and connects to the journal directly over its -// unix socket. -// -// To read from the journal, see the "sdjournal" package, which wraps the -// sd-journal a C API. -// -// http://www.freedesktop.org/software/systemd/man/systemd-journald.service.html -package journal - -import ( - "bytes" - "encoding/binary" - "errors" - "fmt" - "io" - "io/ioutil" - "net" - "os" - "strconv" - "strings" - "sync" - "sync/atomic" - "syscall" - "unsafe" -) - -// Priority of a journal message -type Priority int - -const ( - PriEmerg Priority = iota - PriAlert - PriCrit - PriErr - PriWarning - PriNotice - PriInfo - PriDebug -) - -var ( - // This can be overridden at build-time: - // https://github.com/golang/go/wiki/GcToolchainTricks#including-build-information-in-the-executable - journalSocket = "/run/systemd/journal/socket" - - // unixConnPtr atomically holds the local unconnected Unix-domain socket. - // Concrete safe pointer type: *net.UnixConn - unixConnPtr unsafe.Pointer - // onceConn ensures that unixConnPtr is initialized exactly once. - onceConn sync.Once -) - -func init() { - onceConn.Do(initConn) -} - -// Enabled checks whether the local systemd journal is available for logging. -func Enabled() bool { - onceConn.Do(initConn) - - if (*net.UnixConn)(atomic.LoadPointer(&unixConnPtr)) == nil { - return false - } - - if _, err := net.Dial("unixgram", journalSocket); err != nil { - return false - } - - return true -} - -// Send a message to the local systemd journal. vars is a map of journald -// fields to values. Fields must be composed of uppercase letters, numbers, -// and underscores, but must not start with an underscore. Within these -// restrictions, any arbitrary field name may be used. Some names have special -// significance: see the journalctl documentation -// (http://www.freedesktop.org/software/systemd/man/systemd.journal-fields.html) -// for more details. vars may be nil. -func Send(message string, priority Priority, vars map[string]string) error { - conn := (*net.UnixConn)(atomic.LoadPointer(&unixConnPtr)) - if conn == nil { - return errors.New("could not initialize socket to journald") - } - - socketAddr := &net.UnixAddr{ - Name: journalSocket, - Net: "unixgram", - } - - data := new(bytes.Buffer) - appendVariable(data, "PRIORITY", strconv.Itoa(int(priority))) - appendVariable(data, "MESSAGE", message) - for k, v := range vars { - appendVariable(data, k, v) - } - - _, _, err := conn.WriteMsgUnix(data.Bytes(), nil, socketAddr) - if err == nil { - return nil - } - if !isSocketSpaceError(err) { - return err - } - - // Large log entry, send it via tempfile and ancillary-fd. - file, err := tempFd() - if err != nil { - return err - } - defer file.Close() - _, err = io.Copy(file, data) - if err != nil { - return err - } - // @nonfx - Disabled for wasip1 compilation - // rights := syscall.UnixRights(int(file.Fd())) - // _, _, err = conn.WriteMsgUnix([]byte{}, rights, socketAddr) - // if err != nil { - // return err - // } - - return nil -} - -// Print prints a message to the local systemd journal using Send(). -func Print(priority Priority, format string, a ...interface{}) error { - return Send(fmt.Sprintf(format, a...), priority, nil) -} - -func appendVariable(w io.Writer, name, value string) { - if err := validVarName(name); err != nil { - fmt.Fprintf(os.Stderr, "variable name %s contains invalid character, ignoring\n", name) - } - if strings.ContainsRune(value, '\n') { - /* When the value contains a newline, we write: - * - the variable name, followed by a newline - * - the size (in 64bit little endian format) - * - the data, followed by a newline - */ - fmt.Fprintln(w, name) - binary.Write(w, binary.LittleEndian, uint64(len(value))) - fmt.Fprintln(w, value) - } else { - /* just write the variable and value all on one line */ - fmt.Fprintf(w, "%s=%s\n", name, value) - } -} - -// validVarName validates a variable name to make sure journald will accept it. -// The variable name must be in uppercase and consist only of characters, -// numbers and underscores, and may not begin with an underscore: -// https://www.freedesktop.org/software/systemd/man/sd_journal_print.html -func validVarName(name string) error { - if name == "" { - return errors.New("Empty variable name") - } else if name[0] == '_' { - return errors.New("Variable name begins with an underscore") - } - - for _, c := range name { - if !(('A' <= c && c <= 'Z') || ('0' <= c && c <= '9') || c == '_') { - return errors.New("Variable name contains invalid characters") - } - } - return nil -} - -// isSocketSpaceError checks whether the error is signaling -// an "overlarge message" condition. -func isSocketSpaceError(err error) bool { - opErr, ok := err.(*net.OpError) - if !ok || opErr == nil { - return false - } - - sysErr, ok := opErr.Err.(*os.SyscallError) - if !ok || sysErr == nil { - return false - } - - return sysErr.Err == syscall.EMSGSIZE || sysErr.Err == syscall.ENOBUFS -} - -// tempFd creates a temporary, unlinked file under `/dev/shm`. -func tempFd() (*os.File, error) { - file, err := ioutil.TempFile("/dev/shm/", "journal.XXXXX") - if err != nil { - return nil, err - } - err = syscall.Unlink(file.Name()) - if err != nil { - return nil, err - } - return file, nil -} - -// initConn initializes the global `unixConnPtr` socket. -// It is meant to be called exactly once, at program startup. -func initConn() { - autobind, err := net.ResolveUnixAddr("unixgram", "") - if err != nil { - return - } - - sock, err := net.ListenUnixgram("unixgram", autobind) - if err != nil { - return - } - - atomic.StorePointer(&unixConnPtr, unsafe.Pointer(sock)) -} diff --git a/patches/fsnotify/fsnotify/backend_other.go b/patches/fsnotify/fsnotify/backend_other.go index df82542b..faffe17c 100644 --- a/patches/fsnotify/fsnotify/backend_other.go +++ b/patches/fsnotify/fsnotify/backend_other.go @@ -4,6 +4,9 @@ package fsnotify import "errors" +// ErrNotSupported is returned when fsnotify is not supported on the current platform. +var ErrNotSupported = errors.New("fsnotify not supported on the current platform") + type other struct { Events chan Event Errors chan error @@ -12,11 +15,11 @@ type other struct { var defaultBufferSize = 0 func newBackend(ev chan Event, errs chan error) (backend, error) { - return nil, errors.New("fsnotify not supported on the current platform") + return nil, ErrNotSupported } -func (w *other) Close() error { return nil } +func (w *other) Close() error { return ErrNotSupported } func (w *other) WatchList() []string { return nil } -func (w *other) Add(name string) error { return nil } -func (w *other) AddWith(name string, opts ...addOpt) error { return nil } -func (w *other) Remove(name string) error { return nil } +func (w *other) Add(name string) error { return ErrNotSupported } +func (w *other) AddWith(name string, opts ...addOpt) error { return ErrNotSupported } +func (w *other) Remove(name string) error { return ErrNotSupported } func (w *other) xSupports(op Op) bool { return false } diff --git a/patches/terraform.patch b/patches/terraform.patch deleted file mode 100644 index 6c2c3672..00000000 --- a/patches/terraform.patch +++ /dev/null @@ -1,109 +0,0 @@ -diff --git a/pkg/terraform/configs/configload/loader_snapshot.go b/pkg/terraform/configs/configload/loader_snapshot.go -index 243939f..6ca8b4f 100644 ---- a/pkg/terraform/configs/configload/loader_snapshot.go -+++ b/pkg/terraform/configs/configload/loader_snapshot.go -@@ -325,6 +325,10 @@ func (fs snapshotFS) Chmod(name string, mode os.FileMode) error { - return fmt.Errorf("cannot set file mode inside configuration snapshot") - } - -+func (fs snapshotFS) Chown(string, int, int) error { -+ return fmt.Errorf("cannot set file owner inside configuration snapshot") -+} -+ - func (fs snapshotFS) Chtimes(name string, atime, mtime time.Time) error { - return fmt.Errorf("cannot set file times inside configuration snapshot") - } -diff --git a/pkg/terraform/tfdiags/diagnostics.go b/pkg/terraform/tfdiags/diagnostics.go -index 30476ee..25cd135 100644 ---- a/pkg/terraform/tfdiags/diagnostics.go -+++ b/pkg/terraform/tfdiags/diagnostics.go -@@ -107,24 +107,6 @@ func (diags Diagnostics) HasErrors() bool { - return false - } - --// ForRPC returns a version of the receiver that has been simplified so that --// it is friendly to RPC protocols. --// --// Currently this means that it can be serialized with encoding/gob and --// subsequently re-inflated. It may later grow to include other serialization --// formats. --// --// Note that this loses information about the original objects used to --// construct the diagnostics, so e.g. the errwrap API will not work as --// expected on an error-wrapped Diagnostics that came from ForRPC. --func (diags Diagnostics) ForRPC() Diagnostics { -- ret := make(Diagnostics, len(diags)) -- for i := range diags { -- ret[i] = makeRPCFriendlyDiag(diags[i]) -- } -- return ret --} -- - // Err flattens a diagnostics list into a single Go error, or to nil - // if the diagnostics list does not include any error-level diagnostics. - // -diff --git a/pkg/terraform/tfdiags/rpc_friendly.go b/pkg/terraform/tfdiags/rpc_friendly.go -deleted file mode 100644 -index 485063b..0000000 ---- a/pkg/terraform/tfdiags/rpc_friendly.go -+++ /dev/null -@@ -1,59 +0,0 @@ --package tfdiags -- --import ( -- "encoding/gob" --) -- --type rpcFriendlyDiag struct { -- Severity_ Severity -- Summary_ string -- Detail_ string -- Subject_ *SourceRange -- Context_ *SourceRange --} -- --// rpcFriendlyDiag transforms a given diagnostic so that is more friendly to --// RPC. --// --// In particular, it currently returns an object that can be serialized and --// later re-inflated using gob. This definition may grow to include other --// serializations later. --func makeRPCFriendlyDiag(diag Diagnostic) Diagnostic { -- desc := diag.Description() -- source := diag.Source() -- return &rpcFriendlyDiag{ -- Severity_: diag.Severity(), -- Summary_: desc.Summary, -- Detail_: desc.Detail, -- Subject_: source.Subject, -- Context_: source.Context, -- } --} -- --func (d *rpcFriendlyDiag) Severity() Severity { -- return d.Severity_ --} -- --func (d *rpcFriendlyDiag) Description() Description { -- return Description{ -- Summary: d.Summary_, -- Detail: d.Detail_, -- } --} -- --func (d *rpcFriendlyDiag) Source() Source { -- return Source{ -- Subject: d.Subject_, -- Context: d.Context_, -- } --} -- --func (d rpcFriendlyDiag) FromExpr() *FromExpr { -- // RPC-friendly diagnostics cannot preserve expression information because -- // expressions themselves are not RPC-friendly. -- return nil --} -- --func init() { -- gob.Register((*rpcFriendlyDiag)(nil)) --} From d638ec99de24d6ee018c02c7e0e531992f5d4e34 Mon Sep 17 00:00:00 2001 From: Nikhil Verma Date: Wed, 4 Feb 2026 18:52:40 +0530 Subject: [PATCH 6/7] Bump version to 3.2.3 for npm publish Co-Authored-By: Claude Opus 4.5 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 69d4919d..58607703 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "regula-wasi", - "version": "3.2.2", + "version": "3.2.3", "description": "Infrastructure as Code security and compliance evaluation tool (WASI build). Fork of fugue/regula with security patches.", "type": "module", "main": "index.js", From 43a95c74d8e9fd06960f7ae5c3e574c7d3a88c53 Mon Sep 17 00:00:00 2001 From: Nikhil Verma Date: Wed, 4 Feb 2026 18:53:13 +0530 Subject: [PATCH 7/7] Document all JS API options in README Co-Authored-By: Claude Opus 4.5 --- README.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/README.md b/README.md index c03edb29..28db9013 100644 --- a/README.md +++ b/README.md @@ -79,6 +79,9 @@ const result = await runRegula('./main.tf', { include: ['./custom-rules/'], only: ['FG_R00229'], // Only run specific rules exclude: ['FG_R00100'], // Exclude specific rules + noBuiltIns: false, // Disable built-in rules (use only custom rules) + noIgnore: false, // Disable .gitignore filtering + varFiles: ['./prod.tfvars'], // Terraform variable files }); // Check for failures @@ -88,6 +91,18 @@ if (result.summary.rule_results.FAIL > 0) { } ``` +#### API Options + +| Option | Type | Description | +|--------|------|-------------| +| `inputType` | string | Input type: `auto`, `tf`, `tf-plan`, `cfn`, `k8s`, `arm` | +| `include` | string[] | Additional rego rule files/directories to include | +| `only` | string[] | Only run these specific rule IDs | +| `exclude` | string[] | Exclude these specific rule IDs | +| `noBuiltIns` | boolean | Disable built-in rules (use only custom rules from `include`) | +| `noIgnore` | boolean | Disable .gitignore filtering | +| `varFiles` | string[] | Terraform variable files (.tfvars) to use | + ### Prebuilt Binary Download from [Releases](https://github.com/nonfx/regula/releases) for your platform.