Harness Intelligence Wiki
Research

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:26 explicitly 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:199 and docs/runbooks/ci-verification-and-publication.md:38 record same-repository PR support only. Fork verification is unsupported, not a restore-only lane.
  • cache-release-diff-classification/SPEC.md:87-99 permits 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

ContextObservationLimit
GitHub trusted PR/main CIWorkflow 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 tokenPinned 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 signingturbo.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 settingsTURBO_TEAM is configured as dev-punks; the required development signing secret exists.Names/existence prove configuration presence, not value validity in all contexts.
Local sessionNo 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 executionGitHub API reports fork workflows disabled, write-token forwarding false, secrets/variables forwarding false.Enabling forks would require a separate accepted trust-policy change.
Release builderCurrent 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_TEAM and TURBO_PROTECTED_SIGNATURE_KEY secrets 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

RunCache actionRemote enabledTurbo task summary
Main push 35029793398SuccessYes16/16 tasks successful; 15/16 cached
Internal PR 35024149127SuccessYes16/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 pending

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.

On this page