@magland/mochi 0.3.1
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 +108 -0
- package/dist/ansi.js +174 -0
- package/dist/api/admin.js +416 -0
- package/dist/api/auth.js +166 -0
- package/dist/api/backup.js +598 -0
- package/dist/api/ci.js +336 -0
- package/dist/api/contents.js +339 -0
- package/dist/api/issues.js +165 -0
- package/dist/api/pulls.js +244 -0
- package/dist/api/releases.js +83 -0
- package/dist/api/repos.js +156 -0
- package/dist/api/write.js +518 -0
- package/dist/api.js +326 -0
- package/dist/assets.js +29 -0
- package/dist/atom.js +32 -0
- package/dist/atomic.js +171 -0
- package/dist/avatar.js +81 -0
- package/dist/browse.js +630 -0
- package/dist/build-info.json +4 -0
- package/dist/ci/actionref.js +86 -0
- package/dist/ci/api.js +829 -0
- package/dist/ci/artifacts.js +201 -0
- package/dist/ci/dispatch.js +30 -0
- package/dist/ci/engine.js +1321 -0
- package/dist/ci/expr.js +526 -0
- package/dist/ci/manual.js +199 -0
- package/dist/ci/present.js +82 -0
- package/dist/ci/protocol.js +6 -0
- package/dist/ci/runners.js +256 -0
- package/dist/ci/runs.js +208 -0
- package/dist/ci/trigger.js +28 -0
- package/dist/ci/views.js +441 -0
- package/dist/ci/wake.js +194 -0
- package/dist/ci/web.js +617 -0
- package/dist/ci/workflow.js +436 -0
- package/dist/cli/admin-cmd.js +324 -0
- package/dist/cli/api-cmd.js +128 -0
- package/dist/cli/backup-cmd.js +1500 -0
- package/dist/cli/exit.js +69 -0
- package/dist/cli/input.js +64 -0
- package/dist/cli/issue-cmd.js +243 -0
- package/dist/cli/output.js +93 -0
- package/dist/cli/parse.js +317 -0
- package/dist/cli/pr-cmd.js +289 -0
- package/dist/cli/release-cmd.js +171 -0
- package/dist/cli/repo-cmd.js +763 -0
- package/dist/cli/repo.js +101 -0
- package/dist/cli/run-cmd.js +438 -0
- package/dist/cli/target.js +54 -0
- package/dist/cli-api.js +84 -0
- package/dist/compare.js +111 -0
- package/dist/config.js +212 -0
- package/dist/credentials.js +235 -0
- package/dist/deploy-cli.js +859 -0
- package/dist/deploy-runner-cli.js +592 -0
- package/dist/diff.js +171 -0
- package/dist/discussion.js +253 -0
- package/dist/egress.js +559 -0
- package/dist/filecache.js +68 -0
- package/dist/find.js +162 -0
- package/dist/forms.js +737 -0
- package/dist/git.js +547 -0
- package/dist/githttp.js +428 -0
- package/dist/html.js +87 -0
- package/dist/icons.js +101 -0
- package/dist/import-cli.js +316 -0
- package/dist/index.js +752 -0
- package/dist/issues.js +308 -0
- package/dist/issueweb.js +447 -0
- package/dist/job-cli.js +197 -0
- package/dist/jobtoken.js +96 -0
- package/dist/languages.js +383 -0
- package/dist/layout.js +100 -0
- package/dist/lfs.js +438 -0
- package/dist/lfsstore.js +425 -0
- package/dist/limit.js +259 -0
- package/dist/logo.js +61 -0
- package/dist/markdown.js +382 -0
- package/dist/migrate.js +334 -0
- package/dist/multipart.js +90 -0
- package/dist/ops.js +869 -0
- package/dist/pagescript.js +465 -0
- package/dist/perms.js +370 -0
- package/dist/pointer.js +55 -0
- package/dist/profile.js +106 -0
- package/dist/pulls.js +320 -0
- package/dist/pullweb.js +461 -0
- package/dist/redirects.js +455 -0
- package/dist/releases.js +435 -0
- package/dist/render.js +233 -0
- package/dist/runner/actions.js +448 -0
- package/dist/runner/client.js +428 -0
- package/dist/runner/context.js +247 -0
- package/dist/runner/docker.js +197 -0
- package/dist/runner/externals.js +175 -0
- package/dist/runner/job.js +290 -0
- package/dist/runner/manual-run.js +272 -0
- package/dist/runner/overrides.js +554 -0
- package/dist/runner/steps.js +571 -0
- package/dist/runner/wake.js +84 -0
- package/dist/runner-cli.js +405 -0
- package/dist/scan.js +231 -0
- package/dist/server.js +424 -0
- package/dist/session.js +267 -0
- package/dist/site.js +259 -0
- package/dist/siteshost.js +94 -0
- package/dist/source.js +90 -0
- package/dist/style.js +1295 -0
- package/dist/themes.js +369 -0
- package/dist/vault.js +442 -0
- package/dist/version.js +88 -0
- package/dist/views.js +1007 -0
- package/dist/web.js +182 -0
- package/dist/webops.js +1402 -0
- package/package.json +71 -0
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.ArtifactError = void 0;
|
|
37
|
+
exports.isValidArtifactName = isValidArtifactName;
|
|
38
|
+
exports.artifactsDir = artifactsDir;
|
|
39
|
+
exports.artifactPath = artifactPath;
|
|
40
|
+
exports.listArtifacts = listArtifacts;
|
|
41
|
+
exports.deploySite = deploySite;
|
|
42
|
+
const child_process_1 = require("child_process");
|
|
43
|
+
const fs = __importStar(require("fs"));
|
|
44
|
+
const path = __importStar(require("path"));
|
|
45
|
+
const layout_1 = require("../layout");
|
|
46
|
+
const scan_1 = require("../scan");
|
|
47
|
+
const runs_1 = require("./runs");
|
|
48
|
+
// Workflow artifacts. An artifact is a tar stream a job uploads under a name,
|
|
49
|
+
// stored inside the run's directory so that it is pruned with the run and
|
|
50
|
+
// copied with a vault backup like everything else:
|
|
51
|
+
//
|
|
52
|
+
// <vault>/collections/<collection>/repos/<repo>.runs/12/artifacts/github-pages.tar
|
|
53
|
+
//
|
|
54
|
+
// mochi does not implement GitHub's artifact wire protocol. The
|
|
55
|
+
// upload-artifact and download-artifact actions are substituted by mochi's
|
|
56
|
+
// own (see the runner's overrides), which speak the small API in ci/api.ts;
|
|
57
|
+
// this module is only the storage underneath it.
|
|
58
|
+
class ArtifactError extends Error {
|
|
59
|
+
}
|
|
60
|
+
exports.ArtifactError = ArtifactError;
|
|
61
|
+
// Artifact names come from workflow files. They become filenames, so they are
|
|
62
|
+
// constrained the same way job ids are, and for the same reason.
|
|
63
|
+
function isValidArtifactName(name) {
|
|
64
|
+
return /^[A-Za-z0-9][A-Za-z0-9._-]{0,110}$/.test(name) && !name.includes('..');
|
|
65
|
+
}
|
|
66
|
+
function artifactsDir(root, collection, repo, n) {
|
|
67
|
+
const base = (0, runs_1.runsDir)(root, collection, repo);
|
|
68
|
+
if (!base)
|
|
69
|
+
return null;
|
|
70
|
+
return path.join(base, String(n), 'artifacts');
|
|
71
|
+
}
|
|
72
|
+
function artifactPath(root, collection, repo, n, name) {
|
|
73
|
+
if (!isValidArtifactName(name))
|
|
74
|
+
return null;
|
|
75
|
+
const dir = artifactsDir(root, collection, repo, n);
|
|
76
|
+
if (!dir)
|
|
77
|
+
return null;
|
|
78
|
+
return path.join(dir, `${name}.tar`);
|
|
79
|
+
}
|
|
80
|
+
function listArtifacts(root, collection, repo, n) {
|
|
81
|
+
const dir = artifactsDir(root, collection, repo, n);
|
|
82
|
+
if (!dir)
|
|
83
|
+
return [];
|
|
84
|
+
let entries;
|
|
85
|
+
try {
|
|
86
|
+
entries = fs.readdirSync(dir);
|
|
87
|
+
}
|
|
88
|
+
catch {
|
|
89
|
+
return [];
|
|
90
|
+
}
|
|
91
|
+
const out = [];
|
|
92
|
+
for (const e of entries) {
|
|
93
|
+
if (!e.endsWith('.tar'))
|
|
94
|
+
continue;
|
|
95
|
+
const name = e.slice(0, -4);
|
|
96
|
+
if (!isValidArtifactName(name))
|
|
97
|
+
continue;
|
|
98
|
+
try {
|
|
99
|
+
const st = fs.statSync(path.join(dir, e));
|
|
100
|
+
out.push({ name, size: st.size, createdAt: st.mtime.toISOString() });
|
|
101
|
+
}
|
|
102
|
+
catch {
|
|
103
|
+
// vanished between readdir and stat
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return out.sort((a, b) => a.name.localeCompare(b.name));
|
|
107
|
+
}
|
|
108
|
+
function run(cmd, args) {
|
|
109
|
+
return new Promise((resolve, reject) => {
|
|
110
|
+
(0, child_process_1.execFile)(cmd, args, { maxBuffer: 16 * 1024 * 1024 }, (err, stdout, stderr) => {
|
|
111
|
+
if (err)
|
|
112
|
+
reject(new ArtifactError((stderr || err.message).toString().trim()));
|
|
113
|
+
else
|
|
114
|
+
resolve(stdout.toString());
|
|
115
|
+
});
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
// Deploy an artifact as the repository's site.
|
|
119
|
+
//
|
|
120
|
+
// The bytes arrive from a runner, so extraction is treated as untrusted: tar
|
|
121
|
+
// runs into a scratch directory outside the published one, every resulting
|
|
122
|
+
// path is checked to be inside it, and only then does the new site replace
|
|
123
|
+
// the old one by rename. A half-extracted archive therefore never becomes the
|
|
124
|
+
// live site, and a crafted archive cannot write outside the vault.
|
|
125
|
+
async function deploySite(root, collection, repo, n, artifactName) {
|
|
126
|
+
if (!(0, scan_1.isValidName)(collection) || !(0, scan_1.isValidName)(repo))
|
|
127
|
+
throw new ArtifactError('invalid repository');
|
|
128
|
+
const tar = artifactPath(root, collection, repo, n, artifactName);
|
|
129
|
+
if (!tar || !fs.existsSync(tar)) {
|
|
130
|
+
throw new ArtifactError(`no artifact named ${artifactName} in run #${n}`);
|
|
131
|
+
}
|
|
132
|
+
const dir = (0, layout_1.repoPath)(root, collection, `${(0, scan_1.displayName)(repo)}.site`);
|
|
133
|
+
const scratch = `${dir}.incoming-${process.pid}`;
|
|
134
|
+
const previous = `${dir}.previous-${process.pid}`;
|
|
135
|
+
fs.rmSync(scratch, { recursive: true, force: true });
|
|
136
|
+
fs.mkdirSync(scratch, { recursive: true });
|
|
137
|
+
try {
|
|
138
|
+
// Containment during extraction is tar's own: GNU tar and libarchive both
|
|
139
|
+
// strip a leading `/` and a `..` from member names, and both refuse to
|
|
140
|
+
// write through a symlink a member of the same archive created, which is
|
|
141
|
+
// what stops `link -> /etc` followed by `link/passwd`. The walk below runs
|
|
142
|
+
// after the bytes are on disk, so it removes an escaping link rather than
|
|
143
|
+
// preventing a write through one; that division is load-bearing, and a tar
|
|
144
|
+
// without those two behaviours would not be safe to point at this.
|
|
145
|
+
await run('tar', ['-xf', tar, '-C', scratch, '--no-same-owner', '--no-same-permissions']);
|
|
146
|
+
// upload-pages-artifact wraps the site in a tar of its own, so an
|
|
147
|
+
// artifact holding exactly one artifact.tar is unwrapped once more. This
|
|
148
|
+
// is what makes the real actions/upload-pages-artifact work unchanged.
|
|
149
|
+
const entries = fs.readdirSync(scratch);
|
|
150
|
+
if (entries.length === 1 && entries[0] === 'artifact.tar') {
|
|
151
|
+
const inner = path.join(scratch, 'artifact.tar');
|
|
152
|
+
const unwrapped = `${scratch}.inner`;
|
|
153
|
+
fs.rmSync(unwrapped, { recursive: true, force: true });
|
|
154
|
+
fs.mkdirSync(unwrapped);
|
|
155
|
+
await run('tar', ['-xf', inner, '-C', unwrapped, '--no-same-owner', '--no-same-permissions']);
|
|
156
|
+
fs.rmSync(scratch, { recursive: true, force: true });
|
|
157
|
+
fs.renameSync(unwrapped, scratch);
|
|
158
|
+
}
|
|
159
|
+
const scratchReal = fs.realpathSync(scratch);
|
|
160
|
+
let files = 0;
|
|
161
|
+
const walk = (dir) => {
|
|
162
|
+
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
163
|
+
const full = path.join(dir, entry.name);
|
|
164
|
+
// A symlink pointing outside the site would publish arbitrary files
|
|
165
|
+
// from the vault's disk, so links are removed rather than followed.
|
|
166
|
+
if (entry.isSymbolicLink()) {
|
|
167
|
+
const target = path.resolve(dir, fs.readlinkSync(full));
|
|
168
|
+
if (target !== scratchReal && !target.startsWith(scratchReal + path.sep)) {
|
|
169
|
+
fs.rmSync(full, { force: true });
|
|
170
|
+
continue;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
if (entry.isDirectory())
|
|
174
|
+
walk(full);
|
|
175
|
+
else
|
|
176
|
+
files++;
|
|
177
|
+
}
|
|
178
|
+
};
|
|
179
|
+
walk(scratch);
|
|
180
|
+
if (files === 0)
|
|
181
|
+
throw new ArtifactError(`artifact ${artifactName} contains no files`);
|
|
182
|
+
fs.rmSync(previous, { recursive: true, force: true });
|
|
183
|
+
const had = fs.existsSync(dir);
|
|
184
|
+
if (had)
|
|
185
|
+
fs.renameSync(dir, previous);
|
|
186
|
+
try {
|
|
187
|
+
fs.renameSync(scratch, dir);
|
|
188
|
+
}
|
|
189
|
+
catch (e) {
|
|
190
|
+
if (had)
|
|
191
|
+
fs.renameSync(previous, dir);
|
|
192
|
+
throw e;
|
|
193
|
+
}
|
|
194
|
+
fs.rmSync(previous, { recursive: true, force: true });
|
|
195
|
+
return { files };
|
|
196
|
+
}
|
|
197
|
+
finally {
|
|
198
|
+
fs.rmSync(scratch, { recursive: true, force: true });
|
|
199
|
+
fs.rmSync(`${scratch}.inner`, { recursive: true, force: true });
|
|
200
|
+
}
|
|
201
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.dispatchWorkflow = dispatchWorkflow;
|
|
4
|
+
const git_1 = require("../git");
|
|
5
|
+
const ops_1 = require("../ops");
|
|
6
|
+
/**
|
|
7
|
+
* Plan a workflow_dispatch run, or throw OpError saying why not.
|
|
8
|
+
*
|
|
9
|
+
* The ref must be a branch this repository has: a dispatch runs a workflow file
|
|
10
|
+
* at a commit, and a ref that is not there has no commit to run at. The caller
|
|
11
|
+
* supplies the branches because it has already listed them.
|
|
12
|
+
*/
|
|
13
|
+
async function dispatchWorkflow(engine, repo, branches, defaultBranch, actor, request) {
|
|
14
|
+
const ref = request.ref || defaultBranch || '';
|
|
15
|
+
if (!(0, git_1.isValidRefName)(ref) || ref.startsWith('-'))
|
|
16
|
+
throw new ops_1.OpError('that is not a usable branch name');
|
|
17
|
+
const branch = branches.find((b) => b.name === ref);
|
|
18
|
+
if (!branch)
|
|
19
|
+
throw new ops_1.OpError(`branch ${ref} not found`, 'notfound');
|
|
20
|
+
if (request.workflow.trim() === '')
|
|
21
|
+
throw new ops_1.OpError('name the workflow to run');
|
|
22
|
+
try {
|
|
23
|
+
return await engine.handleDispatch(repo, request.workflow, `refs/heads/${ref}`, branch.sha, actor, request.inputs);
|
|
24
|
+
}
|
|
25
|
+
catch (e) {
|
|
26
|
+
// WorkflowError and anything else the engine raises are the caller's
|
|
27
|
+
// problem to be told about, not a server fault.
|
|
28
|
+
throw new ops_1.OpError(e instanceof Error ? e.message : String(e));
|
|
29
|
+
}
|
|
30
|
+
}
|