Skip to content
Draft
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
21 changes: 21 additions & 0 deletions .github/workflows/turtleterm-correlation.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
name: turtleterm-correlation

on:
pull_request:
push:
branches: [main]

jobs:
validate-turtleterm-correlation:
runs-on: ubuntu-latest
steps:
- name: Check out repository
uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.12'

- name: Validate TurtleTerm correlation fixture
run: python tools/validate_turtleterm_correlation.py

Check warning

Code scanning / CodeQL

Workflow does not contain permissions Medium

Actions job or workflow does not limit the permissions of the GITHUB_TOKEN. Consider setting an explicit permissions block, using the following as a minimal starting point: {contents: read}
Comment on lines +10 to +21
83 changes: 83 additions & 0 deletions docs/integration/turtleterm.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
# TurtleTerm Integration Profile v0 — CloudShell FOG

## Purpose

TurtleTerm is the SourceOS policy-aware, agent-addressable terminal workbench for trusted command execution, terminal receipts, agent delegation, and reproducible operator workflows.

CloudShell FOG is the browser/fog/cloud shell execution plane for session lifecycle, placement, PTY attach, runtime allocation, and audit.

This profile defines how the two systems should interoperate without creating duplicate terminal truth systems.

## Ownership boundary

### CloudShell FOG owns

- browser / fog / cloud shell session lifecycle
- session placement and runtime allocation
- WSS PTY attach contract
- Kubernetes/fog runtime connector behavior
- CloudShell audit events
- placement metadata (`region`, `node_id`, `tier`, `reasons`)

### TurtleTerm / SourceOS terminal contracts own

- local/operator terminal command lifecycle receipts
- command stdout/stderr digests
- SourceOS terminal session/event/receipt schemas
- local agent terminal workflow metadata
- reproducible operator command receipts

## Integration principle

CloudShell FOG should reference TurtleTerm receipt contracts where command-level receipts are needed.
It should not invent a parallel receipt schema for local/operator command execution.

## Correlation model

A CloudShell session MAY propagate SourceOS terminal context into commands or operator workflows:

- `SOURCEOS_TERMINAL_SESSION_ID` = CloudShell session ID or derived stable session identifier
- `SOURCEOS_WORKSPACE` = CloudShell workspace / project identifier, if known
- `SOURCEOS_ACTOR_ID` = authenticated subject or mapped actor identity
- `SOURCEOS_POLICY_BUNDLE_ID` = CloudShell policy/profile identifier, if known
- `SOURCEOS_EXECUTION_DOMAIN` = `cloudshell-fog`, `k8s`, `fog`, or more specific runtime domain

## Event mapping

| CloudShell FOG concept | TurtleTerm / SourceOS terminal concept |
|---|---|
| `session.created` | `sourceos.terminal.session.v0` |
| `session.attached` | terminal frontend attach context |
| `runtime.allocated` | execution domain / runtime metadata |
| `placement.decided` | placement metadata attached to receipt context |
| command execution inside terminal | `command.started` / `command.completed` receipt events |
| `session.terminated` | terminal session completion / teardown context |

## Placement metadata

When CloudShell FOG launches or coordinates a TurtleTerm-backed command workflow, it SHOULD preserve:

- selected region
- selected node ID
- trust tier
- placement reasons
- runtime image or runtime profile

These fields should be attached as receipt metadata rather than replacing TurtleTerm's receipt schema.

## Non-goals

- CloudShell FOG does not replace TurtleTerm's local receipt schema.
- TurtleTerm does not own CloudShell FOG's placement engine.
- This profile does not require all CloudShell PTY streams to emit per-command receipts by default.

## Open questions

1. Should SourceOS terminal schemas move into a shared terminal-contracts repository later?
2. Should CloudShell FOG expose a receipt-export endpoint for completed sessions?
3. Should AgentPlane be the canonical bridge for launching TurtleTerm workflows from CloudShell FOG?

## Tracking

