Skip to content
Closed
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
39 changes: 39 additions & 0 deletions .github/workflows/openshell-scaffold.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
name: OpenShell offline scaffold

on:
pull_request:
paths:
- 'agent-os/openshell/**'
- '.github/workflows/openshell-scaffold.yml'
push:
branches: [main]
paths:
- 'agent-os/openshell/**'
- '.github/workflows/openshell-scaffold.yml'

permissions:
contents: read

jobs:
offline-contract:
runs-on: ${{ matrix.os }}
timeout-minutes: 5
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest]
node: ['20', '22']
steps:
- uses: actions/checkout@v7.0.1
with:
persist-credentials: false
- uses: actions/setup-node@v7.0.0
with:
node-version: ${{ matrix.node }}
- name: Validate offline contracts; do not install OpenShell
run: |
node --check agent-os/openshell/scaffold.mjs
node --check agent-os/openshell/preview.mjs
node --test agent-os/openshell/scaffold.test.mjs
node agent-os/openshell/preview.mjs agent-os/openshell/fixture.json
node agent-os/openshell/preview.mjs --readiness
10 changes: 10 additions & 0 deletions agent-os/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -143,3 +143,13 @@ Use this to track recurring spend, success rate, receipt linkage, and budget pre
- Agent OS quickstart: https://agoragentic.com/guides/agent-os-quickstart/
- API reference: https://agoragentic.com/docs.html
- Discovery check: https://agoragentic.com/api/discovery/check

## OpenShell preparation scaffold

The [OpenShell scaffold](openshell/README.md) compiles offline sandbox-policy proposals for Cartographer, Emissary, and Steward against a pinned upstream source contract. It includes local tests and a [Codex integration handoff](openshell/CODEX_HANDOFF.md), but does not install OpenShell, connect a gateway, provision a sandbox, run an agent, or grant execution/payment authority. No live compatibility or production protection is claimed.

```sh
node --test agent-os/openshell/scaffold.test.mjs
node agent-os/openshell/preview.mjs agent-os/openshell/fixture.json
node agent-os/openshell/preview.mjs --readiness
```
59 changes: 59 additions & 0 deletions agent-os/openshell/CODEX_HANDOFF.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# OpenShell augmentation and integration handoff

## Goal and present state

Integrate OpenShell below Agoragentic's existing control plane, preserving the agent-operated Interchange and all owner, financial, identity, trust, and evidence boundaries. The compiler, offline CLI, observation shaper, tests, and source pin are implemented. A live provider adapter is **not** implemented or qualified. No production migration is authorized by this document.

## Work sequence

### 1. Source and build qualification

Re-read repository instructions and the pinned upstream contracts. Resolve the v0.1.2 release to the recorded commit; verify the SDK package and gateway build rather than trusting a version string. Install only in an owner-approved disposable lab. Verify the generated SDK types accept `createSpec` and verify server-side normalization has not weakened its policy. Upgrade the pin only in a reviewed change that updates the lock and conformance fixtures together.

Build or select a digest-pinned minimal worker image with the `sandbox` user/group, explicitly required paths and binaries, no credentials, no host-runtime socket, and no production configuration. The example digest is fictional. Validate hard-required Landlock on the actual host. Failure must stop setup, not silently downgrade to best effort.

Acceptance: recorded package/image/gateway integrity, generated type/schema checks, policy acceptance, and a reproducible host/image definition. These are not yet containment proof.

### 2. Trusted host adapter

Implement the adapter in the existing platform provider abstraction, not in an agent-importable SDK shim. Keep source activation default-off. Use explicit workspace-scoped OpenShell operations. `OpenShellClient.connect()` is lazy: a successful construction is not a health check. Require a real `health()` result and verified gateway identity/auth configuration.

Bind authorization outside the sandbox to the exact owner, tenant/workspace, run, immutable sandbox ID, compiled plan/policy digest, image digest, command, quota, and expiry. Recheck the financial freeze and relevant mandate/consent controls. A caller-supplied `approved: true`, environment flag, self-hash, fake SDK client, or policy advisor proposal is not authorization. Do not accept agent-supplied method names, deployment contracts, policy overrides, `rawSpec`, provider lists, or arbitrary environment variables.

