@numa-tech/numa 1.26.1 → 1.26.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/README.md +10 -9
  2. package/dist/ai-registry/skill-installer.d.ts +1 -0
  3. package/dist/ai-registry/skill-installer.js +10 -1
  4. package/dist/ai-registry/skill-installer.js.map +1 -1
  5. package/dist/ai-registry/update-commands.d.ts +10 -1
  6. package/dist/ai-registry/update-commands.js +47 -2
  7. package/dist/ai-registry/update-commands.js.map +1 -1
  8. package/dist/ai-registry/update-progress.d.ts +10 -0
  9. package/dist/ai-registry/update-progress.js +74 -0
  10. package/dist/ai-registry/update-progress.js.map +1 -0
  11. package/dist/ai-registry/updates.d.ts +42 -0
  12. package/dist/ai-registry/updates.js +67 -6
  13. package/dist/ai-registry/updates.js.map +1 -1
  14. package/dist/authorization/application-schemas.d.ts +0 -5
  15. package/dist/authorization/application-schemas.js +0 -7
  16. package/dist/authorization/application-schemas.js.map +1 -1
  17. package/dist/authorization/commands.js +0 -2
  18. package/dist/authorization/commands.js.map +1 -1
  19. package/dist/cli.js +0 -7
  20. package/dist/cli.js.map +1 -1
  21. package/dist/command-catalog.js +7 -0
  22. package/dist/command-catalog.js.map +1 -1
  23. package/dist/server.js +1 -5
  24. package/dist/server.js.map +1 -1
  25. package/dist/web-console.js +3 -14
  26. package/dist/web-console.js.map +1 -1
  27. package/docs/application-explicit-access.md +13 -0
  28. package/docs/module-maintenance-and-skills-updates.md +31 -0
  29. package/package.json +5 -5
  30. package/dist/authorization/enrollment-client.d.ts +0 -40
  31. package/dist/authorization/enrollment-client.js +0 -56
  32. package/dist/authorization/enrollment-client.js.map +0 -1
  33. package/dist/authorization/enrollment-commands.d.ts +0 -5
  34. package/dist/authorization/enrollment-commands.js +0 -30
  35. package/dist/authorization/enrollment-commands.js.map +0 -1
  36. package/dist/authorization/enrollment.d.ts +0 -14
  37. package/dist/authorization/enrollment.js +0 -83
  38. package/dist/authorization/enrollment.js.map +0 -1
  39. package/docs/application-default-groups.md +0 -109
