borgmcp-shared 0.4.2 → 0.5.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/README.md +12 -10
- package/dist/conformance/adapter.d.ts.map +1 -1
- package/dist/conformance/adapter.js +6 -5
- package/dist/conformance/adapter.js.map +1 -1
- package/dist/conformance/index.d.ts +6 -0
- package/dist/conformance/index.d.ts.map +1 -1
- package/dist/conformance/index.js +23 -0
- package/dist/conformance/index.js.map +1 -1
- package/dist/protocol/contract.d.ts +4 -2
- package/dist/protocol/contract.d.ts.map +1 -1
- package/dist/protocol/contract.js +5 -3
- package/dist/protocol/contract.js.map +1 -1
- package/dist/protocol/errors.d.ts.map +1 -1
- package/dist/protocol/errors.js.map +1 -1
- package/dist/protocol/version.d.ts +1 -1
- package/dist/protocol/version.js +1 -1
- package/dist/templates.d.ts +3 -2
- package/dist/templates.d.ts.map +1 -1
- package/dist/templates.js +41 -34
- package/dist/templates.js.map +1 -1
- package/docs/compatibility.md +6 -0
- package/docs/enrollment.md +6 -5
- package/docs/releasing.md +123 -306
- package/package.json +1 -1
- package/src/conformance/adapter.ts +6 -5
- package/src/conformance/index.ts +33 -1
- package/src/protocol/contract.ts +11 -11
- package/src/protocol/errors.ts +3 -2
- package/src/protocol/version.ts +2 -2
- package/src/templates.ts +47 -39
package/docs/releasing.md
CHANGED
|
@@ -1,313 +1,130 @@
|
|
|
1
1
|
# Publishing `borgmcp-shared`
|
|
2
2
|
|
|
3
|
-
This repository publishes immutable public releases
|
|
4
|
-
Actions
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
`actions/setup-node`, `actions/upload-artifact`, and
|
|
58
|
-
`actions/download-artifact`, each pinned in source. Keep workflow tokens
|
|
59
|
-
read-only and prohibit them from approving pull requests.
|
|
60
|
-
8. Enable GitHub private vulnerability reporting, secret scanning, push
|
|
61
|
-
protection, and Dependabot security updates unconditionally. Enable secret
|
|
62
|
-
validity checks and non-provider pattern detection whenever the organization
|
|
63
|
-
plan licenses them. GitHub requires a paid plan with GitHub Secret Protection
|
|
64
|
-
for [validity checks](https://docs.github.com/en/code-security/how-tos/secure-your-secrets/customize-leak-detection/enable-validity-checks)
|
|
65
|
-
and [non-provider patterns](https://docs.github.com/en/code-security/secret-scanning/using-advanced-secret-scanning-and-push-protection-features/non-provider-patterns/enabling-secret-scanning-for-non-provider-patterns).
|
|
66
|
-
The configuration guard accepts those two controls as disabled only while the
|
|
67
|
-
live organization plan is exactly `free`; a plan change makes them mandatory.
|
|
68
|
-
`SECURITY.md` directs reporters to the private reporting path, so disabled
|
|
69
|
-
reporting is always a release-blocking documentation failure.
|
|
70
|
-
|
|
71
|
-
The environment approval is the final technical control. It appears only on the
|
|
72
|
-
`publish` job, after `validate` has verified the SR approval tuple. Approval must
|
|
73
|
-
remain pending while Security reviews the artifact produced by the `verify` job.
|
|
74
|
-
GitHub's ephemeral workflow token cannot read every repository-administration
|
|
75
|
-
setting checked by `scripts/verify-release-configuration.mjs`. An authorized
|
|
76
|
-
operator must run the guard with an administration-capable token before creating
|
|
77
|
-
the tag and again immediately before approving the environment:
|
|
3
|
+
This repository publishes immutable public releases through one protected workflow job
|
|
4
|
+
in GitHub Actions. The active `minimal-package-release-assurance` decision replaces the
|
|
5
|
+
former cross-run artifact approval protocol. This runbook describes the current
|
|
6
|
+
operator procedure; it does not authorize a tag or publication.
|
|
7
|
+
|
|
8
|
+
## Assurance Boundary
|
|
9
|
+
|
|
10
|
+
The release lane has one build, test, package, and publication authority:
|
|
11
|
+
`.github/workflows/publish.yml` on an annotated `v*.*.*` tag. The job:
|
|
12
|
+
|
|
13
|
+
1. verifies the public repository context, exact package version, annotated tag,
|
|
14
|
+
tag commit, and ancestry on protected `main`;
|
|
15
|
+
2. installs locked dependencies without lifecycle scripts and runs dependency
|
|
16
|
+
audit, type checks, the full test suite, one clean build, and generated-output
|
|
17
|
+
drift detection;
|
|
18
|
+
3. creates one local tarball, enforces the packed-artifact policy, and installs
|
|
19
|
+
that tarball into a clean consumer that imports every public export;
|
|
20
|
+
4. rejects an existing immutable version or a package not owned solely by the
|
|
21
|
+
configured npm owner before any registry mutation;
|
|
22
|
+
5. publishes that exact local tarball through npm Trusted Publishing with
|
|
23
|
+
provenance; and
|
|
24
|
+
6. uses bounded registry-propagation retries to compare the published
|
|
25
|
+
`dist.integrity` with the tarball, then installs the exact registry version
|
|
26
|
+
with scripts disabled and runs `npm audit signatures`.
|
|
27
|
+
|
|
28
|
+
npm and GitHub verify the registry signature and publish attestation. The
|
|
29
|
+
repository does not reconstruct DSSE or SLSA statements, transfer approval
|
|
30
|
+
tuples between runs, rebuild in a second job, or place checksum, SBOM, and report
|
|
31
|
+
bundles on the critical publication path. SBOM portability remains covered by
|
|
32
|
+
CI and the repository's dedicated deterministic SBOM tests.
|
|
33
|
+
|
|
34
|
+
## Permanent Configuration
|
|
35
|
+
|
|
36
|
+
Keep these controls in place:
|
|
37
|
+
|
|
38
|
+
1. `publish.yml` is the only npm Trusted Publisher workflow for organization
|
|
39
|
+
`Byte-Ventures`, repository `borg-mcp-shared`, and environment `npm-publish`.
|
|
40
|
+
2. The `npm-publish` environment requires the authorized sole operator
|
|
41
|
+
`TheodorStorm`, permits that operator's self-review, prevents administrator
|
|
42
|
+
bypass, and allows only protected `v*.*.*` tags.
|
|
43
|
+
3. `NPM_EXPECTED_OWNER` is `byteventures`. It comes from the live npm package
|
|
44
|
+
maintainer record, not package metadata.
|
|
45
|
+
4. No `NPM_TOKEN`, `NODE_AUTH_TOKEN`, or committed `.npmrc` participates in an
|
|
46
|
+
owned-package release. Authentication is the job's short-lived OIDC exchange.
|
|
47
|
+
5. The publish job uses a GitHub-hosted runner with only `contents: read` and
|
|
48
|
+
`id-token: write`. Actions are GitHub-owned and pinned to full commit SHAs.
|
|
49
|
+
6. Protected `main`, the release-tag ruleset, private vulnerability reporting,
|
|
50
|
+
secret scanning, push protection, and dependency security updates remain
|
|
51
|
+
enabled as checked by `scripts/verify-release-configuration.mjs`. Secret
|
|
52
|
+
scanning validity checks and non-provider patterns remain mandatory whenever
|
|
53
|
+
the organization plan licenses them.
|
|
54
|
+
|
|
55
|
+
Before creating a tag and again before approving the environment, an authorized
|
|
56
|
+
operator runs:
|
|
78
57
|
|
|
79
58
|
```sh
|
|
80
59
|
GITHUB_TOKEN="$(gh auth token)" node scripts/verify-release-configuration.mjs
|
|
81
60
|
```
|
|
82
61
|
|
|
83
|
-
The token
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
the
|
|
97
|
-
`
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
and
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
That recovery completed successfully: the registry tarball is byte-identical to
|
|
153
|
-
the audited artifact, its sole maintainer is `byteventures`, the signed in-toto
|
|
154
|
-
SLSA provenance binds the protected workflow/tag/commit/run, and npm verified one
|
|
155
|
-
registry signature plus one publish attestation. Security approved the recovery
|
|
156
|
-
evidence. Complete the bootstrap credential and Trusted Publisher cleanup below
|
|
157
|
-
before migrating consumers.
|
|
158
|
-
|
|
159
|
-
The eventual first publication will use one temporary credential while still
|
|
160
|
-
generating provenance from GitHub Actions.
|
|
161
|
-
|
|
162
|
-
Before creating the tag, the release operator must verify all of the following:
|
|
163
|
-
|
|
164
|
-
- The npm account is the account that owns `borgmcp`, uses authentication-and-
|
|
165
|
-
writes 2FA, and has tested, protected recovery methods.
|
|
166
|
-
- `borgmcp-shared` is still unclaimed. An `E404` is expected. Any package or
|
|
167
|
-
ownership result that differs from the reviewed state is a stop condition.
|
|
168
|
-
- Code Review, load-bearing Security Review, and Release Quality approved the
|
|
169
|
-
exact commit on `main`.
|
|
170
|
-
- The Queen explicitly authorized generating the final release artifact. This
|
|
171
|
-
authorization does not by itself approve the later environment deployment.
|
|
172
|
-
|
|
173
|
-
Create a short-lived, least-privilege npm publish token under the verified owner
|
|
174
|
-
account. Store it as the `NPM_TOKEN` secret in the `npm-publish` environment;
|
|
175
|
-
never place it in repository variables, workflow files, shell history,
|
|
176
|
-
`package.json`, a committed `.npmrc`, or an issue. Set the protected environment
|
|
177
|
-
variable `ALLOW_UNCLAIMED_FIRST_PUBLISH` to `true` only for this bootstrap.
|
|
178
|
-
|
|
179
|
-
The `0.2.2` package, lockfile, runbook, and version assertions must pass fresh CR,
|
|
180
|
-
Security, and Release Quality gates and merge to protected `main` before the
|
|
181
|
-
Coordinator creates its matching annotated tag under
|
|
182
|
-
`borgmcp-shared-first-publish-autonomy`. The tag starts the workflow but does not
|
|
183
|
-
immediately publish. The unprivileged `verify` job performs the following gates
|
|
184
|
-
first:
|
|
185
|
-
|
|
186
|
-
- verifies the public repository, annotated tag, exact package version, and
|
|
187
|
-
ancestry on `main`;
|
|
188
|
-
- installs the lockfile without lifecycle scripts and runs audit, type checks,
|
|
189
|
-
all tests, a clean build, and the tracked-`dist` drift check;
|
|
190
|
-
- creates one tarball with lifecycle scripts disabled;
|
|
191
|
-
- enforces the explicit public file allowlist, legal files, dependency and
|
|
192
|
-
lifecycle policy, size limits, and resolvable source maps;
|
|
193
|
-
- exercises npm's publish metadata in dry-run mode; and
|
|
194
|
-
- installs the exact tarball with scripts disabled in a clean consumer, verifies
|
|
195
|
-
its production tree, and imports every reviewed public export; and
|
|
196
|
-
- uploads the tarball, verifier report, SHA-512 checksum, SBOM, and
|
|
197
|
-
`RUN_EVIDENCE` for seven days.
|
|
198
|
-
|
|
199
|
-
Security must download and audit that exact workflow artifact. After Security
|
|
200
|
-
approves the tarball, Release Quality confirms the operator procedure, and the
|
|
201
|
-
Queen explicitly authorizes the public flip, the Coordinator writes the SR
|
|
202
|
-
approval tuple (`ARTIFACT_SR_SHA512`, `ARTIFACT_SR_RUN_ID`,
|
|
203
|
-
`ARTIFACT_SR_RUN_ATTEMPT`) to environment variables and dispatches the
|
|
204
|
-
`publish.yml` workflow with the tag. The `validate` job runs first (outside
|
|
205
|
-
the `npm-publish` environment): it re-verifies the source, queries the source
|
|
206
|
-
run's workflow path, tag, conclusion, and attempt via the GitHub API, downloads
|
|
207
|
-
the artifact, binds the SR tuple to the exact tarball, and confirms run identity.
|
|
208
|
-
Only after `validate` succeeds does the `publish` job run, which surfaces the
|
|
209
|
-
`npm-publish` environment approval dialog. The `publish` job re-downloads and
|
|
210
|
-
checksum-verifies the same artifact, re-binds the SR tuple, repeats the artifact
|
|
211
|
-
verifier, checks that `0.2.2` is absent and the name is unclaimed as expected,
|
|
212
|
-
and publishes only the downloaded tarball with `--access public --provenance`.
|
|
213
|
-
|
|
214
|
-
Immediately after a successful first publish:
|
|
215
|
-
|
|
216
|
-
1. Confirm the workflow's registry-integrity, owner, and SLSA provenance checks
|
|
217
|
-
passed before changing any consumer dependency.
|
|
218
|
-
2. Configure npm's trusted publisher for organization `Byte-Ventures`, repository
|
|
219
|
-
`borg-mcp-shared`, workflow filename `publish.yml`, environment
|
|
220
|
-
`npm-publish`, and the `npm publish` action.
|
|
221
|
-
3. Remove the `NPM_TOKEN` environment secret, revoke the bootstrap token at npm,
|
|
222
|
-
and set `ALLOW_UNCLAIMED_FIRST_PUBLISH` to `false`.
|
|
223
|
-
4. Configure npm publishing access to require 2FA and disallow traditional
|
|
224
|
-
tokens. Future releases authenticate through short-lived OIDC credentials.
|
|
225
|
-
5. Only then replace consumers' exact Git SHA dependencies with
|
|
226
|
-
`borgmcp-shared@^0.2.0` and commit their registry lockfiles.
|
|
227
|
-
|
|
228
|
-
## Later Releases
|
|
229
|
-
|
|
230
|
-
### 0.4.2 Cross-Platform SBOM Recovery
|
|
231
|
-
|
|
232
|
-
`borgmcp-shared@0.4.0` is the published, immutable clean-slate v2 contract, but
|
|
233
|
-
its registry artifact was built before the public package's local/self-hosted
|
|
234
|
-
topology cleanup. The immutable `v0.4.1` run `29701429995` built the cleaned
|
|
235
|
-
artifact, but independent macOS verification proved that the SBOM verifier used
|
|
236
|
-
the auditor's installed optional-dependency tree instead of a deterministic
|
|
237
|
-
release graph. The `v0.4.1` tag, run, and artifact are failed evidence: never
|
|
238
|
-
publish, move, reuse, rerun, or substitute them.
|
|
239
|
-
|
|
240
|
-
Version `0.4.2` carries the reviewed cleanup with a lockfile-derived SBOM graph
|
|
241
|
-
for the fixed release target `{os: linux, cpu: x64, libc: glibc}`. It does not
|
|
242
|
-
change the protocol tag or runtime behavior. This source now identifies `0.4.2`.
|
|
243
|
-
The reviewed recovery bump does not authorize creating `v0.4.2` or publishing
|
|
244
|
-
the package.
|
|
245
|
-
|
|
246
|
-
Before a separately authorized `v0.4.2` tag is created:
|
|
247
|
-
|
|
248
|
-
1. The exact `0.4.2` source commit must be merged to protected `main` after Code
|
|
249
|
-
Review, Security, and Release Quality approve the package identity, public
|
|
250
|
-
API, generated output, and release documentation.
|
|
251
|
-
2. The package and root lockfile, `SHARED_PACKAGE_VERSION`, packed-artifact and
|
|
252
|
-
SBOM verifiers, generated declarations, and version assertions must all
|
|
253
|
-
identify `0.4.2`. The protocol tag remains unchanged.
|
|
254
|
-
3. The protected workflow must build one exact tarball and pass its full source,
|
|
255
|
-
test, audit, public-export, source-map, install/import, dry-run, lock-derived
|
|
256
|
-
CycloneDX SBOM, integrity, and provenance gates. Security must approve that
|
|
257
|
-
exact workflow artifact.
|
|
258
|
-
4. The `0.4.2` workflow must generate a CycloneDX SBOM, canonicalize npm's
|
|
259
|
-
checkout-derived root display name to the already-verified manifest name,
|
|
260
|
-
and validate every component's exact canonical registry tarball URL, single
|
|
261
|
-
matching CycloneDX distribution reference, purl, and lock SHA-512 plus the
|
|
262
|
-
exact lockfile-derived release-target graph and zero package runtime
|
|
263
|
-
dependencies. The graph starts from root development dependencies, follows
|
|
264
|
-
required dependencies and peers, includes only target-compatible optional
|
|
265
|
-
dependencies, and includes optional peers only when another reachable edge
|
|
266
|
-
installs them. Root manifest and lock selectors must match and permit the
|
|
267
|
-
fixed target. Verification must not inspect the auditor's operating system,
|
|
268
|
-
installed dependency tree, or `node_modules`. The tarball, SBOM, and SBOM
|
|
269
|
-
validation report must be checksummed and uploaded together for Security
|
|
270
|
-
audit.
|
|
271
|
-
5. The tag and publication each require their own explicit authorization. A
|
|
272
|
-
source-version approval, merge, or successful verification run grants neither.
|
|
273
|
-
|
|
274
|
-
After registry publication and independent integrity/provenance verification,
|
|
275
|
-
the first borgmcp client and borgmcp-server releases must pin exact
|
|
276
|
-
`borgmcp-shared@0.4.2` and commit their registry lockfiles. They must not ship a
|
|
277
|
-
Git dependency, a version range that can resolve to the pre-cleanup artifact, or
|
|
278
|
-
a fallback to the incompatible `0.3.0` v1 enrollment response.
|
|
279
|
-
|
|
280
|
-
Later releases follow the same source gates, annotated protected tag, exact
|
|
281
|
-
tarball audit, Coordinator authorization under the ratified shared release
|
|
282
|
-
autonomy, and environment approval. The registry
|
|
283
|
-
preflight requires the package to be owned by `NPM_EXPECTED_OWNER` and rejects
|
|
284
|
-
an existing target version. It also fails if
|
|
285
|
-
`ALLOW_UNCLAIMED_FIRST_PUBLISH` is not `false` or any `NPM_TOKEN` remains;
|
|
286
|
-
npm must exchange the workflow's OIDC identity through the configured trusted
|
|
287
|
-
publisher.
|
|
288
|
-
|
|
289
|
-
## Stop and Recovery Conditions
|
|
290
|
-
|
|
291
|
-
Stop without approving the environment when any of these conditions occurs:
|
|
292
|
-
|
|
293
|
-
- the repository is private, the tag is lightweight or unprotected, the tag
|
|
294
|
-
does not exactly match `v<package version>`, or its commit is not on `main`;
|
|
295
|
-
- the approved commit, tag target, tarball checksum, or audit artifact differs;
|
|
296
|
-
- `GITHUB_RUN_ATTEMPT` is not `1`, or run/attempt evidence is missing;
|
|
297
|
-
- tests, audit, build, tracked output, artifact policy, legal metadata, or dry
|
|
298
|
-
run fails;
|
|
299
|
-
- the npm name, expected owner, account 2FA, recovery methods, credential scope,
|
|
300
|
-
trusted-publisher configuration, or environment protection cannot be verified;
|
|
301
|
-
- the target version already exists, npm returns anything other than the
|
|
302
|
-
expected ownership/availability response, or npm/GitHub is degraded; or
|
|
303
|
-
- final CR, Security, Release Quality, exact-tarball Security approval, or Queen
|
|
304
|
-
authorization is missing.
|
|
305
|
-
|
|
306
|
-
npm versions are immutable. Never retry by overwriting any published version,
|
|
307
|
-
moving a release tag, force-pushing a branch, or publishing from a local rebuild.
|
|
308
|
-
A failed verification before publication requires fixing the source and
|
|
309
|
-
beginning again with a new reviewed version/tag plan. If npm accepted the version
|
|
310
|
-
but integrity or provenance verification failed, block every consumer migration,
|
|
311
|
-
preserve the workflow logs and artifact, and escalate as a release incident. Do not unpublish,
|
|
312
|
-
deprecate, or publish a replacement version without a separately reviewed and
|
|
313
|
-
authorized recovery decision.
|
|
62
|
+
The token must remain in the operator credential store. Never write it to the
|
|
63
|
+
repository, workflow output, artifact, issue, or shell history.
|
|
64
|
+
|
|
65
|
+
## Release Procedure
|
|
66
|
+
|
|
67
|
+
1. Merge the exact version, lockfile, generated output, and release documentation
|
|
68
|
+
to protected `main` after the required exact-SHA Code Review, Security Review,
|
|
69
|
+
and Release Quality gates.
|
|
70
|
+
2. Verify repository controls with the configuration guard above. Confirm the
|
|
71
|
+
target version does not already exist and `borgmcp-shared` is owned solely by
|
|
72
|
+
`byteventures`.
|
|
73
|
+
3. Obtain the separately required exact-commit tag authorization. Create and push
|
|
74
|
+
one annotated `v<package-version>` tag at that protected-main commit.
|
|
75
|
+
4. The tag starts the single publish job and leaves it pending at the protected
|
|
76
|
+
`npm-publish` environment. Do not use workflow rerun controls; every immutable
|
|
77
|
+
tag gets one first attempt.
|
|
78
|
+
5. Obtain the separately required environment approval, then approve that exact
|
|
79
|
+
pending job. Approval does not permit a local rebuild or alternate artifact.
|
|
80
|
+
6. Require every job step to pass, including exact registry integrity and
|
|
81
|
+
`npm audit signatures`, before announcing the version or updating consumers.
|
|
82
|
+
|
|
83
|
+
The workflow publishes only `./release/<tarball>`. It never publishes from the
|
|
84
|
+
repository directory, a package name, a URL, a prior workflow artifact, or a
|
|
85
|
+
locally rebuilt replacement.
|
|
86
|
+
|
|
87
|
+
## Stop And Recovery
|
|
88
|
+
|
|
89
|
+
Stop before publication when source identity, tag ancestry, repository
|
|
90
|
+
visibility, environment protection, expected owner, target-version absence,
|
|
91
|
+
tests, build output, tarball policy, clean-consumer imports, or Trusted Publishing
|
|
92
|
+
configuration cannot be verified.
|
|
93
|
+
|
|
94
|
+
If a first-attempt tag run fails before npm accepts the version, preserve the tag
|
|
95
|
+
and run as immutable evidence. Fix the source and begin a separately reviewed and
|
|
96
|
+
authorized version/tag plan. Never move, reuse, rerun, or force-update the failed
|
|
97
|
+
tag.
|
|
98
|
+
|
|
99
|
+
If npm accepts the version but a bounded integrity or signature check fails, do
|
|
100
|
+
not rerun or republish. Preserve the run, inspect the live registry integrity and
|
|
101
|
+
`npm audit signatures` result, and require an explicit recovery decision before
|
|
102
|
+
consumer adoption. npm versions are immutable; never overwrite, unpublish, or
|
|
103
|
+
silently substitute a replacement.
|
|
104
|
+
|
|
105
|
+
## Immutable Historical Evidence
|
|
106
|
+
|
|
107
|
+
These records remain evidence, not reusable release inputs:
|
|
108
|
+
|
|
109
|
+
- `v0.2.0` run `29353763609` and `v0.2.1` run `29355823822` failed before
|
|
110
|
+
artifact creation or publication.
|
|
111
|
+
- Protected-main proof runs `29356980492` and `29357632667` diagnosed and then
|
|
112
|
+
verified the earlier tag/source and local-file handling. They are not publish
|
|
113
|
+
artifacts.
|
|
114
|
+
- Run `29360398007` published `borgmcp-shared@0.2.2`; its initial ownership
|
|
115
|
+
readback hit registry propagation. Independent integrity, ownership,
|
|
116
|
+
provenance, and npm signature verification completed before consumer adoption.
|
|
117
|
+
- `v0.4.1` run `29701429995` exposed a non-deterministic cross-platform SBOM
|
|
118
|
+
audit path and was never published.
|
|
119
|
+
- `borgmcp-shared@0.4.2` is accepted as published and verified. Its registry
|
|
120
|
+
integrity matches the audited tarball and npm verifies its signature and
|
|
121
|
+
attestation. Publish run `29729515410` must not be rerun; the failed custom
|
|
122
|
+
postpublish check reconstructed the wrong workflow identity and is the reason
|
|
123
|
+
that machinery was removed.
|
|
124
|
+
|
|
125
|
+
`borgmcp-shared@0.4.3` is published and immutable. This source identifies the
|
|
126
|
+
unpublished `0.5.0` protocol v3 release. Its release requires reviewed source and
|
|
127
|
+
explicit publication authorization through one protected publish run, followed by
|
|
128
|
+
postpublish registry integrity, signature, and attestation verification. Consumers
|
|
129
|
+
must update the reviewed shared artifact before adopting the matching server and
|
|
130
|
+
client releases; protocol v2 and v3 peers fail closed at credential-free preflight.
|
package/package.json
CHANGED
|
@@ -1543,9 +1543,9 @@ export async function runAdapterConformance(
|
|
|
1543
1543
|
const expiredCredential = await environment.admin.issueManagedDroneSession(expiredDrone);
|
|
1544
1544
|
await environment.admin.revokeManagedDroneSession(revokedDrone);
|
|
1545
1545
|
await environment.admin.expireManagedDroneSession(expiredDrone);
|
|
1546
|
-
for (const [label, credential] of [
|
|
1547
|
-
['revoked', revokedCredential],
|
|
1548
|
-
['expired', expiredCredential],
|
|
1546
|
+
for (const [label, credential, code] of [
|
|
1547
|
+
['revoked', revokedCredential, ErrorCode.SESSION_REVOKED],
|
|
1548
|
+
['expired', expiredCredential, ErrorCode.AUTH_EXPIRED],
|
|
1549
1549
|
] as const) {
|
|
1550
1550
|
expectError(
|
|
1551
1551
|
await environment.operations.read(
|
|
@@ -1554,14 +1554,15 @@ export async function runAdapterConformance(
|
|
|
1554
1554
|
createProtocolEnvelope(`${label}-seat-probe`, { cursor: null, limit: 1 }),
|
|
1555
1555
|
),
|
|
1556
1556
|
401,
|
|
1557
|
-
|
|
1557
|
+
code,
|
|
1558
1558
|
`${label} seat probe`,
|
|
1559
1559
|
);
|
|
1560
1560
|
}
|
|
1561
1561
|
return {
|
|
1562
1562
|
revoked_status: 401,
|
|
1563
1563
|
expired_status: 401,
|
|
1564
|
-
|
|
1564
|
+
revoked_code: ErrorCode.SESSION_REVOKED,
|
|
1565
|
+
expired_code: ErrorCode.AUTH_EXPIRED,
|
|
1565
1566
|
};
|
|
1566
1567
|
});
|
|
1567
1568
|
|
package/src/conformance/index.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { BroadcastHwm } from '../log-stream-hwm.js';
|
|
2
|
-
import type { EnrollmentExchangeRequest } from '../protocol/contract.js';
|
|
2
|
+
import type { AttachResponse, EnrollmentExchangeRequest } from '../protocol/contract.js';
|
|
3
3
|
|
|
4
4
|
export * from './adapter.js';
|
|
5
5
|
|
|
@@ -205,3 +205,35 @@ export const ENROLLMENT_REDACTION_CONFORMANCE: readonly ConformanceVector<string
|
|
|
205
205
|
expected: `cube_id=${ENROLLMENT_RETRY_KEY}`,
|
|
206
206
|
},
|
|
207
207
|
];
|
|
208
|
+
|
|
209
|
+
export interface AttachSessionConformanceVector {
|
|
210
|
+
name: string;
|
|
211
|
+
response: unknown;
|
|
212
|
+
accepts: boolean;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
const ATTACH_RESPONSE = {
|
|
216
|
+
result: 'created',
|
|
217
|
+
cube: { id: '10000000-0000-4000-8000-000000000001', name: 'test-cube' },
|
|
218
|
+
role: { id: '20000000-0000-4000-8000-000000000001', name: 'Coordinator' },
|
|
219
|
+
drone: { id: '30000000-0000-4000-8000-000000000001', label: 'one-of-one-coordinator' },
|
|
220
|
+
session: { id: '40000000-0000-4000-8000-000000000001' },
|
|
221
|
+
} satisfies AttachResponse;
|
|
222
|
+
|
|
223
|
+
/** Wire vectors for the v3 non-expiring attach-session response. */
|
|
224
|
+
export const ATTACH_SESSION_CONFORMANCE: readonly AttachSessionConformanceVector[] = [
|
|
225
|
+
{ name: 'accepts exact non-expiring session id', response: ATTACH_RESPONSE, accepts: true },
|
|
226
|
+
{
|
|
227
|
+
name: 'rejects retired expires_at field',
|
|
228
|
+
response: {
|
|
229
|
+
...ATTACH_RESPONSE,
|
|
230
|
+
session: { ...ATTACH_RESPONSE.session, expires_at: '2026-07-18T15:00:00.000Z' },
|
|
231
|
+
},
|
|
232
|
+
accepts: false,
|
|
233
|
+
},
|
|
234
|
+
{
|
|
235
|
+
name: 'rejects session fields beyond id',
|
|
236
|
+
response: { ...ATTACH_RESPONSE, session: { ...ATTACH_RESPONSE.session, extra: 'value' } },
|
|
237
|
+
accepts: false,
|
|
238
|
+
},
|
|
239
|
+
];
|
package/src/protocol/contract.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { ErrorCode } from './errors.js';
|
|
|
2
2
|
import { PROTOCOL_VERSION, type ProtocolVersion } from './version.js';
|
|
3
3
|
|
|
4
4
|
export const SHARED_PACKAGE_NAME = 'borgmcp-shared' as const;
|
|
5
|
-
export const SHARED_PACKAGE_VERSION = '0.
|
|
5
|
+
export const SHARED_PACKAGE_VERSION = '0.5.0' as const;
|
|
6
6
|
|
|
7
7
|
export const HEALTH_PATH = '/healthz' as const;
|
|
8
8
|
export const PROTOCOL_INFO_PATH = '/api/protocol' as const;
|
|
@@ -28,6 +28,9 @@ export const PROTOCOL_HTTP_CONTRACT = {
|
|
|
28
28
|
},
|
|
29
29
|
auth_missing_status: 401,
|
|
30
30
|
auth_invalid_status: 401,
|
|
31
|
+
auth_expired_status: 401,
|
|
32
|
+
session_revoked_status: 401,
|
|
33
|
+
session_rejected_status: 401,
|
|
31
34
|
cursor_expired_status: 410,
|
|
32
35
|
drone_evicted_status: 410,
|
|
33
36
|
content_too_large_status: 413,
|
|
@@ -604,7 +607,7 @@ export function maxLogCursor(a: LogCursor | null, b: LogCursor | null): LogCurso
|
|
|
604
607
|
return compareLogCursor(a, b) >= 0 ? decodeLogCursor(a) : decodeLogCursor(b);
|
|
605
608
|
}
|
|
606
609
|
|
|
607
|
-
// ──
|
|
610
|
+
// ── v3 clean-slate wire types ──────────────────────────────────────────────
|
|
608
611
|
|
|
609
612
|
export const ATTACH_PATH = '/api/client/attach' as const;
|
|
610
613
|
|
|
@@ -636,7 +639,6 @@ export interface AttachDrone {
|
|
|
636
639
|
|
|
637
640
|
export interface AttachSession {
|
|
638
641
|
id: string;
|
|
639
|
-
expires_at: string;
|
|
640
642
|
}
|
|
641
643
|
|
|
642
644
|
export interface AttachResponse {
|
|
@@ -689,15 +691,14 @@ function decodeAttachDrone(value: unknown, path: readonly (string | number)[]):
|
|
|
689
691
|
|
|
690
692
|
function decodeAttachSession(value: unknown, path: readonly (string | number)[]): AttachSession {
|
|
691
693
|
const input = record(value, path);
|
|
692
|
-
exactKeys(input, ['id'
|
|
694
|
+
exactKeys(input, ['id'], ['id'], path);
|
|
693
695
|
return {
|
|
694
696
|
id: decodeUuid(input.id, [...path, 'id']),
|
|
695
|
-
expires_at: decodeCanonicalTimestamp(input.expires_at, [...path, 'expires_at']),
|
|
696
697
|
};
|
|
697
698
|
}
|
|
698
699
|
|
|
699
700
|
/**
|
|
700
|
-
* Decode a
|
|
701
|
+
* Decode a v3 attach request. Strict: exact keys, bounded sizes,
|
|
701
702
|
* session_credential is token-safe and never echoed in errors.
|
|
702
703
|
*/
|
|
703
704
|
export function decodeAttachRequest(value: unknown): AttachRequest {
|
|
@@ -719,7 +720,7 @@ export function decodeAttachRequest(value: unknown): AttachRequest {
|
|
|
719
720
|
}
|
|
720
721
|
|
|
721
722
|
/**
|
|
722
|
-
* Create a
|
|
723
|
+
* Create a v3 attach request envelope. Stamps the canonical protocol version.
|
|
723
724
|
*/
|
|
724
725
|
export function createAttachRequestEnvelope(
|
|
725
726
|
requestId: string,
|
|
@@ -733,7 +734,7 @@ export function createAttachRequestEnvelope(
|
|
|
733
734
|
}
|
|
734
735
|
|
|
735
736
|
/**
|
|
736
|
-
* Decode a
|
|
737
|
+
* Decode a v3 attach request envelope. Verifies protocol_version === PROTOCOL_VERSION
|
|
737
738
|
* BEFORE decoding the payload — a wrong tag never invokes the payload decoder
|
|
738
739
|
* and never exposes or returns the supplied session_credential.
|
|
739
740
|
* Uses a static token-safe diagnostic; does not interpolate attacker-controlled text.
|
|
@@ -763,8 +764,7 @@ export function decodeAttachRequestEnvelope(
|
|
|
763
764
|
}
|
|
764
765
|
|
|
765
766
|
/**
|
|
766
|
-
* Decode a
|
|
767
|
-
* expires_at required non-null finite ISO-8601.
|
|
767
|
+
* Decode a v3 attach response. Strict: exact keys and result discriminant.
|
|
768
768
|
*/
|
|
769
769
|
export function decodeAttachResponse(value: unknown): AttachResponse {
|
|
770
770
|
const input = record(value);
|
|
@@ -788,7 +788,7 @@ export function decodeAttachResponse(value: unknown): AttachResponse {
|
|
|
788
788
|
}
|
|
789
789
|
|
|
790
790
|
/**
|
|
791
|
-
* Decode a
|
|
791
|
+
* Decode a v3 attach response wrapped in a ProtocolEnvelope.
|
|
792
792
|
* Verifies protocol_version === PROTOCOL_VERSION before decoding payload.
|
|
793
793
|
*/
|
|
794
794
|
export function decodeAttachResponseEnvelope(value: unknown): ProtocolEnvelope<AttachResponse> {
|