@redocly/cli 0.0.0-snapshot.1784554531 → 0.0.0-snapshot.1784806880
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/THIRD_PARTY_NOTICES +4 -3
- package/lib/chunks/3NHVLYJH.js +179 -0
- package/lib/chunks/{CQW6BTG6.js → 3PBFD5RJ.js} +8 -6
- package/lib/chunks/4VYNEZM4.js +83 -0
- package/lib/chunks/{N6FJ5HYR.js → 5X37BYJI.js} +19 -478
- package/lib/chunks/63ZYN74V.js +1758 -0
- package/lib/chunks/CWLJO2O3.js +786 -0
- package/lib/chunks/{IT2ABZKC.js → DS7ABUGH.js} +2 -2
- package/lib/chunks/{IJMPB5WN.js → FAHYXYIH.js} +3 -3
- package/lib/chunks/{URE42RCZ.js → KKNHN3WH.js} +2 -2
- package/lib/chunks/{EX5AKFM3.js → KNADXFW6.js} +1 -1
- package/lib/chunks/{T2PUTL2H.js → KXKCFLYG.js} +8 -168
- package/lib/chunks/{7COJB2Y6.js → L4OU3AUH.js} +1 -1
- package/lib/chunks/{QEKGREJP.js → MDPLJ2YY.js} +1 -1
- package/lib/chunks/MOME5JRS.js +496 -0
- package/lib/chunks/{KD24SG2E.js → OR4AMQFM.js} +3816 -3084
- package/lib/chunks/R5XDCRI3.js +18 -0
- package/lib/chunks/{M5ZNR5FB.js → SNRNA7AW.js} +19 -15
- package/lib/chunks/{LGUVWMQ6.js → TF622UZ7.js} +145 -841
- package/lib/chunks/{FLRQX75P.js → WPYZM2D5.js} +2 -2
- package/lib/chunks/{OLYAB3Z5.js → XINOCCSB.js} +3 -3
- package/lib/index.js +98 -87
- package/package.json +1 -1
package/THIRD_PARTY_NOTICES
CHANGED
|
@@ -649,14 +649,14 @@ Packages:
|
|
|
649
649
|
@redocly/ajv@8.18.3 — Copyright (c) 2015-2021 Evgeny Poberezkin
|
|
650
650
|
@redocly/cli-otel@0.3.4 — Copyright 2025 Redocly Inc, all rights reserved.
|
|
651
651
|
@redocly/config@0.22.0 — Copyright 2024 Redocly Inc.
|
|
652
|
-
@redocly/config@0.
|
|
653
|
-
@redocly/openapi-core@1.34.
|
|
652
|
+
@redocly/config@0.52.0 — Copyright 2024 Redocly Inc.
|
|
653
|
+
@redocly/openapi-core@1.34.17
|
|
654
654
|
agent-base@7.1.4 — Copyright (c) 2013 Nathan Rajlich <nathan@tootallnate.net>
|
|
655
655
|
ajv-formats@3.0.1 — Copyright (c) 2020 Evgeny Poberezkin
|
|
656
656
|
ajv@8.20.0 — Copyright (c) 2015-2021 Evgeny Poberezkin
|
|
657
657
|
ansi-styles@4.3.0
|
|
658
658
|
balanced-match@1.0.2 — Copyright (c) 2013 Julian Gruber <julian@juliangruber.com>
|
|
659
|
-
brace-expansion@2.1.
|
|
659
|
+
brace-expansion@2.1.2 — Copyright (c) 2013 Julian Gruber <julian@juliangruber.com>
|
|
660
660
|
call-me-maybe@1.0.2 — Copyright (c) 2015 Eric McCarthy
|
|
661
661
|
chalk@4.1.2
|
|
662
662
|
classnames@2.5.1 — Copyright (c) 2018 Jed Watson
|
|
@@ -679,6 +679,7 @@ Packages:
|
|
|
679
679
|
js-levenshtein@1.1.6 — Copyright (c) 2017 Gustaf Andersson
|
|
680
680
|
js-tokens@4.0.0 — Copyright (c) 2014, 2015, 2016, 2017, 2018 Simon Lydell
|
|
681
681
|
js-yaml@4.2.0 — Copyright (C) 2011-2015 by Vitaly Puzrin
|
|
682
|
+
js-yaml@5.2.1 — Copyright (C) 2011-2015 by Vitaly Puzrin
|
|
682
683
|
json-pointer@0.6.2 — Copyright (c) 2016 Manuel Stofer
|
|
683
684
|
json-schema-traverse@1.0.0 — Copyright (c) 2017 Evgeny Poberezkin
|
|
684
685
|
jsonpointer@5.0.1 — Copyright (c) 2011-2015 Jan Lehnardt <jan@apache.org> & Marc Bachmann <https://github.com/marcbachmann>
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
import { createRequire as __createRequire } from 'node:module';
|
|
2
|
+
import { fileURLToPath as __fileURLToPath } from 'node:url';
|
|
3
|
+
import { dirname as __pathDirname } from 'node:path';
|
|
4
|
+
const require = __createRequire(import.meta.url);
|
|
5
|
+
var __filename = __fileURLToPath(import.meta.url);
|
|
6
|
+
var __dirname = __pathDirname(__filename);
|
|
7
|
+
import {
|
|
8
|
+
selectTrafficParser
|
|
9
|
+
} from "./KXKCFLYG.js";
|
|
10
|
+
import {
|
|
11
|
+
ValidationSession,
|
|
12
|
+
loadOpenApiIndex,
|
|
13
|
+
parseCsv,
|
|
14
|
+
renderReport
|
|
15
|
+
} from "./5X37BYJI.js";
|
|
16
|
+
import {
|
|
17
|
+
listFilesRecursively,
|
|
18
|
+
normalizeFsPath
|
|
19
|
+
} from "./MOME5JRS.js";
|
|
20
|
+
import {
|
|
21
|
+
AbortFlowError,
|
|
22
|
+
exitWithError
|
|
23
|
+
} from "./L4OU3AUH.js";
|
|
24
|
+
import {
|
|
25
|
+
logger
|
|
26
|
+
} from "./OR4AMQFM.js";
|
|
27
|
+
import "./HRYOF224.js";
|
|
28
|
+
import "./YDPUXTSG.js";
|
|
29
|
+
|
|
30
|
+
// src/commands/drift/index.ts
|
|
31
|
+
import { mkdir, writeFile } from "node:fs/promises";
|
|
32
|
+
import path from "node:path";
|
|
33
|
+
|
|
34
|
+
// src/commands/drift/engine/runner.ts
|
|
35
|
+
async function runTrafficValidation(options) {
|
|
36
|
+
const trafficFiles = await listFilesRecursively(options.trafficPath);
|
|
37
|
+
if (trafficFiles.length === 0) {
|
|
38
|
+
throw new Error("No traffic files found in the provided traffic path.");
|
|
39
|
+
}
|
|
40
|
+
const session = ValidationSession.create({
|
|
41
|
+
openApiIndex: options.openApiIndex,
|
|
42
|
+
matchMode: options.matchMode,
|
|
43
|
+
ignoreCookies: options.ignoreCookies,
|
|
44
|
+
ignoreHeaders: options.ignoreHeaders,
|
|
45
|
+
previewFindingsLimit: options.previewFindingsLimit,
|
|
46
|
+
activeRules: options.activeRules,
|
|
47
|
+
server: options.server,
|
|
48
|
+
minSeverity: options.minSeverity
|
|
49
|
+
});
|
|
50
|
+
let supportedTrafficFileCount = 0;
|
|
51
|
+
let exchangeIndex = 0;
|
|
52
|
+
for (const trafficFile of trafficFiles) {
|
|
53
|
+
const parser = await selectTrafficParser(trafficFile, options.format);
|
|
54
|
+
if (!parser) {
|
|
55
|
+
logger.warn(`Skipping traffic file with unrecognized format: ${trafficFile}
|
|
56
|
+
`);
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
supportedTrafficFileCount += 1;
|
|
60
|
+
for await (const exchange of parser.parse(trafficFile)) {
|
|
61
|
+
await session.process({ ...exchange, index: exchangeIndex });
|
|
62
|
+
exchangeIndex += 1;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
if (supportedTrafficFileCount === 0) {
|
|
66
|
+
throw new Error(
|
|
67
|
+
"No supported traffic files found. In auto mode, files must match built-in traffic parser signatures."
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
if (exchangeIndex === 0) {
|
|
71
|
+
throw new Error("No HTTP exchanges were parsed from the provided traffic files.");
|
|
72
|
+
}
|
|
73
|
+
return session.finalize();
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// src/commands/drift/index.ts
|
|
77
|
+
var USE_COLOR = Boolean(process.stdout.isTTY) && process.env.NO_COLOR === void 0;
|
|
78
|
+
function collectSpecServerUrls(openApiIndex) {
|
|
79
|
+
const urls = /* @__PURE__ */ new Set();
|
|
80
|
+
for (const operations of openApiIndex.operationsByMethod.values()) {
|
|
81
|
+
for (const operation of operations) {
|
|
82
|
+
for (const server of operation.servers) {
|
|
83
|
+
urls.add(server.rawUrl);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
return Array.from(urls).sort();
|
|
88
|
+
}
|
|
89
|
+
function warnWhenNothingMatched(summary, openApiIndex, server) {
|
|
90
|
+
const validatedExchanges = summary.totalExchanges - summary.skippedExchanges;
|
|
91
|
+
if (validatedExchanges === 0 && summary.skippedExchanges > 0) {
|
|
92
|
+
logger.warn(
|
|
93
|
+
`All ${summary.skippedExchanges} exchange(s) were outside the --server "${server}" and were skipped. Check that the server matches the traffic URLs.
|
|
94
|
+
`
|
|
95
|
+
);
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
if (summary.documentedExchanges > 0 || validatedExchanges === 0) {
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
const serverUrls = collectSpecServerUrls(openApiIndex);
|
|
102
|
+
const hint = server ? `Check that the --server "${server}" matches the traffic URLs and that the description paths align with the remainder.` : summary.hostCompatibleExchanges === validatedExchanges ? `The traffic hosts are compatible with the description servers (${serverUrls.join(
|
|
103
|
+
", "
|
|
104
|
+
)}), so the endpoints are likely undocumented; if they should be documented, check that the description base paths and paths align with the traffic URLs, or use --server to declare the server the traffic was captured against.` : `Check that the traffic host and base path match the description servers (${serverUrls.join(
|
|
105
|
+
", "
|
|
106
|
+
)}), or use --server to declare the server the traffic was captured against.`;
|
|
107
|
+
logger.warn(
|
|
108
|
+
`None of the ${validatedExchanges} validated exchange(s) matched a documented operation. ${hint}
|
|
109
|
+
`
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
async function writeOutput(outputPath, content) {
|
|
113
|
+
const resolved = normalizeFsPath(outputPath);
|
|
114
|
+
await mkdir(path.dirname(resolved), { recursive: true });
|
|
115
|
+
await writeFile(resolved, content, "utf8");
|
|
116
|
+
}
|
|
117
|
+
async function handleDrift({ argv, config }) {
|
|
118
|
+
const trafficPath = normalizeFsPath(argv.traffic);
|
|
119
|
+
const trafficFormat = argv["traffic-format"];
|
|
120
|
+
const activeRules = argv.rules ? parseCsv(argv.rules) : void 0;
|
|
121
|
+
const ignoreHeaders = argv["ignore-headers"] ? parseCsv(argv["ignore-headers"]) : void 0;
|
|
122
|
+
const server = argv.server;
|
|
123
|
+
if (server && argv["match-mode"]) {
|
|
124
|
+
return exitWithError(
|
|
125
|
+
"The --server and --match-mode options are mutually exclusive: --match-mode controls how requests are located via the description servers, while --server replaces the description servers with the one the traffic was captured against."
|
|
126
|
+
);
|
|
127
|
+
}
|
|
128
|
+
const matchMode = argv["match-mode"] ?? "strict-host";
|
|
129
|
+
const specPath = normalizeFsPath(argv.api);
|
|
130
|
+
const openApiIndex = await loadOpenApiIndex(specPath, config);
|
|
131
|
+
if (openApiIndex.loadedOperations === 0) {
|
|
132
|
+
return exitWithError(`No OpenAPI operations were loaded from: ${specPath}`);
|
|
133
|
+
}
|
|
134
|
+
const { runId, summary, findings } = await runTrafficValidation({
|
|
135
|
+
trafficPath,
|
|
136
|
+
format: trafficFormat,
|
|
137
|
+
matchMode,
|
|
138
|
+
ignoreCookies: argv["ignore-cookies"],
|
|
139
|
+
ignoreHeaders,
|
|
140
|
+
previewFindingsLimit: argv["max-findings"],
|
|
141
|
+
activeRules,
|
|
142
|
+
openApiIndex,
|
|
143
|
+
server,
|
|
144
|
+
minSeverity: argv["min-severity"]
|
|
145
|
+
});
|
|
146
|
+
warnWhenNothingMatched(summary, openApiIndex, server);
|
|
147
|
+
const report = renderReport(
|
|
148
|
+
{
|
|
149
|
+
runId,
|
|
150
|
+
summary,
|
|
151
|
+
findings,
|
|
152
|
+
meta: {
|
|
153
|
+
specSource: specPath,
|
|
154
|
+
trafficPath,
|
|
155
|
+
format: trafficFormat,
|
|
156
|
+
matchMode,
|
|
157
|
+
server
|
|
158
|
+
}
|
|
159
|
+
},
|
|
160
|
+
{
|
|
161
|
+
format: argv["report-format"],
|
|
162
|
+
color: USE_COLOR && argv["report-format"] === "pretty" && !argv.output,
|
|
163
|
+
maxFindings: argv["max-findings"]
|
|
164
|
+
}
|
|
165
|
+
);
|
|
166
|
+
if (argv.output) {
|
|
167
|
+
await writeOutput(argv.output, report);
|
|
168
|
+
logger.info(`Drift report written to: ${normalizeFsPath(argv.output)}
|
|
169
|
+
`);
|
|
170
|
+
} else {
|
|
171
|
+
logger.output(report);
|
|
172
|
+
}
|
|
173
|
+
if (summary.findingsBySeverity.error > 0) {
|
|
174
|
+
throw new AbortFlowError("Drift detected.");
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
export {
|
|
178
|
+
handleDrift
|
|
179
|
+
};
|
|
@@ -6,24 +6,26 @@ var __filename = __fileURLToPath(import.meta.url);
|
|
|
6
6
|
var __dirname = __pathDirname(__filename);
|
|
7
7
|
import {
|
|
8
8
|
ValidationSession,
|
|
9
|
-
createNormalizedExchange,
|
|
10
|
-
isJsonMime,
|
|
11
9
|
loadOpenApiIndex,
|
|
12
|
-
normalizeFsPath,
|
|
13
10
|
parseCsv,
|
|
14
11
|
renderReport
|
|
15
|
-
} from "./
|
|
12
|
+
} from "./5X37BYJI.js";
|
|
13
|
+
import {
|
|
14
|
+
createNormalizedExchange,
|
|
15
|
+
isJsonMime,
|
|
16
|
+
normalizeFsPath
|
|
17
|
+
} from "./MOME5JRS.js";
|
|
16
18
|
import {
|
|
17
19
|
AbortFlowError,
|
|
18
20
|
exitWithError
|
|
19
|
-
} from "./
|
|
21
|
+
} from "./L4OU3AUH.js";
|
|
20
22
|
import {
|
|
21
23
|
require_undici
|
|
22
24
|
} from "./QRC5ADSZ.js";
|
|
23
25
|
import {
|
|
24
26
|
isPlainObject,
|
|
25
27
|
logger
|
|
26
|
-
} from "./
|
|
28
|
+
} from "./OR4AMQFM.js";
|
|
27
29
|
import "./HRYOF224.js";
|
|
28
30
|
import {
|
|
29
31
|
__toESM
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { createRequire as __createRequire } from 'node:module';
|
|
2
|
+
import { fileURLToPath as __fileURLToPath } from 'node:url';
|
|
3
|
+
import { dirname as __pathDirname } from 'node:path';
|
|
4
|
+
const require = __createRequire(import.meta.url);
|
|
5
|
+
var __filename = __fileURLToPath(import.meta.url);
|
|
6
|
+
var __dirname = __pathDirname(__filename);
|
|
7
|
+
import {
|
|
8
|
+
logger
|
|
9
|
+
} from "./OR4AMQFM.js";
|
|
10
|
+
|
|
11
|
+
// src/commands/split/oas/constants.ts
|
|
12
|
+
var OPENAPI3_METHOD_NAMES = [
|
|
13
|
+
"get",
|
|
14
|
+
"put",
|
|
15
|
+
"post",
|
|
16
|
+
"delete",
|
|
17
|
+
"options",
|
|
18
|
+
"head",
|
|
19
|
+
"patch",
|
|
20
|
+
"trace",
|
|
21
|
+
"query"
|
|
22
|
+
];
|
|
23
|
+
var OPENAPI3_COMPONENT_NAMES = [
|
|
24
|
+
"schemas",
|
|
25
|
+
"responses",
|
|
26
|
+
"parameters",
|
|
27
|
+
"examples",
|
|
28
|
+
"headers",
|
|
29
|
+
"requestBodies",
|
|
30
|
+
"links",
|
|
31
|
+
"callbacks",
|
|
32
|
+
"securitySchemes"
|
|
33
|
+
];
|
|
34
|
+
|
|
35
|
+
// src/utils/spinner.ts
|
|
36
|
+
import * as process from "node:process";
|
|
37
|
+
var SPINNER_FRAMES = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
|
|
38
|
+
var Spinner = class {
|
|
39
|
+
frames;
|
|
40
|
+
currentFrame;
|
|
41
|
+
intervalId;
|
|
42
|
+
message;
|
|
43
|
+
constructor() {
|
|
44
|
+
this.frames = SPINNER_FRAMES;
|
|
45
|
+
this.currentFrame = 0;
|
|
46
|
+
this.intervalId = null;
|
|
47
|
+
this.message = "";
|
|
48
|
+
}
|
|
49
|
+
showFrame() {
|
|
50
|
+
logger.info("\r" + this.frames[this.currentFrame] + " " + this.message);
|
|
51
|
+
this.currentFrame = (this.currentFrame + 1) % this.frames.length;
|
|
52
|
+
}
|
|
53
|
+
start(message) {
|
|
54
|
+
if (this.message === message) {
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
this.message = message;
|
|
58
|
+
if (!process.stderr.isTTY) {
|
|
59
|
+
logger.info(`${message}...
|
|
60
|
+
`);
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
if (this.intervalId === null) {
|
|
64
|
+
this.intervalId = setInterval(() => {
|
|
65
|
+
this.showFrame();
|
|
66
|
+
}, 100);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
stop() {
|
|
70
|
+
if (this.intervalId !== null) {
|
|
71
|
+
clearInterval(this.intervalId);
|
|
72
|
+
this.intervalId = null;
|
|
73
|
+
logger.info("\r");
|
|
74
|
+
}
|
|
75
|
+
this.message = "";
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
export {
|
|
80
|
+
OPENAPI3_METHOD_NAMES,
|
|
81
|
+
OPENAPI3_COMPONENT_NAMES,
|
|
82
|
+
Spinner
|
|
83
|
+
};
|