Skip to content

Commit 8e737f1

Browse files
feat: improve respect digest auth error handling (#2288)
1 parent eca9e67 commit 8e737f1

File tree

9 files changed

+190
-30
lines changed

9 files changed

+190
-30
lines changed

.changeset/gold-houses-leave.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
"@redocly/respect-core": patch
3+
"@redocly/cli": patch
4+
---
5+
6+
Improved error reporting and handling for Digest authentication failures in Respect. Now users receive clearer feedback when required headers or status codes are missing.

packages/respect-core/src/modules/__tests__/flow-runner/call-api-and-analyze-results.test.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -373,6 +373,8 @@ describe('callAPIAndAnalyzeResults', () => {
373373
schemaCheck: true,
374374
networkCheck: true,
375375
successCriteriaCheck: true,
376+
unexpectedErrorCheck: true,
377+
statusCodeCheck: true,
376378
});
377379
});
378380
});

packages/respect-core/src/modules/__tests__/flow-runner/run-step.test.ts

Lines changed: 119 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -650,7 +650,13 @@ describe('runStep', () => {
650650
},
651651
];
652652

653-
return { successCriteriaCheck: true, schemaCheck: true, networkCheck: true };
653+
return {
654+
successCriteriaCheck: true,
655+
schemaCheck: true,
656+
networkCheck: true,
657+
unexpectedErrorCheck: true,
658+
statusCodeCheck: true,
659+
};
654660
});
655661

