Skip to content
Agentmart
Submit a tool

ios-codesigning

iOS code signing and provisioning profile management via fastlane match.

Skill by cedricziel

IndexedMIT★ 6
Write a review

Install

Works with Claude Code, Claude apps, Codex, Cursor, Gemini CLI, GitHub Copilot, VS Code, OpenCode, Goose, Windsurf. Read the repository before you give any tool access to your data.

npx agentmarket install skill/cedricziel-ios-codesigning

Asks which of your tools to add it to (Claude Code, Codex, Cursor, VS Code, Windsurf, Gemini CLI, Claude Desktop) and shows the change first. See https://agentmart.dev/cli.

Get the weekly diff

The weekly diff: one email a week with new agent tools, notable updates and grade changes, plus security alerts for tools you follow. Double opt-in, one-click unsubscribe.

We use your email only for this newsletter. Privacy

About

iOS code signing and provisioning profile management via fastlane match. Use when debugging CI signing failures, adding new app extensions or targets, rotating certificates, or troubleshooting match decryption errors.

Use cases: devops

No reviews yet. Installed it? Reviews come from verified installers only. How reviews work

Permissions

What this skill can do and what it asks for, from its SKILL.md. Checked Oct 25, 2026.

Tools
No tools found
Secrets
None asked for
Install scripts
None found

Network hosts it talks to 1

  • codeload.github.com · found in install command

Files it touches

  • ~/.claude/skills/ios-codesigning

What's inside

Skill name
ios-codesigning
Description
iOS code signing and provisioning profile management via fastlane match. Use when debugging CI signing failures, adding new app extensions or targets, rotating certificates, or troubleshooting match decryption errors.
License
MIT
Instructions
152 lines in SKILL.md · view on GitHub

Files (1)

  • SKILL.md

SKILL.md (first lines)

## Architecture

Code signing uses **fastlane match** in git storage mode. Certificates and provisioning
profiles are encrypted and stored in a private git repository. CI and local builds
decrypt the repo using a shared passphrase.

### Key Files

| File                     | Purpose                                                              |
| ------------------------ | -------------------------------------------------------------------- |
| `app/fastlane/Matchfile` | Match config: git URL, storage mode, app identifiers, platform       |
| `app/fastlane/Fastfile`  | Build lanes including `match`, `update_code_signing_settings`, `gym` |
| `app/fastlane/Gymfile`   | Archive settings: scheme, workspace, export method                   |
| `app/fastlane/Appfile`   | Default bundle identifier and team metadata                          |

### Secrets (all stored in 1Password and mirrored to GitHub Actions secrets)

| Purpose               | 1Password item                                      | GitHub Actions secret                 |
| --------------------- | --------------------------------------------------- | ------------------------------------- |
| Match repo URL        | _(in GitHub secret only)_                           | `MATCH_GIT_URL`                       |
| Match encryption pass | `fastlane-ci: match`                                | `MATCH_PASSWORD`                      |
| ASC API key ID        | `AppStore Connect: fastlane-ci` (username field)    | `APP_STORE_CONNECT_API_KEY_KEY_ID`    |
| ASC API issuer ID     | `AppStore Connect: fastlane-ci` (Issue ID field)    | `APP_STORE_CONNECT_API_KEY_ISSUER_ID` |
| ASC API private key   | `AppStore Connect: fastlane-ci` (attached .p8 file) | `APP_STORE_CONNECT_API_KEY_KEY`       |
| Match repo deploy key | _(SSH key)_                                         | `MATCH_DEPLOY_KEY`                    |

## Operations

### Reading credentials from 1Password

The `op` CLI is used to read secrets. Items with special characters in the title
(e.g. colons) must be referenced by **item ID**, not name, when using `op read`.

```sh
# Read match password — use item ID to avoid colon parsing issues
op read 'op://Private/<item-id>/password'

# Or use op item get (works with title but needs --reveal for concealed fields)
op item get "<item-title>" --reveal --fields password
```

