AGENTS.md: External Exposure Policy (MANDATORY); comfyui_rocm seam retargeted
Every Caddy-proxied service is now either behind the auth chain or explicitly internal-only, with the provider-first flip procedure codified. The comfyui GPU-access seam test now asserts the deployed contract (group_add keep-groups + udev MODE 0666 on kfd/renderD*) instead of the pre-fix 'video' group assumption.
This commit is contained in:
@@ -204,6 +204,34 @@ planning/dispatch. See [serverAppConfigs-docs/Architecture/Testing Policy.md](se
|
|||||||
are the auth mechanism. Headless sudo passes the password via the
|
are the auth mechanism. Headless sudo passes the password via the
|
||||||
`FRANK_SUDO_PW` environment variable. The value never enters the repo.
|
`FRANK_SUDO_PW` environment variable. The value never enters the repo.
|
||||||
|
|
||||||
|
|
||||||
|
## External Exposure Policy (MANDATORY)
|
||||||
|
|
||||||
|
Every service reverse-proxied through Caddy is either behind the auth chain
|
||||||
|
(Anubis :8923 → Authentik embedded outpost) or explicitly designated
|
||||||
|
internal-only — no public DNS name, no vhost. New services default to
|
||||||
|
internal-only until guarded.
|
||||||
|
|
||||||
|
When guarding a new vhost, follow this order — provider first, then route:
|
||||||
|
|
||||||
|
1. Create the outpost proxy provider FIRST (`external_host` = the exact vhost
|
||||||
|
URL including trailing slash; `internal_host = http://caddy:8017`). If the
|
||||||
|
vhost flips before the provider exists, authenticated traffic hits the
|
||||||
|
outpost error page instead of the app.
|
||||||
|
2. Flip the vhost to `reverse_proxy anubis:8923` with
|
||||||
|
`header_up X-Real-Ip {remote_host}`, and add the post-auth
|
||||||
|
`@<svc> host <vhost>` handler on the `http://:8017` listener routing to the
|
||||||
|
real upstream.
|
||||||
|
3. The Anubis guard set, the Caddy TLS edge, and the outpost provider list
|
||||||
|
must stay in lockstep — they change together in one deploy.
|
||||||
|
4. Service-to-service traffic (e.g., Alloy → Loki push) targets internal
|
||||||
|
addresses (`loki:3100`), never the public hostname — non-browser clients
|
||||||
|
cannot solve challenges.
|
||||||
|
|
||||||
|
Exempt-by-construction categories stay exempt with a documented reason in the
|
||||||
|
vhost comment: the IdP itself (`auth.` — its login flow must never sit behind a
|
||||||
|
challenge), git smart-HTTP endpoints (git clients cannot solve JS challenges),
|
||||||
|
and services with their own complete auth.
|
||||||
## Deletion & Trash Policy (MANDATORY)
|
## Deletion & Trash Policy (MANDATORY)
|
||||||
|
|
||||||
Never run `rm` to delete files. The command deletes permanently. Move every
|
Never run `rm` to delete files. The command deletes permanently. Move every
|
||||||
|
|||||||
+22
-15
@@ -5,13 +5,16 @@
|
|||||||
# - build from a Containerfile based on the gfx1151 ROCm torch image
|
# - build from a Containerfile based on the gfx1151 ROCm torch image
|
||||||
# - pass /dev/kfd and /dev/dri to the container
|
# - pass /dev/kfd and /dev/dri to the container
|
||||||
# - NOT pass --cpu
|
# - NOT pass --cpu
|
||||||
# - add the video and render groups
|
# - grant GPU access via world-writable compute nodes (udev MODE 0666), not
|
||||||
|
# named-group membership, because systemd user-unit spawns carry NO
|
||||||
|
# supplementary groups at spawn time
|
||||||
#
|
#
|
||||||
# STATUS (2026-08-19): the GPU migration is applied. The compose builds
|
# STATUS (2026-08-31): the GPU migration is applied. The compose builds
|
||||||
# comfyui-rocm:gfx1151 from Containerfile.comfyui (AMD's gfx1151 torch base),
|
# comfyui-rocm:gfx1151 from Containerfile.comfyui (AMD's gfx1151 torch base),
|
||||||
# passes /dev/kfd + /dev/dri, adds the video group (render is unmappable in
|
# passes /dev/kfd + /dev/dri, and relies on the udev rule at
|
||||||
# rootless), and drops --cpu.
|
# dankclaw/udev/99-comfyui-gpu-access.rules (MODE 0666 on kfd + renderD*) for
|
||||||
# The four compose-wiring tests below are active (un-skipped). See
|
# compute-node access; group_add is keep-groups only. The four compose-wiring
|
||||||
|
# tests below are active (un-skipped). See
|
||||||
# serverAppConfigs-docs/Research/ComfyUI ROCm and Vulkan.md.
|
# serverAppConfigs-docs/Research/ComfyUI ROCm and Vulkan.md.
|
||||||
|
|
||||||
load helpers
|
load helpers
|
||||||
@@ -64,19 +67,23 @@ print("command OK:", cmd)
|
|||||||
PYEOF
|
PYEOF
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "comfyui adds the video group (render is unmappable in rootless)" {
|
@test "comfyui GPU access uses keep-groups + udev MODE 0666, not named groups" {
|
||||||
python3 - "$REPO_ROOT/dankclaw/compose.yaml" <<'PYEOF'
|
python3 - "$REPO_ROOT/dankclaw/compose.yaml" "$REPO_ROOT/dankclaw/udev/99-comfyui-gpu-access.rules" <<'PYEOF'
|
||||||
import sys, yaml
|
import sys, yaml
|
||||||
with open(sys.argv[1]) as fh:
|
with open(sys.argv[1]) as fh:
|
||||||
data = yaml.safe_load(fh)
|
data = yaml.safe_load(fh)
|
||||||
groups = data["services"]["comfyui"].get("group_add", [])
|
groups = data["services"]["comfyui"].get("group_add", [])
|
||||||
# 'video' is added (it resolves in the rootless namespace). 'render' (gid 990)
|
# User-unit spawns carry NO supplementary groups, so named group_add entries
|
||||||
# is intentionally ABSENT: rootless podman cannot map it into the container
|
# (video, render) can never be honored at spawn time. The deployed contract is
|
||||||
# namespace (the subgid range is 100000+), so --group-add render fails to start.
|
# keep-groups plus world-writable compute nodes via the udev rule; a future
|
||||||
# GPU access comes from the /dev/kfd + /dev/dri passthrough, checked host-side
|
# edit that drops either half must fail here.
|
||||||
# (the run user is already a member of 'render' on the host).
|
assert list(groups) == ["keep-groups"], \
|
||||||
assert "video" in groups, f"comfyui group_add must include video; got: {groups}"
|
f"comfyui group_add must be exactly ['keep-groups']; got: {groups}"
|
||||||
assert "render" not in groups, f"comfyui group_add must NOT include render (unmappable in rootless); got: {groups}"
|
rule = open(sys.argv[2]).read()
|
||||||
print("groups OK:", groups)
|
assert 'KERNEL=="kfd", MODE="0666"' in rule, \
|
||||||
|
"udev rule must grant MODE 0666 on kfd with NO SUBSYSTEM guard (misc-class devices have no subsystem to match)"
|
||||||
|
assert 'KERNEL=="renderD*", SUBSYSTEM=="drm", MODE="0666"' in rule, \
|
||||||
|
"udev rule must grant MODE 0666 on renderD* (SUBSYSTEM drm guard)"
|
||||||
|
print("GPU access contract OK")
|
||||||
PYEOF
|
PYEOF
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user