@govplane/runtime-sdk 0.2.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,365 @@
1
+ # @govplane/runtime-sdk
2
+
3
+ Official **Govplane Runtime SDK** for Node.js.
4
+
5
+ The Govplane Runtime SDK is a **secure, production-grade client and policy engine** designed to consume **precompiled runtime governance bundles** and evaluate decisions **locally**, with **zero PII**, no exposed endpoints, and minimal operational risk.
6
+
7
+ It is intended for backend services, workers, gateways, and critical paths that must react to policy changes in near real-time without delegating decisions to a remote service.
8
+
9
+ ---
10
+
11
+ ## Design Principles
12
+
13
+ - ๐Ÿ”’ **No exposed endpoints** โ€“ no middleware, no inbound surface
14
+ - ๐Ÿง  **Local-first evaluation** โ€“ decisions are made in-process
15
+ - ๐Ÿงผ **Zero PII by design** โ€“ strict context validation and allowlists
16
+ - ๐Ÿ“ฆ **Precompiled policies** โ€“ no DSL or dynamic code at runtime
17
+ - ๐Ÿงฉ **Deterministic outcomes** โ€“ same input, same decision
18
+ - โšก **Cheap polling** โ€“ HEAD + ETag + conditional GET
19
+ - ๐Ÿงฏ **Failure-safe** โ€“ backoff, degraded mode, deny-by-default
20
+
21
+ ---
22
+
23
+ ## Key Capabilities
24
+
25
+ ### Runtime Client
26
+ - Efficient **HEAD-first polling** using `ETag` and `If-None-Match`
27
+ - In-memory bundle cache
28
+ - Automatic request de-duplication
29
+ - Configurable polling interval
30
+ - **Burst mode** for incident response
31
+ - **Exponential backoff with jitter**
32
+ - Automatic **degraded state**
33
+ - Status subscriptions (`ok` / `degraded`)
34
+
35
+ ### Policy Engine (SDK-only)
36
+ - Supports:
37
+ - `allow`
38
+ - `deny`
39
+ - `kill_switch`
40
+ - `throttle`
41
+ - **Deny-by-default**
42
+ - Kill-switch always wins
43
+ - Throttle selects the **most restrictive rule**
44
+ - Deterministic rule ordering
45
+ - Precompiled `when` AST evaluation
46
+ - No dynamic evaluation or code execution
47
+
48
+ ### Security & Context Safety
49
+ - Explicit context allowlist
50
+ - Unknown keys rejected (PII protection)
51
+ - Configurable limits:
52
+ - max string length
53
+ - max array length
54
+ - max depth
55
+ - Context policy is fully configurable per engine
56
+
57
+ ### Decision Trace / Explain (SDK-only)
58
+ - Optional decision trace generation
59
+ - Compact or full trace modes
60
+ - Sampling support (e.g. 1% in production)
61
+ - Force tracing for debugging
62
+ - Structured JSON trace output
63
+ - **Async trace sinks** (fire-and-forget)
64
+ - Bounded queues with drop strategies
65
+
66
+ ---
67
+
68
+ ## Requirements
69
+
70
+ - **Node.js โ‰ฅ 18**
71
+ - A valid **Govplane Runtime Key**
72
+ - Access to a Govplane Runtime API (`gp-runtime`)
73
+
74
+ ---
75
+
76
+ ## Installation
77
+
78
+ ```bash
79
+ npm install @govplane/runtime-sdk
80
+ ```
81
+
82
+ ---
83
+
84
+ ## Quick Start
85
+
86
+ ### 1. Create a Runtime Client
87
+
88
+ ```ts
89
+ import { RuntimeClient } from "@govplane/runtime-sdk";
90
+
91
+ const client = new RuntimeClient({
92
+ baseUrl: "https://runtime.govplane.com",
93
+ runtimeKey: process.env.GP_RUNTIME_KEY!,
94
+ orgId: "org_dev",
95
+ projectId: "prj_web",
96
+ env: "prod"
97
+ });
98
+
99
+ client.start();
100
+ ```
101
+
102
+ ### 2. Create a Policy Engine
103
+
104
+ ```ts
105
+ import { createPolicyEngine } from "@govplane/runtime-sdk";
106
+
107
+ const engine = createPolicyEngine({
108
+ getBundle: () => client.getCached().bundle,
109
+ validateContext: true,
110
+ contextPolicy: {
111
+ allowedKeys: [
112
+ "ctx.plan",
113
+ "ctx.country",
114
+ "ctx.amount",
115
+ "ctx.isAuthenticated"
116
+ ],
117
+ maxStringLen: 64,
118
+ maxArrayLen: 10
119
+ }
120
+ });
121
+ ```
122
+
123
+ ### 3. Evaluate a Decision
124
+
125
+ ```ts
126
+ const result = engine.evaluate({
127
+ target: {
128
+ service: "payments",
129
+ resource: "checkout",
130
+ action: "create"
131
+ },
132
+ context: {
133
+ plan: "pro",
134
+ country: "ES",
135
+ amount: 42,
136
+ isAuthenticated: true
137
+ }
138
+ });
139
+
140
+ console.log(result.decision); // allow | deny | throttle | kill_switch
141
+ ```
142
+
143
+ ---
144
+
145
+ ## Runtime Bundle Model
146
+
147
+ The SDK retrieves **materialized runtime bundles** generated by Govplane.
148
+
149
+ ```ts
150
+ type RuntimeBundleV1 = {
151
+ schemaVersion: 1;
152
+ orgId: string;
153
+ projectId: string;
154
+ env: string;
155
+ generatedAt: string;
156
+ policies: unknown[];
157
+ };
158
+ ```
159
+
160
+ The bundle is treated as **immutable and read-only**.
161
+
162
+ ---
163
+
164
+ ## Polling & Burst Mode
165
+
166
+ ```ts
167
+ // Force immediate refresh
168
+ await client.refreshNow();
169
+
170
+ // Temporarily increase polling frequency (e.g. incident response)
171
+ await client.refreshNow({ burst: true });
172
+ ```
173
+
174
+ Polling strategy:
175
+ 1. `HEAD /v1/runtime/bundle`
176
+ 2. Compare `ETag`
177
+ 3. If changed โ†’ `GET`
178
+ 4. If unchanged โ†’ no download, no JSON parse
179
+
180
+ ---
181
+
182
+ ## Backoff & Degraded Mode
183
+
184
+ On repeated failures, the client:
185
+ - Applies exponential backoff with jitter
186
+ - Enters **degraded** state after N failures
187
+ - Emits status updates
188
+
189
+ ```ts
190
+ client.onStatus((status) => {
191
+ if (status.state === "degraded") {
192
+ console.warn("Runtime degraded:", status);
193
+ }
194
+ });
195
+ ```
196
+
197
+ In degraded mode, cached bundles remain active.
198
+
199
+ ---
200
+
201
+ ## Runtime Incident Controls
202
+
203
+ During an incident (DDoS, fraud spike, abuse, misconfiguration), it may be necessary to:
204
+ - Force faster policy propagation
205
+ - Trigger immediate policy refresh
206
+ - Temporarily increase polling frequency (โ€œburst modeโ€)
207
+
208
+ Govplane Runtime SDK provides **passive incident controls** that allow operators to react to incidents **without exposing endpoints**, **without handling PII**, and **without recompiling application code**.
209
+
210
+ These controls are designed to be:
211
+ - Local-only
212
+ - Zero-network-surface
213
+ - Safe under active attack
214
+ - Compatible with containerized and orchestrated environments
215
+
216
+ ### Supported Incident Control Mechanisms
217
+
218
+ | Mechanism | Restart Required | Network Surface | Hot | Recommended |
219
+ |---------|------------------|-----------------|-----|-------------|
220
+ | Environment Variable | Usually yes | None | โŒ | โœ… |
221
+ | File-based Hot Reload | No | None | โœ… | โญ **Primary** |
222
+ | POSIX Signal (SIGUSR1) | No | None | โœ… | Optional |
223
+
224
+ ---
225
+
226
+ **Example: Environment Variable Incident Mode**
227
+
228
+ If the following environment variable is set, the Runtime SDK automatically enters **incident mode**:
229
+
230
+ ```bash
231
+ GP_RUNTIME_INCIDENT=1
232
+ ```
233
+
234
+ When detected:
235
+ โ€ข Burst polling is enabled
236
+ โ€ข Refresh cadence increases
237
+ โ€ข Degraded recovery is accelerated
238
+
239
+ Notes
240
+ โ€ข In most container platforms (ECS, Kubernetes), environment variables cannot be changed at runtime
241
+ โ€ข A rolling restart is usually required
242
+ โ€ข For zero-restart response, use File-based Hot Reload
243
+
244
+
245
+ **More details: [Govplane Runtime SDK โ€“ Runtime Incident Controls](docs/operations/Govplane_Runtime_Incident_Controls.md)**
246
+
247
+ ---
248
+
249
+ ## Throttle Decisions
250
+
251
+ ```ts
252
+ if (result.decision === "throttle") {
253
+ rateLimiter.apply(
254
+ result.throttle.key,
255
+ result.throttle.limit,
256
+ result.throttle.windowSeconds
257
+ );
258
+ }
259
+ ```
260
+
261
+ When multiple throttle rules match, the **most restrictive** one is selected.
262
+
263
+ ---
264
+
265
+ ## Decision Trace / Explain
266
+
267
+ ### Production (Sampled)
268
+
269
+ ```ts
270
+ const out = engine.evaluateWithTrace(
271
+ { target, context },
272
+ { sampling: 0.01, mode: "compact" }
273
+ );
274
+
275
+ if (out.trace) {
276
+ console.log(out.trace.summary);
277
+ }
278
+ ```
279
+
280
+ ### Debug (Forced)
281
+
282
+ ```ts
283
+ engine.evaluateWithTrace(
284
+ { target, context },
285
+ { force: true, mode: "full" }
286
+ );
287
+ ```
288
+
289
+ ### Trace Guarantees
290
+
291
+ - No rule bodies
292
+ - No context values
293
+ - No PII
294
+ - Deterministic structure
295
+
296
+ ---
297
+
298
+ ## Async Trace Sink
299
+
300
+ ```ts
301
+ engine.setTraceSink(
302
+ createAsyncTraceSink({
303
+ maxQueue: 100,
304
+ drop: "drop_new",
305
+ sink: async (event) => {
306
+ await fetch("https://trace-endpoint", {
307
+ method: "POST",
308
+ body: JSON.stringify(event)
309
+ });
310
+ }
311
+ })
312
+ );
313
+ ```
314
+
315
+ The sink:
316
+ - Never blocks evaluation
317
+ - Never throws
318
+ - Drops safely under pressure
319
+
320
+ ---
321
+
322
+ ## What This SDK Does NOT Do
323
+
324
+ - โŒ No HTTP middleware
325
+ - โŒ No inbound endpoints
326
+ - โŒ No request interception
327
+ - โŒ No PII handling
328
+ - โŒ No policy authoring
329
+ - โŒ No dynamic code execution
330
+
331
+ ---
332
+
333
+ ## Security Notes
334
+
335
+ - Runtime keys are **read-only**
336
+ - Keys are scoped by org / project / env
337
+ - Bundles are immutable
338
+ - SDK cannot modify state
339
+ - Safe to embed in critical paths
340
+
341
+ ### Threat Model
342
+
343
+ Please refer to the [Govplane Runtime SDK Threat Model & Security Guarantees](docs/security/Govplane_Threat_Model.md) for a detailed analysis.
344
+
345
+ ---
346
+
347
+ ## Performance Notes
348
+
349
+ - Designed for second-level polling
350
+ - Suitable for APIs, workers, gateways
351
+ - Not intended for browser usage
352
+
353
+ ---
354
+
355
+ ## Versioning & Compatibility
356
+
357
+ - Bundles are versioned (`schemaVersion`)
358
+ - Current version: `RuntimeBundleV1`
359
+ - Future versions will be backward-compatible
360
+
361
+ ---
362
+
363
+ ## License
364
+
365
+ MIT ยฉ Govplane