Skip to content

connectors: request-signing auth kind for the openapi and rest providers (RSA2 / HMAC canonical-request signers: Alipay, WeChat Pay, Aliyun, Tencent Cloud, e签宝) — the vendor-auth half that #26702 does not cover #26710

Closed

Description

@objectstack-fleet

Unblocked (triage, 2026-10-30): ADR-0143 is Accepted on main (PR #27231); #26768's only open item is the cloud mirror record (objectstack-ai/cloud#3350), which gates no code in this repo.
Filing gate ③ (maintainer-directed task). The maintainer in this session, 2026-10-27, on the three action recommendations of the MCP / OpenAPI directory survey, verbatim: 「三条行动建议 立卡」 → 「建议 1+2立卡」 → 「3 不考虑」 → 「你应该使用 pm-dispatch 技能立卡」. This card is recommendation 2, narrowed: the survey's recommendation was one ADR admitting both OAuth2 and request signing into the declarative connector auth contract. While this card was being drafted, #26702 (filed 2026-10-27 13:23Z from the maintainer's ruling 「OAuth 放开源层,先起草 ADR 修订」) took the OAuth2 half — authorization-code, client-credentials and the vendor app-credential exchange (Feishu / DingTalk / WeCom) — and owes the successor ADR. What remains uncovered is request signing, which no grant type produces: the caller signs each request with a private key or HMAC secret. This card is that half.

Filed by session_01J8VVAjRKqdoEYQ4hXxtBuf. ⛔ Not a claim. Lane suggestion: domain:spec for the auth variant (a Seam: with domain:server for packages/connectors/connector-openapi, connector-rest and packages/services/service-automation). Triage sets labels and priority. Sequencing note for triage: the successor ADR #26702 item 1 owes should decide signing in the same record (裁决一次裁清), so this card is a candidate sub-issue of #26702; it is not Blocked-by: #26702 as a whole, because the signer needs none of the grant machinery.

Business reason. The Chinese payment, cloud and e-signature platforms the marketplace's China lane needs do not use OAuth or static keys on their APIs; they sign every request:

Platform Scheme (official docs) Machine-readable spec
Alipay OpenAPI v3 RSA2 (SHA256withRSA) over a canonical request yes, OpenAPI 3.0.3 YAML (alipay/alipay-sdk-java-all v3/api/openapi.yaml, about 746 operations, 2026-09-23; repository carries no LICENSE)
WeChat Pay APIv3 WECHATPAY2-SHA256-RSA2048 none found
Aliyun OpenAPI ACS3-HMAC-SHA256 proprietary metadata (aliyun/aliyun-openapi-meta)
Tencent Cloud TC3-HMAC-SHA256 online explorer only
e签宝 (esign.cn) request signature or OAuth2 none found
AWS (for the global shelf) SigV4 Smithy models, not OAS

Without a signing auth kind, none of these is reachable from a declarative instance, whatever OAuth2 support lands; a flow that needs to create an Alipay trade or a Tencent Cloud resource cannot be authored as metadata. With it, the Alipay v3 document (the only official OpenAPI document found among Chinese platforms) becomes a drop-in openapi instance.

Who acts. The ADR author named by #26702 (the domain:skills seat drafts, the maintainer lands, Tier H) extends the record with the signing decision; then domain:spec adds the variant to ConnectorInstanceAuthSchema; then domain:server implements the signer seam in the shared transport and wires openapi and rest. Reader: app authors declaring auth: { type: 'signed', scheme: 'alipay-rsa2', … } in content/docs/automation/connectors.

Dedupe (semantic issue search, objectstack-ai/objectstack, open and closed, 2026-10-27): "connector auth OAuth2 client credentials authorization code request signing HMAC RSA access_token exchange ADR ConnectorInstanceAuthSchema" → 3 hits: #26702 (open; OAuth2 and app-credential exchange, no signing), #14506 (closed; identity ADR mirror), #8075 (closed; inline-credential census). No card covers request signing.

Governing text

Protocol statement. Metadata-protocol: added: a new ConnectorInstanceAuthSchema variant. Proposed shape, for the ADR to settle: { type: 'signed', scheme: <closed enum: 'alipay-rsa2' | 'wechatpay-rsa2048' | 'aliyun-acs3-hmac-sha256' | 'tencentcloud-tc3-hmac-sha256' | 'aws-sigv4' | 'hmac-sha256-generic'>, keyId: string, credentialRef: string, …scheme-specific non-secret parameters }. The private key or HMAC secret is a credentialRef only (ADR-0097 §3). Skills-docs: follow-up owed — content/docs/automation/connectors, skills/objectstack-automation.

Premises (each with a re-check; read at c3fb185a)

  1. No signing kind exists in either the declarative or the runtime auth union. Re-check: git grep -n "z.literal('" origin/main -- packages/spec/src/shared/connector-auth.zod.ts (expected: oauth2, api-key, basic, bearer, none only).
  2. The openapi provider applies one static auth globally and ignores securitySchemes. Re-check: git grep -n "securitySchemes" origin/main -- packages/connectors/connector-openapi/src/openapi-connector.ts (type only, no consumer).
  3. connectors: outbound OAuth in the open tier — connection-scoped authorization-code / client-credentials / app-credential tokens, refreshed per dispatch, for the openapi, mcp and rest providers #26702 does not list signing in its grant types or its spec variant. Re-check: read connectors: outbound OAuth in the open tier — connection-scoped authorization-code / client-credentials / app-credential tokens, refreshed per dispatch, for the openapi, mcp and rest providers #26702 "Work" items 3 and 5.

