feat(discord): git verbs for the Discord Sage on the shared-signals root, seat identity through a package credential helper, vault record protocol (#1509)
Row 24. A writable root that is a git work tree may carry a git object in the binding; the seat then has git_status, git_commit (explicit paths, seat author, Requested-by trailer from the envelope requester, push at once per D6), git_pull (ff-only) and git_push (one branch, never force), plus reserve_id and per-write clone locks under protocol vault. Git children run with no host config and one credential helper, bin/git-credential.mjs, reading the 0600 seat token file named in the binding; the fleet helper serves only the Gitea hosts. Suite 58/58, node 143. rev-code-02 APPROVED round 1 (#1509 comment 26375, tree 82ab962f). Co-Authored-By: Claude Fable 5.1 <[email protected]>
This commit is contained in:
Executable
+61
@@ -0,0 +1,61 @@
|
||||
#!/usr/bin/env node
|
||||
// Credential helper for the Discord Sage's git verbs (row 24). git runs it
|
||||
// as `credential.helper` for the seat's pushes and pulls only, through the
|
||||
// allowlisted environment src/git.mjs builds. It answers `get` and nothing
|
||||
// else, for https only, from the one file named in its environment.
|
||||
//
|
||||
// Why not the fleet helper: git-credential-mosaic serves the two Gitea
|
||||
// hosts and declines every other host, and the host's own GitHub login
|
||||
// (gh) must never sign a seat's push. This helper is the seat's and reads
|
||||
// only the seat's token file.
|
||||
//
|
||||
// The token goes from the file to git's stdin pipe and nowhere else: not
|
||||
// to argv, not to stderr, not to a log. Anything wrong (a missing or loose
|
||||
// file, a non-https request, a value that does not look like a token) is
|
||||
// a short stderr line and exit 1, so git fails the operation and the verb
|
||||
// reports that failure masked.
|
||||
|
||||
import { lstatSync, readFileSync } from "node:fs";
|
||||
|
||||
const TOKEN_FILE_ENV = "MOSAIC_DISCORD_GIT_TOKEN_FILE";
|
||||
const USERNAME_ENV = "MOSAIC_DISCORD_GIT_USERNAME";
|
||||
|
||||
function fail(msg) {
|
||||
process.stderr.write(`git-credential (discord): ${msg}\n`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const action = process.argv[2];
|
||||
if (action !== "get") process.exit(0);
|
||||
|
||||
const file = process.env[TOKEN_FILE_ENV];
|
||||
const username = process.env[USERNAME_ENV];
|
||||
if (!file || !file.startsWith("/")) fail(`${TOKEN_FILE_ENV} is not set`);
|
||||
if (!username || !/^[a-z0-9][a-z0-9._-]{0,63}$/.test(username)) fail(`${USERNAME_ENV} is not set`);
|
||||
|
||||
let input = "";
|
||||
try {
|
||||
input = readFileSync(0, "utf8");
|
||||
} catch {
|
||||
fail("no request on stdin");
|
||||
}
|
||||
const req = {};
|
||||
for (const line of input.split("\n")) {
|
||||
const i = line.indexOf("=");
|
||||
if (i > 0) req[line.slice(0, i)] = line.slice(i + 1);
|
||||
}
|
||||
if (req.protocol !== "https") fail("only https");
|
||||
if (!req.host) fail("no host");
|
||||
|
||||
let st;
|
||||
try {
|
||||
st = lstatSync(file);
|
||||
} catch {
|
||||
fail("token file not found");
|
||||
}
|
||||
if (st.isSymbolicLink() || !st.isFile()) fail("token file must be a regular file");
|
||||
if ((st.mode & 0o777) !== 0o600) fail("token file must be mode 0600");
|
||||
const token = readFileSync(file, "utf8").trim();
|
||||
if (!/^[A-Za-z0-9_]{20,}$/.test(token)) fail("token file does not hold a token");
|
||||
|
||||
process.stdout.write(`username=${username}\npassword=${token}\n`);
|
||||
Reference in New Issue
Block a user