Skip to content
Open
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
3 changes: 3 additions & 0 deletions authorization-server-settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"url": "http://auth.example.com"
}
54 changes: 49 additions & 5 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import { Command } from 'commander';
import { ZodError } from 'zod';
import { readFile } from 'fs/promises';
import {
runConformanceTest,
printClientResults,
Expand Down Expand Up @@ -35,6 +36,7 @@ import {
import type { SpecVersion } from './scenarios';
import { ConformanceCheck } from './types';
import {
AuthorizationServerFileOptionsSchema,
AuthorizationServerOptionsSchema,
ClientOptionsSchema,
ServerOptionsSchema
Expand Down Expand Up @@ -71,6 +73,17 @@ function filterScenariosBySpecVersion(
return allScenarios.filter((s) => allowed.has(s));
}

function mergeAuthorizationServerOptions(
cli: Record<string, any>,
file: Record<string, any>
) {
return {
url: cli.url ?? file?.url,
outputDir: cli.outputDir,
specVersion: cli.specVersion
};
}

const program = new Command();

program
Expand Down Expand Up @@ -460,19 +473,50 @@ program
.description(
'Run conformance tests against an authorization server implementation'
)
.requiredOption('--url <url>', 'URL of the authorization server issuer')
.option('--file <filename>', 'authorization server settings file')
.option('--url <url>', 'URL of the authorization server issuer')
.option('-o, --output-dir <path>', 'Save results to this directory')
.option(
'--spec-version <version>',
'Filter scenarios by spec version (cumulative for date versions)'
)
.action(async (options) => {
try {
let fileOptions: Record<string, any> = {};
if (options.file) {
try {
const content = await readFile(options.file, 'utf-8');
fileOptions = AuthorizationServerFileOptionsSchema.parse(
JSON.parse(content)
) as Record<string, any>;
} catch (error) {
if (error instanceof SyntaxError) {
console.error(`Invalid JSON in setting file: ${options.file}`);
} else if (error instanceof ZodError) {
const details = error.issues
.map((e) => `${e.path.join('.')}: ${e.message}`)
.join(', ');
console.error(
`Invalid setting file format: ${options.file}${details}`
);
} else {
console.error(
`Failed to read setting file: ${options.file}` +
(error instanceof Error ? `: ${error.message}` : '')
);
}
process.exit(1);
}
}
const mergedOptions = mergeAuthorizationServerOptions(
options,
fileOptions
);
// Validate options with Zod
const validated = AuthorizationServerOptionsSchema.parse(options);
const outputDir = options.outputDir;
const specVersionFilter = options.specVersion
? resolveSpecVersion(options.specVersion)
const validated = AuthorizationServerOptionsSchema.parse(mergedOptions);
const outputDir = mergedOptions.outputDir;
const specVersionFilter = mergedOptions.specVersion
? resolveSpecVersion(mergedOptions.specVersion)
: undefined;

let scenarios: string[];
Expand Down
11 changes: 11 additions & 0 deletions src/schemas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,17 @@ export type AuthorizationServerOptions = z.infer<
typeof AuthorizationServerOptionsSchema
>;

// Authorization server file options schema
export const AuthorizationServerFileOptionsSchema = z
.object({
url: z.string().url().optional()
})
.strict();

export type AuthorizationServerFileOptions = z.infer<
typeof AuthorizationServerFileOptionsSchema
>;

// Interactive command options schema
export const InteractiveOptionsSchema = z.object({
scenario: z
Expand Down
Loading