configsentry 0.0.24 → 0.0.26

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.
Files changed (3) hide show
  1. package/README.md +21 -5
  2. package/dist/cli.js +42 -4
  3. package/package.json +4 -2
package/README.md CHANGED
@@ -15,7 +15,7 @@ npx configsentry ./docker-compose.yml
15
15
  ### GitHub Action (minimal)
16
16
 
17
17
  ```yml
18
- - uses: alfredMorgenstern/configsentry@v0.0.23
18
+ - uses: alfredMorgenstern/configsentry@v0.0.25
19
19
  with:
20
20
  target: .
21
21
  ```
@@ -27,7 +27,7 @@ permissions:
27
27
  contents: read
28
28
  security-events: write
29
29
 
30
- - uses: alfredMorgenstern/configsentry@v0.0.23
30
+ - uses: alfredMorgenstern/configsentry@v0.0.25
31
31
  with:
32
32
  target: .
33
33
  sarif: true
@@ -72,10 +72,16 @@ node dist/cli.js --target ./docker-compose.yml
72
72
  node dist/cli.js --target ./docker-compose.yml --format json
73
73
  ```
74
74
 
75
+ Write JSON to a file (no shell redirection needed):
76
+
77
+ ```bash
78
+ node dist/cli.js --target ./docker-compose.yml --format json --output configsentry.json
79
+ ```
80
+
75
81
  ### SARIF output (GitHub Code Scanning)
76
82
 
77
83
  ```bash
78
- node dist/cli.js --target ./docker-compose.yml --format sarif > configsentry.sarif.json
84
+ node dist/cli.js --target ./docker-compose.yml --format sarif --output configsentry.sarif.json
79
85
  ```
80
86
 
81
87
  ## Baselines (incremental adoption)
@@ -146,7 +152,7 @@ jobs:
146
152
  runs-on: ubuntu-latest
147
153
  steps:
148
154
  - uses: actions/checkout@v4
149
- - uses: alfredMorgenstern/configsentry@v0.0.23
155
+ - uses: alfredMorgenstern/configsentry@v0.0.25
150
156
  with:
151
157
  target: .
152
158
  # optional: baseline: .configsentry-baseline.json
@@ -160,13 +166,23 @@ jobs:
160
166
 
161
167
  **Note (consumer repos):** your repo does **not** need a `package-lock.json`. The action installs/builds ConfigSentry from the action package itself.
162
168
 
163
- > Tip: pin to a tag (like `v0.0.18`) for reproducible builds.
169
+ > Tip: pin to a tag (like `v0.0.25`) for reproducible builds.
164
170
 
165
171
  ## Exit codes
166
172
  - `0` no findings
167
173
  - `2` findings present
168
174
  - `1` error
169
175
 
176
+ ## CI: fail only on high severity (optional)
177
+
178
+ If you want ConfigSentry to block builds only on high severity findings:
179
+
180
+ ```bash
181
+ npx configsentry ./docker-compose.yml --severity-threshold high
182
+ ```
183
+
184
+ This also works in GitHub Actions via `args:` (see `docs/action-usage.md`).
185
+
170
186
  ## Example
171
187
 
172
188
  ```bash
package/dist/cli.js CHANGED
@@ -8,6 +8,9 @@ import { runRules } from './rules.js';
8
8
  import { findingsToSarif } from './sarif.js';
9
9
  import { resolveTargets } from './scan.js';
10
10
  import { applyBaseline, loadBaseline, writeBaseline } from './baseline.js';
