opencode-swarm 7.71.0 → 7.71.2
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.
- package/dist/cli/index.js +465 -393
- package/dist/hooks/delegation-gate/worktree-isolation.d.ts +48 -0
- package/dist/hooks/delegation-gate.d.ts +11 -7
- package/dist/hooks/guardrails/destructive-command.d.ts +113 -0
- package/dist/hooks/guardrails/file-authority.d.ts +152 -0
- package/dist/hooks/guardrails/helpers.d.ts +38 -0
- package/dist/hooks/guardrails/index.d.ts +81 -0
- package/dist/hooks/guardrails/messages-transform.d.ts +58 -0
- package/dist/hooks/guardrails/stored-input-args.d.ts +26 -0
- package/dist/hooks/guardrails/tool-before.d.ts +48 -0
- package/dist/hooks/guardrails.d.ts +7 -232
- package/dist/index.js +16969 -16777
- package/dist/prm/index.d.ts +26 -0
- package/dist/tools/phase-complete/gates/gate-helpers.d.ts +37 -0
- package/package.json +1 -1
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Worktree Isolation Subsystem
|
|
3
|
+
*
|
|
4
|
+
* Manages standard worktree-backed coder dispatches: provisioning worktrees,
|
|
5
|
+
* tracking dispatches, serializing when capacity is exceeded, and merging
|
|
6
|
+
* results back after coder completion.
|
|
7
|
+
*
|
|
8
|
+
* Extracted from delegation-gate.ts (FR-003) for modularity.
|
|
9
|
+
* The _internals seam allows test injection of worktree operations.
|
|
10
|
+
*/
|
|
11
|
+
import type { PluginConfig } from '../../config';
|
|
12
|
+
import type { WorktreeHandle } from '../../worktree';
|
|
13
|
+
import { attemptMergeBackFromDirty, postMergeCleanup, provisionWorktree, removeWorktree } from '../../worktree';
|
|
14
|
+
export declare const MAX_TRACKED_STANDARD_WORKTREE_CALLS = 256;
|
|
15
|
+
export interface StandardWorktreeDispatch {
|
|
16
|
+
callID: string;
|
|
17
|
+
parentSessionID: string;
|
|
18
|
+
taskId: string;
|
|
19
|
+
planTaskId?: string;
|
|
20
|
+
handle: WorktreeHandle;
|
|
21
|
+
mergeStrategy: 'merge' | 'rebase' | 'cherry-pick';
|
|
22
|
+
}
|
|
23
|
+
export declare const standardWorktreeByCallID: Map<string, StandardWorktreeDispatch>;
|
|
24
|
+
export declare const standardWorktreeSerializationSessions: Set<string>;
|
|
25
|
+
export declare function resetStandardWorktreeIsolationState(): void;
|
|
26
|
+
export declare function sanitizeWorktreeTaskId(raw: string): string;
|
|
27
|
+
export declare function precreateStandardWorktreeSession(args: {
|
|
28
|
+
config: PluginConfig;
|
|
29
|
+
directory: string;
|
|
30
|
+
parentSessionID: string;
|
|
31
|
+
callID: string;
|
|
32
|
+
taskId: string;
|
|
33
|
+
planTaskId?: string;
|
|
34
|
+
description?: string;
|
|
35
|
+
outputArgs: Record<string, unknown>;
|
|
36
|
+
}): Promise<void>;
|
|
37
|
+
export declare function finishStandardWorktreeDispatch(directory: string, dispatch: StandardWorktreeDispatch): Promise<void>;
|
|
38
|
+
/**
|
|
39
|
+
* _internals seam for test injection of worktree operations.
|
|
40
|
+
* Tests set these entries on delegation-gate's _internals (which proxies
|
|
41
|
+
* here via getters/setters) to mock worktree provisioning, merge-back, etc.
|
|
42
|
+
*/
|
|
43
|
+
export declare const _internals: {
|
|
44
|
+
provisionWorktree: typeof provisionWorktree;
|
|
45
|
+
removeWorktree: typeof removeWorktree;
|
|
46
|
+
attemptMergeBackFromDirty: typeof attemptMergeBackFromDirty;
|
|
47
|
+
postMergeCleanup: typeof postMergeCleanup;
|
|
48
|
+
};
|
|
@@ -8,7 +8,9 @@ import type { PluginConfig } from '../config';
|
|
|
8
8
|
import { loadPlanJsonOnly } from '../plan/manager';
|
|
9
9
|
import type { AgentSessionState } from '../state';
|
|
10
10
|
import type { DelegationEnvelope, EnvelopeValidationResult } from '../types/delegation.js';
|
|
11
|
-
import {
|
|
11
|
+
import { resetStandardWorktreeIsolationState } from './delegation-gate/worktree-isolation';
|
|
12
|
+
export { resetStandardWorktreeIsolationState };
|
|
13
|
+
import { _internals as _wtiInternals } from './delegation-gate/worktree-isolation';
|
|
12
14
|
/**
|
|
13
15
|
* v6.33.1 CRIT-1: Fallback map for declared coder scope by taskId.
|
|
14
16
|
* When messagesTransform sets declaredCoderScope on the architect session,
|
|
@@ -80,7 +82,6 @@ interface MessageWithParts {
|
|
|
80
82
|
info: MessageInfo;
|
|
81
83
|
parts: MessagePart[];
|
|
82
84
|
}
|
|
83
|
-
export declare function resetStandardWorktreeIsolationState(): void;
|
|
84
85
|
declare function resolveDelegatedPlanTaskId(args: Record<string, unknown>, knownPlanTaskIds?: ReadonlySet<string>): string | null;
|
|
85
86
|
declare function buildParallelExecutionGuidance(directory: string | undefined, sessionID: string, session: AgentSessionState): Promise<string | null>;
|
|
86
87
|
/**
|
|
@@ -98,17 +99,21 @@ declare function resolveEvidenceTaskId(args: Record<string, unknown> | undefined
|
|
|
98
99
|
* _internals export for testing — do not use in production code.
|
|
99
100
|
* Exposes resolveEvidenceTaskId, resolveDelegatedPlanTaskId, and
|
|
100
101
|
* buildParallelExecutionGuidance for unit testing.
|
|
102
|
+
*
|
|
103
|
+
* Worktree operation entries (provisionWorktree, removeWorktree, etc.) proxy
|
|
104
|
+
* to delegation-gate/worktree-isolation._internals via getters/setters so
|
|
105
|
+
* that test mutations on this object propagate to the extracted module.
|
|
101
106
|
*/
|
|
102
107
|
export declare const _internals: {
|
|
103
108
|
resolveEvidenceTaskId: typeof resolveEvidenceTaskId;
|
|
104
109
|
resolveDelegatedPlanTaskId: typeof resolveDelegatedPlanTaskId;
|
|
105
110
|
buildParallelExecutionGuidance: typeof buildParallelExecutionGuidance;
|
|
106
111
|
loadPlanJsonOnly: typeof loadPlanJsonOnly;
|
|
107
|
-
provisionWorktree: typeof provisionWorktree;
|
|
108
|
-
removeWorktree: typeof removeWorktree;
|
|
109
|
-
attemptMergeBackFromDirty: typeof attemptMergeBackFromDirty;
|
|
110
|
-
postMergeCleanup: typeof postMergeCleanup;
|
|
111
112
|
resetStandardWorktreeIsolationState: typeof resetStandardWorktreeIsolationState;
|
|
113
|
+
provisionWorktree: typeof _wtiInternals.provisionWorktree;
|
|
114
|
+
removeWorktree: typeof _wtiInternals.removeWorktree;
|
|
115
|
+
attemptMergeBackFromDirty: typeof _wtiInternals.attemptMergeBackFromDirty;
|
|
116
|
+
postMergeCleanup: typeof _wtiInternals.postMergeCleanup;
|
|
112
117
|
};
|
|
113
118
|
/**
|
|
114
119
|
* Creates the experimental.chat.messages.transform hook for delegation gating.
|
|
@@ -132,4 +137,3 @@ export declare function createDelegationGateHook(config: PluginConfig, directory
|
|
|
132
137
|
args?: Record<string, unknown>;
|
|
133
138
|
}, output: unknown) => Promise<void>;
|
|
134
139
|
};
|
|
135
|
-
export {};
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Destructive Command Protection Subsystem
|
|
3
|
+
*
|
|
4
|
+
* Cross-platform helpers for detecting and blocking destructive shell commands.
|
|
5
|
+
* Extracted from guardrails.ts (FR-002) — pure mechanical extraction, zero
|
|
6
|
+
* behavior change.
|
|
7
|
+
*
|
|
8
|
+
* Provides:
|
|
9
|
+
* - Command normalization (homoglyph collapsing, escape decoding)
|
|
10
|
+
* - Shell wrapper unwrapping (cmd /c, powershell -Command, bash -c, sudo, etc.)
|
|
11
|
+
* - Compound command segmentation (splitting on ;, &&, ||, |)
|
|
12
|
+
* - Target validation (vars, remote paths, filesystem roots, lstat ancestor walk)
|
|
13
|
+
* - Junction/symlink creation detection
|
|
14
|
+
* - Target extraction for Windows cmd.exe and PowerShell destructive commands
|
|
15
|
+
*/
|
|
16
|
+
/**
|
|
17
|
+
* Expanded safe-target allowlist for recursive delete operations.
|
|
18
|
+
* These directory names are safe to delete recursively by name alone.
|
|
19
|
+
* NOTE: Subdirectory paths like node_modules/.cache are NOT safe — the
|
|
20
|
+
* check requires the target be exactly one of these bare names.
|
|
21
|
+
*/
|
|
22
|
+
export declare const DC_SAFE_TARGETS: Set<string>;
|
|
23
|
+
/**
|
|
24
|
+
* Normalize a command string for pattern matching:
|
|
25
|
+
* 1. Unicode NFKC normalize (collapses homoglyphs)
|
|
26
|
+
* 2. Detect evasion techniques that exist only to defeat scanners
|
|
27
|
+
*
|
|
28
|
+
* When an evasion technique is detected, the decoded form is returned so
|
|
29
|
+
* that pattern matching can still fire on it. Only fails-closed when the
|
|
30
|
+
* evasion wraps a form we cannot safely decode.
|
|
31
|
+
*/
|
|
32
|
+
export declare function dcNormalizeCommand(cmd: string): string;
|
|
33
|
+
/**
|
|
34
|
+
* Strip one layer of a shell wrapper from a command string.
|
|
35
|
+
* Returns the inner command if a wrapper was found, null otherwise.
|
|
36
|
+
*
|
|
37
|
+
* Handles:
|
|
38
|
+
* - cmd /c "..." cmd /k "..."
|
|
39
|
+
* - powershell -Command "..." / -c "..." / -EncodedCommand <b64> / -enc <b64>
|
|
40
|
+
* - pwsh -Command / -c / -EncodedCommand / -enc
|
|
41
|
+
* - bash -c "..." / sh -c / zsh -c
|
|
42
|
+
* - sudo <...> / env VAR=val <...> / time <...> / nohup <...>
|
|
43
|
+
* - wsl -e ... / wsl -- ... / wsl.exe -e ...
|
|
44
|
+
* - PowerShell & { ... } script blocks
|
|
45
|
+
* - PowerShell iex / Invoke-Expression <...>
|
|
46
|
+
* - call <...> (batch)
|
|
47
|
+
*/
|
|
48
|
+
export declare function dcStripOneWrapper(cmd: string): string | null;
|
|
49
|
+
/**
|
|
50
|
+
* Recursively unwrap all shell wrappers up to DC_MAX_UNWRAP_DEPTH.
|
|
51
|
+
* Returns the innermost unwrapped command.
|
|
52
|
+
*/
|
|
53
|
+
export declare function dcUnwrapWrappers(cmd: string): string;
|
|
54
|
+
/**
|
|
55
|
+
* Split a compound command into individual segments, splitting on:
|
|
56
|
+
* ; && || | newlines
|
|
57
|
+
* Respects double-quoted strings (does not split inside quotes).
|
|
58
|
+
* Returns array of trimmed non-empty segments.
|
|
59
|
+
*/
|
|
60
|
+
export declare function dcSplitSegments(cmd: string): string[];
|
|
61
|
+
/**
|
|
62
|
+
* Returns true if a path string contains unexpanded environment variable
|
|
63
|
+
* references that we cannot resolve at check time.
|
|
64
|
+
*/
|
|
65
|
+
export declare function dcHasUnresolvableVars(p: string): boolean;
|
|
66
|
+
/**
|
|
67
|
+
* Returns true if the path looks like a remote/network filesystem path.
|
|
68
|
+
*/
|
|
69
|
+
export declare function dcIsRemotePath(p: string): boolean;
|
|
70
|
+
/**
|
|
71
|
+
* Walk from target path up to (but not beyond) cwd using synchronous lstat,
|
|
72
|
+
* checking each ancestor for symlinks, junctions, or reparse points.
|
|
73
|
+
*
|
|
74
|
+
* Returns a block reason string if a suspicious ancestor is found, null otherwise.
|
|
75
|
+
* Skips silently on ENOENT (target does not exist — nothing to delete).
|
|
76
|
+
* Fails closed on unexpected lstat errors.
|
|
77
|
+
*/
|
|
78
|
+
export declare function dcLstatAncestorWalk(targetPath: string, cwd: string): string | null;
|
|
79
|
+
/**
|
|
80
|
+
* Given a set of raw target strings from a destructive command, apply:
|
|
81
|
+
* 1. Unresolvable-var check (fail closed)
|
|
82
|
+
* 2. Safe-target allowlist check (allow through)
|
|
83
|
+
* 3. Remote filesystem check (block)
|
|
84
|
+
* 4. Unconditional system-path block
|
|
85
|
+
* 5. lstat ancestor walk (block on symlink/junction in chain)
|
|
86
|
+
*
|
|
87
|
+
* Returns a block reason string or null if targets are acceptable.
|
|
88
|
+
*/
|
|
89
|
+
export declare function dcValidateTargets(targets: string[], cwd: string): string | null;
|
|
90
|
+
/**
|
|
91
|
+
* Detect Windows junction or symlink CREATION commands.
|
|
92
|
+
* Junction creation followed by recursive deletion of the junction is the
|
|
93
|
+
* exact mechanism of the K2.6 data-loss incident.
|
|
94
|
+
* Block junction/symlink creation where the target resolves outside cwd.
|
|
95
|
+
*
|
|
96
|
+
* Patterns covered:
|
|
97
|
+
* mklink /J <link> <target>
|
|
98
|
+
* mklink /D <link> <target>
|
|
99
|
+
* New-Item -ItemType Junction -Path <link> -Target <target>
|
|
100
|
+
* New-Item -ItemType SymbolicLink -Path <link> -Target <target>
|
|
101
|
+
* ln -s <target> <link> (when target is outside cwd)
|
|
102
|
+
*/
|
|
103
|
+
export declare function dcCheckJunctionCreation(segment: string, cwd: string): string | null;
|
|
104
|
+
/**
|
|
105
|
+
* Extract candidate target paths from a destructive Windows cmd.exe command.
|
|
106
|
+
* Returns array of path-like arguments.
|
|
107
|
+
*/
|
|
108
|
+
export declare function dcExtractWindowsCmdTargets(segment: string): string[];
|
|
109
|
+
/**
|
|
110
|
+
* Extract candidate target paths from a destructive PowerShell command.
|
|
111
|
+
* Handles both `Remove-Item <path> -Recurse` and `Remove-Item -Recurse <path>` orderings.
|
|
112
|
+
*/
|
|
113
|
+
export declare function dcExtractPowerShellTargets(segment: string): string[];
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* File Authority Subsystem
|
|
3
|
+
*
|
|
4
|
+
* Extracted from guardrails.ts. Provides file-write authority checking,
|
|
5
|
+
* attestation API, path normalization caching, and glob matching for
|
|
6
|
+
* agent file permissions.
|
|
7
|
+
*
|
|
8
|
+
* All exports are re-exported by the barrel guardrails.ts for backward
|
|
9
|
+
* compatibility.
|
|
10
|
+
*/
|
|
11
|
+
import * as path from 'node:path';
|
|
12
|
+
import { type AuthorityConfig } from '../../config/schema';
|
|
13
|
+
import { type FileZone } from '../../context/zone-classifier';
|
|
14
|
+
/**
|
|
15
|
+
* Hashes tool arguments for repetition detection
|
|
16
|
+
* @param args Tool arguments to hash
|
|
17
|
+
* @returns Numeric hash (0 if hashing fails)
|
|
18
|
+
*/
|
|
19
|
+
export declare function hashArgs(args: unknown): number;
|
|
20
|
+
/** A record of an agent attesting to (resolving/suppressing/deferring) a finding. */
|
|
21
|
+
export interface AttestationRecord {
|
|
22
|
+
findingId: string;
|
|
23
|
+
agent: string;
|
|
24
|
+
attestation: string;
|
|
25
|
+
action: 'resolve' | 'suppress' | 'defer';
|
|
26
|
+
timestamp: string;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Validates that an attestation string meets the minimum length requirement.
|
|
30
|
+
*/
|
|
31
|
+
export declare function validateAttestation(attestation: string, _findingId: string, _agent: string, _action: 'resolve' | 'suppress' | 'defer'): {
|
|
32
|
+
valid: true;
|
|
33
|
+
} | {
|
|
34
|
+
valid: false;
|
|
35
|
+
reason: string;
|
|
36
|
+
};
|
|
37
|
+
/**
|
|
38
|
+
* Appends an attestation record to `.swarm/evidence/attestations.jsonl`.
|
|
39
|
+
*/
|
|
40
|
+
export declare function recordAttestation(dir: string, record: AttestationRecord): Promise<void>;
|
|
41
|
+
/**
|
|
42
|
+
* Validates an attestation and, on success, records it; on failure, logs a rejection event.
|
|
43
|
+
*/
|
|
44
|
+
export declare function validateAndRecordAttestation(dir: string, findingId: string, agent: string, attestation: string, action: 'resolve' | 'suppress' | 'defer'): Promise<{
|
|
45
|
+
valid: true;
|
|
46
|
+
} | {
|
|
47
|
+
valid: false;
|
|
48
|
+
reason: string;
|
|
49
|
+
}>;
|
|
50
|
+
/**
|
|
51
|
+
* Clears all guardrails caches.
|
|
52
|
+
* Use this for test isolation or when guardrails config reloads at runtime.
|
|
53
|
+
*/
|
|
54
|
+
export declare function clearGuardrailsCaches(): void;
|
|
55
|
+
/**
|
|
56
|
+
* Normalizes a file path using fs.realpathSync with caching.
|
|
57
|
+
* This resolves symlinks and normalizes the path for cross-platform consistency.
|
|
58
|
+
* @param filePath The file path to normalize (absolute or relative)
|
|
59
|
+
* @param cwd Working directory for relative paths
|
|
60
|
+
* @returns Normalized absolute path or original on error
|
|
61
|
+
*/
|
|
62
|
+
export declare function normalizePathWithCache(filePath: string, cwd: string): string;
|
|
63
|
+
/**
|
|
64
|
+
* Gets or creates a cached picomatch matcher for a glob pattern.
|
|
65
|
+
* @param pattern Glob pattern to compile
|
|
66
|
+
* @param caseInsensitive Whether to use case-insensitive matching (default: true on Windows/macOS)
|
|
67
|
+
* @returns Matcher function that returns true if path matches the pattern
|
|
68
|
+
*/
|
|
69
|
+
export declare function getGlobMatcher(pattern: string, caseInsensitive?: boolean): (path: string) => boolean;
|
|
70
|
+
export type AgentRule = {
|
|
71
|
+
readOnly?: boolean;
|
|
72
|
+
blockedExact?: string[];
|
|
73
|
+
allowedExact?: string[];
|
|
74
|
+
blockedPrefix?: string[];
|
|
75
|
+
allowedPrefix?: string[];
|
|
76
|
+
blockedZones?: FileZone[];
|
|
77
|
+
blockedGlobs?: string[];
|
|
78
|
+
allowedGlobs?: string[];
|
|
79
|
+
};
|
|
80
|
+
export declare const DEFAULT_AGENT_AUTHORITY_RULES: Record<string, AgentRule>;
|
|
81
|
+
/**
|
|
82
|
+
* Checks whether a write target path (or any ancestor strictly inside cwd)
|
|
83
|
+
* is a symlink. Writing through a symlink can redirect the write to a
|
|
84
|
+
* location outside the working directory, bypassing scope containment.
|
|
85
|
+
*
|
|
86
|
+
* The walk stops at cwd — cwd itself is NOT lstat'd. A user's chosen
|
|
87
|
+
* working directory may legitimately be reached via a symlink (e.g.,
|
|
88
|
+
* macOS's /tmp → /private/tmp), and that symlink does not constitute a
|
|
89
|
+
* redirect *within* the workspace. Only attacker-plantable symlinks
|
|
90
|
+
* BELOW cwd are relevant to this guard.
|
|
91
|
+
*
|
|
92
|
+
* ENOENT on any node in the chain is allowed — the file/dir doesn't exist yet.
|
|
93
|
+
* Any other lstat error (EPERM, EACCES, ENAMETOOLONG, …) fails closed:
|
|
94
|
+
* an unverifiable ancestor must not be written through, even if the OS
|
|
95
|
+
* would eventually reject the write. Defense-in-depth over optimism.
|
|
96
|
+
*
|
|
97
|
+
* @returns A block reason string if a symlink is detected, null if all clear.
|
|
98
|
+
*/
|
|
99
|
+
export declare function checkWriteTargetForSymlink(targetPath: string, cwd: string): string | null;
|
|
100
|
+
/**
|
|
101
|
+
* Builds the effective rules map by merging user-configured rules with defaults.
|
|
102
|
+
* User overrides take precedence for each field.
|
|
103
|
+
*/
|
|
104
|
+
export declare function buildEffectiveRules(authorityConfig?: AuthorityConfig): Record<string, AgentRule>;
|
|
105
|
+
/**
|
|
106
|
+
* Returns true when `targetAbsolute` and `cwdAbsolute` resolve to different
|
|
107
|
+
* filesystem roots. On POSIX this is always false (single root `/`); on
|
|
108
|
+
* Windows it is true when the two paths sit on different drive letters or
|
|
109
|
+
* different UNC roots — the symptom Codex flagged on PR #501, where
|
|
110
|
+
* `path.relative('C:\\repo', 'D:\\secret.txt')` returns the absolute
|
|
111
|
+
* `'D:\\secret.txt'` and slips past `startsWith('../')` containment.
|
|
112
|
+
*
|
|
113
|
+
* Exposed (and accepts an injectable `pathLib`) so the cross-drive guard
|
|
114
|
+
* is falsifiable on Linux CI without depending on a Windows runner: tests
|
|
115
|
+
* pass `path.win32` / `path.posix` directly.
|
|
116
|
+
*/
|
|
117
|
+
export declare function isOnDifferentFilesystemRoot(targetAbsolute: string, cwdAbsolute: string, pathLib?: Pick<typeof path, 'parse'>): boolean;
|
|
118
|
+
/**
|
|
119
|
+
* Checks file path authority against a pre-computed rules map.
|
|
120
|
+
* Implements DENY-first evaluation order:
|
|
121
|
+
* 1. readOnly - blocks all writes
|
|
122
|
+
* 2. blockedExact - exact path matches (fast path)
|
|
123
|
+
* 3. blockedGlobs - glob pattern matches
|
|
124
|
+
* 4. allowedExact - explicit allow for exact paths
|
|
125
|
+
* 5. blockedZones - zone-based blocking (runs before allowedGlobs so that generated
|
|
126
|
+
* output dirs like dist/ and build/ cannot be bypassed by a glob pattern match)
|
|
127
|
+
* 6. allowedGlobs - explicit allow for glob patterns (overrides blockedPrefix/allowedPrefix
|
|
128
|
+
* but NOT blockedZones, which is already decided in Step 5)
|
|
129
|
+
* 7. blockedPrefix - prefix-based blocking (takes priority over allowedPrefix)
|
|
130
|
+
* 8. allowedPrefix - prefix-based allow (whitelist)
|
|
131
|
+
*/
|
|
132
|
+
export declare function checkFileAuthorityWithRules(agentName: string, filePath: string, cwd: string, effectiveRules: Record<string, AgentRule>, options?: {
|
|
133
|
+
declaredScope?: string[] | null;
|
|
134
|
+
}): {
|
|
135
|
+
allowed: true;
|
|
136
|
+
} | {
|
|
137
|
+
allowed: false;
|
|
138
|
+
reason: string;
|
|
139
|
+
zone?: FileZone;
|
|
140
|
+
};
|
|
141
|
+
/**
|
|
142
|
+
* Checks whether the given agent is authorised to write to the given file path.
|
|
143
|
+
*/
|
|
144
|
+
export declare function checkFileAuthority(agentName: string, filePath: string, cwd: string, authorityConfig?: AuthorityConfig, options?: {
|
|
145
|
+
declaredScope?: string[] | null;
|
|
146
|
+
}): {
|
|
147
|
+
allowed: true;
|
|
148
|
+
} | {
|
|
149
|
+
allowed: false;
|
|
150
|
+
reason: string;
|
|
151
|
+
zone?: FileZone;
|
|
152
|
+
};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared Helper Functions — Guardrails
|
|
3
|
+
*
|
|
4
|
+
* Extracted from tool-before.ts (task 1.4 / FR-005).
|
|
5
|
+
* Contains pure utility functions used by the toolBefore handler
|
|
6
|
+
* and potentially other guardrails submodules.
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Checks if a file path is a config file either via zone classification
|
|
10
|
+
* or by matching known verifier config glob patterns.
|
|
11
|
+
*/
|
|
12
|
+
export declare function isConfigFilePath(filePath: string, cwd: string, extraGlobs?: readonly string[]): boolean;
|
|
13
|
+
/**
|
|
14
|
+
* Detects if a tool is a write-class tool that modifies file contents.
|
|
15
|
+
*/
|
|
16
|
+
export declare function isWriteTool(toolName: string): boolean;
|
|
17
|
+
/**
|
|
18
|
+
* Detects if a file path is outside the .swarm/ directory.
|
|
19
|
+
*/
|
|
20
|
+
export declare function isOutsideSwarmDir(filePath: string, directory: string): boolean;
|
|
21
|
+
/**
|
|
22
|
+
* Detects if a file path is source code (not docs, config, or metadata).
|
|
23
|
+
*/
|
|
24
|
+
export declare function isSourceCodePath(filePath: string): boolean;
|
|
25
|
+
/**
|
|
26
|
+
* Detect obvious traversal segments regardless of destination file type.
|
|
27
|
+
*/
|
|
28
|
+
export declare function hasTraversalSegments(filePath: string): boolean;
|
|
29
|
+
/**
|
|
30
|
+
* Check if a file path is within declared scope entries.
|
|
31
|
+
* Handles both exact matches and directory containment.
|
|
32
|
+
*/
|
|
33
|
+
export declare function isInDeclaredScope(filePath: string, scopeEntries: string[], cwd?: string): boolean;
|
|
34
|
+
/**
|
|
35
|
+
* Redacts sensitive values from a shell command string before audit logging.
|
|
36
|
+
* Covers env-var assignments, CLI flags, Bearer/Basic auth, and -H header flags.
|
|
37
|
+
*/
|
|
38
|
+
export declare function redactShellCommand(cmd: string): string;
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Guardrails Hook Module
|
|
3
|
+
*
|
|
4
|
+
* Circuit breaker for runaway LLM agents. Monitors tool usage via OpenCode Plugin API hooks
|
|
5
|
+
* and implements two-layer protection:
|
|
6
|
+
* - Layer 1 (Soft Warning @ warning_threshold): Sets warning flag for messagesTransform to inject warning
|
|
7
|
+
* - Layer 2 (Hard Block @ 100%): Throws error in toolBefore to block further calls, injects STOP message
|
|
8
|
+
*/
|
|
9
|
+
import { extractSwarmIdFromAgentName, getSwarmAgents, resolveFallbackModel } from '../../agents/index';
|
|
10
|
+
import { type AuthorityConfig, type GuardrailsConfig } from '../../config/schema';
|
|
11
|
+
import { dcCheckJunctionCreation } from './destructive-command';
|
|
12
|
+
import { getMostRecentAssistantText, getProviderFailureFingerprint, isTransientProviderFailureText } from './messages-transform';
|
|
13
|
+
export declare const _internals: {
|
|
14
|
+
extractSwarmIdFromAgentName: typeof extractSwarmIdFromAgentName;
|
|
15
|
+
getSwarmAgents: typeof getSwarmAgents;
|
|
16
|
+
getMostRecentAssistantText: typeof getMostRecentAssistantText;
|
|
17
|
+
getProviderFailureFingerprint: typeof getProviderFailureFingerprint;
|
|
18
|
+
isTransientProviderFailureText: typeof isTransientProviderFailureText;
|
|
19
|
+
resolveFallbackModel: typeof resolveFallbackModel;
|
|
20
|
+
dcCheckJunctionCreation: typeof dcCheckJunctionCreation;
|
|
21
|
+
extractErrorSignal: typeof extractErrorSignal;
|
|
22
|
+
};
|
|
23
|
+
/**
|
|
24
|
+
* Issue #853 Layer B: tools that are structurally blocked while
|
|
25
|
+
* `.swarm/spec-staleness.json` exists.
|
|
26
|
+
*/
|
|
27
|
+
export declare const SPEC_DRIFT_BLOCKED_TOOLS: Set<string>;
|
|
28
|
+
/**
|
|
29
|
+
* Throw SPEC_DRIFT_BLOCK if the tool is on the block-list and the
|
|
30
|
+
* spec-staleness marker file exists.
|
|
31
|
+
*/
|
|
32
|
+
export declare function enforceSpecDriftGate(directory: string | undefined, toolName: string): void;
|
|
33
|
+
/**
|
|
34
|
+
* Extracts bounded provider/error signal from unknown hook error payloads.
|
|
35
|
+
*/
|
|
36
|
+
declare function extractErrorSignal(errorContent: unknown): string;
|
|
37
|
+
/**
|
|
38
|
+
* Redacts sensitive values from a shell command string before audit logging.
|
|
39
|
+
*/
|
|
40
|
+
export declare function redactShellCommand(cmd: string): string;
|
|
41
|
+
/**
|
|
42
|
+
* Creates guardrails hooks for circuit breaker protection
|
|
43
|
+
* @param directory Working directory from plugin init context (required)
|
|
44
|
+
* @param directoryOrConfig Guardrails configuration object (when passed as second arg, replaces legacy config param)
|
|
45
|
+
* @param config Guardrails configuration (optional)
|
|
46
|
+
* @returns Tool before/after hooks and messages transform hook
|
|
47
|
+
*/
|
|
48
|
+
export declare function createGuardrailsHooks(directory: string, directoryOrConfig?: string | GuardrailsConfig, config?: GuardrailsConfig, authorityConfig?: AuthorityConfig): {
|
|
49
|
+
toolBefore: (input: {
|
|
50
|
+
tool: string;
|
|
51
|
+
sessionID: string;
|
|
52
|
+
callID: string;
|
|
53
|
+
}, output: {
|
|
54
|
+
args: unknown;
|
|
55
|
+
}) => Promise<void>;
|
|
56
|
+
toolAfter: (input: {
|
|
57
|
+
tool: string;
|
|
58
|
+
sessionID: string;
|
|
59
|
+
callID: string;
|
|
60
|
+
args?: Record<string, unknown>;
|
|
61
|
+
}, output: {
|
|
62
|
+
title: string;
|
|
63
|
+
output: string;
|
|
64
|
+
metadata: unknown;
|
|
65
|
+
}) => Promise<void>;
|
|
66
|
+
messagesTransform: (input: Record<string, never>, output: {
|
|
67
|
+
messages?: Array<{
|
|
68
|
+
info: {
|
|
69
|
+
role: string;
|
|
70
|
+
agent?: string;
|
|
71
|
+
sessionID?: string;
|
|
72
|
+
};
|
|
73
|
+
parts: Array<{
|
|
74
|
+
type: string;
|
|
75
|
+
text?: string;
|
|
76
|
+
[key: string]: unknown;
|
|
77
|
+
}>;
|
|
78
|
+
}>;
|
|
79
|
+
}) => Promise<void>;
|
|
80
|
+
};
|
|
81
|
+
export {};
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Messages Transform Handler Factory
|
|
3
|
+
*
|
|
4
|
+
* Extracted from guardrails.ts. Creates the messagesTransform handler
|
|
5
|
+
* used by createGuardrailsHooks. The factory receives shared configuration
|
|
6
|
+
* and closures from the guardrails hooks factory, so the handler can
|
|
7
|
+
* inject warnings, detect loops, and enforce QA gate compliance.
|
|
8
|
+
*/
|
|
9
|
+
import { type GuardrailsConfig } from '../../config/schema';
|
|
10
|
+
/**
|
|
11
|
+
* Shared context passed from createGuardrailsHooks to the messagesTransform factory.
|
|
12
|
+
*/
|
|
13
|
+
export interface MessagesTransformContext {
|
|
14
|
+
/** Resolved working directory for the guardrails hooks */
|
|
15
|
+
effectiveDirectory: string;
|
|
16
|
+
/** Resolved guardrails configuration */
|
|
17
|
+
cfg: GuardrailsConfig;
|
|
18
|
+
/** Required QA gates tool names */
|
|
19
|
+
requiredQaGates: string[];
|
|
20
|
+
/** Whether reviewer/test_engineer delegation is required */
|
|
21
|
+
requireReviewerAndTestEngineer: boolean;
|
|
22
|
+
/** Shared consecutiveNoToolTurns Map (also used by toolBefore) */
|
|
23
|
+
consecutiveNoToolTurns: Map<string, number>;
|
|
24
|
+
}
|
|
25
|
+
type ChatMessageLike = {
|
|
26
|
+
info?: {
|
|
27
|
+
role?: string;
|
|
28
|
+
sessionID?: string;
|
|
29
|
+
};
|
|
30
|
+
parts?: Array<{
|
|
31
|
+
type?: string;
|
|
32
|
+
text?: unknown;
|
|
33
|
+
}>;
|
|
34
|
+
};
|
|
35
|
+
export declare function getMostRecentAssistantText(messages: ChatMessageLike[]): string;
|
|
36
|
+
export declare function isTransientProviderFailureText(text: string): boolean;
|
|
37
|
+
export declare function getProviderFailureFingerprint(text: string): string;
|
|
38
|
+
/**
|
|
39
|
+
* Creates a messagesTransform handler with the given shared context.
|
|
40
|
+
*
|
|
41
|
+
* @param ctx Shared configuration and closures from createGuardrailsHooks
|
|
42
|
+
* @returns The messagesTransform handler function
|
|
43
|
+
*/
|
|
44
|
+
export declare function createMessagesTransformHandler(ctx: MessagesTransformContext): (_input: Record<string, never>, output: {
|
|
45
|
+
messages?: Array<{
|
|
46
|
+
info: {
|
|
47
|
+
role: string;
|
|
48
|
+
agent?: string;
|
|
49
|
+
sessionID?: string;
|
|
50
|
+
};
|
|
51
|
+
parts: Array<{
|
|
52
|
+
type: string;
|
|
53
|
+
text?: string;
|
|
54
|
+
[key: string]: unknown;
|
|
55
|
+
}>;
|
|
56
|
+
}>;
|
|
57
|
+
}) => Promise<void>;
|
|
58
|
+
export {};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stored Input Args Helpers
|
|
3
|
+
*
|
|
4
|
+
* Extracted from guardrails.ts. Provides module-level storage for tool
|
|
5
|
+
* input args by callID, used by guardrails for delegation detection
|
|
6
|
+
* and exposed via safe accessor helpers.
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Retrieves stored input args for a given callID.
|
|
10
|
+
* Used by other hooks (e.g., delegation-gate) to access tool input args.
|
|
11
|
+
* @param callID The callID to look up
|
|
12
|
+
* @returns The stored args or undefined if not found
|
|
13
|
+
*/
|
|
14
|
+
export declare function getStoredInputArgs(callID: string): unknown | undefined;
|
|
15
|
+
/**
|
|
16
|
+
* Stores input args for a given callID.
|
|
17
|
+
* Used by guardrails toolBefore hook; may be used by other hooks if needed.
|
|
18
|
+
* @param callID The callID to store args under
|
|
19
|
+
* @param args The tool input args to store
|
|
20
|
+
*/
|
|
21
|
+
export declare function setStoredInputArgs(callID: string, args: unknown): void;
|
|
22
|
+
/**
|
|
23
|
+
* Deletes stored input args for a given callID (cleanup after retrieval).
|
|
24
|
+
* @param callID The callID to delete
|
|
25
|
+
*/
|
|
26
|
+
export declare function deleteStoredInputArgs(callID: string): void;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool Before Handler Factory
|
|
3
|
+
*
|
|
4
|
+
* Extracted from guardrails/index.ts (task 1.4 / FR-005).
|
|
5
|
+
* Creates the toolBefore handler used by createGuardrailsHooks.
|
|
6
|
+
* The factory receives shared configuration and closures from the
|
|
7
|
+
* guardrails hooks factory, so the handler can enforce destructive
|
|
8
|
+
* command blocking, file authority, scope, self-coding gates, write
|
|
9
|
+
* target checks, and circuit breaker limits.
|
|
10
|
+
*/
|
|
11
|
+
import { type AuthorityConfig, type GuardrailsConfig } from '../../config/schema';
|
|
12
|
+
import type { AgentRule } from './file-authority';
|
|
13
|
+
/**
|
|
14
|
+
* Shared context passed from createGuardrailsHooks to the toolBefore factory.
|
|
15
|
+
*/
|
|
16
|
+
export interface ToolBeforeContext {
|
|
17
|
+
/** Resolved working directory for the guardrails hooks */
|
|
18
|
+
effectiveDirectory: string;
|
|
19
|
+
/** Resolved guardrails configuration */
|
|
20
|
+
cfg: GuardrailsConfig;
|
|
21
|
+
/** Pre-computed per-agent authority rules */
|
|
22
|
+
precomputedAuthorityRules: Record<string, AgentRule>;
|
|
23
|
+
/** Global deny prefixes — apply to all agents regardless of per-agent rules */
|
|
24
|
+
universalDenyPrefixes: string[];
|
|
25
|
+
/** Shell audit log path */
|
|
26
|
+
shellAuditPath: string;
|
|
27
|
+
/** Whether shell audit logging is enabled */
|
|
28
|
+
shellAuditEnabled: boolean;
|
|
29
|
+
/** Agents allowed to use bash/shell interpreter (undefined = all allowed) */
|
|
30
|
+
interpreterAllowedAgents: string[] | undefined;
|
|
31
|
+
/** Authority config (for verifier config paths) */
|
|
32
|
+
authorityConfig: AuthorityConfig | undefined;
|
|
33
|
+
/** Shared consecutiveNoToolTurns Map (also used by messagesTransform) */
|
|
34
|
+
consecutiveNoToolTurns: Map<string, number>;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Creates a toolBefore handler with the given shared context.
|
|
38
|
+
*
|
|
39
|
+
* @param ctx Shared configuration and closures from createGuardrailsHooks
|
|
40
|
+
* @returns The toolBefore handler function
|
|
41
|
+
*/
|
|
42
|
+
export declare function createToolBeforeHandler(ctx: ToolBeforeContext): (input: {
|
|
43
|
+
tool: string;
|
|
44
|
+
sessionID: string;
|
|
45
|
+
callID: string;
|
|
46
|
+
}, output: {
|
|
47
|
+
args: unknown;
|
|
48
|
+
}) => Promise<void>;
|