Commit Graph

5515 Commits

Author SHA1 Message Date
Bryan Frimin
981ed91572 Error-log all SAML assertion auth failures
SAML refusals are shown as generic authentication_failed, so log
them at Error for investigation and drop the unused SAML error
code mapper.

Signed-off-by: Cursor Agent <cursoragent@cursor.com>

Co-authored-by: Bryan FRIMIN <bryan@frimin.fr>
2026-07-24 22:25:25 +00:00
Bryan Frimin
6cce9b0a6e Log only unexpected auth callback failures
Expected refusals already have a dedicated auth error page, so
warn logs just add noise. Keep Error logging for generic
authentication failures that still need investigation.

Signed-off-by: Cursor Agent <cursoragent@cursor.com>

Co-authored-by: Bryan FRIMIN <bryan@frimin.fr>
2026-07-24 22:25:06 +00:00
Bryan Frimin
4e895df54f Fix TenantID construction in auth error test
TenantID is an [8]byte, so casting 1 does not compile. Use
NewTenantID like the other tests.

Signed-off-by: Cursor Agent <cursoragent@cursor.com>

Co-authored-by: Bryan FRIMIN <bryan@frimin.fr>
2026-07-24 21:48:35 +00:00
Bryan Frimin
77c57cc4a5 Drop redundant SAML auth error helper comment
Signed-off-by: Cursor Agent <cursoragent@cursor.com>

Co-authored-by: Bryan FRIMIN <bryan@frimin.fr>
2026-07-24 21:45:38 +00:00
Bryan Frimin
00ed11e30b Keep SAML auth failures generic for users
Specific SAML refusal reasons leak organization and account state.
Still redirect to the shared auth error page, but always use
authentication_failed while logging the real cause server-side.

Signed-off-by: Cursor Agent <cursoragent@cursor.com>

Co-authored-by: Bryan FRIMIN <bryan@frimin.fr>
2026-07-24 21:45:31 +00:00
Bryan Frimin
b8e5d279a0 Surface invalid OIDC state on auth error page
Missing, expired, or reused OIDC state left users on a JSON error
or a generic failure. Map those cases to invalid_state so they get
a clear prompt to restart sign-in.

Signed-off-by: Cursor Agent <cursoragent@cursor.com>

Co-authored-by: Bryan FRIMIN <bryan@frimin.fr>
2026-07-24 21:37:31 +00:00
Bryan Frimin
318789ec38 Cover magic-link and SAML failures on auth error page
Browser auth callbacks still returned JSON or used one-off pages
for several refusal reasons. Route OIDC email verification,
magic-link, and SAML ACS failures through /auth/error with stable
error codes so users always see an explanation.

Signed-off-by: Cursor Agent <cursoragent@cursor.com>

Co-authored-by: Bryan FRIMIN <bryan@frimin.fr>
2026-07-24 21:32:56 +00:00
Bryan Frimin
68e78a2230 Drop redundant validateIDTokenClaims comment
The check order is clear from the code and covered by tests.

Signed-off-by: Cursor Agent <cursoragent@cursor.com>

Co-authored-by: Bryan FRIMIN <bryan@frimin.fr>
2026-07-24 21:28:28 +00:00
Bryan Frimin
6c4a67d3f7 Route OIDC failures through shared auth error page
A dedicated personal-account page does not scale as more refusal
reasons appear. Redirect the OIDC callback to /auth/error with an
error code query parameter so the frontend can map codes to clear
user-facing messages.

Signed-off-by: Cursor Agent <cursoragent@cursor.com>

Co-authored-by: Bryan FRIMIN <bryan@frimin.fr>
2026-07-24 21:19:33 +00:00
Bryan Frimin
d1814d7051 Show why personal OIDC logins are refused
Personal Google and Microsoft accounts were rejected with a raw
JSON unauthorized response after the OIDC callback. Redirect to a
dedicated auth page that explains the enterprise-account
requirement, and check enterprise eligibility before xms_edov so
Microsoft consumer accounts get the same clear error.

Signed-off-by: Cursor Agent <cursoragent@cursor.com>

Co-authored-by: Bryan FRIMIN <bryan@frimin.fr>
2026-07-24 21:16:11 +00:00
Cursor Agent
b8c3fb086e Separate deadline append for wsl cuddling
require.True cannot sit directly above the deadlines append
under wsl_v5.

Signed-off-by: Cursor Agent <cursoragent@cursor.com>

