Releases: XenPool/ipsolis
Releases · XenPool/ipsolis
Release list
ip·Solis v0.7.1
Added
- Air-gapped runtime. The browser now loads nothing from external CDNs — all CSS, JavaScript
and fonts are served from the ipSolis host. Tailwind is compiled during the Docker image build (a
node:20-alpinestage) into a local stylesheet; htmx, the Monaco script editor (wholevs/tree)
and the Inter font are vendored under/static/vendor/. Internet is required only to build the
image ordocker pulla prebuilt one. OptionalCSP_ENABLEDflag adds a self-only
Content-Security-Policy; a CI guard fails the build if any external asset origin reappears. No
visual/behaviour change (one pre-existing latent bug fixed: the standalone auth pages now render
their surface colors). See the new air-gapped runtime note in the deployment guide. - Order justification. A free-text business justification, configurable per asset definition
(collect on/off + required yes/no), shown to the approver on the decision page and in the approval
email / Teams / Slack notifications. - Portal execution-step visibility, per asset definition.
off(default — status only),
detailed(step names/status/timing), ordebug(adds raw step logs/errors for diagnostics).
Fixed
- External-secret resolution for SMTP. The worker's email send path now resolves an
email.passwordstored as avault://…/ccp://…reference (previously only the Test SMTP
button did, so an externalized SMTP credential passed the test but failed on real sends).
Migration
- Adds
0013(order justification:orders.justification+ twoasset_typesflags) and0014
(asset_types.portal_step_visibility). Both additive (nullable / defaulted columns; no backfill).
ip·Solis v0.7.0
Added
- Drift / out-of-band reconciliation (AD). A Beat task periodically re-reads the AD groups that
drift_monitorasset types provision into and compares actual membership against what ip·Solis
granted (from the order change log). Divergences — missing access (granted, removed in AD) and
out-of-band (added directly, never granted) — are recorded todrift_findings, audit-logged
(streamed to the SIEM), and surfaced on Operations → Drift. Opt-in per type; global schedule +
detect_only/auto_remediatemode under Maintenance → Drift reconciliation; auto-remediate
re-grants / revokes via AD. Best-effort email/Teams alert. - Software license & contract lifecycle. New
SoftwareContractentity (vendor, product, value,
billing interval, licensed seats, renewal date, notice period) bound 1 : N to asset types.
The cost report prices each active order at the contract's per-seat rate (contract value ÷
seats) instead of a flat monthly cost, and tracks utilization + unused-seat shelfware and
seat over-allocation (Model A — actual consumption). New Reports → Licenses & Contracts
page; daily opt-in renewal-reminder Beat task fires when a contract enters its notice window. - Slack approval delivery. Approvals can post a Block Kit message to Slack in parallel with
email (and Teams), reusing the same channel-agnostic signed one-click approve link. Config
slack.mode/slack.webhook_url+ Settings section + test button; covers initial dispatch and
reminders. - Signed attestation artifacts. Optional per asset type: a handover acknowledgment
(Übergabeprotokoll) on provisioning — the recipient gets a signed link to confirm receipt (and an
acceptable-use policy) — and a revocation / disposal certificate on revoke/expiry (audit
evidence of what was removed). Signed-token HTML pages (archival via print); reviewed under
Reports → Attestations; overdue-ack reminder Beat task. - Onboarding bundles & assignment rules. A
Bundlegroups existing asset definitions into a
package; anAssignmentRulemaps user attributes (department, cost center, …) to a bundle
(reusing the approval-rule condition format). Ordering a bundle creates one lightweight
OrderGroupwith one order per position through the normal approval/execution paths (idempotent —
asset types the user already holds are skipped). Triggerable from Onboarding admin (evaluate
for a user), the self-service Packages catalog, a SCIM joiner, and optionally a user's first
portal login (onboarding.eval_on_first_login). - SCIM joiner/mover provisioning. Extends the SCIM endpoint from leaver-only to full
joiner/mover/leaver: a newScimIdentitylast-seen projection;POST/PUT /Users(opt-in
scim.joiner_enabled) evaluate assignment rules and order matched bundles; a mover (attribute
change) reconciles entitlements viascim.mover_mode(disabled/additions_only/
reconcile), where reconcile also revokes lost entitlements — strictly limited to
rule/SCIM-provisioned orders (self-service and manual orders are never auto-revoked). - Entra group provisioning (Microsoft Graph). The
entra_groupaccess-target type now grants /
revokes Entra (cloud-only) security-group membership via Microsoft Graph (app-only, dedicated
graph.*app registration). Closes the gap between Entra login (OIDC) and provisioning Entra
groups for M365 / cloud-only customers. Settings card + Test Credentials.
Changed
- Portal accessibility (structural). Skip link,
mainlandmark + labels, decorative-icon
aria-hidden, live notification badges, an earlylangbinding, and keyboard:focus-visible
outlines across the shared portal templates — no visual redesign. Closes the BITV / EN 301 549
structural basics (portal only; not a formal conformance claim). - SCIM full filter grammar (RFC 7644 §3.4.2.2).
GET /Users?filter=now supports the full
grammar (eq ne co sw ew gt ge lt le pr,and/or/not, grouping) instead of only
userName eq; a malformed filter returns400 invalidFilter. Added a read-only/Groups
shim (empty list; group membership lives in AD, not SCIM). - Access-target validation. Saving an asset type now rejects access-target types without a
provisioning handler (onlyad_group/entra_group;rds_collection/other→ 400).
Migration
- Adds
0004–0012: drift findings + per-type flag; software contracts +asset_types.contract_id;
Slack config; attestation artifacts + flags; onboarding bundles / assignment rules / lightweight
order_groups+ nullableorders.order_group_id; SCIM identity projection; SCIM mover config;
Graph (graph.*) config; onboarding first-login config. All additive (new tables + nullable
columns + seeded config); no backfill of existing rows.
Fixed
- Feature-alert emails now send from the configured
email.fromaddress instead of the
container'sMAIL_FROMdefault, so drift / contract-renewal / attestation alerts match the
rest of the platform's outgoing mail identity.
Testing
- Autonomous feature-test harness (
tests/feature/). A self-contained integration suite
(58 tests) drives the running stack end-to-end over HTTP + DB and a testlab mock-receiver:
order lifecycle (provision / modify / revoke / all deprovision policies, capacity, scheduled,
ServiceNow-webhook HMAC), access provisioning against real AD and mock Microsoft Graph,
drift detection, approvals + certification (incl. auto-revoke), HR leaver, SCIM JML, onboarding
bundles, software-contract cost math + renewal, attestation emission/ack, cost & point-in-time
access reports, LDAP portal login, real Teams delivery, and every Beat cycle. Namespaced and
self-cleaning; not shipped in the runtime image.
ip·Solis v0.6.15
Changed
- Licensing terms & texts updated for the free-tier / volume-band model (reviewed and approved). The XenPool Commercial Source License (
LICENSE, EN + DE), the GermanAGBand the EnglishTerms, plus the README and deployment/onboarding docs now reflect the sales model enforced since 0.6.14: free productive use for up to 25 active users (including in an organizational context), with commercial use (more than 25 active users) licensed in volume bands by active-user count. Adds an authoritative active user definition; the license scope wording changed from "licensed instances" to "licensed number of users / volume band (max. Active Users; 0 = unlimited)"; after expiry + the 30-day grace the software reverts to the Free Tier (no longer described as "evaluation only"). - In-app license texts & shop links. The dashboard unlicensed-state banner is now a "Free tier · up to 25 active users" banner; the Maintenance license card explains the tiers and bands. All purchase / renewal calls-to-action now point to the ip·Solis license shop (locale-aware:
…/en/shop/…/de/shop) instead of a sales email;sales@xenpool.deis retained only for inquiries, support and the imprint.
ip·Solis v0.6.14
Added
- Free-tier / commercial-band user-count enforcement. A free productive tier allows up to 25 active end-users without a license; a valid commercial license raises the limit to its signed
max_usersband (e.g. 75 / 250;0= unlimited). "Active user" = a distinct (case-insensitive)orders.user_emailon an order in an active status. Enforcement is soft: existing operation is untouched — only the creation of an order for a new (not-yet-counted) identity is blocked once at/over the limit (HTTP 403 across the portal,/ordersAPI and the ServiceNow webhook). The Admin Dashboard shows a banner (red at the limit, amber from 80 %). The band rides on the existing 30-day license-expiry grace; demo/evaluation licenses never raise the limit. New endpointGET /admin/tier/status. - Evaluation-license recognition & display. Demo/evaluation licenses (signed by the demo key) are now labelled as such: a dashboard "Evaluation license" banner and an "Evaluation" badge on the Admin → Maintenance → License card, with licensee and validity.
- Built-in tile-icon picker for asset definitions. A bundled set of monochrome IT icons (Desktop/VDI, Laptop, Server, VM, Database, Mailbox, Application, License, Smartphone, Monitor, Cloud, Storage) selectable directly in the asset-type form — no upload needed. Stored as a data-URL like an uploaded logo, so the portal catalog renders them unchanged.
- Reassign an asset definition while Free. Operators can change a personal asset's Asset Definition inline in Personal Assets, but only while the asset's status is
Free(UI dropdown + server-side guard; rejected with 409 otherwise).
Changed
- Unimplemented Access Target types marked "coming soon". In the asset-type form, Entra Group, RDS Collection and Other are now disabled and labelled "(coming soon)" — only AD Group is implemented end-to-end (the others were selectable but failed silently at provision time). Backend status documented in
TASKS.md. - Admin Settings — OIDC provider field labels. Provider-ID placeholder aligned with the Entra example, and a help line added under Client ID.
- Integrations docs — SMTP authentication options. New section (EN + DE) clarifying that ip·Solis is provider-agnostic SMTP-only (no vendor send APIs), with a decision table (relay vs. app password) and an M365 caveat recommending a relay for a future-proof setup.
Fixed
- HTTPS OIDC redirect URIs behind the reverse proxy. uvicorn now runs with
--proxy-headers --forwarded-allow-ips=*so it honours nginx'sX-Forwarded-Proto; previously the app derivedhttp://callback URLs, breaking SSO withAADSTS50011. Image build/push/cache and tags are unchanged. - Admin status banners in dark mode. On reset, the
dark:red/blue colour classes were not cleared, so a successful test (AD/SCCM/email/compliance) could render red. Banners now reset to base classes before applying the new state.
Internal
test_asset_type_constraints.pyrealigned with the migration-0047 validator (two create-time rules; runbook-wiring is now a dispatch-time concern) — the suite previously targeted the removed 5-rule API.
ip·Solis v0.6.13
Added
- Admin Users — masked password reset. The "Reset password" action now opens a dedicated modal with a masked input and a show/hide (👁) toggle, replacing the native browser
prompt()that always displayed the new password in cleartext. The same show/hide toggle was added to the Create-user password field for consistency.
Changed
- Production overlay renamed:
docker-compose.prelive.yml→docker-compose.prod.ymlto match its actual role (the TLS/nginx production overlay; the oldprelivename was historical and misled operators). All references updated — CI (deploy-prelive.yml),docker-compose.ghcr.ymlusage comments,tools/install/bootstrap-certs.sh,README.md, anddocs/DEPLOYMENT.md/.de.md(theCOMPOSE_FILEexamples now usedocker-compose.prod.ymland the interim "historical name" clarifying comments are removed). The prelive environment and its deploy workflow keep their names — only the overlay file was renamed. Operator action: hosts that pin the overlay viaCOMPOSE_FILE(e.g. LinPre1/LinPre3) must update the filename; there is no back-compat alias. - Deployment guide clarified for first-time installers. The TLS section now states explicitly that certificate Options A/B/C are mutually exclusive alternatives, with an "end of options" callout before Configure nginx (the shared step). The Start the Stack intro was simplified — dropped the
locales//scripts/baked-in internals and version wording that confused first-time installers, keeping only pull/start and the prod-pin-vs-latest choice. (EN + DE)
Fixed
- CI: stop uploading buildx
.dockerbuildbuild records. The release workflow now setsDOCKER_BUILD_RECORD_UPLOAD=false(andDOCKER_BUILD_SUMMARY=false) at job level so the API and Workerbuild-pushsteps no longer emit the.dockerbuildartifacts that were accumulating on every release. Image build, push, cache, and tags are unchanged.
ip·Solis v0.6.12
Changed
- Aligned and clarified the license wording across the documentation, the bundled
LICENSEcopies, and the Admin UI so they are consistent with the Terms.
ip·Solis v0.6.11
Changed
- Deployment guide is now prebuilt-image (GHCR) only.
docs/DEPLOYMENT.mddocuments a single supported install path — pulling the publicghcr.io/xenpool/ipsolis-{api,worker}images — and drops the build-from-source variant throughout (start, update, HA, troubleshooting, clean reset). The image tag now defaults to:latest, with per-environment guidance: pinIPSOLIS_VERSIONin production, track:latestin pre-live / test. - License module docstring clarified.
max_users/max_asset_typesare parsed for display only and are not enforced at runtime (no feature/usage gating — all features ship in every edition). Corrected the misleading "enforces …" wording inapi/app/utils/license.pyand the byte-identical worker copy.
Fixed
- License documentation corrected. The README's License section incorrectly claimed AGPL-3.0 / a "dual-licensed open core". ip·Solis is in fact source-available under the XenPool Commercial Source License v1.0 (free for non-commercial use + 30-day evaluation; commercial use requires a purchased license). Removed all AGPL references and aligned "open-source" wording to "source-available".
- Deployment guide:
sudo chmod +xfor the mkcert binary (it is downloaded as root viasudo curl, so the non-sudochmodfailed with "Operation not permitted"); replaced the misleadingacme.comexample hostname withexample.com.
ip·Solis v0.6.10
Added
- Provider-agnostic portal SSO (generic OIDC). The self-service portal now authenticates users against any standards-compliant OpenID Connect identity provider — Entra ID, Okta, Ping, Google, Keycloak, Authentik, Zitadel, … — through a single code path. Each provider self-configures from its issuer URL via the discovery document (
<issuer>/.well-known/openid-configuration); adding an IdP is a config entry, not a vendor integration. New helperapi/app/utils/oidc.pyvalidates ID-token signatures against the provider JWKS (PyJWT) plus iss/aud/exp and the OIDC nonce. - OIDC provider registry. Providers are stored in
app_configunderidp.<id>.*(unlimited providers, stable URL-safe ids). Admin → Settings → Authentication gains an add/edit/delete provider UI with a Test button that runs a discovery probe. New endpoints:GET /admin/config/oidc/providers,PUT/DELETE /admin/config/oidc/{provider_id},POST /admin/config/oidc/{provider_id}/test,PUT /admin/portal-auth. - Login method picker. When more than one login method is enabled the portal shows a chooser at
/portal/login(fully localised, 5 locales); with exactly one it redirects straight to it. - On-prem LDAP portal login. Username/password login against on-prem AD/LDAP, offered alongside OIDC via
auth.ldap_enabled(folds in the earlier short-livedonprem_ldapmode). - Reuse existing tile logos. The asset-definition form gains a "Choose existing" logo picker that reuses any logo already attached to another asset type (deduped), no re-upload. New endpoint
GET /admin/asset-type-logos. - Prebuilt-image install (GHCR). New
docker-compose.ghcr.ymlpulls the publicghcr.io/xenpool/ipsolis-{api,worker}images instead of building — faster, version-pinned installs (IPSOLIS_VERSION).locales/andscripts/are now baked into the images (root build context +.dockerignore) so a prebuilt install needs no repo checkout of them.
Changed
- Parametric OIDC callback. Portal callback is now
/portal/auth/{provider_id}/callback(was the Entra-only/portal/auth/callback). Logout is generic RP-initiated logout via each provider'send_session_endpoint. - Portal auth gate. Replaced the Entra-specific
entra.modewithportal.auth_required(login on/off) + per-provideridp.<id>.enabled+auth.ldap_enabled. Migration0003seeds the toggles and migrates any existingentra.*config intoidp.entra.*. Service-health probeentrarenamed tosso(probes discovery for every enabled provider). SAML 2.0 remains out of scope (separate task). - Admin sidebar layout. Audit Log and API Tokens moved into the compact footer section; theme toggle + signed-in user moved to a sticky top-right header — frees vertical space so the nav no longer needs an internal scrollbar.
- Script modules are PowerShell-only. The Script-type dropdown is removed (Python/Bash were never functional — the worker injects a PowerShell-only
$VARS/$PARAMSpreamble); the API coercesscript_typetopowershell. Module + runbook editors are now English-only.
Fixed
- Login-settings save returned 422.
PUT /admin/config/portal-authwas shadowed by the generic/config/{key}route (parsed as a config key, rejected the body as missingvalue). Moved toPUT /admin/portal-auth. - Portal i18n on prelive. Locales are now baked into the api image, so prelive's
volumes: []("baked code") no longer leaves/app/localesempty (i18n had silently fallen back to English). - nginx config + SSL paths. Mount
nginx.conftoconf.d/default.conf(not the mainnginx.conf); unified the SSL cert path tonginx/ssl/across all compose files and docs. - Docs: corrected all "
alembic upgrade headis automatic" references (it is not); wrapped longdocker composecommands; added the first-install alembic step + an SSL pre-flight to the update section.
Removed
- Entra-only MSAL login path.
api/app/utils/entra.pyand theentra.*config keys are retired; the generic OIDC path supersedes them (no MSAL-only feature was in use).msalis retained only for the legacy Entra credential test. entra_with_onpremauth mode. Removed entirely (never fully implemented; no production deployments).
CI / Build
- Build images from the repo-root context so shared
locales/+scripts/can be baked; added.dockerignoreto keep secrets (.env,licenses/,backups/,nginx/ssl) and.gitout of the images. - GHCR packages made public (anonymous pull);
actions/checkoutv4 → v5 (Node 20 deprecation).
ip·Solis v0.6.9
Added
- Update Notifier: "Check now" button. Triggers an immediate update check from the Settings page without waiting for the daily Beat tick. Shows inline feedback: "Up to date", "New version available: vX.Y.Z", or the actual error text — auto-fades after 5 s on success.
- Update Notifier: GitHub Release created on tag push.
release.ymlnow includes acreate-releasejob that extracts the matching CHANGELOG section and publishes a GitHub Release after images are pushed. Previously only a git tag was pushed, causingreleases/latestto return 404.
Fixed
- Update Notifier: 404 no longer shown as error. When the GitHub repo has no published releases yet, the checker now clears the error field and logs "no releases yet" instead of recording a failure.
- Update Notifier: error box shows actual error text. Settings page previously displayed the static "See server logs for details" message regardless of the real error. Now shows the stored
updates.check_errorvalue.
ip·Solis v0.6.8
Added
- Portal nav badges. My Approvals, Delegations, and Access Reviews now show a live count badge (red / amber) when the signed-in user has pending items. Loaded via
GET /portal/nav-badges(3 parallel COUNT queries) on every page without touching existing route handlers. - Retry failed orders. Admin order detail shows an amber "Retry now" button when an order is in
failedstate. Clears the step history, resets the order toprocessing, re-dispatches the runbook, and writes an audit row.
Fixed
- Audit log: admin cancel now records the acting user.
POST /ui/orders/{id}/cancelwas missingrequest: Request, so the audittriggered_byshowedcelery:dynamic_runnerinstead of the admin session. Fixed.
Changed
- Admin order detail: Admin Actions moved above Execution Steps. Cancel / Extend / Retry panel now appears directly below the user and asset cards, before the step log.
- Docs: ServiceNow webhook fully documented.
integrations.mdsection rewritten from a 4-line stub to a complete integration reference: both auth methods, full payload schema,curlexample, complete response JSON, capacity checks, idempotency, error table, and audit trail. Fixed incorrect scope namewebhook:servicenow→webhook:in.