Skip to content

feat(cli): Add --include-path selective filtering to download-output#1108

Open
larrygao001 wants to merge 15 commits intoaws-deadline:mainlinefrom
larrygao001:feat/download-input-and-path-filter
Open

feat(cli): Add --include-path selective filtering to download-output#1108
larrygao001 wants to merge 15 commits intoaws-deadline:mainlinefrom
larrygao001:feat/download-input-and-path-filter

Conversation

@larrygao001
Copy link
Copy Markdown
Contributor

@larrygao001 larrygao001 commented Apr 15, 2026

Add selective download support for job output attachments:

  • Add --include-path and --include-path-stdin options to download-output for downloading specific files or directory prefixes
  • Add _filter_paths() and _matches_any_filter() in download.py
  • Add path_filters parameter to OutputDownloader
  • Add _validate_and_normalize_include_paths() with path traversal rejection, backslash-to-forward-slash conversion, and normalization
  • Fix bug in get_job_input_paths_by_asset_root() where S3 root prefix was not prepended to input manifest keys
  • Extract shared helpers: _run_download_ux(), _get_job_download_context(), _parse_filters_and_config(), _handle_download_error()
  • Update job_attachments_guide.md to document --include-path
  • Add unit tests for path filtering and validation

A follow-up PR will add the download-input command using the patterns established here.

Fixes:

What was the problem/requirement? (What/Why)

The existing deadline job download-output command downloads all output files for a job. Users have no way to download only specific files or folders from a job's output. This makes the CLI less useful for workflows where users only need a subset of files.

What was the solution? (How)

  • --include-path (repeatable): accepts exact relative file paths or directory prefixes (trailing /). Multiple values are OR'd. Without --include-path, behavior is unchanged — all outputs are downloaded.
  • --include-path-stdin: reads one path per line from stdin until EOF or an empty line (sentinel). After consuming stdin, reopens /dev/tty (or CON on Windows) so interactive prompts still work. This is needed for the Deadline Cloud Monitor desktop app (Tauri) integration, where the Monitor writes file paths to the child process's stdin to avoid shell argument limits and Tauri's scoped command argument validation.
  • Path validation: _validate_and_normalize_include_paths() rejects .. (path traversal), converts \ to / (Windows compatibility), strips ./, collapses //.
  • Bug fix: get_job_input_paths_by_asset_root() was not prepending the S3 root prefix + Manifests folder to input manifest keys (unlike asset_sync.py which does this correctly). Fixed to use s3_settings.add_root_and_manifest_folder_prefix().
  • Refactoring: Extracted shared download UX flow into _run_download_ux(), _get_job_download_context(), _parse_filters_and_config(), and _handle_download_error() to prepare for the follow-up download-input PR.

What is the impact of this change?

  • download-output without --include-path behaves exactly as before — no breaking change.
  • The get_job_input_paths_by_asset_root() bug fix changes the S3 key used to fetch input manifests. This function was not previously called by any CLI command. The worker agent uses asset_sync.py which already had the correct prefix logic.

How was this change tested?

See DEVELOPMENT.md for information on running tests.

  • Have you run the unit tests?
    • Yes. New unit tests + existing download tests all pass (210 passed, 0 failed).
  • Have you run the integration tests?
    • Manually tested end-to-end against a real job with known input/output files:
      • download-output --include-path "output/output_0005.png" → downloaded 1 of 25 files
      • download-output with 10 --include-path values → downloaded exactly 10 of 25 files
      • --include-path "nonexistent.txt" → "No output files available"
      • --include-path "../../etc/passwd" → rejected with "Path filter must not contain '..'"
      • --include-path-stdin without piped data → reads until empty line, then continues to interactive prompts
  • Have you made changes to the download or asset_sync modules? If so, then it is highly recommended
    that you ensure that the docker-based unit tests pass.
    • Yes, changes to download.py. Docker-based tests should be run before merge.

Was this change documented?

  • Are relevant docstrings in the code base updated?
    • Yes. All new functions have docstrings.
  • Has the README.md been updated? If you modified CLI arguments, for instance.
    • The CLI reference (docs/cli_reference/deadline_job.md) is auto-generated from click decorators — new options will appear automatically.
    • docs/job_attachments_guide.md updated to mention --include-path.

Does this PR introduce new dependencies?

  • This PR does not add any new dependencies.

Is this a breaking change?

No. download-output without --include-path behaves identically to before. The get_job_input_paths_by_asset_root() fix changes behavior of a function that was not previously called from any CLI command.

Does this change impact security?

  • The --include-path option introduces a new input vector. Path traversal is mitigated with defense in depth:
    1. _validate_and_normalize_include_paths() rejects any filter containing .. at parse time.
    2. _ensure_paths_within_directory() validates download destination paths stay within the asset root at download time (existing check).
  • No new files/directories are created beyond the existing download behavior.
  • No threat modeling needed — same S3 access patterns and credential flow as existing download-output.

By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.

Comment thread test/unit/deadline_job_attachments/test_path_filtering.py Fixed
Comment thread test/unit/deadline_job_attachments/test_path_filtering.py Fixed
Comment thread test/unit/deadline_job_attachments/test_path_filtering.py Fixed
@github-actions github-actions Bot added the waiting-on-maintainers Waiting on the maintainers to review. label Apr 15, 2026
@larrygao001 larrygao001 force-pushed the feat/download-input-and-path-filter branch 11 times, most recently from 856e788 to d7b27ac Compare April 15, 2026 23:03
Comment thread src/deadline/job_attachments/download.py Fixed
@larrygao001 larrygao001 force-pushed the feat/download-input-and-path-filter branch 4 times, most recently from 98c3e8b to 51e68e8 Compare April 17, 2026 03:59
@larrygao001 larrygao001 marked this pull request as ready for review April 17, 2026 04:08
@larrygao001 larrygao001 requested review from a team as code owners April 17, 2026 04:08
@larrygao001 larrygao001 changed the title feat(cli): Add download-input command and --path-filter to download-o… feat(cli): Add download-input command and --path-filter to download-output Apr 17, 2026
Copy link
Copy Markdown
Contributor

@crowecawcaw crowecawcaw left a comment

Choose a reason for hiding this comment

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

Let's split up the download-input command from the filtering since the changes are independent and to make it easer to review. Suggest starting with the path filtering first and then adding download-input with the patterns we land on in the first PR.

Comment thread src/deadline/client/cli/_groups/job_group.py
Comment thread src/deadline/client/cli/_groups/job_group.py
@larrygao001 larrygao001 force-pushed the feat/download-input-and-path-filter branch from 51e68e8 to d933830 Compare April 17, 2026 20:06
@larrygao001 larrygao001 changed the title feat(cli): Add download-input command and --path-filter to download-output feat(cli): Add --include-path selective filtering to download-output Apr 17, 2026
@sonarqubecloud
Copy link
Copy Markdown

Comment thread src/deadline/client/cli/_groups/job_group.py Outdated
Add selective download support for job output attachments:

- Add --include-path and --include-path-stdin options to download-output
  for downloading specific files or directory prefixes
- Add _filter_paths() and _matches_any_filter() in download.py
- Add path_filters parameter to OutputDownloader
- Add _validate_and_normalize_include_paths() with path traversal
  rejection, backslash-to-forward-slash conversion, and normalization
- Fix bug in get_job_input_paths_by_asset_root() where S3 root prefix
  was not prepended to input manifest keys
- Update job_attachments_guide.md to document --include-path
- Add unit tests for path filtering and validation

Signed-off-by: larrygao <larrygao@amazon.com>
@larrygao001 larrygao001 force-pushed the feat/download-input-and-path-filter branch from ca11fcd to 2ee1e48 Compare April 21, 2026 19:06
Comment thread src/deadline/client/cli/_groups/job_group.py Fixed
Comment on lines +320 to +321
if ".." in f:
raise click.BadParameter(f"Path filter must not contain '..': {f}")
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I don't think we need to reject this, even though it's odd. This is a path filter so it chooses what files are downloaded. So if someone's trying to do something malicious with a weird path, at most they'll download all files for the job. If we were attaching files where .. could get the submitter access to unexpected files on the workstation, we'd need to think a bit more.

I think it's better to leave it out because it's simpler and so it doesn't suggest there's a security issue to defend against and which requires a robust control.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Good call, I left this out and am no longer validating against it so .. would just be treated like any other non-existant path

Comment on lines +1046 to +1051
if output != "json":
try:
tty_path = "CON" if sys.platform == "win32" else "/dev/tty"
sys.stdin = open(tty_path) # noqa: SIM115
except OSError:
pass # Non-interactive environment — no TTY to reopen
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