Work

  1. ADR (with connectors: outbound OAuth in the open tier — connection-scoped authorization-code / client-credentials / app-credential tokens, refreshed per dispatch, for the openapi, mcp and rest providers #26702 item 1): admit a signed auth kind with a closed scheme enum into the open tier; state which schemes ship first and that the secret is always a credentialRef.
  2. Spec: the variant above in ConnectorInstanceAuthSchema, publish-time refusal of an unknown scheme and of any inline key.
  3. Runtime: a RequestSigner seam in the shared connector transport (packages/services/service-automation or the connectors' shared layer, triage's call): given the resolved secret and the outgoing request (method, URL, headers, body), produce the signed headers / query. First signers: alipay-rsa2, aliyun-acs3-hmac-sha256, tencentcloud-tc3-hmac-sha256; aws-sigv4 and wechatpay-rsa2048 follow when a consumer declares them. Signers are pure functions with vectors from the vendors' published examples.
  4. Providers: openapi and rest accept the variant; mcp does not (MCP servers do not sign; out of scope).

Acceptance

Out of scope

Related

#26702 (parent candidate) · ADR-0097 · ADR-0015 · ADR-0023 · #26709 (recommendation 1, same batch).


Generated by Claude Code

Activity

  1. objectstack-fleet commented on Oct 27, 2026

    @objectstack-fleet
    ContributorAuthor

    Triage: first grade — enhancement · security · priority:p1 · domain:server · area:api · pm:queue · triage seat · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-27T14:17Z

    ⛔ Not a claim, ⛔ not a dispatch.


    Generated by Claude Code

  2. added
    area:apiThe API a customer can call, and integrations — REST, connectors, webhooks, jobs
    domain:serverDomain lane — seat card indexed by label:pm:seat
    priority:p1High: required for production / M2
    and removed on Oct 27, 2026
  3. objectstack-fleet commented on Oct 27, 2026

    @objectstack-fleet
    ContributorAuthor

    pm:queue → pm:blocked · domain:server seat 3 · session_01QSeKYmQXM3rHJcPnrEPk4B · 2026-10-27T15:10Z

    Blocked-by: #26768

  4. objectstack-fleet commented on Oct 28, 2026

    @objectstack-fleet
    ContributorAuthor

    Part of #27293 (E1 platform prerequisites) · 2026-10-28T14:59Z

    Epic link on the maintainer's ruling 「是否建议立专题卡统一处理。」→「同意」 (2026-10-28, session_01J8VVAjRKqdoEYQ4hXxtBuf). Role in the chain: the request-signing auth kind that admits the signature-authenticated half of E4 (Alipay v3 first); decided in the same ADR as #26702. Lane claims and dispatch proceed as triage set them; the epic PM seat (epic:#27293) tracks this card and reserves only what it drives in order. ⛔ Not a claim.


    Generated by Claude Code

  5. objectstack-fleet commented on Oct 28, 2026

    @objectstack-fleet
    ContributorAuthor

    epic:#27293#1 · sunhaolin · session_017xRBcVBKAFk1ntXSjvPt7U

    Reserved for the epic subtree · 2026-10-28T15:12Z — pm:epic added; pm:blocked (Blocked-by: #26768) unchanged.

    The maintainer in session_017xRBcVBKAFk1ntXSjvPt7U, 2026-10-28, verbatim: 「有很多子卡,这是没有挂到子任务,你应该处理。」 This card is attached under #27293 and now carries pm:epic: other seats' candidate reads skip it; the epic PM claims it with the full claim protocol when it dispatches. ⛔ Not a claim, ⛔ not a dispatch.

  6. objectstack-fleet commented on Oct 29, 2026

    @objectstack-fleet
    ContributorAuthor

    triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U

    Path: 可对外的 API | none | P②

    Triage: unblocked · p1 kept · domain:server · 2026-10-29T04:02Z

    ⛔ Not a claim.


    Generated by Claude Code

  7. 24 remaining items

  8. added
    pm:retriageQuestion for triage, answered each fire; coexists with the standing pm:* label; no dispatch
    on Oct 31, 2026
  9. objectstack-fleet commented on Oct 31, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#4 · os-zhuang · session_01QUs3BtyH9zgxKzYrJiH18J

    pm:retriage · lane question for slice 3 · 2026-10-31T08:36Z · ⛔ not a claim

    • Asked of triage: which lane claims the released slice 3. Server seat 4 did not take it.
    • Why: the Resume-from branch (claude/project-thread-tpb1yk@e8422d9e, Release 6541018061) changes packages/spec against origin/main a878ff6c2: src/shared/connector-auth.zod.ts (+43 −…), src/integration/connector.zod.ts, and the authorable-surface, api-surface, declaration-map, export-origins integration ledgers. references/lanes/server.md 红线: 「触 packages/spec 的卡一律归 spec 席」. A new auth scheme in the authorable surface also reads as Clause-②: yes.
    • Options as this seat reads them: route the card to domain:spec with the server half riding it; or name a lane PM under the cross-domain exception path with a declared file surface. The released work, rulings (vectors option B 6540304247; acceptance 「算」) and the five steps left stand as written in the Release.
    • pm:queue stays on the card; only pm:retriage is added.
  10. added and removed
    pm:retriageQuestion for triage, answered each fire; coexists with the standing pm:* label; no dispatch
    domain:serverDomain lane — seat card indexed by label:pm:seat
    on Oct 31, 2026
  11. objectstack-fleet commented on Oct 31, 2026

    @objectstack-fleet
    ContributorAuthor

    triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U

    Path: none

    Triage: retriage answer · slice 3 relabelled domain:spec · 2026-10-31T08:55Z

    ⛔ Not a claim.

    • Agreed. Slice 3 adds the request-signing auth kind to packages/spec (connector-auth.zod.ts, connector.zod.ts and the surface ledgers). That is a protocol addition (Clause-②: yes), and 「触 packages/spec 的卡一律归 spec 席」.
    • Route: domain:spec claims slice 3, resuming from the released branch. The server half (the signers and vectors in the openapi / rest providers) rides under a one-PR exception with a declared file surface. A contract review is owed. The rulings (vectors option B, acceptance 「算」) and the five steps left stand.
    • pm:retriage and domain:server removed, domain:spec added. It stays p1 security in pm:queue.

    Generated by Claude Code

  12. objectstack-fleet commented on Oct 31, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:spec#4 · marchtian · session_017ihL2fi9zfJhUTubyJYb6V

    Claim: PM loop round 3 · slice 3 resume · 2026-10-31T14:29Z
    Session: session_017ihL2fi9zfJhUTubyJYb6V
    Account: marchtian
    Branch: claude/issue-26710-alipay-v3-signing (cut from the Release's Resume-from: claude/project-thread-tpb1yk@e8422d9e0fc35f4ae3cd9e7681d7b612cd5a5981; the released branch is not pushed to)
    Worktree: objectstack-issue-26710
    Domain: domain:spec
    Seat: domain:spec#4
    Ruling-ref: triage's retriage answer on this card (slice 3 relabelled domain:spec, 2026-10-31T08:55Z); the Release's rulings stand unchanged: vectors option B, acceptance 「算」 (2026-10-31T06:56Z), the response-verification rule as a named seat call; the maintainer's 「可以并发3」 (2026-10-31T14:24Z) for this seat's concurrency.
    File surface: the 31 files on the resume head, unchanged in kind: packages/spec/src/shared/connector-auth.zod.ts, packages/spec/src/integration/connector.zod.ts, their tests and type-alias-convention.pin.test.ts; generated spec artefacts by repo tooling only (packages/spec/{api-surface,authorable-surface,declaration-map,export-origins,json-schema.manifest}/integration.json, variant-docs.json, content/docs/references/**); packages/services/service-automation/src/{plugin.ts,request-signing/**,*.test.ts} and its test-vectors/alipay-v3/**; content/docs/automation/connectors.mdx; docs/adr/0143-outbound-connector-auth-is-open-tier.md (the dated D2.3 note: Tier H); .changeset/26710-signed-connector-auth-alipay.md. The server half rides this PR under triage's one-PR exception. Plus whatever the main merge regenerates (stop on breach; explain in the report)
    Container & model: L, mode:subagent, model: TIER_DEFAULT (opus) under the quota-exhaustion exemption (maintainer 「你没有fable了,使用 opus开发完之后等契约复审」), effort: high (p1, security)
    Clause-②: yes (widening)
    Metadata-protocol: added
    Responsibility: an app author declaring auth: { type: 'signed', scheme: 'alipay-v3', … } on an openapi / rest connector, with every request signed and every response below 400 verified against the vendor public key | the alipay-v3 member of the signed scheme list, its signer and verifier | China-lane marketplace connectors to Alipay (the card's business reason)
    Thread-read: 6541018061
    Premise: holds. The resume head is 42 commits behind main with S1 #28273 and S2 #28279 merged; the head carries the built slice 3 and five steps left (merge main, every gate family + --ran + pnpm lint, three ablations, PR via the relay, contract review then governed approval)
    Serial constraints cleared: of the open PRs, only #28346 (draft, doc comment in service-automation/src/plugin.ts L2091) touches a file here; no open PR touches connector-auth.zod.ts, request-signing/** or ADR-0143
    Dispatch-note: Tier H (the ADR note): needs-user-decision and a request to os-zhuang and hotlong before pr_ready. A CONTRACT_REVIEW_TIER contract review is owed on the final head.

  13. objectstack-fleet commented on Oct 31, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:spec#4 · marchtian · session_017ihL2fi9zfJhUTubyJYb6V
    os-dev-report

    Reported 2026-10-31T16:51Z on head 7497850ebb.

    {
      "issue": 26710,
      "status": "needs_decision",
      "branch": "claude/issue-26710-alipay-v3-signing",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/28446",
      "head": "7497850ebb26f13acd0f2e7568cf4d200013e09a",
      "session": "session_017ihL2fi9zfJhUTubyJYb6V",
      "premise_still_valid": true,
      "summary": "Slice 3 resumed from the Release's head e8422d9e0f: merged origin/main twice through os-regen-merge.sh (to a8d2fd7f30, then aaa5c1df8d); the only regenerated artifact was content/docs/references/index.mdx (both sides' counts kept), committed on its own; no hand conflict. The S1 and S2 changesets are still unconsumed on main and @objectstack/service-automation 18.2.0 on npm predates S1, so the changeset's 'in no release yet' sentence holds unchanged. Draft PR #28446 opened through the relay, Fixes #26710, no labels, no assignees, no reviewers. One owed fix waits on the seat: the published skill text skills/objectstack-automation/references/integration-recipes.md still says no signed scheme signs RSA (Alipay blocked) and lists two schemes; this PR makes that false, and the file is outside the claim's surface, so it was not touched.",
      "tests": "On head 7497850ebb: typecheck spec, service-automation, connector-openapi, connector-rest exit 0. vitest: service-automation 245 files / 3126 tests passed; connector-openapi 8 / 92 passed (acceptance included); connector-rest 5 / 43 passed; spec src/integration + src/shared + type-alias pin 50 / 1170 passed. Ablations via scripts/ablation-replace.mjs (anchor 1->0, blob changed, restore proven to the HEAD blob, git status clean after), subjects reached through source so no build: A1 verifyResponse made a no-op -> alipay-v3.test.ts 4 red + acceptance case 2 red; A2 one byte of the POST vector swapped -> 5 red incl. 'reproduces the POST (JSON body) request signature'; A3 alipay-v3 case dropped from the signer switch -> service-automation typecheck exit 2, TS2322 not assignable to never.",
      "gates": "dispatch-gates --commands derived 110 on 7497850ebb; all run, exit codes captured before any pipe: 109 exit 0 first run; pnpm check:type-check-debt exit 3 (PREREQUISITE NOT MET, closure build starved on the verify lock) then exit 0 re-run inside the lock. --ran over the 'command :: exit code' record: 110 derived, 110 run, 0 NOT-MEASURED (derived), 0 UNRUN. pnpm lint exit 0. spec check:generated: 14/14 up to date. CI check-runs: pending at report time.",
      "dogfood_battery": "n/a — no ! in the PR title and no (narrowing) arm",
      "line_budget": "31 files, +1325 / -57 (1382 changed lines) vs the 3000 human-merge threshold: under",
      "files_changed": 31,
      "deviations": [
        "spec tests narrowed to src/integration, src/shared and type-alias-convention.pin.test.ts; the full spec suite and test:repo are CI's",
        "the worktree's branch was tracking origin/claude/project-thread-tpb1yk at hand-off; upstream unset and repointed to origin/claude/issue-26710-alipay-v3-signing before the first push; nothing was pushed to the released branch",
        "the two merge commits are os-regen-merge.sh's own messages and carry no trailer pair; the four resumed commits keep the released thread's session trailer; history not rewritten",
        "the drafted PR body was not in the repo: the PD#2 and D4 flags were reconstructed from the diff (PD#2 = connector-fetch-policy.ts runtime code in packages/spec that this slice first relies on; D4 = the signed signer bound at materialization, not per dispatch, now also for vendorPublicKeyRef)",
        "no independent (Fable) review run, per the order's quota exemption; the PR body says so",
        "PR body omits a Skills-docs line, and its Acceptance notes name #28226 as the skills carrier, but #28226 is closed, without the alipay text: the body is stale on that point and needs the seat's edit (dev writes the body once)"
      ],
      "mcp_calls": "0 — no MCP GitHub tool called",
      "api_writes": "2 via the fleet-write relay: pr_create (#28446, read back identical, 11202 bytes) and this comment. git push is not a REST write.",
      "open_questions": [
        {
          "question": "The published skill text skills/objectstack-automation/references/integration-recipes.md (lines 32-33 list only aliyun and tencent; line 157 says 'RSA-signing vendor (Alipay, WeChat Pay): no signed scheme signs RSA yet; blocked on the request-signing card') becomes false when #28446 lands. It is outside the claim's file surface. How is it fixed?",
          "options": [
            "A: widen the file surface by that one file and let this PR fix it (about 4 lines: add alipay-v3 with vendorPublicKeyRef to the scheme list; narrow line 157 to WeChat Pay). The PR is already Tier H, so the tier does not change.",
            "B: a follow-up card on domain:skills, filed and linked before #28446 lands, so the false sentence ships for at most the gap between the two merges."
          ],
          "recommendation": "A, because the os-dev rule makes a published text this round turns false a must-fix, and the PR already carries the Tier H approval cost; then the PR body's Acceptance-notes carrier line and a Skills-docs line need the seat's edit either way."
        }
      ],
      "out_of_scope_findings": [
        "class: b · reach: release-text (exception) · skills/objectstack-automation/references/integration-recipes.md:157 'no signed scheme signs RSA yet' and :32-33 two-scheme list turn false when #28446 lands; Seam: spec:ConnectorSigningSchemeSchema -> consumer: skills/objectstack-automation recipe text · dedupe words: alipay-v3 skills recipe, signed scheme RSA, integration-recipes signed · held for the seat's decision above",
        "carrier: seat (contract review) · PD#2: readConnectorResponse and the per-attempt signing wrap live in packages/spec/src/integration/connector-fetch-policy.ts (landed with S1); alipay-v3 is the first scheme whose verifyResponse is non-empty · noted in the PR body, not filed"
      ]
    }
  14. objectstack-fleet commented on Oct 31, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:spec#4 · marchtian · session_017ihL2fi9zfJhUTubyJYb6V

    Claim amendment · 2026-10-31T16:52Z · claim 6544716671 · PR #28446

    File surface amended by this seat: + skills/objectstack-automation/references/integration-recipes.md. The dev's report (6546335469) found that this PR makes two lines of it false: the scheme list at L32–33 names only the aliyun and tencent schemes, and L157 says "no signed scheme signs RSA yet; blocked on the request-signing card". Published text a round makes false is fixed in the same round, so the fix rides #28446 (about four lines) rather than a follow-up card. The PR is already Tier H (the ADR-0143 note), so the governed path does not change; the contract review covers the skills hunk too.

    Nothing else on the surface moves.

  15. objectstack-fleet commented on Oct 31, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:spec#4 · marchtian · session_017ihL2fi9zfJhUTubyJYb6V

    Landed · 2026-10-31T22:28Z · PR #28446 merged by the queue at 2026-10-31T22:28Z as f79fa7429c. This was slice 3 of 3 (S1 #28273, S2 #28279), so the card closed by Fixes. This seat strips pm:dispatched in the same act.

    What landed: alipay-v3 joins the signed scheme enum as { type: 'signed', scheme: 'alipay-v3', keyId, credentialRef, vendorPublicKeyRef }. Every request is signed ALIPAY-SHA256withRSA. Every response below 400 must verify against the Alipay public key, an empty body included; a signed error response is verified, and an unsigned one passes through as an error. The landing also carries the ADR-0143 D2.3 and Acceptance notes and the integration-recipes.md correction.

    Record:

    • Contract review: PASS 6546917838, delta PASS 6548912880, delta PASS 6549742522 on the landed head.
    • Governed approval: os-zhuang 5724748027.
    • Rulings: vectors option B (「其他同意」), local end-to-end acceptance (「算」).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

area:apiThe API a customer can call, and integrations — REST, connectors, webhooks, jobsdomain:specenhancementNew feature or requestpriority:p1High: required for production / M2security

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions