Files
stack/packages/discord/bin/git-credential.mjs
T
jason.woltjeandClaude Fable 5.1 1949ed8d31 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]>
2026-09-18 07:52:35 -05:00

62 lines
2.2 KiB
JavaScript
Executable File

#!/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`);