From what I can tell, this comes in to play if the caller sends in paths via stdin then later wants to send interactive commands (e.g. confirming something) also via stdin. So this code switches stdin back to TTY after the paths finish reading from stdin. I think this logic is confusing and unnecessary. Let's not mix the two. If someone sends in paths via stdin, they will not get any interactive prompts. If there are interactions required, we should either choose a default option that makes sense or fail with an error so the caller always needs to pass in the choice explicitly.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Makes sense, fixed in latest commit.

Copy link
Copy Markdown
Contributor

@crowecawcaw crowecawcaw left a comment

Choose a reason for hiding this comment

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

We added a new set of testes for job attachment CLI commands in this PR: #1125

The idea to test CLI commands without any internal mocking by using mock HTTP servers for S3 and Deadline. This feature would be great to cover with this new test pattern. It'd look something like creating a temp directory, creating a manifest with some real files in S3, downloading the files with this filter, and asserting the files that are created in our temp/test directory are only the ones we expect.

- Remove path traversal (..) rejection from path filter normalization;
  filters only select which files to download so .. is harmless
- Remove TTY stdin reopen hack; force auto_accept when --include-path-stdin
  is used so no interactive prompts are attempted
- Rename _validate_and_normalize_include_paths to _normalize_include_paths
- Add e2e tests using mock HTTP server pattern: directory prefix, exact
  file, multiple filters, no-match, stdin, and stdin+json (DCM pattern)
- Extract _seed_output_job helper to reduce e2e test boilerplate

Signed-off-by: Nathy MacKinlay <61921733+waninggibbon@users.noreply.github.com>
@waninggibbon
Copy link
Copy Markdown
Contributor

Added the following e2e tests in latest commit:

Test Scenario
include_path Directory prefix filter (renders/) — downloads 2 of 3 files
include_path_exact_file Exact file path — downloads 1 of 2 files
include_path_multiple Two --include-path values OR'd — cherry-picks from different directories
include_path_no_match Filter matches nothing — reports "no output files available", nothing written
include_path_stdin --include-path-stdin with piped paths + empty line sentinel — no interactive prompts
include_path_stdin_json --include-path-stdin + --output json — DCM's exact invocation pattern, verifies all output is valid JSON lines

crowecawcaw
crowecawcaw previously approved these changes Apr 23, 2026
Comment thread src/deadline/client/cli/_groups/job_group.py
raise click.UsageError("Missing option '--step-id' required with '--task-id'")

filters = list(include_path)
if include_path_stdin:
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This is really odd - we did quite a bit of work before on how to source input glob filters. See the previous thinking in manifest snapshot.

Align download-output filtering with the manifest CLI pattern:
- Replace --include-path/--include-path-stdin with -i/--include and
  -e/--exclude options supporting glob patterns via fnmatch
- Add -ie/--include-exclude-config for JSON string or file input,
  reusing _process_glob_inputs from the manifest CLI
- Default to include-all when only --exclude is provided
- Rename OutputDownloader param path_filters to include_filters
- Add e2e tests: exclude, glob patterns, config file, and large
  inline JSON blob (200 files, 150 selected)

Signed-off-by: Nathy MacKinlay <61921733+waninggibbon@users.noreply.github.com>
@waninggibbon
Copy link
Copy Markdown
Contributor

Updated to mirror the manifest style arguments (--include and --exclude with no separate stdin option)

New tests:

Test Scenario
include_path --include "renders/" — directory prefix downloads 2 of 3 files
include_path_exact_file --include "renders/frame_001.exr" — exact path downloads 1 of 2
include_path_multiple Two --include values OR'd — cherry-picks from different directories
include_path_no_match Filter matches nothing — graceful "no output files available" message
exclude --include "renders/" --exclude "renders/draft/" — downloads renders except drafts
glob_pattern --include "renders/*.exr" — fnmatch glob downloads only .exr files
include_exclude_config --include-exclude-config filters.json — JSON file with include + exclude
include_exclude_config_large_inline_json --include-exclude-config '{...}' — inline JSON blob selecting 150 of 200 files (DCM use case)

Replace the --include/--exclude/--include-exclude-config options on
download-output with --include, --include-config, and --submission-path.

Key changes:
- Match glob patterns against the full path (root + relative) instead
  of just the relative path, enabling patterns like "*/renders/*.png"
- Filter against workstation paths by default; add --submission-path
  flag to filter against original submission paths instead
- Remove --exclude and --include-exclude-config; rename to
  --include-config (include-only)
- Normalize Windows backslash root paths for cross-OS glob matching
- Add OutputDownloader.apply_include_filters() to avoid reaching into
  internals from the CLI layer
- Extract _full_path() helper to DRY up path joining in filter functions

