@argszero/cordis-plugin-sandbox-grant-advisor 0.11.0 → 0.12.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
@@ -439,10 +439,13 @@ the advisory never names the dead directory.
439
439
 
440
440
  ### 3. A confined child that never started (`native-init`)
441
441
 
442
- Five reports of one exit code: [`#7876`] and [`#8193`] (the packaged desktop
442
+ Seven reports of one exit code: [`#7876`] and [`#8193`] (the packaged desktop
443
443
  app), [`#8313`] (the same version and the same mode run as the desktop app versus
444
- the Web UI launched from a terminal, which works) and [`#7877`] (MSYS2 / Git
445
- Bash) — and [`#8208`], which found the mechanism the console cases share. All are `0xC0000142`
444
+ the Web UI launched from a terminal, which works), [`#8334`] (the same code with
445
+ the authorization side attached: the grant **succeeded** and every confined child
446
+ still died) and [`#7877`] (MSYS2 / Git
447
+ Bash) — and [`#8208`], which found the mechanism the console cases share, and
448
+ [`#8336`], which measured the creation flags that mechanism turns on. All are `0xC0000142`
446
449
  `STATUS_DLL_INIT_FAILED` — the Windows
447
450
  loader terminated the process while it was initializing its native images, i.e.
448
451
  **before the program's entry point**. A command that ran and then failed exits
@@ -548,10 +551,37 @@ Two producers have been measured under a confining mode:
548
551
  ordinary path (`process.ts:567`, i.e. `0x404`); `CREATE_NO_WINDOW`
549
552
  (`0x08000000`) is **not a constant anywhere in that source**. Those flags are
550
553
  fatal under a console-less runner and harmless under one that owns a console —
551
- so it is the console, not the flag list, that decides. `0.7.x` wrote the
552
- two-set version of that list and called the flags "a necessary ingredient ...
553
- the host process image is what turns it fatal"; both halves were wrong, and
554
- `0.8.0` replaces them.
554
+ so **there** the console decides. `0.7.x` wrote the two-set version of that
555
+ list and called the flags "a necessary ingredient ... the host process image is
556
+ what turns it fatal"; both halves were wrong, and `0.8.0` replaces them.
557
+
558
+ **`0.11.0` and earlier concluded too much from those three sets** — "it is the
559
+ console and not the flag list that decides" — and [`#8336`] measured the case
560
+ that falsifies it: with a console-owning host, a restricted token and the Low
561
+ integrity level, varying only the creation flags, `CREATE_NO_WINDOW` and
562
+ `CREATE_NEW_CONSOLE` both died with `0xC0000142`, while `0`, `DETACHED_PROCESS`
563
+ and `CREATE_NEW_PROCESS_GROUP` reached the program. So the console decides
564
+ **whether a flag that merely shares the inherited console is fatal**, and a
565
+ flag that forces the child to create one of its own is fatal regardless. The
566
+ pair inside that matrix is what makes it a rule rather than a list of forbidden
567
+ flags: the same `CREATE_NO_WINDOW` on an *unrestricted* token reached the
568
+ program, and `STARTF_USESHOWWINDOW` with `SW_HIDE` — how the harness hides a
569
+ window without isolating a console — was harmless on the restricted one.
570
+ `0.12.0` replaces the withdrawn sentence with the rule and that matrix.
571
+
572
+ **The `windowsHide` suspicion, answered.** It is the first thing a search turns
573
+ up for this failure, and it points at the wrong component: the flag appears
574
+ once on the *ordinary* subprocess path
575
+ (`packages/subprocess/subprocess-local/src/spawn.ts:472`,
576
+ `windowsHide: platform === 'win32'`), which starts the runner rather than the
577
+ confined child, and the restricted spawn defines no `CREATE_NO_WINDOW` constant
578
+ at all. It is **not** set in `dsh-jobs` — a search there finds nothing, and
579
+ every `windowsHide` in the tree sits on a host-side or ordinary spawn. And
580
+ where it *is* set, [`#8208`] measured it both ways on a host that works: with
581
+ and without `windowsHide`, the confined `pwsh` reached exit `0` with its own
582
+ stdout intact. The reason is the rule again — a windowless console is still a
583
+ console, and that is what the child inherits; what decides is whether the host
584
+ owns a console **object**, not whether it owns a window.
555
585
 
