mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-11-04 19:28:46 +01:00
merge: preserve shared network admission and map contracts
Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
commit
d8253b2a2c
11 files changed
+336
-3
No files matched your search
@@ -9,6 +9,12 @@ Each capability needs operation-level review before its entire scope can be
|
||||
qualified. No live agent execution is claimed. Follow the [map contract](../README.md)
|
||||
for format, permission checks, evidence and maintenance.
|
||||
|
||||
Scoped runner-default source review: 2026-10-12 at
|
||||
`eee0534154eaf5d0d3f2bbc97c1e24d86f34a5a5`, limited to creation/configuration,
|
||||
approval activation, built-in provisioning and import preservation described
|
||||
below. The original baseline commit above still governs unrelated entries; this
|
||||
update does not claim operation-complete review or live agent verification.
|
||||
|
||||
## `hire`
|
||||
|
||||
Review: `baseline`.
|
||||
@@ -30,17 +36,45 @@ bypass hiring authorization. Source: [runner resolver](../../server/src/services
|
||||
Policy: Agent creation/configuration uses action grants, resource policies and change
|
||||
consent; some controls require a board actor.
|
||||
|
||||
The creation boundary resolves the request-level runner before adapter validation
|
||||
and credential normalization. Omitted/automatic new Codex selection uses the
|
||||
qualified target's default; explicit Legacy is retained. Disabled adapters and
|
||||
external overrides affect new selection, while missing credentials/runtime or
|
||||
incompatible settings remain errors. Existing agents and reviewed pending hires
|
||||
retain their recorded execution. Native `hire_agent` explicitly inherits its
|
||||
caller's runtime and remains subject to permission and credential restrictions;
|
||||
it is not an arbitrary host-configuration or login tool. REST/CLI creation and
|
||||
hire runner options use the [shared request contract](../../packages/shared/src/validators/agent.ts).
|
||||
|
||||
Evidence: `source-only` — [implementation](../../server/src/routes/agents.ts#L1395) at
|
||||
the reviewed commit above.
|
||||
|
||||
Scoped Evidence: `source-only` — [creation policy](../../server/src/services/agent-hiring.ts),
|
||||
[runner resolution](../../server/src/services/agent-runner-selection.ts),
|
||||
[native hire binding](../../server/src/services/native-runtime/paperclip-runner-tool-authority.ts),
|
||||
[frozen approval activation](../../server/src/modules/agent-lifecycle/adapters/approvals.ts)
|
||||
and [same-harness import preservation](../../server/src/services/company-portability.ts)
|
||||
at the scoped commit. No permitted-agent journey was executed for this map update.
|
||||
|
||||
Verification: `not-run` — exercise a listed permitted operation with actual agent
|
||||
credentials/run context; inspect its result and applicable persistence/attribution.
|
||||
Assert the relevant denied actor, owner, company or mode from Policy. Review the
|
||||
remaining operations before qualifying the whole capability.
|
||||
|
||||
For this scope, compare automatic and explicit Legacy creation, assert foreign
|
||||
company/environment and missing-grant denials, then compare pending approval
|
||||
configuration across restart and activation. An unrelated edit/import update must
|
||||
not change existing execution; a new package without a runner choice receives
|
||||
creation defaults. Do not count a board call or component test as agent evidence.
|
||||
|
||||
Gaps: Identity/persona hiring works. Operator account login and sensitive
|
||||
adapter/environment configuration are separate guarded actions.
|
||||
|
||||
The runner request does not grant new account, environment-probe or native API
|
||||
fallback authority; see [validation access](./runs-adapters.md#validation) and
|
||||
[environment administration](./execution-environments.md#probe). Full access
|
||||
qualification remains not run.
|
||||
|
||||
## `instructions`
|
||||
|
||||
Review: `baseline`.
|
||||
@@ -144,3 +178,10 @@ remaining operations before qualifying the whole capability.
|
||||
|
||||
Gaps: Provisioning checks agents:create. Enabling/running its built-in routine is not
|
||||
the same permission path.
|
||||
|
||||
Scoped source review: [built-in provisioning](../../server/src/services/built-in-agents.ts)
|
||||
recognizes the underlying Codex harness of a native company agent. New configured
|
||||
provisioning resolves the runner, while unrelated reconciliation and same-harness
|
||||
edits retain existing execution. Verify explicit runner changes preserve compatible
|
||||
saved settings; the general creation/access policy above still applies. This is
|
||||
source-only evidence at the scoped commit, not a live provisioning result.
|
||||
@@ -10,6 +10,12 @@ Each capability needs operation-level review before its entire scope can be
|
||||
qualified. No live agent execution is claimed. Follow the [map contract](../README.md)
|
||||
for format, permission checks, evidence and maintenance.
|
||||
|
||||
Scoped immutable-platform source review: 2026-10-12 at
|
||||
`d16eccf109b524778ceb896f79ccb3881bc61a9b`, limited to saved sandbox probing,
|
||||
server-owned qualification metadata and read/invalidation behavior. The original
|
||||
baseline commit and review depth remain for unrelated operations; no live agent
|
||||
or provider qualification is claimed by this update.
|
||||
|
||||
## `configuration`
|
||||
|
||||
Review: `baseline`.
|
||||
@@ -34,6 +40,18 @@ own policy and access review.
|
||||
Gaps: API exists; an agent cannot use instance environment management as an ordinary
|
||||
company actor.
|
||||
|
||||
Scoped source review: [environment routes](../../server/src/routes/environments.ts)
|
||||
require board organization access for reads and local-implicit board or instance
|
||||
administrator for management. Create/PATCH reject client-supplied platform-proof
|
||||
metadata; [service updates](../../server/src/services/environments.ts) discard
|
||||
supplied proof, preserve current server proof atomically for metadata-only edits,
|
||||
and invalidate it when the target configuration or driver changes. Public row
|
||||
responses hide the private record. This is source-only at the scoped commit.
|
||||
Verify forged metadata rejection, concurrent probe/update preservation, target
|
||||
invalidation and restricted-reader redaction; actual agent-denial proof remains
|
||||
not run. Company/team packages do not import or export environment rows, so those
|
||||
packages do not transfer platform qualification.
|
||||
|
||||
## `capabilities`
|
||||
|
||||
Review: `baseline`.
|
||||
@@ -73,6 +91,15 @@ Agent access: `restricted` — Board/admin probes / CLI environment.
|
||||
Policy: Environment management is instance administrator/board; permitted assignment
|
||||
uses agent/project policy.
|
||||
|
||||
Both probe endpoints require a board actor that is local-implicit or an instance
|
||||
administrator; ordinary agent identity and company membership alone are denied.
|
||||
The saved sandbox probe also resolves company/environment and secret access
|
||||
before allocating a fresh lease. Its measurement is company-bound to an immutable
|
||||
image digest, effective provider configuration and active custom-image identity;
|
||||
only confirmed cleanup permits recording it. A draft probe does not record saved
|
||||
qualification. Reading stored qualification does not lease/provision a target and
|
||||
does not grant an agent permission to probe or manage that target.
|
||||
|
||||
Evidence: `source-only` — [implementation](../../server/src/routes/environments.ts#L353)
|
||||
at the reviewed commit above.
|
||||
|
||||
@@ -82,6 +109,24 @@ own policy and access review.
|
||||
|
||||
Gaps: Reachability probes are not granted by an agent's right to execute assigned work.
|
||||
|
||||
Scoped Evidence: `source-only` — [probe authorization](../../server/src/routes/environments.ts),
|
||||
[immutable binding, measurement and read](../../server/src/services/environment-probe.ts),
|
||||
[private metadata writes](../../server/src/services/environments.ts) and
|
||||
[custom-image binding](../../server/src/services/environment-custom-image-runtime.ts)
|
||||
at the scoped commit. A connection-only success or a fixture cannot certify
|
||||
native compatibility, account authentication or agent access.
|
||||
|
||||
Scoped Verification: `not-run` — on one authorized owned target, compare pinned
|
||||
image proof with mutable/snapshot and changed-config controls; require independent
|
||||
cleanup evidence before recording proof. Assert agent/non-admin board denial,
|
||||
secret-context denial where the actor lacks access and forged-proof rejection.
|
||||
Verify API reads hide the private record and metadata-only updates cannot overwrite it. Then use
|
||||
[runtime validation](./runs-adapters.md#validation) for account/model/native startup.
|
||||
|
||||
There is no new delegated agent probe binding or client proof-write API. Any
|
||||
human-action request/result handoff requires its own admitted path and verification;
|
||||
an accepted interaction does not turn the caller into a board administrator.
|
||||
|
||||
## `assignment`
|
||||
|
||||
Review: `baseline`.
|
||||
|
||||
@@ -9,6 +9,11 @@ Each capability needs operation-level review before its entire scope can be
|
||||
qualified. No live agent execution is claimed. Follow the [map contract](../README.md)
|
||||
for format, permission checks, evidence and maintenance.
|
||||
|
||||
Scoped runner-default source review: 2026-10-12 at
|
||||
`eee0534154eaf5d0d3f2bbc97c1e24d86f34a5a5`, limited to first-agent selection,
|
||||
selected-runtime validation and draft restoration. Unrelated baseline entries
|
||||
retain the original source commit; no live agent verification is added.
|
||||
|
||||
## `instance`
|
||||
|
||||
Review: `baseline`.
|
||||
@@ -74,10 +79,25 @@ provider-account/environment setup.
|
||||
Policy: Instance setup is operator work; company creation is board; agent creation/task
|
||||
creation retain their individual permissions.
|
||||
|
||||
The wizard selects the Codex harness and lets the server resolve an automatic
|
||||
new-agent runner; explicit Legacy remains available. Supported-platform and
|
||||
immutable sandbox evidence follow [environment probe policy](./execution-environments.md#probe).
|
||||
Creation/discovery do not provision a target to determine this default. Adapter
|
||||
setup validation requires `agents:create`, plus saved-agent update access when
|
||||
testing an existing agent; interactive account login additionally requires a
|
||||
board user and owner-bound session. An agent's right to hire is not login or
|
||||
instance-environment administration authority.
|
||||
|
||||
Evidence: `source-only` —
|
||||
[implementation](../../ui/src/components/OnboardingWizard.tsx#L279) at the reviewed
|
||||
commit above.
|
||||
|
||||
Scoped Evidence: `source-only` — [wizard/default selection](../../ui/src/components/OnboardingWizard.tsx),
|
||||
[creation resolver](../../server/src/services/agent-runner-selection.ts) and
|
||||
[setup/login authorization](../../server/src/routes/agents.ts) at the scoped
|
||||
commit. Existing agent/approval execution preservation follows
|
||||
[hiring access](./agents.md#hire); no live onboarding proof is claimed here.
|
||||
|
||||
Verification: `not-run` — exercise a listed permitted operation with actual agent
|
||||
credentials/run context; inspect its result and applicable persistence/attribution.
|
||||
Assert the relevant denied actor, owner, company or mode from Policy. Review the
|
||||
@@ -86,6 +106,11 @@ remaining operations before qualifying the whole capability.
|
||||
Gaps: Account authorization, environment administration and model selection need
|
||||
separate checks.
|
||||
|
||||
Verify automatic onboarding without a post-hire runner change, explicit Legacy,
|
||||
saved configuration after reload and the actual selected runtime's useful task
|
||||
plus follow-up. Assert denied agent login/probe and foreign-company account or
|
||||
environment access separately. These agent-context checks remain `not-run`.
|
||||
|
||||
## `first-task`
|
||||
|
||||
Review: `baseline`.
|
||||
@@ -134,3 +159,8 @@ evidence.
|
||||
|
||||
Gaps: No server onboarding-draft API for this browser-local state; classify explicitly
|
||||
or intentionally make it a cross-client product feature.
|
||||
|
||||
Scoped source review of [draft restoration](../../ui/src/components/OnboardingWizard.tsx)
|
||||
preserves harness/runner intent and invalidates obsolete setup-test results after
|
||||
a selection change. Browser draft continuity is not API or live-agent evidence,
|
||||
and opening a saved Legacy agent does not apply new-agent defaults.
|
||||
@@ -9,6 +9,11 @@ Each capability needs operation-level review before its entire scope can be
|
||||
qualified. No live agent execution is claimed. Follow the [map contract](../README.md)
|
||||
for format, permission checks, evidence and maintenance.
|
||||
|
||||
Scoped runner-default source review: 2026-10-12 at
|
||||
`eee0534154eaf5d0d3f2bbc97c1e24d86f34a5a5`, limited to runner discovery,
|
||||
selected-runtime testing and saved execution/session preservation. The original
|
||||
baseline source and review depth remain unchanged for unrelated operations.
|
||||
|
||||
## `availability`
|
||||
|
||||
Review: `baseline`.
|
||||
@@ -40,6 +45,15 @@ Source: [adapter discovery](../../server/src/adapters/registry.ts).
|
||||
Gaps: Raw instance adapter listing requires board, while company model discovery exists
|
||||
for eligible agents.
|
||||
|
||||
Scoped source-only evidence: [adapter discovery](../../server/src/routes/adapters.ts)
|
||||
reports supported runners/effective default for the selected company/environment;
|
||||
[selection policy](../../server/src/services/agent-runner-selection.ts) reads
|
||||
server-owned immutable sandbox facts without provisioning. New Codex defaults
|
||||
and explicit overrides follow the [shared runner contract](../../packages/shared/src/agent-runner.ts);
|
||||
other harness defaults remain unchanged. The board inventory does not grant a
|
||||
native agent an equivalent discovery binding. See
|
||||
[probe restrictions](./execution-environments.md#probe) for acquiring qualification.
|
||||
|
||||
## `validation`
|
||||
|
||||
Review: `baseline`.
|
||||
@@ -65,6 +79,22 @@ remaining operations before qualifying the whole capability.
|
||||
Gaps: Environment test path checks creation/configuration policy; missing provider auth
|
||||
must use its owner setup flow.
|
||||
|
||||
Scoped source review: [test authorization and resolution](../../server/src/routes/agents.ts)
|
||||
requires same-company `agents:create`, saved-agent update access when supplied,
|
||||
allowed environment selection, and normal secret/responsible-user checks. An
|
||||
unchanged saved runner avoids new-creation policy but still receives selected
|
||||
runtime validation. [Native readiness](../../server/src/services/native-runtime/setup-readiness.ts)
|
||||
tests native Codex startup/model/account and bounded teardown; an authentication
|
||||
or Legacy CLI check cannot replace that runtime evidence. Missing dependencies,
|
||||
credentials, invalid models and incompatible settings fail without silently
|
||||
changing runners. Account login remains board/owner-bound.
|
||||
|
||||
Verification for this scope remains `not-run`: use an admitted agent REST/CLI
|
||||
validation path, assert missing grants and cross-company targets/accounts are
|
||||
denied, then prove the useful task/follow-up separately. `hire_agent` inherits its
|
||||
caller's runtime; do not assume its binding accepts arbitrary runner or account
|
||||
settings. See [creation access](./agents.md#hire).
|
||||
|
||||
## `runs`
|
||||
|
||||
Review: `baseline`.
|
||||
@@ -114,3 +144,10 @@ own policy and access review.
|
||||
|
||||
Gaps: Execution context reset is not a permitted generic native API mutation or an
|
||||
ordinary agent management path.
|
||||
|
||||
Scoped source-only evidence: [configuration changes](../../server/src/services/agent-configuration.ts)
|
||||
and [native execution/recovery](../../server/src/services/native-runtime/native-session-executor.ts)
|
||||
retain existing execution on unrelated edits and use recorded run configuration
|
||||
for active/recovered runs. Explicit runner changes use revisions and session
|
||||
invalidation. Verify saved configuration, current versus historical run identity,
|
||||
restart and follow-up without granting session-reset authority to an agent.
|
||||
@@ -8,7 +8,7 @@ Agent access: [companion](../agent-access-map/agents.md).
|
||||
|
||||
## Sub-features
|
||||
|
||||
- `hire`: choose identity, adapter, model, and required account settings; edit
|
||||
- `hire`: choose identity, harness, model, and required account settings; edit
|
||||
reporting relationships through the agent configuration afterward.
|
||||
- `instructions`: edit agent configuration and instruction files with durable revisions.
|
||||
- `organization`: inspect and change reporting relationships through supported controls.
|
||||
@@ -39,6 +39,25 @@ Automated: [new agent page](../../ui/src/pages/NewAgent.test.tsx) and [configura
|
||||
|
||||
Manual: Hire an agent with a distinct name and role. Complete any required approval, reload the roster, and open its configuration. Confirm manager, adapter, and model persisted; run a small task to prove execution readiness.
|
||||
|
||||
For a new Codex hire, choose the Codex harness. Automatic selection uses Paperclip
|
||||
Runner on a qualified selected target; Advanced offers an explicit Legacy runner
|
||||
override. Record the persisted runner and
|
||||
underlying harness, rather than treating the displayed Codex name as execution
|
||||
proof. See [runtime selection and validation](./runs-adapters.md#adapter-setup)
|
||||
and [target qualification](./execution-environments.md#environment-settings).
|
||||
|
||||
Repeat with an explicit Legacy Codex hire. If approval is required, compare its
|
||||
reviewed execution configuration before and after restart and activation; approval
|
||||
must retain the reviewed runner. Test an existing Legacy and native agent through
|
||||
an unrelated edit, reload and restart: neither is automatically upgraded.
|
||||
|
||||
Creation defaults also apply to API/CLI hires, built-ins, plugins and new team
|
||||
imports. Exports preserve resolved execution choices; a package without a runner
|
||||
choice uses the new-agent default, while updating an existing same-harness agent
|
||||
preserves its execution. For a native Codex import, edit a model or account binding
|
||||
and verify unchanged runtime settings survive; an explicit clear must stay cleared.
|
||||
Use the [portability recipe](./companies.md) for package preparation and boundaries.
|
||||
|
||||
For Claude Code on Apple Silicon, submit without a runner override and inspect
|
||||
saved configuration: `paperclip_runner`, `provider: acpx`, `acpxAgent: claude`,
|
||||
and ordinary model `claude-opus-5-5`. The Advanced runner selector can explicitly
|
||||
@@ -58,6 +77,12 @@ Automated: [instruction service](../../server/src/__tests__/agent-instructions-s
|
||||
|
||||
Manual: Save a harmless instruction edit, reload, and verify its revision and effect in the next eligible run. Pause and resume the disposable agent; confirm pause prevents new work and does not erase previous runs.
|
||||
|
||||
An explicit runner change is a configuration change, with normal revisions and
|
||||
session invalidation. Incompatible settings must produce a field-specific error;
|
||||
selecting another runner must not silently discard them or change an active run's
|
||||
recorded execution. Keep runner choice in Advanced and verify the next eligible
|
||||
run separately from historical transcripts.
|
||||
|
||||
### `organization`
|
||||
|
||||
Automated: [org chart](../../ui/src/pages/OrgChart.test.tsx) is component evidence. Built-in setup also has [configuration modal tests](../../ui/src/components/ConfigureBuiltInAgentModal.test.tsx).
|
||||
|
||||
@@ -38,6 +38,33 @@ Automated: [environment UI](../../ui/src/pages/CompanyEnvironments.test.tsx), [d
|
||||
|
||||
Manual: Save a disposable target, reload it, and run its available probe. Verify both success and missing-credential/reachability errors identify the target. Confirm unavailable providers are not offered as working run targets.
|
||||
|
||||
For an immutable sandbox image, pin the OCI image with `@sha256` and explicitly
|
||||
probe the saved environment in the intended company. The existing connection
|
||||
probe allocates a fresh lease and can measure its OS, architecture and libc.
|
||||
Qualification is recorded only when the selected image/configuration matches
|
||||
the live lease and cleanup is confirmed. Inspect `platformQualificationRecorded`
|
||||
and its diagnostic in the probe result: connection success alone does not mean
|
||||
the image has native runtime qualification.
|
||||
|
||||
The measured record is server-owned, company-bound and tied to the effective
|
||||
configuration and active custom-image identity. Mutable tags, provider defaults
|
||||
and name-only snapshots do not qualify. Changing the target or image invalidates
|
||||
the record; normal metadata edits cannot forge or overwrite it, and API reads
|
||||
omit the private metadata. Reading this evidence for discovery or creation does
|
||||
not allocate a sandbox. The draft `probe-config` checks are not a saved-image
|
||||
qualification operation. See the [runtime contract](../../packages/paperclip-runner/README.md)
|
||||
and [adapter validation recipe](./runs-adapters.md#adapter-setup) for native
|
||||
binary/provider readiness after platform qualification.
|
||||
|
||||
Verification recipe: probe a pinned owned image, record its company/config/image
|
||||
identity and cleanup result, then change the image or target and verify its old
|
||||
qualification is not reused. A mutable-image connection can succeed while
|
||||
qualification remains absent. Assert ordinary agent and non-admin board probe
|
||||
requests are denied, and environment create/PATCH payloads cannot supply
|
||||
qualification metadata.
|
||||
This recipe and its [probe controls](../../server/src/__tests__/environment-probe.test.ts)
|
||||
are not claims that a live provider or agent-access journey ran for this map update.
|
||||
|
||||
The local row has no UI Test button. Its API/CLI probe reports host/cwd
|
||||
availability only; it does not validate an adapter binary, workspace, or task
|
||||
execution. Remote-driver probes and a real bounded run need their own evidence.
|
||||
@@ -51,5 +78,7 @@ Manual: Run a bounded command in the intended target, inspect its output and wor
|
||||
## Gotchas
|
||||
|
||||
- A probe is narrower evidence than a complete task with tools, files, and resumption.
|
||||
- Platform qualification does not authenticate a model account or qualify every
|
||||
harness; the selected native runtime still needs its own setup and useful-task proof.
|
||||
- The local option may appear only when editing an existing local environment; availability follows current UI/provider capabilities.
|
||||
- Workspace service reachability and environment reachability are separate checks.
|
||||
@@ -50,6 +50,22 @@ company's onboarding route, and finish; drafts save automatically. Follow the
|
||||
created first task, verify the selected agent and company, and inspect its output
|
||||
or explicit authentication gate. Reload both company and task.
|
||||
|
||||
For Codex, choose the harness and leave runner selection automatic to prove the
|
||||
first-agent default. On a qualified target it saves Paperclip Runner; Advanced
|
||||
also permits Legacy. Do not switch runners after onboarding when claiming proof
|
||||
of that default. Test the selected runtime and account, then complete a bounded
|
||||
useful task and follow-up with an independently checked file artifact. Saved
|
||||
execution configuration and recorded run identity must match after reload.
|
||||
Use [runner validation](./runs-adapters.md#adapter-setup) and
|
||||
[environment qualification](./execution-environments.md#environment-settings)
|
||||
for the prerequisites; a successful login alone is insufficient.
|
||||
|
||||
Leave and resume during harness/runner setup. Confirm the draft retains the
|
||||
explicit choice and compatible account bindings, old native Codex setup links
|
||||
recover the harness and runner, and a changed harness or runner invalidates stale
|
||||
test results. Existing Legacy agents remain Legacy when their onboarding/setup
|
||||
configuration is reopened; this journey does not migrate them.
|
||||
|
||||
### `cli-setup`
|
||||
|
||||
Automated: [CLI onboarding](../../cli/src/__tests__/onboard.test.ts) and [isolated test drive](../../cli/src/__tests__/test-drive.test.ts) cover their setup contracts; they do not establish that every model account is usable.
|
||||
|
||||
@@ -37,12 +37,44 @@ models/authentication and unsupported Legacy-only options must fail visibly.
|
||||
|
||||
Manual: Select the intended adapter and account, refresh model choices, and run its environment test. Save, reload, then execute a small task. Repeat with a deliberately unavailable account and verify the failure remains visible.
|
||||
|
||||
Choose Codex as the harness; the UI displays its name/icon for both runners.
|
||||
Advanced identifies the automatic default and offers Paperclip Runner or Legacy.
|
||||
Only new Codex agents default to the native runner on supported macOS or GNU/Linux
|
||||
targets; the [shared selection contract](../../packages/shared/src/agent-runner.ts)
|
||||
and [runtime prerequisites](../../packages/paperclip-runner/README.md) define the
|
||||
platform/libc boundary. Windows and Alpine/musl remain Legacy; other harness
|
||||
defaults are unchanged. Disabled adapters, external overrides, and selected-target
|
||||
qualification also affect availability.
|
||||
|
||||
For sandbox defaults, follow the [environment probe](./execution-environments.md#environment-settings)
|
||||
recipe first. Discovery/creation read company-bound immutable-image evidence
|
||||
without allocating a target. A mutable image or snapshot name does not establish
|
||||
native compatibility. Then test the actual selected runtime with its selected
|
||||
account/model: a legacy CLI or authentication probe alone cannot establish native
|
||||
readiness. Missing dependencies, failed authentication, invalid models and
|
||||
incompatible custom settings must remain actionable errors without silent runner
|
||||
switching. Saved unchanged execution can still be tested without applying new
|
||||
selection policy, but runtime/account validation must still run.
|
||||
|
||||
Verify an automatic Codex hire and an explicit Legacy control through a useful
|
||||
file artifact, follow-up and reload. Preserve Codex reasoning effort and account
|
||||
isolation; retain explicit Legacy permission choices, including false. Reopen an
|
||||
existing agent, make an unrelated edit, and confirm both its persisted runner and
|
||||
next run stay unchanged. Use [hiring/import preservation](./agents.md#hire-agent)
|
||||
for approval and portability controls.
|
||||
|
||||
### `run-history`
|
||||
|
||||
Automated: [live run routes](../../server/src/__tests__/agent-live-run-routes.test.ts) and [run event sequencing](../../server/src/__tests__/heartbeat-run-event-sequencing.test.ts) cover run data contracts.
|
||||
|
||||
Manual: Start a disposable task, open its running transcript, and follow it to a terminal outcome. Reload and compare task/run IDs, status, output, and cost. Verify a failed run remains distinguishable from a completed run with useful output.
|
||||
|
||||
An explicit runner change starts a configuration revision and invalidates the
|
||||
eligible session. Active runs, restart recovery and historical transcript parsing
|
||||
retain their recorded execution configuration; do not infer their runner from a
|
||||
later edit to the agent. Account/harness branding and execution identity are
|
||||
different observations, both required in the evidence.
|
||||
|
||||
## Gotchas
|
||||
|
||||
- Model accounts are managed in Apps and inline agent account controls.
|
||||
|
||||
@@ -52,7 +52,7 @@ test("release assembly rejects rehashed stale or missing packs before staging an
|
||||
const source = dirname(dirname(fileURLToPath(import.meta.url)));
|
||||
try {
|
||||
// Run the actual assembler in an isolated layout so it cannot overwrite built artifacts.
|
||||
for (const file of ["scripts/stage-release-runner-binaries.mjs", "scripts/release-provider-pack.mjs", "src/live/runner-binary.ts", "acpx-profiles.json", "cursor-distributions.json"]) {
|
||||
for (const file of ["scripts/stage-release-runner-binaries.mjs", "scripts/release-provider-pack.mjs", "src/live/runner-binary.ts", "acpx-profiles.json", "cursor-distributions.json", "release-runner-targets.json"]) {
|
||||
mkdirSync(dirname(join(root, file)), { recursive: true }); cpSync(join(source, file), join(root, file));
|
||||
}
|
||||
const platforms = {};
|
||||
|
||||
@@ -9,7 +9,8 @@ vi.mock("./environment-probe.js", () => ({ readSandboxPlatformQualification: sta
|
||||
vi.mock("./environment-config.js", () => ({ resolveEnvironmentDriverConfigForRuntime: state.resolveEnvironment }));
|
||||
vi.mock("@paperclipai/adapter-utils/ssh", () => ({ runSshCommand: state.ssh }));
|
||||
import { AGENT_RUNNER_SSH_PLATFORM_COMMAND, agentRunnerAvailability, resolveAgentRunnerTargetForCompany, resolveNewAgentRunner, resolveNewAgentRunnerForCompany } from "./agent-runner-selection.js";
|
||||
import { buildCodexAcpConfig } from "@paperclipai/adapter-codex-local/server";
|
||||
import { buildCodexAcpConfig, resolveCodexExecutionEngine } from "@paperclipai/adapter-codex-local/server";
|
||||
import { secretService } from "./secrets.js";
|
||||
import { localAgentRunnerTarget } from "../lib/agent-runner-platform.js";
|
||||
const target = { driver: "local", platform: "linux", architecture: "x64" };
|
||||
const qualifiedTargets = [target, { driver: "local", platform: "linux", architecture: "arm64" }, { driver: "local", platform: "darwin", architecture: "arm64" }, { driver: "local", platform: "darwin", architecture: "x64" }];
|
||||
@@ -183,6 +184,71 @@ describe("server-owned Codex runner selection", () => {
|
||||
.toThrow(expect.objectContaining({ status: 422, details: { code: "agent_runner_config_incompatible", fields: ["acpPermissionMode"] } }));
|
||||
});
|
||||
|
||||
it.each([undefined, "acp"])("rejects effective Legacy ACP network denial for engine=%s before native selection", async engine => {
|
||||
const adapterConfig = { ...(engine ? { engine } : {}), env: { PAPERCLIP_CODEX_ACP_NETWORK_ACCESS: "false" } };
|
||||
expect(resolveCodexExecutionEngine(adapterConfig).engine).toBe("acp");
|
||||
expect(buildCodexAcpConfig(adapterConfig)).toMatchObject({ env: { PAPERCLIP_CODEX_ACP_NETWORK_ACCESS: "false" } });
|
||||
// Native permissions use a separately trusted server variable. This would
|
||||
// enable networking despite the saved Legacy flag without admission rejection.
|
||||
const { codexNetworkAccess } = await import(new URL(
|
||||
"../../../packages/paperclip-runner/src/drivers/codex/codex-security-config.ts", import.meta.url,
|
||||
).href);
|
||||
expect(codexNetworkAccess({ PAPERCLIP_RUNNER_NETWORK_ACCESS: "enabled", PAPERCLIP_CODEX_ACP_NETWORK_ACCESS: "false" })).toBe(true);
|
||||
for (const runner of [undefined, "auto", "paperclip"] as const) {
|
||||
expect(() => resolveNewAgentRunner({ adapterType: "codex_local", adapterConfig, target, runner }))
|
||||
.toThrow(expect.objectContaining({ status: 422, details: { code: "agent_runner_config_incompatible", fields: ["env.PAPERCLIP_CODEX_ACP_NETWORK_ACCESS"] } }));
|
||||
}
|
||||
expect(resolveNewAgentRunner({ adapterType: "codex_local", adapterConfig, target, runner: "legacy" }))
|
||||
.toEqual({ adapterType: "codex_local", adapterConfig });
|
||||
expect(adapterConfig.env).toEqual({ PAPERCLIP_CODEX_ACP_NETWORK_ACCESS: "false" });
|
||||
});
|
||||
|
||||
it.each([
|
||||
{ type: "plain", value: "false" },
|
||||
{ type: "secret_ref", secretId: "fixture-policy", version: "latest" },
|
||||
{ type: "user_secret_ref", key: "fixture-policy", version: "latest" },
|
||||
])("does not discard a bound ACP network restriction or guess its value (%j)", async binding => {
|
||||
const adapterConfig = { engine: "acp", env: { PAPERCLIP_CODEX_ACP_NETWORK_ACCESS: binding } };
|
||||
if (binding.type === "plain") {
|
||||
const resolved = await secretService({} as never).resolveEnvBindings("fixture-company", adapterConfig.env);
|
||||
expect(buildCodexAcpConfig({ ...adapterConfig, env: resolved.env }))
|
||||
.toMatchObject({ env: { PAPERCLIP_CODEX_ACP_NETWORK_ACCESS: "false" } });
|
||||
}
|
||||
expect(() => resolveNewAgentRunner({ adapterType: "codex_local", adapterConfig, target }))
|
||||
.toThrow(expect.objectContaining({ status: 422, details: { code: "agent_runner_config_incompatible", fields: ["env.PAPERCLIP_CODEX_ACP_NETWORK_ACCESS"] } }));
|
||||
expect(resolveNewAgentRunner({ adapterType: "codex_local", adapterConfig, target, runner: "legacy" }))
|
||||
.toEqual({ adapterType: "codex_local", adapterConfig });
|
||||
});
|
||||
|
||||
it.each([
|
||||
{ extraArgs: ["-c", "sandbox_workspace_write.network_access=true"] },
|
||||
{ extraArgs: [], args: ["-c", "sandbox_workspace_write.network_access=true"] },
|
||||
])("retains actionable argument errors when Legacy arguments override a network flag (%j)", args => {
|
||||
const adapterConfig = { engine: "acp", ...args, env: { PAPERCLIP_CODEX_ACP_NETWORK_ACCESS: "false" } };
|
||||
expect(buildCodexAcpConfig(adapterConfig)).toMatchObject({ env: { PAPERCLIP_CODEX_ACP_NETWORK_ACCESS: "true" } });
|
||||
expect(() => resolveNewAgentRunner({ adapterType: "codex_local", adapterConfig, target }))
|
||||
.toThrow(expect.objectContaining({ status: 422, details: { code: "agent_runner_config_incompatible", fields: [args.extraArgs.length ? "extraArgs" : "args"] } }));
|
||||
});
|
||||
|
||||
it.each(["true", "False", " false ", { type: "plain", value: "true" }])("keeps compatible ACP environment settings (%j) and native idempotence", value => {
|
||||
const adapterConfig = { engine: "acp", env: { PAPERCLIP_CODEX_ACP_NETWORK_ACCESS: value, OPENAI_API_KEY: { type: "secret_ref", secretId: "fixture-api-key" } } };
|
||||
const literal = typeof value === "string" ? value : value.value;
|
||||
expect(buildCodexAcpConfig({ ...adapterConfig, env: { PAPERCLIP_CODEX_ACP_NETWORK_ACCESS: literal } }))
|
||||
.toMatchObject({ env: { PAPERCLIP_CODEX_ACP_NETWORK_ACCESS: "true" } });
|
||||
const resolved = resolveNewAgentRunner({ adapterType: "codex_local", adapterConfig, target });
|
||||
expect(resolved.adapterType).toBe("paperclip_runner");
|
||||
expect(resolved.adapterConfig.env).toEqual(adapterConfig.env);
|
||||
expect(resolveNewAgentRunner(resolved)).toEqual(resolved);
|
||||
});
|
||||
|
||||
it("keeps a saved native profile and an explicitly selected Legacy CLI's unused ACP flag unchanged", () => {
|
||||
const adapterConfig = { engine: "cli", env: { PAPERCLIP_CODEX_ACP_NETWORK_ACCESS: "false" } };
|
||||
expect(resolveCodexExecutionEngine(adapterConfig).engine).toBe("cli");
|
||||
expect(resolveNewAgentRunner({ adapterType: "codex_local", adapterConfig, target }).adapterType).toBe("paperclip_runner");
|
||||
const saved = { adapterType: "paperclip_runner", adapterConfig: { provider: "codex", env: adapterConfig.env } };
|
||||
expect(resolveNewAgentRunner(saved)).toEqual(saved);
|
||||
});
|
||||
|
||||
it("preserves explicit historical native profiles, including managed configurations", () => {
|
||||
for (const config of [{ provider: "acpx", acpxAgent: "claude", model: "claude-sonnet-5" }, { provider: "claude_managed", managedProfileId: "profile", managedAgentsRetentionAcknowledged: true }, { provider: "aws_agentcore", agentCoreProfileId: "profile" }]) expect(resolveNewAgentRunner({ adapterType: "paperclip_runner", adapterConfig: config })).toEqual({ adapterType: "paperclip_runner", adapterConfig: config });
|
||||
});
|
||||
|
||||
@@ -155,6 +155,18 @@ export function resolveNewAgentRunner(input: AgentRunnerSelection): { adapterTyp
|
||||
if (config.dangerouslyBypassApprovalsAndSandbox === false) unsupported.push("dangerouslyBypassApprovalsAndSandbox");
|
||||
if (config.dangerouslyBypassSandbox === false) unsupported.push("dangerouslyBypassSandbox");
|
||||
if (unsupported.length) incompatible(unsupported.map(field => aliasSources.get(field) ?? field));
|
||||
const env = config.env && typeof config.env === "object" && !Array.isArray(config.env)
|
||||
? config.env as Record<string, unknown> : {};
|
||||
const network = env.PAPERCLIP_CODEX_ACP_NETWORK_ACCESS;
|
||||
const binding = network && typeof network === "object" && !Array.isArray(network)
|
||||
? network as Record<string, unknown> : null;
|
||||
// Native networking is server-owned. Never translate a Legacy restriction
|
||||
// into that trusted variable, or guess the value of a deferred policy binding.
|
||||
if (config.engine !== "cli" && (network === "false"
|
||||
|| (binding?.type === "plain" && binding.value === "false")
|
||||
|| binding?.type === "secret_ref" || binding?.type === "user_secret_ref")) {
|
||||
incompatible(["env.PAPERCLIP_CODEX_ACP_NETWORK_ACCESS"]);
|
||||
}
|
||||
const effort = config.modelReasoningEffort ?? config.reasoningEffort ?? config.effort;
|
||||
for (const key of ["engine", "command", "extraArgs", "args", "agentCommand", "mode", "nonInteractivePermissions", "stateDir", "warmHandleIdleMs", "dangerouslyBypassApprovalsAndSandbox", "dangerouslyBypassSandbox", "search", "fastMode", "reasoningEffort", "effort"]) delete config[key];
|
||||
if (config.model !== undefined && typeof config.model !== "string") incompatible(["model"]);
|
||||
|
||||
Reference in new issue
Block a user