tailkitty 0.1.0__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.
Files changed (46) hide show
  1. tailkitty-0.1.0/.gitignore +11 -0
  2. tailkitty-0.1.0/.mise.toml +60 -0
  3. tailkitty-0.1.0/.python-version +2 -0
  4. tailkitty-0.1.0/AGENTS.md +167 -0
  5. tailkitty-0.1.0/BUILDING.md +42 -0
  6. tailkitty-0.1.0/CHANGELOG.md +11 -0
  7. tailkitty-0.1.0/COMPARISON.md +22 -0
  8. tailkitty-0.1.0/ITERATIONS.md +135 -0
  9. tailkitty-0.1.0/LICENSE +28 -0
  10. tailkitty-0.1.0/PKG-INFO +391 -0
  11. tailkitty-0.1.0/README.md +367 -0
  12. tailkitty-0.1.0/SECURITY.md +18 -0
  13. tailkitty-0.1.0/THIRD_PARTY_NOTICES.md +13 -0
  14. tailkitty-0.1.0/hatch_build.py +52 -0
  15. tailkitty-0.1.0/pyproject.toml +73 -0
  16. tailkitty-0.1.0/scripts/__init__.py +1 -0
  17. tailkitty-0.1.0/scripts/build_binary.py +202 -0
  18. tailkitty-0.1.0/scripts/build_wheels.py +67 -0
  19. tailkitty-0.1.0/scripts/smoke_wheel.py +59 -0
  20. tailkitty-0.1.0/scripts/targets.py +95 -0
  21. tailkitty-0.1.0/scripts/verify_wheel.py +113 -0
  22. tailkitty-0.1.0/src/tailkitty/__init__.py +40 -0
  23. tailkitty-0.1.0/src/tailkitty/__main__.py +5 -0
  24. tailkitty-0.1.0/src/tailkitty/backend.py +107 -0
  25. tailkitty-0.1.0/src/tailkitty/bundle.py +139 -0
  26. tailkitty-0.1.0/src/tailkitty/cli.py +82 -0
  27. tailkitty-0.1.0/src/tailkitty/client.py +150 -0
  28. tailkitty-0.1.0/src/tailkitty/constants.py +7 -0
  29. tailkitty-0.1.0/src/tailkitty/derp.py +140 -0
  30. tailkitty-0.1.0/src/tailkitty/destination.py +66 -0
  31. tailkitty-0.1.0/src/tailkitty/diagnostics.py +38 -0
  32. tailkitty-0.1.0/src/tailkitty/process.py +322 -0
  33. tailkitty-0.1.0/src/tailkitty/py.typed +1 -0
  34. tailkitty-0.1.0/src/tailkitty/token.py +259 -0
  35. tailkitty-0.1.0/tests/test_backend.py +53 -0
  36. tailkitty-0.1.0/tests/test_bundle.py +111 -0
  37. tailkitty-0.1.0/tests/test_cli.py +27 -0
  38. tailkitty-0.1.0/tests/test_derp.py +60 -0
  39. tailkitty-0.1.0/tests/test_destination.py +32 -0
  40. tailkitty-0.1.0/tests/test_module.py +14 -0
  41. tailkitty-0.1.0/tests/test_process.py +88 -0
  42. tailkitty-0.1.0/tests/test_project.py +38 -0
  43. tailkitty-0.1.0/tests/test_targets.py +19 -0
  44. tailkitty-0.1.0/tests/test_token.py +94 -0
  45. tailkitty-0.1.0/tests/test_token_validation.py +32 -0
  46. tailkitty-0.1.0/uv.lock +692 -0
@@ -0,0 +1,11 @@
1
+ .venv/
2
+ .cache/
3
+ .tools/
4
+ __pycache__/
5
+ *.py[cod]
6
+ .pytest_cache/
7
+ .coverage
8
+ dist/
9
+ src/tailkitty/bin/tailcat
10
+ src/tailkitty/bin/tailcat.exe
11
+ src/tailkitty/bin/manifest.json
@@ -0,0 +1,60 @@
1
+ [tools]
2
+ python = "3.13.11"
3
+ go = "1.26.5"
4
+ uv = "0.12.7"
5
+
6
+ [env]
7
+ UV_CACHE_DIR = "{{config_root}}/.cache/uv"
8
+
9
+ [tasks.setup]
10
+ description = "Install Python dependencies and the interoperable Tailcat backend"
11
+ run = [
12
+ "uv sync --all-groups",
13
+ "mise run backend",
14
+ ]
15
+
16
+ [tasks.backend]
17
+ description = "Build the upstream Tailcat data-plane helper"
18
+ run = "uv run python -m scripts.build_binary build --output .tools/bin"
19
+
20
+ [tasks.bundle]
21
+ description = "Build a bundled executable for the host platform"
22
+ run = "uv run python -m scripts.build_binary build --target host --output src/tailkitty/bin"
23
+
24
+ [tasks.bundle-verify]
25
+ description = "Verify the bundled executable and integrity manifest"
26
+ run = "uv run python -m scripts.build_binary verify --output src/tailkitty/bin"
27
+
28
+ [tasks.bundle-clean]
29
+ description = "Remove generated bundled executable files"
30
+ run = "uv run python -m scripts.build_binary clean --output src/tailkitty/bin"
31
+
32
+ [tasks.wheel]
33
+ description = "Build a platform wheel containing the host executable"
34
+ depends = ["bundle", "bundle-verify"]
35
+ run = "uv build --wheel"
36
+
37
+ [tasks.wheels]
38
+ description = "Build and verify all supported platform wheels"
39
+ run = "uv run python -m scripts.build_wheels"
40
+
41
+ [tasks.wheel-smoke]
42
+ description = "Install and inspect the bundled host wheel in an isolated environment"
43
+ run = "uv run python -m scripts.smoke_wheel"
44
+
45
+ [tasks.test]
46
+ description = "Run the Python test suite"
47
+ run = [
48
+ "uv run ruff check src tests scripts hatch_build.py",
49
+ "uv run ruff format --check src tests scripts hatch_build.py",
50
+ "uv run mypy src scripts",
51
+ "uv run pytest",
52
+ ]
53
+
54
+ [tasks.tailkitty]
55
+ description = "Run Tailkitty"
56
+ run = "uv run tailkitty"
57
+
58
+ [tasks.tailcat]
59
+ description = "Run Tailkitty through its Tailcat-compatible alias"
60
+ run = "uv run tailcat"
@@ -0,0 +1,2 @@
1
+ 3.13.11
2
+
@@ -0,0 +1,167 @@
1
+ # Repository instructions for coding agents
2
+
3
+ These instructions apply to the entire repository. They supplement the user request; they do not
4
+ override it.
5
+
6
+ ## Start here
7
+
8
+ Read these files before making architectural, packaging, security, or release changes:
9
+
10
+ 1. `README.md` for the product boundary and public behavior.
11
+ 2. `SECURITY.md` for executable trust and authorization concerns.
12
+ 3. `BUILDING.md` for the reproducible bundle and wheel pipeline.
13
+ 4. `pyproject.toml` and `.mise.toml` for supported versions and canonical tasks.
14
+
15
+ Do not confuse Tailkitty with the separate `pytailcat` distribution on PyPI. This checkout is the
16
+ source of truth for Tailkitty; upstream Tailcat remains the data-plane source of truth.
17
+
18
+ ## Architecture and non-negotiable boundaries
19
+
20
+ The project intentionally has two layers:
21
+
22
+ - The control plane is Python: token encoding/decoding, validation, DNS TXT lookup, DERP-map
23
+ resolution/cache, typed clients, diagnostics, and process lifecycle.
24
+ - The network data plane is the pinned upstream Go Tailcat executable: magicsock, userspace
25
+ WireGuard, DERP transport, and gVisor netstack.
26
+
27
+ Do not replace the data plane with a Python-only protocol that interoperates only with itself. Do
28
+ not silently fall back from a corrupt bundled executable to an unverified backend. Wire
29
+ compatibility and fail-closed bundle discovery are core requirements.
30
+
31
+ ## Repository map
32
+
33
+ | Path | Responsibility |
34
+ | --- | --- |
35
+ | `src/tailkitty/token.py` | Tailcat CBOR/base64url wire format and DERP embedding |
36
+ | `src/tailkitty/destination.py` | Literal-token and DNS TXT destination resolution |
37
+ | `src/tailkitty/derp.py` | Validated, bounded, atomic DERP-map caching |
38
+ | `src/tailkitty/backend.py` | Backend precedence and command execution |
39
+ | `src/tailkitty/bundle.py` | Runtime manifest and executable integrity checks |
40
+ | `src/tailkitty/client.py` | Sync and asyncio client APIs |
41
+ | `src/tailkitty/process.py` | Managed server processes and low-level async execution |
42
+ | `src/tailkitty/cli.py` | Python-native commands and upstream pass-through |
43
+ | `src/tailkitty/constants.py` | Package, Go, module, and upstream Tailcat pins |
44
+ | `scripts/targets.py` | Supported build targets and wheel tags |
45
+ | `scripts/build_binary.py` | Reproducible cross-compilation and manifest creation |
46
+ | `scripts/build_wheels.py` | Isolated five-target wheel orchestration |
47
+ | `scripts/verify_wheel.py` | Wheel metadata, archive, binary, and RECORD verification |
48
+ | `hatch_build.py` | Platform-wheel build hook |
49
+ | `tests/` | Unit and subprocess behavior tests |
50
+
51
+ Public imports are curated in `src/tailkitty/__init__.py`. Adding a public API requires updating
52
+ that file, type annotations, tests, and README documentation.
53
+
54
+ ## Environment and canonical commands
55
+
56
+ Use mise and uv; do not introduce a parallel virtualenv, dependency manager, or ad hoc Go version.
57
+
58
+ ```console
59
+ mise install
60
+ uv sync --all-groups --locked
61
+ mise run test
62
+ ```
63
+
64
+ `mise run test` is the required local quality gate. It runs Ruff linting, Ruff formatting checks,
65
+ strict mypy, and pytest. During iteration, run the narrowest relevant test first, then run the full
66
+ gate before declaring completion.
67
+
68
+ Packaging changes also require:
69
+
70
+ ```console
71
+ mise run bundle
72
+ mise run bundle-verify
73
+ mise run wheels
74
+ uv run python -m scripts.smoke_wheel dist/wheels/<host-wheel>.whl
75
+ ```
76
+
77
+ For Python-version compatibility changes, test the minimum version:
78
+
79
+ ```console
80
+ uv run --isolated --python 3.11 --all-groups pytest
81
+ ```
82
+
83
+ Public DERP relays are external and can be unavailable or rate-limited. Keep unit tests deterministic
84
+ and do not make the default test suite depend on a live relay. Report live integration timeouts
85
+ honestly rather than treating them as proof of a local regression or success.
86
+
87
+ ## Version and build invariants
88
+
89
+ - `TAILKITTY_VERSION` must match `[project].version` in `pyproject.toml`.
90
+ - `GO_VERSION` must match `[tools].go` in `.mise.toml` exactly.
91
+ - `TAILCAT_VERSION` must remain an immutable upstream version or pseudo-version.
92
+ - Bundle builds must use the exact Go toolchain with `GOTOOLCHAIN=local`.
93
+ - Keep `CGO_ENABLED=0`, `-trimpath`, `-buildvcs=false`, the empty build ID, stripped symbols, and
94
+ baseline CPU feature levels unless a documented compatibility decision changes them.
95
+ - Every platform wheel must be non-pure and tagged for exactly one supported target.
96
+ - Source distributions and pure-Python fallback wheels must contain no generated executable or
97
+ bundle manifest.
98
+ - Do not invent a platform tag. Update `scripts/targets.py`, build validation, CI, tests, and docs as
99
+ one change when adding a target.
100
+
101
+ ## Backend and security invariants
102
+
103
+ Backend priority is:
104
+
105
+ 1. `TAILKITTY_BACKEND`, which must be executable or fail immediately.
106
+ 2. A verified, runtime-compatible bundled executable.
107
+ 3. `.tools/bin/tailcat`, followed by the legacy `.tools/bin/tailcat-go` path.
108
+ 4. `tailcat-go` on `PATH`.
109
+
110
+ Preserve these behaviors:
111
+
112
+ - A present but invalid bundle is an integrity error; it must not trigger fallback.
113
+ - Manifest filenames cannot contain paths, and bundled executables cannot be symlinks.
114
+ - Runtime checks cover schema, module, revision, platform, size, and SHA-256.
115
+ - `allow=None` preserves upstream's allow-all behavior; `allow=[]` must become `--allow=none`.
116
+ - Timeout and cancellation paths must terminate and reap child processes.
117
+ - Cache files remain bounded, private, atomically replaced, and safe to use stale after refresh
118
+ failure.
119
+ - Never log saved private keys or embed real active connection addresses in fixtures or docs.
120
+
121
+ ## CLI compatibility
122
+
123
+ The Python CLI owns only `parse`, `resolve`, `doctor`, `--version`, and top-level help. All other
124
+ argument sequences must pass unchanged to the upstream executable, including no arguments.
125
+
126
+ When changing command dispatch, test both the Python-native commands and an arbitrary upstream
127
+ argument sequence. Do not add a Python subcommand whose name silently shadows an upstream command
128
+ without an explicit compatibility decision.
129
+
130
+ ## Code and test conventions
131
+
132
+ - Support Python 3.11 and newer.
133
+ - Keep complete annotations and strict-mypy compatibility.
134
+ - Prefer standard-library types and small typed dataclasses over untyped dictionaries at public
135
+ boundaries.
136
+ - Keep synchronous and asyncio behavior aligned, especially timeout, cancellation, and cleanup.
137
+ - Validate external input early with domain-specific exceptions (`TokenError`, `DestinationError`,
138
+ `DerpMapError`, `BundleError`, or `BackendNotFound`).
139
+ - Add regression tests for bug fixes. Avoid weakening a safety check merely to satisfy a fixture.
140
+ - Use temporary directories in tests; never depend on or overwrite a developer's saved Tailcat
141
+ keys, cache, bundle, or configured backend.
142
+ - Keep Ruff's 100-character line length and run formatting rather than hand-aligning code.
143
+
144
+ ## Generated files and release safety
145
+
146
+ Do not manually edit or commit generated files under:
147
+
148
+ - `src/tailkitty/bin/`
149
+ - `dist/`
150
+ - `.tools/bin/`
151
+ - cache, virtualenv, or `__pycache__` directories
152
+
153
+ Use the scripts and mise tasks that own those artifacts. Publish only the `tailkitty` distribution;
154
+ the `pytailcat` name belongs to another project. Before a release, verify project URLs and the `pypi`
155
+ GitHub environment, build all five wheels plus the source distribution, smoke-test the host wheel,
156
+ and retain checksums and provenance attestations.
157
+
158
+ ## Definition of done
159
+
160
+ A change is complete when:
161
+
162
+ 1. The implementation respects the Python/native boundary and security invariants.
163
+ 2. Focused regression tests cover new behavior or the repaired failure.
164
+ 3. Public behavior and types are documented where users will find them.
165
+ 4. `mise run test` passes.
166
+ 5. Packaging changes pass the full wheel matrix and host installation smoke test.
167
+ 6. Remaining external limitations or unverified assumptions are stated explicitly.
@@ -0,0 +1,42 @@
1
+ # Building bundled wheels
2
+
3
+ The environment is fully pinned by mise: Python 3.13.11, Go 1.26.5, and uv 0.12.7.
4
+
5
+ ```console
6
+ mise install
7
+ uv sync --all-groups --locked
8
+ mise run test
9
+ mise run wheels
10
+ ```
11
+
12
+ `mise run wheels` cross-compiles the exact Tailcat revision in `constants.py` for five targets,
13
+ stages each executable separately, builds a correctly tagged non-pure wheel, and verifies its
14
+ archive paths, executable format, bundle digest, and every wheel `RECORD` entry. Build inputs use
15
+ `CGO_ENABLED=0`, `-trimpath`, no VCS metadata, no Go build ID, baseline CPU levels, and the exact
16
+ mise-managed Go compiler. Dependency downloads receive bounded retries for transient CI failures.
17
+
18
+ Build one target with:
19
+
20
+ ```console
21
+ uv run python -m scripts.build_wheels --target linux-x86_64 --output dist/wheels
22
+ ```
23
+
24
+ Install-test the wheel matching the current host with:
25
+
26
+ ```console
27
+ uv run python -m scripts.smoke_wheel path/to/tailkitty-*.whl
28
+ ```
29
+
30
+ The wheel matrix is:
31
+
32
+ | Build target | Wheel platform tag | Executable |
33
+ | --- | --- | --- |
34
+ | `macos-arm64` | `macosx_12_0_arm64` | Mach-O |
35
+ | `macos-x86_64` | `macosx_12_0_x86_64` | Mach-O |
36
+ | `linux-x86_64` | `manylinux_2_17_x86_64` | ELF |
37
+ | `linux-aarch64` | `manylinux_2_17_aarch64` | ELF |
38
+ | `windows-x86_64` | `win_amd64` | PE |
39
+
40
+ The release workflow rebuilds the matrix, creates a binary-free source distribution, generates
41
+ checksums, creates GitHub build-provenance attestations, and uses PyPI trusted publishing. Configure
42
+ the `pypi` GitHub environment before enabling it.
@@ -0,0 +1,11 @@
1
+ # Changelog
2
+
3
+ ## 0.1.0 - unreleased
4
+
5
+ - Launch under the Tailkitty distribution, import, and primary CLI name.
6
+ - Implement Tailcat token parsing, validation, resolution, DNS destination lookup, and DERP caching
7
+ in Python.
8
+ - Add typed synchronous and asyncio client/server process APIs.
9
+ - Bundle a pinned upstream data plane in verified wheels for five desktop/server targets.
10
+ - Add structured backend diagnostics, reproducible builds, artifact verification, isolated wheel
11
+ smoke tests, CI, release provenance, and trusted-publishing automation.
@@ -0,0 +1,22 @@
1
+ # Tailkitty compared with the existing PyPI project
2
+
3
+ Both projects expose the upstream Tailcat command through Python and use an upstream-compatible
4
+ native data plane. The existing [`pytailcat`](https://pypi.org/project/pytailcat/) primarily ships
5
+ prebuilt executables with a small process wrapper. This implementation adds substantial Python-side
6
+ functionality and a more inspectable supply chain under the distinct Tailkitty name.
7
+
8
+ | Capability | Existing PyPI project | This implementation |
9
+ | --- | --- | --- |
10
+ | Upstream-compatible data plane | Bundled executable | Pinned, verified bundled executable |
11
+ | Token parsing and validation | Delegated to executable | Native Python typed models |
12
+ | DERP resolution and caching | Delegated to executable | Native Python with ETag/stale fallback |
13
+ | DNS `tailcat=` destination lookup | Delegated to executable | Sync and async Python APIs |
14
+ | Process API | Thin synchronous wrapper | Sync/async clients and managed servers |
15
+ | Bundle integrity | Package-manager transport integrity | Runtime manifest, target, size, and SHA-256 checks |
16
+ | Reproducible local toolchain | Not the focus | mise + uv + exact Go compiler and revision |
17
+ | Release evidence | Prebuilt wheels | Matrix verification, checksums, and provenance workflow |
18
+
19
+ The remaining architectural boundary is intentional: reimplementing Tailscale magicsock,
20
+ userspace WireGuard, DERP routing, and gVisor netstack faithfully in pure Python would be a separate
21
+ networking stack and would create interoperability and security risk. The control-plane and wire
22
+ format are Python; the interoperable encrypted transport stays upstream.
@@ -0,0 +1,135 @@
1
+ # 100-iteration improvement ledger
2
+
3
+ Each checkbox is a distinct implementation, hardening, verification, or documentation pass. Items
4
+ are marked only after their stated evidence exists.
5
+
6
+ ## 001-010 — reproducible environment
7
+
8
+ - [x] 001. Update and pin uv to 0.12.7 with mise.
9
+ - [x] 002. Pin Python 3.13.11 with mise.
10
+ - [x] 003. Pin Go 1.26.5 with mise.
11
+ - [x] 004. Keep the virtual environment driven by uv.
12
+ - [x] 005. Lock all Python runtime dependencies.
13
+ - [x] 006. Lock all Python development dependencies.
14
+ - [x] 007. Add a one-command mise setup task.
15
+ - [x] 008. Add a locked CI dependency-sync step.
16
+ - [x] 009. Move package, Tailcat, and Go pins into central constants.
17
+ - [x] 010. Test that project metadata and runtime versions agree.
18
+
19
+ ## 011-020 — Python-native control plane
20
+
21
+ - [x] 011. Decode Tailcat CBOR tokens in Python.
22
+ - [x] 012. Model connection data with typed dataclasses.
23
+ - [x] 013. Validate token prefixes and base64 payloads.
24
+ - [x] 014. Validate node-key length and structure.
25
+ - [x] 015. Validate DERP region fields.
26
+ - [x] 016. Re-encode resolved Tailcat tokens in Python.
27
+ - [x] 017. Resolve DERP maps without invoking Go.
28
+ - [x] 018. Cache DERP maps on disk with a bounded lifetime.
29
+ - [x] 019. Revalidate DERP caches with HTTP ETags.
30
+ - [x] 020. Fall back to stale DERP data during network failure.
31
+
32
+ ## 021-030 — Python APIs and process safety
33
+
34
+ - [x] 021. Resolve DNS `tailcat=` TXT destinations synchronously.
35
+ - [x] 022. Resolve DNS destinations asynchronously.
36
+ - [x] 023. Add a typed synchronous client.
37
+ - [x] 024. Add an asyncio client.
38
+ - [x] 025. Add a managed synchronous server process.
39
+ - [x] 026. Add a managed asyncio server process.
40
+ - [x] 027. Capture server readiness without blocking stdout.
41
+ - [x] 028. Clean up forgotten child processes at interpreter shutdown.
42
+ - [x] 029. Preserve exit status and stderr for non-raising calls.
43
+ - [x] 030. Translate an empty allow-list to the secure `--allow=none` value.
44
+
45
+ ## 031-040 — pinned binary construction
46
+
47
+ - [x] 031. Pin the exact upstream Tailcat pseudo-version.
48
+ - [x] 032. Fetch the command package rather than an ambiguous module root.
49
+ - [x] 033. Build inside an isolated temporary Go module.
50
+ - [x] 034. Disable CGO for portable cross-compilation.
51
+ - [x] 035. Strip source paths with `-trimpath`.
52
+ - [x] 036. Disable VCS stamping.
53
+ - [x] 037. Remove the Go build ID.
54
+ - [x] 038. Strip symbols and debug tables.
55
+ - [x] 039. Set baseline amd64 and arm64 CPU levels.
56
+ - [x] 040. Retry transient module-download failures with a bounded backoff.
57
+
58
+ ## 041-050 — target matrix and build safety
59
+
60
+ - [x] 041. Model build targets with immutable typed records.
61
+ - [x] 042. Support macOS arm64.
62
+ - [x] 043. Support macOS x86-64.
63
+ - [x] 044. Support Linux x86-64.
64
+ - [x] 045. Support Linux arm64.
65
+ - [x] 046. Support Windows x86-64.
66
+ - [x] 047. Normalize common machine-architecture aliases.
67
+ - [x] 048. Detect and reject unsupported build hosts.
68
+ - [x] 049. Validate Mach-O, ELF, and PE executable headers.
69
+ - [x] 050. Replace completed binaries atomically and remove stale opposite-OS files.
70
+
71
+ ## 051-060 — platform-wheel packaging
72
+
73
+ - [x] 051. Migrate to Hatchling for a programmable wheel hook.
74
+ - [x] 052. Mark binary wheels as non-pure.
75
+ - [x] 053. Emit exact Python/ABI/platform wheel tags.
76
+ - [x] 054. Use a correct macOS 12 deployment floor.
77
+ - [x] 055. Use conservative manylinux 2.17 Linux tags.
78
+ - [x] 056. Force-include only the selected staged executable.
79
+ - [x] 057. Force-include its matching integrity manifest.
80
+ - [x] 058. Reject a caller-supplied tag that disagrees with the bundle.
81
+ - [x] 059. Keep generated binaries out of source distributions.
82
+ - [x] 060. Retain a pure-Python wheel fallback when no bundle is staged.
83
+
84
+ ## 061-070 — runtime integrity and discovery
85
+
86
+ - [x] 061. Define a versioned JSON bundle-manifest schema.
87
+ - [x] 062. Record target, platform tag, module, revision, compiler, size, and SHA-256.
88
+ - [x] 063. Reject unsupported manifest schemas.
89
+ - [x] 064. Reject module or upstream-version mismatches.
90
+ - [x] 065. Reject path traversal and symlinked executables.
91
+ - [x] 066. Reject invalid digests and implausible bundle sizes.
92
+ - [x] 067. Recompute size and SHA-256 before execution.
93
+ - [x] 068. Reject a valid bundle copied to an incompatible runtime platform.
94
+ - [x] 069. Restore a missing POSIX user-execute bit after integrity validation.
95
+ - [x] 070. Cache successful verification while preserving explicit cache invalidation for tests.
96
+
97
+ ## 071-080 — diagnostics and artifact verification
98
+
99
+ - [x] 071. Give `TAILKITTY_BACKEND` explicit, fail-closed priority.
100
+ - [x] 072. Prefer verified wheel bundles over development and PATH helpers.
101
+ - [x] 073. Preserve a migration fallback for the former `tailcat-go` development filename.
102
+ - [x] 074. Expose backend path, source, version, and manifest metadata.
103
+ - [x] 075. Add human-readable `tailcat doctor` output.
104
+ - [x] 076. Add machine-readable `tailcat doctor --json` output.
105
+ - [x] 077. Reject unsafe or duplicate wheel archive paths.
106
+ - [x] 078. Verify WHEEL purity and compatibility metadata.
107
+ - [x] 079. Verify the embedded executable and manifest together.
108
+ - [x] 080. Verify every wheel `RECORD` digest, size, and member mapping.
109
+
110
+ ## 081-090 — automation, metadata, and supply chain
111
+
112
+ - [x] 081. Add unit coverage for bundle corruption and backend precedence.
113
+ - [x] 082. Run Ruff, formatting, strict mypy, and pytest from one mise task.
114
+ - [x] 083. Add a five-target CI wheel matrix.
115
+ - [x] 084. Add isolated host-wheel installation smoke testing in CI.
116
+ - [x] 085. Add binary-free source-distribution CI.
117
+ - [x] 086. Add checksums and GitHub build-provenance attestations.
118
+ - [x] 087. Add OIDC trusted-publishing automation with least-privilege permissions.
119
+ - [x] 088. Pin third-party GitHub Actions to immutable commits.
120
+ - [x] 089. Add PEP 561 typing metadata, classifiers, URLs, and third-party notices.
121
+ - [x] 090. Document building, security, architecture boundaries, and the existing-project comparison.
122
+
123
+ ## 091-100 — real artifact and integration validation
124
+
125
+ - [x] 091. Cross-compile and structurally verify all five real platform wheels locally.
126
+ - [x] 092. Install the host wheel into an isolated environment and discover its verified bundle.
127
+ - [x] 093. Rebuild identical host binaries and prove byte-for-byte reproducibility.
128
+ - [x] 094. Detect and close Go's silent automatic-toolchain substitution path.
129
+ - [x] 095. Build and inspect the no-bundle pure-Python wheel fallback.
130
+ - [x] 096. Build and inspect the binary-free source distribution.
131
+ - [x] 097. Run the full suite on the minimum supported Python 3.11.
132
+ - [x] 098. Repeat live encrypted transfer testing and capture the current external DERP timeout
133
+ after earlier successful bundled transfers.
134
+ - [x] 099. Rebuild final artifacts and pass the complete lint, type, test, and integrity audit.
135
+ - [x] 100. Audit this ledger against the workspace and deliver the handoff.
@@ -0,0 +1,28 @@
1
+ BSD 3-Clause License
2
+
3
+ Copyright (c) 2026, Tailkitty contributors
4
+
5
+ Redistribution and use in source and binary forms, with or without
6
+ modification, are permitted provided that the following conditions are met:
7
+
8
+ 1. Redistributions of source code must retain the above copyright notice,
9
+ this list of conditions and the following disclaimer.
10
+
11
+ 2. Redistributions in binary form must reproduce the above copyright notice,
12
+ this list of conditions and the following disclaimer in the documentation
13
+ and/or other materials provided with the distribution.
14
+
15
+ 3. Neither the name of the copyright holder nor the names of its
16
+ contributors may be used to endorse or promote products derived from
17
+ this software without specific prior written permission.
18
+
19
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
23
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.