@foldrun/core 1.4.1 → 2.0.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/index.d.ts +0 -3
- package/dist/index.js +0 -3
- package/dist/src/deploy.d.ts +0 -26
- package/dist/src/deploy.js +10 -53
- package/dist/src/history.d.ts +30 -10
- package/dist/src/history.js +232 -99
- package/dist/src/library.d.ts +0 -13
- package/dist/src/library.js +0 -50
- package/dist/src/platform.d.ts +1 -3
- package/dist/src/platform.js +0 -1
- package/dist/src/run-container.d.ts +29 -0
- package/dist/src/run-container.js +74 -2
- package/dist/src/runner.js +10 -2
- package/dist/src/secrets.js +1 -12
- package/dist/src/starter.js +2 -2
- package/dist/src/store.d.ts +15 -10
- package/dist/src/store.js +45 -21
- package/index.ts +0 -3
- package/package.json +1 -3
- package/src/deploy.ts +5 -71
- package/src/history.ts +230 -108
- package/src/library.ts +0 -44
- package/src/platform.ts +1 -4
- package/src/run-container.ts +78 -2
- package/src/runner.ts +10 -1
- package/src/secrets.ts +1 -11
- package/src/starter.ts +2 -2
- package/src/store.ts +55 -27
- package/dist/src/git-hook.d.ts +0 -1
- package/dist/src/git-hook.js +0 -70
- package/dist/src/git.d.ts +0 -37
- package/dist/src/git.js +0 -101
- package/dist/src/gitrepo.d.ts +0 -113
- package/dist/src/gitrepo.js +0 -404
- package/dist/src/tar.d.ts +0 -30
- package/dist/src/tar.js +0 -112
- package/src/git-hook.ts +0 -73
- package/src/git.ts +0 -117
- package/src/gitrepo.ts +0 -439
- package/src/tar.ts +0 -125
package/src/tar.ts
DELETED
|
@@ -1,125 +0,0 @@
|
|
|
1
|
-
// Reading a .tar.gz, so a deploy can come from a GitHub tarball.
|
|
2
|
-
//
|
|
3
|
-
// `GET /repos/{owner}/{repo}/tarball/{sha}` is one HTTP call and needs no git
|
|
4
|
-
// binary, no clone, and no working copy on the server — which is the whole
|
|
5
|
-
// reason a markdown workspace can deploy from a webhook in a few hundred
|
|
6
|
-
// milliseconds. What it returns is a tar.gz, and Node has gzip but not tar.
|
|
7
|
-
//
|
|
8
|
-
// Deliberately dependency-free, for the same reason the cron parser is: tar is
|
|
9
|
-
// 512-byte blocks with an octal size field, and a reader is shorter than the
|
|
10
|
-
// argument about which library to add.
|
|
11
|
-
|
|
12
|
-
import zlib from "node:zlib";
|
|
13
|
-
import { trimSlashes } from "./paths.ts";
|
|
14
|
-
|
|
15
|
-
const BLOCK = 512;
|
|
16
|
-
|
|
17
|
-
export interface TarEntry {
|
|
18
|
-
path: string;
|
|
19
|
-
content: Buffer;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
const str = (b: Buffer, off: number, len: number) => {
|
|
23
|
-
const raw = b.subarray(off, off + len);
|
|
24
|
-
const end = raw.indexOf(0);
|
|
25
|
-
return raw.subarray(0, end === -1 ? raw.length : end).toString("utf8");
|
|
26
|
-
};
|
|
27
|
-
|
|
28
|
-
// Sizes are octal, space- or NUL-padded. GNU also writes base-256 for large
|
|
29
|
-
// files, flagged by the high bit — irrelevant for markdown, but a silent
|
|
30
|
-
// misparse would be worse than a clear refusal.
|
|
31
|
-
function size(b: Buffer, off: number): number {
|
|
32
|
-
if (b[off] & 0x80) throw new Error("tar: base-256 size field is not supported");
|
|
33
|
-
const raw = str(b, off, 12).trim();
|
|
34
|
-
return raw ? parseInt(raw, 8) : 0;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* Every regular file in a gzipped tarball.
|
|
39
|
-
*
|
|
40
|
-
* Directories, symlinks, and pax/global headers are skipped: a workspace is
|
|
41
|
-
* files, and following a link out of the archive is exactly the thing a deploy
|
|
42
|
-
* from an untrusted repository must not do.
|
|
43
|
-
*/
|
|
44
|
-
export function readTarGz(gz: Buffer): TarEntry[] {
|
|
45
|
-
const buf = zlib.gunzipSync(gz);
|
|
46
|
-
const out: TarEntry[] = [];
|
|
47
|
-
let longName: string | null = null;
|
|
48
|
-
|
|
49
|
-
for (let off = 0; off + BLOCK <= buf.length; ) {
|
|
50
|
-
const header = buf.subarray(off, off + BLOCK);
|
|
51
|
-
// Two consecutive zero blocks end the archive; one is enough to stop.
|
|
52
|
-
if (header.every((b) => b === 0)) break;
|
|
53
|
-
|
|
54
|
-
const name = str(header, 0, 100);
|
|
55
|
-
const bytes = size(header, 124);
|
|
56
|
-
const type = String.fromCharCode(header[156]) || "0";
|
|
57
|
-
const prefix = str(header, 345, 155);
|
|
58
|
-
off += BLOCK;
|
|
59
|
-
|
|
60
|
-
const body = buf.subarray(off, off + bytes);
|
|
61
|
-
off += Math.ceil(bytes / BLOCK) * BLOCK;
|
|
62
|
-
|
|
63
|
-
// GNU long name: the next header's name lives in this entry's body.
|
|
64
|
-
if (type === "L") {
|
|
65
|
-
longName = body.toString("utf8").replace(/\0+$/, "");
|
|
66
|
-
continue;
|
|
67
|
-
}
|
|
68
|
-
if (type !== "0" && type !== "\0") {
|
|
69
|
-
longName = null;
|
|
70
|
-
continue;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
const full = longName ?? (prefix ? `${prefix}/${name}` : name);
|
|
74
|
-
longName = null;
|
|
75
|
-
if (full) out.push({ path: full, content: Buffer.from(body) });
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
return out;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
/**
|
|
82
|
-
* Drop the single wrapper directory an archive is rooted at.
|
|
83
|
-
*
|
|
84
|
-
* GitHub tarballs are rooted at `owner-repo-<sha>/`, which is not part of
|
|
85
|
-
* anyone's workspace. Stripped only when *every* entry shares one first
|
|
86
|
-
* segment, so an archive that is already flat is left alone.
|
|
87
|
-
*/
|
|
88
|
-
export function stripRoot(entries: TarEntry[]): TarEntry[] {
|
|
89
|
-
if (entries.length === 0) return entries;
|
|
90
|
-
const first = entries[0].path.split("/")[0];
|
|
91
|
-
if (!entries.every((e) => e.path.split("/")[0] === first && e.path.includes("/"))) {
|
|
92
|
-
return entries;
|
|
93
|
-
}
|
|
94
|
-
return entries.map((e) => ({ ...e, path: e.path.slice(first.length + 1) }));
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
/**
|
|
98
|
-
* Read a tarball as the file list a deploy ships.
|
|
99
|
-
*
|
|
100
|
-
* `subdir` picks a workspace living inside a larger repository — the common
|
|
101
|
-
* case, since a repo usually holds more than one thing.
|
|
102
|
-
*/
|
|
103
|
-
export function filesFromTarball(gz: Buffer, subdir = ""): { path: string; content: string }[] {
|
|
104
|
-
const prefix = trimSlashes(subdir, "both");
|
|
105
|
-
const out: { path: string; content: string }[] = [];
|
|
106
|
-
|
|
107
|
-
for (const entry of stripRoot(readTarGz(gz))) {
|
|
108
|
-
let rel = entry.path;
|
|
109
|
-
if (prefix) {
|
|
110
|
-
if (!rel.startsWith(`${prefix}/`)) continue;
|
|
111
|
-
rel = rel.slice(prefix.length + 1);
|
|
112
|
-
}
|
|
113
|
-
// A tarball is untrusted input: an entry can name anything at all, and
|
|
114
|
-
// `../` in an archive is the oldest way to write outside the destination.
|
|
115
|
-
if (rel.split("/").includes("..") || rel.startsWith("/")) continue;
|
|
116
|
-
// AppleDouble sidecars. macOS `tar` writes a `._name` beside every file to
|
|
117
|
-
// carry metadata no other system wants; they are not part of anyone's
|
|
118
|
-
// workspace, and letting one through means a deploy rejected for shipping
|
|
119
|
-
// a file the author never wrote.
|
|
120
|
-
if ((rel.split("/").pop() ?? "").startsWith("._")) continue;
|
|
121
|
-
out.push({ path: rel, content: entry.content.toString("utf8") });
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
return out;
|
|
125
|
-
}
|