Issue 215 Shared Cache and Access Research
Issue 215 Shared Cache and Access Research
Scope and conclusion
The user extended the active requirements grill to persistent caches and Turbo reuse across branches, worktrees, PRs and CI, with correct credentials/access. They explicitly rejected hard performance acceptance limits.
This report is readonly evidence for the active grill. It does not approve cache implementation, credential mutation or pipeline changes. Source revision: 1ee7f8b72f8fe116ad74aa15923238d3b985c751. Provider observations were made on 2026-09-16.
Two independent lanes inspected current cache identities/entrypoints and current workflow trust/accepted policy. The coordinator inspected provider metadata, local credential presence, the pinned upstream OIDC action, and sanitized CI log summaries. No repository scripts, builds, tests, new workflow runs or deployment operations were executed for the audit. Secret values were neither requested nor displayed.
Audit verdict: CONDITIONALLY SAFE.
The inspected cache path admits trusted repository code; no confirmed cache-poisoning finding was established. Actual provider token scopes/OIDC policy breadth and runner isolation remain unverified. Existing CI caching works in observed runs, but local-to-CI artifact reuse is not yet proven.
Current policy authority
project/specs/cli/ci-verification-and-publication/SPEC.md:26explicitly supersedes earlier conflicting cache-separation requirements.- Its AC-018 at line 102 permits trusted internal PRs, main and release verification to read/write one signed namespace when deterministic identities match.
- Therefore older separate development/protected-cache namespace prescriptions are historical, not current authority for deterministic verification.
- Current fork behavior is a later amendment:
ci-verification-and-publication/IMPLEMENTATION-NOTES.md:199anddocs/runbooks/ci-verification-and-publication.md:38record same-repository PR support only. Fork verification is unsupported, not a restore-only lane. cache-release-diff-classification/SPEC.md:87-99permits portable cross-platform reuse when relevant source, fixtures, dependencies, controlled environment and runtime identity match. Host-dependent tasks require capability identity; genuinely live witnesses remain fresh.- Publication mutations and publication credentials remain distinct from reusable verification. Cache reuse is not proof that an external publication occurred.
One research lane initially cited the older development/protected split. The newer explicit supersession above resolves that conflict.
Observed authentication and access
| Context | Observation | Limit |
|---|---|---|
| GitHub trusted PR/main CI | Workflow has id-token: write, calls the signed-cache action and uses the development signing secret. | Does not establish the provider's complete allowed subject/audience set. |
| OIDC access token | Pinned Vercel action exchanges GitHub OIDC for a short-lived Turbo access token, masks both, exports TURBO_TOKEN and TURBO_TEAM. | It is not using the legacy static development Turbo token secret in this action path. |
| Artifact signing | turbo.json:3-4 enables signatures; cache policy exports TURBO_REMOTE_CACHE_SIGNATURE_KEY. | Local/CI signing-key consistency has not been checked through a real shared artifact. |
| Repository settings | TURBO_TEAM is configured as dev-punks; the required development signing secret exists. | Names/existence prove configuration presence, not value validity in all contexts. |
| Local session | No Turbo token/team/signing-key environment variables were set; known local Turbo login/link JSON locations were absent. | A different shell, host or credential manager could have configuration. This session has not authenticated a local remote-cache read/write. |
| Fork execution | GitHub API reports fork workflows disabled, write-token forwarding false, secrets/variables forwarding false. | Enabling forks would require a separate accepted trust-policy change. |
| Release builder | Current release subprocess boundary removes Turbo/provider/OIDC credentials and builds historical worktrees directly. | Accepted shared release-verification caching is not proof this direct builder uses Turbo. |
Sources:
.github/workflows/behavior-contract.yml:35-69..github/actions/turbo-cache/action.yml:24-34..github/actions/turbo-cache/cache-trust-policy.mjs:58-64.- Pinned upstream OIDC action and its README.
- GitHub repository secrets/variables metadata APIs, permissions APIs and environment metadata.
apps/cli/scripts/release-execution-boundary.mjs:3-24;release-publication.mjs:535-566.
Other observed metadata:
- Legacy
TURBO_DEVELOPMENT_TOKEN,TURBO_DEVELOPMENT_TEAM,TURBO_PROTECTED_TOKEN,TURBO_PROTECTED_TEAMandTURBO_PROTECTED_SIGNATURE_KEYsecrets also exist. Existence alone is not a reason to rotate, delete or wire them into the current OIDC path. - Default GitHub token permission is read; Actions cannot approve PR reviews.
- Repository is private with forking allowed, but fork Actions disabled.
- Global action policy permits all actions and does not enforce SHA pinning; the cache-related actions inspected here are individually pinned.
- Provider environment metadata shows no environment protection rules on the listed production environments. This alone is not a confirmed cache vulnerability; current job predicates and credential boundaries still require separate analysis.
Actual CI evidence
| Run | Cache action | Remote enabled | Turbo task summary |
|---|---|---|---|
| Main push 35029793398 | Success | Yes | 16/16 tasks successful; 15/16 cached |
| Internal PR 35024149127 | Success | Yes | 16/16 tasks successful; 0/16 cached |
Job IDs: 104585359583 and 104570304966. Log processing emitted only bounded summaries, never credential values. No HTTP 401/403 status errors were found by the status-specific extractor. An initial broad numeric search matched digits inside the pinned action SHA; those matches were rejected as false positives.
These runs prove successful OIDC setup and some effective cache reuse in CI. They do not distinguish whether the 15 main hits came from the GitHub Actions-restored local archive or the remote store, prove remote write permission independently, or prove local-to-CI/cross-platform reuse.
Reuse and correctness findings
Global environment differences partition local and CI tasks
turbo.json:15 hashes CI, NODE_ENV and TZ globally. Unset local CI versus CI=true produces different hashes. CLI build/typecheck additionally hash locale values.
This can prevent desired local/CI hits. Do not simply drop these inputs: first classify whether each changes task output, then normalize controlled values or retain the meaningful distinction.
Proposed change for later implementation: establish a consistent task execution context across eligible local/CI entrypoints and narrow task-specific environment inputs using evidence.
Declared runtime/capability variables lack current producers
Tasks reference HI_RUNTIME_* and HI_HOST_CAPABILITY_*, but inspected current root commands and scripts/behavior-contract/run-ci-verification.mjs:116-135 invoke Turbo directly. Searches of current .mjs scripts found no producers. Historical verification/profile wrappers described in older notes are absent from current source.
An unset identity variable does not attest an actual runtime. This is a cache correctness concern, not proof that a specific bad hit occurred.
Proposed change: generate and validate real runtime/capability identities before hashing, using portable keys only where behavior/output equivalence is established.
Branch identity is not inherently a task-cache partition
The GitHub Actions archive key includes OS, lock/config digest and Git SHA, but its restore prefix omits SHA (cache-trust-policy.mjs:24-30). This outer archive key is distinct from the inner Turbo task hashes. Removing SHA is not automatically the fix.
Separate worktrees normally have separate local .turbo/cache directories; no shared local root was configured in inspected normal entrypoints. Remote reuse can bridge them when authenticated and identities match.
Some inputs and pass-through values need classification
Root lock/package/config/patch inputs invalidate many tasks. Some are necessary; current breadth alone does not prove unnecessary work.
HOME, temp/config paths and test runtime/seed overrides pass through some tasks without hashing, while related runtime identities may be unset. Such variables are safe only when their effects are controlled or represented by another complete identity.
scripts/validate-cutover-repeat.mjs:654-662 deliberately uses a run-specific cache directory and TURBO_FORCE=true for a fresh witness. User-wide reuse should preserve genuinely fresh checks rather than treating every miss as a defect.
Credentials and cached output boundaries
Turbo stores task outputs and logs. Some application build tasks receive sensitive application environment variables (turbo.json:54-64); the declared artifacts include dist and Next output. This identifies exposure surfaces, not a demonstrated leak.
Publication credentials must remain outside cache producers. Suppressing displayed logs is not redaction. Provider credentials should reach cache transport/setup, not arbitrary unnecessary child processes.
Proposed verification: inspect declared cache artifact/log contents, credential forwarding and task environments without emitting values; prove cache transport credentials are correctly scoped and do not become reusable artifacts.
Cache formats and system boundaries
Turbo currently caches repository task results and declared outputs.
The updater independently builds a temporary Validation Candidate, installs dependencies, patches Effect and executes lint through apps/cli/src/runtime/scripts.ts. It has no Turbo task integration. Its new Prepared Installation and Validation Result caches need separate input identity, mutation and containment handling.
Remote Turbo setup therefore does not automatically cache ordinary hi update execution in a consumer repository. The active grill must resolve whether remote sharing is also required for these internal updater entries, and whether any resulting remote capability is optional for consumers without Turbo/authentication.
Dynamic executable configuration is another eligibility boundary: current configs can import code and read ambient files/environment; no complete input tracing exists. Where complete relevant inputs cannot be controlled or identified, reuse cannot be assumed merely because package.json and lockfile hashes match.
Trust map
Authenticated local developers
Trusted internal PR / main verification
│ matching deterministic task identity + valid signing authority
▼
Signed Turbo remote store
▲
eligible verification consumers
Publication: external mutation still executes; credentials isolated
Fork PRs: currently unsupported and receive no trusted credentials
hi update internal caches: separate integration decision pendingAudit limitations and recommended proof
No confirmed Critical/High security remediation is selected. The verdict remains conditional because these facts are not fully observable from the repository:
- Vercel OIDC policy's complete repository/workflow/branch/audience restrictions and issued token permissions.
- Provider team membership and allowed cache writers/readers.
- Blacksmith runner isolation and workspace/credential cleanup.
- Local credential readiness and matching signing authority.
- Artifact-specific authenticated remote upload/download and local↔CI restoration across compatible contexts.
Later delivery should prove a shared artifact produced in one eligible context is restored in another with the expected files/logs and signature, then prove changes to relevant inputs miss. This is correctness/access evidence, not a hard performance-time gate.
Remaining user decisions are the updater/Turbo remote integration boundary and the policy for validation whose full dynamic inputs cannot be represented. Existing trusted-sharing, fork and publication policies do not need to be reopened.