@parity/product-deploy 0.7.28-rc.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/LICENSE +201 -0
- package/README.md +233 -0
- package/assets/environments.json +313 -0
- package/bin/bulletin-bootstrap +84 -0
- package/bin/bulletin-deploy +429 -0
- package/dist/bug-report.d.ts +29 -0
- package/dist/bug-report.js +27 -0
- package/dist/chunk-2VAUMZB2.js +284 -0
- package/dist/chunk-43HLT335.js +232 -0
- package/dist/chunk-5VZQ2KSU.js +231 -0
- package/dist/chunk-ADNBLFDP.js +225 -0
- package/dist/chunk-BMAEWZYV.js +24 -0
- package/dist/chunk-C2TS5MER.js +64 -0
- package/dist/chunk-DNXH4QTI.js +2336 -0
- package/dist/chunk-FZWJV5AD.js +231 -0
- package/dist/chunk-GZD2UFLR.js +8 -0
- package/dist/chunk-HOTQDYHD.js +219 -0
- package/dist/chunk-IDYGYIMH.js +207 -0
- package/dist/chunk-KHVTYIIX.js +146 -0
- package/dist/chunk-KJH2T5TQ.js +172 -0
- package/dist/chunk-KOSF5FDO.js +49 -0
- package/dist/chunk-LZJMVPYW.js +156 -0
- package/dist/chunk-MFTODIIT.js +725 -0
- package/dist/chunk-MMAZFJDG.js +91 -0
- package/dist/chunk-NF2FL4ZO.js +164 -0
- package/dist/chunk-OITUIM2E.js +524 -0
- package/dist/chunk-P6CHOMN3.js +2368 -0
- package/dist/chunk-QMYW3D6E.js +316 -0
- package/dist/chunk-QTZNULSH.js +185 -0
- package/dist/chunk-RI3ZLNPN.js +71 -0
- package/dist/chunk-S7EM5VMW.js +108 -0
- package/dist/chunk-T7EEVWNU.js +32 -0
- package/dist/chunk-UPWEOGLQ.js +37 -0
- package/dist/chunk-ZOC4GITL.js +13 -0
- package/dist/chunk-ZYVGHDMU.js +117 -0
- package/dist/chunk-probe.d.ts +37 -0
- package/dist/chunk-probe.js +18 -0
- package/dist/chunker.d.ts +8 -0
- package/dist/chunker.js +10 -0
- package/dist/deploy.d.ts +299 -0
- package/dist/deploy.js +96 -0
- package/dist/dotns.d.ts +506 -0
- package/dist/dotns.js +101 -0
- package/dist/environments.d.ts +104 -0
- package/dist/environments.js +23 -0
- package/dist/errors.d.ts +6 -0
- package/dist/errors.js +8 -0
- package/dist/gh-pages-mirror.d.ts +76 -0
- package/dist/gh-pages-mirror.js +30 -0
- package/dist/incremental-stats.d.ts +69 -0
- package/dist/incremental-stats.js +10 -0
- package/dist/index.d.ts +23 -0
- package/dist/index.js +146 -0
- package/dist/manifest/byte-budget.d.ts +46 -0
- package/dist/manifest/byte-budget.js +14 -0
- package/dist/manifest/config-load.d.ts +36 -0
- package/dist/manifest/config-load.js +10 -0
- package/dist/manifest/publish.d.ts +54 -0
- package/dist/manifest/publish.js +23 -0
- package/dist/manifest/schema.d.ts +29 -0
- package/dist/manifest/schema.js +10 -0
- package/dist/manifest/types.d.ts +90 -0
- package/dist/manifest/types.js +6 -0
- package/dist/manifest-embed.d.ts +18 -0
- package/dist/manifest-embed.js +9 -0
- package/dist/manifest-fetch.d.ts +32 -0
- package/dist/manifest-fetch.js +21 -0
- package/dist/manifest-roundtrip.d.ts +15 -0
- package/dist/manifest-roundtrip.js +55 -0
- package/dist/manifest.d.ts +44 -0
- package/dist/manifest.js +20 -0
- package/dist/memory-report.d.ts +95 -0
- package/dist/memory-report.js +17 -0
- package/dist/merkle.d.ts +50 -0
- package/dist/merkle.js +33 -0
- package/dist/personhood/bind-paid-alias.d.ts +43 -0
- package/dist/personhood/bind-paid-alias.js +10 -0
- package/dist/personhood/bind-personal-id.d.ts +55 -0
- package/dist/personhood/bind-personal-id.js +12 -0
- package/dist/personhood/bootstrap.d.ts +85 -0
- package/dist/personhood/bootstrap.js +245 -0
- package/dist/personhood/claim-pgas.d.ts +61 -0
- package/dist/personhood/claim-pgas.js +12 -0
- package/dist/personhood/constants.d.ts +23 -0
- package/dist/personhood/constants.js +22 -0
- package/dist/personhood/encoding.d.ts +49 -0
- package/dist/personhood/encoding.js +24 -0
- package/dist/personhood/hashing.d.ts +4 -0
- package/dist/personhood/hashing.js +8 -0
- package/dist/personhood/member-key.d.ts +12 -0
- package/dist/personhood/member-key.js +10 -0
- package/dist/personhood/people-client.d.ts +14 -0
- package/dist/personhood/people-client.js +48 -0
- package/dist/personhood/reprove.d.ts +43 -0
- package/dist/personhood/reprove.js +225 -0
- package/dist/pool.d.ts +51 -0
- package/dist/pool.js +30 -0
- package/dist/run-state.d.ts +22 -0
- package/dist/run-state.js +20 -0
- package/dist/telemetry.d.ts +56 -0
- package/dist/telemetry.js +71 -0
- package/dist/version-check.d.ts +38 -0
- package/dist/version-check.js +30 -0
- package/docs/bootstrap.md +49 -0
- package/docs/e2e-bootstrap.md +154 -0
- package/docs/telemetry.md +62 -0
- package/docs/testing.md +44 -0
- package/package.json +82 -0
- package/tools/release-retry-wrapper.mjs +74 -0
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
import {
|
|
2
|
+
PAID_PROOF_TAG,
|
|
3
|
+
PEOPLE_MEMBER_IDENTIFIER_HEX,
|
|
4
|
+
PGAS_ASSET_ID,
|
|
5
|
+
PGAS_ASSET_LOCATION,
|
|
6
|
+
PROOF_BYTES
|
|
7
|
+
} from "./chunk-T7EEVWNU.js";
|
|
8
|
+
import {
|
|
9
|
+
blake2_256,
|
|
10
|
+
bytesToHex,
|
|
11
|
+
concatBytes,
|
|
12
|
+
encodeMembers,
|
|
13
|
+
hexToBytes
|
|
14
|
+
} from "./chunk-ZYVGHDMU.js";
|
|
15
|
+
|
|
16
|
+
// src/personhood/bind-paid-alias.ts
|
|
17
|
+
import { getSs58AddressInfo } from "polkadot-api";
|
|
18
|
+
var PaidAliasBindingError = class extends Error {
|
|
19
|
+
kind;
|
|
20
|
+
dispatchError;
|
|
21
|
+
constructor(message, options = {}) {
|
|
22
|
+
super(message, options);
|
|
23
|
+
this.name = "PaidAliasBindingError";
|
|
24
|
+
this.kind = options.kind ?? "Unknown";
|
|
25
|
+
this.dispatchError = options.dispatchError;
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
var bindPaidAliasToAccount = async ({
|
|
29
|
+
peopleUnsafeApi,
|
|
30
|
+
ahUnsafeApi,
|
|
31
|
+
account,
|
|
32
|
+
memberKey,
|
|
33
|
+
contextBytes,
|
|
34
|
+
signCall,
|
|
35
|
+
buildRingProof,
|
|
36
|
+
progress
|
|
37
|
+
}) => {
|
|
38
|
+
const people = peopleUnsafeApi;
|
|
39
|
+
const ah = ahUnsafeApi;
|
|
40
|
+
if (memberKey.length !== 32) {
|
|
41
|
+
throw new PaidAliasBindingError("memberKey must be 32 bytes", {
|
|
42
|
+
kind: "ClientError"
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
if (contextBytes.length !== 32) {
|
|
46
|
+
throw new PaidAliasBindingError("contextBytes must be 32 bytes", {
|
|
47
|
+
kind: "ClientError"
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
const fee = await ah.query.AliasAccounts.PaidAliasFee.getValue({ at: "best" });
|
|
51
|
+
if (fee === void 0) {
|
|
52
|
+
throw new PaidAliasBindingError(
|
|
53
|
+
"AliasAccounts.PaidAliasFee is unset \u2014 needs sudo `set_paid_alias_fee`",
|
|
54
|
+
{ kind: "PaidAliasFeeUnset" }
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
const pgas = await ah.query.Assets.Account.getValue(
|
|
58
|
+
PGAS_ASSET_ID,
|
|
59
|
+
account,
|
|
60
|
+
{ at: "best" }
|
|
61
|
+
);
|
|
62
|
+
const pgasBalance = pgas?.balance ?? 0n;
|
|
63
|
+
if (pgasBalance < fee) {
|
|
64
|
+
throw new PaidAliasBindingError(
|
|
65
|
+
`signer has ${pgasBalance.toString()} PGAS but PaidAliasFee is ${fee.toString()} \u2014 claim PGAS first`,
|
|
66
|
+
{ kind: "InsufficientPgas" }
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
const position = await people.query.Members.Members.getValue(
|
|
70
|
+
PEOPLE_MEMBER_IDENTIFIER_HEX,
|
|
71
|
+
bytesToHex(memberKey),
|
|
72
|
+
{ at: "best" }
|
|
73
|
+
);
|
|
74
|
+
if (!position || position.type !== "Included") {
|
|
75
|
+
throw new PaidAliasBindingError(
|
|
76
|
+
`member position is '${position?.type ?? "absent"}', expected 'Included'`,
|
|
77
|
+
{ kind: "NotARecognizedPerson" }
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
const ringIndex = position.value.ring_index;
|
|
81
|
+
const allEntries = await people.query.Members.RingKeys.getEntries({
|
|
82
|
+
at: "best"
|
|
83
|
+
});
|
|
84
|
+
const pages = [];
|
|
85
|
+
const identHex = PEOPLE_MEMBER_IDENTIFIER_HEX.toLowerCase();
|
|
86
|
+
for (const entry of allEntries) {
|
|
87
|
+
if (entry.keyArgs[0].toLowerCase() !== identHex) continue;
|
|
88
|
+
if (Number(entry.keyArgs[1]) !== ringIndex) continue;
|
|
89
|
+
pages.push([Number(entry.keyArgs[2]), [...entry.value]]);
|
|
90
|
+
}
|
|
91
|
+
pages.sort((a, b) => a[0] - b[0]);
|
|
92
|
+
const ringKeys = pages.flatMap(([, ks]) => ks);
|
|
93
|
+
if (ringKeys.length === 0) {
|
|
94
|
+
throw new PaidAliasBindingError("ring has no members on People", {
|
|
95
|
+
kind: "ClientError"
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
const membersBytes = encodeMembers(ringKeys.map((k) => hexToBytes(k)));
|
|
99
|
+
const collectionId = await ah.constants.AliasAccounts.PeopleCollectionIdentifier();
|
|
100
|
+
const ringExp = await ah.constants.AliasAccounts.PeopleRingExponent();
|
|
101
|
+
const ringExponent = ringExp.type === "R2e9" ? 9 : ringExp.type === "R2e10" ? 10 : 14;
|
|
102
|
+
const ringRoots = await ah.query.MembersSubscriber.RingRoots.getValue(
|
|
103
|
+
collectionId,
|
|
104
|
+
ringIndex,
|
|
105
|
+
{ at: "best" }
|
|
106
|
+
);
|
|
107
|
+
if (!ringRoots || ringRoots.length === 0) {
|
|
108
|
+
throw new PaidAliasBindingError(
|
|
109
|
+
"AH has no RingRoots for this (collection, ring_index)",
|
|
110
|
+
{ kind: "RingRootNotFound" }
|
|
111
|
+
);
|
|
112
|
+
}
|
|
113
|
+
const latest = ringRoots[ringRoots.length - 1];
|
|
114
|
+
const revision = latest.revision;
|
|
115
|
+
const ss58Info = getSs58AddressInfo(account);
|
|
116
|
+
if (!ss58Info.isValid) {
|
|
117
|
+
throw new PaidAliasBindingError(`invalid SS58: ${account}`, {
|
|
118
|
+
kind: "ClientError"
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
const paidMsg = blake2_256(concatBytes(PAID_PROOF_TAG, ss58Info.publicKey));
|
|
122
|
+
const { proof, alias } = await buildRingProof({
|
|
123
|
+
ringExponent,
|
|
124
|
+
members: membersBytes,
|
|
125
|
+
context: contextBytes,
|
|
126
|
+
msg: paidMsg
|
|
127
|
+
});
|
|
128
|
+
if (proof.length !== PROOF_BYTES) {
|
|
129
|
+
throw new PaidAliasBindingError(
|
|
130
|
+
`ring proof must be ${PROOF_BYTES} bytes, got ${proof.length}`,
|
|
131
|
+
{ kind: "ClientError" }
|
|
132
|
+
);
|
|
133
|
+
}
|
|
134
|
+
const tx = ah.tx.AliasAccounts.set_paid_alias_account({
|
|
135
|
+
proof: bytesToHex(proof),
|
|
136
|
+
collection: collectionId,
|
|
137
|
+
ring_index: ringIndex,
|
|
138
|
+
ring_revision: revision,
|
|
139
|
+
context: bytesToHex(contextBytes)
|
|
140
|
+
});
|
|
141
|
+
const submitOptions = {
|
|
142
|
+
customSignedExtensions: {
|
|
143
|
+
ChargeAssetTxPayment: {
|
|
144
|
+
value: { tip: 0n, asset_id: PGAS_ASSET_LOCATION }
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
};
|
|
148
|
+
const blockHash = await new Promise((resolve, reject) => {
|
|
149
|
+
let settled = false;
|
|
150
|
+
const fail = (err) => {
|
|
151
|
+
if (settled) return;
|
|
152
|
+
settled = true;
|
|
153
|
+
reject(err);
|
|
154
|
+
};
|
|
155
|
+
const succeed = (h) => {
|
|
156
|
+
if (settled) return;
|
|
157
|
+
settled = true;
|
|
158
|
+
resolve(h);
|
|
159
|
+
};
|
|
160
|
+
tx.signSubmitAndWatch(signCall, submitOptions).subscribe({
|
|
161
|
+
next: (event) => {
|
|
162
|
+
if (settled) return;
|
|
163
|
+
const ev = event;
|
|
164
|
+
if (ev.type === "broadcasted") {
|
|
165
|
+
progress?.onBroadcasted?.();
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
if (ev.type === "txBestBlocksState" && ev.found) {
|
|
169
|
+
if (ev.ok === false) {
|
|
170
|
+
fail(
|
|
171
|
+
new PaidAliasBindingError(
|
|
172
|
+
"set_paid_alias_account dispatched but failed in-block",
|
|
173
|
+
{
|
|
174
|
+
kind: narrowDispatchError(ev.dispatchError),
|
|
175
|
+
dispatchError: ev.dispatchError
|
|
176
|
+
}
|
|
177
|
+
)
|
|
178
|
+
);
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
if (ev.block) progress?.onBestBlock?.(ev.block.hash);
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
if (ev.type === "finalized") {
|
|
185
|
+
if (ev.ok === false) {
|
|
186
|
+
fail(
|
|
187
|
+
new PaidAliasBindingError(
|
|
188
|
+
"set_paid_alias_account failed at finalization",
|
|
189
|
+
{
|
|
190
|
+
kind: narrowDispatchError(ev.dispatchError),
|
|
191
|
+
dispatchError: ev.dispatchError
|
|
192
|
+
}
|
|
193
|
+
)
|
|
194
|
+
);
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
if (ev.block) succeed(ev.block.hash);
|
|
198
|
+
}
|
|
199
|
+
},
|
|
200
|
+
error: (err) => {
|
|
201
|
+
fail(
|
|
202
|
+
err instanceof PaidAliasBindingError ? err : new PaidAliasBindingError(
|
|
203
|
+
err instanceof Error ? `RPC rejected extrinsic: ${err.message}` : "RPC error during submitAndWatch",
|
|
204
|
+
{ cause: err, kind: "RpcError" }
|
|
205
|
+
)
|
|
206
|
+
);
|
|
207
|
+
}
|
|
208
|
+
});
|
|
209
|
+
});
|
|
210
|
+
return { blockHash, alias };
|
|
211
|
+
};
|
|
212
|
+
var narrowDispatchError = (dispatchError) => {
|
|
213
|
+
if (typeof dispatchError === "object" && dispatchError !== null && "type" in dispatchError) {
|
|
214
|
+
const d = dispatchError;
|
|
215
|
+
if (d.type === "Module" && typeof d.value === "object" && d.value !== null) {
|
|
216
|
+
const v = d.value;
|
|
217
|
+
if (v.type === "AliasAccounts" && v.value?.type === "BadProof") {
|
|
218
|
+
return "BadProof";
|
|
219
|
+
}
|
|
220
|
+
if (v.type === "AliasAccounts" && v.value?.type === "PaidAliasFeeUnset") {
|
|
221
|
+
return "PaidAliasFeeUnset";
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
return "DispatchError";
|
|
226
|
+
};
|
|
227
|
+
|
|
228
|
+
export {
|
|
229
|
+
PaidAliasBindingError,
|
|
230
|
+
bindPaidAliasToAccount
|
|
231
|
+
};
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
import {
|
|
2
|
+
classifyErrorArea,
|
|
3
|
+
isInteractive,
|
|
4
|
+
promptYesNo
|
|
5
|
+
} from "./chunk-43HLT335.js";
|
|
6
|
+
import {
|
|
7
|
+
VERSION,
|
|
8
|
+
getCurrentSentryTraceId
|
|
9
|
+
} from "./chunk-MFTODIIT.js";
|
|
10
|
+
|
|
11
|
+
// src/bug-report.ts
|
|
12
|
+
import { execSync, execFileSync } from "child_process";
|
|
13
|
+
import * as os from "os";
|
|
14
|
+
var _deployContext = {};
|
|
15
|
+
function setDeployContext(ctx) {
|
|
16
|
+
_deployContext = { ..._deployContext, ...ctx };
|
|
17
|
+
}
|
|
18
|
+
function hasGhCli() {
|
|
19
|
+
try {
|
|
20
|
+
execSync("gh --version", { stdio: "pipe" });
|
|
21
|
+
return true;
|
|
22
|
+
} catch {
|
|
23
|
+
return false;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
var LOG_TAIL_BYTES = 32 * 1024;
|
|
27
|
+
var _logBuffer = "";
|
|
28
|
+
var _logCaptureInstalled = false;
|
|
29
|
+
function installLogCapture() {
|
|
30
|
+
if (_logCaptureInstalled) return;
|
|
31
|
+
_logCaptureInstalled = true;
|
|
32
|
+
const append = (args) => {
|
|
33
|
+
const line = args.map((a) => typeof a === "string" ? a : safeStringify(a)).join(" ") + "\n";
|
|
34
|
+
_logBuffer += line;
|
|
35
|
+
if (_logBuffer.length > LOG_TAIL_BYTES * 2) {
|
|
36
|
+
_logBuffer = _logBuffer.slice(_logBuffer.length - LOG_TAIL_BYTES);
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
const wrap = (key) => {
|
|
40
|
+
const orig = console[key].bind(console);
|
|
41
|
+
console[key] = (...a) => {
|
|
42
|
+
append(a);
|
|
43
|
+
orig(...a);
|
|
44
|
+
};
|
|
45
|
+
};
|
|
46
|
+
wrap("log");
|
|
47
|
+
wrap("error");
|
|
48
|
+
wrap("warn");
|
|
49
|
+
}
|
|
50
|
+
function safeStringify(v) {
|
|
51
|
+
try {
|
|
52
|
+
if (v instanceof Error) return v.stack || v.message;
|
|
53
|
+
return JSON.stringify(v);
|
|
54
|
+
} catch {
|
|
55
|
+
return String(v);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
function getCapturedTail() {
|
|
59
|
+
if (!_logBuffer) return "";
|
|
60
|
+
const tail = _logBuffer.length > LOG_TAIL_BYTES ? "\u2026 [truncated]\n" + _logBuffer.slice(_logBuffer.length - LOG_TAIL_BYTES) : _logBuffer;
|
|
61
|
+
return scrubSecrets(tail);
|
|
62
|
+
}
|
|
63
|
+
function scrubSecrets(text) {
|
|
64
|
+
if (!text) return text;
|
|
65
|
+
let out = text;
|
|
66
|
+
out = out.replace(/(--mnemonic(?:=|\s+))("[^"]*"|'[^']*'|\S+)/gi, "$1<REDACTED>");
|
|
67
|
+
out = out.replace(/(--password(?:=|\s+))("[^"]*"|'[^']*'|\S+)/gi, "$1<REDACTED>");
|
|
68
|
+
out = out.replace(/\b(MNEMONIC|PASSWORD|BULLETIN_MNEMONIC|GITHUB_TOKEN|GH_TOKEN|NPM_TOKEN|SENTRY_AUTH_TOKEN)=([^\s]+)/gi, "$1=<REDACTED>");
|
|
69
|
+
out = out.replace(/\b(ghp|ghs|gho|ghu|ghr)_[A-Za-z0-9]{20,}\b/g, "<REDACTED_TOKEN>");
|
|
70
|
+
out = out.replace(/\bgithub_pat_[A-Za-z0-9_]{20,}\b/g, "<REDACTED_TOKEN>");
|
|
71
|
+
out = out.replace(/\b(?:[a-z]{3,10}\s+){11}[a-z]{3,10}\b/g, "<REDACTED_MNEMONIC>");
|
|
72
|
+
out = out.replace(/([a-z][a-z0-9+.-]*:\/\/)[^:@\s]+:[^@\s]+@/gi, "$1<REDACTED>@");
|
|
73
|
+
return out;
|
|
74
|
+
}
|
|
75
|
+
function buildCliFlagsSummary(flags) {
|
|
76
|
+
const parts = [];
|
|
77
|
+
if (flags.jsMerkle) parts.push("--js-merkle");
|
|
78
|
+
if (flags.ghPagesMirror) parts.push("--gh-pages-mirror");
|
|
79
|
+
if (flags.publish) parts.push("--publish");
|
|
80
|
+
if (flags.unpublish) parts.push("--unpublish");
|
|
81
|
+
if (flags.failOnPublishError) parts.push("--fail-on-publish-error");
|
|
82
|
+
if (flags.poolSize != null) parts.push(`--pool-size ${String(flags.poolSize)}`);
|
|
83
|
+
if (typeof flags.tag === "string" && flags.tag) parts.push(`--tag ${flags.tag}`);
|
|
84
|
+
if (flags.mnemonic) parts.push("--mnemonic <set>");
|
|
85
|
+
if (flags.password) parts.push("--password <set>");
|
|
86
|
+
if (flags.derivationPath) parts.push("--derivation-path <set>");
|
|
87
|
+
if (typeof flags.rpc === "string" && flags.rpc) parts.push("--rpc <set>");
|
|
88
|
+
return parts.join(" ");
|
|
89
|
+
}
|
|
90
|
+
function buildReportBody(error) {
|
|
91
|
+
const lines = [
|
|
92
|
+
"## Environment",
|
|
93
|
+
"",
|
|
94
|
+
`- **bulletin-deploy**: ${VERSION}`,
|
|
95
|
+
`- **Node.js**: ${process.version}`,
|
|
96
|
+
`- **OS**: ${os.platform()} ${os.arch()} ${os.release()}`,
|
|
97
|
+
"",
|
|
98
|
+
"## Error",
|
|
99
|
+
"",
|
|
100
|
+
"```",
|
|
101
|
+
scrubSecrets(error.stack || error.message),
|
|
102
|
+
"```",
|
|
103
|
+
""
|
|
104
|
+
];
|
|
105
|
+
const ctx = _deployContext;
|
|
106
|
+
const traceId = getCurrentSentryTraceId();
|
|
107
|
+
const hasCtx = ctx.domain || ctx.repo || ctx.rpc || ctx.cliFlags || ctx.ci?.runUrl || traceId;
|
|
108
|
+
if (hasCtx) {
|
|
109
|
+
lines.push("## Deploy Context", "");
|
|
110
|
+
if (ctx.domain) lines.push(`- **Domain**: ${ctx.domain}`);
|
|
111
|
+
if (ctx.repo) lines.push(`- **Repo**: ${ctx.repo}`);
|
|
112
|
+
if (ctx.branch) lines.push(`- **Branch**: ${ctx.branch}`);
|
|
113
|
+
if (ctx.signerMode) lines.push(`- **Signer mode**: ${ctx.signerMode}`);
|
|
114
|
+
if (ctx.chunkCount != null) lines.push(`- **Chunks**: ${ctx.chunkCount}`);
|
|
115
|
+
if (ctx.totalSize) lines.push(`- **Total size**: ${ctx.totalSize}`);
|
|
116
|
+
if (ctx.rpc) lines.push(`- **RPC**: ${ctx.rpc}`);
|
|
117
|
+
if (ctx.deployTag) lines.push(`- **Deploy tag**: ${ctx.deployTag}`);
|
|
118
|
+
if (ctx.cliFlags) lines.push(`- **CLI flags**: \`${ctx.cliFlags}\``);
|
|
119
|
+
if (traceId) lines.push(`- **Sentry trace**: ${traceId}`);
|
|
120
|
+
lines.push("");
|
|
121
|
+
}
|
|
122
|
+
if (ctx.ci?.runUrl) {
|
|
123
|
+
lines.push("## CI", "");
|
|
124
|
+
lines.push(`- **Run**: ${ctx.ci.runUrl}`);
|
|
125
|
+
if (ctx.ci.workflow) lines.push(`- **Workflow**: ${ctx.ci.workflow}`);
|
|
126
|
+
if (ctx.ci.job) lines.push(`- **Job**: ${ctx.ci.job}`);
|
|
127
|
+
if (ctx.ci.sha) lines.push(`- **SHA**: ${ctx.ci.sha}`);
|
|
128
|
+
lines.push("");
|
|
129
|
+
}
|
|
130
|
+
const tail = getCapturedTail();
|
|
131
|
+
if (tail) {
|
|
132
|
+
lines.push("## Log tail", "", "<details><summary>Last ~32 KB of stdout/stderr (secrets scrubbed)</summary>", "", "```", tail.trimEnd(), "```", "", "</details>", "");
|
|
133
|
+
}
|
|
134
|
+
return lines.join("\n");
|
|
135
|
+
}
|
|
136
|
+
function buildTitle(error) {
|
|
137
|
+
const msg = error.message.slice(0, 60);
|
|
138
|
+
return `[deploy-bug] ${msg}`;
|
|
139
|
+
}
|
|
140
|
+
function buildLabels(error) {
|
|
141
|
+
const labels = ["bug", "auto-report"];
|
|
142
|
+
const area = classifyErrorArea(error.message);
|
|
143
|
+
if (area) labels.push(area);
|
|
144
|
+
return labels;
|
|
145
|
+
}
|
|
146
|
+
function createGhIssue(title, body, labels) {
|
|
147
|
+
const args = [
|
|
148
|
+
"issue",
|
|
149
|
+
"create",
|
|
150
|
+
"--repo",
|
|
151
|
+
"paritytech/bulletin-deploy",
|
|
152
|
+
"--title",
|
|
153
|
+
title,
|
|
154
|
+
...labels.flatMap((l) => ["--label", l]),
|
|
155
|
+
"--body-file",
|
|
156
|
+
"-"
|
|
157
|
+
];
|
|
158
|
+
const out = execFileSync("gh", args, { input: body, stdio: ["pipe", "pipe", "inherit"] });
|
|
159
|
+
return out.toString("utf8").trim();
|
|
160
|
+
}
|
|
161
|
+
function applyCoreLabels(issueUrl) {
|
|
162
|
+
try {
|
|
163
|
+
execFileSync(
|
|
164
|
+
"gh",
|
|
165
|
+
["issue", "edit", issueUrl, "--add-label", "bug", "--add-label", "auto-report"],
|
|
166
|
+
{ stdio: ["ignore", "pipe", "pipe"] }
|
|
167
|
+
);
|
|
168
|
+
return true;
|
|
169
|
+
} catch {
|
|
170
|
+
return false;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
async function offerBugReport(error) {
|
|
174
|
+
if (!isInteractive()) return;
|
|
175
|
+
const yes = await promptYesNo("\n This looks like a bug. Open an issue with debug info? [Y/n] ");
|
|
176
|
+
if (!yes) return;
|
|
177
|
+
const title = buildTitle(error);
|
|
178
|
+
const body = buildReportBody(error);
|
|
179
|
+
const labels = buildLabels(error);
|
|
180
|
+
if (!hasGhCli()) {
|
|
181
|
+
console.error("\n gh CLI not found. Debug info below \u2014 paste into a new issue:\n");
|
|
182
|
+
console.error(` https://github.com/paritytech/bulletin-deploy/issues/new
|
|
183
|
+
`);
|
|
184
|
+
printFallback(title, body, labels);
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
try {
|
|
188
|
+
const url = createGhIssue(title, body, labels);
|
|
189
|
+
console.error(` Issue created: ${url}`);
|
|
190
|
+
return;
|
|
191
|
+
} catch {
|
|
192
|
+
}
|
|
193
|
+
try {
|
|
194
|
+
console.error(" Retrying without labels...");
|
|
195
|
+
const url = createGhIssue(title, body, []);
|
|
196
|
+
const applied = applyCoreLabels(url);
|
|
197
|
+
if (applied) {
|
|
198
|
+
console.error(` Issue created: ${url} (labels applied after retry)`);
|
|
199
|
+
} else {
|
|
200
|
+
console.error(` Issue created: ${url} (labels could not be applied; please add 'bug' and 'auto-report' manually)`);
|
|
201
|
+
}
|
|
202
|
+
} catch {
|
|
203
|
+
console.error(" Failed to create issue. Debug info below:\n");
|
|
204
|
+
printFallback(title, body, labels);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
function printFallback(title, body, labels) {
|
|
208
|
+
console.error(` Title: ${title}`);
|
|
209
|
+
console.error(` Labels: ${labels.join(", ")}
|
|
210
|
+
`);
|
|
211
|
+
console.error(body);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
export {
|
|
215
|
+
setDeployContext,
|
|
216
|
+
installLogCapture,
|
|
217
|
+
getCapturedTail,
|
|
218
|
+
scrubSecrets,
|
|
219
|
+
buildCliFlagsSummary,
|
|
220
|
+
buildReportBody,
|
|
221
|
+
buildTitle,
|
|
222
|
+
buildLabels,
|
|
223
|
+
createGhIssue,
|
|
224
|
+
offerBugReport
|
|
225
|
+
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import {
|
|
2
|
+
MEMBER_ENTROPY_KEY
|
|
3
|
+
} from "./chunk-T7EEVWNU.js";
|
|
4
|
+
import {
|
|
5
|
+
blake2b256Keyed
|
|
6
|
+
} from "./chunk-UPWEOGLQ.js";
|
|
7
|
+
|
|
8
|
+
// src/personhood/member-key.ts
|
|
9
|
+
import { mnemonicToEntropy } from "@polkadot-labs/hdkd-helpers";
|
|
10
|
+
import * as verifiable from "verifiablejs/nodejs";
|
|
11
|
+
function deriveMemberEntropy(mnemonic) {
|
|
12
|
+
const normalized = mnemonic.trim().split(/\s+/).join(" ");
|
|
13
|
+
const bip39Entropy = mnemonicToEntropy(normalized);
|
|
14
|
+
return blake2b256Keyed(bip39Entropy, MEMBER_ENTROPY_KEY);
|
|
15
|
+
}
|
|
16
|
+
function deriveMemberKey(mnemonic) {
|
|
17
|
+
const entropy = deriveMemberEntropy(mnemonic);
|
|
18
|
+
return verifiable.member_from_entropy(entropy);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export {
|
|
22
|
+
deriveMemberEntropy,
|
|
23
|
+
deriveMemberKey
|
|
24
|
+
};
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
// src/chunker.ts
|
|
2
|
+
var CHUNK_SIZE_TARGET = 1024 * 1024;
|
|
3
|
+
var CHUNK_SIZE_MAX = 2 * 1024 * 1024 - 1024;
|
|
4
|
+
function concat(parts) {
|
|
5
|
+
let total = 0;
|
|
6
|
+
for (const p of parts) total += p.length;
|
|
7
|
+
const out = new Uint8Array(total);
|
|
8
|
+
let off = 0;
|
|
9
|
+
for (const p of parts) {
|
|
10
|
+
out.set(p, off);
|
|
11
|
+
off += p.length;
|
|
12
|
+
}
|
|
13
|
+
return out;
|
|
14
|
+
}
|
|
15
|
+
function packSection(files) {
|
|
16
|
+
const chunks = [];
|
|
17
|
+
let buffer = [];
|
|
18
|
+
let bufferLen = 0;
|
|
19
|
+
const flush = () => {
|
|
20
|
+
if (bufferLen === 0) return;
|
|
21
|
+
chunks.push(concat(buffer));
|
|
22
|
+
buffer = [];
|
|
23
|
+
bufferLen = 0;
|
|
24
|
+
};
|
|
25
|
+
for (const file of files) {
|
|
26
|
+
const fileBytes = file.blocks.reduce((s, b) => s + b.length, 0);
|
|
27
|
+
if (fileBytes === 0) continue;
|
|
28
|
+
if (fileBytes > CHUNK_SIZE_TARGET) {
|
|
29
|
+
flush();
|
|
30
|
+
if (fileBytes > CHUNK_SIZE_MAX) {
|
|
31
|
+
for (const block of file.blocks) {
|
|
32
|
+
if (bufferLen + block.length > CHUNK_SIZE_MAX) {
|
|
33
|
+
flush();
|
|
34
|
+
}
|
|
35
|
+
buffer.push(block);
|
|
36
|
+
bufferLen += block.length;
|
|
37
|
+
}
|
|
38
|
+
flush();
|
|
39
|
+
} else {
|
|
40
|
+
for (const block of file.blocks) {
|
|
41
|
+
buffer.push(block);
|
|
42
|
+
bufferLen += block.length;
|
|
43
|
+
flush();
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
} else {
|
|
47
|
+
if (bufferLen + fileBytes > CHUNK_SIZE_TARGET) {
|
|
48
|
+
flush();
|
|
49
|
+
}
|
|
50
|
+
for (const block of file.blocks) {
|
|
51
|
+
buffer.push(block);
|
|
52
|
+
bufferLen += block.length;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
flush();
|
|
57
|
+
return chunks;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export {
|
|
61
|
+
CHUNK_SIZE_TARGET,
|
|
62
|
+
CHUNK_SIZE_MAX,
|
|
63
|
+
packSection
|
|
64
|
+
};
|