Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

build: improve node compatibility #8

Merged
merged 3 commits into from
Oct 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 46 additions & 0 deletions .github/workflows/npm-build.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
name: "Node: Build + Integration"

on:
push:
branches:
- main
pull_request:

jobs:
test:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3

- uses: denoland/setup-deno@v2
with:
deno-version: v2.x # Run with latest stable Deno.

- name: Start Pebble and pebble-challtestsrv
run: deno task pebble:start --detach

- name: Wait for Pebble to be ready
run: |
echo "⏳ Waiting for Pebble... 🪨"

# Loop until the port 14000 is open
until nc -zv localhost 14000 2>/dev/null; do
sleep 1
done

echo "✅ Pebble is running!"
- name: Wait for pebble-challtestsrv to be ready
run: |
echo "⏳ Waiting for pebble-challtestsrv... 🪨"

until nc -zv localhost 8055 2>/dev/null; do
sleep 1
done

echo "✅ pebble-challtestsrv is running!"

- run: deno task build:npm:integration

- name: Stop Pebble
run: deno task pebble:stop
10 changes: 7 additions & 3 deletions .github/workflows/publish.yaml
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
name: Publish
on:
push:
branches:
- main
workflow_run:
workflows: ["CI", "E2E", "Integration", "Node: Build + Integration"]
branches: [main]
types:
- completed

jobs:
publish-jsr:
if: ${{ github.event.workflow_run.conclusion == 'success' }}
runs-on: ubuntu-latest

permissions:
Expand All @@ -19,6 +22,7 @@ jobs:
run: npx jsr publish

publish-npm:
if: ${{ github.event.workflow_run.conclusion == 'success' }}
runs-on: ubuntu-latest

permissions:
Expand Down
6 changes: 2 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,9 @@ application.

This is built primarily for Deno.

But since this is built in 100% TypeScript with no dependencies, it should be
But since this is built in 100% TypeScript with no dependencies, it is
compatible with all modern JavaScript platforms that support the [WebCrypto] and
[fetch]. (One exception being `DnsUtils.pollDnsTxtRecord()` which make use of
`Deno.resolveDns`, perhaps we can make this take in a `resolveDns` function
later to make this platform agnostic.)
[fetch].

## Features

Expand Down
3 changes: 2 additions & 1 deletion deno.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@
"test:integration": "deno test --unsafely-ignore-certificate-errors=localhost -A integration",
"pebble:start": "docker compose -f integration/docker-compose.yaml up",
"pebble:stop": "docker compose -f integration/docker-compose.yaml down",
"build:npm": "deno run -A scripts/build-npm.ts"
"build:npm": "deno run -A scripts/build-npm.ts",
"build:npm:integration": "deno run -A scripts/build-npm-integration.ts"
},
"compilerOptions": {
"strict": true,
Expand Down
2 changes: 1 addition & 1 deletion e2e/create-certificate.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
AcmeOrder,
Dns01Challenge,
DnsUtils,
} from "@fishballpkg/acme";
} from "../src/mod.ts";
import { expect, it } from "../test_deps.ts";
import { CloudflareZone } from "./utils/cloudflare.ts";
import { expectToBeDefined } from "./utils/expectToBeDefined.ts";
Expand Down
2 changes: 1 addition & 1 deletion e2e/workflows.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import {
AcmeClient,
AcmeOrder,
AcmeWorkflows,
} from "@fishballpkg/acme";
} from "../src/mod.ts";
import { describe, expect, it } from "../test_deps.ts";
import { CloudflareZone } from "./utils/cloudflare.ts";
import { randomFishballTestingSubdomain } from "./utils/randomFishballTestingSubdomain.ts";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
import { AcmeClient, AcmeOrder, AcmeWorkflows } from "@fishballpkg/acme";
// 01 prefix to this file because of https://github.com/denoland/dnt/issues/432
import { AcmeClient, AcmeOrder, AcmeWorkflows } from "../src/mod.ts";
import { describe, expect, it } from "../test_deps.ts";
import { EMAIL, PEBBLE_DIRECTORY_URL } from "./CONSTANTS.ts";
import { generateRandomDomain } from "./utils/generateRandomDomain.ts";
import { PebbleChallTestSrv } from "./utils/PebbleChallTestSrv.ts";
import { resolveDns } from "./utils/resolveDns.ts";
import { setupNode } from "./utils/setupNode.ts";

setupNode();

const DOMAINS = [
generateRandomDomain(),
Expand All @@ -27,14 +32,7 @@ describe("requestCertificates", () => {
updateDnsRecords: async (dnsRecords) => {
await pebbleChallTestSrv.createDnsRecords(dnsRecords);
},
resolveDns: async (query, recordType) => {
return await Deno.resolveDns(query, recordType, {
nameServer: {
ipAddr: "127.0.0.1",
port: 8053,
},
});
},
resolveDns,
});

expect(certKeyPair.privateKey).toBeInstanceOf(CryptoKey);
Expand Down
5 changes: 4 additions & 1 deletion integration/account.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import { AcmeClient } from "@fishballpkg/acme";
import { AcmeClient } from "../src/mod.ts";
import { expect, it } from "../test_deps.ts";
import { EMAIL, PEBBLE_DIRECTORY_URL } from "./CONSTANTS.ts";
import { setupNode } from "./utils/setupNode.ts";

setupNode();

it("should create the account successfully and the key pair should allow login", async () => {
const client = await AcmeClient.init(PEBBLE_DIRECTORY_URL);
Expand Down
5 changes: 4 additions & 1 deletion integration/order.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import { AcmeClient } from "@fishballpkg/acme";
import { AcmeClient } from "../src/mod.ts";
import { expect, it } from "../test_deps.ts";
import { EMAIL, PEBBLE_DIRECTORY_URL } from "./CONSTANTS.ts";
import { generateRandomDomain } from "./utils/generateRandomDomain.ts";
import { setupNode } from "./utils/setupNode.ts";

setupNode();

it("should place an order correctly and get the corresponding authorizations", async () => {
const client = await AcmeClient.init(PEBBLE_DIRECTORY_URL);
Expand Down
2 changes: 1 addition & 1 deletion integration/utils/PebbleChallTestSrv.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { DnsTxtRecord } from "@fishballpkg/acme";
import type { DnsTxtRecord } from "../../src/mod.ts";
import { afterEach } from "../../test_deps.ts";

const PEBBLE_CHALLTESTSRV_URL = "http://localhost:8055";
Expand Down
19 changes: 19 additions & 0 deletions integration/utils/resolveDns.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import {
defaultResolveDns,
type ResolveDnsFunction,
} from "../../src/DnsUtils/resolveDns.ts";

/**
* A resolveDns function specifically for integration tests to allow TXT lookups to be done via pebble-testchallsrv
*/
export const resolveDns: ResolveDnsFunction = async (query, recordType) => {
return (await defaultResolveDns(query, recordType, {
nameServer: recordType === "TXT"
? {
ipAddr: "127.0.0.1",
port: 8053,
} // only lookup via pebble-challtestsrv for txt records
: undefined,
// deno-lint-ignore no-explicit-any -- typescript is hard
})) as any;
};
6 changes: 6 additions & 0 deletions integration/utils/setupNode.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export const setupNode = () => {
if ("process" in globalThis) {
// @ts-ignore: node specific
globalThis["process"]["env"]["NODE_TLS_REJECT_UNAUTHORIZED"] = 0;
}
};
10 changes: 10 additions & 0 deletions scripts/build-npm-integration.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { build, type BuildOptions } from "jsr:@deno/dnt";
import { dntConfig } from "./build-npm.ts";

const config: BuildOptions = {
...dntConfig,
testPattern: "integration/**/*.test.ts",
test: true,
};

await build(config);
30 changes: 23 additions & 7 deletions scripts/build-npm.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { build, emptyDir } from "jsr:@deno/dnt";
import { build, type BuildOptions, emptyDir } from "jsr:@deno/dnt";
import { join } from "jsr:@std/path";
import DENO_JSON from "../deno.json" with { type: "json" };

Expand All @@ -14,20 +14,24 @@ const OUT_DIR = join(
"./dist-npm",
);

await emptyDir(OUT_DIR);

const GITHUB_REPO = "https://github.com/fishballapp/acme";

await build({
export const dntConfig: BuildOptions = {
entryPoints: Object.entries(DENO_JSON.exports).map(([name, path]) => ({
kind: "export",
name,
path: join(PROJECT_ROOT, path),
})),
outDir: OUT_DIR,
test: false,
typeCheck: false,
shims: {},
shims: {
deno: "dev",
undici: "dev",
},
compilerOptions: {
lib: ["ESNext", "DOM"],
target: "ES2022",
},
package: {
name: DENO_JSON.name,
version: DENO_JSON.version,
Expand All @@ -43,6 +47,13 @@ await build({
},
keywords: ["acme"],
homepage: "https://jsr.io/@fishballpkg/acme/doc",
devDependencies: {
"@types/node": "latest",
},
},
mappings: {
[`${PROJECT_ROOT}/src/DnsUtils/resolveDns.deno.ts`]:
`${PROJECT_ROOT}/src/DnsUtils/resolveDns.node.ts`,
},
postBuild() {
// steps to run after building and before running the tests
Expand All @@ -53,4 +64,9 @@ await build({
);
}
},
});
};

if (import.meta.main) {
await emptyDir(OUT_DIR);
await build(dntConfig);
}
32 changes: 0 additions & 32 deletions src/DnsUtils/ResolveDnsFunction.ts

This file was deleted.

20 changes: 15 additions & 5 deletions src/DnsUtils/_helpers.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { defaultResolveDns, type ResolveDnsFunction } from "./resolveDns.ts";

type IpVersion = "ipv4" | "ipv6";

const QUAD9_DNS_IPS: Record<IpVersion, string> = {
Expand All @@ -12,29 +14,37 @@ const cache: Record<IpVersion, Promise<boolean> | undefined> = {

const isIpVersionSupported = async (
version: IpVersion,
{
resolveDns = defaultResolveDns,
}: {
resolveDns?: ResolveDnsFunction;
} = {},
): Promise<boolean> => {
cache[version] ??= (async () => {
try {
await Deno.resolveDns("example.com", "NS", {
await resolveDns("example.com", "NS", {
nameServer: {
ipAddr: QUAD9_DNS_IPS[version],
},
});
return true;
} catch {
} catch (e) {
console.error(e);
return false;
}
})();

return await cache[version];
};

export const getSupportedIpVersions = async (): Promise<
export const getSupportedIpVersions = async (
opts: { resolveDns?: ResolveDnsFunction } = {},
): Promise<
readonly IpVersion[]
> => {
const [ipv4Supported, ipv6Supported] = await Promise.all([
isIpVersionSupported("ipv4"),
isIpVersionSupported("ipv6"),
isIpVersionSupported("ipv4", opts),
isIpVersionSupported("ipv6", opts),
]);

if (ipv4Supported && ipv6Supported) {
Expand Down
6 changes: 2 additions & 4 deletions src/DnsUtils/findAuthoritativeNameServerIps.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { ResolveDnsFunction } from "./ResolveDnsFunction.ts";
import { defaultResolveDns, type ResolveDnsFunction } from "./resolveDns.ts";
export type FindAuthoritativeNameServerIpsConfig = {
/**
* A function to resolve DNS record.
Expand All @@ -24,9 +24,7 @@ export const findAuthoritativeNameServerIps = async (
domain: string,
config: FindAuthoritativeNameServerIpsConfig = {},
): Promise<string[]> => {
const resolveDns =
(config.resolveDns ?? Deno.resolveDns) as typeof Deno.resolveDns;

const { resolveDns = defaultResolveDns } = config;
while (domain.includes(".")) { // continue the loop if we haven't reached TLD
const nameServers = await (async () => {
try {
Expand Down
2 changes: 1 addition & 1 deletion src/DnsUtils/mod.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,4 @@

export * from "./findAuthoritativeNameServerIps.ts";
export * from "./pollDnsTxtRecord.ts";
export * from "./ResolveDnsFunction.ts";
export * from "./resolveDns.ts";
Loading
Loading