@@ -19,6 +19,8 @@ type MockAllowAlwaysPersistenceInput = Parameters<
1919type MockAllowAlwaysPersistenceDecision =
2020 import ( "../infra/exec-approvals.js" ) . AllowAlwaysPersistenceDecision ;
2121type MockExecApprovalDecision = import ( "../infra/exec-approvals.js" ) . ExecApprovalDecision ;
22+ type MockExecApprovalUnavailableDecision =
23+ import ( "../infra/exec-approvals.js" ) . ExecApprovalUnavailableDecision ;
2224type MockAllowlistSegment = {
2325 raw ?: string ;
2426 resolution : null ;
@@ -151,6 +153,17 @@ const resolveExecApprovalAllowedDecisionsMock = vi.hoisted(() =>
151153 : [ "allow-once" , "allow-always" , "deny" ] ,
152154 ) ,
153155) ;
156+ const resolveExecApprovalUnavailableDecisionsMock = vi . hoisted ( ( ) =>
157+ vi . fn (
158+ ( params ?: {
159+ ask ?: string | null ;
160+ allowAlwaysPersistence ?: { kind : string } | null ;
161+ } ) : readonly MockExecApprovalUnavailableDecision [ ] =>
162+ params ?. ask === "always" || params ?. allowAlwaysPersistence ?. kind === "one-shot"
163+ ? [ "allow-always" ]
164+ : [ ] ,
165+ ) ,
166+ ) ;
154167const resolveExecHostApprovalContextMock = vi . hoisted ( ( ) =>
155168 vi . fn ( ( ) => ( {
156169 approvals : { allowlist : [ ] as ExecAllowlistEntry [ ] , file : { version : 1 , agents : { } } } ,
@@ -209,6 +222,7 @@ vi.mock("../infra/exec-approvals.js", () => ({
209222 resolveAllowAlwaysPersistenceDecision : resolveAllowAlwaysPersistenceDecisionMock ,
210223 resolveAllowAlwaysPatternCoverage : resolveAllowAlwaysPatternCoverageMock ,
211224 resolveExecApprovalAllowedDecisions : resolveExecApprovalAllowedDecisionsMock ,
225+ resolveExecApprovalUnavailableDecisions : resolveExecApprovalUnavailableDecisionsMock ,
212226 resolveExecApprovalsFromFile : resolveExecApprovalsFromFileMock ,
213227 maxAsk : ( a : ExecAsk , b : ExecAsk ) : ExecAsk => {
214228 const order : Record < ExecAsk , number > = { off : 0 , "on-miss" : 1 , always : 2 } ;
@@ -494,6 +508,7 @@ describe("executeNodeHostCommand", () => {
494508 patterns : [ { pattern : "/trusted/bin/tool" } ] ,
495509 } ) ;
496510 resolveExecApprovalAllowedDecisionsMock . mockClear ( ) ;
511+ resolveExecApprovalUnavailableDecisionsMock . mockClear ( ) ;
497512 resolveExecHostApprovalContextMock . mockReset ( ) ;
498513 resolveExecHostApprovalContextMock . mockReturnValue ( {
499514 approvals : { allowlist : [ ] , file : { version : 1 , agents : { } } } ,
@@ -1749,7 +1764,7 @@ describe("executeNodeHostCommand", () => {
17491764 patterns : [ { pattern : "/trusted/bin/tool" } ] ,
17501765 } ,
17511766 } ) ;
1752- expect ( requireRegisteredApprovalRequest ( ) . allowedDecisions ) . toEqual ( [ "allow-once" , "deny "] ) ;
1767+ expect ( requireRegisteredApprovalRequest ( ) . unavailableDecisions ) . toEqual ( [ "allow-always " ] ) ;
17531768 expect ( buildExecApprovalPendingToolResultMock ) . toHaveBeenCalledWith (
17541769 expect . objectContaining ( {
17551770 allowedDecisions : [ "allow-once" , "deny" ] ,
@@ -1798,7 +1813,7 @@ describe("executeNodeHostCommand", () => {
17981813 patterns : [ { pattern : "/trusted/bin/tool" } ] ,
17991814 } ,
18001815 } ) ;
1801- expect ( requireRegisteredApprovalRequest ( ) . allowedDecisions ) . toEqual ( [ "allow-once" , "deny "] ) ;
1816+ expect ( requireRegisteredApprovalRequest ( ) . unavailableDecisions ) . toEqual ( [ "allow-always " ] ) ;
18021817 } ) ;
18031818
18041819 it ( "offers allow-always for prepared node commands with complete node coverage" , async ( ) => {
@@ -1870,11 +1885,7 @@ describe("executeNodeHostCommand", () => {
18701885 patterns : [ { pattern : "/node/bin/git" } ] ,
18711886 } ,
18721887 } ) ;
1873- expect ( requireRegisteredApprovalRequest ( ) . allowedDecisions ) . toEqual ( [
1874- "allow-once" ,
1875- "allow-always" ,
1876- "deny" ,
1877- ] ) ;
1888+ expect ( requireRegisteredApprovalRequest ( ) . unavailableDecisions ) . toBeUndefined ( ) ;
18781889 } ) ;
18791890
18801891 it ( "does not use fallback-full when node auto-review cannot parse the command" , async ( ) => {
@@ -2209,7 +2220,7 @@ describe("executeNodeHostCommand", () => {
22092220 ask : "on-miss" ,
22102221 allowAlwaysPersistence : { kind : "one-shot" , reasons : [ "unplanned" ] } ,
22112222 } ) ;
2212- expect ( requireRegisteredApprovalRequest ( ) . allowedDecisions ) . toEqual ( [ "allow-once" , "deny "] ) ;
2223+ expect ( requireRegisteredApprovalRequest ( ) . unavailableDecisions ) . toEqual ( [ "allow-always " ] ) ;
22132224 expect ( buildExecApprovalPendingToolResultMock ) . toHaveBeenCalledWith (
22142225 expect . objectContaining ( {
22152226 allowedDecisions : [ "allow-once" , "deny" ] ,
0 commit comments