From b57e263ed1fc9089de5195c6ed12f7fc7a816160 Mon Sep 17 00:00:00 2001 From: Graham Christensen Date: Fri, 10 May 2024 16:12:34 -0400 Subject: [PATCH] Behave well when MNCA isn't trusted --- .github/workflows/ci.yml | 23 +++++++++++++ dist/index.js | 72 +++++++++++++++++++++++++++++++++++++--- dist/index.js.map | 2 +- package.json | 2 +- pnpm-lock.yaml | 14 ++++---- src/index.ts | 24 ++++++++++++-- 6 files changed, 121 insertions(+), 16 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index dc6f377..f70f641 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -44,6 +44,29 @@ jobs: - name: Cache the store uses: ./ + run-x86_64-linux-untrusted: + name: Run x86_64 Linux + runs-on: ubuntu-22.04 + permissions: + id-token: "write" + contents: "read" + env: + ACTIONS_STEP_DEBUG: true + steps: + - uses: actions/checkout@v4 + - name: Install Nix + uses: DeterminateSystems/nix-installer-action@main + with: + trust-runner-user: false + flakehub: true + extra-conf: | + narinfo-cache-negative-ttl = 0 + - name: Cache the store + uses: ./ + - name: Check the cache for liveness + run: | + .github/workflows/cache-test.sh + run-x86_64-linux: name: Run x86_64 Linux runs-on: ubuntu-22.04 diff --git a/dist/index.js b/dist/index.js index 3fa3d90..3f0923e 100644 --- a/dist/index.js +++ b/dist/index.js @@ -93752,7 +93752,7 @@ const got = source_create(defaults); const external_node_stream_promises_namespaceObject = __WEBPACK_EXTERNAL_createRequire(import.meta.url)("node:stream/promises"); ;// CONCATENATED MODULE: external "node:zlib" const external_node_zlib_namespaceObject = __WEBPACK_EXTERNAL_createRequire(import.meta.url)("node:zlib"); -;// CONCATENATED MODULE: ./node_modules/.pnpm/github.com+DeterminateSystems+detsys-ts@2391ba1ef3d22027cd4d9ecce147007a88f63643_is35d24tynybsms6zejuqsabhi/node_modules/detsys-ts/dist/index.js +;// CONCATENATED MODULE: ./node_modules/.pnpm/github.com+DeterminateSystems+detsys-ts@c1c2371f083f911beb01d75e4d194df0e8cd4416_laqtfm6jblzcvupdk4zopxnh6q/node_modules/detsys-ts/dist/index.js var __defProp = Object.defineProperty; var __export = (target, all) => { for (var name in all) @@ -94204,6 +94204,7 @@ function constructSourceParameters(legacyPrefix) { + var DEFAULT_IDS_HOST = "https://install.determinate.systems"; var IDS_HOST = process.env["IDS_HOST"] ?? DEFAULT_IDS_HOST; var EVENT_EXCEPTION = "exception"; @@ -94214,12 +94215,17 @@ var FACT_ENDED_WITH_EXCEPTION = "ended_with_exception"; var FACT_FINAL_EXCEPTION = "final_exception"; var FACT_SOURCE_URL = "source_url"; var FACT_SOURCE_URL_ETAG = "source_url_etag"; +var FACT_NIX_STORE_TRUST = "nix_store_trusted"; +var FACT_NIX_STORE_VERSION = "nix_store_version"; +var FACT_NIX_STORE_CHECK_METHOD = "nix_store_check_method"; +var FACT_NIX_STORE_CHECK_ERROR = "nix_store_check_error"; var IdsToolbox = class { constructor(actionOptions) { this.actionOptions = makeOptionsConfident(actionOptions); this.hookMain = void 0; this.hookPost = void 0; this.exceptionAttachments = /* @__PURE__ */ new Map(); + this.nixStoreTrust = "unknown"; this.events = []; this.client = got_dist_source.extend({ retry: { @@ -94332,6 +94338,9 @@ var IdsToolbox = class { if (!await this.preflightRequireNix()) { this.recordEvent("preflight-require-nix-denied"); return; + } else { + await this.preflightNixStoreInfo(); + this.addFact(FACT_NIX_STORE_TRUST, this.nixStoreTrust); } if (this.executionPhase === "main" && this.hookMain) { await this.hookMain(); @@ -94537,6 +94546,7 @@ var IdsToolbox = class { await promises_namespaceObject.access(candidateNix, promises_namespaceObject.constants.X_OK); core.debug(`Found Nix at ${candidateNix}`); nixLocation = candidateNix; + break; } catch { core.debug(`Nix not at ${candidateNix}`); } @@ -94569,6 +94579,46 @@ var IdsToolbox = class { } return false; } + async preflightNixStoreInfo() { + this.nixStoreTrust = "unknown"; + let output = ""; + const options = {}; + options.listeners = { + stdout: (data) => { + output += data.toString(); + } + }; + try { + output = ""; + await exec.exec("nix", ["store", "info", "--json"], options); + this.addFact(FACT_NIX_STORE_CHECK_METHOD, "info"); + } catch { + try { + output = ""; + await exec.exec("nix", ["store", "ping", "--json"], options); + this.addFact(FACT_NIX_STORE_CHECK_METHOD, "ping"); + } catch { + this.addFact(FACT_NIX_STORE_CHECK_METHOD, "none"); + return; + } + } + try { + const parsed = JSON.parse(output); + if (parsed.trusted === 1) { + this.nixStoreTrust = "trusted"; + } else if (parsed.trusted === 0) { + this.nixStoreTrust = "untrusted"; + } else if (parsed.trusted !== void 0) { + this.addFact( + FACT_NIX_STORE_CHECK_ERROR, + `Mysterious trusted value: ${JSON.stringify(parsed.trusted)}` + ); + } + this.addFact(FACT_NIX_STORE_VERSION, JSON.stringify(parsed.version)); + } catch (e) { + this.addFact(FACT_NIX_STORE_CHECK_ERROR, this.stringifyError(e)); + } + } async submitEvents() { if (!this.actionOptions.diagnosticsUrl) { core.debug( @@ -94749,7 +94799,9 @@ var ENV_DAEMON_DIR = "MAGIC_NIX_CACHE_DAEMONDIR"; var STATE_DAEMONDIR = "MAGIC_NIX_CACHE_DAEMONDIR"; var STATE_STARTED = "MAGIC_NIX_CACHE_STARTED"; var STARTED_HINT = "true"; -var NOOP_TEXT = "Magic Nix Cache is already running, this workflow job is in noop mode. Is the Magic Nix Cache in the workflow twice?"; +var TEXT_NOOP = "Magic Nix Cache is already running, this workflow job is in noop mode. Is the Magic Nix Cache in the workflow twice?"; +var TEXT_TRUST_UNTRUSTED = "The Nix daemon does not consider the user running this workflow to be trusted. Magic Nix Cache is disabled."; +var TEXT_TRUST_UNKNOWN = "The Nix daemon may not consider the user running this workflow to be trusted. Magic Nix Cache may not start correctly."; var MagicNixCacheAction = class { constructor() { this.idslib = new IdsToolbox({ @@ -94987,17 +95039,29 @@ function main() { const cacheAction = new MagicNixCacheAction(); cacheAction.idslib.onMain(async () => { if (cacheAction.noopMode) { - core.warning(NOOP_TEXT); + core.warning(TEXT_NOOP); return; } + if (cacheAction.idslib.nixStoreTrust === "untrusted") { + core.warning(TEXT_TRUST_UNTRUSTED); + return; + } else if (cacheAction.idslib.nixStoreTrust === "unknown") { + core.info(TEXT_TRUST_UNKNOWN); + } await cacheAction.setUpAutoCache(); await cacheAction.notifyAutoCache(); }); cacheAction.idslib.onPost(async () => { if (cacheAction.noopMode) { - core.debug(NOOP_TEXT); + core.debug(TEXT_NOOP); return; } + if (cacheAction.idslib.nixStoreTrust === "untrusted") { + core.debug(TEXT_TRUST_UNTRUSTED); + return; + } else if (cacheAction.idslib.nixStoreTrust === "unknown") { + core.debug(TEXT_TRUST_UNKNOWN); + } await cacheAction.tearDownAutoCache(); }); cacheAction.idslib.execute(); diff --git a/dist/index.js.map b/dist/index.js.map index 8c9efd8..8b091c2 100644 --- a/dist/index.js.map +++ b/dist/index.js.map @@ -1 +1 @@ -{"version":3,"sources":["../src/helpers.ts","../src/index.ts"],"sourcesContent":["import * as actionsCore from \"@actions/core\";\nimport * as fs from \"node:fs/promises\";\nimport * as os from \"node:os\";\nimport path from \"node:path\";\nimport { Tail } from \"tail\";\n\nexport function tailLog(daemonDir: string): Tail {\n const log = new Tail(path.join(daemonDir, \"daemon.log\"));\n actionsCore.debug(`tailing daemon.log...`);\n log.on(\"line\", (line) => {\n actionsCore.info(line);\n });\n return log;\n}\n\nexport async function netrcPath(): Promise {\n const expectedNetrcPath = path.join(\n process.env[\"RUNNER_TEMP\"] || os.tmpdir(),\n \"determinate-nix-installer-netrc\",\n );\n try {\n await fs.access(expectedNetrcPath);\n return expectedNetrcPath;\n } catch {\n // `nix-installer` was not used, the user may be registered with FlakeHub though.\n const destinedNetrcPath = path.join(\n process.env[\"RUNNER_TEMP\"] || os.tmpdir(),\n \"magic-nix-cache-netrc\",\n );\n try {\n await flakeHubLogin(destinedNetrcPath);\n } catch (e) {\n actionsCore.info(\"FlakeHub cache disabled.\");\n actionsCore.debug(`Error while logging into FlakeHub: ${e}`);\n }\n return destinedNetrcPath;\n }\n}\n\nasync function flakeHubLogin(netrc: string): Promise {\n const jwt = await actionsCore.getIDToken(\"api.flakehub.com\");\n\n await fs.writeFile(\n netrc,\n [\n `machine api.flakehub.com login flakehub password ${jwt}`,\n `machine flakehub.com login flakehub password ${jwt}`,\n `machine cache.flakehub.com login flakehub password ${jwt}`,\n ].join(\"\\n\"),\n );\n\n actionsCore.info(\"Logged in to FlakeHub.\");\n}\n","import { netrcPath, tailLog } from \"./helpers.js\";\nimport * as actionsCore from \"@actions/core\";\nimport { IdsToolbox, inputs } from \"detsys-ts\";\nimport got, { Got } from \"got\";\nimport * as http from \"http\";\nimport { SpawnOptions, exec, spawn } from \"node:child_process\";\nimport { mkdirSync, openSync, readFileSync } from \"node:fs\";\nimport * as fs from \"node:fs/promises\";\nimport * as os from \"node:os\";\nimport * as path from \"node:path\";\nimport { inspect, promisify } from \"node:util\";\n\n// The ENV_DAEMON_DIR is intended to determine if we \"own\" the daemon or not,\n// in the case that a user has put the magic nix cache into their workflow\n// twice.\nconst ENV_DAEMON_DIR = \"MAGIC_NIX_CACHE_DAEMONDIR\";\n\nconst STATE_DAEMONDIR = \"MAGIC_NIX_CACHE_DAEMONDIR\";\nconst STATE_STARTED = \"MAGIC_NIX_CACHE_STARTED\";\nconst STARTED_HINT = \"true\";\n\nconst NOOP_TEXT =\n \"Magic Nix Cache is already running, this workflow job is in noop mode. Is the Magic Nix Cache in the workflow twice?\";\n\nclass MagicNixCacheAction {\n idslib: IdsToolbox;\n private client: Got;\n\n noopMode: boolean;\n private daemonDir: string;\n private daemonStarted: boolean;\n\n constructor() {\n this.idslib = new IdsToolbox({\n name: \"magic-nix-cache\",\n fetchStyle: \"gh-env-style\",\n idsProjectName: \"magic-nix-cache-closure\",\n requireNix: \"warn\",\n });\n\n this.client = got.extend({\n retry: {\n limit: 1,\n methods: [\"POST\", \"GET\", \"PUT\", \"HEAD\", \"DELETE\", \"OPTIONS\", \"TRACE\"],\n },\n hooks: {\n beforeRetry: [\n (error, retryCount) => {\n actionsCore.info(\n `Retrying after error ${error.code}, retry #: ${retryCount}`,\n );\n },\n ],\n },\n });\n\n this.daemonStarted = actionsCore.getState(STATE_STARTED) === STARTED_HINT;\n\n if (actionsCore.getState(STATE_DAEMONDIR) !== \"\") {\n this.daemonDir = actionsCore.getState(STATE_DAEMONDIR);\n } else {\n this.daemonDir = this.idslib.getTemporaryName();\n mkdirSync(this.daemonDir);\n actionsCore.saveState(STATE_DAEMONDIR, this.daemonDir);\n }\n\n if (process.env[ENV_DAEMON_DIR] === undefined) {\n this.noopMode = false;\n actionsCore.exportVariable(ENV_DAEMON_DIR, this.daemonDir);\n } else {\n this.noopMode = process.env[ENV_DAEMON_DIR] !== this.daemonDir;\n }\n this.idslib.addFact(\"noop_mode\", this.noopMode);\n\n this.idslib.stapleFile(\n \"daemon.log\",\n path.join(this.daemonDir, \"daemon.log\"),\n );\n }\n\n async setUpAutoCache(): Promise {\n const requiredEnv = [\n \"ACTIONS_CACHE_URL\",\n \"ACTIONS_RUNTIME_URL\",\n \"ACTIONS_RUNTIME_TOKEN\",\n ];\n\n let anyMissing = false;\n for (const n of requiredEnv) {\n if (!process.env.hasOwnProperty(n)) {\n anyMissing = true;\n actionsCore.warning(\n `Disabling automatic caching since required environment ${n} isn't available`,\n );\n }\n }\n\n this.idslib.addFact(\"authenticated_env\", !anyMissing);\n if (anyMissing) {\n return;\n }\n\n if (this.daemonStarted) {\n actionsCore.debug(\"Already started.\");\n return;\n }\n\n actionsCore.debug(\n `GitHub Action Cache URL: ${process.env[\"ACTIONS_CACHE_URL\"]}`,\n );\n\n const sourceBinary = inputs.getStringOrNull(\"source-binary\");\n const daemonBin =\n sourceBinary !== null ? sourceBinary : await this.fetchAutoCacher();\n\n let runEnv;\n if (actionsCore.isDebug()) {\n runEnv = {\n RUST_LOG: \"trace,magic_nix_cache=debug,gha_cache=debug\",\n RUST_BACKTRACE: \"full\",\n ...process.env,\n };\n } else {\n runEnv = process.env;\n }\n\n const notifyPort = inputs.getString(\"startup-notification-port\");\n\n const notifyPromise = new Promise>((resolveListening) => {\n const promise = new Promise(async (resolveQuit) => {\n const notifyServer = http.createServer((req, res) => {\n if (req.method === \"POST\" && req.url === \"/\") {\n actionsCore.debug(`Notify server shutting down.`);\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(\"{}\");\n notifyServer.close(() => {\n resolveQuit();\n });\n }\n });\n\n notifyServer.listen(notifyPort, () => {\n actionsCore.debug(`Notify server running.`);\n resolveListening(promise);\n });\n });\n });\n\n // Start tailing the daemon log.\n const outputPath = `${this.daemonDir}/daemon.log`;\n const output = openSync(outputPath, \"a\");\n const log = tailLog(this.daemonDir);\n const netrc = await netrcPath();\n const nixConfPath = `${process.env[\"HOME\"]}/.config/nix/nix.conf`;\n\n const hostAndPort = inputs.getString(\"listen\");\n const upstreamCache = inputs.getString(\"upstream-cache\");\n const diagnosticEndpoint = inputs.getString(\"diagnostic-endpoint\");\n const useFlakeHub = inputs.getBool(\"use-flakehub\");\n const flakeHubCacheServer = inputs.getString(\"flakehub-cache-server\");\n const flakeHubApiServer = inputs.getString(\"flakehub-api-server\");\n const flakeHubFlakeName = inputs.getString(\"flakehub-flake-name\");\n const useGhaCache = inputs.getBool(\"use-gha-cache\");\n\n const daemonCliFlags: string[] = [\n \"--startup-notification-url\",\n `http://127.0.0.1:${notifyPort}`,\n \"--listen\",\n hostAndPort,\n \"--upstream\",\n upstreamCache,\n \"--diagnostic-endpoint\",\n diagnosticEndpoint,\n \"--nix-conf\",\n nixConfPath,\n ]\n .concat(\n useFlakeHub\n ? [\n \"--use-flakehub\",\n \"--flakehub-cache-server\",\n flakeHubCacheServer,\n \"--flakehub-api-server\",\n flakeHubApiServer,\n \"--flakehub-api-server-netrc\",\n netrc,\n \"--flakehub-flake-name\",\n flakeHubFlakeName,\n ]\n : [],\n )\n .concat(useGhaCache ? [\"--use-gha-cache\"] : []);\n\n const opts: SpawnOptions = {\n stdio: [\"ignore\", output, output],\n env: runEnv,\n detached: true,\n };\n\n // Display the final command for debugging purposes\n actionsCore.debug(\"Full daemon start command:\");\n actionsCore.debug(`${daemonBin} ${daemonCliFlags.join(\" \")}`);\n\n // Start the server. Once it is ready, it will notify us via the notification server.\n const daemon = spawn(daemonBin, daemonCliFlags, opts);\n\n this.daemonStarted = true;\n actionsCore.saveState(STATE_STARTED, STARTED_HINT);\n\n const pidFile = path.join(this.daemonDir, \"daemon.pid\");\n await fs.writeFile(pidFile, `${daemon.pid}`);\n\n actionsCore.info(\"Waiting for magic-nix-cache to start...\");\n\n await new Promise((resolve, reject) => {\n notifyPromise\n // eslint-disable-next-line github/no-then\n .then((_value) => {\n resolve();\n })\n // eslint-disable-next-line github/no-then\n .catch((err) => {\n reject(new Error(`error in notifyPromise: ${err}`));\n });\n daemon.on(\"exit\", async (code, signal) => {\n if (signal) {\n reject(new Error(`Daemon was killed by signal ${signal}`));\n } else if (code) {\n reject(new Error(`Daemon exited with code ${code}`));\n } else {\n reject(new Error(`Daemon unexpectedly exited`));\n }\n });\n });\n\n daemon.unref();\n\n actionsCore.info(\"Launched Magic Nix Cache\");\n\n log.unwatch();\n }\n\n private async fetchAutoCacher(): Promise {\n const closurePath = await this.idslib.fetch();\n this.idslib.recordEvent(\"load_closure\");\n const { stdout } = await promisify(exec)(\n `cat \"${closurePath}\" | xz -d | nix-store --import`,\n );\n\n const paths = stdout.split(os.EOL);\n // Since the export is in reverse topologically sorted order, magic-nix-cache is always the penultimate entry in the list (the empty string left by split being the last).\n const lastPath = paths.at(-2);\n return `${lastPath}/bin/magic-nix-cache`;\n }\n\n async notifyAutoCache(): Promise {\n if (!this.daemonStarted) {\n actionsCore.debug(\"magic-nix-cache not started - Skipping\");\n return;\n }\n\n try {\n actionsCore.debug(`Indicating workflow start`);\n const hostAndPort = inputs.getString(\"listen\");\n const res: Response = await this.client\n .post(`http://${hostAndPort}/api/workflow-start`)\n .json();\n actionsCore.debug(`back from post: ${res}`);\n } catch (e) {\n actionsCore.info(`Error marking the workflow as started:`);\n actionsCore.info(inspect(e));\n actionsCore.info(`Magic Nix Cache may not be running for this workflow.`);\n }\n }\n\n async tearDownAutoCache(): Promise {\n if (!this.daemonStarted) {\n actionsCore.debug(\"magic-nix-cache not started - Skipping\");\n return;\n }\n\n const pidFile = path.join(this.daemonDir, \"daemon.pid\");\n const pid = parseInt(await fs.readFile(pidFile, { encoding: \"ascii\" }));\n actionsCore.debug(`found daemon pid: ${pid}`);\n if (!pid) {\n throw new Error(\"magic-nix-cache did not start successfully\");\n }\n\n const log = tailLog(this.daemonDir);\n\n try {\n actionsCore.debug(`about to post to localhost`);\n const hostAndPort = inputs.getString(\"listen\");\n const res: Response = await this.client\n .post(`http://${hostAndPort}/api/workflow-finish`)\n .json();\n actionsCore.debug(`back from post: ${res}`);\n } finally {\n actionsCore.debug(`unwatching the daemon log`);\n log.unwatch();\n }\n\n actionsCore.debug(`killing`);\n try {\n process.kill(pid, \"SIGTERM\");\n } catch (e) {\n if (typeof e === \"object\" && e && \"code\" in e && e.code !== \"ESRCH\") {\n throw e;\n }\n } finally {\n if (actionsCore.isDebug()) {\n actionsCore.info(\"Entire log:\");\n const entireLog = readFileSync(path.join(this.daemonDir, \"daemon.log\"));\n actionsCore.info(entireLog.toString());\n }\n }\n }\n}\n\nfunction main(): void {\n const cacheAction = new MagicNixCacheAction();\n\n cacheAction.idslib.onMain(async () => {\n if (cacheAction.noopMode) {\n actionsCore.warning(NOOP_TEXT);\n return;\n }\n\n await cacheAction.setUpAutoCache();\n await cacheAction.notifyAutoCache();\n });\n cacheAction.idslib.onPost(async () => {\n if (cacheAction.noopMode) {\n actionsCore.debug(NOOP_TEXT);\n return;\n }\n\n await cacheAction.tearDownAutoCache();\n });\n\n cacheAction.idslib.execute();\n}\n\nmain();\n"],"mappings":"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","names":["actionsCore","fs","os","path"]} \ No newline at end of file +{"version":3,"sources":["../src/helpers.ts","../src/index.ts"],"sourcesContent":["import * as actionsCore from \"@actions/core\";\nimport * as fs from \"node:fs/promises\";\nimport * as os from \"node:os\";\nimport path from \"node:path\";\nimport { Tail } from \"tail\";\n\nexport function tailLog(daemonDir: string): Tail {\n const log = new Tail(path.join(daemonDir, \"daemon.log\"));\n actionsCore.debug(`tailing daemon.log...`);\n log.on(\"line\", (line) => {\n actionsCore.info(line);\n });\n return log;\n}\n\nexport async function netrcPath(): Promise {\n const expectedNetrcPath = path.join(\n process.env[\"RUNNER_TEMP\"] || os.tmpdir(),\n \"determinate-nix-installer-netrc\",\n );\n try {\n await fs.access(expectedNetrcPath);\n return expectedNetrcPath;\n } catch {\n // `nix-installer` was not used, the user may be registered with FlakeHub though.\n const destinedNetrcPath = path.join(\n process.env[\"RUNNER_TEMP\"] || os.tmpdir(),\n \"magic-nix-cache-netrc\",\n );\n try {\n await flakeHubLogin(destinedNetrcPath);\n } catch (e) {\n actionsCore.info(\"FlakeHub cache disabled.\");\n actionsCore.debug(`Error while logging into FlakeHub: ${e}`);\n }\n return destinedNetrcPath;\n }\n}\n\nasync function flakeHubLogin(netrc: string): Promise {\n const jwt = await actionsCore.getIDToken(\"api.flakehub.com\");\n\n await fs.writeFile(\n netrc,\n [\n `machine api.flakehub.com login flakehub password ${jwt}`,\n `machine flakehub.com login flakehub password ${jwt}`,\n `machine cache.flakehub.com login flakehub password ${jwt}`,\n ].join(\"\\n\"),\n );\n\n actionsCore.info(\"Logged in to FlakeHub.\");\n}\n","import { netrcPath, tailLog } from \"./helpers.js\";\nimport * as actionsCore from \"@actions/core\";\nimport { IdsToolbox, inputs } from \"detsys-ts\";\nimport got, { Got } from \"got\";\nimport * as http from \"http\";\nimport { SpawnOptions, exec, spawn } from \"node:child_process\";\nimport { mkdirSync, openSync, readFileSync } from \"node:fs\";\nimport * as fs from \"node:fs/promises\";\nimport * as os from \"node:os\";\nimport * as path from \"node:path\";\nimport { inspect, promisify } from \"node:util\";\n\n// The ENV_DAEMON_DIR is intended to determine if we \"own\" the daemon or not,\n// in the case that a user has put the magic nix cache into their workflow\n// twice.\nconst ENV_DAEMON_DIR = \"MAGIC_NIX_CACHE_DAEMONDIR\";\n\nconst STATE_DAEMONDIR = \"MAGIC_NIX_CACHE_DAEMONDIR\";\nconst STATE_STARTED = \"MAGIC_NIX_CACHE_STARTED\";\nconst STARTED_HINT = \"true\";\n\nconst TEXT_NOOP =\n \"Magic Nix Cache is already running, this workflow job is in noop mode. Is the Magic Nix Cache in the workflow twice?\";\nconst TEXT_TRUST_UNTRUSTED =\n \"The Nix daemon does not consider the user running this workflow to be trusted. Magic Nix Cache is disabled.\";\nconst TEXT_TRUST_UNKNOWN =\n \"The Nix daemon may not consider the user running this workflow to be trusted. Magic Nix Cache may not start correctly.\";\n\nclass MagicNixCacheAction {\n idslib: IdsToolbox;\n private client: Got;\n\n noopMode: boolean;\n private daemonDir: string;\n private daemonStarted: boolean;\n\n constructor() {\n this.idslib = new IdsToolbox({\n name: \"magic-nix-cache\",\n fetchStyle: \"gh-env-style\",\n idsProjectName: \"magic-nix-cache-closure\",\n requireNix: \"warn\",\n });\n\n this.client = got.extend({\n retry: {\n limit: 1,\n methods: [\"POST\", \"GET\", \"PUT\", \"HEAD\", \"DELETE\", \"OPTIONS\", \"TRACE\"],\n },\n hooks: {\n beforeRetry: [\n (error, retryCount) => {\n actionsCore.info(\n `Retrying after error ${error.code}, retry #: ${retryCount}`,\n );\n },\n ],\n },\n });\n\n this.daemonStarted = actionsCore.getState(STATE_STARTED) === STARTED_HINT;\n\n if (actionsCore.getState(STATE_DAEMONDIR) !== \"\") {\n this.daemonDir = actionsCore.getState(STATE_DAEMONDIR);\n } else {\n this.daemonDir = this.idslib.getTemporaryName();\n mkdirSync(this.daemonDir);\n actionsCore.saveState(STATE_DAEMONDIR, this.daemonDir);\n }\n\n if (process.env[ENV_DAEMON_DIR] === undefined) {\n this.noopMode = false;\n actionsCore.exportVariable(ENV_DAEMON_DIR, this.daemonDir);\n } else {\n this.noopMode = process.env[ENV_DAEMON_DIR] !== this.daemonDir;\n }\n this.idslib.addFact(\"noop_mode\", this.noopMode);\n\n this.idslib.stapleFile(\n \"daemon.log\",\n path.join(this.daemonDir, \"daemon.log\"),\n );\n }\n\n async setUpAutoCache(): Promise {\n const requiredEnv = [\n \"ACTIONS_CACHE_URL\",\n \"ACTIONS_RUNTIME_URL\",\n \"ACTIONS_RUNTIME_TOKEN\",\n ];\n\n let anyMissing = false;\n for (const n of requiredEnv) {\n if (!process.env.hasOwnProperty(n)) {\n anyMissing = true;\n actionsCore.warning(\n `Disabling automatic caching since required environment ${n} isn't available`,\n );\n }\n }\n\n this.idslib.addFact(\"authenticated_env\", !anyMissing);\n if (anyMissing) {\n return;\n }\n\n if (this.daemonStarted) {\n actionsCore.debug(\"Already started.\");\n return;\n }\n\n actionsCore.debug(\n `GitHub Action Cache URL: ${process.env[\"ACTIONS_CACHE_URL\"]}`,\n );\n\n const sourceBinary = inputs.getStringOrNull(\"source-binary\");\n const daemonBin =\n sourceBinary !== null ? sourceBinary : await this.fetchAutoCacher();\n\n let runEnv;\n if (actionsCore.isDebug()) {\n runEnv = {\n RUST_LOG: \"trace,magic_nix_cache=debug,gha_cache=debug\",\n RUST_BACKTRACE: \"full\",\n ...process.env,\n };\n } else {\n runEnv = process.env;\n }\n\n const notifyPort = inputs.getString(\"startup-notification-port\");\n\n const notifyPromise = new Promise>((resolveListening) => {\n const promise = new Promise(async (resolveQuit) => {\n const notifyServer = http.createServer((req, res) => {\n if (req.method === \"POST\" && req.url === \"/\") {\n actionsCore.debug(`Notify server shutting down.`);\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(\"{}\");\n notifyServer.close(() => {\n resolveQuit();\n });\n }\n });\n\n notifyServer.listen(notifyPort, () => {\n actionsCore.debug(`Notify server running.`);\n resolveListening(promise);\n });\n });\n });\n\n // Start tailing the daemon log.\n const outputPath = `${this.daemonDir}/daemon.log`;\n const output = openSync(outputPath, \"a\");\n const log = tailLog(this.daemonDir);\n const netrc = await netrcPath();\n const nixConfPath = `${process.env[\"HOME\"]}/.config/nix/nix.conf`;\n\n const hostAndPort = inputs.getString(\"listen\");\n const upstreamCache = inputs.getString(\"upstream-cache\");\n const diagnosticEndpoint = inputs.getString(\"diagnostic-endpoint\");\n const useFlakeHub = inputs.getBool(\"use-flakehub\");\n const flakeHubCacheServer = inputs.getString(\"flakehub-cache-server\");\n const flakeHubApiServer = inputs.getString(\"flakehub-api-server\");\n const flakeHubFlakeName = inputs.getString(\"flakehub-flake-name\");\n const useGhaCache = inputs.getBool(\"use-gha-cache\");\n\n const daemonCliFlags: string[] = [\n \"--startup-notification-url\",\n `http://127.0.0.1:${notifyPort}`,\n \"--listen\",\n hostAndPort,\n \"--upstream\",\n upstreamCache,\n \"--diagnostic-endpoint\",\n diagnosticEndpoint,\n \"--nix-conf\",\n nixConfPath,\n ]\n .concat(\n useFlakeHub\n ? [\n \"--use-flakehub\",\n \"--flakehub-cache-server\",\n flakeHubCacheServer,\n \"--flakehub-api-server\",\n flakeHubApiServer,\n \"--flakehub-api-server-netrc\",\n netrc,\n \"--flakehub-flake-name\",\n flakeHubFlakeName,\n ]\n : [],\n )\n .concat(useGhaCache ? [\"--use-gha-cache\"] : []);\n\n const opts: SpawnOptions = {\n stdio: [\"ignore\", output, output],\n env: runEnv,\n detached: true,\n };\n\n // Display the final command for debugging purposes\n actionsCore.debug(\"Full daemon start command:\");\n actionsCore.debug(`${daemonBin} ${daemonCliFlags.join(\" \")}`);\n\n // Start the server. Once it is ready, it will notify us via the notification server.\n const daemon = spawn(daemonBin, daemonCliFlags, opts);\n\n this.daemonStarted = true;\n actionsCore.saveState(STATE_STARTED, STARTED_HINT);\n\n const pidFile = path.join(this.daemonDir, \"daemon.pid\");\n await fs.writeFile(pidFile, `${daemon.pid}`);\n\n actionsCore.info(\"Waiting for magic-nix-cache to start...\");\n\n await new Promise((resolve, reject) => {\n notifyPromise\n // eslint-disable-next-line github/no-then\n .then((_value) => {\n resolve();\n })\n // eslint-disable-next-line github/no-then\n .catch((err) => {\n reject(new Error(`error in notifyPromise: ${err}`));\n });\n daemon.on(\"exit\", async (code, signal) => {\n if (signal) {\n reject(new Error(`Daemon was killed by signal ${signal}`));\n } else if (code) {\n reject(new Error(`Daemon exited with code ${code}`));\n } else {\n reject(new Error(`Daemon unexpectedly exited`));\n }\n });\n });\n\n daemon.unref();\n\n actionsCore.info(\"Launched Magic Nix Cache\");\n\n log.unwatch();\n }\n\n private async fetchAutoCacher(): Promise {\n const closurePath = await this.idslib.fetch();\n this.idslib.recordEvent(\"load_closure\");\n const { stdout } = await promisify(exec)(\n `cat \"${closurePath}\" | xz -d | nix-store --import`,\n );\n\n const paths = stdout.split(os.EOL);\n // Since the export is in reverse topologically sorted order, magic-nix-cache is always the penultimate entry in the list (the empty string left by split being the last).\n const lastPath = paths.at(-2);\n return `${lastPath}/bin/magic-nix-cache`;\n }\n\n async notifyAutoCache(): Promise {\n if (!this.daemonStarted) {\n actionsCore.debug(\"magic-nix-cache not started - Skipping\");\n return;\n }\n\n try {\n actionsCore.debug(`Indicating workflow start`);\n const hostAndPort = inputs.getString(\"listen\");\n const res: Response = await this.client\n .post(`http://${hostAndPort}/api/workflow-start`)\n .json();\n actionsCore.debug(`back from post: ${res}`);\n } catch (e) {\n actionsCore.info(`Error marking the workflow as started:`);\n actionsCore.info(inspect(e));\n actionsCore.info(`Magic Nix Cache may not be running for this workflow.`);\n }\n }\n\n async tearDownAutoCache(): Promise {\n if (!this.daemonStarted) {\n actionsCore.debug(\"magic-nix-cache not started - Skipping\");\n return;\n }\n\n const pidFile = path.join(this.daemonDir, \"daemon.pid\");\n const pid = parseInt(await fs.readFile(pidFile, { encoding: \"ascii\" }));\n actionsCore.debug(`found daemon pid: ${pid}`);\n if (!pid) {\n throw new Error(\"magic-nix-cache did not start successfully\");\n }\n\n const log = tailLog(this.daemonDir);\n\n try {\n actionsCore.debug(`about to post to localhost`);\n const hostAndPort = inputs.getString(\"listen\");\n const res: Response = await this.client\n .post(`http://${hostAndPort}/api/workflow-finish`)\n .json();\n actionsCore.debug(`back from post: ${res}`);\n } finally {\n actionsCore.debug(`unwatching the daemon log`);\n log.unwatch();\n }\n\n actionsCore.debug(`killing`);\n try {\n process.kill(pid, \"SIGTERM\");\n } catch (e) {\n if (typeof e === \"object\" && e && \"code\" in e && e.code !== \"ESRCH\") {\n throw e;\n }\n } finally {\n if (actionsCore.isDebug()) {\n actionsCore.info(\"Entire log:\");\n const entireLog = readFileSync(path.join(this.daemonDir, \"daemon.log\"));\n actionsCore.info(entireLog.toString());\n }\n }\n }\n}\n\nfunction main(): void {\n const cacheAction = new MagicNixCacheAction();\n\n cacheAction.idslib.onMain(async () => {\n if (cacheAction.noopMode) {\n actionsCore.warning(TEXT_NOOP);\n return;\n }\n\n if (cacheAction.idslib.nixStoreTrust === \"untrusted\") {\n actionsCore.warning(TEXT_TRUST_UNTRUSTED);\n return;\n } else if (cacheAction.idslib.nixStoreTrust === \"unknown\") {\n actionsCore.info(TEXT_TRUST_UNKNOWN);\n }\n\n await cacheAction.setUpAutoCache();\n await cacheAction.notifyAutoCache();\n });\n cacheAction.idslib.onPost(async () => {\n if (cacheAction.noopMode) {\n actionsCore.debug(TEXT_NOOP);\n return;\n }\n\n if (cacheAction.idslib.nixStoreTrust === \"untrusted\") {\n actionsCore.debug(TEXT_TRUST_UNTRUSTED);\n return;\n } else if (cacheAction.idslib.nixStoreTrust === \"unknown\") {\n actionsCore.debug(TEXT_TRUST_UNKNOWN);\n }\n\n await cacheAction.tearDownAutoCache();\n });\n\n cacheAction.idslib.execute();\n}\n\nmain();\n"],"mappings":";AAAA,YAAY,iBAAiB;AAC7B,YAAY,QAAQ;AACpB,YAAY,QAAQ;AACpB,OAAO,UAAU;AACjB,SAAS,YAAY;AAEd,SAAS,QAAQ,WAAyB;AAC/C,QAAM,MAAM,IAAI,KAAK,KAAK,KAAK,WAAW,YAAY,CAAC;AACvD,EAAY,kBAAM,uBAAuB;AACzC,MAAI,GAAG,QAAQ,CAAC,SAAS;AACvB,IAAY,iBAAK,IAAI;AAAA,EACvB,CAAC;AACD,SAAO;AACT;AAEA,eAAsB,YAA6B;AACjD,QAAM,oBAAoB,KAAK;AAAA,IAC7B,QAAQ,IAAI,aAAa,KAAQ,UAAO;AAAA,IACxC;AAAA,EACF;AACA,MAAI;AACF,UAAS,UAAO,iBAAiB;AACjC,WAAO;AAAA,EACT,QAAQ;AAEN,UAAM,oBAAoB,KAAK;AAAA,MAC7B,QAAQ,IAAI,aAAa,KAAQ,UAAO;AAAA,MACxC;AAAA,IACF;AACA,QAAI;AACF,YAAM,cAAc,iBAAiB;AAAA,IACvC,SAAS,GAAG;AACV,MAAY,iBAAK,0BAA0B;AAC3C,MAAY,kBAAM,sCAAsC,CAAC,EAAE;AAAA,IAC7D;AACA,WAAO;AAAA,EACT;AACF;AAEA,eAAe,cAAc,OAA8B;AACzD,QAAM,MAAM,MAAkB,uBAAW,kBAAkB;AAE3D,QAAS;AAAA,IACP;AAAA,IACA;AAAA,MACE,oDAAoD,GAAG;AAAA,MACvD,gDAAgD,GAAG;AAAA,MACnD,sDAAsD,GAAG;AAAA,IAC3D,EAAE,KAAK,IAAI;AAAA,EACb;AAEA,EAAY,iBAAK,wBAAwB;AAC3C;;;ACnDA,YAAYA,kBAAiB;AAC7B,SAAS,YAAY,cAAc;AACnC,OAAO,SAAkB;AACzB,YAAY,UAAU;AACtB,SAAuB,MAAM,aAAa;AAC1C,SAAS,WAAW,UAAU,oBAAoB;AAClD,YAAYC,SAAQ;AACpB,YAAYC,SAAQ;AACpB,YAAYC,WAAU;AACtB,SAAS,SAAS,iBAAiB;AAKnC,IAAM,iBAAiB;AAEvB,IAAM,kBAAkB;AACxB,IAAM,gBAAgB;AACtB,IAAM,eAAe;AAErB,IAAM,YACJ;AACF,IAAM,uBACJ;AACF,IAAM,qBACJ;AAEF,IAAM,sBAAN,MAA0B;AAAA,EAQxB,cAAc;AACZ,SAAK,SAAS,IAAI,WAAW;AAAA,MAC3B,MAAM;AAAA,MACN,YAAY;AAAA,MACZ,gBAAgB;AAAA,MAChB,YAAY;AAAA,IACd,CAAC;AAED,SAAK,SAAS,IAAI,OAAO;AAAA,MACvB,OAAO;AAAA,QACL,OAAO;AAAA,QACP,SAAS,CAAC,QAAQ,OAAO,OAAO,QAAQ,UAAU,WAAW,OAAO;AAAA,MACtE;AAAA,MACA,OAAO;AAAA,QACL,aAAa;AAAA,UACX,CAAC,OAAO,eAAe;AACrB,YAAY;AAAA,cACV,wBAAwB,MAAM,IAAI,cAAc,UAAU;AAAA,YAC5D;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,IACF,CAAC;AAED,SAAK,gBAA4B,sBAAS,aAAa,MAAM;AAE7D,QAAgB,sBAAS,eAAe,MAAM,IAAI;AAChD,WAAK,YAAwB,sBAAS,eAAe;AAAA,IACvD,OAAO;AACL,WAAK,YAAY,KAAK,OAAO,iBAAiB;AAC9C,gBAAU,KAAK,SAAS;AACxB,MAAY,uBAAU,iBAAiB,KAAK,SAAS;AAAA,IACvD;AAEA,QAAI,QAAQ,IAAI,cAAc,MAAM,QAAW;AAC7C,WAAK,WAAW;AAChB,MAAY,4BAAe,gBAAgB,KAAK,SAAS;AAAA,IAC3D,OAAO;AACL,WAAK,WAAW,QAAQ,IAAI,cAAc,MAAM,KAAK;AAAA,IACvD;AACA,SAAK,OAAO,QAAQ,aAAa,KAAK,QAAQ;AAE9C,SAAK,OAAO;AAAA,MACV;AAAA,MACK,WAAK,KAAK,WAAW,YAAY;AAAA,IACxC;AAAA,EACF;AAAA,EAEA,MAAM,iBAAgC;AACpC,UAAM,cAAc;AAAA,MAClB;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAEA,QAAI,aAAa;AACjB,eAAW,KAAK,aAAa;AAC3B,UAAI,CAAC,QAAQ,IAAI,eAAe,CAAC,GAAG;AAClC,qBAAa;AACb,QAAY;AAAA,UACV,0DAA0D,CAAC;AAAA,QAC7D;AAAA,MACF;AAAA,IACF;AAEA,SAAK,OAAO,QAAQ,qBAAqB,CAAC,UAAU;AACpD,QAAI,YAAY;AACd;AAAA,IACF;AAEA,QAAI,KAAK,eAAe;AACtB,MAAY,mBAAM,kBAAkB;AACpC;AAAA,IACF;AAEA,IAAY;AAAA,MACV,4BAA4B,QAAQ,IAAI,mBAAmB,CAAC;AAAA,IAC9D;AAEA,UAAM,eAAe,OAAO,gBAAgB,eAAe;AAC3D,UAAM,YACJ,iBAAiB,OAAO,eAAe,MAAM,KAAK,gBAAgB;AAEpE,QAAI;AACJ,QAAgB,qBAAQ,GAAG;AACzB,eAAS;AAAA,QACP,UAAU;AAAA,QACV,gBAAgB;AAAA,QAChB,GAAG,QAAQ;AAAA,MACb;AAAA,IACF,OAAO;AACL,eAAS,QAAQ;AAAA,IACnB;AAEA,UAAM,aAAa,OAAO,UAAU,2BAA2B;AAE/D,UAAM,gBAAgB,IAAI,QAAuB,CAAC,qBAAqB;AACrE,YAAM,UAAU,IAAI,QAAc,OAAO,gBAAgB;AACvD,cAAM,eAAoB,kBAAa,CAAC,KAAK,QAAQ;AACnD,cAAI,IAAI,WAAW,UAAU,IAAI,QAAQ,KAAK;AAC5C,YAAY,mBAAM,8BAA8B;AAChD,gBAAI,UAAU,KAAK,EAAE,gBAAgB,mBAAmB,CAAC;AACzD,gBAAI,IAAI,IAAI;AACZ,yBAAa,MAAM,MAAM;AACvB,0BAAY;AAAA,YACd,CAAC;AAAA,UACH;AAAA,QACF,CAAC;AAED,qBAAa,OAAO,YAAY,MAAM;AACpC,UAAY,mBAAM,wBAAwB;AAC1C,2BAAiB,OAAO;AAAA,QAC1B,CAAC;AAAA,MACH,CAAC;AAAA,IACH,CAAC;AAGD,UAAM,aAAa,GAAG,KAAK,SAAS;AACpC,UAAM,SAAS,SAAS,YAAY,GAAG;AACvC,UAAM,MAAM,QAAQ,KAAK,SAAS;AAClC,UAAM,QAAQ,MAAM,UAAU;AAC9B,UAAM,cAAc,GAAG,QAAQ,IAAI,MAAM,CAAC;AAE1C,UAAM,cAAc,OAAO,UAAU,QAAQ;AAC7C,UAAM,gBAAgB,OAAO,UAAU,gBAAgB;AACvD,UAAM,qBAAqB,OAAO,UAAU,qBAAqB;AACjE,UAAM,cAAc,OAAO,QAAQ,cAAc;AACjD,UAAM,sBAAsB,OAAO,UAAU,uBAAuB;AACpE,UAAM,oBAAoB,OAAO,UAAU,qBAAqB;AAChE,UAAM,oBAAoB,OAAO,UAAU,qBAAqB;AAChE,UAAM,cAAc,OAAO,QAAQ,eAAe;AAElD,UAAM,iBAA2B;AAAA,MAC/B;AAAA,MACA,oBAAoB,UAAU;AAAA,MAC9B;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,EACG;AAAA,MACC,cACI;AAAA,QACE;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF,IACA,CAAC;AAAA,IACP,EACC,OAAO,cAAc,CAAC,iBAAiB,IAAI,CAAC,CAAC;AAEhD,UAAM,OAAqB;AAAA,MACzB,OAAO,CAAC,UAAU,QAAQ,MAAM;AAAA,MAChC,KAAK;AAAA,MACL,UAAU;AAAA,IACZ;AAGA,IAAY,mBAAM,4BAA4B;AAC9C,IAAY,mBAAM,GAAG,SAAS,IAAI,eAAe,KAAK,GAAG,CAAC,EAAE;AAG5D,UAAM,SAAS,MAAM,WAAW,gBAAgB,IAAI;AAEpD,SAAK,gBAAgB;AACrB,IAAY,uBAAU,eAAe,YAAY;AAEjD,UAAM,UAAe,WAAK,KAAK,WAAW,YAAY;AACtD,UAAS,cAAU,SAAS,GAAG,OAAO,GAAG,EAAE;AAE3C,IAAY,kBAAK,yCAAyC;AAE1D,UAAM,IAAI,QAAc,CAAC,SAAS,WAAW;AAC3C,oBAEG,KAAK,CAAC,WAAW;AAChB,gBAAQ;AAAA,MACV,CAAC,EAEA,MAAM,CAAC,QAAQ;AACd,eAAO,IAAI,MAAM,2BAA2B,GAAG,EAAE,CAAC;AAAA,MACpD,CAAC;AACH,aAAO,GAAG,QAAQ,OAAO,MAAM,WAAW;AACxC,YAAI,QAAQ;AACV,iBAAO,IAAI,MAAM,+BAA+B,MAAM,EAAE,CAAC;AAAA,QAC3D,WAAW,MAAM;AACf,iBAAO,IAAI,MAAM,2BAA2B,IAAI,EAAE,CAAC;AAAA,QACrD,OAAO;AACL,iBAAO,IAAI,MAAM,4BAA4B,CAAC;AAAA,QAChD;AAAA,MACF,CAAC;AAAA,IACH,CAAC;AAED,WAAO,MAAM;AAEb,IAAY,kBAAK,0BAA0B;AAE3C,QAAI,QAAQ;AAAA,EACd;AAAA,EAEA,MAAc,kBAAmC;AAC/C,UAAM,cAAc,MAAM,KAAK,OAAO,MAAM;AAC5C,SAAK,OAAO,YAAY,cAAc;AACtC,UAAM,EAAE,OAAO,IAAI,MAAM,UAAU,IAAI;AAAA,MACrC,QAAQ,WAAW;AAAA,IACrB;AAEA,UAAM,QAAQ,OAAO,MAAS,OAAG;AAEjC,UAAM,WAAW,MAAM,GAAG,EAAE;AAC5B,WAAO,GAAG,QAAQ;AAAA,EACpB;AAAA,EAEA,MAAM,kBAAiC;AACrC,QAAI,CAAC,KAAK,eAAe;AACvB,MAAY,mBAAM,wCAAwC;AAC1D;AAAA,IACF;AAEA,QAAI;AACF,MAAY,mBAAM,2BAA2B;AAC7C,YAAM,cAAc,OAAO,UAAU,QAAQ;AAC7C,YAAM,MAAgB,MAAM,KAAK,OAC9B,KAAK,UAAU,WAAW,qBAAqB,EAC/C,KAAK;AACR,MAAY,mBAAM,mBAAmB,GAAG,EAAE;AAAA,IAC5C,SAAS,GAAG;AACV,MAAY,kBAAK,wCAAwC;AACzD,MAAY,kBAAK,QAAQ,CAAC,CAAC;AAC3B,MAAY,kBAAK,uDAAuD;AAAA,IAC1E;AAAA,EACF;AAAA,EAEA,MAAM,oBAAmC;AACvC,QAAI,CAAC,KAAK,eAAe;AACvB,MAAY,mBAAM,wCAAwC;AAC1D;AAAA,IACF;AAEA,UAAM,UAAe,WAAK,KAAK,WAAW,YAAY;AACtD,UAAM,MAAM,SAAS,MAAS,aAAS,SAAS,EAAE,UAAU,QAAQ,CAAC,CAAC;AACtE,IAAY,mBAAM,qBAAqB,GAAG,EAAE;AAC5C,QAAI,CAAC,KAAK;AACR,YAAM,IAAI,MAAM,4CAA4C;AAAA,IAC9D;AAEA,UAAM,MAAM,QAAQ,KAAK,SAAS;AAElC,QAAI;AACF,MAAY,mBAAM,4BAA4B;AAC9C,YAAM,cAAc,OAAO,UAAU,QAAQ;AAC7C,YAAM,MAAgB,MAAM,KAAK,OAC9B,KAAK,UAAU,WAAW,sBAAsB,EAChD,KAAK;AACR,MAAY,mBAAM,mBAAmB,GAAG,EAAE;AAAA,IAC5C,UAAE;AACA,MAAY,mBAAM,2BAA2B;AAC7C,UAAI,QAAQ;AAAA,IACd;AAEA,IAAY,mBAAM,SAAS;AAC3B,QAAI;AACF,cAAQ,KAAK,KAAK,SAAS;AAAA,IAC7B,SAAS,GAAG;AACV,UAAI,OAAO,MAAM,YAAY,KAAK,UAAU,KAAK,EAAE,SAAS,SAAS;AACnE,cAAM;AAAA,MACR;AAAA,IACF,UAAE;AACA,UAAgB,qBAAQ,GAAG;AACzB,QAAY,kBAAK,aAAa;AAC9B,cAAM,YAAY,aAAkB,WAAK,KAAK,WAAW,YAAY,CAAC;AACtE,QAAY,kBAAK,UAAU,SAAS,CAAC;AAAA,MACvC;AAAA,IACF;AAAA,EACF;AACF;AAEA,SAAS,OAAa;AACpB,QAAM,cAAc,IAAI,oBAAoB;AAE5C,cAAY,OAAO,OAAO,YAAY;AACpC,QAAI,YAAY,UAAU;AACxB,MAAY,qBAAQ,SAAS;AAC7B;AAAA,IACF;AAEA,QAAI,YAAY,OAAO,kBAAkB,aAAa;AACpD,MAAY,qBAAQ,oBAAoB;AACxC;AAAA,IACF,WAAW,YAAY,OAAO,kBAAkB,WAAW;AACzD,MAAY,kBAAK,kBAAkB;AAAA,IACrC;AAEA,UAAM,YAAY,eAAe;AACjC,UAAM,YAAY,gBAAgB;AAAA,EACpC,CAAC;AACD,cAAY,OAAO,OAAO,YAAY;AACpC,QAAI,YAAY,UAAU;AACxB,MAAY,mBAAM,SAAS;AAC3B;AAAA,IACF;AAEA,QAAI,YAAY,OAAO,kBAAkB,aAAa;AACpD,MAAY,mBAAM,oBAAoB;AACtC;AAAA,IACF,WAAW,YAAY,OAAO,kBAAkB,WAAW;AACzD,MAAY,mBAAM,kBAAkB;AAAA,IACtC;AAEA,UAAM,YAAY,kBAAkB;AAAA,EACtC,CAAC;AAED,cAAY,OAAO,QAAQ;AAC7B;AAEA,KAAK;","names":["actionsCore","fs","os","path"]} \ No newline at end of file diff --git a/package.json b/package.json index 205b74d..160c6dd 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,7 @@ "dependencies": { "@actions/core": "^1.10.1", "@actions/exec": "^1.1.1", - "detsys-ts": "github:DeterminateSystems/detsys-ts", + "detsys-ts": "github:DeterminateSystems/detsys-ts#store-trust", "got": "^14.2.1", "tail": "^2.2.6" }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 1737513..7e7c001 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -12,8 +12,8 @@ dependencies: specifier: ^1.1.1 version: 1.1.1 detsys-ts: - specifier: github:DeterminateSystems/detsys-ts - version: github.com/DeterminateSystems/detsys-ts/2391ba1ef3d22027cd4d9ecce147007a88f63643 + specifier: github:DeterminateSystems/detsys-ts#store-trust + version: github.com/DeterminateSystems/detsys-ts/c1c2371f083f911beb01d75e4d194df0e8cd4416 got: specifier: ^14.2.1 version: 14.2.1 @@ -1275,7 +1275,7 @@ packages: hasBin: true dependencies: caniuse-lite: 1.0.30001617 - electron-to-chromium: 1.4.761 + electron-to-chromium: 1.4.763 node-releases: 2.0.14 update-browserslist-db: 1.0.15(browserslist@4.23.0) dev: true @@ -1533,8 +1533,8 @@ packages: resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} dev: true - /electron-to-chromium@1.4.761: - resolution: {integrity: sha512-PIbxpiJGx6Bb8dQaonNc6CGTRlVntdLg/2nMa1YhnrwYOORY9a3ZgGN0UQYE6lAcj/lkyduJN7BPt/JiY+jAQQ==} + /electron-to-chromium@1.4.763: + resolution: {integrity: sha512-k4J8NrtJ9QrvHLRo8Q18OncqBCB7tIUyqxRcJnlonQ0ioHKYB988GcDFF3ZePmnb8eHEopDs/wPHR/iGAFgoUQ==} dev: true /emoji-regex@8.0.0: @@ -3818,8 +3818,8 @@ packages: engines: {node: '>=10'} dev: true - github.com/DeterminateSystems/detsys-ts/2391ba1ef3d22027cd4d9ecce147007a88f63643: - resolution: {tarball: https://codeload.github.com/DeterminateSystems/detsys-ts/tar.gz/2391ba1ef3d22027cd4d9ecce147007a88f63643} + github.com/DeterminateSystems/detsys-ts/c1c2371f083f911beb01d75e4d194df0e8cd4416: + resolution: {tarball: https://codeload.github.com/DeterminateSystems/detsys-ts/tar.gz/c1c2371f083f911beb01d75e4d194df0e8cd4416} name: detsys-ts version: 1.0.0 dependencies: diff --git a/src/index.ts b/src/index.ts index 4801010..da4c4a3 100644 --- a/src/index.ts +++ b/src/index.ts @@ -19,8 +19,12 @@ const STATE_DAEMONDIR = "MAGIC_NIX_CACHE_DAEMONDIR"; const STATE_STARTED = "MAGIC_NIX_CACHE_STARTED"; const STARTED_HINT = "true"; -const NOOP_TEXT = +const TEXT_NOOP = "Magic Nix Cache is already running, this workflow job is in noop mode. Is the Magic Nix Cache in the workflow twice?"; +const TEXT_TRUST_UNTRUSTED = + "The Nix daemon does not consider the user running this workflow to be trusted. Magic Nix Cache is disabled."; +const TEXT_TRUST_UNKNOWN = + "The Nix daemon may not consider the user running this workflow to be trusted. Magic Nix Cache may not start correctly."; class MagicNixCacheAction { idslib: IdsToolbox; @@ -322,19 +326,33 @@ function main(): void { cacheAction.idslib.onMain(async () => { if (cacheAction.noopMode) { - actionsCore.warning(NOOP_TEXT); + actionsCore.warning(TEXT_NOOP); return; } + if (cacheAction.idslib.nixStoreTrust === "untrusted") { + actionsCore.warning(TEXT_TRUST_UNTRUSTED); + return; + } else if (cacheAction.idslib.nixStoreTrust === "unknown") { + actionsCore.info(TEXT_TRUST_UNKNOWN); + } + await cacheAction.setUpAutoCache(); await cacheAction.notifyAutoCache(); }); cacheAction.idslib.onPost(async () => { if (cacheAction.noopMode) { - actionsCore.debug(NOOP_TEXT); + actionsCore.debug(TEXT_NOOP); return; } + if (cacheAction.idslib.nixStoreTrust === "untrusted") { + actionsCore.debug(TEXT_TRUST_UNTRUSTED); + return; + } else if (cacheAction.idslib.nixStoreTrust === "unknown") { + actionsCore.debug(TEXT_TRUST_UNKNOWN); + } + await cacheAction.tearDownAutoCache(); });