actions-warden 0.3.0 → 0.4.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/AGENTS.md CHANGED
@@ -58,10 +58,11 @@ actions-warden org-scan ORG --agent-mode
58
58
  checkpoint. It emits only a bounded JSON receipt to stdout. The packaged
59
59
  skill should pass the flag; an integration may instead set
60
60
  `ACTIONS_WARDEN_MODE=agent` once.
61
- - Automatic artifact names are derived from the complete checkpoint identity.
62
- An exact-scope later run resumes its checkpoint; a changed filter, severity,
63
- policy, baseline, tool version, or rule catalog receives a different path.
64
- Compatibility validation still fails closed.
61
+ - Automatic artifact names are derived from the checkpoint compatibility
62
+ identity. An exact-scope later run resumes its checkpoint across compatible
63
+ package versions; a changed filter, severity, policy, baseline, analysis
64
+ generation, or rule catalog receives a different path. Compatibility
65
+ validation still fails closed.
65
66
  - Preserve the scope the user requested. Reducing LLM context use is not
66
67
  permission to omit repositories, severities, findings, or errors.
67
68
  - Explicit CLI choices override agent defaults. If the user asks to watch live
@@ -112,8 +113,13 @@ deprecating a package. A release request does not authorize those actions.
112
113
  ## Non-negotiable invariants
113
114
 
114
115
  - `pin` and `upgrade` are dry-run by default.
116
+ - CLI usage errors return `2`; numeric limits and change IDs are parsed
117
+ strictly, and contradictory flags fail before command work begins.
115
118
  - Writes remain within the real repository root, reject symlink escapes, are
116
119
  atomic, preserve permissions, and reparse modified YAML.
120
+ - CLI report, baseline, and checkpoint destinations are preflighted before
121
+ network or workflow mutation and cannot replace workflow or policy-control
122
+ files.
117
123
  - GitHub ref resolution and commit ownership fail closed.
118
124
  - Credentials are redacted in every format, annotation, and top-level error.
119
125
  - Finding IDs are clone-independent; pin findings and plans share an ID.
@@ -123,6 +129,10 @@ deprecating a package. A release request does not authorize those actions.
123
129
  - Organization resume requires fresh discovery and matching default-branch tree
124
130
  SHAs; never reuse failed results. Checkpoints remain guarded, atomic, and free
125
131
  of tokens or raw YAML.
132
+ - `ORGANIZATION_ANALYSIS_GENERATION` is the organization-result compatibility
133
+ boundary. Increment it whenever discovery, parser, finding identity, rule
134
+ evaluation, or persisted result semantics can change; do not increment it
135
+ for a version-only compatible release.
126
136
  - CLI progress stays on stderr and never corrupts structured report stdout.
127
137
  - Attacker-controlled text cannot forge output records or workflow commands.
128
138
 
package/README.md CHANGED
@@ -57,7 +57,7 @@ actions-warden verify
57
57
  For a one-off run without a global install:
58
58
 
59
59
  ```sh
60
- npx --yes actions-warden@0.3.0 audit --explain
60
+ npx --yes actions-warden@0.4.0 audit --explain
61
61
  ```
62
62
 
63
63
  `audit` returns exit code `1` when it finds issues. That is a completed scan,
@@ -109,6 +109,12 @@ reused; changed and previously failed repositories are scanned again. Progress
109
109
  defaults to interactive terminals; use `--progress=always` for redirected logs
110
110
  or `--progress=never` to disable it.
111
111
 
112
+ Compatible package upgrades reuse the same checkpoint. The producing package
113
+ version is recorded as metadata, while an explicit analysis generation plus
114
+ the rule catalog controls compatibility. A parser, discovery, or rule behavior
115
+ change advances that generation and requires a fresh scan. Compatible older
116
+ checkpoints are rewritten atomically on their first successful resume.
117
+
112
118
  When a coding agent initiates the scan, use the explicit bounded mode:
113
119
 
114
120
  ```sh
@@ -150,8 +156,14 @@ audit/report/pin/upgrade plan → review IDs and diffs → --fix=<id> --write
150
156
  - `pin` and `upgrade` are dry-runs unless `--write` is present.
151
157
  - `--write --dry-run` is rejected instead of guessing intent.
152
158
  - `--fix=<id>` limits a pin or upgrade to one exact source occurrence.
159
+ - Numeric limits and change IDs are parsed strictly; partial, fractional, and
160
+ imprecise values fail before network or write work begins.
153
161
  - Rewrites preserve surrounding YAML and are reparsed before an atomic write.
154
- - Paths, output files, and symlinks are constrained to the selected repository.
162
+ - `--output-path` implies file output; contradictory or incomplete output flags
163
+ are rejected before a scan or authorized mutation begins.
164
+ - Paths, output files, and symlinks are constrained to the selected repository,
165
+ and report/baseline/checkpoint destinations cannot replace workflows or
166
+ policy controls.
155
167
  - Credential-like values are recursively redacted from every output format.
156
168
  - Repository policy is strictly validated; unknown keys and rule IDs fail.
157
169
  - Remote organization source is kept in memory and is not persisted in cache.
package/SECURITY.md CHANGED
@@ -12,7 +12,7 @@ Please include:
12
12
 
13
13
  - A clear description of the issue.
14
14
  - A minimal reproduction (workflow YAML, command line, expected vs. actual).
15
- - The version of `actions-warden` (`npx --yes actions-warden@0.3.0 --version`).
15
+ - The version of `actions-warden` (`npx --yes actions-warden@0.4.0 --version`).
16
16
  - Any disclosure constraints on your side.
17
17
 
18
18
  We aim to acknowledge within **3 business days** and to ship a fix or a
@@ -50,16 +50,21 @@ Out of scope:
50
50
  install dependencies in consumer workflows.
51
51
  - Repository policy and baseline files should be protected with CODEOWNERS or
52
52
  branch rules; changes to them can intentionally alter which findings fail CI.
53
+ - CLI report, baseline, and checkpoint destinations are guarded and preflighted;
54
+ they cannot replace selected/default-discovery workflows or reserved policy
55
+ paths, and active control-file collisions are rejected before output writes.
53
56
  - Parser failures are operational errors and cannot be suppressed by a finding
54
57
  baseline.
55
58
  - Organization scans read count- and size-bounded Git blobs in memory and never
56
59
  clone, check out, or execute code from scanned repositories. Truncated trees,
57
60
  exceeded limits, and unreadable blobs are operational errors.
58
61
  - Organization checkpoints are opt-in, guarded atomic writes. They omit tokens
59
- and raw workflow YAML, validate tool/rule/scope/policy identity, and reuse an
60
- error-free result only after a fresh repository/default-branch tree-SHA
61
- match. They still contain redacted repository and finding evidence and should
62
- be protected like organization reports.
62
+ and raw workflow YAML, validate analysis-generation/rule/scope/policy
63
+ identity, and reuse an error-free result only after a fresh
64
+ repository/default-branch tree-SHA match. The producing package version is
65
+ metadata rather than a compatibility boundary. They still contain redacted
66
+ repository and finding evidence and should be protected like organization
67
+ reports.
63
68
  - Explicit CLI agent mode creates scope-keyed report and checkpoint files with
64
69
  the same guarded writer and `0600` creation mode. Its stdout receipt contains
65
70
  only paths and bounded counts; the artifact files remain sensitive.
package/docs/AI-AGENTS.md CHANGED
@@ -88,6 +88,15 @@ found something. Parse and present the report.
88
88
 
89
89
  Exit code `2` is an invocation-level problem. Read stderr, do not assume stdout
90
90
  contains valid JSON, and do not retry by weakening policy or changing paths.
91
+ Unknown options, conflicting flags, malformed numeric values, invalid change
92
+ IDs, unsafe destinations, and a missing command all use this exit code. These
93
+ checks happen before network requests or authorized workflow mutations whenever
94
+ the required path information is available.
95
+
96
+ When saving a report, `--output-path=<path>` is sufficient and implies file
97
+ output. Do not combine it with explicit `--output=stdout`. Create the parent
98
+ directory first, and never select a workflow, policy, baseline, or checkpoint
99
+ path as the report destination.
91
100
 
92
101
  For an organization scan, report coverage before findings:
93
102
 
@@ -260,19 +269,26 @@ Agent mode is an explicit contract, not heuristic detection. By default it:
260
269
  - selects JSON and writes the full report to a guarded hidden file;
261
270
  - disables progress;
262
271
  - creates a guarded hidden checkpoint on the first run;
263
- - resumes that checkpoint on a later run with the exact same checkpoint
264
- identity;
272
+ - resumes that checkpoint on a later run with the same compatibility identity,
273
+ including across package-version-only upgrades;
265
274
  - emits only a bounded JSON receipt containing status, coverage summary,
266
275
  report path, report format, checkpoint path, and whether resume was used.
267
276
 
268
277
  The automatic artifact key covers the organization, repository filters,
269
278
  inclusion flags, repository limit, severity, explanation setting, normalized
270
- policy, baseline contents, tool version, and rule catalog. A changed scope or
271
- security control therefore receives a different path instead of replacing an
272
- incompatible checkpoint. The generated files begin
279
+ policy, baseline contents, analysis generation, and rule catalog. A compatible
280
+ package upgrade keeps the same path and atomically migrates older checkpoint
281
+ metadata on the first successful resume. A changed scope, security control, or
282
+ analysis behavior receives a different path instead of replacing an
283
+ incompatible checkpoint.
284
+ The generated files begin
273
285
  `.actions-warden-agent.`; protect them as sensitive report artifacts and add
274
286
  that pattern to the consuming repository's ignore rules when appropriate.
275
287
 
288
+ Version-only upgrades do not accumulate new automatic artifacts. A deliberate
289
+ analysis-generation change does retain the older keyed files as audit evidence;
290
+ remove them only under the consuming repository's retention policy.
291
+
276
292
  Explicit CLI options take precedence over agent defaults. Use
277
293
  `--progress=always` when the user requests live progress. Use
278
294
  `--output=stdout` only when the caller intentionally wants the complete report
package/docs/CLI.md CHANGED
@@ -21,7 +21,7 @@ actions-warden --version
21
21
  For reproducible one-off automation, invoke an exact package version:
22
22
 
23
23
  ```sh
24
- npx --yes actions-warden@0.3.0 audit
24
+ npx --yes actions-warden@0.4.0 audit
25
25
  ```
26
26
 
27
27
  Network-backed commands resolve credentials in this order:
@@ -38,16 +38,20 @@ metadata and contents read access needed for the requested scope.
38
38
  ## Target and output options
39
39
 
40
40
  The repository commands (`audit`, `pin`, `verify`, `upgrade`, and `report`)
41
- share these options:
41
+ share these target and output options:
42
42
 
43
43
  | option | default | behavior |
44
44
  |---|---|---|
45
45
  | `-w, --workflow <pattern...>` | discovery | One or more files, directories, or globs |
46
46
  | `--cwd <dir>` | current directory | Repository and path-safety root |
47
- | `--token <token>` | environment | GitHub API credential for network-backed work |
48
47
  | `--format <format>` | `toon` | `toon`, `json`, `text`, or `sarif` |
49
48
  | `--output <destination>` | `stdout` | `stdout` or `file` |
50
- | `--output-path <path>` | none | Required with `--output=file`; resolved inside `--cwd` |
49
+ | `--output-path <path>` | none | Report path inside `--cwd`; implies `--output=file` |
50
+
51
+ `pin`, `verify`, `upgrade`, and online `report` also accept `--token`. `audit`
52
+ is entirely local and does not accept a token. `report --offline` rejects an
53
+ explicit token, mode, or cooldown because those options would otherwise be
54
+ silently unused.
51
55
 
52
56
  Without `--workflow`, actions-warden discovers:
53
57
 
@@ -72,19 +76,28 @@ actions-warden audit --cwd ../service
72
76
  ```
73
77
 
74
78
  Output files are created atomically and must remain within the real working
75
- directory after symlinks are resolved:
79
+ directory after symlinks are resolved. Their parent directory must already
80
+ exist. `--output=file` without a path and an explicit
81
+ `--output=stdout --output-path=...` are invocation errors. Report, baseline,
82
+ and checkpoint destinations are preflighted before network or mutation work;
83
+ they cannot be directories, symlinks, selected workflows, default workflow
84
+ discovery paths, or the reserved `.actions-warden.yml` and
85
+ `.actions-warden.yaml` policy paths. Active configuration and baseline paths
86
+ are checked again before any report or baseline destination is written.
76
87
 
77
88
  ```sh
78
89
  actions-warden audit \
79
90
  --format=sarif \
80
- --output=file \
81
91
  --output-path=reports/actions-warden.sarif
82
92
  ```
83
93
 
94
+ `--output=file --output-path=...` remains valid when an explicit destination
95
+ is clearer in automation.
96
+
84
97
  ## `audit`
85
98
 
86
99
  Scan local workflows and composite actions without making network calls or
87
- changing files.
100
+ changing workflows. It writes only an explicitly requested report or baseline.
88
101
 
89
102
  ```sh
90
103
  actions-warden audit \
@@ -105,8 +118,10 @@ actions-warden audit \
105
118
  --create-baseline=.actions-warden-baseline.json
106
119
  ```
107
120
 
108
- `--create-baseline` cannot be combined with `--baseline`. Parser failures are
109
- never written into the baseline. See [configuration and baselines](./CONFIGURATION.md).
121
+ `--create-baseline` cannot be combined with `--baseline`, cannot share the
122
+ report output path, and is validated before the audit begins. Parser failures
123
+ are never written into the baseline. See
124
+ [configuration and baselines](./CONFIGURATION.md).
110
125
 
