opencode-swarm 7.34.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.
- package/dist/agents/agent-output-schema.d.ts +9 -1
- package/dist/cli/index.js +403 -7
- package/dist/index.js +3682 -2238
- package/dist/memory/curator-decision-helpers.d.ts +14 -0
- package/dist/memory/gateway.d.ts +5 -1
- package/dist/memory/index.d.ts +2 -2
- package/dist/memory/injector.d.ts +1 -1
- package/dist/memory/local-jsonl-provider.d.ts +4 -1
- package/dist/memory/provider.d.ts +2 -1
- package/dist/memory/run-log.d.ts +1 -1
- package/dist/memory/schema.d.ts +5 -1
- package/dist/memory/sqlite-provider.d.ts +6 -1
- package/dist/memory/types.d.ts +74 -0
- package/dist/sandbox/capability-probe.d.ts +55 -0
- package/dist/sandbox/executor.d.ts +51 -0
- package/dist/sandbox/executors/bubblewrap.d.ts +1 -0
- package/dist/sandbox/executors/macos.d.ts +1 -0
- package/dist/sandbox/executors/windows.d.ts +1 -0
- package/dist/sandbox/linux/bubblewrap-executor.d.ts +79 -0
- package/dist/sandbox/linux/edge-cases.d.ts +89 -0
- package/dist/sandbox/macos/edge-cases.d.ts +89 -0
- package/dist/sandbox/macos/sandbox-exec-executor.d.ts +68 -0
- package/dist/sandbox/scope-resolver.d.ts +32 -0
- package/dist/sandbox/win32/edge-cases.d.ts +90 -0
- package/dist/sandbox/win32/restricted-token-executor.d.ts +94 -0
- package/package.json +1 -1
|
@@ -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[];
|
package/dist/memory/gateway.d.ts
CHANGED
|
@@ -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;
|
package/dist/memory/index.d.ts
CHANGED
|
@@ -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
|
}
|
package/dist/memory/run-log.d.ts
CHANGED
|
@@ -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;
|
package/dist/memory/schema.d.ts
CHANGED
|
@@ -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;
|
package/dist/memory/types.d.ts
CHANGED
|
@@ -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;
|