@synapsestudios/lintofu 0.9.0 → 0.9.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/README.md
CHANGED
|
@@ -3,46 +3,68 @@
|
|
|
3
3
|
An ESLint plugin for linting [OpenTofu](https://opentofu.org) configurations.
|
|
4
4
|
|
|
5
5
|
> [!WARNING]
|
|
6
|
-
> The parser depends on Go's [`syscall/js`](https://pkg.go.dev/syscall/js), which the Go team has declared experimental and exempt from the Go compatibility promise. A future Go release
|
|
6
|
+
> The parser depends on Go's [`syscall/js`](https://pkg.go.dev/syscall/js), which the Go team has declared experimental and exempt from the Go compatibility promise. A future Go release _may_ break the functionality of this plugin. `lintofu` will stay on `0.x` until `syscall/js` stabilizes or we replace it. See [ADR 0001](./docs/adr/0001-syscall-js-experimental.md).
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
This is a pre-release and experimental ESLint plugin.
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
Published to npm as [`@synapsestudios/lintofu`](https://www.npmjs.com/package/@synapsestudios/lintofu).
|
|
11
|
+
|
|
12
|
+
## Head striaght to the docs?
|
|
13
|
+
|
|
14
|
+
The lintofu docs are located here: [synapsestudios.github.io/lintofu](https://synapsestudios.github.io/lintofu/) the frontend that represents the documentation located in [`docs/`](./docs).
|
|
11
15
|
|
|
12
16
|
## What it is
|
|
13
17
|
|
|
14
|
-
`lintofu` is an **ESLint language plugin** (the same mechanism that powers [`@eslint/json`](https://github.com/eslint/json) and [`@eslint/css`](https://github.com/eslint/css)).
|
|
18
|
+
`lintofu` is an **ESLint language plugin** (the same mechanism that powers [`@eslint/json`](https://github.com/eslint/json) and [`@eslint/css`](https://github.com/eslint/css)).
|
|
19
|
+
|
|
20
|
+
It parses `.tf` and `.tofu` files using HashiCorp's own `hcl/v2` parser (compiled to WebAssembly) and exposes the AST to ESLint rules so you can enforce OpenTofu or Terraform coding conventions alongside the rest of your ESLint rules.
|
|
21
|
+
|
|
22
|
+
### What it (is not)
|
|
23
|
+
|
|
24
|
+
We (Synapse Studios) have been using this internally for a few months. This statement is to provide clarity on the kind of expectations you should have when engaging with it, we will accept contributions from the community, however, we can make no promises as to what kind of attention we will be able to give it when it comes to approving/reviewing/or otherwise engaging with community feedback.
|
|
25
|
+
|
|
26
|
+
This will be (for the foreseeable future) _best effort_ and sometimes we will be too busy to triage incoming pull requests or bug reports.
|
|
27
|
+
|
|
28
|
+
### AI Disclosure
|
|
29
|
+
|
|
30
|
+
To be clear, AI _has_ been used to help build this tool, but the specifications, features, rules, the way in which the plugin handles rule precedence, processing, and the like have _all_ been defined by humans clearly, with insight and scrutiny from a team of experienced DevOps engineers and Software Engineers in order to build something that isn't complete slop. We're tired of slop.
|
|
15
31
|
|
|
16
32
|
## Scope
|
|
17
33
|
|
|
18
|
-
`lintofu`
|
|
34
|
+
`lintofu` asserts against syntactic problems, stylistic conventions, and some provider specific code smells. We provide a list of somewhat generic (but other times opinionated) set of core rules, listed in our [rules index](https://synapsestudios.github.io/lintofu/rules/), that you can take advantage of.
|
|
35
|
+
|
|
36
|
+
### Our intentions for `lintofu`:
|
|
19
37
|
|
|
20
|
-
-
|
|
21
|
-
- Semantic and evaluated rules (type-checking, symbol resolution) belong to the future built-in linter described in the [OpenTofu linting RFC](https://github.com/opentofu/opentofu/pull/3999), which needs the full language runtime. `lintofu` stays on the syntactic and stylistic side, where ESLint's ecosystem already fits.
|
|
22
|
-
- `lintofu` is a fresh ESLint-native tool. It shares no code with TFLint, which lacks OpenTofu-specific feature support.
|
|
38
|
+
We built lintofu as a stop-gap until feature rich fully fledged linting is available. You can read more about that from the [OpenTofu linting RFC](https://github.com/opentofu/opentofu/pull/3999). This isn't meant to be a complete replacement for what will soon be the linter implementation in OpenTofu, however, it _is_ meant to provide all of the necessary facilities and interfaces to build a comprehensive suite of assertions and rules at the same level.
|
|
23
39
|
|
|
24
40
|
## Install
|
|
25
41
|
|
|
42
|
+
### Pre-requisites
|
|
43
|
+
|
|
44
|
+
Required versions:
|
|
45
|
+
- Node >= `22.13`
|
|
46
|
+
- ESLint >= `9.x`
|
|
47
|
+
|
|
48
|
+
### Setup
|
|
49
|
+
|
|
26
50
|
```sh
|
|
27
51
|
npm install --save-dev @synapsestudios/lintofu
|
|
28
52
|
```
|
|
29
53
|
|
|
30
|
-
|
|
54
|
+
If you installed it from GitHub Packages before, delete these lines from your `.npmrc`. While they're there, npm resolves every `@synapsestudios` package from GitHub Packages, which no longer gets new releases:
|
|
31
55
|
|
|
32
56
|
```
|
|
33
57
|
@synapsestudios:registry=https://npm.pkg.github.com
|
|
34
58
|
//npm.pkg.github.com/:_authToken=${GITHUB_TOKEN}
|
|
35
59
|
```
|
|
36
60
|
|
|
37
|
-
Requires Node ^20.19, ^22.13, or >=24 and ESLint ^9 || ^10.
|
|
38
|
-
|
|
39
61
|
## Supported versions
|
|
40
62
|
|
|
41
|
-
|
|
63
|
+
We would like to have as broad of compatibility as possible, so our aim is to have full compatibility with the major cloud providers in which our rules are tested against, from the _last_ major version to the latest major version.
|
|
42
64
|
|
|
43
|
-
|
|
65
|
+
As this plugin ages, we expect to have to provide _some_ backwards compatibility with our rules that may target older providers' code smells, but our focus will be on moving the tool forwards with the rest of the ecosystem. Our full decision making record and rationale on this is defined in [ADR 0005](./docs/adr/0005-version-support-policy.md).
|
|
44
66
|
|
|
45
|
-
|
|
67
|
+
The parser wraps HashiCorp's `hcl/v2`, which parses HCL2, the syntax that shipped with Terraform 0.12. We _will not be supporting `hcl/v1` or Terraform versions that pre-date `0.12`.
|
|
46
68
|
|
|
47
69
|
<!-- lintofu:support-matrix:start -->
|
|
48
70
|
|
|
@@ -55,20 +77,18 @@ Above the floor, the same ADR defines the per-generation status:
|
|
|
55
77
|
|
|
56
78
|
<!-- lintofu:support-matrix:end -->
|
|
57
79
|
|
|
58
|
-
- **supported**:
|
|
59
|
-
- **best effort**:
|
|
60
|
-
- **unsupported**:
|
|
61
|
-
|
|
62
|
-
These statuses are policy commitments, not CI results: no workflow runs real OpenTofu or Terraform binaries yet. This table is maintained by hand and will be replaced by generated output once the version test harness exists.
|
|
80
|
+
- **supported**: We focus on building rules that apply to these versions.
|
|
81
|
+
- **best effort**: Some rules may target these specific versions and the gotchas associated with upgrading _from_ them, but we won't be writing rules that target specific syntax that is only applicable to these versions.
|
|
82
|
+
- **unsupported**: The parser will reject these.
|
|
63
83
|
|
|
64
84
|
<!-- lintofu:tested-versions:start -->
|
|
65
85
|
|
|
66
86
|
## Tested provider versions
|
|
67
87
|
|
|
68
|
-
Provider-specific rules are validated against these versions. [`provider-versions.json`](./provider-versions.json)
|
|
88
|
+
Provider-specific rules are validated against these versions. This is a list located here: [`provider-versions.json`](./provider-versions.json) which defines which provider versions we test against in CI.
|
|
69
89
|
|
|
70
|
-
- aws provider v6.42.0
|
|
71
|
-
- cloudflare provider v5.24.0
|
|
90
|
+
- aws provider `v6.42.0`
|
|
91
|
+
- cloudflare provider `v5.24.0`
|
|
72
92
|
|
|
73
93
|
<!-- lintofu:tested-versions:end -->
|
|
74
94
|
|
|
@@ -81,7 +101,7 @@ import lintofu from "@synapsestudios/lintofu";
|
|
|
81
101
|
export default [lintofu.configs.recommended];
|
|
82
102
|
```
|
|
83
103
|
|
|
84
|
-
Or
|
|
104
|
+
Or opt into specific rules and error statuses.
|
|
85
105
|
|
|
86
106
|
```js
|
|
87
107
|
// eslint.config.js
|
|
@@ -102,21 +122,11 @@ export default [
|
|
|
102
122
|
|
|
103
123
|
## Rules
|
|
104
124
|
|
|
105
|
-
Every rule's description, severity, category, recommended flag, and autofix
|
|
106
|
-
support lives in the generated rule index:
|
|
107
|
-
|
|
108
|
-
- **[Rule index](https://synapsestudios.github.io/lintofu/rules/)** on the
|
|
109
|
-
documentation site
|
|
110
|
-
- [`docs/rules/index.md`](./docs/rules/index.md) in this repository, the same
|
|
111
|
-
content, which resolves here today while the site is still private
|
|
112
|
-
|
|
113
|
-
The index is generated from each rule's `meta.docs` by `npm run docs:rules`, and
|
|
114
|
-
CI fails on a rule with no docs page or a stale index, so it cannot drift from
|
|
115
|
-
the rules that actually ship.
|
|
125
|
+
Every rule's description, severity, category, recommended flag, and autofix support lives in the generated **[Rule index](https://synapsestudios.github.io/lintofu/rules/)** on the documentation site
|
|
116
126
|
|
|
117
127
|
## Requesting a rule
|
|
118
128
|
|
|
119
|
-
To suggest a new rule, open a [rule request](https://github.com/synapsestudios/lintofu/issues/new?template=rule-request.yml). The form asks for a snippet the rule should flag, the compliant form, a category, a suggested severity, whether an autofix seems possible, and any references.
|
|
129
|
+
To suggest a new rule, open a [rule request](https://github.com/synapsestudios/lintofu/issues/new?template=rule-request.yml). The form asks for a snippet the rule should flag, the compliant form, a category, a suggested severity, whether an autofix seems possible, and any references. One of our maintainers will pick up your issue and approve it or reject it with a reason.
|
|
120
130
|
|
|
121
131
|
## Parser services
|
|
122
132
|
|
|
@@ -129,24 +139,14 @@ in this repository.
|
|
|
129
139
|
|
|
130
140
|
## Writing your own rule
|
|
131
141
|
|
|
132
|
-
`lintofu` re-exports the rule-authoring types it uses internally, so a custom
|
|
133
|
-
rule type-checks without reaching into private modules. The worked example is in
|
|
134
|
-
the developer guide:
|
|
135
|
-
[on the site](https://synapsestudios.github.io/lintofu/developer-guide/writing-a-rule)
|
|
136
|
-
or [`docs/developer-guide/writing-a-rule.md`](./docs/developer-guide/writing-a-rule.md)
|
|
137
|
-
in this repository.
|
|
142
|
+
`lintofu` re-exports the rule-authoring types it uses internally, so a custom rule type-checks without reaching into private modules. We have an example of this [on the site](https://synapsestudios.github.io/lintofu/developer-guide/writing-a-rule) or [`docs/developer-guide/writing-a-rule.md`](./docs/developer-guide/writing-a-rule.md) in this repository.
|
|
138
143
|
|
|
139
144
|
## Architecture
|
|
140
145
|
|
|
141
146
|
The parser is Go: `github.com/hashicorp/hcl/v2/hclsyntax` compiled to
|
|
142
|
-
WebAssembly.
|
|
143
|
-
[on the site](https://synapsestudios.github.io/lintofu/developer-guide/architecture)
|
|
144
|
-
or [`docs/developer-guide/architecture.md`](./docs/developer-guide/architecture.md)
|
|
145
|
-
in this repository.
|
|
147
|
+
WebAssembly. We have a simple ASCII representation of the architecture here [on the site](https://synapsestudios.github.io/lintofu/developer-guide/architecture) or [`docs/developer-guide/architecture.md`](./docs/developer-guide/architecture.md) in this repository.
|
|
146
148
|
|
|
147
149
|
## Known limitations
|
|
148
150
|
|
|
149
|
-
- **Experimental dependency on `syscall/js`.** See [ADR 0001](./docs/adr/0001-syscall-js-experimental.md). The project inherits its experimental status from Go's WASM JS interop package. Pinning a Go version in CI is the mitigation.
|
|
150
151
|
- **`.tf.json` / `.tofu.json` not supported.** The JSON form of HCL is not 1:1 with native syntax; see [hashicorp/hcl#627 for the rationale](https://github.com/hashicorp/hcl/issues/627).
|
|
151
|
-
- **No TFLint custom-rule compatibility.**
|
|
152
|
-
- **Performance is unprofiled.** Go+WASM boot costs ~100ms per ESLint process; per-file parse is sub-millisecond after boot.
|
|
152
|
+
- **No TFLint custom-rule compatibility.** We are _considering_ adding `tflint` support so that users can import rules, but we haven't made a decision on whether or not it should happen.
|
|
Binary file
|
|
@@ -2,7 +2,7 @@ const rule = {
|
|
|
2
2
|
meta: {
|
|
3
3
|
type: 'problem',
|
|
4
4
|
docs: {
|
|
5
|
-
description: 'Flag legacy `aws_security_group_rule` resources and inline `ingress`/`egress` blocks; prefer `
|
|
5
|
+
description: 'Flag legacy `aws_security_group_rule` resources and inline `ingress`/`egress` blocks; prefer `aws_vpc_security_group_ingress_rule` and `aws_vpc_security_group_egress_rule`.',
|
|
6
6
|
recommended: true,
|
|
7
7
|
severity: 'error',
|
|
8
8
|
category: 'aws',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"no-legacy-security-group-rules.js","sourceRoot":"","sources":["../../../src/rules/aws/no-legacy-security-group-rules.ts"],"names":[],"mappings":"AAEA,MAAM,IAAI,GAEL;IACH,IAAI,EAAE;QACJ,IAAI,EAAE,SAAS;QACf,IAAI,EAAE;YACJ,WAAW,EACT,
|
|
1
|
+
{"version":3,"file":"no-legacy-security-group-rules.js","sourceRoot":"","sources":["../../../src/rules/aws/no-legacy-security-group-rules.ts"],"names":[],"mappings":"AAEA,MAAM,IAAI,GAEL;IACH,IAAI,EAAE;QACJ,IAAI,EAAE,SAAS;QACf,IAAI,EAAE;YACJ,WAAW,EACT,8KAA8K;YAChL,WAAW,EAAE,IAAI;YACjB,QAAQ,EAAE,OAAO;YACjB,QAAQ,EAAE,KAAK;SAChB;QACD,QAAQ,EAAE;YACR,uBAAuB,EACrB,qPAAqP;SACxP;QACD,MAAM,EAAE,EAAE;KACX;IACD,MAAM,CAAC,OAAO;QACZ,OAAO;YACL,KAAK,CAAC,IAAI;gBACR,IAAI,IAAI,CAAC,IAAI,KAAK,UAAU;oBAAE,OAAO;gBACrC,IAAI,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,yBAAyB,EAAE,CAAC;oBACjD,OAAO,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,yBAAyB,EAAE,CAAC,CAAC;oBAC/D,OAAO;gBACT,CAAC;gBACD,IAAI,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,oBAAoB,EAAE,CAAC;oBAC5C,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;wBACrC,IAAI,KAAK,CAAC,IAAI,KAAK,SAAS,IAAI,KAAK,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;4BACxD,OAAO,CAAC,MAAM,CAAC;gCACb,IAAI,EAAE,KAAK;gCACX,SAAS,EAAE,yBAAyB;6BACrC,CAAC,CAAC;wBACL,CAAC;oBACH,CAAC;gBACH,CAAC;YACH,CAAC;SACF,CAAC;IACJ,CAAC;CACF,CAAC;AAEF,eAAe,IAAI,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@synapsestudios/lintofu",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.1",
|
|
4
4
|
"description": "ESLint plugin for linting OpenTofu configurations",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -60,23 +60,23 @@
|
|
|
60
60
|
},
|
|
61
61
|
"devDependencies": {
|
|
62
62
|
"@eslint/js": "^10.0.1",
|
|
63
|
-
"@types/node": "^26.6.
|
|
64
|
-
"eslint": "^10.
|
|
63
|
+
"@types/node": "^26.6.6",
|
|
64
|
+
"eslint": "^10.14.0",
|
|
65
65
|
"eslint-config-prettier": "^10.1.8",
|
|
66
66
|
"eslint-plugin-eslint-plugin": "^7.6.2",
|
|
67
|
-
"eslint-plugin-jsdoc": "^
|
|
68
|
-
"eslint-plugin-prettier": "^5.5.
|
|
69
|
-
"eslint-plugin-security": "^4.
|
|
70
|
-
"eslint-plugin-tsdoc": "^0.5.
|
|
71
|
-
"globals": "^17.
|
|
72
|
-
"lefthook": "^2.
|
|
73
|
-
"prettier": "^3.9.
|
|
67
|
+
"eslint-plugin-jsdoc": "^65.4.2",
|
|
68
|
+
"eslint-plugin-prettier": "^5.5.7",
|
|
69
|
+
"eslint-plugin-security": "^4.2.1",
|
|
70
|
+
"eslint-plugin-tsdoc": "^0.5.4",
|
|
71
|
+
"globals": "^17.13.0",
|
|
72
|
+
"lefthook": "^2.2.2",
|
|
73
|
+
"prettier": "^3.9.10",
|
|
74
74
|
"prettier-plugin-organize-imports": "^4.3.0",
|
|
75
75
|
"tsx": "^4.23.15",
|
|
76
76
|
"typescript": "^6.0.3",
|
|
77
|
-
"typescript-eslint": "^8.
|
|
77
|
+
"typescript-eslint": "^8.72.1",
|
|
78
78
|
"vitepress": "^1.6.4",
|
|
79
|
-
"vitest": "^5.0.
|
|
79
|
+
"vitest": "^5.0.5"
|
|
80
80
|
},
|
|
81
81
|
"keywords": [
|
|
82
82
|
"eslint",
|