Signed-off-by: Nathy MacKinlay <61921733+waninggibbon@users.noreply.github.com>
@waninggibbon
Copy link
Copy Markdown
Contributor

Discussed this extensively offline, here is a quick summary of the latest changes:

What changed

CLI options:

  • --include (kept) — glob patterns matched against the full path (root + relative), e.g. /renders/.png or *.exr
  • --include-config (renamed from --include-exclude-config) — JSON string or file path with include patterns, e.g. {"include": ["/renders/.exr"]}
  • --submission-path (new flag) — when set, filters match against the original submission paths instead of the local workstation paths
  • --exclude — removed for now, we can add it back later if needed

Filtering behavior:

  • Glob patterns now match against the full path (root + relative) instead of just the relative path. This enables patterns like /renders/.png that match across directory structures.
  • By default, filters are applied against workstation paths (after path mapping). Pass --submission-path to filter against the original submission paths instead.
  • Windows backslash root paths are normalized to forward slashes for cross-OS glob matching, without affecting the actual download paths.

Code quality:

  • Extracted _full_path() helper to DRY up path joining in _filter_paths and _filter_manifests
  • Added OutputDownloader.apply_include_filters() method instead of reaching into internals from the CLI layer
  • Renamed _parse_include_exclude → _parse_include_config

DCM compatibility

The --include-config option accepting a file path covers DCM's use case for large filter sets (avoids Windows CreateProcess 32KB argument limit). The deadline:// protocol path is
unaffected — it only does full downloads.

Tests

All existing tests updated, plus new coverage for:

  • Full-path glob matching (including Windows root paths)
  • --submission-path flag behavior
  • Workstation path filtering with patterns containing root directory names

Signed-off-by: Nathy MacKinlay <61921733+waninggibbon@users.noreply.github.com>
Plain relative paths (no glob characters, not absolute) are now matched
as a suffix against the full path. This allows filters like
"renders/frame_001.exr" to match "/home/user/project/renders/frame_001.exr"
without requiring glob prefixes.

This supports the DCM use case where the frontend has relative paths from
manifests and passes them directly as include filters.

Signed-off-by: Nathy MacKinlay <61921733+waninggibbon@users.noreply.github.com>
@waninggibbon waninggibbon force-pushed the feat/download-input-and-path-filter branch from da4d3f4 to 1c9f256 Compare April 24, 2026 14:12
Remove --include-config and stdin (--include -) options, keeping only
--include as the single filtering mechanism. This simplifies the CLI
surface while covering all use cases:

- Human CLI: --include "*.exr" or --include "renders/frame_001.exr"
- DCM: multiple --include args via Tauri shell with args:true scope
- Web copy/paste: repeated --include flags in the command

The --include-config and stdin approaches can be added back later if
the Windows 32KB CreateProcess limit becomes a practical concern.

Signed-off-by: Nathy MacKinlay <61921733+waninggibbon@users.noreply.github.com>
@waninggibbon
Copy link
Copy Markdown
Contributor

Summary of latest changes

Simplified the CLI to just two options: --include and --submission-path.

--include (repeatable)

Supports both glob patterns and plain relative paths:

bash

Glob patterns

