New Ory Agent Security is now live! Claim your complimentary test drive. Get Started!

Skip to main content

v26.3.17

v26.3.17

DSYNC_WEBHOOK_LOGS_TTL rejects a value that is not a duration

DSYNC_WEBHOOK_LOGS_TTL summed whichever <number><unit> tokens appeared anywhere in its value, so a typo carrying one was accepted as a retention rather than reported: 1d garbage kept logs for a day, and typo1h for an hour. The release that added the setting described this leniency, but it means a mistyped value changes how long logs are kept and says nothing about it.

A value must now be a duration end to end, such as 720h, 30d or 1d 12h. Anything else falls back to the seven-day default and logs a warning, which is what an unrecognized value has always done. Unset still means seven days and an empty value still keeps logs indefinitely, and now says so in a warning of its own, because a store with no expiry grows for as long as the deployment runs.

Breaking: a value that carries a duration inside something else kept logs for that duration and now keeps them for seven days. 1d garbage and typo1h are the shapes this catches. Check the value before upgrading if you set this; spaced durations such as 1d 12h are unaffected and still mean what they say.

SSO_TRACES_TTL and DSYNC_WEBHOOK_LOGS_TTL now resolve their retention through one shared function, so a duration, an empty value and a typo mean the same thing in both.

SSO_TRACES_TTL now applies in both directions

SSO_TRACES_TTL reached the trace store, which expires the records, but a second cleanup inside Polis deleted anything older than a hardcoded week and never read the setting. Whichever of the two was shorter won, so a value below seven days took effect and a value above it was silently capped at seven. The direction people set this for -- keeping traces long enough to investigate a failure reported weeks later -- was the one that did nothing.

That cleanup is gone and retention is the store's own expiry, so the setting now means what it says. Leaving it unset still keeps traces for seven days.

SSO_TRACES_TTL still takes a number of hours, and now also takes a duration such as 720h or 30d, matching DSYNC_WEBHOOK_LOGS_TTL. Set it to an empty value to keep traces indefinitely. A value that is not a duration end to end falls back to the seven-day default and logs a warning, so a typo never silently changes retention.

Setting it to an empty value now survives option normalization as well. The package filled an unset trace TTL with its seven-day default using a falsy check, which turned the zero that means indefinite back into seven days, so there was no way to ask for it at all.

Breaking: a deployment that declares SSO_TRACES_TTL with an empty value kept traces for seven days and now keeps them indefinitely. If you set the variable but leave it blank, either remove it or give it a retention such as 168h, otherwise the trace table grows for as long as the deployment runs. Polis logs a warning at startup whenever traces are kept indefinitely.

Bulk deletes now remove every record, not just the first page

Deleting all SSO connections for a tenant and product removed only as many connections as a single database read returns, which is capped by DB_PAGE_LIMIT and defaults to 50. The call still reported success, so a tenant with more connections than that was left with working SSO connections after what looked like a complete deprovision. Deleting traces for a product had the same problem and stopped after 50 traces.

Both now page through every matching record. If you have deprovisioned a tenant with more than DB_PAGE_LIMIT SSO connections, run the delete again to clear whatever was left behind, or list the connections for that tenant and product to check.

On MongoDB, paged reads could also repeat some records and skip others when they shared a creation time, which bulk imports make common. Each record now appears exactly once.

Find a customer's SSO connections and directories by tenant

The Admin Portal listed every SSO connection and every directory a page at a time with no way to ask for one customer's, so finding them meant paging until they appeared, and finding both meant doing it twice.

Both lists now take a tenant and a product and answer with that customer's records. A tenant in either list is also a link to the same tenant on the other, so a connection leads to the directories beside it and back.

Both terms are needed and each has to match what was stored: records are indexed by tenant and product together, so this is a lookup rather than a search. The same two parameters work on GET /api/admin/connections and GET /api/admin/directory-sync, which answer with the customer's records in full and no pagination.

Reading a customer's directories by tenant and product returned only as many as a single database read yields, which DB_PAGE_LIMIT caps and defaults to 50, so a customer with more directories than that saw a short list with nothing to indicate records were missing. It now reads through to the end, which also affects GET /api/v1/dsync and the setup link that lists a customer's directories.

Find a directory's users and groups by email or name

The Admin Portal listed a directory's users and groups a page at a time with no way to ask for one of them, so answering whether a person had been provisioned meant paging through the directory until their row appeared.

Both lists now take a term and answer with the matching record. The same parameters work on GET /api/admin/directory-sync/{directoryId}/users, which takes email, and GET /api/admin/directory-sync/{directoryId}/groups, which takes name. Either answers with the record itself and without pagination, since a directory holds one user per address and one group per name.

The term has to match what the identity provider sent, in full: users are indexed by directory and email together and groups by directory and name, so this is a lookup rather than a search. A partial address or name is a different key and finds nothing, which the field says above the list.

A user whose email address changed after they were provisioned, or a group that was renamed, is still indexed under the value it was created with, so the lookup answers to that value and not to the current one. Those records remain in the unfiltered list.

SCIM user and group listings now page past the first set of records

Listing directory users or groups over SCIM reported the first page as the whole directory, so an identity provider reading the list stopped after DB_PAGE_LIMIT records and never saw the rest. Group listings ignored startIndex and count altogether and answered every request with the same records.

Both endpoints now honour startIndex and count and report a totalResults that keeps the caller paging until the directory is exhausted. totalResults is a lower bound while more records remain and becomes exact on the final page, so a client that pages until it has seen totalResults records now reads the whole directory. If a directory looked short in your identity provider, run a synchronisation again to pick up the records that were never returned.