From 13b9a1a5de5de773a0abdb1441bfc8858e7572f1 Mon Sep 17 00:00:00 2001 From: Harry Nguyen Date: Thu, 20 Aug 2026 16:18:46 -0700 Subject: [PATCH] fix: avoid unsafe yaml load in conformance tests --- AGENTS.md | 17 +++++++++++++++++ .../tests/test_otel_examples.py | 15 ++++++++++++++- 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/AGENTS.md b/AGENTS.md index ad1b986b..370e7811 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -54,6 +54,23 @@ again on every replay. This implies four rules: See [Determinism and Replay](https://docs.aws.amazon.com/durable-execution/patterns/best-practices/determinism/) for worked examples. +## Security-sensitive parsing + +- Do not use `yaml.load()` or `yaml.load_all()`, including with `Loader=` + arguments or suppression comments. CodeQL and security scanners flag the + unsafe call form even when the loader subclasses `yaml.SafeLoader`. +- Use `yaml.safe_load()` or `yaml.safe_load_all()` for plain YAML. +- For CloudFormation or SAM templates with short-form tags such as `!Ref`, + `!Sub`, `!GetAtt`, or `!If`, use a `yaml.SafeLoader` subclass with explicit + tag constructors so the tags are preserved. +- For custom safe loaders, instantiate the loader directly, call + `get_single_data()` or the equivalent multi-document API, and call + `dispose()` in a `finally` block. This matches what `yaml.safe_load()` does + internally while preserving custom tag support. +- Before finishing YAML-related changes, check Python code for unsafe call + forms: + `rg -n --glob '*.py' "yaml\\.load\\b|yaml\\.load_all\\b|from yaml import load\\b|from yaml import load_all\\b" .` + ## Testing Requirements All changes MUST include related tests. At minimum, include **unit tests**. Include **e2e integration tests** (in the `tests/e2e/` directory) when the change affects cross-component behavior, public API surfaces, or end-to-end workflows. For isolated bug fixes where a unit test alone sufficiently covers the fix, integration tests are not required. diff --git a/packages/aws-durable-execution-sdk-python-conformance-tests-otel/tests/test_otel_examples.py b/packages/aws-durable-execution-sdk-python-conformance-tests-otel/tests/test_otel_examples.py index 0e2984ea..5908dd7d 100644 --- a/packages/aws-durable-execution-sdk-python-conformance-tests-otel/tests/test_otel_examples.py +++ b/packages/aws-durable-execution-sdk-python-conformance-tests-otel/tests/test_otel_examples.py @@ -194,9 +194,22 @@ def _construct_cfn_tag(loader: CfnLoader, _suffix: str, node: yaml.Node) -> CfnT CfnLoader.add_multi_constructor("!", _construct_cfn_tag) +def _safe_load_cfn(stream: object) -> Any: + """Safely load a CloudFormation template with short-form tags. + + Equivalent to yaml.safe_load (CfnLoader extends yaml.SafeLoader) while + additionally preserving CloudFormation short-form tags. + """ + loader = CfnLoader(stream) + try: + return loader.get_single_data() + finally: + loader.dispose() + + def load_template(path: Path) -> dict[str, Any]: with path.open(encoding="utf-8") as stream: - template: dict[str, Any] = yaml.load(stream, Loader=CfnLoader) + template: dict[str, Any] = _safe_load_cfn(stream) return template