native-packages 0.6.0 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,189 @@
1
+ ---
2
+ title: macOS and Windows installers
3
+ description: Connect your DMG or Inno Setup script to the same build and publication process as your Linux packages.
4
+ nav_order: 5
5
+ ---
6
+
7
+ # macOS and Windows installers
8
+
9
+ This guide shows how to connect an existing DMG or Inno Setup script to
10
+ native-packages. You supply a built app and a packaging script. The build
11
+ command checks the app, runs your script, and records the finished installer's
12
+ checksum.
13
+
14
+ Build **DMGs on macOS** and **Inno installers on Windows**. These targets use
15
+ your native tools and do not need an nFPM executable.
16
+
17
+ ## Prepare your app
18
+
19
+ Build the complete application first, including any libraries and supporting
20
+ files. A macOS input can be `dist/Hello.app`. A Windows input can be a directory
21
+ such as `dist/windows` containing `hello.exe` and its dependencies.
22
+
23
+ If your inputs come from another job, download and unpack them before packaging.
24
+ Native targets require a local directory and use `build --version`; they do
25
+ not accept `build --release` downloads directly.
26
+
27
+ ## Configure the targets
28
+
29
+ Here is a complete configuration for an ARM64 Mac app and an x86-64 Windows app:
30
+
31
+ ```yaml
32
+ schema: 1
33
+ tool:
34
+ version: '0.7.0'
35
+ nfpm: '2.47.0'
36
+ nfpm:
37
+ name: hello
38
+ description: A small greeting application
39
+ maintainer: Your Name <you@example.com>
40
+ license: MIT
41
+ release:
42
+ repository: your-name/hello
43
+ targets:
44
+ macos-arm64:
45
+ platform: macos
46
+ arch: arm64
47
+ formats: [dmg]
48
+ input:
49
+ kind: directory
50
+ local: dist/Hello.app
51
+ native:
52
+ command: [ruby, packaging/dmg.rb, '@PAYLOAD@', '@PACKAGE@']
53
+ output: 'hello-@TAG@-macos-arm64.dmg'
54
+ windows-amd64:
55
+ platform: windows
56
+ arch: amd64
57
+ formats: [inno]
58
+ input:
59
+ kind: directory
60
+ local: dist/windows
61
+ native:
62
+ command: [ruby, packaging/setup.rb, '@PAYLOAD@', '@PACKAGE@', '@VERSION@']
63
+ output: 'hello-@TAG@-windows-setup.exe'
64
+ ```
65
+
66
+ The `nfpm` section still holds shared package metadata, and `tool.nfpm` keeps
67
+ mixed-platform configurations consistent. Native targets use `native.command`
68
+ to create their output.
69
+
70
+ For Intel Macs, use `arch: amd64`. Use `arch: universal` for a build containing
71
+ both Intel and ARM64 code. Architecture checks use Apple's `lipo`.
72
+
73
+ ## Write the packaging command
74
+
75
+ `native.command` is a list of arguments. It must include `@PACKAGE@`:
76
+
77
+ | Value | What your script receives |
78
+ | --- | --- |
79
+ | `@PAYLOAD@` | A temporary copy of the input to package. |
80
+ | `@PACKAGE@` | The exact, absolute path where the output must be created. |
81
+ | `@VERSION@` | App version, such as `1.2.3`. |
82
+ | `@TAG@` | Release tag, such as `v1.2.3`. |
83
+
84
+ Commands run in the configuration directory. They also receive
85
+ `NATIVE_PACKAGES_TARGET`, `NATIVE_PACKAGES_VERSION`, and `SOURCE_DATE_EPOCH`.
86
+
87
+ ### A minimal DMG script
88
+
89
+ For the `Hello.app` input above, create `packaging/dmg.rb`:
90
+
91
+ ```ruby
92
+ require "fileutils"
93
+ require "tmpdir"
94
+
95
+ payload, output = ARGV
96
+ abort "expected payload and output paths" unless payload && output
97
+ abort "output already exists" if File.exist?(output)
98
+
99
+ Dir.mktmpdir("hello-dmg-") do |staging|
100
+ FileUtils.cp_r(payload, File.join(staging, "Hello.app"), preserve: true)
101
+ File.symlink("/Applications", File.join(staging, "Applications"))
102
+ success = system("hdiutil", "create", "-volname", "Hello",
103
+ "-srcfolder", staging, "-format", "UDZO", output)
104
+ abort "DMG creation failed" unless success
105
+ end
106
+
107
+ abort "DMG verification failed" unless system("hdiutil", "verify", output)
108
+ ```
109
+
110
+ This places the app and an Applications shortcut inside a compressed disk
111
+ image. Adapt the volume name and app name to your project.
112
+
113
+ ### An Inno Setup script
114
+
115
+ Keep your app's `.iss` recipe in the repository. Have `packaging/setup.rb`
116
+ invoke your installed Inno compiler and pass it the three arguments above.
117
+ The wrapper should:
118
+
119
+ 1. Use `@PAYLOAD@` as the source directory for the recipe's files.
120
+ 2. Map `@VERSION@` to the app and numeric installer version fields.
121
+ 3. Set the compiler's output directory and filename from `@PACKAGE@`.
122
+ 4. Fail if compilation fails.
123
+
124
+ An Inno recipe also owns your app's identity, installation location, shortcuts,
125
+ and uninstall behavior. See the
126
+ [Inno command-line compiler documentation](https://jrsoftware.org/ishelp/topic_compilercmdline.htm)
127
+ for invoking it from your wrapper.
128
+
129
+ ## Build on each host
130
+
131
+ On the Mac:
132
+
133
+ ```sh
134
+ native-packages doctor --target macos-arm64
135
+ native-packages build --version 1.2.3 --target macos-arm64 --output dist/macos-packages
136
+ ```
137
+
138
+ On Windows:
139
+
140
+ ```sh
141
+ native-packages doctor --target windows-amd64
142
+ native-packages build --version 1.2.3 --target windows-amd64 --output dist/windows-packages
143
+ ```
144
+
145
+ `doctor` checks the host and the command's executable. Your script checks its
146
+ additional tools, such as the Inno compiler. `validate` and `build --dry-run`
147
+ do not execute it.
148
+
149
+ The build checks Mach-O or PE architecture, runs the script, and checks that
150
+ it produced exactly the declared DMG or EXE. Test installation, startup,
151
+ upgrades, and removal separately for your app.
152
+
153
+ ## Preserve the prepared input
154
+
155
+ Package the copy at `@PAYLOAD@`. A top-level `.app` keeps its basename; other
156
+ input directories are copied into a directory named `payload`.
157
+
158
+ The copy preserves file modes and safe internal relative symlinks, including
159
+ framework links. Dangling links, links escaping the input, and special files
160
+ are rejected. Your recipe and output hooks must leave the copied input
161
+ unchanged. Use your own temporary staging directory when arranging files.
162
+
163
+ The command must create only its declared output in the destination directory.
164
+ Keep logs and temporary files elsewhere.
165
+
166
+ ## Sign before recording checksums
167
+
168
+ For DMG targets, providing complete Apple credentials enables automatic input
169
+ signing and DMG notarization. Follow [Apple signing and notarization](apple-notarization.md).
170
+ The DMG script must preserve the signed app when copying it into the image.
171
+
172
+ For Windows, use an `after_package` hook to sign the output:
173
+
174
+ ```yaml
175
+ after_package: [pwsh, -File, packaging/sign.ps1, '@PACKAGE@']
176
+ ```
177
+
178
+ This runs before the output hash is recorded. It must preserve the output's
179
+ filename and file set. Do not sign or otherwise change the installer after
180
+ building; publication would reject the changed hash.
181
+
182
+ MSIX is a separate Windows format. It uses package metadata and file mappings
183
+ instead of `native.command`; see [Supported platforms](../_reference/platforms.md#msix).
184
+
185
+ ## Combine and publish
186
+
187
+ Use [Building across platforms](multi-platform.md) to combine these directories
188
+ with Linux builds. If your configuration also has AUR or Homebrew templates,
189
+ that guide explains how to generate recipes after all native packages exist.
@@ -0,0 +1,72 @@
1
+ ---
2
+ title: Prereleases
3
+ description: Build and publish alpha, beta, and release candidate packages with explicit version rules.
4
+ nav_order: 9
5
+ ---
6
+
7
+ # Prereleases
8
+
9
+ Use a prerelease to let people test an upcoming version before the stable
10
+ release. native-packages supports alpha, beta, and release candidate packages
11
+ for **DEB, RPM, DMG, and Inno Setup**.
12
+
13
+ ## Enable preview versions
14
+
15
+ Add this to your release settings:
16
+
17
+ ```yaml
18
+ release:
19
+ repository: your-name/hello
20
+ prereleases: true
21
+ ```
22
+
23
+ Then build with a version such as:
24
+
25
+ ```sh
26
+ native-packages build --version 1.2.3-alpha.1
27
+ ```
28
+
29
+ Accepted suffixes are `-alpha.N`, `-beta.N`, and `-rc.N`, where `N` is a positive
30
+ integer. Build metadata suffixes such as `+build.5` are not accepted.
31
+ Stable versions such as `1.2.3` continue to work.
32
+
33
+ DEB and RPM use the packaging helper's version conversion; for example,
34
+ `1.2.3-alpha.1` becomes `1.2.3~alpha.1`. Keep the normal SemVer conversion
35
+ enabled and do not override the prerelease field.
36
+
37
+ ## Keep distribution recipes for stable releases
38
+
39
+ The simplest setup is a separate preview configuration with supported formats
40
+ and no `templates`:
41
+
42
+ ```sh
43
+ native-packages --config native-packages.preview.yaml build \
44
+ --version 1.2.3-beta.1
45
+ ```
46
+
47
+ If a native build shares a configuration with stable AUR or Homebrew recipes,
48
+ you can use `--defer-recipes` to produce its preview package. Those recipes
49
+ cannot be finalized for a prerelease, and the deferred build cannot be passed
50
+ to `publish --from`. Collect the native output through your application's
51
+ release job, or use a separate preview configuration for normal CLI publication.
52
+
53
+ ## Publish to a GitHub prerelease
54
+
55
+ Create the matching GitHub release, such as `v1.2.3-alpha.1`, and mark it as a
56
+ prerelease. Then publish a complete, non-deferred build:
57
+
58
+ ```sh
59
+ native-packages publish --from dist/packages/1.2.3-alpha.1 --to github
60
+ ```
61
+
62
+ The command checks that the existing release is marked as a prerelease. It
63
+ does not create the release or change its status. Downstream recipe publication
64
+ is reserved for stable versions.
65
+
66
+ ## Native installer versions
67
+
68
+ Your DMG or Inno script receives the app version, including the suffix.
69
+ If the installer needs numeric version fields, define that mapping in your
70
+ app's script. Test that alpha 2 upgrades alpha 1 and that the stable version
71
+ upgrades the previews. The packaging tool does not choose that ordering policy
72
+ for your application.
@@ -0,0 +1,143 @@
1
+ ---
2
+ title: Publishing a release
3
+ description: Build packages from local files or GitHub release assets and publish the verified result.
4
+ nav_order: 3
5
+ ---
6
+
7
+ # Publishing a release
8
+
9
+ Once you have [built and tested your packages](getting-started.md), you can
10
+ attach them to a GitHub release. This guide covers both local inputs and
11
+ binaries that are already uploaded to a release.
12
+
13
+ ## 1. Choose the release repository
14
+
15
+ Add your GitHub repository to `native-packages.yaml` before building:
16
+
17
+ ```yaml
18
+ release:
19
+ repository: your-name/hello
20
+ ```
21
+
22
+ This is where native-packages downloads release inputs and uploads packages.
23
+ It can be a separate repository from your application's source code.
24
+
25
+ ## 2. Build your packages
26
+
27
+ ### From local files
28
+
29
+ Use the same command as during development:
30
+
31
+ ```sh
32
+ native-packages build --version 1.2.3
33
+ ```
34
+
35
+ This reads each target's `input.local`. You can build and test the packages
36
+ before creating a GitHub release.
37
+
38
+ ### From an existing GitHub release
39
+
40
+ To package binaries your release workflow has already uploaded, declare each
41
+ target's release asset name:
42
+
43
+ ```yaml
44
+ input:
45
+ kind: archive
46
+ local: dist/hello_@VERSION@_linux_amd64.tar.gz
47
+ release_asset: hello_@VERSION@_linux_amd64.tar.gz
48
+ ```
49
+
50
+ The local path remains useful for development. `release_asset` is the exact
51
+ filename attached to the GitHub release; `@VERSION@` becomes `1.2.3`.
52
+
53
+ Upload a `checksums.txt` alongside the input archives. It must contain SHA-256
54
+ hashes with the release filenames. For example, run this in the directory
55
+ containing the archive, then upload both files through your release workflow:
56
+
57
+ ```sh
58
+ sha256sum hello_1.2.3_linux_amd64.tar.gz > checksums.txt
59
+ ```
60
+
61
+ For several binary inputs, include all of them in the same checksum file.
62
+ If your workflow uses another filename, set `release.checksums` to that name.
63
+
64
+ Now build from the published release:
65
+
66
+ ```sh
67
+ native-packages build --release v1.2.3
68
+ ```
69
+
70
+ The command downloads the inputs, verifies their published hashes, and builds
71
+ packages in `dist/packages/1.2.3/`. It skips `before_build` hooks. Every binary
72
+ release input needs a matching checksum.
73
+
74
+ DMG and Inno targets use prepared local directories. Download and unpack their
75
+ inputs in the native build job, then use `--version`. See
76
+ [macOS and Windows installers](native-recipes.md).
77
+
78
+ ## 3. Upload the finished build
79
+
80
+ Install and authenticate the [GitHub CLI](https://cli.github.com/), and create
81
+ release `v1.2.3` in the configured repository using your normal release process.
82
+ The release must exist before you publish packages.
83
+
84
+ ```sh
85
+ native-packages publish --from dist/packages/1.2.3 --to github
86
+ ```
87
+
88
+ Before uploading, native-packages verifies the recorded file hashes, the
89
+ configuration, and the required targets and formats. Keep the build directory
90
+ intact and use the same configuration you built with.
91
+
92
+ The upload includes the package files, a recipe archive if one was generated,
93
+ and `packaging-checksums.txt`. Your original `checksums.txt` is preserved.
94
+ Files with matching names on the release are replaced, so publish the tested
95
+ build you intend users to download.
96
+
97
+ ## Publish selected targets
98
+
99
+ By default, publication requires every configured target and all its formats.
100
+ If one configuration includes targets released by separate jobs, name exactly
101
+ which complete targets this build contains:
102
+
103
+ ```sh
104
+ native-packages build --release v1.2.3 \
105
+ --target linux-amd64 --output dist/linux-packages
106
+ native-packages publish --from dist/linux-packages --to github \
107
+ --target linux-amd64
108
+ ```
109
+
110
+ All formats for `linux-amd64` must be present, and the directory must contain
111
+ no additional targets. A build made with `--format deb` cannot be published
112
+ if that target also declares RPM.
113
+
114
+ To combine builds from several jobs, follow
115
+ [Building across platforms](multi-platform.md). Builds with deferred recipes
116
+ must be finalized before publication.
117
+
118
+ ## Update distribution recipes
119
+
120
+ For AUR, Homebrew, or another downstream repository, first configure its
121
+ [recipe templates and destination](distribution-recipes.md). Then stage and
122
+ review the generated update:
123
+
124
+ ```sh
125
+ native-packages stage aur dist/packages/1.2.3/recipes
126
+ native-packages diff aur
127
+ native-packages publish aur
128
+ ```
129
+
130
+ Once this is part of your tested release process, you can publish configured
131
+ destinations together:
132
+
133
+ ```sh
134
+ native-packages publish --from dist/packages/1.2.3 --to github,aur,homebrew
135
+ ```
136
+
137
+ GitHub pull requests and GitLab merge requests require a reviewed description
138
+ with `--body-file`. Publish those destinations individually.
139
+
140
+ ## Next steps
141
+
142
+ Set up [GitHub Actions](github-actions.md) to run packaging for each release.
143
+ For alpha and beta versions, read [Prereleases](prereleases.md).
@@ -0,0 +1,137 @@
1
+ ---
2
+ title: Release signatures and attestations
3
+ description: Share release signing machinery while keeping application keys, approval policy and build identity separate.
4
+ nav_order: 10
5
+ ---
6
+
7
+ # Release signatures and attestations
8
+
9
+ Publisher signatures authorize release downloads. Build attestations identify
10
+ which repository, workflow and commit produced an artifact. Use both when your
11
+ application downloads its own updates. Neither proves the source code is safe.
12
+ These features are available in native-packages 0.7.0 and later. Use the
13
+ released gem for local commands and pin composite actions to the reviewed
14
+ commit behind the corresponding release tag.
15
+
16
+ ## Keep the trust policy in the application
17
+
18
+ Each application owns its private key, committed public key, updater verification
19
+ and release approval rules. Do not share a key between unrelated applications,
20
+ store private keys in native-packages, or fetch an updater's trust root from the
21
+ same release it is checking. There is no unsigned fallback when signing is used.
22
+
23
+ Store the private PKCS#8 PEM key in a protected GitHub environment in the
24
+ application repository. Restrict that environment to release tags and require
25
+ maintainer approval. Keep an encrypted backup outside GitHub. Approval should
26
+ cover the exact commit, build results and artifacts, not just a version label.
27
+ Only the final signing job needs this secret. PR/build jobs do not.
28
+
29
+ This uses GitHub-hosted key custody, not an independent offline authority.
30
+ Maintain separate Apple notarization and Windows Authenticode credentials where
31
+ needed; a checksum signature does not replace either platform's signing system.
32
+
33
+ ## Generate, sign and verify locally
34
+
35
+ Put only the finished release artifacts in a staging directory. Do not include
36
+ private keys, source checkout folders or intermediate build files. Keep the
37
+ public key outside this directory too.
38
+
39
+ ```sh
40
+ native-packages release-checksums dist/release --output dist/release/checksums.txt
41
+ native-packages sign-checksums dist/release/checksums.txt --public-key assets/update-public-key.hex
42
+ native-packages verify-checksums dist/release/checksums.txt --public-key assets/update-public-key.hex
43
+ ```
44
+
45
+ Provide the private PEM through `NATIVE_PACKAGES_SIGNING_KEY` using your secret
46
+ manager. `--key-env VARIABLE` selects another environment variable, not its
47
+ value. Never put a private key on a command line or enable shell tracing.
48
+ Signing reads the key in-process, removes it from that process's environment,
49
+ and creates no private key file. It does not promise secure erasure of Ruby or
50
+ OpenSSL memory. Missing, malformed, wrong or non-Ed25519 keys fail closed.
51
+
52
+ The output is a deterministic, sorted SHA-256 manifest plus a raw 64-byte
53
+ Ed25519 signature over its exact bytes. The public-key file is 32 bytes encoded
54
+ as 64 hex digits. This is Ed25519, not Ed25519ph. Signing verifies the listed
55
+ files first; verification authenticates the manifest before reading its paths.
56
+ Metadata is limited to 1 MiB. Filenames must be flat ASCII names beginning with
57
+ a letter or digit, using letters, digits, dots, underscores, plus or minus.
58
+ Symlinks, directories, duplicate names (including case collisions), path
59
+ traversal and self-references are rejected. Existing outputs are not overwritten.
60
+ Upload artifacts, `checksums.txt` and `checksums.txt.sig` together.
61
+
62
+ These are explicit commands. Existing `build --release` and `publish` behavior
63
+ is unchanged: they do not silently gain signature verification or signing.
64
+ To verify a downloaded release, stage its files and explicitly run
65
+ `verify-checksums` with your locally trusted public key before using those files.
66
+ Package publication's separate `packaging-checksums.txt` is also unchanged.
67
+
68
+ ## Attest in the application's build job
69
+
70
+ The examples use `v0.7.0` for readability. For release workflows, replace it
71
+ with that release's reviewed full commit SHA, not a mutable branch.
72
+ After producing the final package, before uploading it, add this step to the
73
+ job that built it:
74
+
75
+ ```yaml
76
+ permissions:
77
+ contents: read
78
+ id-token: write
79
+ attestations: write
80
+ steps:
81
+ # Existing checkout, build, platform signing and packaging steps go here.
82
+ - uses: crmne/native-packages/.github/actions/attest@v0.7.0
83
+ with:
84
+ subject-path: dist/*.tar.gz
85
+ ```
86
+
87
+ `subject-path` accepts a glob or newline-separated list. The composite action
88
+ runs inside the calling job, preserving the application's build identity.
89
+ It uses GitHub's pinned `actions/attest` implementation and needs no publisher
90
+ key. It exposes `bundle-path` and `attestation-url` outputs. Each platform job
91
+ attests its own final artifacts. A packaging-only job can attest the package it
92
+ made, but that does not establish provenance for an earlier executable build.
93
+
94
+ Consumers can verify a file with:
95
+
96
+ ```sh
97
+ gh attestation verify FILE --repo OWNER/APP
98
+ ```
99
+
100
+ For tighter policy, also constrain `--signer-workflow` and `--source-digest`.
101
+ See [GitHub's artifact attestation documentation](https://docs.github.com/en/actions/how-tos/secure-your-work/use-artifact-attestations/use-artifact-attestations).
102
+
103
+ ## Sign in the approved publication job
104
+
105
+ After every build passes, download the final artifacts into a flat directory in
106
+ a fresh signing job. Set its `environment: release-signing` in the app workflow
107
+ and install Ruby 3.2 or later with Ed25519-capable OpenSSL before the signing
108
+ step. Then call:
109
+
110
+ ```yaml
111
+ - uses: crmne/native-packages/.github/actions/sign-release@v0.7.0
112
+ with:
113
+ directory: dist/release
114
+ public-key: assets/update-public-key.hex
115
+ env:
116
+ NATIVE_PACKAGES_SIGNING_KEY: ${{ secrets.UPDATE_SIGNING_KEY }}
117
+ ```
118
+
119
+ The action uses the CLI from its own pinned source commit. It neither installs
120
+ the gem nor runs project hooks, builds, tags, publishes or approves deployments.
121
+ The caller checks out its committed public key and owns the publication step.
122
+ For an existing secret variable name, set the action's `key-env` input.
123
+ The action requires a fresh directory without an old checksum/signature pair.
124
+
125
+ ## Updater integration and key changes
126
+
127
+ Embed the public key in the app. Reject missing or invalid signatures before
128
+ accepting a checksum or downloading a package. Bind checksums to exact
129
+ version/platform filenames, reject downgrade/replay updates, and retain package
130
+ size checks, installation acknowledgement and rollback.
131
+
132
+ The initial signature-enforcing version needs a trusted installation. Old
133
+ hash-only clients are not protected until upgraded. Changing the key requires a
134
+ tested compatibility transition in each app; the single-signature format here
135
+ does not provide automatic key rotation. If a key is lost or compromised, stop
136
+ automatic publication, revoke the secret and use an independently verified
137
+ recovery installer. Do not replace an updater's trusted key from unsigned data.