@@ -38,6 +38,7 @@ const EVENT_ARTIFACT_CACHE_HIT = "artifact_cache_hit";
3838const EVENT_ARTIFACT_CACHE_MISS = "artifact_cache_miss" ;
3939const EVENT_ARTIFACT_CACHE_PERSIST = "artifact_cache_persist" ;
4040const EVENT_PREFLIGHT_REQUIRE_NIX_DENIED = "preflight-require-nix-denied" ;
41+ const EVENT_STORE_IDENTITY_FAILED = "store_identity_failed" ;
4142
4243const FACT_ARTIFACT_FETCHED_FROM_CACHE = "artifact_fetched_from_cache" ;
4344const FACT_ENDED_WITH_EXCEPTION = "ended_with_exception" ;
@@ -172,6 +173,64 @@ export type DiagnosticEvent = {
172173 uuid : UUID ;
173174} ;
174175
176+ const determinateStateDir = "/var/lib/determinate" ;
177+ const determinateIdentityFile = path . join ( determinateStateDir , "identity.json" ) ;
178+
179+ const isRoot = os . userInfo ( ) . uid === 0 ;
180+
181+ /** Create the Determinate state directory by escalating via sudo */
182+ async function sudoEnsureDeterminateStateDir ( ) : Promise < void > {
183+ const code = await actionsExec . exec ( "sudo" , [
184+ "mkdir" ,
185+ "-p" ,
186+ determinateStateDir ,
187+ ] ) ;
188+
189+ if ( code !== 0 ) {
190+ throw new Error ( `sudo mkdir -p exit: ${ code } ` ) ;
191+ }
192+ }
193+
194+ /** Ensures the Determinate state directory exists, escalating if necessary */
195+ async function ensureDeterminateStateDir ( ) : Promise < void > {
196+ if ( isRoot ) {
197+ await mkdir ( determinateStateDir , { recursive : true } ) ;
198+ } else {
199+ return sudoEnsureDeterminateStateDir ( ) ;
200+ }
201+ }
202+
203+ /** Writes correlation hashes to the Determinate state directory by writing to a `sudo tee` pipe */
204+ async function sudoWriteCorrelationHashes ( hashes : string ) : Promise < void > {
205+ const buffer = Buffer . from ( hashes ) ;
206+
207+ const code = await actionsExec . exec (
208+ "sudo" ,
209+ [ "tee" , determinateIdentityFile ] ,
210+ {
211+ input : buffer ,
212+
213+ // Ignore output from tee
214+ outStream : createWriteStream ( "/dev/null" ) ,
215+ } ,
216+ ) ;
217+
218+ if ( code !== 0 ) {
219+ throw new Error ( `sudo tee exit: ${ code } ` ) ;
220+ }
221+ }
222+
223+ /** Writes correlation hashes to the Determinate state directory, escalating if necessary */
224+ async function writeCorrelationHashes ( hashes : string ) : Promise < void > {
225+ await ensureDeterminateStateDir ( ) ;
226+
227+ if ( isRoot ) {
228+ await fs . writeFile ( determinateIdentityFile , hashes , "utf-8" ) ;
229+ } else {
230+ return sudoWriteCorrelationHashes ( hashes ) ;
231+ }
232+ }
233+
175234export abstract class DetSysAction {
176235 nixStoreTrust : NixStoreTrust ;
177236 strictMode : boolean ;
@@ -428,9 +487,13 @@ export abstract class DetSysAction {
428487 try {
429488 await this . checkIn ( ) ;
430489
431- process . env . DETSYS_CORRELATION = JSON . stringify (
432- this . getCorrelationHashes ( ) ,
433- ) ;
490+ const correlationHashes = JSON . stringify ( this . getCorrelationHashes ( ) ) ;
491+ process . env . DETSYS_CORRELATION = correlationHashes ;
492+ try {
493+ await writeCorrelationHashes ( correlationHashes ) ;
494+ } catch ( error ) {
495+ this . recordEvent ( EVENT_STORE_IDENTITY_FAILED , { error : String ( error ) } ) ;
496+ }
434497
435498 if ( ! ( await this . preflightRequireNix ( ) ) ) {
436499 this . recordEvent ( EVENT_PREFLIGHT_REQUIRE_NIX_DENIED ) ;
0 commit comments