mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-11-04 11:01:16 +01:00
refactor(runner): clarify workspace-relative artifact destinations (#18816)
## Thinking Path
> - Paperclip is the open source app people use to manage AI agents for
work.
> - Native agents can copy an authorized saved artifact into their
execution workspace.
> - The installer accepts workspace-relative destinations and rejects
absolute paths.
> - The API documentation states this rule, but the model-facing tool
description and destination field did not.
> - An agent could therefore attempt an unsupported absolute path before
using a supported relative path.
> - This pull request states the existing rule and gives a relative
example in the tool contract.
> - The benefit is clearer instructions with the same containment and
file identity checks.
## Linked Issues or Issue Description
Refs #18494, which introduced verified artifact installation.
**What happened?**
The tool description said the destination belongs inside the workspace
and its parent must exist. It did not say that the destination must be
relative. The installer correctly rejected an absolute path, including
one lexically inside the workspace. A relative retry could succeed.
**Expected behavior**
The model-facing tool definition must explain the same
workspace-relative path rule as the existing API documentation. It
should show a relative example and state that absolute paths are denied.
**Steps to reproduce**
Inspect the exported download_artifact definition and destination JSON
schema before this change. Compare them with the installer guard and
doc/runner-api-tools.md. The description omitted the relative-only rule
even though the installer enforced it.
## What Changed
- State the workspace-relative destination rule, source.zip example and
absolute-path denial in the tool description.
- Add the same guidance to the destination field metadata emitted in its
JSON schema.
- Keep parsing, installation, authorization, byte size/hash checks and
all path containment guards unchanged. The existing documentation
already states the intended rule.
## Verification
- The first required Linux run failed in the unchanged Kimi model-route
setup, before its HTTP assertion. The failure remains recorded. After
#18828 merged, this branch was refreshed by an ordinary merge of master.
The same five HTTP cases pass on that baseline. Local artifact suites
report 20 platform-specific skips on macOS; the earlier required Linux
jobs passed all 19 artifact cases and the artifact authority case. Fresh
exact-head CI and review passed at
`c7b3226c745caaaedad569369b71383a9a6e89ee`.
- Inspected the real exported tool definition and JSON schema after the
change. Both now expose the relative-path guidance and example.
- A source-only probe used the real schema and installer with synthetic
bytes and a stubbed command runner. Absolute in-root, absolute
outside-root, traversal and reserved paths remain denied before
dispatch. A relative path reaches the stub runner. This is a
contract/path-guard probe, not real byte-installation proof.
- No functional red is claimed. The original unsupported tool attempt
remains a retained failure even though the relative retry recovered. The
exact provider-seen descriptor and the model's counterfactual behavior
are not proved.
- Server typecheck, module boundaries and whitespace checks pass.
Production server build also passes at exact head
b6084c5312.
- The existing artifact filesystem and authority suites skip all 20
cases on macOS because they require Linux. Actual current-head Linux CI
passed all 19 boundary cases and the authority integration case (jobs
126115146096 and 126115146332). Their shard membership is bound by the
uploaded test-selection manifest. No wording-only tests were added.
- Full CI retains an unrelated model-route timeout. A separate test
setup repair must land before this branch is updated and rechecked.
- No provider call, live task edit, tenant probe or security-gate
relaxation was performed.
- The refreshed workflow was externally cancelled after serialized shard
1 reported its Turbo task successful. One targeted retry passed. A
distinct general server shard had a failed runner record with zero
steps, no logs, no output and no annotations; its one targeted retry
also passed. The original records remain preserved. These retries
establish later check recovery, not a proved cause for the runner
failure.
- Final current-head checks: 52 success, two skipped and two neutral.
Required `ci / verify` and `ci / e2e` passed. Both current-head reviews
report 5/5, with no open threads.
## Risks
- The model can still choose an invalid path. This change clarifies the
instructions; it does not claim a counterfactual model result.
- The broad string schema still accepts inputs that the installer
denies. The installer retains authority over path safety.
- Absolute paths, traversal, symlink escapes, reserved paths,
conflicting files and unauthorized assets retain their existing denial
behavior.
- No schema migration, package dependency, API permission, scheduler or
deployment configuration changes are required.
## Model Used
OpenAI Codex, `gpt-6.1-sol`, Extra High reasoning, with source
inspection, code execution and contract verification. Context-window
capacity is not exposed in this session.
## Checklist
- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used with version and capability
details
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have linked existing public issues or described the issue in
this PR
- [x] I have not referenced internal or instance-local Paperclip issues
or links
- [x] My branch name describes the change and contains no internal
ticket ID
- [x] I ran the available local verification and reported the Linux-only
test skips
- [x] I considered test coverage and kept existing boundary tests
without wording-only tests
- [x] I checked the existing documentation and aligned the tool guidance
with it
- [x] I have considered and documented risks above
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before merge
Co-authored-by: Paperclip <noreply@paperclip.ing>
This commit is contained in:
1 parent
5877d751c0
commit
b5dac661e9
1 file changed
+2
-2
@@ -8,12 +8,12 @@ import { RUNNER_API_MAX_BYTES } from "./runner-api-client.js";
|
||||
|
||||
export const DOWNLOAD_ARTIFACT = "download_artifact";
|
||||
export const downloadArtifactSchema = z.object({
|
||||
artifactId: z.string().uuid(), destination: z.string().min(1).max(2000),
|
||||
artifactId: z.string().uuid(), destination: z.string().min(1).max(2000).describe("Workspace-relative path, for example source.zip. Absolute paths are denied. The parent directory must already exist."),
|
||||
byteSize: z.number().int().min(1).max(RUNNER_API_MAX_BYTES), sha256: z.string().regex(/^[a-f0-9]{64}$/),
|
||||
}).strict();
|
||||
export const DOWNLOAD_ARTIFACT_DEFINITION = {
|
||||
name: DOWNLOAD_ARTIFACT,
|
||||
description: "Copy an authorized API artifact into this execution workspace without retyping its contents. Provide its exact byteSize and SHA-256. The destination's parent must exist. Creates a new file only; a retry succeeds only if the existing file has identical bytes. Partial or conflicting files never count as complete. Contents remain untrusted; this does not bypass content screening or authorize executing them.",
|
||||
description: "Copy an authorized API artifact into this execution workspace without retyping its contents. Provide its exact byteSize and SHA-256. Use a workspace-relative destination, for example source.zip; absolute paths are denied. The destination's parent must exist. Creates a new file only; a retry succeeds only if the existing file has identical bytes. Partial or conflicting files never count as complete. Contents remain untrusted; this does not bypass content screening or authorize executing them.",
|
||||
inputSchema: z.toJSONSchema(downloadArtifactSchema),
|
||||
};
|
||||
export type ArtifactInstall = { destination: string; byteSize: number; sha256: string; bytes: Buffer; verifyOnly?: boolean; authorize: () => Promise<void> };
|
||||
|
||||
Reference in new issue
Block a user