Initial curated DockDeck source from 26772208f608782e88c736dc70878e7b5abd3916
This commit is contained in:
commit
3c61fba98f
146 files changed
+45229
No files matched your search
@@ -0,0 +1,109 @@
|
||||
import { execFileSync, spawnSync } from "node:child_process";
|
||||
import { mkdirSync, readFileSync } from "node:fs";
|
||||
import { dirname, resolve } from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import { build } from "esbuild";
|
||||
|
||||
const projectRoot = fileURLToPath(new URL("../", import.meta.url));
|
||||
const packageJson = JSON.parse(
|
||||
readFileSync(resolve(projectRoot, "package.json"), "utf8"),
|
||||
);
|
||||
|
||||
function getRevision() {
|
||||
const suppliedRevision = process.env.DOCKDECK_BUILD_REVISION?.trim();
|
||||
if (suppliedRevision) return normalizeRevision(suppliedRevision);
|
||||
|
||||
try {
|
||||
return normalizeRevision(
|
||||
execFileSync("git", ["rev-parse", "--verify", "HEAD"], {
|
||||
cwd: projectRoot,
|
||||
encoding: "utf8",
|
||||
stdio: ["ignore", "pipe", "ignore"],
|
||||
}).trim(),
|
||||
);
|
||||
} catch {
|
||||
return "development";
|
||||
}
|
||||
}
|
||||
|
||||
function normalizeRevision(revision) {
|
||||
if (revision === "development") return revision;
|
||||
|
||||
const normalizedRevision = revision.toLowerCase();
|
||||
if (!/^(?:[a-f0-9]{40}|[a-f0-9]{64})$/.test(normalizedRevision)) {
|
||||
throw new Error(
|
||||
"DOCKDECK_BUILD_REVISION must be a complete 40- or 64-character Git revision.",
|
||||
);
|
||||
}
|
||||
|
||||
return normalizedRevision;
|
||||
}
|
||||
|
||||
function getBuildDate() {
|
||||
const buildDate = process.env.DOCKDECK_BUILD_DATE ?? new Date().toISOString();
|
||||
const parsedDate = new Date(buildDate);
|
||||
const hasMilliseconds = /\.\d{3}Z$/.test(buildDate);
|
||||
const canonicalBuildDate = hasMilliseconds
|
||||
? buildDate
|
||||
: `${buildDate.slice(0, -1)}.000Z`;
|
||||
if (
|
||||
!/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{3})?Z$/.test(buildDate) ||
|
||||
Number.isNaN(parsedDate.getTime()) ||
|
||||
parsedDate.toISOString() !== canonicalBuildDate
|
||||
) {
|
||||
throw new Error(
|
||||
"DOCKDECK_BUILD_DATE must be a canonical UTC ISO timestamp with optional milliseconds.",
|
||||
);
|
||||
}
|
||||
|
||||
return buildDate;
|
||||
}
|
||||
|
||||
const suppliedVersion = process.env.DOCKDECK_BUILD_VERSION?.trim();
|
||||
if (suppliedVersion && suppliedVersion !== packageJson.version) {
|
||||
throw new Error(
|
||||
`DOCKDECK_BUILD_VERSION (${suppliedVersion}) does not match package.json (${packageJson.version}).`,
|
||||
);
|
||||
}
|
||||
|
||||
const revision = getRevision();
|
||||
const buildDate = getBuildDate();
|
||||
if (revision !== "development" && Date.parse(buildDate) === 0) {
|
||||
throw new Error(
|
||||
"DOCKDECK_BUILD_DATE must be a real UTC build timestamp when a full Git revision is provided.",
|
||||
);
|
||||
}
|
||||
|
||||
const buildInfo = {
|
||||
version: packageJson.version,
|
||||
revision,
|
||||
shortRevision: revision === "development" ? "dev" : revision.slice(0, 12),
|
||||
buildDate,
|
||||
};
|
||||
|
||||
function runNodeScript(scriptPath, args = []) {
|
||||
const result = spawnSync(
|
||||
process.execPath,
|
||||
[resolve(projectRoot, scriptPath), ...args],
|
||||
{ cwd: projectRoot, stdio: "inherit" },
|
||||
);
|
||||
if (result.error) throw result.error;
|
||||
if (result.status !== 0) process.exit(result.status ?? 1);
|
||||
}
|
||||
|
||||
runNodeScript("node_modules/typescript/bin/tsc", ["-b"]);
|
||||
runNodeScript("node_modules/vite/bin/vite.js", ["build"]);
|
||||
|
||||
const serverOutput = resolve(projectRoot, "dist/server/index.js");
|
||||
mkdirSync(dirname(serverOutput), { recursive: true });
|
||||
await build({
|
||||
entryPoints: [resolve(projectRoot, "src/server/index.ts")],
|
||||
bundle: true,
|
||||
platform: "node",
|
||||
format: "esm",
|
||||
packages: "external",
|
||||
outfile: serverOutput,
|
||||
define: {
|
||||
__DOCKDECK_BUILD_INFO__: JSON.stringify(buildInfo),
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,55 @@
|
||||
#!/usr/bin/env node
|
||||
// Prints a DOCKDECK_OPERATOR_PASSWORD_HASH value ("salt:hash", scrypt,
|
||||
// hex-encoded) for a password read from standard input. Run locally, set the
|
||||
// printed value as an env var, and never place the plaintext in process args.
|
||||
import { randomBytes, scryptSync } from "node:crypto";
|
||||
|
||||
if (process.argv.length > 2) {
|
||||
console.error(
|
||||
"Do not pass a password as an argument; provide it on standard input.",
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
async function readPassword() {
|
||||
if (!process.stdin.isTTY) {
|
||||
let value = "";
|
||||
for await (const chunk of process.stdin) value += chunk;
|
||||
return value.replace(/[\r\n]+$/, "");
|
||||
}
|
||||
return new Promise((resolve, reject) => {
|
||||
let value = "";
|
||||
const finish = (error) => {
|
||||
process.stdin.setRawMode(false);
|
||||
process.stdin.pause();
|
||||
process.stdin.removeListener("data", onData);
|
||||
process.stderr.write("\n");
|
||||
if (error) reject(error);
|
||||
else resolve(value);
|
||||
};
|
||||
const onData = (chunk) => {
|
||||
for (const character of String(chunk)) {
|
||||
if (character === "\u0003") return finish(new Error("Cancelled"));
|
||||
if (character === "\r" || character === "\n") return finish();
|
||||
if (character === "\u007f" || character === "\b")
|
||||
value = value.slice(0, -1);
|
||||
else value += character;
|
||||
}
|
||||
};
|
||||
process.stderr.write("Operator password: ");
|
||||
process.stdin.setRawMode(true);
|
||||
process.stdin.setEncoding("utf8");
|
||||
process.stdin.resume();
|
||||
process.stdin.on("data", onData);
|
||||
});
|
||||
}
|
||||
|
||||
const password = await readPassword();
|
||||
if (!password) {
|
||||
console.error("Usage: provide the password on standard input.");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const salt = randomBytes(16).toString("hex");
|
||||
const hash = scryptSync(password, salt, 32).toString("hex");
|
||||
console.log(`${salt}:${hash}`);
|
||||
Reference in new issue
Block a user