flecto 2.0.0 → 2.1.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/CHANGELOG.md +103 -0
- package/README.md +258 -120
- package/index.js +269 -38
- package/package.json +7 -6
- package/schemas/flecto-policy-pack-2.0.json +124 -0
- package/src/alerter.js +4 -3
- package/src/config.js +23 -2
- package/src/differ.js +95 -45
- package/src/packs/compose.json +45 -0
- package/src/packs/default.json +1 -1
- package/src/packs/node-runtime.json +44 -0
- package/src/packs/strict-prod.json +1 -1
- package/src/policy-test.js +124 -0
- package/src/policy.js +325 -27
- package/src/renderer.js +7 -4
- package/src/watcher.js +18 -8
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to Flecto will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog], and this project adheres to
|
|
6
|
+
[Semantic Versioning].
|
|
7
|
+
|
|
8
|
+
## [Unreleased]
|
|
9
|
+
|
|
10
|
+
## [2.1.0] - 2026-07-24
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- Default-on array identity matching with auto-detect of unique `id`, then
|
|
15
|
+
`name`. Escape hatch: `--no-array-id` or `"arrayId": false` in `.flectorc`.
|
|
16
|
+
Custom keys still work via `--array-id-key`. ([#6])
|
|
17
|
+
- `flecto history` for local snapshot drift baselines (`--limit`). ([#7])
|
|
18
|
+
- Richer declarative policy predicates: `beforeEquals`, `beforeIn` / `afterIn`,
|
|
19
|
+
`beforeTruthy` / `afterTruthy`, `afterMatches`, `numericDelta`,
|
|
20
|
+
`match.pathEquals` / `match.pathPrefix`, and `allOf` / `anyOf`. ([#34])
|
|
21
|
+
- Built-in `compose` and `node-runtime` policy packs. ([#8])
|
|
22
|
+
- JSON Schema + load-time validation for policy packs
|
|
23
|
+
(`schemas/flecto-policy-pack-2.0.json`). ([#36])
|
|
24
|
+
- `flecto policies list` (+ `--json`) for pack discovery. ([#37])
|
|
25
|
+
- `flecto policies test <fixtureDir>` fixture harness for packs/plugins. ([#38])
|
|
26
|
+
- Per-profile `severityRemap` to raise, lower, or silence pack rules without
|
|
27
|
+
forking. ([#39])
|
|
28
|
+
- Reusable GitHub Action wrapper for `flecto ci`
|
|
29
|
+
(`.github/actions/flecto-ci`). ([#9])
|
|
30
|
+
- Policy pack + plugin authoring guides, cookbook, and examples. ([#32], [#35])
|
|
31
|
+
- `CHANGELOG.md` with v2.1 migration notes. ([#33])
|
|
32
|
+
|
|
33
|
+
### Changed
|
|
34
|
+
|
|
35
|
+
- Node.js requirement raised to **>=20.19.0** (matches chokidar 5). CI matrix
|
|
36
|
+
is 20/22/24; publish uses Node 22. ([#22], [#27])
|
|
37
|
+
- `flecto ci` and `flecto watch --snapshot` fail closed when every target is
|
|
38
|
+
missing or unsupported. Pass `--allow-empty` to permit an empty run.
|
|
39
|
+
([#20], [#29], [#40])
|
|
40
|
+
- Only options explicitly set on the CLI override `.flectorc` profiles
|
|
41
|
+
(Commander defaults no longer wipe profile settings). ([#19], [#31])
|
|
42
|
+
- Watch mode fails closed on policy pack/plugin load or evaluation errors,
|
|
43
|
+
independent of `--on-alert-failure`. ([#25])
|
|
44
|
+
- Secret masking recursively redacts nested secret values when enabled. ([#24])
|
|
45
|
+
- Dangerous-toggle rules treat stringy truthy values (`true` / `1` / `yes`) as
|
|
46
|
+
enabled, so `.env` / INI configs are covered. ([#23])
|
|
47
|
+
|
|
48
|
+
### Fixed
|
|
49
|
+
|
|
50
|
+
- `arrayIgnoreOrder` no longer false-positives on object key order or throws on
|
|
51
|
+
non-JSON values such as `undefined`. ([#21])
|
|
52
|
+
- `fireAlerts` preserves its `{ ok }` result and surfaces queue errors; watch
|
|
53
|
+
consumes rejected alert handlers safely. ([#26])
|
|
54
|
+
- GitHub annotation output escapes `%`, newlines, commas, and colons per
|
|
55
|
+
workflow-command rules. ([#28])
|
|
56
|
+
- Removed leftover `.sentinel-snapshots/` gitignore entry. ([#30])
|
|
57
|
+
|
|
58
|
+
### Migration notes
|
|
59
|
+
|
|
60
|
+
- **Array identity is on by default.** Diff paths may change from index-based
|
|
61
|
+
(`services[0].…`) to identity-based (`services["api"].…`). Review snapshots,
|
|
62
|
+
CI baselines, and any automation that consumes diff paths before upgrading.
|
|
63
|
+
- To keep 2.0-style index-based array diffs: `--no-array-id` or
|
|
64
|
+
`"arrayId": false` in `.flectorc`.
|
|
65
|
+
- **Node 18 is no longer supported.** Use Node.js 20.19.0 or newer.
|
|
66
|
+
- Recursive masking only affects output when secret masking is enabled, but
|
|
67
|
+
nested secret values previously visible in terminal/webhook payloads are now
|
|
68
|
+
redacted.
|
|
69
|
+
- `.flectorc` profile settings (for example `mode`, `failOn`, `format`) now
|
|
70
|
+
apply when you omit the corresponding CLI flags.
|
|
71
|
+
- Misconfigured policy packs/plugins cause `watch` to exit non-zero instead of
|
|
72
|
+
continuing with no policies.
|
|
73
|
+
|
|
74
|
+
[Unreleased]: https://github.com/myselfsiddharth/Flecto/compare/v2.1.0...HEAD
|
|
75
|
+
[2.1.0]: https://github.com/myselfsiddharth/Flecto/compare/v2.0.0...v2.1.0
|
|
76
|
+
[#6]: https://github.com/myselfsiddharth/Flecto/issues/6
|
|
77
|
+
[#7]: https://github.com/myselfsiddharth/Flecto/issues/7
|
|
78
|
+
[#8]: https://github.com/myselfsiddharth/Flecto/issues/8
|
|
79
|
+
[#9]: https://github.com/myselfsiddharth/Flecto/issues/9
|
|
80
|
+
[#19]: https://github.com/myselfsiddharth/Flecto/issues/19
|
|
81
|
+
[#20]: https://github.com/myselfsiddharth/Flecto/issues/20
|
|
82
|
+
[#21]: https://github.com/myselfsiddharth/Flecto/issues/21
|
|
83
|
+
[#22]: https://github.com/myselfsiddharth/Flecto/issues/22
|
|
84
|
+
[#23]: https://github.com/myselfsiddharth/Flecto/issues/23
|
|
85
|
+
[#24]: https://github.com/myselfsiddharth/Flecto/issues/24
|
|
86
|
+
[#25]: https://github.com/myselfsiddharth/Flecto/issues/25
|
|
87
|
+
[#26]: https://github.com/myselfsiddharth/Flecto/issues/26
|
|
88
|
+
[#27]: https://github.com/myselfsiddharth/Flecto/issues/27
|
|
89
|
+
[#28]: https://github.com/myselfsiddharth/Flecto/issues/28
|
|
90
|
+
[#29]: https://github.com/myselfsiddharth/Flecto/issues/29
|
|
91
|
+
[#30]: https://github.com/myselfsiddharth/Flecto/issues/30
|
|
92
|
+
[#31]: https://github.com/myselfsiddharth/Flecto/issues/31
|
|
93
|
+
[#32]: https://github.com/myselfsiddharth/Flecto/issues/32
|
|
94
|
+
[#33]: https://github.com/myselfsiddharth/Flecto/issues/33
|
|
95
|
+
[#34]: https://github.com/myselfsiddharth/Flecto/issues/34
|
|
96
|
+
[#35]: https://github.com/myselfsiddharth/Flecto/issues/35
|
|
97
|
+
[#36]: https://github.com/myselfsiddharth/Flecto/issues/36
|
|
98
|
+
[#37]: https://github.com/myselfsiddharth/Flecto/issues/37
|
|
99
|
+
[#38]: https://github.com/myselfsiddharth/Flecto/issues/38
|
|
100
|
+
[#39]: https://github.com/myselfsiddharth/Flecto/issues/39
|
|
101
|
+
[#40]: https://github.com/myselfsiddharth/Flecto/pull/40
|
|
102
|
+
[Keep a Changelog]: https://keepachangelog.com/en/1.1.0/
|
|
103
|
+
[Semantic Versioning]: https://semver.org/spec/v2.0.0.html
|
package/README.md
CHANGED
|
@@ -1,21 +1,56 @@
|
|
|
1
|
-
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="docs/assets/flecto-hero.png" alt="Flecto — semantic config watcher" width="920"/>
|
|
3
|
+
</p>
|
|
2
4
|
|
|
3
|
-
|
|
5
|
+
<h1 align="center">Flecto</h1>
|
|
4
6
|
|
|
5
|
-
|
|
7
|
+
<p align="center">
|
|
8
|
+
<strong>Config changes, in plain English — with risk flags built in.</strong><br/>
|
|
9
|
+
Watch · Diff · Policy · CI · Webhooks
|
|
10
|
+
</p>
|
|
6
11
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
12
|
+
<p align="center">
|
|
13
|
+
<a href="https://www.npmjs.com/package/flecto"><img alt="npm" src="https://img.shields.io/npm/v/flecto?style=flat-square&color=34d399&labelColor=0b1220"/></a>
|
|
14
|
+
<a href="https://github.com/myselfsiddharth/Flecto/actions/workflows/ci.yml"><img alt="CI" src="https://img.shields.io/github/actions/workflow/status/myselfsiddharth/Flecto/ci.yml?branch=main&style=flat-square&label=CI&labelColor=0b1220"/></a>
|
|
15
|
+
<a href="LICENSE"><img alt="MIT" src="https://img.shields.io/badge/license-MIT-8fa3bf?style=flat-square&labelColor=0b1220"/></a>
|
|
16
|
+
<a href="https://github.com/myselfsiddharth/Flecto/stargazers"><img alt="Stars" src="https://img.shields.io/github/stars/myselfsiddharth/Flecto?style=flat-square&color=fbbf24&labelColor=0b1220"/></a>
|
|
17
|
+
</p>
|
|
18
|
+
|
|
19
|
+
<p align="center">
|
|
20
|
+
<a href="https://github.com/myselfsiddharth/Flecto/stargazers">⭐ Star this repo</a> if Flecto saves you from a noisy config diff — it helps others find the project.
|
|
21
|
+
</p>
|
|
22
|
+
|
|
23
|
+
<p align="center">
|
|
24
|
+
<img src="docs/assets/flecto-demo.png" alt="Flecto watch demo in the terminal" width="920"/>
|
|
25
|
+
</p>
|
|
26
|
+
|
|
27
|
+
<p align="center">
|
|
28
|
+
<img src="docs/assets/demo-watch.svg" alt="Animated Flecto watch output" width="920"/>
|
|
29
|
+
</p>
|
|
13
30
|
|
|
14
31
|
---
|
|
15
32
|
|
|
16
|
-
## Why Flecto
|
|
33
|
+
## Why teams use Flecto
|
|
34
|
+
|
|
35
|
+
Line diffs lie about config. Formatting churn, key reorders, and “small” YAML edits hide the changes that actually matter in production.
|
|
36
|
+
|
|
37
|
+
**Flecto** turns structured config into semantic events:
|
|
17
38
|
|
|
18
|
-
|
|
39
|
+
- What changed (`pool_size: 5 → 20`)
|
|
40
|
+
- What was added or removed
|
|
41
|
+
- What looks risky (secrets, dangerous toggles, pool jumps)
|
|
42
|
+
- What to do next (CI gate, webhook, shell command)
|
|
43
|
+
|
|
44
|
+
See the [changelog and migration notes](CHANGELOG.md) for release history and
|
|
45
|
+
upcoming v2.1 behavior changes.
|
|
46
|
+
|
|
47
|
+
> Diff tools compare trees. **Flecto watches, scores risk, and alerts.**
|
|
48
|
+
|
|
49
|
+
| Without Flecto | With Flecto |
|
|
50
|
+
|---|---|
|
|
51
|
+
| `+ 40 lines of YAML noise` | `~ database.pool_size: 5 → 20` |
|
|
52
|
+
| Hope someone notices `debug: true` | Policy finding → CI fails |
|
|
53
|
+
| “Something in `.env` changed” | Exact keys + optional secret masking |
|
|
19
54
|
|
|
20
55
|
---
|
|
21
56
|
|
|
@@ -25,47 +60,61 @@ Standard file watchers tell you *a file changed*. Flecto tells you *what* change
|
|
|
25
60
|
npm install -g flecto
|
|
26
61
|
```
|
|
27
62
|
|
|
28
|
-
|
|
63
|
+
Requires Node.js 20.19.0 or later.
|
|
29
64
|
|
|
30
|
-
|
|
65
|
+
```bash
|
|
66
|
+
flecto --version
|
|
67
|
+
flecto doctor
|
|
68
|
+
```
|
|
31
69
|
|
|
32
|
-
|
|
70
|
+
---
|
|
33
71
|
|
|
34
|
-
|
|
72
|
+
## Quick start
|
|
35
73
|
|
|
36
74
|
```bash
|
|
37
75
|
flecto watch config/prod.yaml
|
|
38
76
|
flecto watch .env
|
|
39
77
|
flecto watch settings.json
|
|
40
78
|
flecto watch pyproject.toml
|
|
79
|
+
flecto watch app.ini
|
|
41
80
|
```
|
|
42
81
|
|
|
43
|
-
That
|
|
82
|
+
That’s it — Flecto prints a clear summary on every meaningful change.
|
|
83
|
+
|
|
84
|
+
---
|
|
85
|
+
|
|
86
|
+
## Features at a glance
|
|
87
|
+
|
|
88
|
+
- **Semantic diffs** for JSON, YAML, TOML, INI, and dotenv (`.env`, `.env.*`, `*.env`)
|
|
89
|
+
- **Live watch** with optional command + webhook delivery
|
|
90
|
+
- **Policy packs** (`default`, `strict-prod`, `compose`, `node-runtime`) + custom `policies/*.json` + local ESM plugins
|
|
91
|
+
- **CI mode** with JSON / NDJSON / GitHub annotations and fail rules
|
|
92
|
+
- **Snapshots & diffs** for deploy scripts and pre-commit hooks
|
|
93
|
+
- **Profiles** via `--profile` or `FLECTO_PROFILE`
|
|
94
|
+
- **Default array identity** (`id` / `name`, or `--array-id-key`) and secret masking
|
|
44
95
|
|
|
45
96
|
---
|
|
46
97
|
|
|
47
|
-
## Common
|
|
98
|
+
## Common use cases
|
|
48
99
|
|
|
49
|
-
### Watch multiple files
|
|
100
|
+
### Watch multiple files
|
|
50
101
|
|
|
51
102
|
```bash
|
|
52
103
|
flecto watch "config/**/*.yaml" ".env"
|
|
53
104
|
```
|
|
54
105
|
|
|
55
|
-
###
|
|
106
|
+
### Verbose before/after
|
|
56
107
|
|
|
57
108
|
```bash
|
|
58
109
|
flecto watch config/prod.yaml --mode verbose
|
|
59
110
|
```
|
|
60
111
|
|
|
61
|
-
### Ignore noisy keys
|
|
112
|
+
### Ignore noisy keys
|
|
62
113
|
|
|
63
114
|
```bash
|
|
64
115
|
flecto watch config/prod.yaml --ignore "updated_at,meta.timestamp"
|
|
65
116
|
```
|
|
66
117
|
|
|
67
|
-
You can ignore exact keys, entire subtrees, wildcards, or keys anywhere in the file:
|
|
68
|
-
|
|
69
118
|
| Pattern | What it ignores |
|
|
70
119
|
|---|---|
|
|
71
120
|
| `meta.timestamp` | That exact key |
|
|
@@ -73,21 +122,15 @@ You can ignore exact keys, entire subtrees, wildcards, or keys anywhere in the f
|
|
|
73
122
|
| `servers[*].meta.timestamp` | That key inside any array item |
|
|
74
123
|
| `**.updated_at` | Any key named `updated_at`, anywhere |
|
|
75
124
|
|
|
76
|
-
### Run a command
|
|
125
|
+
### Run a command on change
|
|
77
126
|
|
|
78
127
|
```bash
|
|
79
128
|
flecto watch .env --command "docker-compose restart app"
|
|
80
129
|
```
|
|
81
130
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
### Send changes to a webhook
|
|
85
|
-
|
|
86
|
-
```bash
|
|
87
|
-
flecto watch config/prod.yaml --webhook https://hooks.example.com/notify
|
|
88
|
-
```
|
|
131
|
+
Changes are passed as JSON via `FLECTO_CHANGES` (large payloads may use `FLECTO_CHANGES_FILE`).
|
|
89
132
|
|
|
90
|
-
|
|
133
|
+
### Webhooks
|
|
91
134
|
|
|
92
135
|
```bash
|
|
93
136
|
flecto watch config/prod.yaml \
|
|
@@ -95,7 +138,7 @@ flecto watch config/prod.yaml \
|
|
|
95
138
|
--webhook-header "Authorization: Bearer TOKEN"
|
|
96
139
|
```
|
|
97
140
|
|
|
98
|
-
|
|
141
|
+
Envelope shape (`schema_version: "2.0"`):
|
|
99
142
|
|
|
100
143
|
```json
|
|
101
144
|
{
|
|
@@ -119,7 +162,7 @@ Each webhook payload includes a full event envelope:
|
|
|
119
162
|
}
|
|
120
163
|
```
|
|
121
164
|
|
|
122
|
-
|
|
165
|
+
JSON Schema: [`schemas/flecto-envelope-2.0.json`](schemas/flecto-envelope-2.0.json).
|
|
123
166
|
|
|
124
167
|
### Policy packs and profiles
|
|
125
168
|
|
|
@@ -127,8 +170,6 @@ Envelope JSON Schema: [`schemas/flecto-envelope-2.0.json`](schemas/flecto-envelo
|
|
|
127
170
|
flecto ci config/prod.yaml --profile prod --snapshot-ref HEAD~1
|
|
128
171
|
```
|
|
129
172
|
|
|
130
|
-
`.flectorc.json` example:
|
|
131
|
-
|
|
132
173
|
```json
|
|
133
174
|
{
|
|
134
175
|
"defaults": {
|
|
@@ -138,29 +179,104 @@ flecto ci config/prod.yaml --profile prod --snapshot-ref HEAD~1
|
|
|
138
179
|
"profiles": {
|
|
139
180
|
"prod": {
|
|
140
181
|
"policies": ["default", "strict-prod"],
|
|
182
|
+
"severityRemap": { "pool-size-jump": "error" },
|
|
141
183
|
"maskSecrets": true
|
|
142
184
|
}
|
|
143
185
|
}
|
|
144
186
|
}
|
|
145
187
|
```
|
|
146
188
|
|
|
147
|
-
Profile selection: `--profile` > `FLECTO_PROFILE` > defaults.
|
|
189
|
+
Profile selection: `--profile` > `FLECTO_PROFILE` > defaults.
|
|
190
|
+
Custom packs: `policies/<id>.json`. Plugins: local ESM exporting `evaluate(changes, ctx)`.
|
|
148
191
|
|
|
149
|
-
|
|
192
|
+
#### Declarative rule predicates
|
|
193
|
+
|
|
194
|
+
Rules combine their top-level predicates with AND. In addition to `when`, regex
|
|
195
|
+
`match.path`, `afterEquals`, and `numericJump`, packs can use:
|
|
196
|
+
|
|
197
|
+
- `beforeEquals`, `afterIn`, and `beforeIn` for exact values or allowed value lists.
|
|
198
|
+
- `beforeTruthy: true` and `afterTruthy: true` to require a truthy before/after value.
|
|
199
|
+
- `afterMatches` to require a string after value that matches a regular expression.
|
|
200
|
+
- `numericDelta: { "min": 10 }` to match an absolute numeric change of at least 10.
|
|
201
|
+
- `match.pathEquals` and `match.pathPrefix` for exact or prefix path matching without regex.
|
|
202
|
+
- `allOf` and `anyOf` arrays of simple match clauses. Every `allOf` clause and at least
|
|
203
|
+
one `anyOf` clause must match. Clauses support the same value, truthiness, numeric, and
|
|
204
|
+
`match` predicates, but cannot nest composition.
|
|
205
|
+
|
|
206
|
+
```json
|
|
207
|
+
{
|
|
208
|
+
"id": "risky-feature-enable",
|
|
209
|
+
"severity": "error",
|
|
210
|
+
"allOf": [
|
|
211
|
+
{ "match": { "pathPrefix": "features." } },
|
|
212
|
+
{ "afterTruthy": true }
|
|
213
|
+
],
|
|
214
|
+
"anyOf": [
|
|
215
|
+
{ "afterEquals": true },
|
|
216
|
+
{ "afterIn": ["unsafe", "disabled"] }
|
|
217
|
+
]
|
|
218
|
+
}
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
Pack loading fails closed for unknown rule or `match` fields, invalid regexes, and invalid
|
|
222
|
+
predicate shapes, so misspelled predicates cannot silently disable a rule.
|
|
223
|
+
|
|
224
|
+
Use `severityRemap` in defaults or a profile to change pack rule severities without forking a pack:
|
|
225
|
+
|
|
226
|
+
```json
|
|
227
|
+
{
|
|
228
|
+
"profiles": {
|
|
229
|
+
"dev": {
|
|
230
|
+
"severityRemap": { "pool-size-jump": "off" }
|
|
231
|
+
},
|
|
232
|
+
"prod": {
|
|
233
|
+
"severityRemap": { "pool-size-jump": "error" }
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
Each key is a rule id and each value must be `info`, `warn`, `error`, or `off`. The remap applies after all configured built-in and local packs load, before findings and CI `--fail-on` checks. When multiple packs provide the same rule id, the remap applies to every matching pack rule. Plugin findings are unchanged. Unknown rule ids print a warning instead of being ignored silently.
|
|
240
|
+
|
|
241
|
+
Authoring guides: [policy packs](docs/policy-packs.md) · [plugins](docs/plugins.md) · [plugin cookbook](docs/plugin-cookbook.md).
|
|
242
|
+
|
|
243
|
+
### Discover policy packs
|
|
150
244
|
|
|
151
245
|
```bash
|
|
152
|
-
flecto
|
|
246
|
+
flecto policies list
|
|
247
|
+
flecto policies list --json
|
|
153
248
|
```
|
|
154
249
|
|
|
155
|
-
|
|
250
|
+
The command lists every bundled and local pack that resolves from the current
|
|
251
|
+
working directory, including its source path and rule count. For a given pack
|
|
252
|
+
id, Flecto resolves local files before bundled packs in this order:
|
|
253
|
+
`policies/<id>.json`, `policies/<id>.yaml`, `policies/<id>.yml`, then the
|
|
254
|
+
built-in pack. A local pack with the same id overrides its built-in counterpart.
|
|
156
255
|
|
|
157
|
-
###
|
|
256
|
+
### Array identity matching
|
|
158
257
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
258
|
+
```bash
|
|
259
|
+
flecto watch config/services.yaml
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
Arrays of objects automatically match by a shared, unique `id` key, falling back
|
|
263
|
+
to `name` when `id` is unavailable. This avoids false changes when named items
|
|
264
|
+
are reordered. Use a custom identity field when needed:
|
|
265
|
+
|
|
266
|
+
```bash
|
|
267
|
+
flecto watch config/services.yaml --array-id-key serviceKey
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
To restore index-based diffs for every array, pass `--no-array-id`:
|
|
271
|
+
|
|
272
|
+
```bash
|
|
273
|
+
flecto watch config/services.yaml --no-array-id
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
In `.flectorc`, set `"arrayId": false` in `defaults` or a profile for the same
|
|
277
|
+
escape hatch.
|
|
278
|
+
|
|
279
|
+
### Command + webhook together
|
|
164
280
|
|
|
165
281
|
```bash
|
|
166
282
|
flecto watch .env \
|
|
@@ -179,37 +295,26 @@ flecto watch config/prod.yaml \
|
|
|
179
295
|
|
|
180
296
|
| Flag | Options | What it does |
|
|
181
297
|
|---|---|---|
|
|
182
|
-
| `--delivery-mode` | `best-effort` (default), `at-least-once` |
|
|
183
|
-
| `--on-alert-failure` | `warn`, `exit`, `retry` |
|
|
298
|
+
| `--delivery-mode` | `best-effort` (default), `at-least-once` | Persist and retry failed webhook events |
|
|
299
|
+
| `--on-alert-failure` | `warn`, `exit`, `retry` | Behavior when command/webhook fails |
|
|
184
300
|
|
|
185
301
|
---
|
|
186
302
|
|
|
187
|
-
## Snapshots &
|
|
188
|
-
|
|
189
|
-
Save a baseline snapshot of your file:
|
|
303
|
+
## Snapshots & diffs
|
|
190
304
|
|
|
191
305
|
```bash
|
|
192
306
|
flecto watch config/prod.yaml --snapshot
|
|
193
|
-
# Saved to .flecto-snapshots/<id>.json
|
|
194
|
-
```
|
|
195
|
-
|
|
196
|
-
Then compare the current file against it anytime:
|
|
197
|
-
|
|
198
|
-
```bash
|
|
199
307
|
flecto watch config/prod.yaml --diff
|
|
308
|
+
flecto history config/prod.yaml --limit 10
|
|
200
309
|
```
|
|
201
310
|
|
|
202
|
-
Exit codes:
|
|
203
|
-
- `0` — no changes (file is clean)
|
|
204
|
-
- `1` — changes detected
|
|
311
|
+
Exit codes: `0` clean · `1` changes detected.
|
|
205
312
|
|
|
206
|
-
|
|
313
|
+
`flecto history` stays local: it lists recent snapshots from `.flecto-snapshots/` with their timestamps and semantic change counts from the previous snapshot. Counts use the same ignore paths, array identity, and order settings as `flecto watch --diff` (CLI flags or `.flectorc`). Omit files to view all saved snapshot history.
|
|
207
314
|
|
|
208
315
|
---
|
|
209
316
|
|
|
210
|
-
## CI
|
|
211
|
-
|
|
212
|
-
Catch risky config changes before they ship:
|
|
317
|
+
## CI mode
|
|
213
318
|
|
|
214
319
|
```bash
|
|
215
320
|
flecto ci "config/**/*.yaml" \
|
|
@@ -218,49 +323,84 @@ flecto ci "config/**/*.yaml" \
|
|
|
218
323
|
--fail-on "changed,policy,error"
|
|
219
324
|
```
|
|
220
325
|
|
|
221
|
-
**
|
|
326
|
+
**Formats:** `json`, `ndjson`, `github-annotations`
|
|
327
|
+
**Fail triggers:** `changed`, `added`, `removed`, `policy`, `error`, `warn`
|
|
328
|
+
Unresolved `--snapshot-ref` fails closed (no silent empty baseline).
|
|
329
|
+
If every target is missing or unsupported, `flecto ci` and `flecto watch --snapshot` exit non-zero (pass `--allow-empty` to opt out).
|
|
222
330
|
|
|
223
|
-
|
|
331
|
+
### GitHub Action
|
|
332
|
+
|
|
333
|
+
Use the [Flecto CI Action](.github/actions/flecto-ci/action.yml) to run `flecto ci` in a workflow with GitHub annotations enabled by default. A complete local-action workflow is available at [`examples/github-action/flecto-ci.yml`](examples/github-action/flecto-ci.yml).
|
|
334
|
+
|
|
335
|
+
```yaml
|
|
336
|
+
permissions:
|
|
337
|
+
contents: read
|
|
338
|
+
|
|
339
|
+
steps:
|
|
340
|
+
- uses: actions/checkout@v7
|
|
341
|
+
with:
|
|
342
|
+
fetch-depth: 2
|
|
343
|
+
- uses: myselfsiddharth/Flecto/.github/actions/flecto-ci@main
|
|
344
|
+
with:
|
|
345
|
+
targets: config/**/*.{yaml,yml,json,toml,ini}
|
|
346
|
+
snapshot-ref: HEAD~1
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
`contents: read` is required by `actions/checkout`. The Action emits workflow-command annotations and needs no write permissions. Keep `fetch-depth: 2` (or use `fetch-depth: 0`) when using the default `HEAD~1` baseline.
|
|
350
|
+
|
|
351
|
+
| Input | Default | Description |
|
|
352
|
+
|---|---|---|
|
|
353
|
+
| `targets` | `config/**/*.{yaml,yml,json,toml,ini}` | Whitespace-separated paths or glob patterns to check |
|
|
354
|
+
| `fail-on` | `policy,error` | Comma-separated events that fail the job |
|
|
355
|
+
| `policies` | _(empty)_ | Comma-separated policy pack IDs; omit to use `.flectorc` / Flecto defaults |
|
|
356
|
+
| `profile` | _(empty)_ | Optional `.flectorc` profile |
|
|
357
|
+
| `format` | `github-annotations` | Flecto output format |
|
|
358
|
+
| `snapshot-ref` | `HEAD~1` | Git ref or snapshot file used as the baseline |
|
|
359
|
+
| `node-version` | `20` | Node.js version used to run Flecto |
|
|
360
|
+
|
|
361
|
+
The Action runs `npx --yes flecto@2 ci`: the major version is pinned so compatible Flecto updates are received. For fully reproducible builds, pin the Action reference to a commit SHA and replace `@2` in a forked Action with an exact published Flecto version.
|
|
224
362
|
|
|
225
363
|
---
|
|
226
364
|
|
|
227
|
-
## Built-in
|
|
365
|
+
## Built-in policy checks
|
|
228
366
|
|
|
229
|
-
|
|
367
|
+
Built-in pack ids:
|
|
230
368
|
|
|
231
|
-
-
|
|
232
|
-
-
|
|
233
|
-
-
|
|
369
|
+
- `default` — secrets, dangerous toggles, and pool-size jumps.
|
|
370
|
+
- `strict-prod` — stricter severities and matching for production use.
|
|
371
|
+
- `compose` — privileged services, host networking, Docker socket mounts, and sensitive host-directory bind mounts.
|
|
372
|
+
- `node-runtime` — removed Node.js engine requirements, TLS verification bypasses, and enabled Node debugging or inspector options.
|
|
234
373
|
|
|
235
|
-
|
|
374
|
+
Fail CI with `--fail-on policy`.
|
|
236
375
|
|
|
237
376
|
---
|
|
238
377
|
|
|
239
|
-
##
|
|
378
|
+
## Migrating from envelope 1.1
|
|
379
|
+
|
|
380
|
+
- `schema_version` is now `"2.0"`
|
|
381
|
+
- Type name is `FlectoEnvelope` (docs/types)
|
|
382
|
+
- New `policies` array on change envelopes
|
|
383
|
+
- Webhook headers unchanged (`X-Flecto-*`)
|
|
384
|
+
|
|
385
|
+
---
|
|
240
386
|
|
|
241
|
-
|
|
387
|
+
## Tuning for network drives / odd editors
|
|
242
388
|
|
|
243
389
|
```bash
|
|
244
390
|
flecto watch config/prod.yaml --polling --interval 500
|
|
245
391
|
```
|
|
246
392
|
|
|
247
|
-
|
|
393
|
+
Polling is off by default (interval default `100ms` when enabled).
|
|
248
394
|
|
|
249
395
|
---
|
|
250
396
|
|
|
251
|
-
## Config
|
|
252
|
-
|
|
253
|
-
Set your defaults once so you don't have to repeat flags every time.
|
|
254
|
-
|
|
255
|
-
Generate a starter config:
|
|
397
|
+
## Config file (`.flectorc`)
|
|
256
398
|
|
|
257
399
|
```bash
|
|
258
400
|
flecto init
|
|
259
401
|
```
|
|
260
402
|
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
Example:
|
|
403
|
+
Looks for `.flectorc`, `.flectorc.json`, `.flectorc.yaml`, or `.flectorc.yml`.
|
|
264
404
|
|
|
265
405
|
```json
|
|
266
406
|
{
|
|
@@ -269,35 +409,35 @@ Example:
|
|
|
269
409
|
"interval": 100,
|
|
270
410
|
"ignore": ["**.updated_at"],
|
|
271
411
|
"deliveryMode": "best-effort",
|
|
272
|
-
"onAlertFailure": "warn"
|
|
412
|
+
"onAlertFailure": "warn",
|
|
413
|
+
"policies": ["default"],
|
|
414
|
+
"arrayId": true
|
|
273
415
|
},
|
|
274
416
|
"profiles": {
|
|
275
417
|
"dev": { "mode": "verbose" },
|
|
276
|
-
"ci": { "failOn": "policy,error" }
|
|
418
|
+
"ci": { "failOn": "policy,error" },
|
|
419
|
+
"prod": {
|
|
420
|
+
"policies": ["default", "strict-prod"],
|
|
421
|
+
"severityRemap": { "pool-size-jump": "error" },
|
|
422
|
+
"maskSecrets": true
|
|
423
|
+
}
|
|
277
424
|
},
|
|
278
|
-
"files": ["config/**/*.yaml", ".env"],
|
|
425
|
+
"files": ["config/**/*.{yaml,yml,json,toml,ini}", ".env", ".env.*", "*.env"],
|
|
279
426
|
"exclude": ["**/node_modules/**"]
|
|
280
427
|
}
|
|
281
428
|
```
|
|
282
429
|
|
|
283
|
-
Use a named profile:
|
|
284
|
-
|
|
285
430
|
```bash
|
|
286
431
|
flecto watch --profile dev
|
|
287
432
|
flecto ci --profile ci
|
|
288
|
-
```
|
|
289
|
-
|
|
290
|
-
CLI flags always override profile/default values.
|
|
291
|
-
|
|
292
|
-
Verify your setup:
|
|
293
|
-
|
|
294
|
-
```bash
|
|
295
433
|
flecto doctor
|
|
296
434
|
```
|
|
297
435
|
|
|
436
|
+
CLI flags override profile/default values.
|
|
437
|
+
|
|
298
438
|
---
|
|
299
439
|
|
|
300
|
-
## Output
|
|
440
|
+
## Output format reference
|
|
301
441
|
|
|
302
442
|
### Compact (default)
|
|
303
443
|
|
|
@@ -315,47 +455,45 @@ flecto doctor
|
|
|
315
455
|
~ path
|
|
316
456
|
before: old_value
|
|
317
457
|
after: new_value
|
|
318
|
-
+ path: value
|
|
319
|
-
(key added)
|
|
320
458
|
```
|
|
321
459
|
|
|
322
460
|
---
|
|
323
461
|
|
|
324
|
-
## Error
|
|
325
|
-
|
|
326
|
-
Flecto is designed to keep running even when things go wrong:
|
|
462
|
+
## Error handling
|
|
327
463
|
|
|
328
464
|
| Situation | Behavior |
|
|
329
465
|
|---|---|
|
|
330
|
-
| File not found | Error
|
|
331
|
-
| Unsupported
|
|
332
|
-
|
|
|
333
|
-
| Command fails | Warning
|
|
334
|
-
|
|
|
335
|
-
| Ctrl+C | Clean shutdown message |
|
|
466
|
+
| File not found | Error + exit 1 |
|
|
467
|
+
| Unsupported format | Lists supported extensions + exit 1 |
|
|
468
|
+
| Parse error while watching | Warning, last valid state kept |
|
|
469
|
+
| Command / webhook fails | Warning (unless `--on-alert-failure exit`) |
|
|
470
|
+
| Ctrl+C | Clean shutdown |
|
|
336
471
|
|
|
337
472
|
---
|
|
338
473
|
|
|
339
|
-
##
|
|
474
|
+
## How it works
|
|
340
475
|
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
476
|
+
1. **Parser** — format by extension / dotenv naming → structured values
|
|
477
|
+
2. **Watcher** — [chokidar](https://github.com/paulmillr/chokidar) + debounce
|
|
478
|
+
3. **Differ** — semantic tree diff (objects, arrays, ignore rules, automatic array ids)
|
|
479
|
+
4. **Policy engine** — packs + plugins → severity findings
|
|
480
|
+
5. **Envelope** — versioned automation payload (`2.0`)
|
|
481
|
+
6. **Alerter** — command and/or webhook with retry modes
|
|
482
|
+
|
|
483
|
+
---
|
|
484
|
+
|
|
485
|
+
## Contributing
|
|
486
|
+
|
|
487
|
+
Flecto is open source. See [CONTRIBUTING.md](CONTRIBUTING.md) for setup, PR rules, and review expectations.
|
|
488
|
+
Please read the [Code of Conduct](CODE_OF_CONDUCT.md) and [Security policy](SECURITY.md).
|
|
346
489
|
|
|
347
|
-
|
|
490
|
+
Roadmap lives in [GitHub milestones](https://github.com/myselfsiddharth/Flecto/milestones).
|
|
348
491
|
|
|
349
492
|
---
|
|
350
493
|
|
|
351
|
-
##
|
|
494
|
+
## Star the project
|
|
352
495
|
|
|
353
|
-
|
|
354
|
-
2. **Watcher** — uses [chokidar](https://github.com/paulmillr/chokidar) with debouncing so rapid saves don't flood you with events.
|
|
355
|
-
3. **Differ** — computes a semantic diff (not a line diff), supporting objects, arrays, scalars, and ignore rules.
|
|
356
|
-
4. **Policy engine** — inspects the changes for patterns that look risky and adds severity findings.
|
|
357
|
-
5. **Envelope** — wraps each batch of changes in a versioned event schema ready for automation.
|
|
358
|
-
6. **Alerter** — delivers events via command execution and/or webhook, with configurable retry logic.
|
|
496
|
+
If Flecto helps your team catch a risky config change — **[star the repo](https://github.com/myselfsiddharth/Flecto)** so more people can find it.
|
|
359
497
|
|
|
360
498
|
---
|
|
361
499
|
|