@@ -1 +0,0 @@
1
- {"version":3,"file":"enrollment-client.js","sourceRoot":"","sources":["../../src/authorization/enrollment-client.ts"],"names":[],"mappings":"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"}
@@ -1,5 +0,0 @@
1
- import type { Command } from "commander";
2
- import { type EnrollmentApi } from "./enrollment-client.js";
3
- export declare function registerEnrollmentCommands(authorization: Command, dependencies?: {
4
- clientFactory?: () => EnrollmentApi;
5
- }): void;
@@ -1,30 +0,0 @@
1
- import process from "node:process";
2
- import { loadConfig } from "../config.js";
3
- import { EnrollmentClient } from "./enrollment-client.js";
4
- import { initializeApplicationMembership } from "./enrollment.js";
5
- import { sanitizeAuthorizationOutput } from "./errors.js";
6
- export function registerEnrollmentCommands(authorization, dependencies = {}) {
7
- const client = dependencies.clientFactory ?? (() => new EnrollmentClient(loadConfig()));
8
- const enrollment = authorization
9
- .command("enrollment")
10
- .description("本人应用成员资格与默认组同步(不操作 realm 默认组)");
11
- enrollment
12
- .command("status")
13
- .description("只读查询本人入组状态,不触发授权")
14
- .action(async (_options, command) => output(command, { ok: true, enrollment: await client().enrollment() }));
15
- enrollment
16
- .command("initialize")
17
- .description("显式初始化本人默认组;机器、暂停和已撤销成员不可自动入组")
18
- .action(async (_options, command) => {
19
- const result = await initializeApplicationMembership(loadConfig(), {
20
- client: client(),
21
- });
22
- await output(command, { ok: result.status === "READY", ...result });
23
- if (result.status !== "READY")
24
- process.exitCode = 1;
25
- });
26
- }
27
- async function output(_command, value) {
28
- process.stdout.write(`${JSON.stringify(sanitizeAuthorizationOutput(value), null, 2)}\n`);
29
- }
30
- //# sourceMappingURL=enrollment-commands.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"enrollment-commands.js","sourceRoot":"","sources":["../../src/authorization/enrollment-commands.ts"],"names":[],"mappings":"AAAA,OAAO,OAAO,MAAM,cAAc,CAAC;AAEnC,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,gBAAgB,EAAsB,MAAM,wBAAwB,CAAC;AAC9E,OAAO,EAAE,+BAA+B,EAAE,MAAM,iBAAiB,CAAC;AAClE,OAAO,EAAE,2BAA2B,EAAE,MAAM,aAAa,CAAC;AAC1D,MAAM,UAAU,0BAA0B,CACxC,aAAsB,EACtB,YAAY,GAA4C,EAAE;IAE1D,MAAM,MAAM,GACV,YAAY,CAAC,aAAa,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,gBAAgB,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC;IAC3E,MAAM,UAAU,GAAG,aAAa;SAC7B,OAAO,CAAC,YAAY,CAAC;SACrB,WAAW,CAAC,+BAA+B,CAAC,CAAC;IAChD,UAAU;SACP,OAAO,CAAC,QAAQ,CAAC;SACjB,WAAW,CAAC,kBAAkB,CAAC;SAC/B,MAAM,CAAC,KAAK,EAAE,QAAiB,EAAE,OAAgB,EAAE,EAAE,CACpD,MAAM,CAAC,OAAO,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,MAAM,EAAE,CAAC,UAAU,EAAE,EAAE,CAAC,CACvE,CAAC;IACJ,UAAU;SACP,OAAO,CAAC,YAAY,CAAC;SACrB,WAAW,CAAC,8BAA8B,CAAC;SAC3C,MAAM,CAAC,KAAK,EAAE,QAAiB,EAAE,OAAgB,EAAE,EAAE;QACpD,MAAM,MAAM,GAAG,MAAM,+BAA+B,CAAC,UAAU,EAAE,EAAE;YACjE,MAAM,EAAE,MAAM,EAAE;SACjB,CAAC,CAAC;QACH,MAAM,MAAM,CAAC,OAAO,EAAE,EAAE,EAAE,EAAE,MAAM,CAAC,MAAM,KAAK,OAAO,EAAE,GAAG,MAAM,EAAE,CAAC,CAAC;QACpE,IAAI,MAAM,CAAC,MAAM,KAAK,OAAO;YAAE,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;IACtD,CAAC,CAAC,CAAC;AACP,CAAC;AACD,KAAK,UAAU,MAAM,CAAC,QAAiB,EAAE,KAAc;IACrD,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,GAAG,IAAI,CAAC,SAAS,CAAC,2BAA2B,CAAC,KAAK,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,CACnE,CAAC;AACJ,CAAC"}
@@ -1,14 +0,0 @@
1
- import type { AuthConfig } from "../config.js";
2
- import { type UserIdentity } from "../identity.js";
3
- import { type EnrollmentApi, type Enrollment } from "./enrollment-client.js";
4
- export interface LoginEnrollmentResult {
5
- status: "READY" | "PENDING" | "FAILED" | "UNKNOWN" | "SKIPPED" | "BLOCKED" | "DISABLED" | "REFRESH_REQUIRED";
6
- message: string;
7
- enrollment?: Enrollment;
8
- }
9
- /** Called only after an explicit successful login / initialize action, never by GET or status. */
10
- export declare function initializeApplicationMembership(config: AuthConfig, dependencies?: {
11
- client?: Pick<EnrollmentApi, "enrollment">;
12
- refreshIdentity?: (config: AuthConfig, forceRefresh: boolean) => Promise<UserIdentity>;
13
- expectedSubject?: string;
14
- }): Promise<LoginEnrollmentResult>;
@@ -1,83 +0,0 @@
1
- import { currentIdentity } from "../identity.js";
2
- import { EnrollmentClient } from "./enrollment-client.js";
3
- /** Called only after an explicit successful login / initialize action, never by GET or status. */
4
- export async function initializeApplicationMembership(config, dependencies = {}) {
5
- if (config.authenticationMode === "client_credentials")
6
- return {
7
- status: "SKIPPED", message: "机器身份不加入人员默认组。"
8
- };
9
- if (!config.backendBaseUrl)
10
- return { status: "SKIPPED", message: "登录成功;尚未配置应用 API,未同步基础权限。" };
11
- const client = dependencies.client ?? new EnrollmentClient(config);
12
- const identityProvider = dependencies.refreshIdentity ?? currentIdentity;
13
- let enrollment;
14
- let subject;
15
- try {
16
- const identity = await identityProvider(config, false);
17
- if (!identity.subject || (dependencies.expectedSubject && identity.subject !== dependencies.expectedSubject)) {
18
- return { status: "UNKNOWN", message: "登录成功;当前会话身份不一致,未执行自动入组。请重新登录。" };
19
- }
20
- subject = identity.subject;
21
- enrollment = await client.enrollment(true);
22
- }
23
- catch {
24
- return { status: "UNKNOWN", message: "登录成功;基础权限同步结果未知。运行 numa authorization enrollment status 查询,勿假定已授权。" };
25
- }
26
- const incomplete = incompleteEnrollment(enrollment, config.clientId);
27
- if (incomplete)
28
- return incomplete;
29
- try {
30
- const identity = await identityProvider(config, enrollment.tokenRefreshRequired);
31
- if (identity.subject !== subject)
32
- return {
33
- status: "UNKNOWN", enrollment, message: "默认组处理后当前会话身份发生变化,无法确认本次入组结果。请重新登录。"
34
- };
35
- // The server checks the current Client default group, including arbitrary registered
36
- // role owners. A read-only readback after refresh replaces the obsolete three-role list.
37
- const current = await client.enrollment(false);
38
- const notReady = incompleteEnrollment(current, config.clientId);
39
- if (notReady)
40
- return notReady;
41
- if (current.policyRevision !== enrollment.policyRevision || current.groupId !== enrollment.groupId)
42
- return {
43
- status: "PENDING", enrollment: current, message: "登录成功;默认组策略已变更,请查询状态并重新初始化。"
44
- };
45
- if (current.tokenRefreshRequired || Object.entries(current.expectedClientRoles ?? {}).some(([owner, roles]) => roles.some(role => !(identity.clientRoles[owner] ?? []).includes(role))))
46
- return {
47
- status: "REFRESH_REQUIRED", enrollment: current,
48
- message: "默认组已同步,但当前令牌未携带组策略要求的角色。请重新登录;仍缺失时请管理员检查登录 Client 的角色 Scope Mapping。"
49
- };
50
- enrollment = current;
51
- }
52
- catch {
53
- return { status: "REFRESH_REQUIRED", enrollment, message: "默认组已同步;会话刷新或只读状态核验未完成,请查询状态或重新登录。" };
54
- }
55
- return {
56
- status: "READY", enrollment,
57
- message: "默认组同步和当前会话核验已完成。具体功能仍受 API 权限、Notion/OSS Grant 和 Skills 空间策略限制。"
58
- };
59
- }
60
- function incompleteEnrollment(enrollment, clientId) {
61
- if (enrollment.clientId && enrollment.clientId !== clientId)
62
- return {
63
- status: "UNKNOWN", enrollment, message: "登录成功;入组结果不属于当前登录 Client,无法确认权限状态。"
64
- };
65
- if (enrollment.blocked || enrollment.membershipStatus === "SUSPENDED" || enrollment.membershipStatus === "REVOKED")
66
- return {
67
- status: "BLOCKED", enrollment, message: "登录成功;该组黑名单或历史成员限制阻止自动入组,请联系管理员处理。"
68
- };
69
- if (enrollment.syncStatus === "DISABLED" || enrollment.policyEnabled === false)
70
- return {
71
- status: "DISABLED", enrollment, message: "登录成功;当前 Client 未启用默认用户组,未自动授予组角色。"
72
- };
73
- if (enrollment.membershipStatus !== "ACTIVE")
74
- return {
75
- status: "PENDING", enrollment, message: "登录成功;应用成员资格尚未建立,基础权限不可视为已就绪。"
76
- };
77
- if (enrollment.syncStatus !== "APPLIED")
78
- return {
79
- status: enrollment.syncStatus === "FAILED" ? "FAILED" : enrollment.syncStatus === "UNKNOWN" ? "UNKNOWN" : "PENDING",
80
- enrollment, message: "登录成功;基础权限尚未同步完成。运行 numa authorization enrollment status 查看状态,或联系管理员。"
81
- };
82
- }
83
- //# sourceMappingURL=enrollment.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"enrollment.js","sourceRoot":"","sources":["../../src/authorization/enrollment.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAqB,MAAM,gBAAgB,CAAC;AACpE,OAAO,EAAE,gBAAgB,EAAuC,MAAM,wBAAwB,CAAC;AAQ/F,kGAAkG;AAClG,MAAM,CAAC,KAAK,UAAU,+BAA+B,CAAC,MAAkB,EAAE,YAAY,GAIlF,EAAE;IACJ,IAAI,MAAM,CAAC,kBAAkB,KAAK,oBAAoB;QAAE,OAAO;YAC7D,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,eAAe;SAC5C,CAAC;IACF,IAAI,CAAC,MAAM,CAAC,cAAc;QAAE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,0BAA0B,EAAE,CAAC;IAC9F,MAAM,MAAM,GAAG,YAAY,CAAC,MAAM,IAAI,IAAI,gBAAgB,CAAC,MAAM,CAAC,CAAC;IACnE,MAAM,gBAAgB,GAAG,YAAY,CAAC,eAAe,IAAI,eAAe,CAAC;IACzE,IAAI,UAAsB,CAAC;IAC3B,IAAI,OAAe,CAAC;IACpB,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,MAAM,gBAAgB,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;QACvD,IAAI,CAAC,QAAQ,CAAC,OAAO,IAAI,CAAC,YAAY,CAAC,eAAe,IAAI,QAAQ,CAAC,OAAO,KAAK,YAAY,CAAC,eAAe,CAAC,EAAE,CAAC;YAC7G,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,+BAA+B,EAAE,CAAC;QACzE,CAAC;QACD,OAAO,GAAG,QAAQ,CAAC,OAAO,CAAC;QAC3B,UAAU,GAAG,MAAM,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;IAC7C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,oEAAoE,EAAE,CAAC;IAC9G,CAAC;IACD,MAAM,UAAU,GAAG,oBAAoB,CAAC,UAAU,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC;IACrE,IAAI,UAAU;QAAE,OAAO,UAAU,CAAC;IAClC,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,MAAM,gBAAgB,CAAC,MAAM,EAAE,UAAU,CAAC,oBAAoB,CAAC,CAAC;QACjF,IAAI,QAAQ,CAAC,OAAO,KAAK,OAAO;YAAE,OAAO;gBACvC,MAAM,EAAE,SAAS,EAAE,UAAU,EAAE,OAAO,EAAE,oCAAoC;aAC7E,CAAC;QACF,qFAAqF;QACrF,yFAAyF;QACzF,MAAM,OAAO,GAAG,MAAM,MAAM,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;QAC/C,MAAM,QAAQ,GAAG,oBAAoB,CAAC,OAAO,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC;QAChE,IAAI,QAAQ;YAAE,OAAO,QAAQ,CAAC;QAC9B,IAAI,OAAO,CAAC,cAAc,KAAK,UAAU,CAAC,cAAc,IAAI,OAAO,CAAC,OAAO,KAAK,UAAU,CAAC,OAAO;YAAE,OAAO;gBACzG,MAAM,EAAE,SAAS,EAAE,UAAU,EAAE,OAAO,EAAE,OAAO,EAAE,4BAA4B;aAC9E,CAAC;QACF,IAAI,OAAO,CAAC,oBAAoB,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,mBAAmB,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,EAAE,KAAK,CAAC,EAAE,EAAE,CAC5G,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC;YAAE,OAAO;gBACjF,MAAM,EAAE,kBAAkB,EAAE,UAAU,EAAE,OAAO;gBAC/C,OAAO,EAAE,sEAAsE;aAChF,CAAC;QACF,UAAU,GAAG,OAAO,CAAC;IACvB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,MAAM,EAAE,kBAAkB,EAAE,UAAU,EAAE,OAAO,EAAE,mCAAmC,EAAE,CAAC;IAClG,CAAC;IACD,OAAO;QACL,MAAM,EAAE,OAAO,EAAE,UAAU;QAC3B,OAAO,EAAE,iEAAiE;KAC3E,CAAC;AACJ,CAAC;AAED,SAAS,oBAAoB,CAAC,UAAsB,EAAE,QAAgB;IACpE,IAAI,UAAU,CAAC,QAAQ,IAAI,UAAU,CAAC,QAAQ,KAAK,QAAQ;QAAE,OAAO;YAClE,MAAM,EAAE,SAAS,EAAE,UAAU,EAAE,OAAO,EAAE,mCAAmC;SAC5E,CAAC;IACF,IAAI,UAAU,CAAC,OAAO,IAAI,UAAU,CAAC,gBAAgB,KAAK,WAAW,IAAI,UAAU,CAAC,gBAAgB,KAAK,SAAS;QAAE,OAAO;YACzH,MAAM,EAAE,SAAS,EAAE,UAAU,EAAE,OAAO,EAAE,mCAAmC;SAC5E,CAAC;IACF,IAAI,UAAU,CAAC,UAAU,KAAK,UAAU,IAAI,UAAU,CAAC,aAAa,KAAK,KAAK;QAAE,OAAO;YACrF,MAAM,EAAE,UAAU,EAAE,UAAU,EAAE,OAAO,EAAE,mCAAmC;SAC7E,CAAC;IACF,IAAI,UAAU,CAAC,gBAAgB,KAAK,QAAQ;QAAE,OAAO;YACnD,MAAM,EAAE,SAAS,EAAE,UAAU,EAAE,OAAO,EAAE,8BAA8B;SACvE,CAAC;IACF,IAAI,UAAU,CAAC,UAAU,KAAK,SAAS;QAAE,OAAO;YAC9C,MAAM,EAAE,UAAU,CAAC,UAAU,KAAK,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,UAAU,CAAC,UAAU,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS;YACnH,UAAU,EAAE,OAAO,EAAE,sEAAsE;SAC5F,CAAC;AACJ,CAAC"}
@@ -1,109 +0,0 @@
1
- # 应用默认组与 CLI
2
-
3
- 这些命令需要部署支持应用受管组 API 的 DevOps 后端;安装旧 CLI 或旧后端不会自动具备该能力。不会修改 Keycloak realm 的 Default roles / Default groups。
4
-
5
- ## 普通用户
6
-
7
- ```sh
8
- numa login --no-console --no-config
9
- numa authorization enrollment status --json
10
- ```
11
-
12
- 用户完成 `numa login`、本地网页控制台登录或 MCP `numa_auth_complete_login` 并保存本机会话后,会显式调用 `POST /api/v1/me/enrollment`。服务端根据可信登录 Client 的默认组策略同步成员。机器身份不参加人员自动入组;组黑名单以及历史 SUSPENDED / REVOKED 限制不会因登录被重新激活。登录过程固定使用发起时的配置,核对回调和当前会话 subject,不把其他登录 Client 或服务的缓存当作本次身份。
13
-
14
- `numa auth status`、profile、命令列表和 `authorization enrollment status` 不触发入组。已有会话可显式初始化,不必人工查询 subject:
15
-
16
- ```sh
17
- numa authorization enrollment initialize --json
18
- ```
19
-
20
- 登录成功和默认组同步是不同结果。同步失败/未知/待处理不会伪报已授权;黑名单显示 BLOCKED,策略未启用显示 DISABLED。组同步完成后,按服务端 `tokenRefreshRequired` 最多强制刷新本会话一次,再通过 GET enrollment 只读回读。只在 Client、组、策略版本一致,且服务端确认当前令牌已满足角色要求时返回 READY。新后端提供 `expectedClientRoles` 时还按精确 Client 校验动态角色;兼容旧后端回读契约,不依赖三个固定角色。
21
-
22
- 默认组角色由平台管理,不预设为 Notion、Skills、OSS 三个名称。READY 只证明入组及当前会话核验完成,不证明每项业务均有权限;仍需要有效 API 角色功能授权、Notion 内容 Grant、OSS Grant 和 Skills namespace 策略。CLI 不自动恢复停用角色、给组增加角色或修改空间策略。
23
-
24
- ## 管理员:应用草稿与统一发布
25
-
26
- 管理命令统一为 `numa authorization application --app <positive-id>`,要求平台 Client Role `mci-devops-platform-ops-admin`。只读目录不创建用户;没有用户密码或账户管理命令。所有 JSON 输出为 `{ok:true,data:...}`,保留服务端字段和分页事实;分页使用 `--page`、`--size`(1–100)及可用时的 `--query`,不自动抓取全部数据。
27
-
28
- 生产操作前用 `numa auth status --json` 和 `numa config --show` 确认 PRD。固定生产前端 `https://mci-devops-platform.mcisaas.com`,issuer `https://kc.mcisaas.com/auth/realms/numa-realm`,浏览器 Client `web-client`,CLI Client `mcp-client`,角色 Client `mci-devops-platform`,API `https://apps-gw-prd.mcisaas.com/mci-devops-platform`。应用的 `--env` 选择已登记的精确身份源;不能传任意 issuer URL,也不能借用浏览器会话。
29
-
30
- ```sh
31
- numa authorization application --app 42 identity sources --json
32
- numa authorization application --app 42 definition show --json
33
- numa authorization application --app 42 definition save --file definition.json --yes --json
34
- numa authorization application --app 42 definition freeze --expected-draft-version 3 --yes --json
35
- numa authorization application --app 42 environment list --page 1 --size 20 --json
36
- numa authorization application --app 42 identity directory users --env <env-uuid> --query name@example.com --json
37
- numa authorization application --app 42 identity client show <reference-uuid> --env <env-uuid> --json
38
- numa authorization application --app 42 identity group registered <definition-uuid> --env <env-uuid> --json
39
- numa authorization application --app 42 identity group blacklist <reference-uuid> --env <env-uuid> --instance <instance-uuid> --json
40
- numa authorization application --app 42 identity relations save --env <env-uuid> --file relations.json --yes --json
41
- numa authorization application --app 42 publication plan --file plan.json --yes --json
42
- numa authorization application --app 42 publication prepare <job-uuid> --expected-version 0 --expected-digest <reviewed-plan-digest> --expected-step-digest <reviewed-step-digest> --yes --json
43
- numa authorization application --app 42 publication apply <job-uuid> --expected-version 1 --expected-digest <reviewed-plan-digest> --expected-step-digest <reviewed-step-digest> --yes --json
44
- ```
45
-
46
- 文件只能包含对应 API 字段,不能把 app/env/file/yes 等控制参数塞入 body。定义保存 `{expectedDraftVersion,defaultRoleClientId,definition}`,完整保留 functions、业务授权、PAGE/API 等文档字段。Client/Group create/save 文件要求 mode、environmentId、全部四个 expected*Version 和对应的配置/需求字段;版本 0 表示实体不存在,不能用作忽略冲突。环境 create/update 保存平台配置,create 的 version 必须是 0。
47
-
48
- relations 文件为 `{expectedRevision,changes}`。支持 ROLE_GRANT、GROUP_MEMBER、GROUP_BLOCK、BLOCK_SOURCE_RELEASE;USER 使用目录返回的稳定 subjectId,SERVICE_ACCOUNT 使用 clientInstanceId。GROUP_BLOCK ABSENT 仅撤销本应用的阻断贡献。释放历史来源必须独立提交 BLOCK_SOURCE_RELEASE、USER、ABSENT、subjectId、groupInstanceId、releaseSource(ADMIN_BLOCK 或 LEGACY_REMOVE)、expectedBlockVersion 及 scoped blacklist 返回的 expectedBlockGeneration;不会移除其他来源阻断。
49
-
50
- LOGIN Client 的 enrollmentTrusted 和 expectedEnrollmentTrustVersion 必须同时填写;这是待发布意图,实际 admission 要等统一发布的激活与验证,不能把草稿当作已生效。共享定义的 configurationReadOnly 与精确 registered hydration 必须遵守,不把目录远端配置自动写回共享定义。
51
-
52
- plan 文件为 `{requestId,definitionVersion,environmentIds,clientModes?}`,requestId 是新 UUID,clientModes 按 instance UUID 映射 CREATE/ADOPT/UPDATE/REPAIR。每次 prepare/apply 都只执行一个阶段,确认必须来自同一 reviewed response,不自动拉取新版本接受冲突。UNKNOWN 时显式 recheck,保留协作问题、receipt、历史、allowedActions 和 finalization;需要继续时另行确认 apply。terminate/cancel 不是回滚,repreview 需要新的 requestId,没有 resume/force 命令。
53
-
54
- 完整命令可通过 `numa authorization application --app 42 --help` 和 `numa commands --json` 查看。registered、versions、history、members、blacklist、catalog、subject-access 均为当前应用/来源限定的只读视图;不使用旧 registry HTTP 路径。网关绑定历史使用 `gateway-binding history <binding-uuid>`,环境历史使用 `environment runs <env-uuid>`。
55
-
56
- ## 凭证只写入文件
57
-
58
- ```sh
59
- numa authorization application --app 42 credential target --env <env-uuid> --reference <ref-uuid> --instance <instance-uuid> --json
60
- numa authorization application --app 42 credential download --env <env-uuid> --reference <ref-uuid> --instance <instance-uuid> --request-id <new-uuid> --expected-instance-version 3 --expected-context-digest <reviewed-digest> --output ./credential.json --yes --json
61
- ```
62
-
63
- rotate 还需完整 `--confirm-client-id` 与 `--acknowledge-impact`。必须显式提供新的 `--output` 文件,拒绝 stdout 和覆盖已有文件;先排他创建 0600 文件,再发送一次请求,只在附件完整落盘后输出 requestId/outputPath。Secret 不进入 JSON、日志或异常。全部写请求包括 recheck 和附件都禁止 401 刷新重放、重定向及自动重试;本地写盘失败也不能重领同一个请求。
64
-
65
- 轮换 A UNKNOWN 后,使用新请求下载 B 恢复当前凭证,再以新请求进行明确轮换 C;不需要等待 A 父作业 ACK。operation/recheck 仅查事实,不重新领取附件。operationRecovered 仅表示历史恢复证据,不代表当前目标凭证 READY。CREDENTIAL_ROTATION 是单阶段窄作业,与完整 IDENTITY_PUBLICATION 图分别解码。
66
-
67
- ## 破坏性升级与发布
68
-
69
- 旧 `authorization role list/create/provision/provisioning-run` 和 `authorization group list/members/users/directory/plan/status/items/impact/apply` 已删除,没有兼容 alias 或旧 HTTP fallback。enrollment、access-request、bootstrap 和独立业务 API 保留。使用既有 lockstep release 流程同时发布工作区包;不能只单独升级一个包。发布前执行 `npm run build` 和 `npm run check`,包括打包边界与编译后 enrollment 烟测。本文不表示已经发布或完成运行时验收。
70
-
71
- Skills/MCP 业务新路径为 `/api/v1/skills`;实例管理和 namespace 写操作为 `/api/v1/admin/nacos/registry`。CLI 不在 401/403 或写超时后退回旧路径重发。发布顺序为:后端兼容 alias 和新路径 → 网关方法映射及权限发布 → CLI 包发布。旧 CLI 继续使用后端保留的 `/api/v1/ai-registry` alias;服务 profile 中的显式 capabilityUrl 仍予以兼容。
72
-
73
- Codex 模块自己的登录使用独立服务 audience 与 token cache,不把该服务令牌转发给 DevOps enrollment;其应用入组应在该服务的可信登录回调完成。这里的自动入组只使用当前明确的 DevOps API 配置。
74
-
75
- ## 应用调用关系与前端页面迁移
76
-
77
- Client 列表的默认关系是本应用拥有的身份。查看外部调用方或本应用调用的服务时显式选择关系:
78
-
79
- ```sh
80
- numa authorization application --app 1 identity client list --relation CALLERS --json
81
- numa authorization application --app 2 identity client list --relation SERVICES --json
82
- ```
83
-
84
- 应用分类使用 `applicationType: FRONTEND | BACKEND | FULLSTACK | UNCLASSIFIED`,可在 onboarding 的 application 配置中选择。仅渲染页面的 SSR 应用属于 FRONTEND,同时提供页面和业务 API 的应用属于 FULLSTACK;不根据框架或 Client 数量推断分类。
85
-
86
- 调用方在本应用拥有的 Client 草稿中配置 `audienceTargets: [{ applicationId: 1, clientId: "backend-api" }]`,精确指定目标后端应用及应用 Client。一个应用可有多个应用 Client,Audience 只由调用方修改;`CALLERS` 是被调用方的只读反查。旧 `consumerApplicationIds` 和 `demand.audience` 写字段已移除。Audience 不授予角色,角色授予仍需独立配置,变更统一通过“环境与发布”生效。
87
-
88
- API 资源通过 `resources[].clientId` 声明资源所属应用 Client,角色通过 `roles[].clientId` 声明所属 Client。同名角色必须按所属 Client 区分;`defaultRoleClientId` 只作为未显式指定时的默认值。PAGE 不配置资源 Client。
89
-
90
- PAGE 草稿可以引用其他应用的固定功能版本,格式为
91
- `permissionSource: { applicationId, definitionVersion, functionCode }` 与 `actions`。
92
- 前端环境使用 `enforcementMode: "PAGE"`,只发布页面规则,不创建 Keycloak 资源 Client。
93
-
94
- 从后端转移现有页面时,先创建并核对前端应用,再读取两份草稿版本和当前实际发布的后端权限版本。
95
- `transfer.json` 必须包含 `targetApplicationId`、`sourceDraftVersion`、`targetDraftVersion` 和
96
- `permissionDefinitionVersion`。预览不会修改草稿;应用请求还必须携带预览的 `expectedDigest`。
97
-
98
- ```sh
99
- numa authorization application --app 1 definition page-transfer preview --file transfer.json --json
100
- numa authorization application --app 1 definition page-transfer apply --file reviewed-transfer.json --yes --json
101
- ```
102
-
103
- 迁移只更新平台草稿,历史版本和线上配置不变。固定前端版本并通过“环境与发布”发布后,页面规则才生效。
104
- 后端权限版本升级后,应相应更新前端的固定版本引用再发布。CLI 需要配合提供 PAGE 与迁移接口的后端版本使用。
105
-
106
-
107
- 多 Client 的角色关系写入使用 `ownerClientId` 和裸 `roleName` 明确角色归属;`clientInstanceId` 始终表示接收角色的服务账号所属 Client 实例。省略 owner 只在应用拥有唯一候选 Client 时可解析,歧义会阻断。查询指定 Client 的已发布角色证据可用 `identity subject-access <subject> --env <uuid> --owner-client <client-id>`。
108
-
109
- 调用方 Client 的 `scopeRoleRefs: ["backend-api/reader"]` 单独限定 Token 可携带的角色范围;它不等于 Audience,也不授予用户或服务账号角色。角色授予继续通过角色关系草稿和统一发布完成。