Skip to content

[Decision] Ontology over external systems: an API-backed external datasource authenticates through a connector instance's credential (one Connect per vendor for actions and records), its own auth block, or static credentialsRef only (epic #27261) #27298

Closed

Description

@objectstack-fleet

director#1 · os-bill · session_01Utp6CbQLcy8yg6vhJVXXi8

Ruled: 6486136301 · letter A · 2026-10-29T02:25Z

Filing gate ② (a decision only the maintainer can make), filed on the maintainer's instruction in this session, 2026-10-28, verbatim: 「你说的问题立决策卡,挂在专题下面」. It follows the re-assessment of #27261 against #26702 / ADR-0143.

Placement. Epic: #27261 (parent; pm:epic subtree). Filed by session_01J8VVAmeQhJepVXSad145da. ⛔ Not a claim. No domain:* label: triage sets it, and domain:spec is expected because the answer is a key on the datasource contract.

维护者速读

Background

Governing text

Protocol statement. A is Metadata-protocol: added: one optional key on the datasource external block that names a connector instance, refused at build unless that instance is declared. B is added too: an auth block on the datasource with the ADR-0143 variants, plus the connection record binding a datasource. C adds nothing. A or B amends the standing rule "credentials only through credentialsRef" for API-backed datasources. That amendment is the point of this card.

Premises (read at origin/main e9c88f7c)

  1. Datasource secrets are sys_secret: references. Re-check: git grep -n "REF_PREFIX = 'sys_secret:'" origin/main -- packages/services/service-datasource/src/datasource-secret-binder.ts.
  2. The connector resolver seam is separate. Re-check: git grep -n "defaultEnvCredentialResolver" origin/main -- packages/services/service-automation/src/credential-resolver.ts.
  3. The two spellings differ across the two surfaces: credentialsRef in 39 non-test source files, credentialRef in 19. Re-check: git grep -lw credentialsRef origin/main -- 'packages/**/src/**' | grep -v -e test -e pin | wc -l (same for credentialRef). Not decided here; under A the divergence does not grow, because a connector-backed datasource names no secret itself.

Options

Option What it does What the customer sees Effort
A reference a connector instance The datasource's external block names a declared connector instance. The driver asks the automation service's resolver for a live credential per request (ADR-0143 D4). Static, OAuth, app-credential and signed kinds are all reused. "Connect HubSpot" once. Flows and HubSpot-backed objects both work. Reconnect fixes both. domain:spec 1 PR (S) + domain:server 1 PR (S–M), with P2 · no UI · no precedent
B own auth block Datasources gain the ADR-0143 variants. The connection record also binds (organization, datasource). A second Connect flow is added on the datasource page. Two "Connect HubSpot" entries, one for actions and one for data, each expiring on its own. spec M + server M + ui M · no precedent
C static only Datasources keep credentialsRef. OAuth sources are reachable only through a Tier A plugin driver written in code. No-code binding works only for key-based APIs. Everything else needs a developer. 0 now

In business terms. A: one key ring per vendor, used for both doing things and reading things. B: two key rings for the same vendor. C: the no-code door opens only for vendors that still accept a static key.

四维分析(业务立场)

  • 项目长远合理性(领起)。 两年后的样子:一个供应商连一次,平台既能对它执行动作,也能把它的数据当对象来读,换授权只换一处。主流平台就是这么建模的:Dataverse 的 virtual connector provider 建虚拟表时,直接用连接器的 connection reference 鉴权;Salesforce 的 Named Credential 是一个独立凭证对象,callout 和外部数据源都引用它的名字。A 正是这个终态。B 让同一个供应商的授权一分为二,过期、撤销、审计都要做两遍。C 把声明式档对 OAuth 系统关死,等于 P2 的主要目标客户用不了。
  • 实际业务拉动。 今天零拉动:object-gantt can no longer write back to a same-origin endpoint after #23082 — a measured producer of the retired view-level api source (read + write) #27130 走代码档,P2 要等第二个客户。所以只裁方向,实施随 P2 立卡,现在不派码。
  • 防 AI 犯错。 A 下 AI 作者只写一个实例名,build 时实例不存在就响亮拒收,凭据形状只有一处定义。B 下同一个供应商要在两处各写一遍鉴权,两处漂移时一边能用、一边失败,看起来像供应商故障。C 下 AI 会给 OAuth 系统写一个静态密钥,运行时 401。
  • 创业阶段不扩散。 A 只加一个可选键,不新增连接形态,不新增 UI。B 复制一整套鉴权契约。C 最省,但代价是 P2 的价值。

os-decision-facets

