M1-04: Code signing and on-device install #16

Merged
wk merged 1 commit from m1-04-code-signing into main 2026-08-06 14:50:28 -04:00
Member

Issue #4. make install puts the current build on the phone.

What changed

Makefile (new) — help, generate, lint, build, run, install, clean. Every target regenerates the .xcodeproj first, so there is no separate step to remember and no way to build a stale project.

project.ymlCODE_SIGN_STYLE: Automatic and DEVELOPMENT_TEAM: ${STASH_DEV_TEAM}, expanded by XcodeGen from the environment.

README.md — build/run collapsed onto the make targets, plus an "On device" section documenting the two overridable variables and never a value.

AGENTS.md — the make path, and the rule that signing is discovered and never committed.

Nothing about signing is in the repository

No certificate, no provisioning profile, no team identifier, no device UDID. STASH_DEV_TEAM defaults to the OU of the Apple Development certificate in the keychain — not the parenthesised identifier on the security find-identity line, which is a different value and the one that is easy to grab by mistake. STASH_DEVICE defaults to the first connected device. Both are overridable, and the examples use my-iphone so even a device name is not committed.

When either is missing, make install says which one and how to get it, and stops before xcodebuild rather than failing inside it.

Validated

From make clean, which is the state a new machine starts in: make lint, make build, make run and make install all exit 0. The device install was done after a devicectl device uninstall, so it was a genuine first install rather than an upgrade, and the app was confirmed in the device process list afterwards.

The CI path was re-checked specifically. Regenerated with STASH_DEV_TEAM unset and rebuilt for the simulator — the unexpanded variable resolves to empty at build time and the build succeeds. This change does not affect CI.

Both make install failure paths were triggered deliberately and confirmed to stop the chain before xcodebuild.

One bug caught in testing: device detection originally matched the State column, which moves between connected and available (paired). It worked, then silently returned nothing. It now matches the hostname column.

Not validated

Auto-detection has only ever run on one machine with one certificate and one connected phone — the overrides exist for the two-of-either case and are untested. The check-team recovery instructions describe a path I have not walked, since there is no second Apple ID here. CI has not run this.

Issue #4 stays open after this merges.

Issue #4. `make install` puts the current build on the phone. ## What changed **`Makefile`** (new) — `help`, `generate`, `lint`, `build`, `run`, `install`, `clean`. Every target regenerates the `.xcodeproj` first, so there is no separate step to remember and no way to build a stale project. **`project.yml`** — `CODE_SIGN_STYLE: Automatic` and `DEVELOPMENT_TEAM: ${STASH_DEV_TEAM}`, expanded by XcodeGen from the environment. **`README.md`** — build/run collapsed onto the make targets, plus an "On device" section documenting the two overridable variables and never a value. **`AGENTS.md`** — the make path, and the rule that signing is discovered and never committed. ## Nothing about signing is in the repository No certificate, no provisioning profile, no team identifier, no device UDID. `STASH_DEV_TEAM` defaults to the **OU** of the Apple Development certificate in the keychain — not the parenthesised identifier on the `security find-identity` line, which is a different value and the one that is easy to grab by mistake. `STASH_DEVICE` defaults to the first connected device. Both are overridable, and the examples use `my-iphone` so even a device name is not committed. When either is missing, `make install` says which one and how to get it, and stops before `xcodebuild` rather than failing inside it. ## Validated From `make clean`, which is the state a new machine starts in: `make lint`, `make build`, `make run` and `make install` all exit 0. The device install was done after a `devicectl device uninstall`, so it was a genuine first install rather than an upgrade, and the app was confirmed in the device process list afterwards. **The CI path was re-checked specifically.** Regenerated with `STASH_DEV_TEAM` unset and rebuilt for the simulator — the unexpanded variable resolves to empty at build time and the build succeeds. This change does not affect CI. Both `make install` failure paths were triggered deliberately and confirmed to stop the chain before `xcodebuild`. One bug caught in testing: device detection originally matched the `State` column, which moves between `connected` and `available (paired)`. It worked, then silently returned nothing. It now matches the hostname column. ## Not validated Auto-detection has only ever run on one machine with one certificate and one connected phone — the overrides exist for the two-of-either case and are untested. The `check-team` recovery instructions describe a path I have not walked, since there is no second Apple ID here. CI has not run this. Issue #4 stays open after this merges.
make install builds signed, installs and launches on a connected iPhone.

Nothing about signing is committed, because this repository is public. There is
no certificate, no provisioning profile, no team identifier and no device UDID
here. Both values a device build needs are discovered from the machine:

  - the team is the OU of the Apple Development certificate in the keychain,
    which is not the parenthesised name on the identity line — a common thing
    to get wrong;
  - the device is the first connected one.

Either can be overridden with STASH_DEV_TEAM or STASH_DEVICE, and README.md
documents what to set without ever naming a value.

project.yml carries DEVELOPMENT_TEAM: ${STASH_DEV_TEAM}, expanded by XcodeGen
from the environment. Unset it expands to nothing, which is what simulator
builds and CI want — neither needs an identity, and the CI path was rebuilt
with it unset to confirm that.

When a device build cannot proceed, make says which value is missing and how to
get it instead of failing somewhere inside xcodebuild.

Device detection matches the hostname column rather than State. State moves
between 'connected' and 'available (paired)' depending on what devicectl last
did, and the first version of this worked until it silently did not.
wk merged commit 8fbd274842 into main 2026-08-06 14:50:28 -04:00
wk deleted branch m1-04-code-signing 2026-08-06 14:50:28 -04:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
Stash/stash-ios!16
No description provided.