Skip to content

feat(_task): allow secret overrides on reusable tasks#1108

Open
EngHabu wants to merge 2 commits into
mainfrom
haytham/fix-reusable-secret-override
Open

feat(_task): allow secret overrides on reusable tasks#1108
EngHabu wants to merge 2 commits into
mainfrom
haytham/fix-reusable-secret-override

Conversation

@EngHabu
Copy link
Copy Markdown
Contributor

@EngHabu EngHabu commented May 23, 2026

Motivation

task.override(secrets=...) currently raises when the task's environment is reusable:

ValueError: Cannot override secrets when reusable is set. Reusable tasks
will use the parent env's secrets. You can disable reusability and
override secrets if needed. (set reusable='off')

The guard's intent — keep one actor pool per env — is already enforced downstream. extract_unique_id_and_image (in _internal/runtime/reuse.py) hashes the task's security_context into the actor pool key. A secret override deterministically maps to a different actor pool, not a polluted shared one.

Concrete use case

We're building a multi-user "Claude Code in Flyte" service where each user owns a per-identifier credentials secret (<identifier>-claude-session). The launcher does:

pinned = claude_session.override(
    secrets=flyte.Secret(key=secret_key, mount=SECRET_MOUNT),
)
return await pinned(...)

We want claude_session to be reusable so multiple concurrent sessions for the same user share an actor pod (and the same FUSE-mounted volume at /root). Cross-user isolation comes from the secret override → different actor pool. The current guard blocks this entirely; reusable='off' would cost us the pool sharing we explicitly want.

What changed

Drop the secrets check from the reusable guard in Task.override(). Resources and env_vars stay locked — they would mutate the pod spec without changing the actor pool key (so a single pool could end up running tasks that disagree on CPU/memory limits or environment values).

Test plan

  • Existing reusable smoke tests still pass.
  • Manually verified that task.override(secrets=...) on a reusable env now schedules into a per-secret actor pool (rather than raising at override-time).
  • Add a focused unit test covering the new allowed override path (happy to follow up).

🤖 Generated with Claude Code

EngHabu and others added 2 commits May 22, 2026 21:47
`flyteidl2.imagebuilder.PythonWheels` only declares `dir` / `options` /
`secret_mounts` — there's no `package_name` field today. The SDK's
remote-builder serializer at remote_builder.py:262 sets
`PythonWheels(... package_name=layer.package_name, ...)`, which the
proto-generated message rejects with:

  Protocol message PythonWheels has no "package_name" field.

Consequence: any image with a `PythonWheels` layer
(`Image.with_local_v2()`, `Image.with_local_v2_plugins(...)`, or any
caller that adds the layer directly) blows up at image-build time on
the remote builder. The local docker builder is unaffected because
it reads `package_name` straight off the Python dataclass.

This was a known gap — the wheel-changes commit (1cdbd6b) literally
says "Will need to update the remote builder as well." Until the
proto + the server-side builder gain a real `package_name` field, we
can sidestep the proto entirely by emitting the equivalent local
docker-builder behavior using existing wire-compatible messages:

  CopyConfig{src=<staged wheel dir>, dst=/<dir_name>}
  Commands{cmd=[
      "pip install ... --find-links /<dir_name> --no-deps --no-index
       --force-reinstall <package_name>",
      "pip install ... <package_name>",
  ]}

The two pip invocations mirror exactly what
`docker_builder.PythonWheelHandler` runs locally:

  1. Install the wheel WITHOUT deps from --find-links (--no-index
     guarantees we never reach PyPI for the package itself).
  2. Install dependencies normally (pip resolves the dep tree from
     PyPI for everything except the package we just baked).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
``task.override(secrets=...)`` previously raised when the task's env was
reusable. The intent was to keep one pool per env, but the actor pool
key (``extract_unique_id_and_image``) already includes the task's
``security_context`` — so a secret override deterministically maps to a
*different* actor pool, not a polluted one.

Concrete use case unblocked: per-user / per-identifier credentials
secrets on a reusable claude-session env. Each identifier gets its own
actor pod hosting that user's concurrent sessions; cross-identifier
isolation is preserved by the pool-key hash.

Resources and env_vars remain locked: they would change the pod spec
(CPU/memory limits, env values seen at exec time) without changing the
pool key, so the same actor pool could end up running tasks that disagree
on those values.

Signed-off-by: Haytham Abuelfutuh <haytham@afutuh.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant