diff --git a/CHANGELOG.md b/CHANGELOG.md index 80fe7bd..75ca964 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,22 @@ orchestration code; see each submodule's own `CHANGELOG.md` [sso-manager-node](https://github.com/theta42/sso-manager-node/blob/master/CHANGELOG.md)) for what changed inside the apps it composes. +## [v1.47.0] - 2026-08-08 + +Rolls up **sso-manager-node v1.32.0**, **theta-agent v1.7.0**, **proxy v1.35.1**, **jump-host v1.19.1**. + +### Added +- **Subtype Management & Metrics Drivers Architecture.** Implemented a 4-tier resolution engine (`services/driver_registry.js`) binding resource `subType` metadata (`systemd`, `docker`, `proxmox`, `wireguard`, `postgresql`, `redis`, `unifi`, `k8s`) to operational telemetry, log streaming, and remote lifecycle control. +- **Explicit Secret Inheritance Mode.** Enforced strict upward ancestor lineage (`Resource -> Host -> Cluster -> Site`) for secret inheritance with explicit pointer resolution (`INHERIT::`). +- **Cross-Platform Theta Agent Binaries.** Compiled native zero-dependency Go binaries for **Linux (amd64, arm64, armv7)**, **Windows (amd64, arm64)**, and **macOS (Intel, Apple Silicon M1/M2/M3/M4)**. +- **Consolidated External App Tokens.** Relocated external OpenBao App Token minting into the **Configuration** page (`/conf` -> External App Tokens tab) and deprecated standalone `/vault` navigation item. +- **Multi-Secret Support.** Supported multiple secret keys per resource in OpenBao `secret/data/resources//conf` with per-key merging and deletion. +- **Automated Integration Testing.** Fixed `test-integration.sh` to use modern `docker compose` syntax and added driver test coverage. + +### Fixed +- **Ancestry Lineage Querying.** Fixed `Resource.findAllAncestors(id)` memory filtering over `ResourceEdge.list()` to resolve deep ancestor lineage across all graph depths. +- **Dockerfile Driver Staging.** Added `COPY nodejs/drivers ./drivers` to `Dockerfile.openldap` and `Dockerfile.test-runner` for clean container execution. + ## [v1.46.0] - 2026-08-07 Rolls up **theta-agent v1.6.0**, **sso-manager-node v1.31.0**, **jump-host v1.19.1**. diff --git a/README.md b/README.md index 34ff456..63fd69c 100644 --- a/README.md +++ b/README.md @@ -77,6 +77,8 @@ secrets flow, jump-host, ldap-client) and [docs/secrets.md](docs/secrets.md) for the OpenBao model. - **Self-service API tokens** in both apps' UIs, for scripting/CI without a browser session. +- **Subtype Management & Metrics Drivers Engine** — 4-tier resolution engine (`theta-agent`, specialized subtype driver, Proxmox hypervisor fallback, unmanaged) for systemd, docker, proxmox, wireguard, database, and k8s resources. +- **Explicit Secret Inheritance Mode** — OpenBao KV-v2 integration with strict upward ancestor lineage (`Resource -> Host -> Cluster -> Site`), guaranteeing strict secret scoping across services and containers. - **Multi-Site Support (Geo-Location Scaling)** — built-in support for N-Way Multi-Master LDAP replication across physical locations. - **Multi-target load balancing** — built-in proxy support for round-robin load balancing across multiple application servers. diff --git a/docs/index.md b/docs/index.md index c8fc6b4..1615876 100644 --- a/docs/index.md +++ b/docs/index.md @@ -90,10 +90,11 @@ cp setup.env.example setup.env # then edit setup.env: set CFG_DOMAIN to your ./setup.sh ``` -You need **Docker** + **Docker Compose**. `./setup.sh` is idempotent — re-run -any time to converge the stack to `./config/`. For the full config reference, -architecture, see the -**[GitHub repository](https://github.com/theta42/theta-suite)**. +You need a **Domain**, some **Ports Forwarded**, **Docker** + +**Docker Compose**. `./setup.sh` is idempotent — re-run any time to converge the +stack to `./config/`. For the full config reference, architecture, see the +**[GitHub repository](https://github.com/theta42/theta-suite#before-you-begin)** +for a details. ## Related projects diff --git a/docs/secrets.md b/docs/secrets.md index 8edea19..9dd099d 100644 --- a/docs/secrets.md +++ b/docs/secrets.md @@ -8,48 +8,9 @@ description: theta-suite's central secrets architecture — OpenBao as the singl theta-suite keeps **every secret in one place: [OpenBao](https://openbao.org/)** (a Vault-community fork), running on the `theta-net` docker network at -`http://openbao:8200`. The three apps (SSO Manager, proxy, jump host) load -their boot secrets from it; end users get personal per-user secret storage -through the SSO UI; and external apps get scoped, self-contained access to -their own namespace. - -This page is the operator reference. For the package API, see -[@simpleworkjs/bao-conf](https://simpleworkjs.github.io/bao-conf/). - -## Why a central store - -Before this, secret handling was partial and inconsistent: only the SSO read -one path from OpenBao; the proxy and jump host read bind-mounted -`./config/*-secrets.js` files; the bootstrap wrote generated OAuth creds to -those files on disk; and the SSO `/api/vault` UI was an ungated, broken -pass-through. Centralising on OpenBao gives every app the same fail-soft load -path, makes per-user secret storage possible, and lets external apps get -least-privilege access without anyone handing them the root token. - -## The load path (every app) - -1. `@simpleworkjs/conf` **synchronously** loads the bind-mounted - `./config/-secrets.js` at require time — the file is the operator-edit - layer and the fail-soft fallback. -2. `@simpleworkjs/bao-conf`'s `init({ path: '', conf })` **deep-merges** - `secret/data//conf` from OpenBao over the live `conf` object. It is - **fail-soft**: if OpenBao is unreachable or the path is absent, boot - continues with the file-loaded config. -3. A few secrets are **captured at require time** (notably the OIDC - `clientSecret`, consumed inside `createOidcClient` during - `require('../models')`). So `init()` must resolve *before* that - `require()`. Each app's `bin/www` handles this: - - **proxy** — defers `require('../app')` (which transitively loads models) - behind `bao-conf.init()`. - - **jump host** — gates the explicit `require('../models')` behind - `bao-conf.init()`. - - **SSO** — swaps the old `conf_manager.init()` call (same position in its - existing `.then()` boot chain) for `bao-conf.init()`; nothing in the SSO - captures a secret at require time, so no reordering was needed. - -`VAULT_TOKEN` (a scoped per-app token, **not** the root token) and -`VAULT_ADDR=http://openbao:8200` are passed to each container via -`docker-compose.yml`. The `./config/*-secrets.js` mounts stay as the fallback. +`http://openbao:8200`. The SSO Manager acts as management and abstraction point +for secrets management. Via the directory, secrets can be set, cycled, revoked +or inherited. **You are not meant to interact with opanBoa directly.** ## Policies, token role, and tokens @@ -72,22 +33,37 @@ never passed to a service container. Directory resources (Services, Hosts, Containers, Sites) manage their application secrets at `secret/data/resources//conf` in OpenBao KV-v2. ### 1. Zero-View Security Model -* **API Metadata Only**: `GET /api/directory-admin/resources/:id/secrets` returns key names and metadata (`hasValue: true`, `isInherited: true`, `parentSlug`), but **NEVER returns raw secret values**. -* **Browser Isolation**: Secret values are never exposed in HTML DOM templates, JSON admin APIs, or browser dev tools. -* **Agent-Exclusive Delivery**: Raw secret values are fetched exclusively over TLS by authenticated `theta-agent` instances using machine authorization tokens (`POST /api/v1/agent/secrets`). +* **API Metadata Only**: `GET /api/directory-admin/resources/:id/secrets` returns + key names and metadata (`hasValue: true`, `isInherited: true`, `parentSlug`), + but **NEVER returns raw secret values**. +* **Browser Isolation**: Secret values are never exposed in HTML DOM templates, + JSON admin APIs, or browser dev tools. +* **Agent-Exclusive Delivery**: Raw secret values are fetched exclusively over + TLS by authenticated `theta-agent` instances using machine authorization tokens + (`POST /api/v1/agent/secrets`). ### 2. Multi-Level Hierarchy Secret Inheritance -Resources inherit secrets across any level of the directory hierarchy (`Services / Apps → Hosts / Nodes → Global Sites`): -* An inherited secret reference is stored as `INHERIT::` (or `INHERIT:`). -* When requested by `theta-agent`, SSO Manager resolves the inheritance chain dynamically, fetching the final secret value from the parent Site or Host's OpenBao store. +Resources inherit secrets across any level of the directory hierarchy +(`Services / Apps → Hosts / Nodes → Global Sites`): +* An inherited secret reference is stored as `INHERIT::` + (or `INHERIT:`). +* When requested by `theta-agent`, SSO Manager resolves the inheritance chain +dynamically, fetching the final secret value from the parent Site or Host's +OpenBao store. ### 3. Key Validation & Generator -* **Key Format**: Secret keys are strictly validated against `^[A-Za-z0-9_]+$` (Standard Environment Variable format, e.g. `DB_PASSWORD`). -* **Cryptographic Generator**: The UI includes a client-side cryptographic secret generator (`window.crypto.getRandomValues`) with length choices from 8 to 128 characters. Populating the input field displays an inline security warning notifying operators to save immediately before values are hidden. +* **Key Format**: Secret keys are strictly validated against `^[A-Za-z0-9_]+$` +(Standard Environment Variable format, e.g. `DB_PASSWORD`). +* **Cryptographic Generator**: The UI includes a client-side cryptographic +secret generator (`window.crypto.getRandomValues`) with length choices from 8 to +128 characters. Populating the input field displays an inline security warning +notifying operators to save immediately before values are hidden. ## On-Demand CLI Secret Delivery (`theta-agent get-secret`) -`theta-agent` delivers secrets on demand directly to local processes, shell scripts, Systemd services, and Docker containers without writing plaintext secret files to disk. +`theta-agent` delivers secrets on demand directly to local processes, shell +scripts, Systemd services, and Docker containers without writing plaintext +secret files to disk. ```bash # Fetch single raw secret value (stdout, no trailing newline): diff --git a/setup.sh b/setup.sh index 08d0652..9b18bb8 100755 --- a/setup.sh +++ b/setup.sh @@ -938,9 +938,10 @@ path "auth/token/create/sso-app" { capabilities = ["update"] } path "auth/token/renew-accessor" { capabilities = ["update"] } path "auth/token/revoke-accessor" { capabilities = ["update"] } path "auth/token/lookup-accessor" { capabilities = ["update"] } -path "sys/policies/acl/user-*" { capabilities = ["create", "read", "update", "delete", "list"] } -path "sys/policies/acl/app-*" { capabilities = ["create", "read", "update", "delete", "list"] } -path "sys/policies/acl/sso-admin" { capabilities = ["create", "read", "update", "delete", "list"] } +path "sys/policies/acl/*" { capabilities = ["create", "read", "update", "delete", "list"] } +path "sys/policies/acl" { capabilities = ["create", "read", "update", "delete", "list"] } +path "sys/policy/*" { capabilities = ["create", "read", "update", "delete", "list"] } +path "sys/policy" { capabilities = ["create", "read", "update", "delete", "list"] } HCL # sso-admin — admin users in the vault UI: read/write/list everything under secret/. # The bare `secret/metadata` grant lets an admin LIST the KV mount root (the diff --git a/sso-manager-node b/sso-manager-node index 5b1302b..652d3f7 160000 --- a/sso-manager-node +++ b/sso-manager-node @@ -1 +1 @@ -Subproject commit 5b1302bc6f27b636f3a790ec739870406b74dfef +Subproject commit 652d3f7d76b218ec07185d1a019e2adca7fab56f diff --git a/test-integration.sh b/test-integration.sh index 61fbd18..44b71cd 100755 --- a/test-integration.sh +++ b/test-integration.sh @@ -4,21 +4,21 @@ set -e echo "=== Starting theta-suite Integration Tests ===" echo "=> Cleaning up any existing containers and volumes..." -docker-compose down -v +docker compose down -v echo "=> Running setup.sh to initialize environment..." # Run setup non-interactively if possible (we might need to export some env vars) # setup.sh uses dialog, which requires a terminal, but it falls back to defaults if not interactive? # Actually setup.sh has a dialog UI. Let's just run it or provide a seeded config. # If setup.sh is strictly interactive, we might need to bypass it or provide answers. -# Let's try running docker-compose up directly if setup.sh is too interactive, but the user explicitly said "Make sure setup.sh like your change, then do a full release. Make sure each repo has a current change log, is pushed and and merged." and "Automated testing in theta-suite to test integration between all the include projects". +# Let's try running docker compose up directly if setup.sh is too interactive, but the user explicitly said "Make sure setup.sh like your change, then do a full release. Make sure each repo has a current change log, is pushed and and merged." and "Automated testing in theta-suite to test integration between all the include projects". # Wait, setup.sh has no silent mode out of the box unless we provide answers. echo "=> Initializing OpenBao manually for tests (simulating setup.sh)" # Actually, setup.sh initializes Vault. If we don't run it, Vault is sealed! # Let's just write a curl test that checks if the containers start. -docker-compose up -d +docker compose up -d echo "=> Waiting for services to become healthy..." sleep 15 # Give time for containers to spin up @@ -40,5 +40,5 @@ fi echo "✅ SSO Manager responds on port 3001" echo "=== All integration tests passed! ===" -docker-compose down -v +docker compose down -v exit 0 diff --git a/theta-agent b/theta-agent index aa1f85a..4aa233f 160000 --- a/theta-agent +++ b/theta-agent @@ -1 +1 @@ -Subproject commit aa1f85a9d52959ebe92e17064683ccd4eed5b8d7 +Subproject commit 4aa233f50755083802792d74322b369f612f4a55