@numa-tech/numa 1.21.1 → 1.22.0

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.
@@ -0,0 +1,84 @@
1
+ import { readFile } from "node:fs/promises";
2
+ import { OssError } from "./errors.js";
3
+ const positive = (value) => {
4
+ if (!/^\d+$/u.test(value) || !Number.isSafeInteger(Number(value)) || Number(value) <= 0)
5
+ throw new OssError("Expected a positive integer.", "oss_input_invalid");
6
+ return Number(value);
7
+ };
8
+ const paging = (command) => command.option("--page <number>", "页码,从 1 开始", positive, 1);
9
+ const file = (command) => command.requiredOption("--file <path>", "经过核对的 JSON 文件");
10
+ const confirm = (o) => { if (!o.yes)
11
+ throw new OssError("Review the exact policy, Client and input before passing --yes.", "oss_confirmation_required"); };
12
+ async function inputFile(path) {
13
+ try {
14
+ const raw = await readFile(path ?? "", "utf8");
15
+ if (Buffer.byteLength(raw) > 1024 * 1024)
16
+ throw new Error("too large");
17
+ return JSON.parse(raw);
18
+ }
19
+ catch {
20
+ throw new OssError("Cannot read a valid OSS input JSON file (maximum 1 MiB).", "oss_input_invalid");
21
+ }
22
+ }
23
+ export function registerOssGovernanceCommands(oss, dependencies) {
24
+ const { client, emit } = dependencies;
25
+ const show = (command, data) => emit(command, { ok: true, data }, JSON.stringify(data, null, 2));
26
+ oss.command("identity").description("读取管理身份源普通 UUID;不读取凭据")
27
+ .action(async (_o, c) => show(c, await client().identity()));
28
+ paging(oss.command("clients").description("列出指定身份源已核验的机器 Client 实例及 Service Account subject")
29
+ .requiredOption("--issuer-id <uuid>", "普通身份源 UUID").option("--query <text>", "Client 编码检索"))
30
+ .action(async (o, c) => show(c, await client().clients(o.issuerId, o.query, o.page)));
31
+ const templates = oss.command("templates").description("查询不可变 OSS 权限模板版本;策略绑定 revision ID");
32
+ paging(templates.command("list").option("--query <text>", "模板检索"))
33
+ .action(async (o, c) => show(c, await client().templates(o.query, o.page)));
34
+ templates.command("get <revisionId>")
35
+ .action(async (revision, _o, c) => show(c, await client().template(positive(revision))));
36
+ const policy = oss.command("policy").description("管理 OSS 策略草稿、发布和机器 Client STS 绑定");
37
+ paging(policy.command("list").requiredOption("--account-id <id>", "云账号 ID", positive).option("--query <text>", "策略检索"))
38
+ .action(async (o, c) => show(c, await client().policies(o.accountId, o.query, o.page)));
39
+ for (const name of ["get", "state", "check"]) {
40
+ policy.command(`${name} <policyId>`).description(name === "check" ? "读取云端状态并更新核对记录,不修改云端策略" : name === "state" ? "查看草稿、已发布快照及待发布差异和 checksum" : "读取策略完整字段与 version")
41
+ .action(async (value, _o, c) => show(c, await client()[name === "get" ? "policy" : name](positive(value))));
42
+ }
43
+ for (const name of ["preview", "save"]) {
44
+ const command = file(policy.command(name).description(name === "preview" ? "根据明确模板版本生成策略文档预览;不保存策略" : "保存策略草稿;需另行检查并发布"))
45
+ .option("--id <policyId>", "编辑已有策略(输入必须含 version)", positive);
46
+ if (name === "save")
47
+ command.option("--yes", "确认保存已经核对的策略草稿");
48
+ command.action(async (o, c) => {
49
+ if (name === "save")
50
+ confirm(o);
51
+ await show(c, await client().savePolicy(await inputFile(o.file), o.id, name === "preview"));
52
+ });
53
+ }
54
+ policy.command("publish <policyId>").description("发布已核对的准确 checksum;同一次请求保持幂等 key")
55
+ .requiredOption("--expected-checksum <checksum>", "state 返回并已核对的 draftChecksum")
56
+ .requiredOption("--idempotency-key <key>", "稳定请求键,8–128 字母、数字、下划线或短横线")
57
+ .option("--yes", "确认应用此策略文档与绑定差异")
58
+ .action(async (value, o, c) => {
59
+ confirm(o);
60
+ await show(c, await client().publish(positive(value), o.expectedChecksum, o.idempotencyKey));
61
+ });
62
+ paging(policy.command("jobs").description("读取发布作业状态;响应未知时先查作业,不生成新幂等键")
63
+ .requiredOption("--account-id <id>", "云账号 ID", positive))
64
+ .action(async (o, c) => show(c, await client().jobs(o.accountId, o.page)));
65
+ paging(policy.command("bindings <policyId>").description("列出 STS 授权,包括停用记录与 version"))
66
+ .action(async (value, o, c) => show(c, await client().bindings(positive(value), o.page)));
67
+ file(policy.command("bind-client <policyId>").description("绑定已登记的机器 Client 实例;已发布策略的 STS Grant 即时生效"))
68
+ .option("--id <bindingId>", "更新已有 Grant(输入必须含 version)", positive)
69
+ .option("--yes", "确认准确 issuer、实例、SA subject、策略范围与权限")
70
+ .action(async (value, o, c) => {
71
+ confirm(o);
72
+ await show(c, await client().bindClient(positive(value), await inputFile(o.file), o.id));
73
+ });
74
+ }
75
+ export const ossGovernanceCommandCatalog = [
76
+ "oss identity", "oss clients --issuer-id <uuid>", "oss templates list", "oss templates get <revisionId>",
77
+ "oss policy list --account-id <id>", "oss policy get <policyId>", "oss policy state <policyId>",
78
+ "oss policy check <policyId>", "oss policy preview --file <path>", "oss policy save --file <path> --yes",
79
+ "oss policy publish <policyId> --expected-checksum <checksum> --idempotency-key <key> --yes",
80
+ "oss policy jobs --account-id <id>", "oss policy bindings <policyId>", "oss policy bind-client <policyId> --file <path> --yes"
81
+ ].map(command => ({ command, summary: "OSS 策略与机器 Client 授权治理", access: "role",
82
+ roles: ["mci-devops-platform-ops-admin"], examples: [`numa ${command} --json`],
83
+ operationalNotes: ["控制面使用平台身份;issuer-id 明确目标普通身份源,不切换操作者登录。", "Client subjectKey 为已登记实例 UUID,非 Client 编码;更新保留读取的版本,不自动重试并发写入。", "策略发布按准确 checksum 和稳定幂等键执行;Grant 在有效策略上即时生效,不重复发布。"] }));
84
+ //# sourceMappingURL=governance-commands.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"governance-commands.js","sourceRoot":"","sources":["../../src/oss/governance-commands.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,144 @@
1
+ import { z } from "zod";
2
+ import { OssClient } from "./client.js";
3
+ export declare const policyInputSchema: z.ZodObject<{
4
+ accountId: z.ZodNumber;
5
+ code: z.ZodString;
6
+ name: z.ZodString;
7
+ region: z.ZodString;
8
+ bucketName: z.ZodString;
9
+ scopeType: z.ZodEnum<{
10
+ BUCKET: "BUCKET";
11
+ PREFIX: "PREFIX";
12
+ }>;
13
+ objectPrefix: z.ZodOptional<z.ZodNullable<z.ZodString>>;
14
+ actionTemplateRevisionIds: z.ZodArray<z.ZodNumber>;
15
+ platformAccessEnabled: z.ZodBoolean;
16
+ consoleAccessEnabled: z.ZodOptional<z.ZodBoolean>;
17
+ cloudPolicyName: z.ZodString;
18
+ status: z.ZodEnum<{
19
+ ACTIVE: "ACTIVE";
20
+ DISABLED: "DISABLED";
21
+ }>;
22
+ description: z.ZodOptional<z.ZodNullable<z.ZodString>>;
23
+ version: z.ZodOptional<z.ZodNumber>;
24
+ }, z.core.$strict>;
25
+ export declare const clientBindingInputSchema: z.ZodObject<{
26
+ issuerId: z.ZodString;
27
+ subjectKey: z.ZodString;
28
+ clientId: z.ZodString;
29
+ serviceAccountSubject: z.ZodString;
30
+ status: z.ZodEnum<{
31
+ ACTIVE: "ACTIVE";
32
+ DISABLED: "DISABLED";
33
+ }>;
34
+ maxSessionSeconds: z.ZodNumber;
35
+ description: z.ZodOptional<z.ZodString>;
36
+ accessPriority: z.ZodOptional<z.ZodEnum<{
37
+ HIGH: "HIGH";
38
+ HIGHEST: "HIGHEST";
39
+ LOW: "LOW";
40
+ LOWEST: "LOWEST";
41
+ NORMAL: "NORMAL";
42
+ }>>;
43
+ version: z.ZodOptional<z.ZodNumber>;
44
+ }, z.core.$strict>;
45
+ /** OSS control plane uses platform identity. It never requests Client secrets or STS. */
46
+ export declare class OssGovernanceClient extends OssClient {
47
+ protected requestPolicy(init: RequestInit): {
48
+ redirect: "error";
49
+ retryUnauthorized: boolean;
50
+ };
51
+ identity(): Promise<{
52
+ [x: string]: unknown;
53
+ managementIssuerId: string;
54
+ identityKey: string;
55
+ issuerUrl: string;
56
+ }>;
57
+ clients(issuerId: string, search?: string, page?: number): Promise<{
58
+ [x: string]: unknown;
59
+ issuerId: string;
60
+ identityKey: string;
61
+ items: {
62
+ [x: string]: unknown;
63
+ id: string;
64
+ clientId: string;
65
+ subject: string;
66
+ }[];
67
+ total: number;
68
+ }>;
69
+ templates(search?: string, page?: number): Promise<{
70
+ [x: string]: unknown;
71
+ items: Record<string, unknown>[];
72
+ total: number;
73
+ }>;
74
+ template(revisionId: number): Promise<{
75
+ [x: string]: unknown;
76
+ id: number;
77
+ templateId: number;
78
+ version: number;
79
+ code: string;
80
+ actions: string[];
81
+ status: string;
82
+ }>;
83
+ policies(accountId: number, search?: string, page?: number): Promise<{
84
+ [x: string]: unknown;
85
+ items: Record<string, unknown>[];
86
+ total: number;
87
+ }>;
88
+ policy(policyId: number): Promise<{
89
+ [x: string]: unknown;
90
+ id: number;
91
+ accountId: number;
92
+ version: number;
93
+ code: string;
94
+ status: string;
95
+ platformAccessEnabled?: boolean | null | undefined;
96
+ }>;
97
+ state(policyId: number): Promise<{
98
+ [x: string]: unknown;
99
+ policyId: number;
100
+ draftChecksum: string;
101
+ draftVersion: number;
102
+ pending: boolean;
103
+ health: string;
104
+ }>;
105
+ check(policyId: number): Promise<{
106
+ [x: string]: unknown;
107
+ policyId: number;
108
+ draftChecksum: string;
109
+ draftVersion: number;
110
+ pending: boolean;
111
+ health: string;
112
+ }>;
113
+ publish(policyId: number, expectedChecksum: string, idempotencyKey: string): Promise<{
114
+ [x: string]: unknown;
115
+ id: string;
116
+ policyId: number;
117
+ status: string;
118
+ checksum: string;
119
+ }>;
120
+ jobs(accountId: number, page?: number): Promise<{
121
+ [x: string]: unknown;
122
+ items: Record<string, unknown>[];
123
+ total: number;
124
+ }>;
125
+ savePolicy(value: unknown, policyId?: number, preview?: boolean): Promise<Record<string, unknown>>;
126
+ bindings(policyId: number, page?: number): Promise<{
127
+ [x: string]: unknown;
128
+ items: Record<string, unknown>[];
129
+ total: number;
130
+ }>;
131
+ private allBindings;
132
+ bindClient(policyId: number, value: unknown, bindingId?: number): Promise<{
133
+ [x: string]: unknown;
134
+ id: number;
135
+ policyId: number;
136
+ subjectType: "CLIENT";
137
+ subjectKey: string;
138
+ issuerId: string | null;
139
+ clientId: string;
140
+ serviceAccountSubject: string;
141
+ version: number;
142
+ status: string;
143
+ }>;
144
+ }
@@ -0,0 +1,187 @@
1
+ import { z } from "zod";
2
+ import { OssClient } from "./client.js";
3
+ import { OssError } from "./errors.js";
4
+ const id = z.number().int().positive().safe();
5
+ const version = z.number().int().nonnegative().safe();
6
+ const uuid = z.string().uuid();
7
+ const record = z.record(z.string(), z.unknown());
8
+ const policySchema = z.object({ id, accountId: id, version, code: z.string(), status: z.string(), platformAccessEnabled: z.boolean().nullable().optional() }).passthrough();
9
+ const pageSchema = z.object({ items: z.array(record), total: z.number().int().nonnegative() }).passthrough();
10
+ const stateSchema = z.object({ policyId: id, draftChecksum: z.string().min(1), draftVersion: version, pending: z.boolean(), health: z.string() }).passthrough();
11
+ const jobSchema = z.object({ id: uuid, policyId: id, status: z.string(), checksum: z.string() }).passthrough();
12
+ const directorySchema = z.object({ issuerId: uuid, identityKey: z.string(), items: z.array(z.object({ id: uuid, clientId: z.string(), subject: z.string() }).passthrough()), total: z.number().int().nonnegative() }).passthrough();
13
+ const bindingSchema = z.object({ id, policyId: id, subjectType: z.literal("CLIENT"), subjectKey: uuid, issuerId: uuid.nullable(), clientId: z.string(), serviceAccountSubject: z.string(), version, status: z.string() }).passthrough();
14
+ const templateSchema = z.object({ id, templateId: id, version, code: z.string(), actions: z.array(z.string()), status: z.string() }).passthrough();
15
+ export const policyInputSchema = z.object({
16
+ accountId: id, code: z.string().min(1).max(120), name: z.string().min(1).max(160),
17
+ region: z.string().min(1), bucketName: z.string().min(1), scopeType: z.enum(["BUCKET", "PREFIX"]),
18
+ objectPrefix: z.string().nullable().optional(), actionTemplateRevisionIds: z.array(id).min(1).max(16),
19
+ platformAccessEnabled: z.boolean(), consoleAccessEnabled: z.boolean().optional(),
20
+ cloudPolicyName: z.string().min(1), status: z.enum(["ACTIVE", "DISABLED"]),
21
+ description: z.string().max(2000).nullable().optional(), version: version.optional()
22
+ }).strict().refine(v => v.scopeType !== "PREFIX" || Boolean(v.objectPrefix?.trim()), "PREFIX requires objectPrefix");
23
+ export const clientBindingInputSchema = z.object({
24
+ issuerId: uuid, subjectKey: uuid, clientId: z.string().min(1), serviceAccountSubject: z.string().min(1),
25
+ status: z.enum(["ACTIVE", "DISABLED"]), maxSessionSeconds: z.number().int().min(900).max(3600),
26
+ description: z.string().max(2000).optional(), accessPriority: z.enum(["HIGHEST", "HIGH", "NORMAL", "LOW", "LOWEST"]).optional(),
27
+ version: version.optional()
28
+ }).strict();
29
+ function input(schema, value) {
30
+ const result = schema.safeParse(value);
31
+ if (!result.success)
32
+ throw new OssError("Invalid OSS governance input; check required fields, IDs and versions.", "oss_input_invalid");
33
+ return result.data;
34
+ }
35
+ function conflict(message) { throw new OssError(message, "oss_governance_conflict", 409); }
36
+ function query(values) {
37
+ return new URLSearchParams(Object.entries(values).filter(([, v]) => v !== undefined).map(([k, v]) => [k, String(v)])).toString();
38
+ }
39
+ const policyPath = (value) => `/api/v1/admin/oss-policy-authorizations/${input(id, value)}`;
40
+ /** OSS control plane uses platform identity. It never requests Client secrets or STS. */
41
+ export class OssGovernanceClient extends OssClient {
42
+ requestPolicy(init) {
43
+ return { redirect: "error", retryUnauthorized: (init.method ?? "GET").toUpperCase() === "GET" };
44
+ }
45
+ async identity() {
46
+ return this.json("/api/v1/admin/oss-authorization-options/identity", z.object({ managementIssuerId: uuid, identityKey: z.string(), issuerUrl: z.string() }).passthrough());
47
+ }
48
+ async clients(issuerId, search = "", page = 1) {
49
+ input(uuid, issuerId);
50
+ input(id, page);
51
+ const result = await this.json(`/api/v1/admin/oss-authorization-options/service-accounts?${query({ issuerId, query: search, page, limit: 100 })}`, directorySchema);
52
+ if (result.issuerId.toLowerCase() !== issuerId.toLowerCase())
53
+ conflict("Client directory belongs to a different issuer.");
54
+ return result;
55
+ }
56
+ async templates(search = "", page = 1) {
57
+ input(id, page);
58
+ return this.json(`/api/v1/admin/oss-action-templates?${query({ q: search, page, size: 100, activeOnly: true })}`, pageSchema);
59
+ }
60
+ async template(revisionId) {
61
+ const result = await this.json(`/api/v1/admin/oss-action-templates/revisions/${input(id, revisionId)}`, templateSchema);
62
+ if (result.id !== revisionId)
63
+ conflict("Template revision mismatch.");
64
+ return result;
65
+ }
66
+ async policies(accountId, search = "", page = 1) {
67
+ input(id, accountId);
68
+ input(id, page);
69
+ return this.json(`/api/v1/admin/oss-policy-authorizations/policies?${query({ accountId, q: search, page })}`, pageSchema);
70
+ }
71
+ async policy(policyId) {
72
+ const result = await this.json(policyPath(policyId), policySchema);
73
+ if (result.id !== policyId)
74
+ conflict("Policy identity mismatch.");
75
+ return result;
76
+ }
77
+ async state(policyId) {
78
+ const result = await this.json(`/api/v1/admin/oss-publications/policies/${input(id, policyId)}`, stateSchema);
79
+ if (result.policyId !== policyId)
80
+ conflict("Policy state identity mismatch.");
81
+ return result;
82
+ }
83
+ async check(policyId) {
84
+ await this.policy(policyId);
85
+ const result = await this.json(`/api/v1/admin/oss-publications/policies/${policyId}/check`, stateSchema, { method: "POST", body: "{}" });
86
+ if (result.policyId !== policyId)
87
+ conflict("Policy check identity mismatch.");
88
+ return result;
89
+ }
90
+ async publish(policyId, expectedChecksum, idempotencyKey) {
91
+ input(z.string().min(1).max(256), expectedChecksum);
92
+ input(z.string().regex(/^[a-zA-Z0-9_-]{8,128}$/u), idempotencyKey);
93
+ await this.policy(policyId);
94
+ // The server checks the reviewed checksum atomically and preserves retries by key.
95
+ // Do not replace it with a newly fetched checksum or silently create a new key.
96
+ const result = await this.json(`/api/v1/admin/oss-publications/policies/${policyId}/publish`, jobSchema, { method: "POST", body: JSON.stringify({ expectedChecksum, idempotencyKey }) });
97
+ if (result.policyId !== policyId || result.checksum !== expectedChecksum)
98
+ conflict("Publication result does not match the requested policy/checksum; inspect job state before retrying.");
99
+ return result;
100
+ }
101
+ async jobs(accountId, page = 1) {
102
+ input(id, accountId);
103
+ input(id, page);
104
+ return this.json(`/api/v1/admin/oss-publications?${query({ accountId, page, size: 100 })}`, pageSchema);
105
+ }
106
+ async savePolicy(value, policyId, preview = false) {
107
+ const data = input(policyInputSchema, value);
108
+ if (policyId !== undefined) {
109
+ if (data.version === undefined)
110
+ throw new OssError("Policy update requires its reviewed version.", "oss_input_invalid");
111
+ if (data.consoleAccessEnabled === undefined)
112
+ throw new OssError("Policy update requires explicit consoleAccessEnabled to preserve reviewed access.", "oss_input_invalid");
113
+ const current = await this.policy(policyId);
114
+ if (current.version !== data.version)
115
+ conflict("Policy version changed; reload and review before saving.");
116
+ if (current.accountId !== data.accountId || current.code !== data.code)
117
+ conflict("Policy account and code cannot be replaced.");
118
+ }
119
+ else if (data.version !== undefined)
120
+ throw new OssError("New policies must omit version.", "oss_input_invalid");
121
+ if (policyId === undefined)
122
+ data.consoleAccessEnabled ??= false;
123
+ for (const revision of data.actionTemplateRevisionIds)
124
+ await this.template(revision);
125
+ const root = "/api/v1/admin/aliyun-oss-access-policies";
126
+ if (preview)
127
+ return this.json(`${root}/preview${policyId === undefined ? "" : `?policyId=${policyId}`}`, record, { method: "POST", body: JSON.stringify(data) });
128
+ const result = await this.json(policyId === undefined ? root : `${root}/${policyId}`, policySchema, { method: policyId === undefined ? "POST" : "PUT", body: JSON.stringify(data) }, policyId === undefined ? [201] : [200]);
129
+ if (result.accountId !== data.accountId || result.code !== data.code || (policyId !== undefined && result.id !== policyId))
130
+ conflict("Saved policy identity mismatch; inspect state before retrying.");
131
+ return result;
132
+ }
133
+ async bindings(policyId, page = 1) {
134
+ input(id, page);
135
+ return this.json(`${policyPath(policyId)}/bindings?${query({ page, history: true, mode: "STS" })}`, pageSchema);
136
+ }
137
+ async allBindings(policyId) {
138
+ const rows = [];
139
+ for (let page = 1; page <= 1000; page++) {
140
+ const result = await this.bindings(policyId, page);
141
+ rows.push(...result.items);
142
+ if (page * 20 >= result.total)
143
+ return rows;
144
+ }
145
+ conflict("Too many policy bindings to verify safely; use the explicit record after narrowing the policy.");
146
+ }
147
+ async bindClient(policyId, value, bindingId) {
148
+ const data = input(clientBindingInputSchema, value);
149
+ if (bindingId !== undefined) {
150
+ input(id, bindingId);
151
+ if (data.version === undefined)
152
+ throw new OssError("Binding update requires its reviewed version.", "oss_input_invalid");
153
+ }
154
+ else if (data.version !== undefined)
155
+ throw new OssError("New Client bindings must omit version.", "oss_input_invalid");
156
+ const policy = await this.policy(policyId);
157
+ const identity = await this.identity();
158
+ const rows = await this.allBindings(policyId);
159
+ const matches = (row) => row.type === "CLIENT" && row.subjectKey === data.subjectKey
160
+ && (row.issuerId === data.issuerId || (row.issuerId === null && identity.managementIssuerId === data.issuerId));
161
+ if (bindingId === undefined && rows.some(matches))
162
+ conflict("This Client already has a binding, including disabled history; update its record/version instead of creating a duplicate.");
163
+ if (bindingId !== undefined) {
164
+ const current = rows.find(row => row.recordId === bindingId);
165
+ if (!current || !matches(current) || current.version !== data.version)
166
+ conflict("Binding identity/version changed; reload before updating.");
167
+ if (data.status === "DISABLED" && (current.clientId !== data.clientId || current.serviceAccountSubject !== data.serviceAccountSubject))
168
+ conflict("Revocation must retain the reviewed stored Client and service-account identity.");
169
+ }
170
+ if (bindingId === undefined || data.status !== "DISABLED") {
171
+ const directory = await this.clients(data.issuerId, data.clientId);
172
+ const machine = directory.items.find(row => row.id.toLowerCase() === data.subjectKey.toLowerCase());
173
+ if (!machine || machine.clientId !== data.clientId || machine.subject !== data.serviceAccountSubject)
174
+ conflict("Client instance or service-account subject changed; review the issuer Client directory again.");
175
+ }
176
+ if (data.status === "ACTIVE" && (!policy.platformAccessEnabled || policy.status !== "ACTIVE"))
177
+ conflict("Client grants need an active policy with platform access enabled and published; inspect policy state first.");
178
+ // Client ID and SA subject are evidence, not caller-controlled identity fields in the API.
179
+ const { clientId: _clientId, serviceAccountSubject: _subject, ...fields } = data;
180
+ const result = await this.json(`${policyPath(policyId)}/bindings${bindingId === undefined ? "" : `/${bindingId}`}`, bindingSchema, { method: bindingId === undefined ? "POST" : "PUT", body: JSON.stringify({ ...fields, type: "CLIENT" }) });
181
+ if ((bindingId !== undefined && result.id !== bindingId) || result.policyId !== policyId || result.subjectKey !== data.subjectKey || result.clientId !== data.clientId || result.serviceAccountSubject !== data.serviceAccountSubject
182
+ || !(result.issuerId === data.issuerId || (result.issuerId === null && identity.managementIssuerId === data.issuerId)))
183
+ conflict("Saved Client binding identity mismatch; inspect bindings before retrying.");
184
+ return result;
185
+ }
186
+ }
187
+ //# sourceMappingURL=governance.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"governance.js","sourceRoot":"","sources":["../../src/oss/governance.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,93 @@
1
+ # Application configuration publication from the CLI
2
+
3
+ The current DevOps API publishes a reviewed complete configuration bundle. Use
4
+ `numa authorization application --app <id> publication preview` for new work.
5
+ The existing `plan`, `prepare`, `review`, `apply` and `recheck` commands remain
6
+ available for historical stage-based jobs; `apply` still executes one stage.
7
+ There is no automatic fallback from the new protocol to the old protocol.
8
+
9
+ All commands use the profile's `platform` service and require the server's
10
+ `mci-devops-platform-ops-admin` role. Select the exact application and environment
11
+ from read-only catalog/source responses before saving anything. An ordinary
12
+ registered issuer can be the DevOps management issuer. Use `REGISTERED` with its
13
+ issuer UUID for new environment bindings. `PLATFORM` remains a server-compatible
14
+ legacy alias; a registered management issuer may retain the historical
15
+ `identityKey: "platform"`. Do not derive the identity key from the issuer UUID.
16
+
17
+ ## Edit with the correct optimistic versions
18
+
19
+ Read the current object immediately before editing and preserve its concurrency
20
+ fields. A stale save returns a conflict; inspect the latest value and make a new
21
+ explicit decision. The CLI never silently refreshes a version and retries a write.
22
+
23
+ | Operation | Concurrency evidence |
24
+ | --- | --- |
25
+ | Definition save/freeze | `expectedDraftVersion` |
26
+ | Role composition change | First `definition preview-compositions --file`, then its `expectedDigest` as `expectedCompositionDigest` on definition save |
27
+ | Client/group draft | `expectedDefinitionVersion`, `expectedReferenceVersion`, `expectedInstanceVersion`, `expectedTargetVersion` |
28
+ | Login trust change | Both `enrollmentTrusted` and `expectedEnrollmentTrustVersion` |
29
+ | Relation changes | `expectedRevision`; source-release changes additionally pin block version/generation |
30
+ | Environment binding | Its `version`, not a Client or publication version |
31
+ | Complete publication | Job `version`, `planDigest` and `plan.configurationBundle.bundleDigest` from the same reviewed response |
32
+
33
+ Saving a draft does not publish. A frozen permission-definition version is an
34
+ immutable input to publication; it is not the edit-concurrency version of every
35
+ Client, group or environment.
36
+
37
+ ## Preview and execute
38
+
39
+ Create a JSON file containing the exact request ID, frozen definition version and
40
+ environment UUIDs returned by the platform. Optional `clientModes` is keyed by
41
+ Client instance UUID with CREATE/ADOPT/UPDATE/REPAIR values. The new `preview`
42
+ command sends `protocolVersion: 2` and rejects an explicit protocol 1 value.
43
+ Preview persists a reviewable job but makes no remote configuration changes, so
44
+ it requires `--yes` to confirm creation of that exact job.
45
+
46
+ ```sh
47
+ numa authorization application --app APP_ID publication preview --file preview.json --yes --json
48
+ numa authorization application --app APP_ID publication show JOB_ID --json
49
+ numa authorization application --app APP_ID publication execute JOB_ID \
50
+ --expected-version JOB_VERSION --expected-digest PLAN_SHA256 \
51
+ --expected-bundle-digest BUNDLE_SHA256 --yes --json
52
+ ```
53
+
54
+ The capitalized values are placeholders to replace with reviewed API evidence.
55
+ Review all bundle `objects`, `differences` (current/desired/baseline), `blockers`
56
+ and role-removal effects. A BLOCKED preview must be resolved before execution.
57
+ Use `--confirm-javascript-policy-deletion` only when the preview specifically
58
+ requires that deletion and it has been approved. Ordinary `--yes` does not grant
59
+ that additional consent. The backend owns object claims, concurrency checks,
60
+ execution, retry scheduling and remote readback.
61
+
62
+ The execute response acknowledges asynchronous work. Repeatedly **read** the same
63
+ job with `publication show`; do not create another job to retry it. Full JSON
64
+ retains the bundle and `execution.status`, `errorCode`, `errorDetails`,
65
+ `verifiedAt`, `observedBundleDigest` and original consent. `QUEUED`, `RUNNING` and
66
+ `RETRY_WAIT` are unfinished. `WAITING_MANUAL` needs examination. `SUCCEEDED`
67
+ requires readback evidence, but a successful configuration readback does not prove
68
+ that a real user's KB/OSS request is allowed. Validate the intended business call
69
+ separately with the proper service identity.
70
+
71
+ ## Resume or abandon
72
+
73
+ After inspecting a waiting job and its readback error, use its current version and
74
+ the original plan/bundle digests:
75
+
76
+ ```sh
77
+ numa authorization application --app APP_ID publication resume JOB_ID \
78
+ --expected-version JOB_VERSION --expected-digest PLAN_SHA256 \
79
+ --expected-bundle-digest BUNDLE_SHA256 --yes --json
80
+ numa authorization application --app APP_ID publication abandon JOB_ID \
81
+ --expected-version JOB_VERSION --expected-digest PLAN_SHA256 \
82
+ --note 'Keep online state; stop further synchronization' --yes --json
83
+ ```
84
+
85
+ Resume must repeat the original JavaScript deletion consent: supply
86
+ `--confirm-javascript-policy-deletion` only if the original execution's
87
+ `javascriptPolicyDeletionConfirmed` is true. It authorizes continuation of the
88
+ original bundle, not new configuration. Abandon stops future writes and preserves
89
+ online effects and historical evidence; it is not a rollback or a draft reset.
90
+
91
+ `repreview --file` accepts `protocolVersion: 2` plus the original job confirmation
92
+ and a new request ID. Historical cleanup remains explicit. No command bypasses a
93
+ live job or turns a 401/409/uncertain request into an automatic mutation replay.
@@ -0,0 +1,93 @@
1
+ # OSS 策略与机器 Client 授权
2
+
3
+ 这些命令通过 DevOps Platform 控制面操作;操作者使用平台身份和服务端校验的管理员权限。`--issuer-id` 是被授权机器所在的普通身份源 UUID,不会切换操作者身份。命令不读取 Client Secret,不输出 STS 凭据。
4
+
5
+ ## 先定位现有配置
6
+
7
+ ```sh
8
+ numa oss identity --json
9
+ numa oss clients --issuer-id <issuer-uuid> --query kb --json
10
+ numa oss policy list --account-id <account-id> --query kb --json
11
+ numa oss policy get <policy-id> --json
12
+ numa oss policy bindings <policy-id> --json
13
+ numa oss policy state <policy-id> --json
14
+ ```
15
+
16
+ `clients` 返回的 `id` 是已登记的 **Client 实例 UUID**,是 Grant 的 `subjectKey`。它不等于 Client 编码、Keycloak Client UUID 或 SA subject。返回的 `clientId` 和 `subject` 是下一步输入核验信息。
17
+
18
+ 分页命令显式支持 `--page`;策略列表和绑定列表每页 20 条,Client、模板和发布作业列表每页最多 100 条。修改绑定前 CLI 会遍历该策略的 STS 授权(含停用历史),防止重复创建。
19
+
20
+ 旧的管理身份源 Grant 可能保存 `issuerId: null`。新请求仍填写 `oss identity` 返回的 `managementIssuerId`;CLI 根据实际身份源绑定识别旧记录,后端处理存储兼容,不需要人为将 UUID 改成 `platform` 或空值。
21
+
22
+ ## 修改策略范围或 Actions
23
+
24
+ 策略基于不可变模板 revision ID;不用旧的 `permissionLevel` 名称猜测 Actions。
25
+
26
+ ```sh
27
+ numa oss templates list --query FILE --json
28
+ numa oss templates get <revision-id> --json
29
+ numa oss policy preview --id <policy-id> --file ./policy.json --json
30
+ numa oss policy save --id <policy-id> --file ./policy.json --yes --json
31
+ ```
32
+
33
+ `policy.json` 描述完整可编辑配置,例如:
34
+
35
+ ```json
36
+ {
37
+ "accountId": 1,
38
+ "code": "kb-files",
39
+ "name": "KB files",
40
+ "region": "cn-shenzhen",
41
+ "bucketName": "example-kb-bucket",
42
+ "scopeType": "PREFIX",
43
+ "objectPrefix": "documents/",
44
+ "actionTemplateRevisionIds": [7],
45
+ "platformAccessEnabled": true,
46
+ "consoleAccessEnabled": false,
47
+ "cloudPolicyName": "kb-files",
48
+ "status": "ACTIVE",
49
+ "version": 4
50
+ }
51
+ ```
52
+
53
+ 示例 ID、Bucket 和版本仅为占位;使用读取到的真实值。编辑保留已核对的 `version`,并明确填写 `consoleAccessEnabled`,避免遗漏字段改变原权限;若发生并发修改,命令拒绝写入并要求重新查看。新建时省略 `--id` 和 `version`。不接受凭据、原始 `policyDocument` 或动态 Action 覆盖字段。
54
+
55
+ 保存仅改变草稿。发布前查看完整 draft/published/observed 快照,并核对 Bucket、Prefix、Actions、平台访问开关和 RAM 绑定:
56
+
57
+ ```sh
58
+ numa oss policy state <policy-id> --json
59
+ numa oss policy publish <policy-id> --expected-checksum <reviewed-draftChecksum> --idempotency-key <stable-request-key> --yes --json
60
+ numa oss policy jobs --account-id <account-id> --json
61
+ numa oss policy check <policy-id> --json
62
+ ```
63
+
64
+ 发布请求使用已审核 checksum,后端原子拒绝过期配置。同一次发布固定幂等 key;网络超时或结果未知时先读取作业和状态,不更换 key 自动重复提交。`check` 会读取云端并更新核对记录,但不修改云端 Policy。作业返回不代表已完成,应核实发布成功和回读健康状态。
65
+
66
+ ## 绑定或更新机器 Client
67
+
68
+ 针对已启用、已发布的策略,准备以下 `binding.json`:
69
+
70
+ ```json
71
+ {
72
+ "issuerId": "00000000-0000-4000-8000-000000000001",
73
+ "subjectKey": "00000000-0000-4000-8000-000000000002",
74
+ "clientId": "kb-oss",
75
+ "serviceAccountSubject": "actual-subject-from-directory",
76
+ "maxSessionSeconds": 1800,
77
+ "status": "ACTIVE",
78
+ "accessPriority": "NORMAL",
79
+ "description": "KB document storage",
80
+ "version": 4
81
+ }
82
+ ```
83
+
84
+ ```sh
85
+ numa oss policy bind-client <policy-id> --id <existing-grant-id> --file ./binding.json --yes --json
86
+ numa oss policy bindings <policy-id> --json
87
+ ```
88
+
89
+ 更新使用绑定列表的 `recordId` 和 `version`;只有确认不存在旧授权时才省略 `--id` 和 `version` 创建。CLI 会核对 issuer、Client 实例、Client 编码及 SA subject,并保留原版本交给后端再次校验。更新省略 `accessPriority` 时保留原值。停用已有授权按原绑定核验身份,允许撤销已失效 Client。它不会在冲突后自动获取新版本覆盖别人修改,也不会自动重放治理写请求。
90
+
91
+ Client Grant 是平台即时生效的授权记录,不属于云端 Policy 发布快照。只修改 Grant 且其引用策略已经有效时,不需重复发布云策略。若策略本身有待发布变化,先完成上面的策略发布。
92
+
93
+ 最后使用应用实际机器身份验证 `oss grants`、STS 签发以及实际 Bucket/Prefix 的读写流程。管理员看到 Grant 存在并不能证明机器 Token 的 issuer、azp、aud、角色及 SA subject 正确;403 应区分平台 API 拒绝、STS 拒绝和 OSS 对象操作拒绝后定位。