Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
96379d6
feat: preview basic Compose builds in native config import
Oct 8, 2026
5934593
chore: reconcile basic-build preview with native readiness
Oct 8, 2026
4e5b031
chore: align build preview with completed compiler cleanup
Oct 8, 2026
d7b2901
feat: preview file-backed config and secret grants
Oct 8, 2026
0a7331d
feat: preview file-backed config and secret grants
Oct 8, 2026
dbafdb9
chore: reconcile build preview with current job conversion
Oct 8, 2026
71f3bb4
chore: align build preview with current fixture diagnostics
Oct 8, 2026
461989c
chore: reconcile file preview with current import purposes
Oct 8, 2026
fad11ca
chore: align retained file foundation with current preview
Oct 8, 2026
ef27492
feat: adopt verified retained file config bindings
Oct 8, 2026
b13d6a9
chore: reconcile retained file ownership with bridge adoption
Oct 8, 2026
562e8c0
feat: preserve protected native file permissions
Oct 8, 2026
a76653b
Merge commit '562e8c0de20e5758c5cb99fa25838b877bdb6dc7' into feat/nat…
Oct 8, 2026
6d6ccb2
feat: preserve protected secrets during retained adoption
Oct 8, 2026
ea3d702
feat(native): integrate protected retained files with current topolog…
Oct 8, 2026
3c4bdce
chore: reconcile retained secret proofs with current fixtures
Oct 8, 2026
dd4ec3b
test(native): add protected file lifecycle acceptance
Oct 8, 2026
c0241b6
chore(native): reconcile protected files with current next
Oct 8, 2026
8f0b8cc
test(native): reconcile protected file selector with next
Oct 8, 2026
dbfb022
test(native): bind protected fixture socket through owner
Oct 8, 2026
8a57ac1
test(native): budget protected snapshot lifecycle
Oct 8, 2026
81f3129
test(native): reconcile protected fixture with lifecycle budget
Oct 8, 2026
b7f0b5a
test(native): fence canonical macOS Git fixture identity
Oct 9, 2026
228b964
feat(native): reconcile retained file proofs with completed jobs
Oct 9, 2026
d26da84
test(native): reconcile protected file acceptance with completed jobs
Oct 9, 2026
1aa67ac
fix(native): observe unnamed retained file binds safely
Oct 9, 2026
427ec16
fix(e2e): observe unnamed protected file mounts faithfully
Oct 9, 2026
9881207
Merge branch 'next' into feat/native-retained-secret-permissions
Oct 9, 2026
0465851
Merge branch 'feat/native-retained-secret-permissions' into feat/nati…
Oct 9, 2026
c5d1b55
test: admit the closed retained-file fixture sources
Oct 9, 2026
7be8ad2
test: align dependency forwarding with owned mount inspection
Oct 9, 2026
d0a9381
test: retain closed mount forwarding in protected acceptance
Oct 9, 2026
e205e35
feat: map retained legacy routing without activation
Oct 9, 2026
e326ea7
feat: retain original Compose routing during native adoption
Oct 9, 2026
1984eae
test(adoption): verify retained routing lifecycle with isolated ingress
Oct 9, 2026
b8c0f91
feat(config): reconcile retained routing with current next
Oct 9, 2026
b3130c8
feat(config): reconcile retained routing with canonical next
Oct 9, 2026
d794bdf
fix(native-compose): coalesce read-only retained routing proofs
Oct 9, 2026
3dd016b
test(native-compose): retain routed TLS failure evidence
Oct 9, 2026
f3ccae8
fix(native-config): reconcile retained routing adoption owners
Oct 9, 2026
7ce4609
chore: reconcile current retained adoption controls
Oct 9, 2026
e50868e
fix: preserve retained routing local open preference
Oct 9, 2026
21373a3
chore: reconcile retained routing with current next
Oct 9, 2026
3fb9319
fix: retain owner-issued process policy refusal diagnostics
Oct 9, 2026
6929937
chore: preserve pending retained routing family
Oct 9, 2026
89b7697
feat: adopt retained protected file grants on current owners
Oct 9, 2026
5675b4f
chore: integrate current next tool lifecycle changes
Oct 9, 2026
913428e
chore: preserve canonical cold-home initialization
Oct 9, 2026
f235a34
fix(test): retain uncertain protected file fixture children
Oct 9, 2026
bf4919d
test(config): preserve stopped retained file fixture identity
Oct 9, 2026
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
1 change: 1 addition & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,7 @@ jobs:
run: HACK_TEST_COMPOSE_CONFIG=1 bun test tests/native-compose-renderer-config.test.ts --test-name-pattern '^one authored bridge keeps internal policy and static aliases through compiler and Compose normalization$'
- name: Run local and Docker E2E
env:
HACK_E2E_PROCESS_POLICY_REFUSAL_CAPSULE: "1"
HACK_E2E_CLI_BIN: ${{ github.workspace }}/dist/hack
run: |
HACK_E2E_DOCKER_HOST="${DOCKER_HOST:-$(docker context inspect --format '{{.Endpoints.docker.Host}}')}"
Expand Down
107 changes: 107 additions & 0 deletions docs/reference/native-compose-adoption.md
Original file line number Diff line number Diff line change
Expand Up @@ -421,6 +421,63 @@ it does not independently terminate a caller-owned engine callback.

## Rollback and interruption recovery

### Original file grants: private version 8

The distinct retained-file preparation owner supports a closed subset:
static image services, the original default bridge, already-bound local named
volumes and explicit file-backed config grants with a verified read-only `0444`
target, plus protected original secret grants with verified `0400` or `0600`
source and guest permissions. The ordinary adoption baseline remains closed; pure import preview
alone never authorizes retained files. Builds, jobs, profiles, routes, custom
networks, readiness/dependency intersections, managed/generated inputs and typed
locals remain refused by this file family before material or engine acquisition.
Unused declarations do not grant access or authorize material reads.

Preparation checks every original bind's exact source path, target and read-only
flag alongside the existing original resource identities. Docker may omit a
bind's `Name` field; its observation projects that absence as the exact empty
name. Named volumes still require their literal verified name. Descriptor-held reads
require canonical owned directories and regular, single-link source files; no
symlink, hardlink, path escape, source replacement or unsafe writable material is
adopted. It never rewrites or chmods the original. Private source facts retain
device/inode, owner, mode, size, timestamps and a content digest. Fixed original-ID
guest `stat`/`sha256sum` queries must agree with the host content and selected
permission policy; effective guest UID/GID and file identity are observed, not inferred as
root. Repeated observations fence drift, but do not atomically freeze the guest,
host filesystem or Docker.

Private manifest and receipt version 8 retain that proof. Material bytes, paths,
identities and digests never enter public plans, reports or diagnostics. Current
material and guest proof are reacquired before retained start/restart or exec,
after effects and immediately before successful journal publication. The file
owner requires one finite mutation deadline. Failure, uncertainty, permission or
content drift leaves pending ownership for explicit stop recovery.

Saved ps/logs, stop/recovery and rollback validate the saved closed proof and exact
original bind/resource identities without acquiring current material. They can
settle stopped originals even after a material source disappears; missing or
changed material still refuses a new start or exec. Rollback restores only the
exact held authored pair and never edits a material file or deletes retained data.

Private file proof version 1 preserves the config-only `0444` contract. Version 2
adds protected original secret binds with exact `0400` or `0600` source and guest
permissions. The strict retained-purpose mapper preserves whether a permission
was omitted or explicitly declared. An omitted secret permission can normalize
only to the verified original effective permission; an explicit permission must
agree with that same source and guest. Explicit `0444` over a protected source
refuses. Config grants remain `0444`, and pure import preview keeps its existing
declarative defaults. The private candidate is normalized only after the original
proof, then compiled. Saved reads derive the same candidate from the immutable
proof and raw authored intent without material reads. Unknown proof versions,
policy-presence swaps, changed source mode and changed guest UID/GID refuse.

This source contract is not complete file/secret or NC04 parity. No original
permission is changed, no guest owner is inferred, and UID/GID overrides remain
refused. Original mount and material ownership, granted and ungranted reads,
read-only write refusal, linked-checkout isolation, retained lifecycle, recovery
and rollback remain required live gates. Mixed build, job, custom-network,
routing, generated, managed and typed-local families stay outside this owner.

After the original containers are stopped, `hack config adopt --rollback`
journals `rolling-back`, holds the installed candidate and restores both exact
legacy originals. Link-before-unlink restoration cannot overwrite another file;
Expand Down Expand Up @@ -524,6 +581,56 @@ Use the same prerequisites and flags as above with
`--only=native-compose-adoption-managed-worktrees`. Registration and synthetic
fixture controls do not establish a live pass.

## Retained routing contract under implementation

The separate private version 14 mapper admits literal legacy `dev_host`, its
already configured OAuth alias and `open.prefer`, together with closed static
Caddy HTTP upstream labels. It pins full HTTPS origins rather than deriving a
new host from the project name or a global domain. Routed services must configure
exactly the existing `hack-dev` attachment and the project default bridge; other
services retain only the default bridge and existing local named storage.

