@git.zone/cli 6.9.0 → 6.10.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_ts/00_commitinfo_data.js +2 -2
- package/dist_ts/helpers.workflow.d.ts +23 -1
- package/dist_ts/helpers.workflow.js +93 -3
- package/dist_ts/mod_config/index.js +49 -7
- package/dist_ts/mod_release/classes.releasejournal.d.ts +20 -1
- package/dist_ts/mod_release/classes.releasejournal.js +191 -9
- package/dist_ts/mod_release/helpers.giteaassets.d.ts +36 -0
- package/dist_ts/mod_release/helpers.giteaassets.js +661 -0
- package/dist_ts/mod_release/helpers.releasepublication.d.ts +2 -0
- package/dist_ts/mod_release/helpers.releasepublication.js +147 -6
- package/dist_ts/mod_release/index.js +86 -11
- package/dist_ts/mod_release/interfaces.giteaassets.d.ts +50 -0
- package/dist_ts/mod_release/interfaces.giteaassets.js +2 -0
- package/package.json +2 -2
- package/readme.md +92 -3
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/helpers.workflow.ts +154 -3
- package/ts/mod_config/index.ts +61 -6
- package/ts/mod_release/classes.releasejournal.ts +298 -14
- package/ts/mod_release/helpers.giteaassets.ts +932 -0
- package/ts/mod_release/helpers.releasepublication.ts +224 -4
- package/ts/mod_release/index.ts +111 -8
- package/ts/mod_release/interfaces.giteaassets.ts +67 -0
|
@@ -0,0 +1,661 @@
|
|
|
1
|
+
import * as plugins from "./mod.plugins.js";
|
|
2
|
+
const maximumManifestBytes = 4 * 1024 * 1024;
|
|
3
|
+
const maximumMetadataBytes = 8 * 1024 * 1024;
|
|
4
|
+
const maximumAssetBytes = 32 * 1024 * 1024 * 1024;
|
|
5
|
+
const maximumAssets = 1024;
|
|
6
|
+
const canonicalName = /^[A-Za-z0-9][A-Za-z0-9._-]{0,199}$/;
|
|
7
|
+
const sha256Pattern = /^[a-f0-9]{64}$/;
|
|
8
|
+
export class GiteaAssetConflictError extends Error {
|
|
9
|
+
constructor(message) {
|
|
10
|
+
super(message);
|
|
11
|
+
this.name = "GiteaAssetConflictError";
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
class GiteaAssetHttpError extends Error {
|
|
15
|
+
constructor(method, status) {
|
|
16
|
+
super(`Gitea asset ${method} returned HTTP ${status}; inspect the retained release before another mutation.`);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
const record = (value) => {
|
|
20
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
21
|
+
throw new Error("Invalid Gitea asset object.");
|
|
22
|
+
}
|
|
23
|
+
return value;
|
|
24
|
+
};
|
|
25
|
+
const exactKeys = (value, keys) => {
|
|
26
|
+
if (Object.keys(value).sort().join("\0") !== [...keys].sort().join("\0")) {
|
|
27
|
+
throw new Error("Unexpected Gitea asset manifest fields.");
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
const positiveId = (value) => {
|
|
31
|
+
if (!Number.isSafeInteger(value) || value <= 0) {
|
|
32
|
+
throw new Error("Invalid Gitea response identifier.");
|
|
33
|
+
}
|
|
34
|
+
return value;
|
|
35
|
+
};
|
|
36
|
+
const assertName = (value) => {
|
|
37
|
+
if (typeof value !== "string" || !canonicalName.test(value)) {
|
|
38
|
+
throw new Error("Gitea asset names must be canonical single path components.");
|
|
39
|
+
}
|
|
40
|
+
return value;
|
|
41
|
+
};
|
|
42
|
+
const assertTag = (value) => {
|
|
43
|
+
if (!canonicalName.test(value) ||
|
|
44
|
+
value.endsWith(".") ||
|
|
45
|
+
value.endsWith(".lock") ||
|
|
46
|
+
value.includes("..")) {
|
|
47
|
+
throw new Error("Gitea asset publication requires a canonical release tag.");
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
const assertSizeAndHash = (value) => {
|
|
51
|
+
if (!Number.isSafeInteger(value.size) ||
|
|
52
|
+
value.size < 0 ||
|
|
53
|
+
value.size > maximumAssetBytes ||
|
|
54
|
+
typeof value.sha256 !== "string" ||
|
|
55
|
+
!sha256Pattern.test(value.sha256)) {
|
|
56
|
+
throw new Error("Invalid Gitea asset size or SHA256.");
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
export const normalizeGiteaAssetDestination = (value) => {
|
|
60
|
+
const candidate = record(value);
|
|
61
|
+
exactKeys(candidate, ["apiOrigin", "owner", "repository"]);
|
|
62
|
+
let url;
|
|
63
|
+
try {
|
|
64
|
+
url = new URL(candidate.apiOrigin);
|
|
65
|
+
}
|
|
66
|
+
catch {
|
|
67
|
+
throw new Error("Invalid Gitea API origin.");
|
|
68
|
+
}
|
|
69
|
+
if (url.protocol !== "https:" ||
|
|
70
|
+
url.username ||
|
|
71
|
+
url.password ||
|
|
72
|
+
url.search ||
|
|
73
|
+
url.hash ||
|
|
74
|
+
url.pathname !== "/" ||
|
|
75
|
+
![url.origin, `${url.origin}/`].includes(candidate.apiOrigin)) {
|
|
76
|
+
throw new Error("Gitea API origin must be credential-free canonical HTTPS.");
|
|
77
|
+
}
|
|
78
|
+
return {
|
|
79
|
+
apiOrigin: url.origin,
|
|
80
|
+
owner: assertName(candidate.owner),
|
|
81
|
+
repository: assertName(candidate.repository),
|
|
82
|
+
};
|
|
83
|
+
};
|
|
84
|
+
export const giteaAssetFileName = (name) => `asset.${plugins.crypto.createHash("sha256").update(assertName(name)).digest("hex")}.bin`;
|
|
85
|
+
export const giteaAssetPublicUrl = (destination, tag, name) => {
|
|
86
|
+
const normalized = normalizeGiteaAssetDestination(destination);
|
|
87
|
+
assertTag(tag);
|
|
88
|
+
return `${normalized.apiOrigin}/${normalized.owner}/${normalized.repository}/releases/download/${encodeURIComponent(tag)}/${assertName(name)}`;
|
|
89
|
+
};
|
|
90
|
+
const assertRelativeAssetPath = (value) => {
|
|
91
|
+
if (typeof value !== "string" ||
|
|
92
|
+
value.length > 4096 ||
|
|
93
|
+
value
|
|
94
|
+
.split("/")
|
|
95
|
+
.some((part) => !canonicalName.test(part) ||
|
|
96
|
+
/^(?:node_modules|coverage|secrets?|credentials?|runtime|data|tmp|temp|id_rsa|id_ed25519)(?:\..*)?$/i.test(part) ||
|
|
97
|
+
/\.(?:pem|key|p12|pfx)$/i.test(part))) {
|
|
98
|
+
throw new Error("Asset inputs require canonical repository paths outside credential/runtime directories.");
|
|
99
|
+
}
|
|
100
|
+
return value;
|
|
101
|
+
};
|
|
102
|
+
/** Reject symlinks in every component, including the caller-provided root. */
|
|
103
|
+
const assertRegularPath = async (absolutePath, directory = false) => {
|
|
104
|
+
const resolved = plugins.path.resolve(absolutePath);
|
|
105
|
+
const parsed = plugins.path.parse(resolved);
|
|
106
|
+
let current = parsed.root;
|
|
107
|
+
const parts = resolved
|
|
108
|
+
.slice(parsed.root.length)
|
|
109
|
+
.split(plugins.path.sep)
|
|
110
|
+
.filter(Boolean);
|
|
111
|
+
for (let index = 0; index < parts.length; index++) {
|
|
112
|
+
current = plugins.path.join(current, parts[index]);
|
|
113
|
+
const stat = await plugins.fs.lstat(current);
|
|
114
|
+
const expectDirectory = index < parts.length - 1 || directory;
|
|
115
|
+
if (stat.isSymbolicLink() ||
|
|
116
|
+
(expectDirectory ? !stat.isDirectory() : !stat.isFile())) {
|
|
117
|
+
throw new Error("Gitea asset paths must use regular files and directories without symlinks.");
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
};
|
|
121
|
+
const openRegularFile = async (path) => {
|
|
122
|
+
await assertRegularPath(path);
|
|
123
|
+
const handle = await plugins.fs.open(path, plugins.fsConstants.O_RDONLY | plugins.fsConstants.O_NOFOLLOW);
|
|
124
|
+
try {
|
|
125
|
+
if (!(await handle.stat()).isFile())
|
|
126
|
+
throw new Error("Gitea asset input is not a regular file.");
|
|
127
|
+
return handle;
|
|
128
|
+
}
|
|
129
|
+
catch (error) {
|
|
130
|
+
await handle.close();
|
|
131
|
+
throw error;
|
|
132
|
+
}
|
|
133
|
+
};
|
|
134
|
+
const readBoundedFile = async (path, maximum) => {
|
|
135
|
+
const handle = await openRegularFile(path);
|
|
136
|
+
try {
|
|
137
|
+
if ((await handle.stat()).size > maximum)
|
|
138
|
+
throw new Error("Gitea asset metadata exceeds its size limit.");
|
|
139
|
+
const chunks = [];
|
|
140
|
+
let size = 0;
|
|
141
|
+
for await (const chunk of handle.createReadStream({
|
|
142
|
+
autoClose: false,
|
|
143
|
+
highWaterMark: 64 * 1024,
|
|
144
|
+
})) {
|
|
145
|
+
size += chunk.length;
|
|
146
|
+
if (size > maximum)
|
|
147
|
+
throw new Error("Gitea asset metadata exceeds its size limit.");
|
|
148
|
+
chunks.push(chunk);
|
|
149
|
+
}
|
|
150
|
+
return Buffer.concat(chunks, size);
|
|
151
|
+
}
|
|
152
|
+
finally {
|
|
153
|
+
await handle.close();
|
|
154
|
+
}
|
|
155
|
+
};
|
|
156
|
+
const verifyHandle = async (handle, asset) => {
|
|
157
|
+
const before = await handle.stat();
|
|
158
|
+
if (before.size !== asset.size)
|
|
159
|
+
throw new Error("Stored Gitea asset size conflicts with its frozen identity.");
|
|
160
|
+
const hash = plugins.crypto.createHash("sha256");
|
|
161
|
+
let size = 0;
|
|
162
|
+
for await (const chunk of handle.createReadStream({
|
|
163
|
+
autoClose: false,
|
|
164
|
+
start: 0,
|
|
165
|
+
highWaterMark: 64 * 1024,
|
|
166
|
+
})) {
|
|
167
|
+
size += chunk.length;
|
|
168
|
+
if (size > asset.size)
|
|
169
|
+
throw new Error("Stored Gitea asset exceeds its frozen size.");
|
|
170
|
+
hash.update(chunk);
|
|
171
|
+
}
|
|
172
|
+
const after = await handle.stat();
|
|
173
|
+
if (size !== asset.size ||
|
|
174
|
+
hash.digest("hex") !== asset.sha256 ||
|
|
175
|
+
before.mtimeMs !== after.mtimeMs ||
|
|
176
|
+
before.ctimeMs !== after.ctimeMs) {
|
|
177
|
+
throw new Error("Stored Gitea asset bytes conflict with their frozen identity.");
|
|
178
|
+
}
|
|
179
|
+
};
|
|
180
|
+
export function assertGiteaFrozenAssets(assets, destination, tag) {
|
|
181
|
+
if (!Array.isArray(assets) ||
|
|
182
|
+
assets.length === 0 ||
|
|
183
|
+
assets.length > maximumAssets)
|
|
184
|
+
throw new Error("Invalid Gitea asset set.");
|
|
185
|
+
const names = new Set();
|
|
186
|
+
for (const entry of assets) {
|
|
187
|
+
const asset = record(entry);
|
|
188
|
+
exactKeys(asset, ["name", "size", "sha256", "fileName", "publicUrl"]);
|
|
189
|
+
const name = assertName(asset.name);
|
|
190
|
+
assertSizeAndHash(asset);
|
|
191
|
+
if (names.has(name) || asset.fileName !== giteaAssetFileName(name))
|
|
192
|
+
throw new Error("Duplicate or invalid stored Gitea asset identity.");
|
|
193
|
+
names.add(name);
|
|
194
|
+
let url;
|
|
195
|
+
try {
|
|
196
|
+
url = new URL(asset.publicUrl);
|
|
197
|
+
}
|
|
198
|
+
catch {
|
|
199
|
+
throw new Error("Invalid frozen Gitea asset URL.");
|
|
200
|
+
}
|
|
201
|
+
if (url.protocol !== "https:" ||
|
|
202
|
+
url.username ||
|
|
203
|
+
url.password ||
|
|
204
|
+
url.search ||
|
|
205
|
+
url.hash ||
|
|
206
|
+
url.href !== asset.publicUrl ||
|
|
207
|
+
(destination &&
|
|
208
|
+
tag &&
|
|
209
|
+
asset.publicUrl !== giteaAssetPublicUrl(destination, tag, name))) {
|
|
210
|
+
throw new Error("Frozen Gitea asset URL conflicts with its destination.");
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
export const validateGiteaAssets = async (artifactDirectory, assets) => {
|
|
215
|
+
assertGiteaFrozenAssets(assets);
|
|
216
|
+
await assertRegularPath(artifactDirectory, true);
|
|
217
|
+
for (const asset of assets) {
|
|
218
|
+
const handle = await openRegularFile(plugins.path.join(artifactDirectory, asset.fileName));
|
|
219
|
+
try {
|
|
220
|
+
await verifyHandle(handle, asset);
|
|
221
|
+
}
|
|
222
|
+
finally {
|
|
223
|
+
await handle.close();
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
};
|
|
227
|
+
export const prepareGiteaAssets = async (options) => {
|
|
228
|
+
const destination = normalizeGiteaAssetDestination(options.destination);
|
|
229
|
+
assertTag(options.tag);
|
|
230
|
+
if (!/^\d+\.\d+\.\d+(?:-[A-Za-z0-9.-]+)?(?:\+[A-Za-z0-9.-]+)?$/.test(options.version))
|
|
231
|
+
throw new Error("Invalid Gitea asset manifest release version.");
|
|
232
|
+
await assertRegularPath(options.repositoryRoot, true);
|
|
233
|
+
const manifestPath = plugins.path.join(options.repositoryRoot, assertRelativeAssetPath(options.manifestPath));
|
|
234
|
+
let manifest;
|
|
235
|
+
try {
|
|
236
|
+
manifest = record(JSON.parse((await readBoundedFile(manifestPath, maximumManifestBytes)).toString("utf8")));
|
|
237
|
+
}
|
|
238
|
+
catch {
|
|
239
|
+
throw new Error("Unable to read a bounded regular Gitea asset manifest.");
|
|
240
|
+
}
|
|
241
|
+
exactKeys(manifest, ["schemaVersion", "version", "assets"]);
|
|
242
|
+
if (manifest.schemaVersion !== 1 ||
|
|
243
|
+
manifest.version !== options.version ||
|
|
244
|
+
!Array.isArray(manifest.assets) ||
|
|
245
|
+
manifest.assets.length === 0 ||
|
|
246
|
+
manifest.assets.length > maximumAssets)
|
|
247
|
+
throw new Error("Gitea asset manifest must match the exact release version and schema.");
|
|
248
|
+
const paths = new Set();
|
|
249
|
+
const assets = manifest.assets.map((entry) => {
|
|
250
|
+
const input = record(entry);
|
|
251
|
+
exactKeys(input, ["name", "path", "size", "sha256"]);
|
|
252
|
+
const path = assertRelativeAssetPath(input.path);
|
|
253
|
+
if (paths.has(path))
|
|
254
|
+
throw new Error("Gitea asset input paths must be unique.");
|
|
255
|
+
paths.add(path);
|
|
256
|
+
const name = assertName(input.name);
|
|
257
|
+
assertSizeAndHash(input);
|
|
258
|
+
return {
|
|
259
|
+
name,
|
|
260
|
+
size: input.size,
|
|
261
|
+
sha256: input.sha256,
|
|
262
|
+
fileName: giteaAssetFileName(name),
|
|
263
|
+
publicUrl: giteaAssetPublicUrl(destination, options.tag, name),
|
|
264
|
+
};
|
|
265
|
+
});
|
|
266
|
+
assertGiteaFrozenAssets(assets, destination, options.tag);
|
|
267
|
+
// The journal owner creates this directory; never follow/create an unexpected root here.
|
|
268
|
+
await assertRegularPath(options.artifactDirectory, true);
|
|
269
|
+
for (let index = 0; index < assets.length; index++) {
|
|
270
|
+
const asset = assets[index];
|
|
271
|
+
const inputPath = plugins.path.join(options.repositoryRoot, [...paths][index]);
|
|
272
|
+
const input = await openRegularFile(inputPath);
|
|
273
|
+
try {
|
|
274
|
+
await verifyHandle(input, asset);
|
|
275
|
+
const outputPath = plugins.path.join(options.artifactDirectory, asset.fileName);
|
|
276
|
+
const output = await plugins.fs.open(outputPath, "wx", 0o600);
|
|
277
|
+
try {
|
|
278
|
+
let position = 0;
|
|
279
|
+
for await (const chunk of input.createReadStream({
|
|
280
|
+
autoClose: false,
|
|
281
|
+
start: 0,
|
|
282
|
+
highWaterMark: 64 * 1024,
|
|
283
|
+
})) {
|
|
284
|
+
if (position + chunk.length > asset.size)
|
|
285
|
+
throw new Error("Gitea asset changed during freezing.");
|
|
286
|
+
let written = 0;
|
|
287
|
+
while (written < chunk.length) {
|
|
288
|
+
const result = await output.write(chunk, written, chunk.length - written, position + written);
|
|
289
|
+
if (!result.bytesWritten)
|
|
290
|
+
throw new Error("Unable to freeze complete Gitea asset bytes.");
|
|
291
|
+
written += result.bytesWritten;
|
|
292
|
+
}
|
|
293
|
+
position += chunk.length;
|
|
294
|
+
}
|
|
295
|
+
await output.sync();
|
|
296
|
+
}
|
|
297
|
+
finally {
|
|
298
|
+
await output.close();
|
|
299
|
+
}
|
|
300
|
+
// Includes detecting same-size mutation between the validation and copy passes.
|
|
301
|
+
await validateGiteaAssets(options.artifactDirectory, [asset]);
|
|
302
|
+
}
|
|
303
|
+
finally {
|
|
304
|
+
await input.close();
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
return assets;
|
|
308
|
+
};
|
|
309
|
+
/** No method retries a remote mutation. The release journal owns attempt admission. */
|
|
310
|
+
export class GiteaAssetsClient {
|
|
311
|
+
destination;
|
|
312
|
+
tag;
|
|
313
|
+
commit;
|
|
314
|
+
#token;
|
|
315
|
+
fetchImplementation;
|
|
316
|
+
timeoutMs;
|
|
317
|
+
repositoryApiPath;
|
|
318
|
+
constructor(options) {
|
|
319
|
+
this.destination = normalizeGiteaAssetDestination(options.destination);
|
|
320
|
+
assertTag(options.tag);
|
|
321
|
+
if (!/^(?:[a-f0-9]{40}|[a-f0-9]{64})$/.test(options.commit))
|
|
322
|
+
throw new Error("Gitea assets require the exact release commit.");
|
|
323
|
+
if (typeof options.token !== "string" ||
|
|
324
|
+
!options.token ||
|
|
325
|
+
/[\s\x00-\x1f\x7f]/.test(options.token))
|
|
326
|
+
throw new Error("A valid configured Gitea token is required.");
|
|
327
|
+
this.tag = options.tag;
|
|
328
|
+
this.commit = options.commit;
|
|
329
|
+
this.#token = options.token;
|
|
330
|
+
this.fetchImplementation = options.fetchImplementation ?? fetch;
|
|
331
|
+
this.timeoutMs = options.timeoutMs ?? 15 * 60_000;
|
|
332
|
+
if (!Number.isSafeInteger(this.timeoutMs) ||
|
|
333
|
+
this.timeoutMs <= 0 ||
|
|
334
|
+
this.timeoutMs > 60 * 60_000)
|
|
335
|
+
throw new Error("Invalid Gitea asset request timeout.");
|
|
336
|
+
this.repositoryApiPath = `/repos/${this.destination.owner}/${this.destination.repository}`;
|
|
337
|
+
}
|
|
338
|
+
async requestJson(path, authenticated, method = "GET", body, headers, allow404 = false) {
|
|
339
|
+
const controller = new AbortController();
|
|
340
|
+
const timeout = setTimeout(() => controller.abort(), this.timeoutMs);
|
|
341
|
+
let response;
|
|
342
|
+
try {
|
|
343
|
+
const init = {
|
|
344
|
+
method,
|
|
345
|
+
redirect: "manual",
|
|
346
|
+
signal: controller.signal,
|
|
347
|
+
headers: {
|
|
348
|
+
Accept: "application/json",
|
|
349
|
+
...headers,
|
|
350
|
+
...(authenticated ? { Authorization: `token ${this.#token}` } : {}),
|
|
351
|
+
},
|
|
352
|
+
...(body === undefined ? {} : { body, duplex: "half" }),
|
|
353
|
+
};
|
|
354
|
+
response = await this.fetchImplementation(`${this.destination.apiOrigin}/api/v1${path}`, init);
|
|
355
|
+
if (allow404 && response.status === 404)
|
|
356
|
+
return null;
|
|
357
|
+
if (response.status !== (method === "POST" ? 201 : 200)) {
|
|
358
|
+
throw new GiteaAssetHttpError(method, response.status);
|
|
359
|
+
}
|
|
360
|
+
const bytes = await this.readResponse(response, maximumMetadataBytes);
|
|
361
|
+
return JSON.parse(bytes.toString("utf8"));
|
|
362
|
+
}
|
|
363
|
+
catch (error) {
|
|
364
|
+
// Never include response text, fetch errors, URLs or causes that can expose the token.
|
|
365
|
+
if (error instanceof GiteaAssetHttpError)
|
|
366
|
+
throw error;
|
|
367
|
+
throw new Error(`Gitea asset ${method} result is inconclusive; inspect the retained release before another mutation.`);
|
|
368
|
+
}
|
|
369
|
+
finally {
|
|
370
|
+
controller.abort();
|
|
371
|
+
clearTimeout(timeout);
|
|
372
|
+
if (response?.body && !response.body.locked)
|
|
373
|
+
await response.body.cancel().catch(() => undefined);
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
async readResponse(response, maximum) {
|
|
377
|
+
if (!response.body)
|
|
378
|
+
throw new Error("Missing Gitea response body.");
|
|
379
|
+
const declared = response.headers.get("content-length");
|
|
380
|
+
if (declared !== null &&
|
|
381
|
+
(!/^\d+$/.test(declared) || Number(declared) > maximum))
|
|
382
|
+
throw new Error("Oversized Gitea response.");
|
|
383
|
+
const reader = response.body.getReader();
|
|
384
|
+
const chunks = [];
|
|
385
|
+
let size = 0;
|
|
386
|
+
try {
|
|
387
|
+
while (true) {
|
|
388
|
+
const result = await reader.read();
|
|
389
|
+
if (result.done)
|
|
390
|
+
break;
|
|
391
|
+
size += result.value.byteLength;
|
|
392
|
+
if (size > maximum)
|
|
393
|
+
throw new Error("Oversized Gitea response.");
|
|
394
|
+
chunks.push(Buffer.from(result.value));
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
finally {
|
|
398
|
+
await reader.cancel().catch(() => undefined);
|
|
399
|
+
reader.releaseLock();
|
|
400
|
+
}
|
|
401
|
+
return Buffer.concat(chunks, size);
|
|
402
|
+
}
|
|
403
|
+
async admitRepository(authenticated) {
|
|
404
|
+
const repo = record(await this.requestJson(this.repositoryApiPath, authenticated));
|
|
405
|
+
if (repo.full_name !==
|
|
406
|
+
`${this.destination.owner}/${this.destination.repository}` ||
|
|
407
|
+
repo.private !== false ||
|
|
408
|
+
repo.internal !== false ||
|
|
409
|
+
repo.archived !== false ||
|
|
410
|
+
repo.has_releases !== true ||
|
|
411
|
+
repo.html_url !==
|
|
412
|
+
`${this.destination.apiOrigin}/${this.destination.owner}/${this.destination.repository}`) {
|
|
413
|
+
throw new GiteaAssetConflictError("Gitea asset destination must be the exact public writable repository with releases enabled.");
|
|
414
|
+
}
|
|
415
|
+
positiveId(repo.id);
|
|
416
|
+
return repo;
|
|
417
|
+
}
|
|
418
|
+
async preflight() {
|
|
419
|
+
const anonymous = await this.admitRepository(false);
|
|
420
|
+
const authenticated = await this.admitRepository(true);
|
|
421
|
+
if (anonymous.id !== authenticated.id)
|
|
422
|
+
throw new GiteaAssetConflictError("Authenticated and public Gitea repository identities differ.");
|
|
423
|
+
// Gitea exposes push for Code only. Repository admins are guaranteed access
|
|
424
|
+
// to the Releases unit; aggregate collaborator/team write is insufficient.
|
|
425
|
+
if (record(authenticated.permissions).admin !== true)
|
|
426
|
+
throw new Error("Gitea asset publication requires an existing repository-admin publisher and a write:repository token; code-push permission alone cannot prove Releases-unit access.");
|
|
427
|
+
const token = record(await this.requestJson("/token", true));
|
|
428
|
+
if (!Array.isArray(token.scopes) ||
|
|
429
|
+
!token.scopes.some((scope) => scope === "all" || scope === "write:repository"))
|
|
430
|
+
throw new Error("Gitea token lacks write:repository scope.");
|
|
431
|
+
const settings = record(await this.requestJson("/settings/attachment", false));
|
|
432
|
+
if (settings.enabled !== true ||
|
|
433
|
+
!Number.isSafeInteger(settings.max_size) ||
|
|
434
|
+
settings.max_size <= 0 ||
|
|
435
|
+
!Number.isSafeInteger(settings.max_size * 1024 * 1024))
|
|
436
|
+
throw new Error("Gitea attachments are disabled or settings cannot be verified.");
|
|
437
|
+
return {
|
|
438
|
+
repositoryId: anonymous.id,
|
|
439
|
+
generalAttachmentMaximumBytes: settings.max_size * 1024 * 1024,
|
|
440
|
+
};
|
|
441
|
+
}
|
|
442
|
+
async admitTag() {
|
|
443
|
+
await this.admitRepository(false);
|
|
444
|
+
const tag = record(await this.requestJson(`${this.repositoryApiPath}/tags/${encodeURIComponent(this.tag)}`, false));
|
|
445
|
+
if (tag.name !== this.tag || record(tag.commit).sha !== this.commit)
|
|
446
|
+
throw new GiteaAssetConflictError("Gitea release tag does not identify the frozen release commit.");
|
|
447
|
+
}
|
|
448
|
+
release(value) {
|
|
449
|
+
const release = record(value);
|
|
450
|
+
const id = positiveId(release.id);
|
|
451
|
+
const publicUrl = `${this.destination.apiOrigin}/${this.destination.owner}/${this.destination.repository}/releases/tag/${encodeURIComponent(this.tag)}`;
|
|
452
|
+
if (release.tag_name !== this.tag ||
|
|
453
|
+
release.draft !== false ||
|
|
454
|
+
release.prerelease !== false ||
|
|
455
|
+
release.html_url !== publicUrl ||
|
|
456
|
+
release.url !==
|
|
457
|
+
`${this.destination.apiOrigin}/api/v1${this.repositoryApiPath}/releases/${id}`)
|
|
458
|
+
throw new GiteaAssetConflictError("Gitea release identity conflicts with the exact public release.");
|
|
459
|
+
return { id, tag: this.tag, publicUrl };
|
|
460
|
+
}
|
|
461
|
+
async inspectRelease() {
|
|
462
|
+
await this.admitTag();
|
|
463
|
+
const path = `${this.repositoryApiPath}/releases/tags/${encodeURIComponent(this.tag)}`;
|
|
464
|
+
const authenticated = await this.requestJson(path, true, "GET", undefined, undefined, true);
|
|
465
|
+
const anonymous = await this.requestJson(path, false, "GET", undefined, undefined, true);
|
|
466
|
+
if (authenticated === null && anonymous === null)
|
|
467
|
+
return null;
|
|
468
|
+
if (authenticated === null || anonymous === null)
|
|
469
|
+
throw new Error("Gitea release visibility is inconclusive; public and authenticated lookups differ.");
|
|
470
|
+
const found = this.release(authenticated);
|
|
471
|
+
if (this.release(anonymous).id !== found.id)
|
|
472
|
+
throw new GiteaAssetConflictError("Gitea release is not anonymously available with the same identity.");
|
|
473
|
+
return found;
|
|
474
|
+
}
|
|
475
|
+
async createRelease() {
|
|
476
|
+
await this.admitTag();
|
|
477
|
+
const result = this.release(await this.requestJson(`${this.repositoryApiPath}/releases`, true, "POST", JSON.stringify({
|
|
478
|
+
tag_name: this.tag,
|
|
479
|
+
target_commitish: this.commit,
|
|
480
|
+
name: this.tag,
|
|
481
|
+
draft: false,
|
|
482
|
+
prerelease: false,
|
|
483
|
+
}), { "Content-Type": "application/json" }));
|
|
484
|
+
const verified = await this.inspectRelease();
|
|
485
|
+
if (!verified)
|
|
486
|
+
throw new Error("Created Gitea release visibility is inconclusive; inspect before another mutation.");
|
|
487
|
+
if (verified.id !== result.id)
|
|
488
|
+
throw new GiteaAssetConflictError("Created Gitea release identity cannot be verified.");
|
|
489
|
+
return result;
|
|
490
|
+
}
|
|
491
|
+
async verifyPublicBytes(asset) {
|
|
492
|
+
const controller = new AbortController();
|
|
493
|
+
const timeout = setTimeout(() => controller.abort(), this.timeoutMs);
|
|
494
|
+
let response;
|
|
495
|
+
try {
|
|
496
|
+
let url = new URL(asset.publicUrl);
|
|
497
|
+
for (let redirects = 0;; redirects++) {
|
|
498
|
+
if (url.protocol !== "https:" ||
|
|
499
|
+
url.username ||
|
|
500
|
+
url.password ||
|
|
501
|
+
url.hash)
|
|
502
|
+
throw new GiteaAssetConflictError("Unsafe anonymous asset redirect.");
|
|
503
|
+
response = await this.fetchImplementation(url.href, {
|
|
504
|
+
redirect: "manual",
|
|
505
|
+
signal: controller.signal,
|
|
506
|
+
headers: { "Accept-Encoding": "identity" },
|
|
507
|
+
});
|
|
508
|
+
if (![301, 302, 303, 307, 308].includes(response.status))
|
|
509
|
+
break;
|
|
510
|
+
if (redirects >= 5 || !response.headers.get("location"))
|
|
511
|
+
throw new GiteaAssetConflictError("Invalid anonymous asset redirect.");
|
|
512
|
+
const next = new URL(response.headers.get("location"), url);
|
|
513
|
+
await response.body?.cancel();
|
|
514
|
+
url = next;
|
|
515
|
+
}
|
|
516
|
+
if (response.status !== 200 ||
|
|
517
|
+
!response.body ||
|
|
518
|
+
(response.headers.get("content-encoding") ?? "identity") !== "identity")
|
|
519
|
+
throw new Error("Asset is not anonymously downloadable.");
|
|
520
|
+
const length = response.headers.get("content-length");
|
|
521
|
+
if (length !== null &&
|
|
522
|
+
(!/^\d+$/.test(length) || Number(length) !== asset.size))
|
|
523
|
+
throw new GiteaAssetConflictError("Anonymous asset size mismatch.");
|
|
524
|
+
const hash = plugins.crypto.createHash("sha256");
|
|
525
|
+
let size = 0;
|
|
526
|
+
const reader = response.body.getReader();
|
|
527
|
+
try {
|
|
528
|
+
while (true) {
|
|
529
|
+
const next = await reader.read();
|
|
530
|
+
if (next.done)
|
|
531
|
+
break;
|
|
532
|
+
size += next.value.byteLength;
|
|
533
|
+
if (size > asset.size)
|
|
534
|
+
throw new GiteaAssetConflictError("Anonymous asset exceeds its frozen size.");
|
|
535
|
+
hash.update(next.value);
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
finally {
|
|
539
|
+
await reader.cancel().catch(() => undefined);
|
|
540
|
+
reader.releaseLock();
|
|
541
|
+
}
|
|
542
|
+
if (size !== asset.size || hash.digest("hex") !== asset.sha256)
|
|
543
|
+
throw new GiteaAssetConflictError("Anonymous asset bytes mismatch.");
|
|
544
|
+
}
|
|
545
|
+
catch (error) {
|
|
546
|
+
if (error instanceof GiteaAssetConflictError)
|
|
547
|
+
throw error;
|
|
548
|
+
throw new Error("Gitea public asset verification is inconclusive; inspect availability before publication.");
|
|
549
|
+
}
|
|
550
|
+
finally {
|
|
551
|
+
controller.abort();
|
|
552
|
+
clearTimeout(timeout);
|
|
553
|
+
if (response?.body && !response.body.locked)
|
|
554
|
+
await response.body.cancel().catch(() => undefined);
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
attachment(value, asset) {
|
|
558
|
+
const attachment = record(value);
|
|
559
|
+
const id = positiveId(attachment.id);
|
|
560
|
+
if (attachment.name !== asset.name ||
|
|
561
|
+
attachment.size !== asset.size ||
|
|
562
|
+
attachment.browser_download_url !== asset.publicUrl)
|
|
563
|
+
throw new GiteaAssetConflictError("Gitea attachment metadata conflicts with the frozen asset.");
|
|
564
|
+
return id;
|
|
565
|
+
}
|
|
566
|
+
async inspectAssetsWithIds(releaseId, expected) {
|
|
567
|
+
positiveId(releaseId);
|
|
568
|
+
assertGiteaFrozenAssets(expected, this.destination, this.tag);
|
|
569
|
+
if ((await this.inspectRelease())?.id !== releaseId)
|
|
570
|
+
throw new GiteaAssetConflictError("Gitea release identifier changed.");
|
|
571
|
+
const values = await this.requestJson(`${this.repositoryApiPath}/releases/${releaseId}/assets`, false);
|
|
572
|
+
if (!Array.isArray(values) || values.length > maximumAssets)
|
|
573
|
+
throw new Error("Invalid Gitea attachment list.");
|
|
574
|
+
const present = [];
|
|
575
|
+
const seenNames = new Set();
|
|
576
|
+
const seenIds = new Set();
|
|
577
|
+
const attachmentIds = new Map();
|
|
578
|
+
for (const value of values) {
|
|
579
|
+
const name = record(value).name;
|
|
580
|
+
const asset = expected.find((candidate) => candidate.name === name);
|
|
581
|
+
if (!asset || seenNames.has(asset.name))
|
|
582
|
+
throw new GiteaAssetConflictError("Unexpected or duplicate Gitea release attachment.");
|
|
583
|
+
const id = this.attachment(value, asset);
|
|
584
|
+
if (seenIds.has(id))
|
|
585
|
+
throw new GiteaAssetConflictError("Duplicate Gitea release attachment identifier.");
|
|
586
|
+
seenNames.add(asset.name);
|
|
587
|
+
seenIds.add(id);
|
|
588
|
+
attachmentIds.set(asset.name, id);
|
|
589
|
+
await this.verifyPublicBytes(asset);
|
|
590
|
+
present.push(asset);
|
|
591
|
+
}
|
|
592
|
+
return {
|
|
593
|
+
inspection: {
|
|
594
|
+
present,
|
|
595
|
+
missing: expected.filter((asset) => !seenNames.has(asset.name)),
|
|
596
|
+
},
|
|
597
|
+
attachmentIds,
|
|
598
|
+
};
|
|
599
|
+
}
|
|
600
|
+
async inspectAssets(releaseId, expected) {
|
|
601
|
+
return (await this.inspectAssetsWithIds(releaseId, expected)).inspection;
|
|
602
|
+
}
|
|
603
|
+
async uploadAsset(releaseId, asset, artifactDirectory) {
|
|
604
|
+
positiveId(releaseId);
|
|
605
|
+
assertGiteaFrozenAssets([asset], this.destination, this.tag);
|
|
606
|
+
const handle = await openRegularFile(plugins.path.join(artifactDirectory, asset.fileName));
|
|
607
|
+
try {
|
|
608
|
+
await verifyHandle(handle, asset);
|
|
609
|
+
if ((await this.inspectRelease())?.id !== releaseId)
|
|
610
|
+
throw new GiteaAssetConflictError("Gitea release identifier changed before upload.");
|
|
611
|
+
const listed = await this.requestJson(`${this.repositoryApiPath}/releases/${releaseId}/assets`, false);
|
|
612
|
+
if (!Array.isArray(listed))
|
|
613
|
+
throw new Error("Invalid Gitea attachment list.");
|
|
614
|
+
if (listed.some((entry) => record(entry).name === asset.name))
|
|
615
|
+
throw new GiteaAssetConflictError("Gitea upload requires an absent attachment name; inspect the retained release.");
|
|
616
|
+
const stream = handle.createReadStream({
|
|
617
|
+
autoClose: false,
|
|
618
|
+
start: 0,
|
|
619
|
+
highWaterMark: 64 * 1024,
|
|
620
|
+
});
|
|
621
|
+
try {
|
|
622
|
+
const result = await this.requestJson(`${this.repositoryApiPath}/releases/${releaseId}/assets?name=${encodeURIComponent(asset.name)}`, true, "POST", stream, {
|
|
623
|
+
"Content-Type": "application/octet-stream",
|
|
624
|
+
"Content-Length": String(asset.size),
|
|
625
|
+
});
|
|
626
|
+
this.attachment(result, asset);
|
|
627
|
+
}
|
|
628
|
+
finally {
|
|
629
|
+
stream.destroy();
|
|
630
|
+
}
|
|
631
|
+
await this.verifyPublicBytes(asset);
|
|
632
|
+
}
|
|
633
|
+
finally {
|
|
634
|
+
await handle.close();
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
async verifyComplete(releaseId, expected) {
|
|
638
|
+
const { inspection, attachmentIds } = await this.inspectAssetsWithIds(releaseId, expected);
|
|
639
|
+
if (inspection.missing.length !== 0)
|
|
640
|
+
throw new Error("Gitea attachment set is incomplete; npm publication is blocked.");
|
|
641
|
+
// Recheck release/tag identity after potentially long full downloads.
|
|
642
|
+
if ((await this.inspectRelease())?.id !== releaseId)
|
|
643
|
+
throw new GiteaAssetConflictError("Gitea release changed during verification.");
|
|
644
|
+
const finalSet = await this.requestJson(`${this.repositoryApiPath}/releases/${releaseId}/assets`, false);
|
|
645
|
+
if (!Array.isArray(finalSet) || finalSet.length !== expected.length)
|
|
646
|
+
throw new GiteaAssetConflictError("Gitea attachment set changed during verification.");
|
|
647
|
+
const names = new Set();
|
|
648
|
+
const ids = new Set();
|
|
649
|
+
for (const value of finalSet) {
|
|
650
|
+
const asset = expected.find((entry) => entry.name === record(value).name);
|
|
651
|
+
if (!asset || names.has(asset.name))
|
|
652
|
+
throw new GiteaAssetConflictError("Gitea attachment set changed during verification.");
|
|
653
|
+
const id = this.attachment(value, asset);
|
|
654
|
+
if (ids.has(id) || attachmentIds.get(asset.name) !== id)
|
|
655
|
+
throw new GiteaAssetConflictError("Gitea attachment set changed during verification.");
|
|
656
|
+
names.add(asset.name);
|
|
657
|
+
ids.add(id);
|
|
658
|
+
}
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaGVscGVycy5naXRlYWFzc2V0cy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3RzL21vZF9yZWxlYXNlL2hlbHBlcnMuZ2l0ZWFhc3NldHMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxLQUFLLE9BQU8sTUFBTSxrQkFBa0IsQ0FBQztBQWE1QyxNQUFNLG9CQUFvQixHQUFHLENBQUMsR0FBRyxJQUFJLEdBQUcsSUFBSSxDQUFDO0FBQzdDLE1BQU0sb0JBQW9CLEdBQUcsQ0FBQyxHQUFHLElBQUksR0FBRyxJQUFJLENBQUM7QUFDN0MsTUFBTSxpQkFBaUIsR0FBRyxFQUFFLEdBQUcsSUFBSSxHQUFHLElBQUksR0FBRyxJQUFJLENBQUM7QUFDbEQsTUFBTSxhQUFhLEdBQUcsSUFBSSxDQUFDO0FBQzNCLE1BQU0sYUFBYSxHQUFHLG9DQUFvQyxDQUFDO0FBQzNELE1BQU0sYUFBYSxHQUFHLGdCQUFnQixDQUFDO0FBRXZDLE1BQU0sT0FBTyx1QkFBd0IsU0FBUSxLQUFLO0lBQ2hELFlBQVksT0FBZTtRQUN6QixLQUFLLENBQUMsT0FBTyxDQUFDLENBQUM7UUFDZixJQUFJLENBQUMsSUFBSSxHQUFHLHlCQUF5QixDQUFDO0lBQ3hDLENBQUM7Q0FDRjtBQUVELE1BQU0sbUJBQW9CLFNBQVEsS0FBSztJQUNyQyxZQUFZLE1BQWMsRUFBRSxNQUFjO1FBQ3hDLEtBQUssQ0FDSCxlQUFlLE1BQU0sa0JBQWtCLE1BQU0seURBQXlELENBQ3ZHLENBQUM7SUFDSixDQUFDO0NBQ0Y7QUFFRCxNQUFNLE1BQU0sR0FBRyxDQUFDLEtBQWMsRUFBMkIsRUFBRTtJQUN6RCxJQUFJLENBQUMsS0FBSyxJQUFJLE9BQU8sS0FBSyxLQUFLLFFBQVEsSUFBSSxLQUFLLENBQUMsT0FBTyxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUM7UUFDaEUsTUFBTSxJQUFJLEtBQUssQ0FBQyw2QkFBNkIsQ0FBQyxDQUFDO0lBQ2pELENBQUM7SUFDRCxPQUFP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
|