actions-warden 0.2.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.
Files changed (63) hide show
  1. package/AGENTS.md +199 -0
  2. package/CONTRIBUTING.md +109 -0
  3. package/README.md +284 -224
  4. package/RELEASING.md +338 -0
  5. package/SECURITY.md +30 -3
  6. package/docs/AI-AGENTS.md +474 -0
  7. package/docs/CLI.md +474 -0
  8. package/docs/CONFIGURATION.md +340 -0
  9. package/docs/DEVELOPMENT.md +373 -0
  10. package/docs/GITHUB-ACTION.md +285 -0
  11. package/docs/JAVASCRIPT-API.md +357 -0
  12. package/docs/OUTPUTS.md +414 -0
  13. package/docs/README.md +27 -0
  14. package/examples/org-scan.yml +42 -0
  15. package/examples/upgrade-pr.yml +57 -0
  16. package/llms.txt +38 -0
  17. package/package.json +32 -10
  18. package/skills/actions-warden/SKILL.md +151 -40
  19. package/src/action.js +306 -0
  20. package/src/cli.js +494 -56
  21. package/src/commands/audit.js +189 -36
  22. package/src/commands/org-scan.js +544 -0
  23. package/src/commands/pin.js +59 -56
  24. package/src/commands/report.js +122 -10
  25. package/src/commands/upgrade.js +102 -62
  26. package/src/commands/verify.js +193 -0
  27. package/src/index.js +21 -4
  28. package/src/lib/action-status.js +27 -0
  29. package/src/lib/agent-mode.js +174 -0
  30. package/src/lib/annotations.js +250 -0
  31. package/src/lib/baseline.js +103 -0
  32. package/src/lib/cache.js +47 -10
  33. package/src/lib/concurrency.js +27 -0
  34. package/src/lib/config.js +185 -0
  35. package/src/lib/execution.js +71 -0
  36. package/src/lib/formatter.js +127 -8
  37. package/src/lib/github-org.js +374 -0
  38. package/src/lib/identity.js +62 -0
  39. package/src/lib/ignore.js +7 -6
  40. package/src/lib/org-checkpoint.js +461 -0
  41. package/src/lib/org-progress.js +60 -0
  42. package/src/lib/parser.js +326 -52
  43. package/src/lib/patcher.js +199 -0
  44. package/src/lib/path-equality.js +30 -0
  45. package/src/lib/paths.js +35 -12
  46. package/src/lib/redact.js +65 -4
  47. package/src/lib/resolver.js +225 -43
  48. package/src/lib/targets.js +28 -0
  49. package/src/lib/triggers.js +12 -0
  50. package/src/lib/writer.js +48 -8
  51. package/src/rules/excessive-permissions.js +24 -33
  52. package/src/rules/index.js +19 -1
  53. package/src/rules/pull-request-target-checkout.js +149 -18
  54. package/src/rules/reusable-workflow-secrets.js +32 -0
  55. package/src/rules/script-injection.js +77 -12
  56. package/src/rules/secrets-in-env.js +101 -18
  57. package/src/rules/unpinned-action.js +3 -2
  58. package/src/rules/unpinned-container-image.js +39 -0
  59. package/src/rules/unpinned-docker-action.js +30 -0
  60. package/src/rules/untrusted-self-hosted-runner.js +109 -0
  61. package/src/rules/workflow-run-artifact-execution.js +122 -0
  62. package/src/rules/workflow-structure.js +396 -0
  63. package/src/version.js +3 -0
@@ -0,0 +1,373 @@
1
+ # Developer guide
2
+
3
+ This guide is for contributors changing actions-warden itself. For public CLI
4
+ usage, start with the [CLI reference](./CLI.md).
5
+
6
+ ## Prerequisites
7
+
8
+ - Node.js 20 or newer;
9
+ - npm with the lockfile committed by the repository;
10
+ - optional: `prek` or Python `pre-commit` for local hooks.
11
+
12
+ Install exactly the locked dependency graph:
13
+
14
+ ```sh
15
+ npm ci
16
+ ```
17
+
18
+ The repository's `.npmrc` pins dependencies exactly and disables package
19
+ lifecycle scripts during installation.
20
+
21
+ Install hooks with either runner:
22
+
23
+ ```sh
24
+ prek install --hook-type pre-commit --hook-type pre-push
25
+ ```
26
+
27
+ or:
28
+
29
+ ```sh
30
+ pre-commit install --hook-type pre-commit
31
+ pre-commit install --hook-type pre-push
32
+ ```
33
+
34
+ ## Validation commands
35
+
36
+ | command | purpose |
37
+ |---|---|
38
+ | `npm test` | Run the complete Vitest suite once |
39
+ | `npm run test:watch` | Run Vitest in watch mode |
40
+ | `npm run lint` | Lint source, scripts, and tests |
41
+ | `npm run check:yaml` | Parse repository YAML files |
42
+ | `npm run check:docs` | Validate local documentation links |
43
+ | `npm run check:package` | Inspect the exact npm tarball manifest, required files, executable mode, and size bounds |
44
+ | `npm run verify-deps` | Require exact runtime and development versions |
45
+ | `npm run verify-version-sync` | Keep package, lockfile, bundled runtime, plugin, and public invocations aligned |
46
+ | `npm run build:action` | Rebuild the committed Action bundle |
47
+ | `npm run check:action-bundle` | Compare a clean rebuild with working and staged bundles |
48
+ | `npm run audit` | Run the configured npm vulnerability threshold |
49
+ | `npm run release:prepare -- X.Y.Z` | Update all local stable-version sources without committing or publishing |
50
+ | `npm run release:check` | Gate a staged release candidate against npm state and every release validation |
51
+
52
+ Before opening a pull request, run:
53
+
54
+ ```sh
55
+ npm run verify-version-sync
56
+ npm run verify-deps
57
+ npm run check:yaml
58
+ npm run check:docs
59
+ npm run check:package
60
+ npm run lint
61
+ npm test
62
+ npm run audit
63
+ ```
64
+
65
+ If code reachable from `src/action.js` changed, also run:
66
+
67
+ ```sh
68
+ npm run build:action
69
+ npm run check:action-bundle
70
+ ```
71
+
72
+ ## Repository map
73
+
74
+ ```text
75
+ src/
76
+ cli.js CLI parsing, exit codes, and output routing
77
+ action.js GitHub Action input/output adapter
78
+ index.js public JavaScript exports
79
+ version.js runtime version embedded in the Action bundle
80
+ commands/ audit, pin, verify, upgrade, report, org-scan
81
+ lib/
82
+ parser.js YAML-to-normalized-workflow model
83
+ targets.js, paths.js repository target discovery
84
+ path-equality.js real-path destination/control comparisons
85
+ config.js, baseline.js policy and accepted-finding controls
86
+ resolver.js, cache.js GitHub API, caching, ref and ownership checks
87
+ github-org.js read-only organization/tree/blob access
88
+ agent-mode.js explicit bounded AI-agent CLI defaults
89
+ org-checkpoint.js validated atomic organization resume state
90
+ org-progress.js human rendering of structured scan progress
91
+ identity.js stable IDs and semantic fingerprints
92
+ patcher.js, writer.js source-range rewrites and guarded atomic writes
93
+ formatter.js, redact.js structured output and credential redaction
94
+ annotations.js GitHub workflow annotations
95
+ concurrency.js bounded async work
96
+ rules/ one module per audit rule
97
+
98
+ test/ Vitest suites and hostile/edge-case fixtures
99
+ scripts/ repository validation and release helpers
100
+ docs/ user, integration, AI, and developer guides
101
+ examples/ copyable GitHub workflow examples
102
+ skills/actions-warden/ Claude Code skill
103
+ dist/ generated, committed GitHub Action bundle
104
+ action.yml public Action inputs, outputs, and runtime
105
+ ```
106
+
107
+ ## Data flow
108
+
109
+ A local audit follows this path:
110
+
111
+ ```text
112
+ targets → source read → YAML parser → normalized workflow model
113
+ → ignore directives → rules → stable identities
114
+ → severity/baseline filtering → renderer
115
+ ```
116
+
117
+ Pin and upgrade add:
118
+
119
+ ```text
120
+ normalized action refs → GitHub resolution and ownership verification
121
+ → source-range patch plan → reparse
122
+ → guarded atomic writer only when dryRun=false
123
+ ```
124
+
125
+ An organization scan follows:
126
+
127
+ ```text
128
+ repository listing → default-branch Git tree → bounded YAML blob reads
129
+ → in-memory auditSources → repository aggregation
130
+
131
+ optional checkpoint → identity validation → fresh tree SHA comparison
132
+ → reuse unchanged error-free result or rescan
133
+ ```
134
+
135
+ Remote repositories are never cloned, checked out, imported, or executed.
136
+
137
+ ## Safety invariants
138
+
139
+ Changes must preserve these boundaries:
140
+
141
+ - `pin` and `upgrade` default to dry-run at the command and API layers.
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`.
145
+ - A resolver failure must not fall back to a guessed tag or SHA.
146
+ - Commits must be verified as belonging to the referenced repository.
147
+ - Workflow rewrites operate on parsed scalar ranges and reparse before write.
148
+ - Writes and configured paths remain inside the real repository root.
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.
154
+ - Credentials are redacted in JSON, TOON, text, SARIF, annotations, and
155
+ top-level errors.
156
+ - Finding and change IDs exclude absolute checkout paths.
157
+ - Parser errors remain findings and cannot be baselined away.
158
+ - Organization coverage failures remain visible and make status fail.
159
+ - Organization source reads remain count- and size-bounded and bypass disk
160
+ cache.
161
+ - Organization resume never trusts a stale result without fresh discovery and
162
+ a matching repository identity, default branch, and tree SHA. Failed results
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.
168
+ - Checkpoints use guarded atomic writes, remain inside the working directory,
169
+ omit tokens and raw YAML, and cannot replace active policy or baseline files.
170
+ - Progress stays outside deterministic report serialization; CLI progress is
171
+ stderr-only and Action progress cannot form workflow commands.
172
+ - Agent mode is an explicit opt-in, never a TTY, parent-process, CI, or
173
+ vendor-environment heuristic. Explicit CLI output and progress options win.
174
+ Its automatic artifact key uses the validated checkpoint compatibility
175
+ identity, and its stdout receipt never includes findings or repository result
176
+ arrays.
177
+ - Attacker-controlled values cannot forge TOON lines or GitHub annotations.
178
+
179
+ Tests should demonstrate the fail-closed behavior for any change touching these
180
+ boundaries.
181
+
182
+ ## Adding or changing a rule
183
+
184
+ A rule module exports:
185
+
186
+ ```js
187
+ export const id = 'example-rule';
188
+ export const severity = 'high';
189
+ export const description = 'Short sentence describing the risk.';
190
+
191
+ export function check(workflow, context = {}) {
192
+ return [{
193
+ id,
194
+ severity,
195
+ line: 1,
196
+ fields: {
197
+ type: id,
198
+ sev: severity,
199
+ evidence: 'structured-value',
200
+ },
201
+ explain: 'one concise remediation',
202
+ }];
203
+ }
204
+ ```
205
+
206
+ Then:
207
+
208
+ 1. register the module in `src/rules/index.js`;
209
+ 2. add focused tests for safe and unsafe cases;
210
+ 3. test trigger, expression, quoting, and malformed-input boundaries relevant
211
+ to the rule;
212
+ 4. when behavior depends on a moving GitHub or first-party action contract,
213
+ verify it against a primary source, record the date/version boundary in code,
214
+ and test the last unsafe plus first safe version;
215
+ 5. test at least one legitimate pattern that must remain clean so remediation
216
+ guidance does not become a false-positive generator;
217
+ 6. update the rule table and accuracy boundaries in `docs/CONFIGURATION.md`,
218
+ plus the Claude skill;
219
+ 7. run `actions-warden rules --format=json` and ensure the ID is not redacted;
220
+ 8. rebuild the Action bundle.
221
+
222
+ Keep `fields` structured and concise. They become JSON evidence, TOON fields,
223
+ SARIF messages, and Action annotations. Never place raw secret values in them.
224
+ Suggestions must name a safe end state, preserve legitimate use cases, and
225
+ avoid claiming that one mitigation closes risks outside the rule's evidence.
226
+
227
+ ## Adding or changing a command
228
+
229
+ A command normally needs changes in:
230
+
231
+ 1. `src/commands/<name>.js` for the API result and renderer;
232
+ 2. `src/cli.js` for public CLI flags and exit semantics;
233
+ 3. `src/index.js` and `package.json` exports;
234
+ 4. `src/action.js` and `action.yml` if the Action exposes it;
235
+ 5. command, CLI, Action, annotation, and output-format tests;
236
+ 6. `docs/CLI.md`, `docs/OUTPUTS.md`, API docs, and relevant examples;
237
+ 7. the Claude skill and version-sync checker when its command surface changes;
238
+ 8. the committed Action bundle.
239
+
240
+ Return operational problems as structured `errors` when useful work can
241
+ continue. Throw when top-level input or discovery makes the requested scope
242
+ undefined or unsafe.
243
+
244
+ Every non-JSON renderer must expose enough information to explain a `FAIL`
245
+ status. Every JSON renderer must include `schemaVersion`, command data, and
246
+ top-level `status`.
247
+
248
+ ## Parser and patcher changes
249
+
250
+ The parser retains both a normalized model for rules and source locations for
251
+ precise rewrites. When changing it:
252
+
253
+ - cover workflow files and composite `action.yml` metadata;
254
+ - preserve and recursively inspect steps inside `parallel` groups, while
255
+ retaining background/control-step declarations for structure checks;
256
+ - include quoted, unquoted, inline, multiline, and malformed YAML cases;
257
+ - avoid evaluating expressions;
258
+ - preserve source offsets for patchable `uses` values;
259
+ - test Windows and POSIX path normalization where relevant.
260
+
261
+ The patcher should make the smallest source-range replacement. Do not reserialize
262
+ the entire YAML document: that would destroy comments, formatting, anchors, and
263
+ reviewable diffs.
264
+
265
+ Property tests in `test/patcher-properties.test.js` exercise rewrite stability.
266
+
267
+ ## GitHub API changes
268
+
269
+ All runtime requests belong in the resolver or organization GitHub layer and
270
+ must remain pinned to `https://api.github.com`.
271
+
272
+ For new endpoints:
273
+
274
+ - validate status and response shape;
275
+ - paginate boundedly;
276
+ - validate identities, SHAs, sizes, encodings, and UTF-8 as applicable;
277
+ - set timeouts and bounded retries through the shared fetch layer;
278
+ - preserve authentication-isolated cache keys;
279
+ - decide explicitly whether private content may be cached;
280
+ - accumulate scoped errors when continued reporting is safe;
281
+ - add tests with mocked responses for truncation and malformed data.
282
+
283
+ Never execute content to determine what it contains.
284
+
285
+ When changing organization resume behavior, cover interrupted writes,
286
+ checkpoint schema and identity mismatches, hostile fields, changed tree SHAs,
287
+ previous repository errors, output equivalence, and concurrent completions.
288
+ Persist each completed result before emitting its completion event so an
289
+ observer failure or process interruption loses at most in-flight work.
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
+
302
+ ## Output compatibility
303
+
304
+ JSON is the public machine interface. Raw command results and serialized JSON
305
+ are deliberately different: renderers add repository-relative paths,
306
+ redaction, and `schemaVersion`.
307
+
308
+ When changing output:
309
+
310
+ - retain top-level `status`;
311
+ - treat new fields as additive where possible;
312
+ - update `docs/OUTPUTS.md`;
313
+ - test all four formats;
314
+ - prevent embedded control characters from forging records;
315
+ - ensure error details are visible in every format;
316
+ - verify stable IDs remain stable unless their semantic input changed.
317
+
318
+ ## GitHub Action bundle
319
+
320
+ Never edit `dist/index.js` or `dist/package.json` by hand. They are generated:
321
+
322
+ ```sh
323
+ npm run build:action
324
+ ```
325
+
326
+ Commit source and its rebuilt bundle together when the Action runtime changes.
327
+ `npm run check:action-bundle` performs a clean build in a temporary directory
328
+ and compares both working-tree and staged bundle files.
329
+
330
+ A docs-only, test-only, or CLI-only change that is unreachable from
331
+ `src/action.js` does not require a bundle rebuild.
332
+
333
+ ## Tests and fixtures
334
+
335
+ Tests use Vitest and should be deterministic and network-independent. Mock
336
+ GitHub responses rather than relying on live repositories. Use temporary
337
+ directories for writes and assert both file content and failure behavior.
338
+
339
+ Useful focused runs:
340
+
341
+ ```sh
342
+ npx vitest --run test/audit.test.js
343
+ npx vitest --run test/org-scan.test.js
344
+ npx vitest --run -t "stable id"
345
+ ```
346
+
347
+ Keep hostile input in fixtures or inline strings when it clarifies the threat
348
+ being tested. Tests should not contain real credentials.
349
+
350
+ ## Documentation maintenance
351
+
352
+ README is the landing page, not the full manual. Put durable detail in the
353
+ focused guide that owns it, then link from README.
354
+
355
+ When CLI, Action, config, output, or API behavior changes:
356
+
357
+ 1. update the owning reference document;
358
+ 2. update examples and AI guidance that depend on it;
359
+ 3. run `npm run check:docs`;
360
+ 4. run live `--help` and at least one documented example against
361
+ `node src/cli.js`.
362
+
363
+ Keep examples copyable, use exact package versions for `npx`, and use full
364
+ commit placeholders for the Action itself.
365
+
366
+ ## Releases
367
+
368
+ The authoritative [release runbook](../RELEASING.md) defines maintainer and
369
+ agent authorization, SemVer selection, live-state preflight, preparation,
370
+ trusted publication, monitoring, verification, and partial-failure recovery.
371
+ Do not bump versions as part of an unrelated contribution. `release:prepare`
372
+ is local-only; `release:check` is intended for a reviewed, staged candidate and
373
+ will fail a stale or already-published version.
@@ -0,0 +1,285 @@
1
+ # GitHub Action guide
2
+
3
+ The bundled JavaScript Action runs the same commands as the CLI on GitHub's
4
+ managed Node 24 runtime. Consumer workflows do not run `npm install`.
5
+
6
+ ## Repository audit
7
+
8
+ Pin every third-party Action, including actions-warden itself, to a reviewed
9
+ full commit SHA:
10
+
11
+ ```yaml
12
+ name: actions-warden
13
+
14
+ on:
15
+ pull_request:
16
+ push:
17
+ branches: [main]
18
+
19
+ permissions:
20
+ contents: read
21
+
22
+ jobs:
23
+ audit:
24
+ runs-on: ubuntu-latest
25
+ steps:
26
+ - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # actions-warden-ref: v5.0.0
27
+ with:
28
+ persist-credentials: false
29
+
30
+ - name: Audit workflows
31
+ uses: chiz0me/actions-warden@<FULL_COMMIT_SHA>
32
+ with:
33
+ command: audit
34
+ severity: high
35
+ explain: 'true'
36
+ ```
37
+
38
+ Findings are written to the log, job summary, and native annotations. Audit
39
+ findings fail the step by default.
40
+
41
+ ## Inputs
42
+
43
+ GitHub passes Action inputs as strings. Boolean values should be quoted in YAML
44
+ for clarity.
45
+
46
+ | input | default | applies to | behavior |
47
+ |---|---|---|---|
48
+ | `command` | `audit` | all | `audit`, `pin`, `upgrade`, `verify`, `report`, `org-scan`, or `rules` |
49
+ | `workflow` | discovery | repository commands | One path/glob per line or a JSON string array |
50
+ | `severity` | all levels | `audit`, `report`, `org-scan` | Minimum `low`, `medium`, `high`, or `critical` |
51
+ | `format` | `toon` | all | `toon`, `json`, `text`, or `sarif` |
52
+ | `mode` | `minor` | `upgrade`, `report` | `major`, `minor`, or `patch` |
53
+ | `min-age` | `7` | `upgrade`, `report` | Non-negative cooldown in days |
54
+ | `write` | `false` | `pin`, `upgrade` | Apply changes in the checked-out workspace |
55
+ | `fix` | none | `pin`, `upgrade` | Limit work to one exact planned ID |
56
+ | `explain` | `false` | `audit`, `report`, `org-scan` | Include remediation hints |
57
+ | `offline` | `false` | `report` | Skip pin and upgrade network work |
58
+ | `fail-on-findings` | `true` | `audit`, `report`, `org-scan` | Allow findings to be advisory when `false` |
59
+ | `annotations` | `true` | all | Emit native workflow-command annotations |
60
+ | `config` | auto | `audit`, `report`, `org-scan` | Policy path inside the working directory |
61
+ | `ignore-config` | `false` | `audit`, `report`, `org-scan` | Ignore repository policy |
62
+ | `baseline` | policy/default | `audit`, `report`, `org-scan` | Accepted-finding baseline |
63
+ | `organization` | none | `org-scan` | Required organization login |
64
+ | `repository` | all eligible | `org-scan` | One repository glob per line or a JSON string array |
65
+ | `visibility` | `all` | `org-scan` | `all`, `public`, `private`, or `internal` |
66
+ | `include-archived` | `false` | `org-scan` | Include archived repositories |
67
+ | `include-disabled` | `false` | `org-scan` | Include disabled repositories |
68
+ | `include-forks` | `false` | `org-scan` | Include forked repositories |
69
+ | `max-repos` | none | `org-scan` | Positive repository limit |
70
+ | `concurrency` | `4` | `org-scan` | Concurrent repository scans from 1 through 16 |
71
+ | `checkpoint-path` | none | `org-scan` | Create or replace an atomic resumable checkpoint |
72
+ | `resume-from` | none | `org-scan` | Resume from and update an existing checkpoint |
73
+ | `progress` | `true` | `org-scan` | Show discovery, repository, retry, and completion updates in the step log |
74
+ | `output-path` | none | all | Save the selected format inside the working directory |
75
+ | `token` | none | network commands | GitHub API token; normally `${{ github.token }}` or a secret |
76
+ | `working-directory` | `$GITHUB_WORKSPACE` | all | Scan and path-safety root |
77
+
78
+ `node-version` is a deprecated compatibility input. It is accepted but ignored
79
+ because the Action runtime is declared by the bundle.
80
+
81
+ Multivalue inputs can be line-separated:
82
+
83
+ ```yaml
84
+ with:
85
+ workflow: |
86
+ .github/workflows/release.yml
87
+ .github/actions
88
+ ```
89
+
90
+ or JSON:
91
+
92
+ ```yaml
93
+ with:
94
+ repository: '["service-*", "platform-*"]'
95
+ ```
96
+
97
+ ## Outputs and failure policy
98
+
99
+ | output | description |
100
+ |---|---|
101
+ | `status` | Semantic `OK` or `FAIL` |
102
+ | `findings` | Finding count for `audit`, `report`, and `org-scan` |
103
+ | `report-path` | Absolute saved path when `output-path` is supplied |
104
+ | `annotations` | Number of annotations emitted |
105
+ | `annotations-skipped` | Number omitted by the per-level cap |
106
+
107
+ Give the step an `id` to read outputs:
108
+
109
+ ```yaml
110
+ - name: Audit workflows
111
+ id: warden
112
+ uses: chiz0me/actions-warden@<FULL_COMMIT_SHA>
113
+ with:
114
+ command: audit
115
+ fail-on-findings: 'false'
116
+
117
+ - name: Show result
118
+ run: echo "status=${{ steps.warden.outputs.status }} findings=${{ steps.warden.outputs.findings }}"
119
+ ```
120
+
121
+ `fail-on-findings: 'false'` changes step failure only for security findings in
122
+ `audit`, `report`, and `org-scan`. It does not hide findings or change the
123
+ `status` output.
124
+
125
+ Operational failures always fail the step, including:
126
+
127
+ - invalid or unparseable workflow YAML;
128
+ - organization repository or blob read failures;
129
+ - ref resolution and ownership-verification failures;
130
+ - unsafe paths or writes;
131
+ - errors in the pin or upgrade phases of `report`.
132
+
133
+ `pin`, `upgrade`, and `verify` errors always fail. Warnings from `verify` do
134
+ not fail.
135
+
136
+ ## Native annotations
137
+
138
+ Annotations are independent of `format`:
139
+
140
+ | result | annotation level |
141
+ |---|---|
142
+ | critical or high finding | error |
143
+ | medium finding | warning |
144
+ | low finding | notice |
145
+ | verification warning | warning |
146
+ | resolver, verification, scan, or write error | error |
147
+
148
+ Local findings attach to the repository-relative file and source line.
149
+ Organization findings belong to other repositories, so they omit a local file
150
+ attachment while retaining repository, remote path, source URL, rule, and
151
+ stable ID in the message and saved report.
152
+
153
+ The Action emits at most 10 annotations per level per step, with more severe
154
+ records first. All omitted records remain in normal output and saved reports.
155
+ Set `annotations: 'false'` to disable annotations without changing status or
156
+ failure behavior.
157
+
158
+ Workflow-command data is escaped and credential-like values are redacted before
159
+ emission.
160
+
161
+ ## Save a report artifact
162
+
163
+ `output-path` writes the selected format in addition to stdout:
164
+
165
+ ```yaml
166
+ - name: Generate report
167
+ id: warden
168
+ uses: chiz0me/actions-warden@<FULL_COMMIT_SHA>
169
+ with:
170
+ command: report
171
+ format: json
172
+ output-path: reports/actions-warden.json
173
+ fail-on-findings: 'false'
174
+ token: ${{ github.token }}
175
+
176
+ - name: Upload report
177
+ if: always()
178
+ uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # actions-warden-ref: v5.0.0
179
+ with:
180
+ name: actions-warden-report
181
+ path: ${{ steps.warden.outputs.report-path }}
182
+ if-no-files-found: error
183
+ ```
184
+
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.
188
+
189
+ ## Organization report
190
+
191
+ The default repository `GITHUB_TOKEN` generally sees only the repository where
192
+ the workflow runs. Use a GitHub App installation token or a fine-grained token
193
+ whose repository access covers the intended organization scope.
194
+
195
+ ```yaml
196
+ name: organization Actions report
197
+
198
+ on:
199
+ workflow_dispatch:
200
+ schedule:
201
+ - cron: '23 7 * * 1'
202
+
203
+ permissions:
204
+ contents: read
205
+
206
+ jobs:
207
+ scan:
208
+ runs-on: ubuntu-latest
209
+ steps:
210
+ - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # actions-warden-ref: v5.0.0
211
+ with:
212
+ persist-credentials: false
213
+
214
+ - name: Scan organization
215
+ id: warden
216
+ uses: chiz0me/actions-warden@<FULL_COMMIT_SHA>
217
+ with:
218
+ command: org-scan
219
+ organization: ${{ github.repository_owner }}
220
+ token: ${{ secrets.ACTIONS_WARDEN_ORG_TOKEN }}
221
+ severity: high
222
+ explain: 'true'
223
+ format: json
224
+ output-path: actions-warden-org-report.json
225
+ checkpoint-path: .actions-warden-org-checkpoint.json
226
+ fail-on-findings: 'false'
227
+
228
+ - name: Upload organization report
229
+ if: always()
230
+ uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # actions-warden-ref: v5.0.0
231
+ with:
232
+ name: actions-warden-org-report
233
+ path: |
234
+ actions-warden-org-report.json
235
+ .actions-warden-org-checkpoint.json
236
+ if-no-files-found: error
237
+ ```
238
+
239
+ Keep the token in Actions secrets, avoid printing it, and grant only metadata
240
+ and contents read access for selected repositories. The complete copyable file
241
+ is [examples/org-scan.yml](../examples/org-scan.yml).
242
+
243
+ The Action writes live progress to the step log separately from the selected
244
+ report format. Set `progress: 'false'` to disable it.
245
+
246
+ CLI `--agent-mode` is not an Action input. The Action already has explicit
247
+ `output-path`, checkpoint, progress, summary, and output channels; configure
248
+ those inputs directly when an agent generates a workflow.
249
+
250
+ `checkpoint-path` starts a new checkpoint. To resume, restore that file into
251
+ the working directory before the actions-warden step, remove
252
+ `checkpoint-path`, and set `resume-from` to the restored path. The Action does
253
+ not itself retain files between ephemeral runners; use a protected artifact or
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`.
262
+
263
+ ## Mutation workflows
264
+
265
+ With `write: 'true'`, `pin` and `upgrade` modify only the runner's checked-out
266
+ working tree. The Action does not commit, push, or open a pull request.
267
+
268
+ A safe automation flow is:
269
+
270
+ 1. run the command without `write` and retain the report;
271
+ 2. require review or select one `fix` ID;
272
+ 3. run with `write: 'true'`;
273
+ 4. run `verify` and repository tests;
274
+ 5. create a pull request using a separately reviewed workflow.
275
+
276
+ See [examples/upgrade-pr.yml](../examples/upgrade-pr.yml) for an opt-in,
277
+ cooldown-aware upgrade pull request workflow. It uses explicit contents and
278
+ pull-request write permissions only in the mutation job.
279
+
280
+ ## Bundle integrity
281
+
282
+ The repository commits `dist/index.js` because GitHub Actions executes the
283
+ bundle directly. Releases verify that a clean rebuild matches the committed
284
+ bundle. Consumers should pin the Action to a full commit SHA, then use
285
+ actions-warden's metadata comment to retain the reviewed release name.