Skip to content

Fix --config on maestro cloud and unify workspace-config handling#3197

Merged
proksh merged 3 commits intomainfrom
fix/config-injection
Apr 21, 2026
Merged

Fix --config on maestro cloud and unify workspace-config handling#3197
proksh merged 3 commits intomainfrom
fix/config-injection

Conversation

@proksh
Copy link
Copy Markdown
Contributor

@proksh proksh commented Apr 21, 2026

Why

maestro cloud --config=<path> was broken for any config filename other than config.yaml/config.yml.

Two independent problems, both on the cloud path:

  1. FileUtils.isWebFlow() did its own workspace traversal that only skipped the hardcoded filenames config.yaml/config.yml. Any other name (config2.yaml, regression_config.yaml, platform_settings.yaml, …) was parsed as a flow and threw before the planner ever ran. The content-based isWorkspaceConfigFile detection added in Skip additional config files in workspace execution planner #3150 was never consulted on this path.

  2. CloudInteractor.upload() never received configFile. Even once local validation passed, the zip that got uploaded contained the workspace unchanged, and the cloud-side WorkspaceValidator hardcodes a lookup for /config.yaml / /config.yml at the zip root. So --config=<non-default-name> was effectively ignored during actual cloud execution. Maestro validate against one config locally and run against a different one (or none) in the cloud.

Rather than patch these in isolation, the design is now: --config=<path> means "this file IS the workspace config, wherever it lives" including outside the workspace directory entirely. You can now keep a library of configs in a shared location (e.g. ~/maestro-configs/smoke.yaml, ~/maestro-configs/regression.yaml) and point --config at any of them; the CLI injects the right one into the upload without touching your workspace layout.

What changed

  • Filters.kt — promoted isWorkspaceConfigFile from private to top-level fun so it's reusable as the single source of truth for "is this a workspace config YAML?"
  • FileUtils.isWebFlow() — replaced the hardcoded "config.yaml"/"config.yml" filename skip with isWorkspaceConfigFile(toPath()). Fixes bothcloud and test (both call isWebFlow) in one change, and removes the filename-coupling that made non-default config names explode.
  • WorkspaceUtils.createWorkspaceZip — new optional configOverride: Path?. The function now enforces a single invariant: the resulting zip has exactly one workspace configuration, always at /config.yaml.
    • With --config=<path> (including paths outside the workspace): the override's bytes are written as /config.yaml.
    • Without --config but with a root-level config.yaml/config.yml in the workspace: its bytes are written as /config.yaml.
    • Single-file upload: synthetic flows: [<relative path>] is written as today.
    • All workspace-config-shaped YAMLs detected by isWorkspaceConfigFile are always stripped from the zip contents — in both override and no-override cases. This prevents duplicate/conflicting config entries and shrinks zips that were previously carrying along regression_config.yaml,platform_settings.yaml, etc. that the worker was going to skip anyway.
  • CloudInteractor.upload — new configFile: File? parameter, threaded into createWorkspaceZip as configOverride.
  • CloudCommand.call — forwards configFile to upload.
  • WorkspaceValidator.validate — comment added at the zip-root lookup documenting that the invariant is provided by createWorkspaceZip, so future readers don't go hunting for how the filename guarantee is enforced.

Why this shape

  • One helper (isWorkspaceConfigFile) used everywhere that needs to answer "is this a workspace config?" — planner, zip builder, web-flow detector. Keeps future fixes in one place.
  • Cloud wire format keeps a single invariant: the zip always has exactly one /config.yaml at the root. No protocol or server changes needed.
  • Enables --config to live anywhere on disk, not just inside the workspace. The override is a file reference, not a workspace member.
  • Always-strip applies to both override and non-override paths, so "what ends up in the zip" is the same question regardless of whether --config is set.

Verified end-to-end

Original repro now completes the build+validate pipeline and proceeds into the real upload.

Copy link
Copy Markdown
Contributor

@Fishbowler Fishbowler left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks rational.

How much more testing still needs to happen against Maestro Cloud?

@proksh
Copy link
Copy Markdown
Contributor Author

proksh commented Apr 21, 2026

Looks rational.

How much more testing still needs to happen against Maestro Cloud?

I have tested it with a-lot of cases locally and it is working nicely. Since its broken anyways, I don't think there is much risk anyway.

What do you think? Should we spend more time testing on it or merge it and take user feedbacks?

Unit test also helps verifying the logic.

@Fishbowler
Copy link
Copy Markdown
Contributor

Ace, merge it!

@proksh proksh merged commit 6a1cf87 into main Apr 21, 2026
13 of 14 checks passed
@proksh proksh deleted the fix/config-injection branch April 21, 2026 22:38
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