Prior rulings read: "external datasource authenticate connector connection OAuth credentialsRef" → 2 hits (#26702 open: connector-side only; #27230 closed, ruled A: connector static secrets, says nothing on datasources); ADR-0143 Q1 A / Q2 B / D3 / D4; ADR-0015 §10; #27261 ruling 6471382887 D1, D2; thread: none.

Recommendation

After the ruling

Related

#27261 (epic) · #26702 · #26768 / ADR-0143 · #27230 · #27130 · ADR-0015 · and the sibling decision card on Tier B's dialect, filed alongside this one.


Generated by Claude Code

Activity

  1. objectstack-fleet commented on Oct 29, 2026

    @objectstack-fleet
    ContributorAuthor

    epic:#27261#1 · marchtian · session_017ihL2c5z3q4h8inrn5kwqV

    A Tier A reading that bears on this decision, carried here, not filed (from the #27278 dev report 6485876530; seam-level probe at origin/main 6d7634a, not measured at a public door):

    • For a datasource whose driver a plugin already registered (driver.<name> service), DatasourceConnectionService returns already-registered before credential resolution: external.credentialsRef is not resolved, not handed to the driver, and does not fail the boot when no secret store is configured (0 resolver calls, with and without a secret store). A driver that is not pre-registered resolves it (1 resolver call).
    • So today a plugin driver gets its credential from the options the host passes to the plugin, and the "credentials only through credentialsRef" rule of ruling 6471382887 is not what Tier A does. The guide (PR docs(data-modeling): virtual objects — rows from your server, shown in any view (plugin-driver recipe) #27349, content/docs/data-modeling/virtual-objects.mdx § Credentials) states this behaviour as it is.
    • The dev's options: (A) the platform hands the resolved credentialsRef to a plugin driver; (B) bless host-composed plugin options as the Tier A channel and amend the rule; (C) refuse at boot a credentialsRef on a plugin-registered driver's datasource, so it is never silently ignored. Whatever this card rules for API-backed datasources should settle the plugin-driver case in the same ruling.
  2. objectstack-fleet commented on Oct 29, 2026

    @objectstack-fleet
    ContributorAuthor

    director#1 · os-bill · session_01Utp6CbQLcy8yg6vhJVXXi8

    Brief-claimed-by: session_01Utp6CbQLcy8yg6vhJVXXi8 · batch #426 · 2026-10-29T02:14Z

    Director seat, summon #54 (ledger objectstack#12708, opening mark 6485456694). Presented to the maintainer in batch #426 as item 1 of 3, together with its sibling #27299 and #27302 (one family: epics #27261 / #27293).

    Seat increment (re-read at origin/main 73725c20, 2026-10-29T02:14Z):

    Prior rulings read: datasource, connector, credential, OAuth, credentialsRef → ADR-0143 D1 / D3 / D4 / Q1 / Q2, ADR-0015 §10; thread: 6471382887 (#27261), #27230 A; repo: objectstack-ai/objectstack

  3. objectstack-fleet commented on Oct 29, 2026

    @objectstack-fleet
    ContributorAuthor

    director#1 · os-bill · session_01Utp6CbQLcy8yg6vhJVXXi8

    Ruling: batch #426 item 1 · letter A · maintainer 「同意」 2026-10-29T02:22Z

    Director seat, summon #54 (ledger objectstack#12708, opening mark 6485456694, brief 6486018608). The maintainer answered batch #426 in the summon chat with one word, verbatim: 「同意」 — the seat's letter on each of the three cards; for this card A.

    What the ruling binds (letter A): an API-backed external datasource authenticates by naming a declared connector instance in its external block and borrowing that instance's credential — static, oauth2, app-credential and signed kinds alike — through ADR-0143 D4's per-dispatch resolver. One Connect per vendor serves both actions (flows) and records (virtual objects); a reconnect fixes both. The key is one optional member of the datasource external block, refused at build when the named instance is not declared (Metadata-protocol: added, filed with P2). Execution identity is not reopened: ADR-0143 Q1 = A (organization-shared) applies to the virtual-object read as to the flow dispatch; object permissions and RLS stay the only gate on what a user sees (#27261 §5.9). Amendment recorded: #27261 ruling 6471382887's standing rule "credentials only through credentialsRef" and the epic body's §4 item 8 now read: through credentialsRef, or through a declared connector instance for an API-backed datasource. Not taken: B (a second grant per vendor, a second Connect flow, drift between two auth blocks), C (a static key for OAuth sources, runtime 401).

    Governing text: ADR-0143 D3 / D4 / Q1 A / Q2 B; ADR-0015 §10; ruling 6471382887 D1 / D2 on #27261; #27230 ruled A (connector static secrets). Premises re-read at origin/main 73725c20 (brief 6486018608).

    Workload of the letter: domain:spec 1 PR (S: the key plus an ADR-0015 amendment note, Tier H) + domain:server 1 PR (S–M: the shared resolver seam) · no UI · filed with P2 on the second customer pull (D1), not now · no precedent. Open readings for P2's spec child: whether the objectql-side driver reaches the automation service's resolver without a new dependency direction; whether the (organization, connector instance) binding fits an environment-level datasource (#27230 S1).

    Execution: nothing is dispatched. The epic PM of #27261 records this as D7 in the epic body and corrects §4 item 8; this card closes completed in this act (the ruling is its content; P2's children cite this comment on a Ruling-ref: line when filed).

    os-decision-facets
    ① 长远:一个供应商一份授权,动作与读数共用,与 Dataverse connection reference / Salesforce Named Credential 同形
    ② 拉动:今天零(#27130 走代码档,P2 等第二个客户);只定方向,实施随 P2
    ③ 防错:只写一个实例名,build 时实例不存在即响亮拒收;B 两处鉴权会漂移,C 诱导静态密钥
    ④ 不扩散:一个可选键,不新增连接形态与 UI

  4. objectstack-fleet commented on Oct 29, 2026

    @objectstack-fleet
    ContributorAuthor

    director#1 · os-bill · session_01Utp6CbQLcy8yg6vhJVXXi8

    Closed completed · 2026-10-29T02:32Z · ruling 6486136301 (batch #426 item 1, letter A: an API-backed datasource borrows a declared connector instance's credential; execution identity stays ADR-0143 Q1 A). The epic PM records it as D7 on #27261 (pointer left there); P2's spec and server children cite the ruling when filed on the second pull. needs-user-decision leaves with the close; pm:epic stays — the card remains a ruled member of the subtree.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions