@mannyc1/ts-release 0.2.2 → 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/ARCHITECTURE.md +60 -0
- package/CHANGELOG.md +82 -0
- package/README.md +129 -6
- package/SPEC.md +51 -0
- package/apps/release-ts/README.md +7 -0
- package/apps/ts-release-agents/package.json +1 -1
- package/apps/ts-release-agents/src/check.ts +7 -2
- package/apps/ts-release-agents/test/contract.test.ts +2 -2
- package/dist/bin/ts-release.js +154 -47
- package/dist/drivers/archive.d.ts +2 -1
- package/dist/drivers/archive.d.ts.map +1 -1
- package/dist/drivers/archive.js +12 -8
- package/dist/drivers/archive.js.map +1 -1
- package/dist/drivers/process.d.ts.map +1 -1
- package/dist/drivers/process.js +4 -4
- package/dist/drivers/process.js.map +1 -1
- package/dist/drivers/python-wheel.d.ts +21 -0
- package/dist/drivers/python-wheel.d.ts.map +1 -0
- package/dist/drivers/python-wheel.js +109 -0
- package/dist/drivers/python-wheel.js.map +1 -0
- package/dist/drivers/workspace.d.ts +3 -0
- package/dist/drivers/workspace.d.ts.map +1 -1
- package/dist/drivers/workspace.js +5 -1
- package/dist/drivers/workspace.js.map +1 -1
- package/dist/operation-journal/authority.d.ts +3 -0
- package/dist/operation-journal/authority.d.ts.map +1 -0
- package/dist/operation-journal/authority.js +147 -0
- package/dist/operation-journal/authority.js.map +1 -0
- package/dist/operation-journal/aws/deadline.d.ts +12 -0
- package/dist/operation-journal/aws/deadline.d.ts.map +1 -0
- package/dist/operation-journal/aws/deadline.js +38 -0
- package/dist/operation-journal/aws/deadline.js.map +1 -0
- package/dist/operation-journal/aws/oidc.d.ts +27 -0
- package/dist/operation-journal/aws/oidc.d.ts.map +1 -0
- package/dist/operation-journal/aws/oidc.js +361 -0
- package/dist/operation-journal/aws/oidc.js.map +1 -0
- package/dist/operation-journal/aws/policy.d.ts +42 -0
- package/dist/operation-journal/aws/policy.d.ts.map +1 -0
- package/dist/operation-journal/aws/policy.js +404 -0
- package/dist/operation-journal/aws/policy.js.map +1 -0
- package/dist/operation-journal/aws/s3-boundary.d.ts +17 -0
- package/dist/operation-journal/aws/s3-boundary.d.ts.map +1 -0
- package/dist/operation-journal/aws/s3-boundary.js +417 -0
- package/dist/operation-journal/aws/s3-boundary.js.map +1 -0
- package/dist/operation-journal/aws.d.ts +11 -0
- package/dist/operation-journal/aws.d.ts.map +1 -0
- package/dist/operation-journal/aws.js +50 -0
- package/dist/operation-journal/aws.js.map +1 -0
- package/dist/operation-journal/canonical.d.ts +52 -0
- package/dist/operation-journal/canonical.d.ts.map +1 -0
- package/dist/operation-journal/canonical.js +282 -0
- package/dist/operation-journal/canonical.js.map +1 -0
- package/dist/operation-journal/model.d.ts +251 -0
- package/dist/operation-journal/model.d.ts.map +1 -0
- package/dist/operation-journal/model.js +56 -0
- package/dist/operation-journal/model.js.map +1 -0
- package/dist/operation-journal/reducer.d.ts +28 -0
- package/dist/operation-journal/reducer.d.ts.map +1 -0
- package/dist/operation-journal/reducer.js +73 -0
- package/dist/operation-journal/reducer.js.map +1 -0
- package/dist/operation-journal/s3.d.ts +7 -0
- package/dist/operation-journal/s3.d.ts.map +1 -0
- package/dist/operation-journal/s3.js +667 -0
- package/dist/operation-journal/s3.js.map +1 -0
- package/dist/operation-journal.d.ts +14 -0
- package/dist/operation-journal.d.ts.map +1 -0
- package/dist/operation-journal.js +12 -0
- package/dist/operation-journal.js.map +1 -0
- package/dist/platform/credentials.d.ts.map +1 -1
- package/dist/platform/credentials.js +65 -3
- package/dist/platform/credentials.js.map +1 -1
- package/dist/publication/github.d.ts.map +1 -1
- package/dist/publication/github.js +66 -15
- package/dist/publication/github.js.map +1 -1
- package/dist/release/capabilities.d.ts.map +1 -1
- package/dist/release/capabilities.js +2 -2
- package/dist/release/capabilities.js.map +1 -1
- package/dist/release/prepare.d.ts.map +1 -1
- package/dist/release/prepare.js +4 -5
- package/dist/release/prepare.js.map +1 -1
- package/dist/release/prepared-store.d.ts.map +1 -1
- package/dist/release/prepared-store.js +11 -9
- package/dist/release/prepared-store.js.map +1 -1
- package/package.json +19 -4
- package/src/drivers/archive.ts +17 -8
- package/src/drivers/process.ts +3 -4
- package/src/drivers/python-wheel.ts +145 -0
- package/src/drivers/workspace.ts +7 -1
- package/src/operation-journal/authority.ts +162 -0
- package/src/operation-journal/aws/deadline.ts +41 -0
- package/src/operation-journal/aws/oidc.ts +439 -0
- package/src/operation-journal/aws/policy.ts +491 -0
- package/src/operation-journal/aws/s3-boundary.ts +562 -0
- package/src/operation-journal/aws.ts +60 -0
- package/src/operation-journal/canonical.ts +373 -0
- package/src/operation-journal/model.ts +301 -0
- package/src/operation-journal/reducer.ts +112 -0
- package/src/operation-journal/s3.ts +884 -0
- package/src/operation-journal.ts +51 -0
- package/src/platform/credentials.ts +71 -3
- package/src/publication/github.ts +83 -15
- package/src/release/capabilities.ts +3 -2
- package/src/release/prepare.ts +3 -5
- package/src/release/prepared-store.ts +8 -7
- package/templates/README.md +2 -2
- package/templates/github-actions/release.yml +24 -7
- package/templates/github-actions/reviewed-release.yml +49 -14
package/ARCHITECTURE.md
CHANGED
|
@@ -33,6 +33,12 @@ the authority for publication progress.
|
|
|
33
33
|
coordinator and provider subjects.
|
|
34
34
|
- `src/correction` binds provider-specific correction requests to exact
|
|
35
35
|
prepared subjects; catalog Git installs the sole conditional correction writer.
|
|
36
|
+
- `src/operation-journal` owns the provider-neutral opaque event envelope,
|
|
37
|
+
finite transition reducer, and the one S3 conditional-write protocol. It
|
|
38
|
+
does not decode provider payloads or acquire cloud credentials.
|
|
39
|
+
- `src/operation-journal/aws` owns the sole production backend: one sealed
|
|
40
|
+
GitHub-OIDC/STS session and exact IAM/S3 policy and object boundary. The core
|
|
41
|
+
subpath does not load the AWS SDK.
|
|
36
42
|
- `src/api` exposes the public lifecycle used by CLI, Action, and library users.
|
|
37
43
|
- `src/platform` supplies Node or Bun filesystem, process, HTTP, durable-store,
|
|
38
44
|
and opaque credential sinks at the host boundary.
|
|
@@ -112,6 +118,60 @@ the engine's private service tags. Credential values remain host-owned; the
|
|
|
112
118
|
public seam carries only prepared requests, opaque grants, safe references,
|
|
113
119
|
typed acquisition failures, and authorized HTTP results.
|
|
114
120
|
|
|
121
|
+
The separate `operation-journal` subpath is not part of the six-operation
|
|
122
|
+
release API. Its credential-agnostic core receives an exact structural S3
|
|
123
|
+
boundary so the protocol can be qualified without live credentials. The
|
|
124
|
+
separate `operation-journal/aws` subpath is the only admitted backend and
|
|
125
|
+
closes over a directly acquired short-lived purpose-scoped session; it exposes
|
|
126
|
+
no profile, ambient credential-chain, endpoint, bucket-selection, or fallback
|
|
127
|
+
input. Operation identities, payloads, and retained objects have fixed
|
|
128
|
+
pre-hash/pre-allocation byte bounds. The
|
|
129
|
+
journal records an immutable event attempt before conditionally advancing one versioned `head.bin`; the
|
|
130
|
+
head version is the only commit point. Every returned acknowledgment follows
|
|
131
|
+
an exact event/head version re-read and full reachable-chain validation.
|
|
132
|
+
Unacknowledged event attempts may be adopted or rebased by a fresh process only
|
|
133
|
+
when one transaction and one legal reducer transition are unambiguous. Reachable
|
|
134
|
+
and orphan attempts sharing a transaction ID must have the same canonical
|
|
135
|
+
logical record and workflow.
|
|
136
|
+
|
|
137
|
+
The authority snapshot distinguishes standard GitHub OIDC claims for the
|
|
138
|
+
caller (`repository`, `ref`, `sha`, `workflow_ref`, and
|
|
139
|
+
`workflow_sha`) from `job_workflow_ref` and `job_workflow_sha` for the called
|
|
140
|
+
reusable workflow. The package validates canonical relationships and exact
|
|
141
|
+
expected-versus-observed equality without embedding a consumer repository,
|
|
142
|
+
ID, environment, subject, or caller filename. The consumer-owned activation
|
|
143
|
+
contract must pin its protected caller workflow and branch; a broader release
|
|
144
|
+
workflow must not possess that authority. The
|
|
145
|
+
snapshot also binds the exact OIDC trust-policy digest. Ref and source SHA are
|
|
146
|
+
never collapsed into one invented claim. Append records
|
|
147
|
+
derive repository/run/attempt from this snapshot. The structural boundary is a
|
|
148
|
+
test and host seam, not policy evidence by itself. The package-owned AWS adapter
|
|
149
|
+
decodes the JWT in memory, re-observes STS caller identity, parses live bucket,
|
|
150
|
+
Object Lock, ownership, and public-access configuration, canonicalizes the
|
|
151
|
+
bucket, role, and OIDC trust policies, and derives every boolean and digest it
|
|
152
|
+
returns. Until that adapter is released and the exact infrastructure,
|
|
153
|
+
opaque-byte workflow topology, and retained-object protocol are qualified, the
|
|
154
|
+
reusable workflow is a permissionless, always-failing interface only.
|
|
155
|
+
|
|
156
|
+
The parsed AWS trust projection is exact `aud`, the frozen environment `sub`,
|
|
157
|
+
repository and immutable repository/owner IDs, caller `workflow`, `ref`,
|
|
158
|
+
`environment`, and called `job_workflow_ref`. Current AWS IAM can condition on
|
|
159
|
+
those GitHub claims directly. `workflow_sha` and `job_workflow_sha` remain
|
|
160
|
+
locally re-observed source evidence; the trust-policy projection does not
|
|
161
|
+
pretend AWS conditions on `job_workflow_sha`.
|
|
162
|
+
The frozen activation selects either the exact name-bound environment subject
|
|
163
|
+
or the exact immutable owner/repository-ID-bound form; validation reconstructs
|
|
164
|
+
the selected form and never falls back to the other. The same STS-admitted
|
|
165
|
+
token is locally pinned to `workflow_dispatch`, a branch ref, public repository
|
|
166
|
+
visibility, and a GitHub-hosted runner. OIDC fetch, every SDK send, and every
|
|
167
|
+
response/body stream have a fixed 10,000 ms wall-clock deadline.
|
|
168
|
+
The reusable `job_workflow_ref` itself is conditioned at an exact lowercase
|
|
169
|
+
40-hex ts-release commit, and the local claim validator requires that suffix to
|
|
170
|
+
equal `job_workflow_sha`. This makes the AWS boundary immutable even though AWS
|
|
171
|
+
does not expose `job_workflow_sha` as a separate condition key. An activated
|
|
172
|
+
job runs the package on Node 22.22.2 through an `env -i` allowlist; it does not
|
|
173
|
+
inherit a caller's Node 24.14.1 process environment.
|
|
174
|
+
|
|
115
175
|
## Extension translation
|
|
116
176
|
|
|
117
177
|
The kernel admits extensions only through an owner with a narrow invariant:
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,87 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## Unreleased
|
|
4
|
+
|
|
5
|
+
## 0.3.0 - 2026-09-01
|
|
6
|
+
|
|
7
|
+
### Self-release hardening
|
|
8
|
+
|
|
9
|
+
- Split credential-free preparation, no-upload npm OIDC certification,
|
|
10
|
+
lightweight tag creation, npm publication, and later GitHub publication
|
|
11
|
+
into five exact-SHA dispatch modes. GitHub and npm consume distinct
|
|
12
|
+
content-addressed prepared bundles
|
|
13
|
+
under separately named environments and least-privilege job permissions;
|
|
14
|
+
no default path receives publication authority.
|
|
15
|
+
- Pin GitHub-hosted runner labels, third-party Actions, Node 22.22.2, Bun
|
|
16
|
+
1.3.14, and the self-release npm CLI at 11.11.0. Reauthenticate the exact
|
|
17
|
+
checkout against the current public `main` tip immediately before every
|
|
18
|
+
preparation or publication boundary, and reject ambient npm credentials.
|
|
19
|
+
- After npm publication, bind the adopted tarball bytes to registry integrity,
|
|
20
|
+
the exact GitHub SLSA v1 provenance statement and run identity, and npm's
|
|
21
|
+
cryptographic signature audit. Select same-run proof for a fresh mutation
|
|
22
|
+
and authenticate the provenance-named prior run for an exact
|
|
23
|
+
`AlreadyEquivalent` response-loss recovery. Pin Sigstore 4.1.0 from the
|
|
24
|
+
audited npm archive and require the exact Fulcio workflow SAN, OIDC issuer,
|
|
25
|
+
environment-bound ID-qualified repository subject, source/workflow SHA, and
|
|
26
|
+
run-invocation certificate extensions. Preserve
|
|
27
|
+
GitHub tag, release, and asset equivalence checks inside the provider-native
|
|
28
|
+
publisher.
|
|
29
|
+
- Keep every credentialed job free of nonlocal Actions by natively checking
|
|
30
|
+
out the exact current-main candidate and executing its local Action. Stage
|
|
31
|
+
GitHub assets only in a private draft; a fresh later full asset reread is the
|
|
32
|
+
sole authority for PATCH-only public promotion. Bind trusted npm children to
|
|
33
|
+
an empty private home and explicit empty mode-0600 user/global configs.
|
|
34
|
+
- Move final npm certification/publication evidence out of the `id-token:
|
|
35
|
+
write` producer jobs. A dependency-free Node bootstrap validates then drops
|
|
36
|
+
the runner-injected OIDC request authority, binds the exact private report,
|
|
37
|
+
and commits one explicitly non-final handoff. A separate no-environment,
|
|
38
|
+
no-id-token job verifies that artifact and alone retains the final v2
|
|
39
|
+
receipt; missing outputs, changed attempts, and unknown writes fail closed.
|
|
40
|
+
|
|
41
|
+
### Canonical operation journal
|
|
42
|
+
|
|
43
|
+
- Add a provider-neutral `operation-journal` subpath with one opaque canonical
|
|
44
|
+
event envelope, one finite transition reducer, and one versioned S3
|
|
45
|
+
conditional-write protocol. Durable acknowledgments require exact retained
|
|
46
|
+
event/head re-read and full-chain validation; response loss, CAS conflict,
|
|
47
|
+
and fresh-process orphan recovery are bounded and fail closed. Every retained
|
|
48
|
+
attempt that shares a transaction ID must carry the same opaque logical
|
|
49
|
+
record and workflow, including attempts already reachable from the head.
|
|
50
|
+
- Keep provider codecs and provider calls outside the journal package boundary.
|
|
51
|
+
Add the sole package-owned `operation-journal/aws` adapter: it rejects
|
|
52
|
+
ambient AWS configuration, exchanges a GitHub OIDC token directly for one
|
|
53
|
+
short-lived role session, re-observes STS/IAM/S3 authority, parses the exact
|
|
54
|
+
role/trust/bucket policies, and emits only single-part conditional S3 writes.
|
|
55
|
+
Serialized SDK requests and fakes qualify this code without claiming live
|
|
56
|
+
AWS policy or retained-object qualification. No SQLite, Git ref, Actions
|
|
57
|
+
artifact, alternate endpoint, credential chain, or fallback store is added.
|
|
58
|
+
- Bind caller and called reusable-workflow OIDC refs and source SHAs as
|
|
59
|
+
distinct claims, derive event run coordinates from the observed session, and
|
|
60
|
+
include the exact OIDC trust-policy digest in authority drift checks. Pin the
|
|
61
|
+
called workflow at one immutable commit, admit one frozen name- or
|
|
62
|
+
immutable-ID-bound environment subject, and locally require hosted public
|
|
63
|
+
workflow-dispatch branch claims from the same STS-admitted token. Bound every
|
|
64
|
+
OIDC fetch, AWS SDK send, and object stream by a fixed wall-clock deadline.
|
|
65
|
+
Operation identities, payloads, retained objects, request/response
|
|
66
|
+
coordinates, and JWT bytes are independently bounded, and Actions request
|
|
67
|
+
coordinates are consumed from the environment before use. The
|
|
68
|
+
checked-in reusable workflow remains permissionless and always fails until a
|
|
69
|
+
released adapter, exact infrastructure, opaque-byte call topology, and live
|
|
70
|
+
retained-object protocol are separately qualified.
|
|
71
|
+
|
|
72
|
+
### PyPI embedded-binary distributions
|
|
73
|
+
|
|
74
|
+
- Reopen the repository-specific PyPI wrapper-wheel decision with four
|
|
75
|
+
deterministic `ts-release` wheels: manylinux 2.17 and macOS 13, each for
|
|
76
|
+
x64 and arm64. Every wheel embeds exactly one Bun-compiled executable and
|
|
77
|
+
exposes the `ts-release` Python console script.
|
|
78
|
+
- Add an isolated manual PyPI workflow. Its build job has read-only repository
|
|
79
|
+
authority; its separate `pypi` environment job grants only `id-token: write`
|
|
80
|
+
and invokes `pypa/gh-action-pypi-publish@release/v1` over the transferred
|
|
81
|
+
four-wheel artifact set.
|
|
82
|
+
- Make native self-release builds use the version-bearing Bun entrypoint and
|
|
83
|
+
require the Linux candidate executable to report the exact manifest version.
|
|
84
|
+
|
|
3
85
|
## 0.2.2 - 2026-08-14
|
|
4
86
|
|
|
5
87
|
This release delivers the intended `0.2` product relative to `0.0.7` and
|
package/README.md
CHANGED
|
@@ -94,6 +94,25 @@ publishing is represented as an external, host-owned
|
|
|
94
94
|
`pypa/gh-action-pypi-publish@release/v1` path; the stock coordinator neither
|
|
95
95
|
exchanges its OIDC token nor claims to recover that external upload.
|
|
96
96
|
|
|
97
|
+
This repository's selected self-release shape is declared in
|
|
98
|
+
`apps/release-ts/pypi-release.config.json`. It deterministically embeds one
|
|
99
|
+
native executable in each of these `ts-release` wheels:
|
|
100
|
+
|
|
101
|
+
- `py3-none-manylinux_2_17_x86_64`
|
|
102
|
+
- `py3-none-manylinux_2_17_aarch64`
|
|
103
|
+
- `py3-none-macosx_13_0_x86_64`
|
|
104
|
+
- `py3-none-macosx_13_0_arm64`
|
|
105
|
+
|
|
106
|
+
`.github/workflows/pypi-release.yml` prepares the exact four-file set in a
|
|
107
|
+
read-only build job, transfers it with GitHub Actions artifact retention, and
|
|
108
|
+
gives only the separate `pypi` environment job `id-token: write`. That job has
|
|
109
|
+
no checkout or arbitrary command step; it downloads the prepared wheels and
|
|
110
|
+
invokes the official PyPA trusted-publishing Action. The PyPI publisher must
|
|
111
|
+
be configured for owner `mannyc2`, repository `ts-release`, workflow
|
|
112
|
+
`pypi-release.yml`, branch `main`, and environment `pypi` before dispatch.
|
|
113
|
+
The macOS wheel tags certify the cross-compiled artifact targets; they do not
|
|
114
|
+
expand the product's Linux-only execution-host claim.
|
|
115
|
+
|
|
97
116
|
With the canonical GitHub origin or package repository configured, `init` can
|
|
98
117
|
discover the exact owner/repository coordinate and write this explicit shape:
|
|
99
118
|
|
|
@@ -104,9 +123,70 @@ ts-release init --preset bun-npm-github
|
|
|
104
123
|
It refuses to guess when no repository coordinate is observable and strictly
|
|
105
124
|
inspects the exact generated configuration before writing it.
|
|
106
125
|
|
|
107
|
-
##
|
|
108
|
-
|
|
109
|
-
The
|
|
126
|
+
## Repository 0.3 self-release
|
|
127
|
+
|
|
128
|
+
The checked-in `.github/workflows/release.yml` is a manual, fail-closed
|
|
129
|
+
five-mode workflow. `prepare-exact-sha` has read-only repository authority
|
|
130
|
+
and independently commits one GitHub-assets bundle and one npm-tarball bundle
|
|
131
|
+
to the content-addressed Actions store. `certify-npm-oidc` adopts the exact npm
|
|
132
|
+
bundle, proves one trusted-publisher exchange through pinned npm's dry-run, and
|
|
133
|
+
proves unchanged anonymous registry state without upload, provenance, or
|
|
134
|
+
publication. `create-tag` has only the separate
|
|
135
|
+
`github-tag` environment and creates or reobserves the lightweight `v0.3.0`
|
|
136
|
+
tag at the exact candidate; it creates no Release. `publish-npm` accepts only
|
|
137
|
+
the npm bundle under the `npm` environment with `id-token: write`, then
|
|
138
|
+
rereads the public registry to prove exact tarball bytes and the exact GitHub
|
|
139
|
+
SLSA provenance identity. The pinned npm archive's Sigstore 4.1.0 verifier
|
|
140
|
+
requires the exact Fulcio workflow SAN and GitHub OIDC issuer, then binds the
|
|
141
|
+
certificate's workflow/source SHA and run-invocation extensions to the same
|
|
142
|
+
candidate and provenance statement. Its repository-subject extension must be
|
|
143
|
+
the ID-qualified `repo:mannyc2@126291407/ts-release@1271545637:environment:npm`
|
|
144
|
+
identity issued for the protected npm environment; the historical ref-bound
|
|
145
|
+
subject is rejected. Generic signature validity is insufficient.
|
|
146
|
+
Only afterward, `publish-github` accepts the GitHub
|
|
147
|
+
bundle plus the already-published npm bundle under the `github-release`
|
|
148
|
+
environment with `contents: write`. Every boundary
|
|
149
|
+
reauthenticates the checkout against the current public `main` tip immediately
|
|
150
|
+
before it can adopt or mutate anything.
|
|
151
|
+
|
|
152
|
+
The npm client itself is fetched from the canonical npm 11.11.0 tarball,
|
|
153
|
+
checked against its fixed SHA-512 and SHA-1 registry digests, and freshly
|
|
154
|
+
rematerialized before every boundary. Any nonempty `npm_config_*`, `PREFIX`,
|
|
155
|
+
`DESTDIR`, token variable, project/user npmrc, or default global npmrc stops
|
|
156
|
+
before repository or provider work.
|
|
157
|
+
|
|
158
|
+
The exact order is preparation, no-upload npm OIDC certification, lightweight
|
|
159
|
+
tag creation, npm publication and report-bound public/provenance verification,
|
|
160
|
+
then GitHub publication. A fresh
|
|
161
|
+
npm mutation must carry provenance for that exact workflow run attempt. If a
|
|
162
|
+
prior run applied the bytes but lost its response, an exact `AlreadyEquivalent`
|
|
163
|
+
retry instead authenticates the earlier canonical publishing run named by the
|
|
164
|
+
public provenance; it never demands impossible same-run provenance from a
|
|
165
|
+
no-op retry. Any uncertain, blocked, malformed, or differently bound Action
|
|
166
|
+
report stops verification. The first
|
|
167
|
+
GitHub publication invocation creates or resumes a private draft and uploads
|
|
168
|
+
only missing exact assets. For a desired public Release that staging result is
|
|
169
|
+
deliberately `uncertain`, not success, and the Release remains nonpublic. A
|
|
170
|
+
fresh invocation with the same candidate and both exact `prepared:gha:`
|
|
171
|
+
references must fully reread draft metadata and every paginated asset, download
|
|
172
|
+
and hash any asset whose API digest is absent, and only then perform a
|
|
173
|
+
PATCH-only public transition. Extra, duplicate, missing, or different assets
|
|
174
|
+
stop that transition. On 2026-09-01, repository environments `github-tag`
|
|
175
|
+
(ID `20986778371`), `npm` (ID `20985327992`), and `github-release`
|
|
176
|
+
(ID `20985328229`) were observed with reviewer `mannyc2`, self-review allowed,
|
|
177
|
+
admin bypass disabled, a custom deployment policy selecting exactly `main`,
|
|
178
|
+
and no environment secrets or variables. Re-query those mutable facts before
|
|
179
|
+
every dispatch. Repository Release immutability was also observed enabled on
|
|
180
|
+
2026-09-01; re-query it before GitHub staging or promotion. The repository OIDC
|
|
181
|
+
policy was observed on that date with the immutable ID-qualified subject
|
|
182
|
+
`repo:mannyc2@126291407/ts-release@1271545637:environment:npm`; re-query it
|
|
183
|
+
before certification or publication. That GitHub-side policy does not prove an
|
|
184
|
+
npm-side trusted-publisher record. The exact npm trusted-publisher subject
|
|
185
|
+
remains a separate prerequisite and is not inferred from an environment.
|
|
186
|
+
|
|
187
|
+
## Automatic GitHub Actions template
|
|
188
|
+
|
|
189
|
+
The reusable automatic template is one job and one Action invocation. Copy the exact
|
|
110
190
|
[automatic workflow template](templates/github-actions/release.yml). It is
|
|
111
191
|
manual-only and requires `candidate_sha` to equal the current commit on
|
|
112
192
|
`refs/heads/main` before the job can reach checkout. Its
|
|
@@ -118,7 +198,7 @@ recovery artifact.
|
|
|
118
198
|
|
|
119
199
|
```yaml
|
|
120
200
|
- id: release
|
|
121
|
-
uses: mannyc2/ts-release/apps/ts-release-action@v0.
|
|
201
|
+
uses: mannyc2/ts-release/apps/ts-release-action@v0.3.0
|
|
122
202
|
env:
|
|
123
203
|
GITHUB_TOKEN: ${{ github.token }}
|
|
124
204
|
with:
|
|
@@ -132,7 +212,7 @@ preparation, dispatch the same candidate with the exact emitted
|
|
|
132
212
|
`prepared:gha:` reference; the job selects `publish`, loads and verifies the
|
|
133
213
|
original bundle, and does not rebuild.
|
|
134
214
|
|
|
135
|
-
`v0.
|
|
215
|
+
`v0.3.0` is the immutable monorepo-subpath coordinate intended for this
|
|
136
216
|
candidate. Packaging and release certification must stop unless that tag is
|
|
137
217
|
created from the exact certified result commit before consumers can see a
|
|
138
218
|
README that names it. A floating Action branch is never an alternative.
|
|
@@ -262,7 +342,9 @@ The kernel translates extension requests to the owner that can enforce them:
|
|
|
262
342
|
|
|
263
343
|
Homebrew and Scoop rendering/delivery use typed renderers and an exact paired
|
|
264
344
|
Git Data subject; arbitrary whole-file catalog templating remains excluded.
|
|
265
|
-
|
|
345
|
+
Generic wrapper-wheel generation remains excluded from the prebuilt PyPI
|
|
346
|
+
capability. The repository-specific four-wheel `ts-release` self-release is an
|
|
347
|
+
explicit product decision and is prepared by its dedicated workflow. PyPI
|
|
266
348
|
support is contract-tested but has not been live-write-dogfooded in this wave.
|
|
267
349
|
Custom library applications may compose full provider subjects through the
|
|
268
350
|
[`provider-sdk`](https://github.com/mannyc2/ts-release/blob/main/docs/native-extensions.md)
|
|
@@ -318,6 +400,47 @@ The public operations are `inspect`, `prepare`, `observe`, `publish`,
|
|
|
318
400
|
prepared paths. The derived graph is ephemeral; the verified prepared
|
|
319
401
|
manifest and blobs are the durable cross-process boundary.
|
|
320
402
|
|
|
403
|
+
The separate `@mannyc1/ts-release/operation-journal` subpath exposes the
|
|
404
|
+
provider-neutral canonical envelope and one S3 CAS protocol for durable
|
|
405
|
+
external-operation continuation. It stores consumer-owned opaque bytes and
|
|
406
|
+
never decodes provider fields. Workflow repository/run coordinates are derived
|
|
407
|
+
from the re-observed GitHub OIDC session rather than accepted from an append
|
|
408
|
+
request. A host can supply one already-authenticated, exact-policy S3 boundary
|
|
409
|
+
as the credential-agnostic qualification seam. The separate
|
|
410
|
+
`@mannyc1/ts-release/operation-journal/aws` subpath is the only operational
|
|
411
|
+
backend implementation: it accepts one sealed activation contract, rejects
|
|
412
|
+
ambient AWS variables and shared files, requests GitHub OIDC directly, uses
|
|
413
|
+
only the returned short-lived role session, and parses live STS, IAM, bucket,
|
|
414
|
+
Object Lock, ownership, public-access, and policy responses. It accepts no
|
|
415
|
+
profile, credential, endpoint, alternate bucket, or fallback-store input.
|
|
416
|
+
Operation identities are bounded to 65,536 bytes, payloads to 1,048,576 bytes,
|
|
417
|
+
and retained objects to 1,500,000 bytes before hashing or allocation. The AWS
|
|
418
|
+
trust and activation contract require the
|
|
419
|
+
reusable workflow to be called as `uses: .../operational-journal.yml@<40-hex>`;
|
|
420
|
+
a branch or tag ref is not authority, and the observed `job_workflow_ref` SHA
|
|
421
|
+
must equal `job_workflow_sha`. The frozen subject selects exactly one GitHub
|
|
422
|
+
environment-subject form: name-bound `repo:owner/repository:environment:name`
|
|
423
|
+
or immutable-ID-bound
|
|
424
|
+
`repo:owner@ownerId/repository@repositoryId:environment:name`; observed IDs
|
|
425
|
+
must reconstruct the latter exactly, and there is no runtime fallback between
|
|
426
|
+
forms. The same STS-admitted token must also report `workflow_dispatch`, a
|
|
427
|
+
branch ref, a public repository, and a GitHub-hosted runner. Every OIDC fetch,
|
|
428
|
+
AWS SDK send, and retained-object stream has a fixed 10,000 ms wall-clock
|
|
429
|
+
deadline in addition to single-attempt retry policy.
|
|
430
|
+
|
|
431
|
+
The checked-in `operational-journal.yml` is intentionally inert: it has no
|
|
432
|
+
OIDC permission, AWS coordinate, credential input, checkout, or executable
|
|
433
|
+
adapter and always stops. Activating it requires the separately provisioned
|
|
434
|
+
bucket/role, a released adapter version, a reviewed opaque-byte caller/callee
|
|
435
|
+
transport, and qualification of the exact retained object protocol. The
|
|
436
|
+
serialized SDK requests, structural boundary, and fake tests are not live AWS
|
|
437
|
+
or workflow qualification.
|
|
438
|
+
An activated reusable job must install the package-supported Node 22.22.2
|
|
439
|
+
runtime independently of the caller and launch the adapter through an
|
|
440
|
+
`env -i` allowlist containing only the exact Actions OIDC request coordinates
|
|
441
|
+
and non-secret activation inputs. The caller's Node 24.14.1 runtime is below a
|
|
442
|
+
transitive dependency's admitted Node 24 floor and must not run this package.
|
|
443
|
+
|
|
321
444
|
## Agent bundles and development
|
|
322
445
|
|
|
323
446
|
The single tracked agent source owner is `apps/ts-release-agents`. Generated
|
package/SPEC.md
CHANGED
|
@@ -127,6 +127,57 @@ Read-convergence timing defaults are conservative assumed bounds until live
|
|
|
127
127
|
post-write evidence measures them. Announcements and unsupported providers
|
|
128
128
|
remain outside the retained product.
|
|
129
129
|
|
|
130
|
+
The provider-neutral `operation-journal` subpath admits only
|
|
131
|
+
`IntentRecorded`, `ReceiptRecorded`, zero or more `ObservationRecorded`, and
|
|
132
|
+
`TerminalRecorded`, with `OutcomeUnknown` as the terminal alternative from an
|
|
133
|
+
intent. Payload bytes and their codec identifier are opaque to ts-release.
|
|
134
|
+
There is one storage protocol: a versioned, Object-Locked S3 namespace with
|
|
135
|
+
immutable conditional event creates and conditional `head.bin` replacement.
|
|
136
|
+
An acknowledgment exists only after exact retained event/head versions and the
|
|
137
|
+
complete chain are re-read. Conditional conflicts, response loss, and process
|
|
138
|
+
death are reconciled by bounded exact-version reads; ambiguity stops and never
|
|
139
|
+
authorizes a provider resubmission. Credential acquisition, provider codecs,
|
|
140
|
+
and provider calls remain host/consumer responsibilities.
|
|
141
|
+
|
|
142
|
+
The release point must equal the re-observed caller `sha`. Standard OIDC claims
|
|
143
|
+
identify the caller while `job_workflow_ref` and
|
|
144
|
+
`job_workflow_sha` separately identify the called ts-release workflow and its
|
|
145
|
+
exact source commit. The OIDC trust-policy digest is independent of the bucket
|
|
146
|
+
and role-policy digests. Repository ID, run ID, and run attempt in journal
|
|
147
|
+
events come only from that observed session; they are not append inputs. The
|
|
148
|
+
checked-in reusable workflow is inert and always fails without OIDC permission
|
|
149
|
+
until the package-owned `operation-journal/aws` adapter has been released and
|
|
150
|
+
the exact infrastructure, opaque-byte workflow topology, and retained-object
|
|
151
|
+
protocol have been separately qualified. Local fake and serialized-request
|
|
152
|
+
tests establish implementation behavior, not live AWS certification.
|
|
153
|
+
AWS trust must compare `job_workflow_ref` to the reusable workflow path at one
|
|
154
|
+
lowercase 40-hex ts-release commit. The called workflow ref must end in the
|
|
155
|
+
same value as `job_workflow_sha`; branch and tag refs are rejected before STS.
|
|
156
|
+
|
|
157
|
+
The library embeds no consumer repository, immutable ID, environment, subject,
|
|
158
|
+
or caller-workflow name. An activation contract supplies those exact expected
|
|
159
|
+
values and the adapter re-observes them. Its parsed trust projection must bind
|
|
160
|
+
`aud`, the frozen environment `sub`, repository/IDs, caller `workflow`, `ref`,
|
|
161
|
+
`environment`, and `job_workflow_ref`. Workflow source SHAs remain separately
|
|
162
|
+
re-observed evidence and are not misrepresented as AWS trust-condition keys.
|
|
163
|
+
The activation contract freezes either the exact name-bound environment
|
|
164
|
+
subject or its immutable owner/repository-ID-bound form; the adapter admits no
|
|
165
|
+
fallback between those forms. After STS admits the token, local equality also
|
|
166
|
+
requires `event_name=workflow_dispatch`, `ref_type=branch`,
|
|
167
|
+
`repository_visibility=public`, and `runner_environment=github-hosted`.
|
|
168
|
+
The adapter accepts no credential, profile, endpoint, or alternate-store input:
|
|
169
|
+
it rejects ambient AWS variables and shared files, directly exchanges GitHub
|
|
170
|
+
OIDC for one short-lived role session, and derives governance facts from signed
|
|
171
|
+
STS/IAM/S3 responses and exact parsed policies rather than caller booleans.
|
|
172
|
+
Operation identities are limited to 65,536 bytes, consumer payloads to
|
|
173
|
+
1,048,576 bytes, and every retained object to 1,500,000 bytes; declared and
|
|
174
|
+
streamed lengths are both enforced before hashing or full object allocation.
|
|
175
|
+
Every OIDC fetch, AWS SDK send, and response/body stream is
|
|
176
|
+
bounded by one fixed 10,000 ms wall-clock deadline. The activated reusable job
|
|
177
|
+
uses pinned Node 22.22.2 and an
|
|
178
|
+
`env -i` allowlist. Node 24.14.1 is not in this package's engine because the
|
|
179
|
+
authoritative transitive floor begins at Node 24.15.0.
|
|
180
|
+
|
|
130
181
|
## 10. Product evidence
|
|
131
182
|
|
|
132
183
|
In the source distribution, the generated capability inventory is joined
|
|
@@ -30,3 +30,10 @@ The preset binds trusted publication to `.github/workflows/release.yml` at
|
|
|
30
30
|
`refs/heads/main`. Change both `workflow` and `workflowRef` when another exact
|
|
31
31
|
workflow/ref is the intended host; a mismatch is rejected before OIDC request
|
|
32
32
|
material is read.
|
|
33
|
+
|
|
34
|
+
The repository-specific PyPI self-release is separate from that npm/GitHub
|
|
35
|
+
path. `pypi-release.config.json` builds the four Linux/macOS x64/arm64 native
|
|
36
|
+
wheel artifacts, and `scripts/prepare-pypi-distributions.ts` materializes the
|
|
37
|
+
verified set for `.github/workflows/pypi-release.yml`. Its external publisher
|
|
38
|
+
identity is the official PyPA Action bound to the `pypi` GitHub environment;
|
|
39
|
+
the script prepares bytes only and never exchanges OIDC or uploads them.
|
|
@@ -25,6 +25,11 @@ const generatedFiles = (directory: string): string[] => readdirSync(directory, {
|
|
|
25
25
|
const containsFiles = (directory: string): boolean => readdirSync(directory, { withFileTypes: true }).some((entry) => {
|
|
26
26
|
return entry.isDirectory() ? containsFiles(join(directory, entry.name)) : true
|
|
27
27
|
})
|
|
28
|
+
const commandFailure = (result: ReturnType<typeof spawnSync>): string => {
|
|
29
|
+
const stderr = typeof result.stderr === "string" ? result.stderr.trim() : ""
|
|
30
|
+
const stdout = typeof result.stdout === "string" ? result.stdout.trim() : ""
|
|
31
|
+
return stderr || stdout || result.error?.message || "unknown command failure"
|
|
32
|
+
}
|
|
28
33
|
|
|
29
34
|
const firstPaths = buildAgents()
|
|
30
35
|
const first = firstPaths.map((path) => bytes(path))
|
|
@@ -54,7 +59,7 @@ for (const path of ["SKILL.md", join("skills", "release", "SKILL.md")]) {
|
|
|
54
59
|
if (existsSync(join(root, path))) fail(`Root canonical agent owner remains: ${path}`)
|
|
55
60
|
}
|
|
56
61
|
const tracked = spawnSync("git", ["ls-files", "-z"], { cwd: root, encoding: "utf8", stdio: "pipe" })
|
|
57
|
-
if (tracked.status !== 0) fail(`Could not inspect tracked agent owners: ${
|
|
62
|
+
if (tracked.status !== 0) fail(`Could not inspect tracked agent owners: ${commandFailure(tracked)}`)
|
|
58
63
|
const trackedFiles = tracked.stdout.split("\0").filter((path) => path.length > 0)
|
|
59
64
|
const canonicalRootOwners = trackedFiles.filter((path) =>
|
|
60
65
|
path === ".codex-plugin/plugin.json" ||
|
|
@@ -95,7 +100,7 @@ try {
|
|
|
95
100
|
stdio: "pipe"
|
|
96
101
|
})
|
|
97
102
|
if (validated.status !== 0) {
|
|
98
|
-
fail(`Installed Claude plugin validator failed: ${
|
|
103
|
+
fail(`Installed Claude plugin validator failed: ${commandFailure(validated)}`)
|
|
99
104
|
}
|
|
100
105
|
}
|
|
101
106
|
providerLayouts.push(relative(disposableRoot, installation.packageRoot).replaceAll("\\", "/"))
|
|
@@ -21,7 +21,7 @@ describe("agent distribution contract", () => {
|
|
|
21
21
|
const native = provider === "codex" ? ".codex-plugin" : ".claude-plugin"
|
|
22
22
|
const manifest = join(root, ".release", "agents", provider, "ts-release", native, "plugin.json")
|
|
23
23
|
expect(existsSync(manifest)).toBe(true)
|
|
24
|
-
expect(JSON.parse(readFileSync(manifest, "utf8")).version).toBe("0.
|
|
24
|
+
expect(JSON.parse(readFileSync(manifest, "utf8")).version).toBe("0.3.0")
|
|
25
25
|
}
|
|
26
26
|
})
|
|
27
27
|
|
|
@@ -43,7 +43,7 @@ describe("agent distribution contract", () => {
|
|
|
43
43
|
"local-archive",
|
|
44
44
|
"ts-release"
|
|
45
45
|
))
|
|
46
|
-
expect(installed.version).toBe("0.
|
|
46
|
+
expect(installed.version).toBe("0.3.0")
|
|
47
47
|
expect(installed.packageRoot).toBe(join(installed.providerRoot, installed.version))
|
|
48
48
|
expect(existsSync(join(installed.packageRoot, provider === "codex" ? ".codex-plugin" : ".claude-plugin", "plugin.json"))).toBe(true)
|
|
49
49
|
expect(existsSync(join(installed.packageRoot, "skills", "release", "SKILL.md"))).toBe(true)
|