mirror of
https://github.com/priyanshujain/sanderling.git
synced 2026-10-04 20:17:09 +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,
|
// 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
|
// matches. The device signature is per-account/per-device, so the build cannot
|
||||||
// be embedded; the stable derivedDataPath makes the build incremental.
|
// be embedded; the stable derivedDataPath makes the build incremental.
|
||||||
func (d *Driver) buildDeviceRunnerIfNeeded(ctx context.Context, companionDir, derivedDataPath string, creds signingCredentials) error {
|
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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
marker := filepath.Join(derivedDataPath, "device-runner.sha256")
|
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")
|
fmt.Fprintln(d.output, "device runner build is up to date; skipping build")
|
||||||
return nil
|
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 {
|
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))
|
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 err
|
||||||
}
|
}
|
||||||
return nil
|
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.
|
// xcodegenArgs regenerates the runner project from its spec.
|
||||||
func xcodegenArgs(specPath string) []string {
|
func xcodegenArgs(specPath string) []string {
|
||||||
return []string{"xcodegen", "--spec", specPath}
|
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) {
|
func TestSourceHashChangesWithSources(t *testing.T) {
|
||||||
dir := t.TempDir()
|
dir := t.TempDir()
|
||||||
if err := os.MkdirAll(filepath.Join(dir, "Sources"), 0o755); err != nil {
|
if err := os.MkdirAll(filepath.Join(dir, "Sources"), 0o755); err != nil {
|
||||||
|
|||||||
Reference in new issue
Block a user