556
586
  **One arm was applied, measured, and rejected.** Putting `DETACHED_PROCESS` on
557
587
  the *restricted child* removes its console request and does stop the crash —
@@ -1041,3 +1071,5 @@ the current runtime cannot distinguish rather than counting it as a pass.
1041
1071
  [#8313]: https://github.com/deepseek-ai/deepseek-harness/discussions/8313
1042
1072
  [#8314]: https://github.com/deepseek-ai/deepseek-harness/discussions/8314
1043
1073
  [#8322]: https://github.com/deepseek-ai/deepseek-harness/discussions/8322
1074
+ [#8334]: https://github.com/deepseek-ai/deepseek-harness/discussions/8334
1075
+ [#8336]: https://github.com/deepseek-ai/deepseek-harness/discussions/8336
package/cordis.patch.yml CHANGED
@@ -105,7 +105,7 @@
105
105
  # running one.
106
106
  #
107
107
  # A THIRD family is recognized from a value, not from text (#7876, #7877,
108
- # #8193, #8208, #8313):
108
+ # #8193, #8208, #8313, #8336, #8334):
109
109
  #
110
110
  # [exit code: -1073741502] (0xC0000142 STATUS_DLL_INIT_FAILED)
111
111
  #
@@ -124,7 +124,17 @@
124
124
  # or spawned without a console), carries the one conversion the model can make
125
125
  # itself (rewrite the work as PowerShell or `cmd`), names the remedy #8193
126
126
  # measured — a real node.exe host, which the desktop ships — and says plainly
127
- # which producers it does not know. Like the second family, it is mode-gated.
127
+ # which producers it does not know. It also states the one rule the whole family
128
+ # follows from, because a reader without it reaches for the wrong flag: in a
129
+ # restricted token a console can be INHERITED but not CREATED, so a creation
130
+ # flag that forces the child to make one of its own — `CREATE_NO_WINDOW`,
131
+ # `CREATE_NEW_CONSOLE` — is fatal on its own, while `DETACHED_PROCESS` (which
132
+ # declines a console rather than creating one) is not; #8336 measured that
133
+ # matrix on one machine, and #8208 measured `windowsHide` both ways on a host
134
+ # that works, so the advisory answers that suspicion with where the flag
135
+ # actually appears — the ordinary subprocess path, not the confined one — and
136
+ # with why a windowless console is still an inheritable console. Like the second
137
+ # family, it is mode-gated.
128
138
  #
129
139
  # A FOURTH family is the other half of the FIRST one's backend (#423). There the
130
140
  # grant could not be applied at all; here it WAS applied — on the workspace root,
package/lib/advice.js CHANGED
@@ -189,7 +189,7 @@ export const PTY_DISCUSSIONS = '#7638 / #8322';
189
189
  * launched from a terminal does not, which is the same variable the PTY family
190
190
  * now names.
191
191
  */
192
- export const NATIVE_INIT_DISCUSSIONS = '#7876 / #7877 / #8193 / #8208 / #8313';
192
+ export const NATIVE_INIT_DISCUSSIONS = '#7876 / #7877 / #8193 / #8208 / #8313 / #8336 / #8334';
193
193
  /**
194
194
  * The upstream thread the workspace-denial advisory is a stopgap for.
195
195
  *
@@ -682,12 +682,31 @@ function nativeInitAdvisory(failure, mode, onElectron, href) {
682
682
  'Honest boundary — 0xC0000142 has producers this list does not have: a program that cannot load one of',
683
683
  'its own DLLs dies this way too, and the backend\'s own source records the console case as an inherent',
684
684
  'limit of the backend (`CREATE_NO_WINDOW` / `CREATE_NEW_CONSOLE` children die with `STATUS_DLL_INIT_FAILED`',
685
- 'under the restriction). #8208 explains that limit instead of repeating it, and the explanation is what the',
686
- 'two shapes above share: in a restricted token a console can be INHERITED but not CREATED. The creation',
687
- 'flags actually passed are three sets and none of them is `CREATE_NO_WINDOW` — `0` on the piped path,',
688
- '`CREATE_SUSPENDED` on the inherited-job path, and `CREATE_SUSPENDED | CREATE_UNICODE_ENVIRONMENT` on the',
689
- 'ordinary path. Those same flags are fatal under a console-less runner and harmless under one that owns a',
690
- 'console, so it is the console and not the flag list that decides.',
685
+ 'under the restriction). #8208 explains that limit instead of repeating it, and the explanation is a single',
686
+ 'rule: in a restricted token a console can be INHERITED but not CREATED. Both shapes above follow from it —',
687
+ 'the child needs a console it did not create, and anything that forces it to CREATE one is fatal on its own.',
688
+ '#8336 measured that side directly, on one machine, with a console-owning host, a restricted token and the',
689
+ 'Low integrity level, varying only the creation flags: `0`, `DETACHED_PROCESS` and `CREATE_NEW_PROCESS_GROUP`',
690
+ 'all reached the program, while `CREATE_NO_WINDOW` and `CREATE_NEW_CONSOLE` both died with the code above.',
691
+ '`STARTF_USESHOWWINDOW` with `SW_HIDE` — how a window is hidden without isolating a console — was harmless,',
692
+ 'and so was `CREATE_NO_WINDOW` on an UNRESTRICTED token, which is what makes the two a pair rather than a',
693
+ 'list of forbidden flags.',
694
+ 'The creation flags this harness actually passes are three sets and none of them is `CREATE_NO_WINDOW` —',
695
+ '`0` on the piped path, `CREATE_SUSPENDED` on the inherited-job path, and',
696
+ '`CREATE_SUSPENDED | CREATE_UNICODE_ENVIRONMENT` on the ordinary path (that constant is not defined anywhere',
697
+ 'in the process source). Those three are fatal under a console-less host and harmless under a host that owns',
698
+ 'a console, so there the console decides. A flag that forces creation is a different animal: it decides even',
699
+ 'when a console is there to be inherited.',
700
+ '',
701
+ 'One thing that gets suspected and is not the cause: `windowsHide`. It is named here because it is the',
702
+ 'first thing a search turns up, and it points at the wrong component — the flag is not set anywhere on the',
703
+ 'confined path above. It appears on the ORDINARY subprocess path (`dsh-subprocess-local`: `windowsHide:`',
704
+ '`platform === \'win32\'`), which starts the runner rather than the confined child, and the restricted spawn',
705
+ 'in `dsh-win32-process` passes the three flag sets just listed and defines no `CREATE_NO_WINDOW` constant at',
706
+ 'all. Where it IS set — on the host — #8208 measured it both ways on a host that works: with and without',
707
+ '`windowsHide`, the confined `pwsh` reached exit 0 with its own stdout intact. The reason is the rule again:',
708
+ 'a windowless console is still a console, and that is what the child inherits. What decides is whether the',
709
+ 'host owns a console OBJECT, not whether it owns a window.',
691
710
  '',
692
711
  'One arm of this family was applied, measured, and rejected — named so a reader does not reach for it:',
693
712
  'putting `DETACHED_PROCESS` on the RESTRICTED CHILD removes its console request and does stop the crash,',
@@ -190,7 +190,7 @@ export declare const PTY_DISCUSSIONS = "#7638 / #8322";
190
190
  * launched from a terminal does not, which is the same variable the PTY family
191
191
  * now names.
192
192
  */
193
- export declare const NATIVE_INIT_DISCUSSIONS = "#7876 / #7877 / #8193 / #8208 / #8313";
193
+ export declare const NATIVE_INIT_DISCUSSIONS = "#7876 / #7877 / #8193 / #8208 / #8313 / #8336 / #8334";
194
194
  /**
195
195
  * The upstream thread the workspace-denial advisory is a stopgap for.
196
196
  *
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@argszero/cordis-plugin-sandbox-grant-advisor",
3
- "description": "Turns four sandbox environment failures that name neither their cause nor a remedy into a diagnosis with a path forward. Family 1, the Windows workspace ACL: twelve reports (#7538, #7622, #7646, #7720, #7750, #7735, #7771, #7804, #7816, #8232, #8272, #8275) of one signature — every sandboxed command fails before it runs with `SetNamedSecurityInfoW failed (Win32 5): grantWrite(<workspace>)`, because the merged DACL + mandatory-label write needs WRITE_OWNER on the directory (an object right the caller can self-grant), not SeSecurityPrivilege and not elevation; the host grant is materialized lazily and caches nothing on the failure path, so the same failure repeats per command. Two further reports (#8312, #8314) describe the other end of that same backend — what its grant leaves behind once it succeeds: three STANDING entries nothing revokes (the workspace capability SID, the world delete-child deny, and an INHERITABLE Low integrity label that lives in the SACL, so resetting the DACL does not take it off), which makes every program launched from a folder DSH has written to run at Low integrity, and — through the NTFS hard links a pnpm workspace is made of, where two names share one file object and therefore one security descriptor — can reach out of the tree onto a content-addressed store's shared objects, leaving every project that builds from that store with Low-integrity executables and failures that name the build tool rather than DSH; the advisory states all of it before handing over the command that applies that grant, and offers no removal command, because the maintainers' own diagnosis skill does not remove the label either and removing one needs WRITE_OWNER. Family 2, the persistent shell (#7638, #8322): with the `minimal` preset under a confining sandbox mode every shell call dies instantly with `PTY shell exited during startup` because the terminal backend cannot create the pseudo-console inside the sandbox, retrying never helps, and `minimal` mounts no fallback shell tool; #8322 separated the arms inside that mode with one runner and one ConPTY — a console-subsystem node.exe host starts the confined shell while the packaged desktop's GUI-subsystem Electron host kills it silently — so the advisory names the host alongside the mode, says the outcome is deterministic per (session mode × host) rather than intermittent, and adds the console-owning host the Web UI provides (#8313) to the user-side options. Family 3, a confined Windows child that died during native initialization (#7876, #7877): every command spawned through the sandbox runner can report exit 0xC0000142 STATUS_DLL_INIT_FAILED with the process never reaching its entry point — the packaged desktop starts that runner as [process.execPath, entry], and that host has been measured twice with one indistinguishable appearance from inside a session — either nothing on the runner path ran because the Electron binary launches as an application unless the child's environment carries ELECTRON_RUN_AS_NODE=1 (#7876), or the desktop launcher does set that variable and the child still dies because the restricted token is derived from the Electron process image (#8193), and an MSYS2 / Git-Bash program cannot create its signal pipe under the restricted token while cmd.exe and pwsh run fine in the same workspace under the same mode (#7877) — and because upstream's runner-failure rules admit only exit 127 with the `windows-acl-run: ` signature, the code is never an error: it arrives as the canonical value of a result the pipeline calls a success. The plugin observes the public `tools/post-execute` waterfall, classifies all four signatures narrowly (only the two `...NamedSecurityInfoW` operations; the PTY message matched on a whole line, never as a substring; the loader status read as a 32-bit integer out of the shell tool's own canonical success value, never from rendered text; the two value-read families advised only when the facts they need hold \u2014 a confining resolved mode for the native-init death, and a Windows host, a `workspace-write` stamped mode and an in-workspace path for the denial), and attaches ONE durable user-role advisory per agent per family through `additionalContexts`. The ACL advisory names the missing right, both environments the identical text can describe (an inherited Modify-only entry, a data volume where no ACE names the caller at all, and a directory owned by another account), the version boundary that arrived with the mandatory label (0.1.7-alpha.1, flag 20, versus the DACL-only flag 4 up to 0.1.6-alpha.x) together with why downgrading is not the remedy, the second boundary the later reports needed (the backend's own `diagnose-windows-sandbox-acl` skill is not part of the 0.1.7 line at all — it arrives with 0.2.0, measured on both published tarballs: 0.1.7-rc.2 names it zero times in either README, ships no assets, and carries no registration symbol anywhere in its tree, while 0.2.0-rc.2 ships assets/diagnose-windows-sandbox-acl/ and names it three times per README — so a reader who found the promise in a README was reading a 0.2.0-era document, and sending them to repair a files glob would be the wrong repair), and why a \"weaker grant\" is a mechanism the backend cannot express rather than a policy it declines (the label rides the SAME SetNamedSecurityInfoW as the grant — there is no DACL-only apply path to fall back to — and the confined token is itself lowered to Low, so the object's Low label is what lets the confined child write there at all; declining the label usefully means declining the token level with it), the discriminator, the remedy forked on an ownership check the user runs (`(Get-Acl \"<dir>\").Owner`), because one command cannot serve both rights situations: where the caller owns the directory, the unelevated `icacls ... :(OI)(CI)(WO)` is the whole of what is missing — the owner's implicit WRITE_DAC already covers the DACL half — and where the caller does not own it that same command is refused for want of WRITE_DAC, so the grant has to come from an elevated account, or by taking ownership first, or by moving the workspace under %USERPROFILE% — and the two remedies that look right and are not (`takeown`, `icacls /reset`), each with the reason it fails — and it states the two things about the failure's shape that the reports had to measure for themselves (#8232): that it belongs to the workspace rather than to the command (a command that only reads fails identically, so there is no harmless retry), and that the grant is scoped to the directory it names and its children, so a sibling workspace root on the same volume needs the line once more; the PTY advisory names the failing combination and the host binary that decides it, states the resolved mode and that the session's recorded mode is the one that counts, tells the model to stop rather than retry, and hands over the user-side options (a preset swap, a patch row, or the console-owning host of #8313) — it never names a shell tool the failing composition does not mount; the native-init advisory states the resolved mode, says the process died before its entry point, enumerates the two producers measured under a confining mode — naming both measured shapes of the desktop host rather than asserting the one that was measured first — with the check that separates them (what program the reader ran; whether this host is the packaged desktop binary, which the plugin measures and reports rather than assumes), carries the one conversion a model can make itself (rewrite the work as PowerShell or `cmd` when an MSYS2 program is what could not start), and — for the Electron host — names the fix #8193 measured rather than a wider mode: host the runner on a real node.exe (the desktop ships one under `resources/runtime/primary-runtime/dependencies/node/bin/node.exe`), where the same confined `pwsh`/`cmd` spawns succeed, while `danger-full-access` is described as a way to confirm the diagnosis and not a fix, together with the warning that unsetting `ELECTRON_RUN_AS_NODE` instead would leave the desktop's Electron-hosted runner unable to execute `runner.js` at all (the interaction #8193 records with #8174), and says plainly which producers it does not know — it never claims the sandbox caused the failure and never offers a widened mode as a fix. Family 4, a confined command DENIED a path inside its own workspace (#423): the workspace grant is applied once, on the root, and relies on Windows ACE inheritance to reach the tree beneath it, so an object that already existed (created by an installer, an editor, another harness under its own account) whose DACL the caller could not write kept its older DACL — silently, because a skipped inherited ACE produces no error, no return value and no log line — after which the backend's root-only check (`hasExactGrant(workspaceRoot)`) short-circuits and those descendants are NEVER revisited, so the identical command keeps failing while a directory the harness itself created works; the family is read from the executors' own structured stamp on a successful result (`sandbox: { mode, denied, enforcement? }`, produced by matching the backend's refusal dialect in the captured stderr, so what it reads is the harness's own reading of its own sandbox), and it speaks only when the host is Windows, the stamped mode is `workspace-write`, and EVERY absolute path the command's own arguments name lies under the session's workspace — a denial anywhere else is the designed escalation path, and a command naming any outside path as well, or only relative ones, is refused rather than guessed at because the plugin cannot say which path was refused; the advisory prints the path it keyed on beside the root it tested it against, states that retrying is provably useless, gives the two-sided discriminator (reading and listing use the normal token while writing and deleting use the restricted one, so an object whose DACL names only Administrators/SYSTEM plus the capability SID looks granted to a check that merely greps for the SID), names the second measured variant of the same shape (coverage missing on the mandatory-integrity LABEL rather than on the DACL, separable outside a session only by the repository's own `diagnose-windows-sandbox-acl`), and states the Windows ceiling that closes the obvious repair (a recursive `icacls /grant` for a capability SID is refused with ERROR_NONE_MAPPED (1332) because that SID has no name to map) — while shipping NO repair command at all, for the reason the standing-grant section ships none: this project has no Windows host to verify a line on. An optional, off-by-default `enforceAfter` refuses an identical ACL call this plugin has watched fail, bounded by `maxDenials`; the blocking half is ACL-only by design. It never edits an ACL, never elevates, never sets another process's environment, and never changes a preset or a mode, and it complements repeat-guard-escalation, which keys on call identity rather than on the environment signature.",
4
- "version": "0.11.0",
3
+ "description": "Turns four sandbox environment failures that name neither their cause nor a remedy into a diagnosis with a path forward. Family 1, the Windows workspace ACL: twelve reports (#7538, #7622, #7646, #7720, #7750, #7735, #7771, #7804, #7816, #8232, #8272, #8275) of one signature — every sandboxed command fails before it runs with `SetNamedSecurityInfoW failed (Win32 5): grantWrite(<workspace>)`, because the merged DACL + mandatory-label write needs WRITE_OWNER on the directory (an object right the caller can self-grant), not SeSecurityPrivilege and not elevation; the host grant is materialized lazily and caches nothing on the failure path, so the same failure repeats per command. Two further reports (#8312, #8314) describe the other end of that same backend — what its grant leaves behind once it succeeds: three STANDING entries nothing revokes (the workspace capability SID, the world delete-child deny, and an INHERITABLE Low integrity label that lives in the SACL, so resetting the DACL does not take it off), which makes every program launched from a folder DSH has written to run at Low integrity, and — through the NTFS hard links a pnpm workspace is made of, where two names share one file object and therefore one security descriptor — can reach out of the tree onto a content-addressed store's shared objects, leaving every project that builds from that store with Low-integrity executables and failures that name the build tool rather than DSH; the advisory states all of it before handing over the command that applies that grant, and offers no removal command, because the maintainers' own diagnosis skill does not remove the label either and removing one needs WRITE_OWNER. Family 2, the persistent shell (#7638, #8322): with the `minimal` preset under a confining sandbox mode every shell call dies instantly with `PTY shell exited during startup` because the terminal backend cannot create the pseudo-console inside the sandbox, retrying never helps, and `minimal` mounts no fallback shell tool; #8322 separated the arms inside that mode with one runner and one ConPTY — a console-subsystem node.exe host starts the confined shell while the packaged desktop's GUI-subsystem Electron host kills it silently — so the advisory names the host alongside the mode, says the outcome is deterministic per (session mode × host) rather than intermittent, and adds the console-owning host the Web UI provides (#8313) to the user-side options. Family 3, a confined Windows child that died during native initialization (#7876, #7877): every command spawned through the sandbox runner can report exit 0xC0000142 STATUS_DLL_INIT_FAILED with the process never reaching its entry point — the packaged desktop starts that runner as [process.execPath, entry], and that host has been measured twice with one indistinguishable appearance from inside a session — either nothing on the runner path ran because the Electron binary launches as an application unless the child's environment carries ELECTRON_RUN_AS_NODE=1 (#7876), or the desktop launcher does set that variable and the child still dies because the restricted token is derived from the Electron process image (#8193), and an MSYS2 / Git-Bash program cannot create its signal pipe under the restricted token while cmd.exe and pwsh run fine in the same workspace under the same mode (#7877) — and because upstream's runner-failure rules admit only exit 127 with the `windows-acl-run: ` signature, the code is never an error: it arrives as the canonical value of a result the pipeline calls a success. The plugin observes the public `tools/post-execute` waterfall, classifies all four signatures narrowly (only the two `...NamedSecurityInfoW` operations; the PTY message matched on a whole line, never as a substring; the loader status read as a 32-bit integer out of the shell tool's own canonical success value, never from rendered text; the two value-read families advised only when the facts they need hold \u2014 a confining resolved mode for the native-init death, and a Windows host, a `workspace-write` stamped mode and an in-workspace path for the denial), and attaches ONE durable user-role advisory per agent per family through `additionalContexts`. The ACL advisory names the missing right, both environments the identical text can describe (an inherited Modify-only entry, a data volume where no ACE names the caller at all, and a directory owned by another account), the version boundary that arrived with the mandatory label (0.1.7-alpha.1, flag 20, versus the DACL-only flag 4 up to 0.1.6-alpha.x) together with why downgrading is not the remedy, the second boundary the later reports needed (the backend's own `diagnose-windows-sandbox-acl` skill is not part of the 0.1.7 line at all — it arrives with 0.2.0, measured on both published tarballs: 0.1.7-rc.2 names it zero times in either README, ships no assets, and carries no registration symbol anywhere in its tree, while 0.2.0-rc.2 ships assets/diagnose-windows-sandbox-acl/ and names it three times per README — so a reader who found the promise in a README was reading a 0.2.0-era document, and sending them to repair a files glob would be the wrong repair), and why a \"weaker grant\" is a mechanism the backend cannot express rather than a policy it declines (the label rides the SAME SetNamedSecurityInfoW as the grant — there is no DACL-only apply path to fall back to — and the confined token is itself lowered to Low, so the object's Low label is what lets the confined child write there at all; declining the label usefully means declining the token level with it), the discriminator, the remedy forked on an ownership check the user runs (`(Get-Acl \"<dir>\").Owner`), because one command cannot serve both rights situations: where the caller owns the directory, the unelevated `icacls ... :(OI)(CI)(WO)` is the whole of what is missing — the owner's implicit WRITE_DAC already covers the DACL half — and where the caller does not own it that same command is refused for want of WRITE_DAC, so the grant has to come from an elevated account, or by taking ownership first, or by moving the workspace under %USERPROFILE% — and the two remedies that look right and are not (`takeown`, `icacls /reset`), each with the reason it fails — and it states the two things about the failure's shape that the reports had to measure for themselves (#8232): that it belongs to the workspace rather than to the command (a command that only reads fails identically, so there is no harmless retry), and that the grant is scoped to the directory it names and its children, so a sibling workspace root on the same volume needs the line once more; the PTY advisory names the failing combination and the host binary that decides it, states the resolved mode and that the session's recorded mode is the one that counts, tells the model to stop rather than retry, and hands over the user-side options (a preset swap, a patch row, or the console-owning host of #8313) — it never names a shell tool the failing composition does not mount; the native-init advisory states the resolved mode, says the process died before its entry point, enumerates the two producers measured under a confining mode — naming both measured shapes of the desktop host rather than asserting the one that was measured first — with the check that separates them (what program the reader ran; whether this host is the packaged desktop binary, which the plugin measures and reports rather than assumes), carries the one conversion a model can make itself (rewrite the work as PowerShell or `cmd` when an MSYS2 program is what could not start), and — for the Electron host — names the fix #8193 measured rather than a wider mode: host the runner on a real node.exe (the desktop ships one under `resources/runtime/primary-runtime/dependencies/node/bin/node.exe`), where the same confined `pwsh`/`cmd` spawns succeed, while `danger-full-access` is described as a way to confirm the diagnosis and not a fix, together with the warning that unsetting `ELECTRON_RUN_AS_NODE` instead would leave the desktop's Electron-hosted runner unable to execute `runner.js` at all (the interaction #8193 records with #8174), and says plainly which producers it does not know — it never claims the sandbox caused the failure and never offers a widened mode as a fix. It also states the single rule the whole family follows from, because a reader without it reaches for the wrong flag: in a restricted token a console can be INHERITED but not CREATED, so a creation flag that forces the child to make one of its own (`CREATE_NO_WINDOW`, `CREATE_NEW_CONSOLE`) is fatal on its own, while `DETACHED_PROCESS` — which declines a console rather than creating one — is not; #8336 measured that matrix on one machine, including the pair that makes it a rule rather than a list (the same flag on an UNRESTRICTED token is harmless, as is `STARTF_USESHOWWINDOW` with `SW_HIDE`), and the advisory answers the `windowsHide` suspicion instead of ignoring it: that flag is not set anywhere on the confined path — it appears on the ORDINARY subprocess path (`dsh-subprocess-local`'s spawn, which starts the runner rather than the confined child), and the restricted spawn defines no `CREATE_NO_WINDOW` constant at all — and where it IS set, #8208 measured it both ways on a host that works, because a windowless console is still a console: what decides is whether the host owns a console OBJECT, not whether it owns a window (#8336, #8334). Family 4, a confined command DENIED a path inside its own workspace (#423): the workspace grant is applied once, on the root, and relies on Windows ACE inheritance to reach the tree beneath it, so an object that already existed (created by an installer, an editor, another harness under its own account) whose DACL the caller could not write kept its older DACL — silently, because a skipped inherited ACE produces no error, no return value and no log line — after which the backend's root-only check (`hasExactGrant(workspaceRoot)`) short-circuits and those descendants are NEVER revisited, so the identical command keeps failing while a directory the harness itself created works; the family is read from the executors' own structured stamp on a successful result (`sandbox: { mode, denied, enforcement? }`, produced by matching the backend's refusal dialect in the captured stderr, so what it reads is the harness's own reading of its own sandbox), and it speaks only when the host is Windows, the stamped mode is `workspace-write`, and EVERY absolute path the command's own arguments name lies under the session's workspace — a denial anywhere else is the designed escalation path, and a command naming any outside path as well, or only relative ones, is refused rather than guessed at because the plugin cannot say which path was refused; the advisory prints the path it keyed on beside the root it tested it against, states that retrying is provably useless, gives the two-sided discriminator (reading and listing use the normal token while writing and deleting use the restricted one, so an object whose DACL names only Administrators/SYSTEM plus the capability SID looks granted to a check that merely greps for the SID), names the second measured variant of the same shape (coverage missing on the mandatory-integrity LABEL rather than on the DACL, separable outside a session only by the repository's own `diagnose-windows-sandbox-acl`), and states the Windows ceiling that closes the obvious repair (a recursive `icacls /grant` for a capability SID is refused with ERROR_NONE_MAPPED (1332) because that SID has no name to map) — while shipping NO repair command at all, for the reason the standing-grant section ships none: this project has no Windows host to verify a line on. An optional, off-by-default `enforceAfter` refuses an identical ACL call this plugin has watched fail, bounded by `maxDenials`; the blocking half is ACL-only by design. It never edits an ACL, never elevates, never sets another process's environment, and never changes a preset or a mode, and it complements repeat-guard-escalation, which keys on call identity rather than on the environment signature.",
4
+ "version": "0.12.0",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",
7
7
  "types": "lib/types/index.d.ts",