@argszero/cordis-plugin-sandbox-grant-advisor 0.4.0 → 0.5.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 +49 -5
- package/lib/advice.js +53 -11
- package/lib/signature.js +26 -11
- package/lib/types/advice.d.ts +19 -1
- package/lib/types/signature.d.ts +34 -15
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -113,18 +113,56 @@ confines deletes to the workspace, and reverting it reintroduces the escape it c
|
|
|
113
113
|
Confirm the cause (unelevated) — `icacls` is a normal user command:
|
|
114
114
|
icacls "D:\ws"
|
|
115
115
|
|
|
116
|
-
|
|
116
|
+
Ownership decides which of the two commands below can work, so read it first — PowerShell 5.1 or later:
|
|
117
|
+
(Get-Acl "D:\ws").Owner # compare with: whoami
|
|
118
|
+
|
|
119
|
+
IF YOU OWN THE DIRECTORY — the usual workspace, on a data volume as much as on C::
|
|
120
|
+
one unelevated line, then run the command again:
|
|
117
121
|
PowerShell: icacls "D:\ws" /grant "$env:USERNAME:(OI)(CI)(WO)"
|
|
118
122
|
cmd: icacls "D:\ws" /grant "%USERNAME%:(OI)(CI)(WO)"
|
|
119
|
-
|
|
120
|
-
|
|
123
|
+
... Full control works just as well — the same line with `F` in place of `(WO)`
|
|
124
|
+
|
|
125
|
+
IF YOU DO NOT OWN IT — a directory an installer or another account created, e.g. owner
|
|
126
|
+
`BUILTIN\Administrators`:
|
|
127
|
+
the line above cannot run at all. Changing a DACL takes WRITE_DAC, which you hold neither as owner nor
|
|
128
|
+
through any ACE, so `icacls /grant` is refused with `Access is denied` — for the very command that would
|
|
129
|
+
fix it. ... Run the grant once from an account that already holds both — that is, from an ELEVATED prompt:
|
|
130
|
+
icacls "D:\ws" /grant "<your-account>:(OI)(CI)F"
|
|
131
|
+
... or take ownership first (also elevated; it wants SeTakeOwnership), after which the unelevated `(WO)`
|
|
132
|
+
line above applies: icacls "D:\ws" /setowner "<your-account>"
|
|
133
|
+
... or sidestep the ACL: create the workspace under `%USERPROFILE%`.
|
|
134
|
+
|
|
135
|
+
What will NOT fix it on its own — both look like the right move, and both were tried and reported:
|
|
121
136
|
takeown /F "D:\ws" /R /D Y
|
|
122
|
-
makes you the owner,
|
|
123
|
-
|
|
137
|
+
makes you the owner, and ownership's implicit rights are READ_CONTROL and WRITE_DAC only — so it
|
|
138
|
+
supplies the DACL half and still not WRITE_OWNER, the right this call needs.
|
|
124
139
|
icacls "D:\ws" /reset /T /C
|
|
125
140
|
restores inheritance, and inheritance is what supplied the Modify-only ACE above.
|
|
126
141
|
```
|
|
127
142
|
|
|
143
|
+
**Why the remedy forks** (added in 0.5.0). The same error covers two different
|
|
144
|
+
rights situations, and one command cannot serve both. Where the caller **owns**
|
|
145
|
+
the directory, the owner's implicit `WRITE_DAC` satisfies the DACL half of the
|
|
146
|
+
merged write, `WRITE_OWNER` is the single missing right, and the unelevated
|
|
147
|
+
`icacls /grant` that supplies it can itself run — [#7750] measured exactly that
|
|
148
|
+
fix working. Where the caller **does not own** it ([#7771]: owner
|
|
149
|
+
`BUILTIN\Administrators`, held deny-only for that token), `WRITE_DAC` is missing
|
|
150
|
+
too, so the very same command is refused before it does anything, and `(WO)`
|
|
151
|
+
alone would not be enough even if it went through. The failure text is identical
|
|
152
|
+
in both, so the classifier cannot pick a branch — the advisory hands over the
|
|
153
|
+
**ownership check** as the selector instead of guessing, which is also the
|
|
154
|
+
actionable-guidance half of what [#7771] asked for. Until 0.5.0 a single
|
|
155
|
+
unconditional one-liner was printed, with a sentence noting it assumed
|
|
156
|
+
ownership; that would have sent the second environment to a command that is
|
|
157
|
+
denied — the same defect this plugin exists to answer.
|
|
158
|
+
|
|
159
|
+
**What is deliberately *not* shipped**: `icacls ... /grant "<user>:(OI)(CI)(WD,WO)"`,
|
|
160
|
+
the two needed rights named explicitly. It is the tighter form and it is
|
|
161
|
+
plausibly correct syntax, but this project has no Windows host to run it on, and
|
|
162
|
+
shipping an unverified command in a remedy whose whole point is that it works is
|
|
163
|
+
the failure mode being fixed. `F` (verified by [#7804]'s reporter) and
|
|
164
|
+
`/setowner` (named by both reports) are given instead.
|
|
165
|
+
|
|
128
166
|
### 2. Persistent shell startup (`pty-startup`)
|
|
129
167
|
|
|
130
168
|
[Discussion #7638] reports the second shape: with the **`minimal` preset** on
|
|
@@ -399,4 +437,10 @@ the current runtime cannot distinguish rather than counting it as a pass.
|
|
|
399
437
|
[discussion #7720]: https://github.com/deepseek-ai/deepseek-harness/discussions/7720
|
|
400
438
|
[discussion #7750]: https://github.com/deepseek-ai/deepseek-harness/discussions/7750
|
|
401
439
|
[discussion #7735]: https://github.com/deepseek-ai/deepseek-harness/discussions/7735
|
|
440
|
+
[discussion #7771]: https://github.com/deepseek-ai/deepseek-harness/discussions/7771
|
|
441
|
+
[discussion #7804]: https://github.com/deepseek-ai/deepseek-harness/discussions/7804
|
|
442
|
+
[discussion #7816]: https://github.com/deepseek-ai/deepseek-harness/discussions/7816
|
|
443
|
+
[#7750]: https://github.com/deepseek-ai/deepseek-harness/discussions/7750
|
|
444
|
+
[#7771]: https://github.com/deepseek-ai/deepseek-harness/discussions/7771
|
|
445
|
+
[#7804]: https://github.com/deepseek-ai/deepseek-harness/discussions/7804
|
|
402
446
|
[discussion #7638]: https://github.com/deepseek-ai/deepseek-harness/discussions/7638
|
package/lib/advice.js
CHANGED
|
@@ -20,6 +20,24 @@
|
|
|
20
20
|
* separates "this is the label failure" from "this is something else", and
|
|
21
21
|
* because rolling back is the reach it invites while making the very problem
|
|
22
22
|
* it closed come back.
|
|
23
|
+
*
|
|
24
|
+
* **The remedy is forked on ownership, because one command cannot serve both
|
|
25
|
+
* environments.** The reports split into two rights situations behind an
|
|
26
|
+
* identical error: a workspace **the caller owns** (`#7622`, `#7646`, `#7720`,
|
|
27
|
+
* `#7750`, `#7804`), where the owner's implicit `WRITE_DAC` satisfies the DACL
|
|
28
|
+
* half and `(WO)` is the whole of what is missing — so the `icacls /grant`
|
|
29
|
+
* that supplies it *can itself run*, unelevated; and a directory **the caller
|
|
30
|
+
* does not own** (`#7771`: owner `BUILTIN\Administrators`, held deny-only for
|
|
31
|
+
* their token), where `WRITE_DAC` is missing too, so `icacls /grant` is denied
|
|
32
|
+
* for the very command that would fix it, and `(WO)` alone would not be enough
|
|
33
|
+
* even if it went through. The classifier cannot tell these apart — the text is
|
|
34
|
+
* identical — so the advisory does what it can do instead of guessing: it hands
|
|
35
|
+
* over the **ownership check** (`(Get-Acl "<dir>").Owner`) as the branch
|
|
36
|
+
* selector, then gives each branch the command that actually works there, and
|
|
37
|
+
* says why the other branch's command is not a fallback. A single unconditional
|
|
38
|
+
* one-liner would send the second environment to a command that is refused
|
|
39
|
+
* before it runs — the same defect this module exists to answer, a remedy that
|
|
40
|
+
* does not work delivered confidently.
|
|
23
41
|
* - **The persistent-shell failure** (`pty-startup`) is *not* fixable by the
|
|
24
42
|
* caller — least of all by the model, which has no shell to run anything in.
|
|
25
43
|
* So its advice says so and stops: the remedy is a user-side preset choice,
|
|
@@ -40,7 +58,7 @@
|
|
|
40
58
|
*/
|
|
41
59
|
import { failureLine } from './signature.js';
|
|
42
60
|
/** The upstream threads the ACL advisory is a stopgap for. */
|
|
43
|
-
export const ACL_DISCUSSIONS = '#7538 / #7622 / #7646 / #7720 / #7750 / #7735';
|
|
61
|
+
export const ACL_DISCUSSIONS = '#7538 / #7622 / #7646 / #7720 / #7750 / #7735 / #7771 / #7804 / #7816';
|
|
44
62
|
/** The upstream thread the persistent-shell advisory is a stopgap for. */
|
|
45
63
|
export const PTY_DISCUSSIONS = '#7638';
|
|
46
64
|
/** The documented prerequisite, quoted from the backend's README. */
|
|
@@ -111,7 +129,7 @@ function diagnosis(failure) {
|
|
|
111
129
|
return [
|
|
112
130
|
'Why it is refused: this is the same merged write, but the Win32 code is not ERROR_ACCESS_DENIED (5), so',
|
|
113
131
|
'the missing-rights story above does not apply verbatim — a missing path, a non-directory target, or a',
|
|
114
|
-
'filesystem that does not carry ACLs are all possibilities. The
|
|
132
|
+
'filesystem that does not carry ACLs are all possibilities. The commands below are safe to try; if the',
|
|
115
133
|
'code persists, it is a different failure and worth reporting with the code.',
|
|
116
134
|
].join('\n');
|
|
117
135
|
}
|
|
@@ -129,7 +147,11 @@ function diagnosis(failure) {
|
|
|
129
147
|
* diagnosis.
|
|
130
148
|
*
|
|
131
149
|
* A negative claim still has to be earned: the failure to avoid is advice that
|
|
132
|
-
* is confidently wrong in the other direction.
|
|
150
|
+
* is confidently wrong in the other direction. That is why the `takeown` line
|
|
151
|
+
* claims only what is true in **both** ownership branches: it supplies the DACL
|
|
152
|
+
* half and never `WRITE_OWNER`, so it is not the fix by itself — while still
|
|
153
|
+
* being a legitimate first step (with elevation) where the caller is not the
|
|
154
|
+
* owner. Calling it useless outright would have been the mirror-image error.
|
|
133
155
|
* @param failure - the recognized provisioning failure.
|
|
134
156
|
* @param path - the directory the error named, or the placeholder.
|
|
135
157
|
* @returns the section's lines, or an empty array for a class it does not fit.
|
|
@@ -138,10 +160,11 @@ function nonFixes(failure, path) {
|
|
|
138
160
|
if (failure.klass !== 'apply-denied')
|
|
139
161
|
return [];
|
|
140
162
|
return [
|
|
141
|
-
'What will NOT fix it — both look like the right move, and both were tried and reported:',
|
|
163
|
+
'What will NOT fix it on its own — both look like the right move, and both were tried and reported:',
|
|
142
164
|
` takeown /F "${path}" /R /D Y`,
|
|
143
|
-
" makes you the owner,
|
|
144
|
-
'
|
|
165
|
+
" makes you the owner, and ownership's implicit rights are READ_CONTROL and WRITE_DAC only — so it",
|
|
166
|
+
' supplies the DACL half and still not WRITE_OWNER, the right this call needs. In the second branch above',
|
|
167
|
+
' it is a legitimate first step with elevation; it is never the fix by itself.',
|
|
145
168
|
` icacls "${path}" /reset /T /C`,
|
|
146
169
|
' restores inheritance, and inheritance is what supplied the Modify-only ACE above.',
|
|
147
170
|
'',
|
|
@@ -214,17 +237,36 @@ function aclAdvisory(failure, href) {
|
|
|
214
237
|
'(WO) / Write owner. If the strongest entry naming you is (M) / Modify — or no entry names you at all and',
|
|
215
238
|
'your access comes from an inherited `Authenticated Users:(M)` — that is this failure.',
|
|
216
239
|
'',
|
|
217
|
-
'
|
|
240
|
+
'Ownership decides which of the two commands below can work, so read it first — PowerShell 5.1 or later:',
|
|
241
|
+
` (Get-Acl "${path}").Owner # compare with: whoami`,
|
|
242
|
+
'If that is not your own account, take the second branch: the first one is refused before it runs.',
|
|
243
|
+
'',
|
|
244
|
+
'IF YOU OWN THE DIRECTORY — the usual workspace, whether on the system drive or a data volume:',
|
|
245
|
+
' one unelevated line, then run the command again:',
|
|
218
246
|
` PowerShell: icacls "${path}" /grant "$env:USERNAME:(OI)(CI)(WO)"`,
|
|
219
247
|
` cmd: icacls "${path}" /grant "%USERNAME%:(OI)(CI)(WO)"`,
|
|
220
248
|
'WRITE_OWNER is exactly the right the prerequisite names, so this grants nothing the harness did not ask for,',
|
|
221
249
|
'and (OI)(CI) makes the ACE inheritable, so one command reaches the workspace\'s existing subdirectories.',
|
|
222
250
|
'Full control works just as well — the same line with `F` in place of `(WO)`:',
|
|
223
251
|
` icacls "${path}" /grant "$env:USERNAME:(OI)(CI)F"`,
|
|
224
|
-
'
|
|
225
|
-
'
|
|
226
|
-
'
|
|
227
|
-
'
|
|
252
|
+
'Why `(WO)` is the whole of what is missing there: an owner holds READ_CONTROL and WRITE_DAC implicitly,',
|
|
253
|
+
'and WRITE_DAC is what `icacls /grant` itself needs — so the DACL half of the merged write already has what',
|
|
254
|
+
'it wants, and WRITE_OWNER is the single missing piece.',
|
|
255
|
+
'',
|
|
256
|
+
'IF YOU DO NOT OWN IT — a directory an installer or another account created, e.g. owner',
|
|
257
|
+
'`BUILTIN\\Administrators`:',
|
|
258
|
+
' the line above cannot run at all. Changing a DACL takes WRITE_DAC, which you hold neither as owner nor',
|
|
259
|
+
' through any ACE, so `icacls /grant` is refused with `Access is denied` — for the very command that would',
|
|
260
|
+
' fix it. The merged write wants WRITE_DAC and WRITE_OWNER together, so `(WO)` alone would not be enough',
|
|
261
|
+
' here even if it went through. Run the grant once from an account that already holds both — that is, from an',
|
|
262
|
+
' ELEVATED prompt:',
|
|
263
|
+
` icacls "${path}" /grant "<your-account>:(OI)(CI)F"`,
|
|
264
|
+
'Full control is used because it is the rights set covering both halves; the other reach both reports name is',
|
|
265
|
+
'to take ownership first, which also needs elevation (it wants SeTakeOwnership), after which the unelevated',
|
|
266
|
+
'`(WO)` line above applies:',
|
|
267
|
+
` icacls "${path}" /setowner "<your-account>"`,
|
|
268
|
+
'Or sidestep the ACL entirely: create the workspace under `%USERPROFILE%` — a directory created there',
|
|
269
|
+
'inherits Full control for you — and open the session on that one.',
|
|
228
270
|
'',
|
|
229
271
|
...nonFixes(failure, path),
|
|
230
272
|
'How to read this: the harness documents the prerequisite (' + PREREQUISITE + ') and this',
|
package/lib/signature.js
CHANGED
|
@@ -30,17 +30,32 @@
|
|
|
30
30
|
* the advisory can quote the exact line the model and the user are looking
|
|
31
31
|
* at, and the path can be re-used in the fix command.
|
|
32
32
|
*
|
|
33
|
-
* One signature covers
|
|
34
|
-
* the classifier cannot and must not try to tell them apart
|
|
35
|
-
*
|
|
36
|
-
* the
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
33
|
+
* One signature covers three environments, the text is identical in all of them,
|
|
34
|
+
* and the classifier cannot and must not try to tell them apart — but the
|
|
35
|
+
* *remedy* is not the same in all of them, which is why the advisory forks on a
|
|
36
|
+
* check the user runs rather than on a guess this module cannot make:
|
|
37
|
+
*
|
|
38
|
+
* - a workspace the caller created with `mkdir` that inherits "Authenticated
|
|
39
|
+
* Users: Modify" from the drive root (`#7622`, `#7646`, `#7720`);
|
|
40
|
+
* - a directory on a data volume where **no ACE names the caller at all**, so
|
|
41
|
+
* the inherited entry is the whole of their access (`#7750` on D:/E:,
|
|
42
|
+
* `#7735`'s second defect);
|
|
43
|
+
* - a directory **the caller does not own** — an installer- or
|
|
44
|
+
* administrator-created one, `#7771` (owner `BUILTIN\Administrators`, held
|
|
45
|
+
* deny-only for that token), which `#7804` reached from the other direction.
|
|
46
|
+
*
|
|
47
|
+
* In the first two the caller is the owner, so their implicit `WRITE_DAC`
|
|
48
|
+
* satisfies the DACL half and `WRITE_OWNER` is the single missing right — one
|
|
49
|
+
* unelevated `icacls /grant` supplies exactly it, and `#7750` measured that
|
|
50
|
+
* remedy working. In the third `WRITE_DAC` is missing as well, so that same
|
|
51
|
+
* `icacls` is refused for the very command that would fix it and `(WO)` alone
|
|
52
|
+
* would not be enough even if it went through. The advisory therefore hands over
|
|
53
|
+
* the ownership check (`(Get-Acl "<dir>").Owner`) as the branch selector and
|
|
54
|
+
* gives each branch the command that works there — the same class, two rights
|
|
55
|
+
* situations, and no guess about which one this is.
|
|
56
|
+
*
|
|
57
|
+
* What the text *does* carry that the failure does not is the version boundary:
|
|
58
|
+
* the merged DACL + label write exists only from `0.1.7-alpha.1` on
|
|
44
59
|
* (`packages/sandbox/sandbox-windows-acl/src/acl.ts`, flag
|
|
45
60
|
* `DACL_SECURITY_INFORMATION | LABEL_SECURITY_INFORMATION`), so on an older line
|
|
46
61
|
* the same string belongs to a different cause space.
|
package/lib/types/advice.d.ts
CHANGED
|
@@ -20,6 +20,24 @@
|
|
|
20
20
|
* separates "this is the label failure" from "this is something else", and
|
|
21
21
|
* because rolling back is the reach it invites while making the very problem
|
|
22
22
|
* it closed come back.
|
|
23
|
+
*
|
|
24
|
+
* **The remedy is forked on ownership, because one command cannot serve both
|
|
25
|
+
* environments.** The reports split into two rights situations behind an
|
|
26
|
+
* identical error: a workspace **the caller owns** (`#7622`, `#7646`, `#7720`,
|
|
27
|
+
* `#7750`, `#7804`), where the owner's implicit `WRITE_DAC` satisfies the DACL
|
|
28
|
+
* half and `(WO)` is the whole of what is missing — so the `icacls /grant`
|
|
29
|
+
* that supplies it *can itself run*, unelevated; and a directory **the caller
|
|
30
|
+
* does not own** (`#7771`: owner `BUILTIN\Administrators`, held deny-only for
|
|
31
|
+
* their token), where `WRITE_DAC` is missing too, so `icacls /grant` is denied
|
|
32
|
+
* for the very command that would fix it, and `(WO)` alone would not be enough
|
|
33
|
+
* even if it went through. The classifier cannot tell these apart — the text is
|
|
34
|
+
* identical — so the advisory does what it can do instead of guessing: it hands
|
|
35
|
+
* over the **ownership check** (`(Get-Acl "<dir>").Owner`) as the branch
|
|
36
|
+
* selector, then gives each branch the command that actually works there, and
|
|
37
|
+
* says why the other branch's command is not a fallback. A single unconditional
|
|
38
|
+
* one-liner would send the second environment to a command that is refused
|
|
39
|
+
* before it runs — the same defect this module exists to answer, a remedy that
|
|
40
|
+
* does not work delivered confidently.
|
|
23
41
|
* - **The persistent-shell failure** (`pty-startup`) is *not* fixable by the
|
|
24
42
|
* caller — least of all by the model, which has no shell to run anything in.
|
|
25
43
|
* So its advice says so and stops: the remedy is a user-side preset choice,
|
|
@@ -41,7 +59,7 @@
|
|
|
41
59
|
import type { ProvisioningFailure, RecognizedFailure } from './signature.js';
|
|
42
60
|
import type { SandboxModeName } from './mode.js';
|
|
43
61
|
/** The upstream threads the ACL advisory is a stopgap for. */
|
|
44
|
-
export declare const ACL_DISCUSSIONS = "#7538 / #7622 / #7646 / #7720 / #7750 / #7735";
|
|
62
|
+
export declare const ACL_DISCUSSIONS = "#7538 / #7622 / #7646 / #7720 / #7750 / #7735 / #7771 / #7804 / #7816";
|
|
45
63
|
/** The upstream thread the persistent-shell advisory is a stopgap for. */
|
|
46
64
|
export declare const PTY_DISCUSSIONS = "#7638";
|
|
47
65
|
/** The documented prerequisite, quoted from the backend's README. */
|
package/lib/types/signature.d.ts
CHANGED
|
@@ -30,17 +30,32 @@
|
|
|
30
30
|
* the advisory can quote the exact line the model and the user are looking
|
|
31
31
|
* at, and the path can be re-used in the fix command.
|
|
32
32
|
*
|
|
33
|
-
* One signature covers
|
|
34
|
-
* the classifier cannot and must not try to tell them apart
|
|
35
|
-
*
|
|
36
|
-
* the
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
33
|
+
* One signature covers three environments, the text is identical in all of them,
|
|
34
|
+
* and the classifier cannot and must not try to tell them apart — but the
|
|
35
|
+
* *remedy* is not the same in all of them, which is why the advisory forks on a
|
|
36
|
+
* check the user runs rather than on a guess this module cannot make:
|
|
37
|
+
*
|
|
38
|
+
* - a workspace the caller created with `mkdir` that inherits "Authenticated
|
|
39
|
+
* Users: Modify" from the drive root (`#7622`, `#7646`, `#7720`);
|
|
40
|
+
* - a directory on a data volume where **no ACE names the caller at all**, so
|
|
41
|
+
* the inherited entry is the whole of their access (`#7750` on D:/E:,
|
|
42
|
+
* `#7735`'s second defect);
|
|
43
|
+
* - a directory **the caller does not own** — an installer- or
|
|
44
|
+
* administrator-created one, `#7771` (owner `BUILTIN\Administrators`, held
|
|
45
|
+
* deny-only for that token), which `#7804` reached from the other direction.
|
|
46
|
+
*
|
|
47
|
+
* In the first two the caller is the owner, so their implicit `WRITE_DAC`
|
|
48
|
+
* satisfies the DACL half and `WRITE_OWNER` is the single missing right — one
|
|
49
|
+
* unelevated `icacls /grant` supplies exactly it, and `#7750` measured that
|
|
50
|
+
* remedy working. In the third `WRITE_DAC` is missing as well, so that same
|
|
51
|
+
* `icacls` is refused for the very command that would fix it and `(WO)` alone
|
|
52
|
+
* would not be enough even if it went through. The advisory therefore hands over
|
|
53
|
+
* the ownership check (`(Get-Acl "<dir>").Owner`) as the branch selector and
|
|
54
|
+
* gives each branch the command that works there — the same class, two rights
|
|
55
|
+
* situations, and no guess about which one this is.
|
|
56
|
+
*
|
|
57
|
+
* What the text *does* carry that the failure does not is the version boundary:
|
|
58
|
+
* the merged DACL + label write exists only from `0.1.7-alpha.1` on
|
|
44
59
|
* (`packages/sandbox/sandbox-windows-acl/src/acl.ts`, flag
|
|
45
60
|
* `DACL_SECURITY_INFORMATION | LABEL_SECURITY_INFORMATION`), so on an older line
|
|
46
61
|
* the same string belongs to a different cause space.
|
|
@@ -73,10 +88,14 @@
|
|
|
73
88
|
export type FailureClass =
|
|
74
89
|
/**
|
|
75
90
|
* `SetNamedSecurityInfoW` returned `ERROR_ACCESS_DENIED` (5): the merged
|
|
76
|
-
* DACL + label write was refused.
|
|
77
|
-
* here — the `mkdir`-inherited Modify workspace
|
|
78
|
-
* with no ACE naming the caller
|
|
79
|
-
*
|
|
91
|
+
* DACL + label write was refused. All three environments in the module doc
|
|
92
|
+
* land here — the `mkdir`-inherited Modify workspace, the data-volume
|
|
93
|
+
* directory with no ACE naming the caller, and the directory owned by another
|
|
94
|
+
* account — because the failure text cannot separate them. The first two are
|
|
95
|
+
* the same rights situation (the caller owns it; `WRITE_OWNER` is the whole of
|
|
96
|
+
* what is missing) and share the unelevated remedy; the third is missing
|
|
97
|
+
* `WRITE_DAC` as well, which is why the advisory hands over the ownership
|
|
98
|
+
* check and forks the command on it.
|
|
80
99
|
*/
|
|
81
100
|
'apply-denied'
|
|
82
101
|
/** `SetNamedSecurityInfoW` failed with a Win32 code other than `ERROR_ACCESS_DENIED`. */
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@argszero/cordis-plugin-sandbox-grant-advisor",
|
|
3
|
-
"description": "Turns two sandbox environment failures that name neither their cause nor a remedy into a diagnosis with a path forward. Family 1, the Windows workspace ACL:
|
|
4
|
-
"version": "0.
|
|
3
|
+
"description": "Turns two sandbox environment failures that name neither their cause nor a remedy into a diagnosis with a path forward. Family 1, the Windows workspace ACL: nine reports (#7538, #7622, #7646, #7720, #7750, #7735, #7771, #7804, #7816) 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. Family 2, the persistent shell (#7638): 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. The plugin observes the public `tools/post-execute` waterfall, classifies both signatures narrowly (only the two `...NamedSecurityInfoW` operations; the PTY message matched on a whole line, never as a substring, and only under a mode the policy resolver reports as confining), 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 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; the PTY advisory names the failing combination, states the resolved mode, tells the model to stop rather than retry, and hands the user-side preset choice over — it never names a shell tool the failing composition does not mount. 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, 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.5.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.js",
|
|
7
7
|
"types": "lib/types/index.d.ts",
|