swarm-orchestrator 14.2.0 → 14.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/CHANGELOG.md +568 -0
- package/README.md +98 -214
- package/dist/action/artifacts.js +72 -0
- package/dist/action/artifacts.js.map +1 -0
- package/dist/action/comment.js +139 -0
- package/dist/action/comment.js.map +1 -0
- package/dist/action/environment.js +106 -0
- package/dist/action/environment.js.map +1 -0
- package/dist/action/verdict.js +103 -0
- package/dist/action/verdict.js.map +1 -0
- package/dist/action/verify.js +424 -0
- package/dist/action/verify.js.map +1 -0
- package/dist/cli-action.js +117 -0
- package/dist/cli-action.js.map +1 -0
- package/dist/cli-check.js +341 -0
- package/dist/cli-check.js.map +1 -0
- package/dist/cli-ci.js +27 -3
- package/dist/cli-ci.js.map +1 -1
- package/dist/cli-command-definitions.js +43 -1
- package/dist/cli-command-definitions.js.map +1 -1
- package/dist/cli-gates.js +33 -10
- package/dist/cli-gates.js.map +1 -1
- package/dist/cli-integrations.js +145 -0
- package/dist/cli-integrations.js.map +1 -0
- package/dist/cli-options.js +32 -0
- package/dist/cli-options.js.map +1 -1
- package/dist/cli-strengthen.js +527 -0
- package/dist/cli-strengthen.js.map +1 -0
- package/dist/cli-task-goal.js +58 -9
- package/dist/cli-task-goal.js.map +1 -1
- package/dist/cli-verdict.js +144 -0
- package/dist/cli-verdict.js.map +1 -0
- package/dist/cli-verify-options.js +85 -0
- package/dist/cli-verify-options.js.map +1 -1
- package/dist/cli.js +82 -8
- package/dist/cli.js.map +1 -1
- package/dist/config/init.js +1 -1
- package/dist/config/init.js.map +1 -1
- package/dist/config/package-discovery.js +47 -1
- package/dist/config/package-discovery.js.map +1 -1
- package/dist/durable/recovery-context.js +3 -2
- package/dist/durable/recovery-context.js.map +1 -1
- package/dist/evidence/blob-manifest.js +9 -0
- package/dist/evidence/blob-manifest.js.map +1 -1
- package/dist/evidence/bundle.js +17 -2
- package/dist/evidence/bundle.js.map +1 -1
- package/dist/evidence/challenge-lines.js +21 -0
- package/dist/evidence/challenge-lines.js.map +1 -0
- package/dist/evidence/ci-summary.js +5 -1
- package/dist/evidence/ci-summary.js.map +1 -1
- package/dist/evidence/goal-contract.js +132 -1
- package/dist/evidence/goal-contract.js.map +1 -1
- package/dist/evidence/signing.js +3 -1
- package/dist/evidence/signing.js.map +1 -1
- package/dist/evidence/verifier/challenges.d.mts +19 -0
- package/dist/evidence/verifier/challenges.mjs +203 -0
- package/dist/evidence/verifier/rederive.mjs +20 -2
- package/dist/evidence/verifier/status.d.mts +2 -0
- package/dist/evidence/verifier/status.mjs +638 -38
- package/dist/evidence/verifier/strengthening.d.mts +18 -0
- package/dist/evidence/verifier/strengthening.mjs +200 -0
- package/dist/evidence/verifier/upgrade.mjs +1 -0
- package/dist/evidence/verifier/verify.mjs +25 -1
- package/dist/exec/child-environment.js +30 -0
- package/dist/exec/child-environment.js.map +1 -1
- package/dist/exec/container-backend.js +103 -12
- package/dist/exec/container-backend.js.map +1 -1
- package/dist/exec/controlled-network.js +20 -1
- package/dist/exec/controlled-network.js.map +1 -1
- package/dist/exec/execution-mode.js +25 -13
- package/dist/exec/execution-mode.js.map +1 -1
- package/dist/exec/runtime-resource.js +6 -1
- package/dist/exec/runtime-resource.js.map +1 -1
- package/dist/gates/base-control.js +7 -2
- package/dist/gates/base-control.js.map +1 -1
- package/dist/gates/certification.js +4 -0
- package/dist/gates/certification.js.map +1 -1
- package/dist/gates/change-source.js +29 -29
- package/dist/gates/change-source.js.map +1 -1
- package/dist/gates/check-admission.js +218 -0
- package/dist/gates/check-admission.js.map +1 -0
- package/dist/gates/check-network-probe.js +42 -0
- package/dist/gates/check-network-probe.js.map +1 -0
- package/dist/gates/check-plan.js +269 -0
- package/dist/gates/check-plan.js.map +1 -0
- package/dist/gates/checkout-environment.js +119 -0
- package/dist/gates/checkout-environment.js.map +1 -0
- package/dist/gates/contract-executor.js +7 -4
- package/dist/gates/contract-executor.js.map +1 -1
- package/dist/gates/default-gates.js +2 -2
- package/dist/gates/default-gates.js.map +1 -1
- package/dist/gates/deferred-setup.js +250 -0
- package/dist/gates/deferred-setup.js.map +1 -0
- package/dist/gates/dependency-install.js +200 -41
- package/dist/gates/dependency-install.js.map +1 -1
- package/dist/gates/engine.js +7 -1
- package/dist/gates/engine.js.map +1 -1
- package/dist/gates/failure-attribution.js +444 -0
- package/dist/gates/failure-attribution.js.map +1 -0
- package/dist/gates/gate-definition.js.map +1 -1
- package/dist/gates/gate-runner.js +31 -5
- package/dist/gates/gate-runner.js.map +1 -1
- package/dist/gates/git-workspace.js +36 -5
- package/dist/gates/git-workspace.js.map +1 -1
- package/dist/gates/goal-challenge-runner.js +99 -0
- package/dist/gates/goal-challenge-runner.js.map +1 -0
- package/dist/gates/goal-challenges.js +337 -0
- package/dist/gates/goal-challenges.js.map +1 -0
- package/dist/gates/harness-reporting.js +7 -3
- package/dist/gates/harness-reporting.js.map +1 -1
- package/dist/gates/independent-checks.js +63 -2
- package/dist/gates/independent-checks.js.map +1 -1
- package/dist/gates/independent-verification.js +569 -82
- package/dist/gates/independent-verification.js.map +1 -1
- package/dist/gates/inspection-gates.js +5 -5
- package/dist/gates/inspection-gates.js.map +1 -1
- package/dist/gates/instrument-dependencies.js +249 -0
- package/dist/gates/instrument-dependencies.js.map +1 -0
- package/dist/gates/instrument-identity.js +794 -0
- package/dist/gates/instrument-identity.js.map +1 -0
- package/dist/gates/mutant-parse.js +23 -0
- package/dist/gates/mutant-parse.js.map +1 -1
- package/dist/gates/node-command-runner.js +16 -2
- package/dist/gates/node-command-runner.js.map +1 -1
- package/dist/gates/node-gates.js +39 -8
- package/dist/gates/node-gates.js.map +1 -1
- package/dist/gates/node-test-command.js +22 -4
- package/dist/gates/node-test-command.js.map +1 -1
- package/dist/gates/noninteractive-runner.js +106 -0
- package/dist/gates/noninteractive-runner.js.map +1 -0
- package/dist/gates/oracle-instrumentation.js +1 -3
- package/dist/gates/oracle-instrumentation.js.map +1 -1
- package/dist/gates/oracle-mutants.js +13 -3
- package/dist/gates/oracle-mutants.js.map +1 -1
- package/dist/gates/parsers.js +110 -4
- package/dist/gates/parsers.js.map +1 -1
- package/dist/gates/patch-paths.js +304 -14
- package/dist/gates/patch-paths.js.map +1 -1
- package/dist/gates/prepare-dependencies.js +2 -0
- package/dist/gates/prepare-dependencies.js.map +1 -1
- package/dist/gates/prepared-tools.js +18 -0
- package/dist/gates/prepared-tools.js.map +1 -0
- package/dist/gates/project-environment.js +1 -0
- package/dist/gates/project-environment.js.map +1 -1
- package/dist/gates/project-type.js +131 -14
- package/dist/gates/project-type.js.map +1 -1
- package/dist/gates/python-gates.js +58 -32
- package/dist/gates/python-gates.js.map +1 -1
- package/dist/gates/python-mutants.js +176 -0
- package/dist/gates/python-mutants.js.map +1 -0
- package/dist/gates/python-offline-build.js +274 -0
- package/dist/gates/python-offline-build.js.map +1 -0
- package/dist/gates/runner-results.js +96 -23
- package/dist/gates/runner-results.js.map +1 -1
- package/dist/gates/scratch-index.js +112 -3
- package/dist/gates/scratch-index.js.map +1 -1
- package/dist/gates/setup-effect.js +16 -0
- package/dist/gates/setup-effect.js.map +1 -0
- package/dist/gates/setup-follow-up.js +113 -0
- package/dist/gates/setup-follow-up.js.map +1 -0
- package/dist/gates/structured-runner.js +37 -8
- package/dist/gates/structured-runner.js.map +1 -1
- package/dist/gates/unified-diff.js +39 -9
- package/dist/gates/unified-diff.js.map +1 -1
- package/dist/gates/upgrade-contract.js +1 -0
- package/dist/gates/upgrade-contract.js.map +1 -1
- package/dist/gates/upgrade-resolution.js +8 -1
- package/dist/gates/upgrade-resolution.js.map +1 -1
- package/dist/install/health.js +3 -3
- package/dist/install/health.js.map +1 -1
- package/dist/integrations/claude-hook.js +200 -0
- package/dist/integrations/claude-hook.js.map +1 -0
- package/dist/integrations/launcher.js +17 -0
- package/dist/integrations/launcher.js.map +1 -0
- package/dist/integrations/mcp-server.js +270 -0
- package/dist/integrations/mcp-server.js.map +1 -0
- package/dist/integrations/pre-commit.js +169 -0
- package/dist/integrations/pre-commit.js.map +1 -0
- package/dist/machine-output.js +1 -0
- package/dist/machine-output.js.map +1 -1
- package/dist/node-floor.js +46 -17
- package/dist/node-floor.js.map +1 -1
- package/dist/swarm-verify.js +28 -4
- package/dist/swarm-verify.js.map +1 -1
- package/dist/workers/bootstrap-history.js +4 -3
- package/dist/workers/bootstrap-history.js.map +1 -1
- package/dist/workers/worktree.js +72 -30
- package/dist/workers/worktree.js.map +1 -1
- package/docs/README.md +5 -1
- package/docs/claims.md +20 -0
- package/docs/security-coverage.md +3 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,221 +2,118 @@
|
|
|
2
2
|
|
|
3
3
|
<div align="center">
|
|
4
4
|
|
|
5
|
-
<h1>
|
|
5
|
+
<h1>Swarm Verify</h1>
|
|
6
6
|
|
|
7
|
-
<p><strong>
|
|
8
|
-
|
|
9
|
-
<p>
|
|
10
|
-
The model can say whatever it likes.<br />
|
|
11
|
-
It cannot make a check pass, mark a claim verified, or change a record after the fact.
|
|
12
|
-
</p>
|
|
13
|
-
|
|
14
|
-
<p>
|
|
15
|
-
<a href="docs/README.md"><strong>Explore the docs »</strong></a>
|
|
16
|
-
·
|
|
17
|
-
<a href="docs/evidence/2026-08-18/live-tasks.md">See a real run</a>
|
|
18
|
-
·
|
|
19
|
-
<a href="https://github.com/moonrunnerkc/swarm-orchestrator/issues/new?labels=bug">Report a bug</a>
|
|
20
|
-
</p>
|
|
21
|
-
|
|
22
|
-
[](https://github.com/moonrunnerkc/swarm-orchestrator/actions/workflows/gates.yml)
|
|
23
|
-
[](https://www.npmjs.com/package/swarm-orchestrator)
|
|
24
|
-
[](package.json)
|
|
25
|
-
[](LICENSE)
|
|
7
|
+
<p><strong>Swarm Verify runs a project's checks and records evidence showing what passed, what failed, and what remains unverified.</strong></p>
|
|
26
8
|
|
|
27
9
|
</div>
|
|
28
10
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
`swarm` takes a task and a git repository, makes a bounded change, runs your project's checks
|
|
34
|
-
over it, and writes a record of every command it ran and every check that passed or failed.
|
|
35
|
-
The record is a hash-chained ledger, exported as a signed bundle that carries its own
|
|
36
|
-
dependency-free verifier, so anyone can check it later with nothing but Node and without
|
|
37
|
-
trusting the machine that produced it.
|
|
38
|
-
|
|
39
|
-
It is for two kinds of people. Engineers who want an agent to make a change and want to review
|
|
40
|
-
what it did from evidence rather than from the agent's own summary. And reviewers who are handed
|
|
41
|
-
somebody else's patch or bundle and need to check it without installing the agent or believing
|
|
42
|
-
its author.
|
|
43
|
-
|
|
44
|
-
**Upgrading from 12.x?** That was a pull-request auditor; 13 and later are a coding agent under
|
|
45
|
-
the same package name, with no migration path. Stay on the `v12-final` tag, or pin the major.
|
|
46
|
-
|
|
47
|
-
## Source upgrade workflows
|
|
11
|
+
This is the main source repository for Swarm Verify, maintained under the swarm-orchestrator
|
|
12
|
+
repository name. It also contains the optional beta coding agent. The separate
|
|
13
|
+
[moonrunnerkc/swarm-verify](https://github.com/moonrunnerkc/swarm-verify) repository distributes
|
|
14
|
+
the GitHub Action.
|
|
48
15
|
|
|
49
|
-
|
|
50
|
-
Node/Python initialization and selected packages; CLI, local HTTP and optional Playwright checks;
|
|
51
|
-
one explicit escalation; and bugfix, refactor and dependency-upgrade presets. The full and
|
|
52
|
-
standalone CLIs share the verifier. [Delivery evidence](docs/upgrade-completion.md) distinguishes
|
|
53
|
-
implemented source, exact-source validation and remote delivery. These additions are not an
|
|
54
|
-
npm publication; use the documented source tarball installation until a release is verified.
|
|
16
|
+

|
|
55
17
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
18
|
+
The recording is a real run of the published package over a committed evidence bundle: it
|
|
19
|
+
verifies, one byte of one record is changed, and the altered bundle is refused with the broken
|
|
20
|
+
link named. That is integrity. Who signed a bundle, and whether the tests it records measured
|
|
21
|
+
the right thing, are separate questions the verifier answers separately
|
|
22
|
+
([transcript](docs/evidence/2026-09-27/verifier-first/tamper-demo-transcript.txt),
|
|
23
|
+
[script](docs/evidence/2026-09-27/verifier-first/tamper-demo.sh)).
|
|
61
24
|
|
|
62
25
|
```sh
|
|
63
|
-
|
|
26
|
+
npx swarm-verify
|
|
64
27
|
```
|
|
65
28
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
29
|
+
Run it in a git repository whose dependencies are installed (`npm ci`, `pnpm install
|
|
30
|
+
--frozen-lockfile` or `uv sync`; it names the missing step and exits 4 when they are not). It
|
|
31
|
+
reads the checks the project declares, runs them unattended the way a CI job would, and reports
|
|
32
|
+
apart: whether the command ran, what each check found, how the commands were contained, and
|
|
33
|
+
what it did not judge. By default it does not challenge the checks and does not judge whether
|
|
34
|
+
the work is correct: a pass is a regression-only pass, and the result line says so. A failed
|
|
35
|
+
check exits 1 and names the check; a check whose result cannot be trusted, such as a pass
|
|
36
|
+
reported by a test configuration the change itself edited, exits 4 and says why.
|
|
37
|
+
|
|
38
|
+
It creates no `swarm.toml` and keeps its evidence outside the repository, under
|
|
39
|
+
`~/.swarm/sessions` by default. While it runs it briefly adds, then removes, its own
|
|
40
|
+
`swarm-falsification-bond.*` fixtures to show each passing check can fail, and the project's
|
|
41
|
+
own commands may write build output, caches or other files as they always do. No model, key
|
|
42
|
+
or configuration is needed.
|
|
43
|
+
|
|
44
|
+
Needs Node 22 or newer, git, and `uv` for a Python project. Linux and macOS run every command;
|
|
45
|
+
Windows runs bundle and verdict verification only. Locally, commands run on the host with a
|
|
46
|
+
built environment and no credentials, which is a policy and not a sandbox; the Action runs
|
|
47
|
+
them in a network-disabled container.
|
|
71
48
|
|
|
72
|
-
|
|
49
|
+
[](https://github.com/moonrunnerkc/swarm-orchestrator/actions/workflows/gates.yml)
|
|
50
|
+
[](https://github.com/moonrunnerkc/swarm-orchestrator/actions/workflows/verifier-matrix.yml)
|
|
51
|
+
[](https://www.npmjs.com/package/swarm-verify)
|
|
52
|
+
[](LICENSE)
|
|
73
53
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
54
|
+
## In CI
|
|
55
|
+
|
|
56
|
+
One job, one Action, the permissions a signed comment needs
|
|
57
|
+
([the complete workflow](docs/examples/swarm-verification.yml)):
|
|
58
|
+
|
|
59
|
+
```yaml
|
|
60
|
+
name: swarm-verify
|
|
61
|
+
on:
|
|
62
|
+
pull_request:
|
|
63
|
+
permissions:
|
|
64
|
+
contents: read
|
|
65
|
+
pull-requests: write
|
|
66
|
+
id-token: write
|
|
67
|
+
attestations: write
|
|
68
|
+
artifact-metadata: write
|
|
69
|
+
jobs:
|
|
70
|
+
verify:
|
|
71
|
+
runs-on: ubuntu-latest
|
|
72
|
+
steps:
|
|
73
|
+
- uses: moonrunnerkc/swarm-verify@v1
|
|
74
|
+
with:
|
|
75
|
+
install: true # install from the lockfile, scripts off, then run skipped scripts offline; omit for a project with no dependencies
|
|
79
76
|
```
|
|
80
77
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
the list of things that may not be said, is [docs/claims.md](docs/claims.md).
|
|
121
|
-
|
|
122
|
-
- **One changed byte breaks verification.** The same bundle verified and then tampered with in
|
|
123
|
-
a single byte, exit 0 and exit 1 side by side, with a script to reproduce it:
|
|
124
|
-
[tamper demo](docs/evidence/2026-08-18/tamper-demo).
|
|
125
|
-
- **A bundle verifies on a machine that has never seen this repository.** Run in a `node:24`
|
|
126
|
-
container with no network and no mount of this repository:
|
|
127
|
-
[clean-container-verification.md](docs/evidence/2026-08-23/clean-container-verification.md).
|
|
128
|
-
- **A green verdict is computed by the harness, and the model cannot produce one.** In a real
|
|
129
|
-
run the model asserted a predicate the language does not parse; the harness rendered it
|
|
130
|
-
`UNVERIFIED` and carried on, twice: [shakedown results](docs/evidence/2026-08-18/shakedown/results.md).
|
|
131
|
-
- **A suite passing is not the task being done.** Four of eighteen real-repository patches
|
|
132
|
-
passed their project's whole suite and failed a hidden acceptance test, which is why `swarm ci`
|
|
133
|
-
reports `regression` and `task` as two answers: [docs/verifying.md](docs/verifying.md).
|
|
134
|
-
- **The oracle is judged too.** Certified tasks turned out to rest on oracles that could not
|
|
135
|
-
fail. The last false green standing, `commander#1671`, was certified by an oracle that runs
|
|
136
|
-
every line the patch adds and never tests the precedence those lines decide; it is refused now
|
|
137
|
-
because that oracle accepted a change to a line it had run:
|
|
138
|
-
[docs/verifying.md](docs/verifying.md#the-oracle-is-judged-too).
|
|
139
|
-
- **The September 6 mined-corpus false-green rate was 0 in 15**, 0.0%, 95% CI [0.0, 20.4], with
|
|
140
|
-
two oracles per task, one handed to the tool and one held back:
|
|
141
|
-
[mined-corpus](docs/evidence/2026-09-06/mined-corpus/README.md). The denominator moved when
|
|
142
|
-
the tool did: four patches both oracles accept are refused because the tool's own oracle never
|
|
143
|
-
ran part of what they changed, five because the sealed half rejects work the held-back half
|
|
144
|
-
accepts, and one because its oracle accepted a change to a line it had run.
|
|
145
|
-
- **Twelve tasks reported as unjudgeable were the agent having written nothing at all**, which
|
|
146
|
-
is a model failure and is recorded as one. An earlier 0-of-18 was withdrawn rather than
|
|
147
|
-
corrected quietly: the same test was handed to the tool and then used as the ground truth it
|
|
148
|
-
was scored against, so it agreed with itself:
|
|
149
|
-
[false-green-measurement.md](docs/evidence/2026-09-05/false-green-measurement.md).
|
|
150
|
-
- **Of the gates this project agreed not to call itself production-ready without**, the
|
|
151
|
-
historical assessment records eight passing, two partial, two unproven, and two reported
|
|
152
|
-
rather than barred: [docs/beta-gates.md](docs/beta-gates.md).
|
|
153
|
-
|
|
154
|
-
<p align="right">(<a href="#readme-top">back to top</a>)</p>
|
|
155
|
-
|
|
156
|
-
## What is not claimed
|
|
157
|
-
|
|
158
|
-
The five that matter most. The full list is in
|
|
159
|
-
[docs/verifying.md](docs/verifying.md#what-is-not-claimed).
|
|
160
|
-
|
|
161
|
-
- **It is not production-ready.** The counts above describe the linked campaigns, not a fresh
|
|
162
|
-
measurement of every gate on this checkout. Each row and what would settle it:
|
|
163
|
-
[docs/beta-gates.md](docs/beta-gates.md).
|
|
164
|
-
- **Not "fully secure".** The secret detector does known-pattern scrubbing, not secret removal.
|
|
165
|
-
Zero crashes at a fuzz budget is evidence, not proof.
|
|
166
|
-
- **The default execution mode is `restricted`, not `isolated`.** A lexical path and program
|
|
167
|
-
policy in front of interpreters unless you pass `--isolation`. Reported before the run starts
|
|
168
|
-
and recorded on the chain rather than quietly assumed, but it is not containment.
|
|
169
|
-
- **0 in 15 says "under 20%", not "zero".** That upper bound is the honest half of the rate,
|
|
170
|
-
and it is a rate for that corpus and that build, not for this one.
|
|
171
|
-
- **Shown its oracle, a model still gets past this.** A patch written to satisfy a visible test
|
|
172
|
-
has its added lines tested by that test, so the oracle refuses every mutant of them and is
|
|
173
|
-
right to. Bonding asks whether the oracle judged what the patch added. It cannot ask what the
|
|
174
|
-
patch left out, and that is what an adversarial patch does.
|
|
175
|
-
|
|
176
|
-
Gates prove mechanical quality, not design quality. What a bundle buys you is that reviewing the
|
|
177
|
-
change is fast and its claims are checkable, not that review is unnecessary.
|
|
178
|
-
|
|
179
|
-
<p align="right">(<a href="#readme-top">back to top</a>)</p>
|
|
180
|
-
|
|
181
|
-
## Roadmap
|
|
182
|
-
|
|
183
|
-
The implementation is ahead of the evidence needed to call this production-ready. The audit
|
|
184
|
-
repairs are recorded in [the implementation record](docs/audit-implementation-2026-09-11.md);
|
|
185
|
-
the local campaign and every excluded case are in
|
|
186
|
-
[the September 11 report](docs/evidence/2026-09-11/local-campaign/report.md).
|
|
187
|
-
|
|
188
|
-
- [x] Connect verification, displayed acceptance, cancellation, budgets and recovery to the
|
|
189
|
-
records that establish them. Use standard DSSE signing bytes and literal replacement text.
|
|
190
|
-
- [x] Build the campaign machinery: separate case author, checker and solver models; admission
|
|
191
|
-
controls before grading; frozen schedules; actual baseline dispatch; every failed launch
|
|
192
|
-
retained; raw evidence that can be checked from the checkout.
|
|
193
|
-
- [x] Run the available Docker security and cleanup matrix. Fourteen declared observations
|
|
194
|
-
passed, with working attack controls and a separate check that ordinary work still runs.
|
|
195
|
-
Repair after abrupt harness death was exercised too.
|
|
196
|
-
- [ ] A false-green interval that supports a population claim. The historical 0 in 15 has a
|
|
197
|
-
20.4% upper bound. The new synthetic pilot admits one evaluation case and cannot narrow
|
|
198
|
-
that bound for real work. Freeze an independent population and a sufficient sample first.
|
|
199
|
-
- [ ] A denominator the tool did not choose. The new admission pass checks references and
|
|
200
|
-
predetermined counterexamples, but model authorship alone does not establish independence
|
|
201
|
-
or complete requirements. Independent admission and review are still needed.
|
|
202
|
-
- [ ] An adversarial verification corpus that covers omitted requirements. Separate local
|
|
203
|
-
models supplied fresh checks and attacks. Mutation of added lines still cannot establish
|
|
204
|
-
that a patch implemented something it left out; the report keeps those outcomes visible.
|
|
205
|
-
- [ ] Task success non-inferior to the strongest alternative. The two local baseline arms now
|
|
206
|
-
execute, with matched tasks and budgets. This pilot is too small to establish which tool
|
|
207
|
-
is strongest or to support a non-inferiority claim.
|
|
208
|
-
- [ ] Security evidence for every supported backend. Docker was measured here; Podman and
|
|
209
|
-
nerdctl were unavailable. Independent attacks and those runtime matrices remain open.
|
|
210
|
-
- [ ] No surviving daemons across the supported runtime boundaries. Docker cleanup passed the
|
|
211
|
-
declared lifecycle cases. Restricted host execution still cannot own a descendant that
|
|
212
|
-
leaves its process group; abrupt harness death requires supervision or later repair.
|
|
213
|
-
- [ ] A new user productive in under ten minutes. The fixture and observer procedure are ready.
|
|
214
|
-
No new users were observed, so setup checks cannot close this item.
|
|
215
|
-
|
|
216
|
-
Each broader claim stays open until its own evidence meets the bar in
|
|
217
|
-
[docs/beta-gates.md](docs/beta-gates.md).
|
|
218
|
-
|
|
219
|
-
<p align="right">(<a href="#readme-top">back to top</a>)</p>
|
|
78
|
+
The Action fetches the pull request's head and base by commit id into a checkout it owns, runs
|
|
79
|
+
the project's checks in a network-disabled container, signs the verdict as a GitHub artifact
|
|
80
|
+
attestation, and posts one comment bound to the head that says what was measured and what was
|
|
81
|
+
not. A route for forks and Dependabot is [documented](docs/examples/swarm-verification-forks.yml);
|
|
82
|
+
what has been exercised on a real fork is recorded in
|
|
83
|
+
[the completion index](docs/verifier-first/README.md). Inputs, outputs and how to verify a
|
|
84
|
+
signed verdict from outside the run are in [the broad-use guide](docs/broad-use.md#github-action).
|
|
85
|
+
|
|
86
|
+
## What it says, and what it does not
|
|
87
|
+
|
|
88
|
+
`regression: pass` means no check failed because of the change. It does not mean every check
|
|
89
|
+
passed: a failure the base commit already had, the same way and in the same tests, is shown as
|
|
90
|
+
inherited and does not count against the change, and the report names those failing tests. It
|
|
91
|
+
does not mean the work was done either.
|
|
92
|
+
|
|
93
|
+
A requirement contract (`swarm-verify ci --goal-contract`) defines what the work must do, and
|
|
94
|
+
the contract's checks are the evidence for each requirement. Neither the contract nor a
|
|
95
|
+
signature proves the code is semantically correct. `--challenges report` asks whether each
|
|
96
|
+
requirement's check could have caught wrong work (does it reject the tree before the change,
|
|
97
|
+
mechanical mutations of the change, a fixture sealed as a violation) and reports gaps;
|
|
98
|
+
`--challenges required` refuses on a gap; `off` asks nothing.
|
|
99
|
+
|
|
100
|
+
Every run exports a bundle carrying its own dependency-free verifier. Integrity, signer
|
|
101
|
+
identity, execution trust, regression, task acceptance and challenge coverage are reported as
|
|
102
|
+
separate answers, and `unmeasured` is one of them.
|
|
103
|
+
|
|
104
|
+
## Where to go next
|
|
105
|
+
|
|
106
|
+
| You want to | Read |
|
|
107
|
+
| --- | --- |
|
|
108
|
+
| verify a patch, branch or pull request from any author, with a contract or without | [docs/verify-only.md](docs/verify-only.md), [docs/broad-use.md](docs/broad-use.md) |
|
|
109
|
+
| check what a bundle establishes, and who signed it | [docs/verify-only.md](docs/verify-only.md#swarm-verify-a-bundle-and-who-signed-it) |
|
|
110
|
+
| route an agent's test command through the ledger, from Claude Code, an MCP client or a git hook | [docs/integrations.md](docs/integrations.md) |
|
|
111
|
+
| every command, flag and exit code | [docs/cli.md](docs/cli.md) |
|
|
112
|
+
| every public claim and the artifact behind it, and what may not be said | [docs/claims.md](docs/claims.md) |
|
|
113
|
+
| the coding agent this verifier was built for, an advanced beta mode | [docs/agent.md](docs/agent.md) |
|
|
114
|
+
| the verifier-first campaign, its baseline, evidence and open items | [docs/verifier-first/README.md](docs/verifier-first/README.md) |
|
|
115
|
+
|
|
116
|
+
The full documentation index is [docs/README.md](docs/README.md).
|
|
220
117
|
|
|
221
118
|
## Contributing
|
|
222
119
|
|
|
@@ -231,17 +128,4 @@ does not establish.
|
|
|
231
128
|
5. Push (`git push origin feature/amazing-feature`)
|
|
232
129
|
6. Open a pull request
|
|
233
130
|
|
|
234
|
-
New dependencies need a one-line justification; the standard library is preferred.
|
|
235
|
-
[docs/build-guide.md](docs/build-guide.md) is worth reading before structural work.
|
|
236
|
-
|
|
237
|
-
## License
|
|
238
|
-
|
|
239
|
-
Distributed under the ISC License. See [LICENSE](LICENSE).
|
|
240
|
-
|
|
241
|
-
## Contact
|
|
242
|
-
|
|
243
|
-
Brad Kinnard, [@KChackerman](https://x.com/KChackerman), bradkinnard@proton.me
|
|
244
|
-
|
|
245
|
-
Project link: [github.com/moonrunnerkc/swarm-orchestrator](https://github.com/moonrunnerkc/swarm-orchestrator)
|
|
246
|
-
|
|
247
131
|
<p align="right">(<a href="#readme-top">back to top</a>)</p>
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { copyFileSync, lstatSync, mkdirSync, readdirSync, readFileSync, writeFileSync, } from "node:fs";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
const byteLimit = 32_000_000;
|
|
5
|
+
const fileByteLimit = 8_000_000;
|
|
6
|
+
const fileLimit = 4096;
|
|
7
|
+
const depthLimit = 8;
|
|
8
|
+
/** Copy the named entries of `directory` under `directory/retained`, within the bounds. */
|
|
9
|
+
export function retainActionArtifacts(directory, names = [
|
|
10
|
+
"bundle",
|
|
11
|
+
"report.json",
|
|
12
|
+
"summary.md",
|
|
13
|
+
"verdict.json",
|
|
14
|
+
"attestation",
|
|
15
|
+
"diagnostic.txt",
|
|
16
|
+
]) {
|
|
17
|
+
const destination = join(directory, "retained");
|
|
18
|
+
mkdirSync(destination, { mode: 0o700, recursive: true });
|
|
19
|
+
const inventory = [];
|
|
20
|
+
let remaining = byteLimit;
|
|
21
|
+
let complete = true;
|
|
22
|
+
const visit = (path, relative, depth) => {
|
|
23
|
+
if (depth > depthLimit || inventory.length >= fileLimit) {
|
|
24
|
+
complete = false;
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
const stat = lstatSync(path);
|
|
28
|
+
if (stat.isDirectory()) {
|
|
29
|
+
mkdirSync(join(destination, relative), { recursive: true, mode: 0o700 });
|
|
30
|
+
for (const name of readdirSync(path))
|
|
31
|
+
visit(join(path, name), join(relative, name), depth + 1);
|
|
32
|
+
}
|
|
33
|
+
else if (stat.isFile() && stat.size <= fileByteLimit && stat.size <= remaining) {
|
|
34
|
+
const bytes = readFileSync(path);
|
|
35
|
+
const digest = `sha256:${createHash("sha256").update(bytes).digest("hex")}`;
|
|
36
|
+
copyFileSync(path, join(destination, relative));
|
|
37
|
+
remaining -= bytes.length;
|
|
38
|
+
inventory.push({ path: relative, bytes: bytes.length, digest, retained: true });
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
complete = false;
|
|
42
|
+
inventory.push({
|
|
43
|
+
path: relative,
|
|
44
|
+
bytes: stat.size,
|
|
45
|
+
retained: false,
|
|
46
|
+
reason: "retention bound or unsupported file type",
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
for (const name of names) {
|
|
51
|
+
try {
|
|
52
|
+
lstatSync(join(directory, name));
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
try {
|
|
58
|
+
visit(join(directory, name), name, 0);
|
|
59
|
+
}
|
|
60
|
+
catch (cause) {
|
|
61
|
+
complete = false;
|
|
62
|
+
inventory.push({
|
|
63
|
+
path: name,
|
|
64
|
+
retained: false,
|
|
65
|
+
reason: cause.code ?? "copy failed",
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
writeFileSync(join(destination, "retention.json"), JSON.stringify({ version: 1, complete, byteLimit, fileLimit, inventory }, null, 2), { mode: 0o600 });
|
|
70
|
+
return { destination, complete, inventory };
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=artifacts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"artifacts.js","sourceRoot":"","sources":["../../src/action/artifacts.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EACL,YAAY,EACZ,SAAS,EACT,SAAS,EACT,WAAW,EACX,YAAY,EACZ,aAAa,GACd,MAAM,SAAS,CAAC;AACjB,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAsBjC,MAAM,SAAS,GAAG,UAAU,CAAC;AAC7B,MAAM,aAAa,GAAG,SAAS,CAAC;AAChC,MAAM,SAAS,GAAG,IAAI,CAAC;AACvB,MAAM,UAAU,GAAG,CAAC,CAAC;AAErB,2FAA2F;AAC3F,MAAM,UAAU,qBAAqB,CACnC,SAAiB,EACjB,KAAK,GAAsB;IACzB,QAAQ;IACR,aAAa;IACb,YAAY;IACZ,cAAc;IACd,aAAa;IACb,gBAAgB;CACjB;IAED,MAAM,WAAW,GAAG,IAAI,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC;IAChD,SAAS,CAAC,WAAW,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACzD,MAAM,SAAS,GAAyB,EAAE,CAAC;IAC3C,IAAI,SAAS,GAAG,SAAS,CAAC;IAC1B,IAAI,QAAQ,GAAG,IAAI,CAAC;IACpB,MAAM,KAAK,GAAG,CAAC,IAAY,EAAE,QAAgB,EAAE,KAAa,EAAQ,EAAE;QACpE,IAAI,KAAK,GAAG,UAAU,IAAI,SAAS,CAAC,MAAM,IAAI,SAAS,EAAE,CAAC;YACxD,QAAQ,GAAG,KAAK,CAAC;YACjB,OAAO;QACT,CAAC;QACD,MAAM,IAAI,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;QAC7B,IAAI,IAAI,CAAC,WAAW,EAAE,EAAE,CAAC;YACvB,SAAS,CAAC,IAAI,CAAC,WAAW,EAAE,QAAQ,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;YACzE,KAAK,MAAM,IAAI,IAAI,WAAW,CAAC,IAAI,CAAC;gBAClC,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,EAAE,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC;QAC7D,CAAC;aAAM,IAAI,IAAI,CAAC,MAAM,EAAE,IAAI,IAAI,CAAC,IAAI,IAAI,aAAa,IAAI,IAAI,CAAC,IAAI,IAAI,SAAS,EAAE,CAAC;YACjF,MAAM,KAAK,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;YACjC,MAAM,MAAM,GAAG,UAAU,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;YAC5E,YAAY,CAAC,IAAI,EAAE,IAAI,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC,CAAC;YAChD,SAAS,IAAI,KAAK,CAAC,MAAM,CAAC;YAC1B,SAAS,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,KAAK,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;QAClF,CAAC;aAAM,CAAC;YACN,QAAQ,GAAG,KAAK,CAAC;YACjB,SAAS,CAAC,IAAI,CAAC;gBACb,IAAI,EAAE,QAAQ;gBACd,KAAK,EAAE,IAAI,CAAC,IAAI;gBAChB,QAAQ,EAAE,KAAK;gBACf,MAAM,EAAE,0CAA0C;aACnD,CAAC,CAAC;QACL,CAAC;IACH,CAAC,CAAC;IACF,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,CAAC;YACH,SAAS,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC,CAAC;QACnC,CAAC;QAAC,MAAM,CAAC;YACP,SAAS;QACX,CAAC;QACD,IAAI,CAAC;YACH,KAAK,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;QACxC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,QAAQ,GAAG,KAAK,CAAC;YACjB,SAAS,CAAC,IAAI,CAAC;gBACb,IAAI,EAAE,IAAI;gBACV,QAAQ,EAAE,KAAK;gBACf,MAAM,EAAG,KAA2B,CAAC,IAAI,IAAI,aAAa;aAC3D,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IACD,aAAa,CACX,IAAI,CAAC,WAAW,EAAE,gBAAgB,CAAC,EACnC,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,QAAQ,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,EAClF,EAAE,IAAI,EAAE,KAAK,EAAE,CAChB,CAAC;IACF,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC;AAC9C,CAAC"}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import { challengeLines } from "../evidence/challenge-lines.js";
|
|
2
|
+
import { reviewerText } from "../evidence/ci-summary.js";
|
|
3
|
+
/**
|
|
4
|
+
* The pull request comment: one per pull request, updated in place, bound to the head it
|
|
5
|
+
* describes. Everything a candidate could have written (check names, findings, paths) arrives
|
|
6
|
+
* through the reviewer text escape, which also neutralises mentions, so a candidate cannot
|
|
7
|
+
* page a maintainer or link out of the comment. The whole body is bounded below GitHub's limit.
|
|
8
|
+
*/
|
|
9
|
+
export const commentMarker = "<!-- swarm-verify -->";
|
|
10
|
+
/** GitHub refuses a comment body over 65536 characters; stay well under with a named cut. */
|
|
11
|
+
const bodyLimit = 60_000;
|
|
12
|
+
function marker(pullRequest, head) {
|
|
13
|
+
return `${commentMarker}\n<!-- swarm-verify pr=${pullRequest} head=${head} -->`;
|
|
14
|
+
}
|
|
15
|
+
/** Text a candidate could have shaped, escaped and with mentions defused. */
|
|
16
|
+
function untrusted(value) {
|
|
17
|
+
return reviewerText(value).replaceAll("@", "@");
|
|
18
|
+
}
|
|
19
|
+
function resultLine(verdict) {
|
|
20
|
+
switch (verdict.decision.result) {
|
|
21
|
+
case "verified":
|
|
22
|
+
return "**Verified**: the recorded checks passed and every declared requirement was accepted.";
|
|
23
|
+
case "regression-only":
|
|
24
|
+
return "**Regression-only pass**: nothing this patch changed broke a check; a failure the base already had, if any, is named below as inherited. No requirement contract was supplied, so whether the work does what was asked is unmeasured.";
|
|
25
|
+
case "not-verified":
|
|
26
|
+
return "**Not verified**: a check failed or a requirement was rejected.";
|
|
27
|
+
case "incomplete":
|
|
28
|
+
return "**Incomplete**: the assessment could not measure what it needed to.";
|
|
29
|
+
case "head-changed":
|
|
30
|
+
return "**Not current**: the pull request moved before this run finished; this result describes an earlier head.";
|
|
31
|
+
case "refused":
|
|
32
|
+
return "**Refused**: the source could not be verified as identified.";
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
/** Render the comment body from the signed verdict and the assessment summary. */
|
|
36
|
+
export function renderComment(options) {
|
|
37
|
+
const { verdict } = options;
|
|
38
|
+
const scope = verdict.decision.task === "accepted" || verdict.decision.task === "rejected"
|
|
39
|
+
? "requirement checks from a trusted contract were run"
|
|
40
|
+
: "no requirement contract was supplied, so task correctness is unmeasured";
|
|
41
|
+
const lines = [
|
|
42
|
+
marker(verdict.pullRequest ?? 0, verdict.eventHead ?? verdict.head),
|
|
43
|
+
"## swarm-verify",
|
|
44
|
+
"",
|
|
45
|
+
resultLine(verdict),
|
|
46
|
+
"",
|
|
47
|
+
`Source: ${verdict.target === "merge" ? "test merge" : "head"} \`${verdict.head}\` against base \`${verdict.base}\`` +
|
|
48
|
+
`${verdict.tree === null ? "" : `, tree \`${verdict.tree}\``}.`,
|
|
49
|
+
`Regression: ${verdict.decision.regression ?? "not run"}. Task: ${verdict.decision.task ?? "unjudged"} (${scope}).`,
|
|
50
|
+
`Execution: ${untrusted(verdict.execution.executionTrust)} under ${verdict.policy.isolation}${verdict.policy.image === null ? "" : ` \`${untrusted(verdict.policy.image)}\``}.`,
|
|
51
|
+
verdict.decision.unmeasured.length === 0
|
|
52
|
+
? "Unmeasured: nothing the policy asked for."
|
|
53
|
+
: `Unmeasured: ${verdict.decision.unmeasured.map(untrusted).join(", ")}.`,
|
|
54
|
+
verdict.decision.reason === null ? "" : `Reason: ${untrusted(verdict.decision.reason)}.`,
|
|
55
|
+
...(verdict.decision.challenges === null
|
|
56
|
+
? []
|
|
57
|
+
: challengeLines(verdict.decision.challenges).map((line, index) => index === 0
|
|
58
|
+
? `${untrusted(line.charAt(0).toUpperCase() + line.slice(1))}.`
|
|
59
|
+
: `- ${untrusted(line)}`)),
|
|
60
|
+
"",
|
|
61
|
+
`Signature: ${options.attestation.status === "signed"
|
|
62
|
+
? `signed by this workflow ([attestation](${options.attestation.url ?? options.runUrl})); verify with \`gh attestation verify verdict.json --repo ${verdict.repository} --predicate-type https://github.com/moonrunnerkc/swarm-verify/verdict/v1\``
|
|
63
|
+
: options.attestation.status === "skipped"
|
|
64
|
+
? `not requested (${untrusted(options.attestation.detail)})`
|
|
65
|
+
: `unavailable: ${untrusted(options.attestation.detail)}`}.`,
|
|
66
|
+
`Evidence: artifact \`${options.artifactName}\` on [this run](${options.runUrl}) holds the JSON report, the signed bundle with its own verifier, and the verdict document (${verdict.evidence.reportDigest ?? "no report"}).`,
|
|
67
|
+
`Verifier: swarm-verify ${untrusted(verdict.verifier.version)}, run ${verdict.execution.runId} attempt ${verdict.execution.runAttempt}.`,
|
|
68
|
+
"",
|
|
69
|
+
"<details><summary>Assessment</summary>",
|
|
70
|
+
"",
|
|
71
|
+
options.summary === null
|
|
72
|
+
? "_No assessment summary was produced._"
|
|
73
|
+
: options.summary.replaceAll("@", "@"),
|
|
74
|
+
"",
|
|
75
|
+
"</details>",
|
|
76
|
+
"",
|
|
77
|
+
"_A regression pass says nothing broke. Only a requirement contract can say the work was done._",
|
|
78
|
+
].filter((line) => line !== null);
|
|
79
|
+
const body = lines.join("\n");
|
|
80
|
+
return body.length <= bodyLimit
|
|
81
|
+
? body
|
|
82
|
+
: `${body.slice(0, bodyLimit - 80)}\n\n_Comment truncated; the full assessment is in the run artifact._`;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Create or update the one comment, only while the pull request still points at the head the
|
|
86
|
+
* verdict describes. A delayed run for an older head finds a newer head and posts nothing.
|
|
87
|
+
*/
|
|
88
|
+
export async function publishComment(options) {
|
|
89
|
+
if (options.token === null)
|
|
90
|
+
return { status: "unavailable", reason: "no token was supplied to publish with" };
|
|
91
|
+
const doFetch = options.fetch ?? globalThis.fetch;
|
|
92
|
+
const headers = {
|
|
93
|
+
Authorization: `Bearer ${options.token}`,
|
|
94
|
+
Accept: "application/vnd.github+json",
|
|
95
|
+
"X-GitHub-Api-Version": "2022-11-28",
|
|
96
|
+
"User-Agent": "swarm-verify",
|
|
97
|
+
};
|
|
98
|
+
const base = `${options.apiUrl}/repos/${options.repository}`;
|
|
99
|
+
const read = async (url) => {
|
|
100
|
+
const response = await doFetch(url, { method: "GET", headers });
|
|
101
|
+
if (response.status !== 200)
|
|
102
|
+
throw new Error(`GET ${url.replace(options.apiUrl, "")} answered ${response.status}`);
|
|
103
|
+
return response.json();
|
|
104
|
+
};
|
|
105
|
+
try {
|
|
106
|
+
const pull = (await read(`${base}/pulls/${options.pullRequest}`));
|
|
107
|
+
const currentHead = pull.head?.sha ?? "";
|
|
108
|
+
if (currentHead !== options.head)
|
|
109
|
+
return { status: "stale-head", currentHead };
|
|
110
|
+
let existing = null;
|
|
111
|
+
for (let page = 1; page <= 10 && existing === null; page += 1) {
|
|
112
|
+
const comments = (await read(`${base}/issues/${options.pullRequest}/comments?per_page=100&page=${page}`));
|
|
113
|
+
existing = comments.find((one) => (one.body ?? "").startsWith(commentMarker)) ?? null;
|
|
114
|
+
if (comments.length < 100)
|
|
115
|
+
break;
|
|
116
|
+
}
|
|
117
|
+
const response = await doFetch(existing === null
|
|
118
|
+
? `${base}/issues/${options.pullRequest}/comments`
|
|
119
|
+
: `${base}/issues/comments/${existing.id}`, {
|
|
120
|
+
method: existing === null ? "POST" : "PATCH",
|
|
121
|
+
headers: { ...headers, "Content-Type": "application/json" },
|
|
122
|
+
body: JSON.stringify({ body: options.body }),
|
|
123
|
+
});
|
|
124
|
+
if (response.status !== 200 && response.status !== 201)
|
|
125
|
+
return {
|
|
126
|
+
status: "unavailable",
|
|
127
|
+
reason: `${existing === null ? "POST" : "PATCH"} answered ${response.status}: ${(await response.text()).slice(0, 300)}`,
|
|
128
|
+
};
|
|
129
|
+
const written = (await response.json());
|
|
130
|
+
return { status: existing === null ? "created" : "updated", url: written.html_url ?? "" };
|
|
131
|
+
}
|
|
132
|
+
catch (cause) {
|
|
133
|
+
return {
|
|
134
|
+
status: "unavailable",
|
|
135
|
+
reason: cause instanceof Error ? cause.message : String(cause),
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
//# sourceMappingURL=comment.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"comment.js","sourceRoot":"","sources":["../../src/action/comment.ts"],"names":[],"mappings":"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"}
|