11
+ function severityRank(s) {
12
+ return s === 'low' ? 1 : s === 'medium' ? 2 : 3;
13
+ }
11
14
  function parseArgs(argv) {
12
15
  const args = argv.slice(2);
13
16
  const help = args.includes('-h') || args.includes('--help');
@@ -29,13 +32,17 @@ function parseArgs(argv) {
29
32
  const baselinePath = baselineIdx >= 0 ? args[baselineIdx + 1] : undefined;
30
33
  const writeBaselineIdx = args.indexOf('--write-baseline');
31
34
  const writeBaselinePath = writeBaselineIdx >= 0 ? args[writeBaselineIdx + 1] : undefined;
35
+ const severityThresholdIdx = args.indexOf('--severity-threshold');
36
+ const severityThreshold = severityThresholdIdx >= 0 ? args[severityThresholdIdx + 1] : undefined;
37
+ const outputIdx = args.indexOf('--output');
38
+ const outputPath = outputIdx >= 0 ? args[outputIdx + 1] : undefined;
32
39
  // Prefer explicit flag (matches the GitHub Action input)
33
40
  const targetIdx = args.indexOf('--target');
34
41
  const targetFromFlag = targetIdx >= 0 ? args[targetIdx + 1] : undefined;
35
42
  // Back-compat: first positional arg
36
43
  const targetFromPositional = args.find((a) => !a.startsWith('-'));
37
44
  const target = targetFromFlag ?? targetFromPositional;
38
- return { args, help, version, output, format, baselinePath, writeBaselinePath, target };
45
+ return { args, help, version, output, format, outputPath, baselinePath, writeBaselinePath, severityThreshold, target };
39
46
  }
40
47
  function usage() {
41
48
  console.log(`ConfigSentry (MVP)
@@ -48,6 +55,9 @@ Output:
48
55
  --json machine-readable findings (deprecated; use --format json)
49
56
  --sarif SARIF 2.1.0 (for GitHub code scanning) (deprecated; use --format sarif)
50
57
  --format <pretty|json|sarif>
58
+ --output <file> write JSON/SARIF output to a file (use with --format)
59
+ --severity-threshold <low|medium|high>
60
+ only report findings at/above this severity (affects exit code)
51
61
 
52
62
  Baselines:
53
63
  --baseline <file> suppress findings present in a baseline file
@@ -60,7 +70,7 @@ Exit codes:
60
70
  `);
61
71
  }
62
72
  async function main() {
63
- const { args, help, version, output, format, baselinePath, writeBaselinePath, target } = parseArgs(process.argv);
73
+ const { args, help, version, output, format, outputPath, baselinePath, writeBaselinePath, severityThreshold, target } = parseArgs(process.argv);
64
74
  if (version) {
65
75
  try {
66
76
  const here = path.dirname(fileURLToPath(import.meta.url));
@@ -90,6 +100,14 @@ async function main() {
90
100
  console.error('Error: choose only one output mode: --json, --sarif, or --format');
91
101
  process.exit(1);
92
102
  }
103
+ if (outputPath && output === 'pretty') {
104
+ console.error('Error: --output requires machine output (use --format json or --format sarif)');
105
+ process.exit(1);
106
+ }
107
+ if (severityThreshold && severityThreshold !== 'low' && severityThreshold !== 'medium' && severityThreshold !== 'high') {
108
+ console.error(`Error: invalid --severity-threshold '${severityThreshold}'. Expected: low | medium | high`);
109
+ process.exit(1);
110
+ }
93
111
  if (!target) {
94
112
  usage();
95
113
  process.exit(1);
@@ -113,6 +131,14 @@ async function main() {
113
131
  findings = res.kept;
114
132
  suppressed = res.suppressed;
115
133
  }
134
+ // Severity threshold filtering (affects reporting + exit code)
135
+ if (severityThreshold) {
136
+ const min = severityRank(severityThreshold);
137
+ findings = findings.filter((f) => {
138
+ const sev = f.severity ?? 'low';
139
+ return severityRank(sev) >= min;
140
+ });
141
+ }
116
142
  // Baseline generation mode
117
143
  if (writeBaselinePath) {
118
144
  await writeBaseline(path.resolve(writeBaselinePath), allFindings);
@@ -120,10 +146,22 @@ async function main() {
120
146
  process.exit(0);
121
147
  }
122
148
  if (output === 'json') {
123
- console.log(JSON.stringify({ targetPaths, findings, suppressedCount: suppressed.length }, null, 2));
149
+ const payload = JSON.stringify({ targetPaths, findings, suppressedCount: suppressed.length }, null, 2);
150
+ if (outputPath) {
151
+ await fs.writeFile(path.resolve(outputPath), payload, 'utf8');
152
+ }
153
+ else {
154
+ console.log(payload);
155
+ }
124
156
  }
125
157
  else if (output === 'sarif') {
126
- console.log(JSON.stringify(findingsToSarif(findings), null, 2));
158
+ const payload = JSON.stringify(findingsToSarif(findings), null, 2);
159
+ if (outputPath) {
160
+ await fs.writeFile(path.resolve(outputPath), payload, 'utf8');
161
+ }
162
+ else {
163
+ console.log(payload);
164
+ }
127
165
  }
128
166
  else {
129
167
  const scope = targetPaths.length === 1 ? targetPaths[0] : `${targetPaths.length} file(s)`;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "configsentry",
3
- "version": "0.0.24",
3
+ "version": "0.0.26",
4
4
  "description": "Developer-first guardrails for docker-compose.yml (security + ops footguns).",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -31,7 +31,9 @@
31
31
  "prepack": "npm run build",
32
32
  "start": "node dist/cli.js",
33
33
  "dev": "node --loader ts-node/esm src/cli.ts",
34
- "lint:example": "node dist/cli.js ./example.docker-compose.yml"
34
+ "lint:example": "node dist/cli.js ./example.docker-compose.yml",
35
+ "demo": "node dist/cli.js --target ./docs/demo/docker-compose.demo.yml",
36
+ "demo:json": "node dist/cli.js --target ./docs/demo/docker-compose.demo.yml --format json --output /tmp/configsentry-demo.json"
35
37
  },
36
38
  "keywords": [
37
39
  "docker",