Skip to content
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
6 changes: 3 additions & 3 deletions deno.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,9 @@
"@opentelemetry/core": "npm:@opentelemetry/core@^2.5.0",
"@opentelemetry/sdk-trace-base": "npm:@opentelemetry/sdk-trace-base@^2.5.0",
"@opentelemetry/semantic-conventions": "npm:@opentelemetry/semantic-conventions@^1.39.0",
"@optique/config": "jsr:@optique/config@^0.10.4",
"@optique/core": "jsr:@optique/core@^0.10.4",
"@optique/run": "jsr:@optique/run@^0.10.4",
"@optique/config": "jsr:@optique/config@^0.10.6",
"@optique/core": "jsr:@optique/core@^0.10.6",
"@optique/run": "jsr:@optique/run@^0.10.6",
"@std/assert": "jsr:@std/assert@^1.0.13",
"@std/async": "jsr:@std/async@^1.0.13",
"@std/encoding": "jsr:@std/encoding@^1.0.10",
Expand Down
29 changes: 16 additions & 13 deletions deno.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

69 changes: 63 additions & 6 deletions packages/cli/src/lookup.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -186,15 +186,72 @@ test("clearTimeoutSignal - cleans up timer properly", async () => {
assert.ok(!signal.aborted);
});

test("authorizedFetchOption - parses successfully without -a flag", async () => {
test("authorizedFetchOption - parses successfully without -a flag", () => {
setActiveConfig(configContext.id, {});
const result = parse(authorizedFetchOption, []);
clearActiveConfig(configContext.id);
assert.ok(result.success);
if (result.success) {
assert.strictEqual(result.value.authorizedFetch, false);
assert.strictEqual(result.value.firstKnock, undefined);
assert.strictEqual(result.value.tunnelService, undefined);
}
});

test("authorizedFetchOption - parses with -a without tunnelService config", async () => {
const result = await runWithConfig(authorizedFetchOption, configContext, {
load: () => ({}),
args: ["-a"],
});
assert.strictEqual(result.authorizedFetch, true);
assert.strictEqual(result.firstKnock, "draft-cavage-http-signatures-12");
assert.strictEqual(result.tunnelService, undefined);
});

test("authorizedFetchOption - uses config to enable authorized fetch", async () => {
const result = await runWithConfig(authorizedFetchOption, configContext, {
load: () => ({ lookup: { authorizedFetch: true } }),
args: [],
});
assert.strictEqual(result.authorizedFetch, false);
// When authorizedFetch is false, firstKnock and tunnelService still get defaults
assert.strictEqual(result.authorizedFetch, true);
assert.strictEqual(result.firstKnock, "draft-cavage-http-signatures-12");
assert.strictEqual(result.tunnelService, "localhost.run");
assert.strictEqual(result.tunnelService, undefined);
});

test("authorizedFetchOption - reads firstKnock from config", async () => {
const result = await runWithConfig(authorizedFetchOption, configContext, {
load: () => ({
lookup: {
authorizedFetch: true,
firstKnock: "rfc9421",
},
tunnelService: "serveo.net",
}),
args: [],
});
assert.strictEqual(result.authorizedFetch, true);
assert.strictEqual(result.firstKnock, "rfc9421");
assert.strictEqual(result.tunnelService, undefined);
});

test("authorizedFetchOption - invalid when --first-knock is used without -a", () => {
setActiveConfig(configContext.id, {});
const result = parse(authorizedFetchOption, [
"--first-knock",
"rfc9421",
]);
clearActiveConfig(configContext.id);
assert.ok(!result.success);
});

test("authorizedFetchOption - invalid when --tunnel-service is used without -a", () => {
setActiveConfig(configContext.id, {});
const result = parse(authorizedFetchOption, [
"--tunnel-service",
"serveo.net",
]);
clearActiveConfig(configContext.id);
assert.ok(!result.success);
});

test("authorizedFetchOption - parses successfully with -a flag", () => {
Expand All @@ -208,7 +265,7 @@ test("authorizedFetchOption - parses successfully with -a flag", () => {
result.value.firstKnock,
"draft-cavage-http-signatures-12",
);
assert.strictEqual(result.value.tunnelService, "localhost.run");
assert.strictEqual(result.value.tunnelService, undefined);
}
});

Expand All @@ -224,7 +281,7 @@ test("authorizedFetchOption - parses with -a and --first-knock", () => {
if (result.success) {
assert.strictEqual(result.value.authorizedFetch, true);
assert.strictEqual(result.value.firstKnock, "rfc9421");
assert.strictEqual(result.value.tunnelService, "localhost.run");
assert.strictEqual(result.value.tunnelService, undefined);
}
});

Expand Down
67 changes: 37 additions & 30 deletions packages/cli/src/lookup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import {
optionNames,
or,
string,
withDefault,
} from "@optique/core";
import { path, print, printError } from "@optique/run";
import { createWriteStream, type WriteStream } from "node:fs";
Expand All @@ -44,48 +45,54 @@ import { getContextLoader, getDocumentLoader } from "./docloader.ts";
import { renderImages } from "./imagerenderer.ts";
import { configureLogging } from "./log.ts";
import {
createTunnelServiceOption,
type GlobalOptions,
tunnelServiceOption,
userAgentOption,
} from "./options.ts";
import { spawnTemporaryServer, type TemporaryServer } from "./tempserver.ts";
import { colorEnabled, colors, formatObject } from "./utils.ts";

const logger = getLogger(["fedify", "cli", "lookup"]);

export const authorizedFetchOption = object("Authorized fetch options", {
authorizedFetch: bindConfig(
map(
flag("-a", "--authorized-fetch", {
description: message`Sign the request with an one-time key.`,
}),
() => true as const,
export const authorizedFetchOption = withDefault(
object("Authorized fetch options", {
authorizedFetch: bindConfig(
map(
flag("-a", "--authorized-fetch", {
description: message`Sign the request with an one-time key.`,
}),
() => true as const,
),
{
context: configContext,
key: (config) => config.lookup?.authorizedFetch ? true : undefined,
},
),
{
context: configContext,
key: (config) => config.lookup?.authorizedFetch ?? false,
default: false,
},
),
firstKnock: bindConfig(
option(
"--first-knock",
choice(["draft-cavage-http-signatures-12", "rfc9421"]),
firstKnock: bindConfig(
option(
"--first-knock",
choice(["draft-cavage-http-signatures-12", "rfc9421"]),
{
description: message`The first-knock spec for ${
optionNames(["-a", "--authorized-fetch"])
}. It is used for the double-knocking technique.`,
},
),
{
description: message`The first-knock spec for ${
optionNames(["-a", "--authorized-fetch"])
}. It is used for the double-knocking technique.`,
context: configContext,
key: (config) =>
config.lookup?.firstKnock ?? "draft-cavage-http-signatures-12",
default: "draft-cavage-http-signatures-12" as const,
},
),
{
context: configContext,
key: (config) =>
config.lookup?.firstKnock ?? "draft-cavage-http-signatures-12",
default: "draft-cavage-http-signatures-12" as const,
},
),
tunnelService: tunnelServiceOption,
});
tunnelService: createTunnelServiceOption(),
}),
{
authorizedFetch: false as const,
firstKnock: undefined,
tunnelService: undefined,
} as const,
);

const traverseOption = object("Traverse options", {
traverse: bindConfig(
Expand Down
47 changes: 27 additions & 20 deletions packages/cli/src/options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ import {
message,
object,
option,
type OptionName,
or,
string,
valueSet,
withDefault,
} from "@optique/core";
import { type Config, configContext } from "./config.ts";
Expand All @@ -32,25 +32,32 @@ export const TUNNEL_SERVICES = [
export type TunnelService = typeof TUNNEL_SERVICES[number];

/**
* Option for selecting a tunneling service.
* Uses the global `tunnelService` config setting.
* Creates a tunnel service option with customizable option names.
*/
export const tunnelServiceOption = bindConfig(
option(
"--tunnel-service",
choice(TUNNEL_SERVICES, { metavar: "SERVICE" }),
{
description: message`The tunneling service to use: ${
valueSet(TUNNEL_SERVICES)
}.`,
},
),
{
context: configContext,
key: (config) => config.tunnelService ?? "localhost.run",
default: "localhost.run" as const,
},
);
export function createTunnelServiceOption(
optionNames: OptionName[] = ["--tunnel-service"],
) {
// Note that we don't provide a default value here, since the tunneling
// implementation will randomly select a service if none is specified.
return withDefault(
bindConfig(
option(
...optionNames,
choice(TUNNEL_SERVICES, { metavar: "SERVICE" }),
{
description: message`The tunneling service to use.
By default, any of the supported tunneling services will be used
(randomly selected for each tunnel).`,
},
),
{
context: configContext,
key: (config) => config.tunnelService,
},
),
undefined,
);
}

/**
* Config sections that support the noTunnel option.
Expand Down Expand Up @@ -83,7 +90,7 @@ export function createTunnelOption<S extends TunnelConfigSection>(section: S) {
default: true,
},
),
tunnelService: tunnelServiceOption,
tunnelService: createTunnelServiceOption(),
});
}

Expand Down
25 changes: 5 additions & 20 deletions packages/cli/src/tunnel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,12 @@ import {
merge,
message,
object,
option,
optional,
valueSet,
} from "@optique/core";
import { choice } from "@optique/core/valueparser";
import { print, printError } from "@optique/run";
import process from "node:process";
import ora from "ora";
import { configureLogging } from "./log.ts";
import { type GlobalOptions, TUNNEL_SERVICES } from "./options.ts";
import { createTunnelServiceOption, type GlobalOptions } from "./options.ts";

export const tunnelCommand = command(
"tunnel",
Expand All @@ -30,21 +26,10 @@ export const tunnelCommand = command(
port: argument(integer({ metavar: "PORT", min: 0, max: 65535 }), {
description: message`The local port number to expose.`,
}),
service: optional(
option(
"-s",
"--service",
"--tunnel-service",
choice(TUNNEL_SERVICES, {
metavar: "SERVICE",
}),
{
description: message`The tunneling service to use: ${
valueSet(TUNNEL_SERVICES)
}.`,
},
),
),
service: createTunnelServiceOption([
"-s",
"--service",
]),
}),
),
{
Expand Down
Loading
Loading