Skip to content

Commit

Permalink
Create codeql.yml
Browse files Browse the repository at this point in the history
  • Loading branch information
baileympearson committed May 21, 2024
1 parent 9f47b12 commit 6254a4c
Show file tree
Hide file tree
Showing 2 changed files with 220 additions and 0 deletions.
95 changes: 95 additions & 0 deletions .github/workflows/codeql.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
# For most projects, this workflow file will not need changing; you simply need
# to commit it to your repository.
#
# You may wish to alter this file to override the set of languages analyzed,
# or to provide custom queries or build logic.
#
# ******** NOTE ********
# We have attempted to detect the languages in your repository. Please check
# the `language` matrix defined below to confirm you have the correct set of
# supported CodeQL languages.
#
name: "CodeQL"

on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]
schedule:
- cron: '15 14 * * 6'

jobs:
analyze:
name: Analyze (${{ matrix.language }})
# Runner size impacts CodeQL analysis time. To learn more, please see:
# - https://gh.io/recommended-hardware-resources-for-running-codeql
# - https://gh.io/supported-runners-and-hardware-resources
# - https://gh.io/using-larger-runners (GitHub.com only)
# Consider using larger runners or machines with greater resources for possible analysis time improvements.
runs-on: ${{ (matrix.language == 'swift' && 'macos-latest') || 'ubuntu-latest' }}
timeout-minutes: ${{ (matrix.language == 'swift' && 120) || 360 }}
permissions:
# required for all workflows
security-events: write

# required to fetch internal or private CodeQL packs
packages: read

# only required for workflows in private repositories
actions: read
contents: read

strategy:
fail-fast: false
matrix:
include:
- language: 'c-cpp'
build-mode: 'manual'
sourceDirectory: './addon'
- language: 'javascript-typescript'
build-mode: 'none'
sourceDirectory: "./src"
# CodeQL supports the following values keywords for 'language': 'c-cpp', 'csharp', 'go', 'java-kotlin', 'javascript-typescript', 'python', 'ruby', 'swift'
# Use `c-cpp` to analyze code written in C, C++ or both
# Use 'java-kotlin' to analyze code written in Java, Kotlin or both
# Use 'javascript-typescript' to analyze code written in JavaScript, TypeScript or both
# To learn more about changing the languages that are analyzed or customizing the build mode for your analysis,
# see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/customizing-your-advanced-setup-for-code-scanning.
# If you are analyzing a compiled language, you can modify the 'build-mode' for that language to customize how
# your codebase is analyzed, see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/codeql-code-scanning-for-compiled-languages
steps:
- name: Checkout repository
uses: actions/checkout@v4

# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v3
with:
languages: ${{ matrix.language }}
build-mode: ${{ matrix.build-mode }}
source-root: ${{ matrix.sourceDirectory }}
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.

# For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
# queries: security-extended,security-and-quality

# If the analyze step fails for one of the languages you are analyzing with
# "We were unable to automatically build your code", modify the matrix above
# to set the build mode to "manual" for that language. Then modify this step
# to build your code.
# ℹ️ Command-line programs to run using the OS shell.
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
- if: matrix.build-mode == 'manual'
shell: bash
run: |
npm install
node ./github/workflows/libmongocrypt.mjs
npm run prebuild
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3
with:
category: "/language:${{matrix.language}}"
125 changes: 125 additions & 0 deletions build.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
import util from 'node:util';
import process from 'node:process';
import fs from 'node:fs/promises';
import child_process from 'node:child_process';
import events from 'node:events';
import path from 'node:path';

async function parseArguments() {
const jsonImport = { [process.version.split('.').at(0) === 'v16' ? 'assert' : 'with']: { type: 'json' } };
const pkg = (await import('./package.json', jsonImport)).default;
const libmongocryptVersion = pkg['mongodb:libmongocrypt'];

const options = {
url: { short: 'u', type: 'string', default: 'https://github.com/mongodb/libmongocrypt.git' },
libversion: { short: 'l', type: 'string', default: libmongocryptVersion },
clean: { short: 'c', type: 'boolean' },
help: { short: 'h', type: 'boolean' }
};

const args = util.parseArgs({ args: process.argv.slice(2), options, allowPositionals: false });

if (args.values.help) {
console.log(
`${process.argv[1]} ${[...Object.keys(options)]
.filter(k => k !== 'help')
.map(k => `[--${k}=${options[k].type}]`)
.join(' ')}`
);
process.exit(0);
}

return {
libmongocrypt: { url: args.values.url, ref: args.values.libversion },
clean: args.values.clean
};
}

