---
title: Code Signing
url: "https://native-sdk.dev/docs/packaging/signing"
docs_index: /llms.txt
lastUpdated: 2026-10-16
---

> For an index of all documentation, see [/llms.txt](/llms.txt).

Sign and notarize your Native SDK app for distribution.

## macOS signing

Sign the bundle with a Developer ID:

```bash
native package --target macos --signing identity --identity "Developer ID Application: Your Name"
```

Identity signing enables the hardened runtime and explicitly requests Apple's secure timestamp. If the timestamp service cannot be reached, packaging fails instead of producing a distribution signature that notarization will reject.

Signing modes:

<table>
  <thead>
    <tr>
      <th>
        Mode
      </th>

      <th>
        Description
      </th>
    </tr>
  </thead>

  <tbody>
    <tr>
      <td>
        `none`
      </td>

      <td>
        No signing (default)
      </td>
    </tr>

    <tr>
      <td>
        `adhoc`
      </td>

      <td>
        Ad-hoc signing for local testing
      </td>
    </tr>

    <tr>
      <td>
        `identity`
      </td>

      <td>
        Sign with a named identity (requires

        `--identity`

        )
      </td>
    </tr>
  </tbody>
</table>

## What Gatekeeper shows for an ad-hoc package

An ad-hoc signature verifies bundle integrity but carries no developer identity. Gatekeeper may block a downloaded copy that has the quarantine attribute. The dialog and available override controls depend on the macOS version and device policy; when permitted, users can allow a blocked app in **System Settings → Privacy & Security**.

Local builds and some file-transfer methods do not add quarantine, but an existing quarantine attribute may be preserved. Do not use the absence of a launch dialog as evidence of a distribution signature.

Use `codesign --verify --strict` to check the signature. If verification fails, rebuild and sign the final bundle after copying its resources. For public distribution, use Developer ID signing and notarization.

## Signing flags

<table>
  <thead>
    <tr>
      <th>
        Flag
      </th>

      <th>
        Description
      </th>
    </tr>
  </thead>

  <tbody>
    <tr>
      <td>
        `--signing`
      </td>

      <td>
        Signing mode:

        `none`

        ,

        `adhoc`

        , or

        `identity`
      </td>
    </tr>

    <tr>
      <td>
        `--identity`
      </td>

      <td>
        Code signing identity name
      </td>
    </tr>

    <tr>
      <td>
        `--entitlements`
      </td>

      <td>
        Path to entitlements file (e.g.

        `assets/native-sdk.entitlements`

        )
      </td>
    </tr>

    <tr>
      <td>
        `--notarize`
      </td>

      <td>
        Submit the final macOS artifact, then staple and validate the accepted ticket
      </td>
    </tr>

    <tr>
      <td>
        `--notary-profile`
      </td>

      <td>
        Name of a

        `notarytool`

        Keychain profile created with

        `store-credentials`
      </td>
    </tr>
  </tbody>
</table>

## Notarization

Store notarization credentials in Keychain once. A team App Store Connect API key is the normal CI choice:

```bash
xcrun notarytool store-credentials "my-app-release" \
  --key /path/to/AuthKey_KEYID.p8 \
  --key-id KEYID \
  --issuer ISSUER_UUID
```

Apple ID credentials work too:

```bash
xcrun notarytool store-credentials "my-app-release" \
  --apple-id "you@example.com" \
  --team-id TEAMID \
  --password APP_SPECIFIC_PASSWORD
```

Then package, timestamp-sign, notarize, staple, and validate in one command:

```bash
native package --target macos \
  --signing identity \
  --identity "Developer ID Application: Your Name (TEAMID)" \
  --archive \
  --notarize \
  --notary-profile "my-app-release"
```

With `--archive`, Native SDK first submits the signed app, staples and validates it, then builds and signs the DMG and submits, staples, and validates that final image. Without `--archive`, only the app submission runs. Any updater ZIP is created afterward from the stapled app.

The framework repository exposes the same path for local release testing:

```bash
zig build notarize \
  -Didentity="Developer ID Application: Your Name (TEAMID)" \
  -Dnotary-profile="my-app-release"
```

## Chromium apps

Chromium packages include `Chromium Embedded Framework.framework` inside the `.app`. Sign and notarize the final package after CEF has been bundled so the app binary, helper executables, and embedded framework are covered by the same distribution identity.

```bash
native cef install --version <pinned-version>
zig build
native package --target macos --signing identity --identity "Developer ID Application: Your Name" --archive
```

Use `.web_engine = "chromium"` and `.cef = .{ .dir = "third_party/cef/macos", .auto_install = false }` in `app.zon` for the normal signing path. `-Dweb-engine`, `--web-engine`, `-Dcef-dir`, and `--cef-dir` remain available for temporary overrides.

If Gatekeeper rejects the app, check that the CEF framework is present in `Contents/Frameworks`, that every nested helper is signed, and that the package was rebuilt after any CEF version change.

## DMG creation

Create a distributable disk image:

```bash
native package --target macos --archive
```

This creates the conventional drag-to-Applications presentation by default: a generated background and arrow, positioned app and Applications icons, hidden Finder chrome, and a compressed final image. Customize it through the [`dmg` manifest fields](/docs/packaging#dmg-archives).

## Entitlements

The project includes `assets/native-sdk.entitlements` as a starting point. Customize it for your app's needs (e.g. network access, file system access, camera).

---

For a semantic overview of all documentation, see [/sitemap.md](/sitemap.md)

For an index of all available documentation, see [/llms.txt](/llms.txt)

For agent-facing discovery, including API and MCP surfaces, see [/agents.md](/agents.md)