Skip to content

feat: launcher orchestration support (current-task, ParentRunId tagging, per-launch key retirement) - #132

Open
accumb3ns wants to merge 6 commits into
mainfrom
feature/launcher-orchestration
Open

accumb3ns wants to merge 6 commits into
mainfrom
feature/launcher-orchestration

Conversation

@accumb3ns

@accumb3ns accumb3ns commented Aug 25, 2026 •

Copy link
Copy Markdown
Collaborator

Why

Bioinformatics launchers (e.g. the RNA-Seq launcher) will run directly as AWS Batch jobs, as first-class GA4GH WES runs that link every child run back to themselves through a ParentRunId tag (see NGS360/GA4GH-WES-API-Service#233). A launcher running that way has to identify its own run, and it needs a credential that outlives the job without anyone pasting a token in.

What changed

  • get_current_task() returns a WESTask built from WES_RUN_ID (SevenBridges uses TASK_ID the same way) instead of always returning None. This lets a launcher read its own inputs back through get_task_input.
  • submit_task() tags every submitted run with ParentRunId when WES_RUN_ID is set. WES can then work out launcher progress from stored rows, without the launcher having to expose a status endpoint.
  • Per-launch key retirement. When NGS360_AUTH_KEY_ID names the ngs360_ API key in NGS360_AUTH_TOKEN, connect() registers an exit handler that retires the key (DELETE /api/v1/auth/api-keys/{id}), so a key minted for one launch doesn't outlive it.
    • The handler is registered before the /auth/me probe, so a launcher that fails to connect still cleans up.
    • A failed retirement is logged, not raised. The key's expiry still bounds it.
  • PlatformFactory.detect_platform() redacts credential-shaped environment values (TOKEN/KEY/SECRET/PASSWORD in the name) before logging them when platform detection fails.
  • The module docstring documents the launcher environment contract.

Changed since the first revision

This branch was rebased onto main, which now sends the bearer token on every NGS360 API call. In the process I dropped the WES_SERVICE_KEY / WES_ON_BEHALF_OF fallback:

  • It authenticated only the WES calls. The NGS360 API doesn't accept the service key, and the launcher calls it directly for project lookup and the results upload.
  • It would also have given every launcher container the service's full trust, since any holder can assert any user.

Instead, the launcher authenticates as the user who started it, with an API key minted for that one job. The minting side is NGS360/APIServer#484.

Not in this PR

Testing

  • uv run pytest: 166 passed, 18 skipped. Every commit in the series passes on its own.
  • pylint on the changed modules: 10.00/10.

🤖 Generated with Claude Code

@golharam

Copy link
Copy Markdown

We may want to support running the launcher as a native CWL workflow hence we get that for free.

vasques1 and others added 6 commits October 28, 2026 08:44
get_current_task() returned None with the note that "WES API doesn't have
a concept of current task". That was accurate when it was written: a run
could not be identified from inside its own container. The corresponding
WES service change makes a launcher execution a first-class WES run, so
the launcher can be told its own run id -- WES_RUN_ID, the same shape as
SevenBridges' TASK_ID -- and read its own run record back.

This is what the RNA-Seq launcher needs to reach its own inputs
(platform.get_task_input(current_task, "factors_file")). The inputs come
from request.workflow_params, which is what the run was submitted with.

Raises ValueError when WES_RUN_ID is unset, matching what the
SevenBridges and Arvados platforms do for their equivalent variables --
a launcher that cannot find itself is misconfigured, not idle.

test_current_task_and_users loses its assertIsNone half and becomes
test_project_users; the current-task behaviour now has its own two tests.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Nothing recorded which launcher execution submitted a given run, so a
launcher's progress could only be answered by asking the launcher. Adding
ParentRunId to the tags submit_task already sends -- ProjectId and
TaskName -- links each child back to the launcher run that created it.

WES promotes ParentRunId into an indexed column, so the service can roll
up launcher progress from persisted rows instead of the launcher exposing
a status endpoint, and a restarted launcher can find the work it already
submitted.

Only set when WES_RUN_ID is present, so a launcher run outside WES (a
developer's shell, an external platform) submits exactly the tags it does
today.

test_submit_task hides the launcher variables so its exact-tags assertion
does not depend on the developer's shell.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
When platform detection fails, PlatformFactory logs every environment
variable so whoever is debugging can see what was set. That dump goes
wherever the container's logs go -- CloudWatch for a launcher running as
an AWS Batch job -- which is a wider audience than whoever provisioned
the credential, and the launcher's environment now carries
WES_SERVICE_KEY alongside the pre-existing NGS360_AUTH_TOKEN and
SB_AUTH_TOKEN.

Mask values whose variable name contains TOKEN, KEY, SECRET, or PASSWORD,
keeping the character count: "set but empty" and "set to a truncated
value" are both real misconfigurations, and the dump exists to tell them
apart. Everything else is logged unchanged.

Adds tests/test_platform_factory.py -- the factory had no test of its own.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The module reads six environment variables across connect(),
get_current_task() and submit_task(), so the full contract was only
discoverable by reading the whole file. Whoever writes the AWS Batch job
definition -- or debugs a launcher that starts and cannot find itself --
needs it in one place.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
A launcher running headless (e.g. as an AWS Batch job) is given an ngs360_
API key minted for the user who started it, in NGS360_AUTH_TOKEN. When
NGS360_AUTH_KEY_ID names that key, connect() registers an exit handler
that retires it through DELETE /api/v1/auth/api-keys/{id}, so the key
does not outlive the run. The key authenticates its own retirement.

The handler is registered before the /auth/me probe, so a launcher that
fails to connect still retires its key. A failed retirement is logged,
not raised; the key's expiry bounds a launcher that is killed first.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@accumb3ns
accumb3ns force-pushed the feature/launcher-orchestration branch from 9ba6760 to a4ac6f7 Compare October 28, 2026 13:41
@accumb3ns accumb3ns changed the title feat: launcher orchestration support (service-key auth, current-task, ParentRunId tagging) feat: launcher orchestration support (current-task, ParentRunId tagging, per-launch key retirement) Oct 28, 2026
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.

2 participants