ChangelogΒΆ
All notable changes to JIM (Junctional Identity Manager) will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
UnreleasedΒΆ
AddedΒΆ
- β¨ Password Synchronisation can now be configured per Connected System. A new Passwords tab, REST resource and
Get-/Set-JIMConnectedSystemPasswordSynchronisationset which Object Type holds the accounts, how many delivery attempts to make and how long to wait between them, and whether to refuse to transmit over a connection JIM cannot confirm is encrypted. The enable toggle is deliberately separate from the configuration, so a system can be set up ahead of a change window and switched on during one; disabling is the supported way to stop delivery, because removing a configuration would discard everything queued against it. The tab appears only on Connected Systems whose connector can set passwords. (#1119) - β¨ A Synchronisation Rule now warns when one of its Attribute Flows targets an attribute whose name suggests it carries a password, pointing at Password Synchronisation instead. The well-known credential attributes were already blocked outright, but a renamed or unfamiliar one could still be flowed as ordinary data, which stores the secret in Metaverse and Connected System Object attribute values, both change histories, Pending Exports, export previews, search results and database backups. The rule stays valid: the check matches on a name, so it advises rather than refuses. (#1119)
- β¨ You can now preview a Connected System schema change before you save it. Deselecting an Object Type or an attribute is the rare configuration change with no visible effect at all: nothing fails, nothing is deleted and nothing is disconnected, JIM simply stops reading, and everything downstream carries on over data that has stopped moving. Deselecting an Object Type does not take its objects out of management: they stay joined to their Metaverse Objects and go on contributing the values they last imported, which never refresh again. The preview says so, and puts a number against it: how many Connected System Objects would stop being imported, which attributes would stop being refreshed and on how many objects (counting only the objects that actually hold a value for them), and whose contributed Metaverse values would be withdrawn, or kept, when their obsolete objects are next synchronised. It names what would go on running over the frozen data too: Synchronisation Rules still bound to the Object Type, and Attribute Flow mappings still reading the attribute. Available from Preview Changes on the Schema tab, over REST at
POST /synchronisation/connected-systems/{id}/schema-selection/preview, and from PowerShell withNew-JIMConfigurationChangePreview -ConnectedSystemId <id> -SchemaObjectType <types>. See What deselecting means. (#1475) -
β¨ You can now preview a Synchronisation Rule behaviour change before you save it. The five toggles that decide whether a rule runs at all and what it may create are the ones whose consequences are hardest to picture, because none of them names a population: disabling a rule reads like pausing it and is closer to withdrawing every value it owns, and turning Provision To Connected System on reads like granting a capability and is account creation at scale. The preview reports, per object, which would stop having an identity created for them, which would stop having an account created, which would be left free to drift from what JIM holds, and each of their inverses. Direction is refused rather than previewed: a saved rule's mappings and Object Matching Rules are written for the direction it has, so a flip would leave every one of them addressing the wrong side. Available from the Synchronisation Rule editor beside the other previews, over REST at
POST /synchronisation/sync-rules/{id}/behaviour/preview, and from PowerShell withNew-JIMConfigurationChangePreview -SyncRuleId <id> -RuleState Disabled. See Previewing a behaviour change. (#1462) -
β¨ A destructive schema refresh now pauses on a three-way decision. The review separates safe additions from destructive changes (removed Object Types and attributes, changed data types), names the configuration each one invalidates with deep links to it, and offers the choice: Cancel (warned honestly that cancelling does not preserve the status quo, since the next Full Import obsoletes a removed Object Type's objects regardless), Apply as-is, or Apply and Disable Dependents, which records the new schema and disables every invalidated Synchronisation Rule and Attribute Flow mapping (including mappings reading a removed attribute inside an expression) with the refresh recorded as the reason, under child Activities of the refresh. Nothing is deleted, and re-enabling is a manual choice per rule or mapping. Available over REST (
disableDependentson the import-schema endpoint, with the preview response naming the dependents) and from PowerShell withImport-JIMConnectedSystemSchema -DisableDependents. See Refreshing the schema. (#1485) - β¨ The schema refresh decision is complete: Apply and Remove joins Cancel and Apply and Disable Dependents as the review's full-commitment choice for a genuinely decommissioned Object Type or attribute. It deletes the invalidated Synchronisation Rules and mappings (audited under the refresh's Activity), then a background worker task marks every Connected System Object of a removed Object Type as Obsolete, deprovisioning them through the standard pipeline with grace periods and Metaverse Deletion Rules applying as configured, and deletes every stored value of a removed attribute. The plan dialog counts both before you confirm, and the task's Activity records every object it touched. Available over REST (
removeDependentson the import-schema endpoint, with the preview response carrying the counts) and from PowerShell withImport-JIMConnectedSystemSchema -RemoveDependents. See Refreshing the schema. (#1485) - β¨ An individual Attribute Flow mapping can now be disabled, without touching the rest of its Synchronisation Rule. A disabled mapping is skipped by synchronisation in both directions: nothing flows inbound (and the mapping drops out of Attribute Priority contention), nothing exports at provisioning or on updates, and Drift Correction leaves its target attribute alone; each run notes how many disabled mappings it skipped. Disabling one mapping is the smallest safe response to a single source attribute that has been removed or redefined at the Connected System, and it is the foundation for the schema refresh decision's protective options (#1485). Available on the Attribute Flow tab, over REST via
PATCH /sync-rules/{id}/mappings/{mappingId}, and from PowerShell withSet-JIMSyncRuleMapping -Enabled $false. See Disabling a single mapping. (#1485) - β¨ Refreshing a Connected System's schema now shows you what changed before anything is applied. The Schema tab previously warned that a refresh could delete Synchronisation Rules, attribute values and entire objects; in truth a refresh has never deleted anything, and the real hazard was the opposite: it committed what it found silently, so a source system that dropped an attribute, or restated a data type, changed what your mappings ran against without a word said. Refresh Schema now retrieves the schema and pauses on a preview: additions, entries the system no longer reports (which JIM retains rather than deletes, with their values frozen from then on), and attribute definition changes (a restated data type or plurality, previously applied in silence), with discovery warnings beside them so a partial read caused by missing permissions is not mistaken for removals. Apply to record it, or discard to keep the schema you have; discarding removals or definition changes asks you to confirm, because staying on the old schema means the next synchronisation runs against a system that no longer matches it, while discarding additions alone costs nothing. Available over REST at
POST /synchronisation/connected-systems/{id}/import-schema/previewand from PowerShell withImport-JIMConnectedSystemSchema -Preview. See Refreshing the schema. (#421) -
β¨ You can now preview an Object Matching change before you save it. Object Matching Rules decide which Metaverse Object an account joins to, and their mistakes never fail: a rule matched too loosely merges an account into the wrong identity and takes everything it contributes with it, while one matched too tightly creates a duplicate identity beside the right one. The preview reports, per object, which accounts would join a different Metaverse Object, which would join instead of projecting a new identity, which would project instead of joining, and which would match more than one and fail. It says first what no count can imply: only objects that are not already joined are ever matched again, so an account with a Metaverse Object keeps it whatever you change. Available from the Matching tab beside Add Matching Rule and on the Simple/Advanced switch, over REST at
POST /synchronisation/connected-systems/{id}/matching-rules/preview, and from PowerShell withNew-JIMConfigurationChangePreview -ConnectedSystemId <id> -MatchingRule <rules>. See Previewing an Object Matching change. (#1457) -
β¨ Data Generation Templates can now be created, updated and deleted through the REST API (
POST/PUT/DELETE /api/v1/example-data/templates) and PowerShell (New-JIMExampleDataTemplate,Set-JIMExampleDataTemplate,Remove-JIMExampleDataTemplate, plusAdd-JIMExampleDataTemplateAttributefor appending one attribute's generation rules without restating the rest of the template). A template is validated as a whole before anything is recorded, using the same rules Data Generation enforces at execution time; references to Metaverse Object Types, Metaverse Attributes, Connected System attributes and Example Data Sets are made by id at the API (PowerShell accepts names and resolves them), unknown references are refused naming the id, built-in templates cannot be changed or deleted, and a duplicate template name is refused. Updates either rename a template or replace its whole Object Type graph, stated explicitly in the request; every change is recorded in the template's configuration change history as before. (#894) - β¨ A Synchronisation Rule's Attribute Flow can now be previewed before it is saved, in the portal, over the REST API and with
New-JIMConfigurationChangePreview -AttributeFlowMapping. The new Preview Attribute Flow Impact button reports, per object and per attribute, the value each managed object would end up with as an old-to-new pair, the values that would be withdrawn, and the objects an Expression could not be evaluated for at all. Import and export mappings both state a true before-and-after, including where the target Connected System already holds what the rule writes today, which is exactly what a domain cutover looks like. Proposed mappings that would lose Attribute Priority are called out: a synchronisation would evaluate them and write nothing. (#1437, #1443) - β¨ A Synchronisation Rule's Scoping Criteria can now be previewed before they are saved, in the portal, over the REST API and with
New-JIMConfigurationChangePreview -ScopingCriteriaGroup. The new Preview Scope Impact button reports every object that would enter or leave scope, what each movement costs it, and which identities the departures would leave eligible for deletion. (#1436) - β¨ A Connected System can now be told to refuse to send a password over a connection JIM cannot confirm is encrypted. Only send passwords over an encrypted connection, on the Connected System's Settings tab under Passwords, governs every password JIM sends to that system: the first password on an account it provisions, one an administrator sets by hand, and a synchronised password change. JIM previously warned and sent anyway in all three cases, because a signed and sealed bind is a legitimate encrypted alternative it cannot detect from a system's settings, so refusing by default would refuse a valid configuration; this is how an administrator who knows their deployment closes that gap. Nothing is discarded when JIM refuses: queued password changes wait, accounts stay owed their first password, and an administrator setting one by hand is told at the time. Also on the Connected System REST resource and
Set-JIMConnectedSystem -RequireSecureTransport. (#1119) - β¨ A password change can now be synchronised to every system a person has an account in, from the portal, the REST API and PowerShell. The Metaverse Object's Actions tab gains Synchronise Password beside the existing Set Password,
POST /api/v1/metaverse/objects/{id}/passwordaccepts one, andSync-JIMMetaverseObjectPasswordscripts it. It is a different operation from setting a password on chosen accounts, not a replacement: that one sets a password you choose on the accounts you tick, straight away, and tells you whether each target accepted it; this one records that the person's password changed and delivers it to every Connected System enabled for Password Synchronisation, retrying if one is unavailable. It defaults to leaving expiry to each system's own policy, because a password the person chose should not demand they choose another one at next sign-in. (#1119) - π REST endpoints that accept a password now refuse the request unless JIM can confirm the transport is encrypted, rather than relying on the deployment having enabled HTTPS. An operator who had not sent the one value JIM can never rotate quietly across the network in the clear, with nothing anywhere saying so. The refusal names its remedy, including the likeliest legitimate cause: TLS terminating at a reverse proxy JIM has not been told to trust, which is fixed by setting
JIM_TRUSTED_PROXIES. Local development over plain HTTP is unaffected. A build-time guard fails if a new password-accepting endpoint is added without the check. (#1119) - β¨ Password Synchronisation now delivers. A password change is recorded once per Connected System the person has an account in, encrypted, and delivered by a Password Delivery task rather than in the request that made it, so nobody waits on a directory and no password change fails because one target is down. A target that was unreachable is retried with a backoff that doubles each attempt; one that refused the password, or cannot do what was asked, is parked rather than retried into the same refusal, and is released the moment the system's delivery settings change or Password Synchronisation is switched on. A change that outlives its time to live is retired with its last failure recorded, and a second password change for the same person and system replaces the first rather than queueing behind it, so only the newest password is ever sent. A system with Require Secure Transport on now refuses to send over a connection JIM cannot confirm is encrypted, leaving the work queued, rather than warning and sending anyway. (#1119)
- β¨ Password Synchronisation can now be configured per Connected System. A new Passwords tab, REST resource and
Get-/Set-JIMConnectedSystemPasswordSynchronisationset which Object Type holds the accounts, how many delivery attempts to make and how long to wait between them, and how long to wait between them. The enable toggle is deliberately separate from the configuration, so a system can be set up ahead of a change window and switched on during one; disabling is the supported way to stop delivery, because removing a configuration would discard everything queued against it. The tab appears only on Connected Systems whose connector can set passwords. (#1119) - β¨ A Synchronisation Rule's two destructive toggles can now be previewed before they are saved. Flipping the Deprovisioning Action to Delete turns every future scope exit into a deletion in the target system, and flipping the Out-of-Scope Action to Disconnect can mass-disconnect joined objects; both were single dropdowns with no impact analysis in front of them. The rule editor's new Preview Deprovisioning Impact button reports which objects the next synchronisation would treat differently, which identities would become eligible for deletion as a result, and how many managed objects' fate on a future scope exit changes, with the counts stated on the save confirmation and the preview recorded against the change. Also available over the REST API and as
New-JIMConfigurationChangePreview -SyncRuleId. (#1115) - β¨ The Pending Exports list now shows how many references each export is still owed: the count of Reference attribute changes that could not be written yet because their targets have no resolvable object in the Connected System. The wait was previously only visible by opening each export's detail page, which explains each owed reference individually. The count is also on the Pending Export list REST resource and
Get-JIMPendingExport. (#1398) - β¨ An Attribute Flow's settings can now be changed after it is created, over the REST API and from PowerShell. Until now the API could add an Attribute Flow and delete one but never change one, so correcting a setting on a live Synchronisation Rule meant deleting the mapping and building it again, which discards its place in the Attribute Priority order and, on an import mapping, silently changes which contributor wins the attribute.
PATCH /sync-rules/{id}/mappings/{mappingId}and the newSet-JIMSyncRuleMappingchange the Expression, Missing Input Behaviour, "Null is a value", inbound value processing, case normalisation and Initial Export Only in place, leaving everything not named alone. What a mapping targets, and whether its source is an attribute or an Expression, deliberately still means delete and recreate: that revalidates against attribute types and reopens the priority position, and an edit that hid those consequences would lose them silently. A setting that cannot apply to the mapping is refused rather than ignored, as is a request naming no setting at all. (#1361) - β¨ An Attribute Flow's Expression can now be told what to do when an attribute it reads has no value on the object. Until now it evaluated regardless, and a concatenation with a missing input produces a real, structurally broken value rather than nothing:
ada.@corp.localfor a person with no surname,CN=,OU=Users,DC=corp,DC=localfor one with no name. Nothing downstream can tell such a value from a good one, so it flows into the Metaverse or out to a directory without complaint. Each Expression source now carries a Missing Input Behaviour: evaluate anyway (the default, and what every existing mapping keeps doing), contribute no value and let Attribute Priority resolve it, fail just this mapping while the object's other attributes still flow, or fail the object outright so nothing is written for it at all. The last two are reported against the object as an Expression Missing Input error on every run until the value is supplied. JIM works out which attributes the Expression reads from the Expression itself, and treats an absent attribute, a null and an empty string alike. Available in the portal beside the Expression, on the REST API, and asNew-JIMSyncRuleMapping -MissingInputBehaviour. (#1361) - β¨ An Expression can now be tested where it is written. Choosing Expression as an Attribute Flow's source offers a box for each attribute the Expression reads, resolved from the Expression itself, and Run test shows what it produces and the type it evaluated to. Leaving a box empty tests the Expression as an object with no value for that attribute, which is how a concatenation that quietly produces a malformed value (
ada.@corp.localfor a person with no surname) can be seen before the Synchronisation Rule is saved rather than after a synchronisation has carried it. The same evaluation has been available over the REST API andTest-JIMExpressionsince Expression support shipped; this brings it to the portal. (#1405) -
β¨ Each Container on the Partitions & Containers tab now shows how many objects it holds, so you can tell a Container worth managing from an empty one before ticking anything. The figure is read from the Connected System itself rather than from what JIM has already imported, which is what makes it useful on a brand new Connected System where JIM holds nothing yet: that is precisely when you are deciding what to manage. It follows each Container's Container Scope, counts only the Object Types you have selected so the number matches what a Full Import would return, and is reported over the REST API and by
Get-JIMConnectedSystemPartitionas well as in the portal. Counting happens as part of Retrieve Hierarchy, so the Containers and their figures always describe the same moment; it is bounded, and a count the directory cuts short at its own size or time limit is reported as incomplete rather than shown as though it were whole. A Connector that cannot report counts leaves the column blank, which is not the same as zero. (#1276) -
β¨ The Schema Object Types and Attributes tabs can now be filtered. Object Types narrow by Deletion Rule, Predefined Searches and Built-in status; Attributes narrow by Type, Plurality, Built-in status and bound Metaverse Object Type, the last also selectable through the same widened
GetMetaverseAttributeHeadersRangeAsyncread the tab already used to scroll. -
β¨ A Container can now be excluded from a selection made above it: select
OU=Corpand carveOU=Service Accountsout of it, rather than ticking eleven sibling OUs and hoping nobody adds a twelfth. Exclusions nest, and survive a rename. Preview one before making it, from the portal, the REST API orNew-JIMConfigurationChangePreview -ExcludedContainerIds, to see exactly which objects it takes out of scope. (#1255) -
β¨ Container Scope can now be stated as text, for the directory whose hierarchy is impractical to click through. Advanced on the Partitions & Containers tab writes the whole scope out as one statement per line (
include OU=Corp,DC=example,DC=com,exclude OU=Service Accounts,OU=Corp,DC=example,DC=com,include one-level ...), so a scope can be pasted in, reviewed as a diff, kept under version control or copied between Connected Systems, withGet-JIMConnectedSystemContainerScopeTextandSet-JIMConnectedSystemContainerScopeTextdoing the same from automation. Nothing is applied by halves: a path naming no Container, a Container stated twice, and a statement an ancestor already makes are each refused against the line that caused them, with the scope left exactly as it was. The text and the tree are two editors for the same selection, so Advanced Mode is previewed, confirmed and audited exactly as ticking boxes is, and switching between them loses nothing in either direction. (#1255) -
β¨ An import that read entries and discarded them because a Container Scope exclusion carved them out now reports how many, per excluded Container, on its Activity. A branch of 500,000 objects excluded from inside a selected parent shows up as a figure you can act on rather than as an unexplained slow import. (#1255)
-
β¨ An Oracle whole-number column now reaches JIM as a whole number, so it can flow into the built-in numeric Metaverse Attributes. Oracle has a single numeric type, and JIM read every
NUMBERas a decimal regardless of what the column declared:EMPLOYEE_ID NUMBER(10)andHEADCOUNT NUMBER(19)arrived looking exactly like a genuinely fractionalFTE NUMBER(9,4). Because an Attribute Flow requires its source and target types to match, and no built-in numeric attribute is a decimal, no Oracle column could be mapped toEmployee Numberor any other built-in numeric attribute at all; the only ways round were a parallel set of custom attributes, or an expression on every numeric flow. The same columns on Microsoft SQL Server, whereintandbigintsay what they mean, worked with no special handling. JIM now reads the declared precision and scale and picks the narrowest type guaranteed to hold every value the column permits: up to nine digits with no scale is a whole number, up to eighteen digits is a 64-bit whole number, and anything wider, anything carrying a scale, and an unconstrainedNUMBERremain decimals. Microsoft SQL Server is unchanged, because its named types state their width exactly. Existing Oracle Connected Systems keep the types they already hold; refresh the schema to adopt the new inference. (#1354) - β¨ The data type JIM inferred for a SQL or Oracle attribute can now be corrected by an administrator, per attribute, on a Connected System's Schema tab. A database catalogue does not always say what a column is for: Oracle's
NUMBER(1)may be a flag or a small number, and aNUMBERidentifier may be narrower in practice than its declaration allows. The override is refused once the attribute is referenced by a Synchronisation Rule or holds values, because changing it then would reinterpret data already imported under the previous type. Available to automation asSet-JIMConnectedSystemAttribute -Typeand onPUT api/v1/synchronisation/connected-systems/{connectedSystemId}/object-types/{objectTypeId}/attributes/{attributeId}; the bulk attribute endpoint refuses a data type rather than silently ignoring it. Connectors whose schema is definitive, such as LDAP and SCIM 2.0, are unaffected and continue to state their own types. (#1354) - β¨ A new Data Flow view under Administration β Schema lists every attribute data flow configured across all Connected Systems, in both directions, so "where does this attribute's value come from, and what writes it out?" can be answered in one place rather than by opening each Synchronisation Rule in turn. Filter by direction, Connected System, Metaverse Object Type or Metaverse Attribute, search across rules, systems, object types, attributes and expression text, or switch on Multiple contributors to see just the inbound flows whose Attribute Priority order actually decides something. Each row reads from the Connected System side to the Metaverse side, whichever way the value travels, and shows the setting that applies in its direction ("Null is a value" inbound, Enforce State outbound), the flow's position in its attribute's priority order, and the Synchronisation Rule that owns it. It is a discovery view: nothing is edited here. Available to automation as
Get-JIMDataFlowandGET api/v1/synchronisation/data-flows. (#1199) -
β¨ How long an account stays owed its initial password is now set per Connected System, instead of a fixed seven days everywhere. Raise it before taking a system out of service for longer, and accounts provisioned meanwhile still get a password when it returns. (#1316)
-
β¨ The Attribute Flow editor now shows where an inbound mapping sits in its target Metaverse Attribute's priority order, so multi-source contribution is visible at the point you create it rather than only afterwards. A new mapping is shown at the bottom of the list, which is where it is created, so it cannot start winning resolution unannounced. Null is a value is now settable here too, and in
New-JIMSyncRuleMapping -NullIsValue. (#1199) - β¨ The Partitions & Containers tab has been rebuilt around the decision it exists for. It now opens with what the Connected System actually imports (how many Containers are selected, out of how many, and how many partitions are managed) rather than with a permanent warning about a button. Container rows are named after the Container, with the Distinguished Name on hover, so a row reads
Salesrather thanou=Sales,ou=Corp,dc=example,dc=com; they are roughly half their previous height; and there is a filter, which together make a directory with hundreds of OUs navigable rather than merely renderable. Container Scope is now a two-segment control showing both Whole subtree and This level, so which one is in effect is readable without hovering anything, and a Container that cannot be ticked says which selected Container already covers it instead of being greyed out with no explanation. The guidance about what a hierarchy refresh does to your selections has moved from a permanent amber alert to a line carrying the more useful fact, when the hierarchy was last retrieved, with the caveat behind a disclosure. Saving now says whether there is anything to save, and offers Preview Changes beside Save Changes rather than leaving the preview to be found separately. (#351) -
β¨ The JIM SQL Connector is now a built-in Connector, so a Connected System can be created against a relational database from the portal, the REST API and PowerShell. It reads and writes Microsoft SQL Server and Oracle Database through fully managed ADO.NET drivers, so nothing native is installed and JIM stays air-gap deployable. One Connected System covers several tables and views: each Object Type names its own table, its anchor columns, the columns that carry another object's anchor as a reference, and any related table whose rows gather onto the parent as a multi-valued attribute. A Full Import pages through a table by keyset rather than by offset, a Delta Import reads either a change-log table or a watermark column, and an Export inserts, updates and deletes rows, reading back a key the database generated or writing one JIM authored for a table keyed on a natural identifier. Date and time columns carrying no offset are interpreted in a Database Time Zone you declare, and inverted on the way out; columns that state their own offset are left alone. Two Oracle opt-ins decide whether
NUMBER(1)columns mean Boolean and whetherRAW(16)columns hold GUIDs, because the catalogue cannot tell either apart. The connection is encrypted by default on both providers, and the server's certificate is always validated. (#170) -
β¨ Deselecting a partition or container on a Connected System can now be previewed before it is saved. The Preview Changes button on the Partitions & Containers tab reports how many Connected System Objects would leave import scope, how many of those are joined and would disconnect from their Metaverse Object (taking the attribute values they contributed with them), how many Metaverse Objects those disconnections would leave eligible for automatic deletion, and how many objects JIM still holds would come back into scope. Saving afterwards states those counts on the confirmation and records which preview informed the change. Two limits are stated rather than papered over: objects JIM has never imported cannot be counted, because there is nothing to count until a Full Import discovers them; and an object JIM cannot place (one imported before partitions were recorded, or one whose Connector cannot say what container an object is in) is left out of the counts entirely rather than guessed at. Available to automation as
New-JIMConfigurationChangePreview -ConnectedSystemIdandPOST connected-systems/{id}/scope-selection/preview. (#1251) -
β¨ A selected Container can now import only the objects held directly in it, rather than everything beneath it. Each selected Container in the Partitions tab carries a scope, shown beside it: Whole subtree, which is the default and how Container selection has always behaved, or This level only. Narrowing one releases the Containers beneath it, which become selectable in their own right and can carry their own scope, so
OU=Corpcan be imported at its own level whileOU=Salesbeneath it is imported whole and the rest ofOU=Corp's sub-OUs are left alone. That arrangement could not be expressed before. Narrowing takes objects out of scope exactly as deselecting those Containers would, so JIM asks you to acknowledge it before saving and says what becomes of the objects already imported. Available to automation asSet-JIMConnectedSystemContainer -Scopeand on the Container update endpoint. (#351) - β¨ An attribute can now be declared settable only when JIM creates the object, which is what a relational table's primary key actually is: JIM has to supply it when it inserts the row, and it is what ties the Connected System Object to that row from then on. Until now JIM had only "writable" and "read-only", so such an attribute had to be marked read-only to stop it being rewritten, which also stopped any export Attribute Flow from targeting it at all; a table keyed on a natural identifier such as an employee number could therefore never be provisioned into. The third state resolves that: an export Attribute Flow may target the attribute, the value flows with the Create Pending Export, and JIM never sends it again. The exclusion is enforced on the export path rather than left to configuration to get right: the attribute is kept out of every Update Pending Export even when the Metaverse value has changed, and Drift Correction does not re-assert a value that has diverged in the Connected System, because rewriting the key would not update the row, it would point JIM at a different one. Where a source value genuinely is reissued, JIM leaves the Connected System alone rather than quietly re-identifying an existing object. The Schema tab shows the state as "Set on creation only" with the reasoning behind it and filters by it, and the Attribute Flow editor marks affected mappings; the REST API and PowerShell report it as
WritableOnCreateon the attribute'swritability. No Connector reports the new state yet, so nothing changes for existing deployments. (#170) - β¨ Automation can now ask JIM for a password rather than inventing one.
Set-JIMConnectedSystemObjectPassword -Generatehas JIM produce a password satisfying the policy it discovered on the Connected System, sets it, and returns what it used as a SecureString; that is the only chance to capture it, because JIM stores nothing and cannot return it again. Prefer it to a generator written into a script: JIM knows what the target demands, and a hand-rolled one rediscovers the passphrase trap, where three words offer two character categories against a directory that wants three. The generate endpoint is the only response body in JIM that carries a password, which is deliberate; what JIM never does is store one, or return one nobody asked for.Set-JIMMetaverseObjectPassword -Generatedoes the same across a person's accounts, and is where it matters most: one password has to satisfy the strictest of several systems at once, and those policies are not something an administrator can see in order to reason about them. JIM reconciles them, and refuses outright where no single password can satisfy them all rather than handing back one that would be accepted on the first account and refused on the second after the first has already changed.Get-JIMConnectedSystemPasswordPolicyand a matching endpoint report what a system will accept, which the portal has always shown and no other surface could read; a null there means JIM could not read that rule rather than that no such rule exists, so checkhasAnyDiscoveredConstraintbefore treating the figures as the whole story. (#1121) - β¨ A directory's own configuration and operational object classes no longer crowd out the ones you manage on a Connected System's Schema tab. A stock OpenLDAP publishes 67 structural classes, of which 27 belong to the server rather than to your directory: the
cn=configbackend'solc*classes, the accesslog overlay'saudit*classes, and the root DSE class. The LDAP Connector now marks those Object Types internal and the Schema tab hides them, saying how many it is holding back and offering Show internal object types to see them. Nothing is discarded: every class is still discovered, still stored, and still selectable, and an Object Type you have already selected is never hidden. The judgement is made from the class's OID rather than its name, because an OID arc is assigned to its vendor and does not change, so a class of your own that happens to be named like a directory's internals is never affected. Active Directory needed no change, as JIM already asks it to exclude its own hidden and defunct classes.Get-JIMConnectedSystemObjectTypeapplies the same default and gains-IncludeInternal; the REST API returns every Object Type as before, now carrying the Connector's classification tags and anisInternalflag so a caller can decide for itself. (#434) - β¨ One password can now be set across several of a person's accounts at once, from that person in the portal. Choose some or all of the accounts they have whose Connector can set a password; JIM writes to each Connected System in turn, showing progress on the same stepped rail a Run Profile execution uses. Nothing is selected by default, so resetting a forgotten password in one system never silently resets the others. The password is generated to satisfy the strictest of the selected systems' discovered rules: the longest minimum length any of them demands, and only the character categories all of them count, since a category one system does not recognise cannot help satisfy another's complexity rule. There is no transaction across Connected Systems, so a run can end with some accounts changed and others not; JIM says which are unchanged in as many words, and offers to retry only those, reusing the password already in hand. Where a system refused the password itself, retrying it would fail identically, so the guidance offers a fresh one for every account instead, including those that already succeeded, rather than leaving the person with two different passwords. Each failure carries remediation guidance you can open, specific to what actually went wrong. Every account gets its own Activity under one parent, and a single account records no parent. Available to automation as
Set-JIMMetaverseObjectPassword, which requires the Connected Systems to be named or-AllAccountsto be passed. (#1172) - β¨ An administrator can now set the password on a single account in a Connected System, from that Connected System Object in the connector space. It is written straight to the system: nothing is staged, retried or stored. Generate produces a password that satisfies the policy JIM discovered on the system, and puts it behind a mask immediately; Copy works while it is still masked, so handing a password to the person who needs it never means putting it on a screen somebody else can read; Reveal is there for reading one aloud and hides itself again after thirty seconds. You can type your own instead. Choose what happens to the password afterwards and whether to enable the account at the same time; leaving the enable switch off leaves the account exactly as it was. A system that refuses the password says why, in its own words, and the dialog stays open so you can try another. Every attempt is recorded as an Activity against the account, carrying the outcome and never the password. Available to automation as
Set-JIMConnectedSystemObjectPasswordand a REST endpoint, which either take a password you supply or generate one against the discovered policy. (#1121) - β¨ A Run Profile execution item now shows Caused by beneath its causality panel: why the changes on it happened, why those happened, and so on back up the chain as far as JIM recorded it. Each step reads as a sentence ("10 Users were deleted, so they were removed from Project Diamond's Static Members") with the relationship the cascade acted through picked out in colour, rather than as another diagram to interpret. Where the cause's own reason was recorded, it follows as a second sentence led by the Connected System responsible ("Yellowstone APAC was the last authoritative source to disconnect, so the Deletion Rule deleted them"). Causes that say the same thing (same reason, same Connected System, same Synchronisation Rule, same object type and attribute) are collapsed into one statement carrying a count, which expands to name each of them; two independent causes converging on one effect stay as two, because that is exactly what needs to be seen. Everything a step says was captured when it happened (the causing object's name and type, the attribute, the system and the rule), so the chain still reads correctly once those objects have been deleted or renamed, which is the normal case: a cause is always older than its effect. The chain always states why it ends, and the three endings are kept distinct: nothing caused this, the causing record has aged out of retention, or the walk stopped at its depth bound. A cause recorded on another execution item links to it. (#1223)
- β¨ An Export execution item now walks its Caused by chain to the root. Previously it showed no chain at all: an export run holds only a queue of changes to make, and the synchronisation that decided on a change ran in a different Activity, often days earlier, with nothing linking the two. JIM now records the synchronisation that stages each change onto the change itself (the one link that could not be recovered after the fact, because a queued change is deleted the moment its export succeeds), and the export item leads with what that synchronisation decided: a create reads "Mia Young was provisioned to Glitterband EMEA, so this run created the record", with the Synchronisation Rule that made the provisioning decision beside it; an update reads "applied the changes"; a deprovision leads with the Identity's deletion. Each links to the run that staged the change, whose own causes continue above it, and behind any synchronisation the chain continues to the import that fed it: "Mia Young was imported into Yellowstone APAC as a new record" is the true root of most stories, and a deleted account's chain runs all the way back to the source record's deletion. Delete and membership-removal exports staged by a deletion cascade or grace-period housekeeping are stamped with the item that reported them, so a deprovisioned account's chain reaches the Deletion Rule decision that ordered it; drift corrections name the drift correction that staged them. Changes already queued before upgrading carry no cause, since it was never captured. (#1223)
SCIM 2.0 Client Connector (#545)ΒΆ
- β¨ JIM now synchronises with any system that publishes a SCIM 2.0 service provider interface, using one standards-based connector rather than one per product: it reads the provider's own schema, imports users and groups with their memberships, and exports changes back.
- β¨ Delta Imports ask the provider for only what changed since the last completed import, falling back to reading everything (and saying so) where a provider cannot filter. Deletions are detected by a Full Import, as the SCIM protocol offers no way to ask what was removed.
- β¨ Exports send only what changed, and against a provider that cannot accept partial updates JIM reads the resource and writes it back intact rather than clearing attributes it does not manage. Entity tags guard updates against overwriting a change JIM never saw.
- β¨ A SCIM connection refused over certificate trust now shows you the certificate the service provider presented, so you can check its thumbprint and add it under Admin > Certificates. That trusts one specific certificate, so a provider later presenting a different one is refused and reported.
- β¨ Rate limits are respected rather than fought: JIM honours a provider's
Retry-After, backs off with jitter, and pauses before an allowance runs out, reporting throttling as a warning instead of failing the run. - β¨ A schema import that had to work around gaps in what a system publishes now says so: the discovery warnings appear on the schema screen's refresh summary, and the import's Activity completes with a warning carrying the same detail for the REST API and PowerShell.
-
β¨ Where a service provider advertises SCIM's Bulk endpoint, the new Use Bulk Operations setting sends exports a batch at a time rather than one request per object, which is considerably faster over a high-latency connection. It is off by default, because a provider that reports outcomes inaccurately would have JIM record changes as applied that were not; per-object exports are always correct, so this is a throughput choice to make once you have seen an export succeed against your provider. JIM stays inside the batch size and payload limits the provider publishes (and halves a batch a provider refuses as too large, which happens when its real limit is lower than the one it advertises), asks it to process every operation regardless of errors, matches each outcome back to the change that produced it rather than counting them off in order, and treats an operation the provider never reported on as failed rather than assuming it applied. A provider that advertises the endpoint and does not serve it falls back to one request per object for the rest of the run.
-
β¨ A Connected System's details page now shows a Directory Capabilities card with the facts JIM has detected about the target system: for LDAP directories, the directory type (Active Directory, Samba AD, OpenLDAP or Generic), vendor, DNS host name, paging support, and, where applicable, the pinned domain controller and its invocation ID. These are read from data JIM already captured during a previous connection; nothing here opens a new connection or changes anything. Before the first successful connection, the card shows a subtle hint rather than an error. Available to automation via
GET /connected-systems/{id}/capabilitiesandGet-JIMConnectedSystemCapability. (#231) - β¨ Connected Systems that can accept passwords now show a Password Channel panel on their Schema tab, carrying the password policy JIM read from the system itself (minimum length, complexity and the character categories it means, history length, and maximum and minimum password age) and a read-only Check password channel button. The check sets no password on anything, so it is safe to run against production, and reports on four things: whether the connection is encrypted, whether the mechanism JIM would use is available, whether the account JIM connects as may actually reset passwords in each container it manages, and whether the password policy could be read. Each result is passed, warning, failed, or could not tell, the last kept deliberately distinct: a directory withholds what a caller may not see by omitting it rather than refusing, so reporting a silence as a failure would tell you an account lacks rights it demonstrably has. Where a domain has password policies that apply to only some accounts, or JIM was not permitted to find out, the discovered figures are presented as a floor rather than a guarantee. (#1121)
- π LDAPS connections to a directory now genuinely validate the certificate it presents, checking the issuer, the validity period, and that the certificate was issued for the host JIM connects to, before the service account's credentials are sent. Certificates added in Admin > Certificates are honoured for the first time: they are trusted in addition to the operating system's trust store, never in place of it, so adding one can only ever allow more connections, never fewer. An internal certificate authority or a directory's own self-signed certificate both work. Previously the validation code could not run at all in JIM's containers, so adding any certificate broke LDAPS with a connectivity error instead. (#1132)
- β¨ The Synchronisation Rules list can now be filtered by Connected System, Direction, Action (Projects, Provisions or Flow Only) and Status. The filters combine with the existing search box, which narrows whatever the filters left.
- β¨ The same filters are available to automation:
Get-JIMSyncRulegains-Direction,-ActionTypeand-Status, and the Synchronisation Rules REST endpoint gains matching query parameters. - β¨ The certificate a server presents can now be trusted from the failure that reported it. Selecting Trust this certificate has JIM read the certificate from the server again, confirm it is still the one you were shown, and add it to Trusted Certificates, so you no longer have to obtain the certificate file by other means. You confirm the thumbprint first, and where the server sent the authority that issued its certificate JIM offers that instead and recommends it, because trusting the authority survives the server's certificate being renewed. A server presenting anything other than the certificate you confirmed stops the action and shows you both thumbprints. Fetch certificate on a Connected System's settings does the same reading before anything has failed, so configuring a new system is not a cycle of save, fail, come back. The action is offered only where trusting genuinely fixes the failure: an expired certificate still has to be renewed, and a name mismatch still means connecting by a name the certificate carries. Available across the portal, the REST API and PowerShell (
Get-JIMConnectedSystemServerCertificate,Approve-JIMConnectedSystemServerCertificate), with every addition recorded on an Activity naming who trusted it and why. (#1139) - β¨ When an LDAPS connection to a directory fails because of the certificate it presented, JIM now shows you that certificate rather than an unhelpful "the server is unavailable": its subject, the names it was issued for, its issuer, validity dates and thumbprint, laid out as the certificate itself, alongside which check it failed and what to do about it. It appears when testing a Connected System's settings and on the failed Activity, with the same detail available to automation on the Activity's
errorDetailfield in the REST API. Nothing is trusted in order to show it, and a failure unrelated to the certificate reports exactly as before. (#1132) - β¨ Saving a configuration change now confirms what you are about to change: a list of the properties that actually changed with their before and after values, a reminder that a Full Synchronisation is what puts them into effect, and, for changes that can delete or disconnect objects, a plain statement of what will happen. Cosmetic edits such as renaming save without a prompt. This covers Synchronisation Rules, Connected Systems (details, settings, schema and partitions), Metaverse Object Types, Metaverse Attributes and Service Settings. Deselecting a Connected System Object Type or a partition, and changing a Metaverse Object Type's deletion settings, previously saved with no confirmation at all.
- β¨ A configuration change can now be previewed before it is made: JIM evaluates the proposed change against the objects already in the metaverse and reports which of them would be affected, changing nothing. The first surface to offer it is a Metaverse Object Type's deletion settings, which is the change most worth asking about because it is the one that can make existing Metaverse Objects eligible for deletion the moment it is saved. Preview Changes, beside Save on the Deletion Rules panel, reports how many objects would become eligible for deletion, how many would stop being eligible, and how many would keep a deletion date that moves, and lets you drill into the objects behind each figure. Saving afterwards states those figures on the confirmation, and the change's Activity records which preview informed it. Edit the settings after previewing and the preview is marked stale and contributes nothing, because it now describes a different change. A preview that failed part-way shows nothing at all rather than counts over an arbitrary subset of the population. Available to automation too:
New-JIMConfigurationChangePreview(with-Wait),Get-JIMConfigurationChangePreview,Get-JIMConfigurationChangePreviewDeltaandStop-JIMConfigurationChangePreview, plusPOST /metaverse/object-types/{id}/deletion-settings/previewand-PreviewActivityIdonSet-JIMMetaverseObjectType. (#827, #1114) - β¨ A Configuration Change Preview now names what kind of edit a summary row describes, where it recognises one: "Email or UPN domain changed" rather than only "Email changed". It recognises a domain change on an address or User Principal Name, a move to a different container, a change of letter case alone, and text added to or removed from the start or end of a value. This is most useful exactly where the values themselves stop being readable: a row covering thousands of distinct value pairs collapses to the attribute alone, and the pattern is what still makes it reviewable. A row is only named where every object in it makes the same kind of edit, so a row covering a mixture is left unnamed and the objects behind it carry their own patterns in the drill-down. Surfaced in the portal, and as a
PatternKeyon both groups and rows for the REST API andGet-JIMConfigurationChangePreview/Get-JIMConfigurationChangePreviewDelta. (#827) - β¨ Long-running Connector work now narrates itself on the Activity instead of appearing frozen: the File Connector reports loading, merging and writing during an export and rows parsed during an import, and the LDAP Connector reports its root DSE query, the container and page it is fetching, and a Delta Import's watermark queries. Object counts still only move once the Connector returns objects; the moving message is what distinguishes a healthy long phase from a stuck run. (#637)
- β¨ A Run Profile execution now shows its whole journey on the Activity, not just what it is doing this second: the run reads left to right as a stepped progress bar, with a tick and how long it took for the steps that are done, the step running now highlighted with the Connector's own steps, message and object counts beneath it, and the steps still to come greyed out. A step the run did not need (deletion detection on a Delta Import) stays on the rail with a dash and says so on hover, rather than looking outstanding; work a run could never do at all (opening a connection for a file-based import) is not shown as a step, and a failed run marks the step it failed in. The steps stay with the Activity, so a run that finished days ago still answers where its four hours went. (#454)
- β¨ Connectors can tell JIM how many objects a Connected System holds and how many they have handed over so far, so an import shows how far through it is rather than a bar with no end to it. The File Connector counts a file's records before reading them, so a file import now shows a percentage and a time remaining throughout. Importing from a directory reports objects as they arrive, so the counters move during the read instead of standing still until the whole directory has been fetched. This covers Delta Imports as well, which can run to a very large number of changes after an outage, and which previously showed no movement at all while they walked the directory's change log. Directories cannot be asked how many objects a search will return without running it twice, so those imports show the count and rate without a percentage rather than a figure JIM guessed. Connector authors are recommended to report both figures wherever their system can be asked cheaply. (#454)
- β¨ Connectors can declare the steps of their internal work, so long Connector phases appear as steps with an end in sight rather than only as a message that changes. The File Connector declares loading, merging and writing for an export and reading for an import; the LDAP Connector declares its directory query, change queries, object fetching and deleted-object queries; the SCIM Connector declares discovering the service provider and fetching resources. (#454)
- β¨ Automation sees the steps too: the Activity progress endpoint reports the current step and its position in the run, the Activity endpoint returns every step with its duration, and
Start-JIMRunProfile -WaitandGet-JIMActivity -Followdisplay "Step 3 of 7: Saving changes" instead of a bare object count. (#454) - β¨ Connected Systems now show when their configuration has changed in a way that needs a Full Synchronisation to take effect: an indicator in the Connected Systems list and a notice on the Connected System page, stating how many changes are waiting and warning distinctly when one of them is destructive. Cosmetic changes such as renames never raise it, and a change to a Metaverse Attribute raises it only on the systems whose Synchronisation Rules actually reference that attribute. Systems that have never completed a Full Synchronisation, and the case where configuration change tracking is switched off, are reported as such rather than as "up to date". Available to automation as
(Get-JIMConnectedSystem -Id <id>).ConfigurationDriftand on the REST Connected System response. - β¨ Deleting identities when an authoritative source disconnects now offers two trigger modes: "All sources disconnect" waits until every selected source has gone before deleting (the default for new configurations, so a single source system failing or being rebuilt cannot trigger deletions), while "Specific source(s) disconnect" deletes when any one of them disconnects (existing configurations keep this behaviour). Configurable on the Metaverse Object Type page, the REST API and PowerShell. (#119)
- β¨ The LDAP Connector now discovers and pins a single domain controller for Active Directory and Samba AD, instead of reconnecting via whatever a domain name Host setting happens to resolve to on each connection. On first connection, JIM records the domain controller reached via Host and pins every later connection, in and across Run Profile executions, to that same domain controller; this avoids the replication lag inconsistencies and delta import correctness risk of DNS round-robin landing on a different domain controller each run. A new optional "Preferred Domain Controller" setting lets you name a specific domain controller instead, taking priority over any pin. If the pinned domain controller becomes unreachable, the run fails outright (no mid-run failover) and the pin is cleared; the next run re-discovers and re-pins via Host, and a Full Import is needed to re-establish the delta baseline (see the existing domain controller mismatch guidance). (#230)
- β¨ The causality view on a Run Profile execution item's detail page has been redesigned: a plain-English summary sentence now tells you at a glance what happened to an object and what it caused, every event is named in plain language with the technical term alongside, and the chain can be explored in three switchable views (Flow, Timeline and Graph) with your choice remembered. Attribute change detail gains operation badges, search and filter chips, and every Connected System, Identity and Synchronisation Rule mentioned links straight to its detail page. (#1087)
- β¨ The Operations queue now shows what a running task is actually doing. Each row carries the run's steps above the running step's own progress bar, with a caption naming the step the figures measure ("Step 3 of 7: Saving changes - 12,480 / 40,000"), so a count that restarts between steps reads as the run advancing rather than progress being lost. Tasks that are not Run Profile executions are unchanged. (#1162)
- β¨ A running Schedule now shows its whole shape in the Operations queue: the header above its tasks draws it as a rail, a marker per step with the step names underneath and the step it has reached named beside them ("Step 2 of 5"), including the steps already finished. A step running several tasks at once is drawn as one divided marker carrying each task's own outcome, so one of two parallel imports failing while the other is still running reads as exactly that, even from a collapsed group. (#1162)
- β¨ Automation sees the same picture:
Get-JIMWorkerTaskandGet-JIMScheduleExecutioneach carry aStepDisplayreading "Step 3 of 7: Saving changes", the same sentence the portal shows, and a Schedule Execution read by ID reports its progress step by step with each concurrent task's outcome. (#1162)
Schedule Execution visibility (#1196)ΒΆ
- β¨ The Schedules list now shows how each Schedule's last run ended, not just when it ran, naming the step a failed run stopped on. Expanding a Schedule lists its recent executions with their outcomes.
- β¨ A new Schedule Execution view shows every step of a run with its outcome, how long it took, and a link straight to the Activity that produced it, so a failed overnight run no longer has to be pieced together from the Activity history.
- π₯οΈ An Activity that a Schedule produced now says so, linking back to the run it belonged to and the step within it.
- β¨ The Activity history can now be filtered to work a Schedule produced, either any Schedule or particular ones, turning "last night failed" into "this step has been failing all week". The attribution lives on the Activity, so it survives the Schedule being deleted.
- β¨ A Synchronisation Rule can now set one password you choose on every account it provisions, so a new starter can be told what to sign in with. JIM does not recommend it, and the portal says so beside the option: every account the rule provisions shares that password until each person changes it, so anybody who learns of it can sign in as any new starter who has not, and leaving Require a change at the next sign-in on is what ends each account's share of it. It exists because the alternative is worse for the people who need it. Every other initial password is generated per account and stored nowhere, which is right for the password's actual job (getting the account into a state the directory will accept and enable) and leaves nobody able to tell a new starter theirs, so today that means setting a password by hand for every person. This is the only password JIM stores: it is stored encrypted and cannot be shown to you again, protected at rest exactly as a Connected System's credentials are and write-only on every surface (the portal fields are blank whenever you open them, and no REST response or cmdlet returns it), and reaches your configuration change history as a keyed hash, which shows that it changed and when without carrying the value. What JIM will tell you is that one is set and when it last changed, which is what a rotation check needs: change it whenever somebody who knew it leaves. A password the Connected System would refuse is rejected when you set it rather than parking every account the rule provisions, and a rule set to this option with no password stored is refused for the same reason. Available to automation as
Set-JIMSyncRuleInitialPassword -Source Static -StaticPassword <securestring>, withstaticPasswordSetandstaticPasswordSetAtonGet-JIMSyncRuleInitialPassword. Delivering a generated password to somebody who should have it is the answer that replaces this one (#1252); it is not built yet. (#1273) - β¨ JIM now says which Synchronisation Rules and Connected Systems have accounts waiting on you over their initial password, rather than leaving you to go looking. Both lists carry an amber chip counting the accounts parked against a rule and a red one counting those that expired without ever getting a password; the two are never added together, because parked work is fixed by correcting the rule's password settings and expired work cannot be fixed that way at all. A rule or system with nothing outstanding shows no chip. On the Synchronisation Rule itself, the Initial Password section carries the parked count on its heading even while collapsed, and opening it shows the accounts grouped by what the target actually said, biggest group first and quoted unaltered, because a directory's rejection code is the one thing precise enough to identify the fault. Correct the settings and the panel confirms, before you save, how many accounts saving will release; it stays quiet for an edit that would not change what is delivered, so it never promises a release that saving will not perform. Available to automation on
Get-JIMSyncRuleInitialPassword(parkedAccountCount,expiredAccountCountand the grouped reasons) and onGet-JIMConnectedSystem -Id. (#1221)
ChangedΒΆ
- π Built-in configuration now reaches deployments that already exist. JIM's built-in Metaverse Object Types, Predefined Searches and Example Data Sets were created once, when an instance was first initialised, and never revisited: anything added to them in a later release arrived on brand-new installations only, and a new built-in Metaverse Object Type would have stopped an existing instance's worker from starting at all. Each service start now brings the built-in configuration into line with what the release ships, creating whatever is absent and leaving everything else exactly as it is, which is what already happened for built-in Metaverse Attributes and Connectors. An instance that is already up to date records nothing and pays well under a second for the check. See What happens during the upgrade window. (#916)
- π Built-in Schedules and Roles are now defined as a list rather than one hardcoded item each, so a second built-in Schedule or Role added in a later release reaches existing instances and survives a factory reset. Both passes previously checked for the single built-in they knew about and stopped, which would have suppressed any other. Nothing changes for the built-ins JIM ships today. (#916)
- π A factory reset now restores JIM's built-in configuration by applying all of it, rather than repairing the particular things earlier resets were found to have lost. The wipe is meant to leave built-in data intact but takes some of it as collateral; that had been patched twice, once for the built-in Example Data Template's attributes and once for the built-in Schedules, and any built-in added afterwards would have needed remembering a third time. One consequence worth knowing: read-only Service Settings that come from the deployment's environment variables, such as the SSO endpoints, are re-asserted from the environment as part of the reset. See Reset-JIMSystem. (#916)
- π The REST API now returns purpose-built response shapes for Connector Definitions, Example Data Sets, Data Generation Templates and Predefined Searches, instead of serialising JIM's internal database entities. What clients gain: a Connector Definition no longer embeds each connector binary as base64 (file metadata, including size and version, is still returned); a Predefined Search carries its target Metaverse Object Type as
metaverseObjectTypeIdandmetaverseObjectTypeNamerather than a nested object, and its attributes and criteria groups arrive ordered by position; a template's attributes identify what they generate by id and name rather than embedding live schema entities. Scripts that read the removed nested objects (for example$search.metaverseObjectType.name) need the new scalar fields; property names are otherwise unchanged. (#1447) - π An outbound Synchronisation Rule can now write back into the same Connected System an inbound rule reads from, so a value JIM derives (an email address, an account name) reaches the system that supplied the identity. Export evaluation previously skipped every rule targeting the system being synchronised, so these rules were silently never evaluated; circular synchronisation is prevented by staging only values the target does not already hold. (#1284)
- π A Connected System whose external system is temporarily unreachable no longer loses its Schema, Partitions & Containers and Matching tabs. Those tabs are gated on the settings being complete, which is a fact about the configuration; saving any change during an outage previously recorded the settings as invalid and locked them until someone re-saved the Settings tab. Saving settings still tests the connection and reports what it finds.
- π₯οΈ Lists in the portal no longer page. Metaverse Objects, the Connector Space, Pending Exports, Pending Deletions, Deleted Objects, Activities, service logs, Synchronisation Rules, Connected Systems, Connectors, Metaverse Object Types, Predefined Searches, API Keys, Certificates and the Example Data lists now scroll continuously, fetching rows as you reach them, so there is no page size to choose and no page controls to work through: a list of eight objects and a list of eight hundred thousand are read the same way. Only the rows on screen (and a screen or so beyond) are ever fetched, so opening a very large list costs no more than opening a small one. Each list now states its size beside its search box, reading "12 of 3,868 Metaverse Objects" while a search narrows it, and searching and sorting run across the whole list rather than the rows on screen. Your search, sort and position live in the address bar, so a link into a list opens where you left it. A list sizes itself to what it holds: a short one collapses to its rows and reads as an ordinary table, a long one fills the page to the footer. An empty list now says which of the two reasons applies, offering to clear a search that matched nothing, or naming what would put objects in it. The REST API and PowerShell module are paged as before. See Working with Lists.
- π₯οΈ The tables that live inside a page no longer page either, so nothing in the portal does. A Run Profile execution's items and an Activity's child Activities, an API Key's usage history, a Connected System Object's attributes and the Pending Exports queued against it, a Pending Export's Attribute Changes, the values of a multi-valued attribute on a Metaverse Object or a Connected System Object, a Change History entry's changes, a causality event's attribute changes, a Connected System's schema, Run Profiles, Object Matching Rules and Attribute Flows, a Metaverse Object Type's attributes, Service Settings, and all three Operations tabs now scroll continuously and state how many rows they hold beside their search box. A group with half a million members is read by scrolling it and narrowed by typing into its search box, rather than by working through page controls ten values at a time; the same is true of an Activity that recorded a million execution items. Searching and sorting run across the whole table rather than the rows on screen wherever the read behind it can sort.
- π₯οΈ Every row of a scrolling table is one line tall, and nothing is lost to the change. A cell holding a list shows its first item with a +n more beside it, opening the whole set in a dialog drawn exactly as the row draws it: an API Key's Roles, the Object Types a Metaverse Attribute is bound to, the sources of an Attribute Flow, an Example Data Template Attribute's generation rules, and a multi-valued attribute's values. Long free text (a schema attribute's description, a service log's message) is clipped with the full text on hover, and a service log entry's message is still there in full in the panel a row click opens. This is what a continuously scrolling table requires: it positions rows arithmetically from one row height, so a row that grows taller than the rest moves every row below it out of place.
- π₯οΈ Two tables that could not become a scrolling list without losing what they do have moved instead. A Metaverse Attribute's contributors, which reorder by dragging, now open in a dialog from the contributor count rather than expanding a row underneath it, and a Schedule's recent executions likewise open from its History action, where they now show the Schedule's whole history rather than its last five. Service Settings no longer groups by Category, which described a page of rows rather than the list; Category is now a column, and leads the order the list arrives in.
- π₯οΈ A Configuration Change Preview now opens with what saving would do, in one sentence, worst consequence first, so a change that disconnects forty thousand objects and deletes two leads with the two deletions. Its transitions are written in English rather than derived from JIM's internal names, counts line up as a column, rows say that they open, and a grace period reads as "45 minutes" rather than "0:45:00". (#1275)
- π An account whose initial password a system refused is no longer stuck for good. When a target refuses the password itself, for not satisfying the rules in force for that account, JIM parks the account instead of retrying, because the same settings produce another password refused for the same reason. Saving a change to that Synchronisation Rule's initial password settings now releases everything parked against it, and the accounts are attempted again on the Connected System's next export run. Nothing has to be regenerated, because no password was ever stored: the retry uses the corrected settings by construction. Saving an unrelated part of the same rule releases nothing, so a rename cannot set accounts retrying against settings the target has already given its answer on. (#1221)
- π An account provisioned but never given its initial password now stops being retried after a week, and says so. It is recorded as expired rather than removed, and counted on the export's Activity ("3 expired without one"), because an account that quietly stopped being owed a password, with nothing to say so, is exactly the silent loss the rest of this behaviour exists to avoid. Accounts already waiting when this release is installed keep being retried; the expiry applies to accounts provisioned from here on. (#1221)
- π₯οΈ Tooltips no longer stretch across the page. A long explanation grew to one very wide line, because nothing limited how far it could run; it now wraps into a readable block. A value with an explanation behind it now responds to the pointer as well, so it is clearer what the tooltip belongs to.
- π An account queued for removal now reports itself as Deprovision queued in the causality views, instead of appearing as an ordinary Export queued that had set a single attribute. A staged delete carries the target's identifying attribute (its distinguished name, for a directory) so the Connector can still find the entry after the record has been disconnected from its Identity; reported as a change, that made a deprovisioning cascade read as an attribute update, which is close to the opposite of what it is. Expanding one now shows those values under Target identified by rather than as a change count. Deprovisions still count towards an Activity's Pending Exports total, because that is what they are. Outcomes recorded before this release keep the wording they were written with. (#1087)
- π₯οΈ Timeline view spaces its events evenly. A branch of nested events ended with twice the gap that separated plain ones, because a parent's own trailing space was added on top of its last child's, compounding once more at every level of nesting. (#1087)
- π₯οΈ Graph view no longer offers a click that does nothing. Every event block invited one, but selecting a block only opens its attribute detail, so a block with no attributes highlighted and then sat there, reading as a click that had failed. Those blocks are now inert, matching how Flow view has always treated the same events. (#1087)
- π₯οΈ A Run Profile execution item's Execution Summary reads more evenly. The Operation and External ID values were the only two of the six fields presented as filled, colour-filled chips, so they shouted over the rest of the panel; they now match their neighbours as an icon beside plain text. The status icon that repeated after the page title has gone, since the title and the Operation field below it already say what happened. (#1087)
- π₯οΈ Text throughout the causality view is now the same size as the rest of the portal. Every size in the panel had been hand-picked in pixels, most of them smaller than the site's own scale, so the whole panel read as noticeably smaller than the page around it; sizes now come from the theme. Graph nodes are correspondingly wider, so node labels still show the same amount of text at the larger size. (#1087)
- π View deletion record in the causality view now opens the deleted object's own change history, instead of the Deleted Objects browser with every deletion JIM has ever recorded in it. A CSO Deleted event now offers the same link, naming the record that was removed; it previously said only that a deletion had happened. Deleted Objects accepts the deep links directly (
/admin/deleted-objects?mvo=<id>and?cso=<id>), so they can be bookmarked and shared. (#1087) - π A Pending Export outcome in the causality view now links to the individual Pending Export it created, rather than to the target Connected System's whole Pending Exports queue. On a deprovisioning cascade that queue can hold thousands of rows, leaving "which of these did this event create?" as the reader's problem. (#1087)
- π Objects are now named consistently everywhere JIM shows them. A Connected System Object resolves its name from
displayName, thencn, thenname, before falling back to its external id; a Metaverse Object resolves Display Name, then Common Name. Group objects imported from LDAP and Active Directory typically carrycnbut nodisplayName, so they previously appeared as raw identifiers (for example1f16ccb0-1f01-1041-8be1-eb9f4cb3f25e) in the causality view, the Connected System Objects list, Pending Exports and change history; they now show their actual name. - π While a Run Profile is running, its live progress message now appears once, under the step it describes, instead of twice on the same page. The Activity's Message row shows the completion summary once the run has finished. (#454)
- π Search boxes across the portal now filter as you type instead of waiting for you to click away. Every list, table and dialog search box behaves the same way, with a short pause after the last keystroke so a search that queries the database is not run per character. The multi-criteria query forms on Deleted Objects and Admin > Logs are unchanged: those apply when you press Search or Refresh, as before. (#864)
- π The REST API now limits how deep you may page by rows retrieved (1,000,000) rather than by page number (1,000). The database's cost comes from the offset rather than the page number, so the old limit was four times stricter at a page size of 25 than at 100 for identical work, and it capped retrieval at roughly 100,000 objects, well below the 500,000-object scale JIM is validated at. Every request that was accepted before is still accepted; the error returned beyond the limit now names your deepest allowed page for the page size you asked for. (#487)
- π Stack traces are now hidden behind a "Show stack trace" toggle wherever JIM reports an error (Activity detail, Import Results detail, the Operations history panel and Pending Export detail), so the error message itself leads. The trace is unchanged and one click away. (#1132)
- π The LDAP Connector's "Certificate Validation" setting has been removed. Its "Skip Validation" option could never be honoured for an individual Connected System, and validation is now always applied to LDAPS connections. Where a directory's certificate is not trusted, add it in Admin > Certificates; where the certificate name does not match the host being connected to, give the JIM containers a host entry for that name (
extra_hostsin Docker Compose) and use the name in the Host setting, rather than weakening validation. See the LDAP Connector documentation for both. (#1132) - π A Delta Import against Active Directory or Samba AD now fails fast, with a clear error naming what changed, if it connects to a different domain controller than the one that produced the persisted USN watermark (for example, a domain name configured as Host resolving to a different DC via DNS round-robin, or the DC being restored from backup). USN watermarks are only meaningful when read back against the same DC; previously a DC change was undetected and could silently skip or re-import changes. Run a Full Import to re-establish the delta baseline. (#230)
- β¨ A Discover... action now sits beside the LDAP Connector's Preferred Domain Controller field, listing every domain controller in the forest with its Active Directory Site so you can pick one rather than typing a hostname blind. Discovery only ever informs; nothing is written until you select a server and save. Available for Active Directory and Samba AD Connected Systems in the portal, the REST API (
GET /connected-systems/{id}/directory-servers) and PowerShell (Get-JIMConnectedSystemDirectoryServer, aliasedGet-JIMConnectedSystemDomainController). (#1167) - π A running Run Profile's Progress panel now states each figure once. Objects processed, throughput and time remaining were previously printed up to three times between the progress message and the lines beneath the bar, and the two sets of figures disagreed with each other because they were measured separately. They now appear as a single labelled readout under the bar, with the percentage beside it, and the progress message narrates what is happening rather than repeating the numbers. The readout says which step it measures ("Step 2 of 3: Processing Connected System Objects"), because every figure in it is reset by each step that counts its own work; without that, the time remaining read as an estimate for the whole run. A step that cannot know its total in advance, such as a paged import, now reports how many objects it has processed instead of showing an empty bar, and a step whose counter has reached its total while it finishes up says so rather than counting down to a moment that has passed.
Get-JIMActivity -FollowandStart-JIMRunProfile -Waitgain the same count. - π Exports and Synchronisations now show the steps they were performing all along. An export records Exporting deferred changes (its second pass, re-resolving references whose target did not exist during the first pass and writing what that makes exportable), Selecting new containers and Delivering initial passwords; previously the run went on working, and narrating what it was doing, while the rail still showed the export as the last thing that had happened. Steps a run does not need, such as the deferred pass when nothing was deferred, show as not needed rather than being hidden. A Synchronisation records Reviewing export scope, the pass that re-evaluates objects whose export scope drifted with the clock. Cross-page reference resolution now counts its own work rather than leaving the previous step's totals on screen, so it no longer reads as complete from the moment it starts.
- π A Connected System's Connector Space and Pending Exports are now reachable from anywhere on its page: both sit above the tabs rather than inside the Details tab, and each shows how many objects or waiting changes it holds. The page they lead to is now titled Connector Space too, matching the term used everywhere else for where Connected System Objects are staged. (#231)
- π An identity reappearing during its deletion grace period now only cancels the scheduled deletion when it undoes the disconnection that triggered it; an unrelated system reconnecting no longer rescues an identity that should still be deleted. (#119)
- π Deletion decisions are now explained from facts recorded at the moment of the decision: the Activity detail page shows the deletion rule, trigger mode, selected sources, triggering system and the date the deletion becomes due, as they were when the decision was made (staying accurate after the rules are edited), and the Pending Deletions page names which system's disconnection triggered each scheduled deletion. (#119)
-
π Breaking: a successful Schedule Execution's status is now
Complete, notCompleted, matching the word Activities already use for the same outcome. The REST API and PowerShell both send and accept onlyComplete; update any script that filters onCompleted. (#1196) -
β¨ The Activity history can now be filtered from automation as thoroughly as from the portal:
GET /api/v1/activitiesandGet-JIMActivitygain filters for operation, outcome, status, initiator, created date range, Connected System, Run Profile and Schedule. -
β¨ Those filters combine, so "which of last week's scheduled Full Imports against Contoso AD recorded errors?" is now one call rather than a sift through pages of Activities. The portal, REST API and PowerShell run the same query, so all three answer identically.
-
π Parked and expired initial password records are now cleared once they have had their retention period, 90 days by default. Nothing removed them before, so a Synchronisation Rule provisioning into a system that refuses its passwords grew one record per account for ever. (#1316)
- π A factory reset no longer fails outright when custom configuration holds the records it ordinarily holds, such as a Predefined Search's criteria or a Connector Definition's settings. It stopped with a foreign-key error and, being one transaction, removed nothing. (#1477)
- π₯οΈ A Run Profile execution item's detail page is now split over tabs. Overview carries the item's own story (what the run did to it, why, and any error); a Pending Export the item created or failed on moves to its own Pending Export tab, since a queued export is a separate subject with its own status, retry count and staged changes. The tab appears only where there is one. The page had accumulated several unrelated subjects in one scroll, which made the answer harder to find than it needed to be.
- π₯οΈ The Projection Details section has been retired from a Run Profile execution item's detail page. The causality panel above it already tells the projection's story (the source record, the Identity created, and links to both objects), leaving the section restating it in a dated side-by-side layout; once either object had been deleted, it showed nothing but a pair of warnings. The attribute values it previewed live on the Connected System Object and Metaverse Object pages it linked to. (#1223)
- π₯οΈ The Metaverse Impact section has been retired from a Run Profile execution item's detail page; everything it said now sits where it belongs. A Deletion Rule that evaluates and decides not to delete records no outcome, because nothing happened, so the causality views gained an Identity not deleted step in the Identity column carrying the reason ("an authoritative source is still connected"), which is the one thing they could not previously show. The rule that decided it is available underneath, collapsed, as Deletion Rule in force at the time. The "what happens next" note for an import-detected deletion moved to page level, being forward-looking rather than causal, and the housekeeping note was removed outright: it restated what the causality panel above it already showed. The section's heading had been promising a Deletion Rule explanation while hosting increasingly unrelated notices. (#1223)
- π₯οΈ Flow view's Source column is now captioned "what happened" rather than "what came in". It has shown more than imports for some time.
- π₯οΈ The causality summary sentence, the Flow view's source card and the Graph's source node now name a record without its external id trailing in brackets. The identifier is on the record itself one click away, and in running prose or inside a chip it was more than was asked for; in the Flow view it pushed the name out of the chip entirely. The Timeline has room to be precise and keeps showing both.
- π₯οΈ A tab bar with only one tab is no longer shown. It offered nothing to click and spent a band of vertical space repeating the page heading; its content now sits where it would have with no tabs at all. This applies wherever a page's tabs are conditional.
- π The background batch that deletes identities once their grace period expires is now called Scheduled Identity Deletion rather than "Metaverse Object Housekeeping", on the Activity itself and in the Activity list's filter. The old name described which internal process ran rather than what happened, and read as a mouthful of vocabulary in the one place an administrator most needs a plain answer. Activities recorded before this release keep the name they were written with.
- π₯οΈ Flow view's connectors meet each block on the middle of its header row rather than a fixed distance down from its top, which missed the middle of every block and by a different amount depending on the kind. The dot at the destination end is larger, and a Connected System group's coloured accent now runs the block's full height instead of starting below its header, which also brings the header's name into line with the events beneath it. Where a lane has no events, the "No Identity changes" note now has a ground of its own like every block around it, so a connector crossing that lane breaks around the words rather than being drawn through them. (#1087)
FixedΒΆ
- π The home page's Run your first synchronisation step now ticks when you run a synchronisation. It was satisfied only by a Schedule having fired, so an administrator who ran a Run Profile by hand from Operations, which is how a first synchronisation is normally run, was never credited with it; on a deployment whose only Schedule is disabled the step could never be completed at all, leaving the Getting Started checklist on screen permanently. Running a Run Profile now completes the step, whether you started it yourself or a Schedule did, and whether the run succeeded, failed or is still going. Defining a Run Profile is still not the same as running one. (#1482)
- π The confirmation shown when you deselect a Connected System Object Type now states what deselecting actually does. It said the objects already imported from the type become obsolete and whatever they are joined to is deprovisioned, which is what happens when you deselect a Partition or a Container, and is not what happens here: deletion detection only looks at selected Object Types, so a deselected type's Connected System Objects are never revisited. They stay joined to their Metaverse Objects and keep contributing the values they last imported, which stop being refreshed. The confirmation now says so, and says plainly that nothing is obsoleted and nothing is deprovisioned, so the setting is not read as a way to take objects out of management. Whether it should behave that way is being decided separately. (#1474)
- π The built-in Words Example Data Set no longer ships
Jalapeã±O, an encoding-damaged spelling ofJalapeΓ±othat generated example objects could pick up as a value. (#1287) - π An instance that stops part way through creating its built-in configuration now recovers on the next start, instead of failing to start ever again. Seeding is safe to repeat: every step checks what the database already holds rather than assuming it holds nothing, so recovery no longer means resetting the schema and starting over. (#1287)
- π A Connector introduced in a future release will reach instances upgraded to it, not only newly installed ones. Built-in Connectors were only ever registered while an instance was setting itself up for the first time, so an upgraded instance would silently lack any Connector added since it was installed; they are now reconciled on every start. (#1287)
- π An Object Matching Rule added in the portal now names the Metaverse Object Type it searches, and matches. Simple mode rules created through the Matching tab were stored without one, and the synchronisation engine skips a rule that does not say where to look, so a Connected System whose rules were all created that way matched nothing at all: every account that should have joined an existing identity projected a new one instead, silently. Creating or updating a rule that could never match is now refused with the reason, and the Matching tab names any such rules already stored so they can be corrected. Rules created through the REST API or PowerShell were never affected. (#1458)
- π PowerShell cmdlets that accept a name where the API wants an id (
-MetaverseAttribute,-ObjectType, Connected System, Example Data Set and template names) now resolve against the whole collection. The internal resolvers read a single unpaged response, which the server caps at its default page size, so a name beyond the first page (attribute 26 of a stock deployment's 97, for example) failed with "not found" even though it existed. Every resolver now pages through the full list. (#894) - π Two Object Types in one Connected System can now share an anchor value space, which is exactly what a table and a view over it do: the view has the table's keys by construction. Import reference resolution indexed anchor values with no Object Type dimension, so the first shared value killed the whole Full Import with a duplicate-external-id error naming neither Object Type, and a reference was assumed to point at an object of the referencer's own type. Resolution is now scoped by Object Type end to end: where the Connected System's schema declares which Object Type a Reference attribute points at (the JIM SQL Connector's
referencesObjectType), the reference resolves within that Object Type alone, and the declared target is shown read-only on the Schema tab, the REST API andGet-JIMConnectedSystemObjectType; where nothing is declared, a value held by exactly one Object Type resolves as before, and a value held by more than one is reported per the Connected System's Unresolved Reference Handling naming the candidates, never resolved by guessing and never a run failure. A genuine duplicate anchor within one Object Type still fails fast, and the error now names the Object Type, the attribute and the value. Also fixed on the way through: references to objects imported in an earlier run now resolve whatever the anchor's data type (the database fallback compared text only, so a reference to a number- or GUID-keyed object never resolved there), and a run whose unresolved references spanned two Object Types looked them all up against whichever type came first. (#1285) - π A Sync Preview now honours Attribute Priority, so it answers for the synchronisation it predicts. Where an attribute has more than one contributing import Synchronisation Rule, the preview evaluated flow with no notion of which rule owns the value: a losing contribution was shown overwriting the attribute when a real run refuses it, and a rule with nothing to contribute was shown clearing an owner's value when a real run leaves it alone. Both the per-object and full-system previews are affected. (#1441)
- π The causality views on a Run Profile execution item now nest Provisioning and Pending Export outcomes beneath the Attribute Flow that produced them, rather than beside it, so an export reads as caused by the flow. Only new runs are affected. (#1428)
- π An execution item's Attribute Flow count now includes references resolved at the end of a batch. A reference to an object processed alongside it (a manager, a group member) resolves only once both identities exist, and the count stopped short of that. (#1428)
- π The JIM SQL Connector now binds every date and time it sends to Microsoft SQL Server as
datetime2. Left to the driver's default, a .NET date and time is bound as the legacydatetimetype, which rounds to a 1/300-second grid (.000, .003, .007), so adatetime2value JIM bound was moved by up to two milliseconds on the way in. A Watermark Column Delta Import therefore re-read the most recently changed row on every run (its watermark rounded down) or, worse, could silently skip rows committed inside the gap (rounded up), and a value exported into adatetime2column lost its milliseconds. Oracle was never affected: ODP.NET binds a date and time asTIMESTAMP, and that is now pinned by a test. (#170) - π A finished import's Activity now describes the whole run. The counters were left at whatever the import's last internal step set them to (the final flush of results, usually nothing) and its label stayed as the message, so a completed Full Import read "0 / 0" and "Recording results" on the Activity list for ever after, however many objects it had imported. The Activity now carries the objects read as both its expected and processed counts, and a message in the same shape as a synchronisation's or an export's: "Import complete: 1,000,000 objects (999,880 created, 0 updated, 120 errors) in 18 min 13 sec (avg 915 obj/s)". (#170)
- π The JIM SQL Connector no longer fails a row whose zoneless date or time falls in the hour the clocks skip when daylight saving starts in the Connected System's Database Time Zone. Such a wall-clock time never happened, but a column can hold one (a last-modified column defaulted to "now" by a server whose own clock is UTC, a value migrated in from another zone), and a Full Import against a Sydney-zoned database of 500,000 employees reported 120 of them as unreadable ("The supplied DateTime represents an invalid time"). The value is now read with the offset in force just before the clocks moved, which is where the clock jumped to, as PostgreSQL and Java read it; a time in the hour the clocks repeat when daylight saving ends keeps its standard-time reading. (#170)
- π The JIM SQL Connector's Delta Import Mode no longer demands a
watermarkColumnor achangeLogon Object Types that are not selected for synchronisation. Choosing Watermark Column or Change-Log Table mode refused the save unless every Object Type in the Object Types document was equipped for it, so a database JIM both imports from and exports to needed a last-modified column, or an empty change-log table, on every table JIM only ever writes to. An unselected Object Type takes no part in any Run Profile, so a Delta Import cannot leave its objects to drift; the requirements now apply to the selected Object Types only. Selecting an Object Type that lacks what the configured mode needs is refused at the point of selection (on the Schema tab, over the REST API and from PowerShell), naming the Object Type and the fix, and a Delta Import that reaches such configuration anyway still fails fast rather than reading around it. (#1424) - π A Connected System whose outbound Synchronisation Rules export different Object Types for different people no longer completes every synchronisation with warnings. When two Rules with non-overlapping Scoping Criteria share one Connected System, each person correctly holds an object of the type their Rule provisions; the other Rule, finding them outside its own scope, then checked whether it had anything to deprovision, found the other Rule's object occupying the system's one slot, and reported it as a conflict, one warning per correctly provisioned person, on every run. An administrator could never see such a configuration complete cleanly, and real problems had to be found among the noise. Deprovisioning an object is always the job of the Rule that provisions its type, so this encounter is now recognised as the configuration working as designed and passed over quietly. The genuine misconfiguration, two overlapping Rules contending for the same person's slot, is still reported exactly as before. (#1399)
- π Exporting an object that references another whose database-generated key is large, such as a row keyed by an Oracle
NUMBER(10)identity column, no longer fails the object. When JIM resolved the reference to the object it points at, it read the target's key from only some of the places a key can be stored: a key held as a large whole number or as a high-precision decimal was missed, the reference was marked resolved with no value at all, and the export then failed at the target database complaining the reference carried nothing to write, on every affected object, every cycle. Manager hierarchies were the visible casualty: only the people with no manager were ever created. Objects whose keys are text, GUIDs or small whole numbers were unaffected, which is why SQL Server tables keyed byINTexported cleanly while Oracle tables keyed byNUMBERdid not. A reference whose target genuinely holds no key yet, because its own export has not been confirmed, is now held back and retried rather than sent to fail; the same reading gap is also closed where JIM works out which references to withdraw when an object is deleted. (#1398) - π An object whose reference cannot be resolved yet no longer waits, silently, for the reference to be written before anything about it is. A Pending Export with an unresolved reference (a manager not yet provisioned, a group member not yet in the target) was held back whole, so an account whose manager was out of scope for the Synchronisation Rule was never created at all, and nothing on the Activity said why: four of forty-three people in a manager hierarchy simply never appeared in the target, run after run. JIM now writes everything it can immediately (the row is inserted without its reference columns; a group gains the members it can resolve) and keeps only the reference values still owed pending, filling them in on a later run as before. It also tells the two reasons apart: a reference that is only waiting for the referenced object's own export to land is ordinary ordering and stays quiet, while a reference to an object that has no Connected System Object in the target at all is reported per the Connected System's Unresolved Reference Handling, exactly as an import reports its own (Error marks the object's Run Profile execution item naming the attribute and the referenced object; Warn summarises the count on the Activity; Ignore logs only). The Pending Export detail page,
Get-JIMPendingExport -Idand the REST API now list each reference still owed with its reason. A partial write the target refuses, such as a reference column declaredNOT NULL, fails that object with an ordinary export error. (#1398) -
π Provisioning into a database table whose primary key is a whole number no longer duplicates the exported rows on every synchronisation cycle. After a successful export, the database-generated key was stored on the Connected System Object as text whatever the anchor attribute's declared type, where the confirming import's typed comparison could not see it; the import then staged a second, typed copy of the anchor, the object ended up holding two values for its External ID attribute, and reading it killed the run with an unreported exception. Because the import never completed, nothing exported was ever confirmed, so the next cycle exported the same people again: one duplicate row per cycle in the target database, with the run's failure naming neither the object nor the cause. The key is now stored in the slot the anchor's type declares, and an object holding two External ID values, however it got them, is reported as an error against that object on the Activity while the rest of the run continues. Text and GUID anchors, such as LDAP's, were unaffected. (#1386)
-
π A SQL or Oracle value carrying a fraction is no longer silently rounded when the attribute it flows into holds whole numbers. It was rounded without comment, so
0.6was imported as1, and nothing on the Activity recorded that the value had changed. The object is now reported with an error naming the column and offering both remedies (record the attribute as a Decimal, or correct the value), and the rest of the run continues. A value that is a whole number carried as a decimal, which is how Oracle returns everyNUMBER, is unaffected and still imports. A value too large for the attribute's type was already reported this way. (#1354) - π A data type an administrator chose for a Connected System attribute now survives a schema refresh. A refresh restated every attribute's type from what the Connector discovered, silently undoing the override; the JIM File Connector has always let an administrator set these types, so any deployment that did so was exposed. The failure was quiet and could corrupt values: an Attribute Flow's types are checked when the mapping is created rather than on every run, so a Synchronisation Rule validated against the chosen type carried on running against the reverted one, and the flow, which selects its behaviour from the source type, then wrote the value into the wrong place on the Metaverse Object. It also sidestepped the rule that an override is refused once an attribute holds values. A refresh now restates only what the Connector discovered (writability, plurality, description) and leaves a chosen type alone. Attributes whose type nobody has overridden are unaffected and continue to follow the Connector. (#1354)
- π A synchronisation run no longer dies with an unreported database error when two outbound Synchronisation Rules target the same Connected System for the same Metaverse Object. A Metaverse Object can have only one Connected System Object per Connected System, so both Rules resolved to that one object and each tried to stage a Pending Export against it; the run then failed on a duplicate-key violation partway through, abandoning every object still to be processed, with nothing on the Activity explaining why. JIM now detects the clash while evaluating exports and reports it against the object as a Run Profile Execution Item naming the Synchronisation Rule and the Connected System Object Type already occupying the slot, and the rest of the run continues. This also closes a latent data-integrity risk: where the Rule targeted a different Connected System Object Type than the object already present, JIM would otherwise have written that Rule's attribute values onto an object of the wrong type. Two configurations reach this, and the message names both remedies: overlapping Scoping Criteria on two outbound Rules into one Connected System, and a Connected System that both imports one Object Type and exports another for the same Metaverse Objects. (#1331)
-
π A theme's colours now update when JIM is upgraded. The theme stylesheet was the only one served without a version, so a browser that had already seen it kept its copy indefinitely and carried the old colours across an upgrade that changed them, with nothing to indicate it. Its address now changes whenever its contents do, as every other stylesheet's already did.
-
π Outlined and text buttons in the primary colour are now legible on the Black Dark theme, which took the accent straight where the other dark themes lighten it. The label read 4.9:1 and the count chip inside it 4.4:1, under the 4.5:1 an accessible reading needs; they now read 6.3:1 and 5.6:1.
-
π Outlined and text buttons in the primary colour are now legible on the light themes. Their labels took the theme's accent straight, which on a pale page left the darkest of them at 2.8:1 and three of the six light themes below the 4.5:1 an accessible reading needs; they now use a darkened shade, measured at 5.3:1 or better on every one. The dark themes already lightened their labels for the same reason and are unchanged. Affects Black Light, Blended Nav Light, Future Minimal Light and Navy Light (O5).
-
π The Created and Updated chips on a Connected System no longer turn near-white, and unreadable, when the pointer passes over them on any of the dark themes. Their hover state asked for a colour none of JIM's themes set, so it came back as a fixed light grey whatever theme was in use, leaving pale text on a pale background: 1.2:1, against the 4.5:1 an accessible reading needs. The hover now lifts the chip away from its own surface, so it reads on every theme.
-
π Selections now show in the colour of the theme in use. The tint marking a selected Container in Partitions & Containers, an excluded Container beneath it, the Attribute Flow being edited in a Synchronisation Rule's priority list, and the row being dragged there, were all painted in one fixed violet rather than the theme's own accent, which on the dark themes was faint to the point of being hard to see at all, and on a theme whose accent is a different colour entirely simply looked wrong.
-
π A selected Object Type on a Connected System's Schema tab is now marked as selected. Its card was meant to carry the accent colour on its border and a tint behind it, and did neither: the styling was written so that it could never apply to the card. Selection was still shown by the switch on each card, so nothing was unusable, only harder to pick out while filtering a long list of types.
-
π The object counts on a Connected System's Connector Space and Pending Exports buttons are now legible. They were painted a shade darker than the button they sit in, on a tint that belonged to no theme JIM ships, which on the darker themes left the number below the contrast a person can comfortably read: on the default dark theme it measured 3.4:1 where 4.5:1 is the accessible minimum, and now measures 7.0:1. The count takes its colour from the button it labels, so it stays legible on every theme.
-
π A link into a list now opens at the row it names. The position in the address bar was worked out from the row height the list asks for rather than the height a row occupies once padding and content land on it, so a link to row 200 opened at about row 178, and further out the deeper into the list it pointed.
-
π A table inside a page no longer collapses to a few rows on a page long enough to scroll. It sized itself against the viewport using a measurement that double-counted how far the page had been scrolled, which the lists you navigate to never showed, because those pages do not scroll.
-
π The Pending Deletions summary now counts every object awaiting deletion, not the first hundred. Deprovisioning, Awaiting Grace Period and Ready for Deletion were worked out from a single page of a hundred objects, so on any deployment with more than that the three cards under-reported, always summing to a hundred while the total beside them read the true figure. The
pending-deletions/summaryREST endpoint, andGet-JIMPendingDeletion -Summarywith it, answered from the same hundred and are corrected too. The counts are now taken across the whole match set by the database, and honour the Metaverse Object Type filter on the page, so the cards always describe exactly the objects listed beneath them. -
π My Activity now takes effect when selected from the Activity page. It changed the address without changing the list, so you were left looking at every user's Activities while the navigation said otherwise; coming to it from any other page had always worked. Two smaller faults on the same view go with it: the navigation no longer highlights Activity and My Activity at once, and the Initiator filter, which on that view can only ever mean you, is now disabled rather than offering a choice that changes nothing.
-
π Returning to a stale sign-in page no longer shows an unhandled error. A restored browser tab, the back button or a refresh of a failed sign-in re-submits a single-use sign-in code the identity provider has already spent, which previously surfaced as an exception page; JIM now restarts the sign-in cleanly and returns you to where you were headed. Failures a retry cannot fix, such as the identity provider refusing the user, still surface loudly, and every failed attempt is still recorded as a security Activity.
-
π A hierarchy refresh that could not finish counting a partition's objects now says so. Container object counts are deliberately discarded when counting is cut short, because figures short of the truth read as complete and understate what deselecting a Container costs; they were discarded silently, which left the tab looking exactly like a Connected System whose Connector cannot count at all. The two need telling apart: only one of them is fixed by raising the directory's size limit or narrowing the selected Object Types. The refresh now completes with a warning naming the affected Partitions and what stopped the count, and a refresh that hits more than one problem reports all of them rather than only whichever happened last. (#1276)
-
π The first Retrieve Hierarchy on a newly created Connected System now keeps the Containers it discovers. It found the whole hierarchy, reported every Container as added, and then deleted every one of them before saving, so only the Partitions persisted and the tab offered nothing to select; pressing the button a second time worked, because by then the Partitions existed and took a different path. The refresh reported success either way, so there was nothing to say the first press had achieved nothing. A Connected System whose Partitions were all new lost its entire discovered Container hierarchy for that pass. (#1369)
-
π Partition discovery against Active Directory and Samba AD no longer fails with an access denial on a connection that is authenticated and working. A directory can return a referral to another server alongside a search's results, and the platform LDAP client was following it on a new connection carrying none of the credentials JIM bound with. Any directory that refuses anonymous reads, which Active Directory does by default, then refused that read, and the refusal surfaced against the original search rather than against the referral, so the error named the wrong thing. JIM now declines referrals outright, and the LDAP Connector documentation says so. Following them properly, on connections JIM authenticates and reports, is tracked as its own feature. (#1352)
- π The contributing Synchronisation Rule recorded against a Metaverse Attribute value now follows the rule that wins Attribute Priority, rather than the rule that happened to write the value first. Where two contributors hold the same value, the winner's contribution changed nothing and so left the value attributed to the other rule, and that record is what JIM reads to decide who currently owns an attribute. Two consequences, both reachable through ordinary administration: deleting a contributing Synchronisation Rule left its values with no contributing rule at all, which is how the value is recorded when JIM manages it internally, and no later synchronisation repaired it, so the priority order stopped being enforced for that attribute and Drift Correction could no longer identify its owner; and a lower-priority source that agreed with the winner remained on record as the owner, so its next change overwrote the higher-priority source's value. Both now correct themselves the next time a contributing system synchronises, whether or not the value changes. (#1292)
- π The container images now build on patched .NET 10 base images, clearing CVE-2026-62901.
- π Deleting an Attribute Flow from a Synchronisation Rule over the REST API or with
Remove-JIMSyncRuleMappingnow works. Every attempt failed with an internal error, so an Attribute Flow could only be removed from the portal. - π Moving a Container in a Connected System no longer removes it from JIM along with its selection, which took the objects beneath it out of scope and obsoleted them on the next Full Import. A moved Container is now filed under its new parent. (#1318)
-
π Deletion detection now works for an Object Type anchored on a 64-bit whole number (a
bigintidentity column, for example). It has never worked: an object removed from the Connected System was recorded as "not found", the import completed successfully, and the object stayed in the Connector Space indefinitely, joined to its Metaverse Object. Nothing reported it, because a missing object and an unrecognised anchor type were indistinguishable to the code that decides. After upgrading, run a Full Import against any Connected System whose Object Types use such an anchor: deletions that happened while this was broken are detected on the next Full Import, and may make Metaverse Objects eligible for deletion in the synchronisation that follows. Anchors of other types were unaffected. An anchor type deletion detection cannot handle now fails the run rather than passing silently. (#1283) -
π A table anchored on a decimal key can now be imported. Oracle's
NUMBERis read as a decimal, so this covers the ordinary sequence-backed primary key: a Full Import previously read the rows correctly and then failed outright in deletion detection, and the objects were never indexed, so every import created duplicates instead of recognising what JIM already held. Anchors are now matched by numeric value, so a key stored as4200.00and read back as4200is one object rather than two. (#1283) -
π An export no longer fails when Drift Correction and a fresh Metaverse value are staged against the same attribute of the same object. JIM combined the two into one Pending Export that both set the attribute's new value and removed the old one; the directory applied the set first, so the removal then referred to a value that was already gone and the whole change was rejected. The export retried until it exhausted its attempts, leaving the object uncorrected. A new value for an attribute now supersedes anything else staged for it. (#1199)
-
π An import Synchronisation Rule's Scoping Criteria are now honoured when its Attribute Flows run, not only when it joins or projects. A Connected System Object that was in scope of any one of a system's import rules previously had every one of that system's import rules flowed into it, including rules it was explicitly scoped out of, so a narrowly scoped rule contributed its values to every object rather than to the subset it named. This is what gives one system authority over a defined subset of objects while another system holds the rest, so it could not be expressed until now, and a deployment that configured it got the opposite of what it asked for. A single import rule per system, which is the common arrangement, is unaffected. Two import rules on one Connected System contributing to the same Metaverse Attribute in the same synchronisation pass also no longer both write: the winner now replaces the loser's value instead of appending beside it, which on a single-valued attribute left two values. (#1199)
-
π Adding, removing or retargeting an inbound Attribute Flow in the portal now maintains the target Metaverse Attribute's priority order, as the REST API and PowerShell already did. A new Attribute Flow lands at the bottom of the list so it never wins resolution until promoted, and one moved to a different attribute arrives at the bottom rather than carrying its old rank across. (#1199)
-
π An export is no longer permitted into a Container narrowed to One Level, or anywhere beneath one. Container Scope narrows what an import returns, and the export scope guard still assumed a whole subtree, so JIM could write an object where its own next import would not find it: the change went unconfirmed, the Full Import treated the object as deleted, and the following synchronisation disconnected it. The same rule now answers the question for import search scope, export, and the partition and container preview. (#1251)
-
π Delta Imports from OpenLDAP and other changelog-based directories no longer bring in objects a Full Import would never have returned. Those directories publish one directory-wide change log rather than letting JIM search per Container, and JIM was filtering its entries by Partition alone, ignoring which Containers within it were actually selected. A Delta Import could therefore import an object from a Container nobody had selected, which the next Full Import would then mark obsolete. Both the changelog and accesslog paths now apply the same Container selection a Full Import uses, and report how many entries they skipped. Active Directory was unaffected, as its Delta Import searches each selected Container directly. (#351)
- π Turning provisioning off on an Export Synchronisation Rule now switches its initial password off with it. Only a newly created account has never had a password, so a rule that creates none can never deliver one; the setting stayed on regardless, reading as configured while being unable to run, and the REST API refused the same combination outright. Any accounts parked waiting on those settings stop waiting. Turning provisioning back on brings the panel back with its settings intact, switched off. (#1273)
- π The portal no longer lets you save initial password settings the REST API would refuse. A Synchronisation Rule whose settings cannot produce a password the Connected System will accept, or which is set to use one password for every account and has none, now lists the reason above Update Synchronisation Rule and disables it, instead of saving quietly and parking every account the rule went on to provision. The panel has always said what was wrong; nothing acted on it. A static password the Connected System would refuse is no longer taken onto the rule at all: it is checked as you type it, and the stored password is left exactly as it was, which is what the REST API has always done with one. (#1273)
-
π The Connector Space now shows, searches and sorts on the External Id of every Connected System Object, not just those with a text anchor. Active Directory and Samba AD objects, anchored on
objectGUID, previously showed a blank External Id and could not be searched for. (#1286) -
π Containers discovered from a directory that publishes no name of its own are now named after themselves rather than after their whole address. Only Active Directory supplies the
nameattribute JIM asked for; against OpenLDAP and other directories it was absent and JIM fell back to the entire Distinguished Name, so every row of the Container tree readou=Sales,ou=Corp,dc=example,dc=cominstead ofSales, restating in text the ancestry the tree already draws and burying the one component that tells two Containers apart. Containers now take the value of their leaf component, which is how Containers created during an export have always been named, so the two can no longer disagree about what the same Container is called. Distinguished Names are unchanged and still identify Containers everywhere JIM records them; a directory that does publish its own name still wins. Refresh the hierarchy on an existing Connected System to rename Containers already discovered. -
π Exports are no longer refused to objects that are plainly inside a selected container. Container membership is now compared component by component rather than character by character, so a Distinguished Name written with the optional whitespace RFC 4514 permits after its separators (
CN=a, OU=Users, DC=example, DC=com, which some directories emit) is recognised as being withinOU=Users,DC=example,DC=com. The same comparison closes the opposite error, whereOU=UsersArchivewas read as sitting insideOU=Users. (#1251) -
π A Schedule Execution containing a parallel step no longer reports more steps than it has to run. Its progress counts two things: the position it has reached counts step groups, where steps running concurrently are one position, but the total was counting Schedule Step rows, so a Schedule whose six rows form five groups reported "step 5 of 6" as it finished and never reached its own total. Automation reading a Schedule Execution's progress from the REST API sees the corrected figure. Executions that have already run keep the total recorded at the time; the number of groups they had was never stored, and inferring it from what they left behind would replace a wrong figure with a guess.
- π Deleting a Connected System that still had a queued Clear Connected System Objects task no longer empties the Operations queue. Naming that task looked its Connected System up and required it to exist, so one orphaned row failed the whole read: every other task in the queue disappeared too, including the ones an administrator would have needed to see to work out what had happened.
- π A queued task whose configuration has since been deleted now names itself after what it was going to act on, rather than reporting an error. Deleting a Connected System takes its Run Profiles with it while leaving any already-queued task behind, and such a row read "Run Profile not found!", which looks like a fault in JIM rather than a row describing something that is no longer there. Clear, delete, synchronisation and example data tasks now all name themselves the same way.
- π The Operations queue no longer opens a separate database connection for every row it displays. It re-reads on every progress notification, so a busy queue was making a connection per task per update, on top of reading that second connection's settings from the container's environment rather than from the connection the rest of the read was already using. Reading an Example Data Template's summary did the same thing and no longer does.
- π A Connected System's settings can now be saved when a Connector offers an either/or choice that only applies to some configurations: the choice is now enforced only where the setting governing it says it applies, and a setting whose governing setting is itself hidden is hidden too, rather than being demanded on the strength of a value left behind by an earlier configuration.
- π An export no longer writes objects outside the containers selected on a Connected System. Container selection applied only to import, so an Export Attribute Flow that moves an account into an unselected container (moving disabled accounts to their own organisational unit, for instance) wrote it somewhere JIM could not read back: the change was never confirmed, the next Full Import treated the object as deleted, and the following synchronisation disconnected it and then orphaned or re-provisioned it, churning objects JIM had exported itself. Such an export now fails with an error naming the Distinguished Name and what to do about it, and the rest of the run proceeds. Containers the Connector creates during the run are in scope, since JIM selects them as soon as it ends. Behaviour change: if you deliberately export into a container you do not import from, select it before upgrading, or those exports will start failing. A Connected System with no container selections is unaffected. (#827)
- π Renaming or moving a container in a directory no longer silently takes it out of import scope. A container's identity was its Distinguished Name, which both operations rewrite, so a hierarchy refresh read the container you had selected as removed and an unfamiliar one as added; the replacement arrived unselected, and the next Full Import treated every object beneath it as deleted. JIM now identifies containers by the directory's own immutable identifier (
objectGUIDon Active Directory,entryUUIDon OpenLDAP), so a rename is reported as a rename and your selection survives it. Containers selected before this release adopt their identifier at the next hierarchy refresh and continue to match on Distinguished Name until then. (#827) - π A container created in a directory since the last hierarchy refresh now appears on the Partitions & Containers tab, so it can be selected. It was reported as added and then removed again by the same refresh, leaving no way to bring a new OU under management. (#827)
- π Deselecting a partition now takes effect on every Run Profile, and a Run Profile it leaves inoperable says so. Previously a partition's selection was honoured only by Run Profiles that target no partition in particular; one that named the partition kept importing it regardless, so removing a partition from management did nothing for some Run Profiles and, on a Full Import that targets no partition, obsoleted every object in it. Nothing warned either way, because the only guard asked whether the Connected System had anything selected at all, which passes while any other partition remains selected. A Run Profile that targets a deselected partition, or one no longer present in the directory, is now refused with an error naming both, and is marked Not selected on the Run Profiles tab, in the REST API (
targetsDeselectedPartition) and inGet-JIMRunProfile. (#827) - π An export now stops showing the Connector's step as running once the Connector has finished with it. The step was left lit until the run entered its next one, so the rail claimed objects were still being written while the run was finalising its results, and the Connector's step absorbed the time that finalising took; on a large export that made the step an administrator would look at first the one least worth trusting. Imports were corrected in the same way already. (#1214)
- π An import no longer describes the same work three times at once. A Connector's steps now finish the moment its call returns, instead of "Fetching objects" staying lit for the whole time JIM then spent matching what it had been handed; that matching is now a step of its own, "Processing imported objects", shown inside "Importing objects" because a Connected System that returns a page at a time alternates between the two. The steps inside the running step have also moved beneath the line naming it, so each reads after the thing it belongs to rather than above it. (#454)
- π An import against a Connected System JIM connects to now shows "Importing objects" as the step running while it reads them, instead of showing every step as either finished or still to come for the whole time objects are arriving. The step was entered before the connection was opened, so it was closed out milliseconds later and never reopened; a run that spent minutes reading a directory recorded that step as having taken four milliseconds. (#454)
- π A Connected System's settings can now be saved after changing a setting that governs which other settings apply. Choosing a different value in a drop-down such as the SCIM Connector's Authentication Method hid the settings the previous value needed, but left their "is required" errors behind, attached to whichever setting had moved up into their place. The form stayed invalid and Save Settings could never be enabled again, so a SCIM Connected System could only be configured with OAuth 2.0 Client Credentials. The settings shown were right; only the errors underneath them belonged to settings that were no longer there.
- π A SCIM service provider's refused certificate is now reported as a certificate problem wherever it surfaces. Testing a SCIM Connected System's settings showed an unhandled error instead of the certificate card, and the REST settings endpoint answered with a generic internal error rather than naming the certificate. An import or export that failed on the certificate reported an opaque transport error too, so the failed Activity carried nothing to act on; schema discovery, imports and exports now all show the certificate, as LDAP runs already did. (#545)
- π Changing which containers a Connected System imports from now asks you to confirm the change before saving, as every other synchronisation-affecting edit does. Selecting or deselecting a container saved in silence, and the change was then recorded in the configuration change history as synchronisation-affecting, so the confirmation you were shown and the record kept afterwards disagreed. Deselecting one is now treated as destructive, matching deselecting a partition or a Connected System Object Type, and says what it will do to the objects already imported through it. A container renamed in the directory is unaffected.
- π A confirmation dialog now describes a whole item added to or removed from a list (a container, a Run Profile, an Object Type) as one change, rather than listing each of its properties separately going to or from nothing. Where the removal is the destructive part, the dialog now says so ("Removing this takes objects out of scope") instead of calling the removed item a property.
- π Problems a Connector reports with an individual imported object now appear on the Activity instead of being discarded. A row whose value would not parse is imported with the values that did parse and the failure is reported against that object; an object the Connector could not identify at all is reported and skipped. Previously none of it was recorded anywhere, so an import of malformed data finished looking clean. (#637)
- π A Full Import no longer fails outright when a single imported object names an object type that is not in the Connected System's schema. The run now reports that object and imports the rest. (#637)
- π A setting withdrawn from a Connector no longer lingers on Connected Systems that already held a value for it. The setting was being detached from its Connector Definition rather than deleted, leaving the row behind with the saved values still pointing at it. (#1132)
- π Saving an LDAPS Connected System's settings, retrieving its schema, or retrieving its hierarchy no longer hangs indefinitely in the portal when certificates are present in Admin > Certificates. Reading the certificate store blocked the page's own thread waiting for work that could only run on that same thread, so the operation never finished and the page sat on its progress spinner. (#1132)
- π Retrieving or refreshing a Connected System's hierarchy from the portal no longer fails with a database error whenever it discovers a new partition or container. Saving the newly discovered items also marked the system's Connector Definition for insertion, and the save was rejected because that Connector Definition already existed. Retrieving a hierarchy through the REST API or PowerShell was unaffected.
- π A schema or hierarchy retrieval that fails now records the failure against its Activity, which finishes as failed and carries the reason. Previously the Activity was left in progress for ever with nothing recorded against it, so the Activity log showed the operation as still running and gave no indication of what went wrong.
- π Importing a schema through the REST API or PowerShell now leaves the same configuration behind as the same import through the portal. Where a Connected System offers exactly one object type and JIM is discovering it for the first time, that object type is selected automatically; only the portal did this, so the two surfaces produced different configuration from identical input.
- π The REST API's pagination depth limit now protects every paginated endpoint. Around half of them, including the Connector Space, Pending Export, attribute value and deleted object lists (the largest reads JIM performs), accepted any page number at all, so a request for a wildly out-of-range page still asked PostgreSQL to walk to that offset before returning nothing. (#487)
- π
-All -Forceon the paginatedGet-JIM*cmdlets no longer fails part-way through with an HTTP error when a result set is larger than the API will let you page through. It now stops at the API's maximum retrieval depth with a warning saying so, after emitting everything it could retrieve. (#487) - π
Get-JIMSyncRulenow returns every Synchronisation Rule rather than only the first 25, paging through the full result set. - π Changes to a Connected System's connector settings, and to its Simple Mode Object Matching Rules, are now classified in the configuration change history instead of being recorded without a classification. Because the changed-since indicator reads that classification, those changes were not raising it; a Connected System could have a pending settings change and still report as up to date.
- π Adding or removing a Connected System from a Metaverse Object Type's deletion trigger list is likewise now classified, and recorded as destructive.
- π Saving a Metaverse Object Type's Deletion Rules now works. It previously failed with a database error on any object type that had attributes bound, which is every real one: the save re-inserted the type's existing attribute bindings instead of leaving them alone. Nothing was written, and the change history recorded the attempt with no detail.
- π Piping a Connected System into
Get-JIMSyncRule, as its documentation has always shown, now works instead of failing to bind. - π The Pending Exports list can once again be sorted by Source Identity, and searching it by an Identity's name once again returns matches. Both silently matched nothing.
- π The causality view no longer prints an object's identifier twice, as
<id> (<id>), when the object carries no name attribute at all. - π Selecting a Partition for a domain the connected Active Directory / Samba AD domain controller does not host now fails the import with clear guidance, instead of silently importing nothing. Partition discovery lists every domain in the forest, but a domain controller only holds its own domain's naming context and does not chase referrals to other domains. (#230)
- π
Start-JIMSchedule -Waitnow waits for the run to finish. It compared the returned status against a number, but the API reports the status by name, so the comparison was satisfied on the first poll and the cmdlet returned immediately with the run still queued. (#1196) - π Re-running Schema Import on a Connected System whose directory schema gained new attributes no longer fails with a duplicate key error. A failed Schema Import also no longer partially applies: previously, recording the failure could flush the half-merged schema to the database alongside the Activity's error, so an import that reported failure had still changed the schema. (#1171)
- π The portal's stylesheets and scripts now carry a content-based version stamp, so after a JIM upgrade your browser fetches the new assets immediately instead of potentially serving a stale cached copy (which could leave the interface looking or behaving as it did before the upgrade until a manual hard refresh).
- π A Pending Export link in the causality view no longer leads to "Pending Export not found". Pending Exports are removed once they have been exported, while the causality record naming one is permanent, so the link died as soon as the export ran. The link now points at the individual Pending Export while it is still queued and at the Connected System's queue once it is not, and the Pending Export page explains that a link which no longer resolves means the change reached its system rather than that something went wrong. (#1087)
- π A newly created Identity is no longer described as
00000000-0000-0000-0000-000000000000in the causality view. Causality outcomes are recorded before the Identity is saved, so asking it for a label fell back to an id it had not been given yet, and the pass that fills in the real details afterwards treated the all-zero id as a name already supplied and left it alone. (#1087) - π The Pending Deletions page and API now show identities scheduled for deletion by an authoritative source disconnecting. Previously they only listed identities whose last connector had gone, so authoritative-source deletions awaiting their grace period were invisible until they happened. (#119)
- π JIM no longer pins a domain controller it cannot reach. A directory advertises its own name, and that name does not always resolve from where JIM runs: split-horizon DNS, a directory reached through an alias or an address, and DMZ deployments all produce one that does not. Pinning it was unrecoverable rather than merely wrong, because clearing the pin on failure only led to the same unreachable name being rediscovered and pinned again on the next run, so every Active Directory or Samba AD run failed from the second connection onwards. JIM now proves a newly discovered domain controller reachable before pinning it, and where it cannot, carries on via the connection that already works and states on the Activity which name it could not reach. An established pin costs no extra connection. (#230)
- π The causality view's Technical names toggle now reaches the two places it was skipping: the summary sentence above the views, and the source row that opens all three of them. Both kept their plain-language stand-ins ("the record", "Identity") whatever the toggle said, and between them they are the first two things read on the page, so the toggle looked as though it had failed. They now say "the Connected System Object" and "Metaverse Object" alongside the rows beneath them. (#1087)
SecurityΒΆ
- π Values imported from connected systems (Distinguished Names, identifiers, CSV fields) can no longer forge or corrupt service log entries via embedded line breaks; all such values are now sanitised before logging across the import, synchronisation, and export paths. Identity display names are no longer written to service logs at all.
- π The expression evaluation engine has been security-reviewed and hardened with defence-in-depth guardrails, with no change to expression functionality.
- π Every response from JIM now carries defence-in-depth security headers, including a Content Security Policy, clickjacking denial, and MIME-sniffing protection.
- π Every NuGet dependency, including transitive packages, is now locked to exact known-good versions, making JIM's builds reproducible and tamper-evident from source through to container image.
- π Sign-ins and API key authentication attempts now appear in the Activity audit log, with successful sign-ins logged individually and failed attempts grouped by key, IP address and reason so the log stays bounded even under a credential-spraying attack. Security events carry their own configurable retention period, defaulting to one year.
- π Patched transitive
System.Security.Cryptography.Xmlto 10.0.10 to address four newly published high-severity advisories against 10.0.9 (GHSA-23rf-6693-g89p, GHSA-8q5v-6pqq-x66h, GHSA-cvvh-rhrc-wg4q, GHSA-g8r8-53c2-pm3f); the package is pulled in via ASP.NET Core Data Protection but not used by JIM at runtime. - π Attributes holding credential material, such as
unicodePwdanduserPassword, can no longer be imported, selected for management, or used in an Attribute Flow. Any that a deployment had already selected are deselected and locked rather than deleted, leaving Synchronisation Rules intact. - π JIM no longer depends on the third-party DNParser library for LDAP Distinguished Name parsing; DN handling is now performed by a small, self-contained parser built into the LDAP Connector. This removes a Code Project Open License (CPOL) dependency, which software composition scanners commonly flag and which is not OSI-approved, along with an unmaintained package from the supply chain, in keeping with JIM's self-contained, air-gap-deployable design.
0.14.0 - 2026-07-25ΒΆ
SecurityΒΆ
- π Values imported from connected systems can no longer forge or corrupt service log entries via embedded line breaks; every such value is now sanitised before logging. Identity display names are no longer written to service logs at all.
- π The expression evaluation engine has been security-reviewed and hardened with defence-in-depth guardrails, with no change to expression functionality.
- π Every response from JIM now carries defence-in-depth security headers, including a Content Security Policy, clickjacking denial, and MIME-sniffing protection.
- π Every NuGet dependency, including transitive packages, is now locked to exact known-good versions, making JIM's builds reproducible and tamper-evident from source through to container image.
- π Sign-ins and API key authentication attempts now appear in the Activity audit log, with failed attempts grouped by key, IP address and reason so the log stays bounded under a credential-spraying attack. Security events carry their own retention period, defaulting to one year.
- π Patched a transitive dependency (
System.Security.Cryptography.Xml) to clear four newly published high-severity advisories. The package arrives via ASP.NET Core Data Protection and is not used by JIM at runtime. - π LDAP Distinguished Name parsing is now built into the LDAP Connector, removing the third-party DNParser package, and its non-OSI-approved licence, from JIM's supply chain.
AddedΒΆ
- β¨ The Attribute Flow editor now shows Standard Mappings as hints while you map attributes: each Metaverse Attribute's counterpart name in the applicable standard's vocabulary sits beside it in the picker (
First Namereads asgivenNameon an LDAP system), and once you choose a source attribute the editor names the attribute the standard says it corresponds to, marks it Suggested, and offers a one-click button to select it. Export Synchronisation Rules get the same treatment in reverse, naming the Connected System attribute that should receive the value. Which vocabulary applies comes from the Connector (the LDAP Connector declares LDAP/AD); where a Connector declares none, attribute names are matched against every standard and labelled with whichever answered. Where the standard names an attribute the mapping cannot target, the editor explains why rather than staying silent: the data types differ (and an Expression source can convert), another Attribute Flow already targets it, or the Connected System reports it read-only. Hints are advisory throughout: nothing is filtered, disabled or chosen for you, an attribute with no counterpart is not flagged as a problem, and synchronisation continues to flow exactly what your Attribute Flows say. (#1122) - β¨ RFC references in a Connected System's schema attribute descriptions (for example "RFC2256: business category" on an LDAP Connector) are now hyperlinks to the corresponding page on the IETF Datatracker, so you can jump straight to the defining specification.
- β¨ Run Profile executions now report live progress with throughput and an estimated time remaining: on the Activity detail page, from a new lightweight progress REST endpoint, and in the terminal via
Get-JIMActivity -FollowandStart-JIMRunProfile -Wait. (#202) - β¨ The Operations page now updates in real time: the queue and history react the moment tasks are queued, progress or complete, pushed from the database rather than polled, with automatic fallback to polling if the notification channel is unavailable. (#307)
- β‘ Schedules now advance between steps and complete near-instantly, instead of waiting up to 30 seconds for the Scheduler's next polling cycle. (#307)
- π₯οΈ Executing an Example Data Template now shows a live progress bar on the template page itself, so you no longer have to switch to the Operations page to watch it. (#307)
- β¨
Invoke-JIMExampleDataTemplategains-Wait(with an optional-Timeout), blocking until generation completes with a live progress display, and-PassThrunow returns the trackingActivityIdandTaskId. (#1112) - β¨ Administrators can now create, rename, re-icon and delete custom Metaverse Object Types, from the portal, the REST API or PowerShell. The built-in User and Group types are protected, and deletion is blocked while any object or Synchronisation Rule still uses the type.
- β¨ Administrators can now create, edit, delete and bind custom Metaverse Attributes, from the portal, the REST API or PowerShell, with a live duplicate-name check. Deletion is blocked only when objects hold a value; configuration-only references cascade behind a confirmation.
- β¨ New built-in Metaverse Attributes make SCIM 2.0 systems map cleanly onto JIM's schema: Emails, Account Enabled, Nickname, Preferred Language, Locale, Time Zone, Middle Name, Honorific Prefix and Honorific Suffix. Existing deployments gain them on upgrade. (#1104)
- β¨ Metaverse Attributes now carry Standard Mappings, recording how each corresponds to its SCIM 2.0 and LDAP/Active Directory counterparts so you can see which attribute to target. They are guidance only; what flows between systems is set solely by your Attribute Flows. (#1104)
- β¨ You can now filter a Metaverse Object Type's list to just the objects holding a value for a given attribute, from the portal (a
hasAttribute:search), the REST API, orSearch-JIMMetaverseObject -HasAttribute. - β¨ Attribute Flows on export Synchronisation Rules can now be marked Initial Export Only: the attribute is set once when JIM provisions the object, then left to the Connected System so Drift Correction ignores it. Ideal for initial passwords and one-time tokens. (#223)
- β¨ Attributes can now be typed as Decimal, an exact fractional number for values like FTE fraction or contracted hours. Decimal values compare numerically in scoping and searches, and round-trip losslessly from import to export. (#1046)
- β¨ Each Connected System can now choose how imports treat reference values that cannot be resolved: raise an error on each affected object (the default), complete with a single warning summary, or ignore them entirely. (#873)
- β¨ The REST API is now protected by configurable rate limiting, tunable from Service Settings without a restart and returning standard 429 responses with Retry-After guidance. Infrastructure API keys are exempt, and the PowerShell module backs off and retries automatically.
- β¨ Background housekeeping that deletes Metaverse Objects past their grace period is now recorded as a Metaverse Object Housekeeping Activity, with every deletion and staged Pending Export visible and filterable on the Activities page. Previously it was only in the log.
- β¨ Full Import Run Profiles gain a Verification Mode toggle that temporarily disables the content-hash skip (see Performance) and reports any disagreement as an error, for validating after an upgrade or investigating a suspected discrepancy. (#1082)
- π₯οΈ Multi-valued attribute values on Connected System Object and Metaverse Object detail pages are now browsed in a searchable, paginated table inline on the page, rather than behind a "+N more" dialog.
ChangedΒΆ
- π An Attribute Flow mapping a Multi-Valued source attribute to a Single-Valued target now raises a per-object error when an object holds more than one value, instead of silently synchronising an arbitrary one. Pre-v1.0 breaking change: review yours before upgrading. (#435)
- π Deleting an identity now deprovisions downstream accounts according to each export Synchronisation Rule's Deprovisioning Action, rather than only deleting accounts JIM originally created. Existing rules keep the safe Disconnect default; set Delete per rule to opt in. (#655)
- π Breaking (REST API and PowerShell): the object type in Metaverse Object list responses is now a nested
typeobject ({ id, name }), matching the single-object response, instead of flattypeId/typeName. Callers must switch to.type.id/.type.name. (#813) - π The REST API now rejects numeric enum values in request bodies with a
400; send the string name instead ("mode": "AllOf"). Responses and the PowerShell module are unaffected, so only a client hand-crafting request bodies must change. Pre-v1.0 breaking change. (#1060) - π The JIM PowerShell module now returns PascalCase property names (
$obj.DisplayName), following PowerShell convention rather than the REST API's camelCase. Member access is case-insensitive, so only scripts comparing property-name strings need updating. - π Paginated list APIs and every
-Allauto-paginating cmdlet now guard against runaway pagination: a page beyond 1000 returns a400rather than being silently clamped, and-Allstops at 1000 pages with a warning. A new-Forcefetches everything. (#487) - π Executing an Example Data Template through the REST API now queues the generation and returns the tracking Activity's id, exactly like the portal, instead of running it inside the HTTP request with no Activity recorded. Pre-v1.0 breaking change. (#1112)
- π Object Matching Rule sources no longer accept a Metaverse attribute as the source value; export matching always needs a Connected System attribute to compare accounts on, and the standard rule shape now serves both import and export matching. (#1053)
- π Exports now default to a conservative connector-recommended degree of parallelism when a Connected System's Max Export Parallelism is not set, instead of always running sequentially. An explicitly configured value is always respected.
- π The LDAP Connector's default Modify Batch Size is now 1000 values per request, up from 100, cutting the round trips needed for very large group memberships by an order of magnitude. Existing Connected Systems keep their stored value; raise it in Export settings to benefit.
FixedΒΆ
- π MVO Deleted and MVO Deletion Scheduled outcomes in an execution item's Causality Tree no longer render as bare labels when an out-of-scope disconnection triggered the deletion. Every such outcome now shows the deleted Identity's display name (captured before deletion), why the Metaverse Object Deletion Rule fired (for example "last connector disconnected"), the grace period for scheduled deletions, and a link to the deletion record browser, so you can see exactly which Identity was removed and why without leaving the Activity. (#1086)
- π Accounts queued for deletion when an identity is deleted are now reported on the Activity of the run that queued them, nested beneath the MVO Deleted outcome and counted in the run's Pending Exports total, instead of appearing only in service logs. (#1044)
- π A Pending Export execution item now shows its Pending Export's details, including its change type, rather than rendering the panel only for export errors; a queued deletion is now described as such. (#1044)
- π Provisioning now joins to a matching existing account instead of always creating a duplicate: export matching previously ignored every configured Object Matching Rule, so a rehire's retained account failed with errors such as "The object exists".
- π Two identities being provisioned at the same time can no longer both join the same pre-existing target system account; the join is now claimed atomically, and the identity that loses the race is provisioned a new account as normal. (#1051)
- π Export matching now works for Object Matching Rules on Long Number attributes, such as numeric badge identifiers, and rules on attribute types that cannot be matched are reported as a warning in the service log instead of silently doing nothing. (#1052)
- π Import matching now works for Object Matching Rules on Long Number and Decimal attributes; these previously never joined an incoming account to its existing identity, so synchronisation projected a duplicate instead. (#1046)
- π An object that left an export Synchronisation Rule's scope and returned before the deprovision executed no longer has its live target account deleted by the stale Pending Delete, even when the returning change touches only the scoping attribute.
- π Deprovisioning a group member no longer destroys the group's other pending exports: a group with an unexported Delete keeps it, and a group provisioned but not yet exported keeps its Create rather than being stranded unprovisioned.
- π Membership removals staged when deleting Metaverse Objects now appear on the run's Activity, named by their referencing group and counted into the run's totals; previously an Activity could stage thousands of removals while reporting zero Pending Exports.
- π Deleting identities referenced by many groups no longer over-reports the resulting membership-removal Pending Exports: each group is now recorded once with its coalesced export (on a 500,000-user run, a reported 21,824 became the 5,421 actually staged).
- π Deleting objects that other objects reference no longer leaves invisible empty entries behind: group member lists no longer show blank rows or inflated member counts, and later exports no longer stage empty attribute changes. Upgrading cleans up any left by earlier deletions.
- π Exports running with Max Export Parallelism above one no longer send unresolved reference values (raw internal identifiers) to the target system; reference resolutions are now persisted before the parallel batches execute.
- π Large exports with many reference-bearing objects no longer fail partway with "the connection pool has been exhausted"; each parallel batch's resources are now released as it completes, instead of being pinned for the rest of the run.
- π The progress shown while an export works through its deferred reference phase is now accurate. It previously restarted the processed count from zero against the full run total, producing a misleadingly low rate and a wildly inflated time remaining.
- π Very large imports no longer fail with a database statement timeout while Pending Exports are loaded for reconciliation; the load now runs in bounded chunks (measured at 525,000 Pending Exports with 9.8 million attribute value changes).
- π Very large synchronisation runs no longer fail with a database command timeout while change history reference links are resolved. Resolution now runs in bounded batches, and the export stage resolves the references its own change records create.
- π Connected System Objects now retain their partition assignment. The high-volume import write paths silently discarded it, leaving objects invisible to their partition's obsoletion sweep, so they could never be flagged as deleted. (#1046)
- π Long Number attributes now flow correctly everywhere the other data types already did: inbound flows no longer fail the object, expression results are no longer dropped or truncated, and export evaluation no longer skips a genuine change as no-net-change. (#1046)
- π The REST API now returns Long Number, Decimal and Binary attribute values instead of null, and every attribute type surfaces its real value in its natural JSON type when listing Metaverse Objects with requested attributes. Binary values are returned as Base64 text. (#1046)
- π Deletion audit records now retain Long Number, Decimal and reference values, which previously recorded blank, and values beyond the 32-bit range are no longer truncated to a wrong number. The stored attribute values themselves were never affected. (#1046, #871)
- π The File Connector now writes Binary attribute values to export files as Base64 text, instead of silently writing empty cells. (#1046)
- π Executing an Example Data Template through the REST API no longer crashes with an index-out-of-range error when generating pattern-based values; a template referencing a genuinely empty Example Data Set now fails with a clear message naming the set. (#1112)
- π Example Data generation no longer crashes intermittently under load. The parallel generator shared a random number generator that is not safe for concurrent use, so its internal state could be corrupted and abort generation partway.
- π The Example Data generation progress bar now advances about once a second instead of appearing frozen and then jumping; the CPU-bound parallel generation was consuming every worker thread and starving the progress reporter.
- π The Operations queue progress bar for Example Data generation now sweeps smoothly from 0% to 100% across the whole job, including the database-persistence phase where it previously sat frozen at 100%, with a rolling estimated time remaining.
- π The rate and time-remaining estimate on a running Activity now reflect recent throughput rather than a whole-run average, which misled badly on long runs with fast and slow phases. A stalled counter now reads "finishing up" instead of showing a fabricated estimate.
- π The Activity Operations tab no longer pegs the server at 100% CPU for Activities with tens of thousands of execution items; it now reads only the columns the grid needs (measured: a 26,824-item Activity page went from effectively unusable to about a second).
- π MVO Deleted and MVO Deletion Scheduled outcomes triggered by an out-of-scope disconnection no longer render as bare labels; each now shows the deleted identity's display name, why the deletion rule fired, and a link to the deletion record browser. (#1086)
- π Synchronisation runs whose only outcomes were out-of-scope disconnections no longer show an empty Outcomes cell in the Operations history and Activity list; new chips display out-of-scope disconnections and out-of-scope retained joins.
- π Temporal Scope Reconciliation tasks now display their name and type on the Operations queue, instead of "Unknown WorkerTask type".
- π LDAP Distinguished Names containing escaped separators (an escaped backslash before a Relative Distinguished Name comma, or a comma inside a quoted value) are now parsed correctly when resolving container hierarchies and parent containers.
- π Recording an API key's last-used timestamp no longer surfaces error-level log entries when the database is briefly saturated by a large synchronisation run. The last-used display is unaffected beyond a coarser precision.
- π Closing the browser or navigating away from a tabbed admin page no longer records spurious Error-level entries in the JIM.Web log. Remaining browser-disconnect noise is logged at Warning, so Error entries once again indicate genuine problems.
- π
Add-JIMScheduleStepworks again, sending step type and execution mode as enum names; it also now passes existing steps through verbatim, instead of silently rewriting any PowerShell or parallel step it did not recognise. - π Piping a Schedule into
Get-JIMScheduleExecutionnow filters executions to that Schedule. Previously the piped Schedule did not bind, so the cmdlet silently returned every execution in the system whilst appearing to filter. - π
Reset-JIMServiceSettingnow accepts Service Settings from the pipeline, as its documentation described.
PerformanceΒΆ
- β‘ Full Imports at large scale are dramatically faster, and confirming a very large group no longer gets disproportionately slower as its membership grows. A Full Import of 210,000 objects that took over 40 minutes now completes in around 8.
- β‘ Full Import now skips loading and comparing objects whose content has not changed since the previous import, making its cost proportional to the number of changed objects rather than the size of the whole connector space. Any doubt falls back to the full comparison. (#1082)
- β‘ Full Imports over existing objects are faster again: the per-object database work that dominated them at scale (over half a million separate lookups at 500,000 users) is now done in bulk.
- β‘ Full Synchronisation at large scale no longer spends most of its time re-verifying large groups for drift; this accounted for 35 minutes of a 52-minute confirming synchronisation at 500,000 users, and is now effectively instant regardless of group size.
- β‘ Synchronisation runs no longer slow down page by page as they work through a large Connected System. Each page used to take longer than the last (around 200ms early, degrading to 1.5s late; 16 minutes of waiting across a 525,000-object run); every page now costs the same.
- β‘ Deleting Metaverse Objects that groups reference is now dramatically faster: a 2,000-user leaver cohort at 200,000 objects with 10,000 groups that took over 9 hours to synchronise is projected to finish in well under one.
- β‘ Deleting Metaverse Objects during synchronisation is dramatically faster: a page of deletions that took around 50 seconds now completes in a fraction of that, and no longer gets slower as the number of objects grows.
- β‘ Deprovisioning users who are members of large groups no longer slows synchronisation to a crawl, however large those groups are.
- β‘ Exports no longer stall between batches at large scale. At 200,000 objects with 10,000 reference-bearing groups, an export previously spent hours getting organised before the first group reached the target system.
- β‘ The tail of a large, reference-heavy export no longer crawls through work it has already identified, so an export that is mostly group memberships finishes promptly instead of trailing off.
- β‘ Export runs no longer spend around 11 minutes preparing to retry previously deferred references at 525,000 Pending Exports, even when there is nothing left to resolve. (#1102)
- β‘ Exports now update JIM's own record of an object the moment the export succeeds, rather than waiting for the next confirming import to read the values back, so that import has far less to do. Applies to LDAP and similar connectors; file-based exports are unchanged. (#1079)
- β‘ Watching a Run Profile execute no longer competes with the run itself: refreshing its statistics cost around 85 minutes of cumulative database time over one 500,000-user run, and is now instant. (#1078)
- β‘ The worker service no longer places constant background load on the database for the entire duration of any running task, competing with the very run it is monitoring.
- β‘ Bookkeeping after an export no longer gets disproportionately slower as a batch grows; a batch containing a 100,000-member group spent over ten minutes in it. This also fixes a batch failure that could abort after the target system write had succeeded.
0.13.0 - 2026-07-10ΒΆ
AddedΒΆ
- β¨ Synchronisation Rules can now carry an optional description recording what the rule is for. Set it in the admin portal, with
New-JIMSyncRule/Set-JIMSyncRule, or the REST API; changes appear in the change history. - β¨ Date/time scope filters and object searches can now be relative to "now" (a count, a unit from Hours to Years, and a direction, for example "30 to 364 days ago") rather than a fixed date, re-evaluating every run so the scope keeps moving with time.
- β¨ Relative-date scopes keep working when source data isn't changing: a new built-in hourly Temporal Scope Reconciliation schedule re-evaluates time-driven transitions, so leavers deprovision and joiners provision as their dates pass. It can be re-timed or disabled, not deleted.
- β¨ Predefined Searches can now filter on any attribute type (Number, Long Number, Date/Time, Boolean and GUID) with type-appropriate operators and case-sensitive or -insensitive text matching. Manage criteria from a new editor, the PowerShell module, or the REST API.
- β¨ Predefined Search criteria can now be combined with AND/OR logic and nested groups, for example "(Department is Finance or Sales) and active", rather than a flat list.
- β¨ Example data templates can now build a text attribute from an expression, using the same
mv["Attribute Name"]syntax and functions as Attribute Flows, so a generated value can derive from other attributes on the same object. Circular references are detected up front. - β¨ The Activity list is easier to audit: category (Configuration, Identity, Synchronisation, System), initiator (user, API key, system) and created-date filters narrow the view, and the filter state is reflected in the URL so a view can be bookmarked or shared.
- β¨ An API Key's Name and Description can now be edited directly from its Details tab in the admin portal, without PowerShell or the REST API.
Attribute Priority (#91)ΒΆ
- β¨ When more than one Connected System contributes a Metaverse attribute, a configurable per-attribute priority order now picks the winner, so a higher-priority source is never overwritten by a lower one; a "Null is a value" option lets an authoritative source assert "no value".
- β¨ Attribute Priority is manageable in the admin portal: a Metaverse Object Type's Attributes tab shows each attribute's contributor count, and expanding a multi-contributor one lets you drag its Synchronisation Rules into priority order and toggle "Null is a value".
- β¨ The REST API and
Get-JIMMetaverseObjectnow show each attribute value's provenance: the Connected System and Synchronisation Rule that won priority resolution. Asserted nulls appear as flagged, value-less rows, distinguishing a deliberate blank from one with no contributor. - β¨ Synchronisation Activities now report when an attribute became blank with nothing to replace it, as a distinct "MVO No Contributor" outcome alongside "MVO Null Asserted", so you can tell a deliberate clear from every source falling away.
Configuration Change History (#14)ΒΆ
- β¨ JIM now tracks a versioned history of who changed what and when across its configuration: Synchronisation Rules, Connected Systems, Schedules, Service Settings, Metaverse schema, and more. Retrieve it in the portal, via
Get-JIMConfigurationChangeHistory, or the REST API. - β¨ Secrets are never captured in the change history: encrypted setting values, a Schedule step's SQL connection string, certificate material, and API key secrets are all flagged as changed but never stored, not even as a hash.
- β¨ You can record a reason for any configuration change:
-ChangeReasonon the write cmdlets or an optional REST field, plus a "Reason for change" prompt when saving in the admin portal. The reason shows with the change and on its Activity. - β¨ Deleting a Connected System records a final snapshot of its configuration, so a decommissioned system's last-known state and who removed it stay auditable; the captured state is shown on the delete Activity as a clearly-marked removal.
- β¨ Configuration change history is retained on its own schedule: a new Configuration change retention period Service Setting (default ~10 years) governs it, separate from general history retention.
- β¨ First-time seeding of built-in configuration now appears as a single System Initialisation Activity with the seeded objects as children, so a new deployment starts with one clear entry instead of a page of system rows.
- π A factory reset now preserves the change-history provenance of the built-in objects it keeps, re-recording their version-1 baselines under a fresh System Initialisation Activity instead of stripping their factory origin from the audit trail.
- π Data-generation runs are now a distinct "Data Generation" activity type, separated from Example Data Template configuration changes, so the Activities Configuration filter isn't cluttered by generation runs. Existing runs are reclassified on upgrade.
API & PowerShell Coverage (#154)ΒΆ
- β¨ Connected System Objects can now be listed and filtered via a paginated REST endpoint and the extended
Get-JIMConnectedSystemObjectcmdlet, rather than looked up one at a time. - β¨ Example Data Sets now support full create, update, and delete via the REST API and the new
New-,Set-, andRemove-JIMExampleDataSetcmdlets, alongside the existing read access. - β¨ Queued and in-progress background operations can now be listed, inspected, and cancelled remotely via a new Worker Tasks REST endpoint and the
Get-JIMWorkerTask/Stop-JIMWorkerTaskcmdlets. - β¨ File system browsing, log viewing, and Metaverse Attribute priority management (previously UI-only) are now available as PowerShell cmdlets, giving the module full parity with the REST API.
- β¨ A single Connected System Object Type can now be retrieved by id from the REST API, returning the object type with its attributes, to match the existing update endpoint.
PowerShell Log Streaming (#466)ΒΆ
- β¨ Service logs can now be streamed live from PowerShell with the new
Watch-JIMLogcmdlet: it polls the Logs API, shows only new entries, supports the same filters asGet-JIMLogEntry, and keeps polling through transient failures until you stop it with Ctrl+C.
ChangedΒΆ
- π Multi-source Metaverse attributes now resolve by attribute priority instead of synchronisation timing (last-writer-wins). Single-source attributes are unaffected; existing multi-source ones resolve deterministically until you set an explicit priority order.
- π When a source supplying a multi-source attribute disconnects, leaves scope, or stops providing the value, JIM now hands it to the next-priority contributor still supplying it (reference attributes included), clearing it only when none survives.
- π A deletion grace period no longer freezes attribute hand-over at scope exit: a re-elected attribute is still handed over, and only a single-source value with no surviving contributor is held for the grace window.
- π Activity displays no longer abbreviate "Synchronisation Rule" to "Sync Rule". The underlying
ActivityTargetType.SyncRuleenum value is renamed toSynchronisationRule, a breaking REST/OpenAPI change acceptable pre-v1.0. - π The Activity children REST endpoint and
Get-JIMActivityChildrenare now paged, returning a paged envelope rather than every child at once; the cmdlet gains-Page,-PageSize, and-All, and is now exported from the module (previously unreachable). - π A Connected System's Settings tab now groups its top-level setting categories into a collapsible accordion and separates second-level headings with a divider, making dense connector settings easier to scan.
PerformanceΒΆ
- β‘ Synchronisation imports use far less memory: comparison no longer keeps every loaded object (plus a change-tracking snapshot) for the whole run, nor loads referenced objects in full just to compare group memberships; at 100,000 users with ~5,000 groups this had cost gigabytes.
- β‘ The worker now returns memory to the operating system after each heavy operation completes, instead of holding its peak allocation while idle, and logs its garbage-collection configuration at startup.
- β‘ Generating example data is dramatically faster: the built-in "Users & Groups" template (10,000 users) now completes in seconds rather than minutes, after moving blocking progress writes out of the parallel generation loop.
- β‘ Example data value uniqueness is now tracked with constant-time lookups instead of rescanning an ever-growing list under a global lock, removing a cost that grew with the square of the object count at larger template sizes.
FixedΒΆ
- π Adding a Trusted Certificate via the REST API or
Add-JIMCertificateno longer returns a "No route matches" error on success (the certificate was stored regardless);Get-JIMCertificateon an empty store no longer emits the pagination envelope as a certificate. - π Re-keying an identity in a source (so a new record re-matches an identity while the old one is removed) no longer fails a Full Synchronisation with a database constraint violation; two new records matching one identity fail cleanly on the second, not aborting the run.
- π A Full Synchronisation after a configuration change (attribute priority, enabling/disabling a rule, scoping) now applies it to every object; previously objects whose source data hadn't changed were skipped, so a pure configuration change never took effect for them.
- π A synchronisation run that both created a Metaverse Object and detected drift on it no longer fails with a database foreign-key violation; drift is now evaluated after new objects are saved, so the corrective export always references a real object.
- π A Full or Delta Synchronisation no longer aborts with a database concurrency error when updating a Metaverse Object created earlier in the same run, a race seen at scale; a page that fails to persist now reports which objects were affected instead of a generic error.
- π Deleting a Metaverse Object (for example a deprovisioned leaver) now stages membership-removal exports for every object that referenced it, so groups in target systems without referential integrity no longer keep the deleted user as a member forever.
- π Deleting a Connected System Object that other objects still reference no longer fails the whole run with a database foreign-key violation; the stale references are cleared as part of the deletion, with the raw strings preserved so the next confirming import reconciles.
- π A synchronisation run that fails while saving to the database no longer leaves its Activity stuck in progress; the failure is recorded via a fresh database session, since the failing one cannot save anything further.
- π A Connected System hierarchy refresh that returns no partitions no longer wipes the configured hierarchy: a transient connection or scope problem previously deleted every partition and container, including selected ones. JIM now leaves it untouched and records a warning.
- π A factory reset no longer strips the built-in "Users & Groups" example data template of its attributes (a side effect of the bulk wipe that left generated objects value-less); the template is now restored as part of the reset.
- π Editing an API Key or Trusted Certificate now records who made the change and when; previously the "last updated" attribution was silently lost on save.
- π Activity targets now deep-link to where their subject is managed: an Attribute Flow change to the rule's Attribute Flow tab, imports to the Connected System's Schema and Partitions tabs, and Schedule, Service Setting, and Metaverse activities to their pages.
- π The Schedules links on the home page now open the Schedules tab on the Operations page directly, instead of landing on the default Queue tab.
- π Save and create buttons across the admin portal now react as you type instead of waiting for the field to lose focus, and no longer start disabled when editing an existing item whose required fields are already filled in.
- π The Service Setting edit dialog no longer allows saving an unparseable duration into a time-period setting; the value is validated as you type and Save stays disabled until it is valid.
- π Updated the bundled Microsoft.OpenApi library to a patched release (2.7.5), clearing a high-severity advisory (GHSA-v5pm-xwqc-g5wc) in JIM's API documentation generation.
- π The
-ConnectedSystemAttributeNameparameter onNew-/Set-JIMScopingCriterionnow resolves the attribute correctly; it previously queried a non-existent endpoint, so scoping criteria specified by attribute name failed (the id-based parameter was unaffected).
0.12.0 - 2026-06-23ΒΆ
AddedΒΆ
- β¨ Inbound attribute mappings can now clean and normalise imported text per mapping: treat whitespace-only and empty values as no value (on by default, so a stray space no longer masquerades as a real value), trim and collapse whitespace, and normalise case (Upper, Lower or Title), configurable in the mapping editor, REST API, and PowerShell module. Switch it off per mapping where whitespace is meaningful, and the portal then flags such values with a "(whitespace)" indicator instead of rendering them blank.
- β¨ Inbound text attribute mappings can now clean and normalise imported values per mapping: treat whitespace-only/empty as no value (default on), trim, collapse internal whitespace, and normalise case. Configurable in the mapping editor, REST API, and PowerShell module.
- β¨ The PowerShell module now persists your interactive SSO sign-in across terminal sessions: after
Connect-JIM, new terminals reconnect silently, storing only the refresh token in the OS credential store. Use-NoPersist,-Force, andDisconnect-JIMto control it. - β¨ Factory reset is now available in the portal: a new Administration danger area (
/admin/factory-reset) with a backup warning, type-to-confirm, and an optional "delete administrators" path. - β¨ The initial administrator can now be bootstrapped via the PowerShell module or REST API, not just the portal. Their first authenticated call just-in-time creates the identity and grants the Administrator role, so an air-gapped instance is fully CLI-administrable.
ChangedΒΆ
- π₯οΈ The Synchronisation Rule editor is now organised into deep-linkable tabs (Details, Matching, Scope, Attribute Flow, Danger Zone) instead of one long page, with a single save bar beneath every tab so the whole rule still saves in one action.
- π₯οΈ The Connected System Schema tab is now split into sub-tabs: a searchable, filterable "Object Types" grid for choosing which types JIM manages, plus a tab per selected type for its attributes. This stays usable when a system exposes hundreds of object types.
- π₯οΈ Connected System settings that only apply in certain configurations are now hidden until relevant and required once shown (for example, LDAP Certificate Validation appears only with LDAPS enabled), enforced in the form and for API callers.
- π The REST API now rejects an invalid Connected System settings update with HTTP 400 and a per-setting list of what failed and why, instead of silently saving it.
Set-JIMConnectedSystemsurfaces these field-level messages. - π JIM now requests the
offline_accessscope at interactive sign-in so the identity provider issues a refresh token; this enables in-session token renewal and PowerShell token persistence. Existing SSO deployments must permitoffline_accesson the interactive client. - π Factory reset now preserves administrator users by default (so you are not locked out) and records a Reset activity. Removing administrators too is opt-in via
-IncludeAdministratorsonReset-JIMSystem(andincludeAdministratorson the reset API). - π The reconnection overlay now shows live attempt progress (for example, "Attempt 2 of 5...") while JIM re-establishes a dropped connection.
- π Running a PowerShell cmdlet before connecting now shows a clear one-line prompt to run
Connect-JIM -Url <your JIM URL>instead of a raw internal error; it is non-terminating by default and can be made fatal with-ErrorAction Stop. - π The "not authorised" message shown when an authenticated user has no JIM identity now explains that identities arrive via synchronisation or administrator provisioning, rather than directing them to sign in to the portal first.
FixedΒΆ
- π Editing an existing Synchronisation Rule in the portal now saves. Changes such as disabling a rule appeared to succeed but were silently discarded; the editor now keeps a single database session and fails loudly rather than dropping the change.
- π Creating a Synchronisation Rule from scratch in the portal no longer fails (previously it raised a database foreign-key violation, so a new rule could not be saved at all), and the page now switches into edit mode once the rule is created.
- π The Synchronisation Rule expression tester now resolves attribute names case-insensitively, exactly as live synchronisation does, so an expression that works during a sync run no longer reports "no result" in the tester purely because an attribute name's casing differs.
- π A failed synchronisation expression is no longer silently swallowed, leaving stale metaverse data. The affected object is errored with a distinct "expression evaluation error" and its target left untouched, while the run continues (inbound and export mappings).
- π The File Connector now enforces "exactly one of Object Type Column or Object Type" at save time, with live form feedback and server-side validation, instead of failing later or silently ignoring a value. Connectors can declare such either/or setting groups generically.
- π Deleting a Connected System (including a synchronised one) no longer fails with a database error and is now atomic. Dependent objects are removed in the correct order, and metaverse values it contributed are kept with their contributor link cleared.
SecurityΒΆ
- π A factory reset now invalidates every existing portal sign-in session, so no stale access or privileges survive the wipe; users must re-authenticate. API key access is unaffected.
- π The REST API now rejects request bodies containing duplicate JSON property names, removing an ambiguous-parsing and request-smuggling vector.
0.11.0 - 2026-06-06ΒΆ
AddedΒΆ
- β¨ Create custom Metaverse Object Types via the API and the new
New-JIMMetaverseObjectTypecmdlet, to model identity types beyond Users and Groups. - β¨ Scoping criteria now support long-integer and case-sensitive comparisons via the API and
New-JIMScopingCriterion. - β¨ Synchronisation Rules can now set their out-of-scope and deprovisioning actions and drift detection via the API and
Set-JIMSyncRule. - β¨ New factory reset (
Reset-JIMSystem/POST /api/v1/system/reset) wipes all customer data and configuration in one transaction while preserving the schema, built-ins, and infrastructure access.
FixedΒΆ
- π Refreshing a Connected System's schema now persists the discovered object types and attributes, so the selection interface appears immediately instead of reading back empty.
- π Outbound deprovisioning no longer fails with a duplicate-key error when the target object still has a Pending Export from a prior run.
- π Adding scoping criteria to an existing Synchronisation Rule via the API no longer fails to save.
ChangedΒΆ
- π JIM is now distributed under the Tetron Software License Agreement v2.0.
0.10.3 - 2026-05-10ΒΆ
AddedΒΆ
- β¨ Metaverse Object change history is now available via the API and PowerShell module: new
GET /api/v1/metaverse/objects/{id}/change-historyendpoint returns paginated change records, and the newGet-JIMMetaverseObjectChangeHistorycmdlet wraps it for automation and compliance scenarios. - β¨ Connected System Object change history is now available via the API and PowerShell module: new
GET /api/v1/synchronisation/connected-systems/{id}/connector-space/{csoId}/change-historyendpoint returns paginated change records, and the newGet-JIMConnectedSystemObjectChangeHistorycmdlet wraps it for automation and compliance scenarios.
PerformanceΒΆ
- β‘ Metaverse Object detail pages load substantially faster on objects with long change histories: the page no longer materialises the entire change graph upfront, fetching only a count alongside the object and loading change rows on demand when the Changes tab is opened.
- β‘ Connected System Object detail pages load substantially faster on objects with long import histories: the page no longer materialises the entire change graph upfront, fetching only a count alongside the object and loading change rows on demand when the Change History tab is opened.
- β‘ Connector Space list pages load substantially faster: the per-page projection no longer materialises full pending-export graphs or attribute-value entities, returning only the scalar columns the table actually renders.
FixedΒΆ
- π Export Run Profile Execution Items and their linked Connected System Object Change rows now persist with the correct
ConnectedSystemObjectIdforeign key, restoring causality navigation from Operations into the CSO detail page and preventing exported objects from being mis-labelled as "Deleted" on the activity item detail page (#683). - π Pending-export reference values in the Causality Tree attribute change table now render the resolved identifier (e.g. group member DN) alongside a clickable link to the stub Connected System Object, instead of showing only a clock icon with no value.
ChangedΒΆ
- π The Activity Run Profile Execution Item detail page no longer duplicates the Connected System Object's external ID in the Execution Summary prose; the identifier is already shown as a chip directly below.
0.10.2 - 2026-04-29ΒΆ
AddedΒΆ
- β¨ Predefined Searches can now be retrieved individually via the API and PowerShell module: new
GET /api/v1/predefined-searches/{id}andGET /api/v1/predefined-searches/by-uri/{uri}endpoints return the full search graph, andGet-JIMPredefinedSearch -Id/-Urinow resolve directly against the server instead of filtering the list client-side (#154)
FixedΒΆ
- π The "Initiated By" link on Activity and Activity Run Profile Execution Item detail pages now points to the correct Metaverse Object URL, derived dynamically from the initiator's Metaverse Object Type plural name (
/t/{typePluralName}/v/{id}) instead of a broken hardcoded/identity/person/{id}path. - π Safari sign-in against the development stack at
http://localhost:5200no longer fails withCorrelation failed; OIDC correlation cookies are now configured appropriately for plain-HTTP localhost in Development while production HTTPS defaults remain untouched. - π The bundled "Users & Groups" example data template now persists at production speed without stalling the worker or pressuring memory; generation has been rewritten to use PostgreSQL
COPYbinary import in bounded batches, mirroring the proven pattern used on the synchronisation hot path. - π Filled alerts in the
navy-o6themes now meet WCAG AA contrast: light-theme info/success/warning/error variants and dark-theme filled info no longer place dark text on saturated backgrounds, and links inside filled alerts pick up the on-colour text colour rather than clashing with the semantic background.
ChangedΒΆ
- π Example data generation now reports live, batch-level persistence progress with a rolling ETA on the Activity record and progress bar, so administrators can see exactly where a large generation run is up to.
- π Compact row spacing on the Metaverse Object detail Table view now extends to multi-valued reference rows (e.g. group Owners, Static Members), keeping large memberships readable at a glance.
- π₯οΈ Refreshed the JIM portal and documentation typography to IBM Plex Sans and IBM Plex Mono, with a Space Grotesk accent on docs hero surfaces and the portal sidebar wordmark, for sharper identifier disambiguation and a more polished, designed feel across the product.
- π₯οΈ The production error page now renders in the JIM brand (broken-cog illustration, Plex / Space Grotesk fonts, navy-o6 palette), honours the user's saved dark-mode preference and
prefers-reduced-motion, and runs without a Blazor circuit so it remains reachable when middleware throws. - π οΈ
jim-resetnow stops any natively-run JIM.Web/Worker/Scheduler processes before tearing down the Docker stack, preventing port collisions (e.g. host port 5200) when the Docker stack is restarted after ajim-build-lightdebug session.
0.10.1 - 2026-04-27ΒΆ
AddedΒΆ
- β¨ Interactive browser-based SSO for the JIM PowerShell module now works against identity providers that require a separate public client registration for desktop/CLI tools, including Keycloak. Two new optional environment variables let administrators advertise client-facing SSO configuration to interactive clients without affecting backend token validation:
JIM_SSO_PUBLIC_AUTHORITYfor deployments where the backend and clients reach the identity provider on different URLs (split-horizon reverse proxies, development containers), andJIM_SSO_PUBLIC_CLIENT_IDfor deployments where the PowerShell module's public OAuth client is a distinct registration from the web application's confidential client. Both variables are optional and fall back toJIM_SSO_AUTHORITY/JIM_SSO_CLIENT_IDrespectively, so single-URL single-client production deployments are unaffected.
ChangedΒΆ
- π Refined sidebar navigation styling: selected and hover items now show a contrasting rounded "pill" background that is inset from the drawer edges, with the hover background a stronger shade than the selected background so it remains visible when hovering an already-selected item. Active and hover backgrounds are theme-driven (
--jim-nav-active-bg/--jim-nav-hover-bg) and tuned per theme, with sensible derived fallbacks for any future theme that does not set them. - π₯οΈ A more polished sidebar experience: the signed-in user menu is now anchored to the bottom of the drawer for quick access regardless of how many sections are above it, and pinning or collapsing the drawer is now a single click on a dedicated chevron in the drawer header.
FixedΒΆ
- π Interactive
Connect-JIMagainst Keycloak deployments previously failed withInvalid parameter: redirect_uribecause JIM advertised the confidential web client ID to the PowerShell module. Administrators can now register a separate public client (as the SSO Setup Guide has always instructed) and advertise it to interactive clients via the newJIM_SSO_PUBLIC_CLIENT_IDenvironment variable. - π
Get-JIMRoleand theGET /api/v1/security/rolesendpoint now report the correct static member count for each role; previously the count was always zero because the underlying query did not load role memberships. The count is now aggregated directly in SQL, so even roles with very large memberships are returned cheaply. - π
Get-JIMRole -IdandGET /api/v1/security/roles/{id}now report the correct static member count when retrieving a single role. - π
Get-JIMMetaverseObjectRoleandGET /api/v1/security/metaverse-objects/{id}/rolesnow report the correct static member count for each role a Metaverse Object belongs to. - π
GET /api/v1/synchronisation/connected-systems/{id}now reports the correct Connected System Object count; previously it always returned zero because the navigation property was not loaded. The count is now sourced from a dedicated count query, mirroring howpendingExportCountis already computed.
SecurityΒΆ
- π Patched
Microsoft.AspNetCore.DataProtectionto 10.0.7 to address CVE-2026-40372 (GHSA-9mv3-2cwr-p262, high-severity elevation of privilege / authentication cookie forgery in ASP.NET Core Data Protection). Also drops the now-redundant transitive override ofSystem.Security.Cryptography.Xml, which Data Protection 10.0.7 brings in at a patched version directly.
0.10.0 - 2026-04-22ΒΆ
AddedΒΆ
- β¨ Added a Service Name and Service ID so you can tell JIM instances apart at a glance. Set a friendly name per instance on the Service Settings page and see it under "JIM" in the sidebar, in the browser tab title, and in the footer. The Service ID is generated once per instance and never changes, useful for tooling, logs, and telemetry (#583)
- β¨ Predefined Searches can now be disabled and re-enabled without deleting them; disabled searches are hidden from the portal, the search API, and the sidebar navigation, while administrators can still manage them via the admin UI, the new
/api/v1/predefined-searchesendpoints, and the newGet-JIMPredefinedSearch/Set-JIMPredefinedSearchPowerShell cmdlets (#555) - β¨ PowerShell cmdlets for System endpoints:
Get-JIMHealth(with-Readyand-Liveprobes),Get-JIMVersion,Get-JIMAuthConfig, andGet-JIMUserInfo; health, version, and auth config cmdlets work withoutConnect-JIMvia a-Urlparameter (#468) - β¨ Interactive API reference powered by Scalar, available at
/api/referencein all environments including air-gapped deployments; OpenAPI document is pre-generated at build time for instant loading with zero runtime overhead - β¨ Public API reference published to the JIM documentation site at docs.junctional.io/api/reference/; automatically updated on every release to match the published JIM version
- β¨ Clear Connected System activity now tracks and displays removal statistics, showing how many Pending Exports and Connected System Objects were removed (#74)
- β¨ New count endpoints for Metaverse Objects, connector space, and Pending Exports, with filtering by object type, partition, change type, and status; suitable for dashboards, SIEM integration, and capacity monitoring (#154)
- β¨ New user menu in the navigation drawer showing the signed-in user's avatar (with initials), display name and username, with pinning, dark mode and sign-out controls in a single polished popover (#49)
- β¨ Automated integration test metrics streaming to central tracking system with Grafana dashboards (#476)
- π API and PowerShell support for managing Role membership on Metaverse Objects, enabling administrators to appoint or remove additional admins without restarting the service (#467)
- β¨ New API endpoints for Role member management: list members, add member, remove member, get Role by ID, and list the Roles a Metaverse Object is a member of
- β¨ New PowerShell cmdlets
Get-JIMRoleMember,Add-JIMRoleMember,Remove-JIMRoleMember, andGet-JIMMetaverseObjectRolewith full pipeline support - β¨
Get-JIMRolecmdlet now supports-Idparameter for direct Role lookup by identifier - π Safety checks prevent administrator lockout: self-removal from the Administrator role and removing the last Administrator are both blocked with clear error messages
- π Sign-out with identity provider, gated by the
SSOEnableLogOutservice setting, with a confirmation dialog to prevent accidental clicks (#49)
PerformanceΒΆ
- β‘ Connected System detail lookups are much cheaper on write-path and validation API calls: introduced a lightweight
GetConnectedSystemCoreAsyncretrieval variant that loads only essential properties, and migrated the API controllers that previously paid for the full schema, partition and container graph just to verify the system exists (#494) - β‘ Connected System container hierarchy loading now handles arbitrary depth and avoids the cartesian-explosion risk of the previous 11-level hard-coded Include chain; containers are loaded flat and rebuilt into a tree in memory (#494)
- β‘ Full Connected System loads now issue one database query for Object Matching Rules instead of four, eliminating the fan-out that split-query mode introduced when walking
Sources.ConnectedSystemAttribute,Sources.MetaverseAttribute,TargetMetaverseAttributeandMetaverseObjectTypeas separate Include branches (#494) - β‘ Default all EF Core queries to
AsNoTracking, reducing memory and CPU overhead for read-heavy operations; write paths explicitly opt in to change tracking (#484) - β‘ Enriched diagnostic spans with cumulative object count and wall-clock offset tags for throughput profiling (#476)
- β‘ Added MetricsCheckpoint log lines for guaranteed throughput tracking at any log level (#476)
ChangedΒΆ
- π₯οΈ Partition-configuration validation errors now pinpoint the exact gap (hierarchy not imported, no partitions selected, or selected partitions have no container selected) and name the partition involved, replacing the previous generic "no partitions or containers have been selected" message and making misconfigurations far faster to diagnose (#564)
- π₯οΈ Page footer now links the Tetron name to tetron.io and includes a GitHub link next to the version number (#49)
- π¦ File Connector storage uses the formal Docker named volume
jim-connector-files-volume, mounted at/connector-filesinside JIM Web and JIM Worker. Default deployments get working File Connector exports out of the box without any host-side permission setup. Customers integrating with external file shares bind-mount over a subdirectory of/connector-files. See the JIM File Connector documentation for both patterns.
FixedΒΆ
- π Group and other multi-valued-reference sync activities no longer produce duplicate execution items; cross-page reference resolution now merges reference Attribute Flow into the original Projected/Joined record instead of creating a second standalone "Attribute Flow" record for the same object. Fixes inflated activity counts and removes the confusing split-outcome rows that appeared in activity detail
- π Static member values and other multi-valued references on group activity detail pages now render as clickable user chips with display names instead of raw GUIDs; reference change records now carry their target as a proper foreign key so the link can be materialised on display
- π Export failures caught by exception handlers now produce Run Profile Execution Items reliably; previously a thrown connector exception could mark a batch failed without producing any RPEI, so the activity appeared to complete successfully despite silent export failures
- π Metaverse Object and Connected System Object change history is now persisted during sync RPEI flush and on single-object create, ensuring the audit timeline reflects every sync run
- π Sign-out with the bundled Keycloak no longer fails with "Missing parameters: id_token_hint"; JIM now persists the ID token during sign-in so the OIDC middleware can include it on the end-session request per the OIDC spec (#49)
- π Keycloak hostname configuration corrected so that browsers and Docker back-channel clients each get the right endpoint URLs, fixing sign-in and sign-out for all four deployment scenarios (Codespaces, devcontainer native, devcontainer Docker, production) (#49)
- π Connected System partition trees now include nested containers below the top level. Directories with nested organisational units (e.g.
OU=Users,OU=Corp) are loaded and returned through the API in full, so administrators can select nested containers for import and automation can address them via PowerShell (#586)
SecurityΒΆ
- π Supply chain hardening: all Docker base images are digest-pinned, all GitHub Actions are pinned by commit SHA, and the main branch is protected with required status checks including automated code review, CodeQL, container scan, and dependency scan (#520, #517, #521)
- π Patched transitive
System.Security.Cryptography.Xmlto 10.0.6 to address CVE-2026-33116 (low-severity DoS inEncryptedXml); the package is pulled in via ASP.NET Core Data Protection but not used by JIM at runtime - π Patched
basic-ftpCRLF injection vulnerabilities (GHSA-chqc-8p9q-pq6q and GHSA-rp42-5vxx-qpwr) and picked up Ubuntu Noble security updates for libldap and cifs-utils in all production container images
0.9.1 - 2026-04-08ΒΆ
AddedΒΆ
Search Objects API (#482, #488)ΒΆ
- β¨ New
GET /api/v1/metaverse/objects/search/{predefinedSearchUri}endpoint for fast, lightweight object searches optimised for 100K+ object deployments - β¨ New
Search-JIMMetaverseObjectPowerShell cmdlet with predefined search support, sorting, filtering, and auto-pagination
PerformanceΒΆ
Paginated List Optimisation (#482, #485)ΒΆ
- β‘ Metaverse Object list sorting now uses a pre-computed cached display name column, eliminating expensive per-query subqueries for display name resolution
- β‘ New composite index on metaverse attribute values for faster attribute-based sorting and filtering
- β‘ Paginated list queries for Metaverse Objects and Connected System Objects rewritten to use keyset pagination with optimised sort subqueries
FixedΒΆ
- π₯οΈ Fixed oversized text on avatar chips in Synchronisation Rule list and detail pages
- π₯οΈ Multi-valued attribute value counts on Metaverse Object detail pages now display with thousand separators for readability
0.9.0 - 2026-04-07ΒΆ
AddedΒΆ
100K Object Scale (#451, #437, #438)ΒΆ
JIM now supports deployments of 100,000+ objects, validated by Scale100K integration tests across the full import, sync, and export pipeline. A bounded memory architecture ensures stable, predictable resource usage regardless of dataset size.
- β¨ Bounded memory sync and export pipelines: change tracker cleared at every page boundary and caches loaded per-page instead of upfront, enabling 100K+ object operations without out-of-memory crashes
- β¨ Partition-scoped deletion detection for full imports: deletion detection is now scoped to the imported partition, preventing CSOs from other partitions being incorrectly marked as obsolete during large-scale imports
- π₯οΈ Import processing now displays throughput (objects/sec) and ETA in progress messages, completing progress tracking coverage across all long-running phases
.NET 10 Migration (#174)ΒΆ
- β¨ Migrated from .NET 9.0 (STS) to .NET 10.0 (LTS), extending support from November 2026 to November 2028
- β¨ Upgraded all NuGet packages to .NET 10-compatible versions, including EF Core 10, MudBlazor 9, and Humanizer 3
- β¨ Replaced Swashbuckle with built-in
Microsoft.AspNetCore.OpenApi+ Scalar for modern API documentation UI - π All Docker containers now run as non-root (
USER app, UID 1654), improving security posture for enterprise deployments - π Docker container hardening (#333): read-only root filesystem, dropped all Linux capabilities with selective re-add, and
no-new-privilegesflag on all application containers - π Moved CIFS/SMB utilities and capabilities from Web to Worker container, applying least-privilege principle (only the Worker executes file connector operations)
- π¦ Docker images migrated from Debian Bookworm to Ubuntu 24.04 Noble base with pinned SHA256 digests
- π¦ Added
global.jsonto pin .NET 10 SDK version across all environments
Service Settings REST API & PowerShell CmdletsΒΆ
- β¨ New REST API for managing service settings (
GET/PUT/DELETE /api/v1/service-settings), enabling automation of change tracking, sync page size, history retention, and other operational settings - β¨ New PowerShell cmdlets:
Get-JIMServiceSetting,Set-JIMServiceSetting,Reset-JIMServiceSettingfor managing service settings from the command line or automation scripts
Data Integrity Validation (#465)ΒΆ
- π Metaverse attribute operations now validate data integrity before executing: deleting attributes with stored values, deleting attributes referenced by Synchronisation Rules, and removing object type mappings with existing data all return structured validation errors instead of silently corrupting state
PowerShell Module EnhancementsΒΆ
- β¨
-Nameparameter added to sixGet-JIM*cmdlets (Get-JIMRunProfile,Get-JIMSyncRule,Get-JIMApiKey,Get-JIMCertificate,Get-JIMRole,Get-JIMConnectorDefinition), enabling direct filtering withoutWhere-Object - β¨ New
Get-JIMPendingDeletioncmdlet with List, Count, and Summary parameter sets for monitoring objects awaiting deletion - β¨ New
Get-JIMActivityChildrencmdlet for retrieving child activities of a parent activity
Integration Test Runner EnhancementsΒΆ
- β¨
-LogLevelparameter for integration test runner: override log verbosity (Verbose/Debug/Information/Warning/Error/Fatal) for the test run without permanently modifying.env - β¨
-DisableChangeTrackingswitch for integration test runner: disable CSO and MVO change tracking during large-scale tests to reduce database writes and improve throughput - π₯οΈ Interactive menus for log level and change tracking selection when running tests without explicit parameters
FixedΒΆ
- π Safe cancellation for sync operations (#339): when an admin cancels a running Full Sync or Delta Sync, the current page's flush pipeline now completes before exiting. Previously, cancellation could leave orphaned Metaverse Objects without corresponding Pending Exports, causing target systems to silently miss updates.
- π Fixed import tasks continuing to process after cancellation (#339); cancelling a Full Import or Delta Import from the Operations Queue now stops the import between pages and skips persistence. Previously, the import processor ignored the cancellation signal and ran to completion.
- π Fixed cancelled tasks having their status overwritten to Completed or Failed; the Worker now correctly preserves the Cancelled activity status instead of overwriting it when the processor finishes.
- π Fixed sync progress bar showing inflated object counts (CSOs + Pending Exports) instead of just CSOs; progress percentage and ETA are now accurate for Full Sync and Delta Sync
ChangedΒΆ
- β‘ LDAP export concurrency is now auto-tuned based on the detected directory server type; AD DS and OpenLDAP default to 16 concurrent operations (up from 4), while Samba AD and unknown directories remain at 4 for compatibility. Administrators who have manually configured the value will not be affected.
PerformanceΒΆ
- β‘ Selective attribute loading for full sync: unchanged CSOs (based on watermark comparison) skip attribute value loading and Attribute Flow entirely, dramatically reducing I/O for large-scale repeat syncs
- β‘ Eliminated redundant per-page COUNT queries during sync; total count is now passed from sync start, removing 200+ unnecessary full-table scans at 100K objects
- β‘ Default sync page size increased from 500 to 1,000, halving the number of database round-trips per sync run
- β‘ Sync progress updates now use direct SQL instead of EF Core change tracker, reducing per-page overhead
- β‘ Removed explicit RepeatableRead transactions from sync page loading; PostgreSQL MVCC provides sufficient consistency without the round-trip overhead
- β‘ Pending Exports table on CSO detail page now uses server-side paging; pages with thousands of pending changes (e.g. 10K member adds) load instantly instead of rendering all rows at once
- β‘ All export evaluation and Pending Export cache queries now use
AsNoTracking, eliminating unnecessary entity tracking overhead during sync - β‘ Per-page memory diagnostics logging: administrators can monitor memory usage across sync pages to verify bounded memory behaviour
0.8.1 - 2026-04-02ΒΆ
AddedΒΆ
- β¨ Pre-export CREATEβDELETE reconciliation β when an object is created and then deleted before export runs, the redundant Pending Exports are automatically cancelled instead of failing during export (#218)
PerformanceΒΆ
- β‘ Export rule evaluation optimised to reduce per-MVO processing cost, improving sync performance for configurations with many export rules (#417)
- β‘ Active Directory schema discovery now batches LDAP queries, reducing connection round-trips during schema import (#433)
FixedΒΆ
- π Fixed entity tracking conflict during cross-page reference resolution at scale β Full Sync no longer fails with "ConnectedSystemObject cannot be tracked" when groups share members across resolution batches (10,000+ users)
- π Error messages no longer display the internal "EMERGENCY UPDATE" prefix β user-facing messages now show clean, actionable text (#448)
- π Activity and RPEI detail page breadcrumbs are now context-aware, showing the correct navigation path based on how the page was reached
- π Sanitised
Request.Methodin global exception handler logging to prevent log injection (CWE-117) (#444)
0.8.0 - 2026-04-01ΒΆ
AddedΒΆ
OpenLDAP Connector Support (#72)ΒΆ
- β¨ Full OpenLDAP and RFC 4512-compliant LDAP directory support β connect to OpenLDAP, 389 Directory Server, and other standards-based LDAP directories alongside Active Directory
- β¨ Automatic directory type detection from rootDSE (Active Directory, OpenLDAP, Generic LDAP) with per-type external ID handling (objectGUID vs entryUUID)
- β¨ RFC 4512 schema discovery β object classes and attribute types parsed from the subschemaSubentry with OID-based data type mapping and superclass hierarchy walking
- β¨ Multi-suffix partition discovery via rootDSE namingContexts for non-AD directories
- β¨ Accesslog-based delta import for OpenLDAP β queries
cn=accesslogfor incremental changes with automatic fallback to full import - β¨ Parallel import with configurable concurrency β each container/objectType combination runs on its own LDAP connection, working around RFC 2696 paging cookie limitations
- β¨ Transparent
groupOfNamesplaceholder member handling β automatically manages the RFC 4519 MUST constraint so administrators never see placeholder entries in the metaverse - β¨ DN-aware RDN attribute detection for correct export naming
- β¨ Partition-scoped imports β Run Profiles can target a specific partition instead of importing all selected partitions (#353)
Worker Redesign (#394)ΒΆ
- β¨ Pure domain engine (
ISyncEngine) β 7 stateless methods with zero I/O dependencies, making core sync logic independently testable with plain objects - β¨ Formal data access boundary (
ISyncRepository) β ~80-method interface separating Worker data access from shared EF Core repositories, with purpose-built in-memory implementation for tests - β¨ Dependency injection throughout Worker and Scheduler β
IJimApplicationFactory,IConnectorFactory, per-task context isolation
Bundled Keycloak IdP for Development (#197)ΒΆ
- β¨ Zero-config SSO β
jim-stackstarts a pre-configured Keycloak instance alongside JIM; developers sign in immediately withadmin/admin - β¨ Pre-configured realm with
jim-web(confidential + PKCE) andjim-powershell(public + PKCE) clients,jim-apiscope, and two test users - β¨
.env.exampledefaults point to the bundled Keycloak β no manual IdP configuration needed for local development - β¨
jim-keycloak/jim-keycloak-stop/jim-keycloak-logsaliases for standalone Keycloak (F5 debugging workflow) - β¨ Keycloak admin console accessible at
http://localhost:8181 - π HTTP OIDC authority support for development (RequireHttpsMetadata conditionally disabled)
Object Type Icons (#92)ΒΆ
- π₯οΈ Configurable icons for Metaverse Object Types β assign icons to object types, displayed across the homepage, navigation menu, schema pages, and object detail views
Pending Export ManagementΒΆ
- π₯οΈ Pending Export detail page with grouped attribute changes, capped multi-valued attribute loading, and server-side paginated drill-down for large change sets
- π₯οΈ
Get-JIMPendingExportandGet-JIMConnectedSystemObjectPowerShell cmdlets with corresponding API endpoints - π₯οΈ Pending Exports list now shows display names instead of raw GUIDs
Activity MonitoringΒΆ
- π₯οΈ Auto-refresh polling on the activity list page β data updates automatically without manual refresh
- π₯οΈ Pause/resume toggle for auto-refresh polling
- π₯οΈ Compact determinate progress bar on the History tab for in-progress activities
- π₯οΈ Phase-specific activity messages during imports β "Connecting to Connected System" and "Importing objects from Connected System" show the current phase before object processing begins (#342)
Run Profile EditingΒΆ
- π₯οΈ Run Profile editing UI β edit name, file path, partition, and page size for existing Run Profiles
- β¨
SupportsFilePathsconnector capability β File Path fields only appear for connectors that use file-based import/export - β¨
SupportsPagingconnector capability β Page Size controls only appear for connectors that support paged queries
Navigation and LayoutΒΆ
- π₯οΈ Browser back/forward navigation support for all tabbed pages via URL query parameters
- π₯οΈ Tabs view mode for Metaverse Object details β attribute categories displayed as horizontal tabs alongside existing form and table views
- π₯οΈ Expanded Target section in the Operations sidebar with type-specific links
- π₯οΈ Connector capabilities grouped by category on the detail page
InfrastructureΒΆ
- π¦ Docker healthchecks for Worker and Scheduler β file-based heartbeat monitoring detects stalled service loops (#185)
- β¨ Multi-valued to single-valued import Attribute Flow β when a multi-valued source Attribute Flows to a single-valued target, JIM automatically selects the first value and records a warning (#435)
PerformanceΒΆ
Worker Redesign (#394)ΒΆ
- β‘ Parallel multi-connection writes β
ParallelBatchWritersplits bulk database writes across N concurrent PostgreSQL connections, utilising multiple CPU cores during save phases. Configurable viaJIM_WRITE_PARALLELISMenvironment variable - β‘ COPY binary protocol for bulk inserts β CSO creates, RPEIs, MVO creates, and sync outcomes now use PostgreSQL's COPY binary import, eliminating SQL parsing overhead and parameter limits (#338)
- β‘ Worker-exclusive bulk SQL in
SyncRepositoryβ hot-path operations (RPEI persistence, CSO bulk create, Pending Export operations) moved from shared repositories into dedicated partial classes, reducing shared repo surface by 1,200+ lines
Import Pipeline (#427, #440)ΒΆ
- β‘ Import CSO matching now uses a pre-fetched dictionary for O(1) external ID lookups, replacing N per-object database queries with a single bulk query at import start β eliminates the dominant bottleneck in full imports (#440)
- β‘ Import reference resolution is now case-insensitive (matching RFC 4514 DN semantics) and batches sort non-referencing objects first with committed ID tracking β eliminates the expensive post-import LOWER() fixup SQL query (#427)
- β‘ Two-phase parallel write commits CSO rows before attribute values, giving cross-partition references full FK visibility and eliminating post-import fixup queries (#427)
Sync and ExportΒΆ
- β‘ Immediate MVO deletion (zero grace period) skips unnecessary attribute recall and export evaluation, eliminating wasted database round-trips (#390)
- β‘ Deferred export resolution progress reporting throttled to every 50 items instead of per-item, eliminating ~540 unnecessary database round-trips for typical batches (#426)
- β‘ Bulk RPEI and CSO change persistence timeouts increased to 300 seconds for large imports (#426)
- β‘ Log file rolling size reduced from 500 MB to 50 MB per file (100 files retained, ~5 GB max per service)
FixedΒΆ
- π Attribute change history is no longer cascade-deleted when a metaverse or Connected System attribute definition is removed β the FK is set to null and snapshot
AttributeName/AttributeTypeproperties preserve the audit trail indefinitely (#58) - π Expression attribute lookups (e.g.
mv["Department"]) are now case-insensitive, preventing silent failures when attribute name casing in expressions did not exactly match stored names (#341) - π Pending Export reconciliation now correctly matches all 8 attribute data types β Boolean, Guid, and LongNumber exports previously failed to reconcile and appeared permanently stuck (#263)
- π Deferred export progress bar no longer shows values exceeding 100%
- π Progress bars on the History tab now update in real-time instead of freezing after initial page load
- π Worker database operations no longer time out during large imports β command timeout increased from 30s default to 300s (#426)
- π Connector-level warnings (e.g. delta import fallback) now appear as activity banners instead of phantom RPEIs with no CSO association
- π MVO reference attribute foreign keys are now reliably persisted across cross-page and cross-batch scenarios
- π MVO change tracking no longer crashes when recording deletion changes for objects with unloaded reference navigation properties
ChangedΒΆ
Worker Redesign (#394)ΒΆ
- π All Worker and Workflow tests (~1,300) migrated from mocked
DbContextto purpose-builtInMemoryData.SyncRepository, eliminating three-way code path divergence between production, workflow tests, and unit tests -
π Removed ~32 try/catch EF fallback blocks from repository files (-642 lines) β production and test code paths are now identical
-
π Object type names from camelCase LDAP schemas (e.g.
groupOfNames) now display correctly as "Group Of Names" - π Error type column merged inline with outcome chips on the activity detail page
0.7.1 - 2026-03-19ΒΆ
FixedΒΆ
- π¨ Sidebar background colour in the Navy O6 theme now matches the page background for a seamless, cohesive look
0.7.0 - 2026-03-19ΒΆ
AddedΒΆ
- β¨
GET /api/v1/userinfoendpoint β returns the authenticated user's JIM identity, roles, and authorisation status without requiring Administrator privileges - β¨
Connect-JIMnow verifies authorisation after authentication and warns if the user has no JIM identity, with clear guidance to sign in via the web portal first - π₯οΈ Improved 403 error messages in the PowerShell module β now explains the likely cause (no JIM identity) and how to resolve it
- π₯οΈ Properties tab on the Metaverse Object detail page β shows creation date, last modified, and clickable initiator links
- π₯οΈ Form and table view toggle on the Metaverse Object detail page
- π₯οΈ Server-side paginated dialog for large multi-valued attributes on the MVO detail page
- π₯οΈ Object type chip prefix on reference values in MVO table view
- π₯οΈ Server-side paging on the schema attributes table
- π₯οΈ Sortable columns on the staging object attribute table
- β¨ Activity tracking for initial admin user creation
- π
Connect-JIMnow skips the authorisation check when using API key authentication
ChangedΒΆ
- π¨ New default theme with a refined colour palette β deeper backgrounds, improved button and chip contrast across dark and light modes, and better visual hierarchy for a more polished, readable experience
- π¨ Switched web font to Inter β self-hosted for air-gapped deployment, delivering improved readability and a modern feel
- ποΈ Removed legacy themes consolidated into the new default
- π "Connected System Objects" pages renamed to "Staging" with cleaner URL structure and improved introductory UX
- π "Data Generation" renamed to "Example Data" across the entire stack for consistent naming β models, API routes (
/example-data/), PowerShell cmdlets (Get-JIMExampleDataTemplate,Invoke-JIMExampleDataTemplate), database tables, and UI all now share the "Example Data" family prefix - β‘ Database migrations flattened into a single
InitialCreatemigration for faster first-start performance and simpler codebase - π₯οΈ Redesigned object matching tab layout and combined status chips on the RPEI detail page
FixedΒΆ
- π Resolved intermittent DbContext concurrency errors across all Blazor Server pages β overlapping async lifecycle methods (e.g. data load and table pagination) no longer share a single database context
- π FK violation in import change history bulk persistence no longer causes import failures
- π
HasPredefinedSearchesnow returns the correct value for object types with predefined searches - π Spurious Pending Exports no longer surface during full sync operations
Deleted Object Change HistoryΒΆ
- π Deleted MVO change history now shows the full timeline of prior changes (Created, AttributeFlow, Disconnected) β previously only the Deleted record was visible due to a broken FK correlation after deletion
- π Final attribute values are now captured on MVO deletion change records, showing exactly what the object looked like before it was removed
- π Final attribute values are now captured on CSO deletion change records β previously only the external ID and display name were preserved
- π MVO deletion no longer fails with FK constraint violations when the deleted object is referenced by other MVOs (e.g., as a Manager) or by change history records
Pending Export Reference Display (#404)ΒΆ
- π Pending Export reference attributes (e.g. group members) now display meaningful identifiers (DN, External ID) instead of raw GUIDs with a misleading "unresolved reference" warning
- π References to objects processed later on the same sync page are now resolved via a post-page resolution pass
- π Resolved reference attributes (e.g. group members) now appear in export causality tree attribute changes β previously they were silently dropped
- π₯οΈ Pending Export references show a "Pending Export" indicator to distinguish them from fully resolved and genuinely unresolved references
Database Resilience (#408, #409)ΒΆ
- π Transient database errors now return HTTP 503 (Service Unavailable) with a
Retry-Afterheader instead of HTTP 400 (Bad Request) - π Cross-batch reference fixup hardened against database timeouts and FK gaps at scale
- β‘ Transient database failures handled gracefully at API level with retry guidance
- β‘ Connection pool sizing reduced from 50 to 30 per service to leave headroom within PostgreSQL's
max_connections - π¦ Development database (
db.yml) now explicitly setsmax_connections=200to match the full Docker stack
PerformanceΒΆ
- β‘ MVO detail page now caps multi-valued attribute values with server-side pagination, dramatically reducing load time for objects with large MVAs
- β‘ Pending Export reconciliation query optimised with sub-phase progress messages
0.6.1 - 2026-03-15ΒΆ
AddedΒΆ
- β¨ Child activity tracking β sync activities now show nested child activities with drill-down navigation (#298)
- β¨
Clear-JIMConnectedSystemPowerShell cmdlet β wipe all objects from a Connected System without deleting the configuration (#365) - π‘οΈ Global error boundary catches unhandled rendering exceptions in the UI β instead of a broken page, users see a friendly error message with "Try Again" and "Go to Dashboard" recovery options (#167)
- π₯οΈ "Has child activities" filter on the Activities list and Operations history pages
- π₯οΈ Contextual page heading icons, refined operation/outcome chip colours, and improved causality tree display
- π Log injection sanitisation across all logging calls to prevent CWE-117 log forging
- π Trivy container image scanning added to CI pipeline
ChangedΒΆ
- π Built-in "Employee Status" metaverse attribute replaced with the more generic "Status"
FixedΒΆ
- π Cross-batch and cross-run reference resolution now correctly handles out-of-order LDAP imports and foreign key persistence
- π Cross-page reference RPEIs are now merged instead of creating duplicates
- π LDAP AddRequest now chunks large multi-valued attributes to avoid directory server size limits
- π Default
userAccountControlto 512 on Create exports via Coalesce, preventing AD account creation failures - π Parent activity progress messages no longer overwritten by child activities
- π Activity detail page correctly reloads when navigating between parent and child activities
- π Group member change history no longer shows "(identifier not recorded)" for members imported in a later batch β the DN string is now recorded when the referenced CSO hasn't been persisted yet at change history time
PerformanceΒΆ
- β‘ Change history and RPEI persistence now uses PostgreSQL COPY binary import, dramatically reducing write time for large sync operations (#398)
- β‘ Cross-batch reference fixup skipped entirely when no unresolved references exist (#398)
- β‘ Partial database indexes added for cross-batch reference fixup queries (#397)
0.6.0 - 2026-03-12ΒΆ
AddedΒΆ
- β¨ Disconnection causality tracking β causality tree now traces MVO attribute changes and deletion fate during disconnection and recall, showing exactly what happened and why (#392)
- β¨ Reference attributes rendered as clickable links on RPEI detail page for easy navigation to related objects
- π₯οΈ Filter controls on the Activities list page for quick searching by status, connector, and profile
- π₯οΈ Initiated-by name now included in activity search results
FixedΒΆ
- π Export activity detail page now shows display name for Create-type exports even after the target CSO is later deleted β display name is now snapshotted from the Pending Export's attribute changes at export time
- π Causality tree no longer shows a spurious attribute count chip on MVO Projected nodes when reference attributes were merged into the projection
- π Export runs no longer silently skip Pending Exports when a batch contains only deferred or ineligible items β all staged exports are now reliably processed in a single export run
- π Activity detail page now shows display name and object context for Create-type Pending Exports surfaced during sync (previously showed dashes as no CSO exists yet)
- π RPEI detail page now shows Pending Export attribute changes for staged (informational) Pending Exports, not only for error states
- π Causality tree no longer shows unrelated Pending Exports when a secondary import connector syncs while a previous connector's Create exports are still queued β only exports caused by the current sync's attribute changes are shown
- π Group membership exports no longer arrive empty β resolved reference foreign keys are now persisted during import
- π Resolved reference values now correctly persisted after export, preventing data loss on subsequent sync runs
- π Duplicate Pending Exports no longer accumulate β stale entries are automatically self-healed
- π Activities with unhandled errors now correctly marked as completed with error instead of appearing successful
- π Multi-valued attributes in LDAP group member exports are now consolidated into a single AddRequest, fixing partial membership writes
- π Export batch queries now include CSO object type, resolving objectClass errors in LDAP targets
- π Single-valued attribute duplicates no longer occur during Pending Export merges
PerformanceΒΆ
CSO Large MVA Pagination (#320)ΒΆ
- β‘ CSO detail page and API now load capped MVA values (first 100) instead of the full collection, dramatically reducing memory and load time for objects with 10K+ multi-valued attributes
- β¨ New paginated attribute values API endpoint (
GET /api/connected-systems/{csId}/objects/{csoId}/attributes/{attributeName}/values) with server-side search and pagination - π₯οΈ MVA dialog now fetches data on demand with server-side search and pagination β no longer holds the full value set in Blazor circuit memory
- β¨ API responses include per-attribute value summaries showing total count, returned count, and whether more values are available
Large-Scale Import OptimisationΒΆ
- β‘ Full import operations now handle 100K+ objects without out-of-memory failures through batch processing, raw SQL persistence, and incremental memory release
- β‘ Export operations at scale now batch-load to eliminate EF change tracker overhead
- β‘ Real-time batch progress reporting during large CSO persistence operations
0.5.0 - 2026-03-08ΒΆ
AddedΒΆ
- β¨ Self-contained Object Matching Rules β Synchronisation Rules now carry their own matching logic for import and export, enabling fully portable rule definitions (#386)
- β¨ CRUD API endpoints for Synchronisation Rule Object Matching Rules (
GET,POST,PUT,DELETE/api/v1/synchronisation/sync-rules/{id}/matching-rules) - β¨ Matching mode switching API β toggle between simple and advanced object matching per Connected System
- π₯οΈ Sortable Object Mapping and Capabilities columns on the Synchronisation Rules page
FixedΒΆ
- π Setup script now correctly detects Docker Desktop alongside Docker Engine
0.4.0 - 2026-03-05ΒΆ
AddedΒΆ
- β¨ One-command deployment β new interactive installer auto-detects the latest release, configures SSO and database, and starts JIM in minutes
- π¦ Production-ready Docker Compose configuration β deploy JIM from pre-built images without needing source code
- π¦ Standalone deployment files attached to each GitHub release for easy download without cloning the repository
- β¨ Welcome banner displayed on successful PowerShell connection
- π Comprehensive Deployment Guide covering prerequisites, topology options, TLS, reverse proxy, upgrades, and monitoring
- π₯οΈ Sortable columns on the Attribute Flow table
- π₯οΈ Filter controls on the Attribute Flow table
- β¨ Edit Attribute Flow mappings inline on the Synchronisation Rule detail page
- π₯οΈ Synchronisation Rule detail page redesign with expression highlighting, table/card views, and improved layout
- π₯οΈ Synchronisation Rules quick link on the homepage dashboard
- π₯οΈ Filter controls on the Connected System Objects list page
- π₯οΈ Full-width layout option for table-heavy pages
- π₯οΈ Confirmation dialog before deleting Attribute Flow mappings
- β¨
Get-JIMMetaverseObject -Allβ automatically paginates through all results in a single command - β¨ Pronouns attribute support (#360, #362)
- β¨ Sync Outcome Graph β full causal tracing of every change during synchronisation, showing exactly why each object was projected, joined, updated, disconnected, or exported (#363)
- β¨ Configurable sync outcome tracking level (None / Standard / Detailed) β control how much causal detail is recorded per synchronisation (#363)
- π₯οΈ Colour-coded outcome summary chips on Activity Detail rows for at-a-glance sync result visibility (#363)
- π₯οΈ Filter activity results by outcome type β quickly find projections, joins, Attribute Flows, exports, and more (#363)
- β¨ Export change history β drill into exactly which attributes were changed on each exported object, with before/after values
- π Hardened release pipeline with container scanning, SBOM attestation, and build validation
- π¦ Application blocks readiness until database migrations are applied
ChangedΒΆ
- π Replaced "Change Type" filter with richer outcome type filtering on the Activity Detail page (#363)
- π Renamed Activity statistics labels for clarity ("Stats" β "Outcomes", "Unchanged" β "CSOs Unchanged")
FixedΒΆ
- π
Get-JIMMetaverseObjectnow correctly returns all results when page size exceeds 100 - π Fixed spurious export operations being generated for objects queued for immediate deletion
- π Activity Attribute Flow statistics now show accurate object counts instead of inflated per-attribute counts
- π Connected System Object join state now reliably persisted during synchronisation
- π Activity Detail rows now show display name and object type even after the Connected System Object has been deleted (#363)
- π OIDC
Identity.Namenow correctly resolved when claims are unmapped - π Two-pass CSO processing prevents false
CouldNotJoinDueToExistingJoinerrors during synchronisation
PerformanceΒΆ
- β‘ Sync engine performance β up to 37% faster synchronisation through optimised batch persistence of activity results (#338)
0.3.0 - 2026-02-25ΒΆ
AddedΒΆ
Scheduler Service (#168)ΒΆ
- Schedule data model with cron and interval-based trigger support
- Background scheduler service with 30-second polling cycle
- Multi-step schedule execution with sequential and parallel step modes
- Schedule management REST API (CRUD, enable/disable, manual trigger, execution monitoring)
- Schedule management UI integrated into Operations page with tabbed interface
- Custom cron expression support with pattern-based UI
- Queue all schedule steps upfront for near-instant step transitions
- PowerShell cmdlets:
New-JIMSchedule,Get-JIMSchedule,Set-JIMSchedule,Remove-JIMSchedule,Enable-JIMSchedule,Disable-JIMSchedule,Add-JIMScheduleStep,Remove-JIMScheduleStep,Start-JIMSchedule,Get-JIMScheduleExecution,Stop-JIMScheduleExecution - Scheduler integration tests (Scenario 6)
Change History (#14, #269)ΒΆ
- Full change tracking for Metaverse Objects and Connected System Objects with timeline UI
- Initiator and mechanism tracking (User, API, Sync, System)
- Deleted objects view with change audit trail
- Configurable retention and cleanup
- Change history records for data generation operations
- Granular per-change-type statistics replacing aggregate activity stats
Progress Indication (#246)ΒΆ
- Real-time progress bars for running operations on Operations page
- Percentage tracking and contextual messages
- Progress reporting for deferred exports and cross-page reference resolution
- Import progress tracking with pagination support
- Hidden page number indicator for single-page imports
DashboardΒΆ
- Home page redesigned as an informative dashboard
- Hover effect on clickable dashboard cards
- Application version displayed in page footer
Security and AuthenticationΒΆ
- Interactive browser-based authentication for the PowerShell module
- API key authentication support for sync endpoints
- Just-in-time initial admin creation on first sign-in (replaces startup-time creation)
LDAP Schema DiscoveryΒΆ
- Attribute writability detection during schema discovery
- Support for LDAP omSyntax 66 (Object(Replica-Link)) mapping to Binary data type
- LDAP description attribute plurality override on AD SAM-managed classes
Data GenerationΒΆ
SplitandJoinfunctions for multi-valued attribute transforms- Centralised GUID/UUID handling with
IdentifierParserutility
PowerShell ModuleΒΆ
- Flattened module directory structure
- Version endpoint with server version display on
Connect-JIM - Module now includes 75 cmdlets (11 new scheduler cmdlets added to the 64 from 0.2.0)
UI EnhancementsΒΆ
- Searchable dialog for large multi-valued CSO attributes
- CSO attribute table sizing and column order improvements
- Persist navigation drawer pin state to user preferences
- Persist category expansion state per object type in user preferences
- Show all attributes on RPEI projection detail page
- Culture-aware thousand separators on all numeric statistics
- Culture-specific day-of-week ordering in schedule configuration
- Theme preview page at
/admin/theme-preview - Demo mode for Operations Queue
Integration TestingΒΆ
-SetupOnlyflag for integration test runner-CaptureMetricsflag for performance metrics on large templates-ExportConcurrencyand-MaxExportParallelismrunner parameters- Scenario 8: Samba AD group existence checks with retry
Assert-ParallelExecutionTimingvalidation helperjim-test-allalias for comprehensive test runs (unit + workflow + Pester)
Logging and ObservabilityΒΆ
- PostgreSQL logs integrated into unified Logs UI
- Diagnostic logging for cache operations and stale entry invalidation
- Separate Disconnected RPEI recorded when processing source deletions
InfrastructureΒΆ
- Automated Structurizr diagram export via
jim-diagramsalias - Review-dependabot Claude Code skill for dependency PR review
ChangedΒΆ
- Purple theme refresh with vibrant logo-inspired colours
- Navy-o5 dark theme improvements
- Execution detail API returns all parallel sub-steps with
ExecutionModeandConnectedSystemId - Expression models and
IExpressionEvaluatormoved to JIM.Models for broader use - Change tracking built into
MetaverseServerCreate/Update methods - JIM version injected into diagram metadata from VERSION file
- Build timestamp added to dev version suffix
- Reduced logging level for high-rate sync events to improve log readability
- Removed hardcoded
JIM_LOG_LEVELoverrides from compose files - Removed fixed height constraint from MVA table on MVO detail page
- Description attribute categorised under Identity on MVO detail page
FixedΒΆ
- Cross-page reference persistence and export evaluation for
AsSplitQuerymaterialisation failures - Post-load SQL repair for
AsSplitQuerymaterialisation failures - LDAP export consolidation and drift merge for multi-valued attributes
- Null-value Update exports now correctly confirmed during reconciliation
- MVO Type included in cross-page reference resolution query
- EF Core identity conflicts during cross-page reference resolution and Pending Export reconciliation
- Pending CSO disconnections now accounted for when validating join constraints
- Connected System settings not persisting on save
- Partition column hidden on Run Profiles tab when connector doesn't support partitions
- Run Profile create/delete and dropdown positioning
- Container tree duplicates and selection not persisting
- Matching rule creation failing with duplicate key violation
ExecuteDeleteAsyncused for Pending Export deletion with inner exception unwrapping- Split child/parent
SaveChangescalls to prevent FK constraint violation FindTrackedOrAttachused for untracked Pending Export persistence- History cleanup interval respected across worker restarts
- Scheduler waits for full application readiness on startup
- Graceful worker cancellation instead of immediate task deletion
- Transient unresolved reference warnings downgraded to debug level
- Button styling improvements and error alert panel overflow prevention
- Visited link hover colour consistency
- Log external ID instead of empty GUID for unpersisted CSOs in reference resolution
- MVA table page size wired to global user preference
- Cache diagnostic logging and stale entry invalidation on external ID changes
- Integration test runner try/finally structure repaired
- Total execution time captured in integration test log files
PerformanceΒΆ
- Batch database operations for export processing (single
SaveChangesAsyncper batch instead of per-object) - Bulk reference resolution for deferred exports (single query instead of N+1)
- LDAP connector async pipelining with configurable "Export Concurrency" setting (1-16)
- Parallel batch export processing with per-system
MaxExportParallelismsetting (1-16) SupportsParallelExportconnector capability flag (LDAP: true, File: false)- Parallel schedule step execution (steps at the same index run concurrently via
Task.WhenAll) - Raw SQL for import and export bulk write operations (replacing EF Core bulk writes)
- Lightweight ID-only matching for MVO join lookups
- Skip CSO lookups entirely for first-ever imports on empty Connected Systems
- Service-lifetime CSO lookup index to eliminate N+1 import queries
- Tracker-aware persistence for untracked Pending Export entities
- Parallel in-memory Pending Export reconciliation using
Parallel.ForEach - Lightweight
AsNoTrackingquery for Pending Export reconciliation - Skip Pending Export reconciliation for CSOs without exports
- Parallel in-memory reference resolution using
Parallel.ForEach - Lightweight DB queries for batch reference resolution
- Raw SQL for
MarkBatchAsExecutingstatus update - Diagnostic instrumentation spans for export DB operations
- Worker heartbeat-based stale task detection and crash recovery
0.2.0-alpha - 2026-01-27ΒΆ
AddedΒΆ
PowerShell Module (61 new cmdlets, 64 total)ΒΆ
- Connected Systems management:
Get-JIMConnectedSystem,New-JIMConnectedSystem,Set-JIMConnectedSystem,Remove-JIMConnectedSystem - Schema management:
Import-JIMConnectedSystemSchema,Set-JIMConnectedSystemObjectType,Set-JIMConnectedSystemAttribute - Hierarchy management:
Import-JIMConnectedSystemHierarchy - Partition and container management:
Get-JIMConnectedSystemPartition,Set-JIMConnectedSystemPartition,Set-JIMConnectedSystemContainer - Connector definitions:
Get-JIMConnectorDefinition - Synchronisation Rules:
Get-JIMSyncRule,New-JIMSyncRule,Set-JIMSyncRule,Remove-JIMSyncRule - Synchronisation Rule Mappings with expression support:
Get-JIMSyncRuleMapping,New-JIMSyncRuleMapping,Remove-JIMSyncRuleMapping - Object Matching Rules:
Get-JIMMatchingRule,New-JIMMatchingRule,Set-JIMMatchingRule,Remove-JIMMatchingRule - Scoping Criteria:
Get-JIMScopingCriteria,New-JIMScopingCriteriaGroup,Set-JIMScopingCriteriaGroup,Remove-JIMScopingCriteriaGroup,New-JIMScopingCriterion,Remove-JIMScopingCriterion - Run Profiles:
Get-JIMRunProfile,New-JIMRunProfile,Set-JIMRunProfile,Remove-JIMRunProfile,Start-JIMRunProfile - Real-time progress tracking for Run Profile executions
- Activities:
Get-JIMActivity,Get-JIMActivityStats - Metaverse:
Get-JIMMetaverseObject,Get-JIMMetaverseObjectType,Set-JIMMetaverseObjectType,Get-JIMMetaverseAttribute,New-JIMMetaverseAttribute,Set-JIMMetaverseAttribute,Remove-JIMMetaverseAttribute - MVO deletion rule configuration
- API Keys:
Get-JIMApiKey,New-JIMApiKey,Set-JIMApiKey,Remove-JIMApiKey - Certificates:
Get-JIMCertificate,Add-JIMCertificate,Set-JIMCertificate,Remove-JIMCertificate,Export-JIMCertificate,Test-JIMCertificate - Security:
Get-JIMRole - Example Data:
Get-JIMExampleDataTemplate,Get-JIMExampleDataSet,Invoke-JIMExampleDataTemplate - Expressions:
Test-JIMExpression - History:
Get-JIMDeletedObject,Get-JIMHistoryCount,Invoke-JIMHistoryCleanup - Name-based parameter alternatives for all cmdlets (e.g.,
-ConnectedSystemNameinstead of-ConnectedSystemId)
API EndpointsΒΆ
- CRUD endpoints for Connected Systems (
POST,PUT/api/v1/synchronisation/connected-systems) - CRUD endpoints for Synchronisation Rules (
POST,PUT,DELETE/api/v1/synchronisation/sync-rules) - CRUD endpoints for Run Profiles (
POST,PUT,DELETE/api/v1/synchronisation/connected-systems/{id}/run-profiles)
InfrastructureΒΆ
- Release workflow for automated builds and publishing
- Air-gapped deployment bundle support
- PowerShell Gallery publishing
ChangedΒΆ
- Server-side filtering and sorting for MVO type list pages
0.1.0-alpha - 2025-12-12ΒΆ
AddedΒΆ
Core PlatformΒΆ
- Initial development release
- Core identity management functionality
- Blazor web interface
- REST API
- PostgreSQL database support
- Docker containerisation
- CSV connector
- Basic synchronisation engine
PowerShell Module (3 cmdlets)ΒΆ
- Initial preview release published to PSGallery
- Connection management:
Connect-JIM,Disconnect-JIM,Test-JIMConnection
InfrastructureΒΆ
- Release workflow for automated builds and publishing
- Air-gapped deployment bundle support
- PowerShell Gallery publishing