Signed-off-by: dawn dawn@tangled.org
+46
-6
Diff
Round #0
+1
-1
cmd/spindle-microvm-run/main_linux.go
+1
-1
cmd/spindle-microvm-run/main_linux.go
···
257
257
}
258
258
defer configCacheDB.Close()
259
259
260
-
configKey, err = microvm.BuildConfigKey(imageSpec, cmd.String("activate-config"))
260
+
configKey, err = microvm.BuildConfigKey(imageSpec, cmd.String("activate-config"), "local")
261
261
if err != nil {
262
262
return fmt.Errorf("calculate config key: %w", err)
263
263
}
+30
spindle/engines/microvm/cid_test.go
+30
spindle/engines/microvm/cid_test.go
···
1
+
package microvm
2
+
3
+
import (
4
+
"testing"
5
+
)
6
+
7
+
func TestBuildConfigKeyScopesByRepo(t *testing.T) {
8
+
spec := ImageSpec{BaseConfigHash: "deadbeef"}
9
+
cfg := manifestConfig{Dependencies: []string{"nodejs"}}
10
+
11
+
a, err := buildConfigKey(spec, cfg, "did:plc:aaa")
12
+
if err != nil {
13
+
t.Fatal(err)
14
+
}
15
+
b, err := buildConfigKey(spec, cfg, "did:plc:bbb")
16
+
if err != nil {
17
+
t.Fatal(err)
18
+
}
19
+
if a == b {
20
+
t.Errorf("same config in different repos produced the same key %q", a)
21
+
}
22
+
23
+
again, err := buildConfigKey(spec, cfg, "did:plc:aaa")
24
+
if err != nil {
25
+
t.Fatal(err)
26
+
}
27
+
if a != again {
28
+
t.Errorf("key not deterministic: %q vs %q", a, again)
29
+
}
30
+
}
+8
-1
spindle/engines/microvm/engine.go
+8
-1
spindle/engines/microvm/engine.go
···
160
160
imageName,
161
161
)
162
162
}
163
+
// the cached toplevel is guest-asserted, so the cache key has to
164
+
// be per-repo. a global key lets one tenant poison the activation
165
+
// of another tenant's identical config
166
+
repoDid := ""
167
+
if md := tpl.TriggerMetadata; md != nil && md.Repo != nil {
168
+
repoDid = md.Repo.Did
169
+
}
163
170
var err error
164
-
configKey, err = buildConfigKey(imageSpec, config)
171
+
configKey, err = buildConfigKey(imageSpec, config, repoDid)
165
172
if err != nil {
166
173
return nil, fmt.Errorf("build config key: %w", err)
167
174
}
+7
-4
spindle/engines/microvm/nixos_toplevel_cache.go
+7
-4
spindle/engines/microvm/nixos_toplevel_cache.go
···
12
12
"tangled.org/core/spindle/db"
13
13
)
14
14
15
-
const nixosToplevelCacheSchemaVersion = 1
15
+
// v2 keys are scoped by repo did in v1 keys were global
16
+
const nixosToplevelCacheSchemaVersion = 2
16
17
17
18
type nixosToplevelCacheRecord struct {
18
19
ConfigKey string `json:"config_key"`
···
72
73
return hex.EncodeToString(sum[:])
73
74
}
74
75
75
-
func buildConfigKey(imageSpec ImageSpec, cfg manifestConfig) (string, error) {
76
+
func buildConfigKey(imageSpec ImageSpec, cfg manifestConfig, repoDid string) (string, error) {
76
77
baseHash, err := BaseConfigHash(imageSpec)
77
78
if err != nil {
78
79
return "", err
···
81
82
Schema int `json:"schema"`
82
83
BaseConfig string `json:"base_config"`
83
84
UserConfig string `json:"user_config"`
85
+
RepoDid string `json:"repo_did"`
84
86
}{
85
87
Schema: nixosToplevelCacheSchemaVersion,
86
88
BaseConfig: baseHash,
87
89
UserConfig: userConfigHash(cfg),
90
+
RepoDid: repoDid,
88
91
}
89
92
data, _ := json.Marshal(payload)
90
93
sum := sha256.Sum256(data)
91
94
return hex.EncodeToString(sum[:]), nil
92
95
}
93
96
94
-
func BuildConfigKey(imageSpec ImageSpec, userConfigJSON string) (string, error) {
97
+
func BuildConfigKey(imageSpec ImageSpec, userConfigJSON string, repoDid string) (string, error) {
95
98
var cfg manifestConfig
96
99
if err := json.Unmarshal([]byte(userConfigJSON), &cfg); err != nil {
97
100
return "", err
98
101
}
99
-
return buildConfigKey(imageSpec, cfg)
102
+
return buildConfigKey(imageSpec, cfg, repoDid)
100
103
}
History
1 round
0 comments
ptr.pet
submitted
#0
1 commit
Expand
Collapse
spindle/microvm: key the activation config cache per repo so tenants can't poison each other's toplevels
Signed-off-by: dawn <dawn@tangled.org>