Skip to content
Solo ProTeamBusinessEnterprise

Validation probes

The built-in probe library, how probes read the keys under a path, building reusable checks for any API, and SSRF protection.

A probe knows how to test one kind of credential. PulsVault ships a curated set; you attach one to a path and configure any probe-specific settings.

Probes validate a path, not a single key#

A real credential is rarely one value. A database connection is a host, a port, a database name, a username and a password — five separate secrets sitting side by side under one path:

text
wrk/local/production/web/postgres/
├── host
├── port
├── dbname
├── username
└── password

So validation attaches to …/web/postgres, and the probe reads the keys beneath it. A path that holds a single key — a GitHub token, an API key — works the same way: the probe reads that one key.

Which key feeds which probe input is decided by bindings. Most of the time you set none: a key called password binds to the password input on its own, and so do the common aliases (PGPASSWORD, db_password, …). When your naming differs, pick the key from the dropdown.

Every field says where its value came from — key: password when you chose it, auto · PGPASSWORD when it was matched for you, default · 5432 when it fell back to the catalog. Matches on a generic name are flagged, because those are the ones that can be wrong: a key called url is a plausible connection URI for a database path and a plausible anything-else, so the form says it matched on a generic name and lets you pick a different key or choose Don't use this field.

Where a probe accepts alternatives — Postgres takes a connection URI or a host, port and database — the form asks which, rather than letting whichever is supplied first win.

Values that are not secrets don't have to be. A public hostname or a port can be typed straight into the field instead of being stored as a secret just to make a probe work.

Built-in probes#

Probe Tests Typical failure
AWS Access Key SigV4-signed sts:GetCallerIdentity AUTH_FAILED (key unknown or secret wrong)
GitHub PAT GET /rate_limit, reads X-OAuth-Scopes AUTH_FAILED (401), PERMISSION_DENIED (scope missing)
PostgreSQL connect, authenticate, SELECT 1 AUTH_FAILED, NETWORK_TIMEOUT
MySQL / MariaDB same pattern as PostgreSQL AUTH_FAILED, CONNECTION_FAILED
Redis AUTH then PING AUTH_FAILED, CONNECTION_FAILED
Generic HTTP Bearer call a URL you configure with the token AUTH_FAILED, UNEXPECTED_STATUS
Generic HTTP Basic call a URL you configure with basic auth AUTH_FAILED, NOT_FOUND
Custom HTTP full control over method, headers, body and assertions UNEXPECTED_STATUS

Every probe except Custom HTTP is read-only (SAFE_READ) and never modifies anything on the target. Custom HTTP can be given any method, so it is marked as possibly having side effects.

Why these particular calls#

AWS Access Key uses GetCallerIdentity because it requires zero IAM permissions. Every other AWS call conflates "this key is dead" with "this key lacks that permission"; GetCallerIdentity cannot be denied by policy, so a failure means the credential itself is invalid. It also returns the caller's ARN and account, which is how a mislabelled key gets caught.

GitHub PAT uses /rate_limit — the one authenticated endpoint exempt from rate limiting, so the probe can never be the reason a token looks broken — and reads X-OAuth-Scopes from the response. That header is what turns a liveness check into a real one: a token whose scopes were quietly narrowed still authenticates and would sail past any "200 means fine" probe, while the pipeline that needs repo has already started failing. Set Required scopes and a scope reduction is reported as a failure.

PostgreSQL / MySQL classify on SQLSTATE. 28P01 and 28000 mean the credential was rejected — that is a failure and it alerts. A refused connection or a timeout is an error, and errors do not alert, so a maintenance window never pages someone about a password that is perfectly fine.

Redis applies the same split: -WRONGPASS and -NOAUTH are credential failures; a refused connection is not.

Validating any API#

The Generic HTTP Bearer and Custom HTTP probes are the flexible ones: you configure the endpoint, so they validate any token-based API. To continuously verify an API key, point the URL at the provider's models or health endpoint and assert 200.

Once you have a check that works, save it as a template and apply it to every path holding that kind of credential.

Testing before you commit#

The Test Lab runs any probe once without saving anything, against either a stored path or values you type in (which are never stored).

The validation form answers the same question in place: Validate now runs the configuration currently on screen, saved or not, and shows the result in the drawer beneath the form. So "does this actually connect?" is answered before you press Save — not on the first scheduled run. Once the configuration is saved and unedited, the same button runs it for real, recording the result in the path's history.

Which destinations can be reached#

A probe reaches the host you configure, so the destination has to be reachable from the public internet.

Private addresses are refused

Hosts that resolve inside a private network — loopback, 10.x, 192.168.x, 172.16–31.x, carrier-grade NAT, link-local including the 169.254.169.254 cloud-metadata address, and their IPv6 equivalents — are refused. This applies to database hosts as well as URLs, and a redirect cannot be used to reach one either.

You will see this as a clear message on the field you typed, when you save the configuration, rather than as a mysterious failure on the first scheduled run.

If the credential you want to validate only works inside your own network, expose a small public health endpoint in front of it and point a Custom HTTP probe at that.

Result categories#

Only a failure counts toward the alert threshold. timeout and error — the validator could not reach the target — are recorded but suppressed from alerting, so a network blip does not page anyone.

A path that holds no readable keys is different: it is recorded as skipped, and the configuration switches itself off rather than running (and failing to connect) on every future schedule. It resumes on its own when a key is written back to the path — you do not need to re-save it.

Was this page helpful?