Skip to content

Commit ba9fea4

Browse files
committed
docs: align connector enrollment with Cloud
1 parent 73cfad8 commit ba9fea4

4 files changed

Lines changed: 30 additions & 24 deletions

File tree

docs/BYOC_CONNECTOR.md

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ inbound ports.**
2323
## The loop (all outbound)
2424

2525
```
26-
register -> POST /api/connector/register enroll once, get a per-connector token
26+
create -> authenticated Cloud settings mint a revocable org-scoped token once
2727
poll -> POST /api/connector/poll long-poll; lease the next queued job
2828
execute -> openadapt-flow run ... the governed admission gate + Replayer,
2929
against the CUSTOMER'S own storage
@@ -39,22 +39,24 @@ the *same* fail-closed `openadapt-flow run` you would run locally.
3939
```bash
4040
pip install openadapt-flow
4141

42-
# 1. Enroll this machine once (mints + persists a per-connector token, 0600).
43-
openadapt-flow connector enroll \
42+
# 1. In app.openadapt.ai, open Dashboard → Settings →
43+
# Customer-controlled connector, create a connector, and copy its token once
44+
# into this machine's service manager or secret store.
45+
export BYOC_CONNECTOR_TOKEN='<shown-once token>'
46+
47+
# 2. Run the daemon (poll -> execute -> report -> ack, until interrupted).
48+
openadapt-flow connector run \
4449
--control-plane-url https://app.openadapt.ai \
45-
--enrollment-secret "$BYOC_ENROLLMENT_SECRET" \
4650
--org-id org_your_clinic \
4751
--profile /opt/openadapt/deployment.yaml \
4852
--storage-backend local \
4953
--storage-root /srv/openadapt # a full-disk-encrypted customer volume
50-
51-
# 2. Run the daemon (poll -> execute -> report -> ack, until interrupted).
52-
openadapt-flow connector run
5354
```
5455

55-
Enrollment persists to `~/.openadapt/connector.toml` (mode 0600 — it holds the
56-
token). A bare `connector run` reads it back. Every flag also resolves from an
57-
env var (`CONTROL_PLANE_URL`, `BYOC_CONNECTOR_TOKEN`, `BYOC_ORG_ID`, ...).
56+
Every flag also resolves from an environment variable
57+
(`CONTROL_PLANE_URL`, `BYOC_CONNECTOR_TOKEN`, `BYOC_ORG_ID`, ...).
58+
`connector enroll` remains available for mock/development control planes; live
59+
Cloud token creation is authenticated and organization-scoped in the dashboard.
5860

5961
## Data boundary and safety
6062

@@ -95,8 +97,9 @@ authorizing a fresh run.
9597
## Enabling the lane (control plane)
9698

9799
The lane is off by default. An operator enables it with
98-
`BYOC_ENABLED=true` **and** a configured `BYOC_ENROLLMENT_SECRET`, and flips the
99-
org's `deployment_kind` to `byoc`. See openadapt-cloud `src/lib/byocLane.ts`.
100+
`BYOC_ENABLED=true` and authenticated run callbacks
101+
(`RUNNER_SHARED_SECRET`), then sets the organization's `deployment_kind` to
102+
`byoc`. See openadapt-cloud `src/lib/byocLane.ts`.
100103

101104
## What works today vs. what remains for production
102105

@@ -112,9 +115,9 @@ org's `deployment_kind` to `byoc`. See openadapt-cloud `src/lib/byocLane.ts`.
112115

113116
**Remaining for production:**
114117

115-
* **Hardened auth.** Enrollment is a single org-shared secret today; production
116-
wants per-org (ideally short-lived, rotating) enrollment tokens, plus
117-
mTLS/private-link between the Connector and the control plane.
118+
* **Private transport options.** Connector tokens are organization-scoped,
119+
revocable, and stored only as hashes in Cloud. Deployments that require
120+
mTLS/private-link add that transport at the customer network boundary.
118121
* **Full policy materialization.** The delivered safety block governs *dispatch*
119122
and the two fail-closed gates above; materializing every safety key into the
120123
engine's runtime config (so e.g. the delivered grounding endpoint is the one

openadapt_flow/__main__.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3411,7 +3411,7 @@ def build_parser() -> argparse.ArgumentParser:
34113411

34123412
pe = csub.add_parser(
34133413
"enroll",
3414-
help="Enroll this machine as a Connector and persist the token (0600)",
3414+
help="Enroll against a mock/development control plane and persist its token",
34153415
)
34163416
pe.add_argument(
34173417
"--control-plane-url", help="Control plane base URL (or CONTROL_PLANE_URL)"
@@ -3632,8 +3632,9 @@ def _cmd_connector(args: argparse.Namespace) -> int:
36323632
# verb == "run"
36333633
if not settings.token:
36343634
print(
3635-
"connector run: not enrolled. Run `openadapt-flow connector enroll` "
3636-
"first, or pass --token / BYOC_CONNECTOR_TOKEN."
3635+
"connector run: no token. Create an organization connector in "
3636+
"OpenAdapt Cloud → Settings, then pass --token or set "
3637+
"BYOC_CONNECTOR_TOKEN."
36373638
)
36383639
return 2
36393640
client = ConnectorClient(settings.control_plane_url, token=settings.token)

openadapt_flow/connector/__init__.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,16 @@
77
PHI-free status/halt metadata ever flows back to the control plane.
88
99
Loop (all outbound HTTPS; zero inbound ports):
10-
register -> POST /api/connector/register (enroll once, get a token)
10+
create -> authenticated Cloud settings (mint an org-scoped token once)
1111
poll -> POST /api/connector/poll (long-poll; lease the next job)
1212
execute -> the governed ``openadapt-flow run`` admission gate + Replayer
1313
(identity gates + effect verification + halt-don't-guess intact),
1414
against the CUSTOMER'S own storage
1515
callback -> POST /api/internal/run-callback (PHI-free status/metrics)
1616
ack -> POST /api/connector/ack (only after callback acceptance)
1717
18-
CLI: ``openadapt-flow connector enroll`` then ``openadapt-flow connector run``.
18+
CLI: create the token in Cloud settings, then ``openadapt-flow connector run``.
19+
``connector enroll`` is retained for mock/development control planes.
1920
"""
2021

2122
from openadapt_flow.connector.client import ConnectorClient, ConnectorClientError

openadapt_flow/connector/client.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,15 @@
66
runner or a Citrix Cloud Connector). The customer opens ZERO inbound ports.
77
88
Endpoints (all outbound):
9-
* ``POST /api/connector/register`` enroll once -> per-connector token
9+
* ``POST /api/connector/register`` mock/dev enrollment compatibility
1010
* ``POST /api/connector/poll`` long-poll -> lease the next job
1111
* ``POST /api/connector/ack`` release the lease (done|failed)
1212
* ``POST /api/internal/run-callback`` PHI-free status/metrics (existing boundary)
1313
14-
Auth: the per-connector token as ``Authorization: Bearer`` on poll/ack; the org
15-
enrollment secret (``x-byoc-enrollment-secret``) once on enroll; the run-scoped
16-
``x-run-token`` on the callback. Only ``httpx`` (already core) + stdlib is used.
14+
Auth: the organization-scoped per-connector token as ``Authorization: Bearer``
15+
on poll/ack and the run-scoped ``x-run-token`` on the callback. Live Cloud
16+
mints the connector token through its authenticated settings API; the legacy
17+
enrollment secret is used only by mock/development control planes.
1718
1819
A custom ``transport`` (an :class:`httpx.BaseTransport`) may be injected so tests
1920
drive the whole enroll -> poll -> callback -> ack loop with ZERO network.

0 commit comments

Comments
 (0)