Unify runtime protection on the vendored node-waf lineage (+ TanStack server-function guard)#43
Merged
Merged
Conversation
patchstack-connect protect [--manifest] scaffolds the WAF guard into a TanStack Start + Supabase app (engine, guard, rules, manifest), patches the generated Supabase client + Start entry idempotently, and wires a manifest refresh into prebuild. --manifest regenerates the package manifest only. The guard tunnels browser data traffic through an in-app server guard that runs the rule engine and blocks exploit payloads against known-vulnerable packages (virtual patching) with zero changes to the user's own code.
…sses tsc Lovable's build type-checks; guard.ts imported ./engine.js and ./manifest.js (plain JS, no declarations) -> TS7016. Ship .d.ts for both, type the rules cast as Rule[], and copy templates post-build (tsup's dts pass was clobbering the .d.ts when copied via onSuccess). Verified: fresh scaffold -> tsc clean.
…a explicit env) — 0.2.10
…untime protection (0.3.0) Merges ps-node's protection into @patchstack/connect so a vibe app installs ONE package: - Vendors the node-waf RuleEngine + adapters, createProtection, and the Supabase-tunnel guard into src/protect/, exported as @patchstack/connect/protect. - `patchstack-connect protect` now scaffolds a thin guard that imports @patchstack/connect/protect (no vendored engine files in the app, no local manifest). - Real engine (rule_v2, inline_xss) with rules from the Patchstack API (cached) + a bundled fallback. Always-on by default; PATCHSTACK_MODE=dry-run for log-only. Replaces the earlier stopgap hand-rolled engine. 116 tests pass (3 new protect tests). main is untouched; pulse-protect-command branch + its releases kept for rollback.
…pes (0.3.1)
Modern Lovable apps mutate data via TanStack server functions (createServerFn) using a
server-side Supabase client, which bypasses the browser-client tunnel the guard patched — so
exploit payloads reached the DB. Register the guard on functionMiddleware too:
- runtime: createServerFnGuard({protection}) — inspects decoded server-fn args via the same
fetchGuard policy (args become the request body; engine resolves post.<field> identically).
- guard.ts template: shared protection + inspectServerFn(); handleGuardRequest unchanged.
- install.ts: patchStart registers patchstackFunctionGuard in functionMiddleware (adds the key
if absent), alongside the existing requestMiddleware tunnel. Idempotent, no user code touched.
- ship hand-authored dist/protect.d.ts + add "types" to the ./protect export (removes the
.d.ts shim strict-TS builds needed).
- tests: +2 server-fn guard cases (118 total).
Covers both Lovable data shapes (browser-direct AND server functions), fully installer-driven.
… 0.3.2 The single-marker idempotency check (skip if patchstackGuard present) meant re-running protect after a connect upgrade silently did nothing — so an app wired by 0.3.0 never gained the new server-function guard. Rework patchStart to reconcile each piece independently: extend the guard import, add each middleware definition, and register each guard only when absent. Re-running now adds exactly what's missing (verified: 0.3.0-wired app gains patchstackFunctionGuard with no duplication; a second run is a no-op).
…lineage Two 0.3.x protect lineages had diverged. main (0.3.3, #36-#41) advanced the scaffold-engine + local-manifest/--manifest approach; this branch vendored the node-waf engine into the package (@patchstack/connect/protect) and added the TanStack server-function guard. This takes the vendored lineage as canonical: - scaffolds only guard.ts + rules.json (the WAF engine ships in the package) - protect wires BOTH request middleware (browser tunnel) AND function middleware (TanStack server functions); per-piece idempotent so upgrades reconcile cleanly - drops the scaffolded engine.js/manifest.js templates and the --manifest flag (the vendored engine handles package-conditional rules via the API/rules) Preserves all of main's non-protect advances: in-package install guide, mark-build build-stack descriptor, tag-driven release workflow, guide command, verify-first install prompt. Typecheck clean; 126 tests pass.
|
Comprehensive vendored runtime protection with clear modular adapters and rich features. 🎯 Quality: 60% Average · 📦 Size: Oversized — strongly consider breaking this down 🛡️ Standards: no pre-flight fit check ran for this change — wire 📈 This month: Your 57th PR — above team average · Averaging Good |
Contributor
Author
|
/review |
ejntaylor
approved these changes
Jul 13, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Unify the connector's runtime-protection lineage on the vendored node-waf engine, and add the TanStack server-function guard so
protectcovers both ways a Lovable app talks to its database.Why
Validating the runtime guard on a fresh Lovable app surfaced a real gap: modern Lovable scaffolds mutate data through TanStack server functions (
createServerFn) using a server-side Supabase client, which bypasses the browser-client tunnel the guard patched. A stored-XSSmarkedpayload sailed through and was saved. Fixed by also registering the guard as a function middleware.Separately, two 0.3.x lineages diverged on npm:
@patchstack/connect/protect, server-function guard, per-piece idempotentlatest)main(#36–#41)engine.js/manifest.js,--manifest, request middleware only0.3.3becamelatestand regressed the server-function fix. This PR lands the vendored lineage onmainsomainis canonical and av0.3.4tag supersedes0.3.3with the fix included.What this changes
RuleEngineships inside the package (@patchstack/connect/protect); the guard scaffolds onlyguard.ts+rules.json(noengine.js/manifest.jsin the user's app).protectwiressrc/start.tsas both a request middleware (browser→Supabase tunnel) and a function middleware (patchstackFunctionGuard→ inspects server-function args). Same block/dry-run/fail-open policy on both paths.patchStart: re-runningprotect(incl. after an upgrade) reconciles only what's missing — no duplication, no silent skip.typesfor the./protectsubpath.--manifestflag and the scaffoldedengine.js/manifest.jstemplates.Preserved from
main(nothing reverted)In-package install guide (
AGENT-INSTALL.md, #38), mark-build build-stack descriptor (#35), tag-driven release workflow (#39/#40), theguideCLI command, and the verify-first install prompt (#41).package.jsonstays at the0.2.11base (release version comes from the tag).Decision for review (@ejntaylor)
The main trade-off: this retires the scaffolded local
manifest.js+package_condmechanism you advanced in the 0.3.3 line. The vendored engine still supports package-conditional rules — but sourced from the Patchstack rules API (or the bundled fallback) rather than a manifest file generated into the user's app. If you want the local-manifest precision kept as well, we can fold it back in; flagging so it's a conscious call, not a silent drop.Validation
<img src=x onerror="window.__ps_pwn_2026=1">that got stored pre-fix is refused post-fix (server function throws the WAF receipt, task never saved, marker never set); a benign task still saves.Release
Tag-driven: after merge, cut
v0.3.4to publish alatestthat contains the server-function guard (superseding0.3.3).