Loading...
Loading...
Compare original and translation side by side
interface PermissionMatrix {
coreTools: {
read: boolean;
write: boolean;
edit: boolean;
glob: boolean;
grep: boolean;
task: boolean;
webFetch: boolean;
webSearch: boolean;
todoWrite: boolean;
};
bash: {
enabled: boolean;
allowedPatterns: string[]; // Regex patterns
deniedPatterns: string[];
sandboxed: boolean;
};
fileSystem: {
readPatterns: string[]; // Glob patterns
writePatterns: string[];
denyPatterns: string[];
};
mcpTools: {
allowed: string[]; // 'server:tool' format
denied: string[];
};
network: {
enabled: boolean;
allowedDomains: string[];
denyDomains: string[];
};
models: {
allowed: ('haiku' | 'sonnet' | 'opus')[];
preferredForSpawning: 'haiku' | 'sonnet' | 'opus';
};
}interface PermissionMatrix {
coreTools: {
read: boolean;
write: boolean;
edit: boolean;
glob: boolean;
grep: boolean;
task: boolean;
webFetch: boolean;
webSearch: boolean;
todoWrite: boolean;
};
bash: {
enabled: boolean;
allowedPatterns: string[]; // Regex patterns
deniedPatterns: string[];
sandboxed: boolean;
};
fileSystem: {
readPatterns: string[]; // Glob patterns
writePatterns: string[];
denyPatterns: string[];
};
mcpTools: {
allowed: string[]; // 'server:tool' format
denied: string[];
};
network: {
enabled: boolean;
allowedDomains: string[];
denyDomains: string[];
};
models: {
allowed: ('haiku' | 'sonnet' | 'opus')[];
preferredForSpawning: 'haiku' | 'sonnet' | 'opus';
};
}interface ValidationResult {
valid: boolean;
violations: PermissionViolation[];
warnings: string[];
suggestions: string[];
}
interface PermissionViolation {
category: string;
field: string;
parentValue: unknown;
childValue: unknown;
message: string;
}
function validatePermissionInheritance(
parent: PermissionMatrix,
child: PermissionMatrix
): ValidationResult {
const violations: PermissionViolation[] = [];
const warnings: string[] = [];
// Validate core tools
validateCoreTools(parent, child, violations);
// Validate bash permissions
validateBashPermissions(parent, child, violations);
// Validate file system access
validateFileSystemAccess(parent, child, violations);
// Validate MCP tools
validateMcpTools(parent, child, violations);
// Validate network access
validateNetworkAccess(parent, child, violations);
// Validate model access
validateModelAccess(parent, child, violations);
return {
valid: violations.length === 0,
violations,
warnings,
suggestions: generateSuggestions(violations),
};
}interface ValidationResult {
valid: boolean;
violations: PermissionViolation[];
warnings: string[];
suggestions: string[];
}
interface PermissionViolation {
category: string;
field: string;
parentValue: unknown;
childValue: unknown;
message: string;
}
function validatePermissionInheritance(
parent: PermissionMatrix,
child: PermissionMatrix
): ValidationResult {
const violations: PermissionViolation[] = [];
const warnings: string[] = [];
// Validate core tools
validateCoreTools(parent, child, violations);
// Validate bash permissions
validateBashPermissions(parent, child, violations);
// Validate file system access
validateFileSystemAccess(parent, child, violations);
// Validate MCP tools
validateMcpTools(parent, child, violations);
// Validate network access
validateNetworkAccess(parent, child, violations);
// Validate model access
validateModelAccess(parent, child, violations);
return {
valid: violations.length === 0,
violations,
warnings,
suggestions: generateSuggestions(violations),
};
}function validateCoreTools(
parent: PermissionMatrix,
child: PermissionMatrix,
violations: PermissionViolation[]
): void {
const toolNames = [
'read', 'write', 'edit', 'glob', 'grep',
'task', 'webFetch', 'webSearch', 'todoWrite',
] as const;
for (const tool of toolNames) {
// Child cannot have permission parent doesn't have
if (child.coreTools[tool] && !parent.coreTools[tool]) {
violations.push({
category: 'coreTools',
field: tool,
parentValue: false,
childValue: true,
message: `Child requests '${tool}' permission but parent doesn't have it`,
});
}
}
}function validateCoreTools(
parent: PermissionMatrix,
child: PermissionMatrix,
violations: PermissionViolation[]
): void {
const toolNames = [
'read', 'write', 'edit', 'glob', 'grep',
'task', 'webFetch', 'webSearch', 'todoWrite',
] as const;
for (const tool of toolNames) {
// Child cannot have permission parent doesn't have
if (child.coreTools[tool] && !parent.coreTools[tool]) {
violations.push({
category: 'coreTools',
field: tool,
parentValue: false,
childValue: true,
message: `Child requests '${tool}' permission but parent doesn't have it`,
});
}
}
}function validateFileSystemAccess(
parent: PermissionMatrix,
child: PermissionMatrix,
violations: PermissionViolation[]
): void {
// Validate read patterns
for (const pattern of child.fileSystem.readPatterns) {
if (!isPatternSubsetOf(pattern, parent.fileSystem.readPatterns)) {
violations.push({
category: 'fileSystem',
field: 'readPatterns',
parentValue: parent.fileSystem.readPatterns,
childValue: pattern,
message: `Child read pattern '${pattern}' exceeds parent's read access`,
});
}
}
// Validate write patterns
for (const pattern of child.fileSystem.writePatterns) {
if (!isPatternSubsetOf(pattern, parent.fileSystem.writePatterns)) {
violations.push({
category: 'fileSystem',
field: 'writePatterns',
parentValue: parent.fileSystem.writePatterns,
childValue: pattern,
message: `Child write pattern '${pattern}' exceeds parent's write access`,
});
}
}
// Ensure child denies at least what parent denies
for (const pattern of parent.fileSystem.denyPatterns) {
if (!child.fileSystem.denyPatterns.includes(pattern)) {
violations.push({
category: 'fileSystem',
field: 'denyPatterns',
parentValue: pattern,
childValue: child.fileSystem.denyPatterns,
message: `Child must deny '${pattern}' as parent denies it`,
});
}
}
}
function isPatternSubsetOf(
pattern: string,
allowedPatterns: string[]
): boolean {
// Check if pattern is covered by any allowed pattern
return allowedPatterns.some(allowed => {
// Exact match
if (pattern === allowed) return true;
// Allowed pattern is more general
if (allowed.includes('**') || allowed.includes('*')) {
return globMatches(allowed, pattern);
}
// Pattern is subdirectory
if (pattern.startsWith(allowed.replace(/\*+/g, ''))) {
return true;
}
return false;
});
}function validateFileSystemAccess(
parent: PermissionMatrix,
child: PermissionMatrix,
violations: PermissionViolation[]
): void {
// Validate read patterns
for (const pattern of child.fileSystem.readPatterns) {
if (!isPatternSubsetOf(pattern, parent.fileSystem.readPatterns)) {
violations.push({
category: 'fileSystem',
field: 'readPatterns',
parentValue: parent.fileSystem.readPatterns,
childValue: pattern,
message: `Child read pattern '${pattern}' exceeds parent's read access`,
});
}
}
// Validate write patterns
for (const pattern of child.fileSystem.writePatterns) {
if (!isPatternSubsetOf(pattern, parent.fileSystem.writePatterns)) {
violations.push({
category: 'fileSystem',
field: 'writePatterns',
parentValue: parent.fileSystem.writePatterns,
childValue: pattern,
message: `Child write pattern '${pattern}' exceeds parent's write access`,
});
}
}
// Ensure child denies at least what parent denies
for (const pattern of parent.fileSystem.denyPatterns) {
if (!child.fileSystem.denyPatterns.includes(pattern)) {
violations.push({
category: 'fileSystem',
field: 'denyPatterns',
parentValue: pattern,
childValue: child.fileSystem.denyPatterns,
message: `Child must deny '${pattern}' as parent denies it`,
});
}
}
}
function isPatternSubsetOf(
pattern: string,
allowedPatterns: string[]
): boolean {
// Check if pattern is covered by any allowed pattern
return allowedPatterns.some(allowed => {
// Exact match
if (pattern === allowed) return true;
// Allowed pattern is more general
if (allowed.includes('**') || allowed.includes('*')) {
return globMatches(allowed, pattern);
}
// Pattern is subdirectory
if (pattern.startsWith(allowed.replace(/\*+/g, ''))) {
return true;
}
return false;
});
}function validateBashPermissions(
parent: PermissionMatrix,
child: PermissionMatrix,
violations: PermissionViolation[]
): void {
// Child can't have bash if parent doesn't
if (child.bash.enabled && !parent.bash.enabled) {
violations.push({
category: 'bash',
field: 'enabled',
parentValue: false,
childValue: true,
message: 'Child requests bash access but parent doesn\'t have it',
});
}
// Child must be sandboxed if parent is
if (parent.bash.sandboxed && !child.bash.sandboxed) {
violations.push({
category: 'bash',
field: 'sandboxed',
parentValue: true,
childValue: false,
message: 'Child must be sandboxed when parent is sandboxed',
});
}
// Validate allowed patterns are subset
for (const pattern of child.bash.allowedPatterns) {
if (!parent.bash.allowedPatterns.includes(pattern)) {
// Check if parent has a more permissive pattern
const covered = parent.bash.allowedPatterns.some(p =>
new RegExp(p).test(pattern) || p === '.*'
);
if (!covered) {
violations.push({
category: 'bash',
field: 'allowedPatterns',
parentValue: parent.bash.allowedPatterns,
childValue: pattern,
message: `Child bash pattern '${pattern}' not covered by parent`,
});
}
}
}
// Child must inherit parent's denied patterns
for (const pattern of parent.bash.deniedPatterns) {
if (!child.bash.deniedPatterns.includes(pattern)) {
violations.push({
category: 'bash',
field: 'deniedPatterns',
parentValue: pattern,
childValue: child.bash.deniedPatterns,
message: `Child must deny bash pattern '${pattern}' as parent denies it`,
});
}
}
}function validateBashPermissions(
parent: PermissionMatrix,
child: PermissionMatrix,
violations: PermissionViolation[]
): void {
// Child can't have bash if parent doesn't
if (child.bash.enabled && !parent.bash.enabled) {
violations.push({
category: 'bash',
field: 'enabled',
parentValue: false,
childValue: true,
message: 'Child requests bash access but parent doesn\'t have it',
});
}
// Child must be sandboxed if parent is
if (parent.bash.sandboxed && !child.bash.sandboxed) {
violations.push({
category: 'bash',
field: 'sandboxed',
parentValue: true,
childValue: false,
message: 'Child must be sandboxed when parent is sandboxed',
});
}
// Validate allowed patterns are subset
for (const pattern of child.bash.allowedPatterns) {
if (!parent.bash.allowedPatterns.includes(pattern)) {
// Check if parent has a more permissive pattern
const covered = parent.bash.allowedPatterns.some(p =>
new RegExp(p).test(pattern) || p === '.*'
);
if (!covered) {
violations.push({
category: 'bash',
field: 'allowedPatterns',
parentValue: parent.bash.allowedPatterns,
childValue: pattern,
message: `Child bash pattern '${pattern}' not covered by parent`,
});
}
}
}
// Child must inherit parent's denied patterns
for (const pattern of parent.bash.deniedPatterns) {
if (!child.bash.deniedPatterns.includes(pattern)) {
violations.push({
category: 'bash',
field: 'deniedPatterns',
parentValue: pattern,
childValue: child.bash.deniedPatterns,
message: `Child must deny bash pattern '${pattern}' as parent denies it`,
});
}
}
}function validateNetworkAccess(
parent: PermissionMatrix,
child: PermissionMatrix,
violations: PermissionViolation[]
): void {
// Child can't have network if parent doesn't
if (child.network.enabled && !parent.network.enabled) {
violations.push({
category: 'network',
field: 'enabled',
parentValue: false,
childValue: true,
message: 'Child requests network access but parent doesn\'t have it',
});
}
// Validate allowed domains
for (const domain of child.network.allowedDomains) {
const allowed = parent.network.allowedDomains.some(d =>
d === domain || d === '*' || domain.endsWith(`.${d}`)
);
if (!allowed) {
violations.push({
category: 'network',
field: 'allowedDomains',
parentValue: parent.network.allowedDomains,
childValue: domain,
message: `Child domain '${domain}' not allowed by parent`,
});
}
}
}function validateNetworkAccess(
parent: PermissionMatrix,
child: PermissionMatrix,
violations: PermissionViolation[]
): void {
// Child can't have network if parent doesn't
if (child.network.enabled && !parent.network.enabled) {
violations.push({
category: 'network',
field: 'enabled',
parentValue: false,
childValue: true,
message: 'Child requests network access but parent doesn\'t have it',
});
}
// Validate allowed domains
for (const domain of child.network.allowedDomains) {
const allowed = parent.network.allowedDomains.some(d =>
d === domain || d === '*' || domain.endsWith(`.${d}`)
);
if (!allowed) {
violations.push({
category: 'network',
field: 'allowedDomains',
parentValue: parent.network.allowedDomains,
childValue: domain,
message: `Child domain '${domain}' not allowed by parent`,
});
}
}
}validationReport:
parentAgent: research-coordinator
childAgent: web-researcher
result: invalid
violations:
- category: coreTools
field: webSearch
parentValue: false
childValue: true
message: "Child requests 'webSearch' permission but parent doesn't have it"
- category: fileSystem
field: writePatterns
parentValue: ["/tmp/**"]
childValue: "/home/user/**"
message: "Child write pattern '/home/user/**' exceeds parent's write access"
warnings:
- "Child requests extensive bash permissions - consider restricting"
suggestions:
- "Remove webSearch from child permissions"
- "Restrict child writePatterns to /tmp/**"
validChildPermissions:
coreTools:
read: true
write: true
webSearch: false # Corrected
fileSystem:
writePatterns: ["/tmp/**"] # CorrectedvalidationReport:
parentAgent: research-coordinator
childAgent: web-researcher
result: invalid
violations:
- category: coreTools
field: webSearch
parentValue: false
childValue: true
message: "Child requests 'webSearch' permission but parent doesn't have it"
- category: fileSystem
field: writePatterns
parentValue: ["/tmp/**"]
childValue: "/home/user/**"
message: "Child write pattern '/home/user/**' exceeds parent's write access"
warnings:
- "Child requests extensive bash permissions - consider restricting"
suggestions:
- "Remove webSearch from child permissions"
- "Restrict child writePatterns to /tmp/**"
validChildPermissions:
coreTools:
read: true
write: true
webSearch: false # Corrected
fileSystem:
writePatterns: ["/tmp/**"] # Correctedfunction validateBeforeSpawn(
parent: PermissionMatrix,
requested: Partial<PermissionMatrix>,
defaults: PermissionMatrix
): ValidationResult {
// Merge requested with defaults
const child = mergePermissions(defaults, requested);
// Validate inheritance
const result = validatePermissionInheritance(parent, child);
if (!result.valid) {
// Generate a valid child permission matrix
result.suggestions.push('Use generateValidChildPermissions() to get valid config');
}
return result;
}
function generateValidChildPermissions(
parent: PermissionMatrix,
requested: Partial<PermissionMatrix>
): PermissionMatrix {
// Start with most restrictive
const child = createRestrictiveDefaults();
// Apply only permissions that parent has
// ... implementation ...
return child;
}function validateBeforeSpawn(
parent: PermissionMatrix,
requested: Partial<PermissionMatrix>,
defaults: PermissionMatrix
): ValidationResult {
// Merge requested with defaults
const child = mergePermissions(defaults, requested);
// Validate inheritance
const result = validatePermissionInheritance(parent, child);
if (!result.valid) {
// Generate a valid child permission matrix
result.suggestions.push('Use generateValidChildPermissions() to get valid config');
}
return result;
}
function generateValidChildPermissions(
parent: PermissionMatrix,
requested: Partial<PermissionMatrix>
): PermissionMatrix {
// Start with most restrictive
const child = createRestrictiveDefaults();
// Apply only permissions that parent has
// ... implementation ...
return child;
}dag-parallel-executordag-scope-enforcerdag-execution-tracerdag-parallel-executordag-scope-enforcerdag-execution-tracer