@jimhoyd/urlcode 0.4.0-alpha.1 → 0.4.0-alpha.2

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.
Files changed (191) hide show
  1. package/.claude/skills/urlcode-authoring/SKILL.md +24 -8
  2. package/.claude/skills/urlcode-operations/SKILL.md +10 -16
  3. package/.claude-plugin/marketplace.json +1 -1
  4. package/README.md +75 -62
  5. package/ROADMAP.md +61 -16
  6. package/SECURITY.md +23 -8
  7. package/dist/BUILD-MANIFEST.json +38 -43
  8. package/dist/agents-guide.js +18 -18
  9. package/dist/build-static.js +134 -0
  10. package/dist/capabilities.js +85 -31
  11. package/dist/capability-query.js +0 -1
  12. package/dist/cli.js +23 -31
  13. package/dist/compliance-rules/baseline.js +2 -10
  14. package/dist/compliance-rules/privacy.js +5 -16
  15. package/dist/compliance-rules/shared.js +0 -2
  16. package/dist/compliance.js +6 -8
  17. package/dist/config.js +15 -8
  18. package/dist/context.js +9 -10
  19. package/dist/examples.js +2 -2
  20. package/dist/explain-cli.js +3 -3
  21. package/dist/explain.js +5 -6
  22. package/dist/extensions.js +61 -2
  23. package/dist/function-sources.js +34 -2
  24. package/dist/function-worker.js +3 -1
  25. package/dist/functions.js +84 -13
  26. package/dist/guest-api.js +29 -3
  27. package/dist/index.js +3 -6
  28. package/dist/manifest.js +5 -7
  29. package/dist/mcp.js +1 -1
  30. package/dist/observability.js +1 -21
  31. package/dist/policies/cache.js +8 -3
  32. package/dist/policy.js +28 -9
  33. package/dist/project-tests.js +3 -3
  34. package/dist/readiness.js +32 -9
  35. package/dist/router.js +5 -7
  36. package/dist/runtime.js +77 -58
  37. package/dist/sandbox.js +48 -0
  38. package/dist/scaffold.js +0 -0
  39. package/dist/scripts/operational-drills.js +12 -54
  40. package/dist/server.js +3 -29
  41. package/dist/tooling.js +1 -1
  42. package/dist/trusted-functions.js +210 -0
  43. package/dist/types/build-static.d.ts +43 -0
  44. package/dist/types/capabilities.d.ts +14 -5
  45. package/dist/types/compliance-rules/shared.d.ts +0 -2
  46. package/dist/types/compliance.d.ts +0 -3
  47. package/dist/types/config.d.ts +2 -1
  48. package/dist/types/context.d.ts +2 -1
  49. package/dist/types/examples.d.ts +1 -1
  50. package/dist/types/extensions.d.ts +55 -0
  51. package/dist/types/function-sources.d.ts +4 -0
  52. package/dist/types/functions.d.ts +48 -5
  53. package/dist/types/guest-api.d.ts +1 -0
  54. package/dist/types/index.d.ts +3 -6
  55. package/dist/types/manifest.d.ts +1 -3
  56. package/dist/types/observability.d.ts +1 -14
  57. package/dist/types/project-tests.d.ts +1 -2
  58. package/dist/types/readiness.d.ts +10 -3
  59. package/dist/types/router.d.ts +2 -1
  60. package/dist/types/runtime.d.ts +0 -27
  61. package/dist/types/sandbox.d.ts +12 -0
  62. package/dist/types/scaffold.d.ts +0 -2
  63. package/dist/types/server.d.ts +1 -4
  64. package/dist/types/tooling.d.ts +3 -3
  65. package/dist/types/trusted-functions.d.ts +29 -0
  66. package/dist/types/types.d.ts +14 -7
  67. package/dist/types/verify-deployment.d.ts +2 -2
  68. package/dist/types.js +17 -4
  69. package/dist/typescript-authoring.js +55 -17
  70. package/dist/verify-deployment.js +3 -3
  71. package/docs/AI-AUTHORING.md +104 -9
  72. package/docs/AWS.md +4 -4
  73. package/docs/BEST-PRACTICES.md +3 -2
  74. package/docs/CAPABILITIES.md +29 -16
  75. package/docs/CAPACITY.md +128 -31
  76. package/docs/CLOUDFLARE.md +1 -2
  77. package/docs/COMPLIANCE.md +6 -9
  78. package/docs/DEPLOYMENT-CHECKS.md +1 -1
  79. package/docs/EXTENSIONS.md +183 -11
  80. package/docs/FRAMEWORK.md +35 -19
  81. package/docs/FUNCTION-SECURITY.md +129 -32
  82. package/docs/INSTALL.md +0 -5
  83. package/docs/LOAD-TESTING.md +4 -4
  84. package/docs/MIDDLEWARE.md +27 -16
  85. package/docs/MONITORING.md +2 -19
  86. package/docs/NEXT-PHASE-PLAN.md +12 -4
  87. package/docs/NEXT-STEPS.md +259 -40
  88. package/docs/OBSERVABILITY.md +7 -16
  89. package/docs/OPEN-DECISIONS.md +212 -0
  90. package/docs/OPERATIONAL-PROOF.md +26 -30
  91. package/docs/OPERATIONS.md +23 -32
  92. package/docs/POLICIES.md +15 -4
  93. package/docs/PRERENDER.md +2 -2
  94. package/docs/PROJECT-DIRECTION.md +34 -9
  95. package/docs/README.md +13 -11
  96. package/docs/RELEASE-READINESS.md +49 -29
  97. package/docs/RELEASE-SECURITY.md +89 -3
  98. package/docs/RESILIENCE.md +16 -15
  99. package/docs/ROUTING.md +8 -10
  100. package/docs/SANDBOX-REVIEW.md +19 -6
  101. package/docs/SCAFFOLDING.md +0 -2
  102. package/docs/SECURITY-AUDIT.md +40 -0
  103. package/docs/SPECIFICATION.md +60 -26
  104. package/docs/SPIKE-AI-FRAMEWORK-BENCHMARK.md +287 -0
  105. package/docs/SPIKE-BUSINESS-SUITE.md +8 -0
  106. package/docs/SPIKE-CORE-LAYERING.md +337 -0
  107. package/docs/SPIKE-DEFAULT-TRUST-MODEL.md +209 -0
  108. package/docs/SPIKE-EXTENSION-MODEL.md +2 -2
  109. package/docs/SPIKE-EXTENSIONS.md +5 -0
  110. package/docs/SPIKE-LAMBDA-COMPILE.md +4 -2
  111. package/docs/SPIKE-MONOREPO.md +322 -0
  112. package/docs/STARTERS.md +1 -1
  113. package/docs/STATIC.md +94 -0
  114. package/docs/TOOLING.md +13 -9
  115. package/docs/TUNNELS.md +0 -3
  116. package/docs/TYPESCRIPT-AUTHORING.md +27 -12
  117. package/docs/TYPESCRIPT.md +25 -4
  118. package/docs/USABILITY-REVIEW.md +7 -1
  119. package/docs/VERCEL.md +4 -5
  120. package/docs/VERSION-ALIGNMENT.md +205 -0
  121. package/docs/YAML-GUIDE.md +0 -3
  122. package/docs/YAML-REFERENCE.md +16 -6
  123. package/docs/policies/cache.md +13 -0
  124. package/examples/assets/example.yaml +1 -1
  125. package/examples/aws/example.yaml +1 -1
  126. package/examples/cloudflare/example.yaml +1 -1
  127. package/examples/conditions/example.yaml +1 -1
  128. package/examples/cookbook/example.yaml +1 -1
  129. package/examples/cookbook/middleware/bucket.mjs +12 -2
  130. package/examples/cookbook/middleware/locale.mjs +7 -3
  131. package/examples/egress/example.yaml +1 -1
  132. package/examples/extensions/example.yaml +1 -1
  133. package/examples/prerender/README.md +2 -2
  134. package/examples/prerender/example.yaml +1 -1
  135. package/examples/provider-conformance/example.yaml +1 -1
  136. package/examples/vercel/example.yaml +1 -1
  137. package/llms-full.txt +594 -219
  138. package/llms.txt +23 -12
  139. package/package.json +10 -3
  140. package/packaging/claude-plugin/.claude-plugin/plugin.json +1 -1
  141. package/packaging/claude-plugin/skills/urlcode-authoring/SKILL.md +24 -8
  142. package/packaging/claude-plugin/skills/urlcode-operations/SKILL.md +10 -16
  143. package/recipes/authenticated-json-api/recipe.yaml +1 -1
  144. package/recipes/contact-form/recipe.yaml +1 -1
  145. package/recipes/cors-api/recipe.yaml +1 -1
  146. package/recipes/health-page/recipe.yaml +1 -1
  147. package/recipes/json-api/recipe.yaml +1 -1
  148. package/recipes/middleware/middleware/bucket.mjs +12 -2
  149. package/recipes/middleware/middleware/locale.mjs +7 -3
  150. package/recipes/middleware/recipe.yaml +1 -1
  151. package/recipes/protected-download/recipe.yaml +1 -1
  152. package/recipes/redirect/recipe.yaml +1 -1
  153. package/recipes/static-plus-api/recipe.yaml +1 -1
  154. package/recipes/typescript/README.md +2 -1
  155. package/recipes/typescript/recipe.yaml +1 -1
  156. package/recipes/webhook-receiver/README.md +5 -1
  157. package/recipes/webhook-receiver/recipe.yaml +2 -1
  158. package/recipes/webhook-receiver/urlcode.yaml +7 -0
  159. package/schemas/recipe.schema.json +4 -3
  160. package/schemas/urlcode.schema.json +14 -41
  161. package/skills/urlcode/SKILL.md +29 -8
  162. package/starters/default/AGENTS.md +18 -18
  163. package/starters/default/urlcode.yaml +0 -1
  164. package/dist/link-api.js +0 -136
  165. package/dist/link-cli.js +0 -141
  166. package/dist/link-events.js +0 -76
  167. package/dist/link-records.js +0 -31
  168. package/dist/link-store-worker.js +0 -150
  169. package/dist/link-store.js +0 -250
  170. package/dist/management-policy.js +0 -40
  171. package/dist/sqlite-version.js +0 -6
  172. package/dist/types/link-api.d.ts +0 -30
  173. package/dist/types/link-cli.d.ts +0 -37
  174. package/dist/types/link-events.d.ts +0 -27
  175. package/dist/types/link-records.d.ts +0 -11
  176. package/dist/types/link-store-worker.d.ts +0 -1
  177. package/dist/types/link-store.d.ts +0 -130
  178. package/dist/types/management-policy.d.ts +0 -8
  179. package/dist/types/sqlite-version.d.ts +0 -1
  180. package/docs/DYNAMIC-LINKS.md +0 -61
  181. package/docs/MANAGEMENT-SECURITY.md +0 -82
  182. package/docs/links/cli.md +0 -110
  183. package/docs/links/limits.md +0 -175
  184. package/docs/links/management-api.md +0 -80
  185. package/docs/links/pools.md +0 -75
  186. package/docs/links/setup.md +0 -135
  187. package/docs/yaml/links.md +0 -30
  188. package/examples/live-links/README.md +0 -11
  189. package/examples/live-links/example.yaml +0 -21
  190. package/examples/live-links/tests/requests.json +0 -6
  191. package/examples/live-links/urlcode.yaml +0 -16
