When pulling container images from ghcr.io, credentials are always
sent. If the token lacks access to a specific repo (e.g., a public
repo the caller's PAT cannot read), the pull fails with a 401/403
even though an unauthenticated pull would succeed.
Add fallback logic across all three pull paths:
- ensure_image() (local Docker daemon): detect auth failure from the
pull stream and retry with no credentials.
- pull_remote_image() (remote SSH daemon): same pattern using the new
consume_pull_stream() helper.
- cluster-entrypoint.sh (k3s/containerd): validate credentials via
the GHCR token endpoint before writing auth config to
registries.yaml; skip auth block when credentials are rejected so
containerd uses anonymous pulls.
Also adds is_auth_failure() helper that matches 401/403 status codes
and common Docker error messages (pull access denied, unauthorized,
denied: access forbidden), curl to the cluster runtime image for the
credential test, and updated error diagnosis messaging.
PR #281 removed the shared openshell-cluster Docker network in favor of
the default bridge. This restores custom bridge networking but makes each
gateway use its own isolated network named openshell-cluster-{name},
matching the existing container/volume naming convention.
Changes:
- Add network_name() to constants.rs for per-gateway network naming
- Add ensure_network() with retry/backoff and force_remove_network()
parameterized by network name instead of a global constant
- Attach containers to their per-gateway network via network_mode
- Disconnect and remove the network during gateway destroy
- Wire ensure_network() into the deploy flow before ensure_volume()
- Update architecture docs to reflect per-gateway network isolation