Connections and credentials
A connection in FACE is made of two things that are stored apart: a record, which holds settings, and a credential bundle, which holds secrets. This page explains how they are split, stored and replicated, and what the connection RPCs report.
The connection record
Connection (in face.proto) carries:
| Field | Meaning |
|---|---|
id | Server-generated when empty (conn_<nanoseconds>). |
name | Display name. It is never used to decide how a connection behaves. |
type | The connector type, for example snowflake or mqtt. Matching ignores case, spaces, underscores and hyphens. |
environment | Free-form tier label (prod, uat, …). It is not a statement about what stands behind the source. |
runner | Which runner executes work for this connection. See Runners. |
config | A oneof holding one typed configuration message, for example snowflake, mqtt or logistics_api. |
properties | A map<string,string> of extra non-secret settings. Many connectors read fallbacks from it. |
credential_state | Filled by ListConnections (see below). |
source_backing | Filled by ListConnections (see below). |
Secrets never stay on the record
Several configuration messages still have secret-looking fields (password,
client_secret, personal_access_token, service_account_json, api_key,
security_token). When a connection is created, FACE reads those fields,
moves them into the credential bundle, and never writes them back out. A
connection you read back through ListConnections has those fields empty. That
is by design.
FACE flattens every setting to its catalogue name and decides secrecy by name,
not by a hand-maintained list. A name is secret if its normalised form contains
any of these markers: password, passwd, passphrase, secret, token,
credential, privatekey, apikey, accesskey, accountkey,
serviceaccountjson, connectionstring, signature, authorization,
bearer. The internal record type has no field that can hold a secret. The same
rule rejects secrets placed in the free-form properties map.
Connectors read their secrets only from the credential bundle they are handed. Setting a password on the record has no effect.
Connection strings
For snowflake and databricks you can paste a connection string in the
connection_string property. FACE parses it at save time:
- The settings it names become typed settings. The string wins for every setting it states. Settings it does not state keep what the form carried.
- The secret it contains goes to the credential bundle under the connector’s normal key. The raw string itself is not kept.
- If the string cannot be parsed, the save fails, so you find out when you paste, not at the next fetch.
- For Snowflake, a DSN field that FACE does not carry is refused rather than dropped silently. So is an explicit host that disagrees with the account.
For other types, a connection_string credential is left in the bundle untouched.
The Azure object store reads it from there.
Creating, listing and deleting
Create. CreateConnection takes the Connection and a credentials map.
FACE writes the credential bundle first and then the record. If writing the
credentials fails, no connection is created, and the response carries
success: false with the underlying message. The response echoes
connection_id either way, so a retry does not create a second row.
List. ListConnections returns every connection with two annotations and a
warnings list:
credential_statetells you what this node holds:Value Meaning CREDENTIAL_STATE_PRESENTA bundle was found and opened on this node. Nothing was dialled, so an expired password still reads PRESENT. CREDENTIAL_STATE_NONE_NEEDEDThe catalogue says this type reads no secret, for example Excel. This is a normal state. CREDENTIAL_STATE_ABSENTThere is no bundle for a type that expects one. FACE cannot tell “never entered” apart from “not present on this node”. CREDENTIAL_STATE_UNREADABLEA bundle exists and could not be opened. Re-entering the credential does not fix a key problem. CREDENTIAL_STATE_UNSPECIFIEDNot computed. This value is not “present” or “absent”. The fetch pipeline uses the same classifier, so the list and a fetch always agree. Opening a present bundle is recorded in the credential audit trail.
source_backingis covered below.warningscarries plain-language conditions about the list itself, such as storage durability. Show them as written. They are not failures.
Delete. DeleteConnection answers with an explicit outcome:
outcome | Meaning |
|---|---|
DELETE_CONNECTION_OUTCOME_DELETED | The credential bundle was removed first, then the record. |
DELETE_CONNECTION_OUTCOME_NOT_FOUND | This instance holds no such id. Nothing was deleted. |
DELETE_CONNECTION_OUTCOME_FAILED | The delete was attempted and failed. message carries the error, and the connection may still exist. An empty id also returns this, with no connection id provided. |
success is true only for DELETED. Deleting a connection does not revoke the
credential at its issuer, and it does not rewrite fetch definitions or lineage
that reference the id.
Test: what live_check_performed means
ConfigService.TestConnection resolves the connector for the connection’s type:
- If the connector has a live probe, FACE runs it with the stored credentials.
- If the connector has no live probe, FACE says so and does not claim a result.
Always read the two booleans together, never the message text:
success | live_check_performed | Meaning | Typical message |
|---|---|---|---|
| true | true | The connector dialled the source, and the source answered and accepted the credential. | Connectivity verified |
| true | false | The configuration is stored. Nothing was verified. The type has no live probe. | Configuration saved — a live connectivity check isn't implemented yet for this source type |
| false | true | The probe ran and failed. message is the connector’s own error. | varies (see Troubleshooting) |
| false | false | The connection could not be resolved. | Connection not found, Unknown connection type "…", could not read the connection: … |
A successful probe establishes reachability and credential acceptance, and nothing more. It does not establish any of the following:
- that a sensor is publishing
- that an antenna is attached
- that a probe is calibrated
- that the credential has scope for any other resource
- that any records exist
Each connector page lists exactly what its probe does.
Source backing
source_backing states what stands behind a connection on this instance. It
is computed from the connection’s address and dials nothing.
| Value | Meaning | What it does not establish |
|---|---|---|
SOURCE_BACKING_LIVE | Nothing that FACE ships stands in for this connection. Whatever it addresses is what it reads. | That the source exists, is reachable, or works. A connection to a host that does not exist is still LIVE and simply fails. |
SOURCE_BACKING_MOCK_SERVICE | The address on the record is a service declared by the FACE demonstration estate, which is a stand-in and never a customer system. | That the demonstration estate is deployed, reachable or serving. It is not deployed by default. |
SOURCE_BACKING_MOCK_SEED_FILE | Defined in the protocol for compatibility. Current servers never return it. | — |
SOURCE_BACKING_UNSPECIFIED | Not computed. Every RPC other than ListConnections leaves it unset. | It is neither “live” nor “mock”. |
When a connector fails, the failure is reported as a failure. No variant of FACE
substitutes bundled sample rows for a failed source. environment is not a
substitute for this field, because a customer may call one of their own systems
“demo”.
Storage and replication
- Records are one replicated snapshot per tenant. FACE stores the snapshot in its own encrypted application filesystem and proposes changes through the platform’s consensus group, so every control-plane replica sees the same set of connections.
- Credential bundles are rows in the same encrypted store. Each row is sealed under a key derived for FACE and bound to its path. Bundles do not travel on the replication log. Only the record snapshot does.
- When a fetch runs on a dedicated runner, the control plane reads the bundle once (an audited read). It then seals the bundle to that runner’s in-memory key for that single dispatch. The runner never writes the credential to disk. See Runners.
For the encryption and key model, see /docs/security/.
Observed lineage
Every connector returned by the registry is wrapped by a lineage recorder. Each extraction appends a record to an append-only log. The record contains:
- column names
- counts and durations
- a literal-free query shape and its fingerprint
- a closed-set error class
A record never contains result values, driver messages or credentials. Camera ingests are recorded separately (one record per ingest, with a row count of zero, because a camera sends frames rather than rows). Lineage is visible in source activity. See /docs/analysis/.