rushabhcodes/fidget-counter

A tscircuit package created by rushabhcodes.

Version
1.0.31
License
unset
Stars
0

validation/check-cloud-build.mjs

import assert from "node:assert/strict"
import { createHash } from "node:crypto"
import { cpSync, mkdtempSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs"
import { tmpdir } from "node:os"
import { dirname, resolve } from "node:path"
import { fileURLToPath } from "node:url"
import { spawnSync } from "node:child_process"

const root = resolve(dirname(fileURLToPath(import.meta.url)), "..")
const scratch = mkdtempSync(resolve(tmpdir(), "fidget-cloud-check-"))
const manifest = JSON.parse(readFileSync(resolve(root, "cloud-assets/manifest.json")))
const originalPackage = JSON.parse(readFileSync(resolve(root, "package.json")))
const hash = bytes => createHash("sha256").update(bytes).digest("hex")
const writePackage = value => writeFileSync(resolve(scratch, "package.json"), JSON.stringify(value, null, 2) + "\n")
const run = (cloud, expectedError) => {
  const result = spawnSync(process.execPath, ["cloud-build.mjs"], {
    cwd: scratch,
    env: { ...process.env, TSCIRCUIT_INSIDE_BUILD_COMMAND: cloud ? "1" : "0" },
    encoding: "utf8",
  })
  const output = result.stdout + result.stderr
  if (expectedError) {
    assert.notEqual(result.status, 0, "A stale preview was accepted")
    assert(output.includes(expectedError), output)
  } else {
    assert.equal(result.status, 0, output)
    for (const artifact of [...manifest.artifacts,...(manifest.variantArtifacts ?? [])])
      assert.equal(hash(readFileSync(resolve(scratch, artifact.output))), artifact.sha256)
  }
}

try {
  const files = new Set([...Object.keys(manifest.inputs), ...manifest.artifacts.flatMap(a => a.sourceParts ?? [a.source]),
    "cloud-assets/manifest.json", ...manifest.cadInputArchives.flatMap(a => a.sourceParts ?? [a.source]), "package.json", "bun.lock"])
  for (const name of files) {
    const target = resolve(scratch, name)
    mkdirSync(dirname(target), { recursive: true })
    cpSync(resolve(root, name), target)
  }
  run(false)

  // TSCI receives the packed exports; its build must reconstruct exact bytes.
  for (const name of manifest.cadInputArchives.flatMap(a => a.files)) rmSync(resolve(scratch, name))
  run(false)
  for (const name of manifest.cadInputArchives.flatMap(a => a.files))
    assert.equal(hash(readFileSync(resolve(scratch, name))), manifest.inputs[name])
  const cadPath = resolve(scratch, manifest.cadInputArchives.flatMap(a => a.files)[0])
  const cadBytes = readFileSync(cadPath)
  writeFileSync(cadPath, "changed CAD export")
  run(false, `${manifest.cadInputArchives.flatMap(a => a.files)[0]} changed`)
  writeFileSync(cadPath, cadBytes)

  const chunkedCad = manifest.cadInputArchives.find(a => a.sourceParts?.length > 1)
  assert(chunkedCad,"Exercise chunked CAD restoration")
  const cadChunkPath=resolve(scratch,chunkedCad.sourceParts[0])
  const cadChunkBytes=readFileSync(cadChunkPath)
  writeFileSync(cadChunkPath,"corrupted CAD archive chunk")
  run(false,"Invalid checked CAD input archive")
  writeFileSync(cadChunkPath,cadChunkBytes)

  const chunked = manifest.artifacts.find(a => a.sourceParts?.length > 1)
  assert(chunked, "Exercise chunked preview restore")
  const partPath = resolve(scratch, chunked.sourceParts[0])
  const partBytes = readFileSync(partPath)
  writeFileSync(partPath, "corrupted preview chunk")
  run(false, "Invalid checked artifact")
  writeFileSync(partPath, partBytes)

  // Match the registry's compiler substitution and the subsequent CI install.
  const cloudPackage = structuredClone(originalPackage)
  cloudPackage.version = "1.0.99"
  for (const field of ["dependencies", "devDependencies", "optionalDependencies", "peerDependencies"])
    if (cloudPackage[field]) delete cloudPackage[field].tscircuit
  cloudPackage.devDependencies.tscircuit = "file:/root/.bun/install/global/node_modules/tscircuit"
  writePackage(cloudPackage)
  writeFileSync(resolve(scratch, "bun.lock"), "Regenerated by the cloud dependency install\n")
  assert.notEqual(hash(readFileSync(resolve(scratch, "package.json"))), hash(readFileSync(resolve(root, "package.json"))))
  run(true)

  // Older cloud workers remove the dependency without adding a file alias.
  delete cloudPackage.devDependencies.tscircuit
  writePackage(cloudPackage)
  run(true)

  writePackage(originalPackage)
  run(false, "local bun.lock changed")

  cloudPackage.dependencies["@tsci/tscircuit.standard-jst-programmer"] = "0.8.1"
  writePackage(cloudPackage)
  run(true, "component dependencies changed")
  const changedCompiler = structuredClone(originalPackage)
  changedCompiler.dependencies.tscircuit = "latest"
  writePackage(changedCompiler)
  run(true, "unexpected tscircuit compiler dependency")
  writePackage(originalPackage)

  const index = readFileSync(resolve(scratch, "index.circuit.tsx"))
  writeFileSync(resolve(scratch, "index.circuit.tsx"), Buffer.concat([index, Buffer.from("\n// changed source\n")]))
  run(true, "index.circuit.tsx changed")
  writeFileSync(resolve(scratch, "index.circuit.tsx"), index)

  const contract = readFileSync(resolve(scratch, "routing-contract.json"))
  writeFileSync(resolve(scratch, "routing-contract.json"), "{}\n")
  run(true, "routing-contract.json changed")
  writeFileSync(resolve(scratch, "routing-contract.json"), contract)


  writeFileSync(resolve(scratch, "cloud-assets/pcb.png.gz.b64"), Buffer.from("corrupted preview").toString("base64"))
  const result = spawnSync(process.execPath, ["cloud-build.mjs"], {
    cwd: scratch, env: { ...process.env, TSCIRCUIT_INSIDE_BUILD_COMMAND: "1" }, encoding: "utf8",
  })
  assert.notEqual(result.status, 0, "A corrupted preview was accepted")
  console.log("Pass: local and both cloud bootstrap formats restore all six artifacts; changed dependencies, lockfile, source and corrupted assets are rejected")
} finally {
  rmSync(scratch, { recursive: true, force: true })
}