@nifrajs/cli 2.13.0 → 2.14.1
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/dist/capabilities-tool.d.ts +54 -1
- package/dist/capabilities-tool.d.ts.map +1 -1
- package/dist/capabilities-tool.js +146 -18
- package/dist/capabilities-tool.js.map +1 -1
- package/dist/check.d.ts +11 -11
- package/dist/check.d.ts.map +1 -1
- package/dist/check.js +234 -43
- package/dist/check.js.map +1 -1
- package/dist/cli.d.ts +11 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +91 -413
- package/dist/cli.js.map +1 -1
- package/dist/command-catalog.d.ts +244 -0
- package/dist/command-catalog.d.ts.map +1 -0
- package/dist/command-catalog.js +1014 -0
- package/dist/command-catalog.js.map +1 -0
- package/dist/contracts.d.ts +9 -0
- package/dist/contracts.d.ts.map +1 -1
- package/dist/contracts.js +22 -6
- package/dist/contracts.js.map +1 -1
- package/dist/doctor.d.ts +13 -0
- package/dist/doctor.d.ts.map +1 -1
- package/dist/doctor.js +18 -2
- package/dist/doctor.js.map +1 -1
- package/dist/load.d.ts.map +1 -1
- package/dist/load.js +22 -5
- package/dist/load.js.map +1 -1
- package/dist/manifest-tool.d.ts +15 -1
- package/dist/manifest-tool.d.ts.map +1 -1
- package/dist/manifest-tool.js +23 -9
- package/dist/manifest-tool.js.map +1 -1
- package/dist/mcp-http.js +1 -1
- package/dist/mcp.d.ts +8 -0
- package/dist/mcp.d.ts.map +1 -1
- package/dist/mcp.js +59 -349
- package/dist/mcp.js.map +1 -1
- package/dist/project-facts.d.ts +40 -0
- package/dist/project-facts.d.ts.map +1 -0
- package/dist/project-facts.js +36 -0
- package/dist/project-facts.js.map +1 -0
- package/dist/rules/comment-markers.d.ts +8 -0
- package/dist/rules/comment-markers.d.ts.map +1 -1
- package/dist/rules/comment-markers.js +36 -0
- package/dist/rules/comment-markers.js.map +1 -1
- package/dist/rules/index.d.ts +2 -3
- package/dist/rules/index.d.ts.map +1 -1
- package/dist/rules/index.js.map +1 -1
- package/dist/rules/routes.d.ts.map +1 -1
- package/dist/rules/routes.js +12 -14
- package/dist/rules/routes.js.map +1 -1
- package/dist/rules/security.js +14 -14
- package/dist/rules/security.js.map +1 -1
- package/docs/types.json +27 -14
- package/package.json +9 -9
- package/src/capabilities-tool.ts +229 -21
- package/src/check.ts +285 -59
- package/src/cli.ts +100 -404
- package/src/command-catalog.ts +1415 -0
- package/src/contracts.ts +28 -7
- package/src/doctor.ts +35 -4
- package/src/load.ts +25 -6
- package/src/manifest-tool.ts +43 -12
- package/src/mcp-http.ts +1 -1
- package/src/mcp.ts +82 -414
- package/src/project-facts.ts +86 -0
- package/src/rules/comment-markers.ts +36 -0
- package/src/rules/index.ts +3 -4
- package/src/rules/routes.ts +13 -14
- package/src/rules/security.ts +14 -14
package/src/rules/index.ts
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import type { Diagnostic } from "../diagnostics.ts"
|
|
2
|
+
import type { ProjectFacts } from "../project-facts.ts"
|
|
2
3
|
import { isBuiltInCode } from "./codes.ts"
|
|
3
4
|
|
|
5
|
+
export type { ProjectFacts } from "../project-facts.ts"
|
|
6
|
+
|
|
4
7
|
export interface SourceFile {
|
|
5
8
|
readonly file: string
|
|
6
9
|
readonly content: string
|
|
@@ -11,10 +14,6 @@ export interface SourceIndex {
|
|
|
11
14
|
read(file: string): string | undefined
|
|
12
15
|
}
|
|
13
16
|
|
|
14
|
-
export interface ProjectFacts {
|
|
15
|
-
readonly [key: string]: unknown
|
|
16
|
-
}
|
|
17
|
-
|
|
18
17
|
export interface RuleContext {
|
|
19
18
|
readonly root: string
|
|
20
19
|
readonly sources: SourceIndex
|
package/src/rules/routes.ts
CHANGED
|
@@ -3,8 +3,8 @@ import { commentBlockHasMarker } from "./comment-markers.ts"
|
|
|
3
3
|
import type { CheckRule, RuleContext } from "./index.ts"
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
|
-
* Route-table lints over the statically collected route registrations (`
|
|
7
|
-
*
|
|
6
|
+
* Route-table lints over the statically collected route registrations (`ProjectFacts.routes` is built
|
|
7
|
+
* once before the registry runs - no rule re-walks source).
|
|
8
8
|
*
|
|
9
9
|
* NF-C018 exists because the typed client's proxy intercepts a fixed set of property names before
|
|
10
10
|
* path resolution (`resolveSegment` + the thenable guard in @nifrajs/client): the seven HTTP verbs
|
|
@@ -41,20 +41,19 @@ interface StaticRouteFact {
|
|
|
41
41
|
|
|
42
42
|
/** Parse-don't-cast over the project fact: a malformed entry is dropped, never trusted. */
|
|
43
43
|
function routeFacts(ctx: RuleContext): StaticRouteFact[] {
|
|
44
|
-
const raw = ctx.project.
|
|
45
|
-
if (!Array.isArray(raw)) return []
|
|
44
|
+
const raw: readonly unknown[] = ctx.project.routes
|
|
46
45
|
const out: StaticRouteFact[] = []
|
|
47
46
|
for (const item of raw) {
|
|
48
|
-
if (typeof item !== "object" || item === null) continue
|
|
49
|
-
const record = item
|
|
47
|
+
if (typeof item !== "object" || item === null || Array.isArray(item)) continue
|
|
48
|
+
const record = Object.fromEntries(Object.entries(item))
|
|
50
49
|
if (
|
|
51
|
-
typeof record.file
|
|
52
|
-
typeof record.line
|
|
53
|
-
typeof record.method
|
|
54
|
-
typeof record.path
|
|
55
|
-
)
|
|
56
|
-
|
|
57
|
-
}
|
|
50
|
+
typeof record.file !== "string" ||
|
|
51
|
+
typeof record.line !== "number" ||
|
|
52
|
+
typeof record.method !== "string" ||
|
|
53
|
+
typeof record.path !== "string"
|
|
54
|
+
)
|
|
55
|
+
continue
|
|
56
|
+
out.push({ file: record.file, line: record.line, method: record.method, path: record.path })
|
|
58
57
|
}
|
|
59
58
|
return out
|
|
60
59
|
}
|
|
@@ -91,7 +90,7 @@ export const reservedSegmentRule: CheckRule = {
|
|
|
91
90
|
if (collision === undefined) continue
|
|
92
91
|
let lines = linesByFile.get(route.file)
|
|
93
92
|
if (lines === undefined) {
|
|
94
|
-
lines = (ctx.
|
|
93
|
+
lines = (ctx.project.source.read(route.file) ?? "").split("\n")
|
|
95
94
|
linesByFile.set(route.file, lines)
|
|
96
95
|
}
|
|
97
96
|
if (commentBlockHasMarker(lines, route.line, RESERVED_SEGMENT_PRAGMA)) continue
|
package/src/rules/security.ts
CHANGED
|
@@ -108,8 +108,8 @@ export const secretComparisonRule: CheckRule = {
|
|
|
108
108
|
const ts = await importProjectTypeScript(ctx.root)
|
|
109
109
|
if (ts === undefined) return didNotRun("NF-S002", "Non-constant-time secret comparison scan")
|
|
110
110
|
const findings: Diagnostic[] = []
|
|
111
|
-
for (const file of ctx.
|
|
112
|
-
const parsed = parsedFile(ts, ctx.
|
|
111
|
+
for (const file of ctx.project.source.files) {
|
|
112
|
+
const parsed = parsedFile(ts, ctx.project.source, file)
|
|
113
113
|
if (parsed === undefined) continue
|
|
114
114
|
const { tree, lines } = parsed
|
|
115
115
|
const visit = (node: TSApi.Node): void => {
|
|
@@ -169,8 +169,8 @@ export const piiLogRule: CheckRule = {
|
|
|
169
169
|
const ts = await importProjectTypeScript(ctx.root)
|
|
170
170
|
if (ts === undefined) return didNotRun("NF-S003", "Sensitive-value-in-log scan")
|
|
171
171
|
const findings: Diagnostic[] = []
|
|
172
|
-
for (const file of ctx.
|
|
173
|
-
const parsed = parsedFile(ts, ctx.
|
|
172
|
+
for (const file of ctx.project.source.files) {
|
|
173
|
+
const parsed = parsedFile(ts, ctx.project.source, file)
|
|
174
174
|
if (parsed === undefined) continue
|
|
175
175
|
const { tree, lines } = parsed
|
|
176
176
|
const visit = (node: TSApi.Node): void => {
|
|
@@ -217,8 +217,8 @@ export const failOpenGateRule: CheckRule = {
|
|
|
217
217
|
const ts = await importProjectTypeScript(ctx.root)
|
|
218
218
|
if (ts === undefined) return didNotRun("NF-S001", "Fail-open gate scan")
|
|
219
219
|
const findings: Diagnostic[] = []
|
|
220
|
-
for (const file of ctx.
|
|
221
|
-
const parsed = parsedFile(ts, ctx.
|
|
220
|
+
for (const file of ctx.project.source.files) {
|
|
221
|
+
const parsed = parsedFile(ts, ctx.project.source, file)
|
|
222
222
|
if (parsed === undefined) continue
|
|
223
223
|
const { tree, lines } = parsed
|
|
224
224
|
const visit = (node: TSApi.Node): void => {
|
|
@@ -284,8 +284,8 @@ export const corsOriginPredicateRule: CheckRule = {
|
|
|
284
284
|
const ts = await importProjectTypeScript(ctx.root)
|
|
285
285
|
if (ts === undefined) return didNotRun("NF-S004", "CORS origin predicate scan")
|
|
286
286
|
const findings: Diagnostic[] = []
|
|
287
|
-
for (const file of ctx.
|
|
288
|
-
const parsed = parsedFile(ts, ctx.
|
|
287
|
+
for (const file of ctx.project.source.files) {
|
|
288
|
+
const parsed = parsedFile(ts, ctx.project.source, file)
|
|
289
289
|
if (parsed === undefined) continue
|
|
290
290
|
const { tree, lines } = parsed
|
|
291
291
|
const visit = (node: TSApi.Node): void => {
|
|
@@ -345,8 +345,8 @@ export const externalRedirectRule: CheckRule = {
|
|
|
345
345
|
const ts = await importProjectTypeScript(ctx.root)
|
|
346
346
|
if (ts === undefined) return didNotRun("NF-S005", "External redirect opt-out scan")
|
|
347
347
|
const findings: Diagnostic[] = []
|
|
348
|
-
for (const file of ctx.
|
|
349
|
-
const parsed = parsedFile(ts, ctx.
|
|
348
|
+
for (const file of ctx.project.source.files) {
|
|
349
|
+
const parsed = parsedFile(ts, ctx.project.source, file)
|
|
350
350
|
if (parsed === undefined) continue
|
|
351
351
|
const { tree, lines } = parsed
|
|
352
352
|
const visit = (node: TSApi.Node): void => {
|
|
@@ -402,8 +402,8 @@ export const assuranceEscapeHatchRule: CheckRule = {
|
|
|
402
402
|
const ts = await importProjectTypeScript(ctx.root)
|
|
403
403
|
if (ts === undefined) return didNotRun("NF-S006", "Security escape hatch scan")
|
|
404
404
|
const findings: Diagnostic[] = []
|
|
405
|
-
for (const file of ctx.
|
|
406
|
-
const parsed = parsedFile(ts, ctx.
|
|
405
|
+
for (const file of ctx.project.source.files) {
|
|
406
|
+
const parsed = parsedFile(ts, ctx.project.source, file)
|
|
407
407
|
if (parsed === undefined) continue
|
|
408
408
|
const { tree, lines } = parsed
|
|
409
409
|
const visit = (node: TSApi.Node): void => {
|
|
@@ -445,8 +445,8 @@ export const unprefixedSecureCookieRule: CheckRule = {
|
|
|
445
445
|
const ts = await importProjectTypeScript(ctx.root)
|
|
446
446
|
if (ts === undefined) return didNotRun("NF-S007", "Secure cookie prefix scan")
|
|
447
447
|
const findings: Diagnostic[] = []
|
|
448
|
-
for (const file of ctx.
|
|
449
|
-
const parsed = parsedFile(ts, ctx.
|
|
448
|
+
for (const file of ctx.project.source.files) {
|
|
449
|
+
const parsed = parsedFile(ts, ctx.project.source, file)
|
|
450
450
|
if (parsed === undefined) continue
|
|
451
451
|
const { tree } = parsed
|
|
452
452
|
const visit = (node: TSApi.Node): void => {
|