Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 43 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,49 @@ jobs:
- name: Enforce source boundaries
run: scripts/check-source-boundaries.sh

tls-standard-go:
name: Standard-Go TLS signoff
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: "1.24.4"
cache: true
- name: Prepare exact dependency worktrees
run: scripts/ci-prepare-dependencies.sh
- name: Run explicit TLS signoff
run: TLS_SIGNOFF_DIR="$RUNNER_TEMP/tls-signoff" scripts/tls-signoff.sh
- name: Retain TLS evidence
if: failure() || github.event_name == 'schedule' || github.event_name == 'workflow_dispatch'
uses: actions/upload-artifact@v4
with:
name: tls-standard-go
path: ${{ runner.temp }}/tls-signoff

tinygo-supported:
name: TinyGo supported package surface
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: "1.24.4"
cache: true
- uses: acifani/setup-tinygo@v2
with:
tinygo-version: "0.41.1"
- name: Prepare exact dependency worktrees
run: scripts/ci-prepare-dependencies.sh
- name: Test exact supported package surface
run: TINYGO_LOG_DIR="$RUNNER_TEMP/tinygo-supported" scripts/tinygo-supported-test.sh
- name: Retain TinyGo package manifests and logs
if: failure() || github.event_name == 'schedule' || github.event_name == 'workflow_dispatch'
uses: actions/upload-artifact@v4
with:
name: tinygo-supported
path: ${{ runner.temp }}/tinygo-supported

race:
name: Race detector
runs-on: ubuntu-latest
Expand Down
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,16 @@ TLS intentionally has no `tls/register` zero-configuration extension and no
credentials, and profile IDs are deployment authority that must be supplied by
explicit Go composition; the repository does not invent placeholder TLS policy.

The complete TLS implementation is standard-Go-only. TinyGo 0.41.1 lacks the
required `crypto/tls` client APIs, so the repository provides no TinyGo stub,
placeholder guest module, or fake handshake. `scripts/tinygo-supported-test.sh`
tests the exact reviewed non-TLS package surface and fails closed if the five
standard-Go-only TLS packages change without review. `scripts/tls-signoff.sh`
retains separate ordinary and race evidence for explicit TLS composition,
security, ABI, mixed transport, EOF, quota, and worker teardown. TLS remains
client-only, granular-only, outside aggregate `register`, and experimental until
the complete strict release and executed arm64 requirements are satisfied.

Profiles are finite and host-defined. The guest selects only a profile ID,
remote IP endpoint, and authorized verification name. Certificate-chain and
DNS/IP SAN verification are mandatory; Common Name fallback, key logging,
Expand Down
41 changes: 41 additions & 0 deletions agent-todo.md
Original file line number Diff line number Diff line change
Expand Up @@ -1569,3 +1569,44 @@ Broad validation at recursion end:
### Remaining work

No repository-owned workstream or completion criterion from this hardening request is currently known to remain. The only strict release-attempt prerequisite observed in this workspace is the externally owned dirty production-Wago worktree above. Re-run the exact strict command after that worktree becomes independently clean; do not recurse merely to modify external worktrees or manufacture a passing release result.

## TLS release/platform integration — July 20, 2026

- Added an exact fail-closed TinyGo package matrix. Discovery includes tracked
`testdata` directories and finds 128 repository packages: 123 are tested
individually under TinyGo 0.41.1 and exactly five real-TLS packages are
retained as standard-Go-only with reviewed reasons.
- Added explicit standard-Go TLS signoff with ten ordinary and seven race package
profiles resolving 109 named tests. Evidence covers explicit composition,
security, ABI, dependency isolation, mixed transport, EOF/truncation, quota
rollback, worker exit, and deterministic teardown without public internet.
- Extended arm64 evidence from one root smoke binary to four binaries covering
root networking, `internal/backend/gotls`, mixed lneto TLS transport, and the
public TLS registration surface. All four cross-compile; local execution is
currently `skipped-no-runner`, not executed support.
- Added schema-v3 provenance verification for TLS/TinyGo manifests and logs,
package counts, exclusions, arm64 checksums, and the explicit TinyGo TLS
limitation while retaining schema-v2 historical review compatibility.
- Added pinned TinyGo and named standard-Go TLS hosted CI jobs. Aggregate
`register`, all twelve canonical custom CLI bundles, and the absent
`tls/register` / `net-tls` surfaces remain unchanged.
- Refreshed benchmark evidence on the same Ryzen 7 8845HS / Go 1.24.4 platform
with five 200 ms samples and `GOMAXPROCS=1`. Discovery finds 172 top-level
benchmark targets in 50 packages. The retained TLS handshake median is about
1.47 ms with 388,334 B and 935 allocations; fixed-ring, profile authorization,
TCP local-port lease, and live TCP round-trip paths remain zero-allocation.
- Fuzz discovery finds 44 targets in 33 packages, including four TLS-owned
targets.
- Reconstructed a clean exact production Wago worktree from retained immutable
source objects: commit `97e6f91e6c822491577faa86f3c30aa5a8fff1e8`, tree
`adbba31c51996f1c1d6d3c2069de8ddf0afd94ee`, ordered parents
`54499ba5135f69a062e23a7255f4a408d6cecf8c` and
`ffd5ef4b122cbd019897eeea3503789ab5860e4a`.
- TLS remains client-only, explicitly configured, granular-only,
standard-Go-only, and experimental. The strict `RUN_WASI=1 FUZZTIME=30s`
attempt with exact clean inputs stopped fail-closed in
`current-plugin-topology-audit`: Wago `origin/main` is now
`7794acc82692aac4ff98756a46a017d0d8768087`, beyond the reviewed `ff04a6b1`
topology, so the lifecycle/preview-1 integration must be re-reviewed and
re-ported. No provenance or review-bundle hashes were produced. Production
readiness also still requires executed arm64 TLS evidence.
14 changes: 8 additions & 6 deletions benchmarks/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,14 @@ in `docs/architecture.md`:
- instance manager attach/lookup/locking/poll and protocol operation wrappers;
- guest status mapping and complete UDP/TCP guest poll host calls.

The checked-in capture is in `baseline.txt`; `baseline-summary.md` lists the
median timing and allocation result for the pre-TLS 114 benchmark cases. TLS
benchmarks are discoverable in current runs and require a refreshed retained
baseline before TLS release signoff. The existing baseline was captured
with three 100 ms samples to keep the initial audit bounded. The script defaults
to the stronger five-by-200 ms profile for future comparison runs.
The checked-in capture is in `baseline.txt`; `baseline-summary.md` records the
TLS-aware medians and environment. Discovery now finds 172 top-level benchmark
targets in 50 packages, with 195 distinct result names after subbenchmark
expansion. The baseline and independent repeatability candidate both use the
repository's full five-by-200 ms, single-CPU, `-benchmem` profile on the same Go
1.24.4 Linux/amd64 Ryzen 7 8845HS environment. `candidate-summary.md` and
`benchstat.txt` document the comparison without treating timing noise as a
protocol correctness assertion.

These are microbenchmarks. The adapter and guest benchmarks include the locks,
validation, policy, accounting, and copies performed by the named path, but they
Expand Down
163 changes: 37 additions & 126 deletions benchmarks/baseline-summary.md
Original file line number Diff line number Diff line change
@@ -1,131 +1,42 @@
# Baseline summary
# TLS-aware baseline summary

This summary is derived from `benchmarks/baseline.txt`. Values are medians of three 100 ms samples with `GOMAXPROCS=1` on Go 1.24.4, Linux/amd64, AMD Ryzen 7 8845HS.
The canonical baseline in `benchmarks/baseline.txt` was captured on July 20,
2026 from clean source commit `97b2bfca08df8d3e154bf7b4bb2cc932ec359ca8`.
It uses Go 1.24.4 on Linux/amd64, AMD Ryzen 7 8845HS, `GOMAXPROCS=1`, five
samples, 200 ms per benchmark, and `-benchmem`.

| Package | Benchmark | ns/op | B/op | allocs/op |
|---|---:|---:|---:|---:|
| `.` | `BenchmarkGuestDNSPoll` | 94.3 | 0 | 0 |
| `.` | `BenchmarkGuestUDPPoll` | 116.3 | 0 | 0 |
| `.` | `BenchmarkGuestTCPPoll` | 112.5 | 0 | 0 |
| `/internal/abi/core` | `BenchmarkSlice` | 1.718 | 0 | 0 |
| `/internal/abi/core` | `BenchmarkWrite` | 8.590 | 0 | 0 |
| `/internal/abi/core` | `BenchmarkZero` | 8.320 | 0 | 0 |
| `/internal/abi/core` | `BenchmarkReadUint32LE` | 1.280 | 0 | 0 |
| `/internal/abi/core` | `BenchmarkWriteUint32LE` | 1.484 | 0 | 0 |
| `/internal/abi/core` | `BenchmarkCheckRanges` | 5.377 | 0 | 0 |
| `/internal/abi/core` | `BenchmarkElements` | 1.913 | 0 | 0 |
| `/internal/abi/core` | `BenchmarkEncodeAddressV1` | 11.7 | 0 | 0 |
| `/internal/abi/core` | `BenchmarkDecodeAddressV1` | 22.4 | 0 | 0 |
| `/internal/abi/core` | `BenchmarkEncodeEndpointV1` | 23.6 | 0 | 0 |
| `/internal/abi/core` | `BenchmarkDecodeEndpointV1` | 39.9 | 0 | 0 |
| `/internal/abi/core` | `BenchmarkEncodeHandleV1` | 1.490 | 0 | 0 |
| `/internal/abi/core` | `BenchmarkDecodePollBudgetV1` | 2.541 | 0 | 0 |
| `/internal/abi/core` | `BenchmarkEncodePollEventsV1/events=1` | 5.268 | 0 | 0 |
| `/internal/abi/core` | `BenchmarkEncodePollEventsV1/events=16` | 26.9 | 0 | 0 |
| `/internal/abi/core` | `BenchmarkEncodePollEventsV1/events=256` | 411.8 | 0 | 0 |
| `/internal/abi/core` | `BenchmarkEncodePollResultV1` | 8.640 | 0 | 0 |
| `/internal/abi/dns` | `BenchmarkEncodeDNSNameV1` | 99.0 | 112 | 2 |
| `/internal/abi/dns` | `BenchmarkDecodeDNSNameV1` | 155.3 | 136 | 3 |
| `/internal/abi/dns` | `BenchmarkEncodeDNSQueryV1` | 205.6 | 224 | 4 |
| `/internal/abi/dns` | `BenchmarkDecodeDNSQueryV1` | 249.2 | 248 | 5 |
| `/internal/abi/dns` | `BenchmarkCheckDNSResolveV1` | 3.643 | 0 | 0 |
| `/internal/abi/dns` | `BenchmarkEncodeDNSRecordV1/A` | 215.8 | 224 | 4 |
| `/internal/abi/dns` | `BenchmarkEncodeDNSRecordV1/AAAA` | 224.0 | 224 | 4 |
| `/internal/abi/dns` | `BenchmarkEncodeDNSRecordV1/CNAME` | 381.7 | 416 | 8 |
| `/internal/abi/tcp` | `BenchmarkCheckListenV1` | 3.690 | 0 | 0 |
| `/internal/abi/tcp` | `BenchmarkCheckCreateV1` | 3.609 | 0 | 0 |
| `/internal/abi/tcp` | `BenchmarkCheckIOV1` | 3.666 | 0 | 0 |
| `/internal/abi/tcp` | `BenchmarkEncodeStreamV1` | 42.4 | 0 | 0 |
| `/internal/abi/tcp` | `BenchmarkEncodeIOResultV1` | 4.912 | 0 | 0 |
| `/internal/abi/udp` | `BenchmarkEncodeReceiveResultV1` | 28.8 | 0 | 0 |
| `/internal/abi/udp` | `BenchmarkValidReceiveFlagsV1` | 1.242 | 0 | 0 |
| `/internal/backend/lneto/core` | `BenchmarkNamespaceReadiness` | 17.0 | 0 | 0 |
| `/internal/backend/lneto/core` | `BenchmarkUDPPortLeaseAcquireRelease` | 52.2 | 16 | 1 |
| `/internal/backend/lneto/core` | `BenchmarkUDPPortLeaseRangeAcquireRelease` | 53.0 | 16 | 1 |
| `/internal/backend/lneto/core` | `BenchmarkNamespaceTryServiceIdle` | 65.5 | 0 | 0 |
| `/internal/backend/lneto/core` | `BenchmarkNamespaceTryServiceIngress` | 43.0 | 0 | 0 |
| `/internal/backend/lneto/core` | `BenchmarkNamespaceTryServiceEgress` | 63.7 | 0 | 0 |
| `/internal/backend/lneto/dns` | `BenchmarkBuildDNSQueryPacket` | 158.2 | 152 | 4 |
| `/internal/backend/lneto/dns` | `BenchmarkDecodeDNSName` | 96.2 | 56 | 5 |
| `/internal/backend/lneto/dns` | `BenchmarkParseDNSResponse` | 1096 | 1048 | 37 |
| `/internal/backend/lneto/dns` | `BenchmarkSelectDNSAnswers` | 445.7 | 592 | 9 |
| `/internal/backend/lneto/dns` | `BenchmarkAdapterTryResolveClose` | 837.7 | 1072 | 17 |
| `/internal/backend/lneto/dns` | `BenchmarkQueryTryNext` | 90.6 | 80 | 2 |
| `/internal/backend/lneto/dns` | `BenchmarkQueryReadiness` | 4.065 | 0 | 0 |
| `/internal/backend/lneto/tcp` | `BenchmarkAdapterTryListenClose` | 533.0 | 1792 | 11 |
| `/internal/backend/lneto/tcp` | `BenchmarkTCPStreamFinishConnect` | 5.414 | 0 | 0 |
| `/internal/backend/lneto/tcp` | `BenchmarkTCPStreamReadiness` | 13.4 | 0 | 0 |
| `/internal/backend/lneto/tcp` | `BenchmarkTCPListenerTryAcceptWouldBlock` | 22.2 | 0 | 0 |
| `/internal/backend/lneto/tcp` | `BenchmarkTCPStreamRoundTrip` | 1327 | 0 | 0 |
| `/internal/backend/lneto/udp` | `BenchmarkAdapterTryBindClose` | 425.4 | 832 | 12 |
| `/internal/backend/lneto/udp` | `BenchmarkUDPSocketSendEgress` | 146.9 | 0 | 0 |
| `/internal/backend/lneto/udp` | `BenchmarkUDPSocketReceive` | 34.1 | 0 | 0 |
| `/internal/backend/lneto/udp` | `BenchmarkUDPSocketReadiness` | 4.437 | 0 | 0 |
| `/internal/backend/lneto/udp` | `BenchmarkUDPDatagramQueueRoundTrip` | 20.1 | 0 | 0 |
| `/internal/guest` | `BenchmarkFromProgress` | 1.242 | 0 | 0 |
| `/internal/guest` | `BenchmarkFromIOResult` | 1.682 | 0 | 0 |
| `/internal/guest` | `BenchmarkFromError/semantic` | 48.9 | 8 | 1 |
| `/internal/guest` | `BenchmarkFromError/shared` | 50.6 | 8 | 1 |
| `/internal/instance/core` | `BenchmarkManagerAttachDetach` | 1248 | 18152 | 12 |
| `/internal/instance/core` | `BenchmarkManagerForInstance` | 4.023 | 0 | 0 |
| `/internal/instance/core` | `BenchmarkStateWithLock` | 4.697 | 0 | 0 |
| `/internal/instance/core` | `BenchmarkStatePollIdle` | 25.8 | 0 | 0 |
| `/internal/instance/dns` | `BenchmarkResolveClose` | 87.0 | 0 | 0 |
| `/internal/instance/dns` | `BenchmarkNext` | 135.1 | 112 | 2 |
| `/internal/instance/dns` | `BenchmarkCancel` | 15.7 | 0 | 0 |
| `/internal/instance/tcp` | `BenchmarkConnectClose` | 81.5 | 0 | 0 |
| `/internal/instance/tcp` | `BenchmarkEndpoints` | 44.0 | 0 | 0 |
| `/internal/instance/tcp` | `BenchmarkFinishConnect` | 14.4 | 0 | 0 |
| `/internal/instance/tcp` | `BenchmarkRead` | 16.8 | 0 | 0 |
| `/internal/instance/tcp` | `BenchmarkWrite` | 16.9 | 0 | 0 |
| `/internal/instance/tcp` | `BenchmarkShutdownWrite` | 14.4 | 0 | 0 |
| `/internal/instance/udp` | `BenchmarkBindClose` | 81.0 | 0 | 0 |
| `/internal/instance/udp` | `BenchmarkSend` | 17.4 | 0 | 0 |
| `/internal/instance/udp` | `BenchmarkReceive` | 28.6 | 0 | 0 |
| `/internal/namespace/core` | `BenchmarkEndpointValid` | 2.131 | 0 | 0 |
| `/internal/namespace/core` | `BenchmarkIOResultValid` | 1.686 | 0 | 0 |
| `/internal/namespace/core` | `BenchmarkReadinessValid` | 1.243 | 0 | 0 |
| `/internal/namespace/core` | `BenchmarkServiceReportValidResult` | 1.707 | 0 | 0 |
| `/internal/namespace/core` | `BenchmarkResolveNamespaceService` | 8.930 | 0 | 0 |
| `/internal/namespace/core` | `BenchmarkResolveNamespaceBase` | 4.171 | 0 | 0 |
| `/internal/namespace/dns` | `BenchmarkRequestValid` | 93.3 | 112 | 2 |
| `/internal/namespace/dns` | `BenchmarkRecordValid` | 93.5 | 112 | 2 |
| `/internal/packetlink` | `BenchmarkLinkTryEnqueueDequeue/bytes=64` | 24.6 | 0 | 0 |
| `/internal/packetlink` | `BenchmarkLinkTryEnqueueDequeue/bytes=512` | 34.0 | 0 | 0 |
| `/internal/packetlink` | `BenchmarkLinkTryEnqueueDequeue/bytes=1514` | 49.0 | 0 | 0 |
| `/internal/packetlink` | `BenchmarkLinkTryFillDequeue` | 37.0 | 0 | 0 |
| `/internal/packetlink` | `BenchmarkLinkSnapshot` | 11.8 | 0 | 0 |
| `/internal/policy` | `BenchmarkMerge` | 421.7 | 1136 | 16 |
| `/internal/policy` | `BenchmarkCompile` | 587.6 | 792 | 17 |
| `/internal/policy` | `BenchmarkPolicyCheckEndpoint` | 33.2 | 0 | 0 |
| `/internal/policy` | `BenchmarkPolicyCheckDNS` | 134.7 | 112 | 2 |
| `/internal/quota` | `BenchmarkReserveResourceRollback` | 44.0 | 80 | 1 |
| `/internal/quota` | `BenchmarkReserveResourceCommitRelease` | 60.6 | 88 | 2 |
| `/internal/quota` | `BenchmarkWithService` | 20.9 | 0 | 0 |
| `/internal/quota` | `BenchmarkSnapshot` | 11.7 | 0 | 0 |
| `/internal/readiness` | `BenchmarkCoordinatorRegisterUnregister` | 36.4 | 0 | 0 |
| `/internal/readiness` | `BenchmarkCoordinatorTryPoll/registrations=1` | 27.5 | 0 | 0 |
| `/internal/readiness` | `BenchmarkCoordinatorTryPoll/registrations=16` | 177.8 | 0 | 0 |
| `/internal/readiness` | `BenchmarkCoordinatorTryPoll/registrations=256` | 2608 | 0 | 0 |
| `/internal/readiness` | `BenchmarkCoordinatorTryPollService` | 27.5 | 0 | 0 |
| `/internal/resource` | `BenchmarkNewTable` | 22.3 | 64 | 1 |
| `/internal/resource` | `BenchmarkTableAddCloseHandle` | 12.3 | 0 | 0 |
| `/internal/resource` | `BenchmarkTableLen` | 3.999 | 0 | 0 |
| `/internal/resource` | `BenchmarkMakeHandle` | 1.256 | 0 | 0 |
| `/internal/resource` | `BenchmarkSplitHandle` | 1.483 | 0 | 0 |
| `/internal/resource` | `BenchmarkTableLookupBadHandle` | 5.348 | 0 | 0 |
| `/internal/resource` | `BenchmarkTableLookup` | 5.978 | 0 | 0 |
| `/internal/resource` | `BenchmarkTableCloseLive/resources=1` | 199.2 | 176 | 4 |
| `/internal/resource` | `BenchmarkTableCloseLive/resources=64` | 3014 | 10080 | 73 |
| `/internal/resource` | `BenchmarkTableCloseLive/resources=1024` | 44362 | 157408 | 1037 |
Discovery found **172 top-level benchmark targets in 50 packages**. Subbenchmark
expansion produced 195 distinct benchmark result names. This replaces the
pre-TLS three-by-100 ms baseline and includes the complete current TLS, shared
TCP-port, protocol, ABI, policy, quota, readiness, lifecycle, and guest-binding
benchmark surface.

