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
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,11 @@ sourceosctl [--version] <command> [<subcommand>] [options]
| `sourceosctl office convert <path> --to <format> --execute --policy-ok` | Run guarded local LibreOffice conversion and emit OfficeArtifactEvidence |
| `sourceosctl office inspect <path>` | Inspect a local office artifact file and hash it |
| `sourceosctl office evidence inspect <path>` | Inspect Office Plane evidence JSON (read-only) |
| `sourceosctl operation conformance --contracts-dir ../prophet-core-contracts` | Run Workspace Operation fixture bundle conformance checks |
| `sourceosctl operation validate-fixture <path>` | Validate one Workspace Operation fixture |
| `sourceosctl operation replay-fixture <output> --surface terminal-command\|browser-capture\|local-agent-execution` | Generate a local replay fixture starter |
| `sourceosctl operation scaffold-adapter <output-dir>` | Scaffold starter adapter skeletons |
| `sourceosctl diagnostics redact <input> --output <output>` | Export redacted diagnostics (cookies/tokens/keys/IDs/prompts/policy snippets) |

### Running from the repo

Expand Down Expand Up @@ -127,6 +132,11 @@ python3 bin/sourceosctl office generate --execute --policy-ok --artifact-type sp
python3 bin/sourceosctl office generate --execute --policy-ok --artifact-type slide-deck --format pptx --title "Demo Deck" --evidence-out ./office-pptx-evidence.json
python3 bin/sourceosctl office convert ./example.docx --to pdf --dry-run
python3 bin/sourceosctl office convert ./example.docx --to pdf --execute --policy-ok --evidence-out ./office-convert-evidence.json
python3 bin/sourceos operation conformance --contracts-dir ../prophet-core-contracts
python3 bin/sourceos operation validate-fixture tests/fixtures/workspace-operation/minimal-operation.json --structural-only
python3 bin/sourceos operation replay-fixture ./tmp-operation-replay.json --surface terminal-command
python3 bin/sourceos operation scaffold-adapter ./tmp-adapter
python3 bin/sourceos diagnostics redact ./diagnostic.log --output ./diagnostic.redacted.log
```

### Local Model Door defaults
Expand Down
10 changes: 10 additions & 0 deletions bin/sourceos
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#!/usr/bin/env python3
"""sourceos alias entry-point script."""

import os
import runpy
import sys

repo_root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.argv[0] = "sourceos"
runpy.run_path(os.path.join(repo_root, "bin", "sourceosctl"), run_name="__main__")
10 changes: 10 additions & 0 deletions bin/sourceosctl
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,16 @@ if len(sys.argv) > 1 and sys.argv[1] == "reasoning":

sys.exit(reasoning_main(sys.argv[2:]))

if len(sys.argv) > 1 and sys.argv[1] == "operation":
from sourceosctl.commands.operation import operation_main

sys.exit(operation_main(sys.argv[2:]))

if len(sys.argv) > 1 and sys.argv[1] == "diagnostics":
from sourceosctl.commands.diagnostics import diagnostics_main

sys.exit(diagnostics_main(sys.argv[2:]))

if len(sys.argv) > 1 and sys.argv[1] == "network":
from sourceosctl.commands.network import network_main

Expand Down
32 changes: 26 additions & 6 deletions docs/operation-conformance-runner.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,28 @@ python3 tools/sourceos_operation_conformance.py \
--schemas-dir ../prophet-core-contracts/schemas
```

From `~/dev/sourceos-devtools`, the first-class CLI wrappers are:

```bash
python3 bin/sourceos operation conformance \
--contracts-dir ../prophet-core-contracts

python3 bin/sourceos operation validate-fixture \
tests/fixtures/workspace-operation/minimal-operation.json \
--structural-only

python3 bin/sourceos operation replay-fixture \
./tmp-operation-replay.json \
--surface terminal-command

python3 bin/sourceos operation scaffold-adapter \
./tmp-adapter

python3 bin/sourceos diagnostics redact \
./diagnostic.log \
--output ./diagnostic.redacted.log
```

## What structural validation checks

- Every fixture is operation-centered.
Expand Down Expand Up @@ -69,10 +91,8 @@ If `jsonschema` is installed, the runner also validates objects against:

This optional path is the bridge between the lightweight contract validation currently in `prophet-core-contracts` and a reusable SourceOS conformance runner that downstream repos can invoke.

## Next work
## Included sample fixtures

- Add a CLI wrapper once the repo's command layout is standardized.
- Add adapter scaffolding commands.
- Add redaction CLI for diagnostic bundles.
- Emit machine-readable validation reports.
- Add fixture-generation helpers for terminal, browser, local agent-machine, sync, and release operations.
- `tests/fixtures/workspace-operation/terminal-command-sample.json`
- `tests/fixtures/workspace-operation/browser-capture-sample.json`
- `tests/fixtures/workspace-operation/local-agent-execution-sample.json`
70 changes: 70 additions & 0 deletions sourceosctl/commands/diagnostics.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
"""Diagnostic redaction CLI helpers."""

from __future__ import annotations

import argparse
import json
import re
from pathlib import Path


REDACTION_PATTERNS: list[tuple[str, re.Pattern[str], str]] = [
("cookies", re.compile(r"(?i)(\bcookie\s*[:=]\s*)([^\n]+)"), r"\1<redacted-cookie>"),
("bearer", re.compile(r"(?i)\bbearer\s+[a-zA-Z0-9._~+/=-]+"), "Bearer <redacted-token>"),
# Token-bearing identity fields (quoted JSON value or plain token blob).
("oauth", re.compile(r'(?is)("?(?:access_token|refresh_token|oauth_token|id_token)"?\s*[:=]\s*)("(?:[^"\\]|\\.)*"|[^,\s]+)'), r'\1"<redacted-token>"'),
("api_keys", re.compile(r'(?is)("?(?:api[_-]?key|x-api-key|apikey|client_secret|authorization)"?\s*[:=]\s*)("(?:[^"\\]|\\.)*"|[^,\s]+)'), r'\1"<redacted-secret>"'),
("secrets", re.compile(r'(?is)("?(?:secret|password|token)"?\s*[:=]\s*)("(?:[^"\\]|\\.)*"|[^,\s]+)'), r'\1"<redacted-secret>"'),
("sensitive_ids", re.compile(r'(?is)("?(?:user|account|session|device|customer|tenant|workspace|organization|org|principal|subject)_id"?\s*[:=]\s*)("(?:[^"\\]|\\.)*"|[^,\s]+)'), r'\1"<redacted-id>"'),
# Prompt-bearing fields, including escaped multi-line quoted strings.
(
"model_prompts",
re.compile(r'(?is)("?(?:prompt|model_prompt|system_prompt|user_prompt)"?\s*[:=]\s*)("(?:[^"\\]|\\.)*"|[^,\n]+)'),
r'\1"<redacted-prompt>"',
),
("policy_marked", re.compile(r"(?is)<policy-marked>.*?</policy-marked>"), "<policy-marked><redacted-policy-snippet></policy-marked>"),
]


def _redact(raw: str) -> tuple[str, dict[str, int]]:
counts: dict[str, int] = {}
redacted = raw
for name, pattern, replacement in REDACTION_PATTERNS:
redacted, count = pattern.subn(replacement, redacted)
if count:
counts[name] = count
return redacted, counts


def redact_cmd(args: argparse.Namespace) -> int:
input_path = Path(args.input).expanduser().resolve()
if not input_path.exists():
print(json.dumps({"type": "DiagnosticRedaction", "result": "fail", "errors": [f"missing input file: {input_path}"]}, indent=2, sort_keys=True))
return 1
raw = input_path.read_text(encoding="utf-8")
redacted, counts = _redact(raw)

if args.output:
output_path = Path(args.output).expanduser().resolve()
output_path.parent.mkdir(parents=True, exist_ok=True)
output_path.write_text(redacted, encoding="utf-8")
print(json.dumps({"type": "DiagnosticRedaction", "result": "pass", "input": str(input_path), "output": str(output_path), "redactionCounts": counts}, indent=2, sort_keys=True))
else:
print(redacted)
return 0


def build_parser() -> argparse.ArgumentParser:
parser = argparse.ArgumentParser(prog="sourceosctl diagnostics", description="Diagnostic helpers")
sub = parser.add_subparsers(dest="diagnostics_command", required=True)
redact_p = sub.add_parser("redact", help="Redact sensitive tokens and snippets from diagnostic exports")
redact_p.add_argument("input")
redact_p.add_argument("--output", default=None)
redact_p.set_defaults(func=redact_cmd)
return parser


def diagnostics_main(argv: list[str] | None = None) -> int:
parser = build_parser()
args = parser.parse_args(argv)
return args.func(args) or 0
Loading