worktrust 0.10.13__tar.gz
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.
- worktrust-0.10.13/LICENSE +21 -0
- worktrust-0.10.13/MANIFEST.in +4 -0
- worktrust-0.10.13/PKG-INFO +110 -0
- worktrust-0.10.13/README.md +98 -0
- worktrust-0.10.13/VERSION +1 -0
- worktrust-0.10.13/build_runtime.py +115 -0
- worktrust-0.10.13/pyproject.toml +29 -0
- worktrust-0.10.13/runtime-lock.json +36 -0
- worktrust-0.10.13/setup.cfg +4 -0
- worktrust-0.10.13/setup.py +55 -0
- worktrust-0.10.13/src/worktrust.egg-info/PKG-INFO +110 -0
- worktrust-0.10.13/src/worktrust.egg-info/SOURCES.txt +32 -0
- worktrust-0.10.13/src/worktrust.egg-info/dependency_links.txt +1 -0
- worktrust-0.10.13/src/worktrust.egg-info/entry_points.txt +2 -0
- worktrust-0.10.13/src/worktrust.egg-info/top_level.txt +1 -0
- worktrust-0.10.13/src/worktrust_cli/__init__.py +88 -0
- worktrust-0.10.13/src/worktrust_cli/__main__.py +4 -0
- worktrust-0.10.13/src/worktrust_cli/bundle/chat-exports.mjs +240 -0
- worktrust-0.10.13/src/worktrust_cli/bundle/config-edits.mjs +87 -0
- worktrust-0.10.13/src/worktrust_cli/bundle/count-behaviour.mjs +1393 -0
- worktrust-0.10.13/src/worktrust_cli/bundle/log-session.mjs +1330 -0
- worktrust-0.10.13/src/worktrust_cli/bundle/manifest.json +19 -0
- worktrust-0.10.13/src/worktrust_cli/bundle/preserve-lines.mjs +252 -0
- worktrust-0.10.13/src/worktrust_cli/bundle/preserve-summary.mjs +42 -0
- worktrust-0.10.13/src/worktrust_cli/bundle/preserve.mjs +390 -0
- worktrust-0.10.13/src/worktrust_cli/bundle/runtime-install.mjs +64 -0
- worktrust-0.10.13/src/worktrust_cli/bundle/session-databases.mjs +472 -0
- worktrust-0.10.13/src/worktrust_cli/bundle/setup-mcp.mjs +343 -0
- worktrust-0.10.13/src/worktrust_cli/bundle/stack-rules.mjs +153 -0
- worktrust-0.10.13/src/worktrust_cli/bundle/stretch-evidence.mjs +748 -0
- worktrust-0.10.13/src/worktrust_cli/bundle/transcript-readers.mjs +269 -0
- worktrust-0.10.13/src/worktrust_cli/bundle/worktrust.mjs +1196 -0
- worktrust-0.10.13/tests/test_distribution.py +189 -0
- worktrust-0.10.13/tests/test_runtime_build.py +87 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 WorkTrust
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: worktrust
|
|
3
|
+
Version: 0.10.13
|
|
4
|
+
Summary: The WorkTrust CLI, using the same measurement engine as npm
|
|
5
|
+
License-Expression: MIT
|
|
6
|
+
Project-URL: Homepage, https://worktrust.io
|
|
7
|
+
Project-URL: Source, https://github.com/fhomey/worktrust-cli
|
|
8
|
+
Requires-Python: >=3.10
|
|
9
|
+
Description-Content-Type: text/markdown
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Dynamic: license-file
|
|
12
|
+
|
|
13
|
+
# WorkTrust for Python tool runners
|
|
14
|
+
|
|
15
|
+
This package launches the same JavaScript measurement engine shipped in the WorkTrust npm
|
|
16
|
+
package. It does not implement another measurement engine or a Python instrumentation SDK.
|
|
17
|
+
Python 3.10+ is required. Supported platform wheels include **Node.js 22.23.3**; no separate
|
|
18
|
+
Node or npm installation is needed. The launcher uses that bundled runtime, never downloads a
|
|
19
|
+
runtime when invoked, and does not silently switch to another CLI version.
|
|
20
|
+
|
|
21
|
+
Wheels target macOS 11+ (Intel and Apple Silicon), Linux with glibc 2.28+ (x64 and arm64), and
|
|
22
|
+
Windows 10+ (x64 and arm64). Linux also requires the Node-supported system C++ runtime
|
|
23
|
+
(GLIBCXX_3.4.25 or newer). Alpine/musl, 32-bit systems and other platforms are not supported.
|
|
24
|
+
A source distribution cannot fetch Node automatically: a source build requires the explicit
|
|
25
|
+
maintainer preparation step below. Supported users should install the matching wheel.
|
|
26
|
+
|
|
27
|
+
After publication under a verified WorkTrust-owned PyPI project, the intended commands are:
|
|
28
|
+
|
|
29
|
+
```sh
|
|
30
|
+
uvx worktrust preserve
|
|
31
|
+
pipx run worktrust preserve
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
These public commands are not a claim that this package has already been published. Test a
|
|
35
|
+
reviewed local wheel first:
|
|
36
|
+
|
|
37
|
+
```sh
|
|
38
|
+
uvx --from /absolute/path/worktrust-VERSION-py3-none-PLATFORM.whl worktrust --help
|
|
39
|
+
pipx run --spec /absolute/path/worktrust-VERSION-py3-none-PLATFORM.whl worktrust --help
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Use your package manager to choose and update the installed version. The package contains
|
|
43
|
+
the CLI modules and Node runtime, so `preserve` itself needs no network after installation. It reads supported
|
|
44
|
+
local session files and can change retention settings or create local metadata archives;
|
|
45
|
+
only the person runs it. Existing WorkTrust agent safeguards and consent prompts remain.
|
|
46
|
+
Other commands can contact WorkTrust. Package installation itself can contact registries.
|
|
47
|
+
|
|
48
|
+
After PyPI publication, explicitly request the latest published package when needed:
|
|
49
|
+
|
|
50
|
+
```sh
|
|
51
|
+
uvx worktrust@latest preserve
|
|
52
|
+
pipx run --no-cache worktrust preserve
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
For persistent installations, use `uv tool upgrade worktrust` or `pipx upgrade worktrust`.
|
|
56
|
+
An existing cache or version constraint can otherwise keep an older release. `worktrust update`
|
|
57
|
+
refreshes the computer coupling using the selected package; it does not upgrade the Python package.
|
|
58
|
+
|
|
59
|
+
Runtime bundle hashes detect missing or changed files; they are not hardware attestation or
|
|
60
|
+
independent proof of authenticity. Request and archive signatures retain the existing CLI's
|
|
61
|
+
software-key threat model. See the npm package SECURITY.md and README.md for the data contract.
|
|
62
|
+
|
|
63
|
+
## Maintainers
|
|
64
|
+
|
|
65
|
+
Running `node tools/worktrust-cli/sync.mjs` from the monorepo also regenerates the Python JavaScript
|
|
66
|
+
bundle and version. `node scripts/build-python-cli.mjs --check` refuses drift. The native runtime
|
|
67
|
+
is a separate build artifact, excluded from Git and sdists. Explicitly prepare it before building:
|
|
68
|
+
|
|
69
|
+
```sh
|
|
70
|
+
python tools/worktrust-python/build_runtime.py
|
|
71
|
+
python -m build --wheel tools/worktrust-python
|
|
72
|
+
python -m build --sdist tools/worktrust-python
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
`build_runtime.py` downloads one official Node archive from nodejs.org at build time, verifies its
|
|
76
|
+
committed SHA256 from `runtime-lock.json`, and extracts only the executable and complete LICENSE.
|
|
77
|
+
It accepts `--target` for a reviewed target and `--cache` for a build cache. Platform wheel tags
|
|
78
|
+
follow the selected runtime. Never label these wheels `any`. Building a wheel from the sdist
|
|
79
|
+
fails closed until this explicit preparation step has been performed; no install hook downloads code.
|
|
80
|
+
|
|
81
|
+
Run `python tools/worktrust-python/tests/test_runtime_build.py`, then
|
|
82
|
+
`node scripts/test-python-cli.mjs` with a Python containing the build requirements (select it with
|
|
83
|
+
`WORKTRUST_TEST_PYTHON`). Tests build and exercise a real wheel using its own runtime with no Node
|
|
84
|
+
on PATH; they use synthetic homes and metadata only. Native execution must pass independently on
|
|
85
|
+
all six claimed OS/architecture combinations before release. Cross-building alone is not that proof.
|
|
86
|
+
Set `WORKTRUST_REQUIRE_TOOL_RUNNERS=1` to require actual uv and pipx wheel smoke tests, and
|
|
87
|
+
`WORKTRUST_TEST_ARTIFACT_DIR` to a fresh directory to retain the exact tested wheel and sdist.
|
|
88
|
+
Existing artifacts are never overwritten. Canonical module bytes match across channels;
|
|
89
|
+
bit-for-bit reproducibility of whole wheel or sdist archives is not asserted.
|
|
90
|
+
|
|
91
|
+
The public `fhomey/worktrust-cli` repository carries this package under `python/`, alongside the
|
|
92
|
+
npm package at its root. There, install `python/requirements-release.txt`, run
|
|
93
|
+
`python python/build_runtime.py`, then `python python/tests/test_distribution.py` with
|
|
94
|
+
`WORKTRUST_TEST_CLI_SOURCE` set to the repository's absolute path and
|
|
95
|
+
`WORKTRUST_REQUIRE_TOOL_RUNNERS=1`. The test derives Node from the built wheel; it does not require
|
|
96
|
+
a system Node installation. Keep build-only workflow results distinct from successful publication.
|
|
97
|
+
|
|
98
|
+
The inactive `release-pypi.yml.example` targets this public layout. Its intended active filename
|
|
99
|
+
is `.github/workflows/release-pypi.yml`, using the protected `pypi` environment and PyPI Trusted
|
|
100
|
+
Publishing. Once activated, the same GitHub release triggers both registries; manual execution
|
|
101
|
+
supports the initial Python publication and retries. npm also requires the supported-platform Python
|
|
102
|
+
artifact/parity tests before publishing. Both channels use the same version and module bytes.
|
|
103
|
+
Approvals and registry failures remain separate; confirm both publications before announcing a
|
|
104
|
+
release as available on both channels. Neither workflow invokes a Vercel deployment.
|
|
105
|
+
|
|
106
|
+
Do not edit generated `bundle/`, `VERSION` or `LICENSE`. Publication requires confirmed
|
|
107
|
+
PyPI ownership and a configured Trusted Publisher; source readiness does not grant that.
|
|
108
|
+
|
|
109
|
+
Official runtime platform requirements: https://github.com/nodejs/node/blob/v22.23.3/BUILDING.md
|
|
110
|
+
Pinned upstream archive checksums: https://nodejs.org/dist/v22.23.3/SHASUMS256.txt
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# WorkTrust for Python tool runners
|
|
2
|
+
|
|
3
|
+
This package launches the same JavaScript measurement engine shipped in the WorkTrust npm
|
|
4
|
+
package. It does not implement another measurement engine or a Python instrumentation SDK.
|
|
5
|
+
Python 3.10+ is required. Supported platform wheels include **Node.js 22.23.3**; no separate
|
|
6
|
+
Node or npm installation is needed. The launcher uses that bundled runtime, never downloads a
|
|
7
|
+
runtime when invoked, and does not silently switch to another CLI version.
|
|
8
|
+
|
|
9
|
+
Wheels target macOS 11+ (Intel and Apple Silicon), Linux with glibc 2.28+ (x64 and arm64), and
|
|
10
|
+
Windows 10+ (x64 and arm64). Linux also requires the Node-supported system C++ runtime
|
|
11
|
+
(GLIBCXX_3.4.25 or newer). Alpine/musl, 32-bit systems and other platforms are not supported.
|
|
12
|
+
A source distribution cannot fetch Node automatically: a source build requires the explicit
|
|
13
|
+
maintainer preparation step below. Supported users should install the matching wheel.
|
|
14
|
+
|
|
15
|
+
After publication under a verified WorkTrust-owned PyPI project, the intended commands are:
|
|
16
|
+
|
|
17
|
+
```sh
|
|
18
|
+
uvx worktrust preserve
|
|
19
|
+
pipx run worktrust preserve
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
These public commands are not a claim that this package has already been published. Test a
|
|
23
|
+
reviewed local wheel first:
|
|
24
|
+
|
|
25
|
+
```sh
|
|
26
|
+
uvx --from /absolute/path/worktrust-VERSION-py3-none-PLATFORM.whl worktrust --help
|
|
27
|
+
pipx run --spec /absolute/path/worktrust-VERSION-py3-none-PLATFORM.whl worktrust --help
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Use your package manager to choose and update the installed version. The package contains
|
|
31
|
+
the CLI modules and Node runtime, so `preserve` itself needs no network after installation. It reads supported
|
|
32
|
+
local session files and can change retention settings or create local metadata archives;
|
|
33
|
+
only the person runs it. Existing WorkTrust agent safeguards and consent prompts remain.
|
|
34
|
+
Other commands can contact WorkTrust. Package installation itself can contact registries.
|
|
35
|
+
|
|
36
|
+
After PyPI publication, explicitly request the latest published package when needed:
|
|
37
|
+
|
|
38
|
+
```sh
|
|
39
|
+
uvx worktrust@latest preserve
|
|
40
|
+
pipx run --no-cache worktrust preserve
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
For persistent installations, use `uv tool upgrade worktrust` or `pipx upgrade worktrust`.
|
|
44
|
+
An existing cache or version constraint can otherwise keep an older release. `worktrust update`
|
|
45
|
+
refreshes the computer coupling using the selected package; it does not upgrade the Python package.
|
|
46
|
+
|
|
47
|
+
Runtime bundle hashes detect missing or changed files; they are not hardware attestation or
|
|
48
|
+
independent proof of authenticity. Request and archive signatures retain the existing CLI's
|
|
49
|
+
software-key threat model. See the npm package SECURITY.md and README.md for the data contract.
|
|
50
|
+
|
|
51
|
+
## Maintainers
|
|
52
|
+
|
|
53
|
+
Running `node tools/worktrust-cli/sync.mjs` from the monorepo also regenerates the Python JavaScript
|
|
54
|
+
bundle and version. `node scripts/build-python-cli.mjs --check` refuses drift. The native runtime
|
|
55
|
+
is a separate build artifact, excluded from Git and sdists. Explicitly prepare it before building:
|
|
56
|
+
|
|
57
|
+
```sh
|
|
58
|
+
python tools/worktrust-python/build_runtime.py
|
|
59
|
+
python -m build --wheel tools/worktrust-python
|
|
60
|
+
python -m build --sdist tools/worktrust-python
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
`build_runtime.py` downloads one official Node archive from nodejs.org at build time, verifies its
|
|
64
|
+
committed SHA256 from `runtime-lock.json`, and extracts only the executable and complete LICENSE.
|
|
65
|
+
It accepts `--target` for a reviewed target and `--cache` for a build cache. Platform wheel tags
|
|
66
|
+
follow the selected runtime. Never label these wheels `any`. Building a wheel from the sdist
|
|
67
|
+
fails closed until this explicit preparation step has been performed; no install hook downloads code.
|
|
68
|
+
|
|
69
|
+
Run `python tools/worktrust-python/tests/test_runtime_build.py`, then
|
|
70
|
+
`node scripts/test-python-cli.mjs` with a Python containing the build requirements (select it with
|
|
71
|
+
`WORKTRUST_TEST_PYTHON`). Tests build and exercise a real wheel using its own runtime with no Node
|
|
72
|
+
on PATH; they use synthetic homes and metadata only. Native execution must pass independently on
|
|
73
|
+
all six claimed OS/architecture combinations before release. Cross-building alone is not that proof.
|
|
74
|
+
Set `WORKTRUST_REQUIRE_TOOL_RUNNERS=1` to require actual uv and pipx wheel smoke tests, and
|
|
75
|
+
`WORKTRUST_TEST_ARTIFACT_DIR` to a fresh directory to retain the exact tested wheel and sdist.
|
|
76
|
+
Existing artifacts are never overwritten. Canonical module bytes match across channels;
|
|
77
|
+
bit-for-bit reproducibility of whole wheel or sdist archives is not asserted.
|
|
78
|
+
|
|
79
|
+
The public `fhomey/worktrust-cli` repository carries this package under `python/`, alongside the
|
|
80
|
+
npm package at its root. There, install `python/requirements-release.txt`, run
|
|
81
|
+
`python python/build_runtime.py`, then `python python/tests/test_distribution.py` with
|
|
82
|
+
`WORKTRUST_TEST_CLI_SOURCE` set to the repository's absolute path and
|
|
83
|
+
`WORKTRUST_REQUIRE_TOOL_RUNNERS=1`. The test derives Node from the built wheel; it does not require
|
|
84
|
+
a system Node installation. Keep build-only workflow results distinct from successful publication.
|
|
85
|
+
|
|
86
|
+
The inactive `release-pypi.yml.example` targets this public layout. Its intended active filename
|
|
87
|
+
is `.github/workflows/release-pypi.yml`, using the protected `pypi` environment and PyPI Trusted
|
|
88
|
+
Publishing. Once activated, the same GitHub release triggers both registries; manual execution
|
|
89
|
+
supports the initial Python publication and retries. npm also requires the supported-platform Python
|
|
90
|
+
artifact/parity tests before publishing. Both channels use the same version and module bytes.
|
|
91
|
+
Approvals and registry failures remain separate; confirm both publications before announcing a
|
|
92
|
+
release as available on both channels. Neither workflow invokes a Vercel deployment.
|
|
93
|
+
|
|
94
|
+
Do not edit generated `bundle/`, `VERSION` or `LICENSE`. Publication requires confirmed
|
|
95
|
+
PyPI ownership and a configured Trusted Publisher; source readiness does not grant that.
|
|
96
|
+
|
|
97
|
+
Official runtime platform requirements: https://github.com/nodejs/node/blob/v22.23.3/BUILDING.md
|
|
98
|
+
Pinned upstream archive checksums: https://nodejs.org/dist/v22.23.3/SHASUMS256.txt
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
0.10.13
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
"""Explicit build-time fetch of pinned official Node binaries. Never imported by the CLI."""
|
|
2
|
+
import argparse
|
|
3
|
+
import hashlib
|
|
4
|
+
import io
|
|
5
|
+
import json
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
import platform
|
|
8
|
+
import shutil
|
|
9
|
+
import stat
|
|
10
|
+
import tarfile
|
|
11
|
+
import tempfile
|
|
12
|
+
import urllib.request
|
|
13
|
+
import zipfile
|
|
14
|
+
|
|
15
|
+
ROOT = Path(__file__).resolve().parent
|
|
16
|
+
MAX_ARCHIVE = 150 * 1024 * 1024
|
|
17
|
+
MAX_BINARY = 200 * 1024 * 1024
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def host_target():
|
|
21
|
+
system = {"Darwin":"darwin", "Linux":"linux", "Windows":"win"}.get(platform.system())
|
|
22
|
+
architecture = {"x86_64":"x64", "amd64":"x64", "arm64":"arm64", "aarch64":"arm64"}.get(platform.machine().lower())
|
|
23
|
+
target = f"{system}-{architecture}"
|
|
24
|
+
if system is None or architecture is None:
|
|
25
|
+
raise ValueError(f"unsupported runtime platform: {target}")
|
|
26
|
+
return target
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def selected_members(data, archive_name, executable):
|
|
30
|
+
"""Copy only two exact regular members; never extract archive paths or links."""
|
|
31
|
+
suffix = ".zip" if archive_name.endswith(".zip") else ".tar.gz" if archive_name.endswith(".tar.gz") else ".tar.xz"
|
|
32
|
+
prefix = archive_name[:-len(suffix)]
|
|
33
|
+
expected = {f"{prefix}/{'node.exe' if executable == 'node.exe' else 'bin/node'}":executable,
|
|
34
|
+
f"{prefix}/LICENSE":"LICENSE"}
|
|
35
|
+
result = {}
|
|
36
|
+
if suffix == ".zip":
|
|
37
|
+
with zipfile.ZipFile(io.BytesIO(data)) as archive:
|
|
38
|
+
for member in archive.infolist():
|
|
39
|
+
if member.filename not in expected:
|
|
40
|
+
continue
|
|
41
|
+
mode = member.external_attr >> 16
|
|
42
|
+
if member.is_dir() or stat.S_ISLNK(mode) or (stat.S_IFMT(mode) not in (0, stat.S_IFREG)):
|
|
43
|
+
raise ValueError("runtime archive member must be a regular file")
|
|
44
|
+
if member.file_size > MAX_BINARY or member.filename in result:
|
|
45
|
+
raise ValueError("invalid runtime archive member")
|
|
46
|
+
result[member.filename] = archive.read(member)
|
|
47
|
+
else:
|
|
48
|
+
with tarfile.open(fileobj=io.BytesIO(data), mode="r:*") as archive:
|
|
49
|
+
for member in archive:
|
|
50
|
+
if member.name not in expected:
|
|
51
|
+
continue
|
|
52
|
+
if not member.isfile() or member.size > MAX_BINARY or member.name in result:
|
|
53
|
+
raise ValueError("invalid runtime archive member")
|
|
54
|
+
stream = archive.extractfile(member)
|
|
55
|
+
result[member.name] = stream.read(MAX_BINARY + 1)
|
|
56
|
+
if set(result) != set(expected):
|
|
57
|
+
raise ValueError("runtime archive is missing an expected file")
|
|
58
|
+
if any(not value or len(value) > MAX_BINARY for value in result.values()):
|
|
59
|
+
raise ValueError("runtime archive member size invalid")
|
|
60
|
+
return {expected[name]: value for name, value in result.items()}
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def prepare(target, cache):
|
|
64
|
+
lock = json.loads((ROOT / "runtime-lock.json").read_text())
|
|
65
|
+
item = lock["targets"].get(target)
|
|
66
|
+
if item is None:
|
|
67
|
+
raise ValueError(f"unsupported runtime target: {target}")
|
|
68
|
+
cache.mkdir(parents=True, exist_ok=True)
|
|
69
|
+
cached = cache / item["archive"]
|
|
70
|
+
if cached.is_symlink():
|
|
71
|
+
raise ValueError("runtime archive cache must not be a symlink")
|
|
72
|
+
if cached.exists():
|
|
73
|
+
if cached.stat().st_size > MAX_ARCHIVE:
|
|
74
|
+
raise ValueError("runtime archive too large")
|
|
75
|
+
data = cached.read_bytes()
|
|
76
|
+
else:
|
|
77
|
+
request = urllib.request.Request(lock["base_url"] + item["archive"], headers={"User-Agent":"WorkTrust-runtime-build"})
|
|
78
|
+
with urllib.request.urlopen(request, timeout=60) as response:
|
|
79
|
+
if not response.url.startswith("https://nodejs.org/dist/"):
|
|
80
|
+
raise ValueError("runtime download redirected away from official origin")
|
|
81
|
+
data = response.read(MAX_ARCHIVE + 1)
|
|
82
|
+
if len(data) > MAX_ARCHIVE or hashlib.sha256(data).hexdigest() != item["sha256"]:
|
|
83
|
+
raise ValueError("official runtime archive checksum mismatch")
|
|
84
|
+
if not cached.exists():
|
|
85
|
+
with tempfile.NamedTemporaryFile(dir=cache, delete=False) as handle:
|
|
86
|
+
handle.write(data)
|
|
87
|
+
pending = Path(handle.name)
|
|
88
|
+
pending.replace(cached)
|
|
89
|
+
executable = "node.exe" if target.startswith("win-") else "node"
|
|
90
|
+
members = selected_members(data, item["archive"], executable)
|
|
91
|
+
destination = ROOT / "src/worktrust_cli/runtime"
|
|
92
|
+
if destination.is_symlink():
|
|
93
|
+
raise ValueError("runtime staging directory must not be a symlink")
|
|
94
|
+
destination.mkdir(parents=True, exist_ok=True)
|
|
95
|
+
for entry in destination.iterdir():
|
|
96
|
+
if entry.is_dir() and not entry.is_symlink():
|
|
97
|
+
raise ValueError("unexpected directory in runtime stage")
|
|
98
|
+
entry.unlink()
|
|
99
|
+
for name, payload in members.items():
|
|
100
|
+
path = destination/name
|
|
101
|
+
path.write_bytes(payload)
|
|
102
|
+
path.chmod(0o755 if name == executable else 0o644)
|
|
103
|
+
descriptor = {"version":lock["version"], "platform":target, "executable":executable,
|
|
104
|
+
"archive_sha256":item["sha256"],
|
|
105
|
+
"files":{name:hashlib.sha256(payload).hexdigest() for name,payload in sorted(members.items())}}
|
|
106
|
+
(destination/"runtime.json").write_text(json.dumps(descriptor,indent=2)+"\n")
|
|
107
|
+
print(f"Staged Node {lock['version']} for {target}; official archive SHA256 verified")
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
if __name__ == "__main__":
|
|
111
|
+
parser = argparse.ArgumentParser(description=__doc__)
|
|
112
|
+
parser.add_argument("--target", default=host_target())
|
|
113
|
+
parser.add_argument("--cache", type=Path, default=Path(tempfile.gettempdir())/"worktrust-node-build-cache")
|
|
114
|
+
args = parser.parse_args()
|
|
115
|
+
prepare(args.target, args.cache)
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=77"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "worktrust"
|
|
7
|
+
dynamic = ["version"]
|
|
8
|
+
description = "The WorkTrust CLI, using the same measurement engine as npm"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.10"
|
|
11
|
+
license = "MIT"
|
|
12
|
+
license-files = ["LICENSE"]
|
|
13
|
+
dependencies = []
|
|
14
|
+
|
|
15
|
+
[project.scripts]
|
|
16
|
+
worktrust = "worktrust_cli:main"
|
|
17
|
+
|
|
18
|
+
[project.urls]
|
|
19
|
+
Homepage = "https://worktrust.io"
|
|
20
|
+
Source = "https://github.com/fhomey/worktrust-cli"
|
|
21
|
+
|
|
22
|
+
[tool.setuptools.dynamic]
|
|
23
|
+
version = {file = "VERSION"}
|
|
24
|
+
|
|
25
|
+
[tool.setuptools.packages.find]
|
|
26
|
+
where = ["src"]
|
|
27
|
+
|
|
28
|
+
[tool.setuptools.package-data]
|
|
29
|
+
worktrust_cli = ["bundle/*.mjs", "bundle/manifest.json", "runtime/*"]
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": "22.23.3",
|
|
3
|
+
"base_url": "https://nodejs.org/dist/v22.23.3/",
|
|
4
|
+
"targets": {
|
|
5
|
+
"darwin-arm64": {
|
|
6
|
+
"archive": "node-v22.23.3-darwin-arm64.tar.gz",
|
|
7
|
+
"sha256": "23b25245dcfb9af7262f8ff142e9e2e0af025368117329e7a7458a51e5922f53",
|
|
8
|
+
"wheel_tag": "macosx_11_0_arm64"
|
|
9
|
+
},
|
|
10
|
+
"darwin-x64": {
|
|
11
|
+
"archive": "node-v22.23.3-darwin-x64.tar.gz",
|
|
12
|
+
"sha256": "8a677b0219178efd6eb0e475457c4afb452b521a92f6e67845a73bd85727f2a8",
|
|
13
|
+
"wheel_tag": "macosx_11_0_x86_64"
|
|
14
|
+
},
|
|
15
|
+
"linux-arm64": {
|
|
16
|
+
"archive": "node-v22.23.3-linux-arm64.tar.xz",
|
|
17
|
+
"sha256": "a44aeb94849a299b22df10b9e622ec2f605c2183501bc40590705131de7c740f",
|
|
18
|
+
"wheel_tag": "manylinux_2_28_aarch64"
|
|
19
|
+
},
|
|
20
|
+
"linux-x64": {
|
|
21
|
+
"archive": "node-v22.23.3-linux-x64.tar.xz",
|
|
22
|
+
"sha256": "df450af89261115ef9f9e3830c3eeb2cc9213b63c720b1af623cb5dcbe2e02de",
|
|
23
|
+
"wheel_tag": "manylinux_2_28_x86_64"
|
|
24
|
+
},
|
|
25
|
+
"win-arm64": {
|
|
26
|
+
"archive": "node-v22.23.3-win-arm64.zip",
|
|
27
|
+
"sha256": "33dad22e4cef5ee8f9fbb1b0d037fdacd0e56d12a4580f0d63f68b894deab535",
|
|
28
|
+
"wheel_tag": "win_arm64"
|
|
29
|
+
},
|
|
30
|
+
"win-x64": {
|
|
31
|
+
"archive": "node-v22.23.3-win-x64.zip",
|
|
32
|
+
"sha256": "2b0ff57b049cda1bbcea2240eec20467018713c1efe1f7360c2681859b90ed71",
|
|
33
|
+
"wheel_tag": "win_amd64"
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"""Platform wheels carrying Node; Python code itself has no interpreter-specific ABI."""
|
|
2
|
+
import hashlib
|
|
3
|
+
import json
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from setuptools import setup
|
|
6
|
+
from setuptools.dist import Distribution
|
|
7
|
+
from setuptools.command.build_py import build_py
|
|
8
|
+
from setuptools.command.bdist_wheel import bdist_wheel
|
|
9
|
+
|
|
10
|
+
ROOT = Path(__file__).resolve().parent
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def runtime():
|
|
14
|
+
directory = ROOT/"src/worktrust_cli/runtime"
|
|
15
|
+
descriptor = directory/"runtime.json"
|
|
16
|
+
if not descriptor.is_file() or descriptor.is_symlink():
|
|
17
|
+
raise RuntimeError("Bundled runtime is absent. Run python build_runtime.py explicitly before building a wheel; runtime downloads never occur during installation or CLI execution.")
|
|
18
|
+
data = json.loads(descriptor.read_text())
|
|
19
|
+
lock = json.loads((ROOT/"runtime-lock.json").read_text())
|
|
20
|
+
expected = lock["targets"].get(data["platform"])
|
|
21
|
+
if expected is None or data["version"] != lock["version"] or data["archive_sha256"] != expected["sha256"]:
|
|
22
|
+
raise RuntimeError("Staged runtime does not match the reviewed runtime lock")
|
|
23
|
+
executable = "node.exe" if data["platform"].startswith("win-") else "node"
|
|
24
|
+
if data["executable"] != executable or set(data["files"]) != {executable,"LICENSE"}:
|
|
25
|
+
raise RuntimeError("Staged runtime has an invalid file list")
|
|
26
|
+
if {path.name for path in directory.iterdir()} != {executable,"LICENSE","runtime.json"}:
|
|
27
|
+
raise RuntimeError("Unexpected runtime file")
|
|
28
|
+
for name,digest in data["files"].items():
|
|
29
|
+
path = directory/name
|
|
30
|
+
if path.is_symlink() or hashlib.sha256(path.read_bytes()).hexdigest() != digest:
|
|
31
|
+
raise RuntimeError("Staged runtime integrity mismatch")
|
|
32
|
+
return expected["wheel_tag"]
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class BuildPython(build_py):
|
|
36
|
+
def run(self):
|
|
37
|
+
runtime()
|
|
38
|
+
super().run()
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class PlatformWheel(bdist_wheel):
|
|
42
|
+
def finalize_options(self):
|
|
43
|
+
super().finalize_options()
|
|
44
|
+
self.root_is_pure = False
|
|
45
|
+
|
|
46
|
+
def get_tag(self):
|
|
47
|
+
return "py3", "none", runtime()
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
class BinaryDistribution(Distribution):
|
|
51
|
+
def has_ext_modules(self):
|
|
52
|
+
return True
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
setup(distclass=BinaryDistribution, cmdclass={"build_py":BuildPython,"bdist_wheel":PlatformWheel})
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: worktrust
|
|
3
|
+
Version: 0.10.13
|
|
4
|
+
Summary: The WorkTrust CLI, using the same measurement engine as npm
|
|
5
|
+
License-Expression: MIT
|
|
6
|
+
Project-URL: Homepage, https://worktrust.io
|
|
7
|
+
Project-URL: Source, https://github.com/fhomey/worktrust-cli
|
|
8
|
+
Requires-Python: >=3.10
|
|
9
|
+
Description-Content-Type: text/markdown
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Dynamic: license-file
|
|
12
|
+
|
|
13
|
+
# WorkTrust for Python tool runners
|
|
14
|
+
|
|
15
|
+
This package launches the same JavaScript measurement engine shipped in the WorkTrust npm
|
|
16
|
+
package. It does not implement another measurement engine or a Python instrumentation SDK.
|
|
17
|
+
Python 3.10+ is required. Supported platform wheels include **Node.js 22.23.3**; no separate
|
|
18
|
+
Node or npm installation is needed. The launcher uses that bundled runtime, never downloads a
|
|
19
|
+
runtime when invoked, and does not silently switch to another CLI version.
|
|
20
|
+
|
|
21
|
+
Wheels target macOS 11+ (Intel and Apple Silicon), Linux with glibc 2.28+ (x64 and arm64), and
|
|
22
|
+
Windows 10+ (x64 and arm64). Linux also requires the Node-supported system C++ runtime
|
|
23
|
+
(GLIBCXX_3.4.25 or newer). Alpine/musl, 32-bit systems and other platforms are not supported.
|
|
24
|
+
A source distribution cannot fetch Node automatically: a source build requires the explicit
|
|
25
|
+
maintainer preparation step below. Supported users should install the matching wheel.
|
|
26
|
+
|
|
27
|
+
After publication under a verified WorkTrust-owned PyPI project, the intended commands are:
|
|
28
|
+
|
|
29
|
+
```sh
|
|
30
|
+
uvx worktrust preserve
|
|
31
|
+
pipx run worktrust preserve
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
These public commands are not a claim that this package has already been published. Test a
|
|
35
|
+
reviewed local wheel first:
|
|
36
|
+
|
|
37
|
+
```sh
|
|
38
|
+
uvx --from /absolute/path/worktrust-VERSION-py3-none-PLATFORM.whl worktrust --help
|
|
39
|
+
pipx run --spec /absolute/path/worktrust-VERSION-py3-none-PLATFORM.whl worktrust --help
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Use your package manager to choose and update the installed version. The package contains
|
|
43
|
+
the CLI modules and Node runtime, so `preserve` itself needs no network after installation. It reads supported
|
|
44
|
+
local session files and can change retention settings or create local metadata archives;
|
|
45
|
+
only the person runs it. Existing WorkTrust agent safeguards and consent prompts remain.
|
|
46
|
+
Other commands can contact WorkTrust. Package installation itself can contact registries.
|
|
47
|
+
|
|
48
|
+
After PyPI publication, explicitly request the latest published package when needed:
|
|
49
|
+
|
|
50
|
+
```sh
|
|
51
|
+
uvx worktrust@latest preserve
|
|
52
|
+
pipx run --no-cache worktrust preserve
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
For persistent installations, use `uv tool upgrade worktrust` or `pipx upgrade worktrust`.
|
|
56
|
+
An existing cache or version constraint can otherwise keep an older release. `worktrust update`
|
|
57
|
+
refreshes the computer coupling using the selected package; it does not upgrade the Python package.
|
|
58
|
+
|
|
59
|
+
Runtime bundle hashes detect missing or changed files; they are not hardware attestation or
|
|
60
|
+
independent proof of authenticity. Request and archive signatures retain the existing CLI's
|
|
61
|
+
software-key threat model. See the npm package SECURITY.md and README.md for the data contract.
|
|
62
|
+
|
|
63
|
+
## Maintainers
|
|
64
|
+
|
|
65
|
+
Running `node tools/worktrust-cli/sync.mjs` from the monorepo also regenerates the Python JavaScript
|
|
66
|
+
bundle and version. `node scripts/build-python-cli.mjs --check` refuses drift. The native runtime
|
|
67
|
+
is a separate build artifact, excluded from Git and sdists. Explicitly prepare it before building:
|
|
68
|
+
|
|
69
|
+
```sh
|
|
70
|
+
python tools/worktrust-python/build_runtime.py
|
|
71
|
+
python -m build --wheel tools/worktrust-python
|
|
72
|
+
python -m build --sdist tools/worktrust-python
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
`build_runtime.py` downloads one official Node archive from nodejs.org at build time, verifies its
|
|
76
|
+
committed SHA256 from `runtime-lock.json`, and extracts only the executable and complete LICENSE.
|
|
77
|
+
It accepts `--target` for a reviewed target and `--cache` for a build cache. Platform wheel tags
|
|
78
|
+
follow the selected runtime. Never label these wheels `any`. Building a wheel from the sdist
|
|
79
|
+
fails closed until this explicit preparation step has been performed; no install hook downloads code.
|
|
80
|
+
|
|
81
|
+
Run `python tools/worktrust-python/tests/test_runtime_build.py`, then
|
|
82
|
+
`node scripts/test-python-cli.mjs` with a Python containing the build requirements (select it with
|
|
83
|
+
`WORKTRUST_TEST_PYTHON`). Tests build and exercise a real wheel using its own runtime with no Node
|
|
84
|
+
on PATH; they use synthetic homes and metadata only. Native execution must pass independently on
|
|
85
|
+
all six claimed OS/architecture combinations before release. Cross-building alone is not that proof.
|
|
86
|
+
Set `WORKTRUST_REQUIRE_TOOL_RUNNERS=1` to require actual uv and pipx wheel smoke tests, and
|
|
87
|
+
`WORKTRUST_TEST_ARTIFACT_DIR` to a fresh directory to retain the exact tested wheel and sdist.
|
|
88
|
+
Existing artifacts are never overwritten. Canonical module bytes match across channels;
|
|
89
|
+
bit-for-bit reproducibility of whole wheel or sdist archives is not asserted.
|
|
90
|
+
|
|
91
|
+
The public `fhomey/worktrust-cli` repository carries this package under `python/`, alongside the
|
|
92
|
+
npm package at its root. There, install `python/requirements-release.txt`, run
|
|
93
|
+
`python python/build_runtime.py`, then `python python/tests/test_distribution.py` with
|
|
94
|
+
`WORKTRUST_TEST_CLI_SOURCE` set to the repository's absolute path and
|
|
95
|
+
`WORKTRUST_REQUIRE_TOOL_RUNNERS=1`. The test derives Node from the built wheel; it does not require
|
|
96
|
+
a system Node installation. Keep build-only workflow results distinct from successful publication.
|
|
97
|
+
|
|
98
|
+
The inactive `release-pypi.yml.example` targets this public layout. Its intended active filename
|
|
99
|
+
is `.github/workflows/release-pypi.yml`, using the protected `pypi` environment and PyPI Trusted
|
|
100
|
+
Publishing. Once activated, the same GitHub release triggers both registries; manual execution
|
|
101
|
+
supports the initial Python publication and retries. npm also requires the supported-platform Python
|
|
102
|
+
artifact/parity tests before publishing. Both channels use the same version and module bytes.
|
|
103
|
+
Approvals and registry failures remain separate; confirm both publications before announcing a
|
|
104
|
+
release as available on both channels. Neither workflow invokes a Vercel deployment.
|
|
105
|
+
|
|
106
|
+
Do not edit generated `bundle/`, `VERSION` or `LICENSE`. Publication requires confirmed
|
|
107
|
+
PyPI ownership and a configured Trusted Publisher; source readiness does not grant that.
|
|
108
|
+
|
|
109
|
+
Official runtime platform requirements: https://github.com/nodejs/node/blob/v22.23.3/BUILDING.md
|
|
110
|
+
Pinned upstream archive checksums: https://nodejs.org/dist/v22.23.3/SHASUMS256.txt
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
LICENSE
|
|
2
|
+
MANIFEST.in
|
|
3
|
+
README.md
|
|
4
|
+
VERSION
|
|
5
|
+
build_runtime.py
|
|
6
|
+
pyproject.toml
|
|
7
|
+
runtime-lock.json
|
|
8
|
+
setup.py
|
|
9
|
+
src/worktrust.egg-info/PKG-INFO
|
|
10
|
+
src/worktrust.egg-info/SOURCES.txt
|
|
11
|
+
src/worktrust.egg-info/dependency_links.txt
|
|
12
|
+
src/worktrust.egg-info/entry_points.txt
|
|
13
|
+
src/worktrust.egg-info/top_level.txt
|
|
14
|
+
src/worktrust_cli/__init__.py
|
|
15
|
+
src/worktrust_cli/__main__.py
|
|
16
|
+
src/worktrust_cli/bundle/chat-exports.mjs
|
|
17
|
+
src/worktrust_cli/bundle/config-edits.mjs
|
|
18
|
+
src/worktrust_cli/bundle/count-behaviour.mjs
|
|
19
|
+
src/worktrust_cli/bundle/log-session.mjs
|
|
20
|
+
src/worktrust_cli/bundle/manifest.json
|
|
21
|
+
src/worktrust_cli/bundle/preserve-lines.mjs
|
|
22
|
+
src/worktrust_cli/bundle/preserve-summary.mjs
|
|
23
|
+
src/worktrust_cli/bundle/preserve.mjs
|
|
24
|
+
src/worktrust_cli/bundle/runtime-install.mjs
|
|
25
|
+
src/worktrust_cli/bundle/session-databases.mjs
|
|
26
|
+
src/worktrust_cli/bundle/setup-mcp.mjs
|
|
27
|
+
src/worktrust_cli/bundle/stack-rules.mjs
|
|
28
|
+
src/worktrust_cli/bundle/stretch-evidence.mjs
|
|
29
|
+
src/worktrust_cli/bundle/transcript-readers.mjs
|
|
30
|
+
src/worktrust_cli/bundle/worktrust.mjs
|
|
31
|
+
tests/test_distribution.py
|
|
32
|
+
tests/test_runtime_build.py
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
worktrust_cli
|