Skip to content

Add code signature validation when installing or updating Azure Functions Core Tools#5126

Open
MicroFish91 wants to merge 36 commits into
mainfrom
mwf/verify-func-cli
Open

Add code signature validation when installing or updating Azure Functions Core Tools#5126
MicroFish91 wants to merge 36 commits into
mainfrom
mwf/verify-func-cli

Conversation

@MicroFish91

@MicroFish91 MicroFish91 commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

Add code signature verification that now runs automatically whenever we install / update func core tools.

Code signature verification references used:

Verified tests on both windows and mac.

@MicroFish91 MicroFish91 requested a review from a team as a code owner July 2, 2026 21:41
Copilot AI review requested due to automatic review settings July 2, 2026 21:41
@MicroFish91 MicroFish91 marked this pull request as draft July 2, 2026 21:41

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds post-install/update validation of Azure Functions Core Tools binaries by verifying platform-specific code signatures (Windows Authenticode, macOS codesign), and introduces tests (including a nightly suite) to ensure signature validation behaves correctly.

Changes:

  • Run code signature validation after Core Tools install/update flows (npm + Homebrew), with a user prompt on signature failure.
  • Add helpers for locating the actual func binary path (including Windows npm shim fallback) and for checking whether signatures are expected for a given platform/version.
  • Add unit tests plus a nightly test suite that downloads Core Tools from the official CLI feed to validate signatures and detect tampering.

Reviewed changes

Copilot reviewed 14 out of 14 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
test/parseFuncCoreToolsPath.test.ts Unit tests for resolving the func executable path from which/where output.
test/nightly/validateFuncCoreToolsCodeSignature/validateFuncCoreToolsCodeSignature.test.ts Nightly validation of real Core Tools binaries’ signatures and tamper detection.
test/nightly/validateFuncCoreToolsCodeSignature/downloadFuncCoreToolsVersions.ts Downloads/extracts Core Tools zips from the official feed for nightly tests.
test/isCodeSignatureExpected.test.ts Unit tests for platform/version signing expectations.
src/utils/cliFeedUtils.ts Exposes CLI feed URL/types needed to resolve Core Tools download links.
src/funcCoreTools/validateFuncCoreToolsCodeSignature.ts Implements signature validation logic and path resolution.
src/funcCoreTools/updateFuncCoreTools.ts Runs signature validation after updating Core Tools.
src/funcCoreTools/uninstallFuncCoreTools.ts Switches npm package constant naming used for uninstall.
src/funcCoreTools/installFuncCoreTools.ts Runs signature validation after installing Core Tools; updates npm/brew flows.
src/funcCoreTools/getFuncPackageManagers.ts Updates npm package constant naming used for detection.
src/funcCoreTools/getBrewPackageName.ts Uses a dedicated brew package name constant for brew formula naming.
src/funcCoreTools/ensureBrewTapTrusted.ts Adds a trust prompt + tap/trust commands before brew install/upgrade.
src/constants.ts Splits package name constants by package manager (npm vs brew).
.vscode/settings.json Disables JS debug network view to avoid fetch inspection crashes during large nightly downloads.


const versionsToTest: FuncVersion[] = Object.values(FuncVersion).filter(v => isCodeSignatureExpected(v));

suite.only('validateFuncCoreToolsCodeSignature', function (this: Mocha.Suite): void {

@MicroFish91 MicroFish91 Jul 3, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Todo: remove .only before merge

Comment thread src/funcCoreTools/installFuncCoreTools.ts
Comment thread src/funcCoreTools/updateFuncCoreTools.ts
Comment thread src/funcCoreTools/validateFuncCoreToolsCodeSignature.ts
Comment thread .vscode/settings.json Outdated
@@ -1,4 +1,9 @@
{
// Node 24's experimental network inspection (node:internal/inspector/network_http) is buggy and

@MicroFish91 MicroFish91 Jul 2, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This randomly started happening after an update. Disabling this flag fixed it for me, will double check this again before merging

const funcTap: string = 'azure/functions';

/**
* Prompts the user to trust the "azure/functions" Homebrew tap, then taps and trusts it.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Newer Homebrew behavior that requires the user to trust azure/functions if they haven't done so before. It's a prerequisite to being able to install core tools.

@MicroFish91 MicroFish91 marked this pull request as ready for review July 3, 2026 20:37
Comment on lines +66 to +69
funcLookupOutput = await cpUtils.executeCommand(ext.outputChannel, workspacePath, 'which', composeArgs(withArg('func'))());
break;
case 'win32':
funcLookupOutput = await cpUtils.executeCommand(ext.outputChannel, workspacePath, 'where.exe', composeArgs(withArg('func'))());

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The processutils package already includes the which package, which is a perfect fit for this. Less parsing to do too. I think you can use it indirectly too; IIRC the package exports a getSafeExecPath or similar.

Though, as I think about it, getSafeExecPath may not do anything on Unix. If so, directly using which is fine (but be sure it is declared as a dependency in package.json).

// strings have no backslash escaping; a literal ' is represented by doubling it ('').
const escapedPath = cliPath.replace(/'/g, "''");
const psCommand = `$sig = Get-AuthenticodeSignature '${escapedPath}'; if ($sig.Status -ne 'Valid') { exit 1 }; $sig.SignerCertificate.Subject`;
const signingResult = await cpUtils.tryExecuteCommand(ext.outputChannel, undefined, 'powershell', composeArgs(withArg('-Command', psCommand))());

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

npm has an audit signatures command, not sure if you can scope it to a specific package, but that may be a better option if we know it's installed from NPM (which, I'm not sure we do know)


async function validateDarwinCodeSignature(cliPath: string): Promise<boolean> {
// Verify the signature is valid (i.e. the binary has not been tampered with)
const codeSignResult = await cpUtils.tryExecuteCommand(ext.outputChannel, undefined, 'codesign', composeArgs(withArg('-v', cliPath))());

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CLI path probably needs quoted

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants