@gjsify/cli 0.43.0 → 0.45.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.
- package/dist/cli.gjs.mjs +453 -425
- package/lib/actions/build.js +2 -1
- package/lib/commands/affected-classify.js +7 -5
- package/lib/commands/build.js +6 -0
- package/lib/commands/flatpak/ci.js +10 -2
- package/lib/commands/flatpak/init.js +15 -16
- package/lib/commands/flatpak/utils.d.ts +0 -26
- package/lib/commands/flatpak/utils.js +4 -29
- package/lib/commands/gettext.d.ts +2 -1
- package/lib/commands/gettext.js +105 -47
- package/lib/commands/onboard.d.ts +7 -0
- package/lib/commands/onboard.js +349 -96
- package/lib/commands/ship.d.ts +3 -0
- package/lib/commands/ship.js +911 -70
- package/lib/commands/trust.d.ts +6 -0
- package/lib/commands/trust.js +1 -1
- package/lib/config.js +25 -0
- package/lib/types/cli-build-options.d.ts +11 -0
- package/lib/types/config-data.d.ts +137 -3
- package/lib/utils/flatpak-runtime.d.ts +41 -0
- package/lib/utils/flatpak-runtime.js +54 -0
- package/lib/utils/msgfmt-merge.d.ts +35 -0
- package/lib/utils/msgfmt-merge.js +102 -0
- package/lib/utils/npm-otp.d.ts +27 -2
- package/lib/utils/npm-otp.js +82 -7
- package/lib/utils/onboard-discovery.d.ts +68 -0
- package/lib/utils/onboard-discovery.js +178 -0
- package/lib/utils/onboard-probe.d.ts +118 -1
- package/lib/utils/onboard-probe.js +153 -4
- package/lib/utils/prompt-output.d.ts +12 -0
- package/lib/utils/prompt-output.js +54 -0
- package/lib/utils/prompt.js +22 -2
- package/lib/utils/publishable-packages.d.ts +1 -1
- package/lib/utils/publishable-packages.js +1 -0
- package/lib/utils/resolve-npm-package.d.ts +56 -0
- package/lib/utils/resolve-npm-package.js +69 -0
- package/lib/utils/ship/app-runtime.d.ts +214 -0
- package/lib/utils/ship/app-runtime.js +429 -0
- package/lib/utils/ship/depends.d.ts +54 -7
- package/lib/utils/ship/depends.js +120 -6
- package/lib/utils/ship/discover.js +18 -1
- package/lib/utils/ship/dmg.d.ts +71 -0
- package/lib/utils/ship/dmg.js +181 -0
- package/lib/utils/ship/flatpak-config.d.ts +66 -0
- package/lib/utils/ship/flatpak-config.js +132 -0
- package/lib/utils/ship/flatpak.d.ts +45 -0
- package/lib/utils/ship/flatpak.js +148 -0
- package/lib/utils/ship/formats.d.ts +116 -3
- package/lib/utils/ship/formats.js +869 -11
- package/lib/utils/ship/launcher.d.ts +13 -3
- package/lib/utils/ship/launcher.js +362 -17
- package/lib/utils/ship/layout.d.ts +268 -0
- package/lib/utils/ship/layout.js +351 -0
- package/lib/utils/ship/localize-metadata.d.ts +22 -0
- package/lib/utils/ship/localize-metadata.js +126 -0
- package/lib/utils/ship/mime.js +1 -9
- package/lib/utils/ship/msi.d.ts +126 -0
- package/lib/utils/ship/msi.js +417 -0
- package/lib/utils/ship/node-runtime.d.ts +71 -0
- package/lib/utils/ship/node-runtime.js +122 -0
- package/lib/utils/ship/payload.d.ts +156 -5
- package/lib/utils/ship/payload.js +580 -14
- package/lib/utils/ship/plan.d.ts +21 -0
- package/lib/utils/ship/plan.js +20 -7
- package/lib/utils/ship/plist.d.ts +58 -0
- package/lib/utils/ship/plist.js +198 -0
- package/lib/utils/ship/rpm.js +9 -3
- package/lib/utils/ship/schemas.d.ts +61 -0
- package/lib/utils/ship/schemas.js +118 -0
- package/lib/utils/ship/scripts.js +7 -3
- package/lib/utils/ship/settings.d.ts +19 -1
- package/lib/utils/ship/settings.js +19 -1
- package/lib/utils/ship/share-dirs.d.ts +23 -0
- package/lib/utils/ship/share-dirs.js +46 -0
- package/lib/utils/ship/signing.d.ts +195 -0
- package/lib/utils/ship/signing.js +317 -0
- package/lib/utils/ship/stage-manifest.d.ts +50 -13
- package/lib/utils/ship/stage-manifest.js +137 -14
- package/lib/utils/ship/stage-writer.d.ts +48 -0
- package/lib/utils/ship/stage-writer.js +71 -1
- package/lib/utils/ship/types.d.ts +264 -16
- package/lib/utils/ship/xml.d.ts +7 -0
- package/lib/utils/ship/xml.js +25 -0
- package/lib/utils/ship/zip.d.ts +69 -0
- package/lib/utils/ship/zip.js +245 -0
- package/lib/utils/trust-registry.js +5 -0
- package/package.json +19 -19
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { AppMetadata, ConfigDataFlatpak, ConfigDataShip, DescriptionBlock } from '../../types/config-data.js';
|
|
2
|
-
import type { ShipSettings } from './types.js';
|
|
2
|
+
import type { HostOs, ShipSettings } from './types.js';
|
|
3
3
|
/** The subset of `package.json` the resolver reads. */
|
|
4
4
|
export interface ShipPackageManifest {
|
|
5
5
|
name?: string;
|
|
@@ -42,11 +42,29 @@ export interface SettingsInput {
|
|
|
42
42
|
ship: ConfigDataShip;
|
|
43
43
|
/** Metadata fallback — `gjsify.flatpak` already carries these fields for many projects. */
|
|
44
44
|
flatpak: ConfigDataFlatpak;
|
|
45
|
+
/**
|
|
46
|
+
* What the command line decided before any config was read.
|
|
47
|
+
*
|
|
48
|
+
* `layoutOs` is REQUIRED, unlike its two neighbours, and the asymmetry is the
|
|
49
|
+
* point: `outDir` and `arch` have derived defaults that are correct when
|
|
50
|
+
* nobody says anything, while the layout is chosen by `gjsify ship <os>` (or
|
|
51
|
+
* by the host) before this function is reached. Making it optional would put
|
|
52
|
+
* a fourth default for it in here, and a second place that decides the layout
|
|
53
|
+
* is how the manifest's `target.os` and the staged paths come apart.
|
|
54
|
+
*/
|
|
45
55
|
cli: {
|
|
46
56
|
outDir?: string;
|
|
47
57
|
arch?: string;
|
|
58
|
+
layoutOs: HostOs;
|
|
48
59
|
};
|
|
49
60
|
discovered: DiscoveredPayload;
|
|
61
|
+
/**
|
|
62
|
+
* `gjsify.app` as DECLARED — `undefined` when the project declares nothing.
|
|
63
|
+
*
|
|
64
|
+
* Deliberately the raw config value and not `Config.forBuild`'s resolved one:
|
|
65
|
+
* see where it is defaulted below.
|
|
66
|
+
*/
|
|
67
|
+
app?: string;
|
|
50
68
|
}
|
|
51
69
|
export interface ResolvedSettings {
|
|
52
70
|
settings: ShipSettings;
|
|
@@ -11,7 +11,8 @@
|
|
|
11
11
|
// indistinguishable from a value the user typed and would clobber the config.
|
|
12
12
|
import { validateMimeTypes } from './mime.js';
|
|
13
13
|
import { basename } from 'node:path';
|
|
14
|
-
import { DEFAULT_GJS_FLOOR } from './depends.js';
|
|
14
|
+
import { DEFAULT_GJS_FLOOR, DEFAULT_NODE_FLOOR } from './depends.js';
|
|
15
|
+
import { resolveShipFlatpakSettings } from './flatpak-config.js';
|
|
15
16
|
import { assertRelease, normaliseVersion } from './version.js';
|
|
16
17
|
/** Freedesktop main category → deb `Section:` / rpm `Group:`. First match wins. */
|
|
17
18
|
const CATEGORY_SECTIONS = [
|
|
@@ -48,6 +49,14 @@ export function resolveShipSettings(input) {
|
|
|
48
49
|
const appId = ship.appId ?? flatpak.appId ?? reverseDnsOrThrow(pkg.name, binaryName);
|
|
49
50
|
const name = metadata.name ?? titleCase(binaryName);
|
|
50
51
|
const kind = metadata.kind ?? 'app';
|
|
52
|
+
// `gjsify.app`, defaulted HERE to `'gjs'` rather than taken from
|
|
53
|
+
// `Config.forBuild`'s resolution, which falls back to the HOST runtime. That
|
|
54
|
+
// fallback is right for a build (`gjsify build` under Node should produce a
|
|
55
|
+
// Node bundle by default) and catastrophic for a package: running this
|
|
56
|
+
// command under Node would silently turn every undeclared GJS project into
|
|
57
|
+
// one whose launcher execs `node`. An undeclared target is the common case
|
|
58
|
+
// for a GJS app, and it means GJS.
|
|
59
|
+
const app = input.app === 'node' ? 'node' : 'gjs';
|
|
51
60
|
const rawVersion = ship.version ?? pkg.version;
|
|
52
61
|
if (!rawVersion) {
|
|
53
62
|
throw new Error('gjsify ship: no version — set `version` in package.json or `gjsify.ship.version`.');
|
|
@@ -71,6 +80,11 @@ export function resolveShipSettings(input) {
|
|
|
71
80
|
warnings.push(`gjsify ship: no icon found — the installed app will show a placeholder in menus and app stores. ` +
|
|
72
81
|
'Point `gjsify.ship.icon` at an SVG (or a directory of sized PNGs).');
|
|
73
82
|
}
|
|
83
|
+
// Resolved here rather than in the packer, because the packer may run on a
|
|
84
|
+
// host with no `package.json` at all (ADR 0024 § A2) — and because the
|
|
85
|
+
// finish-args default depends on `kind`, which is a project fact.
|
|
86
|
+
const flatpakSettings = resolveShipFlatpakSettings({ ship, flatpak, kind });
|
|
87
|
+
warnings.push(...flatpakSettings.warnings);
|
|
74
88
|
const settings = {
|
|
75
89
|
projectDir: input.projectDir,
|
|
76
90
|
appId,
|
|
@@ -100,7 +114,11 @@ export function resolveShipSettings(input) {
|
|
|
100
114
|
execArgs: ship.execArgs ?? [],
|
|
101
115
|
outDir: input.cli.outDir ?? ship.outDir ?? 'ship',
|
|
102
116
|
arch: input.cli.arch ?? process.arch,
|
|
117
|
+
app,
|
|
118
|
+
layoutOs: input.cli.layoutOs,
|
|
103
119
|
minGjsVersion: ship.minGjsVersion ?? DEFAULT_GJS_FLOOR,
|
|
120
|
+
minNodeVersion: ship.minNodeVersion ?? DEFAULT_NODE_FLOOR,
|
|
121
|
+
flatpak: flatpakSettings.settings,
|
|
104
122
|
};
|
|
105
123
|
return { settings, metadata, warnings };
|
|
106
124
|
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Each entry is a directory the freedesktop/GNOME stack looks in BY NAME. None of
|
|
3
|
+
* them is ours to choose: `bindtextdomain` reads `share/locale/<lang>/LC_MESSAGES`,
|
|
4
|
+
* `glib-compile-schemas` compiles `share/glib-2.0/schemas`, and the icon theme
|
|
5
|
+
* spec fixes `share/icons/hicolor`. That is also why this is a closed set rather
|
|
6
|
+
* than a convention — a typo in any of them installs a file nothing ever reads.
|
|
7
|
+
*/
|
|
8
|
+
export declare const SHARE: {
|
|
9
|
+
/** freedesktop desktop entries. */
|
|
10
|
+
readonly applications: "share/applications";
|
|
11
|
+
/** The hicolor icon theme, whose cache `gtk-update-icon-cache` builds. */
|
|
12
|
+
readonly icons: "share/icons/hicolor";
|
|
13
|
+
/** GSettings schema sources, compiled into `gschemas.compiled` at install. */
|
|
14
|
+
readonly schemas: "share/glib-2.0/schemas";
|
|
15
|
+
/** shared-mime-info documents, folded into the mime cache at install. */
|
|
16
|
+
readonly mime: "share/mime/packages";
|
|
17
|
+
/** AppStream components. */
|
|
18
|
+
readonly metainfo: "share/metainfo";
|
|
19
|
+
/** Compiled gettext catalogues, read directly — no install step. */
|
|
20
|
+
readonly locale: "share/locale";
|
|
21
|
+
};
|
|
22
|
+
/** Is `path` inside `dir`? Directory-boundary aware, so `share/mimetypes` is not inside `share/mime`. */
|
|
23
|
+
export declare function isUnder(path: string, dir: string): boolean;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
// The `share/` subdirectories a payload installs into — ONE definition.
|
|
2
|
+
//
|
|
3
|
+
// WHY THIS FILE EXISTS, and it is a repair rather than a tidy-up. Four call
|
|
4
|
+
// sites answer questions about the same directories and every one of them spelled
|
|
5
|
+
// them out again: `plan.ts` stages a file there, `readPayloadFacts` asks whether
|
|
6
|
+
// the payload put anything there, `cacheRefreshCommands` emits the install step
|
|
7
|
+
// that makes it WORK, and `linuxInstallDependent` names the ones a non-Linux
|
|
8
|
+
// layout carries without that step. `share/glib-2.0/schemas` alone existed as
|
|
9
|
+
// five independent string literals across the tree.
|
|
10
|
+
//
|
|
11
|
+
// A comment claiming they "cannot drift" was measured FALSE: pointing one rule in
|
|
12
|
+
// `linuxInstallDependent` at a directory that matches nothing silently dropped a
|
|
13
|
+
// file from the warning `gjsify ship` prints, and the whole suite stayed green at
|
|
14
|
+
// exit 0. The prose was the mechanism, which is to say there was none. Importing
|
|
15
|
+
// one constant makes the compiler the mechanism instead.
|
|
16
|
+
//
|
|
17
|
+
// PREFIX-RELATIVE and POSIX-separated, like every path in the plan. The layout
|
|
18
|
+
// map (`layout.ts`) is what turns these into `Contents/Resources/share/…` or a
|
|
19
|
+
// Windows program directory's `share\`; nothing here knows about that, and
|
|
20
|
+
// nothing here is absolute — `scripts.ts` prepends the format's install prefix,
|
|
21
|
+
// which is `/usr` for a `.deb` and `/app` for a Flatpak.
|
|
22
|
+
/**
|
|
23
|
+
* Each entry is a directory the freedesktop/GNOME stack looks in BY NAME. None of
|
|
24
|
+
* them is ours to choose: `bindtextdomain` reads `share/locale/<lang>/LC_MESSAGES`,
|
|
25
|
+
* `glib-compile-schemas` compiles `share/glib-2.0/schemas`, and the icon theme
|
|
26
|
+
* spec fixes `share/icons/hicolor`. That is also why this is a closed set rather
|
|
27
|
+
* than a convention — a typo in any of them installs a file nothing ever reads.
|
|
28
|
+
*/
|
|
29
|
+
export const SHARE = {
|
|
30
|
+
/** freedesktop desktop entries. */
|
|
31
|
+
applications: 'share/applications',
|
|
32
|
+
/** The hicolor icon theme, whose cache `gtk-update-icon-cache` builds. */
|
|
33
|
+
icons: 'share/icons/hicolor',
|
|
34
|
+
/** GSettings schema sources, compiled into `gschemas.compiled` at install. */
|
|
35
|
+
schemas: 'share/glib-2.0/schemas',
|
|
36
|
+
/** shared-mime-info documents, folded into the mime cache at install. */
|
|
37
|
+
mime: 'share/mime/packages',
|
|
38
|
+
/** AppStream components. */
|
|
39
|
+
metainfo: 'share/metainfo',
|
|
40
|
+
/** Compiled gettext catalogues, read directly — no install step. */
|
|
41
|
+
locale: 'share/locale',
|
|
42
|
+
};
|
|
43
|
+
/** Is `path` inside `dir`? Directory-boundary aware, so `share/mimetypes` is not inside `share/mime`. */
|
|
44
|
+
export function isUnder(path, dir) {
|
|
45
|
+
return path.startsWith(`${dir}/`);
|
|
46
|
+
}
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
import { type PayloadEntry } from './payload.js';
|
|
2
|
+
import type { HostOs } from './types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Everything that is per-OS about making a signature, as data.
|
|
5
|
+
*
|
|
6
|
+
* The same shape argument `FormatDescriptor` makes one directory over: a second
|
|
7
|
+
* OS is a row, not a branch. It is a separate table from `FORMATS` on purpose —
|
|
8
|
+
* § A14 measured that a format declares where it can be PACKED and never what it
|
|
9
|
+
* can be signed with, and darwin has two format rows that must not be able to
|
|
10
|
+
* disagree about their signature.
|
|
11
|
+
*/
|
|
12
|
+
export interface SignerDescriptor {
|
|
13
|
+
/** The layout whose payload this signer signs. */
|
|
14
|
+
layoutOs: HostOs;
|
|
15
|
+
/** The command that makes the signature. */
|
|
16
|
+
tool: string;
|
|
17
|
+
/** OSes whose tooling can run {@link tool}. */
|
|
18
|
+
signOn: readonly HostOs[];
|
|
19
|
+
/** Where {@link tool} comes from, in this signer's own words. */
|
|
20
|
+
installHint: string;
|
|
21
|
+
/**
|
|
22
|
+
* Which payload files carry a signature on this OS.
|
|
23
|
+
*
|
|
24
|
+
* `classifyBinary`'s vocabulary, so the predicate is the magic number and
|
|
25
|
+
* not a filename pattern: a darwin closure names its images `.dylib`,
|
|
26
|
+
* `.so`, `.node` and nothing at all (the interpreter), and a suffix list
|
|
27
|
+
* would sign three of those four.
|
|
28
|
+
*/
|
|
29
|
+
signs: 'macho' | 'pe';
|
|
30
|
+
/** argv after {@link tool}, for ONE file. */
|
|
31
|
+
args: (identity: string, file: string) => readonly string[];
|
|
32
|
+
/** The config key a project spells its default identity under. */
|
|
33
|
+
configKey: string;
|
|
34
|
+
/** What a signature from this signer does NOT yet cover — printed once per run. */
|
|
35
|
+
gap: string;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* The signers, keyed by the LAYOUT they sign — never by the host they run on.
|
|
39
|
+
*
|
|
40
|
+
* Linux is deliberately absent rather than present-and-empty. A `.deb` and an
|
|
41
|
+
* `.rpm` carry no per-file signature: the artifact is signed as a whole, by the
|
|
42
|
+
* repository that serves it (`debsigs`, `rpmsign`), with a key that belongs to
|
|
43
|
+
* that repository and not to this build. A row here would make `--sign` on Linux
|
|
44
|
+
* look like it did something.
|
|
45
|
+
*/
|
|
46
|
+
export declare const SIGNERS: Partial<Record<HostOs, SignerDescriptor>>;
|
|
47
|
+
/** `gjsify.ship.sign` as declared — one entry per {@link HostOs}. */
|
|
48
|
+
export type SignConfig = Partial<Record<HostOs, {
|
|
49
|
+
identity?: string;
|
|
50
|
+
}>>;
|
|
51
|
+
/**
|
|
52
|
+
* What this run will do about signatures.
|
|
53
|
+
*
|
|
54
|
+
* A union rather than an optional string, because the three states need three
|
|
55
|
+
* different words and collapsing them is exactly what § A13 warns about: "no
|
|
56
|
+
* signer for this layout" is silence, "a slot exists and is empty" is a printed
|
|
57
|
+
* skip, and "here is an identity" is work.
|
|
58
|
+
*/
|
|
59
|
+
export type SignPlan = {
|
|
60
|
+
kind: 'unsupported';
|
|
61
|
+
} | {
|
|
62
|
+
kind: 'skip';
|
|
63
|
+
message: string;
|
|
64
|
+
} | {
|
|
65
|
+
kind: 'sign';
|
|
66
|
+
identity: string;
|
|
67
|
+
signer: SignerDescriptor;
|
|
68
|
+
source: 'flag' | 'config';
|
|
69
|
+
};
|
|
70
|
+
/**
|
|
71
|
+
* Resolve the identity for this run, or say why there is none.
|
|
72
|
+
*
|
|
73
|
+
* `flag` beats `config` and neither is a yargs `default:` — the uniform
|
|
74
|
+
* precedence `resolveShipSettings` documents. `config` is `undefined` on the
|
|
75
|
+
* `--from-stage` path and that is not an omission: § A14 amends § A1 to *a
|
|
76
|
+
* format declares where it can be packed; the RUN declares what it can sign
|
|
77
|
+
* with*, and the finishing host has no project to read a default out of.
|
|
78
|
+
*/
|
|
79
|
+
export declare function resolveSignPlan(input: {
|
|
80
|
+
/** `--sign` as typed. `''` is a value: it is `[ -z "$SIGN" ]` (§ A13). */
|
|
81
|
+
flag?: string;
|
|
82
|
+
/** `gjsify.ship.sign`, when a project is in reach. */
|
|
83
|
+
config?: SignConfig;
|
|
84
|
+
layoutOs: HostOs;
|
|
85
|
+
}): SignPlan;
|
|
86
|
+
/**
|
|
87
|
+
* Refuse a signing run this host cannot make, and say which half is missing.
|
|
88
|
+
*
|
|
89
|
+
* Two checks and not one, for the same reason `assertCanPack` splits them: the
|
|
90
|
+
* wrong OS needs another machine, an absent tool needs a package. Both are
|
|
91
|
+
* knowable before anything is packed.
|
|
92
|
+
*/
|
|
93
|
+
export declare function assertHostCanSign(signer: SignerDescriptor): void;
|
|
94
|
+
export interface SignPayloadInput {
|
|
95
|
+
/** What `readStage` returned — the PRE-sign tree, already held against the manifest. */
|
|
96
|
+
payload: readonly PayloadEntry[];
|
|
97
|
+
identity: string;
|
|
98
|
+
signer: SignerDescriptor;
|
|
99
|
+
/** A scratch directory this function owns and WIPES. Never the arriving stage. */
|
|
100
|
+
workDir: string;
|
|
101
|
+
/** Print every invocation. */
|
|
102
|
+
verbose: boolean;
|
|
103
|
+
log: (line: string) => void;
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Re-sign every signable image in the payload, and hand back the new bytes.
|
|
107
|
+
*
|
|
108
|
+
* The signature is made on FILES because that is the only interface `codesign`
|
|
109
|
+
* and `signtool` have, so the payload is materialised into `workDir`, signed
|
|
110
|
+
* there, and read back. `workDir` is a scratch directory rather than the stage:
|
|
111
|
+
* writing into an arriving stage would make the next `--from-stage` run of the
|
|
112
|
+
* same tree fail `readStage`'s size comparison (measured — see the header), and
|
|
113
|
+
* `writeStage`'s wipe would delete the payload it was about to pack.
|
|
114
|
+
*
|
|
115
|
+
* THE FILE SET MAY NOT CHANGE, and that is asserted rather than assumed. Both
|
|
116
|
+
* tools rewrite an image in place, so a payload that gained or lost a path here
|
|
117
|
+
* means something else ran — a bundle seal writing `_CodeSignature/`, say, whose
|
|
118
|
+
* files would then be dropped on the way back into the payload without anyone
|
|
119
|
+
* noticing.
|
|
120
|
+
*/
|
|
121
|
+
export declare function signPayload(input: SignPayloadInput): Promise<PayloadEntry[]>;
|
|
122
|
+
/**
|
|
123
|
+
* What this run will do about notarisation.
|
|
124
|
+
*
|
|
125
|
+
* A SECOND credential and an unrelated one (§ A15): `--sign` names an identity
|
|
126
|
+
* the signing machine holds, `--notarize` names an account credential. They are
|
|
127
|
+
* two flags because they are two inputs, and the reference keeps them in two
|
|
128
|
+
* scripts.
|
|
129
|
+
*/
|
|
130
|
+
export interface NotaryDescriptor {
|
|
131
|
+
layoutOs: HostOs;
|
|
132
|
+
tool: string;
|
|
133
|
+
notarizeOn: readonly HostOs[];
|
|
134
|
+
installHint: string;
|
|
135
|
+
/**
|
|
136
|
+
* argv after {@link tool}.
|
|
137
|
+
*
|
|
138
|
+
* `credential` is threaded straight into the flag the command consumes, and
|
|
139
|
+
* that is the whole design of {@link resolveNotaryPlan}'s guard. § A15
|
|
140
|
+
* measured the trap: `refs/node/tools/osx-notarize.sh` guards on three
|
|
141
|
+
* environment variables it never uses and then submits with a
|
|
142
|
+
* `--keychain-profile` nothing checked, so the skip is reachable from an
|
|
143
|
+
* input the next line does not read. Here the guarded value IS the argument.
|
|
144
|
+
*
|
|
145
|
+
* ⚠️ `--keychain-profile` is the ONLY shape § A15 found evidenced, and the
|
|
146
|
+
* App Store Connect API-key form (`--key`/`--key-id`/`--issuer`) is NOT
|
|
147
|
+
* implemented because nothing measured it. UNVERIFIED, and marked as such:
|
|
148
|
+
* no run in this repository has ever invoked `notarytool` — notarisation
|
|
149
|
+
* needs an Apple account, which ad-hoc signing deliberately does not.
|
|
150
|
+
*/
|
|
151
|
+
args: (credential: string, artifact: string) => readonly string[];
|
|
152
|
+
}
|
|
153
|
+
export declare const NOTARIES: Partial<Record<HostOs, NotaryDescriptor>>;
|
|
154
|
+
export type NotaryPlan = {
|
|
155
|
+
kind: 'unsupported';
|
|
156
|
+
} | {
|
|
157
|
+
kind: 'skip';
|
|
158
|
+
message: string;
|
|
159
|
+
} | {
|
|
160
|
+
kind: 'notarize';
|
|
161
|
+
credential: string;
|
|
162
|
+
notary: NotaryDescriptor;
|
|
163
|
+
};
|
|
164
|
+
/**
|
|
165
|
+
* Resolve the notarisation credential, or say why there is none.
|
|
166
|
+
*
|
|
167
|
+
* Deliberately NOT defaultable from the project. An identity is a name a machine
|
|
168
|
+
* may hold for years and is worth writing into a repository; a notarisation
|
|
169
|
+
* credential is a per-run account credential, and a config key for it is an
|
|
170
|
+
* invitation to commit one.
|
|
171
|
+
*/
|
|
172
|
+
export declare function resolveNotaryPlan(input: {
|
|
173
|
+
flag?: string;
|
|
174
|
+
layoutOs: HostOs;
|
|
175
|
+
sign: SignPlan;
|
|
176
|
+
}): NotaryPlan;
|
|
177
|
+
/**
|
|
178
|
+
* Submit one written artifact for notarisation.
|
|
179
|
+
*
|
|
180
|
+
* ⚠️ UNVERIFIED END TO END. Everything up to the `spawnToCompletion` is covered
|
|
181
|
+
* — the argv by `signing.spec.ts`, the guard and both refusals by
|
|
182
|
+
* `tests/e2e/ship-signing` — and the invocation itself has never run: it needs
|
|
183
|
+
* an Apple Developer account, and § A17's whole point is that M6's proof does
|
|
184
|
+
* not. Whoever first runs this on a real credential should record what it did
|
|
185
|
+
* beside § A15, which is where the question was left open.
|
|
186
|
+
*/
|
|
187
|
+
export declare function notarizeArtifact(input: {
|
|
188
|
+
plan: Extract<NotaryPlan, {
|
|
189
|
+
kind: 'notarize';
|
|
190
|
+
}>;
|
|
191
|
+
/** The artifact to submit. Must be a FILE — notarytool takes an archive or an installer. */
|
|
192
|
+
artifact: string;
|
|
193
|
+
verbose: boolean;
|
|
194
|
+
log: (line: string) => void;
|
|
195
|
+
}): Promise<void>;
|