opencode-swarm 7.35.0 → 7.36.0

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.
@@ -0,0 +1,14 @@
1
+ import type { AppliedMemoryChange, MemoryPatch, MemoryProposal, MemoryRecord, ResolvedCuratorMemoryDecision } from './types';
2
+ export declare function validateDecisionMatchesProposal(decision: ResolvedCuratorMemoryDecision, proposal: MemoryProposal): void;
3
+ export declare function applyPatchToMemory(existing: MemoryRecord, patch: MemoryPatch, updatedAt: string): MemoryRecord;
4
+ export declare function markProposalReviewed(proposal: MemoryProposal, decision: ResolvedCuratorMemoryDecision, status: MemoryProposal['status'], reviewedAt: string, ids: {
5
+ memoryId?: string;
6
+ targetMemoryId?: string;
7
+ oldMemoryId?: string;
8
+ replacementMemoryId?: string;
9
+ }): MemoryProposal;
10
+ export declare function curatorDecisionReason(decision: ResolvedCuratorMemoryDecision): string | undefined;
11
+ export declare function buildCuratorDecisionEvent(change: AppliedMemoryChange, proposal: MemoryProposal): AppliedMemoryChange & {
12
+ proposalOperation: MemoryProposal['operation'];
13
+ };
14
+ export declare function normalizeTags(tags: string[]): string[];
@@ -1,6 +1,6 @@
1
1
  import { type MemoryConfig } from './config';
2
2
  import type { MemoryProposalStore, MemoryProvider } from './provider';
3
- import type { MemoryContext, MemoryKind, MemoryProposal, MemoryRecord, MemoryScopeRef, MemorySource, RecallBundle, RecallMode } from './types';
3
+ import type { AppliedMemoryChange, CuratorMemoryDecision, MemoryContext, MemoryKind, MemoryProposal, MemoryRecord, MemoryScopeRef, MemorySource, RecallBundle, RecallMode } from './types';
4
4
  export interface MemoryGatewayOptions {
5
5
  config?: Partial<MemoryConfig>;
6
6
  provider?: MemoryProvider & Partial<MemoryProposalStore>;
@@ -39,6 +39,7 @@ export declare class MemoryGateway {
39
39
  recall(input: RecallMemoryInput): Promise<RecallBundle>;
40
40
  propose(input: ProposeMemoryInput): Promise<MemoryProposal>;
41
41
  upsertCurated(record: MemoryRecord): Promise<MemoryRecord>;
42
+ applyCuratorDecision(decision: CuratorMemoryDecision): Promise<AppliedMemoryChange>;
42
43
  createRecord(input: {
43
44
  kind: MemoryKind;
44
45
  text: string;
@@ -50,6 +51,9 @@ export declare class MemoryGateway {
50
51
  tags?: string[];
51
52
  metadata?: Record<string, unknown>;
52
53
  }): MemoryRecord;
54
+ private resolveCuratorDecision;
55
+ private createRecordFromNew;
56
+ private resolveRecordScope;
53
57
  private assertEnabled;
54
58
  }
55
59
  export declare function createMemoryGateway(context: MemoryContext, options?: MemoryGatewayOptions): MemoryGateway;
@@ -12,6 +12,6 @@ export { buildMemoryRecallPlan, type MemoryRecallPlan, type MemoryRecallPlannerI
12
12
  export { findSecrets, redactSecrets } from './redaction';
13
13
  export { MEMORY_RECALL_PROFILES, type MemoryRecallProfile, normalizeMemoryAgentRole, resolveMemoryRecallProfile, } from './role-profiles';
14
14
  export { appendMemoryRunLog, sanitizeRunId } from './run-log';
15
- export { computeMemoryContentHash, createBundleId, createMemoryId, createProposalId, isExpired, normalizeMemoryText, validateMemoryProposal, validateMemoryRecordRules, } from './schema';
15
+ export { computeMemoryContentHash, createBundleId, createMemoryId, createProposalId, isExpired, normalizeMemoryText, validateCuratorMemoryDecision, validateMemoryProposal, validateMemoryRecordRules, } from './schema';
16
16
  export { SQLiteMemoryProvider } from './sqlite-provider';
17
- export type { MemoryContext, MemoryKind, MemoryListFilter, MemoryProposal, MemoryRecord, MemoryScopeRef, MemoryScopeType, RecallBundle, RecallInjectionSkipReason, RecallMode, RecallRequest, RecallResultItem, } from './types';
17
+ export type { AppliedMemoryChange, CuratorMemoryDecision, MemoryContext, MemoryKind, MemoryListFilter, MemoryPatch, MemoryProposal, MemoryRecord, MemoryScopeRef, MemoryScopeType, NewMemoryRecord, RecallBundle, RecallInjectionSkipReason, RecallMode, RecallRequest, RecallResultItem, ResolvedCuratorMemoryDecision, } from './types';
@@ -14,7 +14,7 @@ export interface MemoryLifecycleHookOptions {
14
14
  runId?: string;
15
15
  }, options: {
16
16
  config?: Partial<MemoryConfig>;
17
- }) => Pick<MemoryGateway, 'isEnabled' | 'deriveAllowedScopes' | 'recall' | 'propose'>;
17
+ }) => Pick<MemoryGateway, 'isEnabled' | 'deriveAllowedScopes' | 'recall' | 'propose'> & Partial<Pick<MemoryGateway, 'applyCuratorDecision' | 'dispose'>>;
18
18
  appendRunLog?: typeof appendMemoryRunLog;
