@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.
- package/.claude/skills/urlcode-authoring/SKILL.md +24 -8
- package/.claude/skills/urlcode-operations/SKILL.md +10 -16
- package/.claude-plugin/marketplace.json +1 -1
- package/README.md +75 -62
- package/ROADMAP.md +61 -16
- package/SECURITY.md +23 -8
- package/dist/BUILD-MANIFEST.json +38 -43
- package/dist/agents-guide.js +18 -18
- package/dist/build-static.js +134 -0
- package/dist/capabilities.js +85 -31
- package/dist/capability-query.js +0 -1
- package/dist/cli.js +23 -31
- package/dist/compliance-rules/baseline.js +2 -10
- package/dist/compliance-rules/privacy.js +5 -16
- package/dist/compliance-rules/shared.js +0 -2
- package/dist/compliance.js +6 -8
- package/dist/config.js +15 -8
- package/dist/context.js +9 -10
- package/dist/examples.js +2 -2
- package/dist/explain-cli.js +3 -3
- package/dist/explain.js +5 -6
- package/dist/extensions.js +61 -2
- package/dist/function-sources.js +34 -2
- package/dist/function-worker.js +3 -1
- package/dist/functions.js +84 -13
- package/dist/guest-api.js +29 -3
- package/dist/index.js +3 -6
- package/dist/manifest.js +5 -7
- package/dist/mcp.js +1 -1
- package/dist/observability.js +1 -21
- package/dist/policies/cache.js +8 -3
- package/dist/policy.js +28 -9
- package/dist/project-tests.js +3 -3
- package/dist/readiness.js +32 -9
- package/dist/router.js +5 -7
- package/dist/runtime.js +77 -58
- package/dist/sandbox.js +48 -0
- package/dist/scaffold.js +0 -0
- package/dist/scripts/operational-drills.js +12 -54
- package/dist/server.js +3 -29
- package/dist/tooling.js +1 -1
- package/dist/trusted-functions.js +210 -0
- package/dist/types/build-static.d.ts +43 -0
- package/dist/types/capabilities.d.ts +14 -5
- package/dist/types/compliance-rules/shared.d.ts +0 -2
- package/dist/types/compliance.d.ts +0 -3
- package/dist/types/config.d.ts +2 -1
- package/dist/types/context.d.ts +2 -1
- package/dist/types/examples.d.ts +1 -1
- package/dist/types/extensions.d.ts +55 -0
- package/dist/types/function-sources.d.ts +4 -0
- package/dist/types/functions.d.ts +48 -5
- package/dist/types/guest-api.d.ts +1 -0
- package/dist/types/index.d.ts +3 -6
- package/dist/types/manifest.d.ts +1 -3
- package/dist/types/observability.d.ts +1 -14
- package/dist/types/project-tests.d.ts +1 -2
- package/dist/types/readiness.d.ts +10 -3
- package/dist/types/router.d.ts +2 -1
- package/dist/types/runtime.d.ts +0 -27
- package/dist/types/sandbox.d.ts +12 -0
- package/dist/types/scaffold.d.ts +0 -2
- package/dist/types/server.d.ts +1 -4
- package/dist/types/tooling.d.ts +3 -3
- package/dist/types/trusted-functions.d.ts +29 -0
- package/dist/types/types.d.ts +14 -7
- package/dist/types/verify-deployment.d.ts +2 -2
- package/dist/types.js +17 -4
- package/dist/typescript-authoring.js +55 -17
- package/dist/verify-deployment.js +3 -3
- package/docs/AI-AUTHORING.md +104 -9
- package/docs/AWS.md +4 -4
- package/docs/BEST-PRACTICES.md +3 -2
- package/docs/CAPABILITIES.md +29 -16
- package/docs/CAPACITY.md +128 -31
- package/docs/CLOUDFLARE.md +1 -2
- package/docs/COMPLIANCE.md +6 -9
- package/docs/DEPLOYMENT-CHECKS.md +1 -1
- package/docs/EXTENSIONS.md +183 -11
- package/docs/FRAMEWORK.md +35 -19
- package/docs/FUNCTION-SECURITY.md +129 -32
- package/docs/INSTALL.md +0 -5
- package/docs/LOAD-TESTING.md +4 -4
- package/docs/MIDDLEWARE.md +27 -16
- package/docs/MONITORING.md +2 -19
- package/docs/NEXT-PHASE-PLAN.md +12 -4
- package/docs/NEXT-STEPS.md +259 -40
- package/docs/OBSERVABILITY.md +7 -16
- package/docs/OPEN-DECISIONS.md +212 -0
- package/docs/OPERATIONAL-PROOF.md +26 -30
- package/docs/OPERATIONS.md +23 -32
- package/docs/POLICIES.md +15 -4
- package/docs/PRERENDER.md +2 -2
- package/docs/PROJECT-DIRECTION.md +34 -9
- package/docs/README.md +13 -11
- package/docs/RELEASE-READINESS.md +49 -29
- package/docs/RELEASE-SECURITY.md +89 -3
- package/docs/RESILIENCE.md +16 -15
- package/docs/ROUTING.md +8 -10
- package/docs/SANDBOX-REVIEW.md +19 -6
- package/docs/SCAFFOLDING.md +0 -2
- package/docs/SECURITY-AUDIT.md +40 -0
- package/docs/SPECIFICATION.md +60 -26
- package/docs/SPIKE-AI-FRAMEWORK-BENCHMARK.md +287 -0
- package/docs/SPIKE-BUSINESS-SUITE.md +8 -0
- package/docs/SPIKE-CORE-LAYERING.md +337 -0
- package/docs/SPIKE-DEFAULT-TRUST-MODEL.md +209 -0
- package/docs/SPIKE-EXTENSION-MODEL.md +2 -2
- package/docs/SPIKE-EXTENSIONS.md +5 -0
- package/docs/SPIKE-LAMBDA-COMPILE.md +4 -2
- package/docs/SPIKE-MONOREPO.md +322 -0
- package/docs/STARTERS.md +1 -1
- package/docs/STATIC.md +94 -0
- package/docs/TOOLING.md +13 -9
- package/docs/TUNNELS.md +0 -3
- package/docs/TYPESCRIPT-AUTHORING.md +27 -12
- package/docs/TYPESCRIPT.md +25 -4
- package/docs/USABILITY-REVIEW.md +7 -1
- package/docs/VERCEL.md +4 -5
- package/docs/VERSION-ALIGNMENT.md +205 -0
- package/docs/YAML-GUIDE.md +0 -3
- package/docs/YAML-REFERENCE.md +16 -6
- package/docs/policies/cache.md +13 -0
- package/examples/assets/example.yaml +1 -1
- package/examples/aws/example.yaml +1 -1
- package/examples/cloudflare/example.yaml +1 -1
- package/examples/conditions/example.yaml +1 -1
- package/examples/cookbook/example.yaml +1 -1
- package/examples/cookbook/middleware/bucket.mjs +12 -2
- package/examples/cookbook/middleware/locale.mjs +7 -3
- package/examples/egress/example.yaml +1 -1
- package/examples/extensions/example.yaml +1 -1
- package/examples/prerender/README.md +2 -2
- package/examples/prerender/example.yaml +1 -1
- package/examples/provider-conformance/example.yaml +1 -1
- package/examples/vercel/example.yaml +1 -1
- package/llms-full.txt +594 -219
- package/llms.txt +23 -12
- package/package.json +10 -3
- package/packaging/claude-plugin/.claude-plugin/plugin.json +1 -1
- package/packaging/claude-plugin/skills/urlcode-authoring/SKILL.md +24 -8
- package/packaging/claude-plugin/skills/urlcode-operations/SKILL.md +10 -16
- package/recipes/authenticated-json-api/recipe.yaml +1 -1
- package/recipes/contact-form/recipe.yaml +1 -1
- package/recipes/cors-api/recipe.yaml +1 -1
- package/recipes/health-page/recipe.yaml +1 -1
- package/recipes/json-api/recipe.yaml +1 -1
- package/recipes/middleware/middleware/bucket.mjs +12 -2
- package/recipes/middleware/middleware/locale.mjs +7 -3
- package/recipes/middleware/recipe.yaml +1 -1
- package/recipes/protected-download/recipe.yaml +1 -1
- package/recipes/redirect/recipe.yaml +1 -1
- package/recipes/static-plus-api/recipe.yaml +1 -1
- package/recipes/typescript/README.md +2 -1
- package/recipes/typescript/recipe.yaml +1 -1
- package/recipes/webhook-receiver/README.md +5 -1
- package/recipes/webhook-receiver/recipe.yaml +2 -1
- package/recipes/webhook-receiver/urlcode.yaml +7 -0
- package/schemas/recipe.schema.json +4 -3
- package/schemas/urlcode.schema.json +14 -41
- package/skills/urlcode/SKILL.md +29 -8
- package/starters/default/AGENTS.md +18 -18
- package/starters/default/urlcode.yaml +0 -1
- package/dist/link-api.js +0 -136
- package/dist/link-cli.js +0 -141
- package/dist/link-events.js +0 -76
- package/dist/link-records.js +0 -31
- package/dist/link-store-worker.js +0 -150
- package/dist/link-store.js +0 -250
- package/dist/management-policy.js +0 -40
- package/dist/sqlite-version.js +0 -6
- package/dist/types/link-api.d.ts +0 -30
- package/dist/types/link-cli.d.ts +0 -37
- package/dist/types/link-events.d.ts +0 -27
- package/dist/types/link-records.d.ts +0 -11
- package/dist/types/link-store-worker.d.ts +0 -1
- package/dist/types/link-store.d.ts +0 -130
- package/dist/types/management-policy.d.ts +0 -8
- package/dist/types/sqlite-version.d.ts +0 -1
- package/docs/DYNAMIC-LINKS.md +0 -61
- package/docs/MANAGEMENT-SECURITY.md +0 -82
- package/docs/links/cli.md +0 -110
- package/docs/links/limits.md +0 -175
- package/docs/links/management-api.md +0 -80
- package/docs/links/pools.md +0 -75
- package/docs/links/setup.md +0 -135
- package/docs/yaml/links.md +0 -30
- package/examples/live-links/README.md +0 -11
- package/examples/live-links/example.yaml +0 -21
- package/examples/live-links/tests/requests.json +0 -6
- 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
|
|
4
|
-
>
|
|
5
|
-
>
|
|
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
|
|
28
|
-
| Explore a static docs-site integration |
|
|
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
|
|
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.
|
|
4
|
-
top of the `0.3.0` self-hosted release.
|
|
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,
|
|
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
|
-
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
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
|
|
27
|
-
Linux/macOS/Windows and tests the container
|
|
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 |
|
|
33
|
-
| Overload | Function
|
|
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 |
|
|
35
|
-
|
|
|
36
|
-
|
|
|
37
|
-
|
|
|
38
|
-
|
|
39
|
-
|
|
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
|
|
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
|
|
61
|
-
3.
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
4.
|
|
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
|
-
|
|
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,
|
|
92
|
-
|
|
93
|
-
|
|
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
|
package/docs/RELEASE-SECURITY.md
CHANGED
|
@@ -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`
|
|
95
|
-
|
|
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.
|
package/docs/RESILIENCE.md
CHANGED
|
@@ -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
|
|
5
|
-
|
|
6
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
157
|
-
|
|
158
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
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
|
-
|
|
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.
|
package/docs/SANDBOX-REVIEW.md
CHANGED
|
@@ -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
|
|
6
|
-
|
|
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
|
|
19
|
-
|
|
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
|
|
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
|
package/docs/SCAFFOLDING.md
CHANGED
|
@@ -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.
|
package/docs/SECURITY-AUDIT.md
CHANGED
|
@@ -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 |
|