Co-authored-by: Bryan FRIMIN <bryan@frimin.fr>
2026-07-24 23:08:38 +02:00
Cursor Agent
f844933b7d Fix wsl blank lines in DNS check paths
Separate cancel calls, error checks, and declarations so
golangci wsl_v5 accepts the cuddling rules.

Signed-off-by: Cursor Agent <cursoragent@cursor.com>

Co-authored-by: Bryan FRIMIN <bryan@frimin.fr>
2026-07-24 23:08:38 +02:00
Cursor Agent
fff8319e07 Use SplitSeq for CAA issuer domain labels
go fix on Go 1.26 rewrites strings.Split range loops to
SplitSeq; apply that so lint-go passes.

Signed-off-by: Cursor Agent <cursoragent@cursor.com>

Co-authored-by: Bryan FRIMIN <bryan@frimin.fr>
2026-07-24 23:08:37 +02:00
Cursor Agent
3948f47354 Apply CAA exchange timeout per label
A single dnsExchangeTimeout around CheckCAA let slow empty
answers at child names consume the budget before parent
policy was queried. Give each label its own exchange timeout
inside the climb instead.

Signed-off-by: Cursor Agent <cursoragent@cursor.com>

Co-authored-by: Bryan FRIMIN <bryan@frimin.fr>
2026-07-24 23:08:37 +02:00
Cursor Agent
6a1f6d9273 Restore CAA lookup timeout in provision worker
Keep the previous per-lookup dnsExchangeTimeout around CheckCAA
so rebased dnsclient calls do not drop main's deadline.

Signed-off-by: Cursor Agent <cursoragent@cursor.com>

Co-authored-by: Bryan FRIMIN <bryan@frimin.fr>
2026-07-24 23:08:37 +02:00
Cursor Agent
64ef051d18 Harden DNS CAA and TXT verification
Extract shared DNS checks into dnsclient and fail closed on
truncated or non-success CAA responses. Climb past eTLD+1,
validate RFC 8659 issue-value syntax, and map NXDOMAIN TXT
lookups to the pending-verification path.

Signed-off-by: Cursor Agent <cursoragent@cursor.com>

Co-authored-by: Bryan FRIMIN <bryan@frimin.fr>
2026-07-24 23:08:36 +02:00
Ludovic Vielle
ec65b54583 Release probo-agent/v0.3.0
Signed-off-by: Ludovic Vielle <ludovic@probo.com>
2026-07-24 22:48:32 +02:00
Ludovic Vielle
af7f44c0c1 Fix macOS AUTO_UPDATE when updates are disabled
The check read only AutomaticCheckEnabled from /Library/Preferences,
falling back to softwareupdate --schedule when that key was absent.
Both describe automatic checking alone, so a Mac with downloads or
installs turned off still reported PASS. The key is also absent when
a configuration profile manages it, since the value then lives in
/Library/Managed Preferences, a layer never consulted.

Read the five Software Update preferences backing the System Settings
toggles, resolving each from the managed layer before the system one.
macOS treats them as enabled when unset, so only an explicit disabled
value fails. The now-unused softwareupdate binary leaves the command
allowlist.

Signed-off-by: Ludovic Vielle <ludovic@probo.com>
2026-07-24 22:16:18 +02:00
Ludovic Vielle
2532b0bb6b Add branded Finder icon for Probo Agent.app
The macOS URL-handler bundle had no CFBundleIconFile, so
Finder showed the generic app icon after PKG install. Keep a
single master PNG and generate AppIcon.icns at build time
with sips/iconutil, matching the auditor-mode approach.

Signed-off-by: Ludovic Vielle <ludovic@probo.com>
2026-07-24 22:16:15 +02:00
Cursor Agent
002437b568 Verify DNS records on the queried child domain
Custom-domain CNAME and SAML TXT checks accepted answers without
confirming the record owner matched the hostname being verified, so
an apex record could satisfy verification for a subdomain. CAA checks
also looked only at the exact hostname and ignored parent policy.

Add dnsverify helpers to compare owner names and walk from the
requested hostname up to the registrable apex for CAA (RFC 6844).
Require matching record owners for CNAME and TXT answers.

Signed-off-by: Cursor Agent <cursoragent@cursor.com>

