mirror of
https://github.com/priyanshujain/sanderling.git
synced 2026-10-02 11:07:10 +00:00
fix(ioscompanion): key the device build cache on signing identity
The cache marker hashed only sources, so switching signing team or key reused a runner signed with the stale identity, which the device rejects at install (0xe8008018). Fold team + key id into the cache key so a signing change forces a rebuild.
This commit is contained in:
1 parent
0a48502ab8
commit
ac76fcca86
2 files changed
+47
-4
No files matched your search
@@ -162,16 +162,16 @@ func (d *Driver) realSpawnDeviceRunner(ctx context.Context, address string) (*ex
|
||||
}
|
||||
|
||||
// buildDeviceRunnerIfNeeded regenerates the project and runs build-for-testing,
|
||||
// skipping the build when a marker recording the current source hash already
|
||||
// skipping the build when a marker recording the current build key already
|
||||
// matches. The device signature is per-account/per-device, so the build cannot
|
||||
// be embedded; the stable derivedDataPath makes the build incremental.
|
||||
func (d *Driver) buildDeviceRunnerIfNeeded(ctx context.Context, companionDir, derivedDataPath string, creds signingCredentials) error {
|
||||
sources, err := sourceHash(companionDir)
|
||||
key, err := buildCacheKey(companionDir, creds)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
marker := filepath.Join(derivedDataPath, "device-runner.sha256")
|
||||
if existing, readErr := os.ReadFile(marker); readErr == nil && string(existing) == sources {
|
||||
if existing, readErr := os.ReadFile(marker); readErr == nil && string(existing) == key {
|
||||
fmt.Fprintln(d.output, "device runner build is up to date; skipping build")
|
||||
return nil
|
||||
}
|
||||
@@ -186,12 +186,24 @@ func (d *Driver) buildDeviceRunnerIfNeeded(ctx context.Context, companionDir, de
|
||||
if out, buildErr := runQuiet(ctx, companionDir, append([]string{"xcrun"}, args...)...); buildErr != nil {
|
||||
return fmt.Errorf("build-for-testing: %w: %s", buildErr, tailLines(string(out), 20))
|
||||
}
|
||||
if err := os.WriteFile(marker, []byte(sources), 0o644); err != nil {
|
||||
if err := os.WriteFile(marker, []byte(key), 0o644); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// buildCacheKey combines the source hash with the signing identity so a changed
|
||||
// team or key invalidates the cached build. A runner signed with a stale
|
||||
// identity would otherwise be reused and rejected at install (0xe8008018).
|
||||
func buildCacheKey(companionDir string, creds signingCredentials) (string, error) {
|
||||
sources, err := sourceHash(companionDir)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
sum := sha256.Sum256([]byte(sources + "\x00" + creds.team + "\x00" + creds.authKeyID))
|
||||
return hex.EncodeToString(sum[:]), nil
|
||||
}
|
||||
|
||||
// xcodegenArgs regenerates the runner project from its spec.
|
||||
func xcodegenArgs(specPath string) []string {
|
||||
return []string{"xcodegen", "--spec", specPath}
|
||||
|
||||
@@ -168,6 +168,37 @@ func TestReadSigningCredentialsResolvesRelativeKeyPath(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildCacheKeyChangesWithSigningIdentity(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
if err := os.MkdirAll(filepath.Join(dir, "Sources"), 0o755); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := os.WriteFile(filepath.Join(dir, "Sources", "Server.swift"), []byte("v1"), 0o644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := os.WriteFile(filepath.Join(dir, "project.yml"), []byte("name: x"), 0o644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
base, err := buildCacheKey(dir, signingCredentials{team: "TEAM1", authKeyID: "KID1"})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
otherTeam, err := buildCacheKey(dir, signingCredentials{team: "TEAM2", authKeyID: "KID1"})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
otherKey, err := buildCacheKey(dir, signingCredentials{team: "TEAM1", authKeyID: "KID2"})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if base == otherTeam {
|
||||
t.Fatal("a changed team must invalidate the cached build")
|
||||
}
|
||||
if base == otherKey {
|
||||
t.Fatal("a changed signing key must invalidate the cached build")
|
||||
}
|
||||
}
|
||||
|
||||
func TestSourceHashChangesWithSources(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
if err := os.MkdirAll(filepath.Join(dir, "Sources"), 0o755); err != nil {
|
||||
|
||||
Reference in new issue
Block a user