fix(tess): harden durable recovery namespaces
All checks were successful
ci/woodpecker/pr/ci Pipeline was successful

This commit is contained in:
Jarvis
2026-07-12 23:36:14 -05:00
parent 102a7b606b
commit 444988d23b
22 changed files with 449 additions and 391 deletions

View File

@@ -23,6 +23,8 @@ export interface RuntimeTerminationApprovalAction {
tenantId: string;
channelId: string;
correlationId: string;
/** Provisioned roster identity; isolates approvals between interaction agents. */
agentName: string;
}
export interface RuntimeTerminationApproval extends RuntimeTerminationApprovalAction {
@@ -92,7 +94,7 @@ export class CommandAuthorizationService {
}
/**
* Uses the same `tess:command-approval:*` store and one-time deletion rule as
* Uses the same `interaction:command-approval:*` store and one-time deletion rule as
* command approvals. This deliberately avoids a parallel approval database.
*/
async createRuntimeTerminationApproval(
@@ -108,7 +110,12 @@ export class CommandAuthorizationService {
...action,
expiresAt: new Date(Date.now() + 5 * 60_000).toISOString(),
};
await this.redis.set(this.key(approval.approvalId), JSON.stringify(approval), 'EX', '300');
await this.redis.set(
this.runtimeKey(action.agentName, approval.approvalId),
JSON.stringify(approval),
'EX',
'300',
);
return approval;
}
@@ -116,7 +123,7 @@ export class CommandAuthorizationService {
approvalId: string,
action: RuntimeTerminationApprovalAction,
): Promise<boolean> {
const encoded = await this.redis.get(this.key(approvalId));
const encoded = await this.redis.get(this.runtimeKey(action.agentName, approvalId));
if (!encoded) return false;
let approval: unknown;
try {
@@ -134,7 +141,7 @@ export class CommandAuthorizationService {
return false;
}
if ((await this.resolveRole(approval.actorId)) !== 'admin') return false;
return (await this.redis.del(this.key(approvalId))) === 1;
return (await this.redis.del(this.runtimeKey(action.agentName, approvalId))) === 1;
}
private async resolveRole(actorId: string): Promise<CommandRole | null> {
@@ -196,6 +203,7 @@ export class CommandAuthorizationService {
action.tenantId,
action.channelId,
action.correlationId,
action.agentName,
].every((value: string): boolean => value.trim().length > 0);
}
@@ -209,6 +217,7 @@ export class CommandAuthorizationService {
tenantId: action.tenantId,
channelId: action.channelId,
correlationId: action.correlationId,
agentName: action.agentName,
}),
)
.digest('hex');
@@ -244,11 +253,16 @@ export class CommandAuthorizationService {
'sessionId' in value &&
'channelId' in value &&
'correlationId' in value &&
'agentName' in value &&
'expiresAt' in value
);
}
private key(approvalId: string): string {
return `tess:command-approval:${approvalId}`;
return `interaction:command-approval:${approvalId}`;
}
private runtimeKey(agentName: string, approvalId: string): string {
return `agent:${encodeURIComponent(agentName)}:command-approval:${approvalId}`;
}
}