Skip to content

Feature/volume perms firewall UI#62

Merged
insuT0ver merged 11 commits into
mainfrom
feature/volume-perms-firewall-ui
Jul 22, 2026
Merged

Feature/volume perms firewall UI#62
insuT0ver merged 11 commits into
mainfrom
feature/volume-perms-firewall-ui

Conversation

@insuT0ver

@insuT0ver insuT0ver commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Summary

Related issue

Fixes #

Type of change

  • Bug fix (fix)
  • New feature (feat)
  • Documentation (docs)
  • Refactor / maintenance (refactor / chore)
  • Other:

Checklist

  • My branch is up to date with main and focused on a single change.
  • The project builds and type-checks locally.
  • Tests pass (npm --prefix gateway test) and I added/updated tests where relevant.
  • I ran Prettier and did not reformat unrelated code.
  • Commit messages follow Conventional Commits.
  • I did not introduce logging of secrets, tokens, or credentials.
  • Documentation is updated where needed (README / relevant docs).

Notes for reviewers

@insuT0ver
insuT0ver requested a review from a team July 14, 2026 11:34
Comment thread gateway/src/docker-actions.ts Outdated
@insuT0ver
insuT0ver force-pushed the feature/volume-perms-firewall-ui branch 2 times, most recently from 5a7aa9d to 8db472b Compare July 20, 2026 06:18
Comment thread gateway/frontend/src/app/core/services/state.service.ts Outdated
insuT0ver and others added 11 commits July 22, 2026 11:33
In the path sub-request pie menu the 'Allow prefix/*' action (filter icon)
sat on the right while 'Dismiss' sat on the left, so the path icon jumped
sides once a domain was already in path mode. Swap them so everything
path-related stays on the left, matching the general firewall pie.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ymous)

Previously every host-path bind was hard-denied and every named volume was
always allowed. Add three per-devcontainer mount gates to the action catalog:
  - mount.bind      (host-path binds; dangerous, off by default)
  - mount.named     (isolated labelled Docker volumes; on)
  - mount.anonymous (source-less volumes, never touch host; on)

validateHostConfig now classifies each Binds/Mounts entry by kind and consults
the per-container toggles (default perms preserve the old behaviour). Inline
driver-config volumes (host-path bind escape) stay unconditionally rejected.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…gles

Render the new mount gates as a dedicated 'Volume mounts' section in the
docker rights panel: one card per kind with a plain-language hint, the bind
card flagged in danger red, and a notice explaining the risk split. Extends
the action-kind/group models with 'mount'/'mounts'. Updates the proxy
explainer, which previously claimed host binds are always rejected.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Two gaps closed so the per-container view behaves like /firewall:
  - Pending inbox now also lists path sub-requests from path-mode domains
    (container + global markers), with the same path pie menu, instead of
    only non-path requests.
  - Global ('general') rules now follow the active allow/deny/path tab
    instead of always dumping allow+deny+path at once — you see global
    allows under Allowed, global denies under Blocked, and global path
    domains under Path mode. The Path mode tab shows whenever container or
    global path domains exist.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The container-detail page renders its firewall rules from its own local
detail$ (getContainerDetail), not from the shared state.rules$. Inline
actions refresh both state.loadAll() and load(), but the shared
ConfirmModalComponent only called state.loadAll() — so after a 'For everyone'
(global) allow/deny the resolved request stayed visible until a manual page
refresh.

Emit a confirmResolved$ event from ModalService when the confirmation is
applied; container-detail subscribes and reloads its local view. Firewall
and dashboard render from state.rules$ and are unaffected.

Adds a regression test that fails without the fix.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Make mount.named/mount.anonymous default off, matching the module's
  secure-by-default policy (all actions off unless explicitly enabled).
  Keep DEFAULT_MOUNT_PERMS, portal copy, and tests consistent.
- Extract validateBind/validateMount helpers from validateHostConfig to
  cut its length and flatten the deeply nested Binds/Mounts loops;
  behaviour (incl. the VolumeOptions.DriverConfig hard-deny) unchanged.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Mount-soorten staan sinds deze branch secure-by-default uit, en
validateHostConfig raadpleegt die toggles. De boundary-test voor #8
(andermans named volume) mikt op de ownership-check, maar die draait pas
ná validateHostConfig. Zonder mount.named-toggle weigert de HostConfig-
validatie de named-volume-mount al eerder ("named volume mounts are
disabled"), waardoor de assertie op /owned by another devcontainer/ faalt.

Zet mount.named aan in de beforeAll zodat de probe de ownership-check
daadwerkelijk bereikt.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…lumes card

De losse violette "Volume mounts"-sectie verdween; de drie mount-toggles
(bind/named/anonymous) staan nu als subgroep in de Volumes-kaart onder de
altijd-toegestane sectie. Ze horen daar: net als de andere always-acties
vereisen ze geen timer (ze worden bij container-create afgedwongen).

- Twee-regelige mount-rijen (label + korte hint) onder een "Volume mounts"-
  subkopje, visueel gegroepeerd en gescheiden van de read-only rijen.
- Bind-mount rood gemarkeerd als de gevaarlijke escape-vector.
- align-items:start op de always-grid zodat de hogere Volumes-kaart de
  buurkaarten niet meerekt.
- Notice + proxy-uitleg verwijzen nu naar de nieuwe plek ("under Volumes").
- Dode CSS opgeruimd (.da-section.mounts, .da-mount-grid, .da-mount-card*, .ic-red).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Nieuwe firewall-requests verschenen pas na een handmatige refresh. Twee
oorzaken, beide aangepakt:

- StateService: de blinde 30s-fallbackpoll vervangen door een zichtbaarheids-
  gebonden voorgrond-poll (5s terwijl het tabblad zichtbaar is, gepauzeerd
  wanneer verborgen) plus een directe refetch bij focus/visibility. Zo blijft
  state.rules$ vers, ook als de WebSocket niet levert (dev-proxy zonder /ws,
  verbroken socket, gethrottelde achtergrond-tab). Het Angular-equivalent van
  TanStack Query's refetchOnWindowFocus.
- container-detail: deze pagina toont zijn eigen detail$ (getContainerDetail),
  los van state.rules$, en herlaadde alleen na het afhandelen van een regel.
  Nu herlaadt hij mee op elke rules$-emit (skip(1) laat de initiële replay
  vallen), zodat een binnenkomend request binnen ~5s zichtbaar wordt zonder
  refresh.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…vice

Addresses Aikido review on gateway/frontend/src/app/core/services/state.service.ts:

- The 5s foreground poll fired loadAll() (three API calls) continuously while
  the tab was visible, even when the WebSocket push was healthy. The poll is
  only a fallback, so gate it on WS state: it now runs solely when the socket
  is not OPEN (disconnected/absent, e.g. dev-proxy without /ws). A healthy WS
  means no steady-state polling at all.
- Move browser-lifecycle concerns (focus/visibility listeners + poll timer) out
  of StateService into a dedicated ForegroundSyncService, keeping StateService
  focused on state + API/WebSocket sync (single responsibility).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
container-detail now reloads its local detail off state.rules$ (added when
firewall requests became auto-showing), which every allow/deny already refreshes
via state.loadAll(). The older, dedicated modal.confirmResolved$ path fired a
second load() for the same global-confirm event, so a "For everyone" confirm
did two getContainerDetail fetches instead of one.

Remove the now-superseded confirmResolved$ plumbing (ModalService +
ConfirmModal + the container-detail subscription); the rules$ subscription
covers the case on its own. Fixes the pre-existing failure in
container-detail.refresh.spec.ts (detailCalls 3 -> 2).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@insuT0ver
insuT0ver force-pushed the feature/volume-perms-firewall-ui branch from 68ca78d to dc48294 Compare July 22, 2026 11:41
@insuT0ver
insuT0ver merged commit 8ec8c6c into main Jul 22, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant