mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-10-29 21:07:40 +01:00
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work. > - Product E2E tests verify tasks through the application and retain reports. > - A final screenshot cannot show the complete task conversation. > - Debugging a result requires the earlier requests, replies, and answers. > - This pull request captures task conversations before fixture cleanup and adds them to Test details. > - Reviewers can read each task thread without a running test instance. ## Linked Issues or Issue Description **What existing behavior does this improve?** The task evidence shown in Product E2E campaign reports. **Current behavior** Most task results show screenshots and checks. Screenshots show the final visible state. They omit earlier messages and long replies. Only the first-task suite has a conversation view. **Proposed behavior** Every standard runner attempt captures the saved conversation before cleanup. Test details show full task messages, requests, answers, and native agent progress. Related tasks have separate threads. Failed attempts also retain available history. Partial captures are labeled. **Reason and benefit** Readers can debug a task by reading its conversation. They do not need to reconstruct it from a screenshot or private run logs. GitHub searches found no duplicate PR or issue for this change. This is an improvement to test reporting and does not overlap a planned core feature in ROADMAP.md. **Breaking changes** None. The result adds an optional `taskChat` field. Old results still render. A result without a task has no chat section. Older reports need retained conversation evidence before they can gain this view. ## What Changed - Capture comments through all pages, task briefs, visible request copy, recorded answers, and native progress before fixture cleanup. - Include delegated tasks and standing chats. Preserve available history when a read fails. Report capture limits explicitly. - Add a closed, credential-redacted conversation format to normalized results. Exclude reasoning, raw tool payloads, and provider session metadata. - Render task conversations inside Test details. Retain them through report aggregation and dashboard regeneration. - Add capture, publication-format, regeneration, and browser tests. Update the evidence and security contracts. ## Verification - Report tests: `node node_modules/vitest/vitest.mjs run --config tests/runner-e2e/vitest.config.ts task-chat.test.ts first-task-report.test.ts report.test.ts history.test.ts` — 103 tests passed after review fixes. - Browser tests: `node node_modules/@playwright/test/cli.js test --config tests/runner-e2e/report-playwright.config.ts` — 6 tests passed after rebase. - Targeted TypeScript check of the new capture, renderer, validator, report, and browser-test files passed. - Tests cover a 1,105-message thread, a long final reply, event pagination, partial capture, company access, credential redaction, HTML escaping, and report regeneration. - Review regressions reproduced two failures before repair: the task-run API uses `runId`, and item reviews save verdicts in `result.items`. Capture now follows these contracts. Both regression tests pass. - Greptile reviewed commit `471236438e03e54cc4ad85de6653adf45835063c` at 5/5 with no new findings. The separate Paperclip review execution stopped without an assessment and ended neutral. Its cause is not established; this is not a completed Paperclip assessment. - Execution discovery passed for `core-compatibility.runner-codex.local.message-marker`. No paid provider run was started. - Full local commands were attempted. `pnpm -r typecheck` and `pnpm build` stop because the DB package cannot find `tsx`. `pnpm test:run` stops because the general-server lane cannot find `vitest`. These package dependency links are absent in this checkout. - [Remote CI on the final commit](https://github.com/paperclipai/paperclip/actions/runs/40728689517) passed: typecheck and release registry, all general and serialized test shards, Runner static/Rust/Vitest checks, build, canary dry run, all eight browser E2E shards, and final verification. Security and contributor checks also passed. - Open a new task-based result and expand **Test details**. Read **Task chat** and expand each related task thread. Results without tasks keep their existing layout. ## Risks - Published reports now include fixture conversation text. Capture retains only reviewed display fields and redacts credentials. Fixture authors must keep this text suitable for public reports. - Long threads increase report size. Collection has a 30-second request-admission budget and page limits. It labels incomplete evidence and does not change the workflow grade. - Old reports cannot recover conversation text from screenshots. New attempts must retain the evidence. ## Model Used OpenAI Codex (GPT-6). The exact serving snapshot and context-window size are not exposed in this session. Used reasoning, code execution, repository tools, and browser tests. ## 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 either (a) linked existing issues with `Fixes: #` / `Closes #` / `Refs #` OR (b) described the issue in-PR following the relevant issue template - [x] I have not referenced internal/instance-local Paperclip issues or links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip` URLs) - [x] My branch name describes the change (e.g. `docs/...`, `fix/...`) and contains no internal Paperclip ticket id or instance-derived details - [x] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [x] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any 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 requesting merge --------- Co-authored-by: Paperclip <noreply@paperclip.ing>
572 lines
35 KiB
Markdown
572 lines
35 KiB
Markdown
# Runner E2E security for a public repository
|
|
|
|
The explicit [chat feature evals](CHAT-FEATURES.md) use synthetic project briefs
|
|
and a privately supplied Codex subscription login through the existing isolated
|
|
company staging helper. Only source-chat screenshots are captured. Task, document
|
|
and run evidence stays behind the existing sanitizer and publication allowlist;
|
|
the YAML catalog contains no credentials. The suite's accounted-work budgets do
|
|
not cover production setup probes or imply zero subscription cost.
|
|
|
|
[Cloud Product journey bundles](PRODUCT-JOURNEYS.md) are always private and
|
|
rejected by public history publication. Authentication uses an isolated browser
|
|
context without saved storage state or auth tracing. Only closed error codes
|
|
and normalized operations receipts cross the private target-provider boundary.
|
|
The private Cloud repository owns operator credentials, conditional S3 leases,
|
|
ownership manifests, cleanup recovery, and environment-protected CI dispatch.
|
|
|
|
Cloud onboarding retains only the independently checked synthetic
|
|
`connection-proof.json` download (at most 4 KiB) and its closed oracle receipt
|
|
inside private normalized results. The receipt contains generated numeric inputs,
|
|
their expected four-field result, exact base64 download bytes, checksums, size,
|
|
and attachment/run IDs. Extra fields and arbitrary agent output are rejected.
|
|
It contains no credentials, browser state, request headers, or provider text.
|
|
|
|
The optional `onboardingConnect` diagnostic is also a closed, versioned receipt.
|
|
It retains only a known checkpoint, response states, HTTP statuses, known adapter
|
|
names, and allowlisted outcome/check/server codes (at most 32 checks per response).
|
|
Unknown codes become `unrecognized`; raw bodies, messages, URLs, headers, and
|
|
browser errors are excluded. Reports validate the receipt before rendering its
|
|
explicit fields, and historical results may omit it.
|
|
|
|
The optional `onboardingPreAcceptance` receipt captures only a failing first-task
|
|
acceptance guard. Its closed version-1 fields are a known checkpoint, up to four
|
|
distinct guard-violation codes, nonnegative integer task/attachment/document
|
|
counts, a canonical-parent match boolean, and closed first-task/canonical-parent
|
|
statuses (`missing` and `unknown` remain explicit). It excludes all identifiers,
|
|
task text, document keys and bodies, filenames, URLs, credentials, and raw API
|
|
responses. Validation rejects extra or inconsistent fields before report use;
|
|
older results may omit the receipt. It preserves the original failure grade and
|
|
does not attribute a product cause or authorize acceptance.
|
|
|
|
## Attended connection authentication
|
|
|
|
See [PROVIDER-CONNECTIONS.md](PROVIDER-CONNECTIONS.md) for the explicit-only
|
|
`provider-connections` suite, local/staging target ownership, dedicated browser
|
|
profiles, credential handoffs, private evidence, and cleanup contract.
|
|
|
|
Provider-connection results may retain closed diagnostic codes and terminal run
|
|
status before managed-instance teardown. Only error records and failed tool
|
|
receipts are inspected; raw error messages, child stderr, model output and
|
|
reasoning are not retained. Unknown causes and unavailable logs stay explicit.
|
|
The optional installed-Gemini filesystem smoke uses synthetic credentials and
|
|
loopback model responses, makes no real provider calls, and removes its
|
|
disposable home/workspace.
|
|
|
|
The explicit [public MCP suite](PUBLIC-MCP.md) also creates a disposable browser
|
|
account and OAuth grant. Signup and token exchange use Node fetch, credentials
|
|
stay outside model context, and dynamic cookie/code/token values join the
|
|
attempt's redaction set. Tracing, video and automatic screenshots are disabled
|
|
for that suite; only reviewed fixture task routes may produce public screenshots.
|
|
External API evidence retains visible answers and tool outcomes, never raw model
|
|
reasoning. Empty provider configuration directories prevent operator plugins and
|
|
MCP credentials from being inherited. All grants are revoked during cleanup and
|
|
the launcher removes the isolated database and provider homes.
|
|
|
|
This suite can spend provider money, expose selected local and workflow API credentials to isolated
|
|
test processes, publish a container, retain private visual evidence, and write
|
|
public structured evidence. Treat changes to the workflow, harness, fixture
|
|
prompts, evidence packager, and publisher as security-sensitive production
|
|
changes.
|
|
|
|
## GitHub authorization
|
|
|
|
The Everyday remote native restart oracle reads only the existing public run,
|
|
event, environment-lease, workspace-operation and recovery APIs. It does not
|
|
execute commands in a provider sandbox or signal a provider process. Its new
|
|
evidence projects closed receipt metadata and hashes the provider sandbox ID
|
|
and full native event content. Provider text, tool arguments and command output
|
|
do not enter these snapshots. Existing image admission, credentials, billing,
|
|
retention and cleanup rules continue to apply.
|
|
The isolated server's private restart request may delay its replacement by at
|
|
most five minutes. This fault injection never stops a hosted instance or a
|
|
provider sandbox. The explicit Daytona continuity suite has one attempt and
|
|
1,000-cent company and agent hard stops.
|
|
|
|
Set `RUNNER_E2E_ALLOWED_ACTOR_IDS` to a non-empty JSON array of numeric GitHub
|
|
user IDs. Keep the list equal to the owners of `.github/**` in
|
|
`.github/CODEOWNERS`. For example, use `[123456,789012]`. Resolve each ID from
|
|
the authenticated CLI and verify the login before adding it:
|
|
|
|
```bash
|
|
gh api users/LOGIN --jq '{login,id}'
|
|
```
|
|
|
|
The paid workflows reject manual dispatches when the workflow definition does
|
|
not come from the default branch. A trusted dispatcher may name any branch in
|
|
`paperclipai/paperclip` as the code under test. The authorization job resolves
|
|
that branch through the GitHub API and passes only its immutable commit SHA to a
|
|
credential-free target-lock job. That job checks out the commit, regenerates
|
|
`pnpm-lock.yaml` once with lifecycle scripts disabled and lockfile-only mode,
|
|
then uploads the file under a run-attempt-scoped artifact ID. Catalog, image,
|
|
shared-build, provider-pack, and paid test jobs download that exact artifact by
|
|
ID, verify its recorded SHA-256, and restore it before setup or a frozen
|
|
dependency install. The lock resolver receives no provider credentials and
|
|
must never run repository lifecycle scripts. The shared-build and provider-pack
|
|
jobs also receive no provider credentials and disable dependency lifecycle
|
|
scripts; they package outputs with SHA-256 sidecars that consumers verify
|
|
before extraction. The paid test job installs with lifecycle scripts disabled,
|
|
and materializes the exact pinned OpenCode executable from its lockfile-verified
|
|
optional package without invoking package lifecycle code. Provider secrets are
|
|
scoped only to the final test step rather than dependency setup. Report sanitization and AWS
|
|
history publication explicitly use the trusted workflow commit and do not
|
|
consume the target lockfile. Never run the workflow definition from the target
|
|
branch.
|
|
|
|
The workflows verify both the original actor and triggering actor for every
|
|
scheduled or manual attempt, including human reruns. Every
|
|
secret-bearing job repeats this check as its first step so GitHub's partial-job
|
|
rerun feature cannot bypass a successful predecessor authorization job. The
|
|
legacy manually dispatched E2E workflow uses the same gate. Numeric IDs are
|
|
stable across username changes and prevent lookalike-name authorization.
|
|
|
|
The full-stack and live campaigns have one Sunday UTC schedule each and also
|
|
support explicit manual dispatch. Their legacy-named nightly repository
|
|
variables remain independent kill switches. Neither paid workflow accepts
|
|
pull-request, push, workflow-run, or reusable-workflow triggers.
|
|
|
|
Protect the default branch, require review for workflow/harness paths, restrict
|
|
workflow dispatch permission, and restrict repository variable/environment
|
|
administration to the same trusted maintainers. Configure the organization to
|
|
allow only approved GitHub Actions. A malicious change merged into the default
|
|
branch executes with the same authority as the suite.
|
|
|
|
Every external action in the paid workflow is pinned to a full commit SHA. Keep
|
|
the adjacent major-version comment for update tooling, and resolve and review a
|
|
new immutable SHA before upgrading an action. The credential-free security test
|
|
rejects mutable tag or branch references.
|
|
|
|
## Secrets and protected environments
|
|
|
|
Explicit Grok subscription campaigns may select `GROK_AUTH_JSON` from the same
|
|
protected paid environment. Deliver it only to that subscription profile's paid
|
|
test step. Prefer a dedicated test-account login and refresh it before a campaign.
|
|
The fixture stores only the selected login in its disposable company home, rejects
|
|
ambient/redirected homes, and removes the login during teardown. Token fragments
|
|
and account identifiers inside its JSON join the evidence redaction set. The
|
|
subscription suite remains manual-only and never falls back to `XAI_API_KEY`.
|
|
|
|
Create `runner-e2e-paid`, restrict deployments to the default branch, and put
|
|
only provider credentials needed by the selected paid suites, including
|
|
`OPENAI_API_KEY`, `ANTHROPIC_API_KEY`, `OPENROUTER_API_KEY`, `XAI_API_KEY`,
|
|
`COPILOT_GITHUB_TOKEN` and `DAYTONA_API_KEY` in it. Copilot is passed only to
|
|
cells selecting `credentialName: COPILOT_GITHUB_TOKEN`, in the paid Product or
|
|
direct-protocol execution step. Never expose it to ordinary PR, build, catalog,
|
|
image or report jobs. `KIMI_MODEL_API_KEY` remains a local-only catalog name
|
|
for pending explicit profiles and is intentionally absent from the workflow
|
|
environment. Product E2E pending-profile admission remains gated separately.
|
|
Do not duplicate these credentials as repository- or
|
|
organization-level Actions secrets: environment scoping is the boundary that
|
|
prevents branch or pull-request jobs from requesting them. Require approval
|
|
from an account in `RUNNER_E2E_ALLOWED_ACTOR_IDS` for this environment and
|
|
disable administrator bypass. The authorize, target-lock, catalog, image,
|
|
report, history, and Pages jobs receive none of these secrets.
|
|
Each full-stack matrix cell receives only its selected profile credential, plus
|
|
Daytona only for Daytona cells. Secret-bearing and OIDC jobs use frozen installs
|
|
without a shared dependency cache.
|
|
On disposable GitHub Linux runners with Ubuntu's unprivileged-user-namespace
|
|
restriction, the authorized default-branch workflow provisions an AppArmor profile before provider credentials are exposed. The profile is attached to the exact
|
|
lockfile-pinned Codex executable. It grants `userns` so Codex can construct its
|
|
filesystem sandbox; it does not disable the kernel restriction or Codex's
|
|
workspace policy. Setup fails before invoking a model if the noninteractive
|
|
profile load fails. Target-controlled tests only probe the existing sandbox and never invoke sudo or load host policy. This host-only profile disappears with the ephemeral runner.
|
|
See [Ubuntu's namespace restriction documentation](https://documentation.ubuntu.com/security/security-features/privilege-restriction/apparmor/).
|
|
Local developer machines are never modified by this setup. Legacy Codex fixtures
|
|
disable optional shell-environment snapshots to avoid persisting credentials;
|
|
other suites retain the persisted-state scanner. The `first-task` suite omits
|
|
private home/workspace credential-persistence scanning so its evaluation focuses
|
|
on onboarding behavior. Artifact redaction and publication scanning remain in
|
|
force for every suite.
|
|
The Paperclip server process also receives none; the browser posts each value
|
|
once to the encrypted company secret API and agents/environments retain only
|
|
secret references.
|
|
|
|
The explicit managed first-task cell observes the wizard's two owned setup
|
|
responses only to correlate their exact lease IDs with same-company environment
|
|
records. Raw probe/setup responses, account references, opaque provider lease
|
|
identities and setup screenshots remain private. Public first-task evidence
|
|
continues through the existing projection. Missing or foreign lease identities
|
|
cannot acquire attribution or a zero-cost estimate; incomplete setup coverage
|
|
stays unavailable even if later task-run billing succeeds. Platform qualification
|
|
uses the existing permission-gated environment probe, without granting new
|
|
permissions or accepting fixture-authored qualification metadata.
|
|
|
|
The context-integrity catalog lists six pending Kimi/Grok cells for discovery:
|
|
two cases each across `legacy-kimi-cli`, `legacy-kimi-acp`, and `legacy-grok`.
|
|
The launcher and direct Playwright runner reject these profiles before loading
|
|
credentials. Pi has no qualified model source and is not cataloged. Admission
|
|
remains blocked until identity, authentication, skills, session, and billing
|
|
evidence is qualified together.
|
|
|
|
Create `runner-e2e-history`, also default-branch-only, for the OIDC publishing
|
|
job. It contains no long-lived AWS key. Required reviewers may be added when a
|
|
human approval on every nightly publication is acceptable; otherwise rely on
|
|
the actor gate, environment branch restriction, and protected default branch.
|
|
|
|
## Runner fleet isolation
|
|
|
|
When `RUNNER_E2E_AWS_ENABLED=true`, paid matrix cells, reusable runner builds,
|
|
and Daytona image builds use the exact RunsOn fleet
|
|
selector `runs-on/fleet=paperclip-public-pr-x64/env=public-ci`, matching the AWS
|
|
fleet selected by `pr-trusted.yml` only after its stable numeric-ID trust gate.
|
|
Any other or missing toggle value falls back to the GitHub-hosted
|
|
`ubuntu-latest` runner and its lower concurrency ceiling. The workflow chooses
|
|
between those two reviewed literal labels; it never evaluates a configured
|
|
runner label.
|
|
|
|
Daytona image builds depend on successful campaign authorization and keep the
|
|
existing GHCR publication and signing permissions. They receive no provider
|
|
credentials and do not enter the `runner-e2e-paid` environment.
|
|
|
|
Keep both runner targets restricted to `paperclipai/paperclip` and workflows
|
|
that independently authorize trusted source revisions. Never let a fork or
|
|
untrusted pull-request workflow target them. The RunsOn fleet must launch a
|
|
fresh ephemeral instance for every job, prohibit persistent runner reuse, and
|
|
disable interactive SSH/debug access unless a separate incident procedure
|
|
explicitly authorizes it.
|
|
|
|
Changing the runner does not widen who can authorize secret access. The paid
|
|
workflow still has only schedule and manual triggers, requires its trusted
|
|
definition to come from the protected default branch, requires allowlisted
|
|
stable actor IDs before checkout, and repeats that authorization as the first
|
|
matrix step. Provider credentials come only from the protected
|
|
`runner-e2e-paid` environment. The fleet selector is an exact workflow literal;
|
|
the only repository-controlled routing input is its boolean rollout switch, so
|
|
configuration cannot redirect a secret-bearing job to an arbitrary runner.
|
|
|
|
The optional target branch is code, not workflow authority. A CODEOWNER who
|
|
dispatches a target branch explicitly authorizes that branch's selected test
|
|
process to receive the cell's scoped provider credential. The workflow resolves
|
|
the target only inside the same repository, pins one SHA for the campaign, and
|
|
checks it out only after authorization. Target-controlled code cannot replace
|
|
the report sanitizer or the AWS history publisher. Fork refs and
|
|
target-controlled workflow definitions do not enter this path.
|
|
|
|
## AWS OIDC and S3
|
|
|
|
The AWS role trust policy should accept only GitHub's OIDC audience and the
|
|
publishing environment subject:
|
|
|
|
```json
|
|
{
|
|
"Version": "2012-10-17",
|
|
"Statement": [
|
|
{
|
|
"Effect": "Allow",
|
|
"Principal": {
|
|
"Federated": "arn:aws:iam::ACCOUNT_ID:oidc-provider/token.actions.githubusercontent.com"
|
|
},
|
|
"Action": "sts:AssumeRoleWithWebIdentity",
|
|
"Condition": {
|
|
"StringEquals": {
|
|
"token.actions.githubusercontent.com:aud": "sts.amazonaws.com",
|
|
"token.actions.githubusercontent.com:sub": "repo:paperclipai/paperclip:environment:runner-e2e-history"
|
|
}
|
|
}
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
Grant only List on the bucket prefix and Get/Put on its objects. Do not grant
|
|
Delete, ACL, bucket-policy, or wildcard-resource permissions:
|
|
|
|
```json
|
|
{
|
|
"Version": "2012-10-17",
|
|
"Statement": [
|
|
{
|
|
"Effect": "Allow",
|
|
"Action": "s3:ListBucket",
|
|
"Resource": "arn:aws:s3:::BUCKET",
|
|
"Condition": {
|
|
"StringLike": { "s3:prefix": ["runner-e2e", "runner-e2e/*"] }
|
|
}
|
|
},
|
|
{
|
|
"Effect": "Allow",
|
|
"Action": ["s3:GetObject", "s3:PutObject"],
|
|
"Resource": "arn:aws:s3:::BUCKET/runner-e2e/*"
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
Enable S3 versioning, default encryption, and Block Public Access. Disable
|
|
object ACLs. CloudFront receives read-only access through Origin Access Control;
|
|
the bucket itself stays private. Log S3 data writes and alert on attempts to
|
|
write outside the prefix or assume the role with a different subject.
|
|
|
|
Campaign prefixes are content-digested and immutable. The publisher refuses a
|
|
different digest at an existing campaign key. Only the compact history and
|
|
latest pointers are mutable, and S3 versioning makes those updates recoverable.
|
|
|
|
## Public evidence boundary
|
|
|
|
CloudFront and GitHub Pages are public. Fixture identifiers, timing, token
|
|
usage, costs, normalized results, and trusted runner PNG screenshots are
|
|
expected public data. Each
|
|
public screenshot must carry the explicit `public-runner-fixture` marker in
|
|
the normalized result. This includes a `failure.png` capture. Screenshot paths
|
|
must be safe PNG basenames and must be tied to the exact normalized execution
|
|
ID and attempt. The runner capture helper accepts only the exact issue route
|
|
for the live fixture that the harness created. Other issue routes, credential
|
|
pages, setup pages, and administration pages fail closed. The
|
|
CloudFront-backed S3 history also publishes one
|
|
synthetic campaign-summary PNG generated by trusted publisher code solely from
|
|
fixed catalog labels and sanitized numeric/status fields. Video, archives,
|
|
generated Playwright/blob/HTML report trees, SVG or other active content,
|
|
credentials, Paperclip homes, databases, workspaces, master keys,
|
|
raw/unredacted logs, unmarked images, and unallowlisted files are not public.
|
|
Per-attempt JSON snapshots, result copies, logs, Markdown, and text files stay
|
|
in the retained Actions artifact. Credential redaction does not remove hidden
|
|
reasoning or provider session identities, so a text extension never admits a
|
|
file to the public bundle. Graded results remain in `normalized-results.json`.
|
|
|
|
The normalized result may also contain the reviewed `taskChat` projection:
|
|
task titles/briefs, complete saved comments, visible question/approval copy and
|
|
recorded answers, agent display names, timestamps, and explicitly classified
|
|
native assistant progress. It is captured only from the disposable fixture
|
|
company and credential-redacted before retention. Only these presentation
|
|
fields are admitted by the closed result validator. Arbitrary interaction
|
|
payloads, tool arguments/results, provider/session identities, reasoning and
|
|
raw event envelopes are excluded. No per-attempt snapshot or log becomes public
|
|
as a consequence. Fixture authors must keep task conversation text public just
|
|
as they do the visible content of marked screenshots.
|
|
|
|
The packaged evidence uploaded as a 30-day GitHub Actions artifact has a
|
|
different, broader boundary. Text is exact-value and key-shape scanned and
|
|
redacted. PNG and WebM are raw-byte scanned; SVG is rejected during packaging
|
|
because it is active content. Raster pixels cannot be exhaustively
|
|
secret-scanned by bytes, so fixture authors must treat every marked capture as
|
|
public and must never extend the allowed task route to credentials, secrets,
|
|
private user data, or other non-public content. Adding or changing a marked
|
|
capture requires review of the visible page state. Videos remain
|
|
access-controlled.
|
|
|
|
Before permanent publication, the campaign publisher creates a separate S3
|
|
stage and retains only result PNGs with the explicit `public-runner-fixture`
|
|
marker under `evidence/`. This applies even to malformed JSON and renamed
|
|
process logs. Original packaged evidence and grades remain unchanged.
|
|
It then launches publisher-only Chromium with networking blocked to render one
|
|
`public-images/campaign-summary.png`. That fixed-path PNG is capped at 12 MiB
|
|
and its signature is validated. Per-attempt XML is excluded because browsers
|
|
can process XML/XSLT;
|
|
the only public XML is the root `junit.xml`, which the report aggregator
|
|
constructs from fixed markup and XML-escaped fields. Videos, archives,
|
|
raw/unallowlisted logs, SVG, undeclared images, generated reports, and symlinks
|
|
fail closed or are removed before the immutable manifest is calculated.
|
|
|
|
GitHub Pages is built from a second stage without the synthetic summary PNG but
|
|
with the same trusted-fixture screenshot allowlist. A leak detected by the
|
|
existing packager scan fails the cell and withholds the unsafe file.
|
|
|
|
Rotate the affected credential immediately if a secret-scanning failure or
|
|
unexpected public object is observed. Preserve the access-controlled Actions
|
|
artifact and S3 object versions for incident analysis; do not weaken scanning
|
|
to make a campaign publish.
|
|
|
|
`agent-chat-qualification.worker-crash-retry` is local-only and explicit-only.
|
|
Linux with Python pidfd support is required; unsupported hosts fail before signalling.
|
|
The fault target comes from the public run detail, must be native and running,
|
|
and must have an exact `--run-id` command argument. PID 1, the harness PID,
|
|
noninteger PIDs, remote profiles, and mismatched identities are refused. The
|
|
fixture workspace must be within the disposable instance root. The helper pins an owned pidfd, verifies the exact run argument and recorded
|
|
process start ticks again after evidence capture, and signals through that handle.
|
|
PID reuse cannot redirect the signal. This is one
|
|
specific process signal, never a name-based or machine-wide process kill.
|
|
The bounded fixture command is released even on failure; normal instance cleanup
|
|
still owns all disposable processes and files. No credentials enter the prompt,
|
|
fault metadata, or structured grading fixtures.
|
|
|
|
### Candidate ACP qualification
|
|
|
|
The explicit-only `extended-harnesses` launcher removes ambient candidate
|
|
admission, then authorizes only selected candidate/model pairs in its isolated
|
|
server process. The server never reads admission from agent configuration,
|
|
resolved credential bindings, or provider environment. Invalid, duplicate and
|
|
mismatched authorization fails closed. Verified packaging and normal company
|
|
and tool governance still apply. `CURSOR_AUTH_TOKEN` and
|
|
`COPILOT_GITHUB_TOKEN` enter via encrypted company secret references, and all
|
|
Cursor, Copilot, GitHub and GH environment variables are stripped from the
|
|
server environment. GitHub PAT shapes are included in retained-evidence scans.
|
|
Candidates have no automatic infrastructure retries; spending must be reconciled
|
|
before a deliberate repeat.
|
|
|
|
Copilot protection fixtures use production browser/public API permission and
|
|
cancellation paths. Their local one-shot socket accepts a nonce/PID only and owns
|
|
one fixed bounded child; it cannot select commands, arguments, or paths. The exact
|
|
native client command is supplied by the fixture, while production notices retain
|
|
only its SHA-256. The fixture keeps private process identities local, closes its
|
|
owned socket/child in cleanup, and never signals API-reported PIDs. Directory
|
|
watch loss makes the denial oracle incomplete; it must not become a no-effect pass. A run-only Stop without provider dispatch qualifies the denial's
|
|
completed-provider branch only when its exact canonical completion was actually
|
|
read and retained before Stop. A blocked unfinished task additionally requires
|
|
pre-Stop retained missing-result evidence and the exact company/issue/run recovery
|
|
binding. Neither exception qualifies definitely-active cancellation, permits
|
|
extra runs or mutations, or manufactures a receipt for a historical failure.
|
|
|
|
Pi Daytona controls bind process identity to the independent Linux observer's
|
|
PID, start ticks and boot ID within the exact admitted run/lease/sandbox. The
|
|
controller's `processStartedAt` annotations may change as launch metadata settles
|
|
and do not identify a remote process birth. Every remote snapshot and retirement
|
|
seal must retain the original birth identity and complete no-effect journal.
|
|
Local controls retain their separate public process-authority comparison.
|
|
|
|
Pi provider-death admission accepts the native bootstrap's `/proc/self/fd/3`
|
|
or `/proc/self/fd/7` wrapper launch only after binding that held descriptor and
|
|
the wrapper executable to the sealed snapshot Node inode. Exact guard and
|
|
entrypoint paths, closure hashes, Pi title, run/lease ancestry and fresh process
|
|
birth checks remain required. Other descriptor aliases, missing descriptors and
|
|
foreign inodes fail before any signal. Native Linux calibration exercises both
|
|
descriptor launches with synthetic owned processes and no provider credentials;
|
|
it does not qualify paid Pi behavior or change previous failed grades.
|
|
|
|
The private resource-admission marker and raw cleanup results control recovery-state retention independently of evidence packaging. A worker crash after admission keeps the owner-only recovery database; a confirmed pre-allocation bootstrap failure does not. Neither the marker nor the database enters published evidence.
|
|
|
|
## Task workspace fixture source
|
|
|
|
The explicit task-workspaces cells fetch the existing public octocat/Hello-World
|
|
repository through normal anonymous repository preparation. They do not clone the
|
|
Paperclip checkout, copy its Git credentials, create remote repositories or push.
|
|
The agent's synthetic commit remains in the disposable task workspace. Independent
|
|
Git reads validate that workspace's canonical path is inside the isolated instance
|
|
before examining history. The existing credential redactor, private evidence
|
|
packager and task-only screenshot allowlist remain authoritative. Each cell has a
|
|
single attempt, three requested turns and company/agent budget hard stops.
|
|
|
|
The explicit local case-handoff subscription cells accept `CODEX_AUTH_JSON`
|
|
only as a private subscription fixture input. The launcher redaction set includes its individual
|
|
JSON token values; the server process environment excludes the raw input.
|
|
Fixture setup validates a subscription-shaped payload and writes only a new
|
|
mode-0600 `auth.json` inside the isolated company's mode-0700 production Codex
|
|
home. It rejects redirected roots, API-key payloads and existing login files.
|
|
Teardown removes refreshed company login state along with the disposable
|
|
instance. Login bytes, account identity, provider sessions and raw native event
|
|
payloads are not workflow evidence. The separate API-key receipt cell accepts
|
|
`OPENAI_API_KEY` through the ordinary encrypted company-secret fixture and binds
|
|
only secret references to both provider key aliases. It neither stages nor
|
|
inherits an operator subscription login. The raw key is excluded from child
|
|
server environments and public attempt evidence by the existing credential
|
|
boundary; do not print it or store it in tracked configuration. The original
|
|
arithmetic cell remains subscription-only.
|
|
|
|
Upstream Codex also records its subscription account ID in `logs_N.sqlite`,
|
|
`state_N.sqlite` (thread ownership), and their WAL/SHM companions. The isolated-home persistence scan permits only that
|
|
identity value in those exact managed runtime log paths, inside an owner-only
|
|
temporary root. It still scans the entire file for every token and other secret;
|
|
an identity reused as a credential gets no exception. The private rollout scan
|
|
also recognizes only the exact `session_meta.payload.creator_account_id` ownership
|
|
field; all instruction/message content and all other fields retain the full scan.
|
|
Config, workspaces, unrelated files and all packaged/public evidence retain the
|
|
full redaction set. These private databases and rollouts are never copied into evidence and are
|
|
removed with the disposable instance. Historical attempts rejected by the older
|
|
persistence policy remain failed.
|
|
|
|
Case screenshots use the exact case ID/identifier returned by that fixture's
|
|
public kickoff, in addition to its ordinary task route. Other cases, setup,
|
|
settings and external hosts remain outside the public screenshot allowlist.
|
|
|
|
Receipt smoke uses a fresh isolated company with 100-cent company/agent budgets,
|
|
90-second work-run timeouts, low reasoning effort and daily task-run caps of
|
|
one/two/one for triage/builder/verifier. Its work contract is exactly four task
|
|
runs and one five-minute attempt. Production lifecycle hello probes occur
|
|
outside heartbeat counts and budget accounting; up to three initial probes are
|
|
expected, and their detailed tokens and cost are unavailable. The flow serializes
|
|
readiness, waits at most 45 seconds per agent, fails immediately on lifecycle
|
|
error and pauses agents on failure to prevent routine 60-second setup retries.
|
|
A timeout does not immediately cancel an in-flight probe. The cell has no absolute
|
|
provider inference cap, and its work-run usage report excludes setup probes;
|
|
unknown setup usage is not free. The original arithmetic cell keeps its existing settings.
|
|
Role routing prompts are appended through the ordinary instruction API after
|
|
capturing the production-default bundle. Receipt/review bodies are synthetic
|
|
fixture data. Only allowlisted document values, attributed revisions, configured
|
|
limits, case/task state and correlated receipt checks enter workflow evidence.
|
|
Two passive seed cases support browser list assertions; screenshots remain on
|
|
the exact primary case/task routes and document dialogs preserve that case URL.
|
|
The public screenshot allowlist is unchanged.
|
|
|
|
## Eval feedback capture
|
|
|
|
`snapshots/agent-feedback.json` retains company-wide complaint/suggestion bodies
|
|
and attributed invocation outcomes in the access-controlled Actions artifact.
|
|
It passes the existing credential scanner and is excluded from public history
|
|
like other snapshots. Normalized results and campaign attempt receipts contain
|
|
only numeric counts, closed collection statuses, and SHA-256 fingerprints for
|
|
review grouping. Public reports never copy feedback bodies, previews, tool
|
|
arguments, or free-form collection errors. Collecting feedback performs no new
|
|
model call and does not forward it to an external service.
|
|
|
|
Feedback capture retains at most 1,000 full entries and 8 MiB of serialized
|
|
entries/invocations per attempt. Event inspection stops at 10,000 events or
|
|
16 MiB of serialized event data. Limits produce partial collection and a closed
|
|
`evidence_limit_reached` diagnostic; omitted evidence is never reported as absent.
|
|
Checkpoints are considered every ten details, at page boundaries, and at stage
|
|
completion; geometric data growth bounds repeated writes. Reads stop before the
|
|
overall deadline, reserving up to five seconds (20% of shorter windows) to persist
|
|
the collected prefix. Persistence shares the overall collection deadline and
|
|
receives an abort signal. The fixture writes an abortable temporary
|
|
snapshot before replacing the last complete checkpoint, so a stalled write does
|
|
not overwrite earlier evidence with a partially written JSON file.
|
|
Review counts and fingerprints advance only after a checkpoint succeeds. A later
|
|
write failure or expired deadline retains the last saved bodies and marks coverage
|
|
incomplete.
|
|
|
|
Braintrust export requires an explicit eval project UUID. Native capture includes
|
|
prompts, responses, and tool content only after that opt-in configures the isolated
|
|
company's observability destination. The ingestion credential crosses the public API via
|
|
Node fetch, outside Playwright tracing, and is included in launcher evidence
|
|
redaction. Orchestration spans contain identifiers, phase timing, outcome, and
|
|
feedback counts; they never contain provider credentials or feedback bodies.
|
|
|
|
With a bounded operations manifest, the ingestion credential is an expiring
|
|
per-attempt relay token. The organization-wide Braintrust key stays in the
|
|
controller. Only authenticated POSTs to the relay's trace/log ingest paths are
|
|
allowed, with a fixed HTTPS upstream and redirects disabled. Header and payload
|
|
`braintrust.parent` values must reference the selected project. Duplicate protobuf
|
|
singular/oneof fields are refused, and JSON is canonicalized to remove duplicate
|
|
key ambiguity. The token cannot call model, read, delete, or other API endpoints;
|
|
it can still write records within the selected project until its finite request,
|
|
byte or time allowance is exhausted. It is not an attempt-level row permission.
|
|
|
|
The worker environment removes upstream provider/Braintrust credentials before
|
|
inserting the model and OTLP relay tokens. Ambient relay URLs are discarded, and
|
|
the fixture server receives the selected endpoint through company settings.
|
|
Both tokens participate in evidence redaction. Private OTLP receipts retain
|
|
metadata only, and persistence errors stop further admission. The relay closes
|
|
with the model gateway before controller finalization. The controller's direct
|
|
finalization export and tracing without an operations manifest retain the
|
|
existing direct credential path. Remote relay publication is not enabled here.
|
|
|
|
The bounded operations manifest is credential-free and private. Its parent-owned
|
|
loopback gateway uses an ephemeral per-attempt token. Upstream credentials stay
|
|
in the launcher, are included in secret scans, and are removed from the child
|
|
provider environment. Only the selected Responses or Messages endpoint is
|
|
forwarded to a fixed provider or Braintrust HTTPS origin; request headers do not
|
|
select arbitrary destinations. Gateway response caching and fallback are refused.
|
|
Request journal and usage receipts contain no prompt/response bodies or keys.
|
|
The manifest, journal, and receipts are not public report projections.
|
|
|
|
`boundedEvalPayload` is the shared, credential-free request validator and
|
|
normalizer. Qualification callers must apply it before recording budget-denial
|
|
proof. The forwarding path applies the same policy before a ledger reservation.
|
|
OpenAI tools may use one namespace level around local function or custom tools.
|
|
Function and custom leaves require nonblank string names.
|
|
Namespace wrappers contain only `type`, `name`, optional `description`, and
|
|
`tools`. Nested namespaces, hosted tools, and tool lists attached to leaves fail
|
|
closed. The request may contain at most 1,024 tool definitions, counting namespace
|
|
wrappers and their children. Anthropic tool policy stays separate. Output limits,
|
|
billing-mode restrictions, and multimodal exclusions apply in both paths.
|
|
|
|
## Configured repository and conversion proof
|
|
|
|
The repository proof flow seeds only the exact `workspace` child of its resolved
|
|
fixture-owned temporary directory. It initializes that disposable Git checkout
|
|
with a fresh random reference. It never modifies a contributor checkout. Provider
|
|
credentials remain encrypted fixture secret references. Retention evidence keeps
|
|
a digest of allowlisted configuration fields rather than raw environment values.
|
|
The public API performs legacy conversion; no database mutation or private
|
|
Runner hook performs it. Only synthetic source bytes and proof JSON enter the
|
|
existing private attempt evidence and registered-artifact verification pipeline.
|
|
A failed attempt remains retained. These development checks are not staging or
|
|
Slack qualification, and they do not publish trusted archives or credentials.
|