Skip to content

Commit 2437c06

Browse files
committed
Package bounded Linux runtime candidate with opt-in CI retention
1 parent eca2f1a commit 2437c06

7 files changed

Lines changed: 809 additions & 10 deletions

File tree

‎.github/workflows/native-client.yml‎

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,12 @@ on:
66
- tools/session_store/**
77
- .github/workflows/native-client.yml
88
workflow_dispatch:
9+
inputs:
10+
retain_candidate:
11+
description: Retain verified candidate without session state for seven days
12+
type: boolean
13+
required: false
14+
default: false
915

1016
permissions:
1117
contents: read
@@ -82,6 +88,14 @@ jobs:
8288
python3 tools/session_store/native_build.py verify --source-root "$RUNNER_TEMP/native-source" --receipt "$RUNNER_TEMP/build-receipt.json"
8389
sha256sum "$RUNNER_TEMP/native-source/codex-rs/target/dev-small/codex"
8490
file "$RUNNER_TEMP/native-source/codex-rs/target/dev-small/codex"
91+
- name: Package bounded runtime candidate
92+
run: |
93+
set -euo pipefail
94+
cargo +1.95.0 metadata --locked --format-version 1 --filter-platform x86_64-unknown-linux-gnu --manifest-path "$RUNNER_TEMP/native-source/codex-rs/Cargo.toml" > "$RUNNER_TEMP/runtime-metadata.json"
95+
python3 tools/session_store/runtime_bundle.py create \
96+
--source-root "$RUNNER_TEMP/native-source" --build-receipt "$RUNNER_TEMP/build-receipt.json" \
97+
--metadata "$RUNNER_TEMP/runtime-metadata.json" --cargo-home "${CARGO_HOME:-$HOME/.cargo}" \
98+
--output "$RUNNER_TEMP/runtime-candidate" --receipt "$RUNNER_TEMP/runtime-receipt.json" --project-commit "$GITHUB_SHA"
8599
- name: Offline minimal-root version smoke
86100
run: |
87101
set -euo pipefail
@@ -91,13 +105,28 @@ jobs:
91105
--die-with-parent --new-session --cap-drop ALL --cap-add CAP_SETUID --cap-add CAP_SETGID --cap-add CAP_SETPCAP \
92106
--ro-bind /usr /usr --symlink usr/bin /bin --symlink usr/lib /lib \
93107
--symlink usr/lib64 /lib64 --proc /proc --dev /dev --perms 1777 --tmpfs /tmp \
94-
--dir /work --ro-bind "$RUNNER_TEMP/native-source/codex-rs/target/dev-small/codex" /work/client \
108+
--dir /work --ro-bind "$RUNNER_TEMP/runtime-candidate/bin/client" /work/client \
95109
--ro-bind "$GITHUB_WORKSPACE/tools/session_store/offline_smoke.py" /work/check.py \
96110
--chdir /work --clearenv --setenv PATH /usr/bin:/bin \
97111
-- /usr/bin/setpriv --reuid=65534 --regid=65534 --clear-groups \
98112
--bounding-set=-all --inh-caps=-all --ambient-caps=-all --no-new-privs \
99113
/usr/bin/python3 /work/check.py "$host_net"
100114
- name: Synthetic TLS device-code and cancellation
101-
run: bash tools/session_store/protocol_smoke.sh "$RUNNER_TEMP/native-source/codex-rs/target/dev-small/codex"
115+
run: bash tools/session_store/protocol_smoke.sh "$RUNNER_TEMP/runtime-candidate/bin/client"
102116
- name: Synthetic OAuth exchange and session readback
103-
run: bash tools/session_store/protocol_smoke.sh "$RUNNER_TEMP/native-source/codex-rs/target/dev-small/codex" --exchange
117+
run: bash tools/session_store/protocol_smoke.sh "$RUNNER_TEMP/runtime-candidate/bin/client" --exchange
118+
- name: Reverify tested package and publish digest receipt
119+
run: |
120+
set -euo pipefail
121+
digest="$(python3 -c 'import json,sys; print(json.load(open(sys.argv[1]))["manifest_sha256"])' "$RUNNER_TEMP/runtime-receipt.json")"
122+
python3 tools/session_store/runtime_bundle.py verify --root "$RUNNER_TEMP/runtime-candidate" --manifest-sha256 "$digest"
123+
printf 'Candidate manifest SHA256: %s\n' "$digest" >> "$GITHUB_STEP_SUMMARY"
124+
cat "$RUNNER_TEMP/runtime-receipt.json" >> "$GITHUB_STEP_SUMMARY"
125+
- name: Retain verified runtime candidate on explicit dispatch only
126+
if: github.event_name == 'workflow_dispatch' && inputs.retain_candidate
127+
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
128+
with:
129+
name: personal-ai-runtime-linux-x64-${{ github.sha }}
130+
path: ${{ runner.temp }}/runtime-candidate/
131+
if-no-files-found: error
132+
retention-days: 7

‎AI_NOTES.md‎

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,26 @@
1+
# Runtime Candidate Package - 2026-10-15
2+
3+
- Owner explicitly approved retaining the checked Linux runtime in GitHub CI
4+
for seven days. Retention is manual-dispatch opt-in only, not a release or
5+
deployment. No auth, profiles, logs, caches, medical data or databases enter
6+
the allowlisted candidate. Source/provenance/licenses only accompany the ELF.
7+
- Added a source-receipt-gated builder and bounded directory/ZIP verifier using
8+
an external expected manifest digest, streamed hashes, no-follow file opens,
9+
path/type/count/size guards and exact member coverage. Verifier never extracts,
10+
installs or executes. Cargo notices are a public dependency inventory with
11+
explicit declared-only gaps, not a legal/supply-chain/reproducibility claim.
12+
- Native CI now runs existing offline and ten synthetic protocol cases against
13+
packaged bytes, then reverifies before optional upload. Unit and exact-source
14+
native/Verify CI results remain publication/retention gates. Actual host ABI,
15+
immutable installation/rollback, controller/launcher admission and private
16+
owner challenge presentation remain separate. No runtime/provider/phone or
17+
therapy action is connected by this stage.
18+
- Local resolved public metadata:1222packages/1814notice files,85declared-only
19+
entries. One upstream git dependency's shared LICENSE is a source symlink;
20+
resolve only within admitted public roots and copy regular content. Escaping
21+
source links and all candidate links remain refused. No licensing completeness
22+
is claimed. New tests also refuse unknown build-receipt payload fields.
23+
124
# Inactive Session Profile Guard - 2026-10-15
225

326
- First Linux CI run failed two child-process fixtures (534other tests passed):

‎docs/DEVOPS.md‎

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ transaction safety. Actual runtime/credential presentation/adoption is not impli
2020

2121
## Pinned Native Build Validation
2222

23-
Native Client Candidate is a source-only CI workflow, separate from Verify.
23+
Native Client Candidate is a disposable build workflow, separate from Verify.
2424
See tools/session_store/README.md. It fetches the fixed annotated tag and checks
2525
the peeled commit, all clean checkout state, exact native lock/toolchain and the
2626
three-path patch receipt before/after compilation. The upstream dev-small
@@ -35,8 +35,11 @@ production hosts and existing login roots are not build workers.
3535

3636
Isolation preflight executes no client. Native login library tests and the actual CLI build precede the no-network,
3737
minimal-root, nonroot version smoke. A success is build/provenance evidence only,
38-
not authenticated model access or production containment. No binary artifact,
39-
release, deployment, keyring/profile mount or real login is part of this workflow.
38+
not authenticated model access or production containment. Push builds upload no
39+
binary. Owner-approved manual dispatch with retain_candidate=true retains only
40+
the verified runtime candidate for seven days; see the tooling README for the
41+
exact archive/digest contract. No release, deployment, keyring/profile mount or
42+
real login is part of this workflow.
4043
The same workflow now includes a separate synthetic native protocol harness;
4144
see tools/session_store/README.md. It uses only a disposable private CA/loopback
4245
peer, the development build's supported issuer override, six bounded negative/
@@ -53,7 +56,12 @@ account completion/readback and a separate native login status process with no
5356
connection attempts. This is not authenticated app-server restart: pinned native
5457
startup automatically fetches model metadata when already authenticated. Both
5558
auth issuer and ChatGPT base URL stay local; no real provider/credential/signature
56-
validation or model availability is claimed. CI retains no session/binary artifact.
59+
validation or model availability is claimed. CI retains no session/test-state
60+
artifact; explicitly retained binaries contain only the bounded public build
61+
candidate, provenance and notices. Never install from an archive's own digest:
62+
independently pin the exact successful CI run/source and job-summary manifest
63+
digest, verify the downloaded ZIP without extraction, then obtain separate
64+
host/runtime-change admission. Production hosts are not build workers.
5765

5866
## Atomic Session Candidate
5967

‎docs/PLAN.md‎

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,18 @@
11
# PLAN
22

3+
## Runtime Candidate Delivery (2026-10-15)
4+
5+
- Owner approved seven-day CI retention of the verified Linux candidate, not
6+
release/deployment/authorization. Add bounded source-bound package creation,
7+
external-manifest directory/ZIP verification and resolved dependency notices.
8+
- Test the packaged bytes in existing offline and ten synthetic protocol cases;
9+
retain only on explicit manual dispatch. Default push uploads no binary or
10+
session/test-state. Exact-source native/Verify CI and downloaded-archive checks
11+
remain gates; do not infer runtime adoption from successful unit tests.
12+
- Next: host ABI/library/licensing review, immutable installation/rollback,
13+
launcher/profile-controller integration and private owner code presentation.
14+
Existing server, phone, authorization and therapy paths remain unchanged.
15+
316
## Inactive Session Profile Guard (2026-10-15)
417

518
- Added the source-only local serialization/admission component after synthetic

‎tools/session_store/README.md‎

Lines changed: 44 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,8 @@ adds the lockfile as the fourth changed path in the full-build checkout.
5555
Native Rust1.95.0 builds the login library tests and actual CLI with `--locked`
5656
and the upstream `dev-small` profile, two compile jobs and a90-minute job limit.
5757
This is a development validation build, not a release or reproducibility claim.
58-
No binary is uploaded or deployed. CI records source/patch/toolchain/binary
58+
Push builds upload no binary; explicit retention is described below. Nothing is
59+
deployed. CI records source/patch/toolchain/binary
5960
digests; these bind the observed build, not an independently signed attestation.
6061

6162
An isolation-only preflight precedes compilation, creates/verifies the private
@@ -109,7 +110,8 @@ An independent host-side kernel namespace-reference check follows Bubblewrap's
109110
PID-namespace teardown. Passing runs print only count/status receipts. Failure
110111
diagnostics bound synthetic-only stderr/syscall tails and selected process
111112
status; never reuse this reporter with real credentials/profiles. Generated peer
112-
keys are removed by the wrapper; no binary or test-state artifact is uploaded.
113+
keys are removed by the wrapper; no test-state artifact is uploaded. Binary
114+
retention is a separate explicit opt-in below.
113115

114116
Actual native protocol results remain pending until the exact-source workflow
115117
finishes. Synthetic codes are not credentials, successful cancellation is not
@@ -180,9 +182,48 @@ pinned app-server starts a model-catalog refresh worker when auth already exists
180182
Do not broaden this test to real model/provider routes or disable TLS as fallback.
181183
Trace/private-state/process/namespace checks apply to both native processes;
182184
receipts print only counts and booleans, not session contents. The same disposable
183-
tmpfs is destroyed afterward. No persistent credential/binary artifact is uploaded.
185+
tmpfs is destroyed afterward. No credential/test-state artifact is uploaded.
184186
Actual exchange results require the exact-source native workflow to finish.
185187

188+
## Retained Runtime Candidate
189+
190+
`runtime_bundle.py create` first rechecks the locked native source receipt and
191+
packages the actual Linux ELF as `bin/client`, that receipt, the integration
192+
patch, upstream/patch licenses and a resolved Cargo dependency notice inventory.
193+
No profile, authorization, build cache, diagnostic log or database is included.
194+
The same packaged bytes run the offline version and all ten synthetic protocol/
195+
exchange cases. A final directory verification precedes any upload.
196+
197+
Normal push builds retain nothing. An owner-approved manual workflow dispatch
198+
with `retain_candidate=true` uploads only the allowlisted candidate for seven
199+
days. It is not a GitHub Release, deployment or production-runtime admission.
200+
The public repository's artifact can be downloaded by signed-in GitHub users.
201+
The manifest SHA256 and separate count/hash receipt are in the CI job summary;
202+
retain the trusted exact-run receipt separately from any downloaded archive.
203+
204+
`runtime_bundle.py verify --zip candidate.zip --manifest-sha256 <trusted-digest>`
205+
checks the archive without extraction or execution. `--root` checks a directory.
206+
Both require the external manifest digest, exact closed file set, streamed content
207+
hashes, canonical paths, fixed ELF architecture/interpreter and bounded JSON,
208+
member counts and bytes. Links, duplicates, extra files/directories, traversal,
209+
special/encrypted members and unbounded expansion are refused. Legacy single-disk
210+
ZIP only; ZIP64/multipart archives are outside this narrow verifier's contract.
211+
The directory verifier pins a root descriptor and traverses with no-follow opens;
212+
it does not isolate a hostile same-UID/root process that can modify regular bytes.
213+
Archive permissions are not installation permissions or executable admission.
214+
215+
Dependency metadata comes from locked Cargo resolution, filtered for Linux, not
216+
from a user profile. Only regular public-source-root license targets are read;
217+
source notice links may resolve within those public roots, never outside them,
218+
and are copied as regular bytes, not retained as links. Candidate links are refused;
219+
local build paths are omitted from the index. Workspace crates inherit the pinned
220+
upstream license. Packages without a discoverable top-level/explicit notice are
221+
reported as `declared-only`, not certified complete. This inventory is not a legal
222+
compliance audit, a minimal linked-dependency set, a signed attestation or proof
223+
against malicious build inputs. Host ABI/library closure, licensing review,
224+
immutable installation/rollback, launcher containment and profile-controller
225+
integration remain separate gates before real authorization or model use.
226+
186227
## Limits
187228

188229
- Tests execute the actual Rust helper on synthetic files, including controlled

0 commit comments

Comments
 (0)