19
19
  }
20
20
  export interface MemoryLifecycleHooks {
@@ -1,7 +1,7 @@
1
1
  import { type MemoryConfig } from './config';
2
2
  import type { MemoryProposalStore, MemoryProvider, MemoryRecallUsageEvent } from './provider';
3
3
  import type { RecallScoringDiagnostics } from './scoring';
4
- import type { MemoryListFilter, MemoryProposal, MemoryRecord, RecallRequest, RecallResultItem } from './types';
4
+ import type { AppliedMemoryChange, MemoryListFilter, MemoryProposal, MemoryRecord, RecallRequest, RecallResultItem, ResolvedCuratorMemoryDecision } from './types';
5
5
  export declare class LocalJsonlMemoryProvider implements MemoryProvider, MemoryProposalStore {
6
6
  readonly name = "local-jsonl";
7
7
  private readonly rootDirectory;
@@ -27,6 +27,9 @@ export declare class LocalJsonlMemoryProvider implements MemoryProvider, MemoryP
27
27
  status?: MemoryProposal['status'];
28
28
  limit?: number;
29
29
  }): Promise<MemoryProposal[]>;
30
+ applyCuratorDecision(decision: ResolvedCuratorMemoryDecision): Promise<AppliedMemoryChange>;
30
31
  compact(): Promise<void>;
31
32
  private audit;
33
+ private activeMemory;
34
+ private validateDecisionMemory;
32
35
  }
@@ -1,5 +1,5 @@
1
1
  import type { RecallScoringDiagnostics } from './scoring';
2
- import type { MemoryListFilter, MemoryProposal, MemoryRecord, RecallRequest, RecallResultItem } from './types';
2
+ import type { AppliedMemoryChange, MemoryListFilter, MemoryProposal, MemoryRecord, RecallRequest, RecallResultItem, ResolvedCuratorMemoryDecision } from './types';
3
3
  export interface MemoryRecallResult {
4
4
  items: RecallResultItem[];
5
5
  diagnostics?: RecallScoringDiagnostics;
@@ -34,4 +34,5 @@ export interface MemoryProposalStore {
34
34
  status?: MemoryProposal['status'];
35
35
  limit?: number;
36
36
  }): Promise<MemoryProposal[]>;
37
+ applyCuratorDecision?(decision: ResolvedCuratorMemoryDecision): Promise<AppliedMemoryChange>;
37
38
  }
