You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Four targeted SPI changes that close the gap between today's Docker-only sandbox surface and what a future Kubernetes adapter will need:
SandboxSpec.volumeMounts is now a sealed List<VolumeMount> with HostPathMount, EmptyDirMount, ConfigMapMount, and SecretMount records — replacing today's Map<String,String>. InteractiveSandboxSpec gets the same change. The Docker adapter accepts only HostPathMount; the other three throw UnsupportedOperationException with a clear message naming the variant.
NetworkPolicy validates URLs at construction. Non-absolute llmProxyUrl or gitProxyUrl is rejected (URI.create(url).isAbsolute()).
WorkerAuthProvider SPI stub. Interface plus a RegistrationTokenAuthProvider reference implementation under de.tum.in.www1.hephaestus.worker.auth.spi. No worker bean wires this yet — that lands in the worker runtime epic — but the contract exists.
WorkerJwtClaims record.{worker_id, workspace_id, exp, iat, jti}. Five fields, no scope[] — there's no third JWT-protected endpoint to scope-check against, so an unused field would be defense-in-depth theater.
Plus an ArchUnit rule that rejects literal ~/.hephaestus paths under agent/runtime/, agent/sandbox/, and worker/ packages — these subsystems should never assume a user home directory.
Why
These four are coupled by being SPI surface, not by being one logical feature. Splitting them creates four trivially small PRs that each touch the same SPI files and pessimize review attention. Keeping them in one PR keeps the SPI version bump (and the breaking change it represents to any downstream consumer of volumeMounts) in one place.
Acceptance criteria
SandboxSpec.volumeMounts: Map<String,String> replaced by List<VolumeMount> — a sealed interface with HostPathMount, EmptyDirMount, ConfigMapMount, SecretMount records
InteractiveSandboxSpec same refactor
DockerSandboxAdapter accepts only HostPathMount; the other variants throw UnsupportedOperationException with a message that names the unsupported variant
All call sites of volumeMounts(...) migrated (verified by grep showing zero remaining Map<String,String> callers)
NetworkPolicy constructor rejects non-absolute llmProxyUrl AND non-absolute gitProxyUrl; unit tests cover both
WorkerAuthProvider interface + RegistrationTokenAuthProvider reference implementation exist under de.tum.in.www1.hephaestus.worker.auth.spi
WorkerJwtClaims record with fields {worker_id, workspace_id, exp, iat, jti} — no scope[]
ArchUnit rule rejects the literal ~/.hephaestus under agent/runtime/, agent/sandbox/, and worker/ packages
No existing test regresses
OpenAPI codegen unaffected (these SPIs aren't exposed via REST)
Implementation notes
The volumeMounts change is the only breaking move in this PR. Audit downstream consumers (the integration sandbox adapter, the OpenCode adapter) and migrate them as part of the same PR — there should be no leftover Map<String,String> after merge.
The reference RegistrationTokenAuthProvider exists so the interface contract is exercised by a real implementation, not just a mock. Keep it minimal — it's a contract artifact, not a feature.
WorkerJwtClaims deliberately omits scope[]. Adding scope later if a third JWT-protected endpoint shows up is trivial; carrying an unused field today is the kind of defense-in-depth gesture that erodes trust in the rest of the surface.
Part of #1097 (epic).
What ships
Four targeted SPI changes that close the gap between today's Docker-only sandbox surface and what a future Kubernetes adapter will need:
SandboxSpec.volumeMountsis now a sealedList<VolumeMount>withHostPathMount,EmptyDirMount,ConfigMapMount, andSecretMountrecords — replacing today'sMap<String,String>.InteractiveSandboxSpecgets the same change. The Docker adapter accepts onlyHostPathMount; the other three throwUnsupportedOperationExceptionwith a clear message naming the variant.NetworkPolicyvalidates URLs at construction. Non-absolutellmProxyUrlorgitProxyUrlis rejected (URI.create(url).isAbsolute()).WorkerAuthProviderSPI stub. Interface plus aRegistrationTokenAuthProviderreference implementation underde.tum.in.www1.hephaestus.worker.auth.spi. No worker bean wires this yet — that lands in the worker runtime epic — but the contract exists.WorkerJwtClaimsrecord.{worker_id, workspace_id, exp, iat, jti}. Five fields, noscope[]— there's no third JWT-protected endpoint to scope-check against, so an unused field would be defense-in-depth theater.Plus an ArchUnit rule that rejects literal
~/.hephaestuspaths underagent/runtime/,agent/sandbox/, andworker/packages — these subsystems should never assume a user home directory.Why
These four are coupled by being SPI surface, not by being one logical feature. Splitting them creates four trivially small PRs that each touch the same SPI files and pessimize review attention. Keeping them in one PR keeps the SPI version bump (and the breaking change it represents to any downstream consumer of
volumeMounts) in one place.Acceptance criteria
SandboxSpec.volumeMounts: Map<String,String>replaced byList<VolumeMount>— a sealed interface withHostPathMount,EmptyDirMount,ConfigMapMount,SecretMountrecordsInteractiveSandboxSpecsame refactorDockerSandboxAdapteraccepts onlyHostPathMount; the other variants throwUnsupportedOperationExceptionwith a message that names the unsupported variantvolumeMounts(...)migrated (verified by grep showing zero remainingMap<String,String>callers)NetworkPolicyconstructor rejects non-absolutellmProxyUrlAND non-absolutegitProxyUrl; unit tests cover bothWorkerAuthProviderinterface +RegistrationTokenAuthProviderreference implementation exist underde.tum.in.www1.hephaestus.worker.auth.spiWorkerJwtClaimsrecord with fields{worker_id, workspace_id, exp, iat, jti}— noscope[]~/.hephaestusunderagent/runtime/,agent/sandbox/, andworker/packagesImplementation notes
volumeMountschange is the only breaking move in this PR. Audit downstream consumers (the integration sandbox adapter, the OpenCode adapter) and migrate them as part of the same PR — there should be no leftoverMap<String,String>after merge.RegistrationTokenAuthProviderexists so the interface contract is exercised by a real implementation, not just a mock. Keep it minimal — it's a contract artifact, not a feature.WorkerJwtClaimsdeliberately omitsscope[]. Adding scope later if a third JWT-protected endpoint shows up is trivial; carrying an unused field today is the kind of defense-in-depth gesture that erodes trust in the rest of the surface.Dependencies
Depends on #1124. Independent of #1125, #1126.