**Critical caveat:** `op item get --fields password` without `--reveal` returns a
placeholder string like `[use 'op item get <id> --reveal' to reveal]`, NOT the actual
value. If this placeholder is used as `MATCH_PASSWORD` in a `match --force` run, match
will re-encrypt the entire certificates repo with the placeholder as the new passphrase.
Always use `--reveal` or `op read` with the item ID.

### Running match locally

```sh
cd app

export MATCH_GIT_URL="<certificates repo SSH URL>"
export MATCH_PASSWORD="<from 1Password>"

# Read-only fetch (installs profiles, does not modify the repo)
bundle exec fastlane match appstore --readonly

# Force re-create profiles (modifies and pushes to the certificates repo)
bundle exec fastlane match appstore --force
```

For operations that create or modify profiles, match also needs an App Store Connect
API key. Either set the `APP_STORE_CONNECT_API_KEY_*` env vars, or pass
`api_key_path:<path-to-json>` with a JSON file containing `key_id`, `issuer_id`,
`key` (base64), `is_key_content_base64`, and `in_house` (false for standard accounts).

**`in_house` is required.** If omitted from the JSON file, `sigh` (used internally by
match) will crash with `Cannot determine if team is App Store or Enterprise`. Always
set `"in_house": false` for standard Apple Developer accounts. The env var
`SPACESHIP_CONNECT_API_IN_HOUSE=true` is the alternative for Enterprise accounts.

### Adding a new app extension or target

When a new target (e.g. a share extension, widget, notification service) is added to
the Xcode project, code signing requires these steps:

1. **Register the App ID** on the Apple Developer Portal. The `produce` action does
   not support API-key-only auth; use the Spaceship API directly in a Fastfile lane:

   ```ruby
   lane :register_extension do
     require 'spaceship'
     token = Spaceship::ConnectAPI::Token.create(
       key_id:    ENV["APP_STORE_CONNECT_API_KEY_KEY_ID"],
       issuer_id: ENV["APP_STORE_CONNECT_API_KEY_ISSUER_ID"],
       key:       ENV["APP_STORE_CONNECT_API_KEY_KEY"]
     )
     Spaceship::ConnectAPI.token = token
     bid = "<bundle-identifier>"
     unless Spaceship::ConnectAPI::BundleId.find(bid)
       Spaceship::ConnectAPI::BundleId.create(name: "<display-name>", identifier: bid, platform: "IOS")
     end
   end
   ```

2. **Add the bundle identifier to `Matchfile`** in the `app_identifier` array.

3. **Run `match appstore --force`** to generate and store the provisioning profile
   in the certificates repo.

4. **Add `update_code_signing_settings`** in the Fastfile's `build_ios` lane for
   the new target, specifying the correct `profile_name` and `targets`.

5. **Verify** with `match appstore --readonly` that all profiles install cleanly.

### Troubleshooting decryption failures

`AEAD authentication tag verification failed` means the `MATCH_PASSWORD` does not
match the passphrase used to encrypt the certificates repo.

Diagnosis:

- Check the git log of the certificates repo (`git log --oneline`) to see when it
  was last modified and by whom.
- If a recent `match --force` run re-encrypted with a wrong password, the repo and
  all secrets (GitHub + 1Password) need to be re-synchronized.
- The correct password is whatever successfully decrypts the repo **right now**.
  Test with `match appstore --readonly`.

From cedricziel/assistant, MIT.

More from cedricziel/assistant

Signals

Stars
6
Forks
1
Open issues
14
Last commit (this folder)
Apr 20, 2026 (6 months ago)
Last release
May 26, 2026 (5 months ago)

From GitHub (fetched Oct 24, 2026).

Details

License
MIT
First seen
Oct 24, 2026
Last checked
Oct 24, 2026

More from cedricziel

Cite this page

ios-codesigning skill. Agent Mart. https://agentmart.dev/skills/cedricziel-ios-codesigning (last updated 2026-10-24)