Skip to content

fix(studio-cp): resolve short service name to full ECS name before ListTasks - #28

Merged
brettchien merged 2 commits into
mainfrom
fix/service-not-found-short-name
Aug 13, 2026
Merged

fix(studio-cp): resolve short service name to full ECS name before ListTasks#28
brettchien merged 2 commits into
mainfrom
fix/service-not-found-short-name

Conversation

@brettchien

Copy link
Copy Markdown
Contributor

Problem

OAB Studio's deploy_list / get_agent_states (roster) fail with:

deploy_get: failed to list ECS tasks: ServiceNotFoundException: Service not found.

even though the ECS services (oab-prod-orca, oab-prod-mira) exist and the
resolved identity has ECS read permissions. It surfaces only after fleet
credentials resolve to the right account — before that an AccessDenied earlier
in the chain masked it.

Root cause

studio-cp::observe_deployment matches the caller's service selector against
either the full ECS name (oab-{ns}-{name}) or the display short name
({name}):

.find(|s| service == format!("oab-{}-{}", s.namespace, s.name) || service == s.name)

…but then passed that same (possibly short) string straight to
instance_status, which calls ecs.list_tasks().service_name(service). ECS
ListTasks keys on the full service name only, so a short name 404s as
ServiceNotFoundException. get_agent_states (t_states) collects services by
short name (s.name), so it fails for every agent.

Fix

  • studio-cp: centralise the short->full mapping — canonical_service_name()
    • find_service() — and query tasks by the resolved full name, never the
      caller's raw string. Single read choke point (observe_deployment) covers
      both t_states (short names) and t_get (arbitrary caller input).
  • oabctl: harden instance_status to fail loud on a non-oab- name instead
    of letting it reach ECS and return an opaque ServiceNotFoundException.
  • test: service_selector_resolves_to_full_ecs_name guards the short-name
    path (pure, no live ECS).

Not fixed here (follow-up)

Other short-name->ECS/logs boundaries aren't audited yet (e.g. the events filter
goes through CloudWatch string filtering). Suggest a separate audit: every
ECS/logs boundary must use the full service name
.

Rollout

No config change — existing fleets.toml + credentials unaffected. Diagnosis
verified end-to-end against the live oab cluster (ap-east-2,
504190915686): identity/region resolve correctly and ListServices succeeds;
this PR fixes the subsequent ListTasks step. Build validation left to CI
(workspace statically links the full aws-sdk; local release builds OOM).

🤖 Generated with Claude Code

orca and others added 2 commits August 13, 2026 23:43
…stTasks

`observe_deployment` accepted either the display short name (`orca`) or the
full ECS name (`oab-prod-orca`) when matching a service, then passed the
caller's string verbatim to `instance_status`. ECS `ListTasks` filters by
`service_name`, which only accepts the full name, so a short name 404s as
`ServiceNotFoundException`. The roster / `get_agent_states` path collects short
names, so it failed for every agent once credentials resolved to the right
account (previously masked by an AccessDenied earlier in the chain).

- studio-cp: centralise the short->full mapping (`canonical_service_name` +
  `find_service`) and query tasks by the resolved full name.
- oabctl: harden `instance_status` to fail loud when handed a non-`oab-` name
  instead of surfacing an opaque ECS `ServiceNotFoundException`.
- test: `service_selector_resolves_to_full_ecs_name` guards the short-name path.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…site

Address review (Jelly):
- #3: add `ServiceStatus::service_name` carrying the raw ECS name verbatim, and
  query tasks by it instead of `format!`-rebuilding `oab-{ns}-{name}`. The
  rebuild is wrong for any service that doesn't fit the `oab-<ns>-<name>` shape
  (the parser falls back to `namespace = "?"`), so this is a correctness fix,
  not just cleanup.
- #4: the resolver (`resolve_service`) now returns the matched service whose
  `service_name` is passed to `instance_status` with zero further transformation,
  so the test asserts the exact value the call site queries with — not just an
  isolated helper.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@brettchien

Copy link
Copy Markdown
Contributor Author

Reviewed at 57c8048. Approving — both review points are resolved:

  • Carry the raw ECS service_name. ServiceStatus now stores the name exactly as ECS returned it, and observe_deployment queries ListTasks by &svc.service_name, with the format!("oab-{ns}-{name}") rebuild removed. This is a correctness fix, not just cleanup: service_status falls back to namespace = "?" for any name that doesn't split into oab-<ns>-<name>, so the old rebuild would fabricate a wrong name (e.g. oab-?-oab-foo) for such a service. Carrying the raw name removes that failure mode entirely.
  • Test asserts the value the call site actually uses. observe_deployment_resolves_selector_to_full_ecs_service_name checks resolve_service("orca", …).service_name == "oab-prod-orca" — the exact string handed to instance_status, which observe_deployment passes through with zero transformation. A recording-client seam would be the only way to lock the async wiring end-to-end, but with the new instance_status fail-loud guard on non-oab- names, the regression surface is well covered.

Non-blocking follow-up (already agreed): audit the other ECS / CloudWatch-logs boundaries (e.g. the events filter) to confirm they also use the full service name — separate issue.

Build/clippy/test intentionally left to CI (the workspace statically links the full aws-sdk; local release builds OOM), so merge should wait for a green run.

@brettchien
brettchien merged commit 152f1ed into main Aug 13, 2026
2 checks passed
@brettchien
brettchien deleted the fix/service-not-found-short-name branch August 13, 2026 15:54
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