fix: validate sandbox consumer actors early
Some checks failed
ci / validate (push) Has been cancelled
Some checks failed
ci / validate (push) Has been cancelled
Assistant: codex Assistant-Model: gpt-5.6-sol Assistant-Session: 01a0233b-178d-7162-b92f-31a31ea8ca9b
This commit is contained in:
parent
ae2a706a68
commit
79bf88a3c4
9 changed files with 150 additions and 2 deletions
|
|
@ -14,6 +14,7 @@
|
|||
| workplan | GLAS-WP-0003 | finished | — | workplans/GLAS-WP-0003-first-channel-extension.md |
|
||||
| workplan | GLAS-WP-0004 | finished | — | workplans/GLAS-WP-0004-versioned-execution-constellation-profiles.md |
|
||||
| workplan | GLAS-WP-0005 | blocked | — | workplans/GLAS-WP-0005-sandbox-boundary-runtime-hardening.md |
|
||||
| workplan | GLAS-WP-0006 | finished | — | workplans/GLAS-WP-0006-consumer-actor-validation.md |
|
||||
| task | GLAS-0001-T01 | done | — | workplans/GLAS-0001-statehub-bootstrap.md |
|
||||
| task | GLAS-0001-T02 | done | — | workplans/GLAS-0001-statehub-bootstrap.md |
|
||||
| task | GLAS-0001-T03 | done | — | workplans/GLAS-0001-statehub-bootstrap.md |
|
||||
|
|
@ -44,6 +45,8 @@
|
|||
| task | GLAS-WP-0005-T03 | done | — | workplans/GLAS-WP-0005-sandbox-boundary-runtime-hardening.md |
|
||||
| task | GLAS-WP-0005-T04 | done | — | workplans/GLAS-WP-0005-sandbox-boundary-runtime-hardening.md |
|
||||
| task | GLAS-WP-0005-T05 | wait | — | workplans/GLAS-WP-0005-sandbox-boundary-runtime-hardening.md |
|
||||
| task | GLAS-WP-0006-T01 | done | — | workplans/GLAS-WP-0006-consumer-actor-validation.md |
|
||||
| intake | GLAS-IN-0001 | done | blue | docs/intakes/residuals.md |
|
||||
| intake | GLAS-IN-0002 | todo | red | docs/intakes/residuals.md |
|
||||
| intake | GLAS-IN-0003 | todo | green | docs/intakes/residuals.md |
|
||||
| intake | GLAS-IN-0004 | todo | green | docs/intakes/residuals.md |
|
||||
|
|
|
|||
|
|
@ -22,6 +22,12 @@ revision. Channels may obtain a profile choice from their own approved
|
|||
configuration, but must pass it explicitly and must surface resolution refusal
|
||||
to their caller.
|
||||
|
||||
Channels pass `actor` as a governed sandbox consumer type: `adm`, `agt`, or
|
||||
`atm`. A queue's concrete `worker_id` is not an actor and remains upstream
|
||||
ownership metadata. For example, a worker named `rein-aharness@railiance01`
|
||||
invoking ordinary governed agent work passes `actor="agt"`; it does not copy
|
||||
its worker id into the actor field.
|
||||
|
||||
The channel renders the full direct `GatewayResult`. State Hub receives only
|
||||
the compact `ExecutionEvidence` subset.
|
||||
|
||||
|
|
|
|||
|
|
@ -15,6 +15,14 @@ title, and description. It may carry correlation and organizational references
|
|||
leadership/workforce records; they do not transfer organizational authority to
|
||||
Glas.
|
||||
|
||||
`actor` is the governed sandbox consumer type and must be `adm`, `agt`, or
|
||||
`atm`. It is not a worker instance identifier. Queue consumers retain values
|
||||
such as `rein-aharness@railiance01` as upstream `worker_id` ownership metadata
|
||||
and map governed agent execution to `actor="agt"`. Glas validates this before
|
||||
sandbox creation and returns a normalized `resolution` refusal for invalid
|
||||
channel/library requests; the CLI rejects invalid choices during argument
|
||||
parsing.
|
||||
|
||||
The gateway returns `GatewayResult` with:
|
||||
|
||||
- `ok`, derived from normalized outcome;
|
||||
|
|
|
|||
|
|
@ -101,3 +101,31 @@ description: |
|
|||
legacy identifiers without C-35 or C-31 warnings.
|
||||
state_hub_intake_id: "01a02b78-adff-70b5-8088-594784edff23"
|
||||
```
|
||||
|
||||
## GLAS-IN-0004 — Align the mandated ad hoc convention with identifier canon
|
||||
|
||||
```yaml
|
||||
id: GLAS-IN-0004
|
||||
kind: intake
|
||||
title: "Make ADHOC workplans valid under the fleet identifier canon"
|
||||
lane: green
|
||||
status: todo
|
||||
priority: medium
|
||||
owner: repo-manager
|
||||
repo: glas-harness
|
||||
origin: residual
|
||||
origin_ref: GLAS-WP-0006
|
||||
description: |
|
||||
The repository's generated agent instructions mandate
|
||||
workplans/ADHOC-YYYY-MM-DD.md with ADHOC-YYYY-MM-DD-Txx task ids for small,
|
||||
low-risk fixes. On 2026-08-23, statehub fix-consistency accepted the task id
|
||||
but Repo Manager identity preflight raised C-35 because the matching
|
||||
ADHOC-2026-08-23 workplan id is absent from the canon kind registry.
|
||||
|
||||
Align the generated convention, Repo Manager identity preflight, and State
|
||||
Hub synchronization. Either register the documented ad hoc workplan form or
|
||||
replace the generated instruction with one canonical representation. Prove
|
||||
the chosen form through registrar-reconcile without a contradictory identity
|
||||
warning. Do not grandfather the one discarded local attempt; no UUID was
|
||||
assigned and GLAS-WP-0006 is the authoritative record for that work.
|
||||
```
|
||||
|
|
|
|||
|
|
@ -21,7 +21,12 @@ def main(argv: list[str] | None = None) -> int:
|
|||
run.add_argument("--repo", required=True, help="Local repo path to mirror into the sandbox")
|
||||
run.add_argument("--title", required=True)
|
||||
run.add_argument("--description", required=True)
|
||||
run.add_argument("--actor", default="agt")
|
||||
run.add_argument(
|
||||
"--actor",
|
||||
choices=("adm", "agt", "atm"),
|
||||
default="agt",
|
||||
help="Governed execution actor type; queue worker identifiers belong upstream",
|
||||
)
|
||||
run.add_argument("--project", default="glas-harness")
|
||||
run.add_argument("--no-hub", action="store_true", help="Skip the gateway's own hub reporting")
|
||||
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import time
|
|||
import uuid
|
||||
from datetime import UTC, datetime
|
||||
|
||||
from pydantic import ValidationError
|
||||
from sandboxer.core.manager import SandboxManager
|
||||
from sandboxer.models import Consumer, SandboxCreateRequest
|
||||
|
||||
|
|
@ -44,6 +45,18 @@ def _request_refs(request: ExecutionRequest) -> dict:
|
|||
return {key: value for key, value in refs.items() if value not in (None, [], "")}
|
||||
|
||||
|
||||
def _consumer_from_request(request: ExecutionRequest) -> Consumer:
|
||||
"""Validate the governed execution identity before sandbox provisioning."""
|
||||
|
||||
try:
|
||||
return Consumer(actor=request.actor, project=request.project)
|
||||
except ValidationError as exc:
|
||||
raise ValueError(
|
||||
"execution actor must be a governed consumer type: adm, agt, or atm; "
|
||||
"queue worker identifiers are not execution actors"
|
||||
) from exc
|
||||
|
||||
|
||||
def run_execution(
|
||||
request: ExecutionRequest,
|
||||
*,
|
||||
|
|
@ -69,6 +82,7 @@ def run_execution(
|
|||
error: str | None = None
|
||||
|
||||
try:
|
||||
consumer = _consumer_from_request(request)
|
||||
profile, descriptor = catalog.resolve(request.harness_profile_ref)
|
||||
selected_rein = rein or catalog.build_rein(profile, descriptor)
|
||||
except Exception as exc:
|
||||
|
|
@ -102,7 +116,7 @@ def run_execution(
|
|||
SandboxCreateRequest(
|
||||
profile=profile.sandbox_profile,
|
||||
inputs={"repo": request.repo},
|
||||
consumer=Consumer(actor=request.actor, project=request.project),
|
||||
consumer=consumer,
|
||||
ttl=None,
|
||||
)
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
import json
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
from glas_harness.cli import main
|
||||
from glas_harness.contract import ExecutionRequest
|
||||
|
||||
|
|
@ -19,3 +21,24 @@ def test_execution_request_example_matches_contract() -> None:
|
|||
|
||||
assert request.harness_profile_ref == "harness.agent-dev-local@1.0.0"
|
||||
assert request.assignment_ref == "role-assignment:agent-7:42"
|
||||
|
||||
|
||||
def test_run_command_rejects_worker_identifier_as_actor() -> None:
|
||||
with pytest.raises(SystemExit) as exc_info:
|
||||
main(
|
||||
[
|
||||
"run",
|
||||
"--harness-profile",
|
||||
"harness.agent-dev-local@1.0.0",
|
||||
"--repo",
|
||||
"/tmp/repo",
|
||||
"--title",
|
||||
"t",
|
||||
"--description",
|
||||
"d",
|
||||
"--actor",
|
||||
"rein-aharness@railiance01",
|
||||
]
|
||||
)
|
||||
|
||||
assert exc_info.value.code == 2
|
||||
|
|
|
|||
|
|
@ -139,6 +139,22 @@ def test_run_execution_refuses_unknown_profile_before_sandbox() -> None:
|
|||
manager.create.assert_not_called()
|
||||
|
||||
|
||||
def test_run_execution_refuses_worker_identifier_before_sandbox() -> None:
|
||||
manager = MagicMock()
|
||||
request = _request().model_copy(update={"actor": "rein-aharness@railiance01"})
|
||||
|
||||
result = run_execution(request, rein=_FakeRein(), manager=manager)
|
||||
|
||||
assert result.ok is False
|
||||
assert result.evidence.outcome == "refused"
|
||||
assert result.evidence.failure_stage == "resolution"
|
||||
assert result.evidence.error == (
|
||||
"execution actor must be a governed consumer type: adm, agt, or atm; "
|
||||
"queue worker identifiers are not execution actors"
|
||||
)
|
||||
manager.create.assert_not_called()
|
||||
|
||||
|
||||
def test_hub_receives_normalized_evidence_without_raw_output() -> None:
|
||||
manager = MagicMock()
|
||||
manager.create.return_value = _fake_status()
|
||||
|
|
|
|||
45
workplans/GLAS-WP-0006-consumer-actor-validation.md
Normal file
45
workplans/GLAS-WP-0006-consumer-actor-validation.md
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
---
|
||||
id: GLAS-WP-0006
|
||||
type: workplan
|
||||
title: "Fail fast on invalid sandbox consumer actors"
|
||||
domain: infotech
|
||||
repo: glas-harness
|
||||
status: finished
|
||||
owner: codex
|
||||
topic_slug: sandbox-consumer-actor-validation
|
||||
created: "2026-08-23"
|
||||
updated: "2026-08-23"
|
||||
---
|
||||
|
||||
# Fail fast on invalid sandbox consumer actors
|
||||
|
||||
## Validate the actor boundary before provisioning
|
||||
|
||||
```task
|
||||
id: GLAS-WP-0006-T01
|
||||
status: done
|
||||
priority: high
|
||||
```
|
||||
|
||||
The Activity Core live pilot passed its queue/profile boundary but supplied the
|
||||
rein worker identifier as `ExecutionRequest.actor`. Sand-boxer accepts only the
|
||||
governed consumer actor types `adm`, `agt`, and `atm`, so the mismatch was found
|
||||
during sandbox creation.
|
||||
|
||||
Validate and normalize this boundary before provisioning, retain `worker_id` as
|
||||
an upstream queue-ownership field rather than an execution actor, document the
|
||||
distinction, and test that an invalid actor produces resolution refusal without
|
||||
calling sand-boxer.
|
||||
|
||||
**Completed 2026-08-23:** the gateway now validates the sand-boxer `Consumer`
|
||||
while resolving the request and returns a normalized `resolution` refusal
|
||||
without constructing or calling a sandbox manager when the actor is invalid.
|
||||
The CLI constrains `--actor` to `adm|agt|atm`; contract and channel guidance
|
||||
separates the upstream queue `worker_id` from the governed execution actor.
|
||||
Unit coverage proves both gateway and CLI refusal paths. All 58 tests and the
|
||||
packaged profile catalog pass.
|
||||
|
||||
The repo-mandated `ADHOC-YYYY-MM-DD` workplan form was attempted first, but
|
||||
Repo Manager rejected the otherwise instruction-conformant identifier as C-35.
|
||||
That fleet convention mismatch is retained as residual `GLAS-IN-0004`; this
|
||||
completed implementation uses the accepted normal workplan identity.
|
||||
Loading…
Add table
Add a link
Reference in a new issue