111
126
  Exit code `0` means no unsuppressed findings; `1` means findings were reported;
112
127
  `2` means the scan could not be invoked safely or correctly.
@@ -141,7 +156,9 @@ or one exact stable ID:
141
156
  actions-warden pin --fix=18b82e86d7c14fe2 --write
142
157
  ```
143
158
 
144
- `--write` and `--dry-run` together are rejected.
159
+ `--write` and `--dry-run` together are rejected. `--fix` must be one exact
160
+ 16-character hexadecimal ID from a current plan; uppercase input is normalized
161
+ for convenience.
145
162
 
146
163
  ## `verify`
147
164
 
@@ -176,7 +193,9 @@ Defaults are `--mode=minor --min-age=7` and dry-run. Tag discovery is paginated;
176
193
  prereleases and downgrades are excluded. A candidate tag must be older than the
177
194
  cooldown. The age comes from GitHub release publication data when available,
178
195
  then from locally recorded first-seen evidence for the exact tag-to-SHA mapping.
179
- Missing evidence fails closed.
196
+ Missing evidence fails closed. `--min-age` accepts only a non-negative integer;
197
+ values such as `7days`, `1.5`, and values outside JavaScript's safe integer
198
+ range are rejected rather than truncated.
180
199
 
181
200
  SHA-pinned references need `actions-warden-ref` metadata to establish the
182
201
  current semantic version. Legacy plain-semver comments remain readable.
@@ -207,7 +226,8 @@ actions-warden report \
207
226
  The audit determines the target set; pin and upgrade use exactly that same
208
227
  scope. A location with an upgrade is not duplicated as a pin proposal.
209
228
  `--offline` skips both network-backed planning phases and returns only the
210
- local audit.
229
+ local audit. Because they cannot affect an offline report, explicitly combining
230
+ `--offline` with `--token`, `--mode`, or `--min-age` is rejected.
211
231
 
212
232
  Use report for review, issue generation, or an AI planning step. It never
213
233
  accepts `--write`.
@@ -244,7 +264,9 @@ Defaults:
244
264
 
245
265
  Repository patterns match either `name` or `owner/name`, case-insensitively.
246
266
  An explicit pattern set that matches no eligible repository is an error.
247
- Selection is stable before `--max-repos` is applied.
267
+ Selection is stable before `--max-repos` is applied. `--max-repos` must be a
268
+ positive safe integer, and `--concurrency` must be an integer from 1 through
269
+ 16; malformed, fractional, or imprecise values fail before any API request.
248
270
 
249
271
  ```sh
250
272
  actions-warden org-scan my-org \
@@ -287,8 +309,9 @@ When the corresponding options were not explicitly supplied, agent mode sets:
287
309
 
288
310
  The artifact key includes the organization, repository filters, inclusion
289
311
  flags, repository limit, severity, explanation setting, normalized policy,
290
- baseline contents, package version, and rule catalog. A scope or security
291
- control change therefore selects a different checkpoint rather than
312
+ baseline contents, analysis generation, and rule catalog. A compatible package
313
+ upgrade therefore keeps the same paths, while a scope, security-control, or
314
+ analysis-behavior change selects a different checkpoint rather than
292
315
  overwriting incompatible state. Generated paths have these shapes:
293
316
 
294
317
  ```text
@@ -321,7 +344,8 @@ an invocation error. Explicit `--format`, `--output`, `--output-path`,
321
344
  `--progress`, `--checkpoint`, and `--resume` choices override agent defaults.
322
345
  With explicit `--output=stdout`, stdout is the complete selected report and no
323
346
  receipt is added. Use `--no-agent-mode` to override an inherited environment
324
- marker. `ACTIONS_WARDEN_MODE` must be exactly `agent` when set.
347
+ marker. Passing both agent-mode flags is rejected. `ACTIONS_WARDEN_MODE` must
348
+ be exactly `agent` when set.
325
349
 
326
350
  ### Progress and resume
327
351
 
@@ -345,8 +369,8 @@ actions-warden org-scan my-org \
345
369
  ```
346
370
 
347
371
  Resume with the same organization, filters, inclusion flags, repository limit,
348
- severity, explanation setting, configuration, baseline, tool version, and rule
349
- catalog:
372
+ severity, explanation setting, configuration, baseline, analysis generation,
373
+ and rule catalog:
350
374
 
351
375
  ```sh
352
376
  actions-warden org-scan my-org \
@@ -358,11 +382,18 @@ actions-warden org-scan my-org \
358
382
  ```
359
383
 
