Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 | 21x 21x 21x 21x 21x 21x 21x 21x 116x 114x 114x 111x 21x 94x 94x 74x 72x 21x 200x 199x 21x 87x 2x 21x 172x 170x 170x 2x 168x 38x 130x 130x 40x 40x 40x 21x 39x 37x 2x 1x 34x | import type { EffectivePolicy } from '../../configuration/policy';
import { callRestriction, withoutScope } from '../../configuration/policy';
import { readAllowedProject } from '../../configuration/operator-projects';
import { gitlab } from '../../utils/gitlab-api';
import { extractSimpleId } from '../../utils/idConversion';
import { canonicalProjectPath } from '../../utils/api-path';
import { DUO_RESPONSE_BYTES, type Workflow } from './queries';
export interface DuoProject {
id: string;
path: string;
}
/** A missing project or invalid session project ID cannot establish provenance. */
export class UnverifiableDuoProjectError extends Error {}
/** The MCP invocation supplies its already combined operator, account and chat policy. */
export function duoPolicy(
tool: string,
args: Record<string, unknown>,
policy?: EffectivePolicy,
): EffectivePolicy {
if (!policy) throw new Error('Duo tools require the authenticated call execution policy');
const reason = callRestriction(
withoutScope(policy),
{ name: tool, group: 'duo', readOnly: tool === 'browse_duo_sessions' },
args,
);
if (reason) throw new Error(`Duo operation is not allowed: ${reason}`);
return policy;
}
export async function readDuoProject(id: string): Promise<DuoProject> {
const project = await readAllowedProject(id, (path) =>
gitlab.get(path, {
responseByteLimit: DUO_RESPONSE_BYTES,
rawResponse: true,
}),
);
if (!project) throw new UnverifiableDuoProjectError('Duo project is unavailable');
return project;
}
export function permitsDuoProject(project: DuoProject, policy: EffectivePolicy): boolean {
if (policy.operatorProjectIds && !policy.operatorProjectIds.has(project.id)) return false;
return (
!policy.scopeEnforcer ||
policy.scopeEnforcer.listsId(project.id, 'project') ||
policy.scopeEnforcer.isAllowed(project.path)
);
}
export function assertDuoProject(project: DuoProject, policy: EffectivePolicy): void {
if (!permitsDuoProject(project, policy))
throw new Error('Duo session project is outside the permitted projects or working scope');
}
/** Resolve provenance from GitLab, never from a caller's project hint. */
export async function workflowProject(
workflow: Workflow,
projectReads?: Map<string, Promise<DuoProject>>,
): Promise<DuoProject | null> {
if (workflow.projectId === null) return null;
const id = extractSimpleId(workflow.projectId);
if (!/^[1-9]\d*$/.test(id))
throw new UnverifiableDuoProjectError('GitLab returned an invalid Duo project identity');
if (workflow.project && extractSimpleId(workflow.project.id) === id)
return { id, path: canonicalProjectPath(workflow.project.fullPath) };
const cached = projectReads?.get(id);
if (cached) return cached;
const pending = readDuoProject(id);
projectReads?.set(id, pending);
return pending;
}
export async function assertWorkflowProject(
workflow: Workflow,
policy: EffectivePolicy,
): Promise<DuoProject | null> {
const project = await workflowProject(workflow);
if (project) assertDuoProject(project, policy);
else if (policy.scopeEnforcer || policy.operatorProjectIds)
throw new Error('GitLab did not expose a verifiable project for this Duo session');
return project;
}
|