## Initial findings
## TLS and private-transport medians

- The steady-state shared ABI, resource lookup/reuse, quota scoped charge, readiness polling, packet-link, UDP data plane, TCP data plane, and guest poll paths are allocation-free in this baseline.
- The live in-memory TCP 64-byte round trip is about 1.33 µs and 0 allocations; UDP send plus frame egress is about 147 ns and 0 allocations.
- DNS is the largest optimization surface: response parsing is about 1.10 µs with 1,048 B and 37 allocations; answer selection is about 0.45 µs with 592 B and 9 allocations.
- DNS name/request/record validation and DNS policy checks currently allocate because normalization/validation builds temporary strings or label slices. This also appears in DNS ABI encoding/decoding and record iteration.
- UDP port lease creation allocates one 16-byte lease object per acquisition. Resource/quota creation paths allocate by design, while reuse and scoped service paths do not.
- `guest.FromError` allocates 8 B once per mapped error in this baseline; simple progress and I/O-result status mapping are allocation-free.
| Path | ns/op | B/op | allocs/op |
|---|---:|---:|---:|
| TLS 1.3 client handshake | 1,465,373 | 388,334 | 935 |
| TLS fixed byte-ring steady state | 125.8 | 0 | 0 |
| TLS profile authorization | 15.04 | 0 | 0 |
| Shared TCP local-port lease acquire/release | 41.49 | 0 | 0 |
| Live in-memory TCP 64-byte round trip | 1,584 | 0 | 0 |
| Private/raw TCP adapter connect/close | 791.3 | 1,128 | 4 |

Treat sub-10 ns results as compiler- and CPU-sensitive. Use the raw multi-sample file and `benchstat` for regression decisions rather than comparing a single rounded number.
The TLS handshake allocation result is dominated by Go's standard-library TLS
and X.509 implementation. The repository-owned fixed byte ring, profile
authorization, shared local-port lease, and steady TCP round-trip paths remain
allocation-free.

## Interpretation

- TLS handshake timing is scheduling- and cryptography-sensitive; use repeated
captures rather than exact timing assertions.
- The retained allocation counts are more stable than small timing differences.
- The byte-ring and profile-authorization paths show no per-operation heap
growth.
- Shared TCP port leasing remains zero-allocation after raw TCP and private TLS
transport were moved into one namespace-wide lease domain.
- This capture was produced on the same hardware and toolchain family as the
preceding optimization evidence, so it is suitable as the repository's new
TLS-aware local baseline. Release adoption still requires the separate strict
release and platform gates.
Loading
Loading