Skip to content

Commit 2ff8424

Browse files
committed
Fix capability/runtime gating and build config perms
1 parent 9bad15c commit 2ff8424

4 files changed

Lines changed: 71 additions & 5 deletions

File tree

cmd/api/api/capabilities.go

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -55,12 +55,14 @@ func (s *ApiService) GetCapabilities(ctx context.Context, _ oapi.GetCapabilities
5555
if s.InstanceManager != nil {
5656
defaultRuntime = s.InstanceManager.DefaultHypervisor()
5757
}
58-
caps, capsKnown := hypervisor.CapabilitiesForType(defaultRuntime)
58+
supported := supportedRuntimes(runtime.GOOS)
59+
caps, capsKnown := capabilitiesForDefaultRuntime(defaultRuntime, supported)
5960
if !capsKnown {
60-
// The configured default runtime is not available on this platform;
61+
// The configured default runtime is not usable on this host;
6162
// report zeroed features rather than guessing.
62-
log.WarnContext(ctx, "default runtime has no registered capabilities on this host",
63-
"runtime", string(defaultRuntime))
63+
log.WarnContext(ctx, "default runtime has no usable capabilities on this host",
64+
"runtime", string(defaultRuntime),
65+
"supported", supported)
6466
}
6567

6668
emulation := emulationSupported(runtime.GOOS, runtime.GOARCH, defaultRuntime)
@@ -85,7 +87,7 @@ func (s *ApiService) GetCapabilities(ctx context.Context, _ oapi.GetCapabilities
8587
},
8688
Runtime: oapi.CapabilitiesRuntime{
8789
Default: string(defaultRuntime),
88-
Supported: supportedRuntimes(runtime.GOOS),
90+
Supported: supported,
8991
Snapshot: caps.SupportsSnapshot,
9092
Standby: standbySupported(caps),
9193
Pause: caps.SupportsPause,
@@ -157,6 +159,23 @@ func supportedRuntimes(goos string) []string {
157159
}
158160
}
159161

162+
func capabilitiesForDefaultRuntime(defaultRuntime hypervisor.Type, supported []string) (hypervisor.Capabilities, bool) {
163+
if !runtimeSupported(defaultRuntime, supported) {
164+
return hypervisor.Capabilities{}, false
165+
}
166+
return hypervisor.CapabilitiesForType(defaultRuntime)
167+
}
168+
169+
func runtimeSupported(defaultRuntime hypervisor.Type, supported []string) bool {
170+
defaultRuntimeName := string(defaultRuntime)
171+
for _, runtimeName := range supported {
172+
if runtimeName == defaultRuntimeName {
173+
return true
174+
}
175+
}
176+
return false
177+
}
178+
160179
// emulationSupported reports whether the host can boot images built for the
161180
// other CPU architecture. This mirrors the create-path rule for attaching
162181
// the Rosetta share: vz on Apple Silicon macOS.

cmd/api/api/capabilities_test.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,19 @@ func TestSupportedRuntimes(t *testing.T) {
111111
require.Equal(t, []string{"vz"}, supportedRuntimes("darwin"))
112112
}
113113

114+
func TestRuntimeSupported(t *testing.T) {
115+
t.Parallel()
116+
require.True(t, runtimeSupported(hypervisor.TypeVZ, supportedRuntimes("darwin")))
117+
require.False(t, runtimeSupported(hypervisor.TypeCloudHypervisor, supportedRuntimes("darwin")))
118+
}
119+
120+
func TestCapabilitiesForDefaultRuntime_IgnoresUnsupportedRuntime(t *testing.T) {
121+
t.Parallel()
122+
caps, ok := capabilitiesForDefaultRuntime(hypervisor.TypeCloudHypervisor, supportedRuntimes("darwin"))
123+
require.False(t, ok)
124+
require.Equal(t, hypervisor.Capabilities{}, caps)
125+
}
126+
114127
func TestEmulationSupported(t *testing.T) {
115128
t.Parallel()
116129
require.True(t, emulationSupported("darwin", "arm64", hypervisor.TypeVZ))

lib/builds/storage.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,9 @@ func writeBuildConfig(p *paths.Paths, id string, config *BuildConfig) error {
237237
if err := os.WriteFile(configPath, data, 0600); err != nil {
238238
return fmt.Errorf("write build config: %w", err)
239239
}
240+
if err := os.Chmod(configPath, 0600); err != nil {
241+
return fmt.Errorf("chmod build config: %w", err)
242+
}
240243

241244
return nil
242245
}

lib/builds/storage_test.go

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,3 +36,34 @@ func TestBuildMetadataReadWrite_MetadataRoundTrip(t *testing.T) {
3636
loaded.Tags["team"] = "mutated"
3737
require.Equal(t, "backend", build.Tags["team"])
3838
}
39+
40+
func TestWriteBuildConfig_UsesOwnerOnlyPermissions(t *testing.T) {
41+
tempDir := t.TempDir()
42+
p := paths.New(tempDir)
43+
id := "build-config-1"
44+
45+
cfg := &BuildConfig{RegistryToken: "secret-token"}
46+
require.NoError(t, writeBuildConfig(p, id, cfg))
47+
48+
info, err := os.Stat(p.BuildConfig(id))
49+
require.NoError(t, err)
50+
require.Equal(t, os.FileMode(0600), info.Mode().Perm())
51+
}
52+
53+
func TestWriteBuildConfig_TightensLegacyPermissions(t *testing.T) {
54+
tempDir := t.TempDir()
55+
p := paths.New(tempDir)
56+
id := "build-config-legacy"
57+
58+
require.NoError(t, os.MkdirAll(p.BuildDir(id), 0755))
59+
configPath := p.BuildConfig(id)
60+
require.NoError(t, os.WriteFile(configPath, []byte(`{"registry_token":"old-token"}`), 0644))
61+
require.NoError(t, os.Chmod(configPath, 0644))
62+
63+
cfg := &BuildConfig{RegistryToken: "new-token"}
64+
require.NoError(t, writeBuildConfig(p, id, cfg))
65+
66+
info, err := os.Stat(configPath)
67+
require.NoError(t, err)
68+
require.Equal(t, os.FileMode(0600), info.Mode().Perm())
69+
}

0 commit comments

Comments
 (0)