Ordinary import preview remains outside this private family. The retained routing
owner binds the original resources and ingress incarnations, reserves the exact
hostnames, and verifies current proxy dispatch before clearing a startup receipt.
Saved reads preserve literal origins and typed local precedence without acquiring
managed values. Every original-ID lifecycle child has a durable prospective
record; only its one-use known-return and process-group-absence proof settles that
record. Explicit recovery can contain an uncertain child but cannot clear its
uncertainty merely because containers are stopped.

Within one read-only dispatch proof, a private owner-issued context reuses its
entry resource observation while checking source, receipt, claims and lease
authority throughout. Routing, ingress and foreign-site observations remain
fresh. A complete resource/runtime observation brackets the proof, including
final volume and inventory rereads. The context is revoked before return and
cannot cross a lifecycle effect, publication or another observation phase.
This reduces nested inspection calls; it is not a measured runtime or CPU claim.

Rollback requires restored source bytes, stopped original resources and absent
proxy dispatch before handing hostname claims back to the restored legacy source.
It retains a durable handoff state across interrupted claim removal. Builds, jobs,
readiness, source binds, files, branch overrides and custom bridges remain outside
this initial routing family. The owner and private-store model do not prove live
TLS, SQL fidelity, OAuth login or application acceptance. The maintained isolated
ingress lifecycle fixture remains required; global DNS and trust are unchanged.

The explicitly selected `native-compose-adoption-routing-worktrees` scenario
adds an HTTP service to the original two-worktree PostgreSQL fixture. It requires
both literal HTTPS origins and the existing OAuth alias to serve each checkout's
marker, with no published proxy ports. Saved `open` must select alpha's
checkout-local alias over the authored and primary-local dev preference. It also
checks original SQL/IDs/births, a known partial-stop journal and explicit
recovery, two retained up/down cycles, exact source rollback and claim handoff.
Unknown child or cleanup disposition retains the fixture. The temporary Caddy
owner is shared with `native-config-routing`; stopped user proxies and the
existing `hack-dev` network stay intact. This scenario does not perform OAuth
login, change host DNS/trust, or qualify combined unsupported families.

With current compiled artifacts, cached fixture images and an exclusively
coordinated Docker lane, select it using the same prerequisites above and
`--only=native-compose-adoption-routing-worktrees`. Its source and pure controls
are separate from a completed live TLS/SQL run.
## Retained directory binds

Version 12 is a distinct retained source-directory owner. It accepts literal
Expand Down
8 changes: 6 additions & 2 deletions docs/reference/native-config-import.md
Original file line number Diff line number Diff line change
Expand Up @@ -138,8 +138,12 @@ grant does not authorize retained adoption of any of those feature families.

These are Linux declaration defaults. Compose's file-backed binds can ignore
permission options, so this preview does not establish original file modes or
runtime binding equivalence. Retained adoption still refuses these declarations
and grants before private values, keys or engine probes. See Docker's
runtime binding equivalence. The ordinary retained-adoption baseline still refuses
file declarations and grants before private values, keys or engine probes. The
separate [retained-file owner](native-compose-adoption.md) requires original bind
and material proof for its closed config-0444 and protected secret-0400/0600 subset;
preview completeness does not provide that authority or qualify ordinary secret
permissions. See Docker's
[config grants](https://docs.docker.com/reference/compose-file/services/#configs)
and [secret grants](https://docs.docker.com/reference/compose-file/services/#secrets).

Expand Down
9 changes: 9 additions & 0 deletions src/commands/config-adopt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
} from "../lib/native-compose-adoption-generation.ts";
import { previewLegacyComposeAdoption } from "../lib/native-compose-adoption-preview.ts";
import { legacyComposeRetainedOrdered } from "../lib/native-compose-adoption-readiness.ts";
import { runLegacyComposeRetainedRoutingOperation } from "../lib/native-compose-adoption-routing-execution.ts";
import { requireNativeComposeBackend } from "../lib/native-compose-selection.ts";
import { run } from "../lib/shell.ts";

Expand Down Expand Up @@ -117,6 +118,14 @@ async function adoptPrepared(
if (opts.signal.aborted) {
throw new Error("Legacy adoption cancelled; values omitted.");
}
if (input.retainedRouting) {
return await runLegacyComposeRetainedRoutingOperation({
input,
operation: "stop",
deadline,
signal: opts.signal,
});
}
if (
legacyComposeRetainedOrdered(input.retainedPlan) ||
input.retainedBuild ||
Expand Down
Loading
Loading