Files
baiyue-firstleg/lastleg-service/src/main/resources/openapi/self-operated-analytics-egress-v1.yaml
T

172 lines
8.7 KiB
YAML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
openapi: 3.0.3
info:
title: Self-operated Analytics Internal Egress Authority
version: 1.0.0
paths:
/internal/lastleg/self-operated-analytics/egress/runtime:
get:
operationId: getSelfoperatedEgressRuntime
summary: 读取脱敏的实际出口配置快照
description: >-
仅内部服务令牌,不提供公网路由。直接读取 Egress 执行所用的同一配置实例,
不读取数据库、不预留或消费许可、不调用供应商。响应不是部署验证结论,
不包含 verified、镜像版本、原始账号、grant、Token 或 URL。
intervalMs 为当前配置间隔,持久账户间隔可能更严格,须另行只读核验。
pendingMaxSeconds 为实际配置经 1 至 120 秒裁剪后的上限;permitMaxSeconds 为单次许可上限,
VALIDATION 仍可能受验证截止及 grant 截止进一步缩短。
security: [{ internalServiceToken: [] }]
responses:
'200':
description: ApiResponse 成功响应,data 为只读白名单快照
content:
application/json:
schema:
type: object
properties:
code: { type: string }
data: { $ref: '#/components/schemas/RuntimeSnapshot' }
'401': { description: 内部令牌无效 }
'503': { description: 内部令牌未配置 }
/internal/lastleg/self-operated-analytics/egress/authorize:
post:
operationId: authorizeSelfoperatedEgressAttempt
summary: 一次性消费已持久预留的领星请求许可
description: >-
仅内部服务令牌。客户端已登记的 context 和 operation 必须完全匹配;
requestHash 是 Integration 对 OMP 路径和有序业务 JSON 的摘要,首次消费绑定,
后续完成必须完全匹配。同 attemptId 再次消费拒绝。allowedAttempts 固定 1,
expiresAt 最多 30 秒;VALIDATION 不超过验证根截止及 grant 截止。
BUSINESS 不受人为会话或 grant 截止阻断,但保留短许可过期、身份、显式停止及账户保护。
OFF 默认拒绝;BUSINESS 仅接受 production 或 test,人工根及合法派生保持原身份,
连续计划根另须连续开关与持久化 planner 身份。独占交接证明及接续计数由服务端配置核验。
security: [{ internalServiceToken: [] }]
requestBody:
required: true
content:
application/json:
schema: { $ref: '#/components/schemas/AuthorizationRequest' }
responses:
'200':
description: HTTP 200;许可 code=200,正常拒绝 code=B0001,data 为显式预算决策
content:
application/json:
schema:
type: object
properties:
code: { type: string }
data:
oneOf:
- { $ref: '#/components/schemas/AttemptPermit' }
- { $ref: '#/components/schemas/AuthorizationDenial' }
'401': { description: 内部令牌无效 }
'503': { description: 内部令牌未配置 }
/internal/lastleg/self-operated-analytics/egress/complete:
post:
operationId: completeSelfoperatedEgressAttempt
summary: 记录真实尝试次数和账号冷却
description: >-
回调 context、operation、requestHash 必须匹配已消费许可。actualHttpAttempts 仅 0 或 1;
即使 0 也不退回预留,响应丢失同样保留保守消耗。重复已确认完成为幂等成功。
429 对账号全部采集族持久冷却;验证根 DEAD、run FAILED、禁止自动续跑。
未确认结果的许可到期后保守冷却,不使用换日、换仓、重试或重启清零预算。
security: [{ internalServiceToken: [] }]
requestBody:
required: true
content:
application/json:
schema: { $ref: '#/components/schemas/CompletionRequest' }
responses:
'200':
description: ApiResponse code 字符串 200,data 为布尔 true
content:
application/json:
schema:
type: object
properties:
code: { type: string }
data: { type: boolean, enum: [true] }
'401': { description: 内部令牌无效 }
components:
securitySchemes:
internalServiceToken: { type: apiKey, in: header, name: X-Internal-Service-Token }
schemas:
RuntimeSnapshot:
type: object
additionalProperties: false
required: [schemaVersion, service, observedAt, mode, environment, continuousEnabled, sourceAccountFingerprint, grantPresent, grantFingerprint, intervalMs, permitMaxSeconds, executionEnabled, pendingMaxSeconds, exclusiveHandoffVerified, priorEgressClosed, inflightDrained, transferredBudgetVerified]
properties:
schemaVersion: { type: integer, enum: [1] }
service: { type: string, enum: [lastleg] }
observedAt: { type: string, format: date-time, description: UTC 观测时间 }
mode: { type: string, nullable: true, description: 原样返回实际配置,不将未知值转为 BUSINESS }
environment: { type: string, nullable: true }
continuousEnabled: { type: boolean }
sourceAccountFingerprint:
type: string
nullable: true
pattern: '^[a-f0-9]{64}$'
description: 'SHA-256 UTF-8 输入为 selfop-runtime:v1:source-account 加一个 LF 再加原始值;不 trim;null 或 blank 返回显式 null。'
grantPresent: { type: boolean, description: grant 原值非 null 且非 blank }
grantFingerprint:
type: string
nullable: true
pattern: '^[a-f0-9]{64}$'
description: 'SHA-256 UTF-8 输入为 selfop-runtime:v1:grant 加一个 LF 再加原始值;不 trim;null 或 blank 返回显式 null。'
intervalMs: { type: integer, format: int64, description: 实际配置的 BUSINESS 最小请求间隔毫秒数,未合并持久账户间隔 }
permitMaxSeconds: { type: integer, enum: [30] }
executionEnabled: { type: boolean }
pendingMaxSeconds: { type: integer, minimum: 1, maximum: 120 }
exclusiveHandoffVerified: { type: boolean }
priorEgressClosed: { type: boolean }
inflightDrained: { type: boolean }
transferredBudgetVerified: { type: boolean }
EgressContext:
type: object
required: [sourceAccount, executionPurpose, rootTaskId, sessionId, attemptId, exclusiveGrantId]
properties:
sourceAccount: { type: string, maxLength: 64 }
executionPurpose: { type: string, enum: [VALIDATION, BUSINESS] }
rootTaskId: { type: string, pattern: '^[0-9]+$' }
sessionId: { type: string, maxLength: 128 }
attemptId: { type: string, maxLength: 128 }
exclusiveGrantId: { type: string, maxLength: 128 }
Operation:
type: string
enum: [WAREHOUSES, OUTBOUND_QUERY, OUTBOUND_LOCATE, OUTBOUND_DETAIL, PRODUCT_INVENTORY, CUSTOMERS, PRODUCTS]
AuthorizationRequest:
type: object
required: [context, operation, requestHash]
properties:
context: { $ref: '#/components/schemas/EgressContext' }
operation: { $ref: '#/components/schemas/Operation' }
requestHash: { type: string, pattern: '^[a-f0-9]{64}$' }
AuthorizationDenial:
type: object
required: [errorCode, sampleDone, waitUntil]
properties:
errorCode: { type: string, pattern: '^[A-Z][A-Z0-9_]{0,63}$' }
sampleDone: { type: boolean }
waitUntil: { type: string, format: date-time, nullable: true, description: UTC Instant 或显式 null }
AttemptPermit:
allOf:
- { $ref: '#/components/schemas/AuthorizationRequest' }
- type: object
required: [allowedAttempts, expiresAt, exclusiveConfirmed, budgetConsumed]
properties:
allowedAttempts: { type: integer, enum: [1] }
expiresAt: { type: string, format: date-time }
exclusiveConfirmed: { type: boolean, enum: [true] }
budgetConsumed: { type: boolean, enum: [true] }
CompletionRequest:
allOf:
- { $ref: '#/components/schemas/AuthorizationRequest' }
- type: object
required: [actualHttpAttempts, accountPaused]
properties:
actualHttpAttempts: { type: integer, minimum: 0, maximum: 1 }
errorCode: { type: string, nullable: true }
upstreamStatus: { type: integer, nullable: true }
sourceCode: { type: integer, nullable: true }
accountPaused: { type: boolean }
cooldownUntil: { type: string, format: date-time, nullable: true }