Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
62 commits
Select commit Hold shift + click to select a range
880fd51
fix(sandbox): repair Shields removal regressions
ericksoa Sep 3, 2026
18fb464
test(onboard): cover stable create argument positions
ericksoa Sep 3, 2026
6752d85
fix(hermes): refresh validator integrity digest
ericksoa Sep 3, 2026
cee4d82
fix(onboard): preserve optional create callback contract
ericksoa Sep 3, 2026
825d82a
fix(pi): refresh Shields removal qualification receipts
ericksoa Sep 3, 2026
e3ff72f
chore(ci): retrigger exact-head qualification
ericksoa Sep 3, 2026
a3b7c98
docs(pi): clarify qualification receipt ordering
ericksoa Sep 3, 2026
0061eec
merge: integrate current main for E2E
ericksoa Sep 3, 2026
376c7c0
test(e2e): assert accepted messaging placeholders
ericksoa Sep 3, 2026
e7d2948
ci(e2e): add direct regression runner
ericksoa Sep 3, 2026
dc2c549
fix(ci): pass simple E2E catalog explicitly
ericksoa Sep 3, 2026
81d8844
fix(ci): isolate simple E2E catalog from CLI packaging
ericksoa Sep 3, 2026
39252de
fix(ci): correlate direct E2E results
ericksoa Sep 3, 2026
a30c820
ci: run affected E2Es directly
ericksoa Sep 3, 2026
1fe29d4
ci: install OpenShell for MCP regression
ericksoa Sep 3, 2026
6d1102d
fix(e2e): restore Slack runtime dependency and live output
ericksoa Sep 3, 2026
0345383
ci: add maintainer simple E2E runner
ericksoa Sep 3, 2026
bb8551a
ci: build only required E2E bases
ericksoa Sep 3, 2026
9f15ff5
ci: reuse exact simple E2E images
ericksoa Sep 3, 2026
9dc17a7
ci: separate image and candidate revisions
ericksoa Sep 3, 2026
978d703
test(e2e): expose Hermes MCP hash drift
ericksoa Sep 3, 2026
3faa497
fix(openclaw): bundle fast-uri with Slack runtime
ericksoa Sep 3, 2026
00c2edb
fix(e2e): validate mutable Hermes MCP integrity
ericksoa Sep 3, 2026
616f7b1
ci: honor simple E2E selectors
ericksoa Sep 4, 2026
cfb89c3
ci: align simple E2E selector defaults
ericksoa Sep 4, 2026
e3e3123
Merge branch 'main' into fix/shields-removal-e2e-regressions
prekshivyas Sep 4, 2026
7088a7c
fix: let MCP restart repair stale adapters
ericksoa Sep 4, 2026
205e350
fix: install fast-uri in OpenClaw runtime
ericksoa Sep 4, 2026
5e40406
ci: reuse exact OpenClaw E2E bases
ericksoa Sep 4, 2026
2ac0334
fix: restore Hermes cron backup access
ericksoa Sep 4, 2026
513f349
ci: keep runtime check out of base inputs
ericksoa Sep 4, 2026
6ca7518
fix: bundle fast-uri for external Slack runtime
ericksoa Sep 4, 2026
975b0bc
fix: keep Hermes cron state sandbox-owned
ericksoa Sep 4, 2026
38c9efb
fix: expose locked fast-uri to global OpenClaw
ericksoa Sep 4, 2026
dd7ba63
fix: move managed gateway lease into readable trust root
ericksoa Sep 4, 2026
cf4d65d
fix: restore managed WeChat extension link
ericksoa Sep 4, 2026
495eb55
merge: resolve conflicts with main
github-actions[bot] Sep 4, 2026
fc76af1
fix: preserve reviewed WeChat extension link in backups
ericksoa Sep 4, 2026
deb8a07
test: align MCP restart runtime selection
ericksoa Sep 4, 2026
3bc82b4
test(e2e): route WeChat mock through policy transport
ericksoa Sep 4, 2026
8c47ef2
fix(rebuild): retain local supervisor authority
ericksoa Sep 4, 2026
7a47ec2
ci(e2e): honor explicit image cohort reuse
ericksoa Sep 4, 2026
33780fd
ci(e2e): pass the selected base into upgrades
ericksoa Sep 4, 2026
996d41b
ci(e2e): build required base architectures
ericksoa Sep 4, 2026
2d6cfaa
ci(e2e): classify OpenClaw remediation as base input
ericksoa Sep 4, 2026
17627ac
merge: resolve conflicts with main
github-actions[bot] Sep 4, 2026
78234d7
merge: resolve conflicts with main
ericksoa Sep 4, 2026
92fa4e4
test(e2e): align regression mock coverage
ericksoa Sep 4, 2026
2aa547d
merge: take current main audit fix
ericksoa Sep 4, 2026
c3d6453
test: satisfy static validation
ericksoa Sep 4, 2026
9fdc60d
fix(images): verify receipts with audited npm
ericksoa Sep 4, 2026
25914d6
fix(hermes): preserve cron ownership in managed images
ericksoa Sep 4, 2026
a9fa8ab
fix(hermes): select lazy path by runtime identity
ericksoa Sep 4, 2026
c00cec9
fix(hermes): select lazy path by runtime identity
ericksoa Sep 4, 2026
089ab1d
merge: resolve conflicts with main
github-actions[bot] Sep 4, 2026
76029ed
merge: resolve conflicts with main
github-actions[bot] Sep 4, 2026
ff1caff
fix(sandbox): focus Shields migration repairs
prekshivyas Sep 4, 2026
5dc5b88
Merge branch 'main' into fix/shields-removal-e2e-regressions
prekshivyas Sep 4, 2026
7273f6e
Merge remote-tracking branch 'refs/remotes/origin/fix/shields-removal…
prekshivyas Sep 4, 2026
0c33508
fix(sandbox): remove unrelated Hermes base repair
prekshivyas Sep 4, 2026
e80bf46
test(onboard): clarify Shields repair evidence
prekshivyas Sep 4, 2026
9f697dc
fix(sandbox): retain latest main Hermes base repair
prekshivyas Sep 4, 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
Original file line number Diff line number Diff line change
Expand Up @@ -1004,7 +1004,7 @@ describe("sandbox crash-recovery replay (#5961, #6228)", () => {

expect(calls.skipped).not.toHaveBeenCalledWith("sandbox", "my-assistant");
expect(calls.createSandbox).toHaveBeenCalledTimes(1);
expect(calls.createSandbox.mock.calls[0]?.at(-1)).toMatchObject({ recreate: true });
expect(calls.createSandbox.mock.calls[0]?.at(-2)).toMatchObject({ recreate: true });
});