656662
await runStep({
@@ -703,7 +709,13 @@ describe('runStep', () => {
703709
vi.mocked(callAPIAndAnalyzeResults).mockImplementationOnce(async ({ step }: { step: Step }) => {
704710
step.checks = [];
705711

706-
return { successCriteriaCheck: true, schemaCheck: true, networkCheck: true };
712+
return {
713+
successCriteriaCheck: true,
714+
schemaCheck: true,
715+
networkCheck: true,
716+
unexpectedErrorCheck: true,
717+
statusCodeCheck: true,
718+
};
707719
});
708720
await runStep({
709721
step,
@@ -768,7 +780,13 @@ describe('runStep', () => {
768780
},
769781
];
770782

771-
return { successCriteriaCheck: true, schemaCheck: true, networkCheck: true };
783+
return {
784+
successCriteriaCheck: true,
785+
schemaCheck: true,
786+
networkCheck: true,
787+
unexpectedErrorCheck: true,
788+
statusCodeCheck: true,
789+
};
772790
});
773791

774792
vi.mocked(checkCriteria).mockImplementation(() => [
@@ -876,7 +894,13 @@ describe('runStep', () => {
876894
},
877895
];
878896

879-
return { successCriteriaCheck: true, schemaCheck: true, networkCheck: true };
897+
return {
898+
successCriteriaCheck: true,
899+
schemaCheck: true,
900+
networkCheck: true,
901+
unexpectedErrorCheck: true,
902+
statusCodeCheck: true,
903+
};
880904
});
881905

882906
vi.mocked(checkCriteria).mockImplementation(() => [
@@ -1004,7 +1028,13 @@ describe('runStep', () => {
10041028
},
10051029
];
10061030

1007-
return { successCriteriaCheck: true, schemaCheck: true, networkCheck: true };
1031+
return {
1032+
successCriteriaCheck: true,
1033+
schemaCheck: true,
1034+
networkCheck: true,
1035+
unexpectedErrorCheck: true,
1036+
statusCodeCheck: true,
1037+
};
10081038
});
10091039

10101040
vi.mocked(checkCriteria).mockImplementation(() => [
@@ -1128,7 +1158,13 @@ describe('runStep', () => {
11281158
},
11291159
];
11301160

1131-
return { successCriteriaCheck: true, schemaCheck: true, networkCheck: true };
1161+
return {
1162+
successCriteriaCheck: true,
1163+
schemaCheck: true,
1164+
networkCheck: true,
1165+
unexpectedErrorCheck: true,
1166+
statusCodeCheck: true,
1167+
};
11321168
});
11331169

11341170
vi.mocked(checkCriteria).mockImplementation(() => [
@@ -1246,7 +1282,13 @@ describe('runStep', () => {
12461282
},
12471283
];
12481284

1249-
return { successCriteriaCheck: false, schemaCheck: true, networkCheck: true };
1285+
return {
1286+
successCriteriaCheck: false,
1287+
schemaCheck: true,
1288+
networkCheck: true,
1289+
unexpectedErrorCheck: true,
1290+
statusCodeCheck: true,
1291+
};
12501292
});
12511293

12521294
vi.mocked(checkCriteria).mockImplementation(() => [
@@ -1353,7 +1395,13 @@ describe('runStep', () => {
13531395
},
13541396
];
13551397

1356-
return { successCriteriaCheck: false, schemaCheck: true, networkCheck: true };
1398+
return {
1399+
successCriteriaCheck: false,
1400+
schemaCheck: true,
1401+
networkCheck: true,
1402+
unexpectedErrorCheck: true,
1403+
statusCodeCheck: true,
1404+
};
13571405
});
13581406

13591407
vi.mocked(checkCriteria).mockImplementation(() => [
@@ -1483,7 +1531,13 @@ describe('runStep', () => {
14831531
},
14841532
];
14851533

1486-
return { successCriteriaCheck: false, schemaCheck: true, networkCheck: true };
1534+
return {
1535+
successCriteriaCheck: false,
1536+
schemaCheck: true,
1537+
networkCheck: true,
1538+
unexpectedErrorCheck: true,
1539+
statusCodeCheck: true,
1540+
};
14871541
});
14881542

14891543
vi.mocked(checkCriteria).mockImplementation(() => [
@@ -1600,7 +1654,13 @@ describe('runStep', () => {
16001654
},
16011655
];
16021656

1603-
return { successCriteriaCheck: false, schemaCheck: true, networkCheck: true };
1657+
return {
1658+
successCriteriaCheck: false,
1659+
schemaCheck: true,
1660+
networkCheck: true,
1661+
unexpectedErrorCheck: true,
1662+
statusCodeCheck: true,
1663+
};
16041664
});
16051665

16061666
vi.mocked(checkCriteria).mockImplementation(() => [
@@ -1714,7 +1774,13 @@ describe('runStep', () => {
17141774
},
17151775
];
17161776

1717-
return { successCriteriaCheck: false, schemaCheck: true, networkCheck: true };
1777+
return {
1778+
successCriteriaCheck: false,
1779+
schemaCheck: true,
1780+
networkCheck: true,
1781+
unexpectedErrorCheck: true,
1782+
statusCodeCheck: true,
1783+
};
17181784
});
17191785

17201786
vi.mocked(checkCriteria).mockImplementation(() => [
@@ -1836,7 +1902,13 @@ describe('runStep', () => {
18361902
} as unknown as ResponseContext;
18371903
}
18381904

1839-
return { successCriteriaCheck: false, schemaCheck: true, networkCheck: true };
1905+
return {
1906+
successCriteriaCheck: false,
1907+
schemaCheck: true,
1908+
networkCheck: true,
1909+
unexpectedErrorCheck: true,
1910+
statusCodeCheck: true,
1911+
};
18401912
});
18411913

18421914
vi.mocked(callAPIAndAnalyzeResults).mockImplementationOnce(async ({ step }: { step: Step }) => {
@@ -1849,7 +1921,13 @@ describe('runStep', () => {
18491921
},
18501922
];
18511923

1852-
return { successCriteriaCheck: true, schemaCheck: true, networkCheck: true };
1924+
return {
1925+
successCriteriaCheck: true,
1926+
schemaCheck: true,
1927+
networkCheck: true,
1928+
unexpectedErrorCheck: true,
1929+
statusCodeCheck: true,
1930+
};
18531931
});
18541932

18551933
vi.mocked(callAPIAndAnalyzeResults).mockImplementationOnce(async ({ step }: { step: Step }) => {
@@ -1862,7 +1940,13 @@ describe('runStep', () => {
18621940
},
18631941
];
18641942

1865-
return { successCriteriaCheck: false, schemaCheck: true, networkCheck: true };
1943+
return {
1944+
successCriteriaCheck: false,
1945+
schemaCheck: true,
1946+
networkCheck: true,
1947+
unexpectedErrorCheck: true,
1948+
statusCodeCheck: true,
1949+
};
18661950
});
18671951

18681952
vi.mocked(callAPIAndAnalyzeResults).mockImplementationOnce(async ({ step }: { step: Step }) => {
@@ -1875,7 +1959,13 @@ describe('runStep', () => {
18751959
},
18761960
];
18771961

1878-
return { successCriteriaCheck: true, schemaCheck: true, networkCheck: true };
1962+
return {
1963+
successCriteriaCheck: true,
1964+
schemaCheck: true,
1965+
networkCheck: true,
1966+
unexpectedErrorCheck: true,
1967+
statusCodeCheck: true,
1968+
};
18791969
});
18801970

18811971
vi.mocked(checkCriteria).mockImplementation(() => [
@@ -1897,7 +1987,13 @@ describe('runStep', () => {
18971987
},
18981988
];
18991989

1900-
return { successCriteriaCheck: true, schemaCheck: true, networkCheck: true };
1990+
return {
1991+
successCriteriaCheck: true,
1992+
schemaCheck: true,
1993+
networkCheck: true,
1994+
unexpectedErrorCheck: true,
1995+
statusCodeCheck: true,
1996+
};
19011997
});
19021998

19031999
const context = {
@@ -1974,7 +2070,13 @@ describe('runStep', () => {
19742070
},
19752071
];
19762072

1977-
return { successCriteriaCheck: false, schemaCheck: true, networkCheck: true };
2073+
return {
2074+
successCriteriaCheck: false,
2075+
schemaCheck: true,
2076+
networkCheck: true,
2077+
unexpectedErrorCheck: true,
2078+
statusCodeCheck: true,
2079+
};
19782080
});
19792081

19802082
vi.mocked(checkCriteria).mockImplementation(() => [

packages/respect-core/src/modules/checks/checks.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,14 @@ export const CHECKS = {
33
STATUS_CODE_CHECK: 'status code check',
44
SCHEMA_CHECK: 'schema check',
55
CONTENT_TYPE_CHECK: 'content-type check',
6-
UNEXPECTED_ERROR: 'unexpected error',
76
GLOBAL_TIMEOUT_ERROR: 'global timeout error',
8-
NETWORK_ERROR: 'failed network request',
97
MAX_STEPS_REACHED_ERROR: 'maximum steps reached',
8+
NETWORK_ERROR: 'failed network request',
9+
UNEXPECTED_ERROR: 'unexpected error',
1010
};
11+
12+
export class ChecksErrors extends Error {}
13+
14+
export class StatusCodeError extends ChecksErrors {}
15+
16+
export class UnexpectedError extends ChecksErrors {}

packages/respect-core/src/modules/checks/severity.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,10 @@ export const DEFAULT_SEVERITY_CONFIGURATION: {
1010
STATUS_CODE_CHECK: 'error',
1111
SCHEMA_CHECK: 'error',
1212
CONTENT_TYPE_CHECK: 'error',
13-
UNEXPECTED_ERROR: 'error',
14-
NETWORK_ERROR: 'error',
1513
GLOBAL_TIMEOUT_ERROR: 'error',
1614
MAX_STEPS_REACHED_ERROR: 'error',
15+
NETWORK_ERROR: 'error',
16+
UNEXPECTED_ERROR: 'error',
1717
};
1818

1919
export function resolveSeverityConfiguration(severityArgument: string | string[] | undefined): {

packages/respect-core/src/modules/flow-runner/call-api-and-analyze-results.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { checkSchema } from './schema/index.js';
33
import { CHECKS } from '../checks/index.js';
44
import { createRuntimeExpressionCtx } from './context/index.js';
55
import { evaluateRuntimeExpressionPayload } from '../runtime-expressions/index.js';
6+
import { StatusCodeError, UnexpectedError } from '../checks/checks.js';
67

78
import type { RequestData } from './prepare-request.js';
89
import type { TestContext, Step } from '../../types.js';
@@ -26,11 +27,35 @@ export async function callAPIAndAnalyzeResults({
2627
successCriteriaCheck: true,
2728
schemaCheck: true,
2829
networkCheck: true,
30+
unexpectedErrorCheck: true,
31+
statusCodeCheck: true,
2932
};
3033

3134
try {
3235
step.response = await ctx.apiClient.fetchResult({ ctx, step, requestData, workflowId });
3336
} catch (error: any) {
37+
if (error instanceof UnexpectedError) {
38+
step.checks.push({
39+
name: CHECKS.UNEXPECTED_ERROR,
40+
passed: false,
41+
message: error.message,
42+
severity: ctx.severity['UNEXPECTED_ERROR'],
43+
});
44+
checksResult.unexpectedErrorCheck = false;
45+
return checksResult;
46+
}
47+
48+
if (error instanceof StatusCodeError) {
49+
step.checks.push({
50+
name: CHECKS.STATUS_CODE_CHECK,
51+
passed: false,
52+
message: error.message,
53+
severity: ctx.severity['STATUS_CODE_CHECK'],
54+
});
55+
checksResult.statusCodeCheck = false;
56+
return checksResult;
57+
}
58+
3459
step.checks.push({
3560
name: CHECKS.NETWORK_ERROR,
3661
passed: false,

packages/respect-core/src/modules/flow-runner/prepare-request.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import { resolveXSecurityParameters } from './resolve-x-security-parameters.js';
1717
import type { ExtendedSecurity } from '@redocly/openapi-core';
1818
import type { Oas3SecurityScheme } from 'core/src/typings/openapi.js';
1919
import type { ParameterWithIn } from '../context-parser/index.js';
20-
import type { TestContext, Step, Parameter, PublicStep } from '../../types.js';
20+
import type { TestContext, Step, Parameter, PublicStep, OperationMethod } from '../../types.js';
2121
import type { OperationDetails } from '../description-parser/index.js';
2222

2323
export type RequestData = {
@@ -26,7 +26,7 @@ export type RequestData = {
2626
// todo: support variables
2727
};
2828
path: string;
29-
method: string;
29+
method: OperationMethod;
3030
parameters: ParameterWithIn[];
3131
requestBody: any;
3232
openapiOperation?: OperationDetails & { securitySchemes?: Record<string, Oas3SecurityScheme> };

packages/respect-core/src/utils/__tests__/api-fetcher.test.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ import {
66
ApiFetcher,
77
} from '../api-fetcher.js';
88

9+
import type { OperationMethod } from '../../types.js';
10+
911
describe('normalizeHeaders', () => {
1012
it('should return empty object if no headers', () => {
1113
const result = normalizeHeaders(undefined);
@@ -158,7 +160,7 @@ describe('ApiFetcher', () => {
158160
const requestData = {
159161
serverUrl: undefined,
160162
path: '/pets',
161-
method: 'get',
163+
method: 'get' as OperationMethod,
162164
parameters: [],
163165
requestBody: {},
164166
};

0 commit comments

Comments
 (0)