360
384
  The token, concurrency, output format, progress mode, and report destination do
361
- not affect checkpoint compatibility. A resumed scan always lists repositories
362
- again and fetches a fresh default-branch tree for each selected repository.
363
- An error-free result is reused only when repository identity, default branch,
364
- and tree SHA still match. Changed repositories and any checkpointed result with
365
- an operational error are scanned again.
385
+ not affect checkpoint compatibility. Neither does a package-version-only
386
+ upgrade: the producing version is retained as checkpoint metadata, and a
387
+ compatible older checkpoint is rewritten atomically on its first successful
388
+ resume. The
389
+ explicit analysis generation is advanced when discovery, parsing, finding
390
+ identity, rule evaluation, or persisted result behavior changes. An
391
+ incompatible generation fails closed; automatic agent mode selects a new keyed
392
+ path. A resumed scan always lists repositories again and fetches a fresh
393
+ default-branch tree for each selected repository. An error-free result is
394
+ reused only when repository identity, default branch, and tree SHA still match.
395
+ Changed repositories and any checkpointed result with an operational error are
396
+ scanned again.
366
397
 
367
398
  `--checkpoint` starts a new checkpoint and replaces an existing file at that
368
399
  path. `--resume` requires a valid existing checkpoint and updates it. The
@@ -373,6 +404,11 @@ not the token or raw YAML, but can still reveal private repository names,
373
404
  paths, findings, and security posture; protect and retain them accordingly.
374
405
  Checkpoint reads and writes are capped at 256 MiB.
375
406
 
407
+ Version-only upgrades no longer create extra agent artifacts. When an analysis
408
+ generation intentionally changes, the older keyed report and checkpoint are
409
+ retained rather than deleted automatically because they may be needed as audit
410
+ evidence; remove them according to the consuming repository's retention policy.
411
+
376
412
  The scanner reads the default-branch Git tree and YAML blobs in memory. It
377
413
  never clones, checks out, or executes remote content. It fails closed on
378
414
  truncated trees and enforces these bounds per repository:
@@ -398,6 +434,23 @@ actions-warden rules --format=json
398
434
 
399
435
  This command has no repository or network dependency.
400
436
 
437
+ ## Exit status and invocation errors
438
+
439
+ Every command uses the same process contract:
440
+
441
+ - `0`: completed with status `OK`, or displayed help/version information;
442
+ - `1`: completed with a structured `FAIL` result, such as findings or
443
+ operational errors;
444
+ - `2`: could not start or complete safely because the command line, paths,
445
+ configuration, inputs, or environment were invalid.
446
+
447
+ Commander-level failures such as unknown flags, missing values, invalid
448
+ choices, conflicts, excess arguments, and a missing command also return `2`.
449
+ Argument parsing and destination preflight run before network requests and
450
+ before authorized workflow writes; active-control collisions are checked again
451
+ before output. On exit `2`, treat stderr as the error channel and do not assume
452
+ stdout contains a complete structured result.
453
+
401
454
  ## Cache and network behavior
402
455
 
403
456
  Local `pin`, `verify`, `upgrade`, and online `report` work caches successful
@@ -81,6 +81,7 @@ src/
81
81
  lib/
82
82
  parser.js YAML-to-normalized-workflow model
83
83
  targets.js, paths.js repository target discovery
84
+ path-equality.js real-path destination/control comparisons
84
85
  config.js, baseline.js policy and accepted-finding controls
85
86
  resolver.js, cache.js GitHub API, caching, ref and ownership checks
86
87
  github-org.js read-only organization/tree/blob access
@@ -139,11 +140,17 @@ Changes must preserve these boundaries:
139
140
 
140
141
  - `pin` and `upgrade` default to dry-run at the command and API layers.
141
142
  - CLI and Action mutation require an explicit write option.
143
+ - CLI integers and 16-hex change IDs use strict whole-value parsing. Commander
144
+ usage failures and application-level invocation failures both exit `2`.
142
145
  - A resolver failure must not fall back to a guessed tag or SHA.
143
146
  - Commits must be verified as belonging to the referenced repository.
144
147
  - Workflow rewrites operate on parsed scalar ranges and reparse before write.
145
148
  - Writes and configured paths remain inside the real repository root.
146
149
  - Symlink escapes and explicit targets that match nothing fail.
150
+ - CLI report, baseline, and checkpoint destinations are preflighted before
151
+ network or workflow mutation, cannot replace selected/default-discovery
152
+ workflows or reserved policy paths, and are checked against active controls
153
+ again before output is written.
147
154
  - Credentials are redacted in JSON, TOON, text, SARIF, annotations, and
148
155
  top-level errors.
