APIKeyService.List scanned created_utc straight into time.Time, which the
modernc.org/sqlite driver returns as a string — surfacing as a 500 "Failed
to list API keys". Scan it into a string and parse. Regression test covers
the create+list round-trip (created_utc parsed, scope preserved).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add client-side pagination (TablePagination) to lists that could grow long
and cause endless scroll:
- Object Viewer search results
- Object attribute detail dialog
- Windows certificate store list (Security)
- Rule preview matched objects (previously hard-capped at 100 with no paging)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The object viewer showed raw bytes for binary attributes. Format them for
display: objectGUID as a canonical GUID, objectSid/sIDHistory as S-1-… SID
strings, and any other non-printable value as base64. Applied in the
query-preview path that the object viewer uses; printable values pass through.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Toggling LDAPS in the connection form now auto-sets the port (636 on / 389
off when it's still the other default) and enables "Allow invalid certs",
because a non-domain-joined host usually can't validate the DC's LDAPS
certificate. This fixes the common "existing connection was forcibly
closed" seen when LDAPS was enabled while the port stayed 389 (dialing TLS
to the plaintext port). Helper text explains the traffic is still encrypted.
- LDAP client sets tls ServerName to the host so verification succeeds when a
DC cert IS trusted (ignored under InsecureSkipVerify).
- Backups retention reduced from 10 to 3.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Firewall:
- On service initialize/install, create an idempotent inbound allow rule
("OrchestrAD") for the configured listen port, scoped to RFC 1918 private
ranges plus CGNAT (10/8, 172.16/12, 192.168/16, 100.64/10). The rule is
deleted-then-added so it always reflects the current port, and removed on
service uninstall. Best-effort (needs admin; the MSI custom action and
service run elevated); no-op off Windows. Verified the netsh rule lands
with the expected port and remote-address scoping.
MSI:
- Skip the license/EULA page (Welcome now goes straight to the install
directory), since it was blank. A standard short notice is kept in
license.rtf only so the stock license control resolves at build time.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
When TLS is in auto (self-managed) mode, install the generated root into the
LocalMachine "Root" (Trusted Root CAs) store and the intermediate into the
"CA" (Intermediate CAs) store, so clients on this host trust the served
chain without manual import. Runs on every ensure/renewal with a replace
disposition, so it is idempotent and a renewed CA supersedes the previous
one. Best-effort (needs admin; the Windows service runs as LocalSystem);
a no-op on non-Windows.
Verified: OrchestrAD Root CA appears in LocalMachine\Root and the
Intermediate in LocalMachine\CA after startup.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
A new Object Viewer page: pick a connection, choose an object type and search
by name (or drop in a raw LDAP filter and a search base), list the matches,
and drill into any object to see all its attributes with copy buttons for the
attribute name and value — so operators can discover the exact attributes and
values to put in a rule filter.
Built on the existing query-preview endpoint (now typed as QueryPreviewResult);
the detail view requests all attributes (["*"]). Added to the Directory nav.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Roles:
- Add GET /api/v1/roles (built-in SuperAdmin/Admin/Operator/Viewer) and
wire role assignment into user create/update (UserRepository.SetRoles /
GetRoleNames / ListRoles). User responses now include roles.
- User dialog gains a roles multi-select; the users list shows role chips.
OIDC / SSO config UI:
- Default role is now a dropdown populated from /roles.
- Issuer URL shows real provider examples (Entra/Okta/Google).
- Replace the confusing manual "Redirect URL" field with a read-only,
auto-derived callback URL (from the browser origin / public URL) plus a
copy button — the exact value to register at the IdP. The backend still
auto-derives the callback and honors an env override.
Verified: /roles lists the four roles; creating/updating a user with roles
round-trips through GET.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Make the API browsable/usable from Swagger UI without dev tools:
- Normalize chi's trailing slash on collection roots (Post("/")) so registry
detail and pagination attach — previously POST /ad-connections etc. showed
no request body.
- Document request bodies for the main create/update operations (connections,
credentials, schedules, api-keys, users, settings, tls mode/certificate,
query-preview, config import) with component schemas.
- Add standard page/pageSize query params to collection GETs.
- Add the X-API-Key security scheme alongside bearer so both auth methods
show in the Authorize dialog.
Test covers the trailing-slash normalization + body attachment.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The Windows-store certificate list only loaded after clicking a separate
"List certificates" button, so selecting the Windows-store option appeared
to show nothing. Fetch the certificates automatically when the source is
chosen (and the store is supported); the button becomes a Refresh. The
backend endpoint and windowsStoreSupported flag were already correct.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The SQLite database now lives at data/db/orchestrad.db instead of the data
root. db.New creates the db/ directory (SQLite will not) and, on first run,
moves a legacy data/orchestrad.db plus its -wal/-shm sidecars into db/ so
existing installations keep their data. Verified live: an existing demo
database migrated into data/db and all data (connections, rules, schedules)
was retained. Test covers the move + idempotency.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>