@rosthq/cli 0.7.113 → 0.7.114
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +50 -2
- package/dist/index.js.map +2 -2
- package/dist/runner-sandbox.d.ts +50 -0
- package/dist/runner-sandbox.d.ts.map +1 -1
- package/dist/runner-serve.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -38708,6 +38708,14 @@ function accessLevelForScope(scopeTier) {
|
|
|
38708
38708
|
return "admin";
|
|
38709
38709
|
}
|
|
38710
38710
|
}
|
|
38711
|
+
var RUNNER_WIRED_CONNECTOR_IDS = /* @__PURE__ */ new Set([
|
|
38712
|
+
"gmail.read",
|
|
38713
|
+
"gmail.draft",
|
|
38714
|
+
"gmail.send",
|
|
38715
|
+
"sheets.read",
|
|
38716
|
+
"sheets.write",
|
|
38717
|
+
"slack.post_message"
|
|
38718
|
+
]);
|
|
38711
38719
|
function providerRequirementFor(entry) {
|
|
38712
38720
|
if (!entry.credential_required) {
|
|
38713
38721
|
return entry.provider === "rost" || entry.provider === "web" ? "platform_managed" : "none";
|
|
@@ -38730,6 +38738,12 @@ function trustedRequiredMetadataFor(entry) {
|
|
|
38730
38738
|
"authorization_revoked_at"
|
|
38731
38739
|
];
|
|
38732
38740
|
}
|
|
38741
|
+
function laneSupportFor(entry) {
|
|
38742
|
+
if (providerRequirementFor(entry) === "connection" && !RUNNER_WIRED_CONNECTOR_IDS.has(entry.id)) {
|
|
38743
|
+
return ["cloud"];
|
|
38744
|
+
}
|
|
38745
|
+
return ["cloud", "runner", "mcp"];
|
|
38746
|
+
}
|
|
38733
38747
|
function enrichCatalogEntry(entry) {
|
|
38734
38748
|
const accessLevels = [...new Set(entry.scope_tiers.map(accessLevelForScope))];
|
|
38735
38749
|
return {
|
|
@@ -38738,7 +38752,7 @@ function enrichCatalogEntry(entry) {
|
|
|
38738
38752
|
default_access_level: accessLevelForScope(entry.default_scope_tier),
|
|
38739
38753
|
provider_requirement: providerRequirementFor(entry),
|
|
38740
38754
|
cost_class: entry.id === "script.run" || entry.id === "secret.broker" || entry.id === "baserow.read" || entry.id === "baserow.write" ? "metered_standard" : entry.id === "web.search" || entry.id === "web.fetch" || entry.id === "browser.read" ? "metered_low" : "included",
|
|
38741
|
-
lane_support:
|
|
38755
|
+
lane_support: laneSupportFor(entry),
|
|
38742
38756
|
trusted_required_metadata: trustedRequiredMetadataFor(entry)
|
|
38743
38757
|
};
|
|
38744
38758
|
}
|
|
@@ -48681,7 +48695,7 @@ Use the lower-level commands after health names a finding: \`agent.get_run\` for
|
|
|
48681
48695
|
order: 46,
|
|
48682
48696
|
title: "Tool access and vault",
|
|
48683
48697
|
summary: "How to give agents access to tools without exposing raw credentials or expanding authority by accident.",
|
|
48684
|
-
version: "2026-07-
|
|
48698
|
+
version: "2026-07-21.1",
|
|
48685
48699
|
public: true,
|
|
48686
48700
|
audiences: ["human", "cli", "mcp", "in_app_agent"],
|
|
48687
48701
|
stages: ["staffing"],
|
|
@@ -48737,6 +48751,10 @@ The native Gmail handlers run inside the same broker boundary as the REST and Sl
|
|
|
48737
48751
|
|
|
48738
48752
|
Google can be connected from Settings once the workspace OAuth app is configured. The connection flow requests offline access for Gmail read/compose/send and Sheets, stores the returned credential in the vault, and records only account, scope, and capability-availability metadata in the integration row. Partial grants are accepted when at least one connector capability is usable; missing or revoked scopes reduce the affected capability instead of granting more authority. The test action refreshes the vaulted credential and performs a minimal Gmail profile read. Gmail read/draft/send, bounded Sheets read, and approval-held Sheets write handlers run through the guarded broker when Google is connected; connecting Google still does not bypass the signed Charter manifest, tenant policy ceiling, credential vault, or tool-call audit. Sheet grants should use exact signed argument bindings for approved spreadsheet ids and ranges.
|
|
48739
48753
|
|
|
48754
|
+
## Connectors work the same on either lane
|
|
48755
|
+
|
|
48756
|
+
A seat's governed connectors are available whether its agent runs on the cloud lane or the runner lane. {{brand}} projects each connector the seat's signed Charter grants onto the seat's own MCP surface and executes it server-side \u2014 so a runner-lane agent calls the same Gmail, Sheets, and Slack connectors a cloud-lane agent does, with identical governance: the same server guard, the same held-write approval for send/write tiers, and the same tool-call audit row. The OAuth or vaulted credential is resolved and bound only on the server inside the credential closure and never travels to the runner. Because this projection is derived from the Charter manifest and the connected integration, connecting a new integration makes its capabilities available to an already-live runner seat with no charter re-sign or code change. Connectors without a server-side handler yet stay cloud-only and are shown on the seat's Tools tab as not available on the runner lane until one ships.
|
|
48757
|
+
|
|
48740
48758
|
A connected Baserow REST integration (\`integration.connect_rest\`) derives a \`baserow.read\` tenant capability ceiling the same way: a live connection surfaces read, and a disconnected/revoked one collapses to off. The derivation is read-only by design \u2014 \`baserow.write\` is never inferred from the connection and is granted only through an explicit per-seat brokered secret grant, matching the conservative-by-default rule for every connection-backed ceiling.
|
|
48741
48759
|
|
|
48742
48760
|
CLI and MCP can inspect connector readiness without seeing secrets: \`integration.list\` / \`rost_list_integrations\` lists connected providers and health metadata, \`integration.status\` / \`rost_get_integration_status\` reads one provider by id or name, and \`integration.test\` / \`rost_test_integration_connection\` runs the installed provider-specific health check. For Google, the test refreshes the vaulted OAuth credential and reads the Gmail profile, then records only account, scope, and health metadata.
|
|
@@ -56032,6 +56050,20 @@ function forgeBuildUnsupportedReason(platform2) {
|
|
|
56032
56050
|
}
|
|
56033
56051
|
return `Forge build execution is unsupported on this host: no macOS seatbelt (sandbox-exec) confinement is available on '${platform2}', so this runner cannot prove filesystem/egress isolation for an untrusted build turn. The server will not offer Forge-phase work to this runner \u2014 unless its tenant is on the narrow, operator-established trust allowlist (FORGE_SANDBOX_TRUSTED_TENANT_IDS) \u2014 until real Linux confinement (namespaces/Landlock, tracked as a DER-1343 follow-up) ships.`;
|
|
56034
56052
|
}
|
|
56053
|
+
function sandboxRequiredTurnRefusal(input) {
|
|
56054
|
+
if (input.spec.kind === "seatbelt") {
|
|
56055
|
+
return null;
|
|
56056
|
+
}
|
|
56057
|
+
if (input.mode === "off") {
|
|
56058
|
+
return null;
|
|
56059
|
+
}
|
|
56060
|
+
const postureLabel = input.mode === "strict" ? "strict" : "guard";
|
|
56061
|
+
const override = "Set RUNNER_SANDBOX=off only on a trusted, founder-authorized host to override.";
|
|
56062
|
+
if (input.platform !== "darwin") {
|
|
56063
|
+
return `Refusing to run this turn unconfined: sandbox mode is '${postureLabel}', but macOS seatbelt confinement does not exist on this host ('${input.platform}') \u2014 seatbelt is macOS-only, and Linux confinement is a DER-1343 follow-up. The runner refuses rather than running an attacker-influenceable build turn unconfined. ${override}`;
|
|
56064
|
+
}
|
|
56065
|
+
return `Refusing to run this turn unconfined: sandbox mode is '${postureLabel}', but sandbox-exec is unavailable on this macOS host, so filesystem/egress confinement cannot be applied (${input.spec.reason}). The runner refuses rather than silently degrading to no sandbox. ${override}`;
|
|
56066
|
+
}
|
|
56035
56067
|
function wrapCommandWithSandbox(spec, command, args, profilePath) {
|
|
56036
56068
|
if (spec.kind === "none" || profilePath === null) {
|
|
56037
56069
|
return { command, args, profilePath: null };
|
|
@@ -59005,6 +59037,17 @@ async function spawnRunnerTurn(ctx, workOrder, runtime, kind) {
|
|
|
59005
59037
|
if (execution?.profile === "forge_merge") {
|
|
59006
59038
|
return runForgeMergeTurn(ctx, workOrder, execution, runtime);
|
|
59007
59039
|
}
|
|
59040
|
+
const requiresSandbox = Boolean(execution?.needs_repo) || execution?.local_tools === "workspace_write";
|
|
59041
|
+
if (requiresSandbox) {
|
|
59042
|
+
const refusal = sandboxRequiredTurnRefusal({
|
|
59043
|
+
mode: ctx.config.sandboxMode,
|
|
59044
|
+
platform: process.platform,
|
|
59045
|
+
spec: ctx.config.sandbox
|
|
59046
|
+
});
|
|
59047
|
+
if (refusal) {
|
|
59048
|
+
return { ok: false, summary: refusal };
|
|
59049
|
+
}
|
|
59050
|
+
}
|
|
59008
59051
|
let forgePrep = null;
|
|
59009
59052
|
if (execution?.needs_repo) {
|
|
59010
59053
|
const prepared = await prepareForgeTurn(ctx, workOrder, execution);
|
|
@@ -59206,6 +59249,11 @@ async function resolveMergeConflictTurn(ctx, input) {
|
|
|
59206
59249
|
],
|
|
59207
59250
|
allowNetwork: ctx.config.sandboxAllowNetwork
|
|
59208
59251
|
});
|
|
59252
|
+
const sandboxRefusal = sandboxRequiredTurnRefusal({ mode: ctx.config.sandboxMode, platform: process.platform, spec: sandbox });
|
|
59253
|
+
if (sandboxRefusal) {
|
|
59254
|
+
await removeWorkspace(workspace).catch(() => void 0);
|
|
59255
|
+
return { pushed: false, result: { ok: false, summary: sandboxRefusal.slice(0, MERGE_CONFLICT_SUMMARY_MAX) } };
|
|
59256
|
+
}
|
|
59209
59257
|
const modelResult = await spawnMergeConflictModel(ctx, {
|
|
59210
59258
|
workOrder: input.workOrder,
|
|
59211
59259
|
execution: input.execution,
|