flecto 4.0.0 → 4.1.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/CHANGELOG.md +103 -1
- package/README.md +107 -471
- package/package.json +15 -8
- package/src/positions.js +9 -3
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,106 @@ The format is based on [Keep a Changelog], and this project adheres to
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [4.1.1] - 2026-09-29
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
|
|
14
|
+
- **The root `action.yml` description was too long to list on the Marketplace.**
|
|
15
|
+
GitHub rejects a listing whose description is 125 characters or more; 4.1.0
|
|
16
|
+
shipped 194. It is now 119, and a test pins the limit — the constraint is not
|
|
17
|
+
in GitHub's metadata-syntax documentation and the publish form only reports it
|
|
18
|
+
at publish time, by which point the release is already cut.
|
|
19
|
+
|
|
20
|
+
The rest of the pitch — that Flecto never runs `terraform`, `helm`, or `sops`,
|
|
21
|
+
and never decrypts — lives in the README, which has room for it.
|
|
22
|
+
|
|
23
|
+
### Fixed
|
|
24
|
+
|
|
25
|
+
- **Documented Action pins moved from `@v4.0.0` to `@v4.1.0`.** Tags are
|
|
26
|
+
immutable, and the fix that stopped the bundled Actions installing the pre-4.0
|
|
27
|
+
CLI shipped *in* 4.1.0 — so while the examples said `@v4.0.0` they pointed at a
|
|
28
|
+
tag whose `flecto-ci` and `flecto-pr-risk` still run `flecto@3`, the line
|
|
29
|
+
exposed to the baseline-shadowing bypass 4.0 closed.
|
|
30
|
+
|
|
31
|
+
**If you pinned `@v4.0.0` following an earlier example, repin to `@v4.1.0`.**
|
|
32
|
+
The CLI at `flecto@4.0.0` is fine; it is only the bundled Action metadata at
|
|
33
|
+
that tag that is not. [docs/ci.md](docs/ci.md#pinning) now warns against it.
|
|
34
|
+
|
|
35
|
+
[RELEASE.md](RELEASE.md) gained a step that repins the documented Actions as
|
|
36
|
+
part of every release. That step is the real fix — the bug was not the pin, it
|
|
37
|
+
was that nothing tied the documented pin to the release that fixed what it
|
|
38
|
+
pointed at.
|
|
39
|
+
|
|
40
|
+
## [4.1.0] - 2026-09-29
|
|
41
|
+
|
|
42
|
+
### Added
|
|
43
|
+
|
|
44
|
+
- **A root [`action.yml`](action.yml), so the Action can be listed on the GitHub
|
|
45
|
+
Marketplace.** GitHub only lists an action whose metadata file sits at a public
|
|
46
|
+
repository's root; Flecto's Actions live in `.github/actions/`, which is why
|
|
47
|
+
they were never listable. The listed action is `flecto-pr-risk` — the pull
|
|
48
|
+
request risk comment — with branding and the wedge description.
|
|
49
|
+
|
|
50
|
+
`.github/actions/flecto-pr-risk/action.yml` **stays exactly where it is**, so
|
|
51
|
+
nothing referencing that path changes. The two files' `runs:` blocks are
|
|
52
|
+
byte-identical and a test enforces it, so a fix to one is a CI failure until it
|
|
53
|
+
lands in both.
|
|
54
|
+
|
|
55
|
+
Docs continue to reference
|
|
56
|
+
`myselfsiddharth/Flecto/.github/actions/flecto-pr-risk@v4.0.0` until a release
|
|
57
|
+
carrying the root file exists. The shorter `myselfsiddharth/Flecto@vX.Y.Z` form
|
|
58
|
+
becomes correct at that point; see [RELEASE.md](RELEASE.md) step 5.
|
|
59
|
+
|
|
60
|
+
- **`flecto-pr-risk` takes a Terraform plan directly.** A new `terraform-plan`
|
|
61
|
+
input points at `terraform show -json` output and switches the Action to
|
|
62
|
+
`flecto plan`, so reviewing a plan on every pull request is two steps:
|
|
63
|
+
|
|
64
|
+
```yaml
|
|
65
|
+
- run: terraform plan -out=tf.plan && terraform show -json tf.plan > plan.json
|
|
66
|
+
- uses: myselfsiddharth/Flecto/.github/actions/flecto-pr-risk@v4.0.0
|
|
67
|
+
with:
|
|
68
|
+
terraform-plan: plan.json
|
|
69
|
+
fail-on: error
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Because a plan JSON carries its own before and after, **no baseline is resolved
|
|
73
|
+
and no git history is needed** in this mode — the `fetch-depth: 0` that config
|
|
74
|
+
mode wants does not apply, and the Action runs on events with no pull request
|
|
75
|
+
base commit. A missing plan file fails the step rather than letting Flecto
|
|
76
|
+
report nothing. `targets` is ignored; add a second step without
|
|
77
|
+
`terraform-plan` to also check config files.
|
|
78
|
+
|
|
79
|
+
Config mode is unchanged, including its fail-closed behaviour when no baseline
|
|
80
|
+
can be resolved. A complete workflow is in
|
|
81
|
+
[`examples/github-action/flecto-terraform-plan.yml`](examples/github-action/flecto-terraform-plan.yml).
|
|
82
|
+
|
|
83
|
+
- [docs/stability.md](docs/stability.md): what the public contract covers (the
|
|
84
|
+
`schema_version: "2.0"` envelope, exit codes, `.flectorc`, the CLI surface),
|
|
85
|
+
what it deliberately does not, and the deprecation sequence — one minor release
|
|
86
|
+
carrying a warning before any removal, with security fixes the stated
|
|
87
|
+
exception.
|
|
88
|
+
|
|
89
|
+
### Fixed
|
|
90
|
+
|
|
91
|
+
- **The bundled GitHub Actions installed the pre-4.0 CLI.** `flecto-ci`
|
|
92
|
+
hardcoded `npx --yes flecto@3` and `flecto-pr-risk` defaulted
|
|
93
|
+
`flecto-version: "3"`, so both shipped Actions ran the 3.x line after 4.0.0
|
|
94
|
+
released. Two consequences: `flecto-ci`'s advertised `snapshot-file:` input
|
|
95
|
+
passed a flag that does not exist before 4.0, and its default
|
|
96
|
+
`snapshot-ref: HEAD~1` against a 3.x CLI is the baseline-shadowing bypass 4.0
|
|
97
|
+
closed — a pull request commits a file named `HEAD~1`, it is read instead of
|
|
98
|
+
the revision, the diff comes back empty and no `--fail-on` value catches it.
|
|
99
|
+
|
|
100
|
+
Both now default to `4`. `flecto-ci` gains a `flecto-version` input so the CLI
|
|
101
|
+
can be pinned without forking, matching `flecto-pr-risk`. A test asserts the
|
|
102
|
+
floor across both Actions, including hardcoded installs that would bypass the
|
|
103
|
+
input.
|
|
104
|
+
|
|
105
|
+
**If you copied an earlier README example you are affected**: the examples
|
|
106
|
+
referenced the Actions `@main`, which resolved to a 3.x install. Re-pin to
|
|
107
|
+
`@v4.0.0` — every example in the README and [docs/ci.md](docs/ci.md) now does,
|
|
108
|
+
with SHA pinning documented for security-sensitive users.
|
|
109
|
+
|
|
10
110
|
## [4.0.0] - 2026-09-23
|
|
11
111
|
|
|
12
112
|
**A security release.** Every breaking change below exists because a pull
|
|
@@ -1222,7 +1322,9 @@ fixed — those runs were never actually gated — but the failure is new.
|
|
|
1222
1322
|
- Misconfigured policy packs/plugins cause `watch` to exit non-zero instead of
|
|
1223
1323
|
continuing with no policies.
|
|
1224
1324
|
|
|
1225
|
-
[Unreleased]: https://github.com/myselfsiddharth/Flecto/compare/
|
|
1325
|
+
[Unreleased]: https://github.com/myselfsiddharth/Flecto/compare/v4.1.1...HEAD
|
|
1326
|
+
[4.1.1]: https://github.com/myselfsiddharth/Flecto/compare/v4.1.0...v4.1.1
|
|
1327
|
+
[4.1.0]: https://github.com/myselfsiddharth/Flecto/compare/v4.0.0...v4.1.0
|
|
1226
1328
|
[4.0.0]: https://github.com/myselfsiddharth/Flecto/compare/v3.1.0...v4.0.0
|
|
1227
1329
|
[3.1.0]: https://github.com/myselfsiddharth/Flecto/compare/v3.0.2...v3.1.0
|
|
1228
1330
|
[3.0.2]: https://github.com/myselfsiddharth/Flecto/compare/v3.0.1...v3.0.2
|
package/README.md
CHANGED
|
@@ -1,11 +1,8 @@
|
|
|
1
|
-
<p align="center">
|
|
2
|
-
<img src="docs/assets/flecto-hero.png" alt="Flecto — semantic config watcher" width="920"/>
|
|
3
|
-
</p>
|
|
4
|
-
|
|
5
1
|
<h1 align="center">Flecto</h1>
|
|
6
2
|
|
|
7
3
|
<p align="center">
|
|
8
|
-
<strong>
|
|
4
|
+
<strong>Flecto reads your Terraform plan and Kubernetes changes and posts a
|
|
5
|
+
plain-English risk summary on every pull request, blocking the dangerous ones.</strong>
|
|
9
6
|
</p>
|
|
10
7
|
|
|
11
8
|
<p align="center">
|
|
@@ -15,178 +12,87 @@
|
|
|
15
12
|
<a href="#documentation"><img alt="Docs" src="https://img.shields.io/badge/docs-read-34d399?style=flat-square&labelColor=0b1220"/></a>
|
|
16
13
|
</p>
|
|
17
14
|
|
|
18
|
-
<p align="center">
|
|
19
|
-
<img src="docs/assets/demo-watch.svg" alt="Flecto reporting semantic config changes in the terminal" width="920"/>
|
|
20
|
-
</p>
|
|
21
|
-
|
|
22
|
-
---
|
|
23
|
-
|
|
24
|
-
Config drives the parts of a system that break loudest: connection pools, feature
|
|
25
|
-
flags, TLS, retries, secrets. But we still review it as text — so a reordered key
|
|
26
|
-
looks identical to a doubled pool size, and `debug: true` slips through in a
|
|
27
|
-
40-line formatting diff.
|
|
28
|
-
|
|
29
|
-
Flecto reads config as structure, not lines. It tells you what changed in plain
|
|
30
|
-
English, flags what looks risky, and gives you an exit code to gate on.
|
|
31
|
-
|
|
32
|
-
| Reviewing config without Flecto | With Flecto |
|
|
33
|
-
|---|---|
|
|
34
|
-
| `+ 40 lines of YAML noise` | `~ database.pool_size: 5 → 20` |
|
|
35
|
-
| Hope someone notices `debug: true` | Policy finding → build fails |
|
|
36
|
-
| "Something in `.env` changed" | The exact keys, with secrets masked |
|
|
37
|
-
|
|
38
|
-
The same engine reads whatever your change actually lives in:
|
|
39
|
-
|
|
40
|
-
| You are reviewing | Flecto reads |
|
|
41
|
-
|---|---|
|
|
42
|
-
| App config — YAML, JSON, TOML, INI, dotenv | the files directly |
|
|
43
|
-
| A Terraform change | `terraform show -json` output, via `flecto plan` |
|
|
44
|
-
| A Kubernetes change | rendered manifests from `helm`, `kustomize`, or anything else |
|
|
45
|
-
| A SOPS-encrypted file | its structure and recipients — **never its plaintext** |
|
|
46
|
-
|
|
47
|
-
It never invokes `terraform`, `helm`, `kustomize`, `sops`, or `age`, so nothing
|
|
48
|
-
extra has to exist on the CI runner.
|
|
49
|
-
|
|
50
|
-
---
|
|
51
|
-
|
|
52
|
-
## Install
|
|
53
|
-
|
|
54
|
-
```bash
|
|
55
|
-
npm install -g flecto
|
|
56
|
-
```
|
|
57
|
-
|
|
58
|
-
Requires **Node.js 20.19.0+**. Verify:
|
|
59
|
-
|
|
60
|
-
```bash
|
|
61
|
-
flecto --version
|
|
62
|
-
flecto doctor
|
|
63
|
-
```
|
|
64
|
-
|
|
65
|
-
Prefer not to install globally? Every example below works with
|
|
66
|
-
`npx --yes flecto@3` instead of `flecto`.
|
|
67
|
-
|
|
68
15
|
---
|
|
69
16
|
|
|
70
|
-
##
|
|
71
|
-
|
|
72
|
-
A complete walkthrough, start to finish. Copy-paste it anywhere.
|
|
73
|
-
|
|
74
|
-
**1. Create a config file to track.**
|
|
17
|
+
## What lands on the pull request
|
|
75
18
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
database:
|
|
80
|
-
host: db.internal
|
|
81
|
-
pool_size: 5
|
|
82
|
-
ssl: true
|
|
83
|
-
logging:
|
|
84
|
-
level: info
|
|
85
|
-
debug: false
|
|
86
|
-
EOF
|
|
87
|
-
```
|
|
19
|
+
<p align="center">
|
|
20
|
+
<img src="docs/assets/flecto-pr-comment.png" alt="Flecto's comment on a pull request: check failing, six policy errors naming an IAM wildcard, a disabled S3 public-access block, and security group ingress opened to 0.0.0.0/0" width="960"/>
|
|
21
|
+
</p>
|
|
88
22
|
|
|
89
|
-
|
|
23
|
+
That is a real comment on a
|
|
24
|
+
**[real pull request](https://github.com/myselfsiddharth/flecto-example-terraform/pull/1)**
|
|
25
|
+
you can open right now. The PR says it is about partner access and changes eight
|
|
26
|
+
lines; it opens the web tier to the internet, turns off the bucket's
|
|
27
|
+
public-access protection, and widens an IAM policy to `s3:*` on `*`.
|
|
90
28
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
```
|
|
29
|
+
One sticky comment, updated in place on every push. Exit code `1`, so the build
|
|
30
|
+
fails before the change ships.
|
|
94
31
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
**3. Make the kind of edit that causes incidents.**
|
|
100
|
-
|
|
101
|
-
```bash
|
|
102
|
-
cat > config/prod.yaml <<'EOF'
|
|
103
|
-
database:
|
|
104
|
-
host: db.internal
|
|
105
|
-
pool_size: 20
|
|
106
|
-
ssl: true
|
|
107
|
-
logging:
|
|
108
|
-
level: info
|
|
109
|
-
debug: true
|
|
110
|
-
EOF
|
|
111
|
-
```
|
|
32
|
+
**[The same gate on an ordinary change](https://github.com/myselfsiddharth/flecto-example-terraform/pull/2)**
|
|
33
|
+
reports *no findings* and passes. That matters as much: a check that fires on
|
|
34
|
+
everything gets uninstalled in a week.
|
|
112
35
|
|
|
113
|
-
|
|
36
|
+
<details>
|
|
37
|
+
<summary>The same report as text, and what a plan with existing state adds</summary>
|
|
114
38
|
|
|
115
|
-
|
|
116
|
-
flecto watch config/prod.yaml --diff
|
|
117
|
-
```
|
|
39
|
+
The comment above, as `flecto plan` prints it:
|
|
118
40
|
|
|
119
41
|
```
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
~ logging.debug: false → true
|
|
123
|
-
```
|
|
42
|
+
❌ Check failing — 30 changes in 1 file — 0 changed, 30 added, 0 removed.
|
|
43
|
+
Policy: 6 errors.
|
|
124
44
|
|
|
125
|
-
|
|
45
|
+
aws_security_group.web.ingress[0].cidr_blocks[0]
|
|
46
|
+
terraform-security-group-open-ingress
|
|
47
|
+
Security group ingress will accept traffic from the whole internet
|
|
48
|
+
(0.0.0.0/0). Restrict the source to a known CIDR, a prefix list, or
|
|
49
|
+
another security group.
|
|
126
50
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
51
|
+
aws_s3_bucket_public_access_block.uploads.block_public_acls (+3 more)
|
|
52
|
+
terraform-s3-public-access-block-disabled
|
|
53
|
+
S3 public access block is being turned off or removed.
|
|
130
54
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
::warning title=flecto policy pool-size-jump [default]::database.pool_size: Pool size increased from 5 to 20 (>=2x).
|
|
135
|
-
::error title=flecto policy dangerous-toggle-enabled [default]::logging.debug: Potentially dangerous toggle enabled.
|
|
55
|
+
aws_iam_role_policy.app.policy
|
|
56
|
+
terraform-iam-wildcard
|
|
57
|
+
IAM policy grants a wildcard action or resource ("*").
|
|
136
58
|
```
|
|
137
59
|
|
|
138
|
-
|
|
60
|
+
The example repository has no Terraform state, so every resource shows as
|
|
61
|
+
`create`. With existing state, a plan that replaces a database also reports:
|
|
139
62
|
|
|
140
|
-
**5. Watch it live.** Leave this running and edit the file in another window:
|
|
141
|
-
|
|
142
|
-
```bash
|
|
143
|
-
flecto watch config/prod.yaml
|
|
144
63
|
```
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
[18:24:48] /path/to/flecto-demo/config/prod.yaml — 2 changes
|
|
151
|
-
~ database.pool_size: 5 → 20
|
|
152
|
-
~ logging.debug: false → true
|
|
153
|
-
! policy(warn) [default] database.pool_size: Pool size increased from 5 to 20 (>=2x).
|
|
154
|
-
! policy(error) [default] logging.debug: Potentially dangerous toggle enabled.
|
|
64
|
+
aws_db_instance.main.#action
|
|
65
|
+
terraform-stateful-resource-destroyed
|
|
66
|
+
Terraform will destroy a stateful resource. Its data does not survive.
|
|
67
|
+
Take a final snapshot, or add a prevent_destroy lifecycle block, before
|
|
68
|
+
applying.
|
|
155
69
|
```
|
|
156
70
|
|
|
157
|
-
|
|
71
|
+
</details>
|
|
158
72
|
|
|
159
73
|
---
|
|
160
74
|
|
|
161
|
-
##
|
|
162
|
-
|
|
163
|
-
### Catch risky changes before they merge
|
|
75
|
+
## Add it in 60 seconds
|
|
164
76
|
|
|
165
|
-
|
|
166
|
-
the pull request:
|
|
77
|
+
**Terraform** — point it at the plan JSON:
|
|
167
78
|
|
|
168
79
|
```yaml
|
|
169
80
|
permissions:
|
|
170
81
|
contents: read
|
|
82
|
+
pull-requests: write
|
|
171
83
|
|
|
172
84
|
steps:
|
|
173
85
|
- uses: actions/checkout@v7
|
|
86
|
+
- run: |
|
|
87
|
+
terraform plan -out=tf.plan
|
|
88
|
+
terraform show -json tf.plan > plan.json
|
|
89
|
+
- uses: myselfsiddharth/Flecto/.github/actions/flecto-pr-risk@v4.1.0
|
|
174
90
|
with:
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
with:
|
|
178
|
-
targets: config/**/*.{yaml,yml,json,toml,ini}
|
|
179
|
-
snapshot-ref: HEAD~1
|
|
91
|
+
terraform-plan: plan.json
|
|
92
|
+
fail-on: error
|
|
180
93
|
```
|
|
181
94
|
|
|
182
|
-
|
|
183
|
-
policy findings as markdown and, when you opt in with `--pr-comment-post` inside
|
|
184
|
-
a GitHub PR run, keeps **one** sticky comment up to date instead of adding a new
|
|
185
|
-
one per push. Without that flag it just prints the markdown, so it can't post
|
|
186
|
-
from your laptop.
|
|
187
|
-
|
|
188
|
-
The `flecto-pr-risk` Action is that, packaged — the whole adoption is one
|
|
189
|
-
`uses:`, with the baseline resolved from the pull request rather than `HEAD~1`:
|
|
95
|
+
**Kubernetes** — render your manifests, then diff them against the PR's base:
|
|
190
96
|
|
|
191
97
|
```yaml
|
|
192
98
|
permissions:
|
|
@@ -197,324 +103,64 @@ steps:
|
|
|
197
103
|
- uses: actions/checkout@v7
|
|
198
104
|
with:
|
|
199
105
|
fetch-depth: 0
|
|
200
|
-
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
A fork's pull request gets a read-only token, so the comment is skipped with a
|
|
207
|
-
warning there — the check itself still runs and still fails on risky changes.
|
|
208
|
-
|
|
209
|
-
Works on any CI runner — it's a plain CLI with meaningful exit codes.
|
|
210
|
-
→ **[CI guide](docs/ci.md)**
|
|
211
|
-
|
|
212
|
-
### Trigger automation on change
|
|
213
|
-
|
|
214
|
-
Restart a service, reload a process, or notify an endpoint whenever config moves:
|
|
215
|
-
|
|
216
|
-
```bash
|
|
217
|
-
flecto watch .env --command "docker-compose restart app"
|
|
218
|
-
|
|
219
|
-
flecto watch config/prod.yaml \
|
|
220
|
-
--webhook https://hooks.example.com/notify \
|
|
221
|
-
--delivery-mode at-least-once
|
|
222
|
-
```
|
|
223
|
-
|
|
224
|
-
Changes arrive as a versioned JSON envelope, and `at-least-once` persists and
|
|
225
|
-
retries failed deliveries.
|
|
226
|
-
|
|
227
|
-
Posting straight to chat needs no receiver of your own — `--webhook-format`
|
|
228
|
-
shapes the body for Slack, Discord, or Teams, colored by the highest policy
|
|
229
|
-
severity:
|
|
230
|
-
|
|
231
|
-
```bash
|
|
232
|
-
flecto watch config/prod.yaml \
|
|
233
|
-
--webhook "https://hooks.slack.com/services/T000/B000/XXXX" \
|
|
234
|
-
--webhook-format slack
|
|
235
|
-
```
|
|
236
|
-
|
|
237
|
-
→ **[Webhooks and commands](docs/webhooks.md)**
|
|
238
|
-
|
|
239
|
-
### Compare two environments
|
|
240
|
-
|
|
241
|
-
"Works in staging, fails in prod" is usually one key apart:
|
|
242
|
-
|
|
243
|
-
```bash
|
|
244
|
-
flecto compare config/prod.yaml config/staging.yaml
|
|
245
|
-
```
|
|
246
|
-
|
|
247
|
-
```
|
|
248
|
-
"+" exists only in the compared file, "-" only in the baseline, "~" differs
|
|
249
|
-
/path/to/config/staging.yaml — 2 changes from /path/to/config/prod.yaml:
|
|
250
|
-
- only_in_prod: true
|
|
251
|
-
~ database.pool_size: 5 → 20
|
|
252
|
-
! policy(warn) [default] database.pool_size: Pool size increased from 5 to 20 (>=2x).
|
|
253
|
-
```
|
|
254
|
-
|
|
255
|
-
The first file is the baseline, the files don't have to share a format, and
|
|
256
|
-
`--format json` gives you the same output `flecto ci` produces.
|
|
257
|
-
→ **[CLI reference](docs/cli-reference.md#flecto-compare-filea-fileb)**
|
|
258
|
-
|
|
259
|
-
### Track drift over time
|
|
260
|
-
|
|
261
|
-
```bash
|
|
262
|
-
flecto history config/prod.yaml --limit 10
|
|
263
|
-
```
|
|
264
|
-
|
|
265
|
-
Snapshots stay on your machine in `.flecto-snapshots/`. Nothing is uploaded and
|
|
266
|
-
no account is required. To read the same history on a CI runner, save it to the
|
|
267
|
-
git-tracked store instead — `--snapshot-store shared` writes a committable
|
|
268
|
-
`.flecto/snapshots/`, masking secret-like values into digests as it goes.
|
|
269
|
-
→ **[CLI reference](docs/cli-reference.md#flecto-history-files)**
|
|
270
|
-
|
|
271
|
-
### Share what changed before the incident
|
|
272
|
-
|
|
273
|
-
```bash
|
|
274
|
-
flecto report --limit 20 --mask-secrets --output drift.html
|
|
275
|
-
```
|
|
276
|
-
|
|
277
|
-
One HTML file from that same local history: a timeline per file, every change
|
|
278
|
-
with its UTC timestamp, and policy findings grouped by severity. Fully
|
|
279
|
-
self-contained — inline styles, no fonts, no CDN scripts, no analytics — so you
|
|
280
|
-
can attach it to an incident thread and it renders offline. No server and no
|
|
281
|
-
account, same as everything else here.
|
|
282
|
-
→ **[CLI reference](docs/cli-reference.md#flecto-report-files)**
|
|
283
|
-
|
|
284
|
-
### Review a Kubernetes change before it reaches a cluster
|
|
285
|
-
|
|
286
|
-
ArgoCD, Flux, and `helm diff` compare the cluster to the repo — which needs a
|
|
287
|
-
cluster, and an apply that already happened. Flecto compares the manifests *this
|
|
288
|
-
pull request would produce* against the ones `main` produces:
|
|
289
|
-
|
|
290
|
-
```bash
|
|
291
|
-
helm template api ./charts/api -f values/prod.yaml > /tmp/head.yaml
|
|
292
|
-
flecto compare /tmp/base.yaml /tmp/head.yaml --policies kubernetes --fail-on error
|
|
293
|
-
```
|
|
294
|
-
|
|
295
|
-
```
|
|
296
|
-
~ Service/prod/api.spec.type: "ClusterIP" → "LoadBalancer"
|
|
297
|
-
! policy(error) [kubernetes] Service type is LoadBalancer, which exposes the
|
|
298
|
-
workload outside the cluster. Confirm the exposure is intended.
|
|
299
|
-
```
|
|
300
|
-
|
|
301
|
-
Multi-document YAML is keyed by `kind/namespace/name`, so findings name the
|
|
302
|
-
resource. Flecto never runs `helm` or `kustomize` — you render, it diffs, so any
|
|
303
|
-
renderer works and no binary is needed in CI.
|
|
304
|
-
→ **[Kubernetes](docs/kubernetes.md)**
|
|
305
|
-
|
|
306
|
-
### Read a Terraform plan in plain English
|
|
307
|
-
|
|
308
|
-
`terraform plan` output is precise and long. Flecto turns it into the handful of
|
|
309
|
-
lines a reviewer actually needs to argue about:
|
|
310
|
-
|
|
311
|
-
```bash
|
|
312
|
-
terraform show -json plan.tfplan > plan.json
|
|
313
|
-
flecto plan plan.json --fail-on error
|
|
314
|
-
```
|
|
315
|
-
|
|
316
|
-
```
|
|
317
|
-
plan.json — plan format 1.2
|
|
318
|
-
Plan: 0 to add, 1 to change, 0 to destroy, 1 to replace.
|
|
319
|
-
~ aws_security_group.web.ingress[0].cidr_blocks[0]: "10.0.0.0/8" → "0.0.0.0/0"
|
|
320
|
-
- aws_db_instance.main.#action: "replace" [terraform will destroy and recreate aws_db_instance.main]
|
|
321
|
-
~ aws_db_instance.main.password: "(sensitive value)" → "(sensitive value)" [sensitive]
|
|
322
|
-
! policy(error) [terraform] …cidr_blocks[0]: Security group ingress will accept
|
|
323
|
-
traffic from the whole internet (0.0.0.0/0). Restrict the source to a known CIDR…
|
|
324
|
-
! policy(error) [terraform] …#action: Terraform will destroy a stateful resource.
|
|
325
|
-
Its data does not survive. Take a final snapshot, or add a prevent_destroy…
|
|
326
|
-
```
|
|
327
|
-
|
|
328
|
-
A **replace reads as a removal**, not a benign update — a recreated database
|
|
329
|
-
should never look like a config tweak. Values Terraform marks sensitive are
|
|
330
|
-
redacted during parsing, before the policy engine or any formatter sees them, and
|
|
331
|
-
`after_unknown` renders as `(known after apply)` rather than `null`.
|
|
332
|
-
|
|
333
|
-
**Flecto never runs `terraform`** — you produce the JSON, it reads it, so nothing
|
|
334
|
-
extra has to exist on the CI runner.
|
|
335
|
-
→ **[Terraform plans](docs/terraform.md)**
|
|
336
|
-
|
|
337
|
-
### Encode your own rules
|
|
338
|
-
|
|
339
|
-
Beyond the built-in packs, write rules as declarative JSON or YAML — no code:
|
|
340
|
-
|
|
341
|
-
```json
|
|
342
|
-
{
|
|
343
|
-
"id": "risky-feature-enable",
|
|
344
|
-
"severity": "error",
|
|
345
|
-
"allOf": [
|
|
346
|
-
{ "match": { "pathPrefix": "features." } },
|
|
347
|
-
{ "afterTruthy": true }
|
|
348
|
-
]
|
|
349
|
-
}
|
|
350
|
-
```
|
|
351
|
-
|
|
352
|
-
For anything a predicate can't express, a local ESM plugin exporting
|
|
353
|
-
`evaluate(changes, ctx)` gets the full change set.
|
|
354
|
-
→ **[Writing policy packs](docs/policy-packs.md)** · **[Plugins](docs/plugins.md)**
|
|
355
|
-
|
|
356
|
-
### Cut the noise
|
|
357
|
-
|
|
358
|
-
```bash
|
|
359
|
-
flecto watch config/prod.yaml --ignore "updated_at,**.meta.timestamp"
|
|
106
|
+
- run: helm template ./chart > rendered.yaml
|
|
107
|
+
- uses: myselfsiddharth/Flecto/.github/actions/flecto-pr-risk@v4.1.0
|
|
108
|
+
with:
|
|
109
|
+
targets: rendered.yaml
|
|
110
|
+
policies: kubernetes
|
|
360
111
|
```
|
|
361
112
|
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
→ **[Configuration](docs/configuration.md)**
|
|
113
|
+
Flecto **never invokes** `terraform`, `helm`, `kustomize`, `sops`, or `age`, so
|
|
114
|
+
nothing extra has to exist on the runner. → **[CI guide](docs/ci.md)**
|
|
365
115
|
|
|
366
116
|
---
|
|
367
117
|
|
|
368
|
-
##
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
Pass files or glob patterns, quoted so your shell doesn't expand them first — a
|
|
387
|
-
bare directory is not a valid target.
|
|
388
|
-
|
|
389
|
-
A local `policies/<id>.json` overrides the built-in pack of the same id, and
|
|
390
|
-
`severityRemap` raises or silences individual rules per profile without forking
|
|
391
|
-
anything. → **[Policy packs](docs/policy-packs.md)**
|
|
392
|
-
|
|
393
|
-
Community packs ship on npm as `flecto-pack-<id>` packages — a package name and
|
|
394
|
-
one declarative JSON file, nothing else:
|
|
395
|
-
|
|
396
|
-
```bash
|
|
397
|
-
npm install --save-dev flecto-pack-deployment-safety
|
|
398
|
-
flecto policies add deployment-safety
|
|
399
|
-
```
|
|
400
|
-
|
|
401
|
-
`policies add` validates the pack, writes it to `policies/deployment-safety.json`,
|
|
402
|
-
and runs no code from the package. →
|
|
403
|
-
**[Installing community packs](docs/policy-packs.md#installing-a-community-pack)**
|
|
118
|
+
## What it catches
|
|
119
|
+
|
|
120
|
+
- **A database about to be destroyed** — `terraform plan` says `replace`, the
|
|
121
|
+
diff says the data does not survive
|
|
122
|
+
- **Ingress widened to the world** — `10.0.0.0/8` → `0.0.0.0/0` on a security
|
|
123
|
+
group
|
|
124
|
+
- **An IAM policy gone wildcard** — `Action: "*"` where it used to be scoped
|
|
125
|
+
- **S3 public-access protection switched off** — the block removed, not just
|
|
126
|
+
loosened
|
|
127
|
+
- **A container turned privileged**, or `runAsNonRoot` quietly weakened
|
|
128
|
+
- **Resource limits removed** from a Deployment, so one pod can starve a node
|
|
129
|
+
- **An image tag unpinned** — `:1.4.0` → `:latest`
|
|
130
|
+
- **A new recipient on a SOPS file** — someone who could not decrypt it now can
|
|
131
|
+
- **`debug: true` in a 40-line formatting diff**, or a connection pool
|
|
132
|
+
quadrupled
|
|
133
|
+
|
|
134
|
+
Rules live in [policy packs](docs/policy-packs.md) you can extend, remap, or
|
|
135
|
+
replace.
|
|
404
136
|
|
|
405
137
|
---
|
|
406
138
|
|
|
407
|
-
##
|
|
139
|
+
## Also works as
|
|
408
140
|
|
|
409
|
-
|
|
|
141
|
+
| | |
|
|
410
142
|
|---|---|
|
|
411
|
-
|
|
|
412
|
-
|
|
|
413
|
-
|
|
|
414
|
-
|
|
|
415
|
-
|
|
|
416
|
-
|
|
|
417
|
-
|
|
418
|
-
`.json` accepts comments and trailing commas, so `tsconfig.json`,
|
|
419
|
-
`.vscode/settings.json`, `jsconfig.json`, and `devcontainer.json` are read as
|
|
420
|
-
written. →
|
|
421
|
-
**[JSON with comments](docs/configuration.md#json-with-comments)**
|
|
422
|
-
|
|
423
|
-
Terraform plan JSON (`terraform show -json`) is read by **`flecto plan`**, which
|
|
424
|
-
applies Terraform's own sensitivity marking. Point `plan` at it rather than `ci`
|
|
425
|
-
or `watch` — those treat it as ordinary JSON and will print values Terraform
|
|
426
|
-
marks sensitive ([#113](https://github.com/myselfsiddharth/Flecto/issues/113)).
|
|
427
|
-
|
|
428
|
-
Multi-document YAML (`---`-separated, the usual shape of a Kubernetes manifest)
|
|
429
|
-
is supported. Each document is diffed under its own key — `kind/name` for
|
|
430
|
-
Kubernetes-shaped documents, so a document inserted at the top of the file does
|
|
431
|
-
not renumber every other path. →
|
|
432
|
-
**[Multi-document YAML](docs/configuration.md#multi-document-yaml)**
|
|
433
|
-
|
|
434
|
-
---
|
|
435
|
-
|
|
436
|
-
## Encrypted files
|
|
437
|
-
|
|
438
|
-
A `sops`- or age-encrypted file is detected from its **contents**, and diffed
|
|
439
|
-
structurally:
|
|
440
|
-
|
|
441
|
-
```
|
|
442
|
-
+ cache: {"ttl_seconds":300}
|
|
443
|
-
~ database.password: <encrypted value changed>
|
|
444
|
-
+ sops.age.age1exampleexample…: {"recipient":"age1exampleexample…","enc":"<encrypted value>"}
|
|
445
|
-
```
|
|
446
|
-
|
|
447
|
-
You get keys added and removed, which encrypted values moved, and — the useful
|
|
448
|
-
part — who can decrypt the file. A recipient added is a genuine security event
|
|
449
|
-
and the `sops` pack raises it as one.
|
|
450
|
-
|
|
451
|
-
**Flecto never decrypts.** It never shells out to `sops` or `age`, never reads a
|
|
452
|
-
key file or agent socket, and never prints ciphertext — not even without
|
|
453
|
-
`--mask-secrets`. Ciphertext is replaced with an opaque sentinel in the parser,
|
|
454
|
-
so no diff, snapshot, webhook, or report can carry it. →
|
|
455
|
-
**[Encrypted files](docs/encrypted-files.md)**
|
|
143
|
+
| **A CLI** | `flecto ci`, `flecto plan`, `flecto compare` — plain exit codes, any runner → **[CLI reference](docs/cli-reference.md)** |
|
|
144
|
+
| **A file watcher** | `flecto watch` reports changes as you edit → **[Getting started](docs/getting-started.md)** |
|
|
145
|
+
| **A webhook / command trigger** | Restart a service or notify an endpoint on change → **[Webhooks](docs/webhooks.md)** |
|
|
146
|
+
| **An MCP server** | Read-only `diff`, `check`, `explain` tools for agents → **[MCP](docs/mcp.md)** |
|
|
147
|
+
| **An editor language server** | `flecto lsp` — diagnostics while you type → **[Editor](docs/editor.md)** |
|
|
148
|
+
| **A drift detector** | `flecto-drift` compares declared config against what is running → **[Drift](docs/drift.md)** |
|
|
456
149
|
|
|
457
150
|
---
|
|
458
151
|
|
|
459
|
-
##
|
|
460
|
-
|
|
461
|
-
Most teams commit a `.flectorc` so local runs and CI agree:
|
|
462
|
-
|
|
463
|
-
```bash
|
|
464
|
-
flecto init
|
|
465
|
-
```
|
|
466
|
-
|
|
467
|
-
```json
|
|
468
|
-
{
|
|
469
|
-
"defaults": {
|
|
470
|
-
"policies": ["default"],
|
|
471
|
-
"ignore": ["**.updated_at"]
|
|
472
|
-
},
|
|
473
|
-
"profiles": {
|
|
474
|
-
"dev": { "mode": "verbose" },
|
|
475
|
-
"ci": { "failOn": "policy,error" },
|
|
476
|
-
"prod": {
|
|
477
|
-
"policies": ["default", "strict-prod"],
|
|
478
|
-
"severityRemap": { "pool-size-jump": "error" },
|
|
479
|
-
"maskSecrets": true
|
|
480
|
-
}
|
|
481
|
-
},
|
|
482
|
-
"files": ["config/**/*.{yaml,yml,json,toml,ini}", ".env"]
|
|
483
|
-
}
|
|
484
|
-
```
|
|
485
|
-
|
|
486
|
-
```bash
|
|
487
|
-
flecto watch --profile dev
|
|
488
|
-
flecto ci --profile ci
|
|
489
|
-
```
|
|
490
|
-
|
|
491
|
-
Explicit CLI flags win over profiles, which win over `defaults`.
|
|
492
|
-
→ **[Full configuration reference](docs/configuration.md)**
|
|
152
|
+
## Stability
|
|
493
153
|
|
|
494
|
-
|
|
154
|
+
Flecto runs inside your merge path. The **JSON envelope**
|
|
155
|
+
(`schema_version: "2.0"`), **exit codes** (`0` clean, `1` failed — it fails
|
|
156
|
+
closed), **`.flectorc`** keys, and **command and flag names** follow
|
|
157
|
+
[semver](https://semver.org/), and no breaking change to them ships without a
|
|
158
|
+
minor release that warns first. The one exception is a security fix.
|
|
495
159
|
|
|
496
|
-
|
|
160
|
+
Terminal output, message wording, and anything under `src/` are deliberately
|
|
161
|
+
**not** stable — parse `--format json`.
|
|
497
162
|
|
|
498
|
-
|
|
499
|
-
|---|---|
|
|
500
|
-
| `flecto watch [files...]` | Watch for changes and print them as they happen |
|
|
501
|
-
| `flecto watch --snapshot` | Save the current state as a baseline |
|
|
502
|
-
| `flecto watch --diff` | Compare against the baseline and exit |
|
|
503
|
-
| `flecto ci [files...]` | One-shot check with a gate-able exit code |
|
|
504
|
-
| `flecto explain [files...]` | Advisory, model-generated narration of the masked diff (opt-in, your own key) |
|
|
505
|
-
| `flecto compare <fileA> <fileB>` | Diff two files against each other (`fileA` is the baseline) |
|
|
506
|
-
| `flecto plan <planFiles...>` | Review `terraform show -json` output and gate on it |
|
|
507
|
-
| `flecto history [files...]` | Summarize drift across local snapshots |
|
|
508
|
-
| `flecto report [files...]` | Render that history as a self-contained HTML file |
|
|
509
|
-
| `flecto policies add <name>` | Install a pack from an `flecto-pack-*` npm package |
|
|
510
|
-
| `flecto policies list` | List available policy packs |
|
|
511
|
-
| `flecto policies test <dir>` | Assert pack and plugin findings from fixtures |
|
|
512
|
-
| `flecto init` | Create a `.flectorc` from detected stack signals |
|
|
513
|
-
| `flecto mcp` | Serve read-only diff/check/explain tools to an agent over MCP |
|
|
514
|
-
| `flecto lsp` | Show findings and changes as diagnostics while a config file is edited |
|
|
515
|
-
| `flecto doctor` | Check setup, config, and environment |
|
|
516
|
-
|
|
517
|
-
→ **[Every flag, every command](docs/cli-reference.md)**
|
|
163
|
+
→ **[Full stability policy](docs/stability.md)**
|
|
518
164
|
|
|
519
165
|
---
|
|
520
166
|
|
|
@@ -522,40 +168,30 @@ Explicit CLI flags win over profiles, which win over `defaults`.
|
|
|
522
168
|
|
|
523
169
|
| Guide | Covers |
|
|
524
170
|
|---|---|
|
|
525
|
-
| **[
|
|
526
|
-
| **[
|
|
527
|
-
| **[Editor diagnostics](docs/editor.md)** | `flecto lsp` setup for Neovim, Helix, Emacs, and where diagnostics land |
|
|
528
|
-
| **[Encrypted files](docs/encrypted-files.md)** | SOPS and age: what is detected, what is reported, why nothing is decrypted |
|
|
529
|
-
| **[CI](docs/ci.md)** | Baselines, fail triggers, output formats, the bundled GitHub Actions |
|
|
530
|
-
| **[Performance](docs/performance.md)** | Where time goes at scale, and how much smaller a diff is than the config |
|
|
531
|
-
| **[Kubernetes](docs/kubernetes.md)** | Diffing rendered Helm/Kustomize manifests before they reach a cluster |
|
|
171
|
+
| **[Getting started](docs/getting-started.md)** | A full walkthrough, from install to a failing build |
|
|
172
|
+
| **[CI](docs/ci.md)** | Baselines, fail triggers, output formats, the bundled Actions, pinning |
|
|
532
173
|
| **[Terraform plans](docs/terraform.md)** | Reviewing `terraform show -json` output and the `terraform` pack |
|
|
174
|
+
| **[Kubernetes](docs/kubernetes.md)** | Diffing rendered Helm/Kustomize manifests before they reach a cluster |
|
|
175
|
+
| **[Comparison](docs/comparison.md)** | Honest comparison with Checkov, Trivy/tfsec, conftest/OPA, tf-summarize, dyff |
|
|
176
|
+
| **[Supported formats](docs/formats.md)** | YAML, JSON, TOML, INI, dotenv, age — and what each one accepts |
|
|
177
|
+
| **[Encrypted files](docs/encrypted-files.md)** | SOPS and age: what is detected, why nothing is decrypted |
|
|
178
|
+
| **[Configuration](docs/configuration.md)** | `.flectorc`, profiles, ignore patterns, array identity, masking |
|
|
179
|
+
| **[CLI reference](docs/cli-reference.md)** | Every command, flag, and exit code |
|
|
180
|
+
| **[Policy packs](docs/policy-packs.md)** | Writing declarative rules |
|
|
181
|
+
| **[Plugins](docs/plugins.md)** · **[Cookbook](docs/plugin-cookbook.md)** | Rules that need real code |
|
|
533
182
|
| **[Webhooks and commands](docs/webhooks.md)** | Envelope shape, delivery modes, command environment |
|
|
534
183
|
| **[MCP server](docs/mcp.md)** | Read-only diff/check/explain tools for agents, and the security posture |
|
|
535
184
|
| **[Explain](docs/explain.md)** | Opt-in model narration of a diff: what is sent, what it can never do, cost |
|
|
536
|
-
| **[
|
|
537
|
-
| **[
|
|
538
|
-
| **[
|
|
185
|
+
| **[Editor diagnostics](docs/editor.md)** | `flecto lsp` setup for Neovim, Helix, Emacs |
|
|
186
|
+
| **[Live drift](docs/drift.md)** | `flecto-drift`: declared config versus what is actually running |
|
|
187
|
+
| **[Performance](docs/performance.md)** | Where time goes at scale |
|
|
188
|
+
| **[Stability](docs/stability.md)** | What you can build against, and the deprecation sequence |
|
|
539
189
|
| **[Troubleshooting](docs/troubleshooting.md)** | When something doesn't behave |
|
|
540
|
-
| **[Migrating to 4.0](docs/migrating-to-4.md)** | The five breaking changes, and
|
|
190
|
+
| **[Migrating to 4.0](docs/migrating-to-4.md)** | The five breaking changes, and whether they affect you |
|
|
541
191
|
| **[Changelog](CHANGELOG.md)** | Release history and migration notes |
|
|
542
192
|
|
|
543
193
|
---
|
|
544
194
|
|
|
545
|
-
## How it works
|
|
546
|
-
|
|
547
|
-
1. **Parse** — format detected by extension or dotenv naming → structured values
|
|
548
|
-
2. **Watch** — [chokidar](https://github.com/paulmillr/chokidar) with debounce
|
|
549
|
-
3. **Diff** — semantic tree comparison with ignore rules and array identity
|
|
550
|
-
4. **Evaluate** — policy packs and plugins → severity-tagged findings
|
|
551
|
-
5. **Emit** — a versioned envelope (`schema_version: "2.0"`)
|
|
552
|
-
6. **Deliver** — terminal output, shell command, webhook, or CI annotations
|
|
553
|
-
|
|
554
|
-
Flecto runs entirely on your machine. Snapshots are local files, and nothing
|
|
555
|
-
leaves the process unless you configure a webhook or command.
|
|
556
|
-
|
|
557
|
-
---
|
|
558
|
-
|
|
559
195
|
## Project
|
|
560
196
|
|
|
561
197
|
- **Questions and ideas** — [Discussions](https://github.com/myselfsiddharth/Flecto/discussions)
|
package/package.json
CHANGED
|
@@ -4,17 +4,24 @@
|
|
|
4
4
|
"access": "public",
|
|
5
5
|
"provenance": true
|
|
6
6
|
},
|
|
7
|
-
"version": "4.
|
|
8
|
-
"description": "
|
|
7
|
+
"version": "4.1.1",
|
|
8
|
+
"description": "Reads your Terraform plan and Kubernetes changes and posts a plain-English risk summary on every pull request, blocking the dangerous ones",
|
|
9
9
|
"license": "MIT",
|
|
10
10
|
"keywords": [
|
|
11
|
-
"
|
|
12
|
-
"
|
|
13
|
-
"
|
|
14
|
-
"
|
|
11
|
+
"terraform",
|
|
12
|
+
"terraform-plan",
|
|
13
|
+
"kubernetes",
|
|
14
|
+
"helm",
|
|
15
|
+
"pull-request",
|
|
16
|
+
"code-review",
|
|
17
|
+
"policy-as-code",
|
|
18
|
+
"github-actions",
|
|
15
19
|
"semantic-diff",
|
|
20
|
+
"config",
|
|
16
21
|
"devops",
|
|
17
|
-
"ci"
|
|
22
|
+
"ci",
|
|
23
|
+
"cli",
|
|
24
|
+
"flecto"
|
|
18
25
|
],
|
|
19
26
|
"homepage": "https://github.com/myselfsiddharth/Flecto#readme",
|
|
20
27
|
"bugs": {
|
|
@@ -56,7 +63,7 @@
|
|
|
56
63
|
"chalk": "^5.3.0",
|
|
57
64
|
"chokidar": "^5.0.0",
|
|
58
65
|
"commander": "^12.1.0",
|
|
59
|
-
"dotenv": "^
|
|
66
|
+
"dotenv": "^18.0.1",
|
|
60
67
|
"fast-glob": "^3.3.3",
|
|
61
68
|
"js-yaml": "^4.3.0",
|
|
62
69
|
"re2js": "^2.8.6"
|
package/src/positions.js
CHANGED
|
@@ -655,9 +655,15 @@ function readJsonValue(state) {
|
|
|
655
655
|
// dotenv
|
|
656
656
|
|
|
657
657
|
/**
|
|
658
|
-
* dotenv's own line pattern
|
|
659
|
-
*
|
|
660
|
-
*
|
|
658
|
+
* dotenv's own line pattern, with match indices. Reading keys with the parser's
|
|
659
|
+
* exact pattern is what makes the positions agree with it; verification catches
|
|
660
|
+
* a future dotenv that changes it.
|
|
661
|
+
*
|
|
662
|
+
* Upstream source moved in dotenv 18: it was `dotenv/lib/main.js`, and is now
|
|
663
|
+
* bundled and minified into `dotenv/dist/index.cjs`. The pattern itself is
|
|
664
|
+
* unchanged between 17.4.2 and 18.0.1 -- byte-identical apart from the `d` flag
|
|
665
|
+
* added here for match indices. To re-check it after a bump, grep the bundle for
|
|
666
|
+
* `export\s+`, which is distinctive enough to find the regex in minified code.
|
|
661
667
|
*/
|
|
662
668
|
const DOTENV_LINE = /(?:^|^)\s*(?:export\s+)?([\w.-]+)(?:\s*=\s*?|:\s+?)(\s*'(?:\\'|[^'])*'|\s*"(?:\\"|[^"])*"|\s*`(?:\\`|[^`])*`|[^#\r\n]+)?\s*(?:#.*)?(?:$|$)/dgm;
|
|
663
669
|
|