feat: updade workspace

This commit is contained in:
thanhnv
2026-07-11 15:56:31 +09:00
parent 4fc72332f5
commit 193a449829
120 changed files with 868 additions and 350 deletions
@@ -77,8 +77,8 @@ function stableJson(value: unknown): string {
export class ApprovalsService {
list(actor: SettingsActor, status = 'pending') {
this.requireRbac(actor, 'monitoring', 'read');
const res = runFile('python3', [INBOX_CLI, 'list', '--status', status]);
return { ...parseJson<Record<string, any>>(res.stdout, { count: 0, proposals: [], oversight: [] }), audit_verify: this.verifyAudit() };
const res = runFile('python3', [INBOX_CLI, 'list', '--status', status], this.tenantEnv(actor));
return { ...parseJson<Record<string, any>>(res.stdout, { count: 0, proposals: [], oversight: [] }), audit_verify: this.verifyAudit(actor) };
}
submit(input: ApprovalSubmit, actor: SettingsActor) {
@@ -109,8 +109,8 @@ export class ApprovalsService {
JSON.stringify(input.payload ?? {}),
];
if (input.sensitive) args.push('--sensitive');
const res = runFile('python3', args);
return { proposal: parseJson<Record<string, any>>(res.stdout, {}), audit_verify: this.verifyAudit() };
const res = runFile('python3', args, this.tenantEnv(actor));
return { proposal: parseJson<Record<string, any>>(res.stdout, {}), audit_verify: this.verifyAudit(actor) };
}
decide(input: ApprovalDecision, actor: SettingsActor) {
@@ -119,7 +119,7 @@ export class ApprovalsService {
}
this.requireRbac(actor, 'approval', 'grant');
try {
const pending = this.findProposal(input.id);
const pending = this.findProposal(input.id, actor);
this.verifyApprovalIdentity(input, actor, pending);
const res = runFile('python3', [
INBOX_CLI,
@@ -132,10 +132,10 @@ export class ApprovalsService {
actor.actor,
'--reason',
input.reason,
]);
], this.tenantEnv(actor));
const proposal = parseJson<Record<string, any>>(res.stdout, {});
const applied = input.decision === 'approve' ? this.applyApprovedProposal(proposal, actor) : null;
return { proposal, applied, audit_verify: this.verifyAudit() };
return { proposal, applied, audit_verify: this.verifyAudit(actor) };
} catch (err: any) {
if (err instanceof ForbiddenException) throw err;
if (Number(err.status) === 3 || Number(err.status) === 1) {
@@ -145,8 +145,8 @@ export class ApprovalsService {
}
}
private findProposal(id: string) {
const res = runFile('python3', [INBOX_CLI, 'list', '--status', 'all']);
private findProposal(id: string, actor: SettingsActor) {
const res = runFile('python3', [INBOX_CLI, 'list', '--status', 'all'], this.tenantEnv(actor));
const store = parseJson<Record<string, any>>(res.stdout, { proposals: [] });
const proposal = (store.proposals ?? []).find((p: Record<string, any>) => p.id === id);
if (!proposal) throw new ForbiddenException(`APPROVAL_DECIDE_DENY unknown_id ${id}`);
@@ -199,7 +199,7 @@ export class ApprovalsService {
`approved:${proposal.id}:${proposal.decision_reason ?? ''}`,
'--approval',
`inbox:${proposal.id}:${actor.actor}`,
]);
], this.tenantEnv(actor));
return parseJson<Record<string, any>>(res.stdout, {});
} catch (err: any) {
if (Number(err.status) === 2 || Number(err.status) === 3) {
@@ -234,9 +234,13 @@ export class ApprovalsService {
}
}
private verifyAudit() {
private tenantEnv(actor: SettingsActor): NodeJS.ProcessEnv {
return { CASAN_TENANT_ID: actor.tenant || 'default' };
}
private verifyAudit(actor: SettingsActor) {
try {
const res = runFile('python3', [INBOX_CLI, 'verify-audit']);
const res = runFile('python3', [INBOX_CLI, 'verify-audit'], this.tenantEnv(actor));
return { ok: true, output: res.stdout };
} catch (err: any) {
return { ok: false, output: err.stderr || err.stdout || err.message };