Skip to content

Release v0.9.0

Latest

Choose a tag to compare

@eniac111 eniac111 released this 05 Sep 13:05
f0a6d95

New Features

Session Access Policy Type

A new SessionAccess policy type controls when selected users or groups
may use a desktop session — for example a school computer lab usable only
during school hours, or a kiosk restricted to business hours.

  • Weekly schedules per user or group: allowed time windows by day, with
    node-local times and midnight-crossing windows (e.g. 22:0002:00).
  • Two enforcement layers:
    • Layer 1 (logind, always on) — as an allowed window ends the agent warns
      the user (default 30/15/5 minutes, the final warning bypassing
      do-not-disturb) and then locks the screen (apps keep running) or
      logs off the session, per rule. A re-lock watchdog keeps a session
      locked outside its allowed hours.
    • Layer 2 (pam_time, optional) — blocks fresh logins outside the allowed
      hours by managing a marked block in /etc/security/time.conf and enabling
      pam_time in the account stack. Optionally extends to SSH. The block
      encodes the full weekly schedule, so it keeps enforcing even while the
      agent is not running.
  • Distro-aware PAM: on Debian/Ubuntu the agent enables pam_time
    automatically via pam-auth-update; on authselect-managed Fedora/RHEL it
    reports a degraded compliance state with a documented one-time admin step
    while Layer 1 still enforces.
  • Lockout guard rails: root is never restricted, the time.conf block is
    written atomically with a self-check and is tamper-protected, and unbinding
    the policy removes all PAM artifacts fail-open.
  • Web UI: a dedicated editor with per-rule user/group lists, a day-and-time
    window builder, lock/log-off selection, warning thresholds, the PAM and SSH
    switches, and a node-requirements info box.

Known limitation, by design: on GNOME and KDE the screen unlock is enforced
by the Layer-1 watchdog, not PAM — the desktop lockers do not honour the PAM
account phase on unlock. Use the Log off end action with PAM for the
strictest restriction. See docs/session-access.md for full behaviour, the
node requirements, and break-glass recovery.

Flatpak Policy Type and Application Catalog

A new Flatpak policy type manages Flatpak remotes and applications on
managed desktops, with a server-side application catalog.

  • Remotes: configure any number of Flatpak remotes per policy (URL, GPG
    key, subset such as Flathub's verified, allow-/deny-list filters,
    priority, enabled state). Definitions are written to /etc/bor/flatpak/
    and tamper-protected; existing remotes such as a distribution-provided
    flathub are adopted rather than duplicated and restored on unbind.
  • Applications: desired state Present, Latest or Absent per app,
    with remote, branch, optional and delete data flags. The agent drives
    the flatpak CLI idempotently, off the policy stream, with per-operation
    timeouts (default 30 minutes), and reports one compliance item per remote
    and per application.
  • Updates: optional periodic flatpak update and unused-runtime cleanup.
  • Not applicable when Flatpak is absent: nodes without flatpak report
    the policy as Inapplicable, like other unsupported subsystems.
  • Catalog (Settings → Flatpak repositories): Flathub is indexed out of
    the box from its AppStream feed; additional repositories can be added from
    a .flatpakrepo URL or manually, refreshed on a schedule or by uploading
    an appstream.xml.gz for air-gapped servers. The policy editor searches
    the catalog and copies remote definitions into the policy, so policies stay
    self-contained. New permissions flatpak_repo:* (backfilled onto every
    role that holds settings:manage); new server settings
    BOR_FLATPAK_CATALOG_REFRESH, BOR_FLATPAK_CATALOG_MAX_DOWNLOAD_MB and
    BOR_FLATPAK_CATALOG_ALLOW_PRIVATE_NETWORKS.
  • Agent config: optional flatpak: section (binary, state_dir,
    state_file, proxy_url).

See docs/flatpak.md.

Instance-Hosted Agent Packages and Deploy Wizard

