fix(egress): allow single-layer %2f in raw request path (npm scoped packages)#1369
fix(egress): allow single-layer %2f in raw request path (npm scoped packages)#1369Pangjiping wants to merge 1 commit into
Conversation
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 4765a68b02
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
4765a68 to
ed3a846
Compare
ed3a846 to
c5893bf
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: c5893bf02f
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
_path_is_ambiguous() rejected every request whose raw path contained a percent-encoded slash. npm scoped package registry paths are required to be encoded as /@scope%2fname on the wire (npm registry protocol), so credential injection for those requests started returning 403 as soon as the Credential Vault was active — breaking 'npm install @scope/pkg' in sandboxes. Split the two concerns: * At the raw-request stage in request(), tolerate a single-layer %2f (allow_single_encoded_slash=True). Nested encodings (%252f etc.), raw backslash, encoded backslash and dot-segments still trip the guard. * A new _path_encoded_slash_changes_binding() re-runs binding path matching against unquote(raw_path). If the encoded slash would move the request across a credential binding boundary, the request is still rejected with 403. * The post-substitution check in _apply_path_query_substitutions() keeps the strict semantics (allow_single_encoded_slash=False), so substitutions that inject a %2f into the path are still refused. Also wire mitmscripts unit tests into egress-test.yml so this regression is caught in CI, and add a Python E2E case that drives the same wire format through the real sidecar + credential vault + curl inside a sandbox against the echo target. Fixes: https://project.aone.alibaba-inc.com/v2/project/2135082/workitem/84550489
c5893bf to
e5323ce
Compare
Summary
_path_is_ambiguous()in the egress credential proxy rejected every request whose raw path contained%2f. npm scoped packages are required by the registry protocol to send/@scope%2fnameon the wire, so with Credential Vault active,npm install @scope/pkgin sandboxes was returning 403 (reported in Aone workitem 84550489 for@ali/orion-claude-plugin).Split the two concerns:
request()) — tolerate a single-layer%2f(allow_single_encoded_slash=True). Nested encodings (%252f,%252e%252e), raw backslash\, encoded backslash%5c, and dot-segments still trip the guard._path_encoded_slash_changes_binding()— re-runs binding path matching againstunquote(raw_path). If the encoded slash would move the request across a credential binding boundary, the request is still rejected with 403. Legit/@scope%2fnamedecodes into the same binding → allowed; a crafted/api/v8/projects/123%2f..%2f456/...decodes into a different scope → rejected (also caught by the pre-existing dot-segment check)._apply_path_query_substitutions()) — keeps the strict semantics (allow_single_encoded_slash=False), because a%2finjected by the credential proxy itself always shifts the canonical path relative to what the client sent.Also wire mitmscripts unit tests into
egress-test.yml— the tests already existed but weren't being run in CI, so this class of regression had no signal.Testing
python -m unittest discover -s components/egress/tests→ 34 passed (28 existing + 6 new)New tests cover:
npm scoped registry path
/@scope%2fname(lowercase and uppercase%2F) receives credential injection.Encoded
%2fthat stays inside a single binding scope is allowed.Encoded
%2fthat spans two bindings (broad vs. narrow) is rejected with 403.Double-encoded
%252fand encoded backslash%5cremain rejected.Integration tests
e2e / manual verification
Breaking Changes
The credential-proxy 403 semantics only change for a single-layer
%2fthat does not cross a binding boundary. That path previously always returned 403 and now succeeds — this is the intended fix. All other rejection paths (..,%252f,%5c,\,%2fcrossing bindings, substitution introducing%2f) still return 403.Checklist