IMPORTANT: Developer documentation for the current development branch. This content is unreleased, may change without notice, and must not be treated as Buildish release documentation.

Threat Model

Threat model for Buildish Mammoth Cache for Gradle and Maven.

Threat Model - Buildish Mammoth Cache

1. Header

Project: Buildish Mammoth Cache for Gradle and Maven.

Version binding: This draft is versioned alongside the unreleased development source and package version 0.0.0-development. A report should be assessed against the model in the affected source revision, not against a later revision. (documented)

Date: 2026-06-05.

Author: The Buildish Authors. (documented)

Reporting cross-reference: Suspected violations of §8 should be reported through SECURITY.md to security@buildish.org. This draft informs triage, but the security team makes the final disposition. (documented)

Status: Draft, awaiting maintainer review as of 2026-06-05. (inferred)

Provenance legend: (documented) means the claim is present in repository docs, action metadata, tests, or source comments; (maintainer) means confirmed by a maintainer; (inferred) means derived from source behavior or project shape and should be confirmed before publication.

Draft confidence: Rough count: 63 documented / 0 maintainer / 38 inferred. The largest inferred areas are operational assumptions, negative side-effect claims, and exact resource-exhaustion thresholds.

Buildish Mammoth Cache is a Node.js GitHub Action that manages Gradle and Maven build-tool cache directories in CI. It restores and saves partitioned base caches, supports distributed worker/aggregator delta exchange across parallel jobs, and for Gradle can validate and provision missing gradle-wrapper.jar files before the build runs. (documented)

2. Scope and Intended Use

Primary intended use cases:

  • Running as buildish-tooling/buildish-mammoth-cache/actions/github/gradle in GitHub Actions jobs for Gradle builds. (documented)
  • Running as buildish-tooling/buildish-mammoth-cache/actions/github/maven in GitHub Actions jobs for Maven builds. (documented)
  • Restoring, pruning, manifesting, saving, and reporting on selected Gradle user home or Maven local repository partitions. (documented)
  • Exchanging worker cache deltas through GitHub workflow artifacts and merging them in an aggregator job. (documented)
  • Provisioning Gradle wrapper JARs from canonical Gradle sources, with checksum and detached-signature verification. (documented)

Deployment context: a Node 24 GitHub Action running inside a GitHub-hosted or self-hosted Actions runner. Codeberg/Forgejo and GitLab CI support is planned but not part of the current in-scope deployment. (documented)

Expected callers and roles:

Role Trust level In model? Notes
Workflow operator Trusted for the repository/workflow Yes Chooses action inputs, permissions, needs, job topology, and cache partition policy. (inferred)
Repository contributor on trusted branch Trusted by repository policy Yes Can influence workspace files, build outputs, wrapper files, and build-tool cache contents. (inferred)
Pull-request contributor from fork Untrusted Yes May control workspace content and build outputs, but default read-only behavior should prevent cache mutation on PR events. (documented)
GitHub Actions platform/cache/artifact services Trusted service dependency Yes Supplies state, cache, artifact, event metadata, and token-scoped APIs. (inferred)
Gradle distribution and Gradle GitHub source hosts Authenticated upstream dependency Yes for wrapper provisioning Wrapper bytes and metadata are expected from canonical HTTPS hosts and verified before installation. (documented)
Maven/Gradle build process invoked by the workflow Outside this component’s control Partially Its outputs can become cache inputs; its execution behavior is not provided by this action. (inferred)

Component-family table:

Family Representative entry point External touchpoints In model?
GitHub Gradle action main/post actions/github/gradle/action.yml, src/ci/github/gradle/main.ts, src/ci/github/gradle/post.ts GitHub inputs/state/outputs/logs/summaries, workspace, cache API, artifact API, network, gpg, java Yes
GitHub Maven action main/post actions/github/maven/action.yml, src/ci/github/maven/main.ts, src/ci/github/maven/post.ts GitHub inputs/state/outputs/logs/summaries, workspace, cache API, artifact API, java Yes
Shared cache model and base cache src/cache/model.ts, src/cache/service.ts, src/cache/manifest.ts Filesystem, GitHub cache backend Yes
Distributed delta protocol src/delta/service.ts, src/delta/apply.ts, src/delta/apply-execution.ts Filesystem, temporary directories, GitHub artifact backend Yes
Gradle wrapper validation/provisioning src/build-tool/gradle/wrapper/* Workspace, HTTPS fetches, temporary files, GnuPG subprocess Yes
Maven adapter src/build-tool/maven/* Filesystem under Maven local repository Yes
GitHub platform adapter src/ci/github/* GitHub env vars, event payload, toolkit APIs, auth headers Yes
Job summary and logs src/util/html.ts, phase summary builders GitHub job summary, logs Yes
Tests, smoke fixtures, benchmarks test/, scripts/smoke-test.mjs, test/bench/* Local developer machine, test fixtures No
Release and legal tooling buildish-release-tooling/, scripts/release-legal*, scripts/rat-check.mjs Local/release environment No
Documentation/site content docs/, site/ Static documentation build No, except when documenting expected security contract
Vendored package tree node_modules/ Build/test dependency content No

3. Out of Scope

The project does not attempt to provide:

  • A sandbox for arbitrary Gradle or Maven build logic. If a workflow executes untrusted build scripts with secrets or write permissions, that is outside this action’s boundary. (inferred)
  • A security boundary against a malicious workflow operator or someone who can modify workflow YAML on a trusted branch. (inferred)
  • Protection when the caller explicitly disables safety controls, for example Gradle wrapper validation or provenance verification modes. (documented)
  • A cryptographic guarantee that cached Maven or Gradle dependencies are legitimate upstream artifacts. The action transports cache files; dependency provenance remains the build tool’s and repository’s responsibility. (inferred)
  • A defense against a compromised GitHub Actions runner, compromised Node runtime, compromised gpg binary, compromised GitHub cache/artifact service, or compromised repository secrets. (inferred)
  • Cross-runner or cross-architecture delta reuse. Distributed delta reuse requires identical compatible cache-family inputs. (documented)
  • Support for planned non-GitHub CI providers until provider adapters and docs are implemented. (documented)
  • Security review of examples, tests, benchmarks, release tooling, generated bundles, or node_modules as part of this model. (inferred)

Repository code not covered by this model:

Path Policy
test/ Test fixtures and test harnesses are not runtime security surfaces. Findings here are ordinary test-quality issues unless they show an in-scope runtime bug. (inferred)
scripts/ Developer/release scripts are out of this runtime action model. (inferred)
buildish-release-tooling/ Release-process tooling is out of scope for this document. (inferred)
site/ and most docs/ content Static documentation is out of runtime scope except where it defines caller responsibilities. (inferred)
node_modules/ Dependency supply-chain assessment is out of scope for this document. (inferred)
dist/ when generated Generated action bundle should be reviewed through corresponding src/ files. (inferred)

4. Trust Boundaries and Data Flow

The primary boundary is the GitHub Action API surface: action inputs, GitHub environment variables, GitHub event metadata, workspace files, cache backend content, and artifact backend content are treated as external inputs until validated by the action. (documented)

Data flow:

  1. The GitHub entrypoint reads action inputs and selected runner environment values, optionally overlays a workspace-relative config file, and normalizes the merged configuration. (documented)
  2. Bootstrap creates a provider-neutral CI context, derives a cache model, detects Java, and constructs tool-specific cache partitions. (documented)
  3. Gradle bootstrap validates target wrapper property files; when needed it downloads wrapper checksum/signature/JAR data from canonical HTTPS hosts, verifies checksum and signature, and installs the JAR atomically. (documented)
  4. Prepare restores the base cache via the CI cache backend, optionally prunes managed files, applies dependent worker deltas for aggregators, captures the pre-build manifest, and stores post-action state. (documented)
  5. The workflow’s build steps run outside this action and may add, modify, or delete files inside the managed cache partitions. (inferred)
  6. Finalize reads persisted state, runs timestamp cache garbage collection by default for standalone/aggregator jobs, captures the post-build manifest, computes a delta, saves a base cache for standalone/aggregator jobs or uploads a delta artifact for worker jobs, cleans consumed artifacts, and publishes logs/summaries. (documented)

Reachability preconditions per component:

Component family Finding matters only if reachable through
Shared config normalization Action inputs, config-file contents, or GitHub event/env overrides accepted by read*ActionInputs and normalize*ActionConfig. (documented)
Cache family/model generation Validated config plus CI context values and Java detection output. (documented)
Manifest capture Files reachable under active partition include globs and not excluded by partition or hard-exclude rules. (documented)
Timestamp cache GC Files reachable under active partition include globs, not excluded by partition or hard-exclude rules, and older than the configured timestamp cutoff. (documented)
Base cache restore/save Paths emitted by createBaseCachePaths and action-owned family, lineage, and generation keys from the cache model. (documented)
Delta package staging/upload Post-build files in managed partitions that differ from the pre-build manifest. (documented)
Delta package download/apply Artifact packages selected by configured dependent-jobs, current run identity, and artifact name prefix. (documented)
Gradle wrapper static validation Targeted gradle-wrapper.properties files under base-directory. (documented)
Gradle wrapper network download Canonical services.gradle.org, raw.githubusercontent.com, and, when token-scoped, GitHub API host requests derived from a validated distribution URL. (documented)
GnuPG signature verification Wrapper payload/signature bytes and pinned trusted keys passed to the GPG subprocess with stripped environment. (documented)
Job summaries/logs Dynamic strings emitted by bootstrap/prepare/finalize reporting sinks. (documented)

5. Assumptions About the Environment

  • Runtime is Node.js 24, as declared by the action metadata and package engine range. (documented)
  • The active CI platform is GitHub Actions with functioning @actions/core, @actions/cache, and @actions/artifact behavior. (documented)
  • Java is installed or discoverable when cache families should include a real Java major version; otherwise the family renders Java as 0. (documented)
  • GnuPG is available for Gradle wrapper provenance verification unless that verification mode is not used. (documented)
  • GITHUB_WORKSPACE, RUNNER_TEMP, GITHUB_*, RUNNER_OS, and RUNNER_ARCH are supplied honestly by the runner or overridden by documented action inputs. (inferred)
  • The runner filesystem enforces normal process permissions, symlink behavior, O_EXCL, rename, lstat, realpath, and temporary-directory semantics. (inferred)
  • Runner filesystem access-time behavior is platform-specific and may be stale, deferred, coalesced, or disabled; timestamp cache GC treats timestamps as best-effort freshness signals, not precise usage proof. (documented)
  • The action runs as a single Node process per action invocation; separate parallel jobs communicate only through cache/artifact backends, not shared memory. (inferred)
  • Cache and same-run artifact service access uses GitHub-provided, job-scoped Actions runtime credentials. Declared GITHUB_TOKEN permissions separately govern authenticated GitHub API calls and explicit cross-run/repository artifact lookup. (documented)

Concurrency assumptions:

  • Within one job, prepare/finalize state is paired through GitHub post-action state and a single-run prepare guard. (documented)
  • Distributed workers may run concurrently, but only aggregators save merged base cache state; workers upload deltas instead of saving the base cache. (documented)
  • Duplicate dependent delta paths are rejected by default; operators can opt into newest-mtime resolution with allow-duplicate-dependent-delta-paths=true. (documented)

Memory, CPU, and time assumptions:

  • Wrapper downloads have retry caps, per-request timeouts, and response-size caps. (documented)
  • Manifest capture is proportional to the number and size of files in managed cache partitions; timestamp GC uses metadata-only scanning proportional to file count. There is no documented global maximum cache size or file count. (inferred)
  • Delta package processing is proportional to downloaded artifact contents after schema/path/hash validation; exact global size and count limits are delegated to the artifact backend and filesystem capacity. (inferred)

What the project does not do to its host:

Side effect Claim
Opens listening sockets No listening sockets are created. (inferred)
Makes network requests Yes, for Gradle wrapper metadata/JAR downloads and GitHub toolkit cache/artifact/API operations. (documented)
Spawns child processes Yes, java -version fallback and GnuPG verification. (documented)
Reads environment variables Yes, selected GitHub, runner, Java, Maven, Gradle, token, and GPG-related variables. (documented)
Writes to workspace Yes, Gradle wrapper JAR and metadata files may be written next to targeted wrapper properties files. (documented)
Writes to build-tool cache roots Yes, cache restore, timestamp GC, prune-managed cleanup, delta apply, and build hooks may alter managed cache roots. (documented)
Writes to temporary directories Yes, manifests, delta packages, downloads, and GPG homes use temporary locations. (documented)
Writes to logs/summaries/outputs/state Yes, through GitHub Actions runtime APIs. (documented)
Installs signal handlers None identified in source. (inferred)
Mutates process-wide locale or FPU state None identified in source. (inferred)
Sends tokens to arbitrary hosts Auth headers are scoped by exact HTTPS hostname. (documented)

5a. Build-Time and Configuration Variants

Knob Default Security-relevant effect Maintainer stance
read-only true on pull-request events, otherwise false Prevents base cache save and worker delta upload; aggregators perform no artifact exchange when true. Production-supported default. (documented)
cache-enabled true When false, cache restore/save/delta behavior is disabled; wrapper provisioning may still run for Gradle. Supported. (documented)
job-mode standalone Controls base-cache writers and delta behavior. distributed-worker skips base cache save; distributed-aggregator consumes deltas and saves merged state. Supported. (documented)
allow-duplicate-dependent-delta-paths false When true, conflicting dependent deltas can resolve by modification time instead of failing. Supported but should be used only when expected and acceptable. (documented)
Cache family generation Action-owned Always separates build tool, schema, Java major, runner OS/architecture, and partition fingerprint; only the namespace prefix is configurable. Production-supported invariant. (documented)
cache-partitions Tool defaults Changes which cache files are managed; hard safety excludes remain enforced. Supported. (documented)
cache-gc-mode / cache-gc-older-than-days timestamp / 14 Deletes managed files before standalone/aggregator base-cache save when both effective access time and modification time are older than the cutoff; relies on best-effort filesystem timestamps. Supported default; operators can disable with off or increase the cutoff. (documented)
cleanup-enabled true Gates restore cleanup and timestamp garbage collection. Supported global cleanup switch. (documented)
restore-cleanup-mode none prune-managed deletes active managed paths after a hit and re-restores them for either build tool. Supported opt-in cleanup. (documented)
github-token / GITHUB_TOKEN unset input, env fallback Enables authenticated GitHub-host requests and artifact lookup. Token is not persisted in summaries/state by design. Supported. (documented)
BUILDISH_MAMMOTH_CACHE_GRADLE_GPG_COMMAND unset Windows-only absolute GPG override; validated before spawn. Ignored on non-Windows. Supported escape hatch. (documented)
maven-user-home $MAVEN_USER_HOME or ~/.m2 Can target an absolute Maven user-home path outside the workspace, including its repository and wrapper distribution state. Supported; operators must isolate custom roots across trust zones. (documented)
gradle-user-home Tool default Non-default values are rejected by the current version. Supported default only. (documented)

6. Assumptions About Inputs

Inputs accepted by the project:

  • GitHub action inputs declared in actions/github/gradle/action.yml and actions/github/maven/action.yml. (documented)
  • Optional workspace-relative YAML/JSON config files, except secrets such as github-token are rejected in config files. (documented)
  • GitHub Actions environment variables and event payload metadata. (documented)
  • Workspace files including wrapper properties, build-tool cache files, and build reports. (documented)
  • GitHub base cache entries and workflow artifact packages. (documented)
  • Network responses for Gradle wrapper checksum, signature, and JAR resources. (documented)
  • Output of java -version and GnuPG invocations. (documented)

Per-parameter trust table:

Entry point Parameter/input Attacker-controllable? Caller must enforce
Gradle/Maven action config-file Yes, by workflow operator; possibly by repository contributor if workflow points at repo file Only reference config files from trusted branches when write permissions or secrets are available. (inferred)
Gradle/Maven action base-directory Yes, by workflow operator Keep it repository-relative and pointed at intended project root. (documented)
Gradle/Maven action cache-enabled Yes, by workflow operator Set intentionally; disabling removes cache behavior but not all Gradle provisioning behavior. (inferred)
Gradle/Maven action read-only Yes, by workflow operator Do not override to false for untrusted pull-request code unless the cache poisoning risk is accepted. (documented)
Gradle/Maven action job-mode Yes, by workflow operator Match job topology; use workers for parallel producers and aggregator for the single writer. (documented)
Gradle/Maven action dependent-jobs Yes, by workflow operator Include only expected worker jobs and declare needs for them. (documented)
Gradle/Maven action allow-duplicate-dependent-delta-paths Yes, by workflow operator Leave false unless last-writer/newest-mtime behavior is acceptable. (documented)
Gradle/Maven action cache-key-prefix Yes, by workflow operator Choose prefixes that avoid unintended cross-project or cross-context reuse. (inferred)
Gradle/Maven action cache-partitions Yes, by workflow operator/config file Do not include paths containing secrets or machine-local volatile state; hard excludes are not a full secret scanner. (inferred)
Gradle/Maven action cache-gc-mode, cache-gc-older-than-days Yes, by workflow operator/config file Leave timestamp GC enabled for bounded cache growth; disable or increase cutoff only when old, rarely touched cache entries must be retained. (documented)
Gradle/Maven action cleanup-enabled, restore-cleanup-mode Yes, by workflow operator/config file Enable destructive cleanup only for managed roots whose contents can be recreated. (documented)
Gradle action wrapper-properties-files, wrapper-properties-glob, process-all-wrapper-files Yes, by workflow operator/config file Target only intended wrapper property files. (documented)
Gradle action github-token Trusted secret, provided by workflow/operator Scope token minimally and do not pass secrets to untrusted workflows. (inferred)
Maven action maven-user-home Yes, by workflow operator Avoid targeting directories that contain secrets or unrelated state; pass the .m2-equivalent root rather than its repository/ child. (documented)
GitHub context github-event-name, github-ref-name, github-default-branch, github-job-name Yes, by workflow operator In reusable workflows, pass caller context accurately; incorrect values can change read-only defaults, cache keys, and artifact identity. (documented)
Repository config read-only and other allowed config-file keys Yes, by repository contributors and pull-request authors Config may make read-only policy stricter but cannot lower the pull-request floor; write-enabling overrides must be direct workflow inputs. (documented)
GitHub env GITHUB_TOKEN Trusted runner secret Grant least privilege through workflow permissions. (inferred)
Workspace gradle-wrapper.properties Yes for repository contributors Treat changes to wrapper properties as code changes; run with strict validation. (documented)
Build cache root Managed cache files Yes, via build steps and restored cache/artifacts Do not store secrets in managed partitions. (documented)
Artifact backend Delta artifact metadata/payload Potentially attacker-controlled by jobs able to publish artifacts in the same run Restrict writable job topology and configure dependent-jobs accurately. (inferred)
Network Wrapper checksum/signature/JAR bodies Untrusted until validated Rely on HTTPS, checksum, and signature verification; do not disable them for untrusted code. (documented)

Size, shape, and rate assumptions:

  • Cache namespace prefixes and complete action-owned cache keys are length- and character-restricted. (documented)
  • Cache partition IDs, globs, artifact names, SHA-256 values, delta manifests, and metadata are schema-validated. (documented)
  • Wrapper checksum and signature responses are capped at 64 KiB each; wrapper JAR responses are capped at 10 MiB; wrapper requests default to 3 attempts and 30 seconds per attempt. (documented)
  • Delta discovery is capped at 1,000 current-run artifacts and 100 candidates per configured worker. Selected artifacts are capped at 2 GiB reported size, 4 GiB expanded size, and 200,000 manifest entries. Cache-root scanning remains subject to host/backend capacity. (documented)

7. Adversary Model

In-scope adversaries:

Actor Capabilities Goals
Untrusted pull-request author Can change repository files and build outputs for PR workflows; may influence wrapper properties, config files, and cache content observed during the run. Poison shared caches, exfiltrate secrets through logs/summaries/cache/artifacts, cause action failure, or install malicious wrapper bytes. (inferred)
Malicious or compromised worker job in same workflow run Can upload malformed or conflicting delta artifacts if it has artifact write permission and is referenced by the aggregator. Poison merged cache, overwrite files outside the cache root, exhaust resources, or hide conflict. (inferred)
Network attacker or compromised wrapper content endpoint Can return malicious, oversized, slow, or inconsistent wrapper metadata/JAR responses. Install malicious wrapper JAR or deny service. (inferred)
Malicious cache entry producer Can cause future restores to include unexpected cache files if a trusted workflow saved them under a reusable key. Poison dependencies, cause build nondeterminism, or leak cached secret-bearing files. (inferred)
Static analyzer, fuzzer, or human reporter Can report potential vulnerabilities. Needs deterministic triage routing against this model. (inferred)

Out-of-scope adversaries:

  • An attacker who controls the trusted branch workflow YAML or action inputs has already crossed the repository’s CI trust boundary. (inferred)
  • An attacker who controls the runner host, Node runtime, filesystem semantics, GPG binary, GitHub toolkit implementation, or GitHub cache/artifact service is outside this component’s enforceable boundary. (inferred)
  • An attacker who can read repository secrets through another workflow step is outside this action’s boundary. (inferred)
  • An attacker who requires maintainers to run non-default or discouraged configurations is handled as non-default-build or property-disclaimed triage, depending on maintainer stance. (inferred)

8. Security Properties the Project Provides

Property Conditions Violation symptom Severity tier Provenance
Workspace-relative config files cannot escape the workspace through direct .. traversal or symlink resolution. config-file is used through the normal Gradle/Maven config resolution path. Reads a config file outside the workspace. Security-critical if attacker-controlled config path can read sensitive files. (documented)
Repository config cannot lower the event-derived pull-request read-only floor. Normal config-file overlay and normalization are used. A checked-out read-only: false value enables cache or artifact writes on a PR. Security-critical in a privileged workflow that exposes write-capable credentials. (documented)
Read-only distributed execution performs no artifact exchange or aggregation. Effective read-only mode is true. A worker uploads, or an aggregator contacts the artifact backend or mutates merged state. Security-relevant write-policy violation. (documented)
User-supplied repository-relative paths for base directory and Gradle wrapper selection reject absolute/rooted/drive/UNC traversal forms. Normal action input normalization is used. Action reads or writes outside intended workspace through those inputs. Security-critical for untrusted PR/workspace contexts. (documented)
Gradle wrapper properties must be regular files inside the workspace and not symlinks. Gradle wrapper validation is enabled and target files are discovered normally. Symlink traversal or non-file wrapper target is accepted. Security-critical. (documented)
Gradle wrapper distribution URLs are pinned to canonical HTTPS services.gradle.org distribution URLs without credentials, port, query, or fragment. Gradle wrapper validation is not disabled. Wrapper plan derives from an attacker-controlled host or URL shape. Security-critical. (documented)
Missing Gradle wrapper JARs are installed only after SHA-256 and pinned detached-signature verification. Normal wrapper provisioning path, GPG available, and Gradle trusted key allowlist current. Malicious wrapper JAR is installed or accepted. Security-critical. (documented)
Wrapper network requests are bounded by timeout, retry, and response-size caps. Wrapper provisioning uses default or validated request settings. Unbounded hang or memory exhaustion from wrapper endpoints. Security-critical for availability if attacker can influence endpoints; otherwise reliability. (documented)
GitHub auth headers are scoped by exact HTTPS host and token values are not written to summaries/state/logs. GitHub platform adapter creates headers from github-token or GITHUB_TOKEN. Token sent to unrelated host or logged. Security-critical. (documented)
GPG child processes receive a minimal environment excluding CI tokens and application secrets. Signature verification uses buildMinimalChildEnv. Token-bearing parent environment inherited by GPG. Security-critical for confidentiality. (documented)
Cache families always include action-owned build tool, schema, Java, runner, and partition dimensions. Normal cache-model rendering is used. Cache lineage collision across structurally incompatible states. Security-critical if it enables cache poisoning across trust contexts; otherwise correctness. (documented)
Pull-request events default to read-only cache behavior. Event name resolves to pull_request or pull_request_target and caller does not override read-only. Untrusted PR saves base cache or uploads worker delta by default. Security-critical for cache integrity. (documented)
Distributed workers do not save shared base caches. job-mode=distributed-worker. Multiple parallel workers write conflicting base cache state. Correctness/availability; security-critical if it enables poisoned shared cache. (documented)
Dependent delta envelopes must match repository, workflow/run, producer attempt, source revision when available, ref, cache family/lineage, build tool, partition layout, and runner. Aggregator downloads worker deltas through normal path. Cross-context or incompatible delta is applied. Security-critical for cache integrity. (documented)
Delta discovery, selected artifact size, expanded package size, and manifest cardinality are bounded before cache mutation. Aggregator uses the normal v2 discovery and download path. Same-run artifact writers cause unbounded metadata/package processing. Availability boundary; it does not make trusted worker output safe. (documented)
Delta artifact metadata and manifests are schema-validated, sorted, use portable cache-root sentinel, and contain lowercase SHA-256 hashes. Delta package download path uses downloadAndVerifyDeltaArtifactPackage. Malformed package is accepted. Security-critical. (documented)
Delta payload file hashes are verified before apply. Downloaded delta packages include payload files and metadata. Tampered payload is applied. Security-critical. (documented)
Delta payload paths and cache-relative paths cannot escape package/root directories. validateNormalizedRelativePosixPath and resolveNormalizedPathWithinRoot are used before staging/apply. Path traversal writes, deletes, or reads outside package/cache root. Security-critical. (documented)
Symlinks are rejected during delta package walks and before cache file read/write in the delta pipeline. Normal manifest/delta package processing paths are used. Symlink target outside cache root is read or overwritten. Security-critical. (documented)
Writes of wrapper JARs, GPG temp files, guard files, and delta payloads are atomic or use exclusive creation where documented. Underlying filesystem honors wx/rename semantics. Partial writes or race-overwrite are observable. Security-critical for integrity where attacker can race; otherwise reliability. (documented)
Job-summary HTML table cells require escaped/safe HTML values at compile time, and Markdown summary values are escaped by helpers. Callers use escapeHtml, createHtmlLink, escapeSummaryText, or explicit safeHtml only for trusted literals. Branch names, job names, paths, or URLs inject HTML/Markdown into summary. Security-critical if it can spoof links or expose secrets; otherwise UI integrity. (documented)
Hard cache excludes omit known unsafe Gradle and Maven state such as lock files and selected secret/volatile metadata. Default hard excludes remain enforced. Restored cache contains known lock/secret/volatile classes that should never be transported. Security-critical for secret-bearing files; otherwise correctness/availability. (documented)

9. Security Properties the Project Does Not Provide

  • No sandboxing of Gradle, Maven, shell, test, plugin, or build-script execution. The action manages cache state around the build; it does not constrain the build. (inferred)
  • No guarantee that the contents of a restored dependency cache are semantically safe, up to date, license-compliant, or free of malicious artifacts. (inferred)
  • No end-to-end cryptographic authenticity for Maven/Gradle dependency artifacts beyond what Maven/Gradle/repository configuration already provides. (inferred)
  • No protection if operators grant write tokens/secrets to untrusted workflows or override read-only=false for untrusted PRs. (inferred)
  • No guarantee that custom cache partitions are secret-free. Hard excludes cover known built-in unsafe paths, not all possible project-specific secrets. (documented)
  • No constant-time, cryptographic, authentication, authorization, or access-control guarantees for its own APIs; it relies on GitHub Actions permissions and repository policy. (inferred)
  • No promise that concurrent writers make newest-prefix restore globally deterministic; current-ref and default-branch candidates remain compatibility-bounded. (documented)
  • No global resource-exhaustion guarantee for arbitrarily large cache roots or manifest capture. Traversal and hashing concurrency are bounded, but the documented delta-exchange caps cover artifact discovery and package validation rather than local cache-root cardinality. (inferred)
  • No protection against malicious or compromised GitHub cache/artifact services, runner hosts, gpg, Node.js, npm dependencies, or GitHub toolkit packages. (inferred)
  • No support guarantee for non-GitHub CI execution paths in the current model. (documented)

False-friend properties:

  • SHA-256 hashes in manifests and delta packages provide tamper detection for package payloads; they are not an authorization mechanism and do not prove that a worker job was trustworthy. (inferred)
  • Envelope identity checks limit accidental or same-run cross-context substitution; any job with artifact-write authority in the same trusted workflow run may still attempt to impersonate a configured worker, so workflow permissions and topology remain the authorization boundary. (inferred)
  • Cache-family partition fingerprints prevent accidental cache-layout collisions; they do not prove that cache contents are safe or produced by trusted code. (inferred)
  • read-only prevents this action from saving cache/delta state; it does not make the rest of the workflow read-only. (inferred)
  • Gradle wrapper verification authenticates the wrapper JAR provisioning path; it does not authenticate all Gradle distributions, plugins, dependencies, or build scripts. (documented)
  • Job summaries are escaped for display; they are not an audit log or tamper-proof record. (inferred)

Well-known attack classes left to the caller:

  • Cache poisoning through overly broad workflow permissions or namespace sharing must be controlled by workflow topology and branch/PR policy. (inferred)
  • Dependency confusion, malicious transitive dependencies, and compromised package repositories must be handled by Maven/Gradle dependency management and repository policy. (inferred)
  • Secret exfiltration by malicious build scripts must be prevented by workflow permission/secrets design, not by this cache action. (inferred)
  • Build cache poisoning at the build-tool semantic layer must be controlled through trusted build inputs and build-tool configuration. (inferred)

10. Downstream Responsibilities

Operators and workflow authors must:

  • Pin the action reference to a reviewed commit or release appropriate for their repository policy. (inferred)
  • Use least-privilege GitHub permissions; ordinary cache and same-run artifact operations do not require actions: write. Grant actions access only at an explicit GitHub API or cross-execution boundary that documents the need. (documented)
  • Do not expose write-capable cache operation to untrusted pull-request code; preserve default PR read-only behavior unless the risk is explicitly accepted. (documented)
  • Ensure reusable workflows pass the original caller’s event name, ref name, and default branch when needed, so read-only behavior and cache lineages reflect the caller. (documented)
  • Keep distributed worker job names unique and configure aggregator needs to include every worker. (documented)
  • Keep distributed workers and aggregators on compatible runner OS/architecture and identical cache-family/partition inputs. (documented)
  • Treat cache-partitions as a data classification decision; do not include directories that may contain secrets or host-local state. (inferred)
  • Leave Gradle wrapper validation/provenance in strict/verify mode for production use unless maintainers document an approved exception. (inferred)
  • Review changes to gradle-wrapper.properties, cache config files, and workflow YAML as security-relevant. (inferred)
  • Install Java and GnuPG on runners when using cache families and Gradle wrapper provenance verification. (documented)
  • Avoid sharing cache namespaces across repositories or trust zones on backends without repository isolation. Action-owned family dimensions prevent sharing across incompatible build tools, Java versions, runners, and partition layouts. (inferred)
  • For self-hosted runners, ensure temporary directories, Maven local repository paths, Gradle user homes, and workspace cleanup policies do not retain sensitive state across trust boundaries. (inferred)

11. Known Misuse Patterns

  • Setting read-only=false on pull-request workflows from forks, allowing untrusted code to write cache or delta state. (inferred)
  • Choosing a cache-key-prefix that intentionally overlaps unrelated trust domains on a backend without repository-level isolation. (inferred)
  • Adding custom cache partitions that include secret-bearing build output, credentials, local keystores, or machine-specific state. (inferred)
  • Enabling allow-duplicate-dependent-delta-paths=true to mask real worker conflicts instead of excluding volatile files or fixing partition boundaries. (documented)
  • Running a distributed aggregator without needs on all worker jobs, causing incomplete or stale delta consumption. (documented)
  • Reusing worker job names in a workflow run, causing artifact identity collisions. (documented)
  • Disabling Gradle wrapper validation/provenance in workflows that build untrusted repository content. (inferred)
  • Assuming wrapper JAR verification covers dependency/plugin provenance. (documented)
  • Pointing Maven local repository at a shared self-hosted-runner location that also serves jobs from less trusted repositories. (inferred)

11a. Known Non-Findings

Reported pattern Why it is not a bug under this model Suppression guidance
github-token or GITHUB_TOKEN is read from inputs/env. Token use is intentional; headers are scoped to exact HTTPS GitHub API host and diagnostics log presence only. See §8. Suppress if no token value is logged or sent to a non-matching host. (documented)
safeHtml() exists and can mark strings safe. It is an explicit opt-in for trusted literals/pre-sanitized fragments; normal dynamic content should use escaping helpers. Flag only call sites passing attacker-controlled raw values. (documented)
java -version may spawn a process. Java detection is intentional for cache keying and prefers $JAVA_HOME/release before PATH fallback. Suppress command-spawn findings unless untrusted input controls executable path. (documented)
gpg is spawned. GPG is required for detached-signature verification; environment is stripped and Windows override is validated. Suppress generic spawn findings unless command path validation or env stripping is bypassed. (documented)
Cache save is skipped for distributed-worker. This is intentional writer coordination, not a broken save path. Suppress reports claiming workers should save base cache. (documented)
Default-branch generations can warm a cold current-ref lineage. The fallback is explicit and remains inside the same action-owned compatibility family. Treat as by design unless backend scoping lets the lineage cross an unrepresented trust boundary. (documented)
Hard excludes cannot be removed by custom partitions. Hard excludes are deliberate safety policy for known volatile/secret/lock files. Suppress reports treating this as lack of configurability. (documented)
Delta manifests use portable cache-root sentinel instead of absolute paths. This prevents worker absolute paths from leaving the worker and is required for portability. Suppress reports expecting absolute path preservation in artifacts. (documented)
Non-src/ findings in tests, docs, release tooling, or node_modules. Those components are out of this runtime model unless they demonstrate a reachable runtime issue. Route to OUT-OF-MODEL: unsupported-component. (inferred)

12. Conditions That Would Change This Model

Revise this model when any of the following occur:

  • A non-GitHub CI provider becomes supported. (documented)
  • A new public action input, environment override, config-file key, or output is added. (inferred)
  • Default values for read-only, wrapper validation/provenance, job modes, cleanup, or duplicate delta handling change. (inferred)
  • A new build tool adapter or new cache partition family is added. (inferred)
  • Maven gains wrapper provisioning or other network/subprocess behavior. (inferred)
  • The distributed delta package schema, artifact selection identity, or merge conflict rules change. (inferred)
  • The action starts reading or writing new filesystem locations outside current workspace/cache/temp roots. (inferred)
  • The action begins handling secrets, credentials, private package repositories, or dependency provenance directly. (inferred)
  • Any vulnerability report cannot be routed to one of the §13 dispositions. That is a MODEL-GAP and should revise §8, §9, or the relevant assumptions. (inferred)

13. Triage Dispositions

Disposition Meaning Licensed by
VALID Violates a property the project claims, via an in-scope adversary and input. §6, §7, §8
VALID-HARDENING No §8 property is violated, but the API makes a §11 misuse easy enough that the project elects to harden it. Report privately; fix at maintainer discretion; typically no CVE. §11
OUT-OF-MODEL: trusted-input Requires attacker control of a parameter the model marks trusted. §6
OUT-OF-MODEL: adversary-not-in-scope Requires an attacker capability the model excludes. §7
OUT-OF-MODEL: unsupported-component Lands only in tests, docs, release tooling, node_modules, generated bundles, or other code placed out of runtime scope. §3
OUT-OF-MODEL: non-default-build Only manifests under a non-default or maintainer-discouraged configuration variant. §5a
BY-DESIGN: property-disclaimed Concerns a property the project explicitly does not provide. §9
KNOWN-NON-FINDING Matches a documented recurring false positive. §11a
MODEL-GAP Cannot be cleanly routed to any listed disposition. Revise this model before final triage. §12

14. Open Questions for Maintainers

Wave 1 - publishability and production posture:

Question Proposed answer Lands in
Should this document live at docs/threat-model.md, be linked from user security docs, or be mirrored at repository root? Keep docs/threat-model.md canonical and link from docs/user/security.md and SECURITY-ASSESSMENT.md. §1
Is maven-user-home intentionally allowed to point outside the workspace? Yes, because Maven user homes commonly live outside workspaces, but operators must not share them across trust zones. §5a, §10
Are the rough resource guarantees in §8 intentionally limited to wrapper downloads and delta validation, with no global cache-root cap? Yes; large cache roots are operator responsibility and backend limits apply. §5, §8, §9

Wave 2 - trust roles and adversaries:

Question Proposed answer Lands in
Is a trusted-branch repository contributor considered trusted for cache contents? Yes; repository branch protection determines that trust. §2, §7
Should malicious build scripts in untrusted PRs be explicitly in scope only for cache poisoning/exfiltration through this action, not for arbitrary workflow compromise? Yes. The action should not be modeled as a build sandbox. §3, §7, §9
Is a compromised GitHub cache/artifact service out of scope? Yes; the action validates package structure and hashes but relies on GitHub service trust and permissions. §3, §7, §9
Is dependency provenance intentionally left to Maven/Gradle and repository policy? Yes. This action manages transport/reuse of cache files, not package authenticity. §9, §10
Should self-hosted runner persistence across repositories be called out more strongly? Yes, as an operator responsibility for cache roots and temp/workspace cleanup. §5, §10

Wave 3 - side effects and non-findings:

Question Proposed answer Lands in
Are the negative side-effect claims complete: no listening sockets, no signal handlers, no process-wide locale/FPU mutation? Yes for the current source tree. §5
Should findings in generated dist/ be triaged through source files rather than directly against bundles? Yes, unless the release bundle differs from source behavior. §3, §11a
Should safeHtml() be listed as a known non-finding or should every use require local justification? Keep it as known non-finding but require review for attacker-controlled strings. §11a
Should token-presence diagnostics remain explicitly permitted? Yes, as long as values are never logged. §8, §11a
Should cross-runner delta reuse remain categorically unsupported? Yes. §3, §8, §10

15. Optional Machine-Readable Companion

No machine-readable companion is included in this draft. If automated triage consumes this model, generate docs/threat-model.yaml from the prose sections containing:

  • Component families and in/out-of-scope status from §2 and §3.
  • Entry points and per-parameter trust levels from §6.
  • Security-relevant knobs from §5a.
  • Claimed properties and violation symptoms from §8.
  • Disclaimed properties and false friends from §9.
  • Known non-findings from §11a.
  • Closed triage dispositions from §13.