149
156
  - Finding and change IDs exclude absolute checkout paths.
@@ -154,14 +161,19 @@ Changes must preserve these boundaries:
154
161
  - Organization resume never trusts a stale result without fresh discovery and
155
162
  a matching repository identity, default branch, and tree SHA. Failed results
156
163
  are never reused.
164
+ - Organization result compatibility is controlled by
165
+ `ORGANIZATION_ANALYSIS_GENERATION`, not by the package version. Producer
166
+ versions remain checkpoint metadata and compatible checkpoints migrate
167
+ through the guarded atomic writer.
157
168
  - Checkpoints use guarded atomic writes, remain inside the working directory,
158
169
  omit tokens and raw YAML, and cannot replace active policy or baseline files.
159
170
  - Progress stays outside deterministic report serialization; CLI progress is
160
171
  stderr-only and Action progress cannot form workflow commands.
161
172
  - Agent mode is an explicit opt-in, never a TTY, parent-process, CI, or
162
173
  vendor-environment heuristic. Explicit CLI output and progress options win.
163
- Its automatic artifact key uses the validated checkpoint identity, and its
164
- stdout receipt never includes findings or repository result arrays.
174
+ Its automatic artifact key uses the validated checkpoint compatibility
175
+ identity, and its stdout receipt never includes findings or repository result
176
+ arrays.
165
177
  - Attacker-controlled values cannot forge TOON lines or GitHub annotations.
166
178
 
167
179
  Tests should demonstrate the fail-closed behavior for any change touching these
@@ -276,6 +288,17 @@ previous repository errors, output equivalence, and concurrent completions.
276
288
  Persist each completed result before emitting its completion event so an
277
289
  observer failure or process interruption loses at most in-flight work.
278
290
 
291
+ `ORGANIZATION_ANALYSIS_GENERATION` in `src/lib/org-checkpoint.js` is the manual
292
+ semantic compatibility switch. Increment it whenever organization workflow
293
+ selection, parsing, finding identity, rule evaluation, suppression, summaries,
294
+ or other persisted repository-result semantics can change. Keep it unchanged
295
+ for documentation, release metadata, progress rendering, authentication,
296
+ concurrency, or internal refactors that preserve those results. The rule
297
+ catalog hash independently invalidates catalog changes. A generation change
298
+ must add tests proving the old checkpoint fails closed and agent mode selects a
299
+ new artifact key; a compatible format migration must prove the old checkpoint
300
+ is validated, rewritten atomically, and still subject to fresh tree checks.
301
+
279
302
  ## Output compatibility
280
303
 
281
304
  JSON is the public machine interface. Raw command results and serialized JSON
@@ -182,7 +182,9 @@ emission.
182
182
  if-no-files-found: error
