This document summarizes what has been completed so far and provides a detailed, actionable checklist of remaining work to follow the plan in .github/prompts/plan-nativeCppScriptingEngine.prompt.md.
-
Project scaffolding and repository metadata
- Added
CMakeLists.txt(top-level) with C++20 defaults and Ninja-friendly configuration - Created
README.md,LICENSE(MIT), and.gitignore - CI skeleton:
.github/workflows/ci.yml(basic CMake/Ninja job)
- Added
-
Basic code structure and AoT runtime stubs
src/main.cpp— entry point, run loop, subsystem initialization- Subsystem stubs:
src/engine/engine.h,src/engine/engine.cpp(JIT scaffold)src/sandbox/sandbox.h,src/sandbox/sandbox.cpp(Landlock/seccomp stubs)src/services/services.h,src/services/services.cpp(SQLite, MailApp, PropertyStore stubs)
-
Configuration and scripts
config/server.yaml(placeholder server settings)config/syscalls.conf(placeholder seccomp whitelist)scripts/README.md(user script layout)
-
Build/test attempts
- Local build attempted in CI style, but
cmakeis not installed in the current environment (build step aborted withcmake: command not found).- Added a reproducible Docker-based dev image (
Dockerfile.dev) and a small helper script atscripts/dev_setup.shto build and run the image locally.
- Added a reproducible Docker-based dev image (
- Local build attempted in CI style, but
Additional completed items (implementation work)
- Prototype Admin UI:
src/web/ui/index.html(static SPA placeholder). ✅ - Prototype HTTP static server:
src/web/simple_http.{h,cpp}andsrc/web/static_server.*, wired intomainand servingsrc/web/uion port 8081. ✅ - Graceful shutdown (SIGINT/SIGTERM handling) in
src/main.cpp. ✅ /api/statusendpoint that reports uptime and subsystem health (engine/services). ✅- Subsystem health API additions:
engine::is_initialized()andservices::is_initialized(). ✅ - Integration test:
tests/api_status_test.shand CI step to run it. ✅ - Updated
CMakeLists.txtto includesrc/webandsrc/triggerssources. ✅
- Add
third_party/layout and submodule strategy document (LLVM, Drogon, SQLite, mailio, libcron) - Add reproducible build instructions for local dev (docker or dev script that ensures musl toolchain, CMake >= 3.22, Ninja)
- Improve CI to build dependencies (split job: deps build, core build, unit tests)
- Add
CONTRIBUTING.mdwith developer workflow and Docker dev image usage (new) - Add Docker-based dev image and helper script (see
Dockerfile.dev,scripts/dev_setup.sh) - Improve CI to build dependencies (split job: deps build, core build, unit tests)
- Evaluate
ClingvsClangREPL— ClangREPL chosen (see notes) - Add
third_party/llvm/submodule or FetchContent setup for minimal LLVM required for chosen JIT - Implement ClangREPL bootstrap:
- Minimal startup harness that preloads a small "runtime universe" header set
- Compile & execute a tiny user script (smoke test)
- Measure cold start and aim for <100ms baseline (profiling harness)
- Add CMake targets to optionally build the JIT tooling and unit test harness
Notes / next steps (JIT): We chose ClangREPL (LLVM 16+) as the JIT backend for the project. The concrete next steps for contributors:
- Add
third_party/llvm/via git submodule or useFetchContentin CMake to fetch a minimal LLVM build configured with-DLLVM_TARGETS_TO_BUILD=\"host\"and-DLLVM_BUILD_TOOLS=OFF. - Create an
engine/jit_bootstrap.cppwith a minimal ClangREPL harness that:- Preloads commonly used headers (iostream, string, vector, ) into the REPL session.
- Compiles and runs a simple snippet (e.g.,
std::cout << "hello";) as a smoke test.
- Add a
CMakeoption-DENGINE_JIT=ONto build and run the harness during CI for smoke tests.
- Implement Landlock wrapper (C++):
- Runtime kernel capability check (detect <5.13 and fail if missing)
- Ruleset builder and per-script rules application
- Unit tests and integration tests (requires kernel with Landlock)
- Implement Seccomp-BPF loader that reads
config/syscalls.conf - Implement cgroups v2 integration for ephemeral execution cgroups (CPU, memory, pids)
- Decide and implement fallback policy for older kernels (strict logging fallback vs. hard requirement)
Notes / next steps (Sandbox): The repository contains a sandbox stub; next actions for implementers:
- Implement a runtime detection helper that calls
landlock_create_ruleset(or checks/proc/self/attravailability) and returns a clearly documented capability flag. Add an APIsandbox::is_landlock_available(). - Implement a
RulesetBuilderthat reads a JSON/YAML policy (paths + access flags) and applies the Landlock ruleset for the current process before running user code. - Provide a conservative fallback mode when Landlock is not available: deny all write attempts by default, enforce strict seccomp policy from
config/syscalls.conf, and log the degraded mode clearly in startup logs. Document that Landlock is recommended for production.
Updates: A sample policy file has been added at config/landlock_policy.conf (format: <path> <ro|rw>). The sandbox::apply_default_policy() routine now attempts to load this file and applies the configured per-path rules via the RulesetBuilder. If the file is absent, a default minimal ruleset is created and applied. Remember: Landlock is a hard requirement (kernel ≥5.13); the process will abort startup if Landlock is unavailable.
Seccomp update: Added support to load a seccomp syscall whitelist from config/syscalls.conf (one syscall name per line). A sample file config/syscalls.example.conf is provided. When libseccomp is available at compile time, the runtime will apply the whitelist after the Landlock ruleset. The conservative security posture is to require both Landlock and an applied seccomp whitelist for startup.
- SQLite wrapper with WAL and connection pooling
- MailApp wrapper over
mailioor chosen alternative (decide Boost strategy)- Evaluate statically vendoring Boost vs alternate lightweight SMTP library
- PropertyStore key-value API
- Quota tracking (per-script invocation/day limits, mail quotas)
- Add unit & integration tests for services
Notes / next steps (Services): To avoid heavy Boost dependency in early phases, prefer a lightweight SMTP prototype:
- Prototype MailApp over
libcurl's SMTP support or a minimal SMTP client implemented as a small internal module (only send mail, no IMAP). If more features are required later, re-evaluatemailio+Boost with static vendoring. - Implement
services/sqlite_pool.cppwith a small connection pool and WAL mode enabled; add tests that validate concurrent reads/writes. - Add
PropertyStorebacked by SQLite and expose a C++ API that is easy to use for scripts.
- Integrate Drogon (v1.9.x) or evaluate Oat++ (size tradeoffs)
- Implement request dispatcher to map HTTP endpoints to JIT handlers (
doGet/doPostcontract) - Implement HtmlService templating and streaming responses
- Integrate libcron for scheduled triggers and TriggerBuilder API
- Add tests and a small sample webapp in
scripts/webapps/for CI - Add tests and a small sample webapp in
scripts/webapps/for CI (addedtests/api_status_test.shsmoke test that verifies/api/status) Notes / next steps (Web): We've added a minimal prototype static server and SPA; next steps are: - Integrate Drogon behind a CMake option
-DWEB_FRAMEWORK=DROGONand provide example controllers that dispatch requests into the JIT engine. - Implement a request Event object passed to scripts with
doGet(Event)semantics and build a simpleDispatcherthat maps routes to compiled script handlers. - Add an administrative API for script lifecycle (upload, enable/disable, list, logs) and hook the SPA to these endpoints.
- Design single-page Admin UI (React/Vue/Vanilla) for managing scripts, triggers, and viewing logs/metrics
- Implement static asset serving and API endpoints for:
- script listing/upload/manage
- trigger scheduling and management
- logs and real-time status
- Add a small prototype SPA under
src/web/ui/index.html(done: placeholder UI) - Add tests that exercise the web UI endpoints and include a small sample app in
scripts/webapps/
Notes / next steps (Web UI): The prototype SPA exists; implementers should:
- Choose a small framework (Vanilla/Preact/Alpine) or keep the UI static for minimal runtime size.
- Add API endpoints (scripts, triggers, logs) and write integration tests that exercise the entire flow (upload → run → view logs).
- Consider embedding the SPA into the single binary (resource arrays) for single-binary distribution.
- Implement versioned module loader with semantic version resolution
- Final static build strategy:
- musl static link targets
- LTO and symbol visibility for size reduction
- Investigate final binary size target (~34MB) and measurement harness
- Cross compilation and minimal runtime packaging
Notes / next steps (Binary consolidation): For the final single-binary deliverable:
- Build dependencies statically into
.aarchives and link against musl; provide a documented Docker cross-build image that contains the musl toolchain and matching libc headers. - Enable LTO (
-flto),-ffunction-sections -fdata-sectionsand-Wl,--gc-sections, setCMAKE_EXE_LINKER_FLAGSappropriately, and usestripto minimize size. Provide a reproducible measurement script that reports final binary size. - Carefully review LLVM linkage: minimize the LLVM surface area by building only required components and using
-DLLVM_TARGETS_TO_BUILD="host".
- API docs for script authors (auto-inclusion headers,
doGet/doPost,MailApp,PropertyStore) - Security policy docs for administrators (Landlock rules, seccomp whitelist guidance)
- Release/deployment notes and example Dockerfile for reproducible builds
These instructions are targeted at contributors who will implement the remaining phases.
- Install development tools:
cmake(>=3.22),ninja-build,clang,gcc,make,libssl-dev(for OpenSSL) andpkg-config. - Recommended: use the included Docker-based dev image (create one based on
debian:bookwormorubuntu:24.04) and installmusl-tools,build-essential,cmake,ninja-build, andclangto build static musl binaries.
Dev image (new): A Dockerfile.dev and a helper script scripts/dev_setup.sh were added to provide a reproducible development environment. Quick usage:
- Build the image:
./scripts/dev_setup.sh build - Start an interactive shell with the repo mounted:
./scripts/dev_setup.sh shell - Build inside the image:
./scripts/dev_setup.sh build-run
This addresses the earlier cmake: command not found issue and can be used both locally and in CI to ensure consistent tooling.
- Create a build dir:
cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Release - Build:
cmake --build build -j $(nproc) - Run the binary:
./build/native_node(UI served athttp://localhost:8081)
- Unit/integration test pattern: simple shell scripts under
tests/. - Run the api status test locally:
chmod +x tests/api_status_test.sh && ./tests/api_status_test.sh.
- Add
FetchContentor a submodule forllvmconfigured minimally (see notes above). - Add
src/engine/jit_bootstrap.cppthat starts a ClangREPL session and exposes a minimal API for evaluating snippets. - Protect JIT code behind CMake option
-DENGINE_JIT=ONand add a smoke test that runs during CI.
- Add
sandbox/detect.cppto exposesandbox::is_landlock_available(). - Implement
RulesetBuilderand a policy loader that reads JSON/YAML fromconfig/. - Implement the conservative fallback (strict seccomp + deny write) and document the security implications.
- Start with a small SMTP sender using
libcurl(no Boost). Add CMake option-DUSE_MAILIO=ONif switching tomailiolater. - Implement
services/sqlite_pool.cppand tests that validate WAL and concurrency.
- Integrate Drogon behind an option
-DWEB_FRAMEWORK=DROGONand provide example controllers. - Implement the request dispatcher (maps URL to
ScriptHandler), and test via the Admin UI. - Consider embedding static assets into the binary for single-binary distribution (e.g.,
xxd -ior a small resource compiler).
- Make CI build steps explicit: deps build, core build, run unit tests, run integration tests.
- Provide a
Dockerfile.devfor reproducible builds and cross-builds; add a CI job that runs builds inside that image.
- Create feature branches named
feat/<short-desc>orfix/<short-desc>; open PRs againstmainfor review. - Include tests for all non-trivial functionality and document configuration changes in
config/. - Keep commits small and focused; add a short description of design decisions when implementing security or JIT changes.
If you'd like, I can also add a CONTRIBUTING.md, a sample Dockerfile.dev, and CI changes to implement the recommended build pipeline next.
- Landlock requirement: should kernel ≥5.13 be a hard requirement, or should we provide a degraded fallback mode for older kernels?
- JIT backend: ClangREPL (chosen) (LLVM 16+).
- Mail library & Boost: should we statically vendor Boost (increase binary complexity), or choose a smaller SMTP library to avoid Boost?
- Landlock policy chosen: kernel ≥ 5.13 is a hard requirement (no degraded fallback mode).
- JIT backend chosen: ClangREPL (LLVM 16+).
- Add
third_party/and vendor minimal LLVM for the chosen JIT, and add CMake targets to build a small Cling/REPL test harness. - Add a Docker-based dev environment for reproducible builds (ensure
cmake,ninja, and toolchain for musl available).
Note: I attempted a local build as a smoke test;
cmakewas not available in the environment (error:cmake: command not found). Adding a Docker dev image or updating CI to include the dependencies will allow us to run the build jobs automatically.
Report generated by GitHub Copilot (Raptor mini (Preview)).
| Feature | Google Apps Script (GAS) | native_node (current repo) | Gap / Notes |
|---|---|---|---|
| Language & Execution Model | JavaScript (V8-based managed runtime) — instant edit/exec | C++ JIT (ClangREPL/LLVM planned) — aims for REPL/JIT | |
| REPL / Instant deploy | Built-in editor + instant deploy | Planned JIT REPL & instant deploy (engine scaffold) | |
| Web App endpoints (doGet/doPost) | First-class: deploy webapps easily | Static server exists; dispatcher → JIT planned (Drogon) | |
| HTML templating (HtmlService) | Yes (templating & sandboxing) | Planned (HtmlService in design) | ❌ Not implemented |
| Triggers / Scheduling | Time/event triggers built-in | Planned (libcron) | ❌ Not implemented |
| Mail (MailApp) | Integrated MailApp (SMTP) | Planned (Mail prototype via libcurl) | ❌ Not implemented |
| Persistence / Properties | PropertiesService, CacheService, integrated storage | Planned: SQLite + PropertyStore (stubs) | ❌ Not implemented |
| Sandboxing & Security | Host-managed JS sandbox and API quotas | Kernel-level sandboxing (Landlock + seccomp + cgroups) planned and partially implemented | ✅ Partial: Landlock REQUIRED and runtime detection implemented; RulesetBuilder skeleton + test added |
| Per-path filesystem rules | Very limited (managed environment) | Planned per-path Landlock rules (skeleton exists) | |
| Syscall & resource control | Enforced by GAS platform | Seccomp + cgroups planned | ❌ Seccomp & cgroups not implemented yet |
| Versioned libraries / modules | Library system with versions | Planned module loader (design only) | ❌ Not implemented |
| Quotas & limits per script | Built-in quota enforcement | Planned quota tracking (design) | ❌ Not implemented |
| Admin UI & management | Console + deployment tooling | Admin SPA placeholder (ui) | |
| Observability (logs/metrics) | Built-in logging and execution logs | Planned (logs + API) | ❌ Not implemented |
| Single-binary deployment | Not applicable (cloud service) | Aim: single static musl binary (option added) | MUSL_STATIC CMake option + docs added; CI build not yet done |
| Local & reproducible dev | No native local runtime emulation | Docker dev image + build scripts exist | ✅ Implemented (Docker dev image & scripts) |
| Cold-start / perf target | Managed, varies | Target <100ms cold start via JIT | ❌ Not yet measured; JIT not integrated |