You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit 317b646
Browse filesBrowse the repository at this point in the historyBrowse files
<!-- adr-0087: not-required (no-migration-prescription) One member is added to the closed signing-scheme list and one shape to the `signed` union; the signer seam's `scheme` member is typed as that list instead of any string; that interface is in no release yet (it ships with the pending `26710-signed-connector-auth-aliyun` changeset), so no published surface narrows. Nothing an author wrote before is refused or re-shaped, so there is nothing for a migration to rewrite. -->
12
+
13
+
A declarative connector instance can now declare Tencent Cloud's API 3.0 signature (v3) as its signing scheme. It joins Alibaba Cloud's V3 signature, which shipped with the `signed` kind.
- The `signed` union gains its closed shape, `{ type: 'signed', scheme: 'tencentcloud-tc3-hmac-sha256', keyId, credentialRef }`. `keyId` is the SecretId. The SecretKey is only ever a `credentialRef`.
18
+
- The same publish refusals apply as for the first scheme: an inline key spelling by name, an authored `signature`, and `signed` on `provider: 'mcp'`. `secretId` is answered with `keyId`. An unknown scheme's refusal now lists both shipped schemes.
19
+
-`ConnectorRequestSigner.scheme` is typed as `ConnectorSigningScheme` rather than `string`. The interface ships for the first time in this release, together with the first scheme.
20
+
-**`@objectstack/service-automation`**
21
+
- The signer registry binds a `tencentcloud-tc3-hmac-sha256` instance's key to its TC3-HMAC-SHA256 signer.
22
+
- Every attempt is signed with a fresh `X-TC-Timestamp`, over `content-type` and `host`. The scope's service is the first label of the endpoint host.
23
+
- A request without a content type is signed and sent as `application/x-www-form-urlencoded`.
feat(service-datasource): a datasource defined in code reads its credential at connect from `OS_DATASOURCE_<NAME>_PASSWORD`
8
+
9
+
Clause-②: yes (widening) — `@objectstack/service-datasource` exports `datasourceEnvCredentialVar`, `resolveDatasourceEnvCredentialsSwitch`, `DATASOURCE_ENV_CREDENTIALS_SWITCH` and the `DatasourceEnvCredentialSource` type, and `DatasourceConnectionServiceConfig` gains the optional `envCredentials`; `@objectstack/spec/data` exports `CODE_DEFINED_CREDENTIAL_ROUTE`. Nothing an author writes is added or refused.
10
+
Metadata-protocol: none
11
+
12
+
A datasource declared in code (`defineDatasource`, or a package's `*.datasource.ts`) had no way to get its password: the driver contracts refuse `config.password` and a `user:password@` URL, the Setup → Datasources form cannot edit a code datasource, and nothing mints a `sys_secret:` handle for one. Now the credential stays out of the declaration and is read at connect from a variable derived from the datasource name: `warehouse` reads `OS_DATASOURCE_WAREHOUSE_PASSWORD` (upper-cased; every character outside `A-Z0-9` becomes `_`). The value is the connection's secret: the password for postgres, mysql and mongodb, the `authToken` for turso.
13
+
14
+
-**A host switch.**`OS_DATASOURCE_ENV_CREDENTIALS` takes `on` or `off`; any other value refuses the boot with a sentence. `os serve` (and so `os start` and `os dev`) turns it on unless the operator set it. Every other composition leaves it off, so a host that loads several tenants' artifacts into one process never reads the variable.
15
+
-**Code datasources only, by provenance.** The variable is read on the boot's declared connect, for a name in the host's code-datasource set: the booted artifact's datasources and those of a package installed locally. A datasource created through Setup or the API under the same name never reads it, and neither does the `default` datasource, which keeps `OS_DATABASE_URL`. A record's own `origin` is never consulted.
16
+
-**A declared credential wins.** With `external.credentialsRef` or `external.connector` declared the variable is not read, and a reference that fails to resolve stays fail-closed.
17
+
-**Unset.** The connect goes ahead without a secret as before; when the database then refuses, the reason names the variable to set.
18
+
-**Two names deriving one variable** are refused at their connect.
19
+
-**Who can read it.** Any code datasource the host registers under a name reads that name's variable, including one in an installed package. Install only packages you trust with the credentials in the process environment.
20
+
21
+
The credential refusals (`config.password`, a URL userinfo password, a credential query parameter, the mongo `options` passthrough) and the two `password` guidance entries on `DatasourceSchema` / `ExternalDatasourceSettingsSchema` end with one shared sentence naming this route, after the Setup and `external.credentialsRef` routes they already name. `planCredentialMigration`'s remedy for a code-defined row names the row's variable.
feat(platform-objects): the platform identity actions an agent may reach declare it — additive acts exposed, destructive lifecycle acts exposed behind confirmation, credential and ownership acts human-only
6
+
7
+
Clause-②: no
8
+
Metadata-protocol: none
9
+
10
+
The `sys_*` identity objects' actions now carry the ADR-0011 `ai` block by risk, as ADR-0011's 2026-10-30 addendum records (58 actions assessed, 38 declared):
11
+
12
+
-**Exposed (21).** Additive or self-scoped acts declare `ai: { exposed: true, description }`: the four `invite_user` mirrors, resending and accepting an invitation, adding a member to an organization or a team, creating, editing and renaming a team or an organization, switching the active organization, re-enabling an OAuth application, enabling two-factor authentication, updating your own profile, resending the verification email, and requesting SSO domain verification.
13
+
-**Exposed, confirmation required (17).** Destructive or privilege-changing lifecycle acts also declare `requiresConfirmation: true`, so MCP `run_action` refuses them `428 ACTION_CONFIRMATION_REQUIRED`, with nothing run, until the call carries `confirm: true`: banning, unbanning and unlocking a user, setting a user's manager, revoking an API key or a session, signing out other devices, cancelling or declining an invitation, removing a member or a team member, deleting a team, an OAuth application or an SSO provider, disabling an OAuth application, leaving an organization, and unlinking a sign-in provider.
14
+
-**Human-only (20).** Acts that mint a credential or a session, change ownership, a role or a sign-in factor, or destroy an account or an organization (impersonating a user, setting a password, creating a user or an API key, transferring ownership, changing a member's role, deleting an organization, and the rest the addendum names) declare no `ai` block and are not listed over MCP. `sys_invitation.copy_invitation_link` declares none either; it was not part of the assessment.
15
+
16
+
Over MCP these actions are listed and run behind every existing gate: the capability gate, the installation's action switch, the param contract, the confirmation gate and the identity route's own authorization. They are `type: 'api'` actions forwarded to identity routes that accept a signed-in session only, so an agent connected over OAuth sees them listed and is refused at the route when it runs one.
feat(spec): a calendar view can declare the date it opens on, `calendar.initialDate`
6
+
7
+
Clause-②: yes (widening)
8
+
Metadata-protocol: added
9
+
10
+
A calendar view used to open on the current month, always, so a calendar whose records all fall months ahead (a renewals calendar) opened on an empty grid and the author had no key to say otherwise. `CalendarConfigSchema` (the list view's `calendar` block, and the `object-calendar` node's `calendar` prop, which is the same block by reference) gains one optional key:
11
+
12
+
-**`initialDate`, one of two forms.** A record anchor: `'first_record'` opens on the period containing the earliest start date (the `startDateField` value) among the records the view selects, and `'next_record'` on the period containing the earliest start date on or after today among those records; when no record qualifies, the calendar opens on today. Or a wrapped date-macro token, the same formula vocabulary filter values and a dashboard date filter's `defaultValue` already accept (`DATE_MACRO_TOKENS` and the parameterised `{N_unit_ago}` / `{N_unit_from_now}` grammar): `'{today}'`, `'{next_month_start}'`, `'{current_quarter_start}'`, `'{3_months_from_now}'`, resolved each time the calendar opens. The period is the month, week or day the active view mode shows.
13
+
-**Absent means today.** The key has no spec-side default, so a calendar stored before it existed parses to exactly the block it stored and opens where it always did. There is no bare `'today'`: `'{today}'` is its one spelling.
14
+
-**What is refused.** A fixed calendar date (`'2026-11-01'`) or timestamp, an unwrapped token (`'today'`), an unknown token (`'{next_moon}'`) and any other spelling are refused at `calendar.initialDate`. The message names both forms and points to `DATE_MACRO_TOKENS`, and a bare known token is told the wrapped spelling to write. A fixed date goes stale as time passes; a macro does not.
15
+
16
+
The Console renderer reads the key in a follow-up change; until then a calendar that declares it still opens on today.
docs(skills): the field-types guide names the backfill for an amount switched to record mode; the dashboards guide says a record-mode amount aggregate is served only grouped by its code field
6
+
7
+
Clause-②: no
8
+
Metadata-protocol: none
9
+
10
+
-**`objectstack-data/rules/field-types.md`**: an amount field with stored rows that is switched to `currencyMode: 'record'` is backfilled with `os migrate record-currency-codes`. The derived-measure sentence moves out of this guide; it already sits in the dashboards guide, which the line now points to.
11
+
-**`objectstack-ui/rules/dashboards.md`**: a record-mode amount refuses `sum` / `avg` / `min` / `max` unless grouped by its code field. The old "ungrouped" read as if any grouping would do.
Copy file name to clipboardExpand all lines: content/docs/automation/connectors.mdx
+21-2Lines changed: 21 additions & 2 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -483,12 +483,21 @@ auth: {
483
483
keyId: 'YourAccessKeyId', // the AccessKey ID: public, stays in metadata
484
484
credentialRef: 'ALIYUN_ACCESS_KEY_SECRET',
485
485
}
486
+
487
+
// Tencent Cloud API 3.0, signature v3 (TC3-HMAC-SHA256):
488
+
auth: {
489
+
type: 'signed',
490
+
scheme: 'tencentcloud-tc3-hmac-sha256',
491
+
keyId: 'YourSecretId', // the SecretId: public, stays in metadata
492
+
credentialRef: 'TENCENT_SECRET_KEY',
493
+
}
486
494
```
487
495
488
496
What the platform does with it:
489
497
490
498
-**Every request is signed, each attempt fresh.** A retry is signed again with
491
-
a new nonce and date, so a scheme that refuses a replayed nonce accepts it.
499
+
a new nonce and date, so a scheme that refuses a replayed nonce or a stale
500
+
timestamp accepts it.
492
501
-**The key never reaches the provider.** The automation service binds the
493
502
resolved key to the scheme's signer at materialization and hands the
494
503
provider the signer only. A datasource cannot borrow a `signed` instance
@@ -501,6 +510,14 @@ What the platform does with it:
501
510
`x-acs-content-sha256` and `Authorization`. The API's own action and version
502
511
are yours to send, as `x-acs-action` / `x-acs-version` in `defaultHeaders`
503
512
(rest) or in each call's headers.
513
+
-**`tencentcloud-tc3-hmac-sha256`** signs `content-type` and `host`, and sets
514
+
`X-TC-Timestamp` and `Authorization`. The service in the signature's scope is
515
+
the first label of the endpoint host (`cvm.tencentcloudapi.com`, or a
516
+
regional `cvm.ap-guangzhou.tencentcloudapi.com`, is `cvm`), so point
517
+
`baseUrl` at the product's own endpoint. `X-TC-Action`, `X-TC-Version` and
518
+
`X-TC-Region` are yours to send and are not signed. A request without a body
519
+
is sent with `Content-Type: application/x-www-form-urlencoded`, the type it
520
+
is signed with.
504
521
505
522
What the publish door refuses:
506
523
@@ -509,7 +526,8 @@ What the publish door refuses:
509
526
signer and its test vectors, so a scheme the server cannot run is never
510
527
accepted.
511
528
-**An inline key**: `secret`, `privateKey`, `secretKey` or `accessKeySecret`
512
-
is refused by name, pointing at `credentialRef`. An authored `signature` is
529
+
is refused by name, pointing at `credentialRef`. The vendors' words for the
530
+
key id (`accessKeyId`, `secretId`) are answered with `keyId`. An authored `signature` is
513
531
refused too: it is computed for every request.
514
532
-**`provider: 'mcp'`**, at `auth.type`: an MCP server is not signed per
515
533
request. Declare `provider: 'rest'` or `provider: 'openapi'`.
@@ -579,6 +597,7 @@ retry):
579
597
| MCP server unreachable / `tools/list` fails; remote spec URL unreachable or transiently failing (408/429/5xx) |**Not fatal**: the instance registers **degraded** (visible on `GET /api/v1/automation/connectors` with the reason), dispatches fail with that reason, and the platform retries on a 5s→5min backoff — recovery is automatic |
580
598
| A retry of a degraded instance reaches the upstream and meets a configuration fault (an `include` naming a tool or operation the upstream does not offer) |**Not fatal**: the instance stays **degraded**, now with the configuration reason, and is **not retried** — dispatches fail saying to edit its declaration; an edit of the entry (or a restart) re-attempts it |
| A `connector_action` input that, once evaluated, breaks the action's `inputSchema` (a missing `required` parameter, a wrong `type`) |**The step fails before dispatch** with `VALIDATION_ERROR`, naming each parameter path, and nothing is sent; a `fault` edge or `try_catch` can route it. Supply the parameter or send the declared type: text is never converted, so cast it in a CEL envelope (`int()`, `double()`, `bool()`). `GET /api/v1/automation/connectors` lists the schema; `os validate` does not judge the input against the `inputSchema` yet |
582
601
| A bad entry arrives via **runtime reload** (a Studio publish, a direct active save through `PUT /api/v1/meta/connector/:name`, or a delete, made on any replica — peers reconcile on [cluster lane 2](/docs/kernel/cluster#62-the-cluster-invalidation-family); or a dev reload) | Logged and **skipped**, never crashing the live server; a changed instance's old connector keeps serving until its replacement materializes |
583
602
584
603
## Catalog descriptors: entries without a `provider`
0 commit comments