@jimhoyd/urlcode 0.4.1 → 0.4.6

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 (212) hide show
  1. package/.claude/skills/urlcode-authoring/SKILL.md +60 -7
  2. package/.claude/skills/urlcode-operations/SKILL.md +4 -0
  3. package/README.md +19 -15
  4. package/SECURITY.md +5 -3
  5. package/dist/BUILD-MANIFEST.json +31 -28
  6. package/dist/agent-context.js +82 -0
  7. package/dist/agents-guide.js +42 -42
  8. package/dist/authoring.js +12 -2
  9. package/dist/body-schema.js +159 -0
  10. package/dist/build-cloudflare.js +2 -0
  11. package/dist/capabilities.js +1 -1
  12. package/dist/cli.js +29 -12
  13. package/dist/config.js +74 -6
  14. package/dist/context.js +4 -6
  15. package/dist/errors.js +3 -1
  16. package/dist/examples.js +1 -1
  17. package/dist/extensions.js +138 -3
  18. package/dist/http-policy.js +19 -4
  19. package/dist/http-response.js +2 -2
  20. package/dist/init-with.js +71 -9
  21. package/dist/mcp.js +15 -2
  22. package/dist/pattern-guard.js +32 -0
  23. package/dist/policies/security.js +0 -0
  24. package/dist/policy.js +16 -0
  25. package/dist/project-tests.js +35 -11
  26. package/dist/readiness.js +188 -32
  27. package/dist/recipes.js +1 -1
  28. package/dist/router.js +17 -0
  29. package/dist/runtime.js +26 -3
  30. package/dist/scaffold.js +0 -0
  31. package/dist/server.js +26 -3
  32. package/dist/site.js +0 -0
  33. package/dist/tooling.js +3 -1
  34. package/dist/types/agent-context.d.ts +44 -0
  35. package/dist/types/authoring.d.ts +3 -1
  36. package/dist/types/body-schema.d.ts +58 -0
  37. package/dist/types/config.d.ts +10 -2
  38. package/dist/types/context.d.ts +1 -1
  39. package/dist/types/errors.d.ts +9 -1
  40. package/dist/types/examples.d.ts +1 -1
  41. package/dist/types/extensions.d.ts +105 -2
  42. package/dist/types/http-policy.d.ts +3 -0
  43. package/dist/types/init-with.d.ts +10 -1
  44. package/dist/types/pattern-guard.d.ts +10 -0
  45. package/dist/types/project-tests.d.ts +9 -0
  46. package/dist/types/readiness.d.ts +71 -0
  47. package/dist/types/recipes.d.ts +1 -1
  48. package/dist/types/runtime.d.ts +4 -0
  49. package/dist/types/server.d.ts +9 -1
  50. package/dist/types/tooling.d.ts +2 -0
  51. package/dist/types/types.d.ts +13 -0
  52. package/dist/types.js +10 -2
  53. package/dist/typescript-authoring.js +5 -3
  54. package/dist/verify-deployment.js +16 -10
  55. package/examples/body-validation/README.md +16 -0
  56. package/examples/body-validation/example.yaml +17 -0
  57. package/examples/body-validation/tests/requests.json +15 -0
  58. package/examples/body-validation/urlcode.yaml +34 -0
  59. package/examples/coverage-waiver/README.md +8 -0
  60. package/examples/coverage-waiver/example.yaml +16 -0
  61. package/examples/coverage-waiver/functions/notes.mjs +2 -0
  62. package/examples/coverage-waiver/tests/requests.json +3 -0
  63. package/examples/coverage-waiver/urlcode.yaml +10 -0
  64. package/examples/data-dir/README.md +39 -0
  65. package/examples/data-dir/data/welcome.txt +1 -0
  66. package/examples/data-dir/example.yaml +22 -0
  67. package/examples/data-dir/functions/note.mjs +18 -0
  68. package/examples/data-dir/tests/requests.json +6 -0
  69. package/examples/data-dir/urlcode.yaml +6 -0
  70. package/examples/lifecycle/README.md +15 -0
  71. package/examples/lifecycle/example.yaml +19 -0
  72. package/examples/lifecycle/functions/notes.mjs +29 -0
  73. package/examples/lifecycle/tests/requests.json +12 -0
  74. package/examples/lifecycle/urlcode.yaml +29 -0
  75. package/examples/not-found/README.md +10 -0
  76. package/examples/not-found/example.yaml +17 -0
  77. package/examples/not-found/public/404.html +3 -0
  78. package/examples/not-found/public/index.html +3 -0
  79. package/examples/not-found/tests/requests.json +7 -0
  80. package/examples/not-found/urlcode.yaml +7 -0
  81. package/examples/shared-blocks/README.md +11 -0
  82. package/examples/shared-blocks/example.yaml +17 -0
  83. package/examples/shared-blocks/tests/requests.json +7 -0
  84. package/examples/shared-blocks/urlcode.yaml +37 -0
  85. package/llms-full.txt +436 -149
  86. package/llms.txt +44 -6
  87. package/package.json +15 -22
  88. package/recipes/static-page/README.md +9 -0
  89. package/recipes/static-page/public/index.html +11 -0
  90. package/recipes/static-page/recipe.yaml +21 -0
  91. package/recipes/static-page/tests/requests.json +22 -0
  92. package/recipes/static-page/urlcode.yaml +7 -0
  93. package/recipes/static-plus-api/README.md +6 -0
  94. package/recipes/static-plus-api/urlcode.yaml +4 -0
  95. package/recipes/store-crud/README.md +53 -0
  96. package/recipes/store-crud/recipe.yaml +31 -0
  97. package/recipes/store-crud/tests/requests.json +18 -0
  98. package/recipes/store-crud/urlcode.yaml +18 -0
  99. package/schemas/urlcode.schema.json +125 -60
  100. package/skills/urlcode/SKILL.md +53 -26
  101. package/starters/default/AGENTS.md +43 -43
  102. package/starters/page/README.md +14 -0
  103. package/starters/page/public/index.html +12 -0
  104. package/starters/page/tests/requests.json +17 -0
  105. package/starters/page/urlcode.yaml +6 -0
  106. package/.claude-plugin/marketplace.json +0 -18
  107. package/CONTRIBUTING.md +0 -112
  108. package/ROADMAP.md +0 -66
  109. package/docs/AI-AUTHORING.md +0 -338
  110. package/docs/ASSETS.md +0 -107
  111. package/docs/AUTH-BACKUP.md +0 -32
  112. package/docs/AWS.md +0 -86
  113. package/docs/BEST-PRACTICES.md +0 -276
  114. package/docs/BULK.md +0 -79
  115. package/docs/CAPABILITIES.md +0 -192
  116. package/docs/CAPACITY.md +0 -305
  117. package/docs/CI-FOLLOWUP-2026-09-19.md +0 -97
  118. package/docs/CI-RELEASE-AUDIT-2026-09-19.md +0 -322
  119. package/docs/CI.md +0 -147
  120. package/docs/CLOUDFLARE.md +0 -109
  121. package/docs/CODEBASE-AUDIT-2026-09-20.md +0 -284
  122. package/docs/COMPLIANCE.md +0 -239
  123. package/docs/COMPOSING-A-SITE.md +0 -278
  124. package/docs/CONDITIONS.md +0 -74
  125. package/docs/DEPLOYMENT-CHECKS.md +0 -108
  126. package/docs/DEVELOPMENT-PIPELINE.md +0 -270
  127. package/docs/EGRESS.md +0 -125
  128. package/docs/EXTENSIONS.md +0 -438
  129. package/docs/FRAMEWORK.md +0 -217
  130. package/docs/FUNCTION-SECURITY.md +0 -254
  131. package/docs/HTTP.md +0 -129
  132. package/docs/INSTALL.md +0 -128
  133. package/docs/INTERCHANGE.md +0 -134
  134. package/docs/LOAD-TESTING.md +0 -91
  135. package/docs/LOCAL-DEVELOPMENT.md +0 -102
  136. package/docs/MIDDLEWARE-EXAMPLES.md +0 -75
  137. package/docs/MIDDLEWARE.md +0 -102
  138. package/docs/MONITORING.md +0 -115
  139. package/docs/OBSERVABILITY.md +0 -222
  140. package/docs/OPEN-DECISIONS.md +0 -224
  141. package/docs/OPERATIONAL-PROOF.md +0 -41
  142. package/docs/OPERATIONS.md +0 -201
  143. package/docs/ORGANIZATION.md +0 -135
  144. package/docs/PERFORMANCE.md +0 -72
  145. package/docs/PLUGINS.md +0 -271
  146. package/docs/POLICIES.md +0 -211
  147. package/docs/PRERENDER.md +0 -245
  148. package/docs/PROJECT-DIRECTION.md +0 -118
  149. package/docs/PROVIDER-VERIFICATION.md +0 -84
  150. package/docs/READINESS.md +0 -150
  151. package/docs/README.md +0 -87
  152. package/docs/RECIPES.md +0 -99
  153. package/docs/RELEASE-0.4.0-alpha.3.md +0 -50
  154. package/docs/RELEASE-0.4.1.md +0 -73
  155. package/docs/RELEASE-READINESS.md +0 -117
  156. package/docs/RELEASE-SECURITY.md +0 -96
  157. package/docs/RESILIENCE.md +0 -161
  158. package/docs/ROUTING.md +0 -92
  159. package/docs/SANDBOX-REVIEW.md +0 -72
  160. package/docs/SCAFFOLDING.md +0 -70
  161. package/docs/SECURITY-AUDIT.md +0 -164
  162. package/docs/SITE.md +0 -150
  163. package/docs/SPECIFICATION.md +0 -359
  164. package/docs/SPIKE-AI-FRAMEWORK-BENCHMARK.md +0 -288
  165. package/docs/SPIKE-BUSINESS-SUITE.md +0 -1029
  166. package/docs/SPIKE-CORE-LAYERING.md +0 -368
  167. package/docs/SPIKE-DEFAULT-TRUST-MODEL.md +0 -211
  168. package/docs/STANDARDS.md +0 -311
  169. package/docs/STARTERS.md +0 -83
  170. package/docs/STATIC.md +0 -105
  171. package/docs/TOOLING.md +0 -298
  172. package/docs/TUNNELS.md +0 -72
  173. package/docs/TYPESCRIPT-AUTHORING.md +0 -87
  174. package/docs/TYPESCRIPT.md +0 -123
  175. package/docs/VERCEL.md +0 -114
  176. package/docs/VERSION-ALIGNMENT.md +0 -80
  177. package/docs/YAML-GUIDE.md +0 -57
  178. package/docs/YAML-REFERENCE.md +0 -449
  179. package/docs/archive/2026-09-19/EXTENSION-IMPLEMENTATION.md +0 -68
  180. package/docs/archive/2026-09-19/MANAGEMENT-SECURITY.md +0 -102
  181. package/docs/archive/2026-09-19/NEXT-PHASE-PLAN.md +0 -108
  182. package/docs/archive/2026-09-19/NEXT-STEPS.md +0 -646
  183. package/docs/archive/2026-09-19/OPEN-DECISIONS.md +0 -277
  184. package/docs/archive/2026-09-19/RELEASE-SECURITY.md +0 -186
  185. package/docs/archive/2026-09-19/ROADMAP.md +0 -387
  186. package/docs/archive/2026-09-19/SPIKE-EXTENSION-MODEL.md +0 -430
  187. package/docs/archive/2026-09-19/SPIKE-EXTENSIONS.md +0 -492
  188. package/docs/archive/2026-09-19/SPIKE-LAMBDA-COMPILE.md +0 -365
  189. package/docs/archive/2026-09-19/SPIKE-MONOREPO.md +0 -778
  190. package/docs/archive/2026-09-19/USABILITY-REVIEW.md +0 -139
  191. package/docs/archive/README.md +0 -28
  192. package/docs/policies/agents.md +0 -182
  193. package/docs/policies/cache.md +0 -152
  194. package/docs/policies/compression.md +0 -169
  195. package/docs/policies/contract.md +0 -52
  196. package/docs/policies/hardened.md +0 -56
  197. package/docs/policies/interoperability.md +0 -169
  198. package/docs/policies/operations.md +0 -45
  199. package/docs/policies/security.md +0 -161
  200. package/docs/policies/throttle.md +0 -103
  201. package/docs/yaml/assets.md +0 -36
  202. package/docs/yaml/conditions.md +0 -20
  203. package/docs/yaml/functions.md +0 -168
  204. package/docs/yaml/middleware.md +0 -31
  205. package/docs/yaml/organization.md +0 -74
  206. package/docs/yaml/policies.md +0 -37
  207. package/docs/yaml/redirects.md +0 -64
  208. package/docs/yaml/responses.md +0 -57
  209. package/docs/yaml/site.md +0 -24
  210. package/packaging/claude-plugin/.claude-plugin/plugin.json +0 -19
  211. package/packaging/claude-plugin/skills/urlcode-authoring/SKILL.md +0 -120
  212. package/packaging/claude-plugin/skills/urlcode-operations/SKILL.md +0 -108
@@ -1,96 +0,0 @@
1
- # Candidate and release security
2
-
3
- The [development pipeline](DEVELOPMENT-PIPELINE.md) is the operational runbook
4
- for CI selection, release planning, tags, publication and recovery. The
5
- [September 19 audit](CI-RELEASE-AUDIT-2026-09-19.md) explains the changes;
6
- [the prior process and failure history](archive/2026-09-19/RELEASE-SECURITY.md)
7
- is retained as a historical record, not current instructions.
8
-
9
- The license remains Apache-2.0. A successful release is not an independent
10
- security assessment, hostile multi-tenant readiness claim or deployment proof.
11
- See [release readiness](RELEASE-READINESS.md) and [security](../SECURITY.md).
12
-
13
- ## Source and validation
14
-
15
- A release must name the checked-out commit, already on main, with successful
16
- full verification of that exact SHA and CodeQL analysis. Full verification
17
- means a successful nightly or manual `ci.yml` run across every supported OS/Node
18
- combination; the compact push/PR matrix alone does not authorize publication. Package manifests,
19
- lockfile versions and tag names must agree. Published peer floors must exist and
20
- extension tests must resolve the published packages, not workspace source.
21
- The candidate builds all package archives once using the digest-pinned Node
22
- image from Dockerfile; publishers promote those exact signed bytes. The builder
23
- installs Git from Debian for repository-fixture tests; Git is a test dependency,
24
- not an addition to the runtime image or npm package. Locked dependencies,
25
- verification, runtime audit, package installation tests and local drills precede
26
- packing. Build commands in that container receive no GitHub token.
27
-
28
- The candidate workflow stores artifacts without publishing. A tagged release
29
- publishes npm only when `PUBLISH_NPM=true` and core images only when
30
- `PUBLISH_CONTAINER=true`. Candidate and release artifacts are retained for 90 days, and each package
31
- GitHub release stores the complete signed candidate bundle. Retries verify and
32
- reuse original retained or durable bytes; missing originals fail closed. Keep independent last-good artifacts and
33
- rehearse deployment rollback; Actions retention is not an archival guarantee.
34
-
35
- ## Identity and provenance
36
-
37
- The four per-package workflow filenames are stable npm trusted-publisher
38
- identities. npm publishing uses OIDC, npm 11.5.1 and a supported Node version,
39
- with no long-lived npm token. Renaming a workflow or changing the repository
40
- requires a reviewed registry trust migration. Successful preparation does not
41
- prove the registry-side identity permits direct publication.
42
-
43
- `actions/attest` signs the candidate files with GitHub OIDC/Sigstore provenance.
44
- The candidate bundle includes all four archives, dependency SBOM, build manifest,
45
- train metadata, checksums and Homebrew formula. Each publisher retains that
46
- bundle and publishes only its selected npm archive. New annotated version tags
47
- pin the candidate run ID and signed-manifest SHA256. The run ID is also bound
48
- into the manifest; the digest prevents another attempt of that run from
49
- substituting different artifacts. The core manifest records source SHA, lockfile hash, Node and
50
- TypeScript versions and emitted-file hashes. `dist/` is built, never committed.
51
-
52
- Verify an artifact with `gh attestation verify <tarball> --repo
53
- jimhoyd-com/urlcode`, and constrain verification to the expected workflow,
54
- source ref and source digest for the selected release. Compare the source and
55
- artifact hashes to the intended release, rather than accepting any signed file.
56
- A signature establishes provenance, not safety or reproducibility. The npm SBOM
57
- is not a complete OS/container SBOM; hosted runners remain platform-controlled.
58
-
59
- ## Immutability and channels
60
-
61
- Never delete/recreate or move a version tag to repair a workflow. A source fix
62
- requires a new version. Repeating publication of an existing npm version requires
63
- identical SHA-512 integrity. GitHub assets are compared and missing assets added;
64
- existing unequal assets are never clobbered. Transient registry errors fail
65
- closed rather than count as an unpublished version.
66
-
67
- Alpha versions use npm/GHCR `alpha` and GitHub prerelease classification.
68
- Explicit stable versions use npm `latest` and normal GitHub releases. Only the
69
- stable core release advances GitHub `latest`, so the core installer cannot pick
70
- an extension release. Stable preparation removes Changesets prerelease mode;
71
- existing alpha artifacts, tags and channel pointers remain unchanged. Mutable npm
72
- and container channels cannot regress to an older version. Existing core image
73
- versions are reused only with matching source labels; unlabeled historical
74
- images require a reviewed migration rather than an inferred identity.
75
-
76
- The coordinator verifies candidate availability and provenance before creating
77
- any version tag, then creates one at a time and waits for successful publication
78
- and consumer-facing registry installability before releasing dependents. Shared publication concurrency avoids cross-version races.
79
- The active immutable-tag rule blocks release tag updates/deletions with no
80
- bypass actors; its configuration is in `.github/rulesets/release-tags.json`. No automation needs permission to bypass main checks or approve
81
- its own PR. A repository-scoped GitHub App is the preferred eventual automation
82
- identity; a narrowly scoped fine-grained PAT can support a maintainer script.
83
-
84
- ## Remaining validation
85
-
86
- Keep full supported-OS/Node coverage and archive-install tests green. The actual
87
- publish path, OIDC trust for every package, tag protection, GHCR behavior and
88
- partial-failure recovery must be verified on an authorized release; local tests
89
- and workflow inspection cannot prove them. The release helpers do not alter
90
- historical npm channels, GitHub flags, tags or registry artifacts.
91
-
92
- The coordinated `.3` release proved the existing OIDC identities, but exposed
93
- missing-artifact retry behavior tracked in #223. New workflows fail closed or
94
- recover verified durable bytes; old immutable tags retain their original
95
- workflow code. The new promotion path still needs a future explicitly authorized
96
- release rehearsal; implementing it does not publish a new version.
@@ -1,161 +0,0 @@
1
- # DDoS, overload and recovery playbook
2
-
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 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.
9
-
10
- ## Defense responsibilities
11
-
12
- | Layer | Operator action | What URLCode provides today |
13
- |---|---|---|
14
- | Upstream network | Hosting/CDN DDoS mitigation and an escalation contact; protect bandwidth before it reaches the origin | No network-level mitigation service |
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` |
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 |
18
- | Release/recovery | Known-good artifacts, candidate verification, traffic switching, rollback drills | Local validation/tests/audit; explicit snapshot reload; no orchestration |
19
-
20
- NGINX provides request-rate controls and connection controls keyed by values such
21
- as client IP. Their counters do not cover every stage of connection handling;
22
- connection limiting starts after request headers are read. Treat them as layers,
23
- not a complete volumetric defense. Use aggregate budgets too, and test legitimate
24
- users behind shared NATs. Sources: [request limits](https://nginx.org/en/docs/http/ngx_http_limit_req_module.html),
25
- [connection limits](https://nginx.org/en/docs/http/ngx_http_limit_conn_module.html).
26
-
27
- If a CDN/proxy sits ahead of your ingress, configure trusted client-IP restoration
28
- for only that provider's verified proxy addresses. Never use arbitrary incoming
29
- X-Forwarded-For as the rate-limit identity. Keep the origin firewall/private
30
- network restricted to the intended ingress. URLCode deliberately does not trust
31
- forwarded headers to construct its public URL; set `--origin` explicitly.
32
-
33
- The optional [`throttle` policy](policies/throttle.md) adds a per-client budget
34
- inside the runtime, and the [`agents` policy](policies/agents.md) refuses listed
35
- User-Agents before a body is read or the function/middleware call starts,
36
- trusted or sandboxed. Both are a second
37
- layer behind the edge, not a replacement for it: counters are per instance,
38
- the socket and admission limits still apply first, and a flood still costs
39
- connections. The client identity is the socket peer unless
40
- `urlcode serve --trusted-proxies <cidr,...>` names the proxies allowed to set
41
- `X-Forwarded-For`; a forwarded header from any other peer is ignored, and an
42
- unresolved client shares one bucket rather than being exempt. See
43
- [policies](POLICIES.md).
44
-
45
- Cache only responses whose semantics permit public caching. Never cache private,
46
- credential-bearing or personalized responses as a blanket mitigation. Default
47
- function/redirect responses are no-store; assets default to revalidation. Use
48
- versioned immutable asset URLs when appropriate. An NGINX/native-route exporter
49
- is not implemented; adding a reverse proxy does not bypass runtime execution.
50
-
51
- ## Threats and behavior to expect
52
-
53
- | Failure or traffic pattern | Current consequence | Mitigation / recovery |
54
- |---|---|---|
55
- | High-rate ordinary requests | Event-loop, logging, bandwidth or socket exhaustion | Filter/rate-limit upstream; scale only within measured resource/cost budgets |
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 |
58
- | Guest invalid response or failure | Generic 502 | Compare with last deployment; run fixture on a private candidate |
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 |
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 |
61
- | Slow response readers | Retain admission/output buffers until finish/disconnect; 15-second socket inactivity timeout | Proxy downstream timeouts and connection controls |
62
- | Corrupt YAML/code/asset update | Dev/explicit reload rejects candidate and retains old snapshot | Restore reviewed files; verify actual active version; do not assume edit activated |
63
- | Host OOM or process crash | In-process recovery cannot preserve service | Supervisor with backoff; route traffic to healthy replica; restore tested image |
64
- | Disk/log sink trouble | Logs may drop; startup/config reads can fail | Disk/RSS alerts, bounded retention and log-drop monitoring |
65
- | Bandwidth flood at origin link | App may be unreachable regardless of worker limits | Hosting/network mitigation provider escalation |
66
-
67
- A 503/504 can also be an intentional application response. Runtime logs do not
68
- include a per-route reason code, so status alone cannot prove an attack or a
69
- capacity failure. Correlate ingress metrics, release changes and controlled
70
- probes. Do not add secrets, full query strings or request bodies to diagnostics.
71
-
72
- ## Prepare before exposure
73
-
74
- - Name an incident owner, backup and hosting/ingress escalation contacts. Decide
75
- who can change filters, switch traffic, approve rollback and rotate credentials.
76
- - Retain known-good runtime/app commits, locks, images and compatible policy files.
77
- Keep protected backups outside the host. Secret values belong in your secret
78
- system, never the artifact archive or Git.
79
- - Keep at least one verified rollback path; use redundant replicas if your
80
- availability objective needs them. A single instance cannot promise continuity
81
- through a host failure or full restart.
82
- - Define acceptable successful RPS, p95/p99, error rates and resource utilization
83
- using [capacity tests](CAPACITY.md). Set alerts for deviations, readiness failures,
84
- restarts/OOM, memory pressure, bandwidth, log drops and infrastructure spend.
85
- - Restrict `/_urlcode/*` to operator access at ingress. Keep liveness and readiness
86
- separate: busy workers do not make readiness fail; missing workers do.
87
- - Use bounded retries with backoff/jitter where retries are safe. Do not retry
88
- non-idempotent requests blindly or create a synchronized retry storm.
89
-
90
- ## Incident procedure
91
-
92
- 1. **Confirm and record.** Note start time, affected service, runtime/app/image
93
- versions, error/latency trends and recent changes. Check upstream reachability,
94
- process health and readiness through an operator-only path. Distinguish an
95
- ingress incident from a bad deployment or legitimate traffic increase.
96
- 2. **Protect capacity.** Apply reviewed ingress filters/admission limits and
97
- contact the mitigation provider for network saturation. Restrict an abusive
98
- route at ingress if needed. Preserve working simple routes where possible.
99
- Do not raise worker counts/timeouts blindly or scale without a spend ceiling.
100
- 3. **Stabilize.** Remove failed replicas from traffic. If a release is implicated,
101
- switch to the retained verified revision; avoid repeatedly rebuilding snapshots
102
- under attack. For a bad function, an ingress block is faster than a YAML edit
103
- that still needs deployment and may invalidate binding policy.
104
- 4. **Restore deliberately.** Start a candidate with the intended runtime/app,
105
- assets, bindings and matching external policy. Check private readiness and
106
- representative response assertions. Switch a small traffic share first when
107
- supported, observe, then increase. Drain the old instance before stopping it.
108
- 5. **Verify recovery.** Confirm successful traffic, latency, RSS and error rates
109
- return to the agreed envelope. Check native and programmable routes, HEAD,
110
- redirect destinations and critical asset behavior. Readiness alone is not enough.
111
- 6. **Close and improve.** Record cause, actions, outage duration, lost telemetry,
112
- customer impact and costs. Keep useful mitigations; remove temporary broad
113
- restrictions carefully. Add a regression fixture or drill for the failure.
114
-
115
- Restarting can replace failed workers, but it does not fix a malicious request
116
- pattern, broken release or saturated link. Rotate credentials if exposure is
117
- suspected, not automatically for every traffic spike. Redeploy to load new values;
118
- serve does not refresh them. No credential values should enter incident notes.
119
-
120
- ## Recovery objectives and data
121
-
122
- Choose RTO (acceptable recovery time) and RPO (acceptable data loss) per deployment;
123
- URLCode does not promise values. A stateless YAML deployment can be recreated
124
- from retained immutable artifacts, subject to recovery of DNS/ingress and secret
125
- access. Log loss is possible under pressure and has a separate retention target.
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.
128
-
129
- A rollback needs the previous app/runtime and its matching policy and compatible
130
- secret bindings. The health version combines configuration and asset digests;
131
- it is not a complete code/release identity. Track Git/image identities externally.
132
- Browser/CDN-cached permanent redirects may continue after rollback; choose cache
133
- lifetimes accordingly and plan edge purges. Rollback cannot undo external side
134
- effects, and current URLCode has no state migration/restore control plane.
135
-
136
- ## Safe recovery drills and pass criteria
137
-
138
- Run only against owned, isolated test deployments with fixed request/time budgets
139
- and stop conditions. Coordinate with the hosting provider for any network stress
140
- exercise; do not generate uncontrolled floods or target third-party destinations.
141
-
142
- | Drill | Evidence to retain |
143
- |---|---|
144
- | Saturate the function pool with bounded test handlers | Excess work receives bounded failures; native probe remains observable; normal traffic recovers afterward |
145
- | Handler timeout/worker replacement | 504 observed, replacement or bounded unavailable state understood, no leaked request data |
146
- | Invalid dev reload | Old response stays active; rejection logged; corrected candidate activates |
147
- | Kill a disposable replica | Supervisor backoff and health-based routing work; successful capacity of survivors measured |
148
- | Roll back a bad release | Prior exact response restored with matching policy; actual recovery time recorded |
149
- | Restore on a clean host | Artifacts, policy and secure bindings suffice; assets and all critical fixtures pass |
150
- | Simulate a slow/full log sink | Dropped-log reporting is observed; service and disk usage remain bounded |
151
- | Remove mitigation after a bounded overload | Latency/errors/resources return to baseline without a restart loop |
152
-
153
- Existing unit/HTTP tests cover several component failures; these deployment drills
154
- are a plan, not evidence they have all been run. Remaining gaps include distributed
155
- admission/fairness, production metrics/exporters, dedicated slow-reader protection,
156
- provider-level mitigation validation and sustained failure/soak testing. These are
157
- free-runtime/operator requirements.
158
-
159
- Core has no durable store of its own to recover; a durable-state extension is
160
- responsible for its own management listener, backup and recovery procedure. No
161
- such extension ships today — `urlcode-dynamic-link` has been retired.
package/docs/ROUTING.md DELETED
@@ -1,92 +0,0 @@
1
- # Route matching
2
-
3
- ## Supported path patterns
4
-
5
- URLCode matches paths, not regular expressions. Matching is case-sensitive and
6
- covers the whole path; trailing slashes are significant. Query strings are inputs,
7
- not part of the route key.
8
-
9
- | Route key | Matches | Does not match |
10
- |---|---|---|
11
- | `/go` | `/go`, `/go?campaign=spring` | `/Go`, `/go/`, `/go/extra` |
12
- | `/r/{code}` | `/r/abc`, `/r/123` | `/r/`, `/r/abc/extra` |
13
- | `/r/{code}/details` | `/r/abc/details` | `/r/abc/other/details` |
14
- | `/assets/*` with a `static` handler | Files under `/assets/`, including `/assets/css/site.css` | `/assets`, `/assets-other/site.css` |
15
-
16
- A `{parameter}` captures exactly one nonempty path segment. It is **not greedy**:
17
- it cannot consume slashes or the rest of a URL. Declare each path parameter as a
18
- required string in `parameters`. Encoded slashes (`%2F`) and backslashes are
19
- rejected, so encoding a slash cannot bypass this rule.
20
-
21
- Only static directory handlers support `/*`, at the end of an otherwise literal
22
- path. It covers the remaining nested file path; it is not a named capture or a
23
- regex operator. Matching a mount does not guarantee a response file exists:
24
- missing files return 404. It is not a catch-all for functions or redirects.
25
-
26
- No regex routes, greedy parameters, optional segments, partial-segment parameters,
27
- `**` globs, or regex constraints inside `{code}` are implemented. Characters such
28
- as `.` and `+` have no regex meaning in a literal path. Do not paste a regex into
29
- a route key: some regex-looking text is legal literal text, while unsupported
30
- syntax may fail validation. Parameter-schema `pattern` is also unsupported.
31
-
32
- ## Precedence and ambiguity
33
-
34
- 1. An exact literal route wins.
35
- 2. A parameterized route wins next; more literal segments means higher priority.
36
- 3. Static mounts follow; the longest matching mount prefix wins.
37
-
38
- YAML order and include-file order do not decide priority. For example, `/r/help`
39
- wins over `/r/{code}`. Among parameter routes, `/r/fixed/{item}` wins over
40
- `/r/{group}/{item}` for `/r/fixed/book`. The latter still handles `/r/team/book`.
41
-
42
- Equally specific overlapping parameter routes fail configuration validation.
43
- For example, `/r/{code}` and `/r/{name}` conflict, as do `/a/{x}` and `/{y}/b`.
44
- Disjoint patterns with equal specificity are allowed. Duplicate exact route keys
45
- also fail, including duplicates across included files.
46
-
47
- Selection happens before method, enabled/expiry and input validation. A selected
48
- route returning 405, 404, 410 or 400 does not fall through to another route.
49
- Likewise, a missing file in the longest selected static mount does not fall back
50
- to a shorter mount. See [HTTP](HTTP.md) and [the contract](SPECIFICATION.md).
51
-
52
- ## Adding a configured redirect today
53
-
54
- ```sh
55
- urlcode add https://example.com/new-page --alias new-link --project ./my-links
56
- ```
57
-
58
- This validates and writes `/new-link` to the project's `urlcode.yaml`. It is a
59
- local authoring command, not a live route-registration API. It does not commit
60
- to Git or contact a running server. Commit/review the resulting definition as
61
- part of your normal deployment workflow.
62
-
63
- | Running mode | How new YAML routes become active |
64
- |---|---|
65
- | `urlcode dev` | Watches ordinary project files about every 500 ms, builds and validates a complete replacement snapshot, then swaps it in without restarting the HTTP server |
66
- | `urlcode serve` | Fixed snapshot; restart/redeploy to activate configuration changes |
67
- | Embedded server API | The returned server exposes `await app.reload()` for an explicit full snapshot replacement; this is not an HTTP admin endpoint |
68
-
69
- Reload is a full configuration/source/asset snapshot rebuild, not an incremental
70
- single-route insertion. Existing requests finish on the old snapshot; new
71
- requests use the replacement once it is ready. An invalid candidate leaves the
72
- previous snapshot serving. Watcher exclusions and binding-policy rules still
73
- apply: configuration changes invalidate revision-pinned external binding grants.
74
- See [reload details](SPECIFICATION.md#reload-and-status) and
75
- [operator policy](FUNCTION-SECURITY.md).
76
-
77
- ## A TinyURL-style service: application data versus route definitions
78
-
79
- For a service where visitors constantly create short links, the intended design
80
- is one stable route such as `/r/{code}` plus a lookup of `code -> destination` in
81
- application-owned persistent data. A new short code then changes data, not YAML,
82
- and needs no route rebuild or service restart. The same distinction applies to
83
- any per-visitor session record. Git owns route behavior and code; user-created records have
84
- their own persistence, backup and export lifecycle.
85
-
86
- Core has no native handler for this today: the `link` handler that implemented
87
- it was removed. The `urlcode-dynamic-link` extension package that replaced it
88
- has been retired and unpublished, so a project needing stored short links owns
89
- that storage itself.
90
-
91
- Functions still cannot access databases, the filesystem or network directly.
92
- General application state and realtime sessions remain future work.
@@ -1,72 +0,0 @@
1
- # Independent sandbox review gate
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
-
10
- Status: **external assessment not performed**. Internal source review, CI, CodeQL
11
- and adversarial regressions are useful evidence, not an independent sign-off.
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`*.
17
-
18
- ## Review package
19
-
20
- Freeze an exact runtime commit, lockfile, container digest, app/policy examples
21
- with synthetic credentials, Node/SQLite/QuickJS/WASM versions and deployment
22
- resource settings. Give a reviewer independent of the implementation access to:
23
-
24
- - `src/functions.ts`, worker/guest implementation and `src/policy.ts`: VM creation,
25
- module graph, import denial, export validation, binding grants and message bridge.
26
- - `src/config.ts`, `src/config-worker.ts`, router and assets: parser/schema limits,
27
- file containment, activation, memory amplification and host-side compilation.
28
- - HTTP server and policy: request smuggling, admission, body/response framing.
29
- - `test/sandbox.test.ts`, middleware/config/logging/reload tests, Dockerfile,
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`.
35
-
36
- Run `npm ci --ignore-scripts`, `npm run verify`, `npm run test:package`, and
37
- `node scripts/operational-drills.ts`. Record the exact commands and result files.
38
- CI adds a constrained-container test.
39
- Use only disposable local/staging systems with synthetic data.
40
-
41
- ## Threat model and required probes
42
-
43
- An attacker controls project YAML, included files, function/module source, public
44
- requests, request bodies, exported values and static content. The operator controls
45
- the host, deployment, external policy, credentials, database and project activation.
46
- Guests receive only explicitly granted values; granted secrets can be returned by
47
- that guest. QuickJS/WASM is the code boundary; worker threads alone are not.
48
-
49
- Probe module cycles and loader escapes, malformed bridge messages, huge strings,
50
- arrays and ArrayBuffers, deep prototypes, exceptions/getters, asynchronous jobs,
51
- infinite loops, repeated worker replacement, capability confusion, cross-route
52
- and cross-invocation leakage, parser/schema amplification, filesystem races,
53
- slow peers, reload overlap and process/container exhaustion. Test unauthorized
54
- management reads/writes, stale credentials, expiry boundaries, malformed policy,
55
- CAS races, audit failures, poisoned databases and full disks. Verify native routes
56
- and health/recovery remain useful after each bounded guest failure.
57
-
58
- Trusted computing base includes Node/V8, QuickJS/WASM, bindings, dependencies,
59
- OS/kernel, container runtime, secrets/policy administration and build infrastructure.
60
- Current containment does not provide tenant CPU fairness, per-tenant process RSS,
61
- networked microVM isolation, or a proof against engine vulnerabilities. Worker heap
62
- limits exclude external buffers and do not replace a process/container memory cap.
63
-
64
- ## Closure criteria and deliverable
65
-
66
- The maintainer records reviewer identity/independence, scope, dates, tested commit
67
- and environment, methodology, findings with reproductions, severity, remediations
68
- and retest evidence. All critical/high boundary findings must be fixed and retested;
69
- residual risks require explicit owner acceptance. Publish a sanitized assessment
70
- summary and retain exploit details privately through GitHub security advisories.
71
- Reopen review for new capabilities, engine/bridge changes or major isolation changes.
72
- An external review is necessary here, but still does not certify production capacity.
@@ -1,70 +0,0 @@
1
- # Create placeholders from YAML
2
-
3
- Write `urlcode.yaml` first, then generate its missing local references:
4
-
5
- ```sh
6
- urlcode scaffold --project ./my-links --dry-run
7
- urlcode scaffold --project ./my-links
8
- urlcode validate --project ./my-links --local
9
- ```
10
-
11
- The project and entry YAML must already exist. `--dry-run` reports the same plan
12
- without writing. Existing files are preserved byte-for-byte; the command never
13
- adds exports to existing modules or overwrites implementations. Run it again after
14
- adding declarations. No application code is executed and no credentials are read.
15
-
16
- For example:
17
-
18
- ```yaml
19
- version: "1"
20
- routes:
21
- /hello:
22
- function:
23
- source: functions/hello.mjs
24
- export: handle
25
- middleware:
26
- - source: middleware/auth.mjs
27
- /about:
28
- page:
29
- file: public/about.html
30
- /assets/*:
31
- static:
32
- directory: public/assets
33
- index: index.html
34
- ```
35
-
36
- This creates the two modules, an HTML page and the static directory/index.
37
- Both modules return **501 Not implemented** until replaced. In particular, an
38
- auth middleware placeholder does not silently allow requests through. Named
39
- exports sharing a new module are combined; using the same export as both a
40
- function and middleware is rejected as ambiguous. Configured arguments remain
41
- in YAML for your implementation to use.
42
-
43
- | Reference | Missing-file behavior |
44
- |---|---|
45
- | Included YAML | Creates `version: "1"` and empty routes; reports that definitions are still required |
46
- | Function/middleware `.js` or `.mjs` | Creates requested exports returning 501 |
47
- | Page/download `.html` or `.htm` | Creates a clearly labeled placeholder page |
48
- | `.txt`, `.md`, `.csv`, `.css`, `.js`, `.mjs`, `.json` assets | Creates minimal placeholder text; JSON is `{}` |
49
- | Static directory and configured index | Creates directories and index placeholder; cannot infer the rest of a site |
50
- | PDF, image, archive or other asset | Reports unresolved; does not fabricate a corrupt binary file |
51
- | Environment/secret references | Lists required external names; creates no values, policy grants or dotenv files |
52
- | Link collection | Reports the required operator binding; creates no database or records |
53
-
54
- All schema-valid route declarations, including disabled ones, are considered.
55
- Existing included files are read; nested includes and duplicate routes fail.
56
- Scaffolding checks schema and file safety, not complete routing semantics or
57
- business correctness. Files use safe project-relative paths; traversal, hidden
58
- paths, sensitive names, symlinks, hardlinked existing files and conflicting uses
59
- are rejected. Keep the project operator-owned while writing. Planning errors
60
- make no changes; an I/O failure while writing can leave some new placeholders,
61
- which a subsequent run preserves. No transaction spans the whole filesystem.
62
-
63
- After editing placeholders, run `validate`, add explicit response fixtures and
64
- run `test` and `audit`. Validation catches missing modules/imports/exports/assets
65
- and bindings. It does not prove that placeholder logic is complete. The report
66
- always says `needsImplementation: true`; it is not a production-readiness gate.
67
- Scaffolding does not recursively invent dependencies imported by existing code,
68
- crawl HTML/CSS links, generate binary content, or implement your business logic.
69
- See [readiness checks](READINESS.md) and [asset behavior](ASSETS.md).
70
-