Every Bor server now ships and serves the agent packages itself, so managed
nodes never need internet access to install or upgrade the agent.

  • The bor-server packages and the container image embed the bor-agent
    packages for all formats (deb, rpm, apk, Arch) and architectures (amd64,
    arm64, ppc64le) under /usr/share/bor/agent-repo, assembled and
    GPG-signed at release build time.
  • The server serves them at /agent/*: a signed flat apt repository
    (/agent/deb), a signed dnf/zypper repository (/agent/rpm), direct
    downloads for Alpine and Arch, the repository signing key
    (/agent/repo-key.asc), the internal CA certificate (/agent/ca.crt) and a
    static install page at /agent/. Download endpoints are public by design
    (package managers cannot authenticate); files are served through a rooted
    filesystem with no directory listings.
  • Deploy agent wizard (download icon in the masthead, or the button on the
    Nodes page): pick the platform (Debian/Ubuntu, RHEL/Fedora, SUSE, Alpine,
    Arch) and architecture and get a single copy-paste script that trusts the
    server CA, sets up the signed repository or downloads the package, and
    optionally generates a one-time enrollment token inline so the same script
    enrolls and starts the agent. A Direct downloads tab lists every package.
  • New setting BOR_AGENT_REPO_DIR (agent_repo.dir); when the directory
    holds no manifest the feature is off and /agent/* returns 404. The server
    logs a warning at startup when the packaged agent version differs from its
    own.
  • New Prometheus counter bor_agent_package_downloads_total{format,arch}
    (aggregate labels only, no client identifiers).

Policy Export and Import

Policies can be exported and imported as bor.dev/v1 YAML bundles
(schema in proto/export/export.proto), for backups, migration between
servers and keeping policies in version control.

  • Format: Kubernetes-style envelope — one Policy or PolicyBinding
    document per YAML document, with metadata.name / displayName /
    description and a spec holding the policy type and its canonical
    content. Bindings reference policies by slug or display name and node
    groups by name, never by UUID, so bundles are portable across servers.
  • Export from the Policies list: a single policy from its kebab menu, or
    select several and export them as one bundle with their bindings. The API
    (GET /api/v1/policies/export) also supports format=json.
  • Import (POST /api/v1/policies/import): uploading a bundle first runs a
    dry run and shows a preview table of what would be created, updated,
    skipped or rejected; nothing is written until confirmed. Conflict modes
    for an existing policy name: fail the import (default), skip that policy,
    or update the existing draft (released policies are never overwritten).
    A bundle with any invalid document is rejected as a whole, and bindings
    to node groups that do not exist on the server are reported as errors.
  • Export requires policy:view, import requires policy:create; both are
    audited (policy.export, policy.import).

Policy Creation Wizard

  • /policies/new is now a four-step wizard: Type (tiles grouped into
    Browsers / Desktop / System, each with a tagline and a description panel),
    Details (name, description), Configuration (the same editor used on
    the edit page) and Review. A contextual help drawer is available on
    every step after the first.
  • The success screen offers the two things people do next — Release now
    (with confirmation) and Assign to a node group, which opens the binding
    form with the new policy pre-selected — plus open the editor, create another
    or back to the list. Changing the type after configuring or leaving with
    unsaved work asks for confirmation.
  • Policy types now have a single registry (labels, taglines, descriptions,
    icons) used by the wizard, the Policies list, the dashboard and the
    bindings page; Firefox, Chrome, Thunderbird, KDE and Flatpak show their
    brand marks (CC0-licensed) next to the type name.
  • Internally the monolithic policy editor was split into shared per-type
    editors (tree editors for the browser catalogues, KConfig, JSON-backed
    types), so the wizard and the edit page cannot drift apart.

Readable Sidebar and Masthead in Every Theme

  • The sidebar and masthead are now styled through per-theme semantic
    properties, so navigation group titles, the current item, the footer and
    links stay readable in the light, dark and high-contrast themes (group
    titles 7.9:1, links 9.4:1, footer 6.6:1 in the light theme; previously as
    low as 1.65:1). Fixes #138.
  • De-emphasized text (policy descriptions, meta rows) is standardized at
    14 px with a theme-aware subtle token instead of hand-rolled small gray
    text.

Security

  • Flatpak catalog SSRF hardening (CodeQL go/request-forgery): admin-
    supplied repository URLs are validated with a strict https-only pattern
    (host name or IPv4 literal, no credentials); loopback, unspecified,
    link-local, multicast and broadcast addresses are always refused and
    private/CGNAT ranges are refused unless
    BOR_FLATPAK_CATALOG_ALLOW_PRIVATE_NETWORKS=true; the transport resolves
    names itself and dials only approved addresses (DNS pinning), TLS 1.2
    minimum.
  • Agent package downloads are served through an os.Root-scoped
    filesystem (path traversal and symlink escapes are structurally
    impossible), never list directories, set X-Content-Type-Options: nosniff
    and cap manifest reads. Only public material (CA certificate, signing
    public key) is exposed.
  • Release signing: the agent repository signing key may now be
    passphrase-protected; the passphrase is consumed from the environment
    only and never passed on a command line.
  • Dependabot: all open alerts resolved — gRPC-Go HTTP/2 DATA-frame
    memory exhaustion (GHSA-vp52-pcj8-j9qc), five fast-uri host-confusion /
    SSRF advisories, two browserslist advisories, brace-expansion,
    js-yaml, nanoid and postcss-selector-parser.

Bug Fixes

  • Dashboard: nodes without a group and the per-group online/offline tiles
    are computed from the many-to-many node_group_ids array; previously every
    node was reported as unassigned and the group tiles stayed empty. A node in
    several groups is now counted in each.
  • Policies: the Polkit editor no longer crashes on rules created through the
    API, where protojson omits empty action_ids / action_prefixes /
    action_conditions arrays; sparse rules are normalized on load.
  • Agent: the systemd unit sets TimeoutStopSec=120 so long-running
    enforcement steps (Flatpak installs, package transactions) can wind down
    cleanly on stop instead of being killed.
  • Compose: BOR_VERSION build argument sets the version shown in the sidebar
    and /api/v1/version.

Platform & Dependency Updates

  • Server + agent: google.golang.org/grpc 1.82.1 → 1.83.2,
    golang.org/x/crypto 0.52.0 → 0.55.0, golang.org/x/net 0.55.0 → 0.58.0,
    golang.org/x/text 0.39.0 → 0.41.0, golang.org/x/sys 0.45.0 → 0.47.0.
    Server: github.com/go-ldap/ldap/v3 3.4.12 → 3.4.14. Agent:
    google.golang.org/protobuf 1.36.11 → 1.36.12.
  • Frontend: react-router 8.3.0 → 8.3.1 plus the transitive fast-uri,
    browserslist, postcss-selector-parser, js-yaml, brace-expansion
    and nanoid bumps.
  • CI: actions/checkout v7; the pipeline gained an Assemble Agent Repo
    stage between the agent and server package builds, and the container image
    embeds the assembled repository. Dependabot ignores ESLint major updates
    until eslint-plugin-jsx-a11y supports ESLint 10.
  • Metrics: new bor_flatpak_catalog_apps_total,
    bor_flatpak_catalog_last_success_timestamp,
    bor_flatpak_catalog_refresh_total and
    bor_agent_package_downloads_total; see docs/metrics.md.

Notes

  • Agents must be upgraded to v0.9.0 to enforce the new SessionAccess and
    Flatpak policy types; older agents ignore policy types they do not
    understand. The new deploy wizard is the easiest way to roll the upgrade
    out from the server itself.
  • Database migration 000029_flatpak_catalog runs automatically at server
    start: it adds the flatpak_repositories, flatpak_catalog_apps and
    flatpak_catalog_icons tables, the flatpak_repo:* permissions and the
    seeded Flathub repository.
  • The protobuf policy schema gained session_access.proto and
    flatpak.proto (policy fields 20 and 21) and a new
    proto/export/export.proto; regenerate any external tooling built against
    proto/.
  • New server settings: BOR_AGENT_REPO_DIR, BOR_FLATPAK_CATALOG_REFRESH
    (set to false on air-gapped servers; catalog uploads still work),
    BOR_FLATPAK_CATALOG_MAX_DOWNLOAD_MB and
    BOR_FLATPAK_CATALOG_ALLOW_PRIVATE_NETWORKS. See .env.example and
    server/server.yaml.example.
  • Servers built from source or from a container build that did not run the
    release pipeline contain no agent repository; the deploy wizard and
    /agent/* stay off until a packaged build is installed.
  • SessionAccess Layer 2 (pam_time) requires systemd-logind and PAM on the
    node; on authselect-managed Fedora/RHEL a one-time admin step is needed and
    the agent reports the policy as degraded until it is done.