@@ -1,4 +1,4 @@
1
- export type MemoryRunLogEventName = 'recall_requested' | 'recall_returned' | 'prompt_injection_skipped' | 'prompt_injected' | 'proposal_created' | 'proposal_rejected_by_validation';
1
+ export type MemoryRunLogEventName = 'recall_requested' | 'recall_returned' | 'prompt_injection_skipped' | 'prompt_injected' | 'proposal_created' | 'proposal_rejected_by_validation' | 'curator_decision_applied' | 'curator_decision_rejected_by_validation';
2
2
  export interface MemoryRunLogEvent {
3
3
  event: MemoryRunLogEventName;
4
4
  runId: string;
@@ -1,5 +1,5 @@
1
1
  import { z } from 'zod';
2
- import type { MemoryKind, MemoryProposal, MemoryRecord, MemoryScopeRef } from './types';
2
+ import type { CuratorMemoryDecision, MemoryKind, MemoryPatch, MemoryProposal, MemoryRecord, MemoryScopeRef, NewMemoryRecord } from './types';
3
3
  export declare const MemoryScopeTypeSchema: z.ZodEnum<{
4
4
  agent: "agent";
5
5
  project: "project";
@@ -230,6 +230,9 @@ export declare const MemoryProposalSchema: z.ZodObject<{
230
230
  createdAt: z.ZodString;
231
231
  metadata: z.ZodRecord<z.ZodString, z.ZodUnknown>;
232
232
  }, z.core.$strict>;
233
+ export declare const NewMemoryRecordSchema: z.ZodType<NewMemoryRecord>;
234
+ export declare const MemoryPatchSchema: z.ZodType<MemoryPatch>;
235
+ export declare const CuratorMemoryDecisionSchema: z.ZodType<CuratorMemoryDecision>;
233
236
  export declare function normalizeMemoryText(text: string): string;
234
237
  export declare function stableScopeKey(scope: MemoryScopeRef): string;
235
238
  export declare function computeMemoryContentHash(recordLike: {
@@ -254,3 +257,4 @@ export declare function validateMemoryRecordRules(record: MemoryRecord, options:
254
257
  rejectDurableSecrets: boolean;
255
258
  }): MemoryRecord;
256
259
  export declare function validateMemoryProposal(proposal: MemoryProposal): MemoryProposal;
260
+ export declare function validateCuratorMemoryDecision(decision: unknown): CuratorMemoryDecision;
@@ -2,7 +2,7 @@ import { type MemoryConfig } from './config';
2
2
  import { type JsonlMigrationReport } from './jsonl-migration';
3
3
  import type { MemoryProposalStore, MemoryProvider, MemoryRecallUsageEvent } from './provider';
4
4
  import type { RecallScoringDiagnostics } from './scoring';
5
- import type { MemoryListFilter, MemoryProposal, MemoryRecord, RecallRequest, RecallResultItem } from './types';
5
+ import type { AppliedMemoryChange, MemoryListFilter, MemoryProposal, MemoryRecord, RecallRequest, RecallResultItem, ResolvedCuratorMemoryDecision } from './types';
6
6
  export interface SQLiteJsonlImportResult {
7
7
  importedMemories: number;
8
8
  importedProposals: number;
@@ -36,6 +36,7 @@ export declare class SQLiteMemoryProvider implements MemoryProvider, MemoryPropo
36
36
  status?: MemoryProposal['status'];
37
37
  limit?: number;
38
38
  }): Promise<MemoryProposal[]>;
39
+ applyCuratorDecision(decision: ResolvedCuratorMemoryDecision): Promise<AppliedMemoryChange>;
39
40
  close(): void;
40
41
  importJsonl(): Promise<SQLiteJsonlImportResult>;
41
42
  exportJsonl(): Promise<{
@@ -52,6 +53,10 @@ export declare class SQLiteMemoryProvider implements MemoryProvider, MemoryPropo
52
53
  private loadProposals;
53
54
  private writeMemory;
54
55
  private writeProposal;
56
+ private applyDecisionToStorage;
57
+ private readPendingProposal;
58
+ private readActiveMemory;
59
+ private validateDecisionMemory;
55
60
  private migrateLegacyJsonlIfNeeded;
56
61
  private importLegacyJsonlRows;
57
62
  private event;
@@ -56,6 +56,80 @@ export interface MemoryProposal {
56
56
  createdAt: string;
57
57
  metadata: Record<string, unknown>;
58
58
  }
59
+ export interface NewMemoryRecord {
60
+ scope?: MemoryScopeRef;
61
+ kind: MemoryKind;
62
+ text: string;
63
+ tags?: string[];
64
+ confidence?: number;
65
+ stability?: MemoryRecord['stability'];
66
+ source?: MemorySource;
67
+ expiresAt?: string;
68
+ metadata?: Record<string, unknown>;
69
+ }
70
+ export type MemoryPatch = Partial<Pick<NewMemoryRecord, 'scope' | 'kind' | 'text' | 'tags' | 'confidence' | 'stability' | 'source' | 'expiresAt' | 'metadata'>>;
71
+ export type CuratorMemoryDecision = {
72
+ action: 'add';
73
+ proposalId: string;
74
+ memory: NewMemoryRecord;
75
+ } | {
76
+ action: 'update';
77
+ proposalId: string;
78
+ targetMemoryId: string;
79
+ patch: MemoryPatch;
80
+ reason: string;
81
+ } | {
82
+ action: 'supersede';
83
+ proposalId: string;
84
+ oldMemoryId: string;
85
+ replacement: NewMemoryRecord;
86
+ reason: string;
87
+ } | {
88
+ action: 'reject';
89
+ proposalId: string;
90
+ reason: string;
91
+ } | {
92
+ action: 'noop';
93
+ proposalId: string;
94
+ reason: string;
95
+ };
96
+ export type ResolvedCuratorMemoryDecision = {
97
+ action: 'add';
98
+ proposalId: string;
99
+ memory: MemoryRecord;
100
+ } | {
101
+ action: 'update';
102
+ proposalId: string;
103
+ targetMemoryId: string;
104
+ patch: MemoryPatch;
105
+ reason: string;
106
+ } | {
107
+ action: 'supersede';
108
+ proposalId: string;
109
+ oldMemoryId: string;
110
+ replacement: MemoryRecord;
111
+ reason: string;
112
+ } | {
113
+ action: 'reject';
114
+ proposalId: string;
115
+ reason: string;
116
+ } | {
117
+ action: 'noop';
118
+ proposalId: string;
119
+ reason: string;
120
+ };
121
+ export interface AppliedMemoryChange {
122
+ action: CuratorMemoryDecision['action'];
123
+ proposalId: string;
124
+ proposalStatus: MemoryProposal['status'];
125
+ appliedAt: string;
126
+ eventId?: string;
127
+ memoryId?: string;
128
+ targetMemoryId?: string;
129
+ oldMemoryId?: string;
130
+ replacementMemoryId?: string;
131
+ reason?: string;
132
+ }
59
133
  export type RecallMode = 'manual' | 'injection' | 'curator' | 'evaluation';
60
134
  export type RecallInjectionSkipReason = 'disabled' | 'no_signal' | 'below_threshold' | 'no_results';
61
135
  export interface RecallRequest {
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Platform sandbox capability probe.
3
+ *
4
+ * Detects OS-native sandbox mechanism availability for each platform:
5
+ * - Linux: Bubblewrap (bwrap)
6
+ * - macOS: sandbox-exec
7
+ * - Windows: PowerShell-based wrapper (not a native OS sandbox mechanism)
8
+ *
9
+ * Each probe is bounded to 2 seconds via AbortController to satisfy
10
+ * Invariant 1 (plugin init is fast, bounded, fail-open).
11
+ */
12
+ /** Possible sandbox status values. */
13
+ export type SandboxStatus = 'enabled' | 'disabled' | 'unsupported';
14
+ /** Result of a sandbox capability probe. */
15
+ export interface SandboxCapability {
16
+ /** Whether the sandbox mechanism is available. */
17
+ status: SandboxStatus;
18
+ /** Human-readable mechanism name, e.g. "Bubblewrap". */
19
+ mechanism: string;
20
+ /** Current process.platform value. */
21
+ platform: 'linux' | 'darwin' | 'win32';
22
+ /** Error message from the probe, if any. */
23
+ error?: string;
24
+ }
25
+ /**
26
+ * Detects the availability of OS-native sandbox mechanisms.
27
+ *
28
+ * Results are cached for the session lifetime (module-level variable).
29
+ */
30
+ /**
31
+ * Synchronous check whether Bubblewrap was detected as available.
32
+ * Must be called after detect() has resolved — returns false if detect()
33
+ * has not yet been called or if the cached result is not Linux/enabled.
34
+ */
35
+ export declare function isBubblewrapAvailable(): boolean;
36
+ /**
37
+ * Synchronous check whether sandbox-exec was detected as available.
38
+ * Must be called after detect() has resolved — returns false if detect()
39
+ * has not yet been called or if the cached result is not macOS/enabled.
40
+ */
41
+ export declare function isSandboxExecAvailable(): boolean;
42
+ /**
43
+ * Synchronous check whether Windows Restricted Token support is available.
44
+ * Must be called after detect() has resolved — returns false if detect()
45
+ * has not yet been called or if the cached result is not win32/enabled.
46
+ */
47
+ export declare function isWindowsSandboxAvailable(): boolean;
48
+ export declare class SandboxCapabilityProbe {
49
+ /**
50
+ * Detect sandbox capability for the current platform.
51
+ *
52
+ * @returns A promise that resolves to the sandbox capability result.
53
+ */
54
+ detect(): Promise<SandboxCapability>;
55
+ }
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Platform-agnostic sandbox execution abstraction.
3
+ *
4
+ * Provides a unified interface for sandboxed shell command execution across
5
+ * Linux (Bubblewrap), macOS (sandbox-exec), and Windows (restricted token/Low Integrity).
6
+ */
7
+ /**
8
+ * Error thrown when sandbox operations fail.
9
+ */
10
+ export declare class SandboxError extends Error {
11
+ readonly code: string;
12
+ constructor(message: string, code: string);
13
+ }
14
+ /**
15
+ * Interface for platform-specific sandbox executors.
16
+ */
17
+ export interface SandboxExecutor {
18
+ /** Human-readable name of the sandbox mechanism */
19
+ readonly mechanism: string;
20
+ /** Whether this executor is available on the current platform */
21
+ isAvailable(): boolean;
22
+ /**
23
+ * Wrap a shell command with sandbox prefix.
24
+ * @param command - The raw shell command string to execute
25
+ * @param scopePaths - Absolute paths the coder is allowed to write to
26
+ * @param tempDir - Optional temporary directory path (platform default if omitted)
27
+ * @returns The wrapped command string with sandbox prefix
28
+ * @throws SandboxError if sandbox cannot wrap the command
29
+ */
30
+ wrapCommand(command: string, scopePaths: string[], tempDir?: string): string;
31
+ /**
32
+ * Get the environment variable overrides for this sandbox.
33
+ * Returns a record of env vars to set/unset.
34
+ */
35
+ getEnvOverrides(): Record<string, string | null>;
36
+ }
37
+ /**
38
+ * Get the platform-appropriate sandbox executor.
39
+ *
40
+ * Returns null if no sandbox mechanism is available for the current platform.
41
+ * The result is cached after the first call for fast subsequent access.
42
+ *
43
+ * Lazily imports platform-specific executor modules to avoid import-time
44
+ * failures on platforms where they don't exist.
45
+ */
46
+ export declare function getExecutor(): Promise<SandboxExecutor | null>;
47
+ /**
48
+ * Reset the cached executor — useful for testing.
49
+ * @internal
50
+ */
51
+ export declare function _resetExecutorCache(): void;
@@ -0,0 +1 @@
1
+ export { BubblewrapSandboxExecutor } from '../linux/bubblewrap-executor';
@@ -0,0 +1 @@
1
+ export { MacOSSandboxExecutor } from '../macos/sandbox-exec-executor';
@@ -0,0 +1 @@
1
+ export { WindowsSandboxExecutor } from '../win32/restricted-token-executor';
@@ -0,0 +1,79 @@
1
+ /**
2
+ * Linux Bubblewrap sandbox executor.
3
+ *
4
+ * Wraps shell commands with bwrap (Bubblewrap) to restrict process capabilities.
5
+ * Uses --bind to mount scope paths read-write, --tmpfs for /tmp, and --ro-bind
6
+ * for essential read-only system paths.
7
+ */
8
+ import { type SandboxExecutor } from '../executor';
9
+ /**
10
+ * Check whether the bwrap binary is present on PATH.
11
+ * Uses spawnSync to probe synchronously without throwing.
12
+ * Logs specific error codes when bwrap is found but unusable.
13
+ */
14
+ declare function probeBwrap(): boolean;
15
+ /**
16
+ * DI seam for testability. Exposes probeBwrap so tests can simulate
17
+ * ENOENT / EACCES / ENOSPC error conditions without requiring a real bwrap binary.
18
+ * Internal calls use probeBwrap() directly; tests replace _internals.probeBwrap.
19
+ */
20
+ export declare const _internals: {
21
+ probeBwrap: typeof probeBwrap;
22
+ };
23
+ /**
24
+ * Linux Bubblewrap sandbox executor.
25
+ *
26
+ * Instantiated with scope paths and an optional temp directory override.
27
+ * wrapCommand() returns a bwrap-wrapped command string that:
28
+ * - bind-mounts each scope path read-write
29
+ * - mounts a tmpfs at /tmp (writable temporary storage)
30
+ * - bind-mounts essential system paths read-only
31
+ * - spawns the raw command via `bash -c '<command>'`
32
+ */
33
+ export declare class BubblewrapSandboxExecutor implements SandboxExecutor {
34
+ /** Human-readable mechanism identifier */
35
+ readonly mechanism = "Bubblewrap";
36
+ private readonly _scopePaths;
37
+ private readonly _tempDir;
38
+ private _available;
39
+ private _disabledReason;
40
+ /**
41
+ * @param scopePaths - Absolute paths the sandboxed process may write to (default: empty array)
42
+ * @param tempDir - Optional temp directory path (defaults to /tmp)
43
+ */
44
+ constructor(scopePaths?: string[], tempDir?: string);
45
+ /**
46
+ * Returns true when the bwrap binary is found on PATH and the sandbox
47
+ * has not been disabled.
48
+ */
49
+ isAvailable(): boolean;
50
+ /**
51
+ * Disable the sandbox with a reason. Allows external code to force
52
+ * fallback to unwrapped execution (e.g., for testing, explicit opt-out,
53
+ * or when initialization fails).
54
+ *
55
+ * After calling disable():
56
+ * - isAvailable() returns false
57
+ * - wrapCommand() returns the raw command unchanged (passthrough)
58
+ */
59
+ disable(reason: string): void;
60
+ /**
61
+ * Wrap a shell command string with bwrap sandbox arguments.
62
+ *
63
+ * @param command - Raw shell command to execute inside the sandbox
64
+ * @param scopePaths - Additional scope paths to bind (merged with constructor scope)
65
+ * @param tempDir - Optional temp directory override
66
+ * @returns A bwrap-wrapped command string ready for shell execution,
67
+ * or the raw command string when the sandbox is unavailable (passthrough mode)
68
+ */
69
+ wrapCommand(command: string, scopePaths: string[], tempDir?: string): string;
70
+ /**
71
+ * Return environment variable overrides required for the bubblewrap sandbox.
72
+ *
73
+ * Security is achieved through bwrap CLI flags (--unshare-user, --unshare-net,
74
+ * --unshare-ipc, --die-with-parent, --new-session), not environment variables.
75
+ * bwrap ignores unknown environment variables.
76
+ */
77
+ getEnvOverrides(): Record<string, string | null>;
78
+ }
79
+ export {};
@@ -0,0 +1,89 @@
1
+ /**
2
+ * Edge case handling utilities for Bubblewrap sandbox.
3
+ *
4
+ * This module provides functions to detect and prevent:
5
+ * - Symlink escape attacks
6
+ * - /proc/self/fd access
7
+ * - io_uring bypass
8
+ * - Namespace escape
9
+ * - Hard-link creation
10
+ * - Rename/move across scope boundary
11
+ * - mmap interception
12
+ */
13
+ /**
14
+ * Check whether a path is a symlink and resolves to a location outside
15
+ * any of the configured scope paths.
16
+ *
17
+ * @param path - The path to check (may be a symlink)
18
+ * @param scopePaths - Array of absolute scope paths
19
+ * @returns true if the path is a symlink that escapes the sandbox
20
+ */
21
+ export declare function detectSymlinkEscape(path: string, scopePaths: string[]): boolean;
22
+ /**
23
+ * Check whether a path is under /proc/self/fd/, which provides
24
+ * file descriptor access that can bypass normal path checks.
25
+ *
26
+ * @param path - The path to check
27
+ * @returns true if the path is under /proc/self/fd/
28
+ */
29
+ export declare function detectProcFdAccess(path: string): boolean;
30
+ /**
31
+ * Detect whether io_uring is active on the system, which can be used
32
+ * to perform I/O operations that bypass the seccomp filter.
33
+ *
34
+ * Note: This is a detection function only — it does not prevent io_uring usage.
35
+ * Bubblewrap's --unshare-all combined with seccomp filtering can mitigate this.
36
+ *
37
+ * @returns true if io_uring appears to be active
38
+ */
39
+ export declare function detectIoUringBypass(): boolean;
40
+ /**
41
+ * Detect whether the current process is already running inside a user namespace.
42
+ *
43
+ * When a process is already inside a user namespace (rather than the initial
44
+ * namespace), it may have different privileges and isolation properties than
45
+ * expected. This can affect the security assumptions of a bubblewrap sandbox.
46
+ *
47
+ * @returns true if the current process is already inside a non-initial user namespace
48
+ */
49
+ export declare function detectNamespaceEscape(): boolean;
50
+ /**
51
+ * Check whether a path operation would create a hard link that escapes
52
+ * the sandbox scope.
53
+ *
54
+ * Hard links can allow a file inside the sandbox to be linked to a location
55
+ * outside the sandbox, potentially bypassing containment.
56
+ *
57
+ * @param path - The path being linked to
58
+ * @param scopePaths - Array of absolute scope paths
59
+ * @returns true if creating a hard link at path would escape the sandbox
60
+ */
61
+ export declare function detectHardLinkEscape(path: string, scopePaths: string[]): boolean;
62
+ /**
63
+ * Alias for detectHardLinkEscape for API compatibility.
64
+ * @param path - The path being linked to
65
+ * @param scopePaths - Array of absolute scope paths
66
+ * @returns true if creating a hard link at path would escape the sandbox
67
+ */
68
+ export declare function detectHardLinkCreation(path: string, scopePaths: string[]): boolean;
69
+ /**
70
+ * Check whether a rename or move operation crosses a scope boundary.
71
+ *
72
+ * Moving a file from inside a scope path to outside violates containment.
73
+ *
74
+ * @param oldPath - The original path
75
+ * @param newPath - The destination path after rename/move
76
+ * @param scopePaths - Array of absolute scope paths
77
+ * @returns true if the rename crosses a scope boundary
78
+ */
79
+ export declare function detectRenameAcrossBoundary(oldPath: string, newPath: string, scopePaths: string[]): boolean;
80
+ /**
81
+ * Check whether a path pattern suggests mmap interception attempts.
82
+ *
83
+ * mmap can be used to map device files or anonymous memory that bypasses
84
+ * normal file-based access controls.
85
+ *
86
+ * @param path - The path being accessed
87
+ * @returns true if the path suggests mmap interception
88
+ */
89
+ export declare function detectMmapInterception(path: string): boolean;
@@ -0,0 +1,89 @@
1
+ /**
2
+ * Edge case handling utilities for macOS sandbox-exec.
3
+ *
4
+ * This module provides functions to detect and prevent:
5
+ * - DYLD injection attacks
6
+ * - Temp directory manipulation
7
+ * - Sandbox profile bypass attempts
8
+ * - SIP-protected path access
9
+ * - Entitlement escalation
10
+ * - Quarantine bypass
11
+ * - Nested sandbox execution
12
+ */
13
+ /**
14
+ * Check whether the environment contains DYLD environment variables
15
+ * that can be used to inject code into sandboxed processes.
16
+ *
17
+ * These variables are ignored in SIP-protected processes but may
18
+ * work in some sandbox configurations.
19
+ *
20
+ * @param path - Unused, kept for signature compatibility
21
+ * @param env - The environment variables to check
22
+ * @returns true if DYLD injection variables are present
23
+ */
24
+ export declare function detectDyldInjection(_path: string, env: Record<string, string | undefined>): boolean;
25
+ /**
26
+ * Check whether a command tries to escape the temp directory via
27
+ * symlinks, path traversal, or environment variable override.
28
+ *
29
+ * @param tempDir - The allowed temp directory path
30
+ * @param command - The command string to analyze
31
+ * @returns true if temp directory manipulation is detected
32
+ */
33
+ export declare function detectTmpDirManipulation(tempDir: string, command: string): boolean;
34
+ /**
35
+ * Check whether a command tries to bypass sandbox profile restrictions by:
36
+ * - Writing to paths outside scopePaths
37
+ * - Using mktemp in unusual locations
38
+ * - Creating hard/symbolic links to escape scope
39
+ *
40
+ * @param command - The command string to analyze
41
+ * @param scopePaths - Array of allowed scope paths
42
+ * @returns true if sandbox profile bypass is detected
43
+ */
44
+ export declare function detectSandboxProfileBypass(command: string, scopePaths: string[]): boolean;
45
+ /**
46
+ * Check whether a command tries to access System Integrity Protected (SIP) paths.
47
+ *
48
+ * SIP-protected paths on macOS include /System, /usr/libexec, /usr/sbin, /AppleInternal.
49
+ * Writing to these paths can compromise system security even in a sandbox.
50
+ *
51
+ * @param command - The command string to analyze
52
+ * @returns true if SIP-protected path access is detected
53
+ */
54
+ export declare function detectSIPProtectedPathAccess(command: string): boolean;
55
+ /**
56
+ * Check whether a command tries to escalate privileges or modify
57
+ * sandbox entitlements.
58
+ *
59
+ * @param command - The command string to analyze
60
+ * @returns true if entitlement escalation is detected
61
+ */
62
+ export declare function detectEntitlementEscalation(command: string): boolean;
63
+ /**
64
+ * Check whether a command tries to bypass macOS quarantine restrictions.
65
+ *
66
+ * Downloaded files have a quarantine attribute that gates execution.
67
+ * Removing this attribute allows unapproved software to run.
68
+ *
69
+ * @param command - The command string to analyze
70
+ * @returns true if quarantine bypass is detected
71
+ */
72
+ export declare function detectQuarantineBypass(command: string): boolean;
73
+ /**
74
+ * Alias for detectSIPProtectedPathAccess for API compatibility.
75
+ * @param command - The command string to analyze
76
+ * @returns true if SIP-protected path access is detected
77
+ */
78
+ export declare function detectSIPSProtectedPath(command: string): boolean;
79
+ /**
80
+ * Check whether a command tries to spawn another sandbox-exec instance
81
+ * (nested sandboxing).
82
+ *
83
+ * Nested sandbox execution can be used to escape restrictions by
84
+ * spawning a less-restricted sandbox within a sandbox.
85
+ *
86
+ * @param command - The command string to analyze
87
+ * @returns true if nested sandbox execution is detected
88
+ */
89
+ export declare function detectSandboxExecItself(command: string): boolean;