@@ -20,6 +20,7 @@ import { join, resolve } from "node:path";
2020import { performMacOSUpdateCommand , trustedMacOSUpdateSource , type MacOSUpdateHelperIo } from "../src/cli/macos-update" ;
2121import { MacosUpdateTransactionStore , assertMacosUpdateAllowsMutation , type MacosUpdateSemanticSnapshot } from "../src/server/macos-update-transaction" ;
2222import { acquireProxyLifecycleAuthority } from "../src/server/proxy-lifecycle-authority" ;
23+ // Store-backed macOS fixtures require POSIX permissions and durable directory fsync.
2324const temporary : string [ ] = [ ] ;
2425afterEach ( ( ) => { for ( const root of temporary . splice ( 0 ) ) rmSync ( root , { recursive :true , force :true } ) ; } ) ;
2526const id = "c94b8309-5c96-41f1-8dd1-fd57aeab8913" ;
@@ -37,14 +38,14 @@ function fixture(snapshot: Partial<MacosUpdateSemanticSnapshot> = {}) {
3738 return { io, store, resumed, get stopped ( ) { return stopped ; } , replace ( ) { source = { ...source , build :"101" , fingerprint :"replacement" } ; } , setIntent ( ) { fingerprint = "external-edit" ; } , setActive ( n :number ) { active = n ; } , failVerify ( ) { verified = false ; } , failResume ( ) { resumeSucceeds = false ; } , allowResume ( ) { resumeSucceeds = true ; } } ;
3839}
3940const prepare = { action :"prepare" as const , transactionId :id , targetBuild :"101" } ;
40- test ( "active prepare immediately returns confirmation; cancel preserves the live runtime" , async ( ) => {
41+ test . skipIf ( process . platform === "win32" ) ( "active prepare immediately returns confirmation; cancel preserves the live runtime" , async ( ) => {
4142 const f = fixture ( ) ; f . setActive ( 2 ) ;
4243 expect ( ( await performMacOSUpdateCommand ( prepare , f . io ) ) . status ) . toBe ( "confirmation-required" ) ;
4344 expect ( f . stopped ) . toBe ( 0 ) ;
4445 expect ( ( await performMacOSUpdateCommand ( { action :"cancel" , transactionId :id } , f . io ) ) . status ) . toBe ( "recovered" ) ;
4546 expect ( f . stopped ) . toBe ( 0 ) ; expect ( f . resumed ) . toEqual ( [ ] ) ; expect ( f . store . read ( ) ) . toBeNull ( ) ;
4647} ) ;
47- test ( "arming reverifies exit and uncertain/armed cancellation cannot clear exclusion" , async ( ) => {
48+ test . skipIf ( process . platform === "win32" ) ( "arming reverifies exit and uncertain/armed cancellation cannot clear exclusion" , async ( ) => {
4849 const f = fixture ( ) ; await performMacOSUpdateCommand ( prepare , f . io ) ; f . failVerify ( ) ;
4950 expect ( ( await performMacOSUpdateCommand ( { action :"arm" , transactionId :id } , f . io ) ) . status ) . toBe ( "blocked" ) ;
5051 expect ( f . store . read ( ) ) . not . toBeNull ( ) ;
@@ -53,7 +54,7 @@ test("arming reverifies exit and uncertain/armed cancellation cannot clear exclu
5354 expect ( ( await performMacOSUpdateCommand ( { action :"reconcile" } , g . io ) ) . status ) . toBe ( "finish-required" ) ;
5455 expect ( g . resumed ) . toEqual ( [ ] ) ;
5556} ) ;
56- test ( "successful replacement restores owned intent unless newer file edits or native intent superseded it" , async ( ) => {
57+ test . skipIf ( process . platform === "win32" ) ( "successful replacement restores owned intent unless newer file edits or native intent superseded it" , async ( ) => {
5758 for ( const changed of [ false , true ] ) {
5859 const f = fixture ( ) ; await performMacOSUpdateCommand ( prepare , f . io ) ; await performMacOSUpdateCommand ( { action :"arm" , transactionId :id } , f . io ) ; f . replace ( ) ; if ( changed ) f . setIntent ( ) ;
5960 expect ( ( await performMacOSUpdateCommand ( { action :"reconcile" } , f . io ) ) . status ) . toBe ( "recovered" ) ; expect ( f . resumed ) . toEqual ( [ ! changed ] ) ; expect ( f . store . read ( ) ) . toBeNull ( ) ;
@@ -62,13 +63,13 @@ test("successful replacement restores owned intent unless newer file edits or na
6263 const a = await f . io . authority ! ( { includeStart :true } ) ; f . store . recordNative ( a ) ; a . releaseAll ( ) ; f . replace ( ) ;
6364 await performMacOSUpdateCommand ( { action :"reconcile" } , f . io ) ; expect ( f . resumed ) . toEqual ( [ false ] ) ;
6465} ) ;
65- test ( "running-native never enables routing, and failed resume retains a retryable recovery record" , async ( ) => {
66+ test . skipIf ( process . platform === "win32" ) ( "running-native never enables routing, and failed resume retains a retryable recovery record" , async ( ) => {
6667 const f = fixture ( { routing :"native" } ) ; await performMacOSUpdateCommand ( prepare , f . io ) ; f . replace ( ) ; f . failResume ( ) ;
6768 expect ( ( await performMacOSUpdateCommand ( { action :"reconcile" } , f . io ) ) . status ) . toBe ( "blocked" ) ; expect ( f . store . read ( ) ?. phase ) . toBe ( "recovering" ) ;
6869 f . allowResume ( ) ; expect ( ( await performMacOSUpdateCommand ( { action :"reconcile" } , f . io ) ) . status ) . toBe ( "recovered" ) ; expect ( f . resumed ) . toEqual ( [ false , false ] ) ;
6970 expect ( ( await performMacOSUpdateCommand ( { action :"reconcile" } , f . io ) ) . status ) . toBe ( "idle" ) ;
7071} ) ;
71- test ( "prearm cancellation recovery survives helper failure and cold-launch retry" , async ( ) => {
72+ test . skipIf ( process . platform === "win32" ) ( "prearm cancellation recovery survives helper failure and cold-launch retry" , async ( ) => {
7273 const f = fixture ( ) ; await performMacOSUpdateCommand ( prepare , f . io ) ; f . failResume ( ) ;
7374 expect ( ( await performMacOSUpdateCommand ( { action :"cancel" , transactionId :id } , f . io ) ) . status ) . toBe ( "blocked" ) ; f . allowResume ( ) ;
7475 expect ( ( await performMacOSUpdateCommand ( { action :"reconcile" } , f . io ) ) . status ) . toBe ( "recovered" ) ;
@@ -89,15 +90,15 @@ test.skipIf(process.platform !== "darwin")("real bundled CLI helper derives sour
8990} , 15000 ) ;
9091
9192import { macOSUpdateResumeIntent } from "../src/cli/macos-update" ;
92- test ( "semantic matrix preserves stopped/native/supervised and newer OFF without copying settings" , async ( ) => {
93+ test . skipIf ( process . platform === "win32" ) ( "semantic matrix preserves stopped/native/supervised and newer OFF without copying settings" , async ( ) => {
9394 for ( const running of [ true , false ] ) for ( const routing of [ "owned" , "native" , "external" ] as const ) for ( const supervision of [ "none" , "launchd" ] as const ) {
9495 const f = fixture ( { running, routing, supervision} ) ; await performMacOSUpdateCommand ( prepare , f . io ) ;
9596 expect ( macOSUpdateResumeIntent ( f . store . read ( ) ! , "after" ) ) . toEqual ( { running, restoreOwned :routing === "owned" , supervised :supervision === "launchd" } ) ;
9697 await performMacOSUpdateCommand ( { action :"record-off" } , f . io ) ;
9798 expect ( macOSUpdateResumeIntent ( f . store . read ( ) ! , "after" ) ) . toEqual ( { running :false , restoreOwned :false , supervised :supervision === "launchd" } ) ;
9899 }
99100} ) ;
100- test ( "partial preparation stays excluded and Finish Update retries the same captured target" , async ( ) => {
101+ test . skipIf ( process . platform === "win32" ) ( "partial preparation stays excluded and Finish Update retries the same captured target" , async ( ) => {
101102 const f = fixture ( ) ; let stopAttempt = 0 ;
102103 const base = f . io . preparation ! ; f . io . preparation = ( source , authority ) => { const original = base ( source , authority ) ; return { ...original , stop :async ( t , a ) => { if ( ++ stopAttempt === 1 ) throw Error ( "partial stop" ) ; await original . stop ( t , a ) ; } } ; } ;
103104 expect ( ( await performMacOSUpdateCommand ( prepare , f . io ) ) . status ) . toBe ( "blocked" ) ; expect ( f . store . read ( ) ?. phase ) . toBe ( "uncertain" ) ;
@@ -108,7 +109,7 @@ test("partial preparation stays excluded and Finish Update retries the same capt
108109} ) ;
109110
110111import { resumeProduction } from "../src/cli/macos-update" ;
111- test ( "newer OFF stops a recovery child or active bundle supervisor before clearing exclusion" , async ( ) => {
112+ test . skipIf ( process . platform === "win32" ) ( "newer OFF stops a recovery child or active bundle supervisor before clearing exclusion" , async ( ) => {
112113 const f = fixture ( ) ; await performMacOSUpdateCommand ( prepare , f . io ) ; await performMacOSUpdateCommand ( { action :"record-off" } , f . io ) ;
113114 const authority = await f . io . authority ! ( { includeStart :true } ) ; let stops = 0 ;
114115 const stop = async ( ) => { stops ++ ; return { schemaVersion :1 as const , action :"stop" as const , ok :true , state :"stopped" as const , changed :true , pid :null , port :null , message :"stopped" } ; } ;
@@ -129,7 +130,7 @@ test("permission hardening reads do not supersede routing intent but user writes
129130 expect ( macOSUpdateIntentFingerprint ( [ config ] ) ) . not . toBe ( before ) ;
130131} ) ;
131132
132- test ( "deferred native routing applies before independent service/runtime returns and retains exclusion on failure" , async ( ) => {
133+ test . skipIf ( process . platform === "win32" ) ( "deferred native routing applies before independent service/runtime returns and retains exclusion on failure" , async ( ) => {
133134 for ( const independentService of [ false , true ] ) for ( const success of [ false , true ] ) {
134135 const f = fixture ( { running :false } ) ; await performMacOSUpdateCommand ( prepare , f . io ) ;
135136 const a = await f . io . authority ! ( { includeStart :true } ) ; f . store . recordNative ( a ) ; a . releaseAll ( ) ; f . replace ( ) ;
@@ -148,7 +149,7 @@ test("deferred native routing applies before independent service/runtime returns
148149 }
149150} ) ;
150151
151- test ( "deferred native recovery publishes OFF and preserves a newer external route in an isolated home" , async ( ) => {
152+ test . skipIf ( process . platform === "win32" ) ( "deferred native recovery publishes OFF and preserves a newer external route in an isolated home" , async ( ) => {
152153 for ( const external of [ false , true ] ) for ( const confirmation of [ false , true ] ) {
153154 const root = mkdtempSync ( join ( tmpdir ( ) , "ccx-update-native-recovery-" ) ) ; temporary . push ( root ) ;
154155 for ( const directory of [ "home" , "codex" , "state" , "tmp" ] ) mkdirSync ( join ( root , directory ) ) ;
@@ -178,7 +179,7 @@ test("deferred native recovery publishes OFF and preserves a newer external rout
178179 }
179180} , 60000 ) ;
180181
181- test ( "Later publishes deferred native intent under authority and retries without stopping or resuming" , async ( ) => {
182+ test . skipIf ( process . platform === "win32" ) ( "Later publishes deferred native intent under authority and retries without stopping or resuming" , async ( ) => {
182183 for ( const failure of [ "none" , "false" , "throw" ] as const ) for ( const retry of [ "cancel" , "reconcile" ] as const ) {
183184 const f = fixture ( ) ; f . setActive ( 1 ) ;
184185 expect ( ( await performMacOSUpdateCommand ( prepare , f . io ) ) . status ) . toBe ( "confirmation-required" ) ;
@@ -206,7 +207,7 @@ test("Later publishes deferred native intent under authority and retries without
206207 }
207208} ) ;
208209
209- test ( "settings changed before the first stop supersede owned restoration on initial and confirmation preparation" , async ( ) => {
210+ test . skipIf ( process . platform === "win32" ) ( "settings changed before the first stop supersede owned restoration on initial and confirmation preparation" , async ( ) => {
210211 for ( const confirmation of [ false , true ] ) for ( const changed of [ false , true ] ) {
211212 const f = fixture ( ) ;
212213 if ( confirmation ) {
@@ -229,7 +230,7 @@ test("settings changed before the first stop supersede owned restoration on init
229230 }
230231} ) ;
231232
232- test ( "confirmation reached after a partial stop does not become a routing-only cancellation" , async ( ) => {
233+ test . skipIf ( process . platform === "win32" ) ( "confirmation reached after a partial stop does not become a routing-only cancellation" , async ( ) => {
233234 const f = fixture ( ) ; const preparation = f . io . preparation ! ; let first = true ;
234235 f . io . preparation = ( source , authority ) => {
235236 const io = preparation ( source , authority ) ;
0 commit comments