Co-authored-by: Bryan FRIMIN <bryan@frimin.fr>
2026-07-24 19:34:25 +02:00
Cursor Agent
d100826479 Preserve third party category on partial update
When category was omitted from an MCP, GraphQL, or CLI update payload,
ThirdPartyService.Update overwrote the stored category with OTHER. Only
apply category when the request explicitly includes it, matching other
optional fields on the same update path.

Add an MCP e2e test that updates name without category and asserts the
existing category is unchanged.

Signed-off-by: Cursor Agent <cursoragent@cursor.com>

Co-authored-by: Bryan FRIMIN <bryan@frimin.fr>
2026-07-24 19:07:20 +02:00
Sacha Al Himdani
55a1bd03eb Rename My Signatures menu label to Employee Portal
Signed-off-by: Sacha Al Himdani <sacha@probo.com>
2026-07-24 18:53:41 +02:00
Sacha Al Himdani
eff175f7c1 Release @probo/n8n-nodes-probo/v0.206.2
Signed-off-by: Sacha Al Himdani <sacha@probo.com>
2026-07-24 18:05:10 +02:00
Sacha Al Himdani
a9e3044b47 Fix n8n Get User organization selection
Connect Organization has no email field. Requesting it made
the Get User GraphQL query fail; align with list/create/update.

Signed-off-by: Sacha Al Himdani <sacha@probo.com>
2026-07-24 17:00:42 +02:00
Ludovic Vielle
cb151c7c5a Release probo-agent/v0.2.0
Signed-off-by: Ludovic Vielle <ludovic@probo.com>
2026-07-24 16:54:01 +02:00
Arthur Mayoux
2adcc9ab5c feat(skills): add compliance-portal-commitments skill
Adds a @probo/skills skill for creating and updating the public
commitments (commitment groups and their commitments) shown on a Probo
compliance portal. Commitments are grounded strictly in the
organization's own published Probo policies and written in a factual,
understated engineering voice, following the get context -> draft ->
filter -> publish workflow via the Probo MCP.

- skills/compliance-portal-commitments/SKILL.md
- references/voice.md, references/portal-mechanics.md
- CHANGELOG.md entry under Unreleased

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-24 16:28:08 +02:00
Ludovic Vielle
0dc64e1944 Simplify macOS pkg to one fat darwin.pkg
Signed-off-by: Ludovic Vielle <ludovic@probo.com>
2026-07-24 15:08:41 +02:00
Ludovic Vielle
385ddfc0bc Fail Windows elevate on UAC cancel
Start-Process failures left $p null, then exit $null made
PowerShell return 0, so install/uninstall looked successful.
Make launch errors terminating and exit nonzero before
reading ExitCode.

Signed-off-by: Ludovic Vielle <ludovic@probo.com>
2026-07-24 15:08:39 +02:00
Ludovic Vielle
6cac6a8775 Split employee devices from DeviceConnection
viewer.enrolledDevices shared DeviceConnection with the admin
org list, so totalCount had to authorize with both
employee-device:list and device:list. Mirror
EmployeeDocumentConnection: a dedicated EmployeeDeviceConnection
without totalCount, and keep DeviceConnection.totalCount for
the org fleet only. Cover assumed-session device:get IDOR in e2e.

Signed-off-by: Ludovic Vielle <ludovic@probo.com>
2026-07-24 15:08:38 +02:00
Ludovic Vielle
85864a580c Install macOS helper from PKG for XPC enroll
Browser enrollment used osascript on every elevate. Ship a signed
privileged helper installed at PKG time so probo:// can enroll over
XPC with no second admin prompt. Add make install/uninstall/clean for
local PKG test loops, and show alerts only on failure.

Mirror the Go lint path for the macOS SPM package: Make
targets, root configs, and a Linux CI job. Keep checks
syntax-only so they do not need a macOS SDK. Format the
existing sources so the new gates start clean.

Signed-off-by: Ludovic Vielle <ludovic@probo.com>
2026-07-24 15:08:37 +02:00
Ludovic Vielle
754d12d583 Skip tray re-register on deep-link enroll
Browser enrollment succeeds once the device is ACTIVE, but the
macOS URL handler failed whenever install re-bootstrapped a tray
LaunchAgent the PKG had already installed. Skip registration when
the plist is current, treat live bootstrap as best-effort, and
exit successfully if the device is already enrolled so retries
do not show "Enrollment failed".

Signed-off-by: Ludovic Vielle <ludovic@probo.com>
2026-07-24 15:08:35 +02:00
Ludovic Vielle
238c19d509 Add pre-assume enrolled device status query
The /enroll wait UI polled device state via node(), which
requires an assumed org session, so confirmation never
succeeded for unassumed viewers. Expose viewer.enrolledDevice
behind itam:employee-device:get (own-device, skip assumption)
and point the poller at it.

Signed-off-by: Ludovic Vielle <ludovic@probo.com>
2026-07-24 15:08:34 +02:00
Ludovic Vielle
afe0c84881 Ship signed universal macOS probo-agent pkg
Publish a notarized arm64+x86_64 .pkg from CI with the CGO tray
binary, Probo Agent.app, and global LaunchAgent. Keep the
LaunchDaemon enrollment-gated, align its plist path with the
launchd label, and document the Apple signing secrets.

Signed-off-by: Ludovic Vielle <ludovic@probo.com>
2026-07-24 15:08:33 +02:00
Ludovic Vielle
4a56be2e3e Improve probo-agent tray icon and enrollment menu
Replace the placeholder orange-circle tray icon with the monochrome
Probo logo used in auditor-mode. On macOS, show the icon only (no
menu bar title); keep the title on Windows.

Restructure the context menu: status rows with colored indicators,
an Enroll via… submenu for region selection, and a clearer About
label. Surface enrollment errors in native dialogs instead of stderr.

Fix self-hosted enrollment on macOS by reading the hostname from
osascript's returned value; the default dialog output order broke
URL parsing and silently skipped opening the browser.

Signed-off-by: Ludovic Vielle <ludovic@probo.com>
2026-07-24 15:08:32 +02:00
Ludovic Vielle
ae769f52a1 Serialize enrollment install with enrolling.lock
Concurrent enroll-url launches could both pass the enrollment
marker check and run overlapping elevated installs, racing on
LoadOrExchangeAPIKey and overwriting agent.key.

Add an exclusive flock on {configDir}/enrolling.lock for the
full install path and re-check IsEnrolled under that lock so
only one install exchanges a token and configures the device.

Signed-off-by: Ludovic Vielle <ludovic@probo.com>
2026-07-24 15:08:30 +02:00
Ludovic Vielle
1329f2a28e Add tray browser enrollment with region picker
The tray helper carried a ServerURL default that nothing read.
Unenrolled users can now open the console /enroll page from the
menu: US, EU, or self-hosted in production, or --server for dev.

Signed-off-by: Ludovic Vielle <ludovic@probo.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-24 15:08:29 +02:00
Ludovic Vielle
952851c743 Seed device fleet and document agent
Populate varied device posture states in seed data and link the
probo-agent release guide from AGENTS.md.

Signed-off-by: Ludovic Vielle <ludovic@probo.com>
2026-07-24 15:08:28 +02:00
Ludovic Vielle
6dbbd70229 Add console devices UI
Add org admin device management, employee self-service enrollment,
posture views, and owner assignment across console routes.

Signed-off-by: Ludovic Vielle <ludovic@probo.com>
2026-07-24 15:08:27 +02:00
Ludovic Vielle
d0dd87c6c7 Add probo-agent binary, installer, and CI
Signed-off-by: Ludovic Vielle <ludovic@probo.com>
2026-07-24 15:08:25 +02:00
Ludovic Vielle
b442e1ed76 Add device agent library
Provide enrollment, elevated install, posture checks, keystore, and
system-tray helpers shared by the probo-agent binary.

Signed-off-by: Ludovic Vielle <ludovic@probo.com>
2026-07-24 15:08:24 +02:00
Ludovic Vielle
e767dd8377 Add device enrollment API and agent protocol
Expose ITAM REST endpoints for agents, console GraphQL for device
management, and wire probod bootstrap with enrollment e2e coverage.

Signed-off-by: Ludovic Vielle <ludovic@probo.com>
2026-07-24 15:08:23 +02:00
Ludovic Vielle
1f79453386 Add device data model and ITAM service
Introduce device, posture, and enrollment-token entities with ITAM
service policies for agent-managed fleet inventory.

Signed-off-by: Ludovic Vielle <ludovic@probo.com>
2026-07-24 15:08:21 +02:00
Aurélien Sibiril
fa3b7dc2b3 Add docs button to the API-key connect dialog
The Add Source card links to a connector's docs, but the API-key
connect dialog did not, so a user filling in an API key had no path
to the setup instructions. Add a "Documentation" button to the dialog
footer, styled like Cancel and on the left of the Cancel/Connect row,
shown only when the provider has a docs page.

Extract the rendering into a shared ConnectorDocumentationLink
component with a link/button variant (the card keeps the quiet link,
the dialog uses the button) and give DialogFooter an optional start
slot for left-aligned footer content.

Signed-off-by: Aurélien Sibiril <81782+aureliensibiril@users.noreply.github.com>
2026-07-24 14:50:18 +02:00
Aurélien Sibiril
b1a67aba00 Link connector docs in the Add Source dialog
The access review Add Source dialog listed each connector with no
path to its setup documentation. Connectors that have a published
docs page on probo.com now surface a "Documentation" link on the
card, opening the page in a new tab; connectors without a page show
nothing extra.

The link is data-driven from the connector registry: a new
DocumentationURL on the provider Registration, populated for the 12
documented providers via a single accessReviewDocsURL helper, is
surfaced as a nullable documentationUrl on ConnectorProviderInfo and
rendered by the console only when present. This keeps the registry
the single source of truth and adds no client-side provider map.

The links resolve once the probo.com access-review docs pages are
deployed; until then they 404, so deploy the docs alongside this
change.

Signed-off-by: Aurélien Sibiril <81782+aureliensibiril@users.noreply.github.com>
2026-07-24 14:50:18 +02:00
Bryan Frimin
b963730433 Release probod/v0.234.0 2026-07-24 14:24:30 +02:00
Sacha Al Himdani
bcd05a2e55 Reject empty SAML NameIDs on login
Empty NameID values were stored as '' and occupied the
unique saml_subject index, causing duplicate-key failures
on later logins. Reject blank NameIDs during assertion
validation, return a clear error when a NameID is already
linked to another account, and stop returning internal
errors from the SAML consume endpoint.

Signed-off-by: Sacha Al Himdani <sacha@probo.com>
2026-07-24 14:03:30 +02:00
Bryan Frimin
e12351e0f4 Require verified certs for portal redirect hosts
AddCustomDomain only validates the domain's format before inserting
the row; certificate issuance then runs asynchronously. Every host
that row resolved to was accepted by the OIDC, magic-link, and
compliance-portal OAuth `continue` redirect allowlists, so anyone
could self-register an org, claim an arbitrary domain, and have
users redirected there right after a real login. Found while
re-checking GHSA-r9mf-88r7-g6j9 against the compliance portal
rework: the original session-transfer leak is gone, but this open
redirect on the same allowlist was not.

Gate those allowlists on the domain's certificate having reached
Active or Renewing status, which only happens once DNS has pointed
at Probo's edge and an ACME challenge has actually succeeded.

Signed-off-by: Bryan Frimin <bryan@probo.com>
2026-07-24 08:38:17 +02:00
Sacha Al Himdani
5c5f60d5e1 Render longer vetting notes as markdown
Keep more of the orchestrator assessment text,
skipping profile fields already on the third party,
and render the notes as markdown in the console.

Signed-off-by: Sacha Al Himdani <sacha@probo.com>
2026-07-23 08:50:22 +02:00
Aurélien Sibiril
3805afc806 Fix PostHog source disconnected on EU cloud OAuth
The connection-status probe and the access-review driver each had
their own copy of the "try us.posthog.com, then eu.posthog.com"
region-discovery loop, and they drifted. The driver skips a region
that rejects the token (wrong region) and uses the one that answers
2xx; the probe instead returned "credential rejected" on the first
region's 401/403, before ever trying the second.

PostHog Cloud US and EU are separate deployments, so an EU OAuth
token is a 401 on us.posthog.com, which is probed first. The probe
bailed there and marked the source disconnected, while access-review
campaigns -- which use the driver -- kept working.

Delete the probe's copy and delegate to the driver's now-exported
ResolvePostHogRegion, the single resolver the campaign also uses. It
flags a credential every region rejected (ErrPostHogCredentialRejected)
apart from a transient failure on the token's own region, so the probe
marks a source disconnected only for a genuinely dead token and does
not flap on a passing 5xx.

Signed-off-by: Aurélien Sibiril <81782+aureliensibiril@users.noreply.github.com>
2026-07-22 22:44:41 +02:00
Sacha Al Himdani
386962dff6 Fix npm audit vulnerabilities in Vitest and transitive deps.
Signed-off-by: Sacha Al Himdani <sacha@probo.com>
2026-07-22 19:40:25 +02:00