@jimhoyd/urlcode 0.3.0 → 0.4.0-alpha.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/skills/urlcode-authoring/SKILL.md +122 -0
- package/.claude/skills/urlcode-operations/SKILL.md +108 -0
- package/.claude-plugin/marketplace.json +18 -0
- package/CONTRIBUTING.md +30 -2
- package/README.md +195 -255
- package/ROADMAP.md +143 -15
- package/SECURITY.md +31 -9
- package/dist/BUILD-MANIFEST.json +72 -47
- package/dist/adapters.js +4 -23
- package/dist/agent-lists.js +1 -1
- package/dist/agents-guide.js +113 -0
- package/dist/authoring-files.js +60 -0
- package/dist/authoring.js +11 -1
- package/dist/aws.js +4 -3
- package/dist/build-cloudflare.js +11 -24
- package/dist/build-static.js +134 -0
- package/dist/bulk.js +37 -0
- package/dist/capabilities.js +262 -0
- package/dist/capability-query.js +71 -0
- package/dist/catalog.js +105 -0
- package/dist/cli.js +165 -34
- package/dist/client-address.js +1 -1
- package/dist/compliance-rules/baseline.js +9 -17
- package/dist/compliance-rules/privacy.js +7 -18
- package/dist/compliance-rules/shared.js +0 -2
- package/dist/compliance-rules/strict.js +5 -5
- package/dist/compliance.js +6 -8
- package/dist/conditions.js +88 -0
- package/dist/config.js +69 -6
- package/dist/context.js +155 -0
- package/dist/ecosystem-cli.js +88 -0
- package/dist/egress.js +98 -0
- package/dist/examples.js +92 -0
- package/dist/explain-cli.js +64 -0
- package/dist/explain.js +131 -0
- package/dist/extensions.js +231 -0
- package/dist/function-sources.js +49 -5
- package/dist/function-worker.js +3 -1
- package/dist/functions.js +84 -13
- package/dist/guest-api.js +29 -3
- package/dist/index.js +40 -6
- package/dist/init-with.js +165 -0
- package/dist/interchange-cli.js +42 -0
- package/dist/interchange.js +189 -0
- package/dist/manifest.js +109 -0
- package/dist/match.js +2 -2
- package/dist/mcp-authoring.js +147 -0
- package/dist/mcp.js +97 -0
- package/dist/observability.js +7 -21
- package/dist/operator-host.js +29 -0
- package/dist/plugins.js +12 -0
- package/dist/policies/agents.js +2 -2
- package/dist/policies/cache.js +8 -3
- package/dist/policies/compression.js +2 -1
- package/dist/policies/security.js +0 -0
- package/dist/policies.js +1 -1
- package/dist/policy.js +56 -15
- package/dist/prerender.js +100 -41
- package/dist/project-tests.js +3 -3
- package/dist/provider-verification.js +92 -0
- package/dist/proxy.js +44 -0
- package/dist/readiness.js +34 -11
- package/dist/recipes.js +41 -0
- package/dist/route-diff.js +106 -0
- package/dist/router.js +45 -7
- package/dist/runtime.js +164 -64
- package/dist/sandbox.js +48 -0
- package/dist/scaffold.js +0 -0
- package/dist/schema-query.js +62 -0
- package/dist/scripts/operational-drills.js +12 -54
- package/dist/server.js +3 -29
- package/dist/signals.js +24 -0
- package/dist/site.js +0 -0
- package/dist/tooling.js +96 -0
- package/dist/trusted-functions.js +210 -0
- package/dist/types/adapters.d.ts +7 -4
- package/dist/types/agent-lists.d.ts +0 -1
- package/dist/types/agents-guide.d.ts +17 -0
- package/dist/types/authoring-files.d.ts +10 -0
- package/dist/types/aws.d.ts +3 -1
- package/dist/types/build-cloudflare.d.ts +1 -0
- package/dist/types/build-static.d.ts +43 -0
- package/dist/types/bulk.d.ts +27 -0
- package/dist/types/capabilities.d.ts +64 -0
- package/dist/types/capability-query.d.ts +24 -0
- package/dist/types/catalog.d.ts +65 -0
- package/dist/types/client-address.d.ts +0 -1
- package/dist/types/compliance-rules/baseline.d.ts +1 -9
- package/dist/types/compliance-rules/privacy.d.ts +1 -4
- package/dist/types/compliance-rules/shared.d.ts +0 -2
- package/dist/types/compliance-rules/strict.d.ts +0 -5
- package/dist/types/compliance.d.ts +0 -3
- package/dist/types/conditions.d.ts +19 -0
- package/dist/types/config.d.ts +21 -2
- package/dist/types/context.d.ts +66 -0
- package/dist/types/ecosystem-cli.d.ts +17 -0
- package/dist/types/egress.d.ts +46 -0
- package/dist/types/examples.d.ts +50 -0
- package/dist/types/explain-cli.d.ts +11 -0
- package/dist/types/explain.d.ts +95 -0
- package/dist/types/extensions.d.ts +177 -0
- package/dist/types/function-sources.d.ts +9 -0
- package/dist/types/functions.d.ts +48 -5
- package/dist/types/guest-api.d.ts +1 -0
- package/dist/types/index.d.ts +36 -6
- package/dist/types/init-with.d.ts +30 -0
- package/dist/types/interchange-cli.d.ts +16 -0
- package/dist/types/interchange.d.ts +42 -0
- package/dist/types/manifest.d.ts +79 -0
- package/dist/types/match.d.ts +1 -0
- package/dist/types/mcp-authoring.d.ts +92 -0
- package/dist/types/mcp.d.ts +12 -0
- package/dist/types/observability.d.ts +3 -14
- package/dist/types/operator-host.d.ts +8 -0
- package/dist/types/plugins.d.ts +2 -0
- package/dist/types/policies/agents.d.ts +0 -2
- package/dist/types/policies/compression.d.ts +2 -0
- package/dist/types/policies/security.d.ts +0 -1
- package/dist/types/policy.d.ts +15 -4
- package/dist/types/project-tests.d.ts +3 -2
- package/dist/types/provider-verification.d.ts +53 -0
- package/dist/types/proxy.d.ts +21 -0
- package/dist/types/readiness.d.ts +10 -3
- package/dist/types/recipes.d.ts +30 -0
- package/dist/types/route-diff.d.ts +27 -0
- package/dist/types/router.d.ts +2 -1
- package/dist/types/runtime.d.ts +11 -27
- package/dist/types/sandbox.d.ts +12 -0
- package/dist/types/scaffold.d.ts +0 -2
- package/dist/types/schema-query.d.ts +12 -0
- package/dist/types/server.d.ts +1 -4
- package/dist/types/signals.d.ts +25 -0
- package/dist/types/site.d.ts +0 -1
- package/dist/types/tooling.d.ts +115 -0
- package/dist/types/trusted-functions.d.ts +29 -0
- package/dist/types/types.d.ts +71 -7
- package/dist/types/typescript-authoring.d.ts +12 -0
- package/dist/types/vercel.d.ts +3 -1
- package/dist/types/verify-deployment.d.ts +47 -0
- package/dist/types.js +37 -5
- package/dist/typescript-authoring.js +142 -0
- package/dist/vercel.js +4 -3
- package/dist/verify-deployment.js +270 -0
- package/docs/AI-AUTHORING.md +232 -15
- package/docs/AWS.md +4 -4
- package/docs/BEST-PRACTICES.md +3 -2
- package/docs/BULK.md +79 -0
- package/docs/CAPABILITIES.md +192 -0
- package/docs/CAPACITY.md +129 -32
- package/docs/CI.md +142 -0
- package/docs/CLOUDFLARE.md +1 -2
- package/docs/COMPLIANCE.md +6 -9
- package/docs/CONDITIONS.md +74 -0
- package/docs/DEPLOYMENT-CHECKS.md +108 -0
- package/docs/EGRESS.md +125 -0
- package/docs/EXTENSIONS.md +398 -0
- package/docs/FRAMEWORK.md +198 -0
- package/docs/FUNCTION-SECURITY.md +129 -32
- package/docs/INSTALL.md +45 -12
- package/docs/INTERCHANGE.md +134 -0
- package/docs/LOAD-TESTING.md +4 -4
- package/docs/MIDDLEWARE-EXAMPLES.md +75 -0
- package/docs/MIDDLEWARE.md +29 -16
- package/docs/MONITORING.md +2 -19
- package/docs/NEXT-PHASE-PLAN.md +98 -0
- package/docs/NEXT-STEPS.md +634 -0
- package/docs/OBSERVABILITY.md +11 -18
- package/docs/OPEN-DECISIONS.md +212 -0
- package/docs/OPERATIONAL-PROOF.md +30 -31
- package/docs/OPERATIONS.md +29 -35
- package/docs/PLUGINS.md +37 -0
- package/docs/POLICIES.md +23 -309
- package/docs/PRERENDER.md +41 -1
- package/docs/PROJECT-DIRECTION.md +75 -8
- package/docs/PROVIDER-VERIFICATION.md +84 -0
- package/docs/READINESS.md +21 -1
- package/docs/README.md +87 -34
- package/docs/RECIPES.md +99 -0
- package/docs/RELEASE-READINESS.md +57 -35
- package/docs/RELEASE-SECURITY.md +116 -7
- package/docs/RESILIENCE.md +16 -15
- package/docs/ROUTING.md +8 -10
- package/docs/SANDBOX-REVIEW.md +19 -6
- package/docs/SCAFFOLDING.md +0 -2
- package/docs/SECURITY-AUDIT.md +41 -1
- package/docs/SPECIFICATION.md +150 -29
- package/docs/SPIKE-AI-FRAMEWORK-BENCHMARK.md +287 -0
- package/docs/SPIKE-BUSINESS-SUITE.md +1021 -0
- package/docs/SPIKE-CORE-LAYERING.md +337 -0
- package/docs/SPIKE-DEFAULT-TRUST-MODEL.md +209 -0
- package/docs/SPIKE-EXTENSION-MODEL.md +419 -0
- package/docs/SPIKE-EXTENSIONS.md +6 -0
- package/docs/SPIKE-LAMBDA-COMPILE.md +201 -0
- package/docs/SPIKE-MONOREPO.md +322 -0
- package/docs/STANDARDS.md +150 -142
- package/docs/STARTERS.md +21 -1
- package/docs/STATIC.md +94 -0
- package/docs/TOOLING.md +295 -0
- package/docs/TUNNELS.md +0 -3
- package/docs/TYPESCRIPT-AUTHORING.md +82 -0
- package/docs/TYPESCRIPT.md +25 -4
- package/docs/USABILITY-REVIEW.md +129 -0
- package/docs/VERCEL.md +4 -5
- package/docs/VERSION-ALIGNMENT.md +205 -0
- package/docs/YAML-GUIDE.md +15 -479
- package/docs/YAML-REFERENCE.md +143 -22
- package/docs/policies/agents.md +1 -1
- package/docs/policies/cache.md +13 -0
- package/docs/policies/contract.md +52 -0
- package/docs/policies/hardened.md +56 -0
- package/docs/policies/interoperability.md +169 -0
- package/docs/policies/operations.md +45 -0
- package/docs/yaml/assets.md +36 -0
- package/docs/yaml/conditions.md +20 -0
- package/docs/yaml/functions.md +160 -0
- package/docs/yaml/middleware.md +29 -0
- package/docs/yaml/organization.md +74 -0
- package/docs/yaml/policies.md +37 -0
- package/docs/yaml/redirects.md +64 -0
- package/docs/yaml/responses.md +57 -0
- package/docs/yaml/site.md +24 -0
- package/examples/assets/example.yaml +17 -0
- package/examples/aws/example.yaml +20 -0
- package/examples/cloudflare/example.yaml +19 -0
- package/examples/compliance/example.yaml +11 -0
- package/examples/conditions/README.md +12 -0
- package/examples/conditions/example.yaml +19 -0
- package/examples/conditions/tests/requests.json +13 -0
- package/examples/conditions/urlcode.yaml +24 -0
- package/examples/cookbook/README.md +8 -4
- package/examples/cookbook/example.yaml +17 -0
- package/examples/cookbook/functions/catalog.mjs +3 -0
- package/examples/cookbook/functions/fail.mjs +4 -0
- package/examples/cookbook/functions/items.mjs +3 -0
- package/examples/cookbook/functions/profile.mjs +3 -0
- package/examples/cookbook/functions/resource.mjs +3 -0
- package/examples/cookbook/functions/status.mjs +3 -0
- package/examples/cookbook/middleware/auth.mjs +48 -0
- package/examples/cookbook/middleware/body.mjs +15 -0
- package/examples/cookbook/middleware/bucket.mjs +29 -0
- package/examples/cookbook/middleware/cors.mjs +21 -0
- package/examples/cookbook/middleware/debug.mjs +13 -0
- package/examples/cookbook/middleware/envelope.mjs +11 -0
- package/examples/cookbook/middleware/errors.mjs +11 -0
- package/examples/cookbook/middleware/etag.mjs +18 -0
- package/examples/cookbook/middleware/locale.mjs +20 -0
- package/examples/cookbook/middleware/maintenance.mjs +10 -0
- package/examples/cookbook/middleware/methods.mjs +15 -0
- package/examples/cookbook/middleware/negotiate.mjs +20 -0
- package/examples/cookbook/middleware/referer.mjs +12 -0
- package/examples/cookbook/middleware/request-id.mjs +16 -0
- package/examples/cookbook/route-index.json +676 -0
- package/examples/cookbook/routes/middleware.yaml +126 -0
- package/examples/cookbook/tests/requests.json +526 -0
- package/examples/cookbook/urlcode.yaml +1 -0
- package/examples/egress/README.md +22 -0
- package/examples/egress/example.yaml +19 -0
- package/examples/egress/urlcode.yaml +19 -0
- package/examples/extensions/README.md +7 -0
- package/examples/extensions/example.yaml +21 -0
- package/examples/extensions/urlcode.yaml +25 -0
- package/examples/monitoring/example.yaml +8 -0
- package/examples/prerender/README.md +2 -2
- package/examples/prerender/example.yaml +16 -0
- package/examples/provider-conformance/README.md +12 -0
- package/examples/provider-conformance/example.yaml +14 -0
- package/examples/provider-conformance/urlcode.yaml +34 -0
- package/examples/tunnel/example.yaml +8 -0
- package/examples/vercel/example.yaml +19 -0
- package/llms-full.txt +3084 -0
- package/llms.txt +61 -21
- package/package.json +36 -7
- package/packaging/claude-plugin/.claude-plugin/plugin.json +19 -0
- package/packaging/claude-plugin/skills/urlcode-authoring/SKILL.md +122 -0
- package/packaging/claude-plugin/skills/urlcode-operations/SKILL.md +108 -0
- package/recipes/authenticated-json-api/README.md +51 -0
- package/recipes/authenticated-json-api/functions/profile.mjs +5 -0
- package/recipes/authenticated-json-api/recipe.yaml +34 -0
- package/recipes/authenticated-json-api/tests/requests.json +39 -0
- package/recipes/authenticated-json-api/urlcode.yaml +12 -0
- package/recipes/contact-form/README.md +25 -0
- package/recipes/contact-form/functions/contact.mjs +17 -0
- package/recipes/contact-form/recipe.yaml +33 -0
- package/recipes/contact-form/tests/requests.json +47 -0
- package/recipes/contact-form/urlcode.yaml +18 -0
- package/recipes/cors-api/README.md +16 -0
- package/recipes/cors-api/functions/items.mjs +3 -0
- package/recipes/cors-api/middleware/cors.mjs +21 -0
- package/recipes/cors-api/recipe.yaml +26 -0
- package/recipes/cors-api/tests/requests.json +65 -0
- package/recipes/cors-api/urlcode.yaml +12 -0
- package/recipes/health-page/README.md +13 -0
- package/recipes/health-page/recipe.yaml +23 -0
- package/recipes/health-page/tests/requests.json +36 -0
- package/recipes/health-page/urlcode.yaml +19 -0
- package/recipes/json-api/README.md +6 -0
- package/recipes/json-api/functions/echo.mjs +3 -0
- package/recipes/json-api/recipe.yaml +25 -0
- package/recipes/json-api/tests/requests.json +34 -0
- package/recipes/json-api/urlcode.yaml +12 -0
- package/recipes/middleware/README.md +34 -0
- package/recipes/middleware/functions/catalog.mjs +3 -0
- package/recipes/middleware/functions/fail.mjs +4 -0
- package/recipes/middleware/functions/items.mjs +3 -0
- package/recipes/middleware/functions/profile.mjs +3 -0
- package/recipes/middleware/functions/resource.mjs +3 -0
- package/recipes/middleware/functions/status.mjs +3 -0
- package/recipes/middleware/middleware/auth.mjs +48 -0
- package/recipes/middleware/middleware/body.mjs +15 -0
- package/recipes/middleware/middleware/bucket.mjs +29 -0
- package/recipes/middleware/middleware/cors.mjs +21 -0
- package/recipes/middleware/middleware/debug.mjs +13 -0
- package/recipes/middleware/middleware/envelope.mjs +11 -0
- package/recipes/middleware/middleware/errors.mjs +11 -0
- package/recipes/middleware/middleware/etag.mjs +18 -0
- package/recipes/middleware/middleware/locale.mjs +20 -0
- package/recipes/middleware/middleware/maintenance.mjs +10 -0
- package/recipes/middleware/middleware/methods.mjs +15 -0
- package/recipes/middleware/middleware/negotiate.mjs +20 -0
- package/recipes/middleware/middleware/referer.mjs +12 -0
- package/recipes/middleware/middleware/request-id.mjs +16 -0
- package/recipes/middleware/public/guide.txt +1 -0
- package/recipes/middleware/recipe.yaml +50 -0
- package/recipes/middleware/tests/requests.json +528 -0
- package/recipes/middleware/urlcode.yaml +127 -0
- package/recipes/protected-download/README.md +22 -0
- package/recipes/protected-download/files/report.txt +1 -0
- package/recipes/protected-download/recipe.yaml +31 -0
- package/recipes/protected-download/tests/requests.json +32 -0
- package/recipes/protected-download/urlcode.yaml +15 -0
- package/recipes/redirect/README.md +7 -0
- package/recipes/redirect/recipe.yaml +25 -0
- package/recipes/redirect/tests/requests.json +19 -0
- package/recipes/redirect/urlcode.yaml +9 -0
- package/recipes/static-plus-api/README.md +15 -0
- package/recipes/static-plus-api/functions/info.mjs +3 -0
- package/recipes/static-plus-api/public/assets/index.html +3 -0
- package/recipes/static-plus-api/public/assets/site.css +1 -0
- package/recipes/static-plus-api/public/index.html +8 -0
- package/recipes/static-plus-api/recipe.yaml +29 -0
- package/recipes/static-plus-api/tests/requests.json +56 -0
- package/recipes/static-plus-api/urlcode.yaml +23 -0
- package/recipes/typescript/README.md +8 -0
- package/recipes/typescript/functions/hello.ts +5 -0
- package/recipes/typescript/recipe.yaml +23 -0
- package/recipes/typescript/tests/requests.json +18 -0
- package/recipes/typescript/urlcode.yaml +5 -0
- package/recipes/webhook-receiver/README.md +20 -0
- package/recipes/webhook-receiver/functions/receive.mjs +16 -0
- package/recipes/webhook-receiver/recipe.yaml +27 -0
- package/recipes/webhook-receiver/tests/requests.json +59 -0
- package/recipes/webhook-receiver/urlcode.yaml +23 -0
- package/schemas/recipe.schema.json +139 -0
- package/schemas/urlcode.schema.json +659 -110
- package/skills/urlcode/SKILL.md +119 -0
- package/starters/default/.github/workflows/urlcode.yml +23 -0
- package/starters/default/.mcp.json +12 -0
- package/starters/default/AGENTS.md +79 -0
- package/starters/default/urlcode.yaml +0 -1
- package/dist/link-api.js +0 -136
- package/dist/link-cli.js +0 -141
- package/dist/link-events.js +0 -76
- package/dist/link-records.js +0 -31
- package/dist/link-store-worker.js +0 -150
- package/dist/link-store.js +0 -250
- package/dist/management-policy.js +0 -41
- package/dist/sqlite-version.js +0 -6
- package/dist/types/link-api.d.ts +0 -30
- package/dist/types/link-cli.d.ts +0 -36
- package/dist/types/link-events.d.ts +0 -27
- package/dist/types/link-records.d.ts +0 -11
- package/dist/types/link-store-worker.d.ts +0 -1
- package/dist/types/link-store.d.ts +0 -130
- package/dist/types/management-policy.d.ts +0 -9
- package/dist/types/sqlite-version.d.ts +0 -1
- package/docs/DYNAMIC-LINKS.md +0 -561
- package/docs/MANAGEMENT-SECURITY.md +0 -82
- package/examples/live-links/README.md +0 -11
- package/examples/live-links/tests/requests.json +0 -6
- package/examples/live-links/urlcode.yaml +0 -16
package/docs/COMPLIANCE.md
CHANGED
|
@@ -49,11 +49,11 @@ A **project** rule runs once with:
|
|
|
49
49
|
|---|---|
|
|
50
50
|
| `document` | The parsed and validated `urlcode.yaml` (includes are merged into `routes`) |
|
|
51
51
|
| `routes` | Route configuration by pattern, as written in YAML |
|
|
52
|
-
| `plan` | `testPlan()`: `inventory[]` (`path`, `handler`, `methods`, `middleware`, `policies`, `state`), `policies` (the per-route describe map)
|
|
52
|
+
| `plan` | `testPlan()`: `inventory[]` (`path`, `handler`, `methods`, `middleware`, `policies`, `state`), `policies` (the per-route describe map) |
|
|
53
53
|
| `policies` | `effectivePolicies(document, route)` by pattern: the merged configuration of every policy on each route |
|
|
54
54
|
| `origin` | The declared public origin, or `null` |
|
|
55
55
|
| `target` | `node` unless the caller states another |
|
|
56
|
-
| `host` | `{ requestLog
|
|
56
|
+
| `host` | `{ requestLog }` as declared for the deployment; `null` where undeclared |
|
|
57
57
|
|
|
58
58
|
A **route** rule runs once per inventory entry and additionally receives
|
|
59
59
|
`route` (the inventory entry), `config` (that route's YAML), `policy` (the
|
|
@@ -86,7 +86,6 @@ cache and compression secrets handling in `src/policies/cache.ts` and
|
|
|
86
86
|
| `rfc6585/throttle-functions` | [RFC 6585](https://www.rfc-editor.org/rfc/rfc6585) §4 | medium | Every active function or middleware route has an effective `policies.throttle` | Declare a throttle on the route or the project |
|
|
87
87
|
| `rfc9309/robots` | [RFC 9309](https://www.rfc-editor.org/rfc/rfc9309) | low | Some active route declares `policies.agents`, or an active `/robots.txt` `respond` route exists | Add a `/robots.txt` route or an agents deny list |
|
|
88
88
|
| `rfc9110/expired-routes` | [RFC 9110](https://www.rfc-editor.org/rfc/rfc9110) §15.5.11 | info | Lists routes past `expires` that still answer 410 | Remove them once the 410 window has served its purpose |
|
|
89
|
-
| `ops/management-private` | [Management security](MANAGEMENT-SECURITY.md) | info | Reminder when `dynamicLinks: true`: the management API and `/_urlcode` probes belong on a private bind | Run `links api` privately with an auth file; keep probes internal |
|
|
90
89
|
|
|
91
90
|
### `strict` (baseline plus)
|
|
92
91
|
|
|
@@ -102,15 +101,13 @@ cache and compression secrets handling in `src/policies/cache.ts` and
|
|
|
102
101
|
|
|
103
102
|
These rules check deployment settings, so `audit` takes `--request-log` to
|
|
104
103
|
declare the level the deployment uses (the audit process itself always logs
|
|
105
|
-
nothing)
|
|
106
|
-
false`; embedders pass `host` themselves. The references are the runtime's
|
|
104
|
+
nothing); embedders pass `host` themselves. The references are the runtime's
|
|
107
105
|
own [logging guarantees](MONITORING.md): records carry no URL, query, header,
|
|
108
106
|
body or binding, and `detailed` adds only the method and route pattern.
|
|
109
107
|
|
|
110
108
|
| Rule | Standard | Severity | Checks | Remediation |
|
|
111
109
|
|---|---|---|---|---|
|
|
112
110
|
| `privacy/request-log-minimal` | [Monitoring](MONITORING.md), Log records | medium (`info` when undeclared) | `host.requestLog` is `minimal` | Use the default log unless per-route rates are required |
|
|
113
|
-
| `privacy/link-events-off` | [Monitoring](MONITORING.md), The link event channel | medium; `high` with `includeCode` (`info` when undeclared and `dynamicLinks` is on) | The link event channel is off, or on without `includeCode` | Enable it only for a declared purpose; never disclose codes |
|
|
114
111
|
| `privacy/detailed-log-parameters` | [Monitoring](MONITORING.md), Log records | low | With `detailed` logging, no active route takes parameters (records name the pattern and method, never values) | Keep `minimal` on parameterised deployments |
|
|
115
112
|
|
|
116
113
|
## Writing custom rules
|
|
@@ -159,9 +156,9 @@ Without any compliance flag the audit report is unchanged apart from
|
|
|
159
156
|
"findings": [{ "rule": "rfc6585/throttle-functions", "severity": "medium", "route": "/hello/{name}",
|
|
160
157
|
"message": "…", "remediation": "…", "standard": { "name": "RFC 6585 …", "reference": "…", "section": "…" } }],
|
|
161
158
|
"counts": { "high": 0, "medium": 4, "low": 11, "info": 1 }, "pass": true,
|
|
162
|
-
"evidence": { "routes": 21, "active": 19, "
|
|
159
|
+
"evidence": { "routes": 21, "active": 19, "policies": ["agents", "cache", "security", "throttle"],
|
|
163
160
|
"files": ["urlcode.yaml", "routes/code.yaml"], "origin": null, "target": "node",
|
|
164
|
-
"host": { "requestLog": "minimal"
|
|
161
|
+
"host": { "requestLog": "minimal" },
|
|
165
162
|
"scope": "declared configuration and runtime facts; not a deployment or certification" } }
|
|
166
163
|
```
|
|
167
164
|
|
|
@@ -190,7 +187,7 @@ const report = await runCompliance(runtime, {
|
|
|
190
187
|
rules: [], override: {}, disable: [], // as a rules module would export them
|
|
191
188
|
ignore: ['rfc9110/expired-routes'],
|
|
192
189
|
origin: 'https://links.example',
|
|
193
|
-
host: { requestLog: 'minimal'
|
|
190
|
+
host: { requestLog: 'minimal' }, // what the deployment is configured with
|
|
194
191
|
});
|
|
195
192
|
await runtime.close();
|
|
196
193
|
```
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# Conditional routing
|
|
2
|
+
|
|
3
|
+
Conditions are exact string comparisons over a bounded, portable input subset.
|
|
4
|
+
A route's `match` is a conjunction: every declared query/header/cookie, host and
|
|
5
|
+
method must match. A mismatch returns 404 without trying a less-specific path.
|
|
6
|
+
Path precedence is unchanged; matching conditions is not authorization.
|
|
7
|
+
|
|
8
|
+
```yaml
|
|
9
|
+
version: "1"
|
|
10
|
+
routes:
|
|
11
|
+
/beta:
|
|
12
|
+
match:
|
|
13
|
+
headers: {x-beta-user: "true"}
|
|
14
|
+
redirect: {url: https://beta.example.com}
|
|
15
|
+
/campaign:
|
|
16
|
+
conditional:
|
|
17
|
+
cases:
|
|
18
|
+
- match: {query: {source: newsletter}}
|
|
19
|
+
redirect: {url: https://example.com/newsletter}
|
|
20
|
+
- match: {query: {source: partner}}
|
|
21
|
+
redirect: {url: https://example.com/partner}
|
|
22
|
+
fallback:
|
|
23
|
+
respond: {text: "Choose a campaign"}
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Use `conditional.cases` for multiple definitions at one path; duplicate YAML keys
|
|
27
|
+
remain errors. Each case has a nonempty match and exactly one redirect/respond
|
|
28
|
+
handler. The optional fallback has one of those handlers and no condition. No
|
|
29
|
+
nested cases or case-local middleware/bindings/policies. Shared parameters,
|
|
30
|
+
methods, response headers, middleware and policies belong to the route. A missing
|
|
31
|
+
fallback returns 404. Up to 16 cases per route; pairs must be provably disjoint:
|
|
32
|
+
at least one shared field must require different values. Ambiguous cases fail
|
|
33
|
+
activation instead of relying on order. Cases are considered before fallback.
|
|
34
|
+
|
|
35
|
+
Conditions admit query/header/cookie maps with 1–16 entries, names up to 128
|
|
36
|
+
characters and values up to 1,024. Header names normalize to lowercase; duplicate
|
|
37
|
+
case-insensitive names fail validation. Query strings are decoded once, have no
|
|
38
|
+
type conversion or default substitution, and duplicate examined values return
|
|
39
|
+
400. Examined duplicate header/cookie values return 400 when transport counts
|
|
40
|
+
are available. Cookies compare unquoted wire values, without percent decoding;
|
|
41
|
+
the Cookie header is bounded to 8 KiB. Missing values do not match empty strings.
|
|
42
|
+
Standard authentication and transport headers cannot be predicates. There are no regex, numeric,
|
|
43
|
+
geography, device, wildcard or arbitrary-code predicates.
|
|
44
|
+
|
|
45
|
+
`match.host` compares the canonical authority of the **operator-configured public
|
|
46
|
+
origin**, not client Host or forwarded headers. Configure the origin to use host
|
|
47
|
+
conditions; one runtime does not infer multiple trusted public hosts. Methods are
|
|
48
|
+
uppercase existing HTTP method tokens. A top-level match is checked before the
|
|
49
|
+
route's method/handler execution; it may mask a method rejection with 404.
|
|
50
|
+
|
|
51
|
+
Conditional results force `Cache-Control: no-store`; provider-specific CDN and
|
|
52
|
+
surrogate cache directives cannot enable caching. Cache policies must be
|
|
53
|
+
disabled or use no-store. This prevents one header/cookie branch from populating
|
|
54
|
+
a shared origin or downstream cache. Route conditions and case coverage require
|
|
55
|
+
explicit request fixtures; generated probes do not imply branch coverage.
|
|
56
|
+
|
|
57
|
+
Self-hosted, AWS and Vercel execute the shared matcher. Node-adapter tests are
|
|
58
|
+
local, not provider-deployment evidence; provider header coalescing limits still
|
|
59
|
+
apply. Cloudflare refuses conditions until an artifact lowering and conformance
|
|
60
|
+
tests exist. `urlcode capabilities` reports these distinctions. Operator plugins
|
|
61
|
+
remain trusted host code; conditions add no guest authority.
|
|
62
|
+
|
|
63
|
+
The [executable conditions project](../examples/conditions) includes explicit
|
|
64
|
+
branch, fallback, duplicate and trusted-origin requests. Run:
|
|
65
|
+
|
|
66
|
+
```sh
|
|
67
|
+
urlcode test --project examples/conditions --origin https://conditions.example.test
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Host names are canonical ASCII authorities (maximum 255 characters), with an
|
|
71
|
+
optional nondefault port. IPv6 literals and IDN Unicode host spellings are not
|
|
72
|
+
part of this initial condition syntax. Raw query comparisons remain separate
|
|
73
|
+
from typed route inputs: a parameter default does not make an absent condition
|
|
74
|
+
match, while all shared parameter validation still runs before a case handler.
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
# Verify a running deployment against the project
|
|
2
|
+
|
|
3
|
+
`urlcode verify-deployment` answers one question: does the deployment behind
|
|
4
|
+
`--target` behave the way this project declares? It starts the local snapshot
|
|
5
|
+
(as `validate` does), sends a bounded set of HTTP requests to the target and
|
|
6
|
+
compares what came back with what the snapshot says should come back. It reads
|
|
7
|
+
responses only. It has no infrastructure access, uses no credential, follows no
|
|
8
|
+
redirect and offers no `--insecure`.
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
urlcode verify-deployment --project ../my-links --target https://links.example
|
|
12
|
+
urlcode verify-deployment --project ../my-links --target https://links.example \
|
|
13
|
+
--expect-routes 12 --compliance baseline --fail-on medium --timeout-ms 5000
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
Options: `--origin` (the public origin the local snapshot generates absolute
|
|
17
|
+
URLs for; defaults to the target), `--expect-routes N`, `--expect-metrics`
|
|
18
|
+
(the operator chose to expose `/_urlcode/metrics` publicly), `--timeout-ms`
|
|
19
|
+
(per request, 100-120000, default 10000), `--fail-on high|medium|low|info|none`
|
|
20
|
+
(default `high`), the `audit` compliance flags (`--compliance`,
|
|
21
|
+
`--compliance-rules`, `--compliance-ignore`, `--compliance-warn`), and the
|
|
22
|
+
usual `--policy` binding the local snapshot needs to start.
|
|
23
|
+
|
|
24
|
+
## What it verifies
|
|
25
|
+
|
|
26
|
+
Every check yields findings `{check, severity, route?, message, expected?,
|
|
27
|
+
observed?}`. The report carries `checks` (assertions evaluated), `requests`
|
|
28
|
+
(HTTP requests sent), `findings`, `counts` by severity, `notes` (what was
|
|
29
|
+
deliberately not verified, such as compression delegated to a platform) and
|
|
30
|
+
`pass`.
|
|
31
|
+
|
|
32
|
+
| Check | What is compared | Severity |
|
|
33
|
+
|---|---|---|
|
|
34
|
+
| `probes` | `/_urlcode/health` and `/_urlcode/ready` answer 200 with `{status, version, routes}`; the deployed `version` equals the local snapshot's; the deployed route count equals the local count and `--expect-routes`; `/_urlcode/metrics` answers 404 unless `--expect-metrics` | high (metrics expected but absent: medium) |
|
|
35
|
+
| `fixtures` | `tests/requests.json` and the generated native cases, sent exactly as `urlcode test --target` would: status, expected headers and expected body | high |
|
|
36
|
+
| `security` | Per active literal route: every header of the effective security profile (`oshp`, `oshp-no-csp`, `set`, `unset`) with its exact value; a YAML `response.headers` value wins on a success, as it does in the runtime | high |
|
|
37
|
+
| `cache` | `Cache-Control` (and `CDN-Cache-Control`) equal the strategy's emitted value; skipped where YAML or an asset handler owns the header and on function routes, whose handlers may answer `private` | medium |
|
|
38
|
+
| `compression` | A second request with the declared `Accept-Encoding` on a response that is compressible (type, size at or above `minBytes`, no `no-transform`, no cookie, no secrets) carries `Content-Encoding`; on a delegated target it is noted, not checked | medium |
|
|
39
|
+
| `agents` | A `User-Agent` from the denied bundled list answers the configured status on every route with an enforcing agents policy; project list files and bare patterns are not probed | high |
|
|
40
|
+
| `throttle` | `RateLimit-Policy` carries the declared quota and window where the throttle is native | medium |
|
|
41
|
+
| `site` | Generated `robots.txt`, `sitemap.xml`, `favicon`, `security.txt` and `llms.txt` answer 200 with the expected content type; `robots.txt` and `security.txt` bodies equal the generated file (a `Sitemap:` line missing means the deployment was started without `--origin`) | medium |
|
|
42
|
+
| `methods` | A route that does not declare GET answers GET with 405 and `Allow`; a route with explicit `methods` answers OPTIONS with 405 and `Allow` | medium |
|
|
43
|
+
| `head` | On a `respond` route, HEAD answers 200 with GET's `Content-Length` and no body | medium |
|
|
44
|
+
| `errors` | An unmatched path (`/_urlcode-verify-<random>`) answers the runtime's 404 (`nosniff`, `no-store`) with the project-level security headers, which is also how a CDN error page or a different application shows itself | high |
|
|
45
|
+
| `transport` | On an https target, `Strict-Transport-Security` is present wherever the profile emits it (the deployment must have been started with `--origin https://...`); a certificate Node rejects, a refused connection or a timeout on the health probe ends the run; a redirect whose destination is plain `http:` is reported | high (http: destination: low) |
|
|
46
|
+
|
|
47
|
+
Bounds: fixtures plus generated cases, one to four requests per active literal
|
|
48
|
+
route (GET, then HEAD, OPTIONS, an encoded GET or a denied User-Agent where the
|
|
49
|
+
route calls for it), four probes. Concurrency is four for the route checks;
|
|
50
|
+
fixtures run one at a time, as `test` does. A run refuses to start above 10000
|
|
51
|
+
requests. Bodies are read up to 1 MiB and appear in the report only as the
|
|
52
|
+
first 200 bytes of a failing assertion. Requests count against the
|
|
53
|
+
deployment's throttle quotas: a quota smaller than the run turns later probes
|
|
54
|
+
into refusals, which the report shows as fixture and header findings.
|
|
55
|
+
|
|
56
|
+
## What it cannot verify
|
|
57
|
+
|
|
58
|
+
- Anything not visible in a response: process settings, worker counts,
|
|
59
|
+
request logging, binding files, the proxy or CDN configuration, certificates
|
|
60
|
+
beyond Node's default chain and host-name check, DNS.
|
|
61
|
+
- Routes with parameters, middleware or required inputs, except through the
|
|
62
|
+
fixtures the project supplies; the generated cases never invent business
|
|
63
|
+
data. Function bodies are verified only where a fixture asserts them.
|
|
64
|
+
- Agents policies built from project list files or bare patterns, compression
|
|
65
|
+
delegated to a platform, throttle refusals (the run never exhausts a quota
|
|
66
|
+
on purpose) and cache hits (the origin cache is invisible from outside).
|
|
67
|
+
- That the deployment stays this way: the report is a snapshot of one run.
|
|
68
|
+
|
|
69
|
+
A passing report says the target answered like the local snapshot during the
|
|
70
|
+
run. It is not a security assessment, a load test or a certification.
|
|
71
|
+
|
|
72
|
+
## Exit codes
|
|
73
|
+
|
|
74
|
+
`0` when no finding is at or above `--fail-on` (default `high`) and, when
|
|
75
|
+
`--compliance` was given, the compliance report passes or `--compliance-warn`
|
|
76
|
+
was set. `1` otherwise, and for an unreachable target, a rejected certificate,
|
|
77
|
+
a target that is not a bare HTTP(S) origin, or invalid options. The report is
|
|
78
|
+
printed as one JSON line after one `{"event":"finding",...}` line per finding.
|
|
79
|
+
|
|
80
|
+
## How it complements audit, compliance and benchmark
|
|
81
|
+
|
|
82
|
+
| Command | Runs against | Answers |
|
|
83
|
+
|---|---|---|
|
|
84
|
+
| `urlcode audit` | a local snapshot | are every route and method covered by passing checks, and do the counts reconcile |
|
|
85
|
+
| `urlcode audit --compliance` | declared configuration | does the configuration meet the rule set |
|
|
86
|
+
| `urlcode benchmark --target` | the deployment | how fast does it answer the workload |
|
|
87
|
+
| `urlcode verify-deployment` | the deployment | does it answer the way the project declares |
|
|
88
|
+
|
|
89
|
+
`audit` proves the project; `verify-deployment` proves the deployment is that
|
|
90
|
+
project. Neither replaces the [operational drills](OPERATIONAL-PROOF.md).
|
|
91
|
+
|
|
92
|
+
## A rollout gate
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
set -e
|
|
96
|
+
urlcode audit --project . --expect-routes 12 --compliance baseline
|
|
97
|
+
# deploy the candidate to the staging origin, then:
|
|
98
|
+
urlcode verify-deployment --project . --target https://staging.links.example \
|
|
99
|
+
--expect-routes 12 --fail-on medium
|
|
100
|
+
urlcode benchmark --project . --target https://staging.links.example --requests 500 --max-p95-ms 50
|
|
101
|
+
# switch traffic, then verify the production origin the same way:
|
|
102
|
+
urlcode verify-deployment --project . --target https://links.example --expect-routes 12
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
A version mismatch after the switch means traffic reaches a different
|
|
106
|
+
snapshot: an old instance still serving, a cache in front of the origin, or a
|
|
107
|
+
project revision that was never deployed. Roll back per
|
|
108
|
+
[Operations](OPERATIONS.md#deployment-and-rollback-procedure).
|
package/docs/EGRESS.md
ADDED
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
# Bounded proxy and webhook transport
|
|
2
|
+
|
|
3
|
+
Outbound requests use a host-owned HTTPS transport. Guests do not receive a fetch
|
|
4
|
+
API. Project declarations express behavior; an external operator policy, pinned
|
|
5
|
+
to the complete project revision, grants exact HTTPS origins separately to proxy
|
|
6
|
+
and signal operations. A configured destination never grants its own authority.
|
|
7
|
+
Binding injection uses existing explicitly granted secrets, resolved before the
|
|
8
|
+
host transport receives a literal header value. Never log those values.
|
|
9
|
+
|
|
10
|
+
The transport resolves the destination for each request, refuses any DNS response
|
|
11
|
+
containing a nonpublic address, and pins its connection lookup to one validated
|
|
12
|
+
answer. HTTPS certificate and hostname verification remain enabled. There is no
|
|
13
|
+
connection pool, fallback address, redirect following, or automatic retry. Private,
|
|
14
|
+
loopback, link-local, documentation, multicast, IPv4-mapped IPv6 and transition
|
|
15
|
+
addresses are refused. IPv6 filtering is deliberately conservative: 2001::/16,
|
|
16
|
+
2002::/16 and 3fff::/16 are refused along with addresses outside ordinary global
|
|
17
|
+
unicast. Network-level egress controls remain useful defense in depth.
|
|
18
|
+
|
|
19
|
+
Default limits per client are 16 simultaneous requests, five seconds including
|
|
20
|
+
DNS, 1 MiB request and response bodies and 16 KiB headers. Excess concurrency is
|
|
21
|
+
refused immediately. Requests use bounded buffering rather than streaming. Abort
|
|
22
|
+
and shutdown destroy active HTTP requests; unresolved system DNS operations may
|
|
23
|
+
finish in the background but cannot open a socket after cancellation. Those DNS
|
|
24
|
+
operations retain a separate concurrency slot until they settle, so repeatedly
|
|
25
|
+
timing out DNS cannot create an unbounded underlying lookup backlog. A shared
|
|
26
|
+
64-operation DNS cap also spans all client instances and runtime reloads in the
|
|
27
|
+
host Node isolate; closing a client does not release an unresolved DNS slot. Closing a
|
|
28
|
+
client refuses future requests and drains its bounded outstanding promises.
|
|
29
|
+
Errors carry only a fixed category, never a destination, request, header or secret.
|
|
30
|
+
|
|
31
|
+
Proxy destinations have a literal HTTPS authority. Path placeholders are encoded
|
|
32
|
+
as individual components; dot-segment values are refused. Query names and incoming
|
|
33
|
+
and outgoing headers require explicit selection. Host, framing, hop-by-hop and
|
|
34
|
+
proxy-authorization headers cannot be supplied. Ambient authorization, cookies,
|
|
35
|
+
forwarding metadata (the entire `x-forwarded-*` family) and Set-Cookie cannot be selected. Explicit host-resolved
|
|
36
|
+
Authorization injection is supported. Set-Cookie forwarding is deliberately
|
|
37
|
+
unsupported because multiple cookie fields cannot safely be represented by the
|
|
38
|
+
portable scalar header contract. Upstream redirects are returned as responses;
|
|
39
|
+
Location is forwarded only if explicitly selected and is never fetched. Headers
|
|
40
|
+
nominated by an incoming or upstream Connection field are removed even if selected.
|
|
41
|
+
Header names are normalized to lowercase; array-valued upstream fields are omitted.
|
|
42
|
+
An encoded request body requires explicitly selecting its Content-Encoding
|
|
43
|
+
header; literal header injection cannot change or replace that coding. Bodies
|
|
44
|
+
remain raw bytes, including content encoding; select Content-Encoding when
|
|
45
|
+
forwarding compressed responses. No transparent decompression occurs.
|
|
46
|
+
|
|
47
|
+
Webhook signals are best effort. The broker schedules work after the caller's
|
|
48
|
+
synchronous emit operation, with eight concurrent deliveries by default and no
|
|
49
|
+
queue. Saturation and closed brokers drop new events. Each event contains only
|
|
50
|
+
version, declared route pattern, status and method: never the actual request URL,
|
|
51
|
+
parameters, body, client identity, incoming headers or bindings. The webhook
|
|
52
|
+
receives a POST with JSON. Only 2xx responses count as delivered; all other status
|
|
53
|
+
codes and transport failures count as failed. Delivery order is unspecified,
|
|
54
|
+
there are no retries or durability guarantees, and shutdown aborts outstanding
|
|
55
|
+
work and awaits settlement. Counter snapshots report accepted, delivered, failed
|
|
56
|
+
and dropped events without including destination data. Applications must not use
|
|
57
|
+
these signals for guaranteed billing, audit retention or job execution.
|
|
58
|
+
|
|
59
|
+
The transport is a new security-sensitive host bridge. Unit tests and CI are not
|
|
60
|
+
an independent assessment or proof of hostile multi-tenant readiness. Public
|
|
61
|
+
provider network deployments require separate operator-owned fixtures and evidence.
|
|
62
|
+
|
|
63
|
+
## Project declarations and external grants
|
|
64
|
+
|
|
65
|
+
```yaml
|
|
66
|
+
version: "1"
|
|
67
|
+
routes:
|
|
68
|
+
/items/{id}:
|
|
69
|
+
proxy:
|
|
70
|
+
url: https://api.example.com/items/{id}
|
|
71
|
+
query: [page]
|
|
72
|
+
requestHeaders: [accept]
|
|
73
|
+
responseHeaders: [content-type, content-encoding]
|
|
74
|
+
headers:
|
|
75
|
+
authorization: {secret: API_TOKEN}
|
|
76
|
+
parameters:
|
|
77
|
+
- {name: id, in: path, required: true, schema: {type: string}}
|
|
78
|
+
secrets:
|
|
79
|
+
API_TOKEN: {secret: UPSTREAM_AUTHORIZATION}
|
|
80
|
+
signals:
|
|
81
|
+
- url: https://hooks.example.com/events
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
An injected secret is the complete header value (for example an operator-provided
|
|
85
|
+
Bearer value); interpolation and ambient credentials are not supported. Each
|
|
86
|
+
proxy placeholder must name a declared string path parameter. Proxy routes refuse
|
|
87
|
+
middleware in this initial implementation: middleware cannot safely authorize an
|
|
88
|
+
already materialized upstream request. Use host request policies before egress.
|
|
89
|
+
Proxy routes require cache disabled or `no-store`; explicit cache declarations
|
|
90
|
+
cannot override this. Responses always remove CDN cache directives and receive
|
|
91
|
+
`Cache-Control: no-store`. Compressed upstream bytes are refused if their
|
|
92
|
+
Content-Encoding field was not explicitly selected; it cannot be overridden by
|
|
93
|
+
route response headers.
|
|
94
|
+
|
|
95
|
+
The external version-1 policy has the existing `projectSha256` and route grants:
|
|
96
|
+
|
|
97
|
+
```json
|
|
98
|
+
{"version":1,"projectSha256":"<reviewed revision hash>","routes":{"/items/{id}":{"secrets":["UPSTREAM_AUTHORIZATION"],"egress":{"proxy":["https://api.example.com"],"signals":["https://hooks.example.com"]}}}}
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Use `permissions` to generate requested grants for review. Exact origin strings
|
|
102
|
+
omit a trailing slash and the default 443 port. Nondefault ports are explicit.
|
|
103
|
+
Proxy and signal purposes are independent even when they share an origin. Every
|
|
104
|
+
route's grant is checked against the current revision before credentials, assets,
|
|
105
|
+
workers or network clients are activated. Each runtime shares one bounded proxy
|
|
106
|
+
client and one bounded signal client, with at most 64 origins per purpose.
|
|
107
|
+
|
|
108
|
+
Signals emit when route execution and response policies produce a result,
|
|
109
|
+
including guest middleware responses and returned error status codes. Thrown
|
|
110
|
+
handler errors and host request-policy/plugin short circuits (including cache
|
|
111
|
+
hits) do not emit. HEAD requests and generated readiness probes do not emit.
|
|
112
|
+
The response never waits for webhook delivery. Counter events contain only
|
|
113
|
+
accepted/delivered/failed/dropped outcomes and counts and are exposed through
|
|
114
|
+
runtime metrics and the Prometheus `signals_total` series. A closed runtime stops
|
|
115
|
+
new requests, aborts egress and drains bounded pending work. Client disconnects
|
|
116
|
+
are not currently propagated into the runtime transport; the five-second deadline
|
|
117
|
+
still applies. All non-self-hosted targets currently refuse proxy and signals.
|
|
118
|
+
See the [executable example](../examples/egress/README.md).
|
|
119
|
+
|
|
120
|
+
Revision hashes also include declared project policies, profiles and site
|
|
121
|
+
configuration. Changing an inherited pre-egress restriction invalidates grants
|
|
122
|
+
just like changing a route or function source. Projects with these declarations
|
|
123
|
+
must regenerate and review their operator policy after upgrading to this hash
|
|
124
|
+
coverage; an old grant is intentionally refused rather than silently retaining
|
|
125
|
+
network authority under changed behavior.
|