diff --git a/package-lock.json b/package-lock.json index bd8a64af6..b1e2b383f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,13 +10,13 @@ "license": "MIT", "dependencies": { "@babel/parser": "7.16.8", + "@netlify/binary-info": "^1.0.0", "@netlify/esbuild": "0.14.25", "@vercel/nft": "^0.20.0", "archiver": "^5.3.0", "common-path-prefix": "^3.0.0", "cp-file": "^9.0.0", "del": "^6.0.0", - "elf-cam": "^0.1.1", "end-of-stream": "^1.4.4", "es-module-lexer": "^0.10.0", "execa": "^5.0.0", @@ -1077,6 +1077,11 @@ "node": ">=4" } }, + "node_modules/@netlify/binary-info": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@netlify/binary-info/-/binary-info-1.0.0.tgz", + "integrity": "sha512-4wMPu9iN3/HL97QblBsBay3E1etIciR84izI3U+4iALY+JHCrI+a2jO0qbAZ/nxKoegypYEaiiqWXylm+/zfrw==" + }, "node_modules/@netlify/esbuild": { "version": "0.14.25", "resolved": "https://registry.npmjs.org/@netlify/esbuild/-/esbuild-0.14.25.tgz", @@ -4557,11 +4562,6 @@ "integrity": "sha512-FYPir3NSBEGexSZUEeht81oVhHfLFl6mhUKSkjHN/iB/TwEIt/WHQrqVGfTLN5gQxwJCQkIJBe05eOXjI7omgg==", "dev": true }, - "node_modules/elf-cam": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/elf-cam/-/elf-cam-0.1.1.tgz", - "integrity": "sha512-tKSFTWOp5OwJSp6MKyQDX7umYDkvUuI8rxHXw8BuUQ63d9Trj9xLeo6SHyoTGSoZNNZVitFa+RuHHXuoAzN3Rw==" - }, "node_modules/emittery": { "version": "0.11.0", "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.11.0.tgz", @@ -12685,6 +12685,11 @@ "glob-to-regexp": "^0.3.0" } }, + "@netlify/binary-info": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@netlify/binary-info/-/binary-info-1.0.0.tgz", + "integrity": "sha512-4wMPu9iN3/HL97QblBsBay3E1etIciR84izI3U+4iALY+JHCrI+a2jO0qbAZ/nxKoegypYEaiiqWXylm+/zfrw==" + }, "@netlify/esbuild": { "version": "0.14.25", "resolved": "https://registry.npmjs.org/@netlify/esbuild/-/esbuild-0.14.25.tgz", @@ -15175,11 +15180,6 @@ "integrity": "sha512-FYPir3NSBEGexSZUEeht81oVhHfLFl6mhUKSkjHN/iB/TwEIt/WHQrqVGfTLN5gQxwJCQkIJBe05eOXjI7omgg==", "dev": true }, - "elf-cam": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/elf-cam/-/elf-cam-0.1.1.tgz", - "integrity": "sha512-tKSFTWOp5OwJSp6MKyQDX7umYDkvUuI8rxHXw8BuUQ63d9Trj9xLeo6SHyoTGSoZNNZVitFa+RuHHXuoAzN3Rw==" - }, "emittery": { "version": "0.11.0", "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.11.0.tgz", diff --git a/package.json b/package.json index af2d12dc1..c5010b941 100644 --- a/package.json +++ b/package.json @@ -53,13 +53,13 @@ }, "dependencies": { "@babel/parser": "7.16.8", + "@netlify/binary-info": "^1.0.0", "@netlify/esbuild": "0.14.25", "@vercel/nft": "^0.20.0", "archiver": "^5.3.0", "common-path-prefix": "^3.0.0", "cp-file": "^9.0.0", "del": "^6.0.0", - "elf-cam": "^0.1.1", "end-of-stream": "^1.4.4", "es-module-lexer": "^0.10.0", "execa": "^5.0.0", diff --git a/src/bin.ts b/src/bin.ts index 0306a7c75..8b9113ec3 100755 --- a/src/bin.ts +++ b/src/bin.ts @@ -7,6 +7,11 @@ import { hideBin } from 'yargs/helpers' import type { ArchiveFormat } from './archive.js' import { zipFunctions } from './main.js' +declare global { + // eslint-disable-next-line no-var + var ZISI_CLI: boolean +} + // CLI entry point const runCli = async function () { // @ts-expect-error TODO: `destFolder` and `srcFolder` are not being passed @@ -14,6 +19,7 @@ const runCli = async function () { const { destFolder, srcFolder, ...options } = parseArgs() try { + global.ZISI_CLI = true // @ts-expect-error TODO: `options` is not getting the right types. const zipped = await zipFunctions(srcFolder, destFolder, options) diff --git a/src/runtimes/detect_runtime.ts b/src/runtimes/detect_runtime.ts index bf3bc6cd0..f50738105 100644 --- a/src/runtimes/detect_runtime.ts +++ b/src/runtimes/detect_runtime.ts @@ -1,11 +1,25 @@ import type { Buffer } from 'buffer' -import { detect, Runtime } from 'elf-cam' +import { detect, Runtime, Arch, Platform, BinaryInfo } from '@netlify/binary-info' import { cachedReadFile, FsCache } from '../utils/fs.js' import type { RuntimeName } from './runtime.js' +const isValidFunctionBinary = (info: BinaryInfo) => info.arch === Arch.Amd64 && info.platform === Platform.Linux + +const warnIncompatibleBinary = function (path: string, binaryInfo: BinaryInfo): undefined { + if (!global.ZISI_CLI) { + console.warn(` +Found incompatible prebuilt function binary in ${path}. +The binary needs to be built for Linux/Amd64, but it was built for ${Platform[binaryInfo.platform]}/${ + Arch[binaryInfo.arch] + }`) + } + + return undefined +} + // Try to guess the runtime by inspecting the binary file. export const detectBinaryRuntime = async function ({ fsCache, @@ -20,9 +34,13 @@ export const detectBinaryRuntime = async function ({ // We're using the Type Assertion because the `cachedReadFile` abstraction // loses part of the return type information. We can safely say it's a // Buffer in this case because we're not specifying an encoding. - const binaryType = detect(buffer as Buffer) + const binaryInfo = detect(buffer as Buffer) + + if (!isValidFunctionBinary(binaryInfo)) { + return warnIncompatibleBinary(path, binaryInfo) + } - switch (binaryType) { + switch (binaryInfo.runtime) { case Runtime.Go: return 'go' case Runtime.Rust: @@ -30,5 +48,7 @@ export const detectBinaryRuntime = async function ({ default: return undefined } - } catch {} + } catch { + // Possible errors are: non binary files, arch/platforms not supported by binary-info, path is directory + } } diff --git a/tests/fixtures/wrong-prebuilt-architecture/go-arm64 b/tests/fixtures/wrong-prebuilt-architecture/go-arm64 new file mode 100755 index 000000000..91de1cd1d Binary files /dev/null and b/tests/fixtures/wrong-prebuilt-architecture/go-arm64 differ diff --git a/tests/main.js b/tests/main.js index fe604ad47..58a1b5503 100644 --- a/tests/main.js +++ b/tests/main.js @@ -2708,3 +2708,14 @@ test('listFunctionsFiles includes in-source config declarations', async (t) => { t.is(func.schedule, '@daily') }) }) + +test('listFunctionsFiles does not include wrong arch functions and warns', async (t) => { + sinon.spy(console, 'warn') + const functions = await listFunctionsFiles(join(FIXTURES_DIR, 'wrong-prebuilt-architecture')) + + t.is(functions.length, 0) + t.is(console.warn.called, true) + t.is(console.warn.calledWith(sinon.match(/Darwin\/Arm64/)), true) + + console.warn.restore() +})