@jimhoyd/urlcode 0.3.0
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/CONTRIBUTING.md +80 -0
- package/LICENSE +202 -0
- package/NOTICE +20 -0
- package/README.md +342 -0
- package/ROADMAP.md +248 -0
- package/SECURITY.md +40 -0
- package/data/agents/LICENSES/ai-robots-txt.txt +24 -0
- package/data/agents/LICENSES/crawler-user-agents.txt +23 -0
- package/data/agents/ai-crawlers.json +1240 -0
- package/data/agents/crawlers.json +10515 -0
- package/data/agents/index.d.ts +3 -0
- package/data/agents/index.js +2453 -0
- package/data/agents/monitoring.json +1520 -0
- package/data/agents/seo.json +3865 -0
- package/dist/BUILD-MANIFEST.json +60 -0
- package/dist/adapters.js +59 -0
- package/dist/agent-lists.js +59 -0
- package/dist/assets.js +129 -0
- package/dist/authoring.js +68 -0
- package/dist/aws.js +110 -0
- package/dist/build-cloudflare.js +164 -0
- package/dist/cli.js +185 -0
- package/dist/client-address.js +85 -0
- package/dist/cloudflare.js +165 -0
- package/dist/compliance-rules/baseline.js +98 -0
- package/dist/compliance-rules/privacy.js +38 -0
- package/dist/compliance-rules/shared.js +62 -0
- package/dist/compliance-rules/strict.js +61 -0
- package/dist/compliance.js +219 -0
- package/dist/config-worker.js +9 -0
- package/dist/config.js +172 -0
- package/dist/errors.js +8 -0
- package/dist/function-sources.js +54 -0
- package/dist/function-worker.js +105 -0
- package/dist/functions.js +174 -0
- package/dist/guest-api.js +114 -0
- package/dist/header-validation.js +18 -0
- package/dist/http-policy.js +74 -0
- package/dist/http-response.js +84 -0
- package/dist/index.js +11 -0
- package/dist/link-api.js +136 -0
- package/dist/link-cli.js +141 -0
- package/dist/link-events.js +76 -0
- package/dist/link-records.js +31 -0
- package/dist/link-store-worker.js +150 -0
- package/dist/link-store.js +250 -0
- package/dist/logging.js +22 -0
- package/dist/management-policy.js +41 -0
- package/dist/match.js +124 -0
- package/dist/observability.js +242 -0
- package/dist/plugins.js +74 -0
- package/dist/policies/agents.js +248 -0
- package/dist/policies/cache.js +297 -0
- package/dist/policies/compression.js +187 -0
- package/dist/policies/security.js +0 -0
- package/dist/policies/throttle.js +131 -0
- package/dist/policies.js +142 -0
- package/dist/policy.js +55 -0
- package/dist/prerender.js +165 -0
- package/dist/project-tests.js +23 -0
- package/dist/readiness.js +216 -0
- package/dist/router.js +166 -0
- package/dist/runtime.js +244 -0
- package/dist/scaffold.js +0 -0
- package/dist/scripts/operational-drills.js +75 -0
- package/dist/server.js +270 -0
- package/dist/site.js +0 -0
- package/dist/sqlite-version.js +6 -0
- package/dist/types/adapters.d.ts +12 -0
- package/dist/types/agent-lists.d.ts +5 -0
- package/dist/types/assets.d.ts +13 -0
- package/dist/types/authoring.d.ts +2 -0
- package/dist/types/aws.d.ts +35 -0
- package/dist/types/build-cloudflare.d.ts +14 -0
- package/dist/types/cli.d.ts +2 -0
- package/dist/types/client-address.d.ts +9 -0
- package/dist/types/cloudflare.d.ts +75 -0
- package/dist/types/compliance-rules/baseline.d.ts +12 -0
- package/dist/types/compliance-rules/privacy.d.ts +6 -0
- package/dist/types/compliance-rules/shared.d.ts +24 -0
- package/dist/types/compliance-rules/strict.d.ts +9 -0
- package/dist/types/compliance.d.ts +119 -0
- package/dist/types/config-worker.d.ts +1 -0
- package/dist/types/config.d.ts +21 -0
- package/dist/types/errors.d.ts +7 -0
- package/dist/types/function-sources.d.ts +21 -0
- package/dist/types/function-worker.d.ts +1 -0
- package/dist/types/functions.d.ts +92 -0
- package/dist/types/guest-api.d.ts +16 -0
- package/dist/types/header-validation.d.ts +2 -0
- package/dist/types/http-policy.d.ts +39 -0
- package/dist/types/http-response.d.ts +43 -0
- package/dist/types/index.d.ts +11 -0
- package/dist/types/link-api.d.ts +30 -0
- package/dist/types/link-cli.d.ts +36 -0
- package/dist/types/link-events.d.ts +27 -0
- package/dist/types/link-records.d.ts +11 -0
- package/dist/types/link-store-worker.d.ts +1 -0
- package/dist/types/link-store.d.ts +130 -0
- package/dist/types/logging.d.ts +9 -0
- package/dist/types/management-policy.d.ts +9 -0
- package/dist/types/match.d.ts +81 -0
- package/dist/types/observability.d.ts +104 -0
- package/dist/types/plugins.d.ts +27 -0
- package/dist/types/policies/agents.d.ts +86 -0
- package/dist/types/policies/cache.d.ts +82 -0
- package/dist/types/policies/compression.d.ts +41 -0
- package/dist/types/policies/security.d.ts +37 -0
- package/dist/types/policies/throttle.d.ts +55 -0
- package/dist/types/policies.d.ts +36 -0
- package/dist/types/policy.d.ts +21 -0
- package/dist/types/prerender.d.ts +31 -0
- package/dist/types/project-tests.d.ts +13 -0
- package/dist/types/readiness.d.ts +121 -0
- package/dist/types/router.d.ts +11 -0
- package/dist/types/runtime.d.ts +91 -0
- package/dist/types/scaffold.d.ts +17 -0
- package/dist/types/server.d.ts +37 -0
- package/dist/types/site.d.ts +12 -0
- package/dist/types/sqlite-version.d.ts +1 -0
- package/dist/types/types.d.ts +332 -0
- package/dist/types/vercel.d.ts +12 -0
- package/dist/types.js +177 -0
- package/dist/vercel.js +65 -0
- package/docs/AI-AUTHORING.md +113 -0
- package/docs/ASSETS.md +106 -0
- package/docs/AWS.md +77 -0
- package/docs/BEST-PRACTICES.md +267 -0
- package/docs/CAPACITY.md +208 -0
- package/docs/CLOUDFLARE.md +110 -0
- package/docs/COMPLIANCE.md +242 -0
- package/docs/DYNAMIC-LINKS.md +561 -0
- package/docs/FUNCTION-SECURITY.md +113 -0
- package/docs/HTTP.md +129 -0
- package/docs/INSTALL.md +90 -0
- package/docs/LOAD-TESTING.md +91 -0
- package/docs/LOCAL-DEVELOPMENT.md +99 -0
- package/docs/MANAGEMENT-SECURITY.md +82 -0
- package/docs/MIDDLEWARE.md +83 -0
- package/docs/MONITORING.md +132 -0
- package/docs/OBSERVABILITY.md +229 -0
- package/docs/OPERATIONAL-PROOF.md +42 -0
- package/docs/OPERATIONS.md +207 -0
- package/docs/ORGANIZATION.md +135 -0
- package/docs/PERFORMANCE.md +72 -0
- package/docs/PLUGINS.md +234 -0
- package/docs/POLICIES.md +489 -0
- package/docs/PRERENDER.md +193 -0
- package/docs/PROJECT-DIRECTION.md +51 -0
- package/docs/READINESS.md +125 -0
- package/docs/README.md +58 -0
- package/docs/RELEASE-READINESS.md +95 -0
- package/docs/RELEASE-SECURITY.md +72 -0
- package/docs/RESILIENCE.md +160 -0
- package/docs/ROUTING.md +95 -0
- package/docs/SANDBOX-REVIEW.md +59 -0
- package/docs/SCAFFOLDING.md +72 -0
- package/docs/SECURITY-AUDIT.md +124 -0
- package/docs/SITE.md +150 -0
- package/docs/SPECIFICATION.md +232 -0
- package/docs/SPIKE-EXTENSIONS.md +475 -0
- package/docs/STANDARDS.md +303 -0
- package/docs/STARTERS.md +51 -0
- package/docs/TUNNELS.md +75 -0
- package/docs/TYPESCRIPT.md +102 -0
- package/docs/VERCEL.md +107 -0
- package/docs/YAML-GUIDE.md +521 -0
- package/docs/YAML-REFERENCE.md +328 -0
- package/docs/policies/agents.md +182 -0
- package/docs/policies/cache.md +139 -0
- package/docs/policies/compression.md +168 -0
- package/docs/policies/security.md +160 -0
- package/docs/policies/throttle.md +103 -0
- package/examples/assets/.env.example +1 -0
- package/examples/assets/.gitattributes +2 -0
- package/examples/assets/Makefile +30 -0
- package/examples/assets/README.md +18 -0
- package/examples/assets/functions/hello.mjs +3 -0
- package/examples/assets/gitignore.template +7 -0
- package/examples/assets/public/about.html +2 -0
- package/examples/assets/public/assets/example.txt +1 -0
- package/examples/assets/public/guide.txt +1 -0
- package/examples/assets/tests/requests.json +44 -0
- package/examples/assets/urlcode.yaml +27 -0
- package/examples/aws/README.md +13 -0
- package/examples/aws/handler.mjs +5 -0
- package/examples/aws/public/index.html +3 -0
- package/examples/aws/public/notes.txt +1 -0
- package/examples/aws/template.yaml +33 -0
- package/examples/aws/tests/requests.json +9 -0
- package/examples/aws/urlcode.yaml +19 -0
- package/examples/cloudflare/README.md +18 -0
- package/examples/cloudflare/package.json +14 -0
- package/examples/cloudflare/tests/requests.json +9 -0
- package/examples/cloudflare/urlcode.yaml +24 -0
- package/examples/cloudflare/wrangler.toml +5 -0
- package/examples/compliance/README.md +20 -0
- package/examples/compliance/rules.mjs +65 -0
- package/examples/cookbook/README.md +21 -0
- package/examples/cookbook/functions/choice.mjs +4 -0
- package/examples/cookbook/functions/echo.mjs +3 -0
- package/examples/cookbook/functions/hello.mjs +3 -0
- package/examples/cookbook/functions/text.mjs +3 -0
- package/examples/cookbook/middleware/headers.mjs +6 -0
- package/examples/cookbook/public/about.html +1 -0
- package/examples/cookbook/public/assets/index.html +1 -0
- package/examples/cookbook/public/assets/site.css +1 -0
- package/examples/cookbook/public/favicon.svg +1 -0
- package/examples/cookbook/public/guide.txt +1 -0
- package/examples/cookbook/public/llms.txt +6 -0
- package/examples/cookbook/routes/code.yaml +55 -0
- package/examples/cookbook/routes/files.yaml +17 -0
- package/examples/cookbook/routes/policies.yaml +28 -0
- package/examples/cookbook/routes/redirects.yaml +38 -0
- package/examples/cookbook/routes/responses.yaml +26 -0
- package/examples/cookbook/tests/requests.json +254 -0
- package/examples/cookbook/urlcode.yaml +22 -0
- package/examples/live-links/README.md +11 -0
- package/examples/live-links/tests/requests.json +6 -0
- package/examples/live-links/urlcode.yaml +16 -0
- package/examples/monitoring/blackbox-jobs.yaml +37 -0
- package/examples/monitoring/prometheus-rules.yaml +88 -0
- package/examples/monitoring/prometheus-scrape.yaml +20 -0
- package/examples/monitoring/vector.toml +65 -0
- package/examples/prerender/README.md +48 -0
- package/examples/prerender/functions/page.mjs +6 -0
- package/examples/prerender/middleware/template.mjs +29 -0
- package/examples/prerender/prerender.d.mts +4 -0
- package/examples/prerender/prerender.mjs +63 -0
- package/examples/prerender/tests/requests.json +39 -0
- package/examples/prerender/urlcode.yaml +50 -0
- package/examples/tunnel/dev-with-ngrok.sh +61 -0
- package/examples/vercel/README.md +13 -0
- package/examples/vercel/api/index.js +5 -0
- package/examples/vercel/package.json +8 -0
- package/examples/vercel/public/index.html +3 -0
- package/examples/vercel/public/notes.txt +1 -0
- package/examples/vercel/tests/requests.json +48 -0
- package/examples/vercel/urlcode.yaml +19 -0
- package/examples/vercel/vercel.json +10 -0
- package/llms.txt +46 -0
- package/package.json +123 -0
- package/schemas/urlcode.schema.json +1230 -0
- package/starters/default/.gitattributes +1 -0
- package/starters/default/Makefile +30 -0
- package/starters/default/README.md +34 -0
- package/starters/default/functions/hello.mjs +3 -0
- package/starters/default/gitignore.template +8 -0
- package/starters/default/middleware/headers.mjs +6 -0
- package/starters/default/routes/functions.yaml +20 -0
- package/starters/default/routes/marketing/links.yaml +7 -0
- package/starters/default/starter.json +5 -0
- package/starters/default/tests/requests.json +56 -0
- package/starters/default/urlcode.yaml +8 -0
|
@@ -0,0 +1,160 @@
|
|
|
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 sandbox and
|
|
5
|
+
resource limits reduce some failure modes; they cannot protect a saturated
|
|
6
|
+
network link. Keep the public origin behind your existing protected ingress.
|
|
7
|
+
|
|
8
|
+
## Defense responsibilities
|
|
9
|
+
|
|
10
|
+
| Layer | Operator action | What URLCode provides today |
|
|
11
|
+
|---|---|---|
|
|
12
|
+
| Upstream network | Hosting/CDN DDoS mitigation and an escalation contact; protect bandwidth before it reaches the origin | No network-level mitigation service |
|
|
13
|
+
| 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
|
+
| Release/recovery | Known-good artifacts, candidate verification, traffic switching, rollback drills | Local validation/tests/audit; explicit snapshot reload; no orchestration |
|
|
17
|
+
|
|
18
|
+
NGINX provides request-rate controls and connection controls keyed by values such
|
|
19
|
+
as client IP. Their counters do not cover every stage of connection handling;
|
|
20
|
+
connection limiting starts after request headers are read. Treat them as layers,
|
|
21
|
+
not a complete volumetric defense. Use aggregate budgets too, and test legitimate
|
|
22
|
+
users behind shared NATs. Sources: [request limits](https://nginx.org/en/docs/http/ngx_http_limit_req_module.html),
|
|
23
|
+
[connection limits](https://nginx.org/en/docs/http/ngx_http_limit_conn_module.html).
|
|
24
|
+
|
|
25
|
+
If a CDN/proxy sits ahead of your ingress, configure trusted client-IP restoration
|
|
26
|
+
for only that provider's verified proxy addresses. Never use arbitrary incoming
|
|
27
|
+
X-Forwarded-For as the rate-limit identity. Keep the origin firewall/private
|
|
28
|
+
network restricted to the intended ingress. URLCode deliberately does not trust
|
|
29
|
+
forwarded headers to construct its public URL; set `--origin` explicitly.
|
|
30
|
+
|
|
31
|
+
The optional [`throttle` policy](policies/throttle.md) adds a per-client budget
|
|
32
|
+
inside the runtime, and the [`agents` policy](policies/agents.md) refuses listed
|
|
33
|
+
User-Agents before a body is read or the sandbox starts. Both are a second
|
|
34
|
+
layer behind the edge, not a replacement for it: counters are per instance,
|
|
35
|
+
the socket and admission limits still apply first, and a flood still costs
|
|
36
|
+
connections. The client identity is the socket peer unless
|
|
37
|
+
`urlcode serve --trusted-proxies <cidr,...>` names the proxies allowed to set
|
|
38
|
+
`X-Forwarded-For`; a forwarded header from any other peer is ignored, and an
|
|
39
|
+
unresolved client shares one bucket rather than being exempt. See
|
|
40
|
+
[policies](POLICIES.md).
|
|
41
|
+
|
|
42
|
+
Cache only responses whose semantics permit public caching. Never cache private,
|
|
43
|
+
credential-bearing or personalized responses as a blanket mitigation. Default
|
|
44
|
+
function/redirect responses are no-store; assets default to revalidation. Use
|
|
45
|
+
versioned immutable asset URLs when appropriate. An NGINX/native-route exporter
|
|
46
|
+
is not implemented; adding a reverse proxy does not bypass runtime execution.
|
|
47
|
+
|
|
48
|
+
## Threats and behavior to expect
|
|
49
|
+
|
|
50
|
+
| Failure or traffic pattern | Current consequence | Mitigation / recovery |
|
|
51
|
+
|---|---|---|
|
|
52
|
+
| 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 |
|
|
55
|
+
| Guest invalid response or failure | Generic 502 | Compare with last deployment; run fixture on a private candidate |
|
|
56
|
+
| 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
|
+
| 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 |
|
|
58
|
+
| Slow response readers | Retain admission/output buffers until finish/disconnect; 15-second socket inactivity timeout | Proxy downstream timeouts and connection controls |
|
|
59
|
+
| 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 |
|
|
60
|
+
| Host OOM or process crash | In-process recovery cannot preserve service | Supervisor with backoff; route traffic to healthy replica; restore tested image |
|
|
61
|
+
| Disk/log sink trouble | Logs may drop; startup/config reads can fail | Disk/RSS alerts, bounded retention and log-drop monitoring |
|
|
62
|
+
| Bandwidth flood at origin link | App may be unreachable regardless of worker limits | Hosting/network mitigation provider escalation |
|
|
63
|
+
|
|
64
|
+
A 503/504 can also be an intentional application response. Runtime logs do not
|
|
65
|
+
include a per-route reason code, so status alone cannot prove an attack or a
|
|
66
|
+
capacity failure. Correlate ingress metrics, release changes and controlled
|
|
67
|
+
probes. Do not add secrets, full query strings or request bodies to diagnostics.
|
|
68
|
+
|
|
69
|
+
## Prepare before exposure
|
|
70
|
+
|
|
71
|
+
- Name an incident owner, backup and hosting/ingress escalation contacts. Decide
|
|
72
|
+
who can change filters, switch traffic, approve rollback and rotate credentials.
|
|
73
|
+
- Retain known-good runtime/app commits, locks, images and compatible policy files.
|
|
74
|
+
Keep protected backups outside the host. Secret values belong in your secret
|
|
75
|
+
system, never the artifact archive or Git.
|
|
76
|
+
- Keep at least one verified rollback path; use redundant replicas if your
|
|
77
|
+
availability objective needs them. A single instance cannot promise continuity
|
|
78
|
+
through a host failure or full restart.
|
|
79
|
+
- Define acceptable successful RPS, p95/p99, error rates and resource utilization
|
|
80
|
+
using [capacity tests](CAPACITY.md). Set alerts for deviations, readiness failures,
|
|
81
|
+
restarts/OOM, memory pressure, bandwidth, log drops and infrastructure spend.
|
|
82
|
+
- Restrict `/_urlcode/*` to operator access at ingress. Keep liveness and readiness
|
|
83
|
+
separate: busy workers do not make readiness fail; missing workers do.
|
|
84
|
+
- Use bounded retries with backoff/jitter where retries are safe. Do not retry
|
|
85
|
+
non-idempotent requests blindly or create a synchronized retry storm.
|
|
86
|
+
|
|
87
|
+
## Incident procedure
|
|
88
|
+
|
|
89
|
+
1. **Confirm and record.** Note start time, affected service, runtime/app/image
|
|
90
|
+
versions, error/latency trends and recent changes. Check upstream reachability,
|
|
91
|
+
process health and readiness through an operator-only path. Distinguish an
|
|
92
|
+
ingress incident from a bad deployment or legitimate traffic increase.
|
|
93
|
+
2. **Protect capacity.** Apply reviewed ingress filters/admission limits and
|
|
94
|
+
contact the mitigation provider for network saturation. Restrict an abusive
|
|
95
|
+
route at ingress if needed. Preserve working simple routes where possible.
|
|
96
|
+
Do not raise worker counts/timeouts blindly or scale without a spend ceiling.
|
|
97
|
+
3. **Stabilize.** Remove failed replicas from traffic. If a release is implicated,
|
|
98
|
+
switch to the retained verified revision; avoid repeatedly rebuilding snapshots
|
|
99
|
+
under attack. For a bad function, an ingress block is faster than a YAML edit
|
|
100
|
+
that still needs deployment and may invalidate binding policy.
|
|
101
|
+
4. **Restore deliberately.** Start a candidate with the intended runtime/app,
|
|
102
|
+
assets, bindings and matching external policy. Check private readiness and
|
|
103
|
+
representative response assertions. Switch a small traffic share first when
|
|
104
|
+
supported, observe, then increase. Drain the old instance before stopping it.
|
|
105
|
+
5. **Verify recovery.** Confirm successful traffic, latency, RSS and error rates
|
|
106
|
+
return to the agreed envelope. Check native and programmable routes, HEAD,
|
|
107
|
+
redirect destinations and critical asset behavior. Readiness alone is not enough.
|
|
108
|
+
6. **Close and improve.** Record cause, actions, outage duration, lost telemetry,
|
|
109
|
+
customer impact and costs. Keep useful mitigations; remove temporary broad
|
|
110
|
+
restrictions carefully. Add a regression fixture or drill for the failure.
|
|
111
|
+
|
|
112
|
+
Restarting can replace failed workers, but it does not fix a malicious request
|
|
113
|
+
pattern, broken release or saturated link. Rotate credentials if exposure is
|
|
114
|
+
suspected, not automatically for every traffic spike. Redeploy to load new values;
|
|
115
|
+
serve does not refresh them. No credential values should enter incident notes.
|
|
116
|
+
|
|
117
|
+
## Recovery objectives and data
|
|
118
|
+
|
|
119
|
+
Choose RTO (acceptable recovery time) and RPO (acceptable data loss) per deployment;
|
|
120
|
+
URLCode does not promise values. A stateless YAML deployment can be recreated
|
|
121
|
+
from retained immutable artifacts, subject to recovery of DNS/ingress and secret
|
|
122
|
+
access. Log loss is possible under pressure and has a separate retention target.
|
|
123
|
+
Stored live-link records and future app-owned state need their own backups and restore
|
|
124
|
+
verification; Git route configuration does not back up runtime data.
|
|
125
|
+
|
|
126
|
+
A rollback needs the previous app/runtime and its matching policy and compatible
|
|
127
|
+
secret bindings. The health version combines configuration and asset digests;
|
|
128
|
+
it is not a complete code/release identity. Track Git/image identities externally.
|
|
129
|
+
Browser/CDN-cached permanent redirects may continue after rollback; choose cache
|
|
130
|
+
lifetimes accordingly and plan edge purges. Rollback cannot undo external side
|
|
131
|
+
effects, and current URLCode has no state migration/restore control plane.
|
|
132
|
+
|
|
133
|
+
## Safe recovery drills and pass criteria
|
|
134
|
+
|
|
135
|
+
Run only against owned, isolated test deployments with fixed request/time budgets
|
|
136
|
+
and stop conditions. Coordinate with the hosting provider for any network stress
|
|
137
|
+
exercise; do not generate uncontrolled floods or target third-party destinations.
|
|
138
|
+
|
|
139
|
+
| Drill | Evidence to retain |
|
|
140
|
+
|---|---|
|
|
141
|
+
| Saturate the function pool with bounded test handlers | Excess work receives bounded failures; native probe remains observable; normal traffic recovers afterward |
|
|
142
|
+
| Handler timeout/worker replacement | 504 observed, replacement or bounded unavailable state understood, no leaked request data |
|
|
143
|
+
| Invalid dev reload | Old response stays active; rejection logged; corrected candidate activates |
|
|
144
|
+
| Kill a disposable replica | Supervisor backoff and health-based routing work; successful capacity of survivors measured |
|
|
145
|
+
| Roll back a bad release | Prior exact response restored with matching policy; actual recovery time recorded |
|
|
146
|
+
| Restore on a clean host | Artifacts, policy and secure bindings suffice; assets and all critical fixtures pass |
|
|
147
|
+
| Simulate a slow/full log sink | Dropped-log reporting is observed; service and disk usage remain bounded |
|
|
148
|
+
| Remove mitigation after a bounded overload | Latency/errors/resources return to baseline without a restart loop |
|
|
149
|
+
|
|
150
|
+
Existing unit/HTTP tests cover several component failures; these deployment drills
|
|
151
|
+
are a plan, not evidence they have all been run. Remaining gaps include distributed
|
|
152
|
+
admission/fairness, production metrics/exporters, dedicated slow-reader protection,
|
|
153
|
+
provider-level mitigation validation and sustained failure/soak testing. These are
|
|
154
|
+
free-runtime/operator requirements.
|
|
155
|
+
|
|
156
|
+
For optional live links, protect the separate management listener and token, bound
|
|
157
|
+
its traffic, and back up the SQLite store with the documented closed-store or
|
|
158
|
+
SQLite-aware procedure. Store worker failure returns 503; stop the cause before
|
|
159
|
+
reloading/restarting. An uncertain mutation may have committed. See
|
|
160
|
+
[dynamic-link recovery](DYNAMIC-LINKS.md).
|
package/docs/ROUTING.md
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
# Route matching and new links
|
|
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 link 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
|
+
This is now implemented for short-link redirects through the optional `link`
|
|
87
|
+
handler, local SQLite storage, CLI and a separate authenticated management API.
|
|
88
|
+
See [dynamic links](DYNAMIC-LINKS.md) for complete YAML, setup, consistency and
|
|
89
|
+
backup details. No route reload is needed for committed record changes.
|
|
90
|
+
|
|
91
|
+
Functions still cannot access databases, the filesystem or network directly.
|
|
92
|
+
The native link handler performs the bounded lookup, and middleware can wrap a
|
|
93
|
+
successful redirect. General application state and realtime sessions remain
|
|
94
|
+
future work. SQLite is optional and supports local same-host processes; a
|
|
95
|
+
multi-host deployment needs a different adapter. A cache is not the durable store.
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# Independent sandbox review gate
|
|
2
|
+
|
|
3
|
+
Status: **external assessment not performed**. Internal source review, CI, CodeQL
|
|
4
|
+
and adversarial regressions are useful evidence, not an independent sign-off.
|
|
5
|
+
Do not host anonymous hostile multi-tenant code before this gate is closed.
|
|
6
|
+
No unrestricted Node execution fallback is permitted.
|
|
7
|
+
|
|
8
|
+
## Review package
|
|
9
|
+
|
|
10
|
+
Freeze an exact runtime commit, lockfile, container digest, app/policy examples
|
|
11
|
+
with synthetic credentials, Node/SQLite/QuickJS/WASM versions and deployment
|
|
12
|
+
resource settings. Give a reviewer independent of the implementation access to:
|
|
13
|
+
|
|
14
|
+
- `src/functions.ts`, worker/guest implementation and `src/policy.ts`: VM creation,
|
|
15
|
+
module graph, import denial, export validation, binding grants and message bridge.
|
|
16
|
+
- `src/config.ts`, `src/config-worker.ts`, router and assets: parser/schema limits,
|
|
17
|
+
file containment, activation, memory amplification and host-side compilation.
|
|
18
|
+
- HTTP server, management API/policy and link-store worker: request smuggling,
|
|
19
|
+
admission, body/response framing, authorization, revocation and atomic audit.
|
|
20
|
+
- `test/sandbox.test.ts`, middleware/config/links/logging/reload tests, Dockerfile,
|
|
21
|
+
protected workflows and `docs/FUNCTION-SECURITY.md`.
|
|
22
|
+
|
|
23
|
+
Run `npm ci --ignore-scripts`, `npm run verify`, `npm run test:package`, and
|
|
24
|
+
`node scripts/operational-drills.ts`. Record the exact commands and result files.
|
|
25
|
+
CI adds constrained-container and real disposable-volume exhaustion tests.
|
|
26
|
+
Use only disposable local/staging systems with synthetic data.
|
|
27
|
+
|
|
28
|
+
## Threat model and required probes
|
|
29
|
+
|
|
30
|
+
An attacker controls project YAML, included files, function/module source, public
|
|
31
|
+
requests, request bodies, exported values and static content. The operator controls
|
|
32
|
+
the host, deployment, external policy, credentials, database and project activation.
|
|
33
|
+
Guests receive only explicitly granted values; granted secrets can be returned by
|
|
34
|
+
that guest. QuickJS/WASM is the code boundary; worker threads alone are not.
|
|
35
|
+
|
|
36
|
+
Probe module cycles and loader escapes, malformed bridge messages, huge strings,
|
|
37
|
+
arrays and ArrayBuffers, deep prototypes, exceptions/getters, asynchronous jobs,
|
|
38
|
+
infinite loops, repeated worker replacement, capability confusion, cross-route
|
|
39
|
+
and cross-invocation leakage, parser/schema amplification, filesystem races,
|
|
40
|
+
slow peers, reload overlap and process/container exhaustion. Test unauthorized
|
|
41
|
+
management reads/writes, stale credentials, expiry boundaries, malformed policy,
|
|
42
|
+
CAS races, audit failures, poisoned databases and full disks. Verify native routes
|
|
43
|
+
and health/recovery remain useful after each bounded guest failure.
|
|
44
|
+
|
|
45
|
+
Trusted computing base includes Node/V8, QuickJS/WASM, bindings, dependencies,
|
|
46
|
+
OS/kernel, container runtime, secrets/policy administration and build infrastructure.
|
|
47
|
+
Current containment does not provide tenant CPU fairness, per-tenant process RSS,
|
|
48
|
+
networked microVM isolation, or a proof against engine vulnerabilities. Worker heap
|
|
49
|
+
limits exclude external buffers and do not replace a process/container memory cap.
|
|
50
|
+
|
|
51
|
+
## Closure criteria and deliverable
|
|
52
|
+
|
|
53
|
+
The maintainer records reviewer identity/independence, scope, dates, tested commit
|
|
54
|
+
and environment, methodology, findings with reproductions, severity, remediations
|
|
55
|
+
and retest evidence. All critical/high boundary findings must be fixed and retested;
|
|
56
|
+
residual risks require explicit owner acceptance. Publish a sanitized assessment
|
|
57
|
+
summary and retain exploit details privately through GitHub security advisories.
|
|
58
|
+
Reopen review for new capabilities, engine/bridge changes or major isolation changes.
|
|
59
|
+
An external review is necessary here, but still does not certify production capacity.
|
|
@@ -0,0 +1,72 @@
|
|
|
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
|
+
|
|
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.
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
# Security review — 2026-09-17
|
|
2
|
+
|
|
3
|
+
Scope: follow-up source review of worker/connection replacement, probe admission,
|
|
4
|
+
request correlation, operational logging, dependency/release supply chain and the
|
|
5
|
+
live-link Node requirement. Regression tests accompany the fixes. Internal review,
|
|
6
|
+
not an independent penetration test.
|
|
7
|
+
|
|
8
|
+
## Findings fixed in this revision
|
|
9
|
+
|
|
10
|
+
| Finding | Impact and evidence | Fix / regression |
|
|
11
|
+
|---|---|---|
|
|
12
|
+
| Function workers latched off permanently after bounded churn | Availability: replacement stopped after three exits in a minute and was never retried, so eight deadline-exceeded requests — reachable from ordinary request input to any function whose runtime depends on its input — disabled every function route for the life of the process. Reproduced against `serve`, which never reloads: `/fast` and readiness stayed 503 indefinitely | Replacement now backs off (250 ms doubling to a 30-second ceiling) and keeps retrying; a completed invocation clears the backoff. Load is shed while a slot is down, and `function_worker` events record each attempt. Regression drives eight deadlines, then asserts the pool serves and readiness returns to 200 |
|
|
13
|
+
| Link-store connections were never replaced | Availability: one operation reaching the five-second deadline, or any abrupt worker exit, terminated the connection with no replacement path, permanently failing that pool while the records themselves were intact on disk | Connections share the same backed-off replacement and emit `link_store_worker` events. Activation still fails closed and is never retried behind the caller. Covered by the existing 22-test live-link suite; the post-activation failure branch has no automated test because the worker could not be crashed deterministically from a test |
|
|
14
|
+
| Health probes bypassed admission control | Resource exposure: probes were answered outside the in-flight budget, an unmetered path on a public listener, and report the configuration digest and route count without authentication | Probes keep a separate bounded budget (16 by default) so they stay available under application saturation without being unmetered. Operations documents keeping them internal |
|
|
15
|
+
| Request correlation broke at the ingress, and logs could not attribute anything | Operability: `x-request-id` was always regenerated, so traces did not survive a proxy hop, and request records carried no method or route, leaving per-route error rates and abuse (including the exhaustion above) undetectable | Opt-in `--trust-request-id` accepts a single safe upstream value; `--request-log detailed` adds the method and the matched route pattern. Pattern and method come from reviewed configuration, never from request text. Regression asserts a spoofed ID is ignored by default and that path, parameter and query text never reach the log |
|
|
16
|
+
| Deployment capacity controls were unreachable from the supported deployment | Availability: workers, deadlines and byte limits existed only in the embedding JS API while the container entrypoint is the CLI, so the supported target was fixed at two function workers with no way to tune | `serve`/`dev` accept `--workers`, `--function-timeout-ms`, `--max-response-bytes`, `--max-body-bytes`, `--max-in-flight` and `--max-in-flight-health`, validated before the listener starts |
|
|
17
|
+
| Live-link tests failed rather than skipped on an unpatched Node build | Signal loss: a current Node 22 release bundling SQLite 3.51.2 turned 21 tests red for an environmental reason, hiding real regressions behind expected noise | The suite skips with the detected version named, one CI job asserts the suite actually runs somewhere, `doctor` reports `liveLinks`, and activation names the detected version |
|
|
18
|
+
| Release artifacts and dependencies were not gated | Supply chain: advisories were checked by hand on a date, and Actions and the container base image floated on mutable tags | `npm audit --omit=dev` fails CI on runtime advisories, Actions and the base image are pinned by SHA/digest, and Dependabot proposes npm, Actions and image updates weekly |
|
|
19
|
+
|
|
20
|
+
Replacement backs off but does not stop. A cause that keeps recurring keeps the
|
|
21
|
+
instance shedding load with readiness at 503 rather than recovering silently;
|
|
22
|
+
that is an operator signal, not self-healing. Alert on sustained
|
|
23
|
+
`function_worker` and `link_store_worker` restart events.
|
|
24
|
+
|
|
25
|
+
# Security review — 2026-09-16
|
|
26
|
+
|
|
27
|
+
Scope: source review of HTTP serving/management, log handling, filesystem and
|
|
28
|
+
configuration loading, sandbox/module/binding boundaries, stored-link pooling,
|
|
29
|
+
scaffolding, package/container configuration and current dependency advisories.
|
|
30
|
+
Local adversarial regression tests accompany fixes. This is an internal review,
|
|
31
|
+
not an independent penetration test or certification. No production systems,
|
|
32
|
+
third-party targets or external accounts were attacked.
|
|
33
|
+
|
|
34
|
+
## Findings fixed in this revision
|
|
35
|
+
|
|
36
|
+
| Finding | Impact and evidence | Fix / regression |
|
|
37
|
+
|---|---|---|
|
|
38
|
+
| Asynchronous log sink errors escaped request error handling | Availability: a local Writable reporting an async error terminated the process with an unhandled error event | Shared sink error handling suppresses further writes to a failed sink; synchronous failures also contained. Regression covers both failure modes and listener reuse |
|
|
39
|
+
| Management lacked bounded in-flight HTTP admission and socket inactivity enforcement | Resource exposure: connection limits alone did not bound active pipelined work or stalled output; public listener protections were absent here | Default 32 admitted requests through finish/disconnect, 10-second socket inactivity timeout, overload 503 and idempotent shutdown. Regression stalls an authenticated upload, checks overload, waits for disconnect, then verifies recovery |
|
|
40
|
+
| Development watcher read entire unrelated JSON/JS/YAML files | Local availability: a repository file outside the validated dependency graph could cause excessive allocations or fail watching solely because its contents were unreadable | Watch fingerprints use file metadata; actual configuration/source loading retains validation. Regression starts dev with an unreadable unrelated JSON file |
|
|
41
|
+
| Management had no request-level audit events | Operational visibility: mutations, authentication failures and aborted requests lacked structured records | Redacted events include timestamp, request ID, collection, action, authentication result, status and finish/abort outcome. Tests prove tokens, short codes and destinations are absent |
|
|
42
|
+
| Management accepted normalized dot-segment path aliases | Defense-in-depth: URL normalization admitted alternative endpoint spellings that could disagree with upstream path policies; no authorization bypass was demonstrated | Reject raw path normalization before endpoint dispatch; authentication still precedes path handling |
|
|
43
|
+
|
|
44
|
+
Management event status 0 means no response headers were sent before disconnect.
|
|
45
|
+
An aborted request may have committed a mutation: reconcile record/version before
|
|
46
|
+
retrying. These logs are best effort, may be dropped under pressure, identify a configured credential ID (or a legacy shared token), and are not a
|
|
47
|
+
tamper-evident journal. Successful store mutations now have separate transactional
|
|
48
|
+
audit records; see [management security](MANAGEMENT-SECURITY.md). A failed sink needs collector/operator recovery;
|
|
49
|
+
URLCode cannot report failures reliably through the same broken output stream.
|
|
50
|
+
|
|
51
|
+
## Boundaries checked
|
|
52
|
+
|
|
53
|
+
- Guest code stays inside QuickJS/WASM, with fresh invocation state, denied host
|
|
54
|
+
APIs, bounded modules/memory/deadlines and no unrestricted fallback. Import
|
|
55
|
+
allowlists and external revision-pinned binding grants remain in force.
|
|
56
|
+
- Public serving cannot mutate the native link store. Management is a separate
|
|
57
|
+
token-protected listener with conditional writes, scoped collection and bounded
|
|
58
|
+
bodies. YAML requires explicit live-link opt-in; it cannot grant guest storage.
|
|
59
|
+
- SQL uses bound parameters; read/write pools have independent bounded admission,
|
|
60
|
+
patched-SQLite checks, read-only serving and commit/version tests.
|
|
61
|
+
- Asset/scaffold paths reject traversal and unsafe filesystem references. Static
|
|
62
|
+
publication is explicit; sensitive-name filtering is not a secret detector.
|
|
63
|
+
- Log output excludes request URLs, bodies, headers, tokens and user exceptions.
|
|
64
|
+
Management adds safe operational context without logging stored destinations.
|
|
65
|
+
- `npm audit` reported zero known advisories on this date. This does not cover
|
|
66
|
+
every Node, SQLite, WASM engine, operating-system or container vulnerability.
|
|
67
|
+
|
|
68
|
+
Existing and new automated tests cover these contracts; they do not constitute a
|
|
69
|
+
proof that the sandbox engine or complete application is vulnerability-free.
|
|
70
|
+
|
|
71
|
+
## Remaining gaps, prioritized
|
|
72
|
+
|
|
73
|
+
**Before exposing hostile multi-tenant workloads:** obtain independent review of
|
|
74
|
+
WASM/host boundaries, module loading and resource exhaustion. The
|
|
75
|
+
[independent-review package](SANDBOX-REVIEW.md) defines scope and closure evidence.
|
|
76
|
+
YAML parsing now has an aggregate source cap and a bounded worker with a hard
|
|
77
|
+
wall deadline. Route compilation has a cooperative deadline; process-wide RSS,
|
|
78
|
+
individual host operations and overlapping snapshots still require deployment
|
|
79
|
+
limits. No anonymous code/config upload service is approved by these changes.
|
|
80
|
+
|
|
81
|
+
**Management remains private:** literal loopback binding, external per-credential
|
|
82
|
+
collection/action scopes, expiry and hot revocation, plus atomic SQLite mutation
|
|
83
|
+
audits are implemented. Legacy shared tokens remain for compatibility. There is
|
|
84
|
+
no public user-account system, MFA/SSO, built-in rate limiter, credential issuance
|
|
85
|
+
service or external tamper-evident archive. See [management security](MANAGEMENT-SECURITY.md).
|
|
86
|
+
|
|
87
|
+
**Before claiming operational readiness:** execute sustained mixed-workload soak,
|
|
88
|
+
backup restoration, disk-full, process-kill, proxy timeout and rollback drills on
|
|
89
|
+
the real deployment. Monitor disk/WAL growth, pool failures/rejections, RSS,
|
|
90
|
+
readiness, missing logs and restarts. SQLite is single-host; there is no automatic
|
|
91
|
+
multi-host failover or server-database adapter. Logging retention/rotation is owned
|
|
92
|
+
by the external collector and still needs deployment recipes and verification.
|
|
93
|
+
|
|
94
|
+
**Post-0.1 release hardening:** establish a private vulnerability reporting/support
|
|
95
|
+
policy and patch response ownership before managed or hostile multi-tenant use.
|
|
96
|
+
Release artifacts need immutable image and
|
|
97
|
+
dependency identities, upstream vulnerability monitoring and a reviewed update
|
|
98
|
+
process. At the audit cutoff, CI actions/base images used mutable version tags. The
|
|
99
|
+
repository-governance follow-up pins them and enables dependency maintenance,
|
|
100
|
+
secret protection, CodeQL and private reporting; see [governance](../GOVERNANCE.md).
|
|
101
|
+
CI now also gates runtime advisories with `npm audit --omit=dev`. A manual main-only
|
|
102
|
+
signed candidate/SBOM workflow is now defined; see
|
|
103
|
+
[release security](RELEASE-SECURITY.md). It does not publish to registries. The 0.1.0 release is licensed under
|
|
104
|
+
Apache-2.0; the license does not close the independent-review gates.
|
|
105
|
+
|
|
106
|
+
**Application responsibility:** HTML/JS assets are active browser content; choose
|
|
107
|
+
appropriate CSP, cookie flags, authorization and cache policy. Granted secrets
|
|
108
|
+
can intentionally be returned by code receiving them. Filename filters cannot
|
|
109
|
+
identify secrets stored under innocent names. Operator directories/volumes must
|
|
110
|
+
remain protected from other host processes; filesystem checks do not protect
|
|
111
|
+
against a privileged host attacker racing mutations.
|
|
112
|
+
|
|
113
|
+
See [release gates](RELEASE-READINESS.md), [function security](FUNCTION-SECURITY.md),
|
|
114
|
+
[operations](OPERATIONS.md) and [resilience](RESILIENCE.md). Free-product and
|
|
115
|
+
portability boundaries remain unchanged; this audit is not deployment readiness proof.
|
|
116
|
+
|
|
117
|
+
Repeatable local/CI drills now cover mixed HTTP load, quiesced backup restoration,
|
|
118
|
+
configuration rollback and disposable volume exhaustion/recovery. Real deployment
|
|
119
|
+
acceptance remains open; see [operational proof](OPERATIONAL-PROOF.md).
|
|
120
|
+
|
|
121
|
+
The hardening CI pass also exposed a failed-store initialization cleanup race on
|
|
122
|
+
Windows: rejection could precede worker termination and leave the DB file briefly
|
|
123
|
+
locked. Initialization now closes the DB and awaits worker termination before
|
|
124
|
+
returning failure. The missing-metadata regression exercises this cleanup path.
|