183
183
  ```
184
184
 
185
- The output path must remain inside `working-directory`.
185
+ The output path must remain inside `working-directory`, its parent directory
186
+ must already exist, and an existing destination must be a regular file rather
187
+ than a directory or symlink.
186
188
 
187
189
  ## Organization report
188
190
 
@@ -249,12 +251,14 @@ those inputs directly when an agent generates a workflow.
249
251
  the working directory before the actions-warden step, remove
250
252
  `checkpoint-path`, and set `resume-from` to the restored path. The Action does
251
253
  not itself retain files between ephemeral runners; use a protected artifact or
252
- other caller-managed storage. Scope, policy, baseline, package, and rule
253
- identity must match. Fresh repository discovery and tree checks still occur,
254
- and changed or previously failed repositories are rescanned. Checkpoints hold
255
- redacted report evidence about repositories and findings, so protect them like
256
- the organization report. `checkpoint-path` and `resume-from` are mutually
257
- exclusive and cannot equal `output-path`.
254
+ other caller-managed storage. Scope, policy, baseline, analysis generation, and
255
+ rule identity must match; a compatible package-version change is allowed and
256
+ atomically refreshes checkpoint metadata on the first successful resume. Fresh
257
+ repository discovery and tree checks still occur, and changed or previously
258
+ failed repositories are rescanned. Checkpoints hold redacted report evidence
259
+ about repositories and findings, so protect them like the organization report.
260
+ `checkpoint-path` and `resume-from` are mutually exclusive and cannot equal
261
+ `output-path`.
258
262
 
259
263
  ## Mutation workflows
260
264
 
@@ -205,11 +205,13 @@ possible; failures that prevent organization discovery throw.
205
205
  `checkpointPath` explicitly enables atomic checkpoint writes inside `cwd`.
206
206
  Set `resume: true` to require, validate, and update an existing checkpoint at
207
207
  that path. The organization, selection and audit options, normalized policy,
208
- baseline contents, package version, and rule catalog must match. Concurrency
209
- and token changes are allowed. Resume performs fresh discovery and tree reads;
210
- it reuses only error-free results whose repository, default branch, and tree
211
- SHA remain unchanged. Checkpoints contain redacted report data and revision
212
- metadata, never tokens or raw YAML.
208
+ baseline contents, analysis generation, and rule catalog must match.
209
+ Concurrency, token, and compatible package-version changes are allowed. The
210
+ producing package version remains metadata, and compatible older checkpoints
211
+ are atomically migrated on the first successful resume. Resume performs fresh
212
+ discovery and tree reads; it reuses only error-free results whose repository,
213
+ default branch, and tree SHA remain unchanged. Checkpoints contain redacted
214
+ report data and revision metadata, never tokens or raw YAML.
213
215
 
214
216
  `onProgress` may be synchronous or asynchronous and is awaited in event order
215
217
  at each emission point. A callback error rejects the scan; repository results
package/docs/OUTPUTS.md CHANGED
@@ -47,8 +47,10 @@ The CLI maps results to process codes:
47
47
  | `1` | Semantic status `FAIL`; inspect the emitted report |
48
48
  | `2` | Invalid arguments, invalid policy, unsafe paths, or another invocation-level failure |
49
49
 
50
- An invocation-level failure is written to stderr as `error: <message>`. It may
51
- occur before a structured payload can be rendered, so do not assume stdout
50
+ An invocation-level failure is written to stderr as `error: <message>`. Unknown
51
+ options, missing values, invalid choices, conflicting flags, malformed numeric
52
+ values, unsafe destinations, and a missing command all return `2`. The failure
53
+ may occur before a structured payload can be rendered, so do not assume stdout
52
54
  contains JSON when the process exits `2`.
53
55
 
54
56
  Organization-scan live progress is also a stderr-only channel. It never becomes
@@ -119,16 +121,19 @@ node -e '
119
121
  '
120
122
  ```
121
123
 
122
- Writing reports through `--output=file` is safer than shell redirection when
123
- repository path containment matters:
124
+ Writing reports through a guarded output path is safer than shell redirection
125
+ when repository path containment matters. `--output-path` implies file output:
124
126
 
125
127
  ```sh
126
128
  actions-warden audit \
127
129
  --format=json \
128
- --output=file \
129
130
  --output-path=reports/actions-warden.json
130
131
  ```
131
132
 
133
+ The parent directory must exist. Destination safety is checked before command
134
+ work, then active policy and baseline collisions are checked again before the
135
+ report is written. Explicit `--output=stdout --output-path=...` is rejected.
136
+
132
137
  ## TOON
133
138
 
134
139
  TOON is Token-Oriented Object Notation. Each line is:
@@ -26,7 +26,7 @@ jobs:
26
26
  - name: Apply eligible upgrades
27
27
  env:
28
28
  GITHUB_TOKEN: ${{ github.token }}
29
- run: npx --yes actions-warden@0.3.0 upgrade --mode=minor --min-age=7 --write
29
+ run: npx --yes actions-warden@0.4.0 upgrade --mode=minor --min-age=7 --write
30
30
 
31
31
  - name: Open or update pull request
32
32
  env:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "actions-warden",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "description": "Audit GitHub Actions across repositories and organizations; pin, verify, and upgrade dependencies.",
5
5
  "author": "Naveen Yagati",
6
6
  "homepage": "https://github.com/chiz0me/actions-warden#readme",
@@ -33,27 +33,31 @@ Invoke `actions-warden` when the user:
33
33
  The package is on npm as `actions-warden`. Invoke the reviewed version exactly:
34
34
 
