Connection probe
The connection probe checks whether an integration's credentials can connect to the third-party tool, and whether they have the permissions required to sync each kind, without running a resync.
Run it after installing a self-hosted integration or rotating its credentials, to find missing permissions before they cause a resync to fail.
What the probe checks
For each kind supported by the integration, the probe checks the permissions granted to the integration's credentials, and reports one of the following results:
| Result | Meaning |
|---|---|
SUCCESS | All permissions required for the kind are granted. |
FAILURE | One or more required permissions are missing. The message lists them. |
UNKNOWN | The integration does not define the permissions required for the kind. |
If the credentials cannot connect to the tool at all, the probe fails and exits with an error.
For example, a successful probe of the Jira integration reports:
{
"status": "COMPLETED",
"probeMode": "shallow",
"startedAt": "2026-09-29T10:00:00+00:00",
"endedAt": "2026-09-29T10:00:02+00:00",
"checks": [
{ "kind": "project", "scopes": {}, "status": "SUCCESS", "message": "Basic Jira access verified" },
{ "kind": "user", "scopes": {}, "status": "FAILURE", "message": "Missing permission(s): USER_PICKER" }
]
}
What it looks like in code
Each resource configuration in the integration declares the permissions its kind requires, using probe_permissions. The following snippets are adapted from the Jira integration:
from typing import ClassVar
from port_ocean.core.handlers.port_app_config.models import ResourceConfig
class JiraIssueConfig(ResourceConfig):
probe_permissions: ClassVar[tuple[str, ...]] = ("BROWSE_PROJECTS",)
class JiraUserResourceConfig(ResourceConfig):
probe_permissions: ClassVar[tuple[str, ...]] = ("USER_PICKER",)
The integration registers a probe handler with @ocean.on_probe(). The handler verifies authentication, fetches the permissions granted to the credentials, and records a result for each kind:
from port_ocean.core.probe import ProbeCheckStatus, ProbeContext
@ocean.on_probe()
async def probe(context: ProbeContext) -> ProbeContext:
client = get_or_create_jira_client()
try:
await client.verify_current_user()
except (HTTPStatusError, RequestError):
await context.fail("Failed to verify Jira authentication.")
return context
# One check per kind being probed
checks = await context.setup_unscoped_checks()
granted = await client.get_current_user_permissions(required_permissions)
for check in checks:
# Compares the kind's probe_permissions with the granted permissions
check.status, check.message = permission_verdict.verdict(check.kind, granted)
await context.update_progress()
return context
Run the probe
The probe is run with the ocean probe command, which is included in the integration's Docker image. Run the image with the same environment variables you use for the integration, and override its command:
docker run --rm \
--env-file ./integration.env \
ghcr.io/port-labs/port-ocean-jira:latest \
ocean probe --kinds project,issue
The command exits with a non-zero status code if the probe fails, so it can also be used as a check in CI pipelines.
The following options are available:
| Option | Description | Default |
|---|---|---|
--kinds | A comma-separated list of the kinds to check. | All kinds supported by the integration |
--reporting-mode | Where to write the results: log prints them to the output, and file writes them as JSON to a probe_reports directory under the integration's path. | log |
--log-level | The log level: DEBUG, INFO, WARNING, ERROR, or CRITICAL. | INFO |
When using --reporting-mode file, mount a volume at /app/probe_reports to keep the report after the container exits.