/** `xtrace` style command runner, uses spawn so that stdio is inherited */
async function run(command, args = [], options = {}) {
console.error(`+ ${command} ${args.join(' ')}`, options.cwd ? `(in: ${options.cwd})` : '');
await events.once(child_process.spawn(command, args, { stdio: 'inherit', ...options }), 'exit');
}

/** CLI flag maker: `toFlags({a: 1, b: 2})` yields `['-a=1', '-b=2']` */
function toFlags(object) {
return Array.from(Object.entries(object)).map(([k, v]) => `-${k}=${v}`);
}

const args = await parseArguments();
const libmongocryptRoot = path.resolve('_libmongocrypt');

const currentLibMongoCryptBranch = await fs.readFile(path.join(libmongocryptRoot, '.git', 'HEAD'), 'utf8').catch(() => '')
const libmongocryptAlreadyClonedAndCheckedOut = currentLibMongoCryptBranch.trim().endsWith(`r-${args.libmongocrypt.ref}`);

if (!args.clean && !libmongocryptAlreadyClonedAndCheckedOut) {
console.error('fetching libmongocrypt...', args.libmongocrypt);
await fs.rm(libmongocryptRoot, { recursive: true, force: true });
await run('git', ['clone', args.libmongocrypt.url, libmongocryptRoot]);
await run('git', ['fetch', '--tags'], { cwd: libmongocryptRoot });
await run('git', ['checkout', args.libmongocrypt.ref, '-b', `r-${args.libmongocrypt.ref}`], { cwd: libmongocryptRoot });
} else {
console.error('libmongocrypt already up to date...', args.libmongocrypt);
}

const libmongocryptBuiltVersion = await fs.readFile(path.join(libmongocryptRoot, 'VERSION_CURRENT'), 'utf8').catch(() => '');
const libmongocryptAlreadyBuilt = libmongocryptBuiltVersion.trim() === args.libmongocrypt.ref;

if (!args.clean && !libmongocryptAlreadyBuilt) {
console.error('building libmongocrypt...\n', args);

const nodeDepsRoot = path.resolve('deps');
const nodeBuildRoot = path.resolve(nodeDepsRoot, 'tmp', 'libmongocrypt-build');

await fs.rm(nodeBuildRoot, { recursive: true, force: true });
await fs.mkdir(nodeBuildRoot, { recursive: true });

const CMAKE_FLAGS = toFlags({
/**
* We provide crypto hooks from Node.js binding to openssl (so disable system crypto)
* TODO: NODE-5455
*
* One thing that is not obvious from the build instructions for libmongocrypt
* and the Node.js bindings is that the Node.js driver uses libmongocrypt in
* DISABLE_NATIVE_CRYPTO aka nocrypto mode, that is, instead of using native
* system libraries for crypto operations, it provides callbacks to libmongocrypt
* which, in the Node.js addon case, call JS functions that in turn call built-in
* Node.js crypto methods.
*
* That’s way more convoluted than it needs to be, considering that we always
* have a copy of OpenSSL available directly, but for now it seems to make sense
* to stick with what the Node.js addon does here.
*/
DDISABLE_NATIVE_CRYPTO: '1',
/** A consistent name for the output "library" directory */
DCMAKE_INSTALL_LIBDIR: 'lib',
/** No warnings allowed */
DENABLE_MORE_WARNINGS_AS_ERRORS: 'ON',
/** Where to build libmongocrypt */
DCMAKE_PREFIX_PATH: nodeDepsRoot,
/**
* Where to install libmongocrypt
* Note that `binding.gyp` will set `./deps/include`
* as an include path if BUILD_TYPE=static
*/
DCMAKE_INSTALL_PREFIX: nodeDepsRoot
});

const WINDOWS_CMAKE_FLAGS =
process.platform === 'win32' // Windows is still called "win32" when it is 64-bit
? toFlags({ Thost: 'x64', A: 'x64', DENABLE_WINDOWS_STATIC_RUNTIME: 'ON' })
: [];

const MACOS_CMAKE_FLAGS =
process.platform === 'darwin' // The minimum macos target version we want for
? toFlags({ DCMAKE_OSX_DEPLOYMENT_TARGET: '10.12' })
: [];

await run('cmake', [...CMAKE_FLAGS, ...WINDOWS_CMAKE_FLAGS, ...MACOS_CMAKE_FLAGS, libmongocryptRoot], { cwd: nodeBuildRoot });
await run('cmake', ['--build', '.', '--target', 'install', '--config', 'RelWithDebInfo'], { cwd: nodeBuildRoot });
} else {
console.error('libmongocrypt already built...');
}

await run('npm', ['install', '--ignore-scripts']);
await run('npm', ['run', 'rebuild'], { env: { ...process.env, BUILD_TYPE: 'static' } });

0 comments on commit 6254a4c

Please sign in to comment.