diff --git a/.evergreen.yml b/.evergreen.yml index dd83638..6a97e51 100644 --- a/.evergreen.yml +++ b/.evergreen.yml @@ -110,13 +110,13 @@ buildvariants: - check - name: macos_x64_test display_name: 'macOS 11.00 x64' - run_on: macos-1100-gui + run_on: macos-11-gui tasks: - test - test_electron - name: macos_arm64_test display_name: 'macOS 11.00 arm64' - run_on: macos-1100-arm64-gui + run_on: macos-11-arm64-gui tasks: - test - test_electron diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 3f84948..5c3a41e 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -41,7 +41,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL diff --git a/.github/workflows/prepare-release.yml b/.github/workflows/prepare-release.yml index 810398a..ad1a973 100644 --- a/.github/workflows/prepare-release.yml +++ b/.github/workflows/prepare-release.yml @@ -19,6 +19,12 @@ jobs: prepare: runs-on: ubuntu-latest steps: + - uses: mongodb-js/devtools-shared/actions/setup-bot-token@main + id: app-token + with: + app-id: ${{ vars.DEVTOOLS_BOT_APP_ID }} + private-key: ${{ secrets.DEVTOOLS_BOT_PRIVATE_KEY }} + - uses: actions/checkout@v4 - name: Use Node.js 20.x @@ -36,7 +42,7 @@ jobs: with: branch: release/${{ steps.version.outputs.new-version }} title: 'chore: bump version to ${{ steps.version.outputs.new-version }}' - token: ${{ secrets.SVC_DEVTOOLSBOT_TOKEN }} + token: ${{ steps.app-token.outputs.token }} draft: false body: | An automated PR for next release. diff --git a/.github/workflows/publish-release.yml b/.github/workflows/publish-release.yml index 7d23068..604d452 100644 --- a/.github/workflows/publish-release.yml +++ b/.github/workflows/publish-release.yml @@ -11,6 +11,12 @@ jobs: name: Production url: https://www.npmjs.com/package/@mongodb-js/oidc-plugin/v/${{ steps.get-version.outputs.package_version }} steps: + - uses: mongodb-js/devtools-shared/actions/setup-bot-token@main + id: app-token + with: + app-id: ${{ vars.DEVTOOLS_BOT_APP_ID }} + private-key: ${{ secrets.DEVTOOLS_BOT_PRIVATE_KEY }} + - uses: actions/checkout@v4 - name: Use Node.js 20.x @@ -44,7 +50,7 @@ jobs: - name: Merge Pull Request uses: juliangruber/merge-pull-request-action@9234b8714dda9a08f3d1df5b2a6a3abd7b695353 # 1.3.1 with: - github-token: ${{ secrets.SVC_DEVTOOLSBOT_TOKEN }} + github-token: ${{ steps.app-token.outputs.token }} number: ${{ steps.find-pull-request.outputs.number }} method: squash diff --git a/package-lock.json b/package-lock.json index 7aadb7d..c27be8a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@mongodb-js/oidc-plugin", - "version": "1.1.5", + "version": "1.1.6", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@mongodb-js/oidc-plugin", - "version": "1.1.5", + "version": "1.1.6", "license": "Apache-2.0", "dependencies": { "express": "^4.18.2", @@ -36,7 +36,7 @@ "husky": "^8.0.3", "mocha": "^10.2.0", "mongodb": "^6.7.0", - "mongodb-log-writer": "^1.1.5", + "mongodb-log-writer": "^2.1.0", "mongodb-runner": "^5.2.0", "node-fetch": "^3.3.1", "nyc": "^15.1.0", @@ -4800,12 +4800,13 @@ } }, "node_modules/bson": { - "version": "5.5.1", - "resolved": "https://registry.npmjs.org/bson/-/bson-5.5.1.tgz", - "integrity": "sha512-ix0EwukN2EpC0SRWIj/7B5+A6uQMQy6KMREI9qQqvgpkV2frH63T0UDVd1SYedL6dNCmDBYB3QtXi4ISk9YT+g==", + "version": "6.10.1", + "resolved": "https://registry.npmjs.org/bson/-/bson-6.10.1.tgz", + "integrity": "sha512-P92xmHDQjSKPLHqFxefqMxASNq/aWJMEZugpCjf+AF/pgcUpMMQCg7t7+ewko0/u8AapvF3luf/FoehddEK+sA==", "dev": true, + "license": "Apache-2.0", "engines": { - "node": ">=14.20.1" + "node": ">=16.20.1" } }, "node_modules/buffer": { @@ -11104,13 +11105,16 @@ } }, "node_modules/mongodb-log-writer": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/mongodb-log-writer/-/mongodb-log-writer-1.3.0.tgz", - "integrity": "sha512-XFV4tjpZlf9iaHlCFyV49/I2ILeWEbTXJd7Q1gFYXMw07Y9aTp6sDP2tyezMzm5xU0cFwcgRel23pznbJxinkg==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mongodb-log-writer/-/mongodb-log-writer-2.1.0.tgz", + "integrity": "sha512-ZlNts/L9fs6gQNRuqLcB0+yjjfeyapbxjdkDpeb2bEYOUUThG0iOEhzIFejv0g3TX1SSAsdrT2aGYnFqoQILgQ==", "dev": true, + "license": "Apache-2.0", "dependencies": { - "bson": "^4.5.1 || ^5.0.0", "heap-js": "^2.3.0" + }, + "peerDependencies": { + "bson": "6.x" } }, "node_modules/mongodb-runner": { @@ -11138,6 +11142,16 @@ "@types/webidl-conversions": "*" } }, + "node_modules/mongodb-runner/node_modules/bson": { + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/bson/-/bson-5.5.1.tgz", + "integrity": "sha512-ix0EwukN2EpC0SRWIj/7B5+A6uQMQy6KMREI9qQqvgpkV2frH63T0UDVd1SYedL6dNCmDBYB3QtXi4ISk9YT+g==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=14.20.1" + } + }, "node_modules/mongodb-runner/node_modules/cliui": { "version": "8.0.1", "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", @@ -11255,15 +11269,6 @@ "node": ">=12" } }, - "node_modules/mongodb/node_modules/bson": { - "version": "6.7.0", - "resolved": "https://registry.npmjs.org/bson/-/bson-6.7.0.tgz", - "integrity": "sha512-w2IquM5mYzYZv6rs3uN2DZTOBe2a0zXLj53TGDqwF4l6Sz/XsISrisXOJihArF9+BZ6Cq/GjVht7Sjfmri7ytQ==", - "dev": true, - "engines": { - "node": ">=16.20.1" - } - }, "node_modules/moo": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/moo/-/moo-0.5.2.tgz", @@ -20178,9 +20183,9 @@ } }, "bson": { - "version": "5.5.1", - "resolved": "https://registry.npmjs.org/bson/-/bson-5.5.1.tgz", - "integrity": "sha512-ix0EwukN2EpC0SRWIj/7B5+A6uQMQy6KMREI9qQqvgpkV2frH63T0UDVd1SYedL6dNCmDBYB3QtXi4ISk9YT+g==", + "version": "6.10.1", + "resolved": "https://registry.npmjs.org/bson/-/bson-6.10.1.tgz", + "integrity": "sha512-P92xmHDQjSKPLHqFxefqMxASNq/aWJMEZugpCjf+AF/pgcUpMMQCg7t7+ewko0/u8AapvF3luf/FoehddEK+sA==", "dev": true }, "buffer": { @@ -24891,14 +24896,6 @@ "@mongodb-js/saslprep": "^1.1.5", "bson": "^6.7.0", "mongodb-connection-string-url": "^3.0.0" - }, - "dependencies": { - "bson": { - "version": "6.7.0", - "resolved": "https://registry.npmjs.org/bson/-/bson-6.7.0.tgz", - "integrity": "sha512-w2IquM5mYzYZv6rs3uN2DZTOBe2a0zXLj53TGDqwF4l6Sz/XsISrisXOJihArF9+BZ6Cq/GjVht7Sjfmri7ytQ==", - "dev": true - } } }, "mongodb-connection-string-url": { @@ -24957,12 +24954,11 @@ } }, "mongodb-log-writer": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/mongodb-log-writer/-/mongodb-log-writer-1.3.0.tgz", - "integrity": "sha512-XFV4tjpZlf9iaHlCFyV49/I2ILeWEbTXJd7Q1gFYXMw07Y9aTp6sDP2tyezMzm5xU0cFwcgRel23pznbJxinkg==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mongodb-log-writer/-/mongodb-log-writer-2.1.0.tgz", + "integrity": "sha512-ZlNts/L9fs6gQNRuqLcB0+yjjfeyapbxjdkDpeb2bEYOUUThG0iOEhzIFejv0g3TX1SSAsdrT2aGYnFqoQILgQ==", "dev": true, "requires": { - "bson": "^4.5.1 || ^5.0.0", "heap-js": "^2.3.0" } }, @@ -24988,6 +24984,12 @@ "@types/webidl-conversions": "*" } }, + "bson": { + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/bson/-/bson-5.5.1.tgz", + "integrity": "sha512-ix0EwukN2EpC0SRWIj/7B5+A6uQMQy6KMREI9qQqvgpkV2frH63T0UDVd1SYedL6dNCmDBYB3QtXi4ISk9YT+g==", + "dev": true + }, "cliui": { "version": "8.0.1", "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", diff --git a/package.json b/package.json index c404bc0..5014058 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,7 @@ "email": "compass@mongodb.com" }, "homepage": "https://github.com/mongodb-js/oidc-plugin", - "version": "1.1.5", + "version": "1.1.6", "repository": { "type": "git", "url": "https://github.com/mongodb-js/oidc-plugin.git" @@ -75,7 +75,7 @@ "husky": "^8.0.3", "mocha": "^10.2.0", "mongodb": "^6.7.0", - "mongodb-log-writer": "^1.1.5", + "mongodb-log-writer": "^2.1.0", "mongodb-runner": "^5.2.0", "node-fetch": "^3.3.1", "nyc": "^15.1.0", diff --git a/src/rfc-8252-http-server.spec.ts b/src/rfc-8252-http-server.spec.ts index 104c9f4..15de661 100644 --- a/src/rfc-8252-http-server.spec.ts +++ b/src/rfc-8252-http-server.spec.ts @@ -1,4 +1,4 @@ -import { RFC8252HTTPServer } from './rfc-8252-http-server'; +import { getAllInterfaces, RFC8252HTTPServer } from './rfc-8252-http-server'; import { expect } from 'chai'; import type { Server as HTTPServer } from 'http'; import { createServer as createHTTPServer } from 'http'; @@ -485,4 +485,58 @@ describe('RFC8252HTTPServer', function () { }); }); }); + + context('getAllInterfaces', function () { + let dnsLookupStub: sinon.SinonStub; + this.beforeEach(function () { + dnsLookupStub = sinon.stub(); + }); + + it('filters out exact duplicates', async function () { + dnsLookupStub.resolves([ + { address: '127.0.0.1', family: 4 }, + { address: '127.0.0.1', family: 4 }, + { address: '[::1]', family: 6 }, + { address: '[::1]', family: 6 }, + ]); + + const interfaces = await getAllInterfaces('localhost', dnsLookupStub); + + expect(interfaces).to.have.lengthOf(2); + expect(interfaces[0].address).to.equal('127.0.0.1'); + expect(interfaces[1].address).to.equal('[::1]'); + expect(interfaces[0].family).to.equal(4); + expect(interfaces[1].family).to.equal(6); + }); + + it('keeps same addresses, different family', async function () { + dnsLookupStub.resolves([ + { address: '127.0.0.1', family: 4 }, + { address: '127.0.0.1', family: 6 }, + ]); + + const interfaces = await getAllInterfaces('localhost', dnsLookupStub); + + expect(interfaces).to.have.lengthOf(2); + expect(interfaces[0].address).to.equal('127.0.0.1'); + expect(interfaces[1].address).to.equal('127.0.0.1'); + expect(interfaces[0].family).to.equal(4); + expect(interfaces[1].family).to.equal(6); + }); + + it('keeps same familes, different address', async function () { + dnsLookupStub.resolves([ + { address: '127.0.0.1', family: 4 }, + { address: '192.168.1.15', family: 4 }, + ]); + + const interfaces = await getAllInterfaces('localhost', dnsLookupStub); + + expect(interfaces).to.have.lengthOf(2); + expect(interfaces[0].address).to.equal('127.0.0.1'); + expect(interfaces[1].address).to.equal('192.168.1.15'); + expect(interfaces[0].family).to.equal(4); + expect(interfaces[1].family).to.equal(4); + }); + }); }); diff --git a/src/rfc-8252-http-server.ts b/src/rfc-8252-http-server.ts index d937367..b20459d 100644 --- a/src/rfc-8252-http-server.ts +++ b/src/rfc-8252-http-server.ts @@ -29,6 +29,26 @@ export interface RFC8252HTTPServerOptions { redirectServerRequestHandler?: RedirectServerRequestHandler; } +export async function getAllInterfaces( + hostname: string, + lookup: typeof dns.lookup = dns.lookup +): Promise<{ address: string; family: number }[]> { + const dnsResults = await lookup(hostname, { + all: true, + hints: ADDRCONFIG, + }); + + return dnsResults + .filter( + (dns, index, arr) => + arr.findIndex( + (otherDns) => + dns.address === otherDns.address && dns.family === otherDns.family + ) === index + ) + .map(({ address, family }) => ({ address, family })); +} + /** @internal */ export class RFC8252HTTPServer { private readonly redirectUrl: URL; @@ -368,14 +388,11 @@ export class RFC8252HTTPServer { // to do what Node.js does by default when only a host is provided, // namely listening on all interfaces. let hostname = this.redirectUrl.hostname; - if (hostname.startsWith('[') && hostname.endsWith(']')) + if (hostname.startsWith('[') && hostname.endsWith(']')) { hostname = hostname.slice(1, -1); - const dnsResults = ( - await dns.lookup(hostname, { - all: true, - hints: ADDRCONFIG, - }) - ).map(({ address, family }) => ({ address, family })); + } + + const dnsResults = await getAllInterfaces(hostname); this.logger.emit('mongodb-oidc-plugin:local-listen-resolved-hostname', { url: this.redirectUrl.toString(),