it.each([["build", defaultCreateFingerprint("v0.0.108")]] as const)(
Expand All @@ -1028,7 +1028,7 @@ describe("sandbox crash-recovery replay (#5961, #6228)", () => {
});

expect(calls.createSandbox).toHaveBeenCalledOnce();
expect(calls.createSandbox.mock.calls[0]?.at(-1)).toEqual(
expect(calls.createSandbox.mock.calls[0]?.at(-2)).toEqual(
expect.objectContaining({ recreate: true }),
);
expect(calls.error).not.toHaveBeenCalled();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ describe("sandbox create intent machine boundary", () => {
sandboxName: "same-sandbox",
selectedMessagingChannels: ["telegram"],
});
const createIntent = calls.createSandbox.mock.calls[0]?.at(-1) as unknown as {
const createIntent = calls.createSandbox.mock.calls[0]?.at(-2) as unknown as {
resolved: unknown;
};
expect(createIntent).toMatchObject({
Expand Down Expand Up @@ -152,7 +152,7 @@ describe("sandbox create intent machine boundary", () => {
sandboxName: "saved",
});

expect(calls.createSandbox.mock.calls[0]?.at(-1)).toMatchObject({
expect(calls.createSandbox.mock.calls[0]?.at(-2)).toMatchObject({
resolved: {
policy: { options: { additionalPresets: ["mcp-bridge-fake"] } },
},
Expand All @@ -177,7 +177,7 @@ describe("sandbox create intent machine boundary", () => {
sandboxName: "saved",
});

const createIntent = calls.createSandbox.mock.calls[0]?.at(-1);
const createIntent = calls.createSandbox.mock.calls[0]?.at(-2);
expect(createIntent).not.toHaveProperty("rebuildPolicyPresets");
expect(createIntent).toMatchObject({
resolved: { policy: { options: { additionalPresets: [] } } },
Expand All @@ -197,7 +197,7 @@ describe("sandbox create intent machine boundary", () => {
});

expect(calls.recordSkip).not.toHaveBeenCalled();
expect(calls.createSandbox.mock.calls[0]?.at(-1)).toMatchObject({ recreate: true });
expect(calls.createSandbox.mock.calls[0]?.at(-2)).toMatchObject({ recreate: true });
});

it("checkpoints a known sandbox name before an interrupted web-search prompt (#6743)", async () => {
Expand Down
16 changes: 9 additions & 7 deletions src/lib/onboard/machine/handlers/sandbox-dcode-selection.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ function dcodeOptions(
}

describe("handleSandboxState live DCode selection", () => {
it("carries durable observability intent in the sandbox create intent", async () => {
it("keeps observability in the create intent when the verified-create callback is absent (#10964)", async () => {
const session = createSession({
observabilityEnabled: true,
observabilityRequestedExplicitly: true,
Expand All @@ -70,7 +70,7 @@ describe("handleSandboxState live DCode selection", () => {
agent: { name: "langchain-deepagents-code" },
});

expect(calls.createSandbox.mock.calls[0]?.at(-1)).toMatchObject({
expect(calls.createSandbox.mock.calls[0]?.at(-2)).toMatchObject({
resolved: expect.any(Object),
recreate: false,
toolDisclosure: "progressive",
Expand All @@ -80,6 +80,8 @@ describe("handleSandboxState live DCode selection", () => {
dcodeAutoApprovalMode: "disabled",
extraProviders: [],
});
expect(calls.createSandbox.mock.calls[0]).toHaveLength(17);
expect(calls.createSandbox.mock.calls[0]?.at(-1)).toBeUndefined();
});

it("carries authoritative thread opt-in in the create intent (#6478)", async () => {
Expand All @@ -92,7 +94,7 @@ describe("handleSandboxState live DCode selection", () => {
requestedDcodeAutoApprovalMode: "thread-opt-in",
});

expect(calls.createSandbox.mock.calls[0]?.at(-1)).toMatchObject({
expect(calls.createSandbox.mock.calls[0]?.at(-2)).toMatchObject({
dcodeAutoApprovalMode: "thread-opt-in",
});
});
Expand Down Expand Up @@ -121,7 +123,7 @@ describe("handleSandboxState live DCode selection", () => {
requestedDcodeAutoApprovalMode: "thread-opt-in",
});

expect(journal.completeCreate.mock.calls[0]?.at(-1)).toMatchObject({
expect(journal.completeCreate.mock.calls[0]?.at(-2)).toMatchObject({
recreate: true,
recreateTransaction: expect.any(Object),
dcodeAutoApprovalMode: "thread-opt-in",
Expand Down Expand Up @@ -163,7 +165,7 @@ describe("handleSandboxState live DCode selection", () => {
state: "sandbox",
metadata: { repair: "recorded-sandbox-cleanup", sandboxName: "saved" },
});
expect(journal.completeCreate.mock.calls[0]?.at(-1)).toMatchObject({
expect(journal.completeCreate.mock.calls[0]?.at(-2)).toMatchObject({
recreate: true,
recreateTransaction: expect.any(Object),
dcodeAutoApprovalMode: "thread-opt-in",
Expand Down Expand Up @@ -209,7 +211,7 @@ describe("handleSandboxState live DCode selection", () => {
"openai-completions",
null,
);
expect(calls.createSandbox.mock.calls[0]?.at(-1)).toEqual({
expect(calls.createSandbox.mock.calls[0]?.at(-2)).toEqual({
resolved: expect.any(Object),
recreate: true,
toolDisclosure: "progressive",
Expand All @@ -232,7 +234,7 @@ describe("handleSandboxState live DCode selection", () => {
await handleSandboxState(dcodeOptions(deps));

expect(calls.removeSandbox).not.toHaveBeenCalled();
expect(calls.createSandbox.mock.calls[0]?.at(-1)).toEqual({
expect(calls.createSandbox.mock.calls[0]?.at(-2)).toEqual({
resolved: expect.any(Object),
recreate: true,
toolDisclosure: "progressive",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ describe("Hermes portable sandbox endpoint provenance", () => {

expect(calls.skipped).not.toHaveBeenCalledWith("sandbox", "saved");
expect(createSandbox).toHaveBeenCalledOnce();
expect(createSandbox.mock.calls[0]?.at(-1)).toMatchObject({ recreate: false });
expect(createSandbox.mock.calls[0]?.at(-2)).toMatchObject({ recreate: false });
expect(calls.removeSandbox).not.toHaveBeenCalled();
expect(calls.complete).toHaveBeenCalledWith(
"sandbox",
Expand All @@ -70,7 +70,7 @@ describe("Hermes portable sandbox endpoint provenance", () => {
hermesPortableLifecycle: true,
});

expect(calls.createSandbox.mock.calls[0]?.at(-1)).toMatchObject({ endpointSource: null });
expect(calls.createSandbox.mock.calls[0]?.at(-2)).toMatchObject({ endpointSource: null });
expect(calls.updateSandbox).toHaveBeenCalledWith(
"my-assistant",
expect.objectContaining({ endpointSource: null }),
Expand All @@ -88,6 +88,6 @@ describe("Hermes portable sandbox endpoint provenance", () => {
hostLocalInferenceRouteOnly: false,
});

expect(calls.createSandbox.mock.calls[0]?.at(-1)).toMatchObject({ endpointSource: null });
expect(calls.createSandbox.mock.calls[0]?.at(-2)).toMatchObject({ endpointSource: null });
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ describe("handleSandboxState provider effect replay", () => {
});
const createSandbox = vi.fn(async (...args: unknown[]) => {
events.push("sandbox-create");
const createIntent = args.at(-1) as {
const createIntent = args.at(-2) as {
deferSandboxEffectsUntilIdentityVerification?: boolean;
};
expect(createIntent.deferSandboxEffectsUntilIdentityVerification).toBeUndefined();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ it("journals not-ready repair on the selected non-default gateway (#6492)", asyn
});

expect(createSandbox).toHaveBeenCalledOnce();
const createIntent = createSandbox.mock.calls[0]?.at(-1);
const createIntent = createSandbox.mock.calls[0]?.at(-2);
expect(createIntent).toMatchObject({
recreate: true,
recreateTransaction: {
Expand Down Expand Up @@ -272,7 +272,7 @@ it("does not carry a recorded preset list through post-delete onboard resume", a
liveIdentityFingerprint: null,
};
const createSandbox = vi.fn(async (...args: unknown[]) => {
const createIntent = args.at(-1);
const createIntent = args.at(-2);
expect(createIntent).toMatchObject({
recreate: true,
recreateJournalTargetIntentFingerprint: targetIntentFingerprint,
Expand Down Expand Up @@ -441,7 +441,7 @@ it("removes the journaled source image after resuming a registered replacement",
await handleSandboxState(options);

expect(createSandbox).toHaveBeenCalledTimes(2);
expect(createSandbox.mock.calls[1]?.at(-1)).toMatchObject({
expect(createSandbox.mock.calls[1]?.at(-2)).toMatchObject({
recreateTransaction: {
id: journal?.id,
targetGeneration: journal?.targetGeneration,
Expand Down Expand Up @@ -768,7 +768,7 @@ it("opens the lifecycle journal for a fresh route reservation before creation (#
const createSandbox = vi.fn(async (...args: unknown[]) => {
const transaction = session.checkpoint?.sandboxRecreate;
expect(transaction).toBeDefined();
expect(args.at(-1)).toMatchObject({
expect(args.at(-2)).toMatchObject({
recreate: true,
recreateTransaction: {
id: transaction?.id,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ describe("handleSandboxState resume recreation", () => {
},
},
expect.objectContaining({ compatibleEndpointReasoning: "true", recreate: true }),
undefined,
);
});

Expand Down
2 changes: 1 addition & 1 deletion src/lib/onboard/machine/handlers/sandbox-test-fixtures.ts
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ export function bindJournaledRecreate(
const transaction = updateSession((current) => current).checkpoint?.sandboxRecreate;
expect(transaction).toBeDefined();
const ownedTransaction = transaction as CheckpointSandboxRecreateTransaction;
const createIntent = args.at(-1) as
const createIntent = args.at(-2) as
| { recreate?: boolean; recreateTransaction?: { id?: string } }
| undefined;
expect(createIntent?.recreate).toBe(true);
Expand Down
21 changes: 13 additions & 8 deletions src/lib/onboard/machine/handlers/sandbox.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ describe("handleSandboxState", () => {
endpointSource: null,
extraProviders: [],
},
undefined,
);
expect(calls.finalizeRouteReservation).not.toHaveBeenCalled();
expect(calls.updateSandbox).toHaveBeenCalledWith(
Expand Down Expand Up @@ -133,7 +134,7 @@ describe("handleSandboxState", () => {
hostLocalInferenceRouteOnly: true,
});

expect(calls.createSandbox.mock.calls[0]?.at(-1)).toMatchObject({ endpointSource: null });
expect(calls.createSandbox.mock.calls[0]?.at(-2)).toMatchObject({ endpointSource: null });
});

it("records credential-provider bindings and the resource-profile decision in the checkpoint (#7022)", async () => {
Expand Down Expand Up @@ -234,7 +235,7 @@ describe("handleSandboxState", () => {
authoritativeResumeConfig: true,
});

expect(calls.createSandbox.mock.calls[0]?.at(-1)).toMatchObject({});
expect(calls.createSandbox.mock.calls[0]?.at(-2)).toMatchObject({});
});

it("does not persist an authoritative policy tier in sandbox create state", async () => {
Expand All @@ -247,7 +248,7 @@ describe("handleSandboxState", () => {
});

expect(calls.resolveCreateIntent.mock.calls[0]?.[0]).not.toHaveProperty("policyTier");
expect(calls.createSandbox.mock.calls[0]?.at(-1)).not.toHaveProperty("policyTier");
expect(calls.createSandbox.mock.calls[0]?.at(-2)).not.toHaveProperty("policyTier");
});

it("rejects observability for a selected non-DCode agent", async () => {
Expand Down Expand Up @@ -282,7 +283,7 @@ describe("handleSandboxState", () => {
sandboxName: "saved",
});

expect(calls.createSandbox.mock.calls[0]?.at(-1)).toMatchObject({
expect(calls.createSandbox.mock.calls[0]?.at(-2)).toMatchObject({
observabilityEnabled: true,
});
expect(session.observabilityEnabled).toBe(true);
Expand Down Expand Up @@ -359,7 +360,7 @@ describe("handleSandboxState", () => {
requestedObservabilityEnabled: false,
});

expect(calls.createSandbox.mock.calls[0]?.at(-1)).toMatchObject({
expect(calls.createSandbox.mock.calls[0]?.at(-2)).toMatchObject({
observabilityEnabled: false,
observabilityRequestedExplicitly: true,
});
Expand Down Expand Up @@ -417,7 +418,7 @@ describe("handleSandboxState", () => {
requestedObservabilityEnabled: requested,
});

expect(calls.createSandbox.mock.calls[0]?.at(-1)).toMatchObject({
expect(calls.createSandbox.mock.calls[0]?.at(-2)).toMatchObject({
recreate: true,
observabilityEnabled: requested,
});
Expand Down Expand Up @@ -456,7 +457,7 @@ describe("handleSandboxState", () => {
sandboxName: "saved",
});

expect(calls.createSandbox.mock.calls[0]?.at(-1)).toMatchObject({
expect(calls.createSandbox.mock.calls[0]?.at(-2)).toMatchObject({
recreate: true,
observabilityEnabled: requested,
});
Expand Down Expand Up @@ -514,7 +515,7 @@ describe("handleSandboxState", () => {
requestedObservabilityEnabled: false,
});

expect(calls.createSandbox.mock.calls[0]?.at(-1)).toMatchObject({
expect(calls.createSandbox.mock.calls[0]?.at(-2)).toMatchObject({
recreate: true,
observabilityEnabled: false,
});
Expand Down Expand Up @@ -557,6 +558,7 @@ describe("handleSandboxState", () => {
endpointSource: null,
extraProviders: [],
},
undefined,
);
expect(result.hermesToolGateways).toEqual(["nous-audio"]);
expect(calls.note).toHaveBeenCalledWith(
Expand Down Expand Up @@ -845,6 +847,7 @@ describe("handleSandboxState", () => {
endpointSource: null,
extraProviders: [],
},
undefined,
);
});

Expand Down Expand Up @@ -1019,6 +1022,7 @@ describe("handleSandboxState", () => {
targetIntentFingerprint: expect.any(String),
}),
}),
undefined,
);
expect(result.webSearchConfigChanged).toBe(true);
});
Expand Down Expand Up @@ -1152,6 +1156,7 @@ describe("handleSandboxState", () => {
targetIntentFingerprint: expect.any(String),
}),
}),
undefined,
);
expect(result.webSearchConfig).toBeNull();
});
Expand Down
22 changes: 10 additions & 12 deletions src/lib/onboard/machine/handlers/sandbox.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2183,18 +2183,16 @@ class SandboxStateFlow<
}
: null,
effectiveCreateIntent,
...(activateVerifiedCredentialProviders
? [
async (
verifiedContext: import("../../types").VerifiedSandboxCreateEffectsContext,
) => {
state = await activateVerifiedCredentialProviders(
state,
verifiedContext.revalidateSandboxIdentity,
);
},
]
: []),
activateVerifiedCredentialProviders
? async (
verifiedContext: import("../../types").VerifiedSandboxCreateEffectsContext,
) => {
state = await activateVerifiedCredentialProviders(
state,
verifiedContext.revalidateSandboxIdentity,
);
}
: undefined,
),
);
} catch (error) {
Expand Down
27 changes: 20 additions & 7 deletions src/lib/onboard/sandbox-workload-rebuild.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -370,20 +370,33 @@ describe("managed workload rebuild preflight", () => {
}
});

it("rejects a qualification revision that conflicts with durable authority (#9385)", async () => {
const prepare = vi.fn(async () => replacement("langchain-deepagents-code"));
it("uses the GitHub Actions qualification revision and retains the previous workload receipt during rebuild (#10970)", async () => {
const prepare = vi.fn(async () =>
replacement("openclaw", "linux/amd64", "c".repeat(40)),
);
managedWorkloadRebuildDependencies.prepareSandboxWorkloadSource = prepare;
vi.stubEnv("GITHUB_ACTIONS", "true");
vi.stubEnv("E2E_MANAGED_IMAGE_REVISION", "c".repeat(40));

await expect(
prepareManagedWorkloadRebuildHandoff(entry("langchain-deepagents-code"), {
const handoff = await prepareManagedWorkloadRebuildHandoff(
entry("openclaw"),
{
runtime: runtime(),
provider: provider(),
version: "0.0.100",
}),
).rejects.toThrow("live qualification revision does not match the durable workload receipt");
expect(prepare).not.toHaveBeenCalled();
},
);

expect(handoff?.previousReceipt.sourceRevision).toBe("a".repeat(40));
expect(handoff?.replacement.source.contract.source.revision).toBe("c".repeat(40));
expect(prepare).toHaveBeenCalledExactlyOnceWith({
agentName: "openclaw",
legacyDockerfilePath: "managed-rebuild-must-not-stage-this-dockerfile",
runtime: runtime(),
version: "0.0.100",
policy: "require-managed",
catalogRevision: "c".repeat(40),
});
});

it("accepts an exact PR replacement catalog newer than durable authority (#9464)", async () => {
Expand Down
Loading
Loading