Gold-standard safe Lua 5.1 library demonstrating defensive programming patterns. Designed as a reference implementation verified by PMAT CB-600 compliance checks.
| Metric | Value |
|---|---|
| Modules | 6 |
| Tests | 251 (195 unit + 56 adversarial) |
| Coverage | 95%+ on all lib/ modules |
| CB-600 Compliance | 8/8 checks (CB-600 through CB-607) |
| Lint Warnings | 0 (luacheck + selene) |
| SATD | 0 (no TODO/FIXME/HACK/XXX) |
| Bugs Found via Falsification | 5 fixed |
The full reference book is available at https://paiml.github.io/safe-lua-groundtruth (deployed via GitHub Pages on tag push).
Build locally:
make book # build to book/output/
make book-serve # serve locally with hot reloadRequires Lua 5.1 and LuaRocks:
# Clone the repository
git clone https://github.com/paiml/safe-lua-groundtruth.git
cd safe-lua-groundtruth
# Install dependencies
luarocks install busted
luarocks install luacheck
luarocks install luacov
# Verify installation
make checkAdd lib/ to your package path and require modules individually:
package.path = "lib/?.lua;" .. package.path
local guard = require("safe.guard")
local log = require("safe.log")
local validate = require("safe.validate")Run quality gates:
make check # lint + format check + tests
make coverage # 95% minimum coverage on lib/
make bench # performance benchmarks
make examples # run all example programsEach module is required individually:
local guard = require("safe.guard")
local log = require("safe.log")
local validate = require("safe.validate")
local shell = require("safe.shell")
local perf = require("safe.perf")
local helpers = require("safe.test_helpers")Nil-safe access, type contracts, frozen tables, global protection.
-- Nil-safe chained access (never throws)
local name = guard.safe_get(config, "database", "primary", "host")
-- Type contracts
guard.assert_type(port, "number", "port")
guard.assert_not_nil(config, "config")
-- Frozen tables (read-only)
local COLORS = guard.enum({ "RED", "GREEN", "BLUE" })
-- Global protection (errors on undeclared globals)
guard.protect_globals(_G)Level-gated logging with injectable output and timestamps.
log.set_level(log.DEBUG)
log.set_context("myapp")
log.info("Started server on port %d", 8080)
-- Child loggers with preset context
local db_log = log.with_context("database")
db_log.warn("Connection pool exhausted")Non-throwing checks with error accumulation.
-- Individual checks return ok, err
local ok, err = validate.check_range(port, 1, 65535, "port")
-- Accumulate multiple checks
local c = validate.Checker:new()
c:check_type(name, "string", "name")
:check_range(age, 0, 150, "age")
:check_one_of(role, {"admin", "user"}, "role")
c:assert() -- throws with all errors joined
-- Schema validation
local ok, result = validate.schema(input, {
name = { type = "string", required = true },
age = { type = "number", default = 0 },
})Argument-array based command building with proper escaping.
-- Never build commands from raw strings
local ok, code = shell.exec("grep", { "-r", "pattern", "/path" })
local ok, output = shell.capture("date", { "+%Y-%m-%d" })
-- Escaping
shell.escape("it's") --> 'it'\''s'Demonstrates Lua 5.1 performance best practices.
-- Gold standard: table.concat
local result = perf.concat_safe({ "a", "b", "c" })
-- GC-friendly table reuse
perf.reuse_table(buffer, 1000)
-- Cached string.format over lists
local labels = perf.format_many("item_%d", { 1, 2, 3 })Mock factories, temp files, and assertion helpers.
-- Mock shell executor
local exec, calls = helpers.mock_executor({{ true, 0 }})
shell._executor = exec
-- Capture io.write output
local output = helpers.capture_output(function()
io.write("hello")
end)
-- Temp file with automatic cleanup
helpers.with_temp_file("content", function(path)
-- use path, file is cleaned up after
end)| Check | Description | Demonstrated In |
|---|---|---|
| CB-600 | Implicit globals | guard.protect_globals |
| CB-601 | Nil-unsafe access | guard.safe_get, guard.assert_not_nil |
| CB-602 | pcall handling | test_helpers.capture_output |
| CB-603 | Dangerous APIs | shell.exec, shell.capture (with annotations) |
| CB-604 | Unused variables | All modules (enforced by luacheck + selene) |
| CB-605 | String concat in loops | perf.concat_safe vs perf.concat_unsafe |
| CB-606 | Missing module return | All modules return M |
| CB-607 | Colon/dot confusion | validate.Checker (documented colon usage) |
- Linting: luacheck (zero warnings) + selene (all rules deny)
- Formatting: stylua (120 cols, 4-space indent, double quotes)
- Testing: busted test framework
- Coverage: 95% minimum on
lib/via luacov - SATD: Zero TODO/FIXME/HACK/XXX in lib/ and spec/
- Fork the repository
- Run
make checkto verify the baseline passes - Make changes in
lib/safe/with corresponding tests inspec/ - Ensure
make checkandmake coveragepass (95% minimum) - Submit a pull request
All contributions must pass: zero luacheck warnings, zero selene warnings,
stylua formatting, and 95% test coverage on lib/.
MIT