create-principles-disciple 1.134.9 → 1.135.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/console/dist/server/routes/update.js +41 -1
- package/console/dist/server/update/mutation-controller.d.ts +41 -1
- package/console/dist/server/update/mutation-controller.js +34 -2
- package/core/dist/index.d.ts +1 -2
- package/core/dist/index.d.ts.map +1 -1
- package/core/dist/index.js +0 -2
- package/core/dist/index.js.map +1 -1
- package/core/dist/runtime-v2/index.d.ts +0 -3
- package/core/dist/runtime-v2/index.d.ts.map +1 -1
- package/core/dist/runtime-v2/index.js +0 -2
- package/core/dist/runtime-v2/index.js.map +1 -1
- package/core/package.json +1 -1
- package/dist/update/release-manager-authority.d.ts +13 -10
- package/dist/update/release-manager-authority.d.ts.map +1 -1
- package/dist/update/release-manager-authority.js +24 -14
- package/dist/update/release-manager-authority.js.map +1 -1
- package/dist/update/release-metadata-publisher.d.ts +142 -0
- package/dist/update/release-metadata-publisher.d.ts.map +1 -0
- package/dist/update/release-metadata-publisher.js +340 -0
- package/dist/update/release-metadata-publisher.js.map +1 -0
- package/package.json +1 -1
- package/plugin/dist/bundle.js +422 -422
- package/plugin/dist/governance-audit.js +157 -157
- package/plugin/dist/rulehost-evidence.js +166 -166
- package/release-manager/dist/update/release-manager-authority.d.ts +13 -10
- package/release-manager/dist/update/release-manager-authority.d.ts.map +1 -1
- package/release-manager/dist/update/release-manager-authority.js +24 -14
- package/release-manager/dist/update/release-manager-authority.js.map +1 -1
- package/release-manager/dist/update/release-metadata-publisher.d.ts +142 -0
- package/release-manager/dist/update/release-metadata-publisher.d.ts.map +1 -0
- package/release-manager/dist/update/release-metadata-publisher.js +340 -0
- package/release-manager/dist/update/release-metadata-publisher.js.map +1 -0
- package/release-manager/package.json +1 -1
- package/core/dist/runtime-v2/runtime-selector.d.ts +0 -77
- package/core/dist/runtime-v2/runtime-selector.d.ts.map +0 -1
- package/core/dist/runtime-v2/runtime-selector.js +0 -23
- package/core/dist/runtime-v2/runtime-selector.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"release-manager-authority.d.ts","sourceRoot":"","sources":["../../src/update/release-manager-authority.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"release-manager-authority.d.ts","sourceRoot":"","sources":["../../src/update/release-manager-authority.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2CG;AAGH,OAAO,EACL,cAAc,EAEd,KAAK,aAAa,EAClB,KAAK,qBAAqB,EAC3B,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EAAgC,KAAK,qBAAqB,EAAE,MAAM,8BAA8B,CAAC;AAExG,+EAA+E;AAC/E,eAAO,MAAM,+BAA+B,YAAI,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,UAAU,CAAU,CAAC;AACrG,MAAM,MAAM,2BAA2B,GAAG,CAAC,OAAO,+BAA+B,CAAC,CAAC,MAAM,CAAC,CAAC;AAE3F,iGAAiG;AACjG,MAAM,MAAM,2BAA2B,GAAG,wBAAwB,GAAG,2BAA2B,CAAC;AAEjG,MAAM,MAAM,6BAA6B,GACrC,8BAA8B,GAC9B,yBAAyB,GACzB,uBAAuB,GACvB,uBAAuB,GACvB,2BAA2B,CAAC;AAEhC,MAAM,WAAW,gCAAgC;IAC/C,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,OAAO,EAAE,SAAS,6BAA6B,EAAE,CAAC;CAC5D;AAeD,MAAM,WAAW,8BAA8B;IAC7C,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,qFAAqF;IACrF,QAAQ,CAAC,eAAe,EAAE,MAAM,GAAG,SAAS,CAAC;IAC7C,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,IAAI,CAAC;IAC1B,mFAAmF;IACnF,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC,cAAc,EAAE,MAAM,KAAK,OAAO,CAAC,qBAAqB,GAAG,IAAI,CAAC,CAAC;CAC1F;AAED,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,OAAO,EAAE,cAAc,CAAC;IACjC,mFAAmF;IACnF,QAAQ,CAAC,aAAa,EAAE,aAAa,GAAG,IAAI,CAAC;IAC7C,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,2BAA2B,EAAE,gCAAgC,CAAC,CAAC,CAAC;IAChG;;;;;OAKG;IACH,QAAQ,CAAC,cAAc,EAAE,qBAAqB,CAAC;CAChD;AAkBD,wBAAgB,6BAA6B,CAC3C,OAAO,EAAE,8BAA8B,GACtC,uBAAuB,CAkFzB;AAED;;;;;;;;GAQG;AACH,wBAAgB,gCAAgC,CAAC,KAAK,EAAE,OAAO,GAAG;IAChE,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,iBAAiB,EAAE,OAAO,CAAC;CAC5B,CAeA"}
|
|
@@ -27,19 +27,20 @@
|
|
|
27
27
|
* decision that must stay explicit (see the analysis doc §4.3); it can never
|
|
28
28
|
* be relaxed for apply/apply-full/rollback.
|
|
29
29
|
*
|
|
30
|
-
* apply
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
30
|
+
* `apply` and `rollback` stay structurally not-ready until their own work
|
|
31
|
+
* lands; until then these kinds explicitly fall back to the legacy console
|
|
32
|
+
* updater — TEMPORARY migration debt per ADR-0024 D-1, not a supported
|
|
33
|
+
* long-term state. The two gaps are independent (PRI-729 audit §4):
|
|
34
|
+
* `rollback` waits on the Phase 2 same-version restore (`ROLLBACK_AVAILABLE`),
|
|
35
|
+
* while `apply` is the plugin-diff mechanism, which the ReleaseManager does not
|
|
36
|
+
* implement at all — no signed whole-payload release can express it.
|
|
34
37
|
*
|
|
35
38
|
* PRI-698 Phase 1: `apply-full` (full-runtime update) is served by the real
|
|
36
39
|
* ReleaseManager.apply() orchestration (installer + journal) and reports the
|
|
37
40
|
* same base readiness as `check`. The CONSOLE additionally gates the routing
|
|
38
|
-
* behind the `release_manager_write_authority` flag (default
|
|
39
|
-
* dispatches fall back explicitly with
|
|
40
|
-
* `
|
|
41
|
-
* implement) and `rollback` (Phase 2 — must prove same-version restore first)
|
|
42
|
-
* stay structurally not-ready with explicit reasons.
|
|
41
|
+
* behind the `release_manager_write_authority` flag (default ON since the
|
|
42
|
+
* 2026-09-07 graduation) — flag-off dispatches fall back explicitly with
|
|
43
|
+
* `release_manager_write_disabled`.
|
|
43
44
|
*/
|
|
44
45
|
import * as fs from 'node:fs';
|
|
45
46
|
import { ReleaseManager, ReleaseManagerError, } from './release-manager.js';
|
|
@@ -49,9 +50,14 @@ import { resolveReleaseMetadataSource } from './release-metadata-source.js';
|
|
|
49
50
|
export const RELEASE_MANAGER_AUTHORITY_KINDS = ['check', 'apply', 'apply-full', 'rollback'];
|
|
50
51
|
/**
|
|
51
52
|
* Structural gate for the kinds whose write path does not exist yet:
|
|
52
|
-
* `rollback` arrives with the Phase 2 restore migration
|
|
53
|
-
*
|
|
54
|
-
*
|
|
53
|
+
* `rollback` arrives with the Phase 2 restore migration. `apply-full` left
|
|
54
|
+
* this gate in PRI-698 Phase 1.
|
|
55
|
+
*
|
|
56
|
+
* `apply` (plugin diff) is NOT gated here: it is not a ReleaseManager
|
|
57
|
+
* mechanism at all (see the `apply` kind below), so its reason is a separate
|
|
58
|
+
* structural gap — a plugin-diff update needs a "current deployment → target
|
|
59
|
+
* deployment" comparison that signed whole-payload releases cannot express.
|
|
60
|
+
* Conflating the two made the fallback reason inaccurate (PRI-729 audit §4 B3).
|
|
55
61
|
*/
|
|
56
62
|
const ROLLBACK_AVAILABLE = false;
|
|
57
63
|
/**
|
|
@@ -131,11 +137,15 @@ export function createReleaseManagerAuthority(options) {
|
|
|
131
137
|
},
|
|
132
138
|
apply: {
|
|
133
139
|
ready: false,
|
|
134
|
-
|
|
140
|
+
// Structural, and independent of rollback: the plugin-diff mechanism is
|
|
141
|
+
// not a ReleaseManager mechanism, so this kind stays not-ready even once
|
|
142
|
+
// rollback lands (PRI-729 audit §4 B3).
|
|
143
|
+
reasons: [...baseReasons, 'plugin_diff_not_supported'],
|
|
135
144
|
},
|
|
136
145
|
// PRI-698 Phase 1: the full-runtime write path exists (ReleaseManager.apply
|
|
137
146
|
// → installer → journal). Console routing is additionally flag-gated
|
|
138
|
-
// (`release_manager_write_authority`, default
|
|
147
|
+
// (`release_manager_write_authority`, registry default ON since the
|
|
148
|
+
// 2026-09-07 graduation — only an explicit `enabled: false` disables it).
|
|
139
149
|
'apply-full': {
|
|
140
150
|
ready: baseReady,
|
|
141
151
|
reasons: baseReasons,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"release-manager-authority.js","sourceRoot":"","sources":["../../src/update/release-manager-authority.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"release-manager-authority.js","sourceRoot":"","sources":["../../src/update/release-manager-authority.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Release metadata publisher (PRI-727) — the production supply side of the
|
|
3
|
+
* read contracts in release-metadata-source.ts / trust-metadata.ts.
|
|
4
|
+
*
|
|
5
|
+
* For one release this module emits EXACTLY the byte set ReleaseManager
|
|
6
|
+
* already consumes (see apply-payload.ts and release-manager.ts):
|
|
7
|
+
*
|
|
8
|
+
* root.json / timestamp.json / snapshot.json / targets.json TUF chain
|
|
9
|
+
* targets/channels/<channel>.json signed channel pointer payload
|
|
10
|
+
* targets/releases/<releaseId>/metadata.json release metadata payload
|
|
11
|
+
* targets/releases/<releaseId>/release-asset-<platform>-<arch>.tar.gz
|
|
12
|
+
*
|
|
13
|
+
* No second release identity: releaseId and the canonical digests come from
|
|
14
|
+
* deriveReleaseId/buildReleaseMetadata, and both produced documents are
|
|
15
|
+
* re-validated with the SAME strict parsers the ReleaseManager uses, so a
|
|
16
|
+
* publisher-side defect fails here instead of at an install. Publication is
|
|
17
|
+
* byte-deterministic: the same identity inputs, the same signing key and the
|
|
18
|
+
* same previous-state TUF versions re-emit identical files (idempotent
|
|
19
|
+
* re-publish of one release is a no-op, not a mutation).
|
|
20
|
+
*
|
|
21
|
+
* Advance discipline: the channel pointer is only produced together with the
|
|
22
|
+
* artifact target whose sha256 is bound into the release metadata — there is
|
|
23
|
+
* no API shape that advances the pointer without the verifiable artifact
|
|
24
|
+
* existing in the same file set. Monotonicity against the currently
|
|
25
|
+
* published channel pointer (`previous`) is enforced here, fail-loud, before
|
|
26
|
+
* any bytes are emitted.
|
|
27
|
+
*
|
|
28
|
+
* Trust material: one ed25519 key signs all four TUF roles — the same
|
|
29
|
+
* single-key shape the ReleaseManager test suite verifies against. The
|
|
30
|
+
* install side pins root.json at install time, so this module never rotates
|
|
31
|
+
* the root (root version stays 1; rotation is separate governance work).
|
|
32
|
+
*/
|
|
33
|
+
import { type ChannelMetadata } from './channel-metadata.js';
|
|
34
|
+
import { type ReleaseMetadata } from './release-metadata.js';
|
|
35
|
+
import { type ReleaseChannelName } from './product-identity.js';
|
|
36
|
+
export declare const RELEASE_PUBLICATION_TUF_SPEC_VERSION = "1.0.31";
|
|
37
|
+
export type ReleasePublicationErrorCode = 'invalid_input' | 'expires_not_future' | 'publication_not_monotonic' | 'publication_conflict' | 'signing_key_invalid';
|
|
38
|
+
export declare class ReleasePublicationError extends Error {
|
|
39
|
+
readonly code: ReleasePublicationErrorCode;
|
|
40
|
+
readonly field: string;
|
|
41
|
+
readonly nextAction: string;
|
|
42
|
+
constructor(code: ReleasePublicationErrorCode, field: string, message: string, nextAction: string);
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* The release-asset archive that will be published as the artifact target.
|
|
46
|
+
* `bytes` are the EXACT bytes served at the target path — the sha256 bound
|
|
47
|
+
* into the release metadata is computed over them.
|
|
48
|
+
*/
|
|
49
|
+
export interface PublicationArchive {
|
|
50
|
+
readonly platform: string;
|
|
51
|
+
readonly arch: string;
|
|
52
|
+
readonly nodeAbi: string;
|
|
53
|
+
readonly bytes: Buffer;
|
|
54
|
+
}
|
|
55
|
+
/** Previously published state of the metadata repository, when one exists. */
|
|
56
|
+
export interface PreviousPublication {
|
|
57
|
+
/** The currently published `targets/channels/<channel>.json` payload. */
|
|
58
|
+
readonly channelPayload: unknown;
|
|
59
|
+
/** TUF metadata versions of the currently published repository. Absent roles start at 1. */
|
|
60
|
+
readonly tufVersions?: {
|
|
61
|
+
readonly root?: number;
|
|
62
|
+
readonly timestamp?: number;
|
|
63
|
+
readonly snapshot?: number;
|
|
64
|
+
readonly targets?: number;
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
export interface ReleasePublicationInput {
|
|
68
|
+
readonly productVersion: string;
|
|
69
|
+
readonly sourceCommit: string;
|
|
70
|
+
readonly channel: ReleaseChannelName;
|
|
71
|
+
/** Monotonic channel pointer version — must strictly increase per advance. */
|
|
72
|
+
readonly channelVersion: number;
|
|
73
|
+
/** Monotonic publication sequence — must strictly increase per advance. */
|
|
74
|
+
readonly publicationSequence: number;
|
|
75
|
+
/** RFC3339 UTC (`...Z`) expiry for the channel, release metadata and TUF roles. */
|
|
76
|
+
readonly expiresAt: string;
|
|
77
|
+
readonly minBootstrapVersion: string;
|
|
78
|
+
readonly dataSchemaForwardReadableFrom: string;
|
|
79
|
+
readonly archive: PublicationArchive;
|
|
80
|
+
/** PEM-encoded ed25519 PRIVATE key signing the whole repository. */
|
|
81
|
+
readonly signingKeyPem: string;
|
|
82
|
+
readonly previous?: PreviousPublication | null;
|
|
83
|
+
}
|
|
84
|
+
export interface PublicationFile {
|
|
85
|
+
/** Repository-relative path as served at the metadata base URL. */
|
|
86
|
+
readonly path: string;
|
|
87
|
+
readonly bytes: Buffer;
|
|
88
|
+
}
|
|
89
|
+
export interface ReleasePublicationManifest {
|
|
90
|
+
readonly releaseId: string;
|
|
91
|
+
readonly productVersion: string;
|
|
92
|
+
readonly channel: ReleaseChannelName;
|
|
93
|
+
readonly platform: string;
|
|
94
|
+
readonly arch: string;
|
|
95
|
+
readonly nodeAbi: string;
|
|
96
|
+
readonly sourceCommit: string;
|
|
97
|
+
readonly artifactSha256: string;
|
|
98
|
+
readonly artifactSizeBytes: number;
|
|
99
|
+
readonly artifactTargetPath: string;
|
|
100
|
+
readonly keyId: string;
|
|
101
|
+
readonly signingScheme: 'ed25519';
|
|
102
|
+
readonly publicationSequence: number;
|
|
103
|
+
readonly channelVersion: number;
|
|
104
|
+
readonly expiresAt: string;
|
|
105
|
+
readonly files: readonly {
|
|
106
|
+
readonly path: string;
|
|
107
|
+
readonly sha256: string;
|
|
108
|
+
readonly sizeBytes: number;
|
|
109
|
+
}[];
|
|
110
|
+
}
|
|
111
|
+
export interface ReleasePublication {
|
|
112
|
+
readonly manifest: ReleasePublicationManifest;
|
|
113
|
+
readonly releaseMetadata: ReleaseMetadata;
|
|
114
|
+
readonly channelPayload: ChannelMetadata;
|
|
115
|
+
/** The complete served-repository content, ready to publish as-is. */
|
|
116
|
+
readonly files: readonly PublicationFile[];
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Gzip wrapper for a built release archive. Node's zlib emits a deterministic
|
|
120
|
+
* gzip header (no embedded mtime or file name), so the same archive bytes
|
|
121
|
+
* always produce the same published artifact bytes — the CLI `gzip` would not
|
|
122
|
+
* (it stores name + mtime in the header).
|
|
123
|
+
*/
|
|
124
|
+
export declare function gzipReleaseArchive(archiveBytes: Buffer): Buffer;
|
|
125
|
+
/**
|
|
126
|
+
* Parses a `sha256sum`-style digest file (`<hex>` or `<hex> <name>`) into
|
|
127
|
+
* the lowercase hex digest, failing loud on anything else.
|
|
128
|
+
*/
|
|
129
|
+
export declare function parseSha256DigestFile(content: string): string;
|
|
130
|
+
/**
|
|
131
|
+
* True when the input is a syntactically valid RFC3339 UTC timestamp
|
|
132
|
+
* (`...Z`). Exported for CLI argument validation before any IO happens.
|
|
133
|
+
*/
|
|
134
|
+
export declare function isRfc3339UtcTimestamp(value: unknown): value is string;
|
|
135
|
+
/**
|
|
136
|
+
* Builds the complete signed release publication. Pure: no filesystem or
|
|
137
|
+
* network IO — callers (the publish script / CI) own byte transport.
|
|
138
|
+
*/
|
|
139
|
+
export declare function buildReleasePublication(input: ReleasePublicationInput): ReleasePublication;
|
|
140
|
+
/** Ephemeral ed25519 key PEM for dry-run pipelines without configured trust material. */
|
|
141
|
+
export declare function generateEphemeralSigningKeyPem(): string;
|
|
142
|
+
//# sourceMappingURL=release-metadata-publisher.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"release-metadata-publisher.d.ts","sourceRoot":"","sources":["../../src/update/release-metadata-publisher.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAeH,OAAO,EAAwB,KAAK,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACnF,OAAO,EAEL,KAAK,eAAe,EACrB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAEL,KAAK,kBAAkB,EACxB,MAAM,uBAAuB,CAAC;AAG/B,eAAO,MAAM,oCAAoC,WAAW,CAAC;AAE7D,MAAM,MAAM,2BAA2B,GACnC,eAAe,GACf,oBAAoB,GACpB,2BAA2B,GAC3B,sBAAsB,GACtB,qBAAqB,CAAC;AAE1B,qBAAa,uBAAwB,SAAQ,KAAK;IAChD,QAAQ,CAAC,IAAI,EAAE,2BAA2B,CAAC;IAC3C,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAG5B,YAAY,IAAI,EAAE,2BAA2B,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAMhG;CACF;AAQD;;;;GAIG;AACH,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB;AAED,8EAA8E;AAC9E,MAAM,WAAW,mBAAmB;IAClC,yEAAyE;IACzE,QAAQ,CAAC,cAAc,EAAE,OAAO,CAAC;IACjC,4FAA4F;IAC5F,QAAQ,CAAC,WAAW,CAAC,EAAE;QACrB,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QACvB,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;QAC5B,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;QAC3B,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;KAC3B,CAAC;CACH;AAED,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,OAAO,EAAE,kBAAkB,CAAC;IACrC,8EAA8E;IAC9E,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,2EAA2E;IAC3E,QAAQ,CAAC,mBAAmB,EAAE,MAAM,CAAC;IACrC,mFAAmF;IACnF,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,mBAAmB,EAAE,MAAM,CAAC;IACrC,QAAQ,CAAC,6BAA6B,EAAE,MAAM,CAAC;IAC/C,QAAQ,CAAC,OAAO,EAAE,kBAAkB,CAAC;IACrC,oEAAoE;IACpE,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,QAAQ,CAAC,EAAE,mBAAmB,GAAG,IAAI,CAAC;CAChD;AAED,MAAM,WAAW,eAAe;IAC9B,mEAAmE;IACnE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,0BAA0B;IACzC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,OAAO,EAAE,kBAAkB,CAAC;IACrC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CAAC;IACnC,QAAQ,CAAC,kBAAkB,EAAE,MAAM,CAAC;IACpC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,aAAa,EAAE,SAAS,CAAC;IAClC,QAAQ,CAAC,mBAAmB,EAAE,MAAM,CAAC;IACrC,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,KAAK,EAAE,SAAS;QAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;CAC3G;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,QAAQ,EAAE,0BAA0B,CAAC;IAC9C,QAAQ,CAAC,eAAe,EAAE,eAAe,CAAC;IAC1C,QAAQ,CAAC,cAAc,EAAE,eAAe,CAAC;IACzC,sEAAsE;IACtE,QAAQ,CAAC,KAAK,EAAE,SAAS,eAAe,EAAE,CAAC;CAC5C;AAgGD;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAE/D;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAW7D;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,CAErE;AAiGD;;;GAGG;AACH,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,uBAAuB,GAAG,kBAAkB,CAsJ1F;AAED,yFAAyF;AACzF,wBAAgB,8BAA8B,IAAI,MAAM,CAKvD"}
|
|
@@ -0,0 +1,340 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Release metadata publisher (PRI-727) — the production supply side of the
|
|
3
|
+
* read contracts in release-metadata-source.ts / trust-metadata.ts.
|
|
4
|
+
*
|
|
5
|
+
* For one release this module emits EXACTLY the byte set ReleaseManager
|
|
6
|
+
* already consumes (see apply-payload.ts and release-manager.ts):
|
|
7
|
+
*
|
|
8
|
+
* root.json / timestamp.json / snapshot.json / targets.json TUF chain
|
|
9
|
+
* targets/channels/<channel>.json signed channel pointer payload
|
|
10
|
+
* targets/releases/<releaseId>/metadata.json release metadata payload
|
|
11
|
+
* targets/releases/<releaseId>/release-asset-<platform>-<arch>.tar.gz
|
|
12
|
+
*
|
|
13
|
+
* No second release identity: releaseId and the canonical digests come from
|
|
14
|
+
* deriveReleaseId/buildReleaseMetadata, and both produced documents are
|
|
15
|
+
* re-validated with the SAME strict parsers the ReleaseManager uses, so a
|
|
16
|
+
* publisher-side defect fails here instead of at an install. Publication is
|
|
17
|
+
* byte-deterministic: the same identity inputs, the same signing key and the
|
|
18
|
+
* same previous-state TUF versions re-emit identical files (idempotent
|
|
19
|
+
* re-publish of one release is a no-op, not a mutation).
|
|
20
|
+
*
|
|
21
|
+
* Advance discipline: the channel pointer is only produced together with the
|
|
22
|
+
* artifact target whose sha256 is bound into the release metadata — there is
|
|
23
|
+
* no API shape that advances the pointer without the verifiable artifact
|
|
24
|
+
* existing in the same file set. Monotonicity against the currently
|
|
25
|
+
* published channel pointer (`previous`) is enforced here, fail-loud, before
|
|
26
|
+
* any bytes are emitted.
|
|
27
|
+
*
|
|
28
|
+
* Trust material: one ed25519 key signs all four TUF roles — the same
|
|
29
|
+
* single-key shape the ReleaseManager test suite verifies against. The
|
|
30
|
+
* install side pins root.json at install time, so this module never rotates
|
|
31
|
+
* the root (root version stays 1; rotation is separate governance work).
|
|
32
|
+
*/
|
|
33
|
+
import { createHash, createPrivateKey, createPublicKey, generateKeyPairSync, sign as cryptoSign } from 'node:crypto';
|
|
34
|
+
import { gzipSync } from 'node:zlib';
|
|
35
|
+
import { Key, MetaFile, Metadata, Root, Signature, Snapshot, TargetFile, Targets, Timestamp, } from '@tufjs/models';
|
|
36
|
+
import { parseChannelMetadata } from './channel-metadata.js';
|
|
37
|
+
import { buildReleaseMetadata, } from './release-metadata.js';
|
|
38
|
+
import { isReleaseChannelName, } from './product-identity.js';
|
|
39
|
+
import { canonicalJson } from './release-identity.js';
|
|
40
|
+
export const RELEASE_PUBLICATION_TUF_SPEC_VERSION = '1.0.31';
|
|
41
|
+
export class ReleasePublicationError extends Error {
|
|
42
|
+
code;
|
|
43
|
+
field;
|
|
44
|
+
nextAction;
|
|
45
|
+
// eslint-disable-next-line @typescript-eslint/max-params -- (code, field, message, nextAction) mirrors the four fields of the consumer refusal contract (same shape as ReleaseManagerError / ReleaseTrustError)
|
|
46
|
+
constructor(code, field, message, nextAction) {
|
|
47
|
+
super(message);
|
|
48
|
+
this.name = 'ReleasePublicationError';
|
|
49
|
+
this.code = code;
|
|
50
|
+
this.field = field;
|
|
51
|
+
this.nextAction = nextAction;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
const RFC3339_UTC_PATTERN = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?Z$/;
|
|
55
|
+
function isPlainObject(value) {
|
|
56
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
57
|
+
}
|
|
58
|
+
function requirePositiveInteger(value, field) {
|
|
59
|
+
if (typeof value !== 'number' || !Number.isSafeInteger(value) || value <= 0) {
|
|
60
|
+
throw new ReleasePublicationError('invalid_input', field, `${field} must be a positive safe integer, got: ${JSON.stringify(value)}`, 'Pass an explicit monotonic value and retry the publication.');
|
|
61
|
+
}
|
|
62
|
+
return value;
|
|
63
|
+
}
|
|
64
|
+
function requireExpiresAt(value) {
|
|
65
|
+
if (typeof value !== 'string' || !RFC3339_UTC_PATTERN.test(value) || Number.isNaN(Date.parse(value))) {
|
|
66
|
+
throw new ReleasePublicationError('invalid_input', 'expiresAt', `expiresAt must be an RFC3339 UTC timestamp ending in Z, got: ${JSON.stringify(value)}`, 'Pass an explicit expiry (for example 2026-12-01T00:00:00Z); implicit defaults would break reproducible re-publication.');
|
|
67
|
+
}
|
|
68
|
+
if (Date.parse(value) <= Date.now()) {
|
|
69
|
+
throw new ReleasePublicationError('expires_not_future', 'expiresAt', `expiresAt must be in the future, got: ${value}`, 'Publish with an expiry ahead of the release window; clients refuse expired metadata.');
|
|
70
|
+
}
|
|
71
|
+
return value;
|
|
72
|
+
}
|
|
73
|
+
function requireSigner(signingKeyPem) {
|
|
74
|
+
if (typeof signingKeyPem !== 'string' || signingKeyPem.trim().length === 0) {
|
|
75
|
+
throw new ReleasePublicationError('signing_key_invalid', 'signingKeyPem', 'The release signing key is empty.', 'Provide the ed25519 private key PEM (CI secret) that matches the pinned trust root.');
|
|
76
|
+
}
|
|
77
|
+
let privateKey;
|
|
78
|
+
try {
|
|
79
|
+
privateKey = createPrivateKey(signingKeyPem);
|
|
80
|
+
}
|
|
81
|
+
catch (error) {
|
|
82
|
+
throw new ReleasePublicationError('signing_key_invalid', 'signingKeyPem', `The release signing key is not a parseable private key: ${error instanceof Error ? error.message : String(error)}`, 'Provide a PEM-encoded ed25519 private key.');
|
|
83
|
+
}
|
|
84
|
+
if (privateKey.asymmetricKeyType !== 'ed25519') {
|
|
85
|
+
throw new ReleasePublicationError('signing_key_invalid', 'signingKeyPem', `The release signing key must be an ed25519 key, got: ${String(privateKey.asymmetricKeyType)}`, 'Generate an ed25519 key for the release trust material.');
|
|
86
|
+
}
|
|
87
|
+
const publicKeyPem = createPublicKey(privateKey).export({ type: 'spki', format: 'pem' }).toString();
|
|
88
|
+
// Deterministic key id derived from the public key material, so the same
|
|
89
|
+
// key always produces the same root.json bytes (reproducibility).
|
|
90
|
+
const keyId = createHash('sha256').update(publicKeyPem).digest('hex');
|
|
91
|
+
return { keyId, privateKey };
|
|
92
|
+
}
|
|
93
|
+
function signedTufMetadata(signed, signer) {
|
|
94
|
+
const metadata = new Metadata(signed);
|
|
95
|
+
metadata.sign((data) => new Signature({ keyID: signer.keyId, sig: cryptoSign(null, data, signer.privateKey).toString('hex') }), false);
|
|
96
|
+
return Buffer.from(JSON.stringify(metadata.toJSON()), 'utf8');
|
|
97
|
+
}
|
|
98
|
+
function deterministicJsonBytes(value) {
|
|
99
|
+
return Buffer.from(`${JSON.stringify(value, null, 2)}\n`, 'utf8');
|
|
100
|
+
}
|
|
101
|
+
function sha256Hex(bytes) {
|
|
102
|
+
return createHash('sha256').update(bytes).digest('hex');
|
|
103
|
+
}
|
|
104
|
+
function withFileDigests(files) {
|
|
105
|
+
return files.map((file) => ({ path: file.path, sha256: sha256Hex(file.bytes), sizeBytes: file.bytes.length }));
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Gzip wrapper for a built release archive. Node's zlib emits a deterministic
|
|
109
|
+
* gzip header (no embedded mtime or file name), so the same archive bytes
|
|
110
|
+
* always produce the same published artifact bytes — the CLI `gzip` would not
|
|
111
|
+
* (it stores name + mtime in the header).
|
|
112
|
+
*/
|
|
113
|
+
export function gzipReleaseArchive(archiveBytes) {
|
|
114
|
+
return gzipSync(archiveBytes);
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Parses a `sha256sum`-style digest file (`<hex>` or `<hex> <name>`) into
|
|
118
|
+
* the lowercase hex digest, failing loud on anything else.
|
|
119
|
+
*/
|
|
120
|
+
export function parseSha256DigestFile(content) {
|
|
121
|
+
const firstToken = content.trim().split(/\s+/, 1)[0] ?? '';
|
|
122
|
+
if (!/^[a-f0-9]{64}$/i.test(firstToken)) {
|
|
123
|
+
throw new ReleasePublicationError('invalid_input', 'digestFile', `The release archive digest file does not contain a sha256 hex digest: ${JSON.stringify(firstToken.slice(0, 72))}`, 'Regenerate the release asset so its .sha256 sidecar exists, then retry.');
|
|
124
|
+
}
|
|
125
|
+
return firstToken.toLowerCase();
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* True when the input is a syntactically valid RFC3339 UTC timestamp
|
|
129
|
+
* (`...Z`). Exported for CLI argument validation before any IO happens.
|
|
130
|
+
*/
|
|
131
|
+
export function isRfc3339UtcTimestamp(value) {
|
|
132
|
+
return typeof value === 'string' && RFC3339_UTC_PATTERN.test(value) && !Number.isNaN(Date.parse(value));
|
|
133
|
+
}
|
|
134
|
+
function resolvePreviousState(input, channelPayload) {
|
|
135
|
+
const { previous } = input;
|
|
136
|
+
if (previous === undefined || previous === null) {
|
|
137
|
+
return { previousChannel: null, versions: { root: 1, timestamp: 1, snapshot: 1, targets: 1 } };
|
|
138
|
+
}
|
|
139
|
+
if (previous.channelPayload !== undefined && previous.channelPayload !== null) {
|
|
140
|
+
if (!isPlainObject(previous.channelPayload)) {
|
|
141
|
+
throw new ReleasePublicationError('invalid_input', 'previous.channelPayload', 'The previously published channel payload is not a JSON object.', 'Inspect the published metadata repository; a corrupt pointer must be repaired before publishing.');
|
|
142
|
+
}
|
|
143
|
+
// A published pointer without its TUF versions would let this publication
|
|
144
|
+
// emit metadata versions the published repository already superseded —
|
|
145
|
+
// a rollback clients must reject. Require the full previous state.
|
|
146
|
+
const versions = previous.tufVersions;
|
|
147
|
+
if (versions === undefined || versions.root === undefined || versions.timestamp === undefined
|
|
148
|
+
|| versions.snapshot === undefined || versions.targets === undefined) {
|
|
149
|
+
throw new ReleasePublicationError('invalid_input', 'previous.tufVersions', 'Publishing over an existing metadata repository requires the published TUF metadata versions (root/timestamp/snapshot/targets).', 'Read the versions from the currently published repository and pass them as the previous state.');
|
|
150
|
+
}
|
|
151
|
+
// Strict parse: a corrupt previous pointer fails the publication instead
|
|
152
|
+
// of being silently treated as absent (rc-3).
|
|
153
|
+
const previousChannel = parseChannelMetadata(previous.channelPayload);
|
|
154
|
+
if (previousChannel.channel !== input.channel) {
|
|
155
|
+
throw new ReleasePublicationError('invalid_input', 'previous.channelPayload', `The previously published pointer is for channel "${previousChannel.channel}", not "${input.channel}".`, 'Read the previous state of the channel being published.');
|
|
156
|
+
}
|
|
157
|
+
const sameRelease = previousChannel.releaseId === channelPayload.releaseId;
|
|
158
|
+
if (sameRelease) {
|
|
159
|
+
// Re-publishing one release is only legitimate as an exact no-op: any
|
|
160
|
+
// content change (sequence, pointer version, expiry) would mutate an
|
|
161
|
+
// immutable release identity. Equality is checked on the canonical
|
|
162
|
+
// channel payload so formatting cannot fake or break it.
|
|
163
|
+
if (canonicalJson(previous.channelPayload) !== canonicalJson(channelPayload)) {
|
|
164
|
+
throw new ReleasePublicationError('publication_conflict', 'releaseId', `Release ${channelPayload.releaseId.slice(0, 12)} is already published with different pointer content (publicationSequence ${previousChannel.publicationSequence} vs ${channelPayload.publicationSequence}, pointer version ${previousChannel.version} vs ${channelPayload.version}).`, 'Re-publish with the identical inputs that produced the published release, or publish a NEW release with a strictly higher publication sequence.');
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
else {
|
|
168
|
+
if (channelPayload.publicationSequence <= previousChannel.publicationSequence) {
|
|
169
|
+
throw new ReleasePublicationError('publication_not_monotonic', 'publicationSequence', `The new publicationSequence (${channelPayload.publicationSequence}) must be strictly greater than the published one (${previousChannel.publicationSequence}).`, 'Advance the publication sequence; the channel pointer must never move backwards.');
|
|
170
|
+
}
|
|
171
|
+
if (channelPayload.version <= previousChannel.version) {
|
|
172
|
+
throw new ReleasePublicationError('publication_not_monotonic', 'channelVersion', `The new channel pointer version (${channelPayload.version}) must be strictly greater than the published one (${previousChannel.version}).`, 'Advance the channel pointer version; signed pointer versions must never repeat or regress.');
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
return {
|
|
176
|
+
previousChannel,
|
|
177
|
+
versions: {
|
|
178
|
+
root: versions.root,
|
|
179
|
+
// An identical re-publish keeps the SAME TUF metadata versions (the
|
|
180
|
+
// emitted bytes must stay identical); an advance bumps every
|
|
181
|
+
// non-root role so clients see fresh metadata.
|
|
182
|
+
timestamp: sameRelease ? versions.timestamp : versions.timestamp + 1,
|
|
183
|
+
snapshot: sameRelease ? versions.snapshot : versions.snapshot + 1,
|
|
184
|
+
targets: sameRelease ? versions.targets : versions.targets + 1,
|
|
185
|
+
},
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
const versions = previous.tufVersions ?? {};
|
|
189
|
+
return {
|
|
190
|
+
previousChannel: null,
|
|
191
|
+
versions: { root: versions.root ?? 1, timestamp: (versions.timestamp ?? 0) + 1, snapshot: (versions.snapshot ?? 0) + 1, targets: (versions.targets ?? 0) + 1 },
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Builds the complete signed release publication. Pure: no filesystem or
|
|
196
|
+
* network IO — callers (the publish script / CI) own byte transport.
|
|
197
|
+
*/
|
|
198
|
+
export function buildReleasePublication(input) {
|
|
199
|
+
if (!isReleaseChannelName(input.channel)) {
|
|
200
|
+
throw new ReleasePublicationError('invalid_input', 'channel', `channel must be "stable" or "candidate", got: ${JSON.stringify(input.channel)}`, 'Publish to a configured release channel.');
|
|
201
|
+
}
|
|
202
|
+
requirePositiveInteger(input.channelVersion, 'channelVersion');
|
|
203
|
+
requirePositiveInteger(input.publicationSequence, 'publicationSequence');
|
|
204
|
+
requireExpiresAt(input.expiresAt);
|
|
205
|
+
if (!Buffer.isBuffer(input.archive.bytes) || input.archive.bytes.length === 0) {
|
|
206
|
+
throw new ReleasePublicationError('invalid_input', 'archive.bytes', 'The release archive is empty or missing.', 'Build the self-contained release asset first; nothing is published without the artifact bytes.');
|
|
207
|
+
}
|
|
208
|
+
const signer = requireSigner(input.signingKeyPem);
|
|
209
|
+
const artifactBytes = input.archive.bytes;
|
|
210
|
+
const artifactSha256 = sha256Hex(artifactBytes);
|
|
211
|
+
// Artifact bytes are finalized FIRST: the release metadata binds their
|
|
212
|
+
// digest, the channel binds the metadata digest. By construction the
|
|
213
|
+
// emitted channel pointer can never reference an artifact that is not part
|
|
214
|
+
// of the same publication.
|
|
215
|
+
const releaseMetadata = buildReleaseMetadata({
|
|
216
|
+
productVersion: input.productVersion,
|
|
217
|
+
sourceCommit: input.sourceCommit,
|
|
218
|
+
minBootstrapVersion: input.minBootstrapVersion,
|
|
219
|
+
publicationSequence: input.publicationSequence,
|
|
220
|
+
expiresAt: input.expiresAt,
|
|
221
|
+
assets: [{
|
|
222
|
+
platform: input.archive.platform,
|
|
223
|
+
arch: input.archive.arch,
|
|
224
|
+
nodeAbi: input.archive.nodeAbi,
|
|
225
|
+
archiveSha256: artifactSha256,
|
|
226
|
+
archiveSizeBytes: artifactBytes.length,
|
|
227
|
+
}],
|
|
228
|
+
dataSchemaForwardReadableFrom: input.dataSchemaForwardReadableFrom,
|
|
229
|
+
});
|
|
230
|
+
const channelPayload = {
|
|
231
|
+
schemaVersion: 1,
|
|
232
|
+
channel: input.channel,
|
|
233
|
+
version: input.channelVersion,
|
|
234
|
+
expiresAt: input.expiresAt,
|
|
235
|
+
releaseMetadataDigest: releaseMetadata.metadataDigest,
|
|
236
|
+
releaseId: releaseMetadata.releaseId,
|
|
237
|
+
productVersion: releaseMetadata.productVersion,
|
|
238
|
+
publicationSequence: releaseMetadata.publicationSequence,
|
|
239
|
+
};
|
|
240
|
+
// Consume-side strict re-validation: if the publisher ever produces a
|
|
241
|
+
// document the ReleaseManager would refuse, refuse here instead.
|
|
242
|
+
parseChannelMetadata(channelPayload);
|
|
243
|
+
const { versions } = resolvePreviousState(input, channelPayload);
|
|
244
|
+
const channelTargetPath = `channels/${input.channel}.json`;
|
|
245
|
+
const metadataTargetPath = `releases/${releaseMetadata.releaseId}/metadata.json`;
|
|
246
|
+
const artifactTargetPath = `releases/${releaseMetadata.releaseId}/release-asset-${input.archive.platform}-${input.archive.arch}.tar.gz`;
|
|
247
|
+
const channelPayloadBytes = deterministicJsonBytes(channelPayload);
|
|
248
|
+
const releaseMetadataBytes = deterministicJsonBytes(releaseMetadata);
|
|
249
|
+
const targets = new Targets({
|
|
250
|
+
version: versions.targets,
|
|
251
|
+
specVersion: RELEASE_PUBLICATION_TUF_SPEC_VERSION,
|
|
252
|
+
expires: input.expiresAt,
|
|
253
|
+
targets: {
|
|
254
|
+
[channelTargetPath]: new TargetFile({
|
|
255
|
+
path: channelTargetPath,
|
|
256
|
+
length: channelPayloadBytes.length,
|
|
257
|
+
hashes: { sha256: sha256Hex(channelPayloadBytes) },
|
|
258
|
+
unrecognizedFields: {
|
|
259
|
+
custom: { releaseId: releaseMetadata.releaseId, channel: input.channel, platform: 'metadata' },
|
|
260
|
+
},
|
|
261
|
+
}),
|
|
262
|
+
[metadataTargetPath]: new TargetFile({
|
|
263
|
+
path: metadataTargetPath,
|
|
264
|
+
length: releaseMetadataBytes.length,
|
|
265
|
+
hashes: { sha256: sha256Hex(releaseMetadataBytes) },
|
|
266
|
+
unrecognizedFields: {
|
|
267
|
+
custom: { releaseId: releaseMetadata.releaseId, channel: input.channel, platform: 'metadata' },
|
|
268
|
+
},
|
|
269
|
+
}),
|
|
270
|
+
[artifactTargetPath]: new TargetFile({
|
|
271
|
+
path: artifactTargetPath,
|
|
272
|
+
length: artifactBytes.length,
|
|
273
|
+
hashes: { sha256: artifactSha256 },
|
|
274
|
+
unrecognizedFields: {
|
|
275
|
+
custom: { releaseId: releaseMetadata.releaseId, channel: input.channel, platform: input.archive.platform },
|
|
276
|
+
},
|
|
277
|
+
}),
|
|
278
|
+
},
|
|
279
|
+
});
|
|
280
|
+
const root = new Root({
|
|
281
|
+
version: versions.root,
|
|
282
|
+
specVersion: RELEASE_PUBLICATION_TUF_SPEC_VERSION,
|
|
283
|
+
expires: input.expiresAt,
|
|
284
|
+
consistentSnapshot: false,
|
|
285
|
+
});
|
|
286
|
+
const signingKey = new Key({
|
|
287
|
+
keyID: signer.keyId,
|
|
288
|
+
keyType: 'ed25519',
|
|
289
|
+
scheme: 'ed25519',
|
|
290
|
+
keyVal: { public: createPublicKey(signer.privateKey).export({ type: 'spki', format: 'pem' }).toString() },
|
|
291
|
+
});
|
|
292
|
+
for (const role of ['root', 'timestamp', 'snapshot', 'targets'])
|
|
293
|
+
root.addKey(signingKey, role);
|
|
294
|
+
const files = [
|
|
295
|
+
{ path: 'root.json', bytes: signedTufMetadata(root, signer) },
|
|
296
|
+
{ path: 'timestamp.json', bytes: signedTufMetadata(new Timestamp({
|
|
297
|
+
version: versions.timestamp,
|
|
298
|
+
specVersion: RELEASE_PUBLICATION_TUF_SPEC_VERSION,
|
|
299
|
+
expires: input.expiresAt,
|
|
300
|
+
snapshotMeta: new MetaFile({ version: versions.snapshot }),
|
|
301
|
+
}), signer) },
|
|
302
|
+
{ path: 'snapshot.json', bytes: signedTufMetadata(new Snapshot({
|
|
303
|
+
version: versions.snapshot,
|
|
304
|
+
specVersion: RELEASE_PUBLICATION_TUF_SPEC_VERSION,
|
|
305
|
+
expires: input.expiresAt,
|
|
306
|
+
meta: { 'targets.json': new MetaFile({ version: versions.targets }) },
|
|
307
|
+
}), signer) },
|
|
308
|
+
{ path: 'targets.json', bytes: signedTufMetadata(targets, signer) },
|
|
309
|
+
{ path: `targets/${channelTargetPath}`, bytes: channelPayloadBytes },
|
|
310
|
+
{ path: `targets/${metadataTargetPath}`, bytes: releaseMetadataBytes },
|
|
311
|
+
{ path: `targets/${artifactTargetPath}`, bytes: artifactBytes },
|
|
312
|
+
];
|
|
313
|
+
const manifest = {
|
|
314
|
+
releaseId: releaseMetadata.releaseId,
|
|
315
|
+
productVersion: releaseMetadata.productVersion,
|
|
316
|
+
channel: input.channel,
|
|
317
|
+
platform: input.archive.platform,
|
|
318
|
+
arch: input.archive.arch,
|
|
319
|
+
nodeAbi: input.archive.nodeAbi,
|
|
320
|
+
sourceCommit: input.sourceCommit,
|
|
321
|
+
artifactSha256,
|
|
322
|
+
artifactSizeBytes: artifactBytes.length,
|
|
323
|
+
artifactTargetPath,
|
|
324
|
+
keyId: signer.keyId,
|
|
325
|
+
signingScheme: 'ed25519',
|
|
326
|
+
publicationSequence: input.publicationSequence,
|
|
327
|
+
channelVersion: input.channelVersion,
|
|
328
|
+
expiresAt: input.expiresAt,
|
|
329
|
+
files: withFileDigests(files),
|
|
330
|
+
};
|
|
331
|
+
return { manifest, releaseMetadata, channelPayload, files };
|
|
332
|
+
}
|
|
333
|
+
/** Ephemeral ed25519 key PEM for dry-run pipelines without configured trust material. */
|
|
334
|
+
export function generateEphemeralSigningKeyPem() {
|
|
335
|
+
return generateKeyPairSync('ed25519')
|
|
336
|
+
.privateKey
|
|
337
|
+
.export({ type: 'pkcs8', format: 'pem' })
|
|
338
|
+
.toString();
|
|
339
|
+
}
|
|
340
|
+
//# sourceMappingURL=release-metadata-publisher.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"release-metadata-publisher.js","sourceRoot":"","sources":["../../src/update/release-metadata-publisher.ts"],"names":[],"mappings":"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"}
|