package/docs/README.md CHANGED
@@ -1,12 +1,14 @@
1
1
  # URLCode documentation
2
2
 
3
- > **Public documentation has moved to
4
- > [urlcode-docs](https://github.com/jimhoyd-com/urlcode-docs).** That repository
5
- > is the documentation home and is authored directly this tree is no longer
6
- > mirrored into it. New reader-facing pages belong in urlcode-docs; `docs/` here
7
- > keeps contributor and maintainer material (local development, CI, release
3
+ > **Public documentation is authored in a separate `urlcode-docs` repository,
4
+ > not generated from this tree.** New reader-facing pages belong there; `docs/`
5
+ > here keeps contributor and maintainer material (local development, CI, release
8
6
  > process, reviews, spikes, plans and the generated field reference). The
9
7
  > reader-facing pages still listed below are being migrated.
8
+ >
9
+ > `urlcode-docs` is currently private, so it isn't publicly browsable yet —
10
+ > until it is, this file and this repository's README are the practical
11
+ > reference.
10
12
 
11
13
  Start with [the framework](FRAMEWORK.md): the four packages, the ladder from
12
14
  redirects to a full application, the composition contract and the rules an AI
@@ -24,18 +26,16 @@ boundary and the license. Use documentation pinned to your runtime revision;
24
26
  | Let an AI build routes | [AI authoring guide](AI-AUTHORING.md), [llms.txt](../llms.txt) |
25
27
  | Load authoring/operations rules into an agent | [Authoring skill](../.claude/skills/urlcode-authoring/SKILL.md), [operations skill](../.claude/skills/urlcode-operations/SKILL.md), [how they are distributed](AI-AUTHORING.md#agent-skills) |
26
28
  | Run examples | [25-route cookbook](../examples/cookbook/README.md), [prerender recipe](../examples/prerender/README.md), [small starter](STARTERS.md) |
27
- | Explore a standalone application | [URLCode Shortener demo](https://github.com/jimhoyd-com/urlcode-shortener), [build retrospective](https://github.com/jimhoyd-com/urlcode-shortener/blob/main/docs/BUILD-RETROSPECTIVE.md) |
28
- | Explore a static docs-site integration | [URLCode Docs project](https://github.com/jimhoyd-com/urlcode-docs), [build retrospective](https://github.com/jimhoyd-com/urlcode-docs/blob/main/docs/BUILD-RETROSPECTIVE.md) — synced from this repository, which remains the source of truth |
29
- | Create/update short links live | [Dynamic links, storage and management API](DYNAMIC-LINKS.md) |
29
+ | Explore a standalone application | [URLCode Short demo](https://github.com/jimhoyd-com/urlcode-short), [build retrospective](https://github.com/jimhoyd-com/urlcode-short/blob/main/docs/BUILD-RETROSPECTIVE.md) |
30
+ | Explore a static docs-site integration | URLCode Docs project (private repository; not yet publicly browsable) |
30
31
  | Understand exact behavior | [Specification](SPECIFICATION.md), [routing](ROUTING.md), [HTTP](HTTP.md) |
31
32
  | Run examples | [40-route cookbook](../examples/cookbook/README.md), [prerender recipe](../examples/prerender/README.md), [small starter](STARTERS.md) |
32
33
  | Let an AI build routes | [The framework](FRAMEWORK.md), [AI authoring guide](AI-AUTHORING.md), [llms.txt](../llms.txt), [SDK and read-only MCP](TOOLING.md) |
33
34
  | Reuse code around routes | [Middleware](MIDDLEWARE.md), [middleware examples](MIDDLEWARE-EXAMPLES.md) |
34
- | Handle secrets and untrusted code | [Function security](FUNCTION-SECURITY.md) |
35
+ | Handle secrets and decide what to sandbox | [Function security](FUNCTION-SECURITY.md) |
35
36
  | Author guest functions in TypeScript | [Build-time guest transpilation](TYPESCRIPT-AUTHORING.md) |
36
37
  | Serve pages, files and downloads | [Assets](ASSETS.md) |
37
38
  | Publish a site with no request-time guest code | [Prerendering helper and recipe](PRERENDER.md) |
38
- | Create and update short links live | [Dynamic links, storage and management API](DYNAMIC-LINKS.md) |
39
39
  | Select response branches | [Exact conditions](CONDITIONS.md) |
40
40
  | Proxy an API or emit a webhook | [Bounded egress and operator grants](EGRESS.md) |
41
41
  | Throttle, block agents, set security headers, compress or cache | [Policies](POLICIES.md): [throttle](policies/throttle.md), [agents](policies/agents.md), [security](policies/security.md), [compression](policies/compression.md), [cache](policies/cache.md) |
@@ -55,6 +55,7 @@ boundary and the license. Use documentation pinned to your runtime revision;
55
55
  | Manage users, sessions, roles and audit | [urlcode-admin](https://github.com/jimhoyd-com/urlcode-admin#readme) |
56
56
  | Restyle every extension page and translate copy | [urlcode-ui](https://github.com/jimhoyd-com/urlcode-ui#readme), [ui contract](https://github.com/jimhoyd-com/urlcode-ui/blob/main/CONTRACT.md) |
57
57
  | Write or install a versioned extension | [Extensions](EXTENSIONS.md), [example fixture](../examples/extensions/README.md) |
58
+ | Know which core version an extension package supports, and how it says so | [Core version alignment](VERSION-ALIGNMENT.md) |
58
59
  | Add host behavior in operator code | [Plugins](PLUGINS.md) |
59
60
  | Use the API from TypeScript | [TypeScript: shipped declarations, exports, build and fidelity](TYPESCRIPT.md) |
60
61
 
@@ -81,7 +82,6 @@ boundary and the license. Use documentation pinned to your runtime revision;
81
82
  | Watch a deployment | [Monitoring](MONITORING.md), [observability](OBSERVABILITY.md) |
82
83
  | Estimate concurrency and memory | [Capacity and limits](CAPACITY.md), [measurements](PERFORMANCE.md), [load testing](LOAD-TESTING.md) |
83
84
  | Prepare for overload, DDoS and recovery | [Resilience playbook](RESILIENCE.md) |
84
- | Manage private credentials and audit | [Management security](MANAGEMENT-SECURITY.md) |
85
85
 
86
86
  ## Evidence, reviews and design records
87
87
 
@@ -93,12 +93,14 @@ has not, and why the design is the way it is.
93
93
  | [Release readiness](RELEASE-READINESS.md) | Verified safeguards, open gates, supported scope |
94
94
  | [Usability review](USABILITY-REVIEW.md) | Where the framework is easier or harder than the tools it replaces, and ranked changes |
95
95
  | [Next steps](NEXT-STEPS.md) | The phased plan: agent discovery, context compression, retrieval, the ladder, benchmarks and the remaining proof gaps |
96
+ | [AI-first framework benchmark spike](SPIKE-AI-FRAMEWORK-BENCHMARK.md) | Proposed research-first, independent-agent application and runtime benchmark with a verified issue/improvement loop |
96
97
  | [Next-phase implementation status](NEXT-PHASE-PLAN.md) | Source additions after 0.3.0 shipped in 0.4.0-alpha.1, and their evidence limits |
97
98
  | [Security review](SECURITY-AUDIT.md) | Internal findings and fixes; not an independent test |
98
99
  | [Standards audit](STANDARDS.md) | How the runtime conforms to the RFCs it touches |
99
100
  | [Sandbox review package](SANDBOX-REVIEW.md) | What an independent reviewer needs; assessment not yet performed |
100
101
  | [Operational drills](OPERATIONAL-PROOF.md) | Deployment acceptance drills CI runs |
101
102
  | [Release security](RELEASE-SECURITY.md) | Candidate signing and publication process |
103
+ | [Core version alignment](VERSION-ALIGNMENT.md) | The supported core floor for each downstream repository, how it is declared, and the publish-then-raise-then-regenerate order |
102
104
  | [Extension model review](SPIKE-EXTENSION-MODEL.md) | Why extensions are shaped this way, with framework precedents |
103
105
  | [Extensions spike](SPIKE-EXTENSIONS.md) | The design behind policies and plugins; implemented |
104
106
  | [Lambda compile spike](SPIKE-LAMBDA-COMPILE.md) | Proposal: per-route Lambdas for functions; not implemented |
@@ -1,42 +1,59 @@
1
1
  # Release readiness
2
2
 
3
- Status: `0.4.0-alpha.1` alpha of the extension contract and agent tooling on
4
- top of the `0.3.0` self-hosted release. Production approval remains specific to
3
+ Status: `0.4.0-alpha.2` (`package.json`) alpha of the extension contract and
4
+ agent tooling on top of the `0.3.0` self-hosted release; `0.4.0-alpha.1` is the
5
+ most recent alpha actually published; the npm dist-tags for `@jimhoyd/urlcode`
6
+ were `latest` = `0.3.0` and `alpha` = `0.4.0-alpha.1` when checked against the
7
+ registry on 2026-09-19, so the repository's `0.4.0-alpha.2` is unpublished (see
8
+ "Packaging" below). Production approval remains specific to
5
9
  the workload and deployment environment.
6
10
  This register describes the current public runtime, not future promises.
7
11
  Use the contract and docs from the same pinned commit as your installed runtime.
8
12
 
9
13
  ## What is aligned
10
14
 
11
- - One portable YAML project, explicit includes, one handler per route (redirect, respond, page, static, download, function, link, proxy, conditional or extension),
15
+ - One portable YAML project, explicit includes, one handler per route (redirect, respond, page, static, download, function, proxy, conditional or extension),
12
16
  per-route middleware and consistent request/response validation.
13
17
  - One starter with a function route first and an ordinary redirect second.
14
18
  Clone urlcode-template or use `urlcode init`; neither requires a database.
15
19
  - Native handlers avoid user-code execution unless middleware is attached.
16
- - Live links are mutable records behind a declared route. Git owns definitions;
17
- an optional external SQLite store owns records. This is single-host storage.
18
- - Untrusted functions run in isolated QuickJS/WASM with no ambient filesystem,
19
- network or Node APIs. Host bindings require external revision-pinned approval.
20
+ - Functions/middleware run trusted and unsandboxed by default (in-process,
21
+ full Node access); `sandbox: true` opts a route into isolated QuickJS/WASM
22
+ with no ambient filesystem, network or Node APIs (docs/SPIKE-DEFAULT-TRUST-MODEL.md).
23
+ Host bindings require external revision-pinned approval either way.
20
24
  - The runtime is released under Apache-2.0.
21
25
 
22
26
  ## Regression evidence
23
27
 
24
28
  `npm run verify` is the lint, syntax/schema-reference and unit/HTTP regression gate.
25
29
  `npm run test:package` installs the packed artifact and exercises initialized apps,
26
- route audits, bounded benchmarks, assets and live links. CI runs Node 22/24/26 on
27
- Linux/macOS/Windows and tests the container under resource restrictions.
30
+ route audits, bounded benchmarks and assets. On a push to `main`, CI runs Node
31
+ 22/24/26 on Linux/macOS/Windows (nine combinations) and tests the container
32
+ under resource restrictions; a pull request runs the same Node versions on
33
+ Linux only (`.github/workflows/ci.yml`'s matrix), with the macOS/Windows legs
34
+ deferred to the post-merge run.
28
35
 
29
36
  | Area | Covered behavior | Practical limit |
30
37
  |---|---|---|
31
38
  | Routing and HTTP | Exact/parameter/static precedence, methods, inputs, assets, middleware and response assertions | Stable 0.1 contract; unsupported semantics reject rather than emulate |
32
- | Isolation | Sandbox capability/permission boundaries, deadlines, memory and invalid outputs | Not an independent security assessment or multi-tenant service certification |
33
- | Overload | Function/store queue caps; HTTP admission saturation, separate bounded probe budget, health availability and recovery after upload completion/disconnect | 64 application requests default; no fairness, upstream DDoS protection or end-to-end deadline |
34
- | Worker replacement | Repeated guest deadlines shed load and the pool returns to service after backoff, rather than latching off for the life of the process | Store-connection replacement shares this logic but its failure branch has no automated test; a crash there is covered by reasoning and review only |
35
- | Persistence | Committed writes visible to independent readers; concurrent CAS, restart and abrupt writer exit | SQLite on one host; no distributed availability |
36
- | Shutdown | Full accepted store queue drains; new work rejects; repeated close shares completion | Existing deadlines can still fail; uncertain writes must be reconciled |
37
- | Management | Token boundaries, body limits, origin rejection, conditional mutations, endpoint-specific Allow headers | Private operator API, not public end-user account management |
38
- | Activation/recovery | Invalid reload retains last-good snapshot; corrupt revision metadata rejects activation | No deployment orchestration or automatic database repair |
39
- | Packaging | Packed installation and starter examples tested; sensitive files excluded | No published npm/Homebrew release or provider adapter guarantee |
39
+ | Isolation | `sandbox: true` capability/permission boundaries, deadlines, memory and invalid outputs; the trusted default's grant scoping | Not an independent security assessment or multi-tenant service certification; trusted-route code safety is the project's own call |
40
+ | Overload | Function pool queue caps; HTTP admission saturation, separate bounded probe budget, health availability and recovery after upload completion/disconnect | 64 application requests default; no fairness, upstream DDoS protection or end-to-end deadline |
41
+ | Worker replacement | Repeated guest deadlines shed load and the pool returns to service after backoff, rather than latching off for the life of the process | Bounded by the configured worker count; no cross-process load balancing |
42
+ | Shutdown | New work rejects; repeated close shares completion | Existing deadlines can still fail during shutdown |
43
+ | Activation/recovery | Invalid reload retains last-good snapshot; corrupt revision metadata rejects activation | No deployment orchestration |
44
+ | Packaging | Packed installation and starter examples tested; sensitive files excluded | `0.3.0` and `0.4.0-alpha.1` are published to npm as `@jimhoyd/urlcode` (`latest` and `alpha` dist-tags respectively; dist-tags verified against the npm registry on 2026-09-19, when the repository stood at the unpublished `0.4.0-alpha.2`). Published extension packages on the same date: `@jimhoyd/urlcode-auth@0.1.0-alpha.2`, `@jimhoyd/urlcode-admin@0.1.0-alpha.2`, `@jimhoyd/urlcode-ui@0.1.0-alpha.4`, `@jimhoyd/urlcode-short@0.1.0-alpha.1`, `@jimhoyd/urlcode-dynamic-link@0.1.0-alpha.1`, `@jimhoyd/urlcode-middleware@0.1.0-alpha.1`. Observed in passing: auth's dist-tags are split — `alpha` points at `0.1.0-alpha.2` while `latest` still points at `0.1.0-alpha.1`, so a plain `npm install @jimhoyd/urlcode-auth` resolves the older alpha. GitHub Releases attach a Homebrew formula (`urlcode.rb`) for manual copy into a tap, not an automated Homebrew Core/tap publish. No provider adapter guarantee. |
45
+
46
+ `npm run check:downstream-skills` is a manual, advisory report worth running
47
+ before a release: it diffs core's `.claude/skills/` copies against copies
48
+ vendored by downstream repositories (currently `urlcode-template`) when that
49
+ repository is cloned as a sibling checkout, and prints how many lines differ
50
+ per skill. It never fails and never asserts which side is correct -- a
51
+ downstream repo commonly pins an older published core version, and
52
+ divergence from core's current `main` can be the *correct* reflection of
53
+ that pin rather than staleness (see issue #155). It is not part of `check`
54
+ or `verify` because it depends on an out-of-repo sibling checkout that
55
+ normal CI does not have; it is a prompt to review the diff against the
56
+ downstream pin, not a pass/fail gate.
40
57
 
41
58
  `npm audit --omit=dev` now runs in CI and fails the build on any runtime advisory;
42
59
  development-only advisories are reported without blocking. Dependabot proposes npm,
@@ -50,22 +67,20 @@ These remain open. Record workload, runtime/app/image revisions, environment,
50
67
  commands, results and owner for each exercise; do not convert a passing local
51
68
  benchmark into a universal throughput claim.
52
69
 
53
- 1. Independent review of host/sandbox boundaries and authenticated management.
70
+ 1. Independent review of host/sandbox boundaries.
54
71
  2. Sustained load and soak on intended hardware, through the actual TLS/proxy
55
72
  path: successful throughput, tail latency, 503/504 rate, RSS and recovery.
56
73
  `urlcode benchmark --target` measures a running deployment through its real
57
74
  path and separates shed responses from transport errors; see
58
75
  [load testing](LOAD-TESTING.md). The tool is GET/HEAD only and caps at 300
59
76
  seconds, so it does not by itself close this gate.
60
- Include mixed native/function/live-link workloads and slow peers.
61
- 3. A real backup/restore drill on a separate host/volume, with record/version
62
- reconciliation and measured recovery time/data loss. Keep SQLite WAL files
63
- consistent; copying a live main database file alone is not a backup.
64
- 4. Kill/restart, resource exhaustion, disk-full and rolling deployment/rollback
65
- exercises with the chosen supervisor, ingress and persistent storage.
66
- 5. Alerting and ownership for sustained errors, latency, readiness, dropped logs,
77
+ Include mixed native/function workloads and slow peers.
78
+ 3. Kill/restart, resource exhaustion and rolling deployment/rollback
79
+ exercises with the chosen supervisor and ingress. A future durable-state
80
+ extension needs its own backup/restore drill; core has no durable store.
81
+ 4. Alerting and ownership for sustained errors, latency, readiness, dropped logs,
67
82
  disk space, restarts and backups. Pick service objectives for the actual app.
68
- 6. Stable-release support commitments before packaging/public reuse claims.
83
+ 5. Stable-release support commitments before packaging/public reuse claims.
69
84
  Private security reporting and the current support baseline are documented in
70
85
  SECURITY.md.
71
86
 
@@ -88,9 +103,14 @@ independent assessment or real deployment exercises.
88
103
  ## Hardening follow-up
89
104
 
90
105
  Implemented: bounded YAML workers and aggregate source budgets, cooperative route
91
- compilation deadline, loopback-only management, scoped/expiring/revocable operator
92
- credentials, atomic SQLite mutation audits, executable local/CI operational drills,
93
- and a main-only candidate signing/SBOM workflow.
106
+ compilation deadline, scoped/expiring/revocable operator credentials for host
107
+ bindings, executable local/CI operational drills, and a main-only candidate
108
+ signing/SBOM workflow. The loopback-only management API and its atomic SQLite
109
+ mutation audits were part of the `link`/`dynamicLinks` store that PR #126
110
+ removed from core; that functionality, and its hardening, now belongs to the
111
+ `urlcode-dynamic-link` extension (docs/EXTENSIONS.md), published on npm as
112
+ `@jimhoyd/urlcode-dynamic-link@0.1.0-alpha.1` as of 2026-09-19, not this
113
+ runtime.
94
114
 
95
115
  Still required: [independent review](SANDBOX-REVIEW.md), [actual deployment proof](OPERATIONAL-PROOF.md),
96
116
  and publication/support arrangements. The Apache-2.0 license and the 0.3.0 self-hosted
@@ -90,6 +90,92 @@ The SBOM describes npm dependencies; it is not a complete OS/container SBOM. Hos
90
90
  runners and action runtimes remain platform-controlled. Digest pins improve supply
91
91
  chain integrity but do not prove byte-for-byte reproducibility or engine safety.
92
92
  Signing verification must be demonstrated on a successful main workflow run before
93
- claiming a candidate has been signed. Workflow definition alone is not that evidence:
94
- `release.yml` has never been executed, so no release has yet been produced or signed
95
- by it, and the npm and GHCR publication paths are unproven until a real tag runs.
93
+ claiming a candidate has been signed. Workflow definition alone is not that evidence.
94
+ `release.yml` ran successfully for the first time publishing `v0.4.0-alpha.1`
95
+ (2026-09-18), after the fixes below; treat any repository whose workflow has not
96
+ had a real successful tagged run the same way this one was treated before that.
97
+
98
+ ## What broke on every first release, and why
99
+
100
+ Four repositories (core, ui, auth, admin) each cut their first tagged release in
101
+ the same session. Every one hit a subset of the same bugs, because each
102
+ `release.yml` was written and reviewed but never actually run end-to-end against
103
+ a real tag before. None of this is repository-specific; check for all of it
104
+ before trusting an unexercised release workflow:
105
+
106
+ - **`npm ci` on the bare runner's root-owned npm.** A build that runs entirely
107
+ inside a pinned Docker image never calls `actions/setup-node`, so a later
108
+ `npm install --global npm@11.5.1` (needed for the trusted-publishing floor)
109
+ hits the runner's preinstalled, root-owned npm and fails `EACCES`. Add
110
+ `actions/setup-node` before any step that installs global npm packages, even
111
+ if the main build never touches the runner's own Node.
112
+ - **The floor check must run after the pin, not before.** A guard asserting
113
+ "npm ≥ 11.5.1" is useless directly after `setup-node` with `node-version: '22'`,
114
+ which bundles npm ~10.9.x — it can never pass. The floor only means something
115
+ once the publish step's own `npm install --global npm@11.5.1` has actually run.
116
+ - **`npm publish` refuses an unqualified prerelease.** `You must specify a tag
117
+ using --tag when publishing a prerelease version.` npm's safety default is
118
+ `latest`; a prerelease must derive an explicit dist-tag from its version
119
+ (`0.1.0-alpha.1` → `alpha`, anything without a `-` → `latest`) and pass
120
+ `--tag`. This path is only exercised by a package's *first* prerelease, so it
121
+ silently sat broken in every repository until each hit it for the first time.
122
+ - **`npm pack --pack-destination candidate` needs `candidate/` to exist first.**
123
+ npm does not create the destination directory; `mkdir -p candidate` first.
124
+ - **A private repository's unauthenticated `git fetch origin main` cannot work.**
125
+ If checkout uses `persist-credentials: false` (correct, for a step that
126
+ should not need write access) and the repo is private, `git fetch` fails
127
+ `could not read Username for 'https://github.com'` before ever reaching the
128
+ version check. Compare the tag against main through the GitHub API instead
129
+ (`gh api repos/OWNER/REPO/compare/main...SHA --jq .status`, expecting
130
+ `identical` or `behind`) — it needs no credentials and stays read-only. Public
131
+ repositories can keep the plain fetch; it works there.
132
+ - **`--conditions=development` in `npm run verify`'s test script resolves peers
133
+ to source that a real npm install never ships.** The regular CI job symlinks
134
+ sibling checkouts in place of `node_modules`, so `./src/*.ts` exists and the
135
+ flag is correct there. A release installs real published tarballs of its
136
+ peers, which only ever ship `dist/`, so the same flag makes every import of a
137
+ peer fail `ERR_MODULE_NOT_FOUND`. Drop the flag for the release-workflow test
138
+ invocation specifically (run `node scripts/check-sqlite.mjs` explicitly first,
139
+ since bypassing `npm test` skips that pretest hook), and audit any test file
140
+ that separately hardcodes the flag in a spawned child process — it has to be
141
+ fixed the same way, independently, wherever it appears.
142
+ - **A peer-install command with the wrong flag combination is a silent no-op.**
143
+ `npm install --no-save --no-package-lock --ignore-scripts --legacy-peer-deps
144
+ <peer>@<version>` installed *nothing*, with no error, when the target package
145
+ names already appear in `peerDependencies` — `npm ci` earlier reports "added N
146
+ packages" as if it worked. Confirm the install actually happened
147
+ (`ls node_modules/@scope/*/package.json` and print each version) rather than
148
+ trusting the exit code; `--no-save --ignore-scripts <specs>` (no
149
+ `--no-package-lock`, no `--legacy-peer-deps`) is the version that works, paired
150
+ with `git diff --exit-code -- package.json package-lock.json` to prove nothing
151
+ was recorded as a dependency.
152
+ - **A version published from an unbuilt checkout is burned forever.** npm never
153
+ allows a version to be replaced. `@jimhoyd/urlcode-auth@0.1.0-alpha.1` reached
154
+ the registry from something other than the CI workflow (a manual `npm
155
+ publish` run before `npm run build` had produced `dist/`), so the published
156
+ tarball contained only metadata files and no code. Every consumer's typecheck
157
+ failed with `Cannot find module '@jimhoyd/urlcode-auth'` — a real, correct
158
+ failure, not a bug in the consumer. The only fix is bumping to a new version
159
+ and publishing that instead; nothing can repair or unpublish the bad one.
160
+ **Never run `npm publish` by hand outside the release workflow** — the
161
+ workflow is the only place that reliably builds before packing.
162
+ - **`ENEEDAUTH` on `npm publish` under trusted publishing usually means the
163
+ registry-side configuration doesn't exist or doesn't permit direct publish
164
+ yet**, not a workflow bug. Trusted publishing needs an entry under the
165
+ package's npm settings ("Trusted Publisher") naming the exact GitHub
166
+ org/repo and workflow filename, with no environment set unless the workflow
167
+ declares one; recent npm UI changes default new configurations to
168
+ "stage publish" only; "allow npm publish" (direct publish, which is what
169
+ this project's workflows do) must be explicitly enabled too. A wrong
170
+ org/repo/workflow match tends to surface as a 404, not `ENEEDAUTH`;
171
+ `ENEEDAUTH` is the signature of no matching configuration existing at all.
172
+ - **Publish order matters and is easy to get backwards.** Extension packages
173
+ declare `@jimhoyd/urlcode >=X <Y` as a peer range; publish core before ui,
174
+ auth or admin, or their own release-workflow peer-install step has nothing
175
+ real to resolve against.
176
+
177
+ None of the above is exotic; all nine bugs were found by actually running each
178
+ workflow against a real tag, one release at a time, and reading the actual
179
+ failure rather than guessing from the workflow source. Treat "the workflow file
180
+ looks right" and "the workflow has actually published successfully once" as two
181
+ different, unrelated claims.
@@ -1,9 +1,11 @@
1
1
  # DDoS, overload and recovery playbook
2
2
 
3
3
  This is an operator plan for the current self-hosted release, not a claim of built-in DDoS
4
- protection, managed failover or tested high availability. URLCode's sandbox and
5
- resource limits reduce some failure modes; they cannot protect a saturated
6
- network link. Keep the public origin behind your existing protected ingress.
4
+ protection, managed failover or tested high availability. URLCode's resource
5
+ limits the HTTP admission cap either way, plus the worker pool's own
6
+ deadline/queue-less ceiling for a `sandbox: true` route reduce some failure
7
+ modes; they cannot protect a saturated network link. Keep the public origin
8
+ behind your existing protected ingress.
7
9
 
8
10
  ## Defense responsibilities
9
11
 
@@ -11,8 +13,8 @@ network link. Keep the public origin behind your existing protected ingress.
11
13
  |---|---|---|
12
14
  | Upstream network | Hosting/CDN DDoS mitigation and an escalation contact; protect bandwidth before it reaches the origin | No network-level mitigation service |
13
15
  | Edge/proxy | TLS, per-client and aggregate request/connection budgets, header/body/time limits; restrict direct origin access | Private bind default; no automatic TLS/WAF. Optional per-instance [`throttle` and `agents` policies](POLICIES.md) as a second layer behind the edge, with `--trusted-proxies` naming the hops allowed to set `X-Forwarded-For` |
14
- | Application | Validate inputs, bound expensive work, authenticate sensitive operations | Strict route/body validation; sandbox deadlines and no execution queue |
15
- | Process/container | CPU/RAM/PID limits, restart backoff, least privilege, read-only reviewed app | Worker isolation, bounded worker replacement, health and request logs |
16
+ | Application | Validate inputs, bound expensive work, authenticate sensitive operations | Strict route/body validation; a `sandbox: true` route gets worker deadlines and no execution queue, a trusted (default) route shares the HTTP admission cap with no worker ceiling |
17
+ | Process/container | CPU/RAM/PID limits, restart backoff, least privilege, read-only reviewed app | Worker isolation for `sandbox: true` routes, bounded worker replacement, health and request logs |
16
18
  | Release/recovery | Known-good artifacts, candidate verification, traffic switching, rollback drills | Local validation/tests/audit; explicit snapshot reload; no orchestration |
17
19
 
18
20
  NGINX provides request-rate controls and connection controls keyed by values such
@@ -30,7 +32,8 @@ forwarded headers to construct its public URL; set `--origin` explicitly.
30
32
 
31
33
  The optional [`throttle` policy](policies/throttle.md) adds a per-client budget
32
34
  inside the runtime, and the [`agents` policy](policies/agents.md) refuses listed
33
- User-Agents before a body is read or the sandbox starts. Both are a second
35
+ User-Agents before a body is read or the function/middleware call starts,
36
+ trusted or sandboxed. Both are a second
34
37
  layer behind the edge, not a replacement for it: counters are per instance,
35
38
  the socket and admission limits still apply first, and a flood still costs
36
39
  connections. The client identity is the socket peer unless
@@ -50,8 +53,8 @@ is not implemented; adding a reverse proxy does not bypass runtime execution.
50
53
  | Failure or traffic pattern | Current consequence | Mitigation / recovery |
51
54
  |---|---|---|
52
55
  | High-rate ordinary requests | Event-loop, logging, bandwidth or socket exhaustion | Filter/rate-limit upstream; scale only within measured resource/cost budgets |
53
- | Flood of functions or middleware | Two default worker slots fill; further calls receive 503 | Bound programmable traffic before the origin; isolate heavy workloads |
54
- | Infinite/slow application code | Shared invocation deadline returns 504; worker terminated/replaced | Identify bad release/route with protected diagnostics; roll back or block route at ingress |
56
+ | Flood of functions or middleware | Two default worker slots fill for `sandbox: true` routes; further calls receive 503. Trusted (default) routes shed load through the in-flight admission cap instead | Bound programmable traffic before the origin; isolate heavy workloads |
57
+ | Infinite/slow application code | Shared invocation deadline returns 504; a `sandbox: true` worker is terminated/replaced, while a trusted route blocking the event loop synchronously cannot be preempted ([capacity](CAPACITY.md)) | Identify bad release/route with protected diagnostics; roll back or block route at ingress |
55
58
  | Guest invalid response or failure | Generic 502 | Compare with last deployment; run fixture on a private candidate |
56
59
  | Repeated worker exits | Replacement backs off (250 ms doubling to 30 s) and keeps retrying; readiness stays 503 until every slot serves | Contain the cause; load is shed meanwhile. Replacement never stops, because a guest deadline is reachable from ordinary request input and must not disable functions until an operator restarts |
57
60
  | Large/slow requests | 64 admitted application requests, body/header limits and receipt timeouts; copies still consume memory | Smaller proxy/body budgets and connection admission limits |
@@ -120,8 +123,8 @@ Choose RTO (acceptable recovery time) and RPO (acceptable data loss) per deploym
120
123
  URLCode does not promise values. A stateless YAML deployment can be recreated
121
124
  from retained immutable artifacts, subject to recovery of DNS/ingress and secret
122
125
  access. Log loss is possible under pressure and has a separate retention target.
123
- Stored live-link records and future app-owned state need their own backups and restore
124
- verification; Git route configuration does not back up runtime data.
126
+ Future app-owned or extension-owned durable state needs its own backups and
127
+ restore verification; Git route configuration does not back up runtime data.
125
128
 
126
129
  A rollback needs the previous app/runtime and its matching policy and compatible
127
130
  secret bindings. The health version combines configuration and asset digests;
@@ -153,8 +156,6 @@ admission/fairness, production metrics/exporters, dedicated slow-reader protecti
153
156
  provider-level mitigation validation and sustained failure/soak testing. These are
154
157
  free-runtime/operator requirements.
155
158
 
156
- For optional live links, protect the separate management listener and token, bound
157
- its traffic, and back up the SQLite store with the documented closed-store or
158
- SQLite-aware procedure. Store worker failure returns 503; stop the cause before
159
- reloading/restarting. An uncertain mutation may have committed. See
160
- [dynamic-link recovery](DYNAMIC-LINKS.md).
159
+ Core has no durable store of its own to recover; a future durable-state
160
+ extension (such as the planned `urlcode-dynamic-link`) is responsible for its
161
+ own management listener, backup and recovery procedure once it exists.
package/docs/ROUTING.md CHANGED
@@ -1,4 +1,4 @@
1
- # Route matching and new links
1
+ # Route matching
2
2
 
3
3
  ## Supported path patterns
4
4
 
@@ -49,7 +49,7 @@ route returning 405, 404, 410 or 400 does not fall through to another route.
49
49
  Likewise, a missing file in the longest selected static mount does not fall back
50
50
  to a shorter mount. See [HTTP](HTTP.md) and [the contract](SPECIFICATION.md).
51
51
 
52
- ## Adding a configured link today
52
+ ## Adding a configured redirect today
53
53
 
54
54
  ```sh
55
55
  urlcode add https://example.com/new-page --alias new-link --project ./my-links
@@ -83,13 +83,11 @@ and needs no route rebuild or service restart. The same distinction applies to
83
83
  any per-visitor session record. Git owns route behavior and code; user-created records have
84
84
  their own persistence, backup and export lifecycle.
85
85
 
86
- This is now implemented for short-link redirects through the optional `link`
87
- handler, local SQLite storage, CLI and a separate authenticated management API.
88
- See [dynamic links](DYNAMIC-LINKS.md) for complete YAML, setup, consistency and
89
- backup details. No route reload is needed for committed record changes.
86
+ Core has no native handler for this today: the `link` handler that implemented
87
+ it was removed. Stored short links are moving to a future
88
+ `urlcode-dynamic-link` extension package (mount-based, like `auth`/`admin`,
89
+ not yet published); a project needing them declares an `extension` mount once
90
+ that package exists.
90
91
 
91
92
  Functions still cannot access databases, the filesystem or network directly.
92
- The native link handler performs the bounded lookup, and middleware can wrap a
93
- successful redirect. General application state and realtime sessions remain
94
- future work. SQLite is optional and supports local same-host processes; a
95
- multi-host deployment needs a different adapter. A cache is not the durable store.
93
+ General application state and realtime sessions remain future work.
@@ -1,9 +1,19 @@
1
1
  # Independent sandbox review gate
2
2
 
3
+ Scope: this gate is about the `sandbox: true` execution path only —
4
+ `function`/`middleware` routes run trusted and unsandboxed by default
5
+ (docs/SPIKE-DEFAULT-TRUST-MODEL.md), and a trusted route's full Node access is
6
+ by design, not a gap this review closes. Nothing here claims to review
7
+ arbitrary trusted project code; that trust is the project's own call, made
8
+ per route.
9
+
3
10
  Status: **external assessment not performed**. Internal source review, CI, CodeQL
4
11
  and adversarial regressions are useful evidence, not an independent sign-off.
5
- Do not host anonymous hostile multi-tenant code before this gate is closed.
6
- No unrestricted Node execution fallback is permitted.
12
+ Do not host anonymous hostile multi-tenant code in a `sandbox: true` route
13
+ before this gate is closed, and do not run untrusted/unreviewed code in a
14
+ trusted (non-`sandbox`) route at all — that path was never sandboxed and this
15
+ gate does not apply to it. No unrestricted Node execution fallback is
16
+ permitted *within a route that declared `sandbox: true`*.
7
17
 
8
18
  ## Review package
9
19
 
@@ -15,14 +25,17 @@ resource settings. Give a reviewer independent of the implementation access to:
15
25
  module graph, import denial, export validation, binding grants and message bridge.
16
26
  - `src/config.ts`, `src/config-worker.ts`, router and assets: parser/schema limits,
17
27
  file containment, activation, memory amplification and host-side compilation.
18
- - HTTP server, management API/policy and link-store worker: request smuggling,
19
- admission, body/response framing, authorization, revocation and atomic audit.
20
- - `test/sandbox.test.ts`, middleware/config/links/logging/reload tests, Dockerfile,
28
+ - HTTP server and policy: request smuggling, admission, body/response framing.
29
+ - `test/sandbox.test.ts`, middleware/config/logging/reload tests, Dockerfile,
21
30
  protected workflows and `docs/FUNCTION-SECURITY.md`.
31
+ - `src/runtime.ts`'s dispatch decision (`route.sandbox ? pool : trusted`) and
32
+ `src/trusted-functions.ts`: confirm a route that declares `sandbox: true`
33
+ can never be dispatched through the trusted, in-process path by any code
34
+ path, and that `sandbox: false`/absent never reaches `FunctionPool`.
22
35
 
23
36
  Run `npm ci --ignore-scripts`, `npm run verify`, `npm run test:package`, and
24
37
  `node scripts/operational-drills.ts`. Record the exact commands and result files.
25
- CI adds constrained-container and real disposable-volume exhaustion tests.
38
+ CI adds a constrained-container test.
26
39
  Use only disposable local/staging systems with synthetic data.
27
40
 
28
41
  ## Threat model and required probes
@@ -68,5 +68,3 @@ Scaffolding does not recursively invent dependencies imported by existing code,
68
68
  crawl HTML/CSS links, generate binary content, or implement your business logic.
69
69
  See [readiness checks](READINESS.md) and [asset behavior](ASSETS.md).
70
70
 
71
- Scaffolding enforces the entry-level `dynamicLinks` opt-in for `link` handlers
72
- and reports the effective boolean. It never enables this capability for you.
@@ -1,3 +1,38 @@
1
+ # Security review — 2026-09-18
2
+
3
+ Scope: trust-model change (docs/SPIKE-DEFAULT-TRUST-MODEL.md). `function`/
4
+ `middleware` routes now run trusted and unsandboxed by default, with
5
+ `sandbox: true` as an explicit per-route opt-in to the isolation this document's
6
+ earlier entries describe. This is a maintainer-decided policy reversal, not a
7
+ finding; it is recorded here because it changes what every earlier entry's
8
+ "guest"/"sandbox" language means going forward.
9
+
10
+ **What did not change:** the `sandbox: true` execution path — QuickJS/WASM
11
+ isolation, module-graph restriction, fresh heap per call, worker deadline —
12
+ is byte-for-byte the same as every earlier entry describes; nothing in this
13
+ change touched `src/functions.ts`, `src/function-worker.ts` or `src/guest-api.ts`.
14
+ Binding grants are unaffected either way: `env`/`secrets` still reach only a
15
+ route that explicitly declared them and an operator policy pinned to the
16
+ project revision explicitly granted, whether that route is trusted or
17
+ sandboxed.
18
+
19
+ **What did change, and the resulting residual risk:** a `function`/
20
+ `middleware` route with no `sandbox` field (the common case going forward, and
21
+ every existing project's routes after an upgrade with no YAML change) now runs
22
+ in the host process with full Node access — the isolation earlier entries'
23
+ "remaining gaps" language assumed for *all* guest code no longer applies to
24
+ it. The residual-risk framing in earlier entries ("before exposing hostile
25
+ multi-tenant workloads, obtain independent review of WASM/host boundaries")
26
+ is scoped to `sandbox: true` routes specifically; it was never a claim that
27
+ covered a route that opts out of the sandbox, and after this change most
28
+ routes do exactly that by default. Whether a given project's own function/
29
+ middleware code is safe to trust with full host access is now the project's
30
+ judgment call, not something this runtime's isolation reviews (past or
31
+ future) can speak to. New source review of the dispatch decision itself
32
+ (`src/runtime.ts`, `src/trusted-functions.ts`, `src/policy.ts`'s split
33
+ grant-hashing) accompanies the change; see the pull request that introduced
34
+ `sandbox` for its own description of what was and was not verified.
35
+
1
36
  # Security review — 2026-09-17
2
37
 
3
38
  Scope: follow-up source review of worker/connection replacement, probe admission,
@@ -5,6 +40,11 @@ request correlation, operational logging, dependency/release supply chain and th
5
40
  live-link Node requirement. Regression tests accompany the fixes. Internal review,
6
41
  not an independent penetration test.
7
42
 
43
+ This is a dated record, not current guidance. The `link` handler, its SQLite
44
+ store and the link-store/management findings below were removed from core in
45
+ a later change; they describe the runtime as it existed on this date, not the
46
+ current one.
47
+
8
48
  ## Findings fixed in this revision
9
49
 
10
50
  | Finding | Impact and evidence | Fix / regression |