deadline job download-output --include ".exr"
deadline job download-output --include "
/renders/*"

Relative paths (matched as suffix against full path)

deadline job download-output --include "renders/frame_001.exr"

Multiple filters (OR'd)

deadline job download-output -i "renders/frame_001.exr" -i "renders/frame_002.exr" -i "*.log"

Patterns are matched against the full path (root + relative), so /renders/.png works across directory structures. Plain relative paths like renders/frame_001.exr match as a suffix —
any full path ending in /renders/frame_001.exr will match.

--submission-path flag

By default, filters match against the local workstation paths (after storage profile mapping). Pass --submission-path to filter against the original submission paths instead.

Why this covers all our use cases

Use case How it works
Human CLI --include "*.exr" or --include "renders/frame_001.exr"
DCM desktop (filtered) Multiple --include args + --submission-path. DCM has relative paths from manifests and can pass them directly. Tauri scope uses args: true to allow variable argument count.
Web copy/paste Repeated --include flags in the generated command
Web protocol (deadline://) Unaffected — still does full downloads, no filtering
Direct S3 ("Save Selected") Unaffected — bypasses CLI entirely

What was removed

  • --exclude — removed for now, can add back later
  • --include-exclude-config / --include-config — not needed since --include handles both globs and exact paths
  • --path-filter-stdin — not needed; DCM can use repeated --include args instead

Cross-OS

Windows backslash root paths are normalized to forward slashes for matching without affecting download paths. A Windows user's --include "renders\frame.exr" works the same as a Mac
user's --include "renders/frame.exr".

return normalized


def _parse_include_filters(include: tuple[str, ...]) -> Optional[list[str]]:
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Nit: feels like an unnecessary function that could be rolled into _normalize_filters instead.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Yeah pretty redundant, I went ahead and inlined it in the new implementation.

for manifest in job_attachments_manifests:
root_path_format_mapping[manifest["rootPath"]] = manifest["rootPathFormat"]

# When --submission-path is set, filter against the submission (S3) paths.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Super nit: more like the relative job attachment paths. S3 is more of an implementation detail of job attachments

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Dropped "s3" in latest commit!

task_id=task_id,
session_action_id=session_action_id,
session=queue_role_session,
include_filters=include_filters if submission_path else None,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Nit: could use better variable names to differentiate the two include_filters variables. There's probably a 3rd meaning elsewhere for workstation filters.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Renamed to include_patterns when referring to user provided patterns, and include_filters when referring to the actual filter that gets applied to distinguish between the two!

Comment thread src/deadline/job_attachments/download.py Outdated
- Remove _is_relative_filter and suffix matching; instead auto-prepend
  */ to relative patterns so all non-directory filters use fnmatch.
  This enables relative globs like "renders/*.exr" to work naturally.
- Remove _parse_include_filters wrapper; inline _normalize_filters at
  the call site.
- Rename include_filters to include_patterns in _download_job_output
  for clarity (OutputDownloader keeps include_filters as its API).
- Fix unit tests to use full paths as file_path input, matching real
  usage through _full_path().

Signed-off-by: Nathy MacKinlay <61921733+waninggibbon@users.noreply.github.com>
Comment thread src/deadline/client/cli/_groups/job_group.py
Replace the --submission-path boolean flag with --match-paths-by that
accepts SOURCE or WORKSTATION (default). This makes the option
self-documenting about the two filtering modes.

Also clean up comments to reference "source" instead of "S3".

Signed-off-by: Nathy MacKinlay <61921733+waninggibbon@users.noreply.github.com>
Rename SOURCE to JOB and WORKSTATION to LOCAL for clarity:
- JOB matches against the paths recorded at job submission
- LOCAL matches against the local download paths (default)

Also update help text to be more user-friendly.

Signed-off-by: Nathy MacKinlay <61921733+waninggibbon@users.noreply.github.com>
vfs_manager.start(session_dir=session_dir)


def _full_path(root: str, relative: str) -> str:
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

There's other code that joins the roots and manifest paths. Can we use the same mechanism here to make sure we don't have differences?


for f in filters:
if f.endswith("/"):
if file_path.startswith(f):
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Shouldn't this still use fnmatch?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Yes, good catch. Will fix in next commit.

)


class TestMatchesAnyFilter:
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Looks like this is only testing against posix paths, need windows paths with \ separators too.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Adding in next commit!

is_json_format: bool = False,
ignore_storage_profiles: bool = False,
include_patterns: Optional[list[str]] = None,
match_paths_by: str = "LOCAL",
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Question, why a hard coded "LOCAL", not a string enum?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I see this parameter is LOCAL or JOB?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Would it cause the code to be brittle since it implies users to know this string has 2 explicit values.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Just a foolish blunder, no more reasoning than that. Will fix!

match anywhere under the root — e.g. 'renders/*.exr' matches '*/renders/*.exr'.
The file_path should be the full path (root + relative).
"""
from fnmatch import fnmatch
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

nit :) Kiro loves inline imports, can we move it up to the top.

vfs_manager.start(session_dir=session_dir)


def _full_path(root: str, relative: str) -> str:
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Thanks for the heads up, I'll raise a new PR against the new repo.

Copy link
Copy Markdown
Contributor

@leongdl leongdl left a comment

Choose a reason for hiding this comment

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

- Add MatchPathsBy enum (JOB/LOCAL) replacing raw strings
- Use posixpath.join in _full_path for consistency with
  _transform_manifests_to_absolute_paths
- Use fnmatch for directory prefix filters instead of startswith
- Handle Windows drive letter paths as absolute in _matches_any_filter
- Move fnmatch import to top of download.py
- Add Windows path separator tests for _matches_any_filter

Signed-off-by: Nathy MacKinlay <61921733+waninggibbon@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

waiting-on-maintainers Waiting on the maintainers to review.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants