Skip to content

Feat/2026.14.3 - #30

Merged
ConnorHaggerty merged 10 commits into
mainfrom
feat/2026.14.3
Oct 11, 2026
Merged

ConnorHaggerty merged 10 commits into
mainfrom
feat/2026.14.3

Conversation

@ConnorHaggerty

Copy link
Copy Markdown
Member

New

  • The Store: a sidebar page to browse what your machines can install (winget, Flathub, and the Ubuntu/Debian releases you run), with icons, categories and search. An app's page shows where it's available and how many machines have it; Install… builds a task and opens Deploy, Add to policy… adds it to an update policy. The catalog download is off until an admin turns it on.
  • Containers page: a searchable host picker with pinned hosts; sub-tabs for Containers & stacks, Images, Volumes and Networks; a quick-filter bar; a storage summary with Measure. Each image, volume and network shows what uses it, and remove/prune run as signed tasks (volumes are high risk).
  • Stack revisions can be named and pruned; named, current and deployed revisions are kept.
  • Apps page: a Policy… button per app.
  • The sidebar can show page names.

Fixes

  • A policy or Store task covering several package managers runs each step only where that manager exists, instead of failing one step on every host.
  • A stack Vigil deployed shows as Vigil's on the Containers page (it showed as "not deployed", then "external").
  • Catalog downloads: HTTPS only, and decompression is capped.

Hosts need the 2026.14.3 agent for images, volumes and networks and for the new prune actions.

A toggle above the theme switch widens the sidebar to show each page's
name beside its icon, and back. The names are the icons' own tooltips, so
a new page is labelled without a second copy of its name. The choice is
remembered per browser and applied before the first paint.
Each app on the Apps page gets a Policy… button: pick New policy or an
existing one, and the policy editor opens with the app added as Latest,
one rule per package manager it comes from (Mozilla.Firefox from winget,
firefox from dpkg). Nothing is saved until Save. Homebrew, Windows Update
and unmanaged installs cannot be a policy rule, and the button says so.
A policy that keeps Firefox current through winget and dpkg compiled to
two app_ensure steps for every host, so every host failed one of them: the
agent refuses a winget step on Linux and a dpkg step on Fedora. Each rule
that names a source now carries a when: guard (winget, Chocolatey, Scoop on
Windows; dpkg where apt is; rpm where dnf/yum/zypper is; Flatpak and Snap on
Linux) and is skipped elsewhere. The Apps page's Policy button makes exactly
these policies. The guards are checked by the server's validator and by
the agent's own evaluator, and the wiki's compiled example shows one.
Nothing ever marked a deployed stack's compose project as managed. Until
the host's next check-in it had no row, so the page listed it as "Managed
by Vigil, not deployed"; after, the check-in recorded it as external, with
an Adopt button. A deploy now records the project as managed (or adopted)
at once, and a check-in marks any project Vigil holds the compose file for
as Vigil's, so 14.2 rows mend themselves. A stack with no containers yet
says they appear after the host's next check-in.
A Store page in the sidebar: search, Windows/Linux tabs, category chips
and app cards with icons, over a package catalog Vigil keeps from the
public indexes the fleet uses — winget for Windows hosts, Flathub for
Linux, and each Ubuntu/Debian release in the inventory (libraries, -dev
packages and language packs left out). An app's page shows its
description, licence, homepage, each package manager that offers it and
how many machines have it, and:

- Install… builds an "Install <app>" task, one app_install step per
  package manager, each guarded to the machines that have it, and opens
  the Deploy dialog on it;
- Add to policy… adds it to a new or existing update policy.

Vigil does not reach out on its own: the daily sync (VIGIL_CATALOG_SYNC)
is off until an admin turns it on from the Store's empty page, which also
starts the first sync; manage.py sync_catalog runs it by hand. Indexes and
icons come only from an allowlist of hosts, without redirects, under a
size cap; icons must be PNGs and are cached and served by Vigil, as the
page's CSP only loads images from itself.
A downloaded index was gunzipped without a limit, so a small gzip could
inflate to gigabytes in memory. apt and Flathub indexes now decompress
through a 256 MiB cap (Ubuntu universe, the largest, is 69 MiB) and are
refused past it.

The Ubuntu and Debian Packages lists came over plain HTTP. All three
archives serve HTTPS, so the catalog now fetches only over HTTPS from its
allowlist, and an apt package name must follow Debian policy's grammar.
…and prune

The agent now sends each host's images, volumes and networks with every
check-in (three cheap engine calls), and each container's networks (with
its IP) and volume mounts: the edges that say what uses what, and what a
topology view will draw. GET /api/v1/hosts/<id>/docker/ returns the three
lists with the containers using each one, so "unused" is computed.

New actions, each a built-in task:
- docker_disk_usage (low): system df on demand — sizes per image and
  volume, and how much pruning would free. Sizing walks every volume, so
  it is not part of the check-in; the reading is stored per host.
- image_remove, image_prune (standard): never forced; dangling only, or
  every unused image.
- network_remove, network_prune (standard): the engine's own networks are
  refused.
- volume_remove, volume_prune (high): they delete data.
…rks, quick filters

The Containers page is laid out like Portainer's, around one host:

- A host button opens the searchable picker the Firewall page uses,
  listing hosts that run containers first with their counts, beside chips
  for the pinned hosts. The page opens on the Monitor page's host, else
  the first pin, else the host running the most containers.
- Sub-tabs: Containers & stacks, Images, Volumes, Networks, each with its
  count.
- A filter bar on every tab: text, and quick chips (Running / Stopped /
  Crashed / Update available; In use / Unused / Dangling), plus the tab's
  prune buttons. Filtering redraws from what was fetched.
- Images and Volumes show the storage strip: what each kind takes and what
  pruning would free, with Measure.
- Each image, volume and network lists what uses it — containers, mount
  points, IPs — and offers Remove only when nothing does. Every removal is
  a built-in task: signed, TOTP-confirmed, and high risk for volumes.

GET /api/v1/stacks/?host= with a malformed id is a 400, not a 500.
A revision can be named ("before the 2.0 upgrade") from the editor's
Revisions card, which also marks the current revision and the one last
deployed — a deploy now records it. Prune… keeps the newest N and always
keeps named revisions, the current one and the deployed one; deleting by
number can take a named one but never those two. Pruning is audited
(stack.revisions_pruned) with the numbers deleted.
@ConnorHaggerty
ConnorHaggerty merged commit adbf40c into main Oct 11, 2026
8 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