Skip to content
Merged
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
kind: Fixed
body: Preserve the controller channel when workload-exit observation arrives after the controlled-session output-finalization deadline.
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
kind: Fixed
body: Allow controlled-session controller packaging to use the locked local image identity when a staged generation has no registry digest.
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
kind: Docs
body: Document and continuously prove the public controlled-session boundary with an OmegaFlow-shaped asciinema, Playwright, and Chromium conformance workflow, including retained artifacts after failed workload-output finalization.
32 changes: 32 additions & 0 deletions .github/workflows/integration.yml
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,38 @@ jobs:
go test -timeout 15m ./internal/dockerdeploy
-run '^(TestControlledSessionSupervisorDockerIntegration|TestControlledSessionNetworkingDockerIntegration|TestControlledSessionControllerPackageDockerIntegration)$'

- name: Install pinned OmegaFlow conformance fixtures
if: matrix.name == 'Linux amd64'
run: |
asciinema_fixture=testdata/controlled-session/asciinema-v3-linux-amd64.json
asciinema_url=$(jq -r .url "$asciinema_fixture")
asciinema_sha256=$(jq -r .sha256 "$asciinema_fixture")
curl --fail --location --silent --show-error "$asciinema_url" --output "$RUNNER_TEMP/asciinema"
echo "$asciinema_sha256 $RUNNER_TEMP/asciinema" | sha256sum --check --strict
chmod 0755 "$RUNNER_TEMP/asciinema"

conformance_fixture=testdata/controlled-session/omegaflow-conformance-v1.json
playwright_url=$(jq -r '.packages[] | select(.name == "playwright") | .url' "$conformance_fixture")
playwright_sha256=$(jq -r '.packages[] | select(.name == "playwright") | .sha256' "$conformance_fixture")
playwright_core_url=$(jq -r '.packages[] | select(.name == "playwright-core") | .url' "$conformance_fixture")
playwright_core_sha256=$(jq -r '.packages[] | select(.name == "playwright-core") | .sha256' "$conformance_fixture")
curl --fail --location --silent --show-error "$playwright_url" --output "$RUNNER_TEMP/playwright.tgz"
curl --fail --location --silent --show-error "$playwright_core_url" --output "$RUNNER_TEMP/playwright-core.tgz"
echo "$playwright_sha256 $RUNNER_TEMP/playwright.tgz" | sha256sum --check --strict
echo "$playwright_core_sha256 $RUNNER_TEMP/playwright-core.tgz" | sha256sum --check --strict

echo "REPLOY_ASCIINEMA_FIXTURE=$RUNNER_TEMP/asciinema" >> "$GITHUB_ENV"
echo "REPLOY_PLAYWRIGHT_FIXTURE=$RUNNER_TEMP/playwright.tgz" >> "$GITHUB_ENV"
echo "REPLOY_PLAYWRIGHT_CORE_FIXTURE=$RUNNER_TEMP/playwright-core.tgz" >> "$GITHUB_ENV"

- name: Run OmegaFlow controlled-session conformance
if: matrix.name == 'Linux amd64'
env:
REPLOY_DOCKER_INTEGRATION: "1"
run: >-
go test -count=1 -timeout 15m ./internal/dockerdeploy
-run '^TestOmegaFlowControlledSessionConformanceDockerIntegration$'

- name: Run CLI runtime integration
if: ${{ matrix.persistent_install == false }}
env:
Expand Down
24 changes: 24 additions & 0 deletions docs/CONTROLLED_SESSION_DESIGN.md
Original file line number Diff line number Diff line change
Expand Up @@ -1870,6 +1870,30 @@ reports the session failure. The fixture is a conformance test for the generic
Reploy boundary; OmegaFlow continues to own command completion, cwd reporting,
action markers, browser orchestration, and media rendering.

Implementation status: complete for the initial Linux `amd64` conformance
profile. A repository-owned OmegaFlow-shaped controller drives only the public
JSON Lines broker stream and the terminal attachment beneath unmodified,
checksum-pinned asciinema 3.2.1. The public host command runs it against two
ordinary current staged deployments. The controller proves shell continuity
across marked operations and Ctrl-C, a later resize, a terminal-started HTTP
service reached by checksum-pinned Playwright 1.55.0 and Chromium, and retained
cast, text, screenshot, and proof artifacts in the declared output directory.
The browser controller base is pinned by multi-platform image digest; the
conformance run is initially required in Linux `amd64` CI while the independent
client packaging and Docker integration suites continue to cover Linux
`arm64`.

The same fixture injects a host-side PTY-observation timeout by suspending the
public host process, after it publishes `terminating`, across the absolute
output-finalization deadline. The controller, recorder, and private channel
remain live while the workload exits. After the host resumes, the fixture
proves the actionable failed-finalization event reaches the OmegaFlow-shaped
controller, which retains and closes the partial cast, records the failure,
sends `complete`, consumes `terminated`, acknowledges it, and exits cleanly
while the public host command still reports the session failure. The fixture
adds no OmegaFlow code, private-protocol dependency, runtime dependency
installer, or public Reploy surface.

### Slice 6: User-Facing Documentation

After the generic runtime and at least one integration profile are proven,
Expand Down
4 changes: 3 additions & 1 deletion internal/controlledsession/asciinema_fixture_linux_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (
"os"
"os/exec"
"path/filepath"
"runtime"
"strings"
"testing"
"time"
Expand Down Expand Up @@ -140,7 +141,8 @@ func TestTerminalAttachmentRunsBeneathPinnedUnmodifiedAsciinemaV1(t *testing.T)

func readAsciinemaFixtureMetadataV1(t *testing.T) asciinemaFixtureMetadataV1 {
t.Helper()
payload, err := os.ReadFile("../../testdata/controlled-session/asciinema-v3-linux-amd64.json")
fixturePath := "../../testdata/controlled-session/asciinema-v3-linux-" + runtime.GOARCH + ".json"
payload, err := os.ReadFile(fixturePath)
if err != nil {
t.Fatal(err)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,11 @@ func inspectControlledSessionControllerSourceV1(ctx context.Context, current Cur
if err != nil {
return InspectedImageCandidate{}, fmt.Errorf("inspect controlled-session controller generation %q: %w", current.Generation.Reference, err)
}
inspection, err := parseDockerImageInspectionDetails(current.Generation.Reference, current.Lock.Platform, []byte(output))
// Reploy generation references are local mutable tags and deliberately do
// not have registry RepoDigests. Parse the inspected record through the
// immutable config identity already frozen in the build lock; the parser
// then also proves that the generation tag still resolves to that ID.
inspection, err := parseDockerImageInspectionDetails(string(current.Lock.FinalImage.ConfigDigest), current.Lock.Platform, []byte(output))
if err != nil {
return InspectedImageCandidate{}, fmt.Errorf("inspect controlled-session controller generation %q: %w", current.Generation.Reference, err)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package dockerdeploy

import (
"context"
"fmt"
"os"
"os/exec"
"path/filepath"
Expand All @@ -19,6 +20,47 @@ import (
"github.com/omry/reploy/internal/providerstore"
)

func TestInspectControlledSessionControllerSourceAcceptsLocalGenerationTagV1(t *testing.T) {
platform, err := blueprint.ParsePlatform("linux/amd64")
if err != nil {
t.Fatal(err)
}
configID := canonical.Digest("sha256:" + strings.Repeat("4", 64))
diffID := canonical.Digest("sha256:" + strings.Repeat("5", 64))
rootFS, err := deploy.RootFSSubject([]canonical.Digest{diffID})
if err != nil {
t.Fatal(err)
}
current := CurrentBuild{
Generation: deploy.EnvironmentGenerationState{Reference: "reploy/env/controller:g-current"},
Lock: deploy.BuildLockV1{
Platform: platform,
FinalImage: providers.RealizedImageV1{
Digest: configID, ConfigDigest: configID, RootFSSubject: rootFS,
},
},
}
inspection := fmt.Sprintf(
`[{"Id":%q,"RepoDigests":[],"Os":"linux","Architecture":"amd64","RootFS":{"Layers":[%q]},"Config":{}}]`,
configID,
diffID,
)
var calls [][]string
source, err := inspectControlledSessionControllerSourceV1(t.Context(), current, func(_ context.Context, args ...string) (string, error) {
calls = append(calls, append([]string{}, args...))
return inspection, nil
})
if err != nil {
t.Fatal(err)
}
if len(calls) != 1 || strings.Join(calls[0], " ") != "image inspect "+current.Generation.Reference {
t.Fatalf("Docker inspection calls = %#v", calls)
}
if source.Descriptor.AuthorReference != string(configID) || source.Descriptor.ImmutableReference != string(configID) || source.Image != current.Lock.FinalImage {
t.Fatalf("controller source = %#v", source)
}
}

func TestControlledSessionControllerPackageDockerfileAddsOnlyControllerTool(t *testing.T) {
source := applicationRuntimeLayerTestRequest(t).Source
extracted := probearchive.ExtractedSessionClient{
Expand Down
Loading
Loading