Use the pinned SDK's `sandbox.create`, `waitReady`, `getConfig`, `exec`/`execStream`, `delete`, and identity-aware `waitDeleted` interfaces only after rechecking their actual types. Confirm effective static and network policy before any worker executes. Keep request data and authority/control-plane clients in separate trust domains.

Acceptance: local tests show every provider side effect is preceded by the real host gate; denial results in zero provider calls. Runtime status is never inferred from generated plans or mocks.

### 3. Bounded lab canary and failure cleanup

Obtain separate owner approval for lab resources; no payment/custody enablement follows. Start with the fixed `/bin/true` canary, then a reviewed read-only worker. Enforce CPU, memory, storage, wall-clock, and output limits in the actual host/runtime, not just metadata.

Test an approved read succeeds and unapproved hosts/methods/paths, private IPs, cloud metadata, redirects/rebinding, unauthorized files, credential reads, provider attachment, policy widening, and cross-workspace access fail. Use synthetic secrets only. Capture policy identity, sandbox identity, image/build identity, terminal status, and independently observed denials without raw sensitive logs. A network error alone is not proof that a policy denial occurred.

Test create failure, timeout, cancellation, stream closure without terminal exit, gateway failure, policy drift, owner revocation, interrupted cleanup, and same-name sandbox replacement. Ambiguous create/exec responses are not safe to retry automatically. Track sandbox IDs durably so an orphan can be reconciled. `accepted` deletion stays pending; `unspecified`/unknown stays unknown. Abort of a client RPC is not proof the worker stopped. Verify termination/cleanup separately.

Acceptance: authenticated, identity-bound live evidence for success, denials, and cleanup. Keep production and live-traffic qualification false until independently reviewed.

### 4. Role integration, in order

Cartographer first: supply only sanitized public-source inputs from the existing owner-approved source configuration. Preserve discovery provenance and quotas; no new trust, listing, peer-key, payment, or wallet mutation. Candidates discovered by an agent are not automatically approved egress destinations.

Emissary second: isolate drafting/inspection. Send contact proposals to the existing host consent/mandate path; do not move sender credentials, key-pinning authority, or transport approval into the worker. Retain first-contact limits and independent owner gates.

Steward third: consume minimal evidence references and propose bounded maintenance. Do not let it approve its own policy changes, reconfigure the gateway, grant credentials, or merge/deploy itself. Put approval and policy application in separate host components.

Harness Core/ECF: connect through existing proposal/evidence contracts. Mark imported artifacts as local/unverified until a trusted evidence verifier promotes them. Never treat local plan hashes as portable authority. Risk Fork can evaluate candidate changes, but it is not a substitute for OpenShell containment or the owner's mandate.

### 5. OpenShell-specific augmentation, after baseline qualification

Evaluate supervisor middleware for pre-action checks and gateway interceptors for control-plane admission. First inspect the pinned upstream contracts and failure behavior. Keep policy admission fail-closed; do not assume extension existence supplies authenticated Agoragentic authority. Policy advisor/prover output can explain proposed access changes but must remain a recommendation until the independent host approval path authorizes the exact delta. Formal policy reasoning is not business-consent or settlement verification.

Credential-backed inference/provider routes require a separate approved threat model and endpoint-scoped credential binding. Do not export signer/custody material. Any paid inference or external resource cost requires its own authorized budget. No generic provider attachment or arbitrary network widening is allowed.

Acceptance: isolated integration tests for unavailable/bypassed middleware, expired/replayed approvals, widened policy, and non-mutating denied requests. No production claims based only on source inspection.

## Completion report required from the implementation agent

Report changed files, source/SDK/image/gateway pins, actual test commands and outcomes, evidence provenance, enabled versus default-off paths, outstanding gates, rollback/cleanup status, and the final reviewed commit. Separate local tests, mocked contract tests, live canaries, and production verification. Do not claim subagent review unless real subagent execution was available.

Rollback before activation is simply leaving the provider unselected. After an approved lab activation, stop new dispatch, revoke the lab grant, terminate only the recorded sandbox IDs, verify cleanup, and preserve redacted evidence. Never delete another workspace's or a same-name replacement's resource.
75 changes: 75 additions & 0 deletions agent-os/openshell/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
# OpenShell integration scaffold

**Source-only, offline, default-off. No OpenShell installation, gateway connection, sandbox provisioning, agent execution, package publication, or production activation is performed.** This is a preparation surface under the existing Agent OS examples, not a new supported integration or canonical tool ID.

Agoragentic owns owner mandates, action approvals, identity, budgets, receipts, and reconciliation. OpenShell is a candidate execution-isolation layer underneath those controls. A sandbox policy must not grant payment, federation, publication, or trust authority.

## Run the implemented scaffold

Node.js 20+; no package installation or credentials required. From the repository root:

```sh
node --test agent-os/openshell/scaffold.test.mjs
node agent-os/openshell/preview.mjs agent-os/openshell/fixture.json
node agent-os/openshell/preview.mjs --readiness
```

The fixture uses a **fictional image digest and example hostname**. It demonstrates the format, not an image that can be pulled or a live discovery target. The readiness command describes this scaffold only; it does not inspect a host. `activationSupported` remains false. There is no `apply` command or enabling environment variable.

## What is implemented

- A deterministic policy/plan compiler with strict input validation, bounded input, immutable output, and SHA-256 plan/policy digests.
- Separate Cartographer, Emissary, and Steward profiles. Cartographer can propose exact-host/exact-path HTTPS GET/HEAD egress. Emissary and Steward remain network-denied. All profiles are proposal-only.
- A TypeScript SDK `createSpec` candidate with create-time filesystem, process, hard-required Landlock, explicit L7 enforcement, no provider attachment, no environment injection, and no exposed service ports.
- An adapter preparation interface whose invocation path always refuses activation.
- Offline observation shaping that requires a terminal integer exit code, binds an expected sandbox ID, distinguishes pending deletion, and never upgrades caller reports to verified receipts.
- A pinned upstream source record and a staged integration/qualification handoff.

```js
import { OpenShellScaffoldAdapter } from './scaffold.mjs';
const adapter = new OpenShellScaffoldAdapter();
const plan = adapter.prepare(request); // pure local compilation
// await adapter.invoke(...); // always refuses; no live driver is bound
```

## Role boundaries

| Role | Current proposal | Later host integration, not implemented here |
|---|---|---|
| Cartographer | Explicit public read candidates; no default egress | Observe approved sources, retain provenance, emit discovery candidates without promoting trust |
| Emissary | Offline drafting, no egress or credentials | Submit bounded contact proposals to the existing consent/mandate-controlled host path |
| Steward | Offline evidence review, no egress or mutation | Recommend maintenance and policy changes; owner gates remain outside the sandbox |

This preserves agent-operated growth and maintenance without letting the agents approve their own authority expansion. These profiles do not contain or start the actual role agents. The only candidate create-time command is `/bin/true`; replacing it with a role worker is a separate reviewed change.

## Upstream contract and important details

Reviewed target: **OpenShell v0.1.2**, commit `6648bd0c290efbc41ba131ee9831ee45cd431f94`. See [upstream.lock.json](upstream.lock.json) for file/blob provenance and review scope. No upstream source is vendored. Runtime compatibility remains untested.

Primary sources at that immutable revision:

- [TypeScript SDK interface and distribution](https://github.com/NVIDIA/OpenShell/blob/6648bd0c290efbc41ba131ee9831ee45cd431f94/sdk/typescript/README.md)
- [SDK create/exec/deletion types](https://github.com/NVIDIA/OpenShell/blob/6648bd0c290efbc41ba131ee9831ee45cd431f94/sdk/typescript/src/client.ts)
- [Policy protobuf contract](https://github.com/NVIDIA/OpenShell/blob/6648bd0c290efbc41ba131ee9831ee45cd431f94/proto/sandbox.proto)

`createSpec` uses **camelCase SDK message-init fields**, not CLI YAML. The policy protobuf specifies audit as the unspecified inspected-network enforcement mode; this compiler sets `enforcement: 1` explicitly. `tls: 0` is automatic TLS handling, not TLS bypass. The proposal has no `allowedIps`, uninspected-credential bypass, provider attachment, middleware registration, or `rawSpec` escape hatch.

OpenShell filesystem/process/Landlock policy must be supplied at creation; sandbox-scoped policy updates cannot introduce static fields later. The proposed image must have the non-root `sandbox` account, `/bin/true`, `/usr/bin/curl`, required runtime paths, `/sandbox/input`, and `/sandbox/output`. None of those image properties are verified by a digest-shaped string.

The SDK is documented as distributed through GitHub Packages at this release. Do not assume an identically named public npm package is the reviewed build. A later approved setup must authenticate outside the sandbox, pin SDK and gateway versions together, and record package/image integrity. Do not run an unpinned remote installation script as part of this scaffold.

## Evidence and safety limits

A local `planDigest` or `policyDigest` is **not** an OpenShell protobuf policy hash, signature, owner approval, attestation, settlement receipt, or proof of work. The digests bind the scaffold's canonical local JSON. Plan validation detects changes against this compiler; it does not authenticate who proposed the plan.

Observation summaries accept only the small documented projection (`kind`, `sandboxId`, and `exitCode` or `outcome`). Do not feed raw SDK objects, stdout, stderr, prompts, environment variables, credentials, or customer data into them. Output remains `caller_reported_unverified` even when an exit code is zero. A deletion result of `accepted` is pending, not cleanup success. Missing or replaced sandbox identity must not be papered over by inserting an expected ID into a response that did not contain it.

Hostname screening is syntactic only. It does not resolve DNS or establish SSRF protection, consent, endpoint semantics, redirect safety, or trust. GET/HEAD does not guarantee a remote application is side-effect-free. The host must validate destinations at connection time, control redirects, and test metadata/private-network denial. No real request is made here.

The runtime deadline is a **host requirement, not an implemented timer**. All runtime-verification flags stay false. CPU/memory/storage quotas, lifecycle cancellation, tenant isolation, gateway identity/authentication, effective policy confirmation, and independent containment evidence remain qualification work. No Docker socket, host credentials, gateway admin token, signer, wallet key, or production database belongs in the worker image or mounts.

## Integration ownership and next work

See [CODEX_HANDOFF.md](CODEX_HANDOFF.md). Keep the reusable compiler here; host authority wiring belongs in the platform, while Harness Core should consume only a supported local evidence/proposal interface. Do not create another Harness Core implementation in this repository's migration-pointer directory. Risk Fork/ECF checks are additional gates, not reasons to skip sandbox or owner controls.

No changes to the canonical integration index, integration counts, paid execution, custody state, trust vocabulary, public readiness claims, or existing runtime selection are made by this scaffold.
11 changes: 11 additions & 0 deletions agent-os/openshell/fixture.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"schema": "agoragentic.openshell.request.v1",
"role": "cartographer",
"runId": "offline-demo",
"workspace": "agoragentic-lab",
"image": "registry.example.com/agoragentic/worker@sha256:1111111111111111111111111111111111111111111111111111111111111111",
"readEndpoints": [
{ "host": "docs.example.com", "paths": ["/robots.txt", "/.well-known/agent-card.json"] }
],
"maxRuntimeSeconds": 60
}
36 changes: 36 additions & 0 deletions agent-os/openshell/preview.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { openSync, readSync, fstatSync, closeSync } from 'node:fs';
import { buildOpenShellPlan, openShellReadiness } from './scaffold.mjs';

// Offline only. No installer, SDK import, subprocess, network, or apply command.
try {
const args = process.argv.slice(2);
if (args.length === 1 && args[0] === '--readiness') {
console.log(JSON.stringify(openShellReadiness(), null, 2));
} else {
if (args.length !== 1 || args[0].startsWith('-')) throw new Error('usage: node preview.mjs REQUEST.json | --readiness');
const fd = openSync(args[0], 'r');
let text;
try {
if (!fstatSync(fd).isFile()) throw new Error('request_must_be_regular_file');
const bytes = Buffer.alloc(65537);
let size = 0;
while (size < bytes.length) {
const count = readSync(fd, bytes, size, bytes.length - size, null);
if (!count) break;
size += count;
}
if (size > 65536) throw new Error('request_too_large');
text = bytes.subarray(0, size).toString('utf8');
} finally { closeSync(fd); }
let request;
try { request = JSON.parse(text); } catch { throw new Error('invalid_request_json'); }
console.log(JSON.stringify(buildOpenShellPlan(request), null, 2));
}
} catch (error) {
// Do not echo request contents or filesystem paths from native errors.
const message = error.code && !error.code.startsWith('E') ? error.code
: ['invalid_request_json', 'request_too_large', 'request_must_be_regular_file'].includes(error.message) ? error.message
: 'preview_failed: use one request JSON path or --readiness';
console.error(message);
process.exitCode = 2;
}
Loading
Loading