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
package/docs/OUTPUTS.md
ADDED
|
@@ -0,0 +1,409 @@
|
|
|
1
|
+
# Output contracts
|
|
2
|
+
|
|
3
|
+
actions-warden separates three concepts:
|
|
4
|
+
|
|
5
|
+
- the selected serialization format;
|
|
6
|
+
- the result's semantic `status`;
|
|
7
|
+
- the process exit code used by a shell or CI runner.
|
|
8
|
+
|
|
9
|
+
Automation should read all three deliberately.
|
|
10
|
+
|
|
11
|
+
## Formats
|
|
12
|
+
|
|
13
|
+
| format | contract | use case |
|
|
14
|
+
|---|---|---|
|
|
15
|
+
| `toon` | Labeled, one-record-per-line text | Compact terminal or LLM context |
|
|
16
|
+
| `json` | Command-specific object with `schemaVersion: "1.0"` | Programmatic integrations |
|
|
17
|
+
| `text` | Bracketed, one-record-per-line text | Human-readable logs |
|
|
18
|
+
| `sarif` | SARIF 2.1.0 JSON | Code scanning and compatible tooling |
|
|
19
|
+
|
|
20
|
+
Select a format with `--format`. The default is `toon`.
|
|
21
|
+
|
|
22
|
+
All serialized values pass through credential redaction. Known token formats,
|
|
23
|
+
credential-shaped key/value pairs, private keys, JWTs, and likely high-entropy
|
|
24
|
+
secrets are replaced with `<redacted>`. Do not use the output as a secret
|
|
25
|
+
transport.
|
|
26
|
+
|
|
27
|
+
## Status and exit codes
|
|
28
|
+
|
|
29
|
+
Every normal command result has semantic status `OK` or `FAIL`. TOON ends with
|
|
30
|
+
`STATUS: ...`; JSON has a top-level `status`; text ends with `==> ...`.
|
|
31
|
+
|
|
32
|
+
| command | `OK` | `FAIL` |
|
|
33
|
+
|---|---|---|
|
|
34
|
+
| `audit` | No unsuppressed findings | One or more findings |
|
|
35
|
+
| `pin` | Resolution and planning/writes had no errors | One or more errors |
|
|
36
|
+
| `upgrade` | Resolution and planning/writes had no errors | One or more errors |
|
|
37
|
+
| `verify` | No verification errors; warnings are allowed | One or more verification errors |
|
|
38
|
+
| `report` | Audit, pin plan, and upgrade plan are all `OK` | Any phase is `FAIL` |
|
|
39
|
+
| `org-scan` | No findings and no repository errors | Findings or repository errors |
|
|
40
|
+
| `rules` | Rule catalog rendered | Not applicable during a normal result |
|
|
41
|
+
|
|
42
|
+
The CLI maps results to process codes:
|
|
43
|
+
|
|
44
|
+
| code | meaning |
|
|
45
|
+
|---|---|
|
|
46
|
+
| `0` | Semantic status `OK` |
|
|
47
|
+
| `1` | Semantic status `FAIL`; inspect the emitted report |
|
|
48
|
+
| `2` | Invalid arguments, invalid policy, unsafe paths, or another invocation-level failure |
|
|
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
|
|
52
|
+
contains JSON when the process exits `2`.
|
|
53
|
+
|
|
54
|
+
Organization-scan live progress is also a stderr-only channel. It never becomes
|
|
55
|
+
part of JSON, SARIF, TOON, or text stdout. `--progress=auto` enables it for an
|
|
56
|
+
interactive stderr, `always` enables it for redirected/CI logs, and `never`
|
|
57
|
+
disables it. GitHub Action organization scans show the same phase, repository,
|
|
58
|
+
retry, and completion updates in the step log by default.
|
|
59
|
+
|
|
60
|
+
### Agent-mode receipt
|
|
61
|
+
|
|
62
|
+
`org-scan --agent-mode`, or `ACTIONS_WARDEN_MODE=agent`, defaults the complete
|
|
63
|
+
report to a guarded scope-keyed file. Its stdout is a separate bounded JSON
|
|
64
|
+
receipt:
|
|
65
|
+
|
|
66
|
+
```js
|
|
67
|
+
{
|
|
68
|
+
schemaVersion: '1.0',
|
|
69
|
+
kind: 'actions-warden-agent-receipt',
|
|
70
|
+
command: 'org-scan',
|
|
71
|
+
organization: string,
|
|
72
|
+
status: 'OK' | 'FAIL',
|
|
73
|
+
summary: object,
|
|
74
|
+
report: {
|
|
75
|
+
path: string,
|
|
76
|
+
format: 'toon' | 'json' | 'text' | 'sarif'
|
|
77
|
+
},
|
|
78
|
+
checkpoint: {
|
|
79
|
+
path: string,
|
|
80
|
+
resumed: boolean
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
`summary` is the normal bounded organization coverage and severity summary;
|
|
86
|
+
the receipt never embeds repository arrays, findings, or operational error
|
|
87
|
+
details. Read `report.path` for the complete evidence. The receipt remains JSON
|
|
88
|
+
even when an explicit format selects TOON, text, or SARIF for the saved report.
|
|
89
|
+
Status and process exit semantics are unchanged. An invocation error may occur
|
|
90
|
+
before a receipt exists.
|
|
91
|
+
|
|
92
|
+
Explicit `--output=stdout` overrides the file default. In that case stdout is
|
|
93
|
+
the complete report in the selected format and no agent receipt is appended.
|
|
94
|
+
|
|
95
|
+
A mutation plan may contain changes and still return `0`: proposed changes are
|
|
96
|
+
not errors. Conversely, `audit` may emit valid JSON and return `1`: findings are
|
|
97
|
+
the result of a successful scan.
|
|
98
|
+
|
|
99
|
+
### Shell handling
|
|
100
|
+
|
|
101
|
+
Do not let `set -e` discard a valid finding report. Capture the exit code and
|
|
102
|
+
parse stdout for codes `0` and `1`:
|
|
103
|
+
|
|
104
|
+
```sh
|
|
105
|
+
set +e
|
|
106
|
+
actions-warden audit --format=json > actions-warden.json
|
|
107
|
+
warden_status=$?
|
|
108
|
+
set -e
|
|
109
|
+
|
|
110
|
+
if [ "$warden_status" -eq 2 ]; then
|
|
111
|
+
echo "actions-warden could not complete" >&2
|
|
112
|
+
exit 2
|
|
113
|
+
fi
|
|
114
|
+
|
|
115
|
+
node -e '
|
|
116
|
+
const fs = require("node:fs");
|
|
117
|
+
const report = JSON.parse(fs.readFileSync("actions-warden.json", "utf8"));
|
|
118
|
+
console.log(report.status, report.summary.findings);
|
|
119
|
+
'
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
Writing reports through `--output=file` is safer than shell redirection when
|
|
123
|
+
repository path containment matters:
|
|
124
|
+
|
|
125
|
+
```sh
|
|
126
|
+
actions-warden audit \
|
|
127
|
+
--format=json \
|
|
128
|
+
--output=file \
|
|
129
|
+
--output-path=reports/actions-warden.json
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
## TOON
|
|
133
|
+
|
|
134
|
+
TOON is Token-Oriented Object Notation. Each line is:
|
|
135
|
+
|
|
136
|
+
```text
|
|
137
|
+
LABEL: key=value key=value
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
Values containing whitespace, `=`, quotes, backslashes, or control characters
|
|
141
|
+
are JSON-quoted. Empty and null fields are omitted. Embedded newlines are
|
|
142
|
+
escaped, so inspected workflow content cannot forge another record.
|
|
143
|
+
|
|
144
|
+
Record labels by command:
|
|
145
|
+
|
|
146
|
+
| command | labels before the final status |
|
|
147
|
+
|---|---|
|
|
148
|
+
| `audit` | `SCAN`, `FINDING`, `SUMMARY` |
|
|
149
|
+
| `pin` | `PIN`, `ERROR`, `SUMMARY` |
|
|
150
|
+
| `upgrade` | `UPGRADE`, `SKIP`, `ERROR`, `SUMMARY` |
|
|
151
|
+
| `verify` | `VERIFIED`, `WARNING`, `ERROR`, `SUMMARY` |
|
|
152
|
+
| `report` | `FINDING`, `PIN`, `UPGRADE`, `SKIP`, `ERROR`, `SUMMARY` |
|
|
153
|
+
| `org-scan` | `REPOSITORY`, `FINDING`, `ERROR`, `SUMMARY` |
|
|
154
|
+
| `rules` | `RULE` |
|
|
155
|
+
|
|
156
|
+
Example:
|
|
157
|
+
|
|
158
|
+
```text
|
|
159
|
+
SCAN: file=.github/workflows/ci.yml
|
|
160
|
+
FINDING: id=18b82e86d7c14fe2 type=unpinned-action sev=high file=.github/workflows/ci.yml action=actions/checkout@v5 line=14
|
|
161
|
+
SUMMARY: files=1 findings=1 totalFindings=1 suppressed=0 critical=0 high=1 medium=0 low=0
|
|
162
|
+
STATUS: FAIL
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
Consumers should split only on the first `:`, then parse whitespace-delimited
|
|
166
|
+
`key=value` fields with JSON-string awareness. If a real parser is available,
|
|
167
|
+
prefer JSON rather than implementing a partial TOON parser.
|
|
168
|
+
|
|
169
|
+
## JSON
|
|
170
|
+
|
|
171
|
+
JSON output is command-specific and ends with a newline. Every top-level object
|
|
172
|
+
contains:
|
|
173
|
+
|
|
174
|
+
```json
|
|
175
|
+
{
|
|
176
|
+
"schemaVersion": "1.0",
|
|
177
|
+
"status": "OK"
|
|
178
|
+
}
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
Treat `schemaVersion` as the compatibility switch and ignore unknown fields so
|
|
182
|
+
additive metadata does not break consumers.
|
|
183
|
+
|
|
184
|
+
### Finding
|
|
185
|
+
|
|
186
|
+
Audit and organization findings use this core shape:
|
|
187
|
+
|
|
188
|
+
```js
|
|
189
|
+
{
|
|
190
|
+
id: string, // stable source-occurrence ID
|
|
191
|
+
fingerprint: string, // line-independent baseline identity
|
|
192
|
+
ruleId: string,
|
|
193
|
+
severity: 'low' | 'medium' | 'high' | 'critical',
|
|
194
|
+
file: string, // POSIX-style path relative to the selected cwd
|
|
195
|
+
line: number,
|
|
196
|
+
fields: object, // rule-specific structured evidence
|
|
197
|
+
explain?: string
|
|
198
|
+
}
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
Organization findings additionally include `repository`, `branch`, and `url`.
|
|
202
|
+
`fields.type`, `fields.sev`, and `fields.file` provide the equivalent flat
|
|
203
|
+
fields used by line-oriented formats.
|
|
204
|
+
|
|
205
|
+
### `audit`
|
|
206
|
+
|
|
207
|
+
```js
|
|
208
|
+
{
|
|
209
|
+
schemaVersion: '1.0',
|
|
210
|
+
files: string[],
|
|
211
|
+
findings: Finding[],
|
|
212
|
+
summary: {
|
|
213
|
+
files: number,
|
|
214
|
+
findings: number,
|
|
215
|
+
totalFindings: number,
|
|
216
|
+
suppressed: number,
|
|
217
|
+
critical: number,
|
|
218
|
+
high: number,
|
|
219
|
+
medium: number,
|
|
220
|
+
low: number
|
|
221
|
+
},
|
|
222
|
+
baseline: { path: string | null, suppressed: number },
|
|
223
|
+
configPath: string | null,
|
|
224
|
+
status: 'OK' | 'FAIL'
|
|
225
|
+
}
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
### `pin`
|
|
229
|
+
|
|
230
|
+
```js
|
|
231
|
+
{
|
|
232
|
+
schemaVersion: '1.0',
|
|
233
|
+
dryRun: boolean,
|
|
234
|
+
changes: [{
|
|
235
|
+
id: string,
|
|
236
|
+
file: string,
|
|
237
|
+
action: string,
|
|
238
|
+
fromRef: string,
|
|
239
|
+
toSha: string,
|
|
240
|
+
line: number,
|
|
241
|
+
refType: 'tag' | 'branch' | 'commit'
|
|
242
|
+
}],
|
|
243
|
+
errors: object[],
|
|
244
|
+
status: 'OK' | 'FAIL'
|
|
245
|
+
}
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
### `upgrade`
|
|
249
|
+
|
|
250
|
+
```js
|
|
251
|
+
{
|
|
252
|
+
schemaVersion: '1.0',
|
|
253
|
+
dryRun: boolean,
|
|
254
|
+
mode: 'major' | 'minor' | 'patch',
|
|
255
|
+
changes: [{
|
|
256
|
+
id: string,
|
|
257
|
+
file: string,
|
|
258
|
+
action: string,
|
|
259
|
+
fromRef: string,
|
|
260
|
+
fromVersion: string | null,
|
|
261
|
+
toTag: string,
|
|
262
|
+
toSha: string,
|
|
263
|
+
level: 'major' | 'minor' | 'patch' | 'unknown',
|
|
264
|
+
line: number
|
|
265
|
+
}],
|
|
266
|
+
skipped: object[],
|
|
267
|
+
errors: object[],
|
|
268
|
+
status: 'OK' | 'FAIL'
|
|
269
|
+
}
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
### `verify`
|
|
273
|
+
|
|
274
|
+
```js
|
|
275
|
+
{
|
|
276
|
+
schemaVersion: '1.0',
|
|
277
|
+
files: string[],
|
|
278
|
+
checks: object[],
|
|
279
|
+
warnings: object[],
|
|
280
|
+
errors: object[],
|
|
281
|
+
status: 'OK' | 'FAIL'
|
|
282
|
+
}
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
### `report`
|
|
286
|
+
|
|
287
|
+
```js
|
|
288
|
+
{
|
|
289
|
+
schemaVersion: '1.0',
|
|
290
|
+
audit: {
|
|
291
|
+
files: string[],
|
|
292
|
+
findings: Finding[],
|
|
293
|
+
summary: object,
|
|
294
|
+
baseline: object,
|
|
295
|
+
status: 'OK' | 'FAIL'
|
|
296
|
+
},
|
|
297
|
+
pin: {
|
|
298
|
+
changes: object[],
|
|
299
|
+
errors: object[],
|
|
300
|
+
status: 'OK' | 'FAIL'
|
|
301
|
+
},
|
|
302
|
+
upgrade: {
|
|
303
|
+
changes: object[],
|
|
304
|
+
skipped: object[],
|
|
305
|
+
errors: object[],
|
|
306
|
+
mode: 'major' | 'minor' | 'patch',
|
|
307
|
+
status: 'OK' | 'FAIL'
|
|
308
|
+
},
|
|
309
|
+
offline: boolean,
|
|
310
|
+
status: 'OK' | 'FAIL'
|
|
311
|
+
}
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
### `org-scan`
|
|
315
|
+
|
|
316
|
+
```js
|
|
317
|
+
{
|
|
318
|
+
schemaVersion: '1.0',
|
|
319
|
+
organization: string,
|
|
320
|
+
scope: object,
|
|
321
|
+
repositories: [{
|
|
322
|
+
repository: {
|
|
323
|
+
owner: string,
|
|
324
|
+
name: string,
|
|
325
|
+
fullName: string,
|
|
326
|
+
defaultBranch: string | null,
|
|
327
|
+
visibility: 'public' | 'private' | 'internal',
|
|
328
|
+
private: boolean,
|
|
329
|
+
fork: boolean,
|
|
330
|
+
archived: boolean,
|
|
331
|
+
disabled: boolean,
|
|
332
|
+
htmlUrl: string
|
|
333
|
+
},
|
|
334
|
+
revision: { branch: string | null, treeSha: string | null },
|
|
335
|
+
files: string[],
|
|
336
|
+
findings: Finding[],
|
|
337
|
+
errors: object[],
|
|
338
|
+
summary: object,
|
|
339
|
+
status: 'OK' | 'FAIL'
|
|
340
|
+
}],
|
|
341
|
+
findings: Finding[], // flattened across repositories
|
|
342
|
+
errors: object[], // flattened across repositories
|
|
343
|
+
summary: object,
|
|
344
|
+
baseline: object,
|
|
345
|
+
configPath: string | null,
|
|
346
|
+
status: 'OK' | 'FAIL'
|
|
347
|
+
}
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
The organization summary includes repository coverage counts in addition to
|
|
351
|
+
file, finding, suppression, error, and severity counts. A consumer can use the
|
|
352
|
+
flattened arrays for ingestion and the `repositories` array for coverage and
|
|
353
|
+
ownership views.
|
|
354
|
+
|
|
355
|
+
### `rules`
|
|
356
|
+
|
|
357
|
+
```js
|
|
358
|
+
{
|
|
359
|
+
schemaVersion: '1.0',
|
|
360
|
+
rules: [{
|
|
361
|
+
id: string,
|
|
362
|
+
severity: 'low' | 'medium' | 'high' | 'critical',
|
|
363
|
+
description: string
|
|
364
|
+
}],
|
|
365
|
+
status: 'OK'
|
|
366
|
+
}
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
## SARIF
|
|
370
|
+
|
|
371
|
+
SARIF output uses version 2.1.0 and identifies the tool as `actions-warden`.
|
|
372
|
+
Findings and operational records become SARIF results. Finding IDs and semantic
|
|
373
|
+
fingerprints are included as partial fingerprints where available, and source
|
|
374
|
+
locations use repository-relative POSIX paths.
|
|
375
|
+
|
|
376
|
+
For a local repository, upload the generated file with the code-scanning tool
|
|
377
|
+
used by your CI platform. Organization findings point at files in other
|
|
378
|
+
repositories, so a single organization SARIF artifact is best treated as a
|
|
379
|
+
portable report unless your ingestion system explicitly supports
|
|
380
|
+
cross-repository locations.
|
|
381
|
+
|
|
382
|
+
GitHub Action annotations are separate from the selected output format. Choosing
|
|
383
|
+
SARIF does not disable annotations.
|
|
384
|
+
|
|
385
|
+
## Stable identities and ordering
|
|
386
|
+
|
|
387
|
+
Occurrence IDs exclude absolute checkout paths so a cloned repository produces
|
|
388
|
+
the same ID for unchanged source. A pin finding and its corresponding pin plan
|
|
389
|
+
share an ID, enabling a precise `--fix=<id>` handoff.
|
|
390
|
+
|
|
391
|
+
Baseline fingerprints tolerate line movement while distinguishing repeated,
|
|
392
|
+
semantically equivalent findings by source order.
|
|
393
|
+
|
|
394
|
+
File discovery, repository selection, findings, baseline serialization, and
|
|
395
|
+
JSON key construction are deterministic for unchanged inputs. Network-backed
|
|
396
|
+
commands can still change when GitHub refs, releases, default branches, or
|
|
397
|
+
repository access change.
|
|
398
|
+
|
|
399
|
+
Resuming an organization scan does not add execution-history fields to the
|
|
400
|
+
final report. When all validated repository revisions are unchanged, a resumed
|
|
401
|
+
report has the same serialized bytes as a fresh result with the same inputs.
|
|
402
|
+
Checkpoint and progress metadata stay outside the report contract.
|
|
403
|
+
|
|
404
|
+
## GitHub Action outputs
|
|
405
|
+
|
|
406
|
+
The Action exposes `status`, `findings`, `report-path`, `annotations`, and
|
|
407
|
+
`annotations-skipped`. Its `fail-on-findings` input can allow audit findings to
|
|
408
|
+
leave the step successful, but operational errors always fail. See the
|
|
409
|
+
[GitHub Action guide](./GITHUB-ACTION.md#outputs-and-failure-policy).
|
package/docs/README.md
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# Documentation
|
|
2
|
+
|
|
3
|
+
Use this page as the map for actions-warden's user, integration, and maintainer
|
|
4
|
+
documentation.
|
|
5
|
+
|
|
6
|
+
## Use actions-warden
|
|
7
|
+
|
|
8
|
+
| Guide | Use it when |
|
|
9
|
+
|---|---|
|
|
10
|
+
| [CLI reference](./CLI.md) | Running audits, pinning, upgrades, verification, reports, or organization scans |
|
|
11
|
+
| [Configuration](./CONFIGURATION.md) | Defining policy, baselines, path exclusions, inline ignores, or runner trust |
|
|
12
|
+
| [Output contracts](./OUTPUTS.md) | Parsing JSON or TOON, uploading SARIF, or handling status and exit codes |
|
|
13
|
+
| [GitHub Action](./GITHUB-ACTION.md) | Adding repository or organization scanning to a workflow |
|
|
14
|
+
| [JavaScript API](./JAVASCRIPT-API.md) | Calling commands or parser utilities from Node.js |
|
|
15
|
+
|
|
16
|
+
## Build with or contribute to actions-warden
|
|
17
|
+
|
|
18
|
+
| Guide | Use it when |
|
|
19
|
+
|---|---|
|
|
20
|
+
| [AI and coding agents](./AI-AGENTS.md) | Operating the CLI from an agent or integrating structured results into an AI workflow |
|
|
21
|
+
| [Developer guide](./DEVELOPMENT.md) | Understanding the architecture, tests, safety boundaries, and common change paths |
|
|
22
|
+
| [Contributing](../CONTRIBUTING.md) | Preparing a change or pull request |
|
|
23
|
+
| [Security policy](../SECURITY.md) | Reviewing the threat model or reporting a vulnerability |
|
|
24
|
+
| [Release process](../RELEASING.md) | Authorizing, publishing, monitoring, or recovering a maintainer/agent release |
|
|
25
|
+
|
|
26
|
+
The repository also provides [AGENTS.md](../AGENTS.md) for repository-aware
|
|
27
|
+
coding agents and [llms.txt](../llms.txt) as a compact machine-readable index.
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
name: actions-warden organization report
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
workflow_dispatch:
|
|
5
|
+
schedule:
|
|
6
|
+
- cron: '23 7 * * 1'
|
|
7
|
+
|
|
8
|
+
permissions:
|
|
9
|
+
contents: read
|
|
10
|
+
|
|
11
|
+
jobs:
|
|
12
|
+
scan:
|
|
13
|
+
runs-on: ubuntu-latest
|
|
14
|
+
permissions:
|
|
15
|
+
contents: read
|
|
16
|
+
steps:
|
|
17
|
+
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # actions-warden-ref: v5.0.0
|
|
18
|
+
with:
|
|
19
|
+
persist-credentials: false
|
|
20
|
+
|
|
21
|
+
- name: Scan organization workflows
|
|
22
|
+
uses: chiz0me/actions-warden@<FULL_COMMIT_SHA>
|
|
23
|
+
with:
|
|
24
|
+
command: org-scan
|
|
25
|
+
organization: ${{ github.repository_owner }}
|
|
26
|
+
token: ${{ secrets.ACTIONS_WARDEN_ORG_TOKEN }}
|
|
27
|
+
severity: high
|
|
28
|
+
explain: 'true'
|
|
29
|
+
format: json
|
|
30
|
+
output-path: actions-warden-org-report.json
|
|
31
|
+
checkpoint-path: .actions-warden-org-checkpoint.json
|
|
32
|
+
fail-on-findings: 'false'
|
|
33
|
+
|
|
34
|
+
- name: Upload organization report
|
|
35
|
+
if: always()
|
|
36
|
+
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # actions-warden-ref: v5.0.0
|
|
37
|
+
with:
|
|
38
|
+
name: actions-warden-org-report
|
|
39
|
+
path: |
|
|
40
|
+
actions-warden-org-report.json
|
|
41
|
+
.actions-warden-org-checkpoint.json
|
|
42
|
+
if-no-files-found: error
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
name: actions-warden upgrades
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
workflow_dispatch:
|
|
5
|
+
schedule:
|
|
6
|
+
- cron: '17 6 * * 1'
|
|
7
|
+
|
|
8
|
+
permissions:
|
|
9
|
+
contents: read
|
|
10
|
+
|
|
11
|
+
jobs:
|
|
12
|
+
upgrade:
|
|
13
|
+
runs-on: ubuntu-latest
|
|
14
|
+
permissions:
|
|
15
|
+
contents: write
|
|
16
|
+
pull-requests: write
|
|
17
|
+
steps:
|
|
18
|
+
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # actions-warden-ref: v5.0.0
|
|
19
|
+
with:
|
|
20
|
+
persist-credentials: false
|
|
21
|
+
|
|
22
|
+
- uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # actions-warden-ref: v5.0.0
|
|
23
|
+
with:
|
|
24
|
+
node-version: '24'
|
|
25
|
+
|
|
26
|
+
- name: Apply eligible upgrades
|
|
27
|
+
env:
|
|
28
|
+
GITHUB_TOKEN: ${{ github.token }}
|
|
29
|
+
run: npx --yes actions-warden@0.3.0 upgrade --mode=minor --min-age=7 --write
|
|
30
|
+
|
|
31
|
+
- name: Open or update pull request
|
|
32
|
+
env:
|
|
33
|
+
GH_TOKEN: ${{ github.token }}
|
|
34
|
+
REPOSITORY: ${{ github.repository }}
|
|
35
|
+
UPGRADE_BRANCH: actions-warden/weekly-upgrades
|
|
36
|
+
run: |
|
|
37
|
+
set -euo pipefail
|
|
38
|
+
if git diff --quiet; then
|
|
39
|
+
echo "No eligible upgrades."
|
|
40
|
+
exit 0
|
|
41
|
+
fi
|
|
42
|
+
|
|
43
|
+
git config user.name "github-actions[bot]"
|
|
44
|
+
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
|
|
45
|
+
git add -u
|
|
46
|
+
git commit -m "chore: upgrade pinned GitHub Actions"
|
|
47
|
+
remote_sha="$(gh api "repos/${REPOSITORY}/git/ref/heads/${UPGRADE_BRANCH}" --jq .object.sha 2>/dev/null || true)"
|
|
48
|
+
lease="--force-with-lease=refs/heads/${UPGRADE_BRANCH}:${remote_sha}"
|
|
49
|
+
git -c "http.https://github.com/.extraheader=AUTHORIZATION: basic $(printf 'x-access-token:%s' "$GH_TOKEN" | base64 -w0)" \
|
|
50
|
+
push "$lease" "https://github.com/${REPOSITORY}.git" "HEAD:refs/heads/${UPGRADE_BRANCH}"
|
|
51
|
+
|
|
52
|
+
if ! gh pr view "$UPGRADE_BRANCH" >/dev/null 2>&1; then
|
|
53
|
+
gh pr create \
|
|
54
|
+
--head "$UPGRADE_BRANCH" \
|
|
55
|
+
--title "chore: upgrade pinned GitHub Actions" \
|
|
56
|
+
--body "Automated, cooldown-aware upgrade generated by actions-warden."
|
|
57
|
+
fi
|
package/llms.txt
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# actions-warden
|
|
2
|
+
|
|
3
|
+
> Audit GitHub Actions in one repository or across a GitHub organization, then
|
|
4
|
+
> pin, verify, and upgrade dependencies with explicit write authorization.
|
|
5
|
+
|
|
6
|
+
Requires Node.js 20+. The CLI is non-interactive. `pin` and `upgrade` are
|
|
7
|
+
dry-run by default. Normal JSON payloads use `schemaVersion: "1.0"`. Exit code
|
|
8
|
+
1 is a completed `FAIL` result to inspect; exit code 2 is an invocation error.
|
|
9
|
+
Organization scans support guarded `--checkpoint` / `--resume` state and
|
|
10
|
+
stderr-only live progress while retaining fresh repository tree validation.
|
|
11
|
+
For agent-initiated organization scans, pass `--agent-mode` or set
|
|
12
|
+
`ACTIONS_WARDEN_MODE=agent`. It defaults to scope-keyed JSON report and
|
|
13
|
+
checkpoint files, compatible resume, no progress, and a bounded stdout receipt.
|
|
14
|
+
Preserve requested scope; do not load the complete report into model context.
|
|
15
|
+
|
|
16
|
+
## Start
|
|
17
|
+
|
|
18
|
+
- [README](./README.md): product overview and quick start
|
|
19
|
+
- [CLI reference](./docs/CLI.md): commands, options, organization scans, cache
|
|
20
|
+
- [Configuration](./docs/CONFIGURATION.md): policy, rule IDs, ignores, baselines
|
|
21
|
+
- [Output contracts](./docs/OUTPUTS.md): JSON shapes, TOON, SARIF, status, exits
|
|
22
|
+
- [GitHub Action](./docs/GITHUB-ACTION.md): workflow setup, inputs, outputs
|
|
23
|
+
- [JavaScript API](./docs/JAVASCRIPT-API.md): public functions and renderers
|
|
24
|
+
|
|
25
|
+
## AI and development
|
|
26
|
+
|
|
27
|
+
- [AI and coding agents](./docs/AI-AGENTS.md): safe plan/write/verify loop
|
|
28
|
+
- [Repository agent guidance](./AGENTS.md): invariants and validation
|
|
29
|
+
- [Developer guide](./docs/DEVELOPMENT.md): architecture and change recipes
|
|
30
|
+
- [Contributing](./CONTRIBUTING.md): setup and pull request checklist
|
|
31
|
+
- [Security policy](./SECURITY.md): threat model and private reporting
|
|
32
|
+
- [Release process](./RELEASING.md): authoritative maintainer/agent authorization, publication, verification, and recovery runbook
|
|
33
|
+
|
|
34
|
+
## Copyable examples
|
|
35
|
+
|
|
36
|
+
- [Organization report workflow](./examples/org-scan.yml)
|
|
37
|
+
- [Upgrade pull request workflow](./examples/upgrade-pr.yml)
|
|
38
|
+
- [Claude Code skill](./skills/actions-warden/SKILL.md)
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "actions-warden",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Audit
|
|
3
|
+
"version": "0.3.0",
|
|
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",
|
|
7
7
|
"repository": {
|
|
@@ -18,15 +18,23 @@
|
|
|
18
18
|
"./commands/audit": "./src/commands/audit.js",
|
|
19
19
|
"./commands/pin": "./src/commands/pin.js",
|
|
20
20
|
"./commands/upgrade": "./src/commands/upgrade.js",
|
|
21
|
-
"./commands/report": "./src/commands/report.js"
|
|
21
|
+
"./commands/report": "./src/commands/report.js",
|
|
22
|
+
"./commands/verify": "./src/commands/verify.js",
|
|
23
|
+
"./commands/org-scan": "./src/commands/org-scan.js"
|
|
22
24
|
},
|
|
23
25
|
"bin": {
|
|
24
26
|
"actions-warden": "./src/cli.js"
|
|
25
27
|
},
|
|
26
28
|
"files": [
|
|
27
29
|
"src",
|
|
30
|
+
"docs",
|
|
31
|
+
"examples",
|
|
28
32
|
"skills",
|
|
29
33
|
"README.md",
|
|
34
|
+
"CONTRIBUTING.md",
|
|
35
|
+
"AGENTS.md",
|
|
36
|
+
"RELEASING.md",
|
|
37
|
+
"llms.txt",
|
|
30
38
|
"SECURITY.md",
|
|
31
39
|
"LICENSE"
|
|
32
40
|
],
|
|
@@ -40,31 +48,45 @@
|
|
|
40
48
|
"scripts": {
|
|
41
49
|
"test": "vitest --run",
|
|
42
50
|
"test:watch": "vitest",
|
|
43
|
-
"lint": "eslint src test",
|
|
51
|
+
"lint": "eslint src scripts test",
|
|
52
|
+
"build:action": "ncc build src/action.js -o dist",
|
|
53
|
+
"check:action-bundle": "node scripts/verify-action-bundle.js",
|
|
54
|
+
"check:yaml": "node scripts/check-yaml.js",
|
|
55
|
+
"check:docs": "node scripts/check-docs.js",
|
|
56
|
+
"check:package": "node scripts/check-package.js",
|
|
57
|
+
"check:release-version": "node scripts/check-release-version.js",
|
|
44
58
|
"verify-deps": "node scripts/verify-deps.js",
|
|
59
|
+
"verify-version-sync": "node scripts/verify-version-sync.js",
|
|
45
60
|
"audit": "npm audit --audit-level=high",
|
|
46
|
-
"release:
|
|
47
|
-
"
|
|
61
|
+
"release:prepare": "node scripts/set-version.js",
|
|
62
|
+
"release:check": "npm run check:release-version && npm run verify-version-sync && npm run verify-deps && npm run check:yaml && npm run check:docs && npm run lint && npm test && npm audit --audit-level=high && npm run check:package && npm run check:action-bundle",
|
|
63
|
+
"prepublishOnly": "npm run verify-version-sync && npm run verify-deps && npm run check:yaml && npm run check:docs && npm run lint && npm test && npm audit --audit-level=high && npm run check:package"
|
|
48
64
|
},
|
|
49
65
|
"dependencies": {
|
|
50
66
|
"commander": "14.0.3",
|
|
51
|
-
"picomatch": "4.0.
|
|
52
|
-
"semver": "7.8.
|
|
67
|
+
"picomatch": "4.0.5",
|
|
68
|
+
"semver": "7.8.5",
|
|
53
69
|
"yaml": "2.9.0"
|
|
54
70
|
},
|
|
55
71
|
"devDependencies": {
|
|
56
|
-
"eslint": "
|
|
57
|
-
"
|
|
72
|
+
"@eslint/js": "9.39.2",
|
|
73
|
+
"@vercel/ncc": "0.44.1",
|
|
74
|
+
"eslint": "9.39.2",
|
|
75
|
+
"globals": "17.7.0",
|
|
76
|
+
"vitest": "4.1.10"
|
|
58
77
|
},
|
|
59
78
|
"keywords": [
|
|
60
79
|
"github-actions",
|
|
61
80
|
"security",
|
|
62
81
|
"audit",
|
|
82
|
+
"organization",
|
|
83
|
+
"security-report",
|
|
63
84
|
"pin",
|
|
64
85
|
"sha-pin",
|
|
65
86
|
"workflow",
|
|
66
87
|
"supply-chain",
|
|
67
88
|
"toon",
|
|
89
|
+
"sarif",
|
|
68
90
|
"llm"
|
|
69
91
|
],
|
|
70
92
|
"license": "MIT"
|