- CloudShell FOG: issue #35
- TurtleTerm: issue #1
42 changes: 42 additions & 0 deletions fixtures/turtleterm/cloudshell-turtleterm-correlation.v0.1.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
{
"schema": "cloudshell-fog.turtleterm.correlation.v0.1",
"cloudshell_session": {
"session_id": "csf-session-0001",
"subject": "human:operator@example.com",
"workspace_id": "workspace:lattice-demo",
"policy_bundle_id": "policy:cloudshell-default",
"placement": {
"region": "us-east-1",
"node_id": "fog-node-01",
"tier": "fog",
"reasons": ["fog-preferred", "healthy", "capacity-ok"]
},
"runtime": {
"execution_domain": "cloudshell-fog/k8s",
"namespace": "cloudshell-csf-session-0001",
"pod": "shell",
"image_ref": "ghcr.io/socioprophet/cloudshell-fog/runtime@sha256:example"
}
},
"turtleterm_environment": {
"SOURCEOS_TERMINAL_SESSION_ID": "csf-session-0001",
"SOURCEOS_WORKSPACE": "workspace:lattice-demo",
"SOURCEOS_ACTOR_ID": "human:operator@example.com",
"SOURCEOS_POLICY_BUNDLE_ID": "policy:cloudshell-default",
"SOURCEOS_EXECUTION_DOMAIN": "cloudshell-fog/k8s"
},
"expected_receipt_context": {
"session_id": "csf-session-0001",
"workspace_id": "workspace:lattice-demo",
"actor_id": "human:operator@example.com",
"policy_bundle_id": "policy:cloudshell-default",
"execution_domain": "cloudshell-fog/k8s"
},
"correlation_keys": [
"session_id",
"workspace_id",
"actor_id",
"policy_bundle_id",
"execution_domain"
]
}
53 changes: 53 additions & 0 deletions tools/validate_turtleterm_correlation.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
#!/usr/bin/env python3
"""Validate CloudShell FOG ↔ TurtleTerm correlation fixture."""

from __future__ import annotations

import json
from pathlib import Path


REPO_ROOT = Path(__file__).resolve().parents[1]
FIXTURE = REPO_ROOT / "fixtures" / "turtleterm" / "cloudshell-turtleterm-correlation.v0.1.json"


def main() -> int:
data = json.loads(FIXTURE.read_text(encoding="utf-8"))
assert data["schema"] == "cloudshell-fog.turtleterm.correlation.v0.1"

cloudshell = data["cloudshell_session"]
env = data["turtleterm_environment"]
expected = data["expected_receipt_context"]

assert env["SOURCEOS_TERMINAL_SESSION_ID"] == cloudshell["session_id"]
assert env["SOURCEOS_WORKSPACE"] == cloudshell["workspace_id"]
assert env["SOURCEOS_ACTOR_ID"] == cloudshell["subject"]
assert env["SOURCEOS_POLICY_BUNDLE_ID"] == cloudshell["policy_bundle_id"]
assert env["SOURCEOS_EXECUTION_DOMAIN"] == cloudshell["runtime"]["execution_domain"]

assert expected["session_id"] == env["SOURCEOS_TERMINAL_SESSION_ID"]
assert expected["workspace_id"] == env["SOURCEOS_WORKSPACE"]
assert expected["actor_id"] == env["SOURCEOS_ACTOR_ID"]
assert expected["policy_bundle_id"] == env["SOURCEOS_POLICY_BUNDLE_ID"]
assert expected["execution_domain"] == env["SOURCEOS_EXECUTION_DOMAIN"]

placement = cloudshell["placement"]
assert placement["region"]
assert placement["node_id"]
assert placement["tier"]
assert isinstance(placement["reasons"], list) and placement["reasons"]

runtime = cloudshell["runtime"]
assert runtime["namespace"].startswith("cloudshell-")
assert runtime["pod"]
assert "@sha256:" in runtime["image_ref"]

for key in data["correlation_keys"]:
assert key in expected, f"missing correlation key in expected context: {key}"

print(f"validated {FIXTURE}")
return 0


if __name__ == "__main__":
raise SystemExit(main())
Loading