From d997beb03367b3cc3b6c8c0c31b465dcbbefcad6 Mon Sep 17 00:00:00 2001 From: Sarah Asad Date: Tue, 19 May 2026 15:17:28 -0700 Subject: [PATCH 1/8] support k8s setting --- .../resource/pythonvirtualenvironment/PveResource.scala | 8 +++----- .../virtual-environment/virtual-environment.service.ts | 2 +- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/amber/src/main/scala/org/apache/texera/web/resource/pythonvirtualenvironment/PveResource.scala b/amber/src/main/scala/org/apache/texera/web/resource/pythonvirtualenvironment/PveResource.scala index 4d810678cc5..2f60da2c712 100644 --- a/amber/src/main/scala/org/apache/texera/web/resource/pythonvirtualenvironment/PveResource.scala +++ b/amber/src/main/scala/org/apache/texera/web/resource/pythonvirtualenvironment/PveResource.scala @@ -36,12 +36,10 @@ class PveResource { @GET @Path("/system") @Produces(Array(MediaType.APPLICATION_JSON)) - def getSystemPackages: util.Map[String, util.List[String]] = { + def getSystemPackages( + @QueryParam("isLocal") isLocal: Boolean + ): util.Map[String, util.List[String]] = { try { - - // TODO: Support Kubernetes environment handling - val isLocal = true - val systemPkgs = PveManager.getSystemPackages(isLocal).toList.asJava diff --git a/frontend/src/app/workspace/service/virtual-environment/virtual-environment.service.ts b/frontend/src/app/workspace/service/virtual-environment/virtual-environment.service.ts index 7788cba2701..72129dbce64 100644 --- a/frontend/src/app/workspace/service/virtual-environment/virtual-environment.service.ts +++ b/frontend/src/app/workspace/service/virtual-environment/virtual-environment.service.ts @@ -50,7 +50,7 @@ export class WorkflowPveService { } getSystemPackages(isLocal: boolean): Observable { - const params = this.buildBaseParams(); + const params = this.buildBaseParams().set("isLocal", isLocal.toString()); return this.http.get("/pve/system", { params }); } From 661a04ce7847dac249b4bfa3323bb0c275ffdcf8 Mon Sep 17 00:00:00 2001 From: Sarah Asad Date: Tue, 19 May 2026 15:20:58 -0700 Subject: [PATCH 2/8] add gateway routing --- .../resource/AccessControlResource.scala | 21 +++++++++++++++++-- bin/k8s/templates/gateway-routes.yaml | 14 +++++++++++++ 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/access-control-service/src/main/scala/org/apache/texera/service/resource/AccessControlResource.scala b/access-control-service/src/main/scala/org/apache/texera/service/resource/AccessControlResource.scala index 0cd52f49194..c48be41af26 100644 --- a/access-control-service/src/main/scala/org/apache/texera/service/resource/AccessControlResource.scala +++ b/access-control-service/src/main/scala/org/apache/texera/service/resource/AccessControlResource.scala @@ -43,6 +43,14 @@ object AccessControlResource extends LazyLogging { private val wsapiWorkflowWebsocket: Regex = """.*/wsapi/workflow-websocket.*""".r private val apiExecutionsStats: Regex = """.*/api/executions/[0-9]+/stats/[0-9]+.*""".r private val apiExecutionsResultExport: Regex = """.*/api/executions/result/export.*""".r + // PVE REST + websocket endpoints, all per-computing-unit. The REST route + // appears as bare /pve/... to ext-authz (the gateway's URLRewrite to /api/pve + // runs after ext_authz), while websocket traffic comes in as /wsapi/pve/... + private val pveRoute: Regex = """.*/(?:api/|wsapi/)?pve(?:/.*)?""".r + + // Path patterns whose cuid lives in the URL path rather than the query string. + private val pvePvesCuidPath: Regex = """.*/pve/pves/([0-9]+).*""".r + private val pvePackagesCuidPath: Regex = """.*/pve/([0-9]+)/[^/]+/packages/.+""".r /** * Authorize the request based on the path and headers. @@ -60,7 +68,8 @@ object AccessControlResource extends LazyLogging { logger.info(s"Authorizing request for path: $path") path match { - case wsapiWorkflowWebsocket() | apiExecutionsStats() | apiExecutionsResultExport() => + case wsapiWorkflowWebsocket() | apiExecutionsStats() | apiExecutionsResultExport() | + pveRoute() => checkComputingUnitAccess(uriInfo, headers, bodyOpt) case _ => logger.warn(s"No authorization logic for path: $path. Denying access.") @@ -95,7 +104,15 @@ object AccessControlResource extends LazyLogging { qToken.orElse(hToken).orElse(bToken).getOrElse("") } logger.info(s"token extracted from request $token") - val cuid = queryParams.getOrElse("cuid", "") + // Some PVE endpoints carry the cuid in the URL path (e.g. DELETE /pve/pves/{cuid}) instead of + // the query string, so fall back to extracting it from the path when missing from the query. + val cuid = queryParams.get("cuid").filter(_.nonEmpty).getOrElse { + uriInfo.getPath match { + case pvePvesCuidPath(c) => c + case pvePackagesCuidPath(c) => c + case _ => "" + } + } val cuidInt = try { cuid.toInt diff --git a/bin/k8s/templates/gateway-routes.yaml b/bin/k8s/templates/gateway-routes.yaml index 55dc40f581a..ab53c184e83 100644 --- a/bin/k8s/templates/gateway-routes.yaml +++ b/bin/k8s/templates/gateway-routes.yaml @@ -118,6 +118,20 @@ spec: - group: gateway.envoyproxy.io kind: Backend name: texera-dynamic-backend + - matches: + - path: + type: PathPrefix + value: /pve + filters: + - type: URLRewrite + urlRewrite: + path: + type: ReplacePrefixMatch + replacePrefixMatch: /api/pve + backendRefs: + - group: gateway.envoyproxy.io + kind: Backend + name: texera-dynamic-backend --- # MinIO Route {{- if .Values.minio.gateway.enabled }} From c38d532914d4f096e7fe8a532257ef7da597c68e Mon Sep 17 00:00:00 2001 From: Sarah Asad Date: Wed, 20 May 2026 10:02:43 -0700 Subject: [PATCH 3/8] cleanup --- .../texera/service/resource/AccessControlResource.scala | 4 ---- 1 file changed, 4 deletions(-) diff --git a/access-control-service/src/main/scala/org/apache/texera/service/resource/AccessControlResource.scala b/access-control-service/src/main/scala/org/apache/texera/service/resource/AccessControlResource.scala index c48be41af26..de7b4162ab1 100644 --- a/access-control-service/src/main/scala/org/apache/texera/service/resource/AccessControlResource.scala +++ b/access-control-service/src/main/scala/org/apache/texera/service/resource/AccessControlResource.scala @@ -43,11 +43,7 @@ object AccessControlResource extends LazyLogging { private val wsapiWorkflowWebsocket: Regex = """.*/wsapi/workflow-websocket.*""".r private val apiExecutionsStats: Regex = """.*/api/executions/[0-9]+/stats/[0-9]+.*""".r private val apiExecutionsResultExport: Regex = """.*/api/executions/result/export.*""".r - // PVE REST + websocket endpoints, all per-computing-unit. The REST route - // appears as bare /pve/... to ext-authz (the gateway's URLRewrite to /api/pve - // runs after ext_authz), while websocket traffic comes in as /wsapi/pve/... private val pveRoute: Regex = """.*/(?:api/|wsapi/)?pve(?:/.*)?""".r - // Path patterns whose cuid lives in the URL path rather than the query string. private val pvePvesCuidPath: Regex = """.*/pve/pves/([0-9]+).*""".r private val pvePackagesCuidPath: Regex = """.*/pve/([0-9]+)/[^/]+/packages/.+""".r From 6c36784023be0c0e9868ddca0c0d63481515c720 Mon Sep 17 00:00:00 2001 From: Sarah Asad Date: Wed, 20 May 2026 12:42:22 -0700 Subject: [PATCH 4/8] add venv to cu dockerfile --- bin/computing-unit-master.dockerfile | 1 + 1 file changed, 1 insertion(+) diff --git a/bin/computing-unit-master.dockerfile b/bin/computing-unit-master.dockerfile index 191d23f2ddf..08f9669e29f 100644 --- a/bin/computing-unit-master.dockerfile +++ b/bin/computing-unit-master.dockerfile @@ -76,6 +76,7 @@ COPY --from=build /texera/amber/operator-requirements.txt /tmp/operator-requirem RUN apt-get update && apt-get install -y \ python3-pip \ python3-dev \ + python3-venv \ libpq-dev \ && apt-get clean From 503cd7482da31a3982235601803bd97576d6e84a Mon Sep 17 00:00:00 2001 From: Sarah Asad Date: Wed, 20 May 2026 12:56:22 -0700 Subject: [PATCH 5/8] fix access control --- .../power-button/computing-unit-selection.component.ts | 2 +- .../virtual-environment/virtual-environment.service.ts | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/frontend/src/app/workspace/component/power-button/computing-unit-selection.component.ts b/frontend/src/app/workspace/component/power-button/computing-unit-selection.component.ts index a2843a51bf3..fc4de1d482a 100644 --- a/frontend/src/app/workspace/component/power-button/computing-unit-selection.component.ts +++ b/frontend/src/app/workspace/component/power-button/computing-unit-selection.component.ts @@ -802,7 +802,7 @@ export class ComputingUnitSelectionComponent implements OnInit { })); this.workflowPveService - .getSystemPackages(isLocal) + .getSystemPackages(cuId, isLocal) .pipe(untilDestroyed(this)) .subscribe({ next: installedResp => { diff --git a/frontend/src/app/workspace/service/virtual-environment/virtual-environment.service.ts b/frontend/src/app/workspace/service/virtual-environment/virtual-environment.service.ts index 72129dbce64..b0adfa8cfd2 100644 --- a/frontend/src/app/workspace/service/virtual-environment/virtual-environment.service.ts +++ b/frontend/src/app/workspace/service/virtual-environment/virtual-environment.service.ts @@ -49,8 +49,10 @@ export class WorkflowPveService { return params; } - getSystemPackages(isLocal: boolean): Observable { - const params = this.buildBaseParams().set("isLocal", isLocal.toString()); + getSystemPackages(cuid: number, isLocal: boolean): Observable { + const params = this.buildBaseParams() + .set("cuid", cuid.toString()) + .set("isLocal", isLocal.toString()); return this.http.get("/pve/system", { params }); } From 9e1b8a53e7269732bd1bd5ef4623c1cb564c985f Mon Sep 17 00:00:00 2001 From: Sarah Asad Date: Fri, 22 May 2026 00:51:31 -0700 Subject: [PATCH 6/8] bug fix --- .../service/resource/AccessControlResource.scala | 11 ++++++++++- bin/computing-unit-master.dockerfile | 1 + 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/access-control-service/src/main/scala/org/apache/texera/service/resource/AccessControlResource.scala b/access-control-service/src/main/scala/org/apache/texera/service/resource/AccessControlResource.scala index de7b4162ab1..47f473c2f13 100644 --- a/access-control-service/src/main/scala/org/apache/texera/service/resource/AccessControlResource.scala +++ b/access-control-service/src/main/scala/org/apache/texera/service/resource/AccessControlResource.scala @@ -22,7 +22,7 @@ import com.fasterxml.jackson.module.scala.DefaultScalaModule import com.typesafe.scalalogging.LazyLogging import jakarta.ws.rs.client.{Client, ClientBuilder, Entity} import jakarta.ws.rs.core._ -import jakarta.ws.rs.{Consumes, GET, POST, Path, Produces} +import jakarta.ws.rs.{Consumes, DELETE, GET, POST, Path, Produces} import org.apache.texera.auth.JwtParser.parseToken import org.apache.texera.auth.SessionUser import org.apache.texera.auth.util.{ComputingUnitAccess, HeaderField} @@ -226,6 +226,15 @@ class AccessControlResource extends LazyLogging { logger.info("Request body: " + body) AccessControlResource.authorize(uriInfo, headers, Option(body).map(_.trim).filter(_.nonEmpty)) } + + @DELETE + @Path("/{path:.*}") + def authorizeDelete( + @Context uriInfo: UriInfo, + @Context headers: HttpHeaders + ): Response = { + AccessControlResource.authorize(uriInfo, headers) + } } @Path("/chat") diff --git a/bin/computing-unit-master.dockerfile b/bin/computing-unit-master.dockerfile index 08f9669e29f..6d92303571e 100644 --- a/bin/computing-unit-master.dockerfile +++ b/bin/computing-unit-master.dockerfile @@ -71,6 +71,7 @@ WORKDIR /texera/amber COPY --from=build /texera/amber/requirements.txt /tmp/requirements.txt COPY --from=build /texera/amber/operator-requirements.txt /tmp/operator-requirements.txt +COPY --from=build /texera/amber/system-requirements-lock.txt /tmp/system-requirements-lock.txt # Install Python runtime dependencies RUN apt-get update && apt-get install -y \ From 4b6c6ca5b067daa15c0ff76ad7cf37820b89f5f2 Mon Sep 17 00:00:00 2001 From: Sarah Asad Date: Fri, 22 May 2026 00:56:49 -0700 Subject: [PATCH 7/8] formatting --- .../apache/texera/service/resource/AccessControlResource.scala | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/access-control-service/src/main/scala/org/apache/texera/service/resource/AccessControlResource.scala b/access-control-service/src/main/scala/org/apache/texera/service/resource/AccessControlResource.scala index 47f473c2f13..a931eb3e909 100644 --- a/access-control-service/src/main/scala/org/apache/texera/service/resource/AccessControlResource.scala +++ b/access-control-service/src/main/scala/org/apache/texera/service/resource/AccessControlResource.scala @@ -100,8 +100,7 @@ object AccessControlResource extends LazyLogging { qToken.orElse(hToken).orElse(bToken).getOrElse("") } logger.info(s"token extracted from request $token") - // Some PVE endpoints carry the cuid in the URL path (e.g. DELETE /pve/pves/{cuid}) instead of - // the query string, so fall back to extracting it from the path when missing from the query. + val cuid = queryParams.get("cuid").filter(_.nonEmpty).getOrElse { uriInfo.getPath match { case pvePvesCuidPath(c) => c From ec6508ecfb4925863a9caf4661f2f420ce3303ee Mon Sep 17 00:00:00 2001 From: Sarah Asad Date: Fri, 22 May 2026 01:02:06 -0700 Subject: [PATCH 8/8] fix formatting --- .../virtual-environment/virtual-environment.service.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/frontend/src/app/workspace/service/virtual-environment/virtual-environment.service.ts b/frontend/src/app/workspace/service/virtual-environment/virtual-environment.service.ts index b0adfa8cfd2..b4227ee36b1 100644 --- a/frontend/src/app/workspace/service/virtual-environment/virtual-environment.service.ts +++ b/frontend/src/app/workspace/service/virtual-environment/virtual-environment.service.ts @@ -50,9 +50,7 @@ export class WorkflowPveService { } getSystemPackages(cuid: number, isLocal: boolean): Observable { - const params = this.buildBaseParams() - .set("cuid", cuid.toString()) - .set("isLocal", isLocal.toString()); + const params = this.buildBaseParams().set("cuid", cuid.toString()).set("isLocal", isLocal.toString()); return this.http.get("/pve/system", { params }); }