Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 | 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 43x 43x 42x 43x 43x 40x 40x 115x 115x 115x 338x 338x 338x 338x 76x 76x 75x 338x 1x 338x 115x 40x 37x 37x 37x 37x 42x 36x 104x 104x 104x 103x 104x 36x 34x 34x 34x 42x 43x 43x 43x 43x 43x 43x 43x 43x 43x 43x 43x 43x 43x 43x 43x 43x 43x 43x 43x 43x 43x 12x 43x 43x 11x 42x 26x 26x 26x 26x 26x 26x 26x 20x 26x 26x 19x 19x 19x 26x 18x 18x 18x 18x 26x 26x 26x 43x 2x 2x 3x 3x 3x 2x 3x 2x 2x 2x 2x 2x 3x | import { createHash } from "node:crypto"
import { lstat, readFile, readdir } from "node:fs/promises"
import { join } from "node:path"
import process from "node:process"
export const releaseFiles = [
"package.json",
"runtime-artifact.json",
"dist/index.js",
"dist/scripts/authorizeBot.js",
"dist/scripts/sendSmokeMessage.js",
"dist/scripts/checkReadiness.js",
]
export async function validateArtifact(directory, expectedSha) {
if (!/^[a-f0-9]{40}$/.test(expectedSha))
throw new Error("Invalid release SHA.")
const root = await lstat(directory)
if (!root.isDirectory() || root.isSymbolicLink())
throw new Error("Invalid release directory.")
const names = []
async function walk(relative) {
for (const entry of await readdir(join(directory, relative), {
withFileTypes: true,
})) {
const path = relative ? `${relative}/${entry.name}` : entry.name
if (entry.isSymbolicLink())
throw new Error("Release symlinks are forbidden.")
if (entry.isDirectory()) {
if (path !== "dist" && path !== "dist/scripts")
throw new Error("Unexpected release directory.")
await walk(path)
} else if (entry.isFile()) names.push(path)
else throw new Error("Only regular release files are permitted.")
}
}
await walk("")
if (
JSON.stringify(names.sort()) !==
JSON.stringify([...releaseFiles, "manifest.json"].sort())
)
throw new Error("Unexpected release contents.")
const readJson = async (name) => {
const file = join(directory, name)
if ((await lstat(file)).size > 65536)
throw new Error("Oversized release metadata.")
return JSON.parse(await readFile(file, "utf8"))
}
const manifest = await readJson("manifest.json")
const contract = await readJson("runtime-artifact.json")
const pkg = await readJson("package.json")
if (
!manifest ||
manifest.contractVersion !== 1 ||
manifest.sha !== expectedSha ||
manifest.service !== "twitch-bot" ||
manifest.platform !== "linux-x64" ||
manifest.nodeVersion !== "v24.15.0" ||
!Array.isArray(manifest.files) ||
manifest.files.length !== releaseFiles.length ||
!contract ||
contract.contractVersion !== 1 ||
contract.service !== "twitch-bot" ||
contract.packageName !== "@workspace/twitch-bot" ||
contract.packageVersion !== "0.1.0" ||
contract.nodeVersion !== "v24.15.0" ||
contract.platform !== "linux-x64" ||
contract.runtimeEntrypoint !== "dist/index.js" ||
contract.smokeEntrypoint !== "dist/scripts/sendSmokeMessage.js" ||
contract.readinessEntrypoint !== "dist/scripts/checkReadiness.js" ||
!pkg ||
pkg.name !== "@workspace/twitch-bot" ||
pkg.version !== "0.1.0" ||
pkg.type !== "module" ||
pkg.dependencies
)
throw new Error("Release metadata does not match the Twitch host contract.")
const seen = new Set()
for (const entry of manifest.files) {
if (
!entry ||
!releaseFiles.includes(entry.path) ||
seen.has(entry.path) ||
!/^[a-f0-9]{64}$/.test(entry.sha256) ||
!Number.isSafeInteger(entry.size) ||
entry.size < 1 ||
entry.size > 10 * 1024 * 1024
)
throw new Error("Invalid release integrity metadata.")
seen.add(entry.path)
const path = join(directory, entry.path)
if ((await lstat(path)).size !== entry.size)
throw new Error("Release integrity check failed.")
const content = await readFile(path)
if (
content.length !== entry.size ||
createHash("sha256").update(content).digest("hex") !== entry.sha256
)
throw new Error("Release integrity check failed.")
}
}
export async function main(args = process.argv.slice(2)) {
try {
if (args.length !== 2)
throw new Error("Expected release directory and SHA.")
await validateArtifact(args[0], args[1])
} catch {
process.stderr.write(
'{"level":"error","namespace":"twitch-artifact","message":"Invalid Twitch release artifact."}\n'
)
process.exitCode = 1
}
}
|