@landstrip/landstrip-api 0.19.20 → 0.20.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/README.md CHANGED
@@ -18,7 +18,7 @@ See the [quick start](../../README.md#quick-start) for a policy and CLI example;
18
18
  const { execFileSync } = require("node:child_process");
19
19
  const { binaryPath } = require("@landstrip/landstrip-api");
20
20
 
21
- execFileSync(binaryPath(), ["-p", "policy.json", "--", "cargo", "test"], {
21
+ execFileSync(binaryPath(), ["run", "-p", "policy.json", "--", "cargo", "test"], {
22
22
  stdio: "inherit",
23
23
  });
24
24
  ```
@@ -39,6 +39,37 @@ Proxy helpers: [`/proxy`](lib/proxy.d.ts). [`/shared`](lib/shared.d.ts) provides
39
39
  Failed writes clean up; failed cleanup reports both errors and the directory
40
40
  path in an `AggregateError`.
41
41
 
42
+ ## macOS log correlation
43
+
44
+ Both `LandstripDarwinPolicy` and `SandboxDarwinConfig` accept optional
45
+ `logTag?: string`, under the JSON key `macos` (not `darwin`):
46
+
47
+ ```js
48
+ const { buildLandstripPolicy } = require("@landstrip/landstrip-api/shared");
49
+ const policy = buildLandstripPolicy({ macos: { logTag: "agent-session-42" } });
50
+ ```
51
+
52
+ `macos.logTag` tags Seatbelt denial logs for correlation. It must be nonempty
53
+ and contain no double quote, backslash, ASCII control character (0x00–0x1f),
54
+ or DEL (0x7f). `null` is invalid. `buildLandstripPolicy` and `parseSandboxConfig`
55
+ validate and forward it; `deepMergeSandboxConfig` uses the override tag when
56
+ provided, otherwise preserving the base tag.
57
+
58
+ ## Trap transport and reporting
59
+
60
+ On Unix, `--trap FD|PATH` accepts either an inherited open FD ≥3 or an absolute
61
+ Unix domain stream socket path. Start the socket listener before launching
62
+ Landstrip: the host Landstrip process connects before sandbox setup, and the
63
+ sandboxed child never inherits the trap transport.
64
+
65
+ On Linux, the stream is bidirectional and uses the existing broker query
66
+ protocol, not merely passive monitoring. For `state: "query"` events, reply on
67
+ the same socket with `controlResponseLine(trap.query_id, "allow")` (or `"deny"`);
68
+ the syscall waits for an answer. Completed events have `state: "info"`.
69
+ Explicit read denials (`DenyMatch`, JSON `reason: "deny_match"`) are reported
70
+ even when the command exits 0. macOS reports setup/launch failures on the trap
71
+ transport and closes it on successful exec; use Seatbelt logs for runtime denials.
72
+
42
73
  ## Development
43
74
 
44
75
  Run `make ci` from the repository root.
package/lib/index.d.ts CHANGED
@@ -93,6 +93,7 @@ export type LandstripPolicyErrorCode =
93
93
  | 'POLICY_DENY_WRITE_SYMLINK_ANCESTOR'
94
94
  | 'POLICY_INVALID_PORT'
95
95
  | 'POLICY_EMPTY_PATH'
96
+ | 'POLICY_INVALID_LOG_TAG'
96
97
  | 'POLICY_HOME_UNAVAILABLE'
97
98
  | 'POLICY_TRAVERSAL_DEPTH';
98
99
 
@@ -145,24 +146,38 @@ export interface LandstripControlResponse {
145
146
  action: 'allow' | 'deny';
146
147
  }
147
148
 
149
+ export type LandstripPathSelector =
150
+ | string
151
+ | { literal: string }
152
+ | { glob: string };
153
+
148
154
  export interface LandstripFilesystemPolicy {
149
- denyRead?: string[];
150
- denyReadAlways?: string[];
151
- allowRead?: string[];
152
- allowWrite?: string[];
153
- denyWrite?: string[];
154
- denyWriteAlways?: string[];
155
+ denyRead?: LandstripPathSelector[];
156
+ denyReadAlways?: LandstripPathSelector[];
157
+ allowRead?: LandstripPathSelector[];
158
+ allowWrite?: LandstripPathSelector[];
159
+ denyWrite?: LandstripPathSelector[];
160
+ denyWriteAlways?: LandstripPathSelector[];
155
161
  }
156
162
 
157
163
  export interface LandstripNetworkPolicy {
158
164
  allowNetwork?: boolean;
159
165
  allowLocalBinding?: boolean;
160
166
  allowAllUnixSockets?: boolean;
161
- allowUnixSockets?: string[];
167
+ allowUnixSockets?: LandstripPathSelector[];
162
168
  httpProxyPort?: number;
163
169
  socksProxyPort?: number;
164
170
  }
165
171
 
172
+ export interface LandstripDarwinPolicy {
173
+ /** Seatbelt log correlation tag: nonempty, without double quotes, backslashes, ASCII controls or DEL; not null. */
174
+ logTag?: string;
175
+ allowTrustd?: boolean;
176
+ allowMachLookup?: string[];
177
+ allowAppleEvents?: boolean;
178
+ allowPty?: boolean;
179
+ }
180
+
166
181
  export type LandstripWindowsAppContainerMode = 'lpac' | 'standard';
167
182
 
168
183
  export interface LandstripWindowsPolicy {
@@ -173,9 +188,32 @@ export interface LandstripWindowsPolicy {
173
188
  export interface LandstripPolicy {
174
189
  filesystem?: LandstripFilesystemPolicy;
175
190
  network?: LandstripNetworkPolicy;
191
+ macos?: LandstripDarwinPolicy;
176
192
  windows?: LandstripWindowsPolicy;
177
193
  }
178
194
 
195
+ export type SandboxImplementation =
196
+ | 'landlock+seccomp'
197
+ | 'seatbelt'
198
+ | 'appContainer'
199
+ | 'restrictedUser';
200
+
201
+ export interface FeatureCapabilities {
202
+ filesystemTiers: string[];
203
+ networkMediation: boolean;
204
+ unixSocketFiltering: boolean;
205
+ processIsolation: boolean;
206
+ }
207
+
208
+ export interface DoctorReport {
209
+ ok: boolean;
210
+ platform: string;
211
+ implementation: SandboxImplementation;
212
+ supported: FeatureCapabilities;
213
+ available: FeatureCapabilities;
214
+ error?: string;
215
+ }
216
+
179
217
  export interface SandboxFilesystemConfig {
180
218
  denyRead: string[];
181
219
  denyReadAlways: string[];
@@ -200,6 +238,15 @@ export interface SandboxNetworkConfig {
200
238
  deniedDomains: string[];
201
239
  }
202
240
 
241
+ export interface SandboxDarwinConfig {
242
+ /** Optional Seatbelt log correlation tag; same restrictions as LandstripDarwinPolicy.logTag. */
243
+ logTag?: string;
244
+ allowTrustd: boolean;
245
+ allowMachLookup: string[];
246
+ allowAppleEvents: boolean;
247
+ allowPty: boolean;
248
+ }
249
+
203
250
  export interface SandboxWindowsConfig {
204
251
  appContainerMode: LandstripWindowsAppContainerMode;
205
252
  allowLoopback: boolean;
@@ -210,12 +257,14 @@ export interface SandboxConfig {
210
257
  shell?: SandboxShellConfig;
211
258
  network: SandboxNetworkConfig;
212
259
  filesystem: SandboxFilesystemConfig;
260
+ macos?: SandboxDarwinConfig;
213
261
  windows?: SandboxWindowsConfig;
214
262
  }
215
263
 
216
264
  export type SandboxFilesystemConfigFile = Partial<SandboxFilesystemConfig>;
217
265
  export type SandboxShellConfigFile = Partial<SandboxShellConfig>;
218
266
  export type SandboxNetworkConfigFile = Partial<SandboxNetworkConfig>;
267
+ export type SandboxDarwinConfigFile = Partial<SandboxDarwinConfig>;
219
268
  export type SandboxWindowsConfigFile = Partial<SandboxWindowsConfig>;
220
269
 
221
270
  export interface SandboxConfigFile {
@@ -223,12 +272,12 @@ export interface SandboxConfigFile {
223
272
  shell?: SandboxShellConfigFile;
224
273
  network?: SandboxNetworkConfigFile;
225
274
  filesystem?: SandboxFilesystemConfigFile;
275
+ macos?: SandboxDarwinConfigFile;
226
276
  windows?: SandboxWindowsConfigFile;
227
277
  }
228
278
 
229
279
  export type SandboxConfigOverrides = SandboxConfigFile;
230
280
 
231
-
232
281
  export type PathAccessDecision = 'allow' | 'ask' | 'deny' | 'denyAlways';
233
282
 
234
283
  export type DomainAccessDecision = 'allow' | 'ask' | 'deny';
package/lib/shared.d.ts CHANGED
@@ -1,19 +1,26 @@
1
1
  // SPDX-License-Identifier: Apache-2.0
2
2
 
3
3
  import type {
4
+ DoctorReport,
5
+ FeatureCapabilities,
4
6
  LandstripControlResponse,
7
+ LandstripDarwinPolicy,
5
8
  LandstripFilesystemPolicy,
6
9
  LandstripFilesystemTrap,
7
10
  LandstripNetworkPolicy,
8
11
  LandstripNetworkTrap,
12
+ LandstripPathSelector,
9
13
  LandstripPolicy,
10
14
  LandstripTrap,
11
15
  LandstripWindowsPolicy,
12
16
  SandboxConfig,
13
17
  SandboxConfigFile,
14
18
  SandboxConfigOverrides,
19
+ SandboxDarwinConfig,
20
+ SandboxDarwinConfigFile,
15
21
  SandboxFilesystemConfig,
16
22
  SandboxFilesystemConfigFile,
23
+ SandboxImplementation,
17
24
  SandboxNetworkConfig,
18
25
  SandboxNetworkConfigFile,
19
26
  SandboxShellConfig,
@@ -27,11 +34,18 @@ export type LandstripDenialTrap = LandstripFilesystemTrap | LandstripNetworkTrap
27
34
  export type LandstripQueryTrap = LandstripDenialTrap & { state: 'query' };
28
35
 
29
36
  export type {
37
+ DoctorReport,
38
+ FeatureCapabilities,
39
+ LandstripDarwinPolicy,
40
+ LandstripPathSelector,
30
41
  SandboxConfig,
31
42
  SandboxConfigFile,
32
43
  SandboxConfigOverrides,
44
+ SandboxDarwinConfig,
45
+ SandboxDarwinConfigFile,
33
46
  SandboxFilesystemConfig,
34
47
  SandboxFilesystemConfigFile,
48
+ SandboxImplementation,
35
49
  SandboxNetworkConfig,
36
50
  SandboxNetworkConfigFile,
37
51
  SandboxShellConfig,
@@ -92,24 +106,25 @@ export function controlResponseLine(
92
106
 
93
107
 
94
108
  export interface BuildLandstripPolicyOptions {
95
- filesystem?: LandstripFilesystemPolicy;
96
- network?: LandstripNetworkPolicy;
97
- windows?: LandstripWindowsPolicy;
98
- baseDirectory?: string;
99
- httpProxyPort?: number | null;
100
- socksProxyPort?: number | null;
109
+ filesystem?: LandstripFilesystemPolicy | undefined;
110
+ network?: LandstripNetworkPolicy | undefined;
111
+ macos?: LandstripDarwinPolicy | undefined;
112
+ windows?: LandstripWindowsPolicy | undefined;
113
+ baseDirectory?: string | undefined;
114
+ httpProxyPort?: number | null | undefined;
115
+ socksProxyPort?: number | null | undefined;
101
116
  }
102
117
 
103
118
  export function resolveFilesystemPatterns(
104
- patterns: string[] | undefined,
119
+ patterns: LandstripPathSelector[] | undefined,
105
120
  baseDirectory?: string,
106
- ): string[];
107
-
121
+ ): LandstripPathSelector[];
108
122
  export function resolveFilesystemPolicy(
109
123
  filesystem?: LandstripFilesystemPolicy,
110
124
  baseDirectory?: string,
111
125
  ): LandstripFilesystemPolicy;
112
126
 
127
+ /** Forwards macos.logTag; throws if it is empty, non-string, or contains a double quote, backslash, ASCII control or DEL. */
113
128
  export function buildLandstripPolicy(
114
129
  options: BuildLandstripPolicyOptions,
115
130
  ): LandstripPolicy;
@@ -122,10 +137,11 @@ export function writeLandstripPolicyFile(
122
137
  ): { dir: string; path: string };
123
138
 
124
139
 
125
- export function mergeArray(base: string[], override?: string[]): string[];
126
-
140
+ export function mergeArray<T = string>(base: T[], override?: T[]): T[];
141
+ /** Parses sandbox settings, validating macos.logTag with the same rules as buildLandstripPolicy (null is invalid). */
127
142
  export function parseSandboxConfig(value: unknown): SandboxConfigFile;
128
143
 
144
+ /** Merges arrays and applies override scalar precedence, including macos.logTag. */
129
145
  export function deepMergeSandboxConfig<T extends SandboxConfig = SandboxConfig>(
130
146
  base: T,
131
147
  overrides?: SandboxConfigFile,
@@ -153,36 +169,35 @@ export interface EvaluateDomainOptions {
153
169
 
154
170
  export function matchesPathPattern(
155
171
  filePath: string,
156
- patterns: string[],
172
+ patterns: LandstripPathSelector[],
157
173
  baseDirectory?: string,
158
174
  ): boolean;
159
175
 
160
176
  export function matchPathSpecificity(
161
177
  filePath: string,
162
- patterns: string[],
178
+ patterns: LandstripPathSelector[],
163
179
  baseDirectory?: string,
164
180
  ): number;
165
181
 
166
182
  export function isPathReadAllowed(
167
183
  filePath: string,
168
- allowRead: string[],
169
- denyRead: string[],
184
+ allowRead: LandstripPathSelector[],
185
+ denyRead: LandstripPathSelector[],
170
186
  baseDirectory?: string,
171
187
  options?: { requireAllowMatch?: boolean },
172
188
  ): boolean;
173
189
 
174
190
  export function isPathWriteAllowed(
175
191
  filePath: string,
176
- allowWrite: string[],
192
+ allowWrite: LandstripPathSelector[],
177
193
  baseDirectory?: string,
178
194
  ): boolean;
179
195
 
180
196
  export function shouldPromptForWrite(
181
197
  filePath: string,
182
- allowWrite: string[],
198
+ allowWrite: LandstripPathSelector[],
183
199
  baseDirectory?: string,
184
200
  ): boolean;
185
-
186
201
  export function evaluateReadAccess(
187
202
  filePath: string,
188
203
  filesystem: SandboxFilesystemConfig | SandboxFilesystemConfigFile | SandboxConfig | SandboxConfigFile,
package/lib/shared.js CHANGED
@@ -142,6 +142,7 @@ const LANDSTRIP_INTERNAL_CODES = new Set([
142
142
  'POLICY_DENY_WRITE_SYMLINK_ANCESTOR',
143
143
  'POLICY_INVALID_PORT',
144
144
  'POLICY_EMPTY_PATH',
145
+ 'POLICY_INVALID_LOG_TAG',
145
146
  'POLICY_HOME_UNAVAILABLE',
146
147
  'POLICY_TRAVERSAL_DEPTH',
147
148
  'SUPERVISE_FAILED',
@@ -418,14 +419,27 @@ function controlResponseLine(queryId, action) {
418
419
  return JSON.stringify({ query_id: queryId, action }) + '\n';
419
420
  }
420
421
 
422
+ function resolvePathSelector(entry, baseDirectory) {
423
+ if (typeof entry === 'string') {
424
+ return /[*?[\]]/.test(entry)
425
+ ? canonicalizeGlobPattern(entry, baseDirectory)
426
+ : canonicalizePath(entry, baseDirectory);
427
+ }
428
+ if (isRecord(entry)) {
429
+ if (typeof entry.literal === 'string') {
430
+ return { literal: canonicalizePath(entry.literal, baseDirectory) };
431
+ }
432
+ if (typeof entry.glob === 'string') {
433
+ return { glob: canonicalizeGlobPattern(entry.glob, baseDirectory) };
434
+ }
435
+ }
436
+ return entry;
437
+ }
438
+
421
439
  function resolveFilesystemPatterns(patterns, baseDirectory) {
422
440
  if (!patterns || !Array.isArray(patterns)) return [];
423
441
  if (!baseDirectory) return [...patterns];
424
- return patterns.map((pattern) =>
425
- /[*?[\]]/.test(pattern)
426
- ? canonicalizeGlobPattern(pattern, baseDirectory)
427
- : canonicalizePath(pattern, baseDirectory),
428
- );
442
+ return patterns.map((pattern) => resolvePathSelector(pattern, baseDirectory));
429
443
  }
430
444
 
431
445
  function resolveFilesystemPolicy(filesystem, baseDirectory) {
@@ -452,6 +466,14 @@ function resolveFilesystemPolicy(filesystem, baseDirectory) {
452
466
  return resolved;
453
467
  }
454
468
 
469
+ function validateDarwinLogTag(value) {
470
+ if (typeof value !== 'string' || value.length === 0 || /["\\\x00-\x1f\x7f]/.test(value)) {
471
+ throw new Error(
472
+ 'macos.logTag must be a nonempty string without double quotes, backslashes, ASCII control characters or DEL',
473
+ );
474
+ }
475
+ }
476
+
455
477
  function buildLandstripPolicy(options) {
456
478
  const policy = {};
457
479
  if (options.network) {
@@ -485,6 +507,20 @@ function buildLandstripPolicy(options) {
485
507
  options.baseDirectory,
486
508
  );
487
509
  }
510
+ if (options.macos) {
511
+ policy.macos = {
512
+ allowTrustd: Boolean(options.macos.allowTrustd),
513
+ allowMachLookup: Array.isArray(options.macos.allowMachLookup)
514
+ ? [...options.macos.allowMachLookup]
515
+ : [],
516
+ allowAppleEvents: Boolean(options.macos.allowAppleEvents),
517
+ allowPty: Boolean(options.macos.allowPty),
518
+ };
519
+ if (options.macos.logTag !== undefined) {
520
+ validateDarwinLogTag(options.macos.logTag);
521
+ policy.macos.logTag = options.macos.logTag;
522
+ }
523
+ }
488
524
  if (options.windows) {
489
525
  policy.windows = {
490
526
  appContainerMode: options.windows.appContainerMode ?? 'lpac',
@@ -552,12 +588,28 @@ function validateStringArrayFields(value, fields, prefix = '') {
552
588
 
553
589
  function mergeArray(base, override) {
554
590
  if (!override) return base;
555
- return [...new Set([...(base ?? []), ...override])];
591
+ const result = [];
592
+ const seen = new Set();
593
+ for (const item of [...(base ?? []), ...override]) {
594
+ const key = typeof item === 'string' ? `s:${item}` : `o:${JSON.stringify(item)}`;
595
+ if (!seen.has(key)) {
596
+ seen.add(key);
597
+ result.push(item);
598
+ }
599
+ }
600
+ return result;
556
601
  }
557
602
 
558
603
  function parseSandboxConfig(value) {
559
604
  requireSandboxObject(value, 'sandbox config');
560
- rejectUnknownSandboxFields(value, ['enabled', 'shell', 'network', 'filesystem', 'windows']);
605
+ rejectUnknownSandboxFields(value, [
606
+ 'enabled',
607
+ 'shell',
608
+ 'network',
609
+ 'filesystem',
610
+ 'macos',
611
+ 'windows',
612
+ ]);
561
613
  validateBooleanFields(value, ['enabled']);
562
614
 
563
615
  const config = {};
@@ -656,6 +708,38 @@ function parseSandboxConfig(value) {
656
708
  }
657
709
  }
658
710
 
711
+ if (value.macos !== undefined) {
712
+ requireSandboxObject(value.macos, 'macos');
713
+ rejectUnknownSandboxFields(
714
+ value.macos,
715
+ ['allowTrustd', 'allowMachLookup', 'allowAppleEvents', 'allowPty', 'logTag'],
716
+ 'macos.',
717
+ );
718
+ validateBooleanFields(
719
+ value.macos,
720
+ ['allowTrustd', 'allowAppleEvents', 'allowPty'],
721
+ 'macos.',
722
+ );
723
+ validateStringArrayFields(value.macos, ['allowMachLookup'], 'macos.');
724
+ config.macos = {};
725
+ if (value.macos.allowTrustd !== undefined) {
726
+ config.macos.allowTrustd = value.macos.allowTrustd;
727
+ }
728
+ if (value.macos.allowMachLookup !== undefined) {
729
+ config.macos.allowMachLookup = [...value.macos.allowMachLookup];
730
+ }
731
+ if (value.macos.allowAppleEvents !== undefined) {
732
+ config.macos.allowAppleEvents = value.macos.allowAppleEvents;
733
+ }
734
+ if (value.macos.allowPty !== undefined) {
735
+ config.macos.allowPty = value.macos.allowPty;
736
+ }
737
+ if (value.macos.logTag !== undefined) {
738
+ validateDarwinLogTag(value.macos.logTag);
739
+ config.macos.logTag = value.macos.logTag;
740
+ }
741
+ }
742
+
659
743
  if (value.windows !== undefined) {
660
744
  requireSandboxObject(value.windows, 'windows');
661
745
  rejectUnknownSandboxFields(value.windows, ['appContainerMode', 'allowLoopback'], 'windows.');
@@ -685,6 +769,7 @@ function deepMergeSandboxConfig(base, overrides) {
685
769
  const shell = overrides.shell;
686
770
  const network = overrides.network;
687
771
  const filesystem = overrides.filesystem;
772
+ const macos = overrides.macos;
688
773
  const windows = overrides.windows;
689
774
 
690
775
  const result = {
@@ -713,6 +798,19 @@ function deepMergeSandboxConfig(base, overrides) {
713
798
  };
714
799
  }
715
800
 
801
+ if (base.macos !== undefined || macos !== undefined) {
802
+ result.macos = {
803
+ allowTrustd: macos?.allowTrustd ?? base.macos?.allowTrustd ?? false,
804
+ allowMachLookup: mergeArray(base.macos?.allowMachLookup ?? [], macos?.allowMachLookup),
805
+ allowAppleEvents: macos?.allowAppleEvents ?? base.macos?.allowAppleEvents ?? false,
806
+ allowPty: macos?.allowPty ?? base.macos?.allowPty ?? false,
807
+ };
808
+ const logTag = macos?.logTag ?? base.macos?.logTag;
809
+ if (logTag !== undefined) {
810
+ result.macos.logTag = logTag;
811
+ }
812
+ }
813
+
716
814
  if (base.windows !== undefined || windows !== undefined) {
717
815
  result.windows = {
718
816
  appContainerMode: windows?.appContainerMode ?? base.windows?.appContainerMode ?? 'standard',
@@ -729,14 +827,43 @@ function normalizePathForComparison(filePath) {
729
827
  return process.platform === 'win32' ? normalized.toLowerCase() : normalized;
730
828
  }
731
829
 
830
+ function resolveSelectorForMatch(pattern, baseDirectory) {
831
+ if (isRecord(pattern)) {
832
+ if (typeof pattern.literal === 'string') {
833
+ return {
834
+ canonical: canonicalizePath(pattern.literal, baseDirectory),
835
+ isGlob: false,
836
+ };
837
+ }
838
+ if (typeof pattern.glob === 'string') {
839
+ const isGlob = /[*?[\]]/.test(pattern.glob);
840
+ return {
841
+ canonical: isGlob
842
+ ? canonicalizeGlobPattern(pattern.glob, baseDirectory)
843
+ : canonicalizePath(pattern.glob, baseDirectory),
844
+ isGlob,
845
+ };
846
+ }
847
+ }
848
+ const raw = String(pattern);
849
+ const isGlob = /[*?[\]]/.test(raw);
850
+ return {
851
+ canonical: isGlob
852
+ ? canonicalizeGlobPattern(raw, baseDirectory)
853
+ : canonicalizePath(raw, baseDirectory),
854
+ isGlob,
855
+ };
856
+ }
857
+
732
858
  function matchesPathPattern(filePath, patterns, baseDirectory = process.cwd()) {
733
859
  if (!Array.isArray(patterns) || patterns.length === 0) return false;
734
860
  const abs = normalizePathForComparison(canonicalizePath(filePath, baseDirectory));
735
861
 
736
862
  return patterns.some((pattern) => {
737
- const absPattern = normalizePathForComparison(canonicalizeGlobPattern(pattern, baseDirectory));
863
+ const { canonical, isGlob } = resolveSelectorForMatch(pattern, baseDirectory);
864
+ const absPattern = normalizePathForComparison(canonical);
738
865
 
739
- if (/[*?[\]]/.test(pattern)) {
866
+ if (isGlob) {
740
867
  const matcher = globToRegExp(absPattern);
741
868
  for (let candidate = abs; ;) {
742
869
  if (matcher.test(candidate)) return true;
@@ -757,7 +884,7 @@ function matchPathSpecificity(filePath, patterns, baseDirectory = process.cwd())
757
884
  let best = -1;
758
885
  for (const pattern of patterns) {
759
886
  if (!matchesPathPattern(filePath, [pattern], baseDirectory)) continue;
760
- const canonical = canonicalizeGlobPattern(pattern, baseDirectory);
887
+ const { canonical } = resolveSelectorForMatch(pattern, baseDirectory);
761
888
  if (canonical.length > best) {
762
889
  best = canonical.length;
763
890
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@landstrip/landstrip-api",
3
- "version": "0.19.20",
3
+ "version": "0.20.0",
4
4
  "description": "Sandbox runner using Landlock, Seatbelt, and AppContainer",
5
5
  "license": "Apache-2.0",
6
6
  "homepage": "https://github.com/landstrip/landstrip#readme",
@@ -40,12 +40,12 @@
40
40
  "ipaddr.js": "^2.5.0"
41
41
  },
42
42
  "optionalDependencies": {
43
- "@landstrip/landstrip-darwin-arm64": "0.19.20",
44
- "@landstrip/landstrip-darwin-x64": "0.19.20",
45
- "@landstrip/landstrip-linux-x64": "0.19.20",
46
- "@landstrip/landstrip-linux-arm64": "0.19.20",
47
- "@landstrip/landstrip-win32-x64": "0.19.20",
48
- "@landstrip/landstrip-win32-arm64": "0.19.20"
43
+ "@landstrip/landstrip-darwin-arm64": "0.20.0",
44
+ "@landstrip/landstrip-darwin-x64": "0.20.0",
45
+ "@landstrip/landstrip-linux-x64": "0.20.0",
46
+ "@landstrip/landstrip-linux-arm64": "0.20.0",
47
+ "@landstrip/landstrip-win32-x64": "0.20.0",
48
+ "@landstrip/landstrip-win32-arm64": "0.20.0"
49
49
  },
50
50
  "publishConfig": {
51
51
  "access": "public"