35
35
  ```sh
36
- npx --yes actions-warden@0.3.0 audit
37
- npx --yes actions-warden@0.3.0 audit --severity=high --explain
38
- npx --yes actions-warden@0.3.0 audit --create-baseline=.actions-warden-baseline.json
39
- npx --yes actions-warden@0.3.0 audit --baseline=.actions-warden-baseline.json
40
- npx --yes actions-warden@0.3.0 audit --format=sarif
41
- npx --yes actions-warden@0.3.0 pin
42
- npx --yes actions-warden@0.3.0 pin --write
43
- npx --yes actions-warden@0.3.0 upgrade --mode=minor
44
- npx --yes actions-warden@0.3.0 upgrade --min-age=14 --write
45
- npx --yes actions-warden@0.3.0 verify
46
- npx --yes actions-warden@0.3.0 report --offline
47
- npx --yes actions-warden@0.3.0 org-scan my-org --severity=high --format=json
48
- npx --yes actions-warden@0.3.0 org-scan my-org --severity=high --agent-mode
49
- npx --yes actions-warden@0.3.0 org-scan my-org --severity=high --checkpoint=.actions-warden-org-checkpoint.json
50
- npx --yes actions-warden@0.3.0 org-scan my-org --severity=high --resume=.actions-warden-org-checkpoint.json
51
- npx --yes actions-warden@0.3.0 rules
36
+ npx --yes actions-warden@0.4.0 audit
37
+ npx --yes actions-warden@0.4.0 audit --severity=high --explain
38
+ npx --yes actions-warden@0.4.0 audit --create-baseline=.actions-warden-baseline.json
39
+ npx --yes actions-warden@0.4.0 audit --baseline=.actions-warden-baseline.json
40
+ npx --yes actions-warden@0.4.0 audit --format=sarif
41
+ npx --yes actions-warden@0.4.0 pin
42
+ npx --yes actions-warden@0.4.0 pin --write
43
+ npx --yes actions-warden@0.4.0 upgrade --mode=minor
44
+ npx --yes actions-warden@0.4.0 upgrade --min-age=14 --write
45
+ npx --yes actions-warden@0.4.0 verify
46
+ npx --yes actions-warden@0.4.0 report --offline
47
+ npx --yes actions-warden@0.4.0 org-scan my-org --severity=high --format=json
48
+ npx --yes actions-warden@0.4.0 org-scan my-org --severity=high --agent-mode
49
+ npx --yes actions-warden@0.4.0 org-scan my-org --severity=high --checkpoint=.actions-warden-org-checkpoint.json
50
+ npx --yes actions-warden@0.4.0 org-scan my-org --severity=high --resume=.actions-warden-org-checkpoint.json
51
+ npx --yes actions-warden@0.4.0 rules
52
52
  ```
53
53
 
54
- Useful global flags: `--workflow <path-or-glob>` (repeatable), `--cwd <dir>`,
55
- `--format toon|json|text|sarif`, `--output stdout|file`, `--output-path <path>`,
56
- `--token <gh-token>` (also reads `GITHUB_TOKEN` / `GH_TOKEN`).
54
+ Useful shared command flags: `--workflow <path-or-glob>` (repeatable),
55
+ `--cwd <dir>`, `--format toon|json|text|sarif`, `--output stdout|file`, and
56
+ `--output-path <path>`. An output path implies file output; never combine it
57
+ with explicit `--output=stdout`, and create its parent directory first.
58
+ Network-backed commands accept `--token <gh-token>` and also read
59
+ `GITHUB_TOKEN` / `GH_TOKEN`; prefer the environment. Local `audit` does not
60
+ accept or need a token.
57
61
  Audit, report, and org-scan also accept `--config <path>` and `--baseline <path>`.
58
62
  `.actions-warden.yml` is loaded automatically when present.
59
63
  Organization scans accept `--repository <glob...>`, `--visibility`,
@@ -69,7 +73,10 @@ precedence.
69
73
  Exit codes: `0` for a normal `OK` result, `1` for a normal structured `FAIL`
70
74
  result (findings or operational errors), and `2` for an invocation-level error.
71
75
  For code `1`, inspect the report. For code `2`, read stderr and do not assume
72
- stdout contains a complete structured payload.
76
+ stdout contains a complete structured payload. Do not retry code `2` by
77
+ guessing alternative flags: fix the named conflict, integer, ID, working
78
+ directory, or destination. The CLI rejects those errors before network or
79
+ authorized workflow mutation whenever the needed path information is known.
73
80
 
74
81
  ## What to do when invoked
75
82
 
@@ -124,7 +131,7 @@ stdout contains a complete structured payload.
124
131
  agent-initiated broad scan must use the explicit agent mode:
125
132
 
126
133
  ```sh
127
- npx --yes actions-warden@0.3.0 org-scan my-org \
134
+ npx --yes actions-warden@0.4.0 org-scan my-org \
128
135
  --agent-mode
129
136
  ```
130
137
 
@@ -144,7 +151,9 @@ stdout contains a complete structured payload.
144
151
  inference tokens to plan, monitor, and summarize; output admitted to its
145
152
  context adds to that usage. Resume primarily saves GitHub API/blob work and
146
153
  elapsed time. A changed scope or security control receives a different
147
- artifact key rather than overwriting an incompatible checkpoint.
154
+ artifact key rather than overwriting an incompatible checkpoint. Compatible
155
+ package upgrades retain the same key and resume state; an analysis-behavior
156
+ change receives a new key.
148
157
 
149
158
  ## Audit rules
150
159