Repository navigation
feat(egress): the proxy includes the declared model endpoints, rendered by pi-dispatch egress render (#503, 2/6) - #517
Merged
Conversation
edgehero
force-pushed
the
feat/503-proxy-include
branch
from
October 2, 2026 07:12
d93b422 to
c2b2a93
Compare
…ed by pi-dispatch egress render (#503) The second change of #503. The proxy's rules now read the include that the first change renders, every way of starting the proxy mounts it, and a new verb writes it and prints the reload. - deploy/egress-proxy.conf (and its mirror): `include /etc/pi-dispatch/model-endpoints.conf` directly after `http_access deny allowed to_host_local` and before `http_access deny CONNECT !SSL_ports`. pi tunnels every provider call and first match wins, so the include must come before the port-443 deny. It coexists with #508's port-80 rule. - The third mount, read-only with `z`, from the deployment folder's own model-endpoints.conf: compose (and mirror), up's run argv, the Quadlet unit (a third placeholder rendered to <deployDir>/model-endpoints.conf, mounted directly like the allowlist and never copied like the rules, because the render writes that file in place), the hand-started Podman recipe, podman-conformance.yml and the host check's mount list. squid refuses to start without the file, so up, service install and doctor name it missing (or a directory) and start nothing. - The proxy, never a job, gets host.docker.internal:host-gateway on Docker (compose and up). Docker Desktop resolves the name already and its host-gateway is the same host address, so one line serves both. Rootless Podman adds nothing: host.containers.internal resolves. - worker/src/egress-cli.mjs, `pi-dispatch egress render`: loads the declaration through the worker's loader, renders in memory, then writes the include IN PLACE (no O_CREAT, O_NOFOLLOW, truncate, fsync). A temp file renamed over a single-file bind mount is invisible to the running proxy and `squid -k reconfigure` then reloads the old rules silently (measured on Docker 29.1.3 and Podman 4.9.3 and 5.8.1, 2026-09-30). A symlink, a directory or a missing file is refused; an unchanged render writes nothing. It prints `docker exec` or `podman exec ... squid -k reconfigure` for the deployment's venues and never runs it. - One governing rule: the folder's rules include model-endpoints.conf only together with a proxy that mounts it. A two-mount proxy stays current; a third bind must be this folder's file; an absent one is drift only when the folder's rules include the file (its next start exits on squid's missing-include FATAL, measured), and such a proxy of this folder is said to be out of date. up's rules refresh and the replace of a proxy without the mount are one step, asked once: declined or not possible here, nothing is written; a failed replace puts the old rules back from the backup. In each of those cases the usual proxy step then runs on the old rules (start a stopped proxy, unpause a paused one, name declared endpoints), and a blocked step names the way out (rm -f -v the proxy, then up). - Endpoints declared under rules that predate #503 are not drift (a replace would cut tunnels and fix nothing): up, doctor and egress render print one shared line naming the rules refresh (docker: the folder's rules; podman: the account copy and service install --force). doctor says a missing include with a cross only when the running rules include it, else a warning. - render: truncates only after judging the file (a hard-linked include is refused), empties the include when a write fails rather than leaving a prefix, compares PI_MODEL_ENDPOINTS_FILE as resolved paths and warns when only the shell sets it. - A replaced proxy is removed with `rm -f -v`, so its anonymous squid volumes go with it. - canonicalHost: `a.lan:` (an empty port) is refused as carrying a port, not as an IPv6 address with an IPv4 tail (PR #515's review). - docs/egress.md gains a short "Local model servers" section (per-venue reachability, jobs cannot use it until the keyless gate and slots land), and says a hand-started proxy or an old compose copy must be recreated with the third mount, never just restarted. Specs: INT-EGRESS-POLICY-CONTRACT amended (the include, its order, its mounts, the in-place render, reload by reconfigure, the governing rule, the endpoint case in Acceptance). REQ-EGRESS-ALLOWLIST amended (endpoint acceptance). DES-EGRESS-DENY-ON-A-DEDICATED-NETWORK amended (through the proxy, never the host network). INT-MODEL-ENDPOINTS-FILE-CONTRACT amended (Status, the empty port). INT-CONTAINER-RUNTIME-CONTRACT unchanged, checked. Signed-off-by: Rob Boerman <robboerman@live.nl>
edgehero
force-pushed
the
feat/503-proxy-include
branch
from
October 2, 2026 07:39
c2b2a93 to
1b7f64b
Compare
8 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Part of #503: PR 2 of 6. The egress proxy now includes the declared model endpoints. A new verb,
pi-dispatch egress render, writes the include, and every place the proxy is started mounts it.What changes
deploy/egress-proxy.conf(and its mirror) addsinclude /etc/pi-dispatch/model-endpoints.confdirectly afterhttp_access deny allowed to_host_local, beforehttp_access deny CONNECT !SSL_ports.allow CONNECT <host> <port>for each declared pair. By default it is empty.pi-dispatch egress render.model-endpoints.confin place: noO_CREAT,O_NOFOLLOW, truncate, write, fsync.docker exec/podman exec pi-dispatch-egress-proxy squid -k reconfigureand never reloads the proxy itself. Measured: reconfigure re-reads the include, keeps open tunnels, and keeps the proxy's networks and IPs.model-endpoints.confis mounted read-only (ro,z) in compose and its mirror,up's run argv, the Quadlet unit and its mirror, the hand-started recipe indocs/podman.md,podman-conformance.yml, the host check and the deploy-lint fixture.up,service installand doctor refuse or flag a missing include, or a directory at its path.upgive the proxy, never jobs,host.docker.internal:host-gateway. Measured on Docker Engine 29.1.3: this reaches a server on 172.17.0.1 or 0.0.0.0. On Desktop the name already resolves. Rootless Podman needs nothing (host.containers.internal).egress-proxy-state.mjs).upreplaces it instead of restarting it.docs/egress.mdgains a "Local model servers" stub.a.lan:) now gets the "carries a port" refusal.Tests
upargv, Quadlet, podman-doc and CI-sites tests.