package config import ( "gerrit.wikimedia.org/r/blubber/build" ) // VariantConfig holds configuration fields for each defined build variant. // type VariantConfig struct { Includes []string `json:"includes" validate:"dive,variantref"` Copies CopiesConfig `json:"copies" validate:"omitempty,unique,dive"` CommonConfig `json:",inline"` } // Merge takes another VariantConfig and overwrites this struct's fields. // func (vc *VariantConfig) Merge(vc2 VariantConfig) { vc.Copies.Merge(vc2.Copies) vc.CommonConfig.Merge(vc2.CommonConfig) } // InstructionsForPhase injects build instructions related to dropping // priviledge and the application entrypoint, then it delegates to its common // and copies configurations. It also enforces the correct UID/GID on all copy // instructions returned from deeper config structs. // // PhasePrivileged // // Ensure the process and file owner is root. // // PhasePrivilegeDropped // // Ensure the process and file owner is the "lives.as" user. // // PhasePreInstall // // Ensure the process and file owner is the "lives.as" user. // // PhaseInstall // // Ensure the process and file owner is the "lives.as" user. // // PhasePostInstall // // Ensure the process and file owner is the "runs.as" user, unless configured // to run insecurely as the "lives.as" user. Finally, sets the application // entrypoint. // func (vc *VariantConfig) InstructionsForPhase(phase build.Phase) []build.Instruction { instructions := vc.CommonConfig.InstructionsForPhase(phase) var switchUser string var uid, gid uint switch phase { case build.PhasePrivileged: switchUser = "root" case build.PhasePrivilegeDropped: switchUser = vc.Lives.As uid, gid = vc.Lives.UID, vc.Lives.GID case build.PhasePreInstall: uid, gid = vc.Lives.UID, vc.Lives.GID case build.PhaseInstall: uid, gid = vc.Lives.UID, vc.Lives.GID case build.PhasePostInstall: if vc.Runs.Insecurely.True { uid, gid = vc.Lives.UID, vc.Lives.GID } else { switchUser = vc.Runs.As uid, gid = vc.Runs.UID, vc.Runs.GID } if len(vc.EntryPoint) > 0 { instructions = append(instructions, build.EntryPoint{vc.EntryPoint}) } } // CopiesConfig may not implement InstructionsForPhase for all possible // phases, which makes the expansion of it here less than efficient, but to // assume which phases it does implement would result in gross coupling instructions = append(instructions, vc.Copies.Expand(vc.Lives.In).InstructionsForPhase(phase)...) if switchUser != "" { instructions = append( []build.Instruction{ build.User{switchUser}, build.Home(switchUser), }, instructions..., ) } if uid != 0 { instructions = build.ApplyUser(uid, gid, instructions) } return instructions }