@birdcc/linter 0.0.1-alpha.0
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/.oxfmtrc.json +16 -0
- package/LICENSE +674 -0
- package/README.md +210 -0
- package/dist/index.d.ts +21 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +93 -0
- package/dist/index.js.map +1 -0
- package/dist/rules/bgp.d.ts +5 -0
- package/dist/rules/bgp.d.ts.map +1 -0
- package/dist/rules/bgp.js +131 -0
- package/dist/rules/bgp.js.map +1 -0
- package/dist/rules/catalog.d.ts +14 -0
- package/dist/rules/catalog.d.ts.map +1 -0
- package/dist/rules/catalog.js +61 -0
- package/dist/rules/catalog.js.map +1 -0
- package/dist/rules/cfg.d.ts +5 -0
- package/dist/rules/cfg.d.ts.map +1 -0
- package/dist/rules/cfg.js +264 -0
- package/dist/rules/cfg.js.map +1 -0
- package/dist/rules/net.d.ts +5 -0
- package/dist/rules/net.d.ts.map +1 -0
- package/dist/rules/net.js +140 -0
- package/dist/rules/net.js.map +1 -0
- package/dist/rules/normalize.d.ts +6 -0
- package/dist/rules/normalize.d.ts.map +1 -0
- package/dist/rules/normalize.js +65 -0
- package/dist/rules/normalize.js.map +1 -0
- package/dist/rules/ospf.d.ts +5 -0
- package/dist/rules/ospf.d.ts.map +1 -0
- package/dist/rules/ospf.js +136 -0
- package/dist/rules/ospf.js.map +1 -0
- package/dist/rules/shared.d.ts +46 -0
- package/dist/rules/shared.d.ts.map +1 -0
- package/dist/rules/shared.js +184 -0
- package/dist/rules/shared.js.map +1 -0
- package/dist/rules/sym.d.ts +5 -0
- package/dist/rules/sym.d.ts.map +1 -0
- package/dist/rules/sym.js +188 -0
- package/dist/rules/sym.js.map +1 -0
- package/dist/rules/type.d.ts +5 -0
- package/dist/rules/type.d.ts.map +1 -0
- package/dist/rules/type.js +130 -0
- package/dist/rules/type.js.map +1 -0
- package/package.json +41 -0
- package/src/index.ts +155 -0
- package/src/rules/bgp.ts +239 -0
- package/src/rules/catalog.ts +80 -0
- package/src/rules/cfg.ts +562 -0
- package/src/rules/net.ts +262 -0
- package/src/rules/normalize.ts +90 -0
- package/src/rules/ospf.ts +221 -0
- package/src/rules/shared.ts +354 -0
- package/src/rules/sym.ts +342 -0
- package/src/rules/type.ts +210 -0
- package/test/linter.bgp-ospf.test.ts +129 -0
- package/test/linter.migration.test.ts +66 -0
- package/test/linter.net-type.test.ts +132 -0
- package/test/linter.sym-cfg.test.ts +224 -0
- package/test/linter.test.ts +21 -0
- package/tsconfig.json +8 -0
package/README.md
ADDED
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
|
|
3
|
+
# 🧩 BIRD Config Linter (@birdcc/linter)
|
|
4
|
+
|
|
5
|
+
</div>
|
|
6
|
+
|
|
7
|
+
[](https://www.npmjs.com/package/@birdcc/linter) [](https://www.gnu.org/licenses/gpl-3.0) [](https://www.typescriptlang.org/)
|
|
8
|
+
|
|
9
|
+
> [Overview](#overview) · [Features](#features) · [Installation](#installation) · [Usage](#usage) · [Rules](#rules) · [API Reference](#api-reference)
|
|
10
|
+
|
|
11
|
+
## Overview
|
|
12
|
+
|
|
13
|
+
**@birdcc/linter** is the rule engine layer of the BIRD-LSP toolchain, providing a pluggable lint rule system for checking protocol compliance, security, and performance issues in BIRD2 configuration files.
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## Features
|
|
18
|
+
|
|
19
|
+
- 🧩 **Pluggable Rules** — Flexible rule system based on the `BirdRule` type
|
|
20
|
+
- 🌐 **Protocol Rules** — BGP/OSPF configuration completeness checks
|
|
21
|
+
- 🔒 **Security Rules** — Configuration security best practices
|
|
22
|
+
- ⚡ **Performance Rules** — Performance optimization recommendations
|
|
23
|
+
- 🔍 **32+ Built-in Rules** — Comprehensive coverage of common issues
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## Installation
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
# Using pnpm (recommended)
|
|
31
|
+
pnpm add @birdcc/linter
|
|
32
|
+
|
|
33
|
+
# Using npm
|
|
34
|
+
npm install @birdcc/linter
|
|
35
|
+
|
|
36
|
+
# Using yarn
|
|
37
|
+
yarn add @birdcc/linter
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
## Usage
|
|
43
|
+
|
|
44
|
+
### Basic Linting
|
|
45
|
+
|
|
46
|
+
```typescript
|
|
47
|
+
import { lintBirdConfig } from "@birdcc/linter";
|
|
48
|
+
|
|
49
|
+
const config = `
|
|
50
|
+
protocol bgp example {
|
|
51
|
+
neighbor 192.168.1.1 as 65001;
|
|
52
|
+
}
|
|
53
|
+
`;
|
|
54
|
+
|
|
55
|
+
const result = lintBirdConfig(config);
|
|
56
|
+
|
|
57
|
+
console.log(result.diagnostics);
|
|
58
|
+
// [{ code: "bgp/missing-local-as", message: "BGP protocol missing local as configuration", severity: "warning" }]
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### Custom Rules
|
|
62
|
+
|
|
63
|
+
```typescript
|
|
64
|
+
import type { BirdRule, BirdDiagnostic } from "@birdcc/linter";
|
|
65
|
+
|
|
66
|
+
const namingConventionRule: BirdRule = ({ core }) => {
|
|
67
|
+
const diagnostics: BirdDiagnostic[] = [];
|
|
68
|
+
|
|
69
|
+
for (const symbol of core.symbols) {
|
|
70
|
+
if (symbol.kind === "protocol") {
|
|
71
|
+
if (!/^[a-z][a-z0-9-]*$/.test(symbol.name)) {
|
|
72
|
+
diagnostics.push({
|
|
73
|
+
code: "structure/invalid-protocol-name",
|
|
74
|
+
message: `Protocol name '${symbol.name}' should only contain lowercase letters, numbers, and hyphens`,
|
|
75
|
+
severity: "warning",
|
|
76
|
+
source: "linter",
|
|
77
|
+
range: { /* ... */ },
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return diagnostics;
|
|
84
|
+
};
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
---
|
|
88
|
+
|
|
89
|
+
## Rules
|
|
90
|
+
|
|
91
|
+
### Symbol Rules (`sym/*`)
|
|
92
|
+
|
|
93
|
+
| Rule | Description | Level |
|
|
94
|
+
| ---- | ----------- | ----- |
|
|
95
|
+
| `sym/undefined` | Reference to undefined symbol | error |
|
|
96
|
+
| `sym/duplicate` | Duplicate symbol definition | error |
|
|
97
|
+
| `sym/proto-type-mismatch` | Protocol type mismatch | error |
|
|
98
|
+
|
|
99
|
+
### Config Rules (`cfg/*`)
|
|
100
|
+
|
|
101
|
+
| Rule | Description | Level |
|
|
102
|
+
| ---- | ----------- | ----- |
|
|
103
|
+
| `cfg/no-protocol` | No protocol defined | error |
|
|
104
|
+
| `cfg/missing-router-id` | Missing router id | error |
|
|
105
|
+
| `cfg/syntax-error` | Syntax error detected | error |
|
|
106
|
+
| `cfg/value-out-of-range` | Value out of valid range | error |
|
|
107
|
+
|
|
108
|
+
### Network Rules (`net/*`)
|
|
109
|
+
|
|
110
|
+
| Rule | Description | Level |
|
|
111
|
+
| ---- | ----------- | ----- |
|
|
112
|
+
| `net/invalid-prefix-length` | Invalid prefix length | error |
|
|
113
|
+
| `net/invalid-ipv4-prefix` | Invalid IPv4 prefix | error |
|
|
114
|
+
| `net/invalid-ipv6-prefix` | Invalid IPv6 prefix | error |
|
|
115
|
+
|
|
116
|
+
### Type Rules (`type/*`)
|
|
117
|
+
|
|
118
|
+
| Rule | Description | Level |
|
|
119
|
+
| ---- | ----------- | ----- |
|
|
120
|
+
| `type/mismatch` | Type mismatch | error |
|
|
121
|
+
| `type/not-iterable` | Non-iterable in loop | error |
|
|
122
|
+
|
|
123
|
+
### BGP Rules (`bgp/*`)
|
|
124
|
+
|
|
125
|
+
| Rule | Description | Level |
|
|
126
|
+
| ---- | ----------- | ----- |
|
|
127
|
+
| `bgp/missing-local-as` | Missing local AS | warning |
|
|
128
|
+
| `bgp/missing-neighbor` | Missing neighbor | warning |
|
|
129
|
+
| `bgp/missing-remote-as` | Missing remote AS | warning |
|
|
130
|
+
| `bgp/as-mismatch` | AS number mismatch | warning |
|
|
131
|
+
|
|
132
|
+
### OSPF Rules (`ospf/*`)
|
|
133
|
+
|
|
134
|
+
| Rule | Description | Level |
|
|
135
|
+
| ---- | ----------- | ----- |
|
|
136
|
+
| `ospf/missing-area` | Missing area configuration | warning |
|
|
137
|
+
| `ospf/backbone-stub` | Stub area on backbone | warning |
|
|
138
|
+
|
|
139
|
+
---
|
|
140
|
+
|
|
141
|
+
## API Reference
|
|
142
|
+
|
|
143
|
+
### `lintBirdConfig(text: string, options?): LintResult`
|
|
144
|
+
|
|
145
|
+
Perform complete lint checks (semantic analysis + rule checks).
|
|
146
|
+
|
|
147
|
+
```typescript
|
|
148
|
+
import { lintBirdConfig } from "@birdcc/linter";
|
|
149
|
+
|
|
150
|
+
const result = lintBirdConfig(birdConfigText);
|
|
151
|
+
// result.parsed → Parsed AST
|
|
152
|
+
// result.core → Semantic analysis snapshot
|
|
153
|
+
// result.diagnostics → All diagnostic messages
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
### Types
|
|
157
|
+
|
|
158
|
+
```typescript
|
|
159
|
+
interface LintResult {
|
|
160
|
+
parsed: ParsedBirdDocument;
|
|
161
|
+
core: CoreSnapshot;
|
|
162
|
+
diagnostics: BirdDiagnostic[];
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
type BirdRule = (context: RuleContext) => BirdDiagnostic[];
|
|
166
|
+
|
|
167
|
+
interface RuleContext {
|
|
168
|
+
text: string;
|
|
169
|
+
parsed: ParsedBirdDocument;
|
|
170
|
+
core: CoreSnapshot;
|
|
171
|
+
}
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
---
|
|
175
|
+
|
|
176
|
+
## Related Packages
|
|
177
|
+
|
|
178
|
+
| Package | Description |
|
|
179
|
+
| ------- | ----------- |
|
|
180
|
+
| [@birdcc/parser](../parser/) | Tree-sitter grammar and parser |
|
|
181
|
+
| [@birdcc/core](../core/) | Semantic analysis engine |
|
|
182
|
+
| [@birdcc/formatter](../formatter/) | Code formatting engine |
|
|
183
|
+
| [@birdcc/lsp](../lsp/) | LSP server implementation |
|
|
184
|
+
| [@birdcc/cli](../cli/) | Command-line interface |
|
|
185
|
+
|
|
186
|
+
---
|
|
187
|
+
|
|
188
|
+
### 📖 Documentation
|
|
189
|
+
|
|
190
|
+
- [BIRD Official Documentation](https://bird.network.cz/)
|
|
191
|
+
- [BIRD2 User Manual](https://bird.network.cz/doc/bird.html)
|
|
192
|
+
- [GitHub Project](https://github.com/bird-chinese-community/BIRD-LSP)
|
|
193
|
+
|
|
194
|
+
---
|
|
195
|
+
|
|
196
|
+
## 📝 License
|
|
197
|
+
|
|
198
|
+
This project is licensed under the [GPL-3.0 License](https://github.com/bird-chinese-community/BIRD-LSP/blob/main/LICENSE).
|
|
199
|
+
|
|
200
|
+
---
|
|
201
|
+
|
|
202
|
+
<p align="center">
|
|
203
|
+
<sub>Built with ❤️ by the BIRD Chinese Community (BIRDCC)</sub>
|
|
204
|
+
</p>
|
|
205
|
+
|
|
206
|
+
<p align="center">
|
|
207
|
+
<a href="https://github.com/bird-chinese-community/BIRD-LSP">🕊 GitHub</a> ·
|
|
208
|
+
<a href="https://marketplace.visualstudio.com/items?itemName=birdcc.bird2-lsp">🛒 Marketplace</a> ·
|
|
209
|
+
<a href="https://github.com/bird-chinese-community/BIRD-LSP/issues">🐛 Report Issues</a>
|
|
210
|
+
</p>
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { CrossFileResolutionResult } from "@birdcc/core";
|
|
2
|
+
import { type BirdDiagnostic, type CoreSnapshot } from "@birdcc/core";
|
|
3
|
+
import { type ParsedBirdDocument } from "@birdcc/parser";
|
|
4
|
+
export interface LintResult {
|
|
5
|
+
parsed: ParsedBirdDocument;
|
|
6
|
+
core: CoreSnapshot;
|
|
7
|
+
diagnostics: BirdDiagnostic[];
|
|
8
|
+
}
|
|
9
|
+
export interface LintBirdConfigOptions {
|
|
10
|
+
parsed?: ParsedBirdDocument;
|
|
11
|
+
core?: CoreSnapshot;
|
|
12
|
+
uri?: string;
|
|
13
|
+
}
|
|
14
|
+
export interface CrossFileLintResult {
|
|
15
|
+
diagnostics: BirdDiagnostic[];
|
|
16
|
+
byUri: Record<string, LintResult>;
|
|
17
|
+
}
|
|
18
|
+
/** Runs parser + core + normalized 32-rule linter pipeline and returns merged diagnostics. */
|
|
19
|
+
export declare const lintBirdConfig: (text: string, options?: LintBirdConfigOptions) => Promise<LintResult>;
|
|
20
|
+
export declare const lintResolvedCrossFileGraph: (resolution: CrossFileResolutionResult) => Promise<CrossFileLintResult>;
|
|
21
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,yBAAyB,EAAe,MAAM,cAAc,CAAC;AAC3E,OAAO,EAEL,KAAK,cAAc,EACnB,KAAK,YAAY,EAClB,MAAM,cAAc,CAAC;AACtB,OAAO,EAAmB,KAAK,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAU1E,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,kBAAkB,CAAC;IAC3B,IAAI,EAAE,YAAY,CAAC;IACnB,WAAW,EAAE,cAAc,EAAE,CAAC;CAC/B;AAkDD,MAAM,WAAW,qBAAqB;IACpC,MAAM,CAAC,EAAE,kBAAkB,CAAC;IAC5B,IAAI,CAAC,EAAE,YAAY,CAAC;IACpB,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,mBAAmB;IAClC,WAAW,EAAE,cAAc,EAAE,CAAC;IAC9B,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;CACnC;AAED,8FAA8F;AAC9F,eAAO,MAAM,cAAc,GACzB,MAAM,MAAM,EACZ,UAAS,qBAA0B,KAClC,OAAO,CAAC,UAAU,CAkCpB,CAAC;AAEF,eAAO,MAAM,0BAA0B,GACrC,YAAY,yBAAyB,KACpC,OAAO,CAAC,mBAAmB,CA+B7B,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { buildCoreSnapshotFromParsed, } from "@birdcc/core";
|
|
2
|
+
import { parseBirdConfig } from "@birdcc/parser";
|
|
3
|
+
import { collectBgpRuleDiagnostics } from "./rules/bgp.js";
|
|
4
|
+
import { collectCfgRuleDiagnostics } from "./rules/cfg.js";
|
|
5
|
+
import { collectNetRuleDiagnostics } from "./rules/net.js";
|
|
6
|
+
import { normalizeBaseDiagnostics } from "./rules/normalize.js";
|
|
7
|
+
import { collectOspfRuleDiagnostics } from "./rules/ospf.js";
|
|
8
|
+
import { collectSymRuleDiagnostics } from "./rules/sym.js";
|
|
9
|
+
import { collectTypeRuleDiagnostics } from "./rules/type.js";
|
|
10
|
+
const dedupeDiagnostics = (diagnostics) => {
|
|
11
|
+
const seen = new Set();
|
|
12
|
+
const output = [];
|
|
13
|
+
for (const diagnostic of diagnostics) {
|
|
14
|
+
const key = [
|
|
15
|
+
diagnostic.code,
|
|
16
|
+
diagnostic.message,
|
|
17
|
+
diagnostic.uri ?? "",
|
|
18
|
+
diagnostic.range.line,
|
|
19
|
+
diagnostic.range.column,
|
|
20
|
+
diagnostic.range.endLine,
|
|
21
|
+
diagnostic.range.endColumn,
|
|
22
|
+
].join(":");
|
|
23
|
+
if (seen.has(key)) {
|
|
24
|
+
continue;
|
|
25
|
+
}
|
|
26
|
+
seen.add(key);
|
|
27
|
+
output.push(diagnostic);
|
|
28
|
+
}
|
|
29
|
+
return output;
|
|
30
|
+
};
|
|
31
|
+
const diagnosticsForUri = (diagnostics, uri, entryUri) => {
|
|
32
|
+
return diagnostics.filter((diagnostic) => (diagnostic.uri ?? entryUri) === uri);
|
|
33
|
+
};
|
|
34
|
+
const createMergedCoreSnapshot = (localCore, mergedSymbolTable, scopedDiagnostics) => ({
|
|
35
|
+
...localCore,
|
|
36
|
+
symbols: mergedSymbolTable.definitions,
|
|
37
|
+
references: mergedSymbolTable.references,
|
|
38
|
+
symbolTable: mergedSymbolTable,
|
|
39
|
+
diagnostics: scopedDiagnostics,
|
|
40
|
+
});
|
|
41
|
+
/** Runs parser + core + normalized 32-rule linter pipeline and returns merged diagnostics. */
|
|
42
|
+
export const lintBirdConfig = async (text, options = {}) => {
|
|
43
|
+
const parsed = options.parsed ?? (await parseBirdConfig(text));
|
|
44
|
+
const core = options.core ?? buildCoreSnapshotFromParsed(parsed, { uri: options.uri });
|
|
45
|
+
const context = { text, parsed, core };
|
|
46
|
+
const normalizedBaseDiagnostics = normalizeBaseDiagnostics(parsed, core.diagnostics, {
|
|
47
|
+
uri: options.uri,
|
|
48
|
+
});
|
|
49
|
+
const ruleDiagnostics = [
|
|
50
|
+
...collectSymRuleDiagnostics(context),
|
|
51
|
+
...collectCfgRuleDiagnostics(context),
|
|
52
|
+
...collectNetRuleDiagnostics(context),
|
|
53
|
+
...collectTypeRuleDiagnostics(context),
|
|
54
|
+
...collectBgpRuleDiagnostics(context),
|
|
55
|
+
...collectOspfRuleDiagnostics(context),
|
|
56
|
+
].map((diagnostic) => ({
|
|
57
|
+
...diagnostic,
|
|
58
|
+
uri: diagnostic.uri ?? options.uri,
|
|
59
|
+
}));
|
|
60
|
+
return {
|
|
61
|
+
parsed,
|
|
62
|
+
core,
|
|
63
|
+
diagnostics: dedupeDiagnostics([
|
|
64
|
+
...normalizedBaseDiagnostics,
|
|
65
|
+
...ruleDiagnostics,
|
|
66
|
+
]),
|
|
67
|
+
};
|
|
68
|
+
};
|
|
69
|
+
export const lintResolvedCrossFileGraph = async (resolution) => {
|
|
70
|
+
const byUri = {};
|
|
71
|
+
const diagnostics = [];
|
|
72
|
+
const uris = resolution.visitedUris.length > 0
|
|
73
|
+
? resolution.visitedUris
|
|
74
|
+
: [resolution.entryUri];
|
|
75
|
+
for (const uri of uris) {
|
|
76
|
+
const text = resolution.documents[uri];
|
|
77
|
+
const localCore = resolution.snapshots[uri];
|
|
78
|
+
if (!text || !localCore) {
|
|
79
|
+
continue;
|
|
80
|
+
}
|
|
81
|
+
const lintResult = await lintBirdConfig(text, {
|
|
82
|
+
uri,
|
|
83
|
+
core: createMergedCoreSnapshot(localCore, resolution.symbolTable, diagnosticsForUri(resolution.diagnostics, uri, resolution.entryUri)),
|
|
84
|
+
});
|
|
85
|
+
byUri[uri] = lintResult;
|
|
86
|
+
diagnostics.push(...lintResult.diagnostics);
|
|
87
|
+
}
|
|
88
|
+
return {
|
|
89
|
+
byUri,
|
|
90
|
+
diagnostics: dedupeDiagnostics(diagnostics),
|
|
91
|
+
};
|
|
92
|
+
};
|
|
93
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { BirdDiagnostic } from "@birdcc/core";
|
|
2
|
+
import { type BirdRule } from "./shared.js";
|
|
3
|
+
export declare const bgpRules: BirdRule[];
|
|
4
|
+
export declare const collectBgpRuleDiagnostics: (context: Parameters<BirdRule>[0]) => BirdDiagnostic[];
|
|
5
|
+
//# sourceMappingURL=bgp.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bgp.d.ts","sourceRoot":"","sources":["../../src/rules/bgp.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AACnD,OAAO,EAOL,KAAK,QAAQ,EACd,MAAM,aAAa,CAAC;AAyNrB,eAAO,MAAM,QAAQ,EAAE,QAAQ,EAM9B,CAAC;AAEF,eAAO,MAAM,yBAAyB,GACpC,SAAS,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,KAC/B,cAAc,EAEhB,CAAC"}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import { createProtocolDiagnostic, createRuleDiagnostic, extractFirstNumberAfterKeyword, isProtocolType, numericValue, protocolDeclarations, } from "./shared.js";
|
|
2
|
+
const isInternalSession = (value) => /^(internal|ibgp)$/i.test(value?.trim() ?? "");
|
|
3
|
+
const isExternalSession = (value) => /^(external|ebgp)$/i.test(value?.trim() ?? "");
|
|
4
|
+
const bgpMissingLocalAsRule = ({ parsed }) => {
|
|
5
|
+
const diagnostics = [];
|
|
6
|
+
for (const declaration of protocolDeclarations(parsed)) {
|
|
7
|
+
if (!isProtocolType(declaration, "bgp")) {
|
|
8
|
+
continue;
|
|
9
|
+
}
|
|
10
|
+
if (declaration.statements.some((statement) => statement.kind === "local-as")) {
|
|
11
|
+
continue;
|
|
12
|
+
}
|
|
13
|
+
diagnostics.push(createProtocolDiagnostic("bgp/missing-local-as", `BGP protocol '${declaration.name}' missing local AS number`, declaration));
|
|
14
|
+
}
|
|
15
|
+
return diagnostics;
|
|
16
|
+
};
|
|
17
|
+
const bgpMissingNeighborRule = ({ parsed }) => {
|
|
18
|
+
const diagnostics = [];
|
|
19
|
+
for (const declaration of protocolDeclarations(parsed)) {
|
|
20
|
+
if (!isProtocolType(declaration, "bgp")) {
|
|
21
|
+
continue;
|
|
22
|
+
}
|
|
23
|
+
if (declaration.statements.some((statement) => statement.kind === "neighbor")) {
|
|
24
|
+
continue;
|
|
25
|
+
}
|
|
26
|
+
diagnostics.push(createProtocolDiagnostic("bgp/missing-neighbor", `BGP protocol '${declaration.name}' missing neighbor configuration`, declaration));
|
|
27
|
+
}
|
|
28
|
+
return diagnostics;
|
|
29
|
+
};
|
|
30
|
+
const bgpMissingRemoteAsRule = ({ parsed }) => {
|
|
31
|
+
const diagnostics = [];
|
|
32
|
+
for (const declaration of protocolDeclarations(parsed)) {
|
|
33
|
+
if (!isProtocolType(declaration, "bgp")) {
|
|
34
|
+
continue;
|
|
35
|
+
}
|
|
36
|
+
for (const statement of declaration.statements) {
|
|
37
|
+
if (statement.kind !== "neighbor") {
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
if (isInternalSession(statement.asn) ||
|
|
41
|
+
isExternalSession(statement.asn)) {
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
44
|
+
if (statement.asn && numericValue(statement.asn) !== null) {
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
diagnostics.push(createRuleDiagnostic("bgp/missing-remote-as", `BGP protocol '${declaration.name}' neighbor '${statement.address}' missing remote AS`, statement.asnRange ?? statement.addressRange));
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return diagnostics;
|
|
51
|
+
};
|
|
52
|
+
const bgpAsMismatchRule = ({ parsed }) => {
|
|
53
|
+
const diagnostics = [];
|
|
54
|
+
for (const declaration of protocolDeclarations(parsed)) {
|
|
55
|
+
if (!isProtocolType(declaration, "bgp")) {
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
const localAsStatement = declaration.statements.find((statement) => statement.kind === "local-as");
|
|
59
|
+
if (!localAsStatement || localAsStatement.kind !== "local-as") {
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
const localAs = numericValue(localAsStatement.asn);
|
|
63
|
+
if (localAs === null) {
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
const hasInternalNeighbor = declaration.statements.some((statement) => statement.kind === "neighbor" && isInternalSession(statement.asn));
|
|
67
|
+
if (!hasInternalNeighbor) {
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
for (const statement of declaration.statements) {
|
|
71
|
+
if (statement.kind !== "neighbor" || !statement.asn) {
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
if (isInternalSession(statement.asn) ||
|
|
75
|
+
isExternalSession(statement.asn)) {
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
const remoteAs = numericValue(statement.asn);
|
|
79
|
+
if (remoteAs === null || remoteAs === localAs) {
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
diagnostics.push(createRuleDiagnostic("bgp/as-mismatch", `BGP protocol '${declaration.name}' internal session requires same ASN (local ${localAs}, remote ${remoteAs})`, statement.asnRange ?? statement.addressRange));
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return diagnostics;
|
|
86
|
+
};
|
|
87
|
+
const bgpTimerInvalidRule = ({ parsed }) => {
|
|
88
|
+
const diagnostics = [];
|
|
89
|
+
for (const declaration of protocolDeclarations(parsed)) {
|
|
90
|
+
if (!isProtocolType(declaration, "bgp")) {
|
|
91
|
+
continue;
|
|
92
|
+
}
|
|
93
|
+
let hold = null;
|
|
94
|
+
let keepalive = null;
|
|
95
|
+
for (const statement of declaration.statements) {
|
|
96
|
+
if (statement.kind !== "other") {
|
|
97
|
+
continue;
|
|
98
|
+
}
|
|
99
|
+
const text = statement.text.toLowerCase();
|
|
100
|
+
const holdValue = extractFirstNumberAfterKeyword(text, "hold");
|
|
101
|
+
const keepaliveValue = extractFirstNumberAfterKeyword(text, "keepalive");
|
|
102
|
+
if (holdValue !== null) {
|
|
103
|
+
hold = holdValue;
|
|
104
|
+
if (hold < 3 || hold > 65_535) {
|
|
105
|
+
diagnostics.push(createRuleDiagnostic("bgp/timer-invalid", `BGP protocol '${declaration.name}' hold time must be in range 3..65535`, statement));
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
if (keepaliveValue !== null) {
|
|
109
|
+
keepalive = keepaliveValue;
|
|
110
|
+
if (keepalive < 1 || keepalive > 65_535) {
|
|
111
|
+
diagnostics.push(createRuleDiagnostic("bgp/timer-invalid", `BGP protocol '${declaration.name}' keepalive must be in range 1..65535`, statement));
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
if (hold !== null && keepalive !== null && keepalive >= hold) {
|
|
116
|
+
diagnostics.push(createProtocolDiagnostic("bgp/timer-invalid", `BGP protocol '${declaration.name}' keepalive (${keepalive}) must be smaller than hold (${hold})`, declaration));
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
return diagnostics;
|
|
120
|
+
};
|
|
121
|
+
export const bgpRules = [
|
|
122
|
+
bgpMissingLocalAsRule,
|
|
123
|
+
bgpMissingNeighborRule,
|
|
124
|
+
bgpMissingRemoteAsRule,
|
|
125
|
+
bgpAsMismatchRule,
|
|
126
|
+
bgpTimerInvalidRule,
|
|
127
|
+
];
|
|
128
|
+
export const collectBgpRuleDiagnostics = (context) => {
|
|
129
|
+
return bgpRules.flatMap((rule) => rule(context));
|
|
130
|
+
};
|
|
131
|
+
//# sourceMappingURL=bgp.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bgp.js","sourceRoot":"","sources":["../../src/rules/bgp.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { BirdDiagnosticSeverity } from "@birdcc/core";
|
|
2
|
+
export declare const RULE_CODES: {
|
|
3
|
+
readonly sym: readonly ["sym/undefined", "sym/duplicate", "sym/proto-type-mismatch", "sym/filter-required", "sym/function-required", "sym/table-required", "sym/variable-scope"];
|
|
4
|
+
readonly cfg: readonly ["cfg/no-protocol", "cfg/missing-router-id", "cfg/syntax-error", "cfg/value-out-of-range", "cfg/switch-value-expected", "cfg/number-expected", "cfg/incompatible-type", "cfg/ip-network-mismatch", "cfg/circular-template"];
|
|
5
|
+
readonly net: readonly ["net/invalid-prefix-length", "net/invalid-ipv4-prefix", "net/invalid-ipv6-prefix", "net/max-prefix-length"];
|
|
6
|
+
readonly type: readonly ["type/mismatch", "type/not-iterable", "type/set-incompatible"];
|
|
7
|
+
readonly bgp: readonly ["bgp/missing-local-as", "bgp/missing-neighbor", "bgp/missing-remote-as", "bgp/as-mismatch", "bgp/timer-invalid"];
|
|
8
|
+
readonly ospf: readonly ["ospf/missing-area", "ospf/backbone-stub", "ospf/vlink-in-backbone", "ospf/asbr-stub-area"];
|
|
9
|
+
};
|
|
10
|
+
export type RuleCode = (typeof RULE_CODES.sym)[number] | (typeof RULE_CODES.cfg)[number] | (typeof RULE_CODES.net)[number] | (typeof RULE_CODES.type)[number] | (typeof RULE_CODES.bgp)[number] | (typeof RULE_CODES.ospf)[number];
|
|
11
|
+
export declare const RULE_SEVERITY: Record<RuleCode, BirdDiagnosticSeverity>;
|
|
12
|
+
export declare const LEGACY_CODE_PATTERNS: readonly [RegExp, RegExp, RegExp, RegExp];
|
|
13
|
+
export declare const isRuleCode: (code: string) => code is RuleCode;
|
|
14
|
+
//# sourceMappingURL=catalog.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"catalog.d.ts","sourceRoot":"","sources":["../../src/rules/catalog.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,cAAc,CAAC;AAE3D,eAAO,MAAM,UAAU;;;;;;;CAyCb,CAAC;AAEX,MAAM,MAAM,QAAQ,GAChB,CAAC,OAAO,UAAU,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,GAC/B,CAAC,OAAO,UAAU,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,GAC/B,CAAC,OAAO,UAAU,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,GAC/B,CAAC,OAAO,UAAU,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,GAChC,CAAC,OAAO,UAAU,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,GAC/B,CAAC,OAAO,UAAU,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC;AAarC,eAAO,MAAM,aAAa,EAAE,MAAM,CAAC,QAAQ,EAAE,sBAAsB,CAIhE,CAAC;AAEJ,eAAO,MAAM,oBAAoB,2CAKvB,CAAC;AAEX,eAAO,MAAM,UAAU,GAAI,MAAM,MAAM,KAAG,IAAI,IAAI,QAEjD,CAAC"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
export const RULE_CODES = {
|
|
2
|
+
sym: [
|
|
3
|
+
"sym/undefined",
|
|
4
|
+
"sym/duplicate",
|
|
5
|
+
"sym/proto-type-mismatch",
|
|
6
|
+
"sym/filter-required",
|
|
7
|
+
"sym/function-required",
|
|
8
|
+
"sym/table-required",
|
|
9
|
+
"sym/variable-scope",
|
|
10
|
+
],
|
|
11
|
+
cfg: [
|
|
12
|
+
"cfg/no-protocol",
|
|
13
|
+
"cfg/missing-router-id",
|
|
14
|
+
"cfg/syntax-error",
|
|
15
|
+
"cfg/value-out-of-range",
|
|
16
|
+
"cfg/switch-value-expected",
|
|
17
|
+
"cfg/number-expected",
|
|
18
|
+
"cfg/incompatible-type",
|
|
19
|
+
"cfg/ip-network-mismatch",
|
|
20
|
+
"cfg/circular-template",
|
|
21
|
+
],
|
|
22
|
+
net: [
|
|
23
|
+
"net/invalid-prefix-length",
|
|
24
|
+
"net/invalid-ipv4-prefix",
|
|
25
|
+
"net/invalid-ipv6-prefix",
|
|
26
|
+
"net/max-prefix-length",
|
|
27
|
+
],
|
|
28
|
+
type: ["type/mismatch", "type/not-iterable", "type/set-incompatible"],
|
|
29
|
+
bgp: [
|
|
30
|
+
"bgp/missing-local-as",
|
|
31
|
+
"bgp/missing-neighbor",
|
|
32
|
+
"bgp/missing-remote-as",
|
|
33
|
+
"bgp/as-mismatch",
|
|
34
|
+
"bgp/timer-invalid",
|
|
35
|
+
],
|
|
36
|
+
ospf: [
|
|
37
|
+
"ospf/missing-area",
|
|
38
|
+
"ospf/backbone-stub",
|
|
39
|
+
"ospf/vlink-in-backbone",
|
|
40
|
+
"ospf/asbr-stub-area",
|
|
41
|
+
],
|
|
42
|
+
};
|
|
43
|
+
const ruleSeverityEntries = [
|
|
44
|
+
...RULE_CODES.sym.map((code) => [code, "error"]),
|
|
45
|
+
...RULE_CODES.cfg.map((code) => [code, "error"]),
|
|
46
|
+
...RULE_CODES.net.map((code) => [code, "error"]),
|
|
47
|
+
...RULE_CODES.type.map((code) => [code, "error"]),
|
|
48
|
+
...RULE_CODES.bgp.map((code) => [code, "warning"]),
|
|
49
|
+
...RULE_CODES.ospf.map((code) => [code, "warning"]),
|
|
50
|
+
];
|
|
51
|
+
export const RULE_SEVERITY = Object.fromEntries(ruleSeverityEntries);
|
|
52
|
+
export const LEGACY_CODE_PATTERNS = [
|
|
53
|
+
/^protocol\//,
|
|
54
|
+
/^security\//,
|
|
55
|
+
/^performance\//,
|
|
56
|
+
/^structure\//,
|
|
57
|
+
];
|
|
58
|
+
export const isRuleCode = (code) => {
|
|
59
|
+
return code in RULE_SEVERITY;
|
|
60
|
+
};
|
|
61
|
+
//# sourceMappingURL=catalog.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"catalog.js","sourceRoot":"","sources":["../../src/rules/catalog.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,UAAU,GAAG;IACxB,GAAG,EAAE;QACH,eAAe;QACf,eAAe;QACf,yBAAyB;QACzB,qBAAqB;QACrB,uBAAuB;QACvB,oBAAoB;QACpB,oBAAoB;KACrB;IACD,GAAG,EAAE;QACH,iBAAiB;QACjB,uBAAuB;QACvB,kBAAkB;QAClB,wBAAwB;QACxB,2BAA2B;QAC3B,qBAAqB;QACrB,uBAAuB;QACvB,yBAAyB;QACzB,uBAAuB;KACxB;IACD,GAAG,EAAE;QACH,2BAA2B;QAC3B,yBAAyB;QACzB,yBAAyB;QACzB,uBAAuB;KACxB;IACD,IAAI,EAAE,CAAC,eAAe,EAAE,mBAAmB,EAAE,uBAAuB,CAAC;IACrE,GAAG,EAAE;QACH,sBAAsB;QACtB,sBAAsB;QACtB,uBAAuB;QACvB,iBAAiB;QACjB,mBAAmB;KACpB;IACD,IAAI,EAAE;QACJ,mBAAmB;QACnB,oBAAoB;QACpB,wBAAwB;QACxB,qBAAqB;KACtB;CACO,CAAC;AAUX,MAAM,mBAAmB,GAErB;IACF,GAAG,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,OAAO,CAAU,CAAC;IACzD,GAAG,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,OAAO,CAAU,CAAC;IACzD,GAAG,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,OAAO,CAAU,CAAC;IACzD,GAAG,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,OAAO,CAAU,CAAC;IAC1D,GAAG,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,SAAS,CAAU,CAAC;IAC3D,GAAG,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,SAAS,CAAU,CAAC;CAC7D,CAAC;AAEF,MAAM,CAAC,MAAM,aAAa,GACxB,MAAM,CAAC,WAAW,CAAC,mBAAmB,CAGrC,CAAC;AAEJ,MAAM,CAAC,MAAM,oBAAoB,GAAG;IAClC,aAAa;IACb,aAAa;IACb,gBAAgB;IAChB,cAAc;CACN,CAAC;AAEX,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,IAAY,EAAoB,EAAE;IAC3D,OAAO,IAAI,IAAI,aAAa,CAAC;AAC/B,CAAC,CAAC"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { BirdDiagnostic } from "@birdcc/core";
|
|
2
|
+
import { type BirdRule } from "./shared.js";
|
|
3
|
+
export declare const cfgRules: BirdRule[];
|
|
4
|
+
export declare const collectCfgRuleDiagnostics: (context: Parameters<BirdRule>[0]) => BirdDiagnostic[];
|
|
5
|
+
//# sourceMappingURL=cfg.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cfg.d.ts","sourceRoot":"","sources":["../../src/rules/cfg.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAEnD,OAAO,EAYL,KAAK,QAAQ,EACd,MAAM,aAAa,CAAC;AAkhBrB,eAAO,MAAM,QAAQ,EAAE,QAAQ,EAS9B,CAAC;AAEF,eAAO,MAAM,yBAAyB,GACpC,SAAS,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,KAC/B,cAAc,EAEhB,CAAC"}
|