actions-warden 0.2.0 → 0.3.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 +189 -0
- package/CONTRIBUTING.md +109 -0
- package/README.md +272 -224
- package/RELEASING.md +338 -0
- package/SECURITY.md +25 -3
- package/docs/AI-AGENTS.md +458 -0
- package/docs/CLI.md +421 -0
- package/docs/CONFIGURATION.md +340 -0
- package/docs/DEVELOPMENT.md +350 -0
- package/docs/GITHUB-ACTION.md +281 -0
- package/docs/JAVASCRIPT-API.md +355 -0
- package/docs/OUTPUTS.md +409 -0
- package/docs/README.md +27 -0
- package/examples/org-scan.yml +42 -0
- package/examples/upgrade-pr.yml +57 -0
- package/llms.txt +38 -0
- package/package.json +32 -10
- package/skills/actions-warden/SKILL.md +140 -38
- package/src/action.js +317 -0
- package/src/cli.js +267 -22
- package/src/commands/audit.js +189 -36
- package/src/commands/org-scan.js +549 -0
- package/src/commands/pin.js +59 -56
- package/src/commands/report.js +122 -10
- package/src/commands/upgrade.js +102 -62
- package/src/commands/verify.js +193 -0
- package/src/index.js +21 -4
- package/src/lib/action-status.js +27 -0
- package/src/lib/agent-mode.js +175 -0
- package/src/lib/annotations.js +250 -0
- package/src/lib/baseline.js +103 -0
- package/src/lib/cache.js +47 -10
- package/src/lib/concurrency.js +27 -0
- package/src/lib/config.js +185 -0
- package/src/lib/execution.js +71 -0
- package/src/lib/formatter.js +127 -8
- package/src/lib/github-org.js +374 -0
- package/src/lib/identity.js +62 -0
- package/src/lib/ignore.js +7 -6
- package/src/lib/org-checkpoint.js +378 -0
- package/src/lib/org-progress.js +60 -0
- package/src/lib/parser.js +326 -52
- package/src/lib/patcher.js +199 -0
- package/src/lib/paths.js +35 -12
- package/src/lib/redact.js +65 -4
- package/src/lib/resolver.js +225 -43
- package/src/lib/targets.js +28 -0
- package/src/lib/triggers.js +12 -0
- package/src/lib/writer.js +45 -8
- package/src/rules/excessive-permissions.js +24 -33
- package/src/rules/index.js +19 -1
- package/src/rules/pull-request-target-checkout.js +149 -18
- package/src/rules/reusable-workflow-secrets.js +32 -0
- package/src/rules/script-injection.js +77 -12
- package/src/rules/secrets-in-env.js +101 -18
- package/src/rules/unpinned-action.js +3 -2
- package/src/rules/unpinned-container-image.js +39 -0
- package/src/rules/unpinned-docker-action.js +30 -0
- package/src/rules/untrusted-self-hosted-runner.js +109 -0
- package/src/rules/workflow-run-artifact-execution.js +122 -0
- package/src/rules/workflow-structure.js +396 -0
- package/src/version.js +3 -0
|
@@ -0,0 +1,281 @@
|
|
|
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`.
|
|
186
|
+
|
|
187
|
+
## Organization report
|
|
188
|
+
|
|
189
|
+
The default repository `GITHUB_TOKEN` generally sees only the repository where
|
|
190
|
+
the workflow runs. Use a GitHub App installation token or a fine-grained token
|
|
191
|
+
whose repository access covers the intended organization scope.
|
|
192
|
+
|
|
193
|
+
```yaml
|
|
194
|
+
name: organization Actions report
|
|
195
|
+
|
|
196
|
+
on:
|
|
197
|
+
workflow_dispatch:
|
|
198
|
+
schedule:
|
|
199
|
+
- cron: '23 7 * * 1'
|
|
200
|
+
|
|
201
|
+
permissions:
|
|
202
|
+
contents: read
|
|
203
|
+
|
|
204
|
+
jobs:
|
|
205
|
+
scan:
|
|
206
|
+
runs-on: ubuntu-latest
|
|
207
|
+
steps:
|
|
208
|
+
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # actions-warden-ref: v5.0.0
|
|
209
|
+
with:
|
|
210
|
+
persist-credentials: false
|
|
211
|
+
|
|
212
|
+
- name: Scan organization
|
|
213
|
+
id: warden
|
|
214
|
+
uses: chiz0me/actions-warden@<FULL_COMMIT_SHA>
|
|
215
|
+
with:
|
|
216
|
+
command: org-scan
|
|
217
|
+
organization: ${{ github.repository_owner }}
|
|
218
|
+
token: ${{ secrets.ACTIONS_WARDEN_ORG_TOKEN }}
|
|
219
|
+
severity: high
|
|
220
|
+
explain: 'true'
|
|
221
|
+
format: json
|
|
222
|
+
output-path: actions-warden-org-report.json
|
|
223
|
+
checkpoint-path: .actions-warden-org-checkpoint.json
|
|
224
|
+
fail-on-findings: 'false'
|
|
225
|
+
|
|
226
|
+
- name: Upload organization report
|
|
227
|
+
if: always()
|
|
228
|
+
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # actions-warden-ref: v5.0.0
|
|
229
|
+
with:
|
|
230
|
+
name: actions-warden-org-report
|
|
231
|
+
path: |
|
|
232
|
+
actions-warden-org-report.json
|
|
233
|
+
.actions-warden-org-checkpoint.json
|
|
234
|
+
if-no-files-found: error
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
Keep the token in Actions secrets, avoid printing it, and grant only metadata
|
|
238
|
+
and contents read access for selected repositories. The complete copyable file
|
|
239
|
+
is [examples/org-scan.yml](../examples/org-scan.yml).
|
|
240
|
+
|
|
241
|
+
The Action writes live progress to the step log separately from the selected
|
|
242
|
+
report format. Set `progress: 'false'` to disable it.
|
|
243
|
+
|
|
244
|
+
CLI `--agent-mode` is not an Action input. The Action already has explicit
|
|
245
|
+
`output-path`, checkpoint, progress, summary, and output channels; configure
|
|
246
|
+
those inputs directly when an agent generates a workflow.
|
|
247
|
+
|
|
248
|
+
`checkpoint-path` starts a new checkpoint. To resume, restore that file into
|
|
249
|
+
the working directory before the actions-warden step, remove
|
|
250
|
+
`checkpoint-path`, and set `resume-from` to the restored path. The Action does
|
|
251
|
+
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`.
|
|
258
|
+
|
|
259
|
+
## Mutation workflows
|
|
260
|
+
|
|
261
|
+
With `write: 'true'`, `pin` and `upgrade` modify only the runner's checked-out
|
|
262
|
+
working tree. The Action does not commit, push, or open a pull request.
|
|
263
|
+
|
|
264
|
+
A safe automation flow is:
|
|
265
|
+
|
|
266
|
+
1. run the command without `write` and retain the report;
|
|
267
|
+
2. require review or select one `fix` ID;
|
|
268
|
+
3. run with `write: 'true'`;
|
|
269
|
+
4. run `verify` and repository tests;
|
|
270
|
+
5. create a pull request using a separately reviewed workflow.
|
|
271
|
+
|
|
272
|
+
See [examples/upgrade-pr.yml](../examples/upgrade-pr.yml) for an opt-in,
|
|
273
|
+
cooldown-aware upgrade pull request workflow. It uses explicit contents and
|
|
274
|
+
pull-request write permissions only in the mutation job.
|
|
275
|
+
|
|
276
|
+
## Bundle integrity
|
|
277
|
+
|
|
278
|
+
The repository commits `dist/index.js` because GitHub Actions executes the
|
|
279
|
+
bundle directly. Releases verify that a clean rebuild matches the committed
|
|
280
|
+
bundle. Consumers should pin the Action to a full commit SHA, then use
|
|
281
|
+
actions-warden's metadata comment to retain the reviewed release name.
|
|
@@ -0,0 +1,355 @@
|
|
|
1
|
+
# JavaScript API
|
|
2
|
+
|
|
3
|
+
actions-warden is an ECMAScript module for Node.js 20 or newer. Public command
|
|
4
|
+
functions return structured objects and do not write reports to stdout.
|
|
5
|
+
|
|
6
|
+
```sh
|
|
7
|
+
npm install actions-warden
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
```js
|
|
11
|
+
import { audit } from 'actions-warden';
|
|
12
|
+
|
|
13
|
+
const result = await audit({
|
|
14
|
+
cwd: '/path/to/repository',
|
|
15
|
+
severity: 'high',
|
|
16
|
+
explain: true,
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
if (result.status === 'FAIL') {
|
|
20
|
+
for (const finding of result.findings) {
|
|
21
|
+
console.log(finding.id, finding.ruleId, finding.file, finding.line);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
From CommonJS, use a dynamic import:
|
|
27
|
+
|
|
28
|
+
```js
|
|
29
|
+
const { audit } = await import('actions-warden');
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
The raw API result does not include `schemaVersion`; renderers add the versioned
|
|
33
|
+
wire format.
|
|
34
|
+
|
|
35
|
+
## Command functions
|
|
36
|
+
|
|
37
|
+
### `audit(options)`
|
|
38
|
+
|
|
39
|
+
```js
|
|
40
|
+
const result = await audit({
|
|
41
|
+
cwd,
|
|
42
|
+
workflows, // string[] of files, directories, or globs
|
|
43
|
+
severity, // low | medium | high | critical
|
|
44
|
+
explain, // boolean
|
|
45
|
+
configPath, // string, false to disable policy, or undefined for discovery
|
|
46
|
+
baseline, // baseline path
|
|
47
|
+
ignoreBaseline, // boolean; primarily used while creating a baseline
|
|
48
|
+
});
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Returns:
|
|
52
|
+
|
|
53
|
+
```js
|
|
54
|
+
{
|
|
55
|
+
files,
|
|
56
|
+
findings,
|
|
57
|
+
allFindings,
|
|
58
|
+
summary,
|
|
59
|
+
baseline,
|
|
60
|
+
configPath,
|
|
61
|
+
status
|
|
62
|
+
}
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
`findings` reflects severity and baseline filtering. `allFindings` is the
|
|
66
|
+
unfiltered rule output used to create a baseline.
|
|
67
|
+
|
|
68
|
+
### `auditSources(options)`
|
|
69
|
+
|
|
70
|
+
Audit caller-supplied YAML without writing it to disk:
|
|
71
|
+
|
|
72
|
+
```js
|
|
73
|
+
import { auditSources, DEFAULT_CONFIG } from 'actions-warden';
|
|
74
|
+
|
|
75
|
+
const result = await auditSources({
|
|
76
|
+
cwd: '/virtual/root',
|
|
77
|
+
sources: [
|
|
78
|
+
{
|
|
79
|
+
file: '/virtual/root/acme/service/.github/workflows/ci.yml',
|
|
80
|
+
source: workflowYaml,
|
|
81
|
+
},
|
|
82
|
+
],
|
|
83
|
+
severity: 'high',
|
|
84
|
+
explain: true,
|
|
85
|
+
config: DEFAULT_CONFIG,
|
|
86
|
+
});
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Every source needs a unique string `file` and string `source`. The function uses
|
|
90
|
+
the same parser, ignore directives, identities, and rules as local audit. It
|
|
91
|
+
does not execute supplied YAML.
|
|
92
|
+
|
|
93
|
+
When passing a custom config, use the normalized shape returned by `loadConfig`,
|
|
94
|
+
not raw YAML keys.
|
|
95
|
+
|
|
96
|
+
### `pin(options)`
|
|
97
|
+
|
|
98
|
+
```js
|
|
99
|
+
const result = await pin({
|
|
100
|
+
cwd,
|
|
101
|
+
workflows,
|
|
102
|
+
dryRun: true, // default
|
|
103
|
+
token,
|
|
104
|
+
fix, // optional stable change ID
|
|
105
|
+
});
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
Returns `{ changes, errors, status }`. Set `dryRun: false` only after explicit
|
|
109
|
+
write authorization.
|
|
110
|
+
|
|
111
|
+
### `verify(options)`
|
|
112
|
+
|
|
113
|
+
```js
|
|
114
|
+
const result = await verify({ cwd, workflows, token });
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
Returns `{ files, checks, warnings, errors, status }`. Warnings do not make the
|
|
118
|
+
status fail.
|
|
119
|
+
|
|
120
|
+
### `upgrade(options)`
|
|
121
|
+
|
|
122
|
+
```js
|
|
123
|
+
const result = await upgrade({
|
|
124
|
+
cwd,
|
|
125
|
+
workflows,
|
|
126
|
+
dryRun: true, // default
|
|
127
|
+
token,
|
|
128
|
+
mode: 'minor', // major | minor | patch
|
|
129
|
+
minAgeDays: 7,
|
|
130
|
+
fix,
|
|
131
|
+
});
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
Returns `{ changes, skipped, errors, status }`.
|
|
135
|
+
|
|
136
|
+
### `report(options)`
|
|
137
|
+
|
|
138
|
+
```js
|
|
139
|
+
const result = await report({
|
|
140
|
+
cwd,
|
|
141
|
+
workflows,
|
|
142
|
+
token,
|
|
143
|
+
mode: 'minor',
|
|
144
|
+
severity: 'high',
|
|
145
|
+
explain: true,
|
|
146
|
+
skipResolve: false,
|
|
147
|
+
minAgeDays: 7,
|
|
148
|
+
configPath,
|
|
149
|
+
baseline,
|
|
150
|
+
});
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
Returns `{ audit, pin, upgrade, offline, status }`. Both mutation phases are
|
|
154
|
+
always dry-runs.
|
|
155
|
+
|
|
156
|
+
### `scanOrganization(options)`
|
|
157
|
+
|
|
158
|
+
```js
|
|
159
|
+
const result = await scanOrganization({
|
|
160
|
+
organization: 'my-org',
|
|
161
|
+
cwd: process.cwd(),
|
|
162
|
+
token: process.env.GITHUB_TOKEN,
|
|
163
|
+
repositories: ['service-*', 'my-org/platform-*'],
|
|
164
|
+
visibility: 'all',
|
|
165
|
+
includeArchived: false,
|
|
166
|
+
includeDisabled: false,
|
|
167
|
+
includeForks: false,
|
|
168
|
+
maxRepositories: 100,
|
|
169
|
+
concurrency: 4,
|
|
170
|
+
severity: 'high',
|
|
171
|
+
explain: true,
|
|
172
|
+
configPath: '.actions-warden.yml',
|
|
173
|
+
baseline: '.actions-warden-baseline.json',
|
|
174
|
+
checkpointPath: '.actions-warden-org-checkpoint.json',
|
|
175
|
+
resume: false,
|
|
176
|
+
onProgress(event) {
|
|
177
|
+
console.error(event.type, event.repository ?? '');
|
|
178
|
+
},
|
|
179
|
+
});
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
Returns:
|
|
183
|
+
|
|
184
|
+
```js
|
|
185
|
+
{
|
|
186
|
+
organization,
|
|
187
|
+
scope,
|
|
188
|
+
repositories,
|
|
189
|
+
findings,
|
|
190
|
+
errors,
|
|
191
|
+
summary,
|
|
192
|
+
baseline,
|
|
193
|
+
configPath,
|
|
194
|
+
status
|
|
195
|
+
}
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
`findings` and `errors` are flattened for ingestion. `repositories` retains
|
|
199
|
+
per-repository identity, revision, files, findings, errors, summary, and status.
|
|
200
|
+
|
|
201
|
+
The organization scan is read-only and does not clone, check out, execute, or
|
|
202
|
+
persist raw remote workflow sources. Repository failures are accumulated when
|
|
203
|
+
possible; failures that prevent organization discovery throw.
|
|
204
|
+
|
|
205
|
+
`checkpointPath` explicitly enables atomic checkpoint writes inside `cwd`.
|
|
206
|
+
Set `resume: true` to require, validate, and update an existing checkpoint at
|
|
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.
|
|
213
|
+
|
|
214
|
+
`onProgress` may be synchronous or asynchronous and is awaited in event order
|
|
215
|
+
at each emission point. A callback error rejects the scan; repository results
|
|
216
|
+
whose completion event was reached have already been checkpointed. Event
|
|
217
|
+
objects are shallow-frozen and use these `type` values:
|
|
218
|
+
|
|
219
|
+
| type | important fields |
|
|
220
|
+
|---|---|
|
|
221
|
+
| `scan-started` | `organization` |
|
|
222
|
+
| `checkpoint-loaded` | `repositories` |
|
|
223
|
+
| `checkpoint-created` | none |
|
|
224
|
+
| `discovery-started` | `organization` |
|
|
225
|
+
| `discovery-completed` | `discovered`, `eligible`, `selected` |
|
|
226
|
+
| `repository-started` | `repository`, `position`, `total` |
|
|
227
|
+
| `request-retry` | optional `repository`, `attempt`, `maxRetries`, `reason`, `delayMs`, optional `status` |
|
|
228
|
+
| `repository-completed` | `repository`, `completed`, `total`, `reused`, `status`, `files`, `findings`, `errors` |
|
|
229
|
+
| `scan-completed` | `organization`, `status`, `completed`, `total`, `reused`, `findings`, `errors`, `elapsedMs` |
|
|
230
|
+
|
|
231
|
+
Progress is observational and is not included in the returned result or its
|
|
232
|
+
rendered wire formats.
|
|
233
|
+
|
|
234
|
+
The CLI's `--agent-mode` is an output-routing adapter, not a
|
|
235
|
+
`scanOrganization()` option. JavaScript callers already control checkpoint
|
|
236
|
+
paths, progress callbacks, rendering, persistence, and how much of the returned
|
|
237
|
+
object enters an AI context. Implement the same bounded behavior by saving the
|
|
238
|
+
rendered report and returning only `status`, `summary`, and the saved path to
|
|
239
|
+
the agent.
|
|
240
|
+
|
|
241
|
+
## Renderers
|
|
242
|
+
|
|
243
|
+
Use the matching renderer to obtain the CLI-compatible wire format:
|
|
244
|
+
|
|
245
|
+
```js
|
|
246
|
+
import { audit, renderAudit } from 'actions-warden';
|
|
247
|
+
|
|
248
|
+
const result = await audit({ cwd: '/repo', explain: true });
|
|
249
|
+
|
|
250
|
+
const json = renderAudit(result, {
|
|
251
|
+
format: 'json',
|
|
252
|
+
explain: true,
|
|
253
|
+
cwd: '/repo',
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
const toon = renderAudit(result, {
|
|
257
|
+
format: 'toon',
|
|
258
|
+
explain: true,
|
|
259
|
+
cwd: '/repo',
|
|
260
|
+
});
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
Command/render pairs are:
|
|
264
|
+
|
|
265
|
+
| command | renderer |
|
|
266
|
+
|---|---|
|
|
267
|
+
| `audit` | `renderAudit` |
|
|
268
|
+
| `pin` | `renderPin` |
|
|
269
|
+
| `upgrade` | `renderUpgrade` |
|
|
270
|
+
| `verify` | `renderVerify` |
|
|
271
|
+
| `report` | `renderReport` |
|
|
272
|
+
| `scanOrganization` | `renderOrganizationScan` |
|
|
273
|
+
|
|
274
|
+
Lower-level formatters are also exported: `format`, `renderToon`, `renderJson`,
|
|
275
|
+
`renderText`, `renderSarif`, `summarize`, and `SEVERITY_ORDER`.
|
|
276
|
+
|
|
277
|
+
Every renderer applies credential redaction. See [output contracts](./OUTPUTS.md)
|
|
278
|
+
before depending on the serialized structure.
|
|
279
|
+
|
|
280
|
+
## Parser and policy utilities
|
|
281
|
+
|
|
282
|
+
The package root exports:
|
|
283
|
+
|
|
284
|
+
```js
|
|
285
|
+
import {
|
|
286
|
+
collectImages,
|
|
287
|
+
collectUses,
|
|
288
|
+
discoverWorkflows,
|
|
289
|
+
isIgnored,
|
|
290
|
+
loadConfig,
|
|
291
|
+
parseActionRef,
|
|
292
|
+
parseIgnoreDirectives,
|
|
293
|
+
parseWorkflowFile,
|
|
294
|
+
parseWorkflowSource,
|
|
295
|
+
} from 'actions-warden';
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
Additional exports include baseline helpers, organization GitHub readers
|
|
299
|
+
(`listOrganizationRepositories`, `fetchRepositoryWorkflowTree`, and
|
|
300
|
+
`fetchRepositoryWorkflows`), redaction, the live rule catalog, and organization
|
|
301
|
+
size limits. A validated workflow-tree snapshot can be supplied to
|
|
302
|
+
`fetchRepositoryWorkflows` to avoid a duplicate tree request. See
|
|
303
|
+
[src/index.js](../src/index.js) for the exact export list in the checked-out
|
|
304
|
+
version.
|
|
305
|
+
|
|
306
|
+
Command entry points are also available as explicit package subpaths:
|
|
307
|
+
|
|
308
|
+
```js
|
|
309
|
+
import { audit } from 'actions-warden/commands/audit';
|
|
310
|
+
import { scanOrganization } from 'actions-warden/commands/org-scan';
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
## Error handling
|
|
314
|
+
|
|
315
|
+
Command functions use two error channels:
|
|
316
|
+
|
|
317
|
+
- per-file or per-repository operational problems are usually returned in an
|
|
318
|
+
`errors` array with status `FAIL`;
|
|
319
|
+
- invalid top-level input, unsafe paths, invalid policy, failed target
|
|
320
|
+
discovery, or inability to list an organization rejects the promise.
|
|
321
|
+
|
|
322
|
+
Handle both:
|
|
323
|
+
|
|
324
|
+
```js
|
|
325
|
+
try {
|
|
326
|
+
const result = await scanOrganization(options);
|
|
327
|
+
|
|
328
|
+
if (result.status === 'FAIL') {
|
|
329
|
+
for (const error of result.errors) {
|
|
330
|
+
console.error(error.repository, error.path, error.error);
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
} catch (error) {
|
|
334
|
+
console.error('scan could not start:', error.message);
|
|
335
|
+
}
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
Do not log tokens or raw credentials in an error handler. Built-in renderers
|
|
339
|
+
redact their output; arbitrary caller logging does not.
|
|
340
|
+
|
|
341
|
+
## Concurrency
|
|
342
|
+
|
|
343
|
+
Network-backed helpers use bounded concurrency. `pin` and `verify` resolve up to
|
|
344
|
+
four references at once. Organization scans accept `concurrency` from 1 through
|
|
345
|
+
16 and default to 4.
|
|
346
|
+
|
|
347
|
+
Do not mutate shared workflow files concurrently through multiple `pin` or
|
|
348
|
+
`upgrade` calls. Run a single plan/write cycle for a repository.
|
|
349
|
+
|
|
350
|
+
## Related guides
|
|
351
|
+
|
|
352
|
+
- [CLI reference](./CLI.md)
|
|
353
|
+
- [Output contracts](./OUTPUTS.md)
|
|
354
|
+
- [AI and coding agents](./AI-AGENTS.md)
|
|
355
|
+
- [Developer guide](./DEVELOPMENT.md)
|