Repository navigation
Conversation
🧪 Hands-on test plan (not run: hands-on runs are disabled)Commit Summary: Run sam local start-api on small SAM templates. Invalid REST Api paths (the issue's example, a greedy variable that isn't last, unicode or space segments, a parameter-resolved path) should fail fast with a clear Error and exit code 1. Valid paths should still mount and invoke, and HttpApi paths should stay unvalidated. Compare with the merge base, where the invalid paths are served, and run the provider unit tests. Why: The PR changes what users see from sam local start-api: REST Api event paths that API Gateway rejects now fail at startup with a user error, where before they were served. This is easy to show with small templates, and comparing against the merge base confirms the fix. The change is a pure regex check with no new dependencies, network calls, install hooks or CI/agent-file changes, so a run is safe. Docker is needed because start-api creates its container client before route extraction reaches the new check. Needs Docker: yes Needs cloud resources (would not be run):
Setup: Scenarios (8)S1: Issue #7613 repro: an Api event path with a partial-segment variable ({y}.png) should now be rejected at start-api startup with a user error (compared with the base branch) Expected: PR: exit=1; out.log contains "Error: Invalid Path '/api/map/{z}/{x}/{y}.png' in Api event of function 'MapFunction': Resource's path part '{y}.png' only allows a-zA-Z0-9._,:-"; no 'Mounting' line and no Python traceback. Merge base: no error, a line 'Mounting MapFunction at hxxp://127.0.0.1:3011/ap… S2: Valid REST paths still mount and invoke: path variables, a literal segment after a variable, a colon in a literal, and a trailing greedy variable Expected: out.log shows four 'Mounting MapFunction at hxxp://127.0.0.1:3012/...' lines (users/{id}, files/{name}/data.json, items/v1:batch-get, api/{version}/{proxy+}) and no 'Error'. Each curl prints a body equal to the requested path followed by code=200. Behavior matches the merge base. S3: New error path: a greedy variable that is not the last segment (compared with the base branch) Expected: PR: exit=1; out.log contains "Error: Invalid Path '/{proxy+}/items' in Api event of function 'MapFunction': greedy path variable '{proxy+}' must be the last part of the path." and no traceback. Merge base: the route is mounted (or fails differently); record what the base does. S4: Out-of-scope check: an HttpApi event with the same partial-segment variable is still not validated and starts as before Expected: exit=124 (server kept running until timeout); out.log contains 'Mounting MapFunction at hxxp://127.0.0.1:3014/api/map/{y}.png [GET]' and no 'Invalid Path' error. S5: Path set with !Ref to a parameter: check whether the resolved string is validated (the PR says intrinsic paths are skipped) and that a valid default still starts (compared with the base branch) Expected: First run (PR): exit=1 with "Invalid Path '/bad/{id}.png'" and path part '{id}.png', since the parameter is resolved before route extraction. If it instead mounts /bad/{id}.png, record that parameter-driven paths bypass validation. Second run: exit=124 and 'Mounting MapFunction at hxxp://127.0.0.1:… S6: Unicode and space segments: rejected with a readable message, no encoding errors or tracebacks (compared with the base branch) Expected: PR: exit=1; out.log contains "Invalid Path '/café/hello world'" and "path part 'café'" with the é intact; no UnicodeEncodeError and no traceback. Merge base: the route is mounted (exit=124) or fails differently; record it. S7: Lenient edge cases the regex accepts: an empty segment (/a//b), a dash in a variable name (/{a-b}), a comma literal (/items/a,b). Record the local behavior; whether API Gateway accepts them is in needs_cloud (compared with the base branch) Expected: PR: no 'Invalid Path' error for any of the three paths; the result matches the merge base (expected exit=124 with three Mounting lines). Any traceback, such as from Flask rule conversion of {a-b}, should match the base; a difference from the base is a regression. S8: Unit tests for the provider, the new validation tests and the start-api wiring pass with the PR Expected: Exit code 0. All tests pass, including TestSamApiRestApiPathValidation (9 valid, 6 invalid, 1 HttpApi case). No existing test in test_sam_api_provider.py fails because its Api path is now rejected. 🤖 Automated hands-on test — not a review approval · model claude-opus-5.5 · commit History (1)
|
Which issue(s) does this change fix?
#7613
Why is this change necessary?
sam local start-apiservesApievent paths that API Gateway rejects on deploy, e.g./api/map/{z}/{x}/{y}.png. The template works locally and then fails in CloudFormation with "Resource's path part only allow a-zA-Z0-9._-: or a valid greedy path variable and curly braces at the beginning and the end."How does it address the issue?
SamApiProvider._convert_event_routenow validates thePathof REST (Api) events. Each path part must be either a literal ofa-zA-Z0-9._,:-(the character set documented for REST API path segments in Amazon API Gateway important notes) or a whole-part path variable ({name}or{name+}), and a greedy variable must be the last part. Paths that are intrinsic functions are not validated. Invalid paths raiseInvalidSamDocumentException, the error the provider already uses for invalid event properties, whichstart-apireports as a user error.Out of scope:
HttpApievents, OpenAPIDefinitionBodypaths, and CloudFormationAWS::ApiGateway::Resourcepaths are not validated.What side effects does this change have?
Templates with REST
Apievent paths that API Gateway would reject now fail atsam local start-apistartup instead of being served locally. Valid paths are unaffected.Mandatory Checklist
PRs will only be reviewed after checklist is complete
make prpassesmake update-reproducible-reqsif dependencies were changed (no dependency changes)By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.