11//go:build linux
22
3- // Package ompimport compiles explicit host OMP file imports. Selected host
4- // files, including the OAuth database and its existing sidecars, are copied
5- // into workspace-owned writable snapshots.
3+ // Package ompimport compiles explicit host OMP imports into workspace-owned
4+ // writable snapshots.
65package ompimport
76
87import (
@@ -113,16 +112,22 @@ func Compile(root *hostroot.Root, workspaceID string, spec config.OMPAgentSpec,
113112 }
114113 plan .Mounts = append (plan .Mounts , runtime.Mount {Source : snapshot , Target : containerNative , Type : "bind" , Propagation : "rprivate" })
115114 }
116- if spec .Import .OAuthDB && sources .Agent == "" {
117- return Plan {}, fmt .Errorf ("OMP OAuth database source is unavailable" )
118- }
119- if (spec .Import .Models || spec .Import .Config || spec .Import .OAuthDB ) && sources .Agent != "" {
115+ if spec .Import .OAuthDB {
116+ if sources .Agent == "" {
117+ return Plan {}, fmt .Errorf ("OMP agent directory source is unavailable" )
118+ }
119+ snapshot , err := prepareDirectorySnapshot (root , workspaceID , "agent" , sources .Agent , spec .Import .RequireCOW )
120+ if err != nil {
121+ return Plan {}, err
122+ }
123+ plan .Mounts = append (plan .Mounts , runtime.Mount {Source : snapshot , Target : containerAgent , Type : "bind" , Propagation : "rprivate" })
124+ } else if (spec .Import .Models || spec .Import .Config ) && sources .Agent != "" {
120125 selected , err := selectedAgentFiles (spec .Import , sources .Agent )
121126 if err != nil {
122127 return Plan {}, err
123128 }
124- if len (selected ) != 0 || spec . Import . OAuthDB {
125- snapshot , err := prepareAgentSnapshot (root , workspaceID , sources .Agent , selected , spec .Import .RequireCOW )
129+ if len (selected ) != 0 {
130+ snapshot , err := prepareSelectedSnapshot (root , workspaceID , "agent" , sources .Agent , selected , spec .Import .RequireCOW )
126131 if err != nil {
127132 return Plan {}, err
128133 }
@@ -141,19 +146,6 @@ func selectedAgentFiles(spec config.OMPImportSpec, root string) ([]string, error
141146 candidates = append (candidates , "models.yml" , "models.yaml" )
142147 }
143148 selected := make ([]string , 0 , len (candidates ))
144- if spec .OAuthDB {
145- for _ , name := range []string {"agent.db" , "agent.db-wal" , "agent.db-shm" , "agent.db-journal" } {
146- path := filepath .Join (root , name )
147- err := requireRegular (path , false )
148- if name != "agent.db" && errors .Is (err , os .ErrNotExist ) {
149- continue
150- }
151- if err != nil {
152- return nil , fmt .Errorf ("validate OMP OAuth database file %s: %w" , name , err )
153- }
154- selected = append (selected , name )
155- }
156- }
157149 for _ , name := range candidates {
158150 path := filepath .Join (root , name )
159151 err := requireRegular (path , false )
@@ -196,38 +188,6 @@ func prepareSelectedSnapshot(root *hostroot.Root, workspaceID, name, source stri
196188 })
197189}
198190
199- func prepareAgentSnapshot (root * hostroot.Root , workspaceID , source string , selected []string , requireCOW bool ) (string , error ) {
200- fingerprint , err := selectedFingerprint (source , selected )
201- if err != nil {
202- return "" , err
203- }
204- return prepareSnapshot (root , workspaceID , "agent" , fingerprint , func (staging string ) error {
205- for _ , relative := range selected {
206- sourcePath := filepath .Join (source , relative )
207- destinationPath := filepath .Join (staging , relative )
208- var err error
209- if isOAuthDatabaseFile (relative ) {
210- err = copyRegularFile (sourcePath , destinationPath , false )
211- } else {
212- err = cloneRegularFile (sourcePath , destinationPath , false , requireCOW )
213- }
214- if err != nil {
215- return err
216- }
217- }
218- return nil
219- })
220- }
221-
222- func isOAuthDatabaseFile (name string ) bool {
223- switch name {
224- case "agent.db" , "agent.db-wal" , "agent.db-shm" , "agent.db-journal" :
225- return true
226- default :
227- return false
228- }
229- }
230-
231191func prepareDirectorySnapshot (root * hostroot.Root , workspaceID , name , source string , requireCOW bool ) (string , error ) {
232192 fingerprint , err := directoryFingerprint (source )
233193 if err != nil {
@@ -318,10 +278,6 @@ func cloneRegularFile(source, destination string, executable, requireCOW bool) e
318278 return writeRegularFile (source , destination , executable , true , requireCOW )
319279}
320280
321- func copyRegularFile (source , destination string , executable bool ) error {
322- return writeRegularFile (source , destination , executable , false , false )
323- }
324-
325281func writeRegularFile (source , destination string , executable , tryReflink , requireCOW bool ) error {
326282 sourceFD , err := unix .Open (source , unix .O_RDONLY | unix .O_NOFOLLOW | unix .O_CLOEXEC , 0 )
327283 if err != nil {
@@ -399,13 +355,16 @@ func selectedFingerprint(root string, names []string) (string, error) {
399355 sort .Strings (names )
400356 for _ , name := range names {
401357 path := filepath .Join (root , name )
402- entry , err := os .Stat (path )
358+ entry , err := os .Lstat (path )
403359 if err != nil {
404360 return "" , err
405361 }
406362 if _ , err := fmt .Fprintf (hash , "%s\x00 %d\x00 %d\x00 %d\x00 " , name , entry .Mode (), entry .Size (), entry .ModTime ().UnixNano ()); err != nil {
407363 return "" , err
408364 }
365+ if err := fingerprintRegularFile (hash , path ); err != nil {
366+ return "" , err
367+ }
409368 }
410369 return hex .EncodeToString (hash .Sum (nil )[:16 ]), nil
411370}
@@ -426,9 +385,30 @@ func fingerprintEntry(hash interface{ Write([]byte) (int, error) }, path, relati
426385 _ , err = fmt .Fprintf (hash , "%s\x00 " , target )
427386 return err
428387 }
388+ if info .Mode ().IsRegular () {
389+ return fingerprintRegularFile (hash , path )
390+ }
429391 return nil
430392}
431393
394+ func fingerprintRegularFile (hash io.Writer , path string ) error {
395+ fd , err := unix .Open (path , unix .O_RDONLY | unix .O_NOFOLLOW | unix .O_CLOEXEC , 0 )
396+ if err != nil {
397+ return err
398+ }
399+ file := os .NewFile (uintptr (fd ), path )
400+ defer file .Close ()
401+ var stat unix.Stat_t
402+ if err := unix .Fstat (fd , & stat ); err != nil {
403+ return err
404+ }
405+ if stat .Mode & unix .S_IFMT != unix .S_IFREG {
406+ return fmt .Errorf ("unsafe OMP file %s" , path )
407+ }
408+ _ , err = io .Copy (hash , file )
409+ return err
410+ }
411+
432412func requireRegular (path string , executable bool ) error {
433413 info , err := os .Lstat (path )
434414 if err != nil {
0 commit comments