docs(frd): add FRD 0005 for web_request system tool#87
Closed
larohra wants to merge 7 commits into
Closed
Conversation
Design doc for a built-in, opt-in http_call system tool that lets agents invoke HTTP endpoints declaratively instead of code-generating requests in the sandbox. Includes SSRF security floor, per-host auth via typed env secret-refs, per-agent override model, and full telemetry parity with the sandbox. Incorporates two independent architecture reviews (gpt-5.4 + gpt-5.5). Status: In review, pending human sign-off. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Fold the follow-up security discussion into FRD 0004 for the http_call system tool: - New section 4 subsections: 'Execution surfaces & the in-worker-code boundary' (model code runs only in the ACA sandbox, never the worker, with no in-worker fallback; tools/*.py is the sole in-worker author-code path, in-trust-domain and not model-reachable at runtime; standing invariant + author guideline), 'Residual threat: reflection / confused-deputy exfiltration' (named, with a mitigation ladder), and 'Alternatives considered: out-of-process secret custody' (ACA egress-proxy pros/cons table, why v1 is independent of it, compute re-host rejection, and a tiered custody roadmap). - New section 5 Decisions rows I1-I4 (Human-decided, 2026-07-09). - Section 7 docs impact + section 8 review record updated. No product-code or scope changes; the sign-off gate is unchanged. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
In-progress: reduce v1 to a public, unauthenticated fetch primitive (SSRF floor + caps + exact-host allowlist + minimal telemetry). Summary, motivation, and Goals updated; Non-goals/Phased-delivery table, section 4 v2 tags, and Decisions rows still pending in a follow-up commit. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 6c80e793-f72f-4629-ba8e-16e5847dbe53
Resolved docs/frds/README.md index conflict. main added FRD 0004 (Dynamic workflows, Finalized), which collides with this branch's FRD 0004 (http_call). Renumbered the http_call FRD to 0005 (git mv + frontmatter + heading) so main's 0004 owns the slot; README lists both 0004 and 0005. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 6c80e793-f72f-4629-ba8e-16e5847dbe53
Narrow FRD 0005 v1 to a public, unauthenticated fetch primitive and make the tool on-by-default (opt out via `http_call: false` or `tools: false`). Restructure the section 4 examples to a v1-minimal surface, moving the full auth/wildcard/override example into a 'once all versions ship' subsection. Tag the section 4 security subsections and section 6 tests with v1/v2 markers, append Decisions J1-J7 (scope reduction + default-on), and refresh the docs-impact and status sections. FRD stays In review; the human sign-off gate is unchanged. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 6c80e793-f72f-4629-ba8e-16e5847dbe53
Rename the FRD 0005 tool and config key http_call -> web_request, and the scheme flag allow_http (default false) -> require_https (default true, inverted polarity). This removes the overloaded "http" (tool name vs URL scheme) and the misread where allow_http: false looked like it disabled a now default-on tool. Also renames the FRD file slug, updates the docs/frds README index, and appends Decisions row J8. Historical log rows A1-J7 intentionally keep the original identifiers (append-only log); a naming note points to J8. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 6c80e793-f72f-4629-ba8e-16e5847dbe53
Remove deep v2/v3+ why-analysis prose that duplicated the append-only Decisions log: drop the Trust-model subsection, collapse Redirect/Secret-custody/Execution-surface/Reflection/egress-proxy-alternatives (~200 lines) into a compact 'Deferred to v2/v3+' notes block, and cut the review-history retrospective from section 8. Also compress the section 2 motivation and section 3 non-goals prose. Section 5 Decisions log (A1-J8) is preserved verbatim per the append-only convention; the full rationale remains there and in git history. No design change; FRD stays In review. 865 -> 594 lines. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 6c80e793-f72f-4629-ba8e-16e5847dbe53
Contributor
Author
|
Superseded by #96, which combines this FRD (0005) with the v1 implementation, tests, and docs in a single feature PR to main. Closing this FRD-only PR to consolidate review there. |
larohra
added a commit
that referenced
this pull request
Jul 13, 2026
Human sign-off received: flip status In review -> Finalized, confirm the Agent-decided rows, add PR #96 to pull_requests, and record the sign-off / PR-consolidation decision as append-only row K1. Update section 8 to reflect completed implementation (587 tests) shipped via #96; PR #87 closed as superseded. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 6c80e793-f72f-4629-ba8e-16e5847dbe53
larohra
added a commit
that referenced
this pull request
Jul 14, 2026
* docs(frd): add FRD 0004 for http_call system tool Design doc for a built-in, opt-in http_call system tool that lets agents invoke HTTP endpoints declaratively instead of code-generating requests in the sandbox. Includes SSRF security floor, per-host auth via typed env secret-refs, per-agent override model, and full telemetry parity with the sandbox. Incorporates two independent architecture reviews (gpt-5.4 + gpt-5.5). Status: In review, pending human sign-off. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> * docs(frd): capture secret-custody & egress-proxy analysis in FRD 0004 Fold the follow-up security discussion into FRD 0004 for the http_call system tool: - New section 4 subsections: 'Execution surfaces & the in-worker-code boundary' (model code runs only in the ACA sandbox, never the worker, with no in-worker fallback; tools/*.py is the sole in-worker author-code path, in-trust-domain and not model-reachable at runtime; standing invariant + author guideline), 'Residual threat: reflection / confused-deputy exfiltration' (named, with a mitigation ladder), and 'Alternatives considered: out-of-process secret custody' (ACA egress-proxy pros/cons table, why v1 is independent of it, compute re-host rejection, and a tiered custody roadmap). - New section 5 Decisions rows I1-I4 (Human-decided, 2026-07-09). - Section 7 docs impact + section 8 review record updated. No product-code or scope changes; the sign-off gate is unchanged. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> * docs(frd): WIP v1 scope reduction (summary/motivation/goals) In-progress: reduce v1 to a public, unauthenticated fetch primitive (SSRF floor + caps + exact-host allowlist + minimal telemetry). Summary, motivation, and Goals updated; Non-goals/Phased-delivery table, section 4 v2 tags, and Decisions rows still pending in a follow-up commit. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 6c80e793-f72f-4629-ba8e-16e5847dbe53 * docs(frd): reduce v1 scope and make http_call default-on Narrow FRD 0005 v1 to a public, unauthenticated fetch primitive and make the tool on-by-default (opt out via `http_call: false` or `tools: false`). Restructure the section 4 examples to a v1-minimal surface, moving the full auth/wildcard/override example into a 'once all versions ship' subsection. Tag the section 4 security subsections and section 6 tests with v1/v2 markers, append Decisions J1-J7 (scope reduction + default-on), and refresh the docs-impact and status sections. FRD stays In review; the human sign-off gate is unchanged. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 6c80e793-f72f-4629-ba8e-16e5847dbe53 * docs(frd): rename http_call system tool to web_request Rename the FRD 0005 tool and config key http_call -> web_request, and the scheme flag allow_http (default false) -> require_https (default true, inverted polarity). This removes the overloaded "http" (tool name vs URL scheme) and the misread where allow_http: false looked like it disabled a now default-on tool. Also renames the FRD file slug, updates the docs/frds README index, and appends Decisions row J8. Historical log rows A1-J7 intentionally keep the original identifiers (append-only log); a naming note points to J8. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 6c80e793-f72f-4629-ba8e-16e5847dbe53 * docs(frd-0005): trim web_request FRD to v1 scope Remove deep v2/v3+ why-analysis prose that duplicated the append-only Decisions log: drop the Trust-model subsection, collapse Redirect/Secret-custody/Execution-surface/Reflection/egress-proxy-alternatives (~200 lines) into a compact 'Deferred to v2/v3+' notes block, and cut the review-history retrospective from section 8. Also compress the section 2 motivation and section 3 non-goals prose. Section 5 Decisions log (A1-J8) is preserved verbatim per the append-only convention; the full rationale remains there and in git history. No design change; FRD stays In review. 865 -> 594 lines. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 6c80e793-f72f-4629-ba8e-16e5847dbe53 * config+observability: add web_request system tool schema, resolution, and telemetry Adds WebRequestConfig, SystemToolsConfig.web_request, SystemToolsAgentOverride.web_request, and ResolvedAgent.web_request_config to config/schema.py; adds default-on _resolve_web_request() to config/merge.py; adds FaultDomain.WEB_REQUEST and record_web_request() counter plumbing to _observability.py. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 53035269-5774-46e6-a0bc-a7eba5601967 * system_tools: implement web_request outbound HTTP tool (v1) Default-on, unauthenticated, single-request web_request tool with an always-on SSRF security floor: exact-host allowlist, global-unicast-only IP validation via an injectable async resolver, IP pinning through a custom aiohttp resolver/connector (DNS caching disabled), request-header denylist, response-header redaction, and capped/truncating response reads. Config is clamped to operator-defined absolute ceilings (timeout 120s max, request/response body 10MB max; defaults: 30s timeout, 5MB max response, 1MB max request). Built once per agent at registration (no Azure resource required). Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 53035269-5774-46e6-a0bc-a7eba5601967 * wire web_request tool through registration, runner, and app Adds AgentCapabilities.web_request_tools (built once per agent, lazily importing the factory), threads a dedicated web_request_tools parameter through runner.run_agent()/ run_agent_stream() parallel to sandbox_tools, passes it at every registration/_handlers.py and registration/endpoints.py call site, tracks 'web_request' in app.py's system_tools_used reporting (respecting default-on + global/per-agent disable), and exports create_web_request_tools from the package __init__. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 53035269-5774-46e6-a0bc-a7eba5601967 * tests: add comprehensive coverage for the web_request system tool New tests/test_web_request.py: param-schema validation, response shaping (JSON/text/ binary/HEAD/truncation), the full SSRF suite (IMDS/loopback/private/link-local/ULA/CGNAT/ unspecified/multicast/reserved, IPv4-mapped IPv6 unwrap, non-canonical numeric IP literal rejection, embedded-userinfo rejection, exact-host allowlist, https floor), IP pinning (validated IPs, DNS cache disabled, Host/SNI preserved), header policy, telemetry (span + counter, no query/secret leakage), config clamping, and default-on registration. New tests/test_config_merge.py cases for _resolve_web_request's default-on resolution. New fixtures/config_scenarios/14_web_request scenario plus a test_config_fixtures.py case exercising global config + per-agent opt-out through compose(). Updates test_package_imports.py and test_registration_capabilities.py for the new export/field. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 53035269-5774-46e6-a0bc-a7eba5601967 * docs: document the web_request system tool Regenerates docs/front-matter-reference.md (schema-driven) after adding WEB_REQUEST_DESCRIPTIONS and a system_tools.web_request table to eng/scripts/generate_config_reference.py. Adds a system_tools.web_request section with default-on/disable/opt-out examples to front-matter-spec.md (v2 items called out as future work), updates docs/architecture.md's module map and pipeline narrative for the new default-on, built-once-at-registration tool, adds a web_request span/metric/fault-domain reference to docs/observability.md, and adds a one-line quickstart mention to README.md. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 53035269-5774-46e6-a0bc-a7eba5601967 * test: harden web_request SSRF/header/capability regression coverage Address gpt-5.5 FIX-THEN-SHIP validation feedback (test-only, no product code changes): - tests/test_web_request.py: add explicit regression tests for trailing-dot allowlist normalization (single dot stripped -> match; double dot -> no match) and non-HTTP(S) scheme rejection (ftp://, file://) prior to any DNS/connect. Parameterize the request-header-denylist and response-header-redaction tests over the actual module-level '_REQUEST_HEADER_DENYLIST' / '_RESPONSE_HEADER_REDACT' constants (canonical + mixed-case variants) so coverage can't silently drift from the implementation. - tests/test_registration_capabilities.py: add a direct build_capabilities() regression for the web_request_tools channel — default WebRequestConfig() builds exactly one tool; None config and tools_disabled=True both suppress the tool AND skip the lazy 'import_module' factory call entirely (asserted via a monkeypatched import_module that raises if invoked). Gate (via uv run, Python 3.13.7): ruff clean, mypy --strict clean (37 files), pytest 587 passed (+35 vs. 552 baseline). Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 53035269-5774-46e6-a0bc-a7eba5601967 * docs(frd): finalize FRD 0005 web_request (sign-off + PR #96) Human sign-off received: flip status In review -> Finalized, confirm the Agent-decided rows, add PR #96 to pull_requests, and record the sign-off / PR-consolidation decision as append-only row K1. Update section 8 to reflect completed implementation (587 tests) shipped via #96; PR #87 closed as superseded. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 6c80e793-f72f-4629-ba8e-16e5847dbe53 * fix: address PR reviewer feedback (URL leakage, global stmt, docs wording, ceiling values) * fix: split global statement in _ensure_metrics across two lines for readability --------- Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
Tracks the design for a built-in
web_requestsystem tool (issue #1176) so agents can call HTTP/REST endpoints directly instead of generating and running code. This PR is the FRD only (medium+ feature pipeline, AGENTS.md §1) — no product code yet. The FRD staysIn review, gated on human sign-off before implementation.What's here
docs/frds/0005-web-request-system-tool.md— the full Feature Requirements Document: motivation, proposed design mapped to the discover -> translate -> register -> execute pipeline, an always-on SSRF security floor, a security analysis (trust model, SSRF validator, header/redirect/secret handling, execution-surface boundary, reflection residual, and an out-of-process-custody / ACA egress-proxy alternatives study), an append-only Decisions log, a test plan, and docs impact.Naming (latest)
Renamed the tool and config key
http_call->web_request, and the scheme flagallow_http(default false) ->require_https(default true, inverted polarity). This drops the overloaded "http" (tool name vs URL scheme) and the misread whereallow_http: falselooked like it disabled a now default-on tool. The FRD file slug was renamed to match; Decisions row J8 records the change, and historical log rows keep the original identifiers (append-only).Revision (scope reduction + default-on)
web_requestis now on by default. The reduced, SSRF-floored public-fetch scope makes it safe as a standard built-in (unlike the opt-in sandbox, which needs an Azure resource). Operators opt out withsystem_tools.web_request: false(app-wide), per-agentweb_request: false, or thetools: falsekill-switch. This is a behavior change on upgrade, called out in Compatibility.(v1)/(v2)tags so readers aren't told to configure things the runtime rejects.Status
In review— ready for human sign-off. Not flipped toFinalized; no implementation until sign-off.Refs #1176