Skip to content

Commit 3402243

Browse files
author
Homer
committed
Provision OpenShell policies from resolved configuration
1 parent 068eabb commit 3402243

5 files changed

Lines changed: 46 additions & 1 deletion

File tree

‎README.md‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
# MirrorNeuron CLI
22

3+
OpenShell worker policies may declare `policy_config_bindings: true` and bind
4+
unquoted `${config.path.to.scalar}` values from their SDK-resolved configuration.
5+
The SDK renders bounded JSON-quoted scalars before native provisioning and
6+
payload staging, preserving source policy files and existing network rules.
7+
Missing bindings fail before image preparation. This requires SDK
8+
`>=1.3.58.dev63,<2`; workers without the declaration retain their policy behavior.
9+
310
Blueprint `execution.json` can set `runtime.placement.must_run_local: true` to
411
pin its Job owner and all workers to the submitting computer. `mn blueprint run`
512
honors that requirement before resource/model preparation, rejects a remote

‎SPEC.md‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -800,3 +800,12 @@ than operating-system or runtime installers. Keep it private: configuration and
800800
local data may contain sensitive values. Core, SDK, CLI and API must be upgraded
801801
together for the new streamed backup RPCs. `mn blueprint export <run-id>` remains
802802
a run report export (JSON/Markdown/HTML), with no job restore counterpart.
803+
# Configured OpenShell policies
804+
805+
OpenShell workers may declare `policy_config_bindings: true` and bind unquoted
806+
`${config.path.to.scalar}` values from the SDK-resolved configuration snapshot.
807+
The SDK owns scalar validation and rendering. The CLI validates before image
808+
preparation and uses the derived policy for native sandbox provisioning; SDK
809+
payload staging carries the same policy to Core without changing source files.
810+
Missing or invalid bindings fail; existing undeclared policies remain unchanged.
811+
This contract requires SDK `>=1.3.58.dev63,<2`.

‎mn_cli/libs/run_cmds/openshell.py‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from mn_sdk.native_resource_registry import register_native_resource
22
from mn_sdk.errors import AppError
3+
from mn_sdk.openshell_policy import materialize_worker_policy, render_worker_policy
34
from mn_sdk.submission_preparation import (
45
_ensure_docker_worker_requirements_install,
56
_local_skill_dependency_source_records,
@@ -54,6 +55,11 @@ def _prepare_openshell_custom_images(
5455
continue
5556
if config.get("runner_module") not in OPENSHELL_RUNNER_MODULES:
5657
continue
58+
if config.get("policy_config_bindings") is True:
59+
policy = _openshell_policy_path(bundle_dir, config.get("policy"))
60+
if policy is None:
61+
raise ValueError("Configured OpenShell policy is missing")
62+
render_worker_policy(policy.read_text(encoding="utf-8"), config)
5763

5864
# Resolve before image builds or native-resource registration.
5965
_openshell_executable()
@@ -274,6 +280,8 @@ def _prepare_openshell_shared_sandbox(
274280
command.extend([option, value.strip()])
275281
policy = _openshell_policy_path(bundle_dir, config.get("policy"))
276282
if policy is not None:
283+
if config.get("policy_config_bindings") is True:
284+
policy = materialize_worker_policy(policy, config, mn_home() / "openshell" / "policies")
277285
command.extend(["--policy", str(policy)])
278286
for provider in config.get("providers") or []:
279287
if isinstance(provider, str) and provider.strip():

‎pyproject.toml‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ classifiers = [
99
"Programming Language :: Python :: 3",
1010
]
1111
dependencies = [
12-
"mirrorneuron-python-sdk[local-source]>=1.3.58.dev46,<2.0",
12+
"mirrorneuron-python-sdk[local-source]>=1.3.58.dev63,<2.0",
1313
"click>=8.1.0",
1414
"jsonschema>=4.25",
1515
"typer>=0.9.0",

‎tests/test_run_cmds_openshell.py‎

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -694,3 +694,24 @@ def test_openshell_definition_revisions_have_separate_sandboxes(tmp_path, mocker
694694
assert len(records) == 2
695695
assert len({r["external_id"] for r in records}) == 2
696696
assert {r["job_id"] for r in records} == {"job-one"}
697+
698+
699+
def test_configured_policy_is_rendered_before_sandbox_creation(mocker, tmp_path):
700+
from mn_cli.libs.run_cmds import openshell
701+
mocker.patch.object(openshell, 'mn_home', return_value=tmp_path/'mn')
702+
mocker.patch.object(openshell, '_openshell_executable', return_value='openshell')
703+
mocker.patch.object(openshell, '_openshell_env', return_value={})
704+
mocker.patch.object(openshell, 'register_native_resource')
705+
policy=tmp_path/'bundle/payloads/policy.yaml'
706+
policy.parent.mkdir(parents=True)
707+
policy.write_text('version: 1\nhost: ${config.gateway.host}\n')
708+
config={'policy':'policy.yaml','policy_config_bindings':True,
709+
'environment':{'MN_BLUEPRINT_CONFIG_JSON':json.dumps({'gateway':{'host':'test-gateway'}})}}
710+
run=mocker.patch.object(openshell.subprocess,'run',side_effect=[
711+
subprocess.CompletedProcess([],1,'','missing'), subprocess.CompletedProcess([],0,'created','')])
712+
openshell._prepare_openshell_shared_sandbox(tmp_path/'bundle',config,job_id='job',
713+
submission_id='definition',node_id='review')
714+
command=run.call_args_list[1].args[0]
715+
rendered=Path(command[command.index('--policy')+1])
716+
assert rendered.read_text()=='version: 1\nhost: "test-gateway"\n'
717+
assert policy.read_text()=='version: 1\nhost: ${config.gateway.host}\n'

0 commit comments

Comments
 (0)