Every sandboxed build kept its own Gradle home under /root: on mih09 six repositories held six dependency caches and six provisioned JDKs, about 5 GiB of a 16 GiB SSD. The Docker runner has had a persistent Gradle volume since step 11; the werkdock runner never got the equivalent. werkdock.gradleHome names a host directory that every sandbox naming the same path mounts as /gradle-user-home, with GRADLE_USER_HOME pointing there — the same pair the Docker runner uses. Beside /root rather than over /root/.gradle, so a leftover per-repository cache is unused, not hidden. Pinned and opt-in: the path is mounted read-write, and a shared cache is shared trust. Set once in the defaults block of ~/.werkator.yml. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Co-authored-by: mhoennig <michael@hoennig.de> Reviewed-on: #76
102 lines
5.6 KiB
Markdown
102 lines
5.6 KiB
Markdown
> **WARNING:** This document describes only the change applied in this PR.
|
|
> It may already be outdated once the next PR is merged.
|
|
> Historic PR-documentation is not maintained along with new PRs — treat it as a snapshot, not as current documentation.
|
|
|
|
## The Problem
|
|
|
|
Every sandboxed build gets its own persistent home under `.git/werkator/buildenv/home`, mounted as `/root`, and with it its own Gradle user home.
|
|
On mih09 that is six repositories with six dependency caches, six provisioned JDKs and six Gradle wrapper distributions, mostly of the same versions: about 5 GiB of a 16 GiB SSD, growing with every repository added.
|
|
The Docker runner has had a persistent Gradle volume since step 11; the werkdock runner never got the equivalent, because per-repository isolation was the simpler default.
|
|
|
|
## Non-Goals
|
|
|
|
- No sharing of anything else in the sandbox home: `.konan`, `.npm`, `.vaadin`, SSH keys stay per repository.
|
|
- No change to the Docker runner's per-repository volume.
|
|
- No migration of existing per-repository caches: a `.gradle` left under `/root` stays where it is, unused, until deleted by hand.
|
|
- Not the default. See the trust note under The Solution.
|
|
|
|
## The Scenarios
|
|
|
|
### Feature: one Gradle user home for all sandboxes of a host
|
|
|
|
#### Background
|
|
|
|
- `werkdock.gradleHome` names a directory on the host; empty (the default) keeps the per-repository Gradle home under `/root`.
|
|
- Gradle locks its caches for concurrent use by several builds on one machine.
|
|
|
|
#### Scenario#76.01: A configured Gradle home is mounted and announced
|
|
|
|
So that Gradle inside the sandbox uses the shared cache and nothing else has to know about it.
|
|
|
|
- **Given** a build with `werkdock.gradleHome` set
|
|
- **When** the sandbox is started
|
|
- **Then** the directory is mounted read-write as `/gradle-user-home`, after the `/root` mount
|
|
- **and** `GRADLE_USER_HOME=/gradle-user-home` is set inside the sandbox
|
|
- **and** the directory exists on the host before the command starts
|
|
|
|
##### Verified by
|
|
|
|
- [WerkdockBuildRunnerTest — mounts a shared Gradle home after /root and points GRADLE_USER_HOME at it](../../src/test/kotlin/de/hoennig/werkator/build/WerkdockBuildRunnerTest.kt)
|
|
|
|
#### Scenario#76.02: Without the key nothing changes
|
|
|
|
- **Given** a build without `werkdock.gradleHome`
|
|
- **When** the sandbox is started
|
|
- **Then** no extra mount and no `GRADLE_USER_HOME` are added; Gradle keeps its cache under `/root`
|
|
|
|
##### Verified by
|
|
|
|
- [WerkdockBuildRunnerTest — without a shared Gradle home the sandbox keeps its own under /root](../../src/test/kotlin/de/hoennig/werkator/build/WerkdockBuildRunnerTest.kt)
|
|
|
|
#### Scenario#76.03: A branch cannot choose the directory
|
|
|
|
So that a branch cannot mount a host directory of its choosing read-write into its sandbox.
|
|
|
|
- **Given** a host configuration without `werkdock.gradleHome`
|
|
- **and** a branch whose committed configuration sets it to `/home/ci/.ssh`
|
|
- **When** the branch's build settings are resolved
|
|
- **Then** the key is empty: the branch's value is stripped like the other pinned werkdock keys
|
|
|
|
##### Verified by
|
|
|
|
- [ConfigLoaderTest — a branch cannot disable its werkdock sandbox or substitute a foreign rootfs through a build definition](../../src/test/kotlin/de/hoennig/werkator/config/ConfigLoaderTest.kt)
|
|
- [BuildDefinitionTest — every docker and werkdock setting can be said in a build definition](../../src/test/kotlin/de/hoennig/werkator/config/BuildDefinitionTest.kt) (the structural guard from PR#72, which is what made adding the key to `WerkdockOverrides` mandatory)
|
|
|
|
## The Solution
|
|
|
|
One new pinned key, `werkdock.gradleHome`.
|
|
When set, `WerkdockBuildRunner` creates the directory, adds `-v <dir>:/gradle-user-home` after the `/root` mount and `-e GRADLE_USER_HOME=/gradle-user-home` — the same pair the Docker runner has used with its volume since step 11.
|
|
|
|
The mount goes to its own path, not to `/root/.gradle`.
|
|
Mounting over `/root/.gradle` would have shadowed a per-repository cache that is still there; mounting beside it leaves that cache visible and unused, so it can be deleted at leisure and nothing is hidden from `du`.
|
|
|
|
**Why opt-in and pinned.**
|
|
The path is a host directory mounted read-write into a sandbox whose whole point is filesystem isolation, so a branch that could set it could reach any directory of the host user.
|
|
And a shared cache is shared trust: a build that can write it can feed a tampered dependency to every other repository on the host.
|
|
Both are host decisions.
|
|
On mih09 every repository belongs to the same person; on a host serving several parties the key should stay empty, or point to one directory per party.
|
|
|
|
**Rollout on mih09.**
|
|
One line in `~/.werkator.yml`, so that every repository gets it without touching six fragments:
|
|
|
|
```yaml
|
|
defaults:
|
|
builds:
|
|
default:
|
|
werkdock:
|
|
gradleHome: /home/pacs/mih09/users/werkator/.cache/werkator/gradle
|
|
```
|
|
|
|
The first build of each repository fills the shared cache from scratch; from the second repository on, the dependencies and the JDK are already there.
|
|
Afterwards the per-repository `.gradle` directories under `*/.git/werkator/buildenv/home/` can be deleted — that is where the 5 GiB come back.
|
|
|
|
## Open Questions
|
|
|
|
- Whether the shared Gradle home should count as a build environment in the System page's disk breakdown.
|
|
Today the breakdown walks the repositories, so a shared directory outside them falls under whatever category the filesystem total leaves; the per-repository figure shrinks accordingly.
|
|
Left for when the breakdown is next touched.
|
|
|
|
## Follow-up PRs
|
|
|
|
- The same idea for the Kotlin/Native toolchain (`.konan`, 1.